186470930SIngo Molnar /* 286470930SIngo Molnar * GIT - The information manager from hell 386470930SIngo Molnar * 486470930SIngo Molnar * Copyright (C) Linus Torvalds, 2005 586470930SIngo Molnar * Copyright (C) Johannes Schindelin, 2005 686470930SIngo Molnar * 786470930SIngo Molnar */ 886470930SIngo Molnar #include "util.h" 986470930SIngo Molnar #include "cache.h" 1086470930SIngo Molnar #include "exec_cmd.h" 1186470930SIngo Molnar 1286470930SIngo Molnar #define MAXNAME (256) 1386470930SIngo Molnar 1486470930SIngo Molnar static FILE *config_file; 1586470930SIngo Molnar static const char *config_file_name; 1686470930SIngo Molnar static int config_linenr; 1786470930SIngo Molnar static int config_file_eof; 1886470930SIngo Molnar 19*a41794cdSArnaldo Carvalho de Melo static const char *config_exclusive_filename; 2086470930SIngo Molnar 2186470930SIngo Molnar static int get_next_char(void) 2286470930SIngo Molnar { 2386470930SIngo Molnar int c; 2486470930SIngo Molnar FILE *f; 2586470930SIngo Molnar 2686470930SIngo Molnar c = '\n'; 2786470930SIngo Molnar if ((f = config_file) != NULL) { 2886470930SIngo Molnar c = fgetc(f); 2986470930SIngo Molnar if (c == '\r') { 3086470930SIngo Molnar /* DOS like systems */ 3186470930SIngo Molnar c = fgetc(f); 3286470930SIngo Molnar if (c != '\n') { 3386470930SIngo Molnar ungetc(c, f); 3486470930SIngo Molnar c = '\r'; 3586470930SIngo Molnar } 3686470930SIngo Molnar } 3786470930SIngo Molnar if (c == '\n') 3886470930SIngo Molnar config_linenr++; 3986470930SIngo Molnar if (c == EOF) { 4086470930SIngo Molnar config_file_eof = 1; 4186470930SIngo Molnar c = '\n'; 4286470930SIngo Molnar } 4386470930SIngo Molnar } 4486470930SIngo Molnar return c; 4586470930SIngo Molnar } 4686470930SIngo Molnar 4786470930SIngo Molnar static char *parse_value(void) 4886470930SIngo Molnar { 4986470930SIngo Molnar static char value[1024]; 50f37a291cSIngo Molnar int quote = 0, comment = 0, space = 0; 51f37a291cSIngo Molnar size_t len = 0; 5286470930SIngo Molnar 5386470930SIngo Molnar for (;;) { 5486470930SIngo Molnar int c = get_next_char(); 55f37a291cSIngo Molnar 5686470930SIngo Molnar if (len >= sizeof(value) - 1) 5786470930SIngo Molnar return NULL; 5886470930SIngo Molnar if (c == '\n') { 5986470930SIngo Molnar if (quote) 6086470930SIngo Molnar return NULL; 6186470930SIngo Molnar value[len] = 0; 6286470930SIngo Molnar return value; 6386470930SIngo Molnar } 6486470930SIngo Molnar if (comment) 6586470930SIngo Molnar continue; 6686470930SIngo Molnar if (isspace(c) && !quote) { 6786470930SIngo Molnar space = 1; 6886470930SIngo Molnar continue; 6986470930SIngo Molnar } 7086470930SIngo Molnar if (!quote) { 7186470930SIngo Molnar if (c == ';' || c == '#') { 7286470930SIngo Molnar comment = 1; 7386470930SIngo Molnar continue; 7486470930SIngo Molnar } 7586470930SIngo Molnar } 7686470930SIngo Molnar if (space) { 7786470930SIngo Molnar if (len) 7886470930SIngo Molnar value[len++] = ' '; 7986470930SIngo Molnar space = 0; 8086470930SIngo Molnar } 8186470930SIngo Molnar if (c == '\\') { 8286470930SIngo Molnar c = get_next_char(); 8386470930SIngo Molnar switch (c) { 8486470930SIngo Molnar case '\n': 8586470930SIngo Molnar continue; 8686470930SIngo Molnar case 't': 8786470930SIngo Molnar c = '\t'; 8886470930SIngo Molnar break; 8986470930SIngo Molnar case 'b': 9086470930SIngo Molnar c = '\b'; 9186470930SIngo Molnar break; 9286470930SIngo Molnar case 'n': 9386470930SIngo Molnar c = '\n'; 9486470930SIngo Molnar break; 9586470930SIngo Molnar /* Some characters escape as themselves */ 9686470930SIngo Molnar case '\\': case '"': 9786470930SIngo Molnar break; 9886470930SIngo Molnar /* Reject unknown escape sequences */ 9986470930SIngo Molnar default: 10086470930SIngo Molnar return NULL; 10186470930SIngo Molnar } 10286470930SIngo Molnar value[len++] = c; 10386470930SIngo Molnar continue; 10486470930SIngo Molnar } 10586470930SIngo Molnar if (c == '"') { 10686470930SIngo Molnar quote = 1-quote; 10786470930SIngo Molnar continue; 10886470930SIngo Molnar } 10986470930SIngo Molnar value[len++] = c; 11086470930SIngo Molnar } 11186470930SIngo Molnar } 11286470930SIngo Molnar 11386470930SIngo Molnar static inline int iskeychar(int c) 11486470930SIngo Molnar { 11586470930SIngo Molnar return isalnum(c) || c == '-'; 11686470930SIngo Molnar } 11786470930SIngo Molnar 11886470930SIngo Molnar static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 11986470930SIngo Molnar { 12086470930SIngo Molnar int c; 12186470930SIngo Molnar char *value; 12286470930SIngo Molnar 12386470930SIngo Molnar /* Get the full name */ 12486470930SIngo Molnar for (;;) { 12586470930SIngo Molnar c = get_next_char(); 12686470930SIngo Molnar if (config_file_eof) 12786470930SIngo Molnar break; 12886470930SIngo Molnar if (!iskeychar(c)) 12986470930SIngo Molnar break; 13086470930SIngo Molnar name[len++] = tolower(c); 13186470930SIngo Molnar if (len >= MAXNAME) 13286470930SIngo Molnar return -1; 13386470930SIngo Molnar } 13486470930SIngo Molnar name[len] = 0; 13586470930SIngo Molnar while (c == ' ' || c == '\t') 13686470930SIngo Molnar c = get_next_char(); 13786470930SIngo Molnar 13886470930SIngo Molnar value = NULL; 13986470930SIngo Molnar if (c != '\n') { 14086470930SIngo Molnar if (c != '=') 14186470930SIngo Molnar return -1; 14286470930SIngo Molnar value = parse_value(); 14386470930SIngo Molnar if (!value) 14486470930SIngo Molnar return -1; 14586470930SIngo Molnar } 14686470930SIngo Molnar return fn(name, value, data); 14786470930SIngo Molnar } 14886470930SIngo Molnar 14986470930SIngo Molnar static int get_extended_base_var(char *name, int baselen, int c) 15086470930SIngo Molnar { 15186470930SIngo Molnar do { 15286470930SIngo Molnar if (c == '\n') 15386470930SIngo Molnar return -1; 15486470930SIngo Molnar c = get_next_char(); 15586470930SIngo Molnar } while (isspace(c)); 15686470930SIngo Molnar 15786470930SIngo Molnar /* We require the format to be '[base "extension"]' */ 15886470930SIngo Molnar if (c != '"') 15986470930SIngo Molnar return -1; 16086470930SIngo Molnar name[baselen++] = '.'; 16186470930SIngo Molnar 16286470930SIngo Molnar for (;;) { 16383a0944fSIngo Molnar int ch = get_next_char(); 16483a0944fSIngo Molnar 16583a0944fSIngo Molnar if (ch == '\n') 16686470930SIngo Molnar return -1; 16783a0944fSIngo Molnar if (ch == '"') 16886470930SIngo Molnar break; 16983a0944fSIngo Molnar if (ch == '\\') { 17083a0944fSIngo Molnar ch = get_next_char(); 17183a0944fSIngo Molnar if (ch == '\n') 17286470930SIngo Molnar return -1; 17386470930SIngo Molnar } 17483a0944fSIngo Molnar name[baselen++] = ch; 17586470930SIngo Molnar if (baselen > MAXNAME / 2) 17686470930SIngo Molnar return -1; 17786470930SIngo Molnar } 17886470930SIngo Molnar 17986470930SIngo Molnar /* Final ']' */ 18086470930SIngo Molnar if (get_next_char() != ']') 18186470930SIngo Molnar return -1; 18286470930SIngo Molnar return baselen; 18386470930SIngo Molnar } 18486470930SIngo Molnar 18586470930SIngo Molnar static int get_base_var(char *name) 18686470930SIngo Molnar { 18786470930SIngo Molnar int baselen = 0; 18886470930SIngo Molnar 18986470930SIngo Molnar for (;;) { 19086470930SIngo Molnar int c = get_next_char(); 19186470930SIngo Molnar if (config_file_eof) 19286470930SIngo Molnar return -1; 19386470930SIngo Molnar if (c == ']') 19486470930SIngo Molnar return baselen; 19586470930SIngo Molnar if (isspace(c)) 19686470930SIngo Molnar return get_extended_base_var(name, baselen, c); 19786470930SIngo Molnar if (!iskeychar(c) && c != '.') 19886470930SIngo Molnar return -1; 19986470930SIngo Molnar if (baselen > MAXNAME / 2) 20086470930SIngo Molnar return -1; 20186470930SIngo Molnar name[baselen++] = tolower(c); 20286470930SIngo Molnar } 20386470930SIngo Molnar } 20486470930SIngo Molnar 20586470930SIngo Molnar static int perf_parse_file(config_fn_t fn, void *data) 20686470930SIngo Molnar { 20786470930SIngo Molnar int comment = 0; 20886470930SIngo Molnar int baselen = 0; 20986470930SIngo Molnar static char var[MAXNAME]; 21086470930SIngo Molnar 21186470930SIngo Molnar /* U+FEFF Byte Order Mark in UTF8 */ 21286470930SIngo Molnar static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 21386470930SIngo Molnar const unsigned char *bomptr = utf8_bom; 21486470930SIngo Molnar 21586470930SIngo Molnar for (;;) { 21686470930SIngo Molnar int c = get_next_char(); 21786470930SIngo Molnar if (bomptr && *bomptr) { 21886470930SIngo Molnar /* We are at the file beginning; skip UTF8-encoded BOM 21986470930SIngo Molnar * if present. Sane editors won't put this in on their 22086470930SIngo Molnar * own, but e.g. Windows Notepad will do it happily. */ 22186470930SIngo Molnar if ((unsigned char) c == *bomptr) { 22286470930SIngo Molnar bomptr++; 22386470930SIngo Molnar continue; 22486470930SIngo Molnar } else { 22586470930SIngo Molnar /* Do not tolerate partial BOM. */ 22686470930SIngo Molnar if (bomptr != utf8_bom) 22786470930SIngo Molnar break; 22886470930SIngo Molnar /* No BOM at file beginning. Cool. */ 22986470930SIngo Molnar bomptr = NULL; 23086470930SIngo Molnar } 23186470930SIngo Molnar } 23286470930SIngo Molnar if (c == '\n') { 23386470930SIngo Molnar if (config_file_eof) 23486470930SIngo Molnar return 0; 23586470930SIngo Molnar comment = 0; 23686470930SIngo Molnar continue; 23786470930SIngo Molnar } 23886470930SIngo Molnar if (comment || isspace(c)) 23986470930SIngo Molnar continue; 24086470930SIngo Molnar if (c == '#' || c == ';') { 24186470930SIngo Molnar comment = 1; 24286470930SIngo Molnar continue; 24386470930SIngo Molnar } 24486470930SIngo Molnar if (c == '[') { 24586470930SIngo Molnar baselen = get_base_var(var); 24686470930SIngo Molnar if (baselen <= 0) 24786470930SIngo Molnar break; 24886470930SIngo Molnar var[baselen++] = '.'; 24986470930SIngo Molnar var[baselen] = 0; 25086470930SIngo Molnar continue; 25186470930SIngo Molnar } 25286470930SIngo Molnar if (!isalpha(c)) 25386470930SIngo Molnar break; 25486470930SIngo Molnar var[baselen] = tolower(c); 25586470930SIngo Molnar if (get_value(fn, data, var, baselen+1) < 0) 25686470930SIngo Molnar break; 25786470930SIngo Molnar } 25886470930SIngo Molnar die("bad config file line %d in %s", config_linenr, config_file_name); 25986470930SIngo Molnar } 26086470930SIngo Molnar 26186470930SIngo Molnar static int parse_unit_factor(const char *end, unsigned long *val) 26286470930SIngo Molnar { 26386470930SIngo Molnar if (!*end) 26486470930SIngo Molnar return 1; 26586470930SIngo Molnar else if (!strcasecmp(end, "k")) { 26686470930SIngo Molnar *val *= 1024; 26786470930SIngo Molnar return 1; 26886470930SIngo Molnar } 26986470930SIngo Molnar else if (!strcasecmp(end, "m")) { 27086470930SIngo Molnar *val *= 1024 * 1024; 27186470930SIngo Molnar return 1; 27286470930SIngo Molnar } 27386470930SIngo Molnar else if (!strcasecmp(end, "g")) { 27486470930SIngo Molnar *val *= 1024 * 1024 * 1024; 27586470930SIngo Molnar return 1; 27686470930SIngo Molnar } 27786470930SIngo Molnar return 0; 27886470930SIngo Molnar } 27986470930SIngo Molnar 28086470930SIngo Molnar static int perf_parse_long(const char *value, long *ret) 28186470930SIngo Molnar { 28286470930SIngo Molnar if (value && *value) { 28386470930SIngo Molnar char *end; 28486470930SIngo Molnar long val = strtol(value, &end, 0); 28586470930SIngo Molnar unsigned long factor = 1; 28686470930SIngo Molnar if (!parse_unit_factor(end, &factor)) 28786470930SIngo Molnar return 0; 28886470930SIngo Molnar *ret = val * factor; 28986470930SIngo Molnar return 1; 29086470930SIngo Molnar } 29186470930SIngo Molnar return 0; 29286470930SIngo Molnar } 29386470930SIngo Molnar 29486470930SIngo Molnar static void die_bad_config(const char *name) 29586470930SIngo Molnar { 29686470930SIngo Molnar if (config_file_name) 29786470930SIngo Molnar die("bad config value for '%s' in %s", name, config_file_name); 29886470930SIngo Molnar die("bad config value for '%s'", name); 29986470930SIngo Molnar } 30086470930SIngo Molnar 30186470930SIngo Molnar int perf_config_int(const char *name, const char *value) 30286470930SIngo Molnar { 30386470930SIngo Molnar long ret = 0; 30486470930SIngo Molnar if (!perf_parse_long(value, &ret)) 30586470930SIngo Molnar die_bad_config(name); 30686470930SIngo Molnar return ret; 30786470930SIngo Molnar } 30886470930SIngo Molnar 309*a41794cdSArnaldo Carvalho de Melo static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 31086470930SIngo Molnar { 31186470930SIngo Molnar *is_bool = 1; 31286470930SIngo Molnar if (!value) 31386470930SIngo Molnar return 1; 31486470930SIngo Molnar if (!*value) 31586470930SIngo Molnar return 0; 31686470930SIngo Molnar if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 31786470930SIngo Molnar return 1; 31886470930SIngo Molnar if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 31986470930SIngo Molnar return 0; 32086470930SIngo Molnar *is_bool = 0; 32186470930SIngo Molnar return perf_config_int(name, value); 32286470930SIngo Molnar } 32386470930SIngo Molnar 32486470930SIngo Molnar int perf_config_bool(const char *name, const char *value) 32586470930SIngo Molnar { 32686470930SIngo Molnar int discard; 32786470930SIngo Molnar return !!perf_config_bool_or_int(name, value, &discard); 32886470930SIngo Molnar } 32986470930SIngo Molnar 330f37a291cSIngo Molnar static int perf_default_core_config(const char *var __used, const char *value __used) 33186470930SIngo Molnar { 33286470930SIngo Molnar /* Add other config variables here and to Documentation/config.txt. */ 33386470930SIngo Molnar return 0; 33486470930SIngo Molnar } 33586470930SIngo Molnar 336f37a291cSIngo Molnar int perf_default_config(const char *var, const char *value, void *dummy __used) 33786470930SIngo Molnar { 33886470930SIngo Molnar if (!prefixcmp(var, "core.")) 33986470930SIngo Molnar return perf_default_core_config(var, value); 34086470930SIngo Molnar 34186470930SIngo Molnar /* Add other config variables here and to Documentation/config.txt. */ 34286470930SIngo Molnar return 0; 34386470930SIngo Molnar } 34486470930SIngo Molnar 345*a41794cdSArnaldo Carvalho de Melo static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 34686470930SIngo Molnar { 34786470930SIngo Molnar int ret; 34886470930SIngo Molnar FILE *f = fopen(filename, "r"); 34986470930SIngo Molnar 35086470930SIngo Molnar ret = -1; 35186470930SIngo Molnar if (f) { 35286470930SIngo Molnar config_file = f; 35386470930SIngo Molnar config_file_name = filename; 35486470930SIngo Molnar config_linenr = 1; 35586470930SIngo Molnar config_file_eof = 0; 35686470930SIngo Molnar ret = perf_parse_file(fn, data); 35786470930SIngo Molnar fclose(f); 35886470930SIngo Molnar config_file_name = NULL; 35986470930SIngo Molnar } 36086470930SIngo Molnar return ret; 36186470930SIngo Molnar } 36286470930SIngo Molnar 363*a41794cdSArnaldo Carvalho de Melo static const char *perf_etc_perfconfig(void) 36486470930SIngo Molnar { 36586470930SIngo Molnar static const char *system_wide; 36686470930SIngo Molnar if (!system_wide) 36786470930SIngo Molnar system_wide = system_path(ETC_PERFCONFIG); 36886470930SIngo Molnar return system_wide; 36986470930SIngo Molnar } 37086470930SIngo Molnar 37186470930SIngo Molnar static int perf_env_bool(const char *k, int def) 37286470930SIngo Molnar { 37386470930SIngo Molnar const char *v = getenv(k); 37486470930SIngo Molnar return v ? perf_config_bool(k, v) : def; 37586470930SIngo Molnar } 37686470930SIngo Molnar 377*a41794cdSArnaldo Carvalho de Melo static int perf_config_system(void) 37886470930SIngo Molnar { 37986470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 38086470930SIngo Molnar } 38186470930SIngo Molnar 382*a41794cdSArnaldo Carvalho de Melo static int perf_config_global(void) 38386470930SIngo Molnar { 38486470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 38586470930SIngo Molnar } 38686470930SIngo Molnar 38786470930SIngo Molnar int perf_config(config_fn_t fn, void *data) 38886470930SIngo Molnar { 38986470930SIngo Molnar int ret = 0, found = 0; 39086470930SIngo Molnar char *repo_config = NULL; 39186470930SIngo Molnar const char *home = NULL; 39286470930SIngo Molnar 39386470930SIngo Molnar /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 39486470930SIngo Molnar if (config_exclusive_filename) 39586470930SIngo Molnar return perf_config_from_file(fn, config_exclusive_filename, data); 39686470930SIngo Molnar if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 39786470930SIngo Molnar ret += perf_config_from_file(fn, perf_etc_perfconfig(), 39886470930SIngo Molnar data); 39986470930SIngo Molnar found += 1; 40086470930SIngo Molnar } 40186470930SIngo Molnar 40286470930SIngo Molnar home = getenv("HOME"); 40386470930SIngo Molnar if (perf_config_global() && home) { 40486470930SIngo Molnar char *user_config = strdup(mkpath("%s/.perfconfig", home)); 40586470930SIngo Molnar if (!access(user_config, R_OK)) { 40686470930SIngo Molnar ret += perf_config_from_file(fn, user_config, data); 40786470930SIngo Molnar found += 1; 40886470930SIngo Molnar } 40986470930SIngo Molnar free(user_config); 41086470930SIngo Molnar } 41186470930SIngo Molnar 41286470930SIngo Molnar repo_config = perf_pathdup("config"); 41386470930SIngo Molnar if (!access(repo_config, R_OK)) { 41486470930SIngo Molnar ret += perf_config_from_file(fn, repo_config, data); 41586470930SIngo Molnar found += 1; 41686470930SIngo Molnar } 41786470930SIngo Molnar free(repo_config); 41886470930SIngo Molnar if (found == 0) 41986470930SIngo Molnar return -1; 42086470930SIngo Molnar return ret; 42186470930SIngo Molnar } 42286470930SIngo Molnar 42386470930SIngo Molnar /* 42486470930SIngo Molnar * Call this to report error for your variable that should not 42586470930SIngo Molnar * get a boolean value (i.e. "[my] var" means "true"). 42686470930SIngo Molnar */ 42786470930SIngo Molnar int config_error_nonbool(const char *var) 42886470930SIngo Molnar { 42986470930SIngo Molnar return error("Missing value for '%s'", var); 43086470930SIngo Molnar } 431