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