]> git.tdb.fi Git - ext/subsurface.git/blob - parse.c
Fill in dummy parse target code
[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  * Some silly typedefs to make our units very explicit.
9  *
10  * Also, the units are chosen so that values can be expressible as
11  * integers, so that we never have FP rounding issues. And they
12  * are small enough that converting to/from imperial units doesn't
13  * really matter.
14  *
15  * We also strive to make '0' a meaningless number saying "not
16  * initialized", since many values are things that may not have
17  * been reported (eg tank pressure or temperature from dive
18  * computers that don't support them). But sometimes -1 is an even
19  * more explicit way of saying "not there".
20  *
21  * Thus "millibar" for pressure, for example, or "millikelvin" for
22  * temperatures. Doing temperatures in celsius or fahrenheit would
23  * make for loss of precision when converting from one to the other,
24  * and using millikelvin is SI-like but also means that a temperature
25  * of '0' is clearly just a missing temperature or tank pressure.
26  *
27  * Also strive to use units that can not possibly be mistaken for a
28  * valid value in a "normal" system without conversion. If the max
29  * depth of a dive is '20000', you probably didn't convert from mm on
30  * output, or if the max depth gets reported as "0.2ft" it was either
31  * a really boring dive, or there was some missing input conversion,
32  * and a 60-ft dive got recorded as 60mm.
33  *
34  * Doing these as "structs containing value" means that we always
35  * have to explicitly write out those units in order to get at the
36  * actual value. So there is hopefully little fear of using a value
37  * in millikelvin as Fahrenheit by mistake.
38  *
39  * We don't actually use these all yet, so maybe they'll change, but
40  * I made a number of types as guidelines.
41  */
42 typedef struct {
43         int seconds;
44 } duration_t;
45
46 typedef struct {
47         int mm;
48 } depth_t;
49
50 typedef struct {
51         int mbar;
52 } pressure_t;
53
54 typedef struct {
55         int mkelvin;
56 } temperature_t;
57
58 typedef struct {
59         int mliter;
60 } volume_t;
61
62 typedef struct {
63         int permille;
64 } fraction_t;
65
66 typedef struct {
67         int grams;
68 } weight_t;
69
70 typedef struct {
71         fraction_t o2;
72         fraction_t n2;
73         fraction_t he2;
74 } gasmix_t;
75
76 typedef struct {
77         volume_t size;
78         pressure_t pressure;
79 } tank_type_t;
80
81 struct sample {
82         duration_t time;
83         depth_t depth;
84         temperature_t temperature;
85         pressure_t tankpressure;
86         int tankindex;
87 };
88
89 struct dive {
90         time_t when;
91         depth_t maxdepth, meandepth;
92         duration_t duration, surfacetime;
93         depth_t visibility;
94         temperature_t airtemp, watertemp;
95         pressure_t beginning_pressure, end_pressure;
96         int samples;
97         struct sample sample[];
98 };
99
100 static void record_dive(struct dive *dive)
101 {
102         static int nr;
103
104         printf("Recording dive %d with %d samples\n", ++nr, dive->samples);
105 }
106
107 /* We're in samples - try to convert the random xml value to something useful */
108 static void try_to_fill_sample(struct sample *sample, const char *name, int size, const char *buffer)
109 {
110 }
111
112 /* We're in the top-level dive xml. Try to convert whatever value to a dive value */
113 static void try_to_fill_dive(struct dive *dive, const char *name, int size, const char *buffer)
114 {
115 }
116
117 /*
118  * Dive info as it is being built up..
119  */
120 static int alloc_samples;
121 static struct dive *dive;
122 static struct sample *sample;
123
124 static unsigned int dive_size(int samples)
125 {
126         return sizeof(struct dive) + samples*sizeof(struct sample);
127 }
128
129 /*
130  * File boundaries are dive boundaries. But sometimes there are
131  * multiple dives per file, so there can be other events too that
132  * trigger a "new dive" marker and you may get some nesting due
133  * to that. Just ignore nesting levels.
134  */
135 static void dive_start(void)
136 {
137         unsigned int size;
138
139         alloc_samples = 5;
140         size = dive_size(alloc_samples);
141         dive = malloc(size);
142         if (!dive)
143                 exit(1);
144         memset(dive, 0, size);
145 }
146
147 static void dive_end(void)
148 {
149         if (!dive)
150                 return;
151         record_dive(dive);
152         dive = NULL;
153 }
154
155 static void sample_start(void)
156 {
157         int nr;
158
159         if (!dive)
160                 return;
161         nr = dive->samples;
162         if (nr >= alloc_samples) {
163                 unsigned int size;
164
165                 alloc_samples = (alloc_samples * 3)/2 + 10;
166                 size = dive_size(alloc_samples);
167                 dive = realloc(dive, size);
168                 if (!dive)
169                         return;
170         }
171         sample = dive->samples + nr;
172 }
173
174 static void sample_end(void)
175 {
176         sample = NULL;
177         if (!dive)
178                 return;
179         dive->samples++;
180 }
181
182 static void entry(const char *name, int size, const char *buffer)
183 {
184         if (sample) {
185                 try_to_fill_sample(sample, name, size, buffer);
186                 return;
187         }
188         if (dive) {
189                 try_to_fill_dive(dive, name, size, buffer);
190                 return;
191         }
192 }
193
194 static const char *nodename(xmlNode *node, char *buf, int len)
195 {
196         /* Don't print out the node name if it is "text" */
197         if (!strcmp(node->name, "text")) {
198                 node = node->parent;
199                 if (!node || !node->name)
200                         return "root";
201         }
202
203         buf += len;
204         *--buf = 0;
205         len--;
206
207         for(;;) {
208                 const char *name = node->name;
209                 int i = strlen(name);
210                 while (--i >= 0) {
211                         unsigned char c = name[i];
212                         *--buf = tolower(c);
213                         if (!--len)
214                                 return buf;
215                 }
216                 node = node->parent;
217                 if (!node || !node->name)
218                         return buf;
219                 *--buf = '.';
220                 if (!--len)
221                         return buf;
222         }
223 }
224
225 #define MAXNAME 64
226
227 static void visit_one_node(xmlNode *node)
228 {
229         int len;
230         const unsigned char *content;
231         char buffer[MAXNAME];
232         const char *name;
233
234         content = node->content;
235         if (!content)
236                 return;
237
238         /* Trim whitespace at beginning */
239         while (isspace(*content))
240                 content++;
241
242         /* Trim whitespace at end */
243         len = strlen(content);
244         while (len && isspace(content[len-1]))
245                 len--;
246
247         if (!len)
248                 return;
249
250         name = nodename(node, buffer, sizeof(buffer));
251
252         entry(name, len, content);
253 }
254
255 static void traverse(xmlNode *node)
256 {
257         xmlNode *n;
258
259         for (n = node; n; n = n->next) {
260                 /* XML from libdivecomputer: 'dive' per new dive */
261                 if (!strcmp(n->name, "dive")) {
262                         dive_start();
263                         traverse(n->children);
264                         dive_end();
265                         continue;
266                 }
267
268                 /*
269                  * At least both libdivecomputer and Suunto
270                  * agree on "sample".
271                  *
272                  * Well - almost. Ignore case.
273                  */
274                 if (!strcasecmp(n->name, "sample")) {
275                         sample_start();
276                         traverse(n->children);
277                         sample_end();
278                         continue;
279                 }
280
281                 /* Anything else - just visit it and recurse */
282                 visit_one_node(n);
283                 traverse(n->children);
284         }
285 }
286
287 static void parse(const char *filename)
288 {
289         xmlDoc *doc;
290
291         doc = xmlReadFile(filename, NULL, 0);
292         if (!doc) {
293                 fprintf(stderr, "Failed to parse '%s'.\n", filename);
294                 return;
295         }
296
297         dive_start();
298         traverse(xmlDocGetRootElement(doc));
299         dive_end();
300         xmlFreeDoc(doc);
301         xmlCleanupParser();
302 }
303
304 int main(int argc, char **argv)
305 {
306         int i;
307
308         LIBXML_TEST_VERSION
309
310         for (i = 1; i < argc; i++)
311                 parse(argv[i]);
312         return 0;
313 }