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