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