mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	Cleanup: move tag functions into own translation unit
Make dive.h a bit slimmer. It's only a drop in the bucket - but at least when modifying tag functions not the *whole* application is rebuilt anymore. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
		
							parent
							
								
									46c69fccb7
								
							
						
					
					
						commit
						6200909ba4
					
				
					 25 changed files with 321 additions and 267 deletions
				
			
		| 
						 | 
					@ -144,6 +144,8 @@ set(SUBSURFACE_CORE_LIB_SRCS
 | 
				
			||||||
	subsurfacestartup.h
 | 
						subsurfacestartup.h
 | 
				
			||||||
	subsurfacesysinfo.cpp
 | 
						subsurfacesysinfo.cpp
 | 
				
			||||||
	subsurfacesysinfo.h
 | 
						subsurfacesysinfo.h
 | 
				
			||||||
 | 
						tag.c
 | 
				
			||||||
 | 
						tag.h
 | 
				
			||||||
	taxonomy.c
 | 
						taxonomy.c
 | 
				
			||||||
	taxonomy.h
 | 
						taxonomy.h
 | 
				
			||||||
	time.c
 | 
						time.c
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
#include "file.h"
 | 
					#include "file.h"
 | 
				
			||||||
#include "divesite.h"
 | 
					#include "divesite.h"
 | 
				
			||||||
#include "ssrf.h"
 | 
					#include "ssrf.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int two_bytes_to_int(unsigned char x, unsigned char y)
 | 
					static unsigned int two_bytes_to_int(unsigned char x, unsigned char y)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										223
									
								
								core/dive.c
									
										
									
									
									
								
							
							
						
						
									
										223
									
								
								core/dive.c
									
										
									
									
									
								
							| 
						 | 
					@ -14,24 +14,14 @@
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
#include "metadata.h"
 | 
					#include "metadata.h"
 | 
				
			||||||
#include "membuffer.h"
 | 
					#include "membuffer.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					#include "structured_list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* one could argue about the best place to have this variable -
 | 
					/* one could argue about the best place to have this variable -
 | 
				
			||||||
 * it's used in the UI, but it seems to make the most sense to have it
 | 
					 * it's used in the UI, but it seems to make the most sense to have it
 | 
				
			||||||
 * here */
 | 
					 * here */
 | 
				
			||||||
struct dive displayed_dive;
 | 
					struct dive displayed_dive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tag_entry *g_tag_list = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static 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")
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *cylinderuse_text[] = {
 | 
					const char *cylinderuse_text[] = {
 | 
				
			||||||
	QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
 | 
						QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -474,31 +464,6 @@ struct dive *alloc_dive(void)
 | 
				
			||||||
	return dive;
 | 
						return dive;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Clear everything but the first element;
 | 
					 | 
				
			||||||
 * this works for taglist, picturelist, even dive computers */
 | 
					 | 
				
			||||||
#define STRUCTURED_LIST_FREE(_type, _start, _free) \
 | 
					 | 
				
			||||||
	{                                          \
 | 
					 | 
				
			||||||
		_type *_ptr = _start;              \
 | 
					 | 
				
			||||||
		while (_ptr) {                     \
 | 
					 | 
				
			||||||
			_type *_next = _ptr->next; \
 | 
					 | 
				
			||||||
			_free(_ptr);               \
 | 
					 | 
				
			||||||
			_ptr = _next;              \
 | 
					 | 
				
			||||||
		}                                  \
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define STRUCTURED_LIST_COPY(_type, _first, _dest, _cpy) \
 | 
					 | 
				
			||||||
	{                                                \
 | 
					 | 
				
			||||||
		_type *_sptr = _first;                   \
 | 
					 | 
				
			||||||
		_type **_dptr = &_dest;                  \
 | 
					 | 
				
			||||||
		while (_sptr) {                          \
 | 
					 | 
				
			||||||
			*_dptr = malloc(sizeof(_type));  \
 | 
					 | 
				
			||||||
			_cpy(_sptr, *_dptr);             \
 | 
					 | 
				
			||||||
			_sptr = _sptr->next;             \
 | 
					 | 
				
			||||||
			_dptr = &(*_dptr)->next;         \
 | 
					 | 
				
			||||||
		}                                        \
 | 
					 | 
				
			||||||
		*_dptr = 0;                              \
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void free_dc(struct divecomputer *dc);
 | 
					static void free_dc(struct divecomputer *dc);
 | 
				
			||||||
static void free_dc_contents(struct divecomputer *dc);
 | 
					static void free_dc_contents(struct divecomputer *dc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -548,14 +513,6 @@ static void copy_pl(struct picture *sp, struct picture *dp)
 | 
				
			||||||
	dp->filename = copy_string(sp->filename);
 | 
						dp->filename = copy_string(sp->filename);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* copy an element in a list of tags */
 | 
					 | 
				
			||||||
static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	dt->tag = malloc(sizeof(struct divetag));
 | 
					 | 
				
			||||||
	dt->tag->name = copy_string(st->tag->name);
 | 
					 | 
				
			||||||
	dt->tag->source = copy_string(st->tag->source);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void free_dive_structures(struct dive *d)
 | 
					static void free_dive_structures(struct dive *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!d)
 | 
						if (!d)
 | 
				
			||||||
| 
						 | 
					@ -3253,182 +3210,6 @@ static void join_dive_computers(struct dive *d, struct divecomputer *res,
 | 
				
			||||||
	remove_redundant_dc(res, prefer_downloaded);
 | 
						remove_redundant_dc(res, prefer_downloaded);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	while (start && start != before) {
 | 
					 | 
				
			||||||
		if (same_string(start->tag->name, before->tag->name))
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		start = start->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* remove duplicates and empty nodes */
 | 
					 | 
				
			||||||
void taglist_cleanup(struct tag_entry **tag_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct tag_entry **tl = tag_list;
 | 
					 | 
				
			||||||
	while (*tl) {
 | 
					 | 
				
			||||||
		/* skip tags that are empty or that we have seen before */
 | 
					 | 
				
			||||||
		if (empty_string((*tl)->tag->name) || tag_seen_before(*tag_list, *tl)) {
 | 
					 | 
				
			||||||
			*tl = (*tl)->next;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tl = &(*tl)->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
char *taglist_get_tagstring(struct tag_entry *tag_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	bool first_tag = true;
 | 
					 | 
				
			||||||
	struct membuffer b = { 0 };
 | 
					 | 
				
			||||||
	struct tag_entry *tmp = tag_list;
 | 
					 | 
				
			||||||
	while (tmp != NULL) {
 | 
					 | 
				
			||||||
		if (!empty_string(tmp->tag->name)) {
 | 
					 | 
				
			||||||
			if (first_tag) {
 | 
					 | 
				
			||||||
				put_format(&b, "%s", tmp->tag->name);
 | 
					 | 
				
			||||||
				first_tag = false;
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				put_format(&b, ", %s", tmp->tag->name);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		tmp = tmp->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Ensures we do return null terminated empty string for:
 | 
					 | 
				
			||||||
	 *  - empty tag list
 | 
					 | 
				
			||||||
	 *  - tag list with empty tag only
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	mb_cstring(&b);
 | 
					 | 
				
			||||||
	return detach_buffer(&b);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 *next, *entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while ((next = *tag_list) != NULL) {
 | 
					 | 
				
			||||||
		int cmp = strcmp(next->tag->name, tag->name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Already have it? */
 | 
					 | 
				
			||||||
		if (!cmp)
 | 
					 | 
				
			||||||
			return next->tag;
 | 
					 | 
				
			||||||
		/* Is the entry larger? If so, insert here */
 | 
					 | 
				
			||||||
		if (cmp > 0)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		/* Continue traversing the list */
 | 
					 | 
				
			||||||
		tag_list = &next->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Insert in front of it */
 | 
					 | 
				
			||||||
	entry = malloc(sizeof(struct tag_entry));
 | 
					 | 
				
			||||||
	entry->next = next;
 | 
					 | 
				
			||||||
	entry->tag = tag;
 | 
					 | 
				
			||||||
	*tag_list = entry;
 | 
					 | 
				
			||||||
	return tag;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t i = 0;
 | 
					 | 
				
			||||||
	int is_default_tag = 0;
 | 
					 | 
				
			||||||
	struct divetag *ret_tag, *new_tag;
 | 
					 | 
				
			||||||
	const char *translation;
 | 
					 | 
				
			||||||
	new_tag = malloc(sizeof(struct divetag));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++) {
 | 
					 | 
				
			||||||
		if (strcmp(default_tags[i], tag) == 0) {
 | 
					 | 
				
			||||||
			is_default_tag = 1;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Only translate default tags */
 | 
					 | 
				
			||||||
	if (is_default_tag) {
 | 
					 | 
				
			||||||
		translation = translate("gettextFromC", tag);
 | 
					 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		new_tag->source = NULL;
 | 
					 | 
				
			||||||
		new_tag->name = malloc(strlen(tag) + 1);
 | 
					 | 
				
			||||||
		memcpy(new_tag->name, 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_free(struct tag_entry *entry)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	STRUCTURED_LIST_FREE(struct tag_entry, entry, free)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct tag_entry *taglist_copy(struct tag_entry *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct tag_entry *res;
 | 
					 | 
				
			||||||
	STRUCTURED_LIST_COPY(struct tag_entry, s, res, copy_tl);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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 *entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (entry = src1; entry; entry = entry->next)
 | 
					 | 
				
			||||||
		taglist_add_divetag(dst, entry->tag);
 | 
					 | 
				
			||||||
	for (entry = src2; entry; entry = entry->next)
 | 
					 | 
				
			||||||
		taglist_add_divetag(dst, entry->tag);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void taglist_init_global()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++)
 | 
					 | 
				
			||||||
		taglist_add_tag(&g_tag_list, default_tags[i]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool taglist_contains(struct tag_entry *tag_list, const char *tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	while (tag_list) {
 | 
					 | 
				
			||||||
		if (same_string(tag_list->tag->name, tag))
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		tag_list = tag_list->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct tag_entry *added_list = NULL;
 | 
					 | 
				
			||||||
	while (new_list) {
 | 
					 | 
				
			||||||
		if (!taglist_contains(original_list, new_list->tag->name))
 | 
					 | 
				
			||||||
			taglist_add_tag(&added_list, new_list->tag->name);
 | 
					 | 
				
			||||||
		new_list = new_list->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return added_list;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool is_dc_planner(const struct divecomputer *dc)
 | 
					bool is_dc_planner(const struct divecomputer *dc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return same_string(dc->model, "planned dive");
 | 
						return same_string(dc->model, "planned dive");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										46
									
								
								core/dive.h
									
										
									
									
									
								
							
							
						
						
									
										46
									
								
								core/dive.h
									
										
									
									
									
								
							| 
						 | 
					@ -177,52 +177,6 @@ struct sample                         // BASE TYPE BYTES  UNITS    RANGE
 | 
				
			||||||
					  //                                               not calculated when planning a dive
 | 
										  //                                               not calculated when planning a dive
 | 
				
			||||||
};	                                  // Total size of structure: 57 bytes, excluding padding at end
 | 
					};	                                  // Total size of structure: 57 bytes, excluding padding at end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Writes all divetags form tag_list into internally allocated buffer
 | 
					 | 
				
			||||||
 * Function returns pointer to allocated buffer
 | 
					 | 
				
			||||||
 * Buffer contains comma separated list of tags names or null terminated string
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * NOTE! The returned buffer must be freed once used.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
char *taglist_get_tagstring(struct tag_entry *tag_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* cleans up a list: removes empty tags and duplicates */
 | 
					 | 
				
			||||||
void taglist_cleanup(struct tag_entry **tag_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void taglist_init_global();
 | 
					 | 
				
			||||||
void taglist_free(struct tag_entry *tag_list);
 | 
					 | 
				
			||||||
struct tag_entry *taglist_copy(struct tag_entry *s);
 | 
					 | 
				
			||||||
bool taglist_contains(struct tag_entry *tag_list, const char *tag);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct extra_data {
 | 
					struct extra_data {
 | 
				
			||||||
	const char *key;
 | 
						const char *key;
 | 
				
			||||||
	const char *value;
 | 
						const char *value;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include "device.h"
 | 
					#include "device.h"
 | 
				
			||||||
#include "membuffer.h"
 | 
					#include "membuffer.h"
 | 
				
			||||||
#include "gettext.h"
 | 
					#include "gettext.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int dm4_events(void *param, int columns, char **data, char **column)
 | 
					static int dm4_events(void *param, int columns, char **data, char **column)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "membuffer.h"
 | 
					#include "membuffer.h"
 | 
				
			||||||
#include "git-access.h"
 | 
					#include "git-access.h"
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *saved_git_id = NULL;
 | 
					const char *saved_git_id = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
#include "device.h"
 | 
					#include "device.h"
 | 
				
			||||||
#include "membuffer.h"
 | 
					#include "membuffer.h"
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int verbose, quit, force_root;
 | 
					int verbose, quit, force_root;
 | 
				
			||||||
int last_xml_version = -1;
 | 
					int last_xml_version = -1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
#include <sys/time.h>
 | 
					#include <sys/time.h>
 | 
				
			||||||
#include "exif.h"
 | 
					#include "exif.h"
 | 
				
			||||||
#include "file.h"
 | 
					#include "file.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
#include "imagedownloader.h"
 | 
					#include "imagedownloader.h"
 | 
				
			||||||
#include <QFile>
 | 
					#include <QFile>
 | 
				
			||||||
#include <QRegExp>
 | 
					#include <QRegExp>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include "version.h"
 | 
					#include "version.h"
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
#include "gettext.h"
 | 
					#include "gettext.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VA_BUF(b, fmt) do { va_list args; va_start(args, fmt); put_vformat(b, fmt, args); va_end(args); } while (0)
 | 
					#define VA_BUF(b, fmt) do { va_list args; va_start(args, fmt); put_vformat(b, fmt, args); va_end(args); } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
#include "gettext.h"
 | 
					#include "gettext.h"
 | 
				
			||||||
#include "divesite.h"
 | 
					#include "divesite.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void write_attribute(struct membuffer *b, const char *att_name, const char *value, const char *separator)
 | 
					void write_attribute(struct membuffer *b, const char *att_name, const char *value, const char *separator)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "git-access.h"
 | 
					#include "git-access.h"
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
#include "gettext.h"
 | 
					#include "gettext.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * We're outputting utf8 in xml.
 | 
					 * We're outputting utf8 in xml.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								core/structured_list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								core/structured_list.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					#ifndef STRUCTURED_LIST_H
 | 
				
			||||||
 | 
					#define STRUCTURED_LIST_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Clear everything but the first element;
 | 
				
			||||||
 | 
					 * this works for taglist, picturelist, even dive computers */
 | 
				
			||||||
 | 
					#define STRUCTURED_LIST_FREE(_type, _start, _free) \
 | 
				
			||||||
 | 
						{                                          \
 | 
				
			||||||
 | 
							_type *_ptr = _start;              \
 | 
				
			||||||
 | 
							while (_ptr) {                     \
 | 
				
			||||||
 | 
								_type *_next = _ptr->next; \
 | 
				
			||||||
 | 
								_free(_ptr);               \
 | 
				
			||||||
 | 
								_ptr = _next;              \
 | 
				
			||||||
 | 
							}                                  \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STRUCTURED_LIST_COPY(_type, _first, _dest, _cpy) \
 | 
				
			||||||
 | 
						{                                                \
 | 
				
			||||||
 | 
							_type *_sptr = _first;                   \
 | 
				
			||||||
 | 
							_type **_dptr = &_dest;                  \
 | 
				
			||||||
 | 
							while (_sptr) {                          \
 | 
				
			||||||
 | 
								*_dptr = malloc(sizeof(_type));  \
 | 
				
			||||||
 | 
								_cpy(_sptr, *_dptr);             \
 | 
				
			||||||
 | 
								_sptr = _sptr->next;             \
 | 
				
			||||||
 | 
								_dptr = &(*_dptr)->next;         \
 | 
				
			||||||
 | 
							}                                        \
 | 
				
			||||||
 | 
							*_dptr = 0;                              \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										206
									
								
								core/tag.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								core/tag.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,206 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
 | 
					#include "structured_list.h"
 | 
				
			||||||
 | 
					#include "subsurface-string.h"
 | 
				
			||||||
 | 
					#include "membuffer.h"
 | 
				
			||||||
 | 
					#include "gettext.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tag_entry *g_tag_list = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static 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")
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* copy an element in a list of tags */
 | 
				
			||||||
 | 
					static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dt->tag = malloc(sizeof(struct divetag));
 | 
				
			||||||
 | 
						dt->tag->name = copy_string(st->tag->name);
 | 
				
			||||||
 | 
						dt->tag->source = copy_string(st->tag->source);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (start && start != before) {
 | 
				
			||||||
 | 
							if (same_string(start->tag->name, before->tag->name))
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							start = start->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* remove duplicates and empty nodes */
 | 
				
			||||||
 | 
					void taglist_cleanup(struct tag_entry **tag_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tag_entry **tl = tag_list;
 | 
				
			||||||
 | 
						while (*tl) {
 | 
				
			||||||
 | 
							/* skip tags that are empty or that we have seen before */
 | 
				
			||||||
 | 
							if (empty_string((*tl)->tag->name) || tag_seen_before(*tag_list, *tl)) {
 | 
				
			||||||
 | 
								*tl = (*tl)->next;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							tl = &(*tl)->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *taglist_get_tagstring(struct tag_entry *tag_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool first_tag = true;
 | 
				
			||||||
 | 
						struct membuffer b = { 0 };
 | 
				
			||||||
 | 
						struct tag_entry *tmp = tag_list;
 | 
				
			||||||
 | 
						while (tmp != NULL) {
 | 
				
			||||||
 | 
							if (!empty_string(tmp->tag->name)) {
 | 
				
			||||||
 | 
								if (first_tag) {
 | 
				
			||||||
 | 
									put_format(&b, "%s", tmp->tag->name);
 | 
				
			||||||
 | 
									first_tag = false;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									put_format(&b, ", %s", tmp->tag->name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							tmp = tmp->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* Ensures we do return null terminated empty string for:
 | 
				
			||||||
 | 
						 *  - empty tag list
 | 
				
			||||||
 | 
						 *  - tag list with empty tag only
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						mb_cstring(&b);
 | 
				
			||||||
 | 
						return detach_buffer(&b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 *next, *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((next = *tag_list) != NULL) {
 | 
				
			||||||
 | 
							int cmp = strcmp(next->tag->name, tag->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Already have it? */
 | 
				
			||||||
 | 
							if (!cmp)
 | 
				
			||||||
 | 
								return next->tag;
 | 
				
			||||||
 | 
							/* Is the entry larger? If so, insert here */
 | 
				
			||||||
 | 
							if (cmp > 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							/* Continue traversing the list */
 | 
				
			||||||
 | 
							tag_list = &next->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Insert in front of it */
 | 
				
			||||||
 | 
						entry = malloc(sizeof(struct tag_entry));
 | 
				
			||||||
 | 
						entry->next = next;
 | 
				
			||||||
 | 
						entry->tag = tag;
 | 
				
			||||||
 | 
						*tag_list = entry;
 | 
				
			||||||
 | 
						return tag;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t i = 0;
 | 
				
			||||||
 | 
						int is_default_tag = 0;
 | 
				
			||||||
 | 
						struct divetag *ret_tag, *new_tag;
 | 
				
			||||||
 | 
						const char *translation;
 | 
				
			||||||
 | 
						new_tag = malloc(sizeof(struct divetag));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++) {
 | 
				
			||||||
 | 
							if (strcmp(default_tags[i], tag) == 0) {
 | 
				
			||||||
 | 
								is_default_tag = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* Only translate default tags */
 | 
				
			||||||
 | 
						if (is_default_tag) {
 | 
				
			||||||
 | 
							translation = translate("gettextFromC", tag);
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							new_tag->source = NULL;
 | 
				
			||||||
 | 
							new_tag->name = malloc(strlen(tag) + 1);
 | 
				
			||||||
 | 
							memcpy(new_tag->name, 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_free(struct tag_entry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						STRUCTURED_LIST_FREE(struct tag_entry, entry, free)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tag_entry *taglist_copy(struct tag_entry *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tag_entry *res;
 | 
				
			||||||
 | 
						STRUCTURED_LIST_COPY(struct tag_entry, s, res, copy_tl);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Merge src1 and src2, write to *dst */
 | 
				
			||||||
 | 
					void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tag_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (entry = src1; entry; entry = entry->next)
 | 
				
			||||||
 | 
							taglist_add_divetag(dst, entry->tag);
 | 
				
			||||||
 | 
						for (entry = src2; entry; entry = entry->next)
 | 
				
			||||||
 | 
							taglist_add_divetag(dst, entry->tag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void taglist_init_global()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sizeof(default_tags) / sizeof(char *); i++)
 | 
				
			||||||
 | 
							taglist_add_tag(&g_tag_list, default_tags[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool taglist_contains(struct tag_entry *tag_list, const char *tag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (tag_list) {
 | 
				
			||||||
 | 
							if (same_string(tag_list->tag->name, tag))
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							tag_list = tag_list->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tag_entry *added_list = NULL;
 | 
				
			||||||
 | 
						while (new_list) {
 | 
				
			||||||
 | 
							if (!taglist_contains(original_list, new_list->tag->name))
 | 
				
			||||||
 | 
								taglist_add_tag(&added_list, new_list->tag->name);
 | 
				
			||||||
 | 
							new_list = new_list->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return added_list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										62
									
								
								core/tag.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								core/tag.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					// Dive tag related structures and helpers
 | 
				
			||||||
 | 
					#ifndef TAG_H
 | 
				
			||||||
 | 
					#define TAG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					struct tag_entry *taglist_added(struct tag_entry *original_list, struct tag_entry *new_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Writes all divetags form tag_list into internally allocated buffer
 | 
				
			||||||
 | 
					 * Function returns pointer to allocated buffer
 | 
				
			||||||
 | 
					 * Buffer contains comma separated list of tags names or null terminated string
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * NOTE! The returned buffer must be freed once used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *taglist_get_tagstring(struct tag_entry *tag_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cleans up a list: removes empty tags and duplicates */
 | 
				
			||||||
 | 
					void taglist_cleanup(struct tag_entry **tag_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void taglist_init_global();
 | 
				
			||||||
 | 
					void taglist_free(struct tag_entry *tag_list);
 | 
				
			||||||
 | 
					struct tag_entry *taglist_copy(struct tag_entry *s);
 | 
				
			||||||
 | 
					bool taglist_contains(struct tag_entry *tag_list, const char *tag);
 | 
				
			||||||
 | 
					void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include "uemis.h"
 | 
					#include "uemis.h"
 | 
				
			||||||
#include "divelist.h"
 | 
					#include "divelist.h"
 | 
				
			||||||
#include "divesite.h"
 | 
					#include "divesite.h"
 | 
				
			||||||
 | 
					#include "tag.h"
 | 
				
			||||||
#include "core/subsurface-string.h"
 | 
					#include "core/subsurface-string.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ERR_FS_ALMOST_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is almost full.\nDisconnect/reconnect the dive computer\nand click \'Retry\'")
 | 
					#define ERR_FS_ALMOST_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is almost full.\nDisconnect/reconnect the dive computer\nand click \'Retry\'")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include "core/divelist.h"
 | 
					#include "core/divelist.h"
 | 
				
			||||||
#include "core/qthelper.h" // for copy_qstring
 | 
					#include "core/qthelper.h" // for copy_qstring
 | 
				
			||||||
#include "core/subsurface-string.h"
 | 
					#include "core/subsurface-string.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
#include "desktop-widgets/mapwidget.h" // TODO: Replace desktop-dependency by signal
 | 
					#include "desktop-widgets/mapwidget.h" // TODO: Replace desktop-dependency by signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Command {
 | 
					namespace Command {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
#include "profile-widget/profilewidget2.h"
 | 
					#include "profile-widget/profilewidget2.h"
 | 
				
			||||||
#include "core/save-profiledata.h"
 | 
					#include "core/save-profiledata.h"
 | 
				
			||||||
#include "core/divesite.h"
 | 
					#include "core/divesite.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Retrieves the current unit settings defined in the Subsurface preferences.
 | 
					// Retrieves the current unit settings defined in the Subsurface preferences.
 | 
				
			||||||
#define GET_UNIT(name, field, f, t)           \
 | 
					#define GET_UNIT(name, field, f, t)           \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "profile-widget/profilewidget2.h"
 | 
					#include "profile-widget/profilewidget2.h"
 | 
				
			||||||
#include "desktop-widgets/command.h"
 | 
					#include "desktop-widgets/command.h"
 | 
				
			||||||
#include "core/metadata.h"
 | 
					#include "core/metadata.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
double MinMaxAvgWidget::average() const
 | 
					double MinMaxAvgWidget::average() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \
 | 
				
			||||||
	../../core/membuffer.c \
 | 
						../../core/membuffer.c \
 | 
				
			||||||
	../../core/sha1.c \
 | 
						../../core/sha1.c \
 | 
				
			||||||
	../../core/strtod.c \
 | 
						../../core/strtod.c \
 | 
				
			||||||
 | 
						../../core/tag.c \
 | 
				
			||||||
	../../core/taxonomy.c \
 | 
						../../core/taxonomy.c \
 | 
				
			||||||
	../../core/time.c \
 | 
						../../core/time.c \
 | 
				
			||||||
	../../core/uemis.c \
 | 
						../../core/uemis.c \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
#include "qt-models/completionmodels.h"
 | 
					#include "qt-models/completionmodels.h"
 | 
				
			||||||
#include "core/dive.h"
 | 
					#include "core/dive.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
#include <QSet>
 | 
					#include <QSet>
 | 
				
			||||||
#include <QString>
 | 
					#include <QString>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#include "core/divelist.h"
 | 
					#include "core/divelist.h"
 | 
				
			||||||
#include "core/qthelper.h"
 | 
					#include "core/qthelper.h"
 | 
				
			||||||
#include "core/subsurface-string.h"
 | 
					#include "core/subsurface-string.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
#include <QIcon>
 | 
					#include <QIcon>
 | 
				
			||||||
#include <QDebug>
 | 
					#include <QDebug>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@
 | 
				
			||||||
#include "core/libdivecomputer.h"
 | 
					#include "core/libdivecomputer.h"
 | 
				
			||||||
#include "core/divesite.h"
 | 
					#include "core/divesite.h"
 | 
				
			||||||
#include "core/membuffer.h"
 | 
					#include "core/membuffer.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SmartTrak version, constant for every single file */
 | 
					/* SmartTrak version, constant for every single file */
 | 
				
			||||||
int smtk_version;
 | 
					int smtk_version;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include "core/qthelper.h"
 | 
					#include "core/qthelper.h"
 | 
				
			||||||
#include "core/subsurfacestartup.h"
 | 
					#include "core/subsurfacestartup.h"
 | 
				
			||||||
#include "core/settings/qPref.h"
 | 
					#include "core/settings/qPref.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
#include "desktop-widgets/diveplanner.h"
 | 
					#include "desktop-widgets/diveplanner.h"
 | 
				
			||||||
#include "desktop-widgets/mainwindow.h"
 | 
					#include "desktop-widgets/mainwindow.h"
 | 
				
			||||||
#include "desktop-widgets/preferences/preferencesdialog.h"
 | 
					#include "desktop-widgets/preferences/preferencesdialog.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
#include "core/subsurfacestartup.h"
 | 
					#include "core/subsurfacestartup.h"
 | 
				
			||||||
#include "core/settings/qPref.h"
 | 
					#include "core/settings/qPref.h"
 | 
				
			||||||
#include "core/settings/qPrefDisplay.h"
 | 
					#include "core/settings/qPrefDisplay.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QApplication>
 | 
					#include <QApplication>
 | 
				
			||||||
#include <QLocale>
 | 
					#include <QLocale>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
#include "testtaglist.h"
 | 
					#include "testtaglist.h"
 | 
				
			||||||
#include "core/dive.h"
 | 
					#include "core/dive.h"
 | 
				
			||||||
 | 
					#include "core/tag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TestTagList::initTestCase()
 | 
					void TestTagList::initTestCase()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue