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