Merge branch 'fix' of git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6
[pandora-kernel.git] / tools / perf / util / config.c
1 /*
2  * GIT - The information manager from hell
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  * Copyright (C) Johannes Schindelin, 2005
6  *
7  */
8 #include "util.h"
9 #include "cache.h"
10 #include "exec_cmd.h"
11
12 #define MAXNAME (256)
13
14 static FILE *config_file;
15 static const char *config_file_name;
16 static int config_linenr;
17 static int config_file_eof;
18
19 static const char *config_exclusive_filename;
20
21 static int get_next_char(void)
22 {
23         int c;
24         FILE *f;
25
26         c = '\n';
27         if ((f = config_file) != NULL) {
28                 c = fgetc(f);
29                 if (c == '\r') {
30                         /* DOS like systems */
31                         c = fgetc(f);
32                         if (c != '\n') {
33                                 ungetc(c, f);
34                                 c = '\r';
35                         }
36                 }
37                 if (c == '\n')
38                         config_linenr++;
39                 if (c == EOF) {
40                         config_file_eof = 1;
41                         c = '\n';
42                 }
43         }
44         return c;
45 }
46
47 static char *parse_value(void)
48 {
49         static char value[1024];
50         int quote = 0, comment = 0, space = 0;
51         size_t len = 0;
52
53         for (;;) {
54                 int c = get_next_char();
55
56                 if (len >= sizeof(value) - 1)
57                         return NULL;
58                 if (c == '\n') {
59                         if (quote)
60                                 return NULL;
61                         value[len] = 0;
62                         return value;
63                 }
64                 if (comment)
65                         continue;
66                 if (isspace(c) && !quote) {
67                         space = 1;
68                         continue;
69                 }
70                 if (!quote) {
71                         if (c == ';' || c == '#') {
72                                 comment = 1;
73                                 continue;
74                         }
75                 }
76                 if (space) {
77                         if (len)
78                                 value[len++] = ' ';
79                         space = 0;
80                 }
81                 if (c == '\\') {
82                         c = get_next_char();
83                         switch (c) {
84                         case '\n':
85                                 continue;
86                         case 't':
87                                 c = '\t';
88                                 break;
89                         case 'b':
90                                 c = '\b';
91                                 break;
92                         case 'n':
93                                 c = '\n';
94                                 break;
95                         /* Some characters escape as themselves */
96                         case '\\': case '"':
97                                 break;
98                         /* Reject unknown escape sequences */
99                         default:
100                                 return NULL;
101                         }
102                         value[len++] = c;
103                         continue;
104                 }
105                 if (c == '"') {
106                         quote = 1-quote;
107                         continue;
108                 }
109                 value[len++] = c;
110         }
111 }
112
113 static inline int iskeychar(int c)
114 {
115         return isalnum(c) || c == '-';
116 }
117
118 static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
119 {
120         int c;
121         char *value;
122
123         /* Get the full name */
124         for (;;) {
125                 c = get_next_char();
126                 if (config_file_eof)
127                         break;
128                 if (!iskeychar(c))
129                         break;
130                 name[len++] = tolower(c);
131                 if (len >= MAXNAME)
132                         return -1;
133         }
134         name[len] = 0;
135         while (c == ' ' || c == '\t')
136                 c = get_next_char();
137
138         value = NULL;
139         if (c != '\n') {
140                 if (c != '=')
141                         return -1;
142                 value = parse_value();
143                 if (!value)
144                         return -1;
145         }
146         return fn(name, value, data);
147 }
148
149 static int get_extended_base_var(char *name, int baselen, int c)
150 {
151         do {
152                 if (c == '\n')
153                         return -1;
154                 c = get_next_char();
155         } while (isspace(c));
156
157         /* We require the format to be '[base "extension"]' */
158         if (c != '"')
159                 return -1;
160         name[baselen++] = '.';
161
162         for (;;) {
163                 int ch = get_next_char();
164
165                 if (ch == '\n')
166                         return -1;
167                 if (ch == '"')
168                         break;
169                 if (ch == '\\') {
170                         ch = get_next_char();
171                         if (ch == '\n')
172                                 return -1;
173                 }
174                 name[baselen++] = ch;
175                 if (baselen > MAXNAME / 2)
176                         return -1;
177         }
178
179         /* Final ']' */
180         if (get_next_char() != ']')
181                 return -1;
182         return baselen;
183 }
184
185 static int get_base_var(char *name)
186 {
187         int baselen = 0;
188
189         for (;;) {
190                 int c = get_next_char();
191                 if (config_file_eof)
192                         return -1;
193                 if (c == ']')
194                         return baselen;
195                 if (isspace(c))
196                         return get_extended_base_var(name, baselen, c);
197                 if (!iskeychar(c) && c != '.')
198                         return -1;
199                 if (baselen > MAXNAME / 2)
200                         return -1;
201                 name[baselen++] = tolower(c);
202         }
203 }
204
205 static int perf_parse_file(config_fn_t fn, void *data)
206 {
207         int comment = 0;
208         int baselen = 0;
209         static char var[MAXNAME];
210
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;
214
215         for (;;) {
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) {
222                                 bomptr++;
223                                 continue;
224                         } else {
225                                 /* Do not tolerate partial BOM. */
226                                 if (bomptr != utf8_bom)
227                                         break;
228                                 /* No BOM at file beginning. Cool. */
229                                 bomptr = NULL;
230                         }
231                 }
232                 if (c == '\n') {
233                         if (config_file_eof)
234                                 return 0;
235                         comment = 0;
236                         continue;
237                 }
238                 if (comment || isspace(c))
239                         continue;
240                 if (c == '#' || c == ';') {
241                         comment = 1;
242                         continue;
243                 }
244                 if (c == '[') {
245                         baselen = get_base_var(var);
246                         if (baselen <= 0)
247                                 break;
248                         var[baselen++] = '.';
249                         var[baselen] = 0;
250                         continue;
251                 }
252                 if (!isalpha(c))
253                         break;
254                 var[baselen] = tolower(c);
255                 if (get_value(fn, data, var, baselen+1) < 0)
256                         break;
257         }
258         die("bad config file line %d in %s", config_linenr, config_file_name);
259 }
260
261 static int parse_unit_factor(const char *end, unsigned long *val)
262 {
263         if (!*end)
264                 return 1;
265         else if (!strcasecmp(end, "k")) {
266                 *val *= 1024;
267                 return 1;
268         }
269         else if (!strcasecmp(end, "m")) {
270                 *val *= 1024 * 1024;
271                 return 1;
272         }
273         else if (!strcasecmp(end, "g")) {
274                 *val *= 1024 * 1024 * 1024;
275                 return 1;
276         }
277         return 0;
278 }
279
280 static int perf_parse_long(const char *value, long *ret)
281 {
282         if (value && *value) {
283                 char *end;
284                 long val = strtol(value, &end, 0);
285                 unsigned long factor = 1;
286                 if (!parse_unit_factor(end, &factor))
287                         return 0;
288                 *ret = val * factor;
289                 return 1;
290         }
291         return 0;
292 }
293
294 static void die_bad_config(const char *name)
295 {
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);
299 }
300
301 int perf_config_int(const char *name, const char *value)
302 {
303         long ret = 0;
304         if (!perf_parse_long(value, &ret))
305                 die_bad_config(name);
306         return ret;
307 }
308
309 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
310 {
311         *is_bool = 1;
312         if (!value)
313                 return 1;
314         if (!*value)
315                 return 0;
316         if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
317                 return 1;
318         if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
319                 return 0;
320         *is_bool = 0;
321         return perf_config_int(name, value);
322 }
323
324 int perf_config_bool(const char *name, const char *value)
325 {
326         int discard;
327         return !!perf_config_bool_or_int(name, value, &discard);
328 }
329
330 static int perf_default_core_config(const char *var __used, const char *value __used)
331 {
332         /* Add other config variables here and to Documentation/config.txt. */
333         return 0;
334 }
335
336 int perf_default_config(const char *var, const char *value, void *dummy __used)
337 {
338         if (!prefixcmp(var, "core."))
339                 return perf_default_core_config(var, value);
340
341         /* Add other config variables here and to Documentation/config.txt. */
342         return 0;
343 }
344
345 static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
346 {
347         int ret;
348         FILE *f = fopen(filename, "r");
349
350         ret = -1;
351         if (f) {
352                 config_file = f;
353                 config_file_name = filename;
354                 config_linenr = 1;
355                 config_file_eof = 0;
356                 ret = perf_parse_file(fn, data);
357                 fclose(f);
358                 config_file_name = NULL;
359         }
360         return ret;
361 }
362
363 static const char *perf_etc_perfconfig(void)
364 {
365         static const char *system_wide;
366         if (!system_wide)
367                 system_wide = system_path(ETC_PERFCONFIG);
368         return system_wide;
369 }
370
371 static int perf_env_bool(const char *k, int def)
372 {
373         const char *v = getenv(k);
374         return v ? perf_config_bool(k, v) : def;
375 }
376
377 static int perf_config_system(void)
378 {
379         return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
380 }
381
382 static int perf_config_global(void)
383 {
384         return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
385 }
386
387 int perf_config(config_fn_t fn, void *data)
388 {
389         int ret = 0, found = 0;
390         char *repo_config = NULL;
391         const char *home = NULL;
392
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(),
398                                             data);
399                 found += 1;
400         }
401
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);
407                         found += 1;
408                 }
409                 free(user_config);
410         }
411
412         repo_config = perf_pathdup("config");
413         if (!access(repo_config, R_OK)) {
414                 ret += perf_config_from_file(fn, repo_config, data);
415                 found += 1;
416         }
417         free(repo_config);
418         if (found == 0)
419                 return -1;
420         return ret;
421 }
422
423 /*
424  * Call this to report error for your variable that should not
425  * get a boolean value (i.e. "[my] var" means "true").
426  */
427 int config_error_nonbool(const char *var)
428 {
429         return error("Missing value for '%s'", var);
430 }