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 <sys/ioctl.h> 12 #include <sys/wait.h> 13 #include <ctype.h> 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <limits.h> 17 #include <signal.h> 18 #include <stdarg.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <termios.h> 22 #include <unistd.h> 23 #include <locale.h> 24 25 #define LKC_DIRECT_LINK 26 #include "lkc.h" 27 28 static char menu_backtitle[128]; 29 static const char mconf_readme[] = N_( 30 "Overview\n" 31 "--------\n" 32 "Some kernel features may be built directly into the kernel.\n" 33 "Some may be made into loadable runtime modules. Some features\n" 34 "may be completely removed altogether. There are also certain\n" 35 "kernel parameters which are not really features, but must be\n" 36 "entered in as decimal or hexadecimal numbers or possibly text.\n" 37 "\n" 38 "Menu items beginning with [*], <M> or [ ] represent features\n" 39 "configured to be built in, modularized or removed respectively.\n" 40 "Pointed brackets <> represent module capable features.\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 removed it. You may also press the <Space Bar> to cycle\n" 45 "through the available options (ie. 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\n" 52 " you wish to change or submenu wish to select and press <Enter>.\n" 53 " Submenus are designated 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> and <Help>\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 "\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 <SPACE BAR> and <B> for those\n" 109 " who are familiar with less and lynx.\n" 110 "\n" 111 "o Press <E>, <X>, <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 kernel 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 kernel options listed in a single\n" 152 "menu, rather than the default multimenu hierarchy, run the menuconfig\n" 153 "with 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. (default)\n" 175 "\n"), 176 menu_instructions[] = N_( 177 "Arrow keys navigate the menu. " 178 "<Enter> selects submenus --->. " 179 "Highlighted letters are hotkeys. " 180 "Pressing <Y> includes, <N> excludes, <M> modularizes features. " 181 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. " 182 "Legend: [*] built-in [ ] excluded <M> module < > module capable"), 183 radiolist_instructions[] = N_( 184 "Use the arrow keys to navigate this window or " 185 "press the hotkey of the item you wish to select " 186 "followed by the <SPACE BAR>. " 187 "Press <?> for additional information about this option."), 188 inputbox_instructions_int[] = N_( 189 "Please enter a decimal value. " 190 "Fractions will not be accepted. " 191 "Use the <TAB> key to move from the input field to the buttons below it."), 192 inputbox_instructions_hex[] = N_( 193 "Please enter a hexadecimal value. " 194 "Use the <TAB> key to move from the input field to the buttons below it."), 195 inputbox_instructions_string[] = N_( 196 "Please enter a string value. " 197 "Use the <TAB> key to move from the input field to the buttons below it."), 198 setmod_text[] = N_( 199 "This feature depends on another which has been configured as a module.\n" 200 "As a result, this feature will be built as a module."), 201 nohelp_text[] = N_( 202 "There is no help available for this kernel option.\n"), 203 load_config_text[] = N_( 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[] = N_( 208 "\n" 209 "For various reasons, one may wish to keep several different kernel\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 "kernel's default, entering the name of the file here will allow you\n" 214 "to modify that configuration.\n" 215 "\n" 216 "If you are uncertain, then you have probably never used alternate\n" 217 "configuration files. You should therefor leave this blank to abort.\n"), 218 save_config_text[] = N_( 219 "Enter a filename to which this configuration should be saved " 220 "as an alternate. Leave blank to abort."), 221 save_config_help[] = N_( 222 "\n" 223 "For various reasons, one may wish to keep different kernel\n" 224 "configurations 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[] = N_( 233 "\n" 234 "Search for CONFIG_ 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 "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, MCA, ISA)\n" 245 " -> PCI support (PCI [=y])\n" 246 " -> PCI access mode (<choice> [=y])\n" 247 "Selects: LIBCRC32\n" 248 "Selected by: BAR\n" 249 "-----------------------------------------------------------------\n" 250 "o The line 'Prompt:' shows the text used in the menu structure for\n" 251 " this CONFIG_ symbol\n" 252 "o The 'Defined at' line tell at what file / line number the symbol\n" 253 " is defined\n" 254 "o The 'Depends on:' line tell what symbols needs to be defined for\n" 255 " this symbol to be visible in the menu (selectable)\n" 256 "o The 'Location:' lines tell where in the menu structure this symbol\n" 257 " is located\n" 258 " A location followed by a [=y] indicate that this is a selectable\n" 259 " menu item - and current value is displayed inside brackets.\n" 260 "o The 'Selects:' line tell what symbol will be automatically\n" 261 " selected if this symbol is selected (y or m)\n" 262 "o The 'Selected by' line tell what symbol has selected this symbol\n" 263 "\n" 264 "Only relevant lines are shown.\n" 265 "\n\n" 266 "Search examples:\n" 267 "Examples: USB => find all CONFIG_ symbols containing USB\n" 268 " ^USB => find all CONFIG_ symbols starting with USB\n" 269 " USB$ => find all CONFIG_ symbols ending with USB\n" 270 "\n"); 271 272 static char buf[4096], *bufptr = buf; 273 static char input_buf[4096]; 274 static char filename[PATH_MAX+1] = ".config"; 275 static char *args[1024], **argptr = args; 276 static int indent; 277 static struct termios ios_org; 278 static int rows = 0, cols = 0; 279 static struct menu *current_menu; 280 static int child_count; 281 static int do_resize; 282 static int single_menu_mode; 283 284 static void conf(struct menu *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 void show_textbox(const char *title, const char *text, int r, int c); 290 static void show_helptext(const char *title, const char *text); 291 static void show_help(struct menu *menu); 292 static void show_file(const char *filename, const char *title, int r, int c); 293 294 static void cprint_init(void); 295 static int cprint1(const char *fmt, ...); 296 static void cprint_done(void); 297 static int cprint(const char *fmt, ...); 298 299 static void init_wsize(void) 300 { 301 struct winsize ws; 302 char *env; 303 304 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) { 305 rows = ws.ws_row; 306 cols = ws.ws_col; 307 } 308 309 if (!rows) { 310 env = getenv("LINES"); 311 if (env) 312 rows = atoi(env); 313 if (!rows) 314 rows = 24; 315 } 316 if (!cols) { 317 env = getenv("COLUMNS"); 318 if (env) 319 cols = atoi(env); 320 if (!cols) 321 cols = 80; 322 } 323 324 if (rows < 19 || cols < 80) { 325 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); 326 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); 327 exit(1); 328 } 329 330 rows -= 4; 331 cols -= 5; 332 } 333 334 static void cprint_init(void) 335 { 336 bufptr = buf; 337 argptr = args; 338 memset(args, 0, sizeof(args)); 339 indent = 0; 340 child_count = 0; 341 cprint("./scripts/kconfig/lxdialog/lxdialog"); 342 cprint("--backtitle"); 343 cprint(menu_backtitle); 344 } 345 346 static int cprint1(const char *fmt, ...) 347 { 348 va_list ap; 349 int res; 350 351 if (!*argptr) 352 *argptr = bufptr; 353 va_start(ap, fmt); 354 res = vsprintf(bufptr, fmt, ap); 355 va_end(ap); 356 bufptr += res; 357 358 return res; 359 } 360 361 static void cprint_done(void) 362 { 363 *bufptr++ = 0; 364 argptr++; 365 } 366 367 static int cprint(const char *fmt, ...) 368 { 369 va_list ap; 370 int res; 371 372 *argptr++ = bufptr; 373 va_start(ap, fmt); 374 res = vsprintf(bufptr, fmt, ap); 375 va_end(ap); 376 bufptr += res; 377 *bufptr++ = 0; 378 379 return res; 380 } 381 382 static void get_prompt_str(struct gstr *r, struct property *prop) 383 { 384 int i, j; 385 struct menu *submenu[8], *menu; 386 387 str_printf(r, "Prompt: %s\n", prop->text); 388 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, 389 prop->menu->lineno); 390 if (!expr_is_yes(prop->visible.expr)) { 391 str_append(r, " Depends on: "); 392 expr_gstr_print(prop->visible.expr, r); 393 str_append(r, "\n"); 394 } 395 menu = prop->menu->parent; 396 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) 397 submenu[i++] = menu; 398 if (i > 0) { 399 str_printf(r, " Location:\n"); 400 for (j = 4; --i >= 0; j += 2) { 401 menu = submenu[i]; 402 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); 403 if (menu->sym) { 404 str_printf(r, " (%s [=%s])", menu->sym->name ? 405 menu->sym->name : "<choice>", 406 sym_get_string_value(menu->sym)); 407 } 408 str_append(r, "\n"); 409 } 410 } 411 } 412 413 static void get_symbol_str(struct gstr *r, struct symbol *sym) 414 { 415 bool hit; 416 struct property *prop; 417 418 str_printf(r, "Symbol: %s [=%s]\n", sym->name, 419 sym_get_string_value(sym)); 420 for_all_prompts(sym, prop) 421 get_prompt_str(r, prop); 422 hit = false; 423 for_all_properties(sym, prop, P_SELECT) { 424 if (!hit) { 425 str_append(r, " Selects: "); 426 hit = true; 427 } else 428 str_printf(r, " && "); 429 expr_gstr_print(prop->expr, r); 430 } 431 if (hit) 432 str_append(r, "\n"); 433 if (sym->rev_dep.expr) { 434 str_append(r, " Selected by: "); 435 expr_gstr_print(sym->rev_dep.expr, r); 436 str_append(r, "\n"); 437 } 438 str_append(r, "\n\n"); 439 } 440 441 static struct gstr get_relations_str(struct symbol **sym_arr) 442 { 443 struct symbol *sym; 444 struct gstr res = str_new(); 445 int i; 446 447 for (i = 0; sym_arr && (sym = sym_arr[i]); i++) 448 get_symbol_str(&res, sym); 449 if (!i) 450 str_append(&res, "No matches found.\n"); 451 return res; 452 } 453 454 pid_t pid; 455 456 static void winch_handler(int sig) 457 { 458 if (!do_resize) { 459 kill(pid, SIGINT); 460 do_resize = 1; 461 } 462 } 463 464 static int exec_conf(void) 465 { 466 int pipefd[2], stat, size; 467 struct sigaction sa; 468 sigset_t sset, osset; 469 470 sigemptyset(&sset); 471 sigaddset(&sset, SIGINT); 472 sigprocmask(SIG_BLOCK, &sset, &osset); 473 474 signal(SIGINT, SIG_DFL); 475 476 sa.sa_handler = winch_handler; 477 sigemptyset(&sa.sa_mask); 478 sa.sa_flags = SA_RESTART; 479 sigaction(SIGWINCH, &sa, NULL); 480 481 *argptr++ = NULL; 482 483 pipe(pipefd); 484 pid = fork(); 485 if (pid == 0) { 486 sigprocmask(SIG_SETMASK, &osset, NULL); 487 dup2(pipefd[1], 2); 488 close(pipefd[0]); 489 close(pipefd[1]); 490 execv(args[0], args); 491 _exit(EXIT_FAILURE); 492 } 493 494 close(pipefd[1]); 495 bufptr = input_buf; 496 while (1) { 497 size = input_buf + sizeof(input_buf) - bufptr; 498 size = read(pipefd[0], bufptr, size); 499 if (size <= 0) { 500 if (size < 0) { 501 if (errno == EINTR || errno == EAGAIN) 502 continue; 503 perror("read"); 504 } 505 break; 506 } 507 bufptr += size; 508 } 509 *bufptr++ = 0; 510 close(pipefd[0]); 511 waitpid(pid, &stat, 0); 512 513 if (do_resize) { 514 init_wsize(); 515 do_resize = 0; 516 sigprocmask(SIG_SETMASK, &osset, NULL); 517 return -1; 518 } 519 if (WIFSIGNALED(stat)) { 520 printf("\finterrupted(%d)\n", WTERMSIG(stat)); 521 exit(1); 522 } 523 #if 0 524 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf); 525 sleep(1); 526 #endif 527 sigpending(&sset); 528 if (sigismember(&sset, SIGINT)) { 529 printf("\finterrupted\n"); 530 exit(1); 531 } 532 sigprocmask(SIG_SETMASK, &osset, NULL); 533 534 return WEXITSTATUS(stat); 535 } 536 537 static void search_conf(void) 538 { 539 struct symbol **sym_arr; 540 int stat; 541 struct gstr res; 542 543 again: 544 cprint_init(); 545 cprint("--title"); 546 cprint(_("Search Configuration Parameter")); 547 cprint("--inputbox"); 548 cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)")); 549 cprint("10"); 550 cprint("75"); 551 cprint(""); 552 stat = exec_conf(); 553 if (stat < 0) 554 goto again; 555 switch (stat) { 556 case 0: 557 break; 558 case 1: 559 show_helptext(_("Search Configuration"), search_help); 560 goto again; 561 default: 562 return; 563 } 564 565 sym_arr = sym_re_search(input_buf); 566 res = get_relations_str(sym_arr); 567 free(sym_arr); 568 show_textbox(_("Search Results"), str_get(&res), 0, 0); 569 str_free(&res); 570 } 571 572 static void build_conf(struct menu *menu) 573 { 574 struct symbol *sym; 575 struct property *prop; 576 struct menu *child; 577 int type, tmp, doint = 2; 578 tristate val; 579 char ch; 580 581 if (!menu_is_visible(menu)) 582 return; 583 584 sym = menu->sym; 585 prop = menu->prompt; 586 if (!sym) { 587 if (prop && menu != current_menu) { 588 const char *prompt = menu_get_prompt(menu); 589 switch (prop->type) { 590 case P_MENU: 591 child_count++; 592 cprint("m%p", menu); 593 594 if (single_menu_mode) { 595 cprint1("%s%*c%s", 596 menu->data ? "-->" : "++>", 597 indent + 1, ' ', prompt); 598 } else 599 cprint1(" %*c%s --->", indent + 1, ' ', prompt); 600 601 cprint_done(); 602 if (single_menu_mode && menu->data) 603 goto conf_childs; 604 return; 605 default: 606 if (prompt) { 607 child_count++; 608 cprint(":%p", menu); 609 cprint("---%*c%s", indent + 1, ' ', prompt); 610 } 611 } 612 } else 613 doint = 0; 614 goto conf_childs; 615 } 616 617 type = sym_get_type(sym); 618 if (sym_is_choice(sym)) { 619 struct symbol *def_sym = sym_get_choice_value(sym); 620 struct menu *def_menu = NULL; 621 622 child_count++; 623 for (child = menu->list; child; child = child->next) { 624 if (menu_is_visible(child) && child->sym == def_sym) 625 def_menu = child; 626 } 627 628 val = sym_get_tristate_value(sym); 629 if (sym_is_changable(sym)) { 630 cprint("t%p", menu); 631 switch (type) { 632 case S_BOOLEAN: 633 cprint1("[%c]", val == no ? ' ' : '*'); 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 cprint1("<%c>", ch); 642 break; 643 } 644 } else { 645 cprint("%c%p", def_menu ? 't' : ':', menu); 646 cprint1(" "); 647 } 648 649 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); 650 if (val == yes) { 651 if (def_menu) { 652 cprint1(" (%s)", menu_get_prompt(def_menu)); 653 cprint1(" --->"); 654 cprint_done(); 655 if (def_menu->list) { 656 indent += 2; 657 build_conf(def_menu); 658 indent -= 2; 659 } 660 } else 661 cprint_done(); 662 return; 663 } 664 cprint_done(); 665 } else { 666 if (menu == current_menu) { 667 cprint(":%p", menu); 668 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); 669 goto conf_childs; 670 } 671 child_count++; 672 val = sym_get_tristate_value(sym); 673 if (sym_is_choice_value(sym) && val == yes) { 674 cprint(":%p", menu); 675 cprint1(" "); 676 } else { 677 switch (type) { 678 case S_BOOLEAN: 679 cprint("t%p", menu); 680 if (sym_is_changable(sym)) 681 cprint1("[%c]", val == no ? ' ' : '*'); 682 else 683 cprint1("---"); 684 break; 685 case S_TRISTATE: 686 cprint("t%p", menu); 687 switch (val) { 688 case yes: ch = '*'; break; 689 case mod: ch = 'M'; break; 690 default: ch = ' '; break; 691 } 692 if (sym_is_changable(sym)) 693 cprint1("<%c>", ch); 694 else 695 cprint1("---"); 696 break; 697 default: 698 cprint("s%p", menu); 699 tmp = cprint1("(%s)", sym_get_string_value(sym)); 700 tmp = indent - tmp + 4; 701 if (tmp < 0) 702 tmp = 0; 703 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu), 704 (sym_has_value(sym) || !sym_is_changable(sym)) ? 705 "" : " (NEW)"); 706 cprint_done(); 707 goto conf_childs; 708 } 709 } 710 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), 711 (sym_has_value(sym) || !sym_is_changable(sym)) ? 712 "" : " (NEW)"); 713 if (menu->prompt->type == P_MENU) { 714 cprint1(" --->"); 715 cprint_done(); 716 return; 717 } 718 cprint_done(); 719 } 720 721 conf_childs: 722 indent += doint; 723 for (child = menu->list; child; child = child->next) 724 build_conf(child); 725 indent -= doint; 726 } 727 728 static void conf(struct menu *menu) 729 { 730 struct menu *submenu; 731 const char *prompt = menu_get_prompt(menu); 732 struct symbol *sym; 733 char active_entry[40]; 734 int stat, type, i; 735 736 unlink("lxdialog.scrltmp"); 737 active_entry[0] = 0; 738 while (1) { 739 cprint_init(); 740 cprint("--title"); 741 cprint("%s", prompt ? prompt : _("Main Menu")); 742 cprint("--menu"); 743 cprint(_(menu_instructions)); 744 cprint("%d", rows); 745 cprint("%d", cols); 746 cprint("%d", rows - 10); 747 cprint("%s", active_entry); 748 current_menu = menu; 749 build_conf(menu); 750 if (!child_count) 751 break; 752 if (menu == &rootmenu) { 753 cprint(":"); 754 cprint("--- "); 755 cprint("L"); 756 cprint(_(" Load an Alternate Configuration File")); 757 cprint("S"); 758 cprint(_(" Save Configuration to an Alternate File")); 759 } 760 stat = exec_conf(); 761 if (stat < 0) 762 continue; 763 764 if (stat == 1 || stat == 255) 765 break; 766 767 type = input_buf[0]; 768 if (!type) 769 continue; 770 771 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++) 772 ; 773 if (i >= sizeof(active_entry)) 774 i = sizeof(active_entry) - 1; 775 input_buf[i] = 0; 776 strcpy(active_entry, input_buf); 777 778 sym = NULL; 779 submenu = NULL; 780 if (sscanf(input_buf + 1, "%p", &submenu) == 1) 781 sym = submenu->sym; 782 783 switch (stat) { 784 case 0: 785 switch (type) { 786 case 'm': 787 if (single_menu_mode) 788 submenu->data = (void *) (long) !submenu->data; 789 else 790 conf(submenu); 791 break; 792 case 't': 793 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) 794 conf_choice(submenu); 795 else if (submenu->prompt->type == P_MENU) 796 conf(submenu); 797 break; 798 case 's': 799 conf_string(submenu); 800 break; 801 case 'L': 802 conf_load(); 803 break; 804 case 'S': 805 conf_save(); 806 break; 807 } 808 break; 809 case 2: 810 if (sym) 811 show_help(submenu); 812 else 813 show_helptext("README", _(mconf_readme)); 814 break; 815 case 3: 816 if (type == 't') { 817 if (sym_set_tristate_value(sym, yes)) 818 break; 819 if (sym_set_tristate_value(sym, mod)) 820 show_textbox(NULL, setmod_text, 6, 74); 821 } 822 break; 823 case 4: 824 if (type == 't') 825 sym_set_tristate_value(sym, no); 826 break; 827 case 5: 828 if (type == 't') 829 sym_set_tristate_value(sym, mod); 830 break; 831 case 6: 832 if (type == 't') 833 sym_toggle_tristate_value(sym); 834 else if (type == 'm') 835 conf(submenu); 836 break; 837 case 7: 838 search_conf(); 839 break; 840 } 841 } 842 } 843 844 static void show_textbox(const char *title, const char *text, int r, int c) 845 { 846 int fd; 847 848 fd = creat(".help.tmp", 0777); 849 write(fd, text, strlen(text)); 850 close(fd); 851 show_file(".help.tmp", title, r, c); 852 unlink(".help.tmp"); 853 } 854 855 static void show_helptext(const char *title, const char *text) 856 { 857 show_textbox(title, text, 0, 0); 858 } 859 860 static void show_help(struct menu *menu) 861 { 862 struct gstr help = str_new(); 863 struct symbol *sym = menu->sym; 864 865 if (sym->help) 866 { 867 if (sym->name) { 868 str_printf(&help, "CONFIG_%s:\n\n", sym->name); 869 str_append(&help, _(sym->help)); 870 str_append(&help, "\n"); 871 } 872 } else { 873 str_append(&help, nohelp_text); 874 } 875 get_symbol_str(&help, sym); 876 show_helptext(menu_get_prompt(menu), str_get(&help)); 877 str_free(&help); 878 } 879 880 static void show_file(const char *filename, const char *title, int r, int c) 881 { 882 do { 883 cprint_init(); 884 if (title) { 885 cprint("--title"); 886 cprint("%s", title); 887 } 888 cprint("--textbox"); 889 cprint("%s", filename); 890 cprint("%d", r ? r : rows); 891 cprint("%d", c ? c : cols); 892 } while (exec_conf() < 0); 893 } 894 895 static void conf_choice(struct menu *menu) 896 { 897 const char *prompt = menu_get_prompt(menu); 898 struct menu *child; 899 struct symbol *active; 900 int stat; 901 902 active = sym_get_choice_value(menu->sym); 903 while (1) { 904 cprint_init(); 905 cprint("--title"); 906 cprint("%s", prompt ? prompt : _("Main Menu")); 907 cprint("--radiolist"); 908 cprint(_(radiolist_instructions)); 909 cprint("15"); 910 cprint("70"); 911 cprint("6"); 912 913 current_menu = menu; 914 for (child = menu->list; child; child = child->next) { 915 if (!menu_is_visible(child)) 916 continue; 917 cprint("%p", child); 918 cprint("%s", menu_get_prompt(child)); 919 if (child->sym == sym_get_choice_value(menu->sym)) 920 cprint("ON"); 921 else if (child->sym == active) 922 cprint("SELECTED"); 923 else 924 cprint("OFF"); 925 } 926 927 stat = exec_conf(); 928 switch (stat) { 929 case 0: 930 if (sscanf(input_buf, "%p", &child) != 1) 931 break; 932 sym_set_tristate_value(child->sym, yes); 933 return; 934 case 1: 935 if (sscanf(input_buf, "%p", &child) == 1) { 936 show_help(child); 937 active = child->sym; 938 } else 939 show_help(menu); 940 break; 941 case 255: 942 return; 943 } 944 } 945 } 946 947 static void conf_string(struct menu *menu) 948 { 949 const char *prompt = menu_get_prompt(menu); 950 int stat; 951 952 while (1) { 953 cprint_init(); 954 cprint("--title"); 955 cprint("%s", prompt ? prompt : _("Main Menu")); 956 cprint("--inputbox"); 957 switch (sym_get_type(menu->sym)) { 958 case S_INT: 959 cprint(_(inputbox_instructions_int)); 960 break; 961 case S_HEX: 962 cprint(_(inputbox_instructions_hex)); 963 break; 964 case S_STRING: 965 cprint(_(inputbox_instructions_string)); 966 break; 967 default: 968 /* panic? */; 969 } 970 cprint("10"); 971 cprint("75"); 972 cprint("%s", sym_get_string_value(menu->sym)); 973 stat = exec_conf(); 974 switch (stat) { 975 case 0: 976 if (sym_set_string_value(menu->sym, input_buf)) 977 return; 978 show_textbox(NULL, _("You have made an invalid entry."), 5, 43); 979 break; 980 case 1: 981 show_help(menu); 982 break; 983 case 255: 984 return; 985 } 986 } 987 } 988 989 static void conf_load(void) 990 { 991 int stat; 992 993 while (1) { 994 cprint_init(); 995 cprint("--inputbox"); 996 cprint(load_config_text); 997 cprint("11"); 998 cprint("55"); 999 cprint("%s", filename); 1000 stat = exec_conf(); 1001 switch(stat) { 1002 case 0: 1003 if (!input_buf[0]) 1004 return; 1005 if (!conf_read(input_buf)) 1006 return; 1007 show_textbox(NULL, _("File does not exist!"), 5, 38); 1008 break; 1009 case 1: 1010 show_helptext(_("Load Alternate Configuration"), load_config_help); 1011 break; 1012 case 255: 1013 return; 1014 } 1015 } 1016 } 1017 1018 static void conf_save(void) 1019 { 1020 int stat; 1021 1022 while (1) { 1023 cprint_init(); 1024 cprint("--inputbox"); 1025 cprint(save_config_text); 1026 cprint("11"); 1027 cprint("55"); 1028 cprint("%s", filename); 1029 stat = exec_conf(); 1030 switch(stat) { 1031 case 0: 1032 if (!input_buf[0]) 1033 return; 1034 if (!conf_write(input_buf)) 1035 return; 1036 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); 1037 break; 1038 case 1: 1039 show_helptext(_("Save Alternate Configuration"), save_config_help); 1040 break; 1041 case 255: 1042 return; 1043 } 1044 } 1045 } 1046 1047 static void conf_cleanup(void) 1048 { 1049 tcsetattr(1, TCSAFLUSH, &ios_org); 1050 unlink(".help.tmp"); 1051 unlink("lxdialog.scrltmp"); 1052 } 1053 1054 int main(int ac, char **av) 1055 { 1056 struct symbol *sym; 1057 char *mode; 1058 int stat; 1059 1060 setlocale(LC_ALL, ""); 1061 bindtextdomain(PACKAGE, LOCALEDIR); 1062 textdomain(PACKAGE); 1063 1064 conf_parse(av[1]); 1065 conf_read(NULL); 1066 1067 sym = sym_lookup("KERNELVERSION", 0); 1068 sym_calc_value(sym); 1069 sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"), 1070 sym_get_string_value(sym)); 1071 1072 mode = getenv("MENUCONFIG_MODE"); 1073 if (mode) { 1074 if (!strcasecmp(mode, "single_menu")) 1075 single_menu_mode = 1; 1076 } 1077 1078 tcgetattr(1, &ios_org); 1079 atexit(conf_cleanup); 1080 init_wsize(); 1081 conf(&rootmenu); 1082 1083 do { 1084 cprint_init(); 1085 cprint("--yesno"); 1086 cprint(_("Do you wish to save your new kernel configuration?")); 1087 cprint("5"); 1088 cprint("60"); 1089 stat = exec_conf(); 1090 } while (stat < 0); 1091 1092 if (stat == 0) { 1093 if (conf_write(NULL)) { 1094 fprintf(stderr, _("\n\n" 1095 "Error during writing of the kernel configuration.\n" 1096 "Your kernel configuration changes were NOT saved." 1097 "\n\n")); 1098 return 1; 1099 } 1100 printf(_("\n\n" 1101 "*** End of Linux kernel configuration.\n" 1102 "*** Execute 'make' to build the kernel or try 'make help'." 1103 "\n\n")); 1104 } else { 1105 fprintf(stderr, _("\n\n" 1106 "Your kernel configuration changes were NOT saved." 1107 "\n\n")); 1108 } 1109 1110 return 0; 1111 } 1112