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