]> git.tdb.fi Git - ext/subsurface.git/blob - parse.c
Move the parser closer to being usable
[ext/subsurface.git] / parse.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <libxml/parser.h>
5 #include <libxml/tree.h>
6
7 /*
8  * File boundaries are dive boundaries. But sometimes there are
9  * multiple dives per file, so there can be other events too that
10  * trigger a "new dive" marker and you may get some nesting due
11  * to that. Just ignore nesting levels.
12  */
13 static void dive_start(void)
14 {
15         printf("---\n");
16 }
17
18 static void dive_end(void)
19 {
20 }
21
22 static void sample_start(void)
23 {
24         printf("Sample:\n");
25 }
26
27 static void sample_end(void)
28 {
29 }
30
31 static void entry(const char *name, int size, const char *buffer)
32 {
33         printf("%s: %.*s\n", name, size, buffer);
34 }
35
36 static const char *nodename(xmlNode *node, char *buf, int len)
37 {
38         /* Don't print out the node name if it is "text" */
39         if (!strcmp(node->name, "text")) {
40                 node = node->parent;
41                 if (!node || !node->name)
42                         return "root";
43         }
44
45         buf += len;
46         *--buf = 0;
47         len--;
48
49         for(;;) {
50                 const char *name = node->name;
51                 int i = strlen(name);
52                 while (--i >= 0) {
53                         unsigned char c = name[i];
54                         *--buf = tolower(c);
55                         if (!--len)
56                                 return buf;
57                 }
58                 node = node->parent;
59                 if (!node || !node->name)
60                         return buf;
61                 *--buf = '.';
62                 if (!--len)
63                         return buf;
64         }
65 }
66
67 #define MAXNAME 64
68
69 static void visit_one_node(xmlNode *node)
70 {
71         int len;
72         const unsigned char *content;
73         char buffer[MAXNAME];
74         const char *name;
75
76         content = node->content;
77         if (!content)
78                 return;
79
80         /* Trim whitespace at beginning */
81         while (isspace(*content))
82                 content++;
83
84         /* Trim whitespace at end */
85         len = strlen(content);
86         while (len && isspace(content[len-1]))
87                 len--;
88
89         if (!len)
90                 return;
91
92         name = nodename(node, buffer, sizeof(buffer));
93
94         entry(name, len, content);
95 }
96
97 static void traverse(xmlNode *node)
98 {
99         xmlNode *n;
100
101         for (n = node; n; n = n->next) {
102                 /* XML from libdivecomputer: 'dive' per new dive */
103                 if (!strcmp(n->name, "dive")) {
104                         dive_start();
105                         traverse(n->children);
106                         dive_end();
107                         continue;
108                 }
109
110                 /*
111                  * At least both libdivecomputer and Suunto
112                  * agree on "sample".
113                  *
114                  * Well - almost. Ignore case.
115                  */
116                 if (!strcasecmp(n->name, "sample")) {
117                         sample_start();
118                         traverse(n->children);
119                         sample_end();
120                         continue;
121                 }
122
123                 /* Anything else - just visit it and recurse */
124                 visit_one_node(n);
125                 traverse(n->children);
126         }
127 }
128
129 static void parse(const char *filename)
130 {
131         xmlDoc *doc;
132
133         doc = xmlReadFile(filename, NULL, 0);
134         if (!doc) {
135                 fprintf(stderr, "Failed to parse '%s'.\n", filename);
136                 return;
137         }
138
139         dive_start();
140         traverse(xmlDocGetRootElement(doc));
141         dive_end();
142         xmlFreeDoc(doc);
143         xmlCleanupParser();
144 }
145
146 int main(int argc, char **argv)
147 {
148         int i;
149
150         LIBXML_TEST_VERSION
151
152         for (i = 1; i < argc; i++)
153                 parse(argv[i]);
154         return 0;
155 }