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
}