blob: 884175e543e246aa2473bab2b22f405631753cef [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
38#if 0
39static void printc(int ch)
40{
41 static int sep = 0;
42
43 if (!sep) {
44 putchar('[');
45 sep = 1;
46 } else if (ch)
47 putchar('/');
48 if (!ch) {
49 putchar(']');
50 putchar(' ');
51 sep = 0;
52 } else
53 putchar(ch);
54}
55#endif
56
57static void printo(const char *o)
58{
59 static int sep = 0;
60
61 if (!sep) {
62 putchar('(');
63 sep = 1;
64 } else if (o) {
65 putchar(',');
66 putchar(' ');
67 }
68 if (!o) {
69 putchar(')');
70 putchar(' ');
71 sep = 0;
72 } else
73 printf("%s", o);
74}
75
76static void strip(char *str)
77{
78 char *p = str;
79 int l;
80
81 while ((isspace((int)*p)))
82 p++;
83 l = strlen(p);
84 if (p != str)
85 memmove(str, p, l + 1);
86 if (!l)
87 return;
88 p = str + l - 1;
89 while ((isspace((int)*p)))
90 *p-- = 0;
91}
92
93static void conf_askvalue(struct symbol *sym, const char *def)
94{
95 enum symbol_type type = sym_get_type(sym);
96 tristate val;
97
98 if (!sym_has_value(sym))
99 printf("(NEW) ");
100
101 line[0] = '\n';
102 line[1] = 0;
103
104 switch (input_mode) {
105 case ask_new:
106 case ask_silent:
107 if (sym_has_value(sym)) {
108 printf("%s\n", def);
109 return;
110 }
111 if (!valid_stdin && input_mode == ask_silent) {
112 printf("aborted!\n\n");
113 printf("Console input/output is redirected. ");
114 printf("Run 'make oldconfig' to update configuration.\n\n");
115 exit(1);
116 }
117 case ask_all:
118 fflush(stdout);
119 fgets(line, 128, stdin);
120 return;
121 case set_default:
122 printf("%s\n", def);
123 return;
124 default:
125 break;
126 }
127
128 switch (type) {
129 case S_INT:
130 case S_HEX:
131 case S_STRING:
132 printf("%s\n", def);
133 return;
134 default:
135 ;
136 }
137 switch (input_mode) {
138 case set_yes:
139 if (sym_tristate_within_range(sym, yes)) {
140 line[0] = 'y';
141 line[1] = '\n';
142 line[2] = 0;
143 break;
144 }
145 case set_mod:
146 if (type == S_TRISTATE) {
147 if (sym_tristate_within_range(sym, mod)) {
148 line[0] = 'm';
149 line[1] = '\n';
150 line[2] = 0;
151 break;
152 }
153 } else {
154 if (sym_tristate_within_range(sym, yes)) {
155 line[0] = 'y';
156 line[1] = '\n';
157 line[2] = 0;
158 break;
159 }
160 }
161 case set_no:
162 if (sym_tristate_within_range(sym, no)) {
163 line[0] = 'n';
164 line[1] = '\n';
165 line[2] = 0;
166 break;
167 }
168 case set_random:
169 do {
170 val = (tristate)(random() % 3);
171 } while (!sym_tristate_within_range(sym, val));
172 switch (val) {
173 case no: line[0] = 'n'; break;
174 case mod: line[0] = 'm'; break;
175 case yes: line[0] = 'y'; break;
176 }
177 line[1] = '\n';
178 line[2] = 0;
179 break;
180 default:
181 break;
182 }
183 printf("%s", line);
184}
185
186int conf_string(struct menu *menu)
187{
188 struct symbol *sym = menu->sym;
189 const char *def, *help;
190
191 while (1) {
192 printf("%*s%s ", indent - 1, "", menu->prompt->text);
193 printf("(%s) ", sym->name);
194 def = sym_get_string_value(sym);
195 if (sym_get_string_value(sym))
196 printf("[%s] ", def);
197 conf_askvalue(sym, def);
198 switch (line[0]) {
199 case '\n':
200 break;
201 case '?':
202 /* print help */
203 if (line[1] == 0) {
204 help = nohelp_text;
205 if (menu->sym->help)
206 help = menu->sym->help;
207 printf("\n%s\n", menu->sym->help);
208 def = NULL;
209 break;
210 }
211 default:
212 line[strlen(line)-1] = 0;
213 def = line;
214 }
215 if (def && sym_set_string_value(sym, def))
216 return 0;
217 }
218}
219
220static int conf_sym(struct menu *menu)
221{
222 struct symbol *sym = menu->sym;
223 int type;
224 tristate oldval, newval;
225 const char *help;
226
227 while (1) {
228 printf("%*s%s ", indent - 1, "", menu->prompt->text);
229 if (sym->name)
230 printf("(%s) ", sym->name);
231 type = sym_get_type(sym);
232 putchar('[');
233 oldval = sym_get_tristate_value(sym);
234 switch (oldval) {
235 case no:
236 putchar('N');
237 break;
238 case mod:
239 putchar('M');
240 break;
241 case yes:
242 putchar('Y');
243 break;
244 }
245 if (oldval != no && sym_tristate_within_range(sym, no))
246 printf("/n");
247 if (oldval != mod && sym_tristate_within_range(sym, mod))
248 printf("/m");
249 if (oldval != yes && sym_tristate_within_range(sym, yes))
250 printf("/y");
251 if (sym->help)
252 printf("/?");
253 printf("] ");
254 conf_askvalue(sym, sym_get_string_value(sym));
255 strip(line);
256
257 switch (line[0]) {
258 case 'n':
259 case 'N':
260 newval = no;
261 if (!line[1] || !strcmp(&line[1], "o"))
262 break;
263 continue;
264 case 'm':
265 case 'M':
266 newval = mod;
267 if (!line[1])
268 break;
269 continue;
270 case 'y':
271 case 'Y':
272 newval = yes;
273 if (!line[1] || !strcmp(&line[1], "es"))
274 break;
275 continue;
276 case 0:
277 newval = oldval;
278 break;
279 case '?':
280 goto help;
281 default:
282 continue;
283 }
284 if (sym_set_tristate_value(sym, newval))
285 return 0;
286help:
287 help = nohelp_text;
288 if (sym->help)
289 help = sym->help;
290 printf("\n%s\n", help);
291 }
292}
293
294static int conf_choice(struct menu *menu)
295{
296 struct symbol *sym, *def_sym;
297 struct menu *cmenu, *def_menu;
298 const char *help;
299 int type, len;
300 bool is_new;
301
302 sym = menu->sym;
303 type = sym_get_type(sym);
304 is_new = !sym_has_value(sym);
305 if (sym_is_changable(sym)) {
306 conf_sym(menu);
307 sym_calc_value(sym);
308 switch (sym_get_tristate_value(sym)) {
309 case no:
310 return 1;
311 case mod:
312 return 0;
313 case yes:
314 break;
315 }
316 } else {
317 sym->def = sym->curr;
318 if (S_TRI(sym->curr) == mod) {
319 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
320 return 0;
321 }
322 }
323
324 while (1) {
325 printf("%*s%s ", indent - 1, "", menu_get_prompt(menu));
326 def_sym = sym_get_choice_value(sym);
327 def_menu = NULL;
328 for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
329 if (!menu_is_visible(cmenu))
330 continue;
331 printo(menu_get_prompt(cmenu));
332 if (cmenu->sym == def_sym)
333 def_menu = cmenu;
334 }
335 printo(NULL);
336 if (def_menu)
337 printf("[%s] ", menu_get_prompt(def_menu));
338 else {
339 printf("\n");
340 return 1;
341 }
342 switch (input_mode) {
343 case ask_new:
344 case ask_silent:
345 case ask_all:
346 conf_askvalue(sym, menu_get_prompt(def_menu));
347 strip(line);
348 break;
349 default:
350 line[0] = 0;
351 printf("\n");
352 }
353 if (line[0] == '?' && !line[1]) {
354 help = nohelp_text;
355 if (menu->sym->help)
356 help = menu->sym->help;
357 printf("\n%s\n", help);
358 continue;
359 }
360 if (line[0]) {
361 len = strlen(line);
362 line[len] = 0;
363
364 def_menu = NULL;
365 for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
366 if (!cmenu->sym || !menu_is_visible(cmenu))
367 continue;
368 if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
369 def_menu = cmenu;
370 break;
371 }
372 }
373 }
374 if (def_menu) {
375 sym_set_choice_value(sym, def_menu->sym);
376 if (def_menu->list) {
377 indent += 2;
378 conf(def_menu->list);
379 indent -= 2;
380 }
381 return 1;
382 }
383 }
384}
385
386static void conf(struct menu *menu)
387{
388 struct symbol *sym;
389 struct property *prop;
390 struct menu *child;
391
392 if (!menu_is_visible(menu))
393 return;
394
395 sym = menu->sym;
396 prop = menu->prompt;
397 if (prop) {
398 const char *prompt;
399
400 switch (prop->type) {
401 case P_MENU:
402 if (input_mode == ask_silent && rootEntry != menu) {
403 check_conf(menu);
404 return;
405 }
406 case P_COMMENT:
407 prompt = menu_get_prompt(menu);
408 if (prompt)
409 printf("%*c\n%*c %s\n%*c\n",
410 indent, '*',
411 indent, '*', prompt,
412 indent, '*');
413 default:
414 ;
415 }
416 }
417
418 if (!sym)
419 goto conf_childs;
420
421 if (sym_is_choice(sym)) {
422 conf_choice(menu);
423 if (S_TRI(sym->curr) != mod)
424 return;
425 goto conf_childs;
426 }
427
428 switch (sym->type) {
429 case S_INT:
430 case S_HEX:
431 case S_STRING:
432 conf_string(menu);
433 break;
434 default:
435 conf_sym(menu);
436 break;
437 }
438
439conf_childs:
440 if (sym)
441 indent += 2;
442 for (child = menu->list; child; child = child->next)
443 conf(child);
444 if (sym)
445 indent -= 2;
446}
447
448static void check_conf(struct menu *menu)
449{
450 struct symbol *sym;
451 struct menu *child;
452
453 if (!menu_is_visible(menu))
454 return;
455
456 sym = menu->sym;
457 if (!sym)
458 goto conf_childs;
459
460 if (sym_is_choice(sym)) {
461 if (!sym_has_value(sym)) {
462 if (!conf_cnt++)
463 printf("*\n* Restart config...\n*\n");
464 rootEntry = menu_get_parent_menu(menu);
465 conf(rootEntry);
466 }
467 if (sym_get_tristate_value(sym) != mod)
468 return;
469 goto conf_childs;
470 }
471
472 if (!sym_has_value(sym)) {
473 if (!conf_cnt++)
474 printf("*\n* Restart config...\n*\n");
475 rootEntry = menu_get_parent_menu(menu);
476 conf(rootEntry);
477 }
478
479conf_childs:
480 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"
539 "*** Please run some configurator (e.g. \"make oldconfig\"\n"
540 "*** or \"make menuconfig\").\n"
541 "***\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}