+/* We're in the top-level dive xml. Try to convert whatever value to a dive value */
+static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
+{
+ const char *last = last_part(name);
+
+ if (match("date", last, divedate, buf, &dive->when))
+ return;
+ if (match("time", last, divetime, buf, &dive->when))
+ return;
+ if (match("datetime", last, divedatetime, buf, &dive->when))
+ return;
+ if (match("maxdepth", last, depth, buf, &dive->maxdepth))
+ return;
+ if (match("meandepth", last, depth, buf, &dive->meandepth))
+ return;
+ if (match("divetime", last, duration, buf, &dive->duration))
+ return;
+ if (match("divetimesec", last, duration, buf, &dive->duration))
+ return;
+ if (match("surfacetime", last, duration, buf, &dive->surfacetime))
+ return;
+ if (match("airtemp", last, temperature, buf, &dive->airtemp))
+ return;
+ if (match("watertemp", last, temperature, buf, &dive->watertemp))
+ return;
+ if (match("cylinderstartpressure", last, pressure, buf, &dive->beginning_pressure))
+ return;
+ if (match("cylinderendpressure", last, pressure, buf, &dive->end_pressure))
+ return;
+ if (match("divenumber", last, ignore, buf, NULL))
+ return;
+ if (match("diveseries", last, ignore, buf, NULL))
+ return;
+ if (match("number", last, ignore, buf, NULL))
+ return;
+ if (match("size", last, ignore, buf, NULL))
+ return;
+ if (match("fingerprint", last, ignore, buf, NULL))
+ return;
+ nonmatch("dive", name, last, buf);
+}
+
+static unsigned int dive_size(int samples)
+{
+ return sizeof(struct dive) + samples*sizeof(struct sample);
+}
+
+/*
+ * File boundaries are dive boundaries. But sometimes there are
+ * multiple dives per file, so there can be other events too that
+ * trigger a "new dive" marker and you may get some nesting due
+ * to that. Just ignore nesting levels.
+ */
+static void dive_start(void)
+{
+ unsigned int size;
+
+ if (dive)
+ return;
+
+ alloc_samples = 5;
+ size = dive_size(alloc_samples);
+ dive = malloc(size);
+ if (!dive)
+ exit(1);
+ memset(dive, 0, size);
+ memset(&tm, 0, sizeof(tm));
+}
+
+static char *generate_name(struct dive *dive)
+{
+ int len;
+ struct tm *tm;
+ char buffer[256], *p;
+
+ tm = gmtime(&dive->when);
+
+ len = snprintf(buffer, sizeof(buffer),
+ "%04d-%02d-%02d "
+ "%02d:%02d:%02d "
+ "(%d ft, %d min)\n",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ to_feet(dive->maxdepth), dive->duration.seconds / 60);
+ p = malloc(len+1);
+ if (!p)
+ exit(1);
+ memcpy(p, buffer, len+1);
+ return p;
+}
+
+static void dive_end(void)
+{
+ if (!dive)
+ return;
+ if (!dive->name)
+ dive->name = generate_name(dive);
+ record_dive(dive);
+ dive = NULL;
+}
+
+static void sample_start(void)
+{
+ int nr;
+
+ if (!dive)
+ return;
+ nr = dive->samples;
+ if (nr >= alloc_samples) {
+ unsigned int size;
+
+ alloc_samples = (alloc_samples * 3)/2 + 10;
+ size = dive_size(alloc_samples);
+ dive = realloc(dive, size);
+ if (!dive)
+ return;
+ }
+ sample = dive->sample + nr;
+ memset(sample, 0, sizeof(*sample));
+}
+
+static void sample_end(void)
+{
+ sample = NULL;
+ if (!dive)
+ return;
+ dive->samples++;
+}
+
+static void entry(const char *name, int size, const char *raw)
+{
+ char *buf = malloc(size+1);
+
+ if (!buf)
+ return;
+ memcpy(buf, raw, size);
+ buf[size] = 0;
+ if (sample) {
+ try_to_fill_sample(sample, name, buf);
+ return;
+ }
+ if (dive) {
+ try_to_fill_dive(dive, name, buf);
+ return;
+ }
+}
+
+static const char *nodename(xmlNode *node, char *buf, int len)
+{
+ if (!node || !node->name)
+ return "root";
+
+ buf += len;
+ *--buf = 0;
+ len--;
+
+ for(;;) {
+ const char *name = node->name;
+ int i = strlen(name);
+ while (--i >= 0) {
+ unsigned char c = name[i];
+ *--buf = tolower(c);
+ if (!--len)
+ return buf;
+ }
+ node = node->parent;
+ if (!node || !node->name)
+ return buf;
+ *--buf = '.';
+ if (!--len)
+ return buf;
+ }
+}
+
+#define MAXNAME 64
+
+static void visit_one_node(xmlNode *node)
+{
+ int len;
+ const unsigned char *content;
+ char buffer[MAXNAME];
+ const char *name;
+
+ content = node->content;
+ if (!content)
+ return;
+
+ /* Trim whitespace at beginning */
+ while (isspace(*content))
+ content++;
+
+ /* Trim whitespace at end */
+ len = strlen(content);
+ while (len && isspace(content[len-1]))
+ len--;
+
+ if (!len)
+ return;
+
+ /* Don't print out the node name if it is "text" */
+ if (!strcmp(node->name, "text"))
+ node = node->parent;
+
+ name = nodename(node, buffer, sizeof(buffer));
+
+ entry(name, len, content);
+}
+
+static void traverse(xmlNode *node)