summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.c35
-rw-r--r--dive.h27
-rw-r--r--divelist.c6
-rw-r--r--file.c2
-rw-r--r--gps.c2
-rw-r--r--info.c2
-rw-r--r--main.c7
-rw-r--r--parse-xml.c82
-rw-r--r--webservice.c56
9 files changed, 142 insertions, 77 deletions
diff --git a/dive.c b/dive.c
index d86c7de2a..a0cb60ba6 100644
--- a/dive.c
+++ b/dive.c
@@ -1519,3 +1519,38 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean pr
fixup_dive(res);
return res;
}
+
+struct dive *find_dive_including(timestamp_t when)
+{
+ int i;
+ struct dive *dive;
+
+ /* binary search, anyone? Too lazy for now;
+ * also we always use the duration from the first divecomputer
+ * could this ever be a problem? */
+ for_each_dive(i, dive) {
+ if (dive->when <= when && when <= dive->when + dive->dc.duration.seconds)
+ return dive;
+ }
+ return NULL;
+}
+
+gboolean dive_within_time_range(struct dive *dive, timestamp_t when, timestamp_t offset)
+{
+ return when - offset <= dive->when && dive->when + dive->dc.duration.seconds <= when + offset;
+}
+
+/* find the n-th dive that is part of a group of dives within the offset around 'when'.
+ * How is that for a vague definition of what this function should do... */
+struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset)
+{
+ int i, j = 0;
+ struct dive *dive;
+
+ for_each_dive(i, dive) {
+ if (dive_within_time_range(dive, when, offset))
+ if (++j == n)
+ return dive;
+ }
+ return NULL;
+}
diff --git a/dive.h b/dive.h
index 4132d0c30..e719f2289 100644
--- a/dive.h
+++ b/dive.h
@@ -321,11 +321,19 @@ struct dive {
struct divecomputer dc;
};
-static inline int dive_has_location(struct dive *dive)
+static inline int dive_has_gps_location(struct dive *dive)
{
return dive->latitude.udeg || dive->longitude.udeg;
}
+static inline void copy_gps_location(struct dive *from, struct dive *to)
+{
+ if (from && to) {
+ to->latitude.udeg = from->latitude.udeg;
+ to->longitude.udeg = from->longitude.udeg;
+ }
+}
+
/* Pa = N/m^2 - so we determine the weight (in N) of the mass of 10m
* of water (and use standard salt water at 1.03kg per liter if we don't know salinity)
* and add that to the surface pressure (or to 1013 if that's unknown) */
@@ -433,6 +441,13 @@ extern struct dive_table dive_table;
extern int selected_dive;
#define current_dive (get_dive(selected_dive))
+static inline struct dive *get_gps_location(int nr, struct dive_table *table)
+{
+ if (nr >= table->nr || nr < 0)
+ return NULL;
+ return table->dives[nr];
+}
+
static inline struct dive *get_dive(int nr)
{
if (nr >= dive_table.nr || nr < 0)
@@ -450,6 +465,9 @@ static inline struct dive *get_dive(int nr)
#define for_each_dive(_i,_x) \
for ((_i) = 0; ((_x) = get_dive(_i)) != NULL; (_i)++)
+#define for_each_gps_location(_i,_x) \
+ for ((_i) = 0; ((_x) = get_gps_location(_i, &gps_location_table)) != NULL; (_i)++)
+
static inline struct dive *get_dive_by_diveid(int diveid, int deviceid)
{
int i;
@@ -464,12 +482,15 @@ static inline struct dive *get_dive_by_diveid(int diveid, int deviceid)
}
return NULL;
}
+extern struct dive *find_dive_including(timestamp_t when);
+extern gboolean dive_within_time_range(struct dive *dive, timestamp_t when, timestamp_t offset);
+struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset);
/* Check if two dive computer entries are the exact same dive (-1=no/0=maybe/1=yes) */
extern int match_one_dc(struct divecomputer *a, struct divecomputer *b);
extern void parse_xml_init(void);
-extern void parse_xml_buffer(const char *url, const char *buf, int size, GError **error);
+extern void parse_xml_buffer(const char *url, const char *buf, int size, struct dive_table *table, GError **error);
extern void parse_xml_exit(void);
extern void set_filename(const char *filename, gboolean force);
@@ -500,11 +521,11 @@ extern void utc_mkdate(timestamp_t, struct tm *tm);
extern struct dive *alloc_dive(void);
extern void record_dive(struct dive *dive);
-extern void delete_dive(struct dive *dive);
extern struct sample *prepare_sample(struct divecomputer *dc);
extern void finish_sample(struct divecomputer *dc);
+extern void sort_table(struct dive_table *table);
extern void report_dives(gboolean imported, gboolean prefer_imported);
extern struct dive *fixup_dive(struct dive *dive);
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean prefer_downloaded);
diff --git a/divelist.c b/divelist.c
index 882ba3bc6..5a942c13f 100644
--- a/divelist.c
+++ b/divelist.c
@@ -875,7 +875,7 @@ GdkPixbuf *get_gps_icon(void)
static GdkPixbuf *get_gps_icon_for_dive(struct dive *dive)
{
- if (dive_has_location(dive))
+ if (dive_has_gps_location(dive))
return get_gps_icon();
else
return NULL;
@@ -1608,7 +1608,7 @@ gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data)
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
dive = get_dive(idx);
- if (dive && dive_has_location(dive))
+ if (dive && dive_has_gps_location(dive))
show_gps_location(dive, NULL);
}
if (path)
@@ -2435,7 +2435,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
}
#if HAVE_OSM_GPS_MAP
/* Only offer to show on map if it has a location. */
- if (dive_has_location(dive)) {
+ if (dive_has_gps_location(dive)) {
menuitem = gtk_menu_item_new_with_label(_("Show in map"));
g_signal_connect(menuitem, "activate", G_CALLBACK(show_gps_location_cb), dive);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
diff --git a/file.c b/file.c
index 10bb4274e..73c07f82d 100644
--- a/file.c
+++ b/file.c
@@ -246,7 +246,7 @@ static void parse_file_buffer(const char *filename, struct memblock *mem, GError
if (fmt && open_by_filename(filename, fmt+1, mem, error))
return;
- parse_xml_buffer(filename, mem->buffer, mem->size, error);
+ parse_xml_buffer(filename, mem->buffer, mem->size, &dive_table, error);
}
void parse_file(const char *filename, GError **error, gboolean possible_default_filename)
diff --git a/gps.c b/gps.c
index 31be2bbc5..15ee65830 100644
--- a/gps.c
+++ b/gps.c
@@ -242,7 +242,7 @@ void show_gps_locations()
map = init_map();
for_each_dive(idx, dive) {
- if (dive_has_location(dive)) {
+ if (dive_has_gps_location(dive)) {
add_gps_point(map, dive->latitude.udeg / 1000000.0,
dive->longitude.udeg / 1000000.0);
}
diff --git a/info.c b/info.c
index 65ad8b128..2916c0eaf 100644
--- a/info.c
+++ b/info.c
@@ -675,7 +675,7 @@ static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info
info->location = text_entry(box, _("Location"), location_list, dive->location);
- if (dive_has_location(dive))
+ if (dive_has_gps_location(dive))
print_gps_coordinates(gps_text, sizeof(gps_text), dive->latitude.udeg / 1000000.0,
dive->longitude.udeg / 1000000.0);
hbox = gtk_hbox_new(FALSE, 2);
diff --git a/main.c b/main.c
index 4cacb0375..170481035 100644
--- a/main.c
+++ b/main.c
@@ -50,6 +50,11 @@ static int sortfn(const void *_a, const void *_b)
return 0;
}
+void sort_table(struct dive_table *table)
+{
+ qsort(table->dives, table->nr, sizeof(struct dive *), sortfn);
+}
+
const char *weekday(int wday)
{
static const char wday_array[7][7] = {
@@ -157,7 +162,7 @@ void report_dives(gboolean is_imported, gboolean prefer_imported)
/* This does the right thing for -1: NULL */
last = get_dive(preexisting-1);
- qsort(dive_table.dives, dive_table.nr, sizeof(struct dive *), sortfn);
+ sort_table(&dive_table);
for (i = 1; i < dive_table.nr; i++) {
struct dive **pp = &dive_table.dives[i-1];
diff --git a/parse-xml.c b/parse-xml.c
index 184a0e89d..eb75e74c0 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <assert.h>
#define __USE_XOPEN
#include <time.h>
#include <libxml/parser.h>
@@ -18,85 +19,34 @@
int verbose;
+/* the dive table holds the overall dive list; target table points at
+ * the table we are currently filling */
struct dive_table dive_table;
-
+struct dive_table *target_table = NULL;
/*
* Add a dive into the dive_table array
*/
-void record_dive(struct dive *dive)
+static void record_dive_to_table(struct dive *dive, struct dive_table *table)
{
- int nr = dive_table.nr, allocated = dive_table.allocated;
- struct dive **dives = dive_table.dives;
+ assert(table != NULL);
+ int nr = table->nr, allocated = table->allocated;
+ struct dive **dives = table->dives;
if (nr >= allocated) {
allocated = (nr + 32) * 3 / 2;
dives = realloc(dives, allocated * sizeof(struct dive *));
if (!dives)
exit(1);
- dive_table.dives = dives;
- dive_table.allocated = allocated;
+ table->dives = dives;
+ table->allocated = allocated;
}
dives[nr] = fixup_dive(dive);
- dive_table.nr = nr+1;
+ table->nr = nr+1;
}
-static void delete_dive_renumber(struct dive **dives, int i, int nr)
-{
- struct dive *dive = dives[i];
- int number = dive->number, j;
-
- if (!number)
- return;
-
- /*
- * Check that all numbered dives after the deleted
- * ones are consecutive, return without renumbering
- * if that is not the case.
- */
- for (j = i+1; j < nr; j++) {
- struct dive *next = dives[j];
- if (!next->number)
- break;
- number++;
- if (next->number != number)
- return;
- }
-
- /*
- * Ok, we hit the end of the dives or a unnumbered
- * dive - renumber.
- */
- for (j = i+1 ; j < nr; j++) {
- struct dive *next = dives[j];
- if (!next->number)
- break;
- next->number--;
- }
-}
-
-/*
- * Remove a dive from the dive_table array
- */
-void delete_dive(struct dive *dive)
+void record_dive(struct dive *dive)
{
- int nr = dive_table.nr, i;
- struct dive **dives = dive_table.dives;
-
- /*
- * Stupid. We know the dive table is sorted by date,
- * we could do a binary lookup. Sue me.
- */
- for (i = 0; i < nr; i++) {
- struct dive *d = dives[i];
- if (d != dive)
- continue;
- /* should we re-number? */
- delete_dive_renumber(dives, i, nr);
- memmove(dives+i, dives+i+1, sizeof(struct dive *)*(nr-i-1));
- dives[nr] = NULL;
- dive_table.nr = nr-1;
- break;
- }
+ record_dive_to_table(dive, &dive_table);
}
static void start_match(const char *type, const char *name, char *buffer)
@@ -1172,7 +1122,7 @@ static void dive_end(void)
if (!is_dive())
free(cur_dive);
else
- record_dive(cur_dive);
+ record_dive_to_table(cur_dive, target_table);
cur_dive = NULL;
cur_dc = NULL;
cur_cylinder_index = 0;
@@ -1480,10 +1430,12 @@ static void reset_all(void)
import_source = UNKNOWN;
}
-void parse_xml_buffer(const char *url, const char *buffer, int size, GError **error)
+void parse_xml_buffer(const char *url, const char *buffer, int size,
+ struct dive_table *table, GError **error)
{
xmlDoc *doc;
+ target_table = table;
doc = xmlReadMemory(buffer, size, url, NULL, 0);
if (!doc) {
fprintf(stderr, _("Failed to parse '%s'.\n"), url);
diff --git a/webservice.c b/webservice.c
index 243d9b5a0..fec2ccf2d 100644
--- a/webservice.c
+++ b/webservice.c
@@ -4,8 +4,11 @@
#include <libxml/tree.h>
#include <libxml/parser.h>
#include "dive.h"
+#include "divelist.h"
#include "display-gtk.h"
+struct dive_table gps_location_table;
+
enum {
DD_STATUS_OK,
DD_STATUS_ERROR_CONNECT,
@@ -142,6 +145,52 @@ static void download_dialog_delete(GtkWidget *w, gpointer data)
download_dialog_release_xml(state);
}
+static gboolean is_automatic_fix(struct dive *gpsfix)
+{
+ if (gpsfix && gpsfix->location && !strcmp(gpsfix->location, "automatic fix"))
+ return TRUE;
+ return FALSE;
+}
+
+#define SAME_GROUP 6 * 3600 // six hours
+
+static void merge_locations_into_dives(void)
+{
+ int i, nr = 0;
+ struct dive *gpsfix, *last_named_fix = NULL, *dive;
+
+ sort_table(&gps_location_table);
+
+ for_each_gps_location(i, gpsfix) {
+ if (is_automatic_fix(gpsfix)) {
+ dive = find_dive_including(gpsfix->when);
+ if (dive && !dive_has_gps_location(dive))
+ copy_gps_location(gpsfix, dive);
+ } else {
+ if (last_named_fix && dive_within_time_range(last_named_fix, gpsfix->when, SAME_GROUP)) {
+ nr++;
+ } else {
+ nr = 1;
+ last_named_fix = gpsfix;
+ }
+ dive = find_dive_n_near(gpsfix->when, nr, SAME_GROUP);
+ if (dive) {
+ if (!dive_has_gps_location(dive))
+ copy_gps_location(gpsfix, dive);
+ if (!dive->location)
+ dive->location = strdup(gpsfix->location);
+ } else {
+ struct tm tm;
+ utc_mkdate(gpsfix->when, &tm);
+ printf("didn't find dive matching gps fix named %s @ %04d-%02d-%02d %02d:%02d:%02d\n",
+ gpsfix->location,
+ tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ }
+ }
+ }
+}
+
void webservice_download_dialog(void)
{
const guint pad = 6;
@@ -203,8 +252,11 @@ void webservice_download_dialog(void)
result = gtk_dialog_run(GTK_DIALOG(dialog));
if (result == GTK_RESPONSE_ACCEPT) {
/* apply download */
- parse_xml_buffer(_("Webservice"), state.xmldata, state.xmldata_len, NULL);
- report_dives(TRUE, FALSE);
+ parse_xml_buffer(_("Webservice"), state.xmldata, state.xmldata_len, &gps_location_table, NULL);
+ /* now merge the data in the gps_location table into the dive_table */
+ merge_locations_into_dives();
+ mark_divelist_changed(TRUE);
+ dive_list_update_dives();
/* store last entered uid in config */
subsurface_set_conf("webservice_uid", gtk_entry_get_text(GTK_ENTRY(uid)));
}