show-branch: optionally use unique prefix as name.
[git/git.git] / config.c
CommitLineData
17712991
LT
1#include <ctype.h>
2
3#include "cache.h"
4
5#define MAXNAME (256)
6
7static FILE *config_file;
8static int config_linenr;
9static int get_next_char(void)
10{
11 int c;
12 FILE *f;
13
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';
22 }
23 }
24 return c;
25}
26
27static char *parse_value(void)
28{
29 static char value[1024];
30 int quote = 0, comment = 0, len = 0, space = 0;
31
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;
41 }
42 if (comment)
43 continue;
44 if (isspace(c) && !quote) {
45 space = 1;
46 continue;
47 }
48 if (space) {
49 if (len)
50 value[len++] = ' ';
51 space = 0;
52 }
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 return NULL;
68 }
69 value[len++] = c;
70 continue;
71 }
72 if (c == '"') {
73 quote = 1-quote;
74 continue;
75 }
76 if (!quote) {
77 if (c == ';' || c == '#') {
78 comment = 1;
79 continue;
80 }
81 }
82 value[len++] = c;
83 }
84}
85
86static int get_value(config_fn_t fn, char *name, unsigned int len)
87{
88 int c;
89 char *value;
90
91 /* Get the full name */
92 for (;;) {
93 c = get_next_char();
94 if (c == EOF)
95 break;
96 if (!isalnum(c))
97 break;
98 name[len++] = tolower(c);
99 if (len >= MAXNAME)
100 return -1;
101 }
102 name[len] = 0;
103 while (c == ' ' || c == '\t')
104 c = get_next_char();
105
106 value = NULL;
107 if (c != '\n') {
108 if (c != '=')
109 return -1;
110 value = parse_value();
111 if (!value)
112 return -1;
113 }
114 return fn(name, value);
115}
116
117static int get_base_var(char *name)
118{
119 int baselen = 0;
120
121 for (;;) {
122 int c = get_next_char();
123 if (c == EOF)
124 return -1;
125 if (c == ']')
126 return baselen;
127 if (!isalnum(c))
128 return -1;
129 if (baselen > MAXNAME / 2)
130 return -1;
131 name[baselen++] = tolower(c);
132 }
133}
134
135static int git_parse_file(config_fn_t fn)
136{
137 int comment = 0;
138 int baselen = 0;
139 static char var[MAXNAME];
140
141 for (;;) {
142 int c = get_next_char();
143 if (c == '\n') {
144 /* EOF? */
145 if (!config_file)
146 return 0;
147 comment = 0;
148 continue;
149 }
150 if (comment || isspace(c))
151 continue;
152 if (c == '#' || c == ';') {
153 comment = 1;
154 continue;
155 }
156 if (c == '[') {
157 baselen = get_base_var(var);
158 if (baselen <= 0)
159 break;
160 var[baselen++] = '.';
161 var[baselen] = 0;
162 continue;
163 }
164 if (!isalpha(c))
165 break;
166 var[baselen] = c;
167 if (get_value(fn, var, baselen+1) < 0)
168 break;
169 }
170 die("bad config file line %d", config_linenr);
171}
172
173int git_config_int(const char *name, const char *value)
174{
175 if (value && *value) {
176 char *end;
177 int val = strtol(value, &end, 0);
178 if (!*end)
179 return val;
180 }
181 die("bad config value for '%s'", name);
182}
183
184int git_config_bool(const char *name, const char *value)
185{
186 if (!value)
187 return 1;
188 if (!*value)
189 return 0;
190 if (!strcasecmp(value, "true"))
191 return 1;
192 if (!strcasecmp(value, "false"))
193 return 0;
194 return git_config_int(name, value) != 0;
195}
196
197int git_default_config(const char *var, const char *value)
198{
199 /* This needs a better name */
200 if (!strcmp(var, "core.filemode")) {
201 trust_executable_bit = git_config_bool(var, value);
202 return 0;
203 }
204
205 /* Add other config variables here.. */
206 return 0;
207}
208
209int git_config(config_fn_t fn)
210{
211 int ret;
212 FILE *f = fopen(git_path("config"), "r");
213
214 ret = -1;
215 if (f) {
216 config_file = f;
217 config_linenr = 1;
218 ret = git_parse_file(fn);
219 fclose(f);
220 }
221 return ret;
222}