scripts: update SPDX license names
[openwrt/staging/yousong.git] / scripts / config / mconf.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4 *
5 * Introduced single menu mode (show all sub-menus in one large tree).
6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7 *
8 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9 */
10
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <signal.h>
20 #include <unistd.h>
21
22 #include "lkc.h"
23 #include "lxdialog/dialog.h"
24
25 static const char mconf_readme[] =
26 "OpenWrt config is based on Kernel kconfig\n"
27 "so ipkg packages are referred here as modules.\n"
28 "\n"
29 "Overview\n"
30 "--------\n"
31 "This interface lets you select features and parameters for the build.\n"
32 "Features can either be built-in, modularized, or ignored. Parameters\n"
33 "must be entered in as decimal or hexadecimal numbers or text.\n"
34 "\n"
35 "Menu items beginning with following braces represent features that\n"
36 " [ ] can be built in or removed\n"
37 " < > can be built in, modularized or removed\n"
38 " { } can be built in or modularized (selected by other feature)\n"
39 " - - are selected by other feature,\n"
40 "while *, M or whitespace inside braces means to build in, build as\n"
41 "a module or to exclude the feature respectively.\n"
42 "\n"
43 "To change any of these features, highlight it with the cursor\n"
44 "keys and press <Y> to build it in, <M> to make it a module or\n"
45 "<N> to remove it. You may also press the <Space Bar> to cycle\n"
46 "through the available options (i.e. Y->N->M->Y).\n"
47 "\n"
48 "Some additional keyboard hints:\n"
49 "\n"
50 "Menus\n"
51 "----------\n"
52 "o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n"
53 " wish to change or the submenu you wish to select and press <Enter>.\n"
54 " Submenus are designated by \"--->\", empty ones by \"----\".\n"
55 "\n"
56 " Shortcut: Press the option's highlighted letter (hotkey).\n"
57 " Pressing a hotkey more than once will sequence\n"
58 " through all visible items which use that hotkey.\n"
59 "\n"
60 " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
61 " unseen options into view.\n"
62 "\n"
63 "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
64 " and press <ENTER>.\n"
65 "\n"
66 " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
67 " using those letters. You may press a single <ESC>, but\n"
68 " there is a delayed response which you may find annoying.\n"
69 "\n"
70 " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
71 " <Exit>, <Help>, <Save>, and <Load>.\n"
72 "\n"
73 "o To get help with an item, use the cursor keys to highlight <Help>\n"
74 " and press <ENTER>.\n"
75 "\n"
76 " Shortcut: Press <H> or <?>.\n"
77 "\n"
78 "o To toggle the display of hidden options, press <Z>.\n"
79 "\n"
80 "\n"
81 "Radiolists (Choice lists)\n"
82 "-----------\n"
83 "o Use the cursor keys to select the option you wish to set and press\n"
84 " <S> or the <SPACE BAR>.\n"
85 "\n"
86 " Shortcut: Press the first letter of the option you wish to set then\n"
87 " press <S> or <SPACE BAR>.\n"
88 "\n"
89 "o To see available help for the item, use the cursor keys to highlight\n"
90 " <Help> and Press <ENTER>.\n"
91 "\n"
92 " Shortcut: Press <H> or <?>.\n"
93 "\n"
94 " Also, the <TAB> and cursor keys will cycle between <Select> and\n"
95 " <Help>\n"
96 "\n"
97 "\n"
98 "Data Entry\n"
99 "-----------\n"
100 "o Enter the requested information and press <ENTER>\n"
101 " If you are entering hexadecimal values, it is not necessary to\n"
102 " add the '0x' prefix to the entry.\n"
103 "\n"
104 "o For help, use the <TAB> or cursor keys to highlight the help option\n"
105 " and press <ENTER>. You can try <TAB><H> as well.\n"
106 "\n"
107 "\n"
108 "Text Box (Help Window)\n"
109 "--------\n"
110 "o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
111 " keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
112 " those who are familiar with less and lynx.\n"
113 "\n"
114 "o Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
115 "\n"
116 "\n"
117 "Alternate Configuration Files\n"
118 "-----------------------------\n"
119 "Menuconfig supports the use of alternate configuration files for\n"
120 "those who, for various reasons, find it necessary to switch\n"
121 "between different configurations.\n"
122 "\n"
123 "The <Save> button will let you save the current configuration to\n"
124 "a file of your choosing. Use the <Load> button to load a previously\n"
125 "saved alternate configuration.\n"
126 "\n"
127 "Even if you don't use alternate configuration files, but you find\n"
128 "during a Menuconfig session that you have completely messed up your\n"
129 "settings, you may use the <Load> button to restore your previously\n"
130 "saved settings from \".config\" without restarting Menuconfig.\n"
131 "\n"
132 "Other information\n"
133 "-----------------\n"
134 "If you use Menuconfig in an XTERM window, make sure you have your\n"
135 "$TERM variable set to point to an xterm definition which supports\n"
136 "color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n"
137 "not display correctly in an RXVT window because rxvt displays only one\n"
138 "intensity of color, bright.\n"
139 "\n"
140 "Menuconfig will display larger menus on screens or xterms which are\n"
141 "set to display more than the standard 25 row by 80 column geometry.\n"
142 "In order for this to work, the \"stty size\" command must be able to\n"
143 "display the screen's current row and column geometry. I STRONGLY\n"
144 "RECOMMEND that you make sure you do NOT have the shell variables\n"
145 "LINES and COLUMNS exported into your environment. Some distributions\n"
146 "export those variables via /etc/profile. Some ncurses programs can\n"
147 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
148 "the true screen size.\n"
149 "\n"
150 "Optional personality available\n"
151 "------------------------------\n"
152 "If you prefer to have all of the options listed in a single menu,\n"
153 "rather than the default multimenu hierarchy, run the menuconfig with\n"
154 "MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
155 "\n"
156 "make MENUCONFIG_MODE=single_menu menuconfig\n"
157 "\n"
158 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
159 "is already unrolled.\n"
160 "\n"
161 "Note that this mode can eventually be a little more CPU expensive\n"
162 "(especially with a larger number of unrolled categories) than the\n"
163 "default mode.\n"
164 "\n"
165 "Different color themes available\n"
166 "--------------------------------\n"
167 "It is possible to select different color themes using the variable\n"
168 "MENUCONFIG_COLOR. To select a theme use:\n"
169 "\n"
170 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
171 "\n"
172 "Available themes are\n"
173 " mono => selects colors suitable for monochrome displays\n"
174 " blackbg => selects a color scheme with black background\n"
175 " classic => theme with blue background. The classic look\n"
176 " bluetitle => an LCD friendly version of classic. (default)\n"
177 "\n",
178 menu_instructions[] =
179 "Arrow keys navigate the menu. "
180 "<Enter> selects submenus ---> (or empty submenus ----). "
181 "Highlighted letters are hotkeys. "
182 "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
183 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
184 "Legend: [*] built-in [ ] excluded <M> module < > module capable",
185 radiolist_instructions[] =
186 "Use the arrow keys to navigate this window or "
187 "press the hotkey of the item you wish to select "
188 "followed by the <SPACE BAR>. "
189 "Press <?> for additional information about this option.",
190 inputbox_instructions_int[] =
191 "Please enter a decimal value. "
192 "Fractions will not be accepted. "
193 "Use the <TAB> key to move from the input field to the buttons below it.",
194 inputbox_instructions_hex[] =
195 "Please enter a hexadecimal value. "
196 "Use the <TAB> key to move from the input field to the buttons below it.",
197 inputbox_instructions_string[] =
198 "Please enter a string value. "
199 "Use the <TAB> key to move from the input field to the buttons below it.",
200 setmod_text[] =
201 "This feature depends on another which has been configured as a module.\n"
202 "As a result, this feature will be built as a module.",
203 load_config_text[] =
204 "Enter the name of the configuration file you wish to load. "
205 "Accept the name shown to restore the configuration you "
206 "last retrieved. Leave blank to abort.",
207 load_config_help[] =
208 "\n"
209 "For various reasons, one may wish to keep several different\n"
210 "configurations available on a single machine.\n"
211 "\n"
212 "If you have saved a previous configuration in a file other than the\n"
213 "default one, entering its name here will allow you to modify that\n"
214 "configuration.\n"
215 "\n"
216 "If you are uncertain, then you have probably never used alternate\n"
217 "configuration files. You should therefore leave this blank to abort.\n",
218 save_config_text[] =
219 "Enter a filename to which this configuration should be saved "
220 "as an alternate. Leave blank to abort.",
221 save_config_help[] =
222 "\n"
223 "For various reasons, one may wish to keep different configurations\n"
224 "available on a single machine.\n"
225 "\n"
226 "Entering a file name here will allow you to later retrieve, modify\n"
227 "and use the current configuration as an alternate to whatever\n"
228 "configuration options you have selected at that time.\n"
229 "\n"
230 "If you are uncertain what all this means then you should probably\n"
231 "leave this blank.\n",
232 search_help[] =
233 "\n"
234 "Search for symbols and display their relations.\n"
235 "Regular expressions are allowed.\n"
236 "Example: search for \"^FOO\"\n"
237 "Result:\n"
238 "-----------------------------------------------------------------\n"
239 "Symbol: FOO [=m]\n"
240 "Type : tristate\n"
241 "Prompt: Foo bus is used to drive the bar HW\n"
242 " Location:\n"
243 " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
244 " -> PCI support (PCI [=y])\n"
245 "(1) -> PCI access mode (<choice> [=y])\n"
246 " Defined at drivers/pci/Kconfig:47\n"
247 " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
248 " Selects: LIBCRC32\n"
249 " Selected by: BAR [=n]\n"
250 "-----------------------------------------------------------------\n"
251 "o The line 'Type:' shows the type of the configuration option for\n"
252 " this symbol (bool, tristate, string, ...)\n"
253 "o The line 'Prompt:' shows the text used in the menu structure for\n"
254 " this symbol\n"
255 "o The 'Defined at' line tells at what file / line number the symbol\n"
256 " is defined\n"
257 "o The 'Depends on:' line tells what symbols need to be defined for\n"
258 " this symbol to be visible in the menu (selectable)\n"
259 "o The 'Location:' lines tells where in the menu structure this symbol\n"
260 " is located\n"
261 " A location followed by a [=y] indicates that this is a\n"
262 " selectable menu item - and the current value is displayed inside\n"
263 " brackets.\n"
264 " Press the key in the (#) prefix to jump directly to that\n"
265 " location. You will be returned to the current search results\n"
266 " after exiting this new menu.\n"
267 "o The 'Selects:' line tells what symbols will be automatically\n"
268 " selected if this symbol is selected (y or m)\n"
269 "o The 'Selected by' line tells what symbol has selected this symbol\n"
270 "\n"
271 "Only relevant lines are shown.\n"
272 "\n\n"
273 "Search examples:\n"
274 "Examples: USB => find all symbols containing USB\n"
275 " ^USB => find all symbols starting with USB\n"
276 " USB$ => find all symbols ending with USB\n"
277 "\n";
278
279 static int indent;
280 static struct menu *current_menu;
281 static int child_count;
282 static int single_menu_mode;
283 static int show_all_options;
284 static int save_and_exit;
285 static int silent;
286
287 static void conf(struct menu *menu, struct menu *active_menu);
288 static void conf_choice(struct menu *menu);
289 static void conf_string(struct menu *menu);
290 static void conf_load(void);
291 static void conf_save(void);
292 static int show_textbox_ext(const char *title, char *text, int r, int c,
293 int *keys, int *vscroll, int *hscroll,
294 update_text_fn update_text, void *data);
295 static void show_textbox(const char *title, const char *text, int r, int c);
296 static void show_helptext(const char *title, const char *text);
297 static void show_help(struct menu *menu);
298
299 static char filename[PATH_MAX+1];
300 static void set_config_filename(const char *config_filename)
301 {
302 static char menu_backtitle[PATH_MAX+128];
303 int size;
304
305 size = snprintf(menu_backtitle, sizeof(menu_backtitle),
306 "%s - %s", config_filename, rootmenu.prompt->text);
307 if (size >= sizeof(menu_backtitle))
308 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
309 set_dialog_backtitle(menu_backtitle);
310
311 size = snprintf(filename, sizeof(filename), "%s", config_filename);
312 if (size >= sizeof(filename))
313 filename[sizeof(filename)-1] = '\0';
314 }
315
316 struct subtitle_part {
317 struct list_head entries;
318 const char *text;
319 };
320 static LIST_HEAD(trail);
321
322 static struct subtitle_list *subtitles;
323 static void set_subtitle(void)
324 {
325 struct subtitle_part *sp;
326 struct subtitle_list *pos, *tmp;
327
328 for (pos = subtitles; pos != NULL; pos = tmp) {
329 tmp = pos->next;
330 free(pos);
331 }
332
333 subtitles = NULL;
334 list_for_each_entry(sp, &trail, entries) {
335 if (sp->text) {
336 if (pos) {
337 pos->next = xcalloc(1, sizeof(*pos));
338 pos = pos->next;
339 } else {
340 subtitles = pos = xcalloc(1, sizeof(*pos));
341 }
342 pos->text = sp->text;
343 }
344 }
345
346 set_dialog_subtitles(subtitles);
347 }
348
349 static void reset_subtitle(void)
350 {
351 struct subtitle_list *pos, *tmp;
352
353 for (pos = subtitles; pos != NULL; pos = tmp) {
354 tmp = pos->next;
355 free(pos);
356 }
357 subtitles = NULL;
358 set_dialog_subtitles(subtitles);
359 }
360
361 struct search_data {
362 struct list_head *head;
363 struct menu **targets;
364 int *keys;
365 };
366
367 static void update_text(char *buf, size_t start, size_t end, void *_data)
368 {
369 struct search_data *data = _data;
370 struct jump_key *pos;
371 int k = 0;
372
373 list_for_each_entry(pos, data->head, entries) {
374 if (pos->offset >= start && pos->offset < end) {
375 char header[4];
376
377 if (k < JUMP_NB) {
378 int key = '0' + (pos->index % JUMP_NB) + 1;
379
380 sprintf(header, "(%c)", key);
381 data->keys[k] = key;
382 data->targets[k] = pos->target;
383 k++;
384 } else {
385 sprintf(header, " ");
386 }
387
388 memcpy(buf + pos->offset, header, sizeof(header) - 1);
389 }
390 }
391 data->keys[k] = 0;
392 }
393
394 static void search_conf(void)
395 {
396 struct symbol **sym_arr;
397 struct gstr res;
398 struct gstr title;
399 char *dialog_input;
400 int dres, vscroll = 0, hscroll = 0;
401 bool again;
402 struct gstr sttext;
403 struct subtitle_part stpart;
404
405 title = str_new();
406 str_printf( &title, "Enter (sub)string or regexp to search for "
407 "(with or without \"%s\")", CONFIG_);
408
409 again:
410 dialog_clear();
411 dres = dialog_inputbox("Search Configuration Parameter",
412 str_get(&title),
413 10, 75, "");
414 switch (dres) {
415 case 0:
416 break;
417 case 1:
418 show_helptext("Search Configuration", search_help);
419 goto again;
420 default:
421 str_free(&title);
422 return;
423 }
424
425 /* strip the prefix if necessary */
426 dialog_input = dialog_input_result;
427 if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
428 dialog_input += strlen(CONFIG_);
429
430 sttext = str_new();
431 str_printf(&sttext, "Search (%s)", dialog_input_result);
432 stpart.text = str_get(&sttext);
433 list_add_tail(&stpart.entries, &trail);
434
435 sym_arr = sym_re_search(dialog_input);
436 do {
437 LIST_HEAD(head);
438 struct menu *targets[JUMP_NB];
439 int keys[JUMP_NB + 1], i;
440 struct search_data data = {
441 .head = &head,
442 .targets = targets,
443 .keys = keys,
444 };
445 struct jump_key *pos, *tmp;
446
447 res = get_relations_str(sym_arr, &head);
448 set_subtitle();
449 dres = show_textbox_ext("Search Results", (char *)
450 str_get(&res), 0, 0, keys, &vscroll,
451 &hscroll, &update_text, (void *)
452 &data);
453 again = false;
454 for (i = 0; i < JUMP_NB && keys[i]; i++)
455 if (dres == keys[i]) {
456 conf(targets[i]->parent, targets[i]);
457 again = true;
458 }
459 str_free(&res);
460 list_for_each_entry_safe(pos, tmp, &head, entries)
461 free(pos);
462 } while (again);
463 free(sym_arr);
464 str_free(&title);
465 list_del(trail.prev);
466 str_free(&sttext);
467 }
468
469 static void build_conf(struct menu *menu)
470 {
471 struct symbol *sym;
472 struct property *prop;
473 struct menu *child;
474 int type, tmp, doint = 2;
475 tristate val;
476 char ch;
477 bool visible;
478
479 /*
480 * note: menu_is_visible() has side effect that it will
481 * recalc the value of the symbol.
482 */
483 visible = menu_is_visible(menu);
484 if (show_all_options && !menu_has_prompt(menu))
485 return;
486 else if (!show_all_options && !visible)
487 return;
488
489 sym = menu->sym;
490 prop = menu->prompt;
491 if (!sym) {
492 if (prop && menu != current_menu) {
493 const char *prompt = menu_get_prompt(menu);
494 switch (prop->type) {
495 case P_MENU:
496 child_count++;
497 if (single_menu_mode) {
498 item_make("%s%*c%s",
499 menu->data ? "-->" : "++>",
500 indent + 1, ' ', prompt);
501 } else
502 item_make(" %*c%s %s",
503 indent + 1, ' ', prompt,
504 menu_is_empty(menu) ? "----" : "--->");
505 item_set_tag('m');
506 item_set_data(menu);
507 if (single_menu_mode && menu->data)
508 goto conf_childs;
509 return;
510 case P_COMMENT:
511 if (prompt) {
512 child_count++;
513 item_make(" %*c*** %s ***", indent + 1, ' ', prompt);
514 item_set_tag(':');
515 item_set_data(menu);
516 }
517 break;
518 default:
519 if (prompt) {
520 child_count++;
521 item_make("---%*c%s", indent + 1, ' ', prompt);
522 item_set_tag(':');
523 item_set_data(menu);
524 }
525 }
526 } else
527 doint = 0;
528 goto conf_childs;
529 }
530
531 type = sym_get_type(sym);
532 if (sym_is_choice(sym)) {
533 struct symbol *def_sym = sym_get_choice_value(sym);
534 struct menu *def_menu = NULL;
535
536 child_count++;
537 for (child = menu->list; child; child = child->next) {
538 if (menu_is_visible(child) && child->sym == def_sym)
539 def_menu = child;
540 }
541
542 val = sym_get_tristate_value(sym);
543 if (sym_is_changeable(sym)) {
544 switch (type) {
545 case S_BOOLEAN:
546 item_make("[%c]", val == no ? ' ' : '*');
547 break;
548 case S_TRISTATE:
549 switch (val) {
550 case yes: ch = '*'; break;
551 case mod: ch = 'M'; break;
552 default: ch = ' '; break;
553 }
554 item_make("<%c>", ch);
555 break;
556 }
557 item_set_tag('t');
558 item_set_data(menu);
559 } else {
560 item_make(" ");
561 item_set_tag(def_menu ? 't' : ':');
562 item_set_data(menu);
563 }
564
565 item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
566 if (val == yes) {
567 if (def_menu) {
568 item_add_str(" (%s)", menu_get_prompt(def_menu));
569 item_add_str(" --->");
570 if (def_menu->list) {
571 indent += 2;
572 build_conf(def_menu);
573 indent -= 2;
574 }
575 }
576 return;
577 }
578 } else {
579 if (menu == current_menu) {
580 item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
581 item_set_tag(':');
582 item_set_data(menu);
583 goto conf_childs;
584 }
585 child_count++;
586 val = sym_get_tristate_value(sym);
587 if (sym_is_choice_value(sym) && val == yes) {
588 item_make(" ");
589 item_set_tag(':');
590 item_set_data(menu);
591 } else {
592 switch (type) {
593 case S_BOOLEAN:
594 if (sym_is_changeable(sym))
595 item_make("[%c]", val == no ? ' ' : '*');
596 else
597 item_make("-%c-", val == no ? ' ' : '*');
598 item_set_tag('t');
599 item_set_data(menu);
600 break;
601 case S_TRISTATE:
602 switch (val) {
603 case yes: ch = '*'; break;
604 case mod: ch = 'M'; break;
605 default: ch = ' '; break;
606 }
607 if (sym_is_changeable(sym)) {
608 if (sym->rev_dep.tri == mod)
609 item_make("{%c}", ch);
610 else
611 item_make("<%c>", ch);
612 } else
613 item_make("-%c-", ch);
614 item_set_tag('t');
615 item_set_data(menu);
616 break;
617 default:
618 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
619 item_make("(%s)", sym_get_string_value(sym));
620 tmp = indent - tmp + 4;
621 if (tmp < 0)
622 tmp = 0;
623 item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
624 (sym_has_value(sym) || !sym_is_changeable(sym)) ?
625 "" : " (NEW)");
626 item_set_tag('s');
627 item_set_data(menu);
628 goto conf_childs;
629 }
630 }
631 item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
632 (sym_has_value(sym) || !sym_is_changeable(sym)) ?
633 "" : " (NEW)");
634 if (menu->prompt->type == P_MENU) {
635 item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
636 return;
637 }
638 }
639
640 conf_childs:
641 indent += doint;
642 for (child = menu->list; child; child = child->next)
643 build_conf(child);
644 indent -= doint;
645 }
646
647 static void conf(struct menu *menu, struct menu *active_menu)
648 {
649 struct menu *submenu;
650 const char *prompt = menu_get_prompt(menu);
651 struct subtitle_part stpart;
652 struct symbol *sym;
653 int res;
654 int s_scroll = 0;
655
656 if (menu != &rootmenu)
657 stpart.text = menu_get_prompt(menu);
658 else
659 stpart.text = NULL;
660 list_add_tail(&stpart.entries, &trail);
661
662 while (1) {
663 item_reset();
664 current_menu = menu;
665 build_conf(menu);
666 if (!child_count)
667 break;
668 set_subtitle();
669 dialog_clear();
670 res = dialog_menu(prompt ? prompt : "Main Menu",
671 menu_instructions,
672 active_menu, &s_scroll);
673 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
674 break;
675 if (item_count() != 0) {
676 if (!item_activate_selected())
677 continue;
678 if (!item_tag())
679 continue;
680 }
681 submenu = item_data();
682 active_menu = item_data();
683 if (submenu)
684 sym = submenu->sym;
685 else
686 sym = NULL;
687
688 switch (res) {
689 case 0:
690 switch (item_tag()) {
691 case 'm':
692 if (single_menu_mode)
693 submenu->data = (void *) (long) !submenu->data;
694 else
695 conf(submenu, NULL);
696 break;
697 case 't':
698 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
699 conf_choice(submenu);
700 else if (submenu->prompt->type == P_MENU)
701 conf(submenu, NULL);
702 break;
703 case 's':
704 conf_string(submenu);
705 break;
706 }
707 break;
708 case 2:
709 if (sym)
710 show_help(submenu);
711 else {
712 reset_subtitle();
713 show_helptext("README", mconf_readme);
714 }
715 break;
716 case 3:
717 reset_subtitle();
718 conf_save();
719 break;
720 case 4:
721 reset_subtitle();
722 conf_load();
723 break;
724 case 5:
725 if (item_is_tag('t')) {
726 if (sym_set_tristate_value(sym, yes))
727 break;
728 if (sym_set_tristate_value(sym, mod))
729 show_textbox(NULL, setmod_text, 6, 74);
730 }
731 break;
732 case 6:
733 if (item_is_tag('t'))
734 sym_set_tristate_value(sym, no);
735 break;
736 case 7:
737 if (item_is_tag('t'))
738 sym_set_tristate_value(sym, mod);
739 break;
740 case 8:
741 if (item_is_tag('t'))
742 sym_toggle_tristate_value(sym);
743 else if (item_is_tag('m'))
744 conf(submenu, NULL);
745 break;
746 case 9:
747 search_conf();
748 break;
749 case 10:
750 show_all_options = !show_all_options;
751 break;
752 }
753 }
754
755 list_del(trail.prev);
756 }
757
758 static int show_textbox_ext(const char *title, char *text, int r, int c, int
759 *keys, int *vscroll, int *hscroll, update_text_fn
760 update_text, void *data)
761 {
762 dialog_clear();
763 return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
764 update_text, data);
765 }
766
767 static void show_textbox(const char *title, const char *text, int r, int c)
768 {
769 show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
770 NULL, NULL);
771 }
772
773 static void show_helptext(const char *title, const char *text)
774 {
775 show_textbox(title, text, 0, 0);
776 }
777
778 static void conf_message_callback(const char *s)
779 {
780 if (save_and_exit) {
781 if (!silent)
782 printf("%s", s);
783 } else {
784 show_textbox(NULL, s, 6, 60);
785 }
786 }
787
788 static void show_help(struct menu *menu)
789 {
790 struct gstr help = str_new();
791
792 help.max_width = getmaxx(stdscr) - 10;
793 menu_get_ext_help(menu, &help);
794
795 show_helptext(menu_get_prompt(menu), str_get(&help));
796 str_free(&help);
797 }
798
799 static void conf_choice(struct menu *menu)
800 {
801 const char *prompt = menu_get_prompt(menu);
802 struct menu *child;
803 struct symbol *active;
804 struct property *prop;
805
806 active = sym_get_choice_value(menu->sym);
807 while (1) {
808 int res;
809 int selected;
810 item_reset();
811
812 current_menu = menu;
813 for (child = menu->list; child; child = child->next) {
814 if (!menu_is_visible(child))
815 continue;
816 if (child->sym)
817 item_make("%s", menu_get_prompt(child));
818 else {
819 item_make("*** %s ***", menu_get_prompt(child));
820 item_set_tag(':');
821 }
822 item_set_data(child);
823 if (child->sym == active)
824 item_set_selected(1);
825 if (child->sym == sym_get_choice_value(menu->sym))
826 item_set_tag('X');
827 }
828 dialog_clear();
829 res = dialog_checklist(prompt ? prompt : "Main Menu",
830 radiolist_instructions,
831 MENUBOX_HEIGTH_MIN,
832 MENUBOX_WIDTH_MIN,
833 CHECKLIST_HEIGTH_MIN);
834 selected = item_activate_selected();
835 switch (res) {
836 case 0:
837 if (selected) {
838 child = item_data();
839 if (!child->sym)
840 break;
841
842 if (sym_get_tristate_value(child->sym) != yes) {
843 for_all_properties(menu->sym, prop, P_RESET) {
844 if (expr_calc_value(prop->visible.expr) == no)
845 continue;
846
847 conf_reset(S_DEF_USER);
848 break;
849 }
850 }
851 sym_set_tristate_value(child->sym, yes);
852 }
853 return;
854 case 1:
855 if (selected) {
856 child = item_data();
857 show_help(child);
858 active = child->sym;
859 } else
860 show_help(menu);
861 break;
862 case KEY_ESC:
863 return;
864 case -ERRDISPLAYTOOSMALL:
865 return;
866 }
867 }
868 }
869
870 static void conf_string(struct menu *menu)
871 {
872 const char *prompt = menu_get_prompt(menu);
873
874 while (1) {
875 int res;
876 const char *heading;
877
878 switch (sym_get_type(menu->sym)) {
879 case S_INT:
880 heading = inputbox_instructions_int;
881 break;
882 case S_HEX:
883 heading = inputbox_instructions_hex;
884 break;
885 case S_STRING:
886 heading = inputbox_instructions_string;
887 break;
888 default:
889 heading = "Internal mconf error!";
890 }
891 dialog_clear();
892 res = dialog_inputbox(prompt ? prompt : "Main Menu",
893 heading, 10, 75,
894 sym_get_string_value(menu->sym));
895 switch (res) {
896 case 0:
897 if (sym_set_string_value(menu->sym, dialog_input_result))
898 return;
899 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
900 break;
901 case 1:
902 show_help(menu);
903 break;
904 case KEY_ESC:
905 return;
906 }
907 }
908 }
909
910 static void conf_load(void)
911 {
912
913 while (1) {
914 int res;
915 dialog_clear();
916 res = dialog_inputbox(NULL, load_config_text,
917 11, 55, filename);
918 switch(res) {
919 case 0:
920 if (!dialog_input_result[0])
921 return;
922 if (!conf_read(dialog_input_result)) {
923 set_config_filename(dialog_input_result);
924 sym_set_change_count(1);
925 return;
926 }
927 show_textbox(NULL, "File does not exist!", 5, 38);
928 break;
929 case 1:
930 show_helptext("Load Alternate Configuration", load_config_help);
931 break;
932 case KEY_ESC:
933 return;
934 }
935 }
936 }
937
938 static void conf_save(void)
939 {
940 while (1) {
941 int res;
942 dialog_clear();
943 res = dialog_inputbox(NULL, save_config_text,
944 11, 55, filename);
945 switch(res) {
946 case 0:
947 if (!dialog_input_result[0])
948 return;
949 if (!conf_write(dialog_input_result)) {
950 set_config_filename(dialog_input_result);
951 return;
952 }
953 show_textbox(NULL, "Can't create file!", 5, 60);
954 break;
955 case 1:
956 show_helptext("Save Alternate Configuration", save_config_help);
957 break;
958 case KEY_ESC:
959 return;
960 }
961 }
962 }
963
964 static int handle_exit(void)
965 {
966 int res;
967
968 save_and_exit = 1;
969 reset_subtitle();
970 dialog_clear();
971 if (conf_get_changed())
972 res = dialog_yesno(NULL,
973 "Do you wish to save your new configuration?\n"
974 "(Press <ESC><ESC> to continue kernel configuration.)",
975 6, 60);
976 else
977 res = -1;
978
979 end_dialog(saved_x, saved_y);
980
981 switch (res) {
982 case 0:
983 if (conf_write(filename)) {
984 fprintf(stderr, "\n\n"
985 "Error while writing of the configuration.\n"
986 "Your configuration changes were NOT saved."
987 "\n\n");
988 return 1;
989 }
990 conf_write_autoconf(0);
991 /* fall through */
992 case -1:
993 if (!silent)
994 printf("\n\n"
995 "*** End of the configuration.\n"
996 "*** Execute 'make' to start the build or try 'make help'."
997 "\n\n");
998 res = 0;
999 break;
1000 default:
1001 if (!silent)
1002 fprintf(stderr, "\n\n"
1003 "Your configuration changes were NOT saved."
1004 "\n\n");
1005 if (res != KEY_ESC)
1006 res = 0;
1007 }
1008
1009 return res;
1010 }
1011
1012 static void sig_handler(int signo)
1013 {
1014 exit(handle_exit());
1015 }
1016
1017 int main(int ac, char **av)
1018 {
1019 char *mode;
1020 int res;
1021
1022 signal(SIGINT, sig_handler);
1023
1024 if (ac > 1 && strcmp(av[1], "-s") == 0) {
1025 silent = 1;
1026 /* Silence conf_read() until the real callback is set up */
1027 conf_set_message_callback(NULL);
1028 av++;
1029 }
1030 conf_parse(av[1]);
1031 conf_read(NULL);
1032
1033 mode = getenv("MENUCONFIG_MODE");
1034 if (mode) {
1035 if (!strcasecmp(mode, "single_menu"))
1036 single_menu_mode = 1;
1037 }
1038
1039 if (init_dialog(NULL)) {
1040 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
1041 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
1042 return 1;
1043 }
1044
1045 set_config_filename(conf_get_configname());
1046 conf_set_message_callback(conf_message_callback);
1047 do {
1048 conf(&rootmenu, NULL);
1049 res = handle_exit();
1050 } while (res == KEY_ESC);
1051
1052 return res;
1053 }