510456ceb59d5608d13164fe976631b3ba874fd6
1#include <ctype.h>
2
3#include "cache.h"
4
5#define MAXNAME (256)
6
7static FILE *config_file;
8static int config_linenr;
9static int get_next_char(void)
10{
11 int c;
12 FILE *f;
13
14 c = '\n';
15 if ((f = config_file) != NULL) {
16 c = fgetc(f);
17 if (c == '\n')
18 config_linenr++;
19 if (c == EOF) {
20 config_file = NULL;
21 c = '\n';
22 }
23 }
24 return c;
25}
26
27static char *parse_value(void)
28{
29 static char value[1024];
30 int quote = 0, comment = 0, len = 0, space = 0;
31
32 for (;;) {
33 int c = get_next_char();
34 if (len >= sizeof(value))
35 return NULL;
36 if (c == '\n') {
37 if (quote)
38 return NULL;
39 value[len] = 0;
40 return value;
41 }
42 if (comment)
43 continue;
44 if (isspace(c) && !quote) {
45 space = 1;
46 continue;
47 }
48 if (space) {
49 if (len)
50 value[len++] = ' ';
51 space = 0;
52 }
53 if (c == '\\') {
54 c = get_next_char();
55 switch (c) {
56 case '\n':
57 continue;
58 case 't':
59 c = '\t';
60 break;
61 case 'b':
62 c = '\b';
63 break;
64 case 'n':
65 c = '\n';
66 break;
67 /* Some characters escape as themselves */
68 case '\\': case '"':
69 break;
70 /* Reject unknown escape sequences */
71 default:
72 return NULL;
73 }
74 value[len++] = c;
75 continue;
76 }
77 if (c == '"') {
78 quote = 1-quote;
79 continue;
80 }
81 if (!quote) {
82 if (c == ';' || c == '#') {
83 comment = 1;
84 continue;
85 }
86 }
87 value[len++] = c;
88 }
89}
90
91static int get_value(config_fn_t fn, char *name, unsigned int len)
92{
93 int c;
94 char *value;
95
96 /* Get the full name */
97 for (;;) {
98 c = get_next_char();
99 if (c == EOF)
100 break;
101 if (!isalnum(c))
102 break;
103 name[len++] = tolower(c);
104 if (len >= MAXNAME)
105 return -1;
106 }
107 name[len] = 0;
108 while (c == ' ' || c == '\t')
109 c = get_next_char();
110
111 value = NULL;
112 if (c != '\n') {
113 if (c != '=')
114 return -1;
115 value = parse_value();
116 if (!value)
117 return -1;
118 }
119 return fn(name, value);
120}
121
122static int get_base_var(char *name)
123{
124 int baselen = 0;
125
126 for (;;) {
127 int c = get_next_char();
128 if (c == EOF)
129 return -1;
130 if (c == ']')
131 return baselen;
132 if (!isalnum(c))
133 return -1;
134 if (baselen > MAXNAME / 2)
135 return -1;
136 name[baselen++] = tolower(c);
137 }
138}
139
140static int git_parse_file(config_fn_t fn)
141{
142 int comment = 0;
143 int baselen = 0;
144 static char var[MAXNAME];
145
146 for (;;) {
147 int c = get_next_char();
148 if (c == '\n') {
149 /* EOF? */
150 if (!config_file)
151 return 0;
152 comment = 0;
153 continue;
154 }
155 if (comment || isspace(c))
156 continue;
157 if (c == '#' || c == ';') {
158 comment = 1;
159 continue;
160 }
161 if (c == '[') {
162 baselen = get_base_var(var);
163 if (baselen <= 0)
164 break;
165 var[baselen++] = '.';
166 var[baselen] = 0;
167 continue;
168 }
169 if (!isalpha(c))
170 break;
171 var[baselen] = c;
172 if (get_value(fn, var, baselen+1) < 0)
173 break;
174 }
175 die("bad config file line %d", config_linenr);
176}
177
178int git_config_int(const char *name, const char *value)
179{
180 if (value && *value) {
181 char *end;
182 int val = strtol(value, &end, 0);
183 if (!*end)
184 return val;
185 }
186 die("bad config value for '%s'", name);
187}
188
189int git_config_bool(const char *name, const char *value)
190{
191 if (!value)
192 return 1;
193 if (!*value)
194 return 0;
195 if (!strcasecmp(value, "true"))
196 return 1;
197 if (!strcasecmp(value, "false"))
198 return 0;
199 return git_config_int(name, value) != 0;
200}
201
202int git_default_config(const char *var, const char *value)
203{
204 /* This needs a better name */
205 if (!strcmp(var, "core.filemode")) {
206 trust_executable_bit = git_config_bool(var, value);
207 return 0;
208 }
209
210 /* Add other config variables here.. */
211 return 0;
212}
213
214int git_config(config_fn_t fn)
215{
216 int ret;
217 FILE *f = fopen(git_path("config"), "r");
218
219 ret = -1;
220 if (f) {
221 config_file = f;
222 config_linenr = 1;
223 ret = git_parse_file(fn);
224 fclose(f);
225 }
226 return ret;
227}