format-patch: take sequence of ranges.
[git/dscho.git] / config.c
blob9b7c6f2942483c7791277ad659b5683accafab8d
1 #include <ctype.h>
3 #include "cache.h"
5 #define MAXNAME (256)
7 static FILE *config_file;
8 static int config_linenr;
9 static int get_next_char(void)
11 int c;
12 FILE *f;
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';
24 return c;
27 static char *parse_value(void)
29 static char value[1024];
30 int quote = 0, comment = 0, len = 0, space = 0;
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;
42 if (comment)
43 continue;
44 if (isspace(c) && !quote) {
45 space = 1;
46 continue;
48 if (space) {
49 if (len)
50 value[len++] = ' ';
51 space = 0;
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;
74 value[len++] = c;
75 continue;
77 if (c == '"') {
78 quote = 1-quote;
79 continue;
81 if (!quote) {
82 if (c == ';' || c == '#') {
83 comment = 1;
84 continue;
87 value[len++] = c;
91 static int get_value(config_fn_t fn, char *name, unsigned int len)
93 int c;
94 char *value;
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;
107 name[len] = 0;
108 while (c == ' ' || c == '\t')
109 c = get_next_char();
111 value = NULL;
112 if (c != '\n') {
113 if (c != '=')
114 return -1;
115 value = parse_value();
116 if (!value)
117 return -1;
119 return fn(name, value);
122 static int get_base_var(char *name)
124 int baselen = 0;
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);
140 static int git_parse_file(config_fn_t fn)
142 int comment = 0;
143 int baselen = 0;
144 static char var[MAXNAME];
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;
155 if (comment || isspace(c))
156 continue;
157 if (c == '#' || c == ';') {
158 comment = 1;
159 continue;
161 if (c == '[') {
162 baselen = get_base_var(var);
163 if (baselen <= 0)
164 break;
165 var[baselen++] = '.';
166 var[baselen] = 0;
167 continue;
169 if (!isalpha(c))
170 break;
171 var[baselen] = tolower(c);
172 if (get_value(fn, var, baselen+1) < 0)
173 break;
175 die("bad config file line %d", config_linenr);
178 int git_config_int(const char *name, const char *value)
180 if (value && *value) {
181 char *end;
182 int val = strtol(value, &end, 0);
183 if (!*end)
184 return val;
186 die("bad config value for '%s'", name);
189 int git_config_bool(const char *name, const char *value)
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;
202 int git_default_config(const char *var, const char *value)
204 /* This needs a better name */
205 if (!strcmp(var, "core.filemode")) {
206 trust_executable_bit = git_config_bool(var, value);
207 return 0;
210 if (!strcmp(var, "user.name")) {
211 strncpy(git_default_name, value, sizeof(git_default_name));
212 return 0;
215 if (!strcmp(var, "user.email")) {
216 strncpy(git_default_email, value, sizeof(git_default_email));
217 return 0;
220 /* Add other config variables here.. */
221 return 0;
224 int git_config(config_fn_t fn)
226 int ret;
227 FILE *f = fopen(git_path("config"), "r");
229 ret = -1;
230 if (f) {
231 config_file = f;
232 config_linenr = 1;
233 ret = git_parse_file(fn);
234 fclose(f);
236 return ret;