Documentation: talk about guts of merge in tutorial.
[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 == '\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
34 static 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
98 static 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
129 static 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
147 static 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
185 int 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
196 int 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
209 int 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
231 int 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 }