884175e543e246aa2473bab2b22f405631753cef
[people/mcb30/busybox.git] / scripts / 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 <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
16 static void conf(struct menu *menu);
17 static void check_conf(struct menu *menu);
18
19 enum {
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
30 static int indent = 1;
31 static int valid_stdin = 1;
32 static int conf_cnt;
33 static char line[128];
34 static struct menu *rootEntry;
35
36 static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
37
38 #if 0
39 static 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
57 static 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
76 static 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
93 static 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
186 int 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
220 static 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;
286 help:
287                 help = nohelp_text;
288                 if (sym->help)
289                         help = sym->help;
290                 printf("\n%s\n", help);
291         }
292 }
293
294 static 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
386 static 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
439 conf_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
448 static 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
479 conf_childs:
480         for (child = menu->list; child; child = child->next)
481                 check_conf(child);
482 }
483
484 int 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 }