2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
5 * Copyright (C) Johannes Schindelin, 2005
14 static FILE *config_file;
15 static const char *config_file_name;
16 static int config_linenr;
17 static int config_file_eof;
19 static const char *config_exclusive_filename;
21 static int get_next_char(void)
27 if ((f = config_file) != NULL) {
30 /* DOS like systems */
47 static char *parse_value(void)
49 static char value[1024];
50 int quote = 0, comment = 0, space = 0;
54 int c = get_next_char();
56 if (len >= sizeof(value) - 1)
66 if (isspace(c) && !quote) {
71 if (c == ';' || c == '#') {
95 /* Some characters escape as themselves */
98 /* Reject unknown escape sequences */
113 static inline int iskeychar(int c)
115 return isalnum(c) || c == '-';
118 static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
123 /* Get the full name */
130 name[len++] = tolower(c);
135 while (c == ' ' || c == '\t')
142 value = parse_value();
146 return fn(name, value, data);
149 static int get_extended_base_var(char *name, int baselen, int c)
155 } while (isspace(c));
157 /* We require the format to be '[base "extension"]' */
160 name[baselen++] = '.';
163 int ch = get_next_char();
170 ch = get_next_char();
174 name[baselen++] = ch;
175 if (baselen > MAXNAME / 2)
180 if (get_next_char() != ']')
185 static int get_base_var(char *name)
190 int c = get_next_char();
196 return get_extended_base_var(name, baselen, c);
197 if (!iskeychar(c) && c != '.')
199 if (baselen > MAXNAME / 2)
201 name[baselen++] = tolower(c);
205 static int perf_parse_file(config_fn_t fn, void *data)
209 static char var[MAXNAME];
211 /* U+FEFF Byte Order Mark in UTF8 */
212 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
213 const unsigned char *bomptr = utf8_bom;
216 int c = get_next_char();
217 if (bomptr && *bomptr) {
218 /* We are at the file beginning; skip UTF8-encoded BOM
219 * if present. Sane editors won't put this in on their
220 * own, but e.g. Windows Notepad will do it happily. */
221 if ((unsigned char) c == *bomptr) {
225 /* Do not tolerate partial BOM. */
226 if (bomptr != utf8_bom)
228 /* No BOM at file beginning. Cool. */
238 if (comment || isspace(c))
240 if (c == '#' || c == ';') {
245 baselen = get_base_var(var);
248 var[baselen++] = '.';
254 var[baselen] = tolower(c);
255 if (get_value(fn, data, var, baselen+1) < 0)
258 die("bad config file line %d in %s", config_linenr, config_file_name);
261 static int parse_unit_factor(const char *end, unsigned long *val)
265 else if (!strcasecmp(end, "k")) {
269 else if (!strcasecmp(end, "m")) {
273 else if (!strcasecmp(end, "g")) {
274 *val *= 1024 * 1024 * 1024;
280 static int perf_parse_long(const char *value, long *ret)
282 if (value && *value) {
284 long val = strtol(value, &end, 0);
285 unsigned long factor = 1;
286 if (!parse_unit_factor(end, &factor))
294 static void die_bad_config(const char *name)
296 if (config_file_name)
297 die("bad config value for '%s' in %s", name, config_file_name);
298 die("bad config value for '%s'", name);
301 int perf_config_int(const char *name, const char *value)
304 if (!perf_parse_long(value, &ret))
305 die_bad_config(name);
309 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
316 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
318 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
321 return perf_config_int(name, value);
324 int perf_config_bool(const char *name, const char *value)
327 return !!perf_config_bool_or_int(name, value, &discard);
330 static int perf_default_core_config(const char *var __used, const char *value __used)
332 /* Add other config variables here and to Documentation/config.txt. */
336 int perf_default_config(const char *var, const char *value, void *dummy __used)
338 if (!prefixcmp(var, "core."))
339 return perf_default_core_config(var, value);
341 /* Add other config variables here and to Documentation/config.txt. */
345 static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
348 FILE *f = fopen(filename, "r");
353 config_file_name = filename;
356 ret = perf_parse_file(fn, data);
358 config_file_name = NULL;
363 static const char *perf_etc_perfconfig(void)
365 static const char *system_wide;
367 system_wide = system_path(ETC_PERFCONFIG);
371 static int perf_env_bool(const char *k, int def)
373 const char *v = getenv(k);
374 return v ? perf_config_bool(k, v) : def;
377 static int perf_config_system(void)
379 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
382 static int perf_config_global(void)
384 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
387 int perf_config(config_fn_t fn, void *data)
389 int ret = 0, found = 0;
390 char *repo_config = NULL;
391 const char *home = NULL;
393 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
394 if (config_exclusive_filename)
395 return perf_config_from_file(fn, config_exclusive_filename, data);
396 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
397 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
402 home = getenv("HOME");
403 if (perf_config_global() && home) {
404 char *user_config = strdup(mkpath("%s/.perfconfig", home));
405 if (!access(user_config, R_OK)) {
406 ret += perf_config_from_file(fn, user_config, data);
412 repo_config = perf_pathdup("config");
413 if (!access(repo_config, R_OK)) {
414 ret += perf_config_from_file(fn, repo_config, data);
424 * Call this to report error for your variable that should not
425 * get a boolean value (i.e. "[my] var" means "true").
427 int config_error_nonbool(const char *var)
429 return error("Missing value for '%s'", var);