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