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