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