4 #include <libxml/parser.h>
5 #include <libxml/tree.h>
8 * Some silly typedefs to make our units very explicit.
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
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".
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.
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.
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.
39 * We don't actually use these all yet, so maybe they'll change, but
40 * I made a number of types as guidelines.
84 temperature_t temperature;
85 pressure_t tankpressure;
91 depth_t maxdepth, meandepth;
92 duration_t duration, surfacetime;
94 temperature_t airtemp, watertemp;
95 pressure_t beginning_pressure, end_pressure;
97 struct sample sample[];
100 static void record_dive(struct dive *dive)
104 printf("Recording dive %d with %d samples\n", ++nr, dive->samples);
107 static void nonmatch(const char *type, const char *fullname, const char *name, int size, const char *buffer)
109 printf("Unable to match %s '(%.*s)%s' (%.*s)\n", type,
110 (int) (name - fullname), fullname, name,
114 static const char *last_part(const char *name)
116 const char *p = strrchr(name, '.');
117 return p ? p+1 : name;
120 /* We're in samples - try to convert the random xml value to something useful */
121 static void try_to_fill_sample(struct sample *sample, const char *name, int size, const char *buffer)
123 const char *last = last_part(name);
124 nonmatch("sample", name, last, size, buffer);
127 /* We're in the top-level dive xml. Try to convert whatever value to a dive value */
128 static void try_to_fill_dive(struct dive *dive, const char *name, int size, const char *buffer)
130 const char *last = last_part(name);
131 nonmatch("dive", name, last, size, buffer);
135 * Dive info as it is being built up..
137 static int alloc_samples;
138 static struct dive *dive;
139 static struct sample *sample;
141 static unsigned int dive_size(int samples)
143 return sizeof(struct dive) + samples*sizeof(struct sample);
147 * File boundaries are dive boundaries. But sometimes there are
148 * multiple dives per file, so there can be other events too that
149 * trigger a "new dive" marker and you may get some nesting due
150 * to that. Just ignore nesting levels.
152 static void dive_start(void)
157 size = dive_size(alloc_samples);
161 memset(dive, 0, size);
164 static void dive_end(void)
172 static void sample_start(void)
179 if (nr >= alloc_samples) {
182 alloc_samples = (alloc_samples * 3)/2 + 10;
183 size = dive_size(alloc_samples);
184 dive = realloc(dive, size);
188 sample = dive->samples + nr;
191 static void sample_end(void)
199 static void entry(const char *name, int size, const char *buffer)
202 try_to_fill_sample(sample, name, size, buffer);
206 try_to_fill_dive(dive, name, size, buffer);
211 static const char *nodename(xmlNode *node, char *buf, int len)
213 /* Don't print out the node name if it is "text" */
214 if (!strcmp(node->name, "text")) {
216 if (!node || !node->name)
225 const char *name = node->name;
226 int i = strlen(name);
228 unsigned char c = name[i];
234 if (!node || !node->name)
244 static void visit_one_node(xmlNode *node)
247 const unsigned char *content;
248 char buffer[MAXNAME];
251 content = node->content;
255 /* Trim whitespace at beginning */
256 while (isspace(*content))
259 /* Trim whitespace at end */
260 len = strlen(content);
261 while (len && isspace(content[len-1]))
267 name = nodename(node, buffer, sizeof(buffer));
269 entry(name, len, content);
272 static void traverse(xmlNode *node)
276 for (n = node; n; n = n->next) {
277 /* XML from libdivecomputer: 'dive' per new dive */
278 if (!strcmp(n->name, "dive")) {
280 traverse(n->children);
286 * At least both libdivecomputer and Suunto
289 * Well - almost. Ignore case.
291 if (!strcasecmp(n->name, "sample")) {
293 traverse(n->children);
298 /* Anything else - just visit it and recurse */
300 traverse(n->children);
304 static void parse(const char *filename)
308 doc = xmlReadFile(filename, NULL, 0);
310 fprintf(stderr, "Failed to parse '%s'.\n", filename);
315 traverse(xmlDocGetRootElement(doc));
321 int main(int argc, char **argv)
327 for (i = 1; i < argc; i++)