OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||
3 | * Released under the terms of the GNU GPL v2.0. |
||
4 | */ |
||
5 | |||
6 | #include <sys/stat.h> |
||
7 | #include <ctype.h> |
||
8 | #include <errno.h> |
||
9 | #include <fcntl.h> |
||
10 | #include <stdarg.h> |
||
11 | #include <stdio.h> |
||
12 | #include <stdlib.h> |
||
13 | #include <string.h> |
||
14 | #include <time.h> |
||
15 | #include <unistd.h> |
||
16 | |||
17 | #include "lkc.h" |
||
18 | |||
19 | struct conf_printer { |
||
20 | void (*print_symbol)(FILE *, struct symbol *, const char *, void *); |
||
21 | void (*print_comment)(FILE *, const char *, void *); |
||
22 | }; |
||
23 | |||
24 | static void conf_warning(const char *fmt, ...) |
||
25 | __attribute__ ((format (printf, 1, 2))); |
||
26 | |||
27 | static void conf_message(const char *fmt, ...) |
||
28 | __attribute__ ((format (printf, 1, 2))); |
||
29 | |||
30 | static const char *conf_filename; |
||
31 | static int conf_lineno, conf_warnings, conf_unsaved; |
||
32 | |||
33 | const char conf_defname[] = "arch/$ARCH/defconfig"; |
||
34 | |||
35 | static void conf_warning(const char *fmt, ...) |
||
36 | { |
||
37 | va_list ap; |
||
38 | va_start(ap, fmt); |
||
39 | fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); |
||
40 | vfprintf(stderr, fmt, ap); |
||
41 | fprintf(stderr, "\n"); |
||
42 | va_end(ap); |
||
43 | conf_warnings++; |
||
44 | } |
||
45 | |||
46 | static void conf_default_message_callback(const char *fmt, va_list ap) |
||
47 | { |
||
48 | printf("#\n# "); |
||
49 | vprintf(fmt, ap); |
||
50 | printf("\n#\n"); |
||
51 | } |
||
52 | |||
53 | static void (*conf_message_callback) (const char *fmt, va_list ap) = |
||
54 | conf_default_message_callback; |
||
55 | void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) |
||
56 | { |
||
57 | conf_message_callback = fn; |
||
58 | } |
||
59 | |||
60 | static void conf_message(const char *fmt, ...) |
||
61 | { |
||
62 | va_list ap; |
||
63 | |||
64 | va_start(ap, fmt); |
||
65 | if (conf_message_callback) |
||
66 | conf_message_callback(fmt, ap); |
||
67 | va_end(ap); |
||
68 | } |
||
69 | |||
70 | const char *conf_get_configname(void) |
||
71 | { |
||
72 | char *name = getenv("KCONFIG_CONFIG"); |
||
73 | |||
74 | return name ? name : ".config"; |
||
75 | } |
||
76 | |||
77 | const char *conf_get_autoconfig_name(void) |
||
78 | { |
||
79 | char *name = getenv("KCONFIG_AUTOCONFIG"); |
||
80 | |||
81 | return name ? name : "include/config/auto.conf"; |
||
82 | } |
||
83 | |||
84 | static char *conf_expand_value(const char *in) |
||
85 | { |
||
86 | struct symbol *sym; |
||
87 | const char *src; |
||
88 | static char res_value[SYMBOL_MAXLENGTH]; |
||
89 | char *dst, name[SYMBOL_MAXLENGTH]; |
||
90 | |||
91 | res_value[0] = 0; |
||
92 | dst = name; |
||
93 | while ((src = strchr(in, '$'))) { |
||
94 | strncat(res_value, in, src - in); |
||
95 | src++; |
||
96 | dst = name; |
||
97 | while (isalnum(*src) || *src == '_') |
||
98 | *dst++ = *src++; |
||
99 | *dst = 0; |
||
100 | sym = sym_lookup(name, 0); |
||
101 | sym_calc_value(sym); |
||
102 | strcat(res_value, sym_get_string_value(sym)); |
||
103 | in = src; |
||
104 | } |
||
105 | strcat(res_value, in); |
||
106 | |||
107 | return res_value; |
||
108 | } |
||
109 | |||
110 | char *conf_get_default_confname(void) |
||
111 | { |
||
112 | struct stat buf; |
||
113 | static char fullname[PATH_MAX+1]; |
||
114 | char *env, *name; |
||
115 | |||
116 | name = conf_expand_value(conf_defname); |
||
117 | env = getenv(SRCTREE); |
||
118 | if (env) { |
||
119 | sprintf(fullname, "%s/%s", env, name); |
||
120 | if (!stat(fullname, &buf)) |
||
121 | return fullname; |
||
122 | } |
||
123 | return name; |
||
124 | } |
||
125 | |||
126 | static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) |
||
127 | { |
||
128 | char *p2; |
||
129 | |||
130 | switch (sym->type) { |
||
131 | case S_TRISTATE: |
||
132 | if (p[0] == 'm') { |
||
133 | sym->def[def].tri = mod; |
||
134 | sym->flags |= def_flags; |
||
135 | break; |
||
136 | } |
||
137 | /* fall through */ |
||
138 | case S_BOOLEAN: |
||
139 | if (p[0] == 'y') { |
||
140 | sym->def[def].tri = yes; |
||
141 | sym->flags |= def_flags; |
||
142 | break; |
||
143 | } |
||
144 | if (p[0] == 'n') { |
||
145 | sym->def[def].tri = no; |
||
146 | sym->flags |= def_flags; |
||
147 | break; |
||
148 | } |
||
149 | if (def != S_DEF_AUTO) |
||
150 | conf_warning("symbol value '%s' invalid for %s", |
||
151 | p, sym->name); |
||
152 | return 1; |
||
153 | case S_OTHER: |
||
154 | if (*p != '"') { |
||
155 | for (p2 = p; *p2 && !isspace(*p2); p2++) |
||
156 | ; |
||
157 | sym->type = S_STRING; |
||
158 | goto done; |
||
159 | } |
||
160 | /* fall through */ |
||
161 | case S_STRING: |
||
162 | if (*p++ != '"') |
||
163 | break; |
||
164 | for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { |
||
165 | if (*p2 == '"') { |
||
166 | *p2 = 0; |
||
167 | break; |
||
168 | } |
||
169 | memmove(p2, p2 + 1, strlen(p2)); |
||
170 | } |
||
171 | if (!p2) { |
||
172 | if (def != S_DEF_AUTO) |
||
173 | conf_warning("invalid string found"); |
||
174 | return 1; |
||
175 | } |
||
176 | /* fall through */ |
||
177 | case S_INT: |
||
178 | case S_HEX: |
||
179 | done: |
||
180 | if (sym_string_valid(sym, p)) { |
||
181 | sym->def[def].val = strdup(p); |
||
182 | sym->flags |= def_flags; |
||
183 | } else { |
||
184 | if (def != S_DEF_AUTO) |
||
185 | conf_warning("symbol value '%s' invalid for %s", |
||
186 | p, sym->name); |
||
187 | return 1; |
||
188 | } |
||
189 | break; |
||
190 | default: |
||
191 | ; |
||
192 | } |
||
193 | return 0; |
||
194 | } |
||
195 | |||
196 | #define LINE_GROWTH 16 |
||
197 | static int add_byte(int c, char **lineptr, size_t slen, size_t *n) |
||
198 | { |
||
199 | char *nline; |
||
200 | size_t new_size = slen + 1; |
||
201 | if (new_size > *n) { |
||
202 | new_size += LINE_GROWTH - 1; |
||
203 | new_size *= 2; |
||
204 | nline = realloc(*lineptr, new_size); |
||
205 | if (!nline) |
||
206 | return -1; |
||
207 | |||
208 | *lineptr = nline; |
||
209 | *n = new_size; |
||
210 | } |
||
211 | |||
212 | (*lineptr)[slen] = c; |
||
213 | |||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) |
||
218 | { |
||
219 | char *line = *lineptr; |
||
220 | size_t slen = 0; |
||
221 | |||
222 | for (;;) { |
||
223 | int c = getc(stream); |
||
224 | |||
225 | switch (c) { |
||
226 | case '\n': |
||
227 | if (add_byte(c, &line, slen, n) < 0) |
||
228 | goto e_out; |
||
229 | slen++; |
||
230 | /* fall through */ |
||
231 | case EOF: |
||
232 | if (add_byte('\0', &line, slen, n) < 0) |
||
233 | goto e_out; |
||
234 | *lineptr = line; |
||
235 | if (slen == 0) |
||
236 | return -1; |
||
237 | return slen; |
||
238 | default: |
||
239 | if (add_byte(c, &line, slen, n) < 0) |
||
240 | goto e_out; |
||
241 | slen++; |
||
242 | } |
||
243 | } |
||
244 | |||
245 | e_out: |
||
246 | line[slen-1] = '\0'; |
||
247 | *lineptr = line; |
||
248 | return -1; |
||
249 | } |
||
250 | |||
251 | void conf_reset(int def) |
||
252 | { |
||
253 | struct symbol *sym; |
||
254 | int i, def_flags; |
||
255 | |||
256 | def_flags = SYMBOL_DEF << def; |
||
257 | for_all_symbols(i, sym) { |
||
258 | sym->flags |= SYMBOL_CHANGED; |
||
259 | sym->flags &= ~(def_flags|SYMBOL_VALID); |
||
260 | if (sym_is_choice(sym)) |
||
261 | sym->flags |= def_flags; |
||
262 | switch (sym->type) { |
||
263 | case S_INT: |
||
264 | case S_HEX: |
||
265 | case S_STRING: |
||
266 | if (sym->def[def].val) |
||
267 | free(sym->def[def].val); |
||
268 | /* fall through */ |
||
269 | default: |
||
270 | sym->def[def].val = NULL; |
||
271 | sym->def[def].tri = no; |
||
272 | } |
||
273 | } |
||
274 | } |
||
275 | |||
276 | int conf_read_simple(const char *name, int def) |
||
277 | { |
||
278 | FILE *in = NULL; |
||
279 | char *line = NULL; |
||
280 | size_t line_asize = 0; |
||
281 | char *p, *p2; |
||
282 | struct symbol *sym; |
||
283 | int def_flags; |
||
284 | |||
285 | if (name) { |
||
286 | in = zconf_fopen(name); |
||
287 | } else { |
||
288 | struct property *prop; |
||
289 | |||
290 | name = conf_get_configname(); |
||
291 | in = zconf_fopen(name); |
||
292 | if (in) |
||
293 | goto load; |
||
294 | sym_add_change_count(1); |
||
295 | if (!sym_defconfig_list) |
||
296 | return 1; |
||
297 | |||
298 | for_all_defaults(sym_defconfig_list, prop) { |
||
299 | if (expr_calc_value(prop->visible.expr) == no || |
||
300 | prop->expr->type != E_SYMBOL) |
||
301 | continue; |
||
302 | name = conf_expand_value(prop->expr->left.sym->name); |
||
303 | in = zconf_fopen(name); |
||
304 | if (in) { |
||
305 | conf_message(_("using defaults found in %s"), |
||
306 | name); |
||
307 | goto load; |
||
308 | } |
||
309 | } |
||
310 | } |
||
311 | if (!in) |
||
312 | return 1; |
||
313 | |||
314 | load: |
||
315 | conf_filename = name; |
||
316 | conf_lineno = 0; |
||
317 | conf_warnings = 0; |
||
318 | conf_unsaved = 0; |
||
319 | |||
320 | def_flags = SYMBOL_DEF << def; |
||
321 | conf_reset(def); |
||
322 | |||
323 | while (compat_getline(&line, &line_asize, in) != -1) { |
||
324 | conf_lineno++; |
||
325 | sym = NULL; |
||
326 | if (line[0] == '#') { |
||
327 | if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) |
||
328 | continue; |
||
329 | p = strchr(line + 2 + strlen(CONFIG_), ' '); |
||
330 | if (!p) |
||
331 | continue; |
||
332 | *p++ = 0; |
||
333 | if (strncmp(p, "is not set", 10)) |
||
334 | continue; |
||
335 | if (def == S_DEF_USER) { |
||
336 | sym = sym_find(line + 2 + strlen(CONFIG_)); |
||
337 | if (!sym) { |
||
338 | sym_add_change_count(1); |
||
339 | goto setsym; |
||
340 | } |
||
341 | } else { |
||
342 | sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); |
||
343 | if (sym->type == S_UNKNOWN) |
||
344 | sym->type = S_BOOLEAN; |
||
345 | } |
||
346 | switch (sym->type) { |
||
347 | case S_BOOLEAN: |
||
348 | case S_TRISTATE: |
||
349 | sym->def[def].tri = no; |
||
350 | sym->flags |= def_flags; |
||
351 | break; |
||
352 | default: |
||
353 | ; |
||
354 | } |
||
355 | } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { |
||
356 | p = strchr(line + strlen(CONFIG_), '='); |
||
357 | if (!p) |
||
358 | continue; |
||
359 | *p++ = 0; |
||
360 | p2 = strchr(p, '\n'); |
||
361 | if (p2) { |
||
362 | *p2-- = 0; |
||
363 | if (*p2 == '\r') |
||
364 | *p2 = 0; |
||
365 | } |
||
366 | if (def == S_DEF_USER) { |
||
367 | sym = sym_find(line + strlen(CONFIG_)); |
||
368 | if (!sym) { |
||
369 | sym_add_change_count(1); |
||
370 | goto setsym; |
||
371 | } |
||
372 | } else { |
||
373 | sym = sym_lookup(line + strlen(CONFIG_), 0); |
||
374 | if (sym->type == S_UNKNOWN) |
||
375 | sym->type = S_OTHER; |
||
376 | } |
||
377 | if (conf_set_sym_val(sym, def, def_flags, p)) |
||
378 | continue; |
||
379 | } else { |
||
380 | if (line[0] != '\r' && line[0] != '\n') |
||
381 | conf_warning("unexpected data: %.*s", |
||
382 | (int)strcspn(line, "\r\n"), line); |
||
383 | |||
384 | continue; |
||
385 | } |
||
386 | setsym: |
||
387 | if (sym && sym_is_choice_value(sym)) { |
||
388 | struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); |
||
389 | switch (sym->def[def].tri) { |
||
390 | case no: |
||
391 | break; |
||
392 | case mod: |
||
393 | if (cs->def[def].tri == yes) { |
||
394 | conf_warning("%s creates inconsistent choice state", sym->name); |
||
395 | cs->flags &= ~def_flags; |
||
396 | } |
||
397 | break; |
||
398 | case yes: |
||
399 | if (cs->def[def].tri != no) |
||
400 | conf_warning("override: %s changes choice state", sym->name); |
||
401 | cs->def[def].val = sym; |
||
402 | break; |
||
403 | } |
||
404 | cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); |
||
405 | } |
||
406 | } |
||
407 | free(line); |
||
408 | fclose(in); |
||
409 | return 0; |
||
410 | } |
||
411 | |||
412 | int conf_read(const char *name) |
||
413 | { |
||
414 | struct symbol *sym; |
||
415 | int i; |
||
416 | |||
417 | sym_set_change_count(0); |
||
418 | |||
419 | if (conf_read_simple(name, S_DEF_USER)) { |
||
420 | sym_calc_value(modules_sym); |
||
421 | return 1; |
||
422 | } |
||
423 | |||
424 | sym_calc_value(modules_sym); |
||
425 | |||
426 | for_all_symbols(i, sym) { |
||
427 | sym_calc_value(sym); |
||
428 | if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) |
||
429 | continue; |
||
430 | if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { |
||
431 | /* check that calculated value agrees with saved value */ |
||
432 | switch (sym->type) { |
||
433 | case S_BOOLEAN: |
||
434 | case S_TRISTATE: |
||
435 | if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) |
||
436 | break; |
||
437 | if (!sym_is_choice(sym)) |
||
438 | continue; |
||
439 | /* fall through */ |
||
440 | default: |
||
441 | if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) |
||
442 | continue; |
||
443 | break; |
||
444 | } |
||
445 | } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) |
||
446 | /* no previous value and not saved */ |
||
447 | continue; |
||
448 | conf_unsaved++; |
||
449 | /* maybe print value in verbose mode... */ |
||
450 | } |
||
451 | |||
452 | for_all_symbols(i, sym) { |
||
453 | if (sym_has_value(sym) && !sym_is_choice_value(sym)) { |
||
454 | /* Reset values of generates values, so they'll appear |
||
455 | * as new, if they should become visible, but that |
||
456 | * doesn't quite work if the Kconfig and the saved |
||
457 | * configuration disagree. |
||
458 | */ |
||
459 | if (sym->visible == no && !conf_unsaved) |
||
460 | sym->flags &= ~SYMBOL_DEF_USER; |
||
461 | switch (sym->type) { |
||
462 | case S_STRING: |
||
463 | case S_INT: |
||
464 | case S_HEX: |
||
465 | /* Reset a string value if it's out of range */ |
||
466 | if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) |
||
467 | break; |
||
468 | sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); |
||
469 | conf_unsaved++; |
||
470 | break; |
||
471 | default: |
||
472 | break; |
||
473 | } |
||
474 | } |
||
475 | } |
||
476 | |||
477 | sym_add_change_count(conf_warnings || conf_unsaved); |
||
478 | |||
479 | return 0; |
||
480 | } |
||
481 | |||
482 | /* |
||
483 | * Kconfig configuration printer |
||
484 | * |
||
485 | * This printer is used when generating the resulting configuration after |
||
486 | * kconfig invocation and `defconfig' files. Unset symbol might be omitted by |
||
487 | * passing a non-NULL argument to the printer. |
||
488 | * |
||
489 | */ |
||
490 | static void |
||
491 | kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) |
||
492 | { |
||
493 | |||
494 | switch (sym->type) { |
||
495 | case S_BOOLEAN: |
||
496 | case S_TRISTATE: |
||
497 | if (*value == 'n') { |
||
498 | bool skip_unset = (arg != NULL); |
||
499 | |||
500 | if (!skip_unset) |
||
501 | fprintf(fp, "# %s%s is not set\n", |
||
502 | CONFIG_, sym->name); |
||
503 | return; |
||
504 | } |
||
505 | break; |
||
506 | default: |
||
507 | break; |
||
508 | } |
||
509 | |||
510 | fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); |
||
511 | } |
||
512 | |||
513 | static void |
||
514 | kconfig_print_comment(FILE *fp, const char *value, void *arg) |
||
515 | { |
||
516 | const char *p = value; |
||
517 | size_t l; |
||
518 | |||
519 | for (;;) { |
||
520 | l = strcspn(p, "\n"); |
||
521 | fprintf(fp, "#"); |
||
522 | if (l) { |
||
523 | fprintf(fp, " "); |
||
524 | xfwrite(p, l, 1, fp); |
||
525 | p += l; |
||
526 | } |
||
527 | fprintf(fp, "\n"); |
||
528 | if (*p++ == '\0') |
||
529 | break; |
||
530 | } |
||
531 | } |
||
532 | |||
533 | static struct conf_printer kconfig_printer_cb = |
||
534 | { |
||
535 | .print_symbol = kconfig_print_symbol, |
||
536 | .print_comment = kconfig_print_comment, |
||
537 | }; |
||
538 | |||
539 | /* |
||
540 | * Header printer |
||
541 | * |
||
542 | * This printer is used when generating the `include/generated/autoconf.h' file. |
||
543 | */ |
||
544 | static void |
||
545 | header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) |
||
546 | { |
||
547 | |||
548 | switch (sym->type) { |
||
549 | case S_BOOLEAN: |
||
550 | case S_TRISTATE: { |
||
551 | const char *suffix = ""; |
||
552 | |||
553 | switch (*value) { |
||
554 | case 'n': |
||
555 | break; |
||
556 | case 'm': |
||
557 | suffix = "_MODULE"; |
||
558 | /* fall through */ |
||
559 | default: |
||
560 | fprintf(fp, "#define %s%s%s 1\n", |
||
561 | CONFIG_, sym->name, suffix); |
||
562 | } |
||
563 | break; |
||
564 | } |
||
565 | case S_HEX: { |
||
566 | const char *prefix = ""; |
||
567 | |||
568 | if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) |
||
569 | prefix = "0x"; |
||
570 | fprintf(fp, "#define %s%s %s%s\n", |
||
571 | CONFIG_, sym->name, prefix, value); |
||
572 | break; |
||
573 | } |
||
574 | case S_STRING: |
||
575 | case S_INT: |
||
576 | fprintf(fp, "#define %s%s %s\n", |
||
577 | CONFIG_, sym->name, value); |
||
578 | break; |
||
579 | default: |
||
580 | break; |
||
581 | } |
||
582 | |||
583 | } |
||
584 | |||
585 | static void |
||
586 | header_print_comment(FILE *fp, const char *value, void *arg) |
||
587 | { |
||
588 | const char *p = value; |
||
589 | size_t l; |
||
590 | |||
591 | fprintf(fp, "/*\n"); |
||
592 | for (;;) { |
||
593 | l = strcspn(p, "\n"); |
||
594 | fprintf(fp, " *"); |
||
595 | if (l) { |
||
596 | fprintf(fp, " "); |
||
597 | xfwrite(p, l, 1, fp); |
||
598 | p += l; |
||
599 | } |
||
600 | fprintf(fp, "\n"); |
||
601 | if (*p++ == '\0') |
||
602 | break; |
||
603 | } |
||
604 | fprintf(fp, " */\n"); |
||
605 | } |
||
606 | |||
607 | static struct conf_printer header_printer_cb = |
||
608 | { |
||
609 | .print_symbol = header_print_symbol, |
||
610 | .print_comment = header_print_comment, |
||
611 | }; |
||
612 | |||
613 | /* |
||
614 | * Tristate printer |
||
615 | * |
||
616 | * This printer is used when generating the `include/config/tristate.conf' file. |
||
617 | */ |
||
618 | static void |
||
619 | tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) |
||
620 | { |
||
621 | |||
622 | if (sym->type == S_TRISTATE && *value != 'n') |
||
623 | fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); |
||
624 | } |
||
625 | |||
626 | static struct conf_printer tristate_printer_cb = |
||
627 | { |
||
628 | .print_symbol = tristate_print_symbol, |
||
629 | .print_comment = kconfig_print_comment, |
||
630 | }; |
||
631 | |||
632 | static void conf_write_symbol(FILE *fp, struct symbol *sym, |
||
633 | struct conf_printer *printer, void *printer_arg) |
||
634 | { |
||
635 | const char *str; |
||
636 | |||
637 | switch (sym->type) { |
||
638 | case S_OTHER: |
||
639 | case S_UNKNOWN: |
||
640 | break; |
||
641 | case S_STRING: |
||
642 | str = sym_get_string_value(sym); |
||
643 | str = sym_escape_string_value(str); |
||
644 | printer->print_symbol(fp, sym, str, printer_arg); |
||
645 | free((void *)str); |
||
646 | break; |
||
647 | default: |
||
648 | str = sym_get_string_value(sym); |
||
649 | printer->print_symbol(fp, sym, str, printer_arg); |
||
650 | } |
||
651 | } |
||
652 | |||
653 | static void |
||
654 | conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) |
||
655 | { |
||
656 | char buf[256]; |
||
657 | |||
658 | snprintf(buf, sizeof(buf), |
||
659 | "\n" |
||
660 | "Automatically generated file; DO NOT EDIT.\n" |
||
661 | "%s\n", |
||
662 | rootmenu.prompt->text); |
||
663 | |||
664 | printer->print_comment(fp, buf, printer_arg); |
||
665 | } |
||
666 | |||
667 | /* |
||
668 | * Write out a minimal config. |
||
669 | * All values that has default values are skipped as this is redundant. |
||
670 | */ |
||
671 | int conf_write_defconfig(const char *filename) |
||
672 | { |
||
673 | struct symbol *sym; |
||
674 | struct menu *menu; |
||
675 | FILE *out; |
||
676 | |||
677 | out = fopen(filename, "w"); |
||
678 | if (!out) |
||
679 | return 1; |
||
680 | |||
681 | sym_clear_all_valid(); |
||
682 | |||
683 | /* Traverse all menus to find all relevant symbols */ |
||
684 | menu = rootmenu.list; |
||
685 | |||
686 | while (menu != NULL) |
||
687 | { |
||
688 | sym = menu->sym; |
||
689 | if (sym == NULL) { |
||
690 | if (!menu_is_visible(menu)) |
||
691 | goto next_menu; |
||
692 | } else if (!sym_is_choice(sym)) { |
||
693 | sym_calc_value(sym); |
||
694 | if (!(sym->flags & SYMBOL_WRITE)) |
||
695 | goto next_menu; |
||
696 | sym->flags &= ~SYMBOL_WRITE; |
||
697 | /* If we cannot change the symbol - skip */ |
||
698 | if (!sym_is_changable(sym)) |
||
699 | goto next_menu; |
||
700 | /* If symbol equals to default value - skip */ |
||
701 | if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) |
||
702 | goto next_menu; |
||
703 | |||
704 | /* |
||
705 | * If symbol is a choice value and equals to the |
||
706 | * default for a choice - skip. |
||
707 | * But only if value is bool and equal to "y" and |
||
708 | * choice is not "optional". |
||
709 | * (If choice is "optional" then all values can be "n") |
||
710 | */ |
||
711 | if (sym_is_choice_value(sym)) { |
||
712 | struct symbol *cs; |
||
713 | struct symbol *ds; |
||
714 | |||
715 | cs = prop_get_symbol(sym_get_choice_prop(sym)); |
||
716 | ds = sym_choice_default(cs); |
||
717 | if (!sym_is_optional(cs) && sym == ds) { |
||
718 | if ((sym->type == S_BOOLEAN) && |
||
719 | sym_get_tristate_value(sym) == yes) |
||
720 | goto next_menu; |
||
721 | } |
||
722 | } |
||
723 | conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); |
||
724 | } |
||
725 | next_menu: |
||
726 | if (menu->list != NULL) { |
||
727 | menu = menu->list; |
||
728 | } |
||
729 | else if (menu->next != NULL) { |
||
730 | menu = menu->next; |
||
731 | } else { |
||
732 | while ((menu = menu->parent)) { |
||
733 | if (menu->next != NULL) { |
||
734 | menu = menu->next; |
||
735 | break; |
||
736 | } |
||
737 | } |
||
738 | } |
||
739 | } |
||
740 | fclose(out); |
||
741 | return 0; |
||
742 | } |
||
743 | |||
744 | int conf_write(const char *name) |
||
745 | { |
||
746 | FILE *out; |
||
747 | struct symbol *sym; |
||
748 | struct menu *menu; |
||
749 | const char *basename; |
||
750 | const char *str; |
||
751 | char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; |
||
752 | char *env; |
||
753 | |||
754 | dirname[0] = 0; |
||
755 | if (name && name[0]) { |
||
756 | struct stat st; |
||
757 | char *slash; |
||
758 | |||
759 | if (!stat(name, &st) && S_ISDIR(st.st_mode)) { |
||
760 | strcpy(dirname, name); |
||
761 | strcat(dirname, "/"); |
||
762 | basename = conf_get_configname(); |
||
763 | } else if ((slash = strrchr(name, '/'))) { |
||
764 | int size = slash - name + 1; |
||
765 | memcpy(dirname, name, size); |
||
766 | dirname[size] = 0; |
||
767 | if (slash[1]) |
||
768 | basename = slash + 1; |
||
769 | else |
||
770 | basename = conf_get_configname(); |
||
771 | } else |
||
772 | basename = name; |
||
773 | } else |
||
774 | basename = conf_get_configname(); |
||
775 | |||
776 | sprintf(newname, "%s%s", dirname, basename); |
||
777 | env = getenv("KCONFIG_OVERWRITECONFIG"); |
||
778 | if (!env || !*env) { |
||
779 | sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); |
||
780 | out = fopen(tmpname, "w"); |
||
781 | } else { |
||
782 | *tmpname = 0; |
||
783 | out = fopen(newname, "w"); |
||
784 | } |
||
785 | if (!out) |
||
786 | return 1; |
||
787 | |||
788 | conf_write_heading(out, &kconfig_printer_cb, NULL); |
||
789 | |||
790 | if (!conf_get_changed()) |
||
791 | sym_clear_all_valid(); |
||
792 | |||
793 | menu = rootmenu.list; |
||
794 | while (menu) { |
||
795 | sym = menu->sym; |
||
796 | if (!sym) { |
||
797 | if (!menu_is_visible(menu)) |
||
798 | goto next; |
||
799 | str = menu_get_prompt(menu); |
||
800 | fprintf(out, "\n" |
||
801 | "#\n" |
||
802 | "# %s\n" |
||
803 | "#\n", str); |
||
804 | } else if (!(sym->flags & SYMBOL_CHOICE)) { |
||
805 | sym_calc_value(sym); |
||
806 | if (!(sym->flags & SYMBOL_WRITE)) |
||
807 | goto next; |
||
808 | sym->flags &= ~SYMBOL_WRITE; |
||
809 | |||
810 | conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); |
||
811 | } |
||
812 | |||
813 | next: |
||
814 | if (menu->list) { |
||
815 | menu = menu->list; |
||
816 | continue; |
||
817 | } |
||
818 | if (menu->next) |
||
819 | menu = menu->next; |
||
820 | else while ((menu = menu->parent)) { |
||
821 | if (menu->next) { |
||
822 | menu = menu->next; |
||
823 | break; |
||
824 | } |
||
825 | } |
||
826 | } |
||
827 | fclose(out); |
||
828 | |||
829 | if (*tmpname) { |
||
830 | strcat(dirname, basename); |
||
831 | strcat(dirname, ".old"); |
||
832 | rename(newname, dirname); |
||
833 | if (rename(tmpname, newname)) |
||
834 | return 1; |
||
835 | } |
||
836 | |||
837 | conf_message(_("configuration written to %s"), newname); |
||
838 | |||
839 | sym_set_change_count(0); |
||
840 | |||
841 | return 0; |
||
842 | } |
||
843 | |||
844 | static int conf_split_config(void) |
||
845 | { |
||
846 | const char *name; |
||
847 | char path[PATH_MAX+1]; |
||
848 | char *s, *d, c; |
||
849 | struct symbol *sym; |
||
850 | struct stat sb; |
||
851 | int res, i, fd; |
||
852 | |||
853 | name = conf_get_autoconfig_name(); |
||
854 | conf_read_simple(name, S_DEF_AUTO); |
||
855 | sym_calc_value(modules_sym); |
||
856 | |||
857 | if (chdir("include/config")) |
||
858 | return 1; |
||
859 | |||
860 | res = 0; |
||
861 | for_all_symbols(i, sym) { |
||
862 | sym_calc_value(sym); |
||
863 | if ((sym->flags & SYMBOL_AUTO) || !sym->name) |
||
864 | continue; |
||
865 | if (sym->flags & SYMBOL_WRITE) { |
||
866 | if (sym->flags & SYMBOL_DEF_AUTO) { |
||
867 | /* |
||
868 | * symbol has old and new value, |
||
869 | * so compare them... |
||
870 | */ |
||
871 | switch (sym->type) { |
||
872 | case S_BOOLEAN: |
||
873 | case S_TRISTATE: |
||
874 | if (sym_get_tristate_value(sym) == |
||
875 | sym->def[S_DEF_AUTO].tri) |
||
876 | continue; |
||
877 | break; |
||
878 | case S_STRING: |
||
879 | case S_HEX: |
||
880 | case S_INT: |
||
881 | if (!strcmp(sym_get_string_value(sym), |
||
882 | sym->def[S_DEF_AUTO].val)) |
||
883 | continue; |
||
884 | break; |
||
885 | default: |
||
886 | break; |
||
887 | } |
||
888 | } else { |
||
889 | /* |
||
890 | * If there is no old value, only 'no' (unset) |
||
891 | * is allowed as new value. |
||
892 | */ |
||
893 | switch (sym->type) { |
||
894 | case S_BOOLEAN: |
||
895 | case S_TRISTATE: |
||
896 | if (sym_get_tristate_value(sym) == no) |
||
897 | continue; |
||
898 | break; |
||
899 | default: |
||
900 | break; |
||
901 | } |
||
902 | } |
||
903 | } else if (!(sym->flags & SYMBOL_DEF_AUTO)) |
||
904 | /* There is neither an old nor a new value. */ |
||
905 | continue; |
||
906 | /* else |
||
907 | * There is an old value, but no new value ('no' (unset) |
||
908 | * isn't saved in auto.conf, so the old value is always |
||
909 | * different from 'no'). |
||
910 | */ |
||
911 | |||
912 | /* Replace all '_' and append ".h" */ |
||
913 | s = sym->name; |
||
914 | d = path; |
||
915 | while ((c = *s++)) { |
||
916 | c = tolower(c); |
||
917 | *d++ = (c == '_') ? '/' : c; |
||
918 | } |
||
919 | strcpy(d, ".h"); |
||
920 | |||
921 | /* Assume directory path already exists. */ |
||
922 | fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
||
923 | if (fd == -1) { |
||
924 | if (errno != ENOENT) { |
||
925 | res = 1; |
||
926 | break; |
||
927 | } |
||
928 | /* |
||
929 | * Create directory components, |
||
930 | * unless they exist already. |
||
931 | */ |
||
932 | d = path; |
||
933 | while ((d = strchr(d, '/'))) { |
||
934 | *d = 0; |
||
935 | if (stat(path, &sb) && mkdir(path, 0755)) { |
||
936 | res = 1; |
||
937 | goto out; |
||
938 | } |
||
939 | *d++ = '/'; |
||
940 | } |
||
941 | /* Try it again. */ |
||
942 | fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
||
943 | if (fd == -1) { |
||
944 | res = 1; |
||
945 | break; |
||
946 | } |
||
947 | } |
||
948 | close(fd); |
||
949 | } |
||
950 | out: |
||
951 | if (chdir("../..")) |
||
952 | return 1; |
||
953 | |||
954 | return res; |
||
955 | } |
||
956 | |||
957 | int conf_write_autoconf(void) |
||
958 | { |
||
959 | struct symbol *sym; |
||
960 | const char *name; |
||
961 | FILE *out, *tristate, *out_h; |
||
962 | int i; |
||
963 | |||
964 | sym_clear_all_valid(); |
||
965 | |||
966 | file_write_dep("include/config/auto.conf.cmd"); |
||
967 | |||
968 | if (conf_split_config()) |
||
969 | return 1; |
||
970 | |||
971 | out = fopen(".tmpconfig", "w"); |
||
972 | if (!out) |
||
973 | return 1; |
||
974 | |||
975 | tristate = fopen(".tmpconfig_tristate", "w"); |
||
976 | if (!tristate) { |
||
977 | fclose(out); |
||
978 | return 1; |
||
979 | } |
||
980 | |||
981 | out_h = fopen(".tmpconfig.h", "w"); |
||
982 | if (!out_h) { |
||
983 | fclose(out); |
||
984 | fclose(tristate); |
||
985 | return 1; |
||
986 | } |
||
987 | |||
988 | conf_write_heading(out, &kconfig_printer_cb, NULL); |
||
989 | |||
990 | conf_write_heading(tristate, &tristate_printer_cb, NULL); |
||
991 | |||
992 | conf_write_heading(out_h, &header_printer_cb, NULL); |
||
993 | |||
994 | for_all_symbols(i, sym) { |
||
995 | sym_calc_value(sym); |
||
996 | if (!(sym->flags & SYMBOL_WRITE) || !sym->name) |
||
997 | continue; |
||
998 | |||
999 | /* write symbol to auto.conf, tristate and header files */ |
||
1000 | conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); |
||
1001 | |||
1002 | conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); |
||
1003 | |||
1004 | conf_write_symbol(out_h, sym, &header_printer_cb, NULL); |
||
1005 | } |
||
1006 | fclose(out); |
||
1007 | fclose(tristate); |
||
1008 | fclose(out_h); |
||
1009 | |||
1010 | name = getenv("KCONFIG_AUTOHEADER"); |
||
1011 | if (!name) |
||
1012 | name = "include/generated/autoconf.h"; |
||
1013 | if (rename(".tmpconfig.h", name)) |
||
1014 | return 1; |
||
1015 | name = getenv("KCONFIG_TRISTATE"); |
||
1016 | if (!name) |
||
1017 | name = "include/config/tristate.conf"; |
||
1018 | if (rename(".tmpconfig_tristate", name)) |
||
1019 | return 1; |
||
1020 | name = conf_get_autoconfig_name(); |
||
1021 | /* |
||
1022 | * This must be the last step, kbuild has a dependency on auto.conf |
||
1023 | * and this marks the successful completion of the previous steps. |
||
1024 | */ |
||
1025 | if (rename(".tmpconfig", name)) |
||
1026 | return 1; |
||
1027 | |||
1028 | return 0; |
||
1029 | } |
||
1030 | |||
1031 | static int sym_change_count; |
||
1032 | static void (*conf_changed_callback)(void); |
||
1033 | |||
1034 | void sym_set_change_count(int count) |
||
1035 | { |
||
1036 | int _sym_change_count = sym_change_count; |
||
1037 | sym_change_count = count; |
||
1038 | if (conf_changed_callback && |
||
1039 | (bool)_sym_change_count != (bool)count) |
||
1040 | conf_changed_callback(); |
||
1041 | } |
||
1042 | |||
1043 | void sym_add_change_count(int count) |
||
1044 | { |
||
1045 | sym_set_change_count(count + sym_change_count); |
||
1046 | } |
||
1047 | |||
1048 | bool conf_get_changed(void) |
||
1049 | { |
||
1050 | return sym_change_count; |
||
1051 | } |
||
1052 | |||
1053 | void conf_set_changed_callback(void (*fn)(void)) |
||
1054 | { |
||
1055 | conf_changed_callback = fn; |
||
1056 | } |
||
1057 | |||
1058 | static bool randomize_choice_values(struct symbol *csym) |
||
1059 | { |
||
1060 | struct property *prop; |
||
1061 | struct symbol *sym; |
||
1062 | struct expr *e; |
||
1063 | int cnt, def; |
||
1064 | |||
1065 | /* |
||
1066 | * If choice is mod then we may have more items selected |
||
1067 | * and if no then no-one. |
||
1068 | * In both cases stop. |
||
1069 | */ |
||
1070 | if (csym->curr.tri != yes) |
||
1071 | return false; |
||
1072 | |||
1073 | prop = sym_get_choice_prop(csym); |
||
1074 | |||
1075 | /* count entries in choice block */ |
||
1076 | cnt = 0; |
||
1077 | expr_list_for_each_sym(prop->expr, e, sym) |
||
1078 | cnt++; |
||
1079 | |||
1080 | /* |
||
1081 | * find a random value and set it to yes, |
||
1082 | * set the rest to no so we have only one set |
||
1083 | */ |
||
1084 | def = (rand() % cnt); |
||
1085 | |||
1086 | cnt = 0; |
||
1087 | expr_list_for_each_sym(prop->expr, e, sym) { |
||
1088 | if (def == cnt++) { |
||
1089 | sym->def[S_DEF_USER].tri = yes; |
||
1090 | csym->def[S_DEF_USER].val = sym; |
||
1091 | } |
||
1092 | else { |
||
1093 | sym->def[S_DEF_USER].tri = no; |
||
1094 | } |
||
1095 | sym->flags |= SYMBOL_DEF_USER; |
||
1096 | /* clear VALID to get value calculated */ |
||
1097 | sym->flags &= ~SYMBOL_VALID; |
||
1098 | } |
||
1099 | csym->flags |= SYMBOL_DEF_USER; |
||
1100 | /* clear VALID to get value calculated */ |
||
1101 | csym->flags &= ~(SYMBOL_VALID); |
||
1102 | |||
1103 | return true; |
||
1104 | } |
||
1105 | |||
1106 | void set_all_choice_values(struct symbol *csym) |
||
1107 | { |
||
1108 | struct property *prop; |
||
1109 | struct symbol *sym; |
||
1110 | struct expr *e; |
||
1111 | |||
1112 | prop = sym_get_choice_prop(csym); |
||
1113 | |||
1114 | /* |
||
1115 | * Set all non-assinged choice values to no |
||
1116 | */ |
||
1117 | expr_list_for_each_sym(prop->expr, e, sym) { |
||
1118 | if (!sym_has_value(sym)) |
||
1119 | sym->def[S_DEF_USER].tri = no; |
||
1120 | } |
||
1121 | csym->flags |= SYMBOL_DEF_USER; |
||
1122 | /* clear VALID to get value calculated */ |
||
1123 | csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); |
||
1124 | } |
||
1125 | |||
1126 | bool conf_set_all_new_symbols(enum conf_def_mode mode) |
||
1127 | { |
||
1128 | struct symbol *sym, *csym; |
||
1129 | int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y |
||
1130 | * pty: probability of tristate = y |
||
1131 | * ptm: probability of tristate = m |
||
1132 | */ |
||
1133 | |||
1134 | pby = 50; pty = ptm = 33; /* can't go as the default in switch-case |
||
1135 | * below, otherwise gcc whines about |
||
1136 | * -Wmaybe-uninitialized */ |
||
1137 | if (mode == def_random) { |
||
1138 | int n, p[3]; |
||
1139 | char *env = getenv("KCONFIG_PROBABILITY"); |
||
1140 | n = 0; |
||
1141 | while( env && *env ) { |
||
1142 | char *endp; |
||
1143 | int tmp = strtol( env, &endp, 10 ); |
||
1144 | if( tmp >= 0 && tmp <= 100 ) { |
||
1145 | p[n++] = tmp; |
||
1146 | } else { |
||
1147 | errno = ERANGE; |
||
1148 | perror( "KCONFIG_PROBABILITY" ); |
||
1149 | exit( 1 ); |
||
1150 | } |
||
1151 | env = (*endp == ':') ? endp+1 : endp; |
||
1152 | if( n >=3 ) { |
||
1153 | break; |
||
1154 | } |
||
1155 | } |
||
1156 | switch( n ) { |
||
1157 | case 1: |
||
1158 | pby = p[0]; ptm = pby/2; pty = pby-ptm; |
||
1159 | break; |
||
1160 | case 2: |
||
1161 | pty = p[0]; ptm = p[1]; pby = pty + ptm; |
||
1162 | break; |
||
1163 | case 3: |
||
1164 | pby = p[0]; pty = p[1]; ptm = p[2]; |
||
1165 | break; |
||
1166 | } |
||
1167 | |||
1168 | if( pty+ptm > 100 ) { |
||
1169 | errno = ERANGE; |
||
1170 | perror( "KCONFIG_PROBABILITY" ); |
||
1171 | exit( 1 ); |
||
1172 | } |
||
1173 | } |
||
1174 | bool has_changed = false; |
||
1175 | |||
1176 | sym_clear_all_valid(); |
||
1177 | |||
1178 | for_all_symbols(i, sym) { |
||
1179 | if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) |
||
1180 | continue; |
||
1181 | switch (sym_get_type(sym)) { |
||
1182 | case S_BOOLEAN: |
||
1183 | case S_TRISTATE: |
||
1184 | has_changed = true; |
||
1185 | switch (mode) { |
||
1186 | case def_yes: |
||
1187 | sym->def[S_DEF_USER].tri = yes; |
||
1188 | break; |
||
1189 | case def_mod: |
||
1190 | sym->def[S_DEF_USER].tri = mod; |
||
1191 | break; |
||
1192 | case def_no: |
||
1193 | if (sym->flags & SYMBOL_ALLNOCONFIG_Y) |
||
1194 | sym->def[S_DEF_USER].tri = yes; |
||
1195 | else |
||
1196 | sym->def[S_DEF_USER].tri = no; |
||
1197 | break; |
||
1198 | case def_random: |
||
1199 | sym->def[S_DEF_USER].tri = no; |
||
1200 | cnt = rand() % 100; |
||
1201 | if (sym->type == S_TRISTATE) { |
||
1202 | if (cnt < pty) |
||
1203 | sym->def[S_DEF_USER].tri = yes; |
||
1204 | else if (cnt < (pty+ptm)) |
||
1205 | sym->def[S_DEF_USER].tri = mod; |
||
1206 | } else if (cnt < pby) |
||
1207 | sym->def[S_DEF_USER].tri = yes; |
||
1208 | break; |
||
1209 | default: |
||
1210 | continue; |
||
1211 | } |
||
1212 | if (!(sym_is_choice(sym) && mode == def_random)) |
||
1213 | sym->flags |= SYMBOL_DEF_USER; |
||
1214 | break; |
||
1215 | default: |
||
1216 | break; |
||
1217 | } |
||
1218 | |||
1219 | } |
||
1220 | |||
1221 | /* |
||
1222 | * We have different type of choice blocks. |
||
1223 | * If curr.tri equals to mod then we can select several |
||
1224 | * choice symbols in one block. |
||
1225 | * In this case we do nothing. |
||
1226 | * If curr.tri equals yes then only one symbol can be |
||
1227 | * selected in a choice block and we set it to yes, |
||
1228 | * and the rest to no. |
||
1229 | */ |
||
1230 | if (mode != def_random) { |
||
1231 | for_all_symbols(i, csym) { |
||
1232 | if ((sym_is_choice(csym) && !sym_has_value(csym)) || |
||
1233 | sym_is_choice_value(csym)) |
||
1234 | csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; |
||
1235 | } |
||
1236 | } |
||
1237 | |||
1238 | for_all_symbols(i, csym) { |
||
1239 | if (sym_has_value(csym) || !sym_is_choice(csym)) |
||
1240 | continue; |
||
1241 | |||
1242 | sym_calc_value(csym); |
||
1243 | if (mode == def_random) |
||
1244 | has_changed = randomize_choice_values(csym); |
||
1245 | else { |
||
1246 | set_all_choice_values(csym); |
||
1247 | has_changed = true; |
||
1248 | } |
||
1249 | } |
||
1250 | |||
1251 | return has_changed; |
||
1252 | } |