git-config: collect values instead of immediately printing

This is a refactor that will allow us to more easily tweak the behavior for multi-valued variables, and it will ultimately allow us to remove a lot git-config's custom code in favor of the regular git_config code. It does mean we're no longer streaming, and we're storing more in memory for the --get-all case, but in practice it is a tiny amount of data, and the results are instantaneous. Signed-off-by: Jeff King <peff@peff.net>

Jeff King committed Oct 23, 2012 at 15:51 UTC 7acdd6f0bc27bba37591e2d5fc2ca84e2af13ce4
1 file changed +35 -15
builtin/config.c
+35 -15
@@ -15,7 +15,6 @@ static int show_keys;
15 static int use_key_regexp;
16 static int do_all;
17 static int do_not_match;
18 -static int seen;
18 static char delim = '=';
19 static char key_delim = ' ';
20 static char term = '\n';
@@ -95,8 +94,16 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
94 return 0;
95 }
96
98 -static int show_config(const char *key_, const char *value_, void *cb)
97 +struct strbuf_list {
98 + struct strbuf *items;
99 + int nr;
100 + int alloc;
101 +};
102 +
103 +static int collect_config(const char *key_, const char *value_, void *cb)
104 {
105 + struct strbuf_list *values = cb;
106 + struct strbuf *buf;
107 char value[256];
108 const char *vptr = value;
109 int must_free_vptr = 0;
@@ -111,11 +118,15 @@ static int show_config(const char *key_, const char *value_, void *cb)
118 (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
119 return 0;
120
121 + ALLOC_GROW(values->items, values->nr + 1, values->alloc);
122 + buf = &values->items[values->nr++];
123 + strbuf_init(buf, 0);
124 +
125 if (show_keys) {
115 - printf("%s", key_);
126 + strbuf_addstr(buf, key_);
127 must_print_delim = 1;
128 }
118 - if (seen && !do_all)
129 + if (values->nr > 1 && !do_all)
130 dup_error = 1;
131 if (types == TYPE_INT)
132 sprintf(value, "%d", git_config_int(key_, value_?value_:""));
@@ -138,15 +149,15 @@ static int show_config(const char *key_, const char *value_, void *cb)
149 vptr = "";
150 must_print_delim = 0;
151 }
141 - seen++;
152 if (dup_error) {
153 error("More than one value for the key %s: %s",
154 key_, vptr);
155 }
156 else {
157 if (must_print_delim)
148 - printf("%c", key_delim);
149 - printf("%s%c", vptr, term);
158 + strbuf_addch(buf, key_delim);
159 + strbuf_addstr(buf, vptr);
160 + strbuf_addch(buf, term);
161 }
162 if (must_free_vptr)
163 /* If vptr must be freed, it's a pointer to a
@@ -166,6 +177,8 @@ static int get_value(const char *key_, const char *regex_)
177 struct config_include_data inc = CONFIG_INCLUDE_INIT;
178 config_fn_t fn;
179 void *data;
180 + struct strbuf_list values = {0};
181 + int i;
182
183 local = given_config_file;
184 if (!local) {
@@ -223,8 +236,8 @@ static int get_value(const char *key_, const char *regex_)
236 }
237 }
238
226 - fn = show_config;
227 - data = NULL;
239 + fn = collect_config;
240 + data = &values;
241 if (respect_includes) {
242 inc.fn = fn;
243 inc.data = data;
@@ -241,19 +254,26 @@ static int get_value(const char *key_, const char *regex_)
254 if (do_all)
255 git_config_from_file(fn, local, data);
256 git_config_from_parameters(fn, data);
244 - if (!do_all && !seen)
257 + if (!do_all && !values.nr)
258 git_config_from_file(fn, local, data);
246 - if (!do_all && !seen && global)
259 + if (!do_all && !values.nr && global)
260 git_config_from_file(fn, global, data);
248 - if (!do_all && !seen && xdg)
261 + if (!do_all && !values.nr && xdg)
262 git_config_from_file(fn, xdg, data);
250 - if (!do_all && !seen && system_wide)
263 + if (!do_all && !values.nr && system_wide)
264 git_config_from_file(fn, system_wide, data);
265
266 if (do_all)
254 - ret = !seen;
267 + ret = !values.nr;
268 else
256 - ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
269 + ret = (values.nr == 1) ? 0 : values.nr > 1 ? 2 : 1;
270 +
271 + for (i = 0; i < values.nr; i++) {
272 + struct strbuf *buf = values.items + i;
273 + fwrite(buf->buf, 1, buf->len, stdout);
274 + strbuf_release(buf);
275 + }
276 + free(values.items);
277
278 free_strings:
279 free(repo_config);