blob: 78c1af5967f12d5586f1f57d4bcf33a19f093a30 [file] [log] [blame]
Eric Andersenc9f20d92002-12-05 08:41:41 +00001/*
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
16static void conf(struct menu *menu);
17static void check_conf(struct menu *menu);
18
19enum {
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;
Eric Andersen16f94a62004-01-16 12:49:06 +000029char *defconfig_file;
Eric Andersenc9f20d92002-12-05 08:41:41 +000030
31static int indent = 1;
32static int valid_stdin = 1;
33static int conf_cnt;
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +000034static signed char line[128];
Eric Andersenc9f20d92002-12-05 08:41:41 +000035static struct menu *rootEntry;
36
37static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
38
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +000039static void strip(signed char *str)
Eric Andersenc9f20d92002-12-05 08:41:41 +000040{
Peter Kjellerstedtbae38db2005-04-19 09:55:06 +000041 signed char *p = str;
Eric Andersenc9f20d92002-12-05 08:41:41 +000042 int l;
43
Eric Andersen72d8e442003-08-05 02:18:25 +000044 while ((isspace(*p)))
Eric Andersenc9f20d92002-12-05 08:41:41 +000045 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;
Eric Andersen72d8e442003-08-05 02:18:25 +000052 while ((isspace(*p)))
Eric Andersenc9f20d92002-12-05 08:41:41 +000053 *p-- = 0;
54}
55
Eric Andersen72d8e442003-08-05 02:18:25 +000056static 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
Eric Andersenc9f20d92002-12-05 08:41:41 +000066static void conf_askvalue(struct symbol *sym, const char *def)
67{
68 enum symbol_type type = sym_get_type(sym);
69 tristate val;
70
71 if (!sym_has_value(sym))
72 printf("(NEW) ");
73
74 line[0] = '\n';
75 line[1] = 0;
76
Eric Andersen72d8e442003-08-05 02:18:25 +000077 if (!sym_is_changable(sym)) {
78 printf("%s\n", def);
79 line[0] = '\n';
80 line[1] = 0;
81 return;
82 }
83
Eric Andersenc9f20d92002-12-05 08:41:41 +000084 switch (input_mode) {
85 case ask_new:
86 case ask_silent:
87 if (sym_has_value(sym)) {
88 printf("%s\n", def);
89 return;
90 }
Eric Andersen72d8e442003-08-05 02:18:25 +000091 check_stdin();
Eric Andersenc9f20d92002-12-05 08:41:41 +000092 case ask_all:
93 fflush(stdout);
94 fgets(line, 128, stdin);
95 return;
96 case set_default:
97 printf("%s\n", def);
98 return;
99 default:
100 break;
101 }
102
103 switch (type) {
104 case S_INT:
105 case S_HEX:
106 case S_STRING:
107 printf("%s\n", def);
108 return;
109 default:
110 ;
111 }
112 switch (input_mode) {
113 case set_yes:
114 if (sym_tristate_within_range(sym, yes)) {
115 line[0] = 'y';
116 line[1] = '\n';
117 line[2] = 0;
118 break;
119 }
120 case set_mod:
121 if (type == S_TRISTATE) {
122 if (sym_tristate_within_range(sym, mod)) {
123 line[0] = 'm';
124 line[1] = '\n';
125 line[2] = 0;
126 break;
127 }
128 } else {
129 if (sym_tristate_within_range(sym, yes)) {
130 line[0] = 'y';
131 line[1] = '\n';
132 line[2] = 0;
133 break;
134 }
135 }
136 case set_no:
137 if (sym_tristate_within_range(sym, no)) {
138 line[0] = 'n';
139 line[1] = '\n';
140 line[2] = 0;
141 break;
142 }
143 case set_random:
144 do {
145 val = (tristate)(random() % 3);
146 } while (!sym_tristate_within_range(sym, val));
147 switch (val) {
148 case no: line[0] = 'n'; break;
149 case mod: line[0] = 'm'; break;
150 case yes: line[0] = 'y'; break;
151 }
152 line[1] = '\n';
153 line[2] = 0;
154 break;
155 default:
156 break;
157 }
158 printf("%s", line);
159}
160
161int conf_string(struct menu *menu)
162{
163 struct symbol *sym = menu->sym;
164 const char *def, *help;
165
166 while (1) {
167 printf("%*s%s ", indent - 1, "", menu->prompt->text);
168 printf("(%s) ", sym->name);
169 def = sym_get_string_value(sym);
170 if (sym_get_string_value(sym))
171 printf("[%s] ", def);
172 conf_askvalue(sym, def);
173 switch (line[0]) {
174 case '\n':
175 break;
176 case '?':
177 /* print help */
Eric Andersen16f94a62004-01-16 12:49:06 +0000178 if (line[1] == '\n') {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000179 help = nohelp_text;
180 if (menu->sym->help)
181 help = menu->sym->help;
182 printf("\n%s\n", menu->sym->help);
183 def = NULL;
184 break;
185 }
186 default:
187 line[strlen(line)-1] = 0;
188 def = line;
189 }
190 if (def && sym_set_string_value(sym, def))
191 return 0;
192 }
193}
194
195static int conf_sym(struct menu *menu)
196{
197 struct symbol *sym = menu->sym;
198 int type;
199 tristate oldval, newval;
200 const char *help;
201
202 while (1) {
203 printf("%*s%s ", indent - 1, "", menu->prompt->text);
204 if (sym->name)
205 printf("(%s) ", sym->name);
206 type = sym_get_type(sym);
207 putchar('[');
208 oldval = sym_get_tristate_value(sym);
209 switch (oldval) {
210 case no:
211 putchar('N');
212 break;
213 case mod:
214 putchar('M');
215 break;
216 case yes:
217 putchar('Y');
218 break;
219 }
220 if (oldval != no && sym_tristate_within_range(sym, no))
221 printf("/n");
222 if (oldval != mod && sym_tristate_within_range(sym, mod))
223 printf("/m");
224 if (oldval != yes && sym_tristate_within_range(sym, yes))
225 printf("/y");
226 if (sym->help)
227 printf("/?");
228 printf("] ");
229 conf_askvalue(sym, sym_get_string_value(sym));
230 strip(line);
231
232 switch (line[0]) {
233 case 'n':
234 case 'N':
235 newval = no;
236 if (!line[1] || !strcmp(&line[1], "o"))
237 break;
238 continue;
239 case 'm':
240 case 'M':
241 newval = mod;
242 if (!line[1])
243 break;
244 continue;
245 case 'y':
246 case 'Y':
247 newval = yes;
248 if (!line[1] || !strcmp(&line[1], "es"))
249 break;
250 continue;
251 case 0:
252 newval = oldval;
253 break;
254 case '?':
255 goto help;
256 default:
257 continue;
258 }
259 if (sym_set_tristate_value(sym, newval))
260 return 0;
261help:
262 help = nohelp_text;
263 if (sym->help)
264 help = sym->help;
265 printf("\n%s\n", help);
266 }
267}
268
269static int conf_choice(struct menu *menu)
270{
271 struct symbol *sym, *def_sym;
Eric Andersen72d8e442003-08-05 02:18:25 +0000272 struct menu *child;
273 int type;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000274 bool is_new;
275
276 sym = menu->sym;
277 type = sym_get_type(sym);
278 is_new = !sym_has_value(sym);
279 if (sym_is_changable(sym)) {
280 conf_sym(menu);
281 sym_calc_value(sym);
282 switch (sym_get_tristate_value(sym)) {
283 case no:
284 return 1;
285 case mod:
286 return 0;
287 case yes:
288 break;
289 }
290 } else {
Eric Andersen72d8e442003-08-05 02:18:25 +0000291 switch (sym_get_tristate_value(sym)) {
292 case no:
293 return 1;
294 case mod:
Eric Andersenc9f20d92002-12-05 08:41:41 +0000295 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
296 return 0;
Eric Andersen72d8e442003-08-05 02:18:25 +0000297 case yes:
298 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000299 }
300 }
301
302 while (1) {
Eric Andersen72d8e442003-08-05 02:18:25 +0000303 int cnt, def;
304
305 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
Eric Andersenc9f20d92002-12-05 08:41:41 +0000306 def_sym = sym_get_choice_value(sym);
Eric Andersen72d8e442003-08-05 02:18:25 +0000307 cnt = def = 0;
308 line[0] = '0';
309 line[1] = 0;
310 for (child = menu->list; child; child = child->next) {
311 if (!menu_is_visible(child))
Eric Andersenc9f20d92002-12-05 08:41:41 +0000312 continue;
Eric Andersen72d8e442003-08-05 02:18:25 +0000313 if (!child->sym) {
314 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
315 continue;
316 }
317 cnt++;
318 if (child->sym == def_sym) {
319 def = cnt;
320 printf("%*c", indent, '>');
321 } else
322 printf("%*c", indent, ' ');
323 printf(" %d. %s", cnt, menu_get_prompt(child));
324 if (child->sym->name)
325 printf(" (%s)", child->sym->name);
326 if (!sym_has_value(child->sym))
327 printf(" (NEW)");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000328 printf("\n");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000329 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000330 printf("%*schoice", indent - 1, "");
331 if (cnt == 1) {
332 printf("[1]: 1\n");
333 goto conf_childs;
334 }
335 printf("[1-%d", cnt);
336 if (sym->help)
337 printf("?");
338 printf("]: ");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000339 switch (input_mode) {
340 case ask_new:
341 case ask_silent:
Eric Andersen72d8e442003-08-05 02:18:25 +0000342 if (!is_new) {
343 cnt = def;
344 printf("%d\n", cnt);
345 break;
346 }
347 check_stdin();
Eric Andersenc9f20d92002-12-05 08:41:41 +0000348 case ask_all:
Eric Andersen72d8e442003-08-05 02:18:25 +0000349 fflush(stdout);
350 fgets(line, 128, stdin);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000351 strip(line);
Eric Andersen72d8e442003-08-05 02:18:25 +0000352 if (line[0] == '?') {
353 printf("\n%s\n", menu->sym->help ?
354 menu->sym->help : nohelp_text);
355 continue;
356 }
357 if (!line[0])
358 cnt = def;
359 else if (isdigit(line[0]))
360 cnt = atoi(line);
361 else
362 continue;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000363 break;
Eric Andersen72d8e442003-08-05 02:18:25 +0000364 case set_random:
365 def = (random() % cnt) + 1;
366 case set_default:
367 case set_yes:
368 case set_mod:
369 case set_no:
370 cnt = def;
371 printf("%d\n", cnt);
372 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000373 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000374
375 conf_childs:
376 for (child = menu->list; child; child = child->next) {
377 if (!child->sym || !menu_is_visible(child))
378 continue;
379 if (!--cnt)
380 break;
381 }
382 if (!child)
383 continue;
384 if (line[strlen(line) - 1] == '?') {
385 printf("\n%s\n", child->sym->help ?
386 child->sym->help : nohelp_text);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000387 continue;
388 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000389 sym_set_choice_value(sym, child->sym);
390 if (child->list) {
391 indent += 2;
392 conf(child->list);
393 indent -= 2;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000394 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000395 return 1;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000396 }
397}
398
399static void conf(struct menu *menu)
400{
401 struct symbol *sym;
402 struct property *prop;
403 struct menu *child;
404
405 if (!menu_is_visible(menu))
406 return;
407
408 sym = menu->sym;
409 prop = menu->prompt;
410 if (prop) {
411 const char *prompt;
412
413 switch (prop->type) {
414 case P_MENU:
415 if (input_mode == ask_silent && rootEntry != menu) {
416 check_conf(menu);
417 return;
418 }
419 case P_COMMENT:
420 prompt = menu_get_prompt(menu);
421 if (prompt)
422 printf("%*c\n%*c %s\n%*c\n",
423 indent, '*',
424 indent, '*', prompt,
425 indent, '*');
426 default:
427 ;
428 }
429 }
430
431 if (!sym)
432 goto conf_childs;
433
434 if (sym_is_choice(sym)) {
435 conf_choice(menu);
Eric Andersen72d8e442003-08-05 02:18:25 +0000436 if (sym->curr.tri != mod)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000437 return;
438 goto conf_childs;
439 }
440
441 switch (sym->type) {
442 case S_INT:
443 case S_HEX:
444 case S_STRING:
445 conf_string(menu);
446 break;
447 default:
448 conf_sym(menu);
449 break;
450 }
451
452conf_childs:
453 if (sym)
454 indent += 2;
455 for (child = menu->list; child; child = child->next)
456 conf(child);
457 if (sym)
458 indent -= 2;
459}
460
461static void check_conf(struct menu *menu)
462{
463 struct symbol *sym;
464 struct menu *child;
465
466 if (!menu_is_visible(menu))
467 return;
468
469 sym = menu->sym;
Eric Andersen72d8e442003-08-05 02:18:25 +0000470 if (sym) {
471 if (sym_is_changable(sym) && !sym_has_value(sym)) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000472 if (!conf_cnt++)
473 printf("*\n* Restart config...\n*\n");
474 rootEntry = menu_get_parent_menu(menu);
475 conf(rootEntry);
476 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000477 if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000478 return;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000479 }
480
Eric Andersenc9f20d92002-12-05 08:41:41 +0000481 for (child = menu->list; child; child = child->next)
482 check_conf(child);
483}
484
485int main(int ac, char **av)
486{
Eric Andersen16f94a62004-01-16 12:49:06 +0000487 int i = 1;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000488 const char *name;
489 struct stat tmpstat;
490
Eric Andersen16f94a62004-01-16 12:49:06 +0000491 if (ac > i && av[i][0] == '-') {
492 switch (av[i++][1]) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000493 case 'o':
494 input_mode = ask_new;
495 break;
496 case 's':
497 input_mode = ask_silent;
498 valid_stdin = isatty(0) && isatty(1) && isatty(2);
499 break;
500 case 'd':
501 input_mode = set_default;
502 break;
Eric Andersen16f94a62004-01-16 12:49:06 +0000503 case 'D':
504 input_mode = set_default;
505 defconfig_file = av[i++];
506 if (!defconfig_file) {
507 printf("%s: No default config file specified\n",
508 av[0]);
509 exit(1);
510 }
511 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000512 case 'n':
513 input_mode = set_no;
514 break;
515 case 'm':
516 input_mode = set_mod;
517 break;
518 case 'y':
519 input_mode = set_yes;
520 break;
521 case 'r':
522 input_mode = set_random;
523 srandom(time(NULL));
524 break;
525 case 'h':
526 case '?':
527 printf("%s [-o|-s] config\n", av[0]);
528 exit(0);
529 }
Eric Andersen16f94a62004-01-16 12:49:06 +0000530 }
531 name = av[i];
532 if (!name) {
533 printf("%s: configuration file missing\n", av[0]);
534 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000535 conf_parse(name);
536 //zconfdump(stdout);
537 switch (input_mode) {
538 case set_default:
Eric Andersen16f94a62004-01-16 12:49:06 +0000539 if (!defconfig_file)
540 defconfig_file = conf_get_default_confname();
541 if (conf_read(defconfig_file)) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000542 printf("***\n"
543 "*** Can't find default configuration \"%s\"!\n"
Eric Andersen16f94a62004-01-16 12:49:06 +0000544 "***\n", defconfig_file);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000545 exit(1);
546 }
547 break;
548 case ask_silent:
549 if (stat(".config", &tmpstat)) {
550 printf("***\n"
551 "*** You have not yet configured BusyBox!\n"
552 "***\n"
Eric Andersen16f94a62004-01-16 12:49:06 +0000553 "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
554 "*** \"make menuconfig\" or \"make config\").\n"
Eric Andersenc9f20d92002-12-05 08:41:41 +0000555 "***\n");
556 exit(1);
557 }
558 case ask_all:
559 case ask_new:
560 conf_read(NULL);
561 break;
562 default:
563 break;
564 }
565
566 if (input_mode != ask_silent) {
567 rootEntry = &rootmenu;
568 conf(&rootmenu);
569 if (input_mode == ask_all) {
570 input_mode = ask_silent;
571 valid_stdin = 1;
572 }
573 }
574 do {
575 conf_cnt = 0;
576 check_conf(&rootmenu);
577 } while (conf_cnt);
Eric Andersen16f94a62004-01-16 12:49:06 +0000578 if (conf_write(NULL)) {
579 fprintf(stderr, "\n*** Error during writing of the BusyBox configuration.\n\n");
580 return 1;
581 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000582 return 0;
583}