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