From 6fe8cb652191728586f3731dcf6688b5a5b3efbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20G=C3=BCntner?= Date: Sat, 2 Nov 2013 02:12:42 +0100 Subject: [PATCH] Replaced the tag implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new implementation supports custom tags which are provided by the user as well as default tags which are provided by subsurface. Default tags can be translated and will be written to XML in their non-localized form. Signed-off-by: Maximilian Güntner --- dive.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++- dive.h | 69 ++++++++++++---------- divelist.c | 7 ++- main.cpp | 1 + parse-xml.c | 59 +++++++++++++------ save-xml.c | 26 ++++++--- statistics.c | 9 --- 7 files changed, 265 insertions(+), 66 deletions(-) diff --git a/dive.c b/dive.c index a98b10412..d2cda168d 100644 --- a/dive.c +++ b/dive.c @@ -6,6 +6,8 @@ #include "gettext.h" #include "dive.h" +struct tag_entry *g_tag_list = NULL; + void add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name) { struct event *ev, **p; @@ -189,6 +191,7 @@ struct dive *alloc_dive(void) if (!dive) exit(1); memset(dive, 0, sizeof(*dive)); + taglist_init(&(dive->tag_list)); return dive; } @@ -1813,6 +1816,161 @@ static void join_dive_computers(struct divecomputer *res, struct divecomputer *a remove_redundant_dc(res, prefer_downloaded); } +int taglist_get_tagstring(struct tag_entry *tag_list, char *buffer, int len) { + int i = 0; + struct tag_entry *tmp; + tmp = tag_list->next; + memset(buffer, 0, len); + while(tmp != NULL) { + int newlength = strlen(tmp->tag->name); + if (i > 0) + newlength += 2; + if ((i+newlength) < len) { + if (i > 0) { + strcpy(buffer+i, ", "); + strcpy(buffer+i+2, tmp->tag->name); + } else { + strcpy(buffer, tmp->tag->name); + } + } else { + return i; + } + i += newlength; + tmp = tmp->next; + } + return i; +} + +struct divetag *taglist_get_tag(struct tag_entry *tag_list, const char *tag) +{ + struct tag_entry *tmp; + tmp = tag_list->next; + while(tmp != NULL) { + if (tmp->tag != NULL) + if (strcmp(tmp->tag->name, tag) == 0) + return tmp->tag; + else + tmp = tmp->next; + } + return NULL; +} + +static inline void taglist_free_divetag(struct divetag *tag) { + if (tag->name != NULL) + free(tag->name); + if (tag->source != NULL) + free(tag->source); + free(tag); +} + +/* Add a tag to the tag_list, keep the list sorted */ +static struct divetag *taglist_add_divetag(struct tag_entry *tag_list, struct divetag *tag) +{ + struct tag_entry *tmp, *last; + last = tag_list; + tmp = tag_list->next; + while(1) { + if (tmp == NULL || strcmp(tmp->tag->name, tag->name) > 0) { + /* Insert in front of it */ + last->next = malloc(sizeof(struct tag_entry)); + last->next->next = tmp; + last->next->tag = tag; + return last->next->tag; + } else if (strcmp(tmp->tag->name, tag->name) == 0) { + /* Already in list */ + return tmp->tag; + } else { + last = tmp; + tmp = tmp->next; + } + } +} + +struct divetag *taglist_add_tag(struct tag_entry *tag_list, const char *tag) +{ + struct divetag *ret_tag, *new_tag; + const char *translation; + new_tag = malloc(sizeof(struct divetag)); + + translation = translate("gettextFromC", tag); + if (strcmp(tag, translation) == 0) { + new_tag->source = NULL; + new_tag->name = malloc(strlen(tag)+1); + memcpy(new_tag->name, tag, strlen(tag)+1); + } else { + new_tag->name = malloc(strlen(translation)+1); + memcpy(new_tag->name, translation, strlen(translation)+1); + new_tag->source = malloc(strlen(tag)+1); + memcpy(new_tag->source, tag, strlen(tag)+1); + } + /* Try to insert new_tag into g_tag_list if we are not operating on it */ + if (tag_list != g_tag_list) { + ret_tag = taglist_add_divetag(g_tag_list, new_tag); + /* g_tag_list already contains new_tag, free the duplicate */ + if (ret_tag != new_tag) + taglist_free_divetag(new_tag); + ret_tag = taglist_add_divetag(tag_list, ret_tag); + } else { + ret_tag = taglist_add_divetag(tag_list, new_tag); + if (ret_tag != new_tag) + taglist_free_divetag(new_tag); + } + return ret_tag; +} + +void taglist_init(struct tag_entry **tag_list) { + *tag_list = malloc(sizeof(struct tag_entry)); + (*tag_list)->next = NULL; + (*tag_list)->tag = NULL; +} + +/* Clear everything but the first element */ +void taglist_clear(struct tag_entry *tag_list) { + struct tag_entry *current_tag_entry, *next; + current_tag_entry = tag_list->next; + while (current_tag_entry != NULL) { + next = current_tag_entry->next; + free(current_tag_entry); + current_tag_entry = next; + } + tag_list->next = NULL; +} + +/* Merge src1 and src2, write to *dst */ +static void taglist_merge(struct tag_entry *dst, struct tag_entry *src1, struct tag_entry *src2) +{ + struct tag_entry *current_tag_entry; + current_tag_entry = src1->next; + while (current_tag_entry != NULL) { + taglist_add_divetag(dst, current_tag_entry->tag); + current_tag_entry = current_tag_entry->next; + } + current_tag_entry = src2->next; + while (current_tag_entry != NULL) { + taglist_add_divetag(dst, current_tag_entry->tag); + current_tag_entry = current_tag_entry->next; + } +} + +void taglist_init_global() +{ + int i; + const char* default_tags[] = { + QT_TRANSLATE_NOOP("gettextFromC", "boat"), QT_TRANSLATE_NOOP("gettextFromC", "shore"), QT_TRANSLATE_NOOP("gettextFromC", "drift"), + QT_TRANSLATE_NOOP("gettextFromC", "deep"), QT_TRANSLATE_NOOP("gettextFromC", "cavern") , QT_TRANSLATE_NOOP("gettextFromC", "ice"), + QT_TRANSLATE_NOOP("gettextFromC", "wreck"), QT_TRANSLATE_NOOP("gettextFromC", "cave"), QT_TRANSLATE_NOOP("gettextFromC", "altitude"), + QT_TRANSLATE_NOOP("gettextFromC", "pool"), QT_TRANSLATE_NOOP("gettextFromC", "lake"), QT_TRANSLATE_NOOP("gettextFromC", "river"), + QT_TRANSLATE_NOOP("gettextFromC", "night"), QT_TRANSLATE_NOOP("gettextFromC", "fresh"), QT_TRANSLATE_NOOP("gettextFromC", "student"), + QT_TRANSLATE_NOOP("gettextFromC", "instructor"), QT_TRANSLATE_NOOP("gettextFromC", "photo"), QT_TRANSLATE_NOOP("gettextFromC", "video"), + QT_TRANSLATE_NOOP("gettextFromC", "deco") + }; + + taglist_init(&g_tag_list); + + for(i=0; itag_list, a->tag_list, b->tag_list); merge_equipment(res, a, b); merge_airtemps(res, a, b); if (dl) { diff --git a/dive.h b/dive.h index 3724cef29..89ea73df3 100644 --- a/dive.h +++ b/dive.h @@ -59,34 +59,6 @@ typedef int bool; #define SEAWATER_SALINITY 10300 #define FRESHWATER_SALINITY 10000 -/* Dive tag definitions */ -#define DTAG_INVALID (1 << 0) -#define DTAG_BOAT (1 << 1) -#define DTAG_SHORE (1 << 2) -#define DTAG_DRIFT (1 << 3) -#define DTAG_DEEP (1 << 4) -#define DTAG_CAVERN (1 << 5) -#define DTAG_ICE (1 << 6) -#define DTAG_WRECK (1 << 7) -#define DTAG_CAVE (1 << 8) -#define DTAG_ALTITUDE (1 << 9) -#define DTAG_POOL (1 << 10) -#define DTAG_LAKE (1 << 11) -#define DTAG_RIVER (1 << 12) -#define DTAG_NIGHT (1 << 13) -#define DTAG_FRESH (1 << 14) -#define DTAG_FRESH_NR 14 -#define DTAG_STUDENT (1 << 15) -#define DTAG_INSTRUCTOR (1 << 16) -#define DTAG_PHOTO (1 << 17) -#define DTAG_VIDEO (1 << 18) -#define DTAG_DECO (1 << 19) -#define DTAG_NR 20 -/* defined in statistics.c */ -extern char *dtag_names[DTAG_NR]; -extern int dtag_shown[DTAG_NR]; -extern int dive_mask; - /* * Some silly typedefs to make our units very explicit. * @@ -309,6 +281,45 @@ struct sample { int po2; }; +struct divetag { + /* + * The name of the divetag. If a translation is available, name contains + * the translated tag + */ + char *name; + /* + * If a translation is available, we write the original tag to source. + * This enables us to write a non-localized tag to the xml file. + */ + char *source; +}; + +struct tag_entry { + struct divetag *tag; + struct tag_entry *next; +}; + +/* + * divetags are only stored once, each dive only contains + * a list of tag_entries which then point to the divetags + * in the global g_tag_list + */ + +extern struct tag_entry *g_tag_list; + +struct divetag *taglist_add_tag(struct tag_entry *tag_list, const char *tag); + +/* + * Writes all divetags in tag_list to buffer, limited by the buffer's (len)gth. + * Returns the characters written + */ +int taglist_get_tagstring(struct tag_entry *tag_list, char *buffer, int len); + +void taglist_init(struct tag_entry **tag_list); +void taglist_clear(struct tag_entry *tag_list); +void taglist_init_global(); + + /* * Events are currently pretty meaningless. This is * just based on the random data that libdivecomputer @@ -399,7 +410,7 @@ struct dive { pressure_t surface_pressure; duration_t duration; int salinity; // kg per 10000 l - int dive_tags; + struct tag_entry *tag_list; struct divecomputer dc; }; diff --git a/divelist.c b/divelist.c index 858d61533..28d082029 100644 --- a/divelist.c +++ b/divelist.c @@ -735,6 +735,11 @@ void delete_single_dive(int idx) free((void *)dive->buddy); if (dive->suit) free((void *)dive->suit); + if (dive->tag_list) { + taglist_clear(dive->tag_list); + /* Remove head of list */ + free((void *)dive->tag_list); + } free(dive); } @@ -800,8 +805,6 @@ void select_dive(int idx) struct dive *dive = get_dive(idx); if (dive) { /* never select an invalid dive that isn't displayed */ - if (dive->dive_tags & DTAG_INVALID && !prefs.display_invalid_dives) - return; if (!dive->selected) { dive->selected = 1; amount_selected++; diff --git a/main.cpp b/main.cpp index 72a6cc585..dddd40d35 100644 --- a/main.cpp +++ b/main.cpp @@ -24,6 +24,7 @@ int main(int argc, char **argv) init_ui(&argc, &argv); parse_xml_init(); + taglist_init_global(); QStringList files; QStringList importedFiles; diff --git a/parse-xml.c b/parse-xml.c index 8e1a052a9..5042f9161 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -210,26 +210,53 @@ static void divedatetime(char *buffer, void *_when) } } +enum ParseState {FINDSTART, FINDEND}; static void divetags(char *buffer, void *_tags) { - int *tags = _tags; - int i; - - for (i = 0; i < DTAG_NR; i++) { - if (strstr(buffer, dtag_names[i])) { - /* stupidly we have 'cave' and 'cavern' */ - if (1 << i == DTAG_CAVE) { - char *cave = strstr(buffer, "cave"); - while (cave && !strncmp(cave, "cavern", strlen("cavern"))) { - cave++; - cave = strstr(cave, "cave"); + struct tag_entry *tags = _tags; + char tag[128]; + int i = 0, start = 0, end = 0; + enum ParseState state = FINDEND; + i=0; + while(i < strlen(buffer)) { + if (buffer[i] == ',') { + if (state == FINDSTART) { + /* Detect empty tags */ + } else if (state == FINDEND) { + /* Found end of tag */ + if (i > 1) { + if(buffer[i-1] != '\\') { + strncpy(tag, buffer+start, end-start+1); + tag[end-start+1] = '\0'; + state=FINDSTART; + taglist_add_tag(tags, tag); + } + } else { + state=FINDSTART; } - if (!cave) - continue; } - *tags |= (1 << i); + } else if (buffer[i] == ' ') { + /* Handled */ + } else { + /* Found start of tag */ + if (state == FINDSTART) { + state = FINDEND; + start = i; + } else if (state == FINDEND) { + end=i; + } } - } + i++; + } + if (state == FINDEND) { + if (end < start) + end = strlen(buffer)-1; + if (strlen(buffer) > 0) { + strncpy(tag, buffer+start, end-start+1); + tag[end-start+1] = '\0'; + taglist_add_tag(tags, tag); + } + } } enum number_type { @@ -1161,7 +1188,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) if (MATCH(".number", get_index, &dive->number)) return; - if (MATCH(".tags", divetags, &dive->dive_tags)) + if (MATCH(".tags", divetags, dive->tag_list)) return; if (MATCH(".tripflag", get_tripflag, &dive->tripflag)) return; diff --git a/save-xml.c b/save-xml.c index ab81c1590..5b0ef42ec 100644 --- a/save-xml.c +++ b/save-xml.c @@ -392,20 +392,28 @@ static void save_events(FILE *f, struct event *ev) } } -static void save_tags(FILE *f, int tags) +static void save_tags(FILE *f, struct tag_entry *tag_list) { - int i, more = 0; + int more = 0; + struct tag_entry *tmp = tag_list->next; - fprintf(f, " tags='"); - for (i = 0; i < DTAG_NR; i++) { - if (tags & (1 << i)) { + /* Only write tag attribute if the list contains at least one item */ + if (tmp != NULL) { + fprintf(f, " tags='"); + + while (tmp != NULL) { if (more) fprintf(f, ", "); - fprintf(f, "%s", dtag_names[i]); + /* If the tag has been translated, write the source to the xml file */ + if (tmp->tag->source != NULL) + fprintf(f, "%s", tmp->tag->source); + else + fprintf(f, "%s", tmp->tag->name); + tmp = tmp->next; more = 1; } + fprintf(f, "'"); } - fprintf(f, "'"); } static void show_date(FILE *f, timestamp_t when) @@ -468,8 +476,8 @@ void save_dive(FILE *f, struct dive *dive) fprintf(f, " rating='%d'", dive->rating); if (dive->visibility) fprintf(f, " visibility='%d'", dive->visibility); - if (dive->dive_tags) - save_tags(f, dive->dive_tags); + if (dive->tag_list != NULL) + save_tags(f, dive->tag_list); show_date(f, dive->when); fprintf(f, " duration='%u:%02u min'>\n", diff --git a/statistics.c b/statistics.c index 5aecd1bfe..a151aee27 100644 --- a/statistics.c +++ b/statistics.c @@ -15,15 +15,6 @@ #include "divelist.h" #include "statistics.h" -/* mark for translation but don't translate here as these terms are used - * in save-xml.c */ -char *dtag_names[DTAG_NR] = { - QT_TRANSLATE_NOOP("gettextFromC","invalid"), QT_TRANSLATE_NOOP("gettextFromC","boat"), QT_TRANSLATE_NOOP("gettextFromC","shore"), QT_TRANSLATE_NOOP("gettextFromC","drift"), QT_TRANSLATE_NOOP("gettextFromC","deep"), QT_TRANSLATE_NOOP("gettextFromC","cavern"), - QT_TRANSLATE_NOOP("gettextFromC","ice"), QT_TRANSLATE_NOOP("gettextFromC","wreck"), QT_TRANSLATE_NOOP("gettextFromC","cave"), QT_TRANSLATE_NOOP("gettextFromC","altitude"), QT_TRANSLATE_NOOP("gettextFromC","pool"), QT_TRANSLATE_NOOP("gettextFromC","lake"), - QT_TRANSLATE_NOOP("gettextFromC","river"), QT_TRANSLATE_NOOP("gettextFromC","night"), QT_TRANSLATE_NOOP("gettextFromC","freshwater"), QT_TRANSLATE_NOOP("gettextFromC","training"), QT_TRANSLATE_NOOP("gettextFromC","teaching"), - QT_TRANSLATE_NOOP("gettextFromC","photo"), QT_TRANSLATE_NOOP("gettextFromC","video"), QT_TRANSLATE_NOOP("gettextFromC","deco") -}; - static stats_t stats; stats_t stats_selection; stats_t *stats_monthly = NULL;