c = '\n'; if ((f = config_file) != NULL) {
c = fgetc(f); if (c == '\r') { /* DOS like systems */
c = fgetc(f); if (c != '\n') {
ungetc(c, f);
c = '\r';
}
} if (c == '\n')
config_linenr++; if (c == EOF) {
config_file_eof = 1;
c = '\n';
}
} return c;
}
staticchar *parse_value(void)
{ staticchar value[1024]; int quote = 0, comment = 0, space = 0;
size_t len = 0;
for (;;) { int c = get_next_char();
if (len >= sizeof(value) - 1) return NULL; if (c == '\n') { if (quote) return NULL;
value[len] = 0; return value;
} if (comment) continue; if (isspace(c) && !quote) {
space = 1; continue;
} if (!quote) { if (c == ';' || c == '#') {
comment = 1; continue;
}
} if (space) { if (len)
value[len++] = ' ';
space = 0;
} if (c == '\\') {
c = get_next_char(); switch (c) { case'\n': continue; case't':
c = '\t'; break; case'b':
c = '\b'; break; case'n':
c = '\n'; break; /* Some characters escape as themselves */ case'\\': case'"': break; /* Reject unknown escape sequences */ default: return NULL;
}
value[len++] = c; continue;
} if (c == '"') {
quote = 1-quote; continue;
}
value[len++] = c;
}
}
staticinlineint iskeychar(int c)
{ return isalnum(c) || c == '-' || c == '_';
}
/* Get the full name */ for (;;) {
c = get_next_char(); if (config_file_eof) break; if (!iskeychar(c)) break;
name[len++] = c; if (len >= MAXNAME) return -1;
}
name[len] = 0; while (c == ' ' || c == '\t')
c = get_next_char();
value = NULL; if (c != '\n') { if (c != '=') return -1;
value = parse_value(); if (!value) return -1;
} return fn(name, value, data);
}
staticint get_extended_base_var(char *name, int baselen, int c)
{ do { if (c == '\n') return -1;
c = get_next_char();
} while (isspace(c));
/* We require the format to be '[base "extension"]' */ if (c != '"') return -1;
name[baselen++] = '.';
for (;;) { int ch = get_next_char();
if (ch == '\n') return -1; if (ch == '"') break; if (ch == '\\') {
ch = get_next_char(); if (ch == '\n') return -1;
}
name[baselen++] = ch; if (baselen > MAXNAME / 2) return -1;
}
/* Final ']' */ if (get_next_char() != ']') return -1; return baselen;
}
staticint get_base_var(char *name)
{ int baselen = 0;
for (;;) { int c = get_next_char(); if (config_file_eof) return -1; if (c == ']') return baselen; if (isspace(c)) return get_extended_base_var(name, baselen, c); if (!iskeychar(c) && c != '.') return -1; if (baselen > MAXNAME / 2) return -1;
name[baselen++] = tolower(c);
}
}
staticint perf_parse_file(config_fn_t fn, void *data)
{ int comment = 0; int baselen = 0; staticchar var[MAXNAME];
/* U+FEFF Byte Order Mark in UTF8 */ staticconstunsignedchar *utf8_bom = (unsignedchar *) "\xef\xbb\xbf"; constunsignedchar *bomptr = utf8_bom;
for (;;) { int line, c = get_next_char();
if (bomptr && *bomptr) { /* We are at the file beginning; skip UTF8-encoded BOM * if present. Sane editors won't put this in on their
* own, but e.g. Windows Notepad will do it happily. */ if ((unsignedchar) c == *bomptr) {
bomptr++; continue;
} else { /* Do not tolerate partial BOM. */ if (bomptr != utf8_bom) break; /* No BOM at file beginning. Cool. */
bomptr = NULL;
}
} if (c == '\n') { if (config_file_eof) return 0;
comment = 0; continue;
} if (comment || isspace(c)) continue; if (c == '#' || c == ';') {
comment = 1; continue;
} if (c == '[') {
baselen = get_base_var(var); if (baselen <= 0) break;
var[baselen++] = '.';
var[baselen] = 0; continue;
} if (!isalpha(c)) break;
var[baselen] = tolower(c);
/* * The get_value function might or might not reach the '\n', * so saving the current line number for error reporting.
*/
line = config_linenr; if (get_value(fn, data, var, baselen+1) < 0) {
config_linenr = line; break;
}
}
pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); return -1;
}
if (!parse_unit_factor(end, &factor)) return 0;
*ret = val * factor; return 1;
} return 0;
}
staticint perf_parse_long(constchar *value, long *ret)
{ if (value && *value) { char *end; long val = strtol(value, &end, 0); unsignedlong factor = 1; if (!parse_unit_factor(end, &factor)) return 0;
*ret = val * factor; return 1;
} return 0;
}
staticvoid bad_config(constchar *name)
{ if (config_file_name)
pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); else
pr_warning("bad config value for '%s', ignoring...\n", name);
}
int perf_config_u64(u64 *dest, constchar *name, constchar *value)
{ longlong ret = 0;
if (!perf_parse_llong(value, &ret)) {
bad_config(name); return -1;
}
*dest = ret; return 0;
}
int perf_config_int(int *dest, constchar *name, constchar *value)
{ long ret = 0; if (!perf_parse_long(value, &ret)) {
bad_config(name); return -1;
}
*dest = ret; return 0;
}
int perf_config_u8(u8 *dest, constchar *name, constchar *value)
{ long ret = 0;
staticint perf_buildid_config(constchar *var, constchar *value)
{ /* same dir for all commands */ if (!strcmp(var, "buildid.dir")) { constchar *dir = perf_config_dirname(var, value);
/* * Skip reading user config if: * - there is no place to read it from (HOME) * - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
*/ if (!home || !*home || !perf_config_global()) return NULL;
config = strdup(mkpath(path, sizeof(path), "%s/.perfconfig", home)); if (config == NULL) {
pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.\n", home); return NULL;
}
if (stat(config, &st) < 0) goto out_free;
if (st.st_uid && (st.st_uid != geteuid())) {
pr_warning("File %s not owned by current user or root, ignoring it.\n", config); goto out_free;
}
section_name = strsep(&ptr, ".");
name = ptr; if (name == NULL || value == NULL) goto out_free;
section = find_section(sections, section_name); if (!section) {
section = add_section(sections, section_name); if (!section) goto out_free;
}
item = find_config_item(name, section); if (!item) {
item = add_config_item(section, name); if (!item) goto out_free;
}
/* perf_config_set can contain both user and system config items. * So we should know where each value is from. * The classification would be needed when a particular config file * is overwritten by setting feature i.e. set_config().
*/ if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
section->from_system_config = true;
item->from_system_config = true;
} else {
section->from_system_config = false;
item->from_system_config = false;
}
if (value) {
scnprintf(key, sizeof(key), "%s.%s",
section->name, item->name);
ret = fn(key, value, data); if (ret < 0) {
pr_err("Error in the given config file: wrong config key-value pair %s=%s\n",
key, value); /* * Can't be just a 'break', as perf_config_set__for_each_entry() * expands to two nested for() loops.
*/ goto out;
}
}
}
out: return ret;
}
int perf_config(config_fn_t fn, void *data)
{ if (config_set == NULL && perf_config__init()) return -1;
void perf_config_set__delete(struct perf_config_set *set)
{ if (set == NULL) return;
perf_config_set__purge(set);
free(set);
}
/* * Call this to report error for your variable that should not * get a boolean value (i.e. "[my] var" means "true").
*/ int config_error_nonbool(constchar *var)
{
pr_err("Missing value for '%s'", var); return -1;
}
void set_buildid_dir(constchar *dir)
{ if (dir)
scnprintf(buildid_dir, MAXPATHLEN, "%s", dir);
/* default to $HOME/.debug */ if (buildid_dir[0] == '\0') { char *home = getenv("HOME");
if (home) {
snprintf(buildid_dir, MAXPATHLEN, "%s/%s",
home, DEBUG_CACHE_DIR);
} else {
strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
}
buildid_dir[MAXPATHLEN-1] = '\0';
} /* for communicating with external commands */
setenv("PERF_BUILDID_DIR", buildid_dir, 1);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.