diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2020-06-20 18:15:50 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-09-29 16:13:03 -0700 |
commit | 1fcf4f891d9530639c82cc72ad748b23b57a44a1 (patch) | |
tree | b39f4e445acfa2ecfff9831b5455a94f5b23fa5a | |
parent | 3bfd448b596017be28c4f8af5dbb70b67eb2fc6b (diff) | |
download | subsurface-1fcf4f891d9530639c82cc72ad748b23b57a44a1.tar.gz |
filter: implement loading of filter presets from git repositories
This is mostly copy and paste of other git loading code. Sadly,
it adds a lot of state to the parser-state. I wish we could pass
different parser states to the parser_* functions.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r-- | core/file.c | 2 | ||||
-rw-r--r-- | core/git-access.h | 4 | ||||
-rw-r--r-- | core/load-git.c | 146 | ||||
-rw-r--r-- | mobile-widgets/qmlmanager.cpp | 2 |
4 files changed, 150 insertions, 4 deletions
diff --git a/core/file.c b/core/file.c index 0878d4c42..e53859081 100644 --- a/core/file.c +++ b/core/file.c @@ -322,7 +322,7 @@ int parse_file(const char *filename, struct dive_table *table, struct trip_table return -1; } if (git) - return git_load_dives(git, branch, table, trips, sites); + return git_load_dives(git, branch, table, trips, sites, filter_presets); if ((ret = readfile(filename, &mem)) < 0) { /* we don't want to display an error if this was the default file */ diff --git a/core/git-access.h b/core/git-access.h index b02bd3280..b980c5f9b 100644 --- a/core/git-access.h +++ b/core/git-access.h @@ -3,6 +3,7 @@ #define GITACCESS_H #include "git2.h" +#include "filterpreset.h" #ifdef __cplusplus extern "C" { @@ -19,7 +20,8 @@ extern struct git_repository *is_git_repository(const char *filename, const char extern int check_git_sha(const char *filename, git_repository **git_p, const char **branch_p); extern int sync_with_remote(struct git_repository *repo, const char *remote, const char *branch, enum remote_transport rt); extern int git_save_dives(struct git_repository *, const char *, const char *remote, bool select_only); -extern int git_load_dives(struct git_repository *repo, const char *branch, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); +extern int git_load_dives(struct git_repository *repo, const char *branch, struct dive_table *table, struct trip_table *trips, + struct dive_site_table *sites, filter_preset_table_t *filter_presets); extern const char *get_sha(git_repository *repo, const char *branch); extern int do_git_save(git_repository *repo, const char *branch, const char *remote, bool select_only, bool create_empty); extern const char *saved_git_id; diff --git a/core/load-git.c b/core/load-git.c index 444303399..0cf18d48c 100644 --- a/core/load-git.c +++ b/core/load-git.c @@ -34,11 +34,20 @@ struct git_parser_state { struct divecomputer *active_dc; struct dive *active_dive; dive_trip_t *active_trip; + char *fulltext_mode; + char *fulltext_query; + char *filter_constraint_type; + char *filter_constraint_string_mode; + char *filter_constraint_range_mode; + bool filter_constraint_negate; + char *filter_constraint_data; struct picture active_pic; struct dive_site *active_site; + struct filter_preset *active_filter; struct dive_table *table; struct trip_table *trips; struct dive_site_table *sites; + filter_preset_table_t *filter_presets; int o2pressure_sensor; }; @@ -1096,6 +1105,114 @@ static void picture_parser(char *line, struct membuffer *str, struct git_parser_ match_action(line, str, state, picture_action, ARRAY_SIZE(picture_action)); } +static void parse_filter_preset_constraint_keyvalue(void *_state, const char *key, const char *value) +{ + struct git_parser_state *state = _state; + if (!strcmp(key, "type")) { + free(state->filter_constraint_type); + state->filter_constraint_type = strdup(value); + return; + } + if (!strcmp(key, "rangemode")) { + free(state->filter_constraint_range_mode); + state->filter_constraint_range_mode = strdup(value); + return; + } + if (!strcmp(key, "stringmode")) { + free(state->filter_constraint_string_mode); + state->filter_constraint_string_mode = strdup(value); + return; + } + if (!strcmp(key, "negate")) { + state->filter_constraint_negate = true; + return; + } + if (!strcmp(key, "data")) { + free(state->filter_constraint_data); + state->filter_constraint_data = strdup(value); + return; + } + + report_error("Unknown filter preset constraint key/value pair (%s/%s)", key, value); +} + +static void parse_filter_preset_constraint(char *line, struct membuffer *str, struct git_parser_state *state) +{ + for (;;) { + char c; + while (isspace(c = *line)) + line++; + if (!c) + break; + line = parse_keyvalue_entry(parse_filter_preset_constraint_keyvalue, state, line, str); + } + + filter_preset_add_constraint(state->active_filter, state->filter_constraint_type, state->filter_constraint_string_mode, + state->filter_constraint_range_mode, state->filter_constraint_negate, state->filter_constraint_data); + free(state->filter_constraint_type); + free(state->filter_constraint_string_mode); + free(state->filter_constraint_range_mode); + free(state->filter_constraint_data); + state->filter_constraint_type = NULL; + state->filter_constraint_string_mode = NULL; + state->filter_constraint_range_mode = NULL; + state->filter_constraint_negate = false; + state->filter_constraint_data = NULL; +} + +static void parse_filter_preset_fulltext_keyvalue(void *_state, const char *key, const char *value) +{ + struct git_parser_state *state = _state; + if (!strcmp(key, "mode")) { + free(state->fulltext_mode); + state->fulltext_mode = strdup(value); + return; + } + if (!strcmp(key, "query")) { + free(state->fulltext_query); + state->fulltext_query = strdup(value); + return; + } + + report_error("Unknown filter preset fulltext key/value pair (%s/%s)", key, value); +} + +static void parse_filter_preset_fulltext(char *line, struct membuffer *str, struct git_parser_state *state) +{ + for (;;) { + char c; + while (isspace(c = *line)) + line++; + if (!c) + break; + line = parse_keyvalue_entry(parse_filter_preset_fulltext_keyvalue, state, line, str); + } + + filter_preset_set_fulltext(state->active_filter, state->fulltext_query, state->fulltext_mode); + free(state->fulltext_mode); + free(state->fulltext_query); + state->fulltext_mode = NULL; + state->fulltext_query = NULL; +} + +static void parse_filter_preset_name(char *line, struct membuffer *str, struct git_parser_state *state) +{ + UNUSED(line); + filter_preset_set_name(state->active_filter, detach_cstring(str)); +} + +/* These need to be sorted! */ +struct keyword_action filter_preset_action[] = { +#undef D +#define D(x) { #x, parse_filter_preset_ ## x } + D(constraint), D(fulltext), D(name) +}; + +static void filter_preset_parser(char *line, struct membuffer *str, struct git_parser_state *state) +{ + match_action(line, str, state, filter_preset_action, ARRAY_SIZE(filter_preset_action)); +} + /* * We have a very simple line-based interface, with the small * complication that lines can have strings in the middle, and @@ -1446,6 +1563,9 @@ static int walk_tree_directory(const char *root, const git_tree_entry *entry, st if (!strcmp(name, "01-Divesites")) return GIT_WALK_OK; + if (!strcmp(name, "02-Filterpresets")) + return GIT_WALK_OK; + while (isdigit(c = name[digits])) digits++; @@ -1618,6 +1738,24 @@ static int parse_picture_entry(struct git_parser_state *state, const git_tree_en return 0; } +static int parse_filter_preset(struct git_parser_state *state, const git_tree_entry *entry) +{ + git_blob *blob = git_tree_entry_blob(state->repo, entry); + if (!blob) + return report_error("Unable to read filter preset file"); + + state->active_filter = alloc_filter_preset(); + for_each_line(blob, filter_preset_parser, state); + + git_blob_free(blob); + + add_filter_preset_to_table(state->active_filter, state->filter_presets); + free_filter_preset(state->active_filter); + state->active_filter = NULL; + + return 0; +} + static int walk_tree_file(const char *root, const git_tree_entry *entry, struct git_parser_state *state) { struct dive *dive = state->active_dive; @@ -1636,6 +1774,10 @@ static int walk_tree_file(const char *root, const git_tree_entry *entry, struct if (dive && !strncmp(name, "Dive", 4)) return parse_dive_entry(state, entry, name + 4); break; + case 'P': + if (!strncmp(name, "Preset-", 7)) + return parse_filter_preset(state, entry); + break; case 'S': if (!strncmp(name, "Site", 4)) return parse_site_entry(state, entry, name + 5); @@ -1736,7 +1878,8 @@ const char *get_sha(git_repository *repo, const char *branch) * If it is a git repository, we return zero for success, * or report an error and return 1 if the load failed. */ -int git_load_dives(struct git_repository *repo, const char *branch, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites) +int git_load_dives(struct git_repository *repo, const char *branch, struct dive_table *table, struct trip_table *trips, + struct dive_site_table *sites, filter_preset_table_t *filter_presets) { int ret; struct git_parser_state state = { 0 }; @@ -1744,6 +1887,7 @@ int git_load_dives(struct git_repository *repo, const char *branch, struct dive_ state.table = table; state.trips = trips; state.sites = sites; + state.filter_presets = filter_presets; if (repo == dummy_git_repository) return report_error("Unable to open git repository at '%s'", branch); diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index 86e5052e1..71e025f7e 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -707,7 +707,7 @@ void QMLManager::loadDivesWithValidCredentials() } if (git != dummy_git_repository) { appendTextToLog(QString("have repository and branch %1").arg(branch)); - error = git_load_dives(git, branch, &dive_table, &trip_table, &dive_site_table); + error = git_load_dives(git, branch, &dive_table, &trip_table, &dive_site_table, &filter_preset_table); } else { appendTextToLog(QString("didn't receive valid git repo, try again")); error = parse_file(fileNamePrt.data(), &dive_table, &trip_table, &dive_site_table, &filter_preset_table); |