config: initial multivar iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index 45599dc..477d472 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -36,9 +36,10 @@ struct git_config_iterator {
unsigned int flags;
/**
- * Return the current entry and advance the iterator
+ * Return the current entry and advance the iterator. The
+ * memory belongs to the library.
*/
- int (*next)(git_config_entry *entry, git_config_iterator *iter);
+ int (*next)(const git_config_entry *entry, git_config_iterator *iter);
/**
* Free the iterator
@@ -58,6 +59,7 @@ struct git_config_backend {
int (*open)(struct git_config_backend *, git_config_level_t level);
int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry);
int (*get_multivar_foreach)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload);
+ int (*get_multivar)(git_config_iterator **, struct git_config_backend *, const char *name, const char *regexp);
int (*set)(struct git_config_backend *, const char *key, const char *value);
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
int (*del)(struct git_config_backend *, const char *key);
diff --git a/src/config.c b/src/config.c
index 5bec0f0..77c5580 100644
--- a/src/config.c
+++ b/src/config.c
@@ -602,6 +602,24 @@ int git_config_get_multivar_foreach(
return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0;
}
+struct config_multivar_iter {
+ git_config_iterator parent;
+};
+
+int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
+{
+ struct config_multivar_iter *iter;
+
+ iter = git__calloc(1, sizeof(struct config_multivar_iter));
+ GITERR_CHECK_ALLOC(iter);
+
+ /* get multivar from each */
+
+ *out = (git_config_iterator *) iter;
+
+ return 0;
+}
+
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
{
git_config_backend *file;
diff --git a/src/config_file.c b/src/config_file.c
index 3e0c6cc..5559bd4 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -416,6 +416,95 @@ static int config_get(const git_config_backend *cfg, const char *name, const git
return 0;
}
+typedef struct {
+ git_config_iterator parent;
+ cvar_t *var;
+ regex_t regex;
+ int have_regex;
+} foreach_iter;
+
+static void foreach_iter_free(git_config_iterator *_iter)
+{
+ foreach_iter *iter = (foreach_iter *) _iter;
+
+ if (iter->have_regex)
+ regfree(&iter->regex);
+
+ git__free(iter);
+}
+
+static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter)
+{
+ foreach_iter *iter = (foreach_iter *) _iter;
+
+ cvar_t* var = iter->var;
+
+ if (var == NULL)
+ return GIT_ITEROVER;
+
+ if (!iter->have_regex) {
+ *out = var->entry;
+ iter->var = var->next;
+ return 0;
+ }
+
+ /* For the regex case, we must loop until we find something we like */
+ do {
+ git_config_entry *entry = var->entry;
+ regex_t *regex = &iter->regex;;
+ if (regexec(regex, entry->value, 0, NULL, 0) == 0) {
+ *out = entry;
+ return 0;
+ }
+ } while(var != NULL);
+
+ return GIT_ITEROVER;
+}
+
+static int config_get_multivar(git_config_iterator **out, git_config_backend *_backend,
+ const char *name, const char *regexp)
+{
+ foreach_iter *iter;
+ diskfile_backend *b = (diskfile_backend *) _backend;
+
+ char *key;
+ khiter_t pos;
+ int error = 0;
+
+ if ((error = normalize_name(name, &key)) < 0)
+ return error;
+
+ pos = git_strmap_lookup_index(b->values, key);
+ git__free(key);
+
+ if (!git_strmap_valid_index(b->values, pos))
+ return GIT_ENOTFOUND;
+
+ iter = git__calloc(1, sizeof(foreach_iter));
+ GITERR_CHECK_ALLOC(iter);
+
+ iter->var = git_strmap_value_at(b->values, pos);
+
+ if (regexp != NULL) {
+ int result;
+
+ result = regcomp(&iter->regex, regexp, REG_EXTENDED);
+ if (result < 0) {
+ giterr_set_regex(&iter->regex, result);
+ regfree(&iter->regex);
+ return -1;
+ }
+ iter->have_regex = 1;
+ }
+
+ iter->parent.free = foreach_iter_free;
+ iter->parent.next = foreach_iter_next;
+
+ *out = (git_config_iterator *) iter;
+
+ return 0;
+ }
+
static int config_get_multivar_foreach(
git_config_backend *cfg,
const char *name,
@@ -607,6 +696,7 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend->parent.open = config_open;
backend->parent.get = config_get;
backend->parent.get_multivar_foreach = config_get_multivar_foreach;
+ backend->parent.get_multivar = config_get_multivar;
backend->parent.set = config_set;
backend->parent.set_multivar = config_set_multivar;
backend->parent.del = config_delete;