diff options
-rw-r--r-- | dive.c | 160 | ||||
-rw-r--r-- | dive.h | 69 | ||||
-rw-r--r-- | divelist.c | 7 | ||||
-rw-r--r-- | main.cpp | 1 | ||||
-rw-r--r-- | parse-xml.c | 59 | ||||
-rw-r--r-- | save-xml.c | 26 | ||||
-rw-r--r-- | statistics.c | 9 |
7 files changed, 265 insertions, 66 deletions
@@ -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; i<sizeof(default_tags)/sizeof(char*); i++) + taglist_add_tag(g_tag_list, default_tags[i]); +} + struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded) { struct dive *res = alloc_dive(); @@ -1841,7 +1999,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer MERGE_MAX(res, a, b, number); MERGE_NONZERO(res, a, b, cns); MERGE_NONZERO(res, a, b, visibility); - MERGE_NONZERO(res, a, b, dive_tags); + taglist_merge(res->tag_list, a->tag_list, b->tag_list); merge_equipment(res, a, b); merge_airtemps(res, a, b); if (dl) { @@ -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++; @@ -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; |