Skip to content

Commit 099ba55

Browse files
committed
Merge branch 'jk/config-parsing-cleanup'
Configuration parsing for tar.* configuration variables were broken. Introduce a new config-keyname parser API to make the callers much less error prone. * jk/config-parsing-cleanup: reflog: use parse_config_key in config callback help: use parse_config_key for man config submodule: simplify memory handling in config parsing submodule: use parse_config_key when parsing config userdiff: drop parse_driver function convert some config callbacks to parse_config_key archive-tar: use parse_config_key when parsing config config: add helper function for parsing key names
2 parents 149a421 + b3873c3 commit 099ba55

File tree

10 files changed

+117
-99
lines changed

10 files changed

+117
-99
lines changed

archive-tar.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,12 @@ static struct archiver *find_tar_filter(const char *name, int len)
327327
static int tar_filter_config(const char *var, const char *value, void *data)
328328
{
329329
struct archiver *ar;
330-
const char *dot;
331330
const char *name;
332331
const char *type;
333332
int namelen;
334333

335-
if (prefixcmp(var, "tar."))
334+
if (parse_config_key(var, "tar", &name, &namelen, &type) < 0 || !name)
336335
return 0;
337-
dot = strrchr(var, '.');
338-
if (dot == var + 9)
339-
return 0;
340-
341-
name = var + 4;
342-
namelen = dot - name;
343-
type = dot + 1;
344336

345337
ar = find_tar_filter(name, namelen);
346338
if (!ar) {

builtin/help.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,21 +236,21 @@ static int add_man_viewer_cmd(const char *name,
236236

237237
static int add_man_viewer_info(const char *var, const char *value)
238238
{
239-
const char *name = var + 4;
240-
const char *subkey = strrchr(name, '.');
239+
const char *name, *subkey;
240+
int namelen;
241241

242-
if (!subkey)
242+
if (parse_config_key(var, "man", &name, &namelen, &subkey) < 0 || !name)
243243
return 0;
244244

245-
if (!strcmp(subkey, ".path")) {
245+
if (!strcmp(subkey, "path")) {
246246
if (!value)
247247
return config_error_nonbool(var);
248-
return add_man_viewer_path(name, subkey - name, value);
248+
return add_man_viewer_path(name, namelen, value);
249249
}
250-
if (!strcmp(subkey, ".cmd")) {
250+
if (!strcmp(subkey, "cmd")) {
251251
if (!value)
252252
return config_error_nonbool(var);
253-
return add_man_viewer_cmd(name, subkey - name, value);
253+
return add_man_viewer_cmd(name, namelen, value);
254254
}
255255

256256
return 0;

builtin/reflog.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -510,26 +510,27 @@ static int parse_expire_cfg_value(const char *var, const char *value, unsigned l
510510

511511
static int reflog_expire_config(const char *var, const char *value, void *cb)
512512
{
513-
const char *lastdot = strrchr(var, '.');
513+
const char *pattern, *key;
514+
int pattern_len;
514515
unsigned long expire;
515516
int slot;
516517
struct reflog_expire_cfg *ent;
517518

518-
if (!lastdot || prefixcmp(var, "gc."))
519+
if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
519520
return git_default_config(var, value, cb);
520521

521-
if (!strcmp(lastdot, ".reflogexpire")) {
522+
if (!strcmp(key, "reflogexpire")) {
522523
slot = EXPIRE_TOTAL;
523524
if (parse_expire_cfg_value(var, value, &expire))
524525
return -1;
525-
} else if (!strcmp(lastdot, ".reflogexpireunreachable")) {
526+
} else if (!strcmp(key, "reflogexpireunreachable")) {
526527
slot = EXPIRE_UNREACH;
527528
if (parse_expire_cfg_value(var, value, &expire))
528529
return -1;
529530
} else
530531
return git_default_config(var, value, cb);
531532

532-
if (lastdot == var + 2) {
533+
if (!pattern) {
533534
switch (slot) {
534535
case EXPIRE_TOTAL:
535536
default_reflog_expire = expire;
@@ -541,7 +542,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
541542
return 0;
542543
}
543544

544-
ent = find_cfg_ent(var + 3, lastdot - (var+3));
545+
ent = find_cfg_ent(pattern, pattern_len);
545546
if (!ent)
546547
return -1;
547548
switch (slot) {

cache.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,21 @@ struct config_include_data {
11701170
#define CONFIG_INCLUDE_INIT { 0 }
11711171
extern int git_config_include(const char *name, const char *value, void *data);
11721172

1173+
/*
1174+
* Match and parse a config key of the form:
1175+
*
1176+
* section.(subsection.)?key
1177+
*
1178+
* (i.e., what gets handed to a config_fn_t). The caller provides the section;
1179+
* we return -1 if it does not match, 0 otherwise. The subsection and key
1180+
* out-parameters are filled by the function (and subsection is NULL if it is
1181+
* missing).
1182+
*/
1183+
extern int parse_config_key(const char *var,
1184+
const char *section,
1185+
const char **subsection, int *subsection_len,
1186+
const char **key);
1187+
11731188
extern int committer_ident_sufficiently_given(void);
11741189
extern int author_ident_sufficiently_given(void);
11751190

config.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,3 +1681,36 @@ int config_error_nonbool(const char *var)
16811681
{
16821682
return error("Missing value for '%s'", var);
16831683
}
1684+
1685+
int parse_config_key(const char *var,
1686+
const char *section,
1687+
const char **subsection, int *subsection_len,
1688+
const char **key)
1689+
{
1690+
int section_len = strlen(section);
1691+
const char *dot;
1692+
1693+
/* Does it start with "section." ? */
1694+
if (prefixcmp(var, section) || var[section_len] != '.')
1695+
return -1;
1696+
1697+
/*
1698+
* Find the key; we don't know yet if we have a subsection, but we must
1699+
* parse backwards from the end, since the subsection may have dots in
1700+
* it, too.
1701+
*/
1702+
dot = strrchr(var, '.');
1703+
*key = dot + 1;
1704+
1705+
/* Did we have a subsection at all? */
1706+
if (dot == var + section_len) {
1707+
*subsection = NULL;
1708+
*subsection_len = 0;
1709+
}
1710+
else {
1711+
*subsection = var + section_len + 1;
1712+
*subsection_len = dot - *subsection;
1713+
}
1714+
1715+
return 0;
1716+
}

convert.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -457,18 +457,16 @@ static struct convert_driver {
457457

458458
static int read_convert_config(const char *var, const char *value, void *cb)
459459
{
460-
const char *ep, *name;
460+
const char *key, *name;
461461
int namelen;
462462
struct convert_driver *drv;
463463

464464
/*
465465
* External conversion drivers are configured using
466466
* "filter.<name>.variable".
467467
*/
468-
if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6)
468+
if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
469469
return 0;
470-
name = var + 7;
471-
namelen = ep - name;
472470
for (drv = user_convert; drv; drv = drv->next)
473471
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
474472
break;
@@ -479,8 +477,6 @@ static int read_convert_config(const char *var, const char *value, void *cb)
479477
user_convert_tail = &(drv->next);
480478
}
481479

482-
ep++;
483-
484480
/*
485481
* filter.<name>.smudge and filter.<name>.clean specifies
486482
* the command line:
@@ -490,13 +486,13 @@ static int read_convert_config(const char *var, const char *value, void *cb)
490486
* The command-line will not be interpolated in any way.
491487
*/
492488

493-
if (!strcmp("smudge", ep))
489+
if (!strcmp("smudge", key))
494490
return git_config_string(&drv->smudge, var, value);
495491

496-
if (!strcmp("clean", ep))
492+
if (!strcmp("clean", key))
497493
return git_config_string(&drv->clean, var, value);
498494

499-
if (!strcmp("required", ep)) {
495+
if (!strcmp("required", key)) {
500496
drv->required = git_config_bool(var, value);
501497
return 0;
502498
}

ll-merge.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ static const char *default_ll_merge;
222222
static int read_merge_config(const char *var, const char *value, void *cb)
223223
{
224224
struct ll_merge_driver *fn;
225-
const char *ep, *name;
225+
const char *key, *name;
226226
int namelen;
227227

228228
if (!strcmp(var, "merge.default")) {
@@ -236,15 +236,13 @@ static int read_merge_config(const char *var, const char *value, void *cb)
236236
* especially, we do not want to look at variables such as
237237
* "merge.summary", "merge.tool", and "merge.verbosity".
238238
*/
239-
if (prefixcmp(var, "merge.") || (ep = strrchr(var, '.')) == var + 5)
239+
if (parse_config_key(var, "merge", &name, &namelen, &key) < 0 || !name)
240240
return 0;
241241

242242
/*
243243
* Find existing one as we might be processing merge.<name>.var2
244244
* after seeing merge.<name>.var1.
245245
*/
246-
name = var + 6;
247-
namelen = ep - name;
248246
for (fn = ll_user_merge; fn; fn = fn->next)
249247
if (!strncmp(fn->name, name, namelen) && !fn->name[namelen])
250248
break;
@@ -256,16 +254,14 @@ static int read_merge_config(const char *var, const char *value, void *cb)
256254
ll_user_merge_tail = &(fn->next);
257255
}
258256

259-
ep++;
260-
261-
if (!strcmp("name", ep)) {
257+
if (!strcmp("name", key)) {
262258
if (!value)
263259
return error("%s: lacks value", var);
264260
fn->description = xstrdup(value);
265261
return 0;
266262
}
267263

268-
if (!strcmp("driver", ep)) {
264+
if (!strcmp("driver", key)) {
269265
if (!value)
270266
return error("%s: lacks value", var);
271267
/*
@@ -289,7 +285,7 @@ static int read_merge_config(const char *var, const char *value, void *cb)
289285
return 0;
290286
}
291287

292-
if (!strcmp("recursive", ep)) {
288+
if (!strcmp("recursive", key)) {
293289
if (!value)
294290
return error("%s: lacks value", var);
295291
fn->recursive = xstrdup(value);

submodule.c

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -126,45 +126,44 @@ void gitmodules_config(void)
126126

127127
int parse_submodule_config_option(const char *var, const char *value)
128128
{
129-
int len;
130129
struct string_list_item *config;
131-
struct strbuf submodname = STRBUF_INIT;
130+
const char *name, *key;
131+
int namelen;
132132

133-
var += 10; /* Skip "submodule." */
133+
if (parse_config_key(var, "submodule", &name, &namelen, &key) < 0 || !name)
134+
return 0;
134135

135-
len = strlen(var);
136-
if ((len > 5) && !strcmp(var + len - 5, ".path")) {
137-
strbuf_add(&submodname, var, len - 5);
136+
if (!strcmp(key, "path")) {
138137
config = unsorted_string_list_lookup(&config_name_for_path, value);
139138
if (config)
140139
free(config->util);
141140
else
142141
config = string_list_append(&config_name_for_path, xstrdup(value));
143-
config->util = strbuf_detach(&submodname, NULL);
144-
strbuf_release(&submodname);
145-
} else if ((len > 23) && !strcmp(var + len - 23, ".fetchrecursesubmodules")) {
146-
strbuf_add(&submodname, var, len - 23);
147-
config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, submodname.buf);
142+
config->util = xmemdupz(name, namelen);
143+
} else if (!strcmp(key, "fetchrecursesubmodules")) {
144+
char *name_cstr = xmemdupz(name, namelen);
145+
config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name_cstr);
148146
if (!config)
149-
config = string_list_append(&config_fetch_recurse_submodules_for_name,
150-
strbuf_detach(&submodname, NULL));
147+
config = string_list_append(&config_fetch_recurse_submodules_for_name, name_cstr);
148+
else
149+
free(name_cstr);
151150
config->util = (void *)(intptr_t)parse_fetch_recurse_submodules_arg(var, value);
152-
strbuf_release(&submodname);
153-
} else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
151+
} else if (!strcmp(key, "ignore")) {
152+
char *name_cstr;
153+
154154
if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
155155
strcmp(value, "all") && strcmp(value, "none")) {
156156
warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
157157
return 0;
158158
}
159159

160-
strbuf_add(&submodname, var, len - 7);
161-
config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf);
162-
if (config)
160+
name_cstr = xmemdupz(name, namelen);
161+
config = unsorted_string_list_lookup(&config_ignore_for_name, name_cstr);
162+
if (config) {
163163
free(config->util);
164-
else
165-
config = string_list_append(&config_ignore_for_name,
166-
strbuf_detach(&submodname, NULL));
167-
strbuf_release(&submodname);
164+
free(name_cstr);
165+
} else
166+
config = string_list_append(&config_ignore_for_name, name_cstr);
168167
config->util = xstrdup(value);
169168
return 0;
170169
}

t/t5000-tar-tree.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ test_expect_success 'git-archive --prefix=olde-' '
212212
test_expect_success 'setup tar filters' '
213213
git config tar.tar.foo.command "tr ab ba" &&
214214
git config tar.bar.command "tr ab ba" &&
215-
git config tar.bar.remote true
215+
git config tar.bar.remote true &&
216+
git config tar.invalid baz
216217
'
217218

218219
test_expect_success 'archive --list mentions user filter' '

0 commit comments

Comments
 (0)