Rework object refs tracking to reduce memory usage
[git.git] / config.c
blobe89bab26c99f95e6bb7d3346343ab0c623843c42
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 == '\r') {
17 /* DOS like systems */
18 c = fgetc(f);
19 if (c != '\n') {
20 ungetc(c, f);
21 c = '\r';
24 if (c == '\n')
25 config_linenr++;
26 if (c == EOF) {
27 config_file = NULL;
28 c = '\n';
31 return c;
34 static char *parse_value(void)
36 static char value[1024];
37 int quote = 0, comment = 0, len = 0, space = 0;
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;
49 if (comment)
50 continue;
51 if (isspace(c) && !quote) {
52 space = 1;
53 continue;
55 if (space) {
56 if (len)
57 value[len++] = ' ';
58 space = 0;
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;
81 value[len++] = c;
82 continue;
84 if (c == '"') {
85 quote = 1-quote;
86 continue;
88 if (!quote) {
89 if (c == ';' || c == '#') {
90 comment = 1;
91 continue;
94 value[len++] = c;
98 static int get_value(config_fn_t fn, char *name, unsigned int len)
100 int c;
101 char *value;
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;
114 name[len] = 0;
115 while (c == ' ' || c == '\t')
116 c = get_next_char();
118 value = NULL;
119 if (c != '\n') {
120 if (c != '=')
121 return -1;
122 value = parse_value();
123 if (!value)
124 return -1;
126 return fn(name, value);
129 static int get_base_var(char *name)
131 int baselen = 0;
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);
147 static int git_parse_file(config_fn_t fn)
149 int comment = 0;
150 int baselen = 0;
151 static char var[MAXNAME];
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;
162 if (comment || isspace(c))
163 continue;
164 if (c == '#' || c == ';') {
165 comment = 1;
166 continue;
168 if (c == '[') {
169 baselen = get_base_var(var);
170 if (baselen <= 0)
171 break;
172 var[baselen++] = '.';
173 var[baselen] = 0;
174 continue;
176 if (!isalpha(c))
177 break;
178 var[baselen] = tolower(c);
179 if (get_value(fn, var, baselen+1) < 0)
180 break;
182 die("bad config file line %d", config_linenr);
185 int git_config_int(const char *name, const char *value)
187 if (value && *value) {
188 char *end;
189 int val = strtol(value, &end, 0);
190 if (!*end)
191 return val;
193 die("bad config value for '%s'", name);
196 int git_config_bool(const char *name, const char *value)
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;
209 int git_default_config(const char *var, const char *value)
211 /* This needs a better name */
212 if (!strcmp(var, "core.filemode")) {
213 trust_executable_bit = git_config_bool(var, value);
214 return 0;
217 if (!strcmp(var, "user.name")) {
218 strncpy(git_default_name, value, sizeof(git_default_name));
219 return 0;
222 if (!strcmp(var, "user.email")) {
223 strncpy(git_default_email, value, sizeof(git_default_email));
224 return 0;
227 /* Add other config variables here.. */
228 return 0;
231 int git_config(config_fn_t fn)
233 int ret;
234 FILE *f = fopen(git_path("config"), "r");
236 ret = -1;
237 if (f) {
238 config_file = f;
239 config_linenr = 1;
240 ret = git_parse_file(fn);
241 fclose(f);
243 return ret;