Forward port the "funny ref avoidance" in clone and fetch from maint branch.
[git/gitweb.git] / config.c
blob519fecfee4cd7344b538528f7fa923b7fda280d2
2 #include "cache.h"
4 #define MAXNAME (256)
6 static FILE *config_file;
7 static int config_linenr;
8 static int get_next_char(void)
10 int c;
11 FILE *f;
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';
23 return c;
26 static char *parse_value(void)
28 static char value[1024];
29 int quote = 0, comment = 0, len = 0, space = 0;
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;
41 if (comment)
42 continue;
43 if (isspace(c) && !quote) {
44 space = 1;
45 continue;
47 if (space) {
48 if (len)
49 value[len++] = ' ';
50 space = 0;
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;
73 value[len++] = c;
74 continue;
76 if (c == '"') {
77 quote = 1-quote;
78 continue;
80 if (!quote) {
81 if (c == ';' || c == '#') {
82 comment = 1;
83 continue;
86 value[len++] = c;
90 static int get_value(config_fn_t fn, char *name, unsigned int len)
92 int c;
93 char *value;
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;
106 name[len] = 0;
107 while (c == ' ' || c == '\t')
108 c = get_next_char();
110 value = NULL;
111 if (c != '\n') {
112 if (c != '=')
113 return -1;
114 value = parse_value();
115 if (!value)
116 return -1;
118 return fn(name, value);
121 static int get_base_var(char *name)
123 int baselen = 0;
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);
139 static int git_parse_file(config_fn_t fn)
141 int comment = 0;
142 int baselen = 0;
143 static char var[MAXNAME];
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;
154 if (comment || isspace(c))
155 continue;
156 if (c == '#' || c == ';') {
157 comment = 1;
158 continue;
160 if (c == '[') {
161 baselen = get_base_var(var);
162 if (baselen <= 0)
163 break;
164 var[baselen++] = '.';
165 var[baselen] = 0;
166 continue;
168 if (!isalpha(c))
169 break;
170 var[baselen] = tolower(c);
171 if (get_value(fn, var, baselen+1) < 0)
172 break;
174 die("bad config file line %d", config_linenr);
177 int git_config_int(const char *name, const char *value)
179 if (value && *value) {
180 char *end;
181 int val = strtol(value, &end, 0);
182 if (!*end)
183 return val;
185 die("bad config value for '%s'", name);
188 int git_config_bool(const char *name, const char *value)
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;
201 int git_default_config(const char *var, const char *value)
203 /* This needs a better name */
204 if (!strcmp(var, "core.filemode")) {
205 trust_executable_bit = git_config_bool(var, value);
206 return 0;
209 if (!strcmp(var, "user.name")) {
210 strncpy(git_default_name, value, sizeof(git_default_name));
211 return 0;
214 if (!strcmp(var, "user.email")) {
215 strncpy(git_default_email, value, sizeof(git_default_email));
216 return 0;
219 /* Add other config variables here.. */
220 return 0;
223 int git_config(config_fn_t fn)
225 int ret;
226 FILE *f = fopen(git_path("config"), "r");
228 ret = -1;
229 if (f) {
230 config_file = f;
231 config_linenr = 1;
232 ret = git_parse_file(fn);
233 fclose(f);
235 return ret;