blob: 013a679dd711a761cd73c46b2cd9561fe0815d94 [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;
29
30static int indent = 1;
31static int valid_stdin = 1;
32static int conf_cnt;
33static char line[128];
34static struct menu *rootEntry;
35
36static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
37
Eric Andersenc9f20d92002-12-05 08:41:41 +000038static void strip(char *str)
39{
40 char *p = str;
41 int l;
42
Eric Andersen72d8e442003-08-05 02:18:25 +000043 while ((isspace(*p)))
Eric Andersenc9f20d92002-12-05 08:41:41 +000044 p++;
45 l = strlen(p);
46 if (p != str)
47 memmove(str, p, l + 1);
48 if (!l)
49 return;
50 p = str + l - 1;
Eric Andersen72d8e442003-08-05 02:18:25 +000051 while ((isspace(*p)))
Eric Andersenc9f20d92002-12-05 08:41:41 +000052 *p-- = 0;
53}
54
Eric Andersen72d8e442003-08-05 02:18:25 +000055static void check_stdin(void)
56{
57 if (!valid_stdin && input_mode == ask_silent) {
58 printf("aborted!\n\n");
59 printf("Console input/output is redirected. ");
60 printf("Run 'make oldconfig' to update configuration.\n\n");
61 exit(1);
62 }
63}
64
Eric Andersenc9f20d92002-12-05 08:41:41 +000065static void conf_askvalue(struct symbol *sym, const char *def)
66{
67 enum symbol_type type = sym_get_type(sym);
68 tristate val;
69
70 if (!sym_has_value(sym))
71 printf("(NEW) ");
72
73 line[0] = '\n';
74 line[1] = 0;
75
Eric Andersen72d8e442003-08-05 02:18:25 +000076 if (!sym_is_changable(sym)) {
77 printf("%s\n", def);
78 line[0] = '\n';
79 line[1] = 0;
80 return;
81 }
82
Eric Andersenc9f20d92002-12-05 08:41:41 +000083 switch (input_mode) {
84 case ask_new:
85 case ask_silent:
86 if (sym_has_value(sym)) {
87 printf("%s\n", def);
88 return;
89 }
Eric Andersen72d8e442003-08-05 02:18:25 +000090 check_stdin();
Eric Andersenc9f20d92002-12-05 08:41:41 +000091 case ask_all:
92 fflush(stdout);
93 fgets(line, 128, stdin);
94 return;
95 case set_default:
96 printf("%s\n", def);
97 return;
98 default:
99 break;
100 }
101
102 switch (type) {
103 case S_INT:
104 case S_HEX:
105 case S_STRING:
106 printf("%s\n", def);
107 return;
108 default:
109 ;
110 }
111 switch (input_mode) {
112 case set_yes:
113 if (sym_tristate_within_range(sym, yes)) {
114 line[0] = 'y';
115 line[1] = '\n';
116 line[2] = 0;
117 break;
118 }
119 case set_mod:
120 if (type == S_TRISTATE) {
121 if (sym_tristate_within_range(sym, mod)) {
122 line[0] = 'm';
123 line[1] = '\n';
124 line[2] = 0;
125 break;
126 }
127 } else {
128 if (sym_tristate_within_range(sym, yes)) {
129 line[0] = 'y';
130 line[1] = '\n';
131 line[2] = 0;
132 break;
133 }
134 }
135 case set_no:
136 if (sym_tristate_within_range(sym, no)) {
137 line[0] = 'n';
138 line[1] = '\n';
139 line[2] = 0;
140 break;
141 }
142 case set_random:
143 do {
144 val = (tristate)(random() % 3);
145 } while (!sym_tristate_within_range(sym, val));
146 switch (val) {
147 case no: line[0] = 'n'; break;
148 case mod: line[0] = 'm'; break;
149 case yes: line[0] = 'y'; break;
150 }
151 line[1] = '\n';
152 line[2] = 0;
153 break;
154 default:
155 break;
156 }
157 printf("%s", line);
158}
159
160int conf_string(struct menu *menu)
161{
162 struct symbol *sym = menu->sym;
163 const char *def, *help;
164
165 while (1) {
166 printf("%*s%s ", indent - 1, "", menu->prompt->text);
167 printf("(%s) ", sym->name);
168 def = sym_get_string_value(sym);
169 if (sym_get_string_value(sym))
170 printf("[%s] ", def);
171 conf_askvalue(sym, def);
172 switch (line[0]) {
173 case '\n':
174 break;
175 case '?':
176 /* print help */
177 if (line[1] == 0) {
178 help = nohelp_text;
179 if (menu->sym->help)
180 help = menu->sym->help;
181 printf("\n%s\n", menu->sym->help);
182 def = NULL;
183 break;
184 }
185 default:
186 line[strlen(line)-1] = 0;
187 def = line;
188 }
189 if (def && sym_set_string_value(sym, def))
190 return 0;
191 }
192}
193
194static int conf_sym(struct menu *menu)
195{
196 struct symbol *sym = menu->sym;
197 int type;
198 tristate oldval, newval;
199 const char *help;
200
201 while (1) {
202 printf("%*s%s ", indent - 1, "", menu->prompt->text);
203 if (sym->name)
204 printf("(%s) ", sym->name);
205 type = sym_get_type(sym);
206 putchar('[');
207 oldval = sym_get_tristate_value(sym);
208 switch (oldval) {
209 case no:
210 putchar('N');
211 break;
212 case mod:
213 putchar('M');
214 break;
215 case yes:
216 putchar('Y');
217 break;
218 }
219 if (oldval != no && sym_tristate_within_range(sym, no))
220 printf("/n");
221 if (oldval != mod && sym_tristate_within_range(sym, mod))
222 printf("/m");
223 if (oldval != yes && sym_tristate_within_range(sym, yes))
224 printf("/y");
225 if (sym->help)
226 printf("/?");
227 printf("] ");
228 conf_askvalue(sym, sym_get_string_value(sym));
229 strip(line);
230
231 switch (line[0]) {
232 case 'n':
233 case 'N':
234 newval = no;
235 if (!line[1] || !strcmp(&line[1], "o"))
236 break;
237 continue;
238 case 'm':
239 case 'M':
240 newval = mod;
241 if (!line[1])
242 break;
243 continue;
244 case 'y':
245 case 'Y':
246 newval = yes;
247 if (!line[1] || !strcmp(&line[1], "es"))
248 break;
249 continue;
250 case 0:
251 newval = oldval;
252 break;
253 case '?':
254 goto help;
255 default:
256 continue;
257 }
258 if (sym_set_tristate_value(sym, newval))
259 return 0;
260help:
261 help = nohelp_text;
262 if (sym->help)
263 help = sym->help;
264 printf("\n%s\n", help);
265 }
266}
267
268static int conf_choice(struct menu *menu)
269{
270 struct symbol *sym, *def_sym;
Eric Andersen72d8e442003-08-05 02:18:25 +0000271 struct menu *child;
272 int type;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000273 bool is_new;
274
275 sym = menu->sym;
276 type = sym_get_type(sym);
277 is_new = !sym_has_value(sym);
278 if (sym_is_changable(sym)) {
279 conf_sym(menu);
280 sym_calc_value(sym);
281 switch (sym_get_tristate_value(sym)) {
282 case no:
283 return 1;
284 case mod:
285 return 0;
286 case yes:
287 break;
288 }
289 } else {
Eric Andersen72d8e442003-08-05 02:18:25 +0000290 switch (sym_get_tristate_value(sym)) {
291 case no:
292 return 1;
293 case mod:
Eric Andersenc9f20d92002-12-05 08:41:41 +0000294 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
295 return 0;
Eric Andersen72d8e442003-08-05 02:18:25 +0000296 case yes:
297 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000298 }
299 }
300
301 while (1) {
Eric Andersen72d8e442003-08-05 02:18:25 +0000302 int cnt, def;
303
304 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
Eric Andersenc9f20d92002-12-05 08:41:41 +0000305 def_sym = sym_get_choice_value(sym);
Eric Andersen72d8e442003-08-05 02:18:25 +0000306 cnt = def = 0;
307 line[0] = '0';
308 line[1] = 0;
309 for (child = menu->list; child; child = child->next) {
310 if (!menu_is_visible(child))
Eric Andersenc9f20d92002-12-05 08:41:41 +0000311 continue;
Eric Andersen72d8e442003-08-05 02:18:25 +0000312 if (!child->sym) {
313 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
314 continue;
315 }
316 cnt++;
317 if (child->sym == def_sym) {
318 def = cnt;
319 printf("%*c", indent, '>');
320 } else
321 printf("%*c", indent, ' ');
322 printf(" %d. %s", cnt, menu_get_prompt(child));
323 if (child->sym->name)
324 printf(" (%s)", child->sym->name);
325 if (!sym_has_value(child->sym))
326 printf(" (NEW)");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000327 printf("\n");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000328 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000329 printf("%*schoice", indent - 1, "");
330 if (cnt == 1) {
331 printf("[1]: 1\n");
332 goto conf_childs;
333 }
334 printf("[1-%d", cnt);
335 if (sym->help)
336 printf("?");
337 printf("]: ");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000338 switch (input_mode) {
339 case ask_new:
340 case ask_silent:
Eric Andersen72d8e442003-08-05 02:18:25 +0000341 if (!is_new) {
342 cnt = def;
343 printf("%d\n", cnt);
344 break;
345 }
346 check_stdin();
Eric Andersenc9f20d92002-12-05 08:41:41 +0000347 case ask_all:
Eric Andersen72d8e442003-08-05 02:18:25 +0000348 fflush(stdout);
349 fgets(line, 128, stdin);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000350 strip(line);
Eric Andersen72d8e442003-08-05 02:18:25 +0000351 if (line[0] == '?') {
352 printf("\n%s\n", menu->sym->help ?
353 menu->sym->help : nohelp_text);
354 continue;
355 }
356 if (!line[0])
357 cnt = def;
358 else if (isdigit(line[0]))
359 cnt = atoi(line);
360 else
361 continue;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000362 break;
Eric Andersen72d8e442003-08-05 02:18:25 +0000363 case set_random:
364 def = (random() % cnt) + 1;
365 case set_default:
366 case set_yes:
367 case set_mod:
368 case set_no:
369 cnt = def;
370 printf("%d\n", cnt);
371 break;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000372 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000373
374 conf_childs:
375 for (child = menu->list; child; child = child->next) {
376 if (!child->sym || !menu_is_visible(child))
377 continue;
378 if (!--cnt)
379 break;
380 }
381 if (!child)
382 continue;
383 if (line[strlen(line) - 1] == '?') {
384 printf("\n%s\n", child->sym->help ?
385 child->sym->help : nohelp_text);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000386 continue;
387 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000388 sym_set_choice_value(sym, child->sym);
389 if (child->list) {
390 indent += 2;
391 conf(child->list);
392 indent -= 2;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000393 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000394 return 1;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000395 }
396}
397
398static void conf(struct menu *menu)
399{
400 struct symbol *sym;
401 struct property *prop;
402 struct menu *child;
403
404 if (!menu_is_visible(menu))
405 return;
406
407 sym = menu->sym;
408 prop = menu->prompt;
409 if (prop) {
410 const char *prompt;
411
412 switch (prop->type) {
413 case P_MENU:
414 if (input_mode == ask_silent && rootEntry != menu) {
415 check_conf(menu);
416 return;
417 }
418 case P_COMMENT:
419 prompt = menu_get_prompt(menu);
420 if (prompt)
421 printf("%*c\n%*c %s\n%*c\n",
422 indent, '*',
423 indent, '*', prompt,
424 indent, '*');
425 default:
426 ;
427 }
428 }
429
430 if (!sym)
431 goto conf_childs;
432
433 if (sym_is_choice(sym)) {
434 conf_choice(menu);
Eric Andersen72d8e442003-08-05 02:18:25 +0000435 if (sym->curr.tri != mod)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000436 return;
437 goto conf_childs;
438 }
439
440 switch (sym->type) {
441 case S_INT:
442 case S_HEX:
443 case S_STRING:
444 conf_string(menu);
445 break;
446 default:
447 conf_sym(menu);
448 break;
449 }
450
451conf_childs:
452 if (sym)
453 indent += 2;
454 for (child = menu->list; child; child = child->next)
455 conf(child);
456 if (sym)
457 indent -= 2;
458}
459
460static void check_conf(struct menu *menu)
461{
462 struct symbol *sym;
463 struct menu *child;
464
465 if (!menu_is_visible(menu))
466 return;
467
468 sym = menu->sym;
Eric Andersen72d8e442003-08-05 02:18:25 +0000469 if (sym) {
470 if (sym_is_changable(sym) && !sym_has_value(sym)) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000471 if (!conf_cnt++)
472 printf("*\n* Restart config...\n*\n");
473 rootEntry = menu_get_parent_menu(menu);
474 conf(rootEntry);
475 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000476 if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000477 return;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000478 }
479
Eric Andersenc9f20d92002-12-05 08:41:41 +0000480 for (child = menu->list; child; child = child->next)
481 check_conf(child);
482}
483
484int main(int ac, char **av)
485{
486 const char *name;
487 struct stat tmpstat;
488
489 if (ac > 1 && av[1][0] == '-') {
490 switch (av[1][1]) {
491 case 'o':
492 input_mode = ask_new;
493 break;
494 case 's':
495 input_mode = ask_silent;
496 valid_stdin = isatty(0) && isatty(1) && isatty(2);
497 break;
498 case 'd':
499 input_mode = set_default;
500 break;
501 case 'n':
502 input_mode = set_no;
503 break;
504 case 'm':
505 input_mode = set_mod;
506 break;
507 case 'y':
508 input_mode = set_yes;
509 break;
510 case 'r':
511 input_mode = set_random;
512 srandom(time(NULL));
513 break;
514 case 'h':
515 case '?':
516 printf("%s [-o|-s] config\n", av[0]);
517 exit(0);
518 }
519 name = av[2];
520 } else
521 name = av[1];
522 conf_parse(name);
523 //zconfdump(stdout);
524 switch (input_mode) {
525 case set_default:
526 name = conf_get_default_confname();
527 if (conf_read(name)) {
528 printf("***\n"
529 "*** Can't find default configuration \"%s\"!\n"
530 "***\n", name);
531 exit(1);
532 }
533 break;
534 case ask_silent:
535 if (stat(".config", &tmpstat)) {
536 printf("***\n"
537 "*** You have not yet configured BusyBox!\n"
538 "***\n"
Eric Andersen72d8e442003-08-05 02:18:25 +0000539 "*** Please run some configurator (e.g. \"make config\" or\n"
540 "*** \"make oldconfig\" or \"make menuconfig\").\n"
Eric Andersenc9f20d92002-12-05 08:41:41 +0000541 "***\n");
542 exit(1);
543 }
544 case ask_all:
545 case ask_new:
546 conf_read(NULL);
547 break;
548 default:
549 break;
550 }
551
552 if (input_mode != ask_silent) {
553 rootEntry = &rootmenu;
554 conf(&rootmenu);
555 if (input_mode == ask_all) {
556 input_mode = ask_silent;
557 valid_stdin = 1;
558 }
559 }
560 do {
561 conf_cnt = 0;
562 check_conf(&rootmenu);
563 } while (conf_cnt);
564 conf_write(NULL);
565 return 0;
566}