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