Skip to content

Commit a603c19

Browse files
Nico von Geysocarlosmn
authored andcommitted
replaced foreach() with non callback based iterations in git_config_backend
new functions in struct git_config_backend: * iterator_new(...) * iterator_free(...) * next(...) The old callback based foreach style can still be used with `git_config_backend_foreach_match`
1 parent 6385fc5 commit a603c19

5 files changed

Lines changed: 123 additions & 41 deletions

File tree

include/git2/config.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ typedef struct {
6161
} git_config_entry;
6262

6363
typedef int (*git_config_foreach_cb)(const git_config_entry *, void *);
64+
typedef struct git_config_backend_iter* git_config_backend_iter;
6465

6566
typedef enum {
6667
GIT_CVAR_FALSE = 0,
@@ -535,6 +536,25 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value);
535536
GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value);
536537

537538

539+
/**
540+
* Perform an operation on each config variable in given config backend
541+
* matching a regular expression.
542+
*
543+
* This behaviors like `git_config_foreach_match` except instead of all config
544+
* entries it just enumerates through the given backend entry.
545+
*
546+
* @param backend where to get the variables from
547+
* @param regexp regular expression to match against config names (can be NULL)
548+
* @param callback the function to call on each variable
549+
* @param payload the data to pass to the callback
550+
*/
551+
GIT_EXTERN(int) git_config_backend_foreach_match(
552+
git_config_backend *backend,
553+
const char *regexp,
554+
int (*fn)(const git_config_entry *, void *),
555+
void *data);
556+
557+
538558
/** @} */
539559
GIT_END_DECL
540560
#endif

include/git2/sys/config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ struct git_config_backend {
3535
int (*set)(struct git_config_backend *, const char *key, const char *value);
3636
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
3737
int (*del)(struct git_config_backend *, const char *key);
38-
int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload);
38+
int (*iterator_new)(git_config_backend_iter **, struct git_config_backend *);
39+
void (*iterator_free)(git_config_backend_iter *);
40+
int (*next)(git_config_backend_iter *, git_config_entry *, struct git_config_backend *);
3941
int (*refresh)(struct git_config_backend *);
4042
void (*free)(struct git_config_backend *);
4143
};

src/config.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,50 @@ int git_config_foreach(
321321
return git_config_foreach_match(cfg, NULL, cb, payload);
322322
}
323323

324+
int git_config_backend_foreach_match(
325+
git_config_backend *backend,
326+
const char *regexp,
327+
int (*fn)(const git_config_entry *, void *),
328+
void *data)
329+
{
330+
git_config_entry entry;
331+
git_config_backend_iter iter;
332+
regex_t regex;
333+
int result = 0;
334+
335+
if (regexp != NULL) {
336+
if ((result = regcomp(&regex, regexp, REG_EXTENDED)) < 0) {
337+
giterr_set_regex(&regex, result);
338+
regfree(&regex);
339+
return -1;
340+
}
341+
}
342+
343+
if (backend->iterator_new(&iter, backend) < 0)
344+
return 0;
345+
346+
while(!(backend->next(&iter, &entry, backend) < 0)) {
347+
/* skip non-matching keys if regexp was provided */
348+
if (regexp && regexec(&regex, entry.name, 0, NULL, 0) != 0)
349+
continue;
350+
351+
/* abort iterator on non-zero return value */
352+
if (fn(&entry, data)) {
353+
giterr_clear();
354+
result = GIT_EUSER;
355+
goto cleanup;
356+
}
357+
}
358+
359+
cleanup:
360+
if (regexp != NULL)
361+
regfree(&regex);
362+
363+
backend->iterator_free(iter);
364+
365+
return result;
366+
}
367+
324368
int git_config_foreach_match(
325369
const git_config *cfg,
326370
const char *regexp,
@@ -335,7 +379,7 @@ int git_config_foreach_match(
335379
for (i = 0; i < cfg->files.length && ret == 0; ++i) {
336380
internal = git_vector_get(&cfg->files, i);
337381
file = internal->file;
338-
ret = file->foreach(file, regexp, cb, payload);
382+
ret = git_config_backend_foreach_match(file, regexp, cb, payload);
339383
}
340384

341385
return ret;

src/config_file.c

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ typedef struct cvar_t {
2727
git_config_entry *entry;
2828
} cvar_t;
2929

30+
typedef struct git_config_file_iter {
31+
git_strmap_iter iter;
32+
cvar_t* next;
33+
} git_config_file_iter;
34+
35+
3036
#define CVAR_LIST_HEAD(list) ((list)->head)
3137

3238
#define CVAR_LIST_TAIL(list) ((list)->tail)
@@ -247,52 +253,60 @@ static void backend_free(git_config_backend *_backend)
247253
git__free(backend);
248254
}
249255

250-
static int file_foreach(
251-
git_config_backend *backend,
252-
const char *regexp,
253-
int (*fn)(const git_config_entry *, void *),
254-
void *data)
256+
static int config_iterator_new(
257+
git_config_backend_iter *iter,
258+
struct git_config_backend* backend)
255259
{
256260
diskfile_backend *b = (diskfile_backend *)backend;
257-
cvar_t *var, *next_var;
258-
const char *key;
259-
regex_t regex;
260-
int result = 0;
261+
git_config_file_iter **it= ((git_config_file_iter**) iter);
261262

262-
if (!b->values)
263-
return 0;
263+
if (!b->values || git_strmap_num_entries(b->values) < 1)
264+
return -1;
264265

265-
if (regexp != NULL) {
266-
if ((result = regcomp(&regex, regexp, REG_EXTENDED)) < 0) {
267-
giterr_set_regex(&regex, result);
268-
regfree(&regex);
269-
return -1;
270-
}
271-
}
266+
*it = git__calloc(1, sizeof(git_config_file_iter));
267+
GITERR_CHECK_ALLOC(it);
272268

273-
git_strmap_iter iter = git_strmap_begin(b->values);
274-
while (!(git_strmap_next(&key, (void**) &var, &iter, b->values) < 0)) {
275-
for (; var != NULL; var = next_var) {
276-
next_var = CVAR_LIST_NEXT(var);
269+
(*it)->iter = git_strmap_begin(b->values);
270+
(*it)->next = NULL;
277271

278-
/* skip non-matching keys if regexp was provided */
279-
if (regexp && regexec(&regex, key, 0, NULL, 0) != 0)
280-
continue;
272+
return 0;
273+
}
281274

282-
/* abort iterator on non-zero return value */
283-
if (fn(var->entry, data)) {
284-
giterr_clear();
285-
result = GIT_EUSER;
286-
goto cleanup;
287-
}
288-
}
275+
static void config_iterator_free(
276+
git_config_backend_iter iter)
277+
{
278+
git__free(iter);
279+
}
280+
281+
static int config_next(
282+
git_config_backend_iter *iter,
283+
git_config_entry* entry,
284+
struct git_config_backend* backend)
285+
{
286+
diskfile_backend *b = (diskfile_backend *)backend;
287+
git_config_file_iter *it = *((git_config_file_iter**) iter);
288+
int err;
289+
cvar_t * var;
290+
const char* key;
291+
292+
if (it->next == NULL) {
293+
err = git_strmap_next(&key, (void**) &var, &(it->iter), b->values);
294+
} else {
295+
key = it->next->entry->name;
296+
var = it->next;
289297
}
290298

291-
cleanup:
292-
if (regexp != NULL)
293-
regfree(&regex);
299+
if (err < 0) {
300+
it->next = NULL;
301+
return -1;
302+
}
294303

295-
return result;
304+
entry->name = key;
305+
entry->value = var->entry->value;
306+
entry->level = var->entry->level;
307+
it->next = CVAR_LIST_NEXT(var);
308+
309+
return 0;
296310
}
297311

298312
static int config_set(git_config_backend *cfg, const char *name, const char *value)
@@ -595,7 +609,9 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
595609
backend->parent.set = config_set;
596610
backend->parent.set_multivar = config_set_multivar;
597611
backend->parent.del = config_delete;
598-
backend->parent.foreach = file_foreach;
612+
backend->parent.iterator_new = config_iterator_new;
613+
backend->parent.iterator_free = config_iterator_free;
614+
backend->parent.next = config_next;
599615
backend->parent.refresh = config_refresh;
600616
backend->parent.free = backend_free;
601617

src/config_file.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ GIT_INLINE(int) git_config_file_foreach(
4242
int (*fn)(const git_config_entry *entry, void *data),
4343
void *data)
4444
{
45-
return cfg->foreach(cfg, NULL, fn, data);
45+
return git_config_backend_foreach_match(cfg, NULL, fn, data);
4646
}
4747

4848
GIT_INLINE(int) git_config_file_foreach_match(
@@ -51,7 +51,7 @@ GIT_INLINE(int) git_config_file_foreach_match(
5151
int (*fn)(const git_config_entry *entry, void *data),
5252
void *data)
5353
{
54-
return cfg->foreach(cfg, regexp, fn, data);
54+
return git_config_backend_foreach_match(cfg, regexp, fn, data);
5555
}
5656

5757
extern int git_config_file_normalize_section(char *start, char *end);

0 commit comments

Comments
 (0)