summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-06-20 18:15:50 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2020-09-29 16:13:03 -0700
commit1fcf4f891d9530639c82cc72ad748b23b57a44a1 (patch)
treeb39f4e445acfa2ecfff9831b5455a94f5b23fa5a
parent3bfd448b596017be28c4f8af5dbb70b67eb2fc6b (diff)
downloadsubsurface-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.c2
-rw-r--r--core/git-access.h4
-rw-r--r--core/load-git.c146
-rw-r--r--mobile-widgets/qmlmanager.cpp2
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);