scripts/config: backport output file option from r25230
[openwrt/svn-archive/archive.git] / scripts / config / conf.c
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 <ctype.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <sys/stat.h>
12
13 #define LKC_DIRECT_LINK
14 #include "lkc.h"
15
16 static void conf(struct menu *menu);
17 static void check_conf(struct menu *menu);
18
19 enum {
20 ask_all,
21 ask_new,
22 ask_silent,
23 set_default,
24 set_yes,
25 set_mod,
26 set_no,
27 set_random
28 } input_mode = ask_all;
29 char *defconfig_file;
30
31 static int indent = 1;
32 static int valid_stdin = 1;
33 static int conf_cnt;
34 static char line[128];
35 static struct menu *rootEntry;
36
37 static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
38
39 static void strip(char *str)
40 {
41 char *p = str;
42 int l;
43
44 while ((isspace(*p)))
45 p++;
46 l = strlen(p);
47 if (p != str)
48 memmove(str, p, l + 1);
49 if (!l)
50 return;
51 p = str + l - 1;
52 while ((isspace(*p)))
53 *p-- = 0;
54 }
55
56 static void check_stdin(void)
57 {
58 if (!valid_stdin && input_mode == ask_silent) {
59 printf(_("aborted!\n\n"));
60 printf(_("Console input/output is redirected. "));
61 printf(_("Run 'make oldconfig' to update configuration.\n\n"));
62 exit(1);
63 }
64 }
65
66 static char *fgets_check_stream(char *s, int size, FILE *stream)
67 {
68 char *ret = fgets(s, size, stream);
69
70 if (ret == NULL && feof(stream)) {
71 printf(_("aborted!\n\n"));
72 printf(_("Console input is closed. "));
73 printf(_("Run 'make oldconfig' to update configuration.\n\n"));
74 exit(1);
75 }
76
77 return ret;
78 }
79
80 static void conf_askvalue(struct symbol *sym, const char *def)
81 {
82 enum symbol_type type = sym_get_type(sym);
83 tristate val;
84
85 if (!sym_has_value(sym))
86 printf("(NEW) ");
87
88 line[0] = '\n';
89 line[1] = 0;
90
91 if (!sym_is_changable(sym)) {
92 printf("%s\n", def);
93 line[0] = '\n';
94 line[1] = 0;
95 return;
96 }
97
98 switch (input_mode) {
99 case set_no:
100 case set_mod:
101 case set_yes:
102 case set_random:
103 if (sym_has_value(sym)) {
104 printf("%s\n", def);
105 return;
106 }
107 break;
108 case ask_new:
109 case ask_silent:
110 if (sym_has_value(sym)) {
111 printf("%s\n", def);
112 return;
113 }
114 check_stdin();
115 case ask_all:
116 fflush(stdout);
117 fgets_check_stream(line, 128, stdin);
118 return;
119 case set_default:
120 printf("%s\n", def);
121 return;
122 default:
123 break;
124 }
125
126 switch (type) {
127 case S_INT:
128 case S_HEX:
129 case S_STRING:
130 printf("%s\n", def);
131 return;
132 default:
133 ;
134 }
135 switch (input_mode) {
136 case set_yes:
137 if (sym_tristate_within_range(sym, yes)) {
138 line[0] = 'y';
139 line[1] = '\n';
140 line[2] = 0;
141 break;
142 }
143 case set_mod:
144 if (type == S_TRISTATE) {
145 if (sym_tristate_within_range(sym, mod)) {
146 line[0] = 'm';
147 line[1] = '\n';
148 line[2] = 0;
149 break;
150 }
151 } else {
152 if (sym_tristate_within_range(sym, yes)) {
153 line[0] = 'y';
154 line[1] = '\n';
155 line[2] = 0;
156 break;
157 }
158 }
159 case set_no:
160 if (sym_tristate_within_range(sym, no)) {
161 line[0] = 'n';
162 line[1] = '\n';
163 line[2] = 0;
164 break;
165 }
166 case set_random:
167 do {
168 val = (tristate)(random() % 3);
169 } while (!sym_tristate_within_range(sym, val));
170 switch (val) {
171 case no: line[0] = 'n'; break;
172 case mod: line[0] = 'm'; break;
173 case yes: line[0] = 'y'; break;
174 }
175 line[1] = '\n';
176 line[2] = 0;
177 break;
178 default:
179 break;
180 }
181 printf("%s", line);
182 }
183
184 int conf_string(struct menu *menu)
185 {
186 struct symbol *sym = menu->sym;
187 const char *def, *help;
188
189 while (1) {
190 printf("%*s%s ", indent - 1, "", menu->prompt->text);
191 printf("(%s) ", sym->name);
192 def = sym_get_string_value(sym);
193 if (sym_get_string_value(sym))
194 printf("[%s] ", def);
195 conf_askvalue(sym, def);
196 switch (line[0]) {
197 case '\n':
198 break;
199 case '?':
200 /* print help */
201 if (line[1] == '\n') {
202 help = nohelp_text;
203 if (menu->sym->help)
204 help = menu->sym->help;
205 printf("\n%s\n", menu->sym->help);
206 def = NULL;
207 break;
208 }
209 default:
210 line[strlen(line)-1] = 0;
211 def = line;
212 }
213 if (def && sym_set_string_value(sym, def))
214 return 0;
215 }
216 }
217
218 static int conf_sym(struct menu *menu)
219 {
220 struct symbol *sym = menu->sym;
221 int type;
222 tristate oldval, newval;
223 const char *help;
224
225 while (1) {
226 printf("%*s%s ", indent - 1, "", menu->prompt->text);
227 if (sym->name)
228 printf("(%s) ", sym->name);
229 type = sym_get_type(sym);
230 putchar('[');
231 oldval = sym_get_tristate_value(sym);
232 switch (oldval) {
233 case no:
234 putchar('N');
235 break;
236 case mod:
237 putchar('M');
238 break;
239 case yes:
240 putchar('Y');
241 break;
242 }
243 if (oldval != no && sym_tristate_within_range(sym, no))
244 printf("/n");
245 if (oldval != mod && sym_tristate_within_range(sym, mod))
246 printf("/m");
247 if (oldval != yes && sym_tristate_within_range(sym, yes))
248 printf("/y");
249 if (sym->help)
250 printf("/?");
251 printf("] ");
252 conf_askvalue(sym, sym_get_string_value(sym));
253 strip(line);
254
255 switch (line[0]) {
256 case 'n':
257 case 'N':
258 newval = no;
259 if (!line[1] || !strcmp(&line[1], "o"))
260 break;
261 continue;
262 case 'm':
263 case 'M':
264 newval = mod;
265 if (!line[1])
266 break;
267 continue;
268 case 'y':
269 case 'Y':
270 newval = yes;
271 if (!line[1] || !strcmp(&line[1], "es"))
272 break;
273 continue;
274 case 0:
275 newval = oldval;
276 break;
277 case '?':
278 goto help;
279 default:
280 continue;
281 }
282 if (sym_set_tristate_value(sym, newval))
283 return 0;
284 help:
285 help = nohelp_text;
286 if (sym->help)
287 help = sym->help;
288 printf("\n%s\n", help);
289 }
290 }
291
292 static int conf_choice(struct menu *menu)
293 {
294 struct symbol *sym, *def_sym;
295 struct menu *child;
296 int type;
297 bool is_new;
298
299 sym = menu->sym;
300 type = sym_get_type(sym);
301 is_new = !sym_has_value(sym);
302 if (sym_is_changable(sym)) {
303 conf_sym(menu);
304 sym_calc_value(sym);
305 switch (sym_get_tristate_value(sym)) {
306 case no:
307 return 1;
308 case mod:
309 return 0;
310 case yes:
311 break;
312 }
313 } else {
314 switch (sym_get_tristate_value(sym)) {
315 case no:
316 return 1;
317 case mod:
318 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
319 return 0;
320 case yes:
321 break;
322 }
323 }
324
325 while (1) {
326 int cnt, def;
327
328 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
329 def_sym = sym_get_choice_value(sym);
330 cnt = def = 0;
331 line[0] = '0';
332 line[1] = 0;
333 for (child = menu->list; child; child = child->next) {
334 if (!menu_is_visible(child))
335 continue;
336 if (!child->sym) {
337 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
338 continue;
339 }
340 cnt++;
341 if (child->sym == def_sym) {
342 def = cnt;
343 printf("%*c", indent, '>');
344 } else
345 printf("%*c", indent, ' ');
346 printf(" %d. %s", cnt, menu_get_prompt(child));
347 if (child->sym->name)
348 printf(" (%s)", child->sym->name);
349 if (!sym_has_value(child->sym))
350 printf(" (NEW)");
351 printf("\n");
352 }
353 printf("%*schoice", indent - 1, "");
354 if (cnt == 1) {
355 printf("[1]: 1\n");
356 goto conf_childs;
357 }
358 printf("[1-%d", cnt);
359 if (sym->help)
360 printf("?");
361 printf("]: ");
362 switch (input_mode) {
363 case ask_new:
364 case ask_silent:
365 if (!is_new) {
366 cnt = def;
367 printf("%d\n", cnt);
368 break;
369 }
370 check_stdin();
371 case ask_all:
372 fflush(stdout);
373 fgets_check_stream(line, 128, stdin);
374 strip(line);
375 if (line[0] == '?') {
376 printf("\n%s\n", menu->sym->help ?
377 menu->sym->help : nohelp_text);
378 continue;
379 }
380 if (!line[0])
381 cnt = def;
382 else if (isdigit(line[0]))
383 cnt = atoi(line);
384 else
385 continue;
386 break;
387 case set_random:
388 def = (random() % cnt) + 1;
389 case set_default:
390 case set_yes:
391 case set_mod:
392 case set_no:
393 cnt = def;
394 printf("%d\n", cnt);
395 break;
396 }
397
398 conf_childs:
399 for (child = menu->list; child; child = child->next) {
400 if (!child->sym || !menu_is_visible(child))
401 continue;
402 if (!--cnt)
403 break;
404 }
405 if (!child)
406 continue;
407 if (line[strlen(line) - 1] == '?') {
408 printf("\n%s\n", child->sym->help ?
409 child->sym->help : nohelp_text);
410 continue;
411 }
412 sym_set_choice_value(sym, child->sym);
413 if (child->list) {
414 indent += 2;
415 conf(child->list);
416 indent -= 2;
417 }
418 return 1;
419 }
420 }
421
422 static void conf(struct menu *menu)
423 {
424 struct symbol *sym;
425 struct property *prop;
426 struct menu *child;
427
428 if (!menu_is_visible(menu))
429 return;
430
431 sym = menu->sym;
432 prop = menu->prompt;
433 if (prop) {
434 const char *prompt;
435
436 switch (prop->type) {
437 case P_MENU:
438 if (input_mode == ask_silent && rootEntry != menu) {
439 check_conf(menu);
440 return;
441 }
442 case P_COMMENT:
443 prompt = menu_get_prompt(menu);
444 if (prompt)
445 printf("%*c\n%*c %s\n%*c\n",
446 indent, '*',
447 indent, '*', prompt,
448 indent, '*');
449 default:
450 ;
451 }
452 }
453
454 if (!sym)
455 goto conf_childs;
456
457 if (sym_is_choice(sym)) {
458 conf_choice(menu);
459 if (sym->curr.tri != mod)
460 return;
461 goto conf_childs;
462 }
463
464 switch (sym->type) {
465 case S_INT:
466 case S_HEX:
467 case S_STRING:
468 conf_string(menu);
469 break;
470 default:
471 conf_sym(menu);
472 break;
473 }
474
475 conf_childs:
476 if (sym)
477 indent += 2;
478 for (child = menu->list; child; child = child->next)
479 conf(child);
480 if (sym)
481 indent -= 2;
482 }
483
484 static void check_conf(struct menu *menu)
485 {
486 struct symbol *sym;
487 struct menu *child;
488
489 if (!menu_is_visible(menu))
490 return;
491
492 sym = menu->sym;
493 if (sym && !sym_has_value(sym)) {
494 if (sym_is_changable(sym) ||
495 (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
496 if (!conf_cnt++)
497 printf(_("*\n* Restart config...\n*\n"));
498 rootEntry = menu_get_parent_menu(menu);
499 conf(rootEntry);
500 }
501 }
502
503 for (child = menu->list; child; child = child->next)
504 check_conf(child);
505 }
506
507 int main(int ac, char **av)
508 {
509 int i = 1;
510 const char *name;
511 char *output = NULL;
512 struct stat tmpstat;
513
514 while (ac > i && av[i][0] == '-') {
515 switch (av[i++][1]) {
516 case 'o':
517 input_mode = ask_new;
518 break;
519 case 's':
520 input_mode = ask_silent;
521 valid_stdin = isatty(0) && isatty(1) && isatty(2);
522 break;
523 case 'd':
524 input_mode = set_default;
525 break;
526 case 'D':
527 input_mode = set_default;
528 defconfig_file = av[i++];
529 if (!defconfig_file) {
530 printf(_("%s: No default config file specified\n"),
531 av[0]);
532 exit(1);
533 }
534 break;
535 case 'w':
536 output = av[i++];
537 break;
538 case 'n':
539 input_mode = set_no;
540 break;
541 case 'm':
542 input_mode = set_mod;
543 break;
544 case 'y':
545 input_mode = set_yes;
546 break;
547 case 'r':
548 input_mode = set_random;
549 srandom(time(NULL));
550 break;
551 case 'h':
552 case '?':
553 printf("%s [-o|-s] config\n", av[0]);
554 exit(0);
555 }
556 }
557 name = av[i];
558 if (!name) {
559 printf(_("%s: Kconfig file missing\n"), av[0]);
560 }
561 conf_parse(name);
562 //zconfdump(stdout);
563 switch (input_mode) {
564 case set_default:
565 if (!defconfig_file)
566 defconfig_file = conf_get_default_confname();
567 if (conf_read(defconfig_file)) {
568 printf("***\n"
569 "*** Can't find default configuration \"%s\"!\n"
570 "***\n", defconfig_file);
571 exit(1);
572 }
573 break;
574 case ask_silent:
575 if (stat(".config", &tmpstat)) {
576 printf(_("***\n"
577 "*** You have not yet configured your build!\n"
578 "***\n"
579 "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
580 "*** \"make menuconfig\" or \"make xconfig\").\n"
581 "***\n"));
582 exit(1);
583 }
584 case ask_all:
585 case ask_new:
586 case set_no:
587 case set_mod:
588 case set_yes:
589 case set_random:
590 conf_read(NULL);
591 break;
592 default:
593 break;
594 }
595
596 if (input_mode != ask_silent) {
597 rootEntry = &rootmenu;
598 conf(&rootmenu);
599 if (input_mode == ask_all) {
600 input_mode = ask_silent;
601 valid_stdin = 1;
602 }
603 }
604 do {
605 conf_cnt = 0;
606 check_conf(&rootmenu);
607 } while (conf_cnt);
608 if (conf_write(output)) {
609 fprintf(stderr, _("\n*** Error during writing of the build configuration.\n\n"));
610 return 1;
611 }
612 return 0;
613 }