config: make parsing stack struct independent from actual data source

To simplify adding other sources we extract all functions needed for parsing into a list of callbacks. We implement those callbacks for the current file parsing. A new source can implement its own set of callbacks. Instead of storing the concrete FILE pointer for parsing we store a void pointer. A new source can use this to store its custom data. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Heiko Voigt committed Jul 12, 2013 at 00:44 UTC 4d8dd1494e9f3af2e9738edaca40ada096f7bf10
1 file changed +43 -21
config.c
+43 -21
@@ -10,20 +10,41 @@
10 #include "strbuf.h"
11 #include "quote.h"
12
13 -typedef struct config_file {
14 - struct config_file *prev;
15 - FILE *f;
13 +struct config_source {
14 + struct config_source *prev;
15 + union {
16 + FILE *file;
17 + } u;
18 const char *name;
19 int linenr;
20 int eof;
21 struct strbuf value;
22 struct strbuf var;
21 -} config_file;
23
23 -static config_file *cf;
24 + int (*fgetc)(struct config_source *c);
25 + int (*ungetc)(int c, struct config_source *conf);
26 + long (*ftell)(struct config_source *c);
27 +};
28 +
29 +static struct config_source *cf;
30
31 static int zlib_compression_seen;
32
33 +static int config_file_fgetc(struct config_source *conf)
34 +{
35 + return fgetc(conf->u.file);
36 +}
37 +
38 +static int config_file_ungetc(int c, struct config_source *conf)
39 +{
40 + return ungetc(c, conf->u.file);
41 +}
42 +
43 +static long config_file_ftell(struct config_source *conf)
44 +{
45 + return ftell(conf->u.file);
46 +}
47 +
48 #define MAX_INCLUDE_DEPTH 10
49 static const char include_depth_advice[] =
50 "exceeded maximum include depth (%d) while including\n"
@@ -168,15 +189,13 @@ int git_config_from_parameters(config_fn_t fn, void *data)
189
190 static int get_next_char(void)
191 {
171 - int c;
172 - FILE *f = cf->f;
192 + int c = cf->fgetc(cf);
193
174 - c = fgetc(f);
194 if (c == '\r') {
195 /* DOS like systems */
177 - c = fgetc(f);
196 + c = cf->fgetc(cf);
197 if (c != '\n') {
179 - ungetc(c, f);
198 + cf->ungetc(c, cf);
199 c = '\r';
200 }
201 }
@@ -336,7 +355,7 @@ static int get_base_var(struct strbuf *name)
355 }
356 }
357
339 -static int git_parse_file(config_fn_t fn, void *data)
358 +static int git_parse_source(config_fn_t fn, void *data)
359 {
360 int comment = 0;
361 int baselen = 0;
@@ -894,10 +913,11 @@ int git_default_config(const char *var, const char *value, void *dummy)
913 }
914
915 /*
897 - * The fields f and name of top need to be initialized before calling
916 + * All source specific fields in the union, name and the callbacks
917 + * fgetc, ungetc, ftell of top need to be initialized before calling
918 * this function.
919 */
900 -static int do_config_from(struct config_file *top, config_fn_t fn, void *data)
920 +static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
921 {
922 int ret;
923
@@ -909,7 +929,7 @@ static int do_config_from(struct config_file *top, config_fn_t fn, void *data)
929 strbuf_init(&top->var, 1024);
930 cf = top;
931
912 - ret = git_parse_file(fn, data);
932 + ret = git_parse_source(fn, data);
933
934 /* pop config-file parsing state stack */
935 strbuf_release(&top->value);
@@ -926,10 +946,13 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
946
947 ret = -1;
948 if (f) {
929 - config_file top;
949 + struct config_source top;
950
931 - top.f = f;
951 + top.u.file = f;
952 top.name = filename;
953 + top.fgetc = config_file_fgetc;
954 + top.ungetc = config_file_ungetc;
955 + top.ftell = config_file_ftell;
956
957 ret = do_config_from(&top, fn, data);
958
@@ -1064,7 +1087,6 @@ static int store_aux(const char *key, const char *value, void *cb)
1087 {
1088 const char *ep;
1089 size_t section_len;
1067 - FILE *f = cf->f;
1090
1091 switch (store.state) {
1092 case KEY_SEEN:
@@ -1076,7 +1098,7 @@ static int store_aux(const char *key, const char *value, void *cb)
1098 return 1;
1099 }
1100
1079 - store.offset[store.seen] = ftell(f);
1101 + store.offset[store.seen] = cf->ftell(cf);
1102 store.seen++;
1103 }
1104 break;
@@ -1103,19 +1125,19 @@ static int store_aux(const char *key, const char *value, void *cb)
1125 * Do not increment matches: this is no match, but we
1126 * just made sure we are in the desired section.
1127 */
1106 - store.offset[store.seen] = ftell(f);
1128 + store.offset[store.seen] = cf->ftell(cf);
1129 /* fallthru */
1130 case SECTION_END_SEEN:
1131 case START:
1132 if (matches(key, value)) {
1111 - store.offset[store.seen] = ftell(f);
1133 + store.offset[store.seen] = cf->ftell(cf);
1134 store.state = KEY_SEEN;
1135 store.seen++;
1136 } else {
1137 if (strrchr(key, '.') - key == store.baselen &&
1138 !strncmp(key, store.key, store.baselen)) {
1139 store.state = SECTION_SEEN;
1118 - store.offset[store.seen] = ftell(f);
1140 + store.offset[store.seen] = cf->ftell(cf);
1141 }
1142 }
1143 }