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