base/config/kconfig/mconf.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 00003 * Released under the terms of the GNU GPL v2.0. 00004 * 00005 * Introduced single menu mode (show all sub-menus in one large tree). 00006 * 2002-11-06 Petr Baudis <pasky@ucw.cz> 00007 */ 00008 00009 #include <sys/ioctl.h> 00010 #include <sys/wait.h> 00011 #include <ctype.h> 00012 #include <errno.h> 00013 #include <fcntl.h> 00014 #include <limits.h> 00015 #include <signal.h> 00016 #include <stdarg.h> 00017 #include <stdlib.h> 00018 #include <string.h> 00019 #include <termios.h> 00020 #include <unistd.h> 00021 00022 #define LKC_DIRECT_LINK 00023 #include "lkc.h" 00024 00025 static char menu_backtitle[128]; 00026 static const char menu_instructions[] = 00027 "Arrow keys navigate the menu. " 00028 "<Enter> selects submenus --->. " 00029 "Highlighted letters are hotkeys. " 00030 "Pressing <Y> includes, <N> excludes, <M> modularizes features. " 00031 "Press <Esc><Esc> to exit, <?> for Help. " 00032 "Legend: [*] built-in [ ] excluded <M> module < > module capable", 00033 radiolist_instructions[] = 00034 "Use the arrow keys to navigate this window or " 00035 "press the hotkey of the item you wish to select " 00036 "followed by the <SPACE BAR>. " 00037 "Press <?> for additional information about this option.", 00038 inputbox_instructions_int[] = 00039 "Please enter a decimal value. " 00040 "Fractions will not be accepted. " 00041 "Use the <TAB> key to move from the input field to the buttons below it.", 00042 inputbox_instructions_hex[] = 00043 "Please enter a hexadecimal value. " 00044 "Use the <TAB> key to move from the input field to the buttons below it.", 00045 inputbox_instructions_string[] = 00046 "Please enter a string value. " 00047 "Use the <TAB> key to move from the input field to the buttons below it.", 00048 setmod_text[] = 00049 "This feature depends on another which has been configured as a module.\n" 00050 "As a result, this feature will be built as a module.", 00051 nohelp_text[] = 00052 "There is no help available for this RTAI option.\n", 00053 load_config_text[] = 00054 "Enter the name of the configuration file you wish to load. " 00055 "Accept the name shown to restore the configuration you " 00056 "last retrieved. Leave blank to abort.", 00057 load_config_help[] = 00058 "\n" 00059 "For various reasons, one may wish to keep several different RTAI\n" 00060 "configurations available on a single machine.\n" 00061 "\n" 00062 "If you have saved a previous configuration in a file other than\n" 00063 "RTAI's default, entering the name of the file here will allow you\n" 00064 "to modify that configuration.\n" 00065 "\n" 00066 "If you are uncertain, then you have probably never used alternate\n" 00067 "configuration files. You should therefor leave this blank to abort.\n", 00068 save_config_text[] = 00069 "Enter a filename to which this configuration should be saved " 00070 "as an alternate. Leave blank to abort.", 00071 save_config_help[] = 00072 "\n" 00073 "For various reasons, one may wish to keep different RTAI\n" 00074 "configurations available on a single machine.\n" 00075 "\n" 00076 "Entering a file name here will allow you to later retrieve, modify\n" 00077 "and use the current configuration as an alternate to whatever\n" 00078 "configuration options you have selected at that time.\n" 00079 "\n" 00080 "If you are uncertain what all this means then you should probably\n" 00081 "leave this blank.\n" 00082 ; 00083 00084 static char buf[4096], *bufptr = buf; 00085 static char input_buf[4096]; 00086 static char filename[PATH_MAX+1] = ".config"; 00087 static char *args[1024], **argptr = args; 00088 static int indent = 0; 00089 static struct termios ios_org; 00090 static int rows, cols; 00091 static struct menu *curr_menu; 00092 static int child_count; 00093 static int do_resize; 00094 static int single_menu_mode; 00095 00096 static void conf(struct menu *menu); 00097 static void conf_choice(struct menu *menu); 00098 static void conf_string(struct menu *menu); 00099 static void conf_load(void); 00100 static void conf_save(void); 00101 static void show_textbox(const char *title, const char *text, int r, int c); 00102 static void show_helptext(const char *title, const char *text); 00103 static void show_help(struct menu *menu); 00104 static void show_readme(void); 00105 00106 static void cprint_init(void); 00107 static int cprint1(const char *fmt, ...); 00108 static void cprint_done(void); 00109 static int cprint(const char *fmt, ...); 00110 00111 static void init_wsize(void) 00112 { 00113 struct winsize ws; 00114 char *env; 00115 00116 if (ioctl(1, TIOCGWINSZ, &ws) == -1) { 00117 rows = 24; 00118 cols = 80; 00119 } else { 00120 rows = ws.ws_row; 00121 cols = ws.ws_col; 00122 if (!rows) { 00123 env = getenv("LINES"); 00124 if (env) 00125 rows = atoi(env); 00126 if (!rows) 00127 rows = 24; 00128 } 00129 if (!cols) { 00130 env = getenv("COLUMNS"); 00131 if (env) 00132 cols = atoi(env); 00133 if (!cols) 00134 cols = 80; 00135 } 00136 } 00137 00138 if (rows < 19 || cols < 80) { 00139 fprintf(stderr, "Your display is too small to run Menuconfig!\n"); 00140 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); 00141 exit(1); 00142 } 00143 00144 rows -= 4; 00145 cols -= 5; 00146 } 00147 00148 static void cprint_init(void) 00149 { 00150 bufptr = buf; 00151 argptr = args; 00152 memset(args, 0, sizeof(args)); 00153 indent = 0; 00154 child_count = 0; 00155 cprint("./lxdialog/lxdialog"); 00156 cprint("--backtitle"); 00157 cprint(menu_backtitle); 00158 } 00159 00160 static int cprint1(const char *fmt, ...) 00161 { 00162 va_list ap; 00163 int res; 00164 00165 if (!*argptr) 00166 *argptr = bufptr; 00167 va_start(ap, fmt); 00168 res = vsprintf(bufptr, fmt, ap); 00169 va_end(ap); 00170 bufptr += res; 00171 00172 return res; 00173 } 00174 00175 static void cprint_done(void) 00176 { 00177 *bufptr++ = 0; 00178 argptr++; 00179 } 00180 00181 static int cprint(const char *fmt, ...) 00182 { 00183 va_list ap; 00184 int res; 00185 00186 *argptr++ = bufptr; 00187 va_start(ap, fmt); 00188 res = vsprintf(bufptr, fmt, ap); 00189 va_end(ap); 00190 bufptr += res; 00191 *bufptr++ = 0; 00192 00193 return res; 00194 } 00195 00196 pid_t pid; 00197 00198 static void winch_handler(int sig) 00199 { 00200 if (!do_resize) { 00201 kill(pid, SIGINT); 00202 do_resize = 1; 00203 } 00204 } 00205 00206 static int exec_conf(void) 00207 { 00208 int pipefd[2], stat, size; 00209 struct sigaction sa; 00210 sigset_t sset, osset; 00211 00212 sigemptyset(&sset); 00213 sigaddset(&sset, SIGINT); 00214 sigprocmask(SIG_BLOCK, &sset, &osset); 00215 00216 signal(SIGINT, SIG_DFL); 00217 00218 sa.sa_handler = winch_handler; 00219 sigemptyset(&sa.sa_mask); 00220 sa.sa_flags = SA_RESTART; 00221 sigaction(SIGWINCH, &sa, NULL); 00222 00223 *argptr++ = NULL; 00224 00225 pipe(pipefd); 00226 pid = fork(); 00227 if (pid == 0) { 00228 sigprocmask(SIG_SETMASK, &osset, NULL); 00229 dup2(pipefd[1], 2); 00230 close(pipefd[0]); 00231 close(pipefd[1]); 00232 execv(args[0], args); 00233 _exit(EXIT_FAILURE); 00234 } 00235 00236 close(pipefd[1]); 00237 bufptr = input_buf; 00238 while (1) { 00239 size = input_buf + sizeof(input_buf) - bufptr; 00240 size = read(pipefd[0], bufptr, size); 00241 if (size <= 0) { 00242 if (size < 0) { 00243 if (errno == EINTR || errno == EAGAIN) 00244 continue; 00245 perror("read"); 00246 } 00247 break; 00248 } 00249 bufptr += size; 00250 } 00251 *bufptr++ = 0; 00252 close(pipefd[0]); 00253 waitpid(pid, &stat, 0); 00254 00255 if (do_resize) { 00256 init_wsize(); 00257 do_resize = 0; 00258 sigprocmask(SIG_SETMASK, &osset, NULL); 00259 return -1; 00260 } 00261 if (WIFSIGNALED(stat)) { 00262 printf("\finterrupted(%d)\n", WTERMSIG(stat)); 00263 exit(1); 00264 } 00265 #if 0 00266 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf); 00267 sleep(1); 00268 #endif 00269 sigpending(&sset); 00270 if (sigismember(&sset, SIGINT)) { 00271 printf("\finterrupted\n"); 00272 exit(1); 00273 } 00274 sigprocmask(SIG_SETMASK, &osset, NULL); 00275 00276 return WEXITSTATUS(stat); 00277 } 00278 00279 static void build_conf(struct menu *menu) 00280 { 00281 struct symbol *sym; 00282 struct property *prop; 00283 struct menu *child; 00284 int type, tmp, doint = 2; 00285 tristate val; 00286 char ch; 00287 00288 if (!menu_is_visible(menu)) 00289 return; 00290 00291 sym = menu->sym; 00292 prop = menu->prompt; 00293 if (!sym) { 00294 if (prop && menu != curr_menu) { 00295 const char *prompt = menu_get_prompt(menu); 00296 switch (prop->type) { 00297 case P_MENU: 00298 child_count++; 00299 cprint("m%p", menu); 00300 00301 if (single_menu_mode) { 00302 cprint1("%s%*c%s", 00303 menu->data ? "-->" : "++>", 00304 indent + 1, ' ', prompt); 00305 } else 00306 cprint1(" %*c%s --->", indent + 1, ' ', prompt); 00307 00308 cprint_done(); 00309 if (single_menu_mode && menu->data) 00310 goto conf_childs; 00311 return; 00312 default: 00313 if (prompt) { 00314 child_count++; 00315 cprint(":%p", menu); 00316 cprint("---%*c%s", indent + 1, ' ', prompt); 00317 } 00318 } 00319 } else 00320 doint = 0; 00321 goto conf_childs; 00322 } 00323 00324 type = sym_get_type(sym); 00325 if (sym_is_choice(sym)) { 00326 struct symbol *def_sym = sym_get_choice_value(sym); 00327 struct menu *def_menu = NULL; 00328 00329 child_count++; 00330 for (child = menu->list; child; child = child->next) { 00331 if (menu_is_visible(child) && child->sym == def_sym) 00332 def_menu = child; 00333 } 00334 00335 val = sym_get_tristate_value(sym); 00336 if (sym_is_changable(sym)) { 00337 cprint("t%p", menu); 00338 switch (type) { 00339 case S_BOOLEAN: 00340 cprint1("[%c]", val == no ? ' ' : '*'); 00341 break; 00342 case S_TRISTATE: 00343 switch (val) { 00344 case yes: ch = '*'; break; 00345 case mod: ch = 'M'; break; 00346 default: ch = ' '; break; 00347 } 00348 cprint1("<%c>", ch); 00349 break; 00350 } 00351 } else { 00352 cprint("%c%p", def_menu ? 't' : ':', menu); 00353 cprint1(" "); 00354 } 00355 00356 cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); 00357 if (val == yes) { 00358 if (def_menu) { 00359 cprint1(" (%s)", menu_get_prompt(def_menu)); 00360 cprint1(" --->"); 00361 cprint_done(); 00362 if (def_menu->list) { 00363 indent += 2; 00364 build_conf(def_menu); 00365 indent -= 2; 00366 } 00367 } else 00368 cprint_done(); 00369 return; 00370 } 00371 cprint_done(); 00372 } else { 00373 if (menu == curr_menu) { 00374 cprint(":%p", menu); 00375 cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); 00376 goto conf_childs; 00377 } 00378 child_count++; 00379 val = sym_get_tristate_value(sym); 00380 if (sym_is_choice_value(sym) && val == yes) { 00381 cprint(":%p", menu); 00382 cprint1(" "); 00383 } else { 00384 switch (type) { 00385 case S_BOOLEAN: 00386 cprint("t%p", menu); 00387 if (sym_is_changable(sym)) 00388 cprint1("[%c]", val == no ? ' ' : '*'); 00389 else 00390 cprint1("---"); 00391 break; 00392 case S_TRISTATE: 00393 cprint("t%p", menu); 00394 switch (val) { 00395 case yes: ch = '*'; break; 00396 case mod: ch = 'M'; break; 00397 default: ch = ' '; break; 00398 } 00399 if (sym_is_changable(sym)) 00400 cprint1("<%c>", ch); 00401 else 00402 cprint1("---"); 00403 break; 00404 default: 00405 cprint("s%p", menu); 00406 tmp = cprint1("(%s)", sym_get_string_value(sym)); 00407 tmp = indent - tmp + 4; 00408 if (tmp < 0) 00409 tmp = 0; 00410 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu), 00411 (sym_has_value(sym) || !sym_is_changable(sym)) ? 00412 "" : " (NEW)"); 00413 cprint_done(); 00414 goto conf_childs; 00415 } 00416 } 00417 cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), 00418 (sym_has_value(sym) || !sym_is_changable(sym)) ? 00419 "" : " (NEW)"); 00420 if (menu->prompt->type == P_MENU) { 00421 cprint1(" --->"); 00422 cprint_done(); 00423 return; 00424 } 00425 cprint_done(); 00426 } 00427 00428 conf_childs: 00429 indent += doint; 00430 for (child = menu->list; child; child = child->next) 00431 build_conf(child); 00432 indent -= doint; 00433 } 00434 00435 static void conf(struct menu *menu) 00436 { 00437 struct menu *submenu; 00438 const char *prompt = menu_get_prompt(menu); 00439 struct symbol *sym; 00440 char active_entry[40]; 00441 int stat, type, i; 00442 00443 unlink("lxdialog.scrltmp"); 00444 active_entry[0] = 0; 00445 while (1) { 00446 cprint_init(); 00447 cprint("--title"); 00448 cprint("%s", prompt ? prompt : "Main Menu"); 00449 cprint("--menu"); 00450 cprint(menu_instructions); 00451 cprint("%d", rows); 00452 cprint("%d", cols); 00453 cprint("%d", rows - 10); 00454 cprint("%s", active_entry); 00455 curr_menu = menu; 00456 build_conf(menu); 00457 if (!child_count) 00458 break; 00459 if (menu == &rootmenu) { 00460 cprint(":"); 00461 cprint("--- "); 00462 cprint("L"); 00463 cprint(" Load an Alternate Configuration File"); 00464 cprint("S"); 00465 cprint(" Save Configuration to an Alternate File"); 00466 } 00467 stat = exec_conf(); 00468 if (stat < 0) 00469 continue; 00470 00471 if (stat == 1 || stat == 255) 00472 break; 00473 00474 type = input_buf[0]; 00475 if (!type) 00476 continue; 00477 00478 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++) 00479 ; 00480 if (i >= sizeof(active_entry)) 00481 i = sizeof(active_entry) - 1; 00482 input_buf[i] = 0; 00483 strcpy(active_entry, input_buf); 00484 00485 sym = NULL; 00486 submenu = NULL; 00487 if (sscanf(input_buf + 1, "%p", &submenu) == 1) 00488 sym = submenu->sym; 00489 00490 switch (stat) { 00491 case 0: 00492 switch (type) { 00493 case 'm': 00494 if (single_menu_mode) 00495 submenu->data = (void *) (long) !submenu->data; 00496 else 00497 conf(submenu); 00498 break; 00499 case 't': 00500 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) 00501 conf_choice(submenu); 00502 else if (submenu->prompt->type == P_MENU) 00503 conf(submenu); 00504 break; 00505 case 's': 00506 conf_string(submenu); 00507 break; 00508 case 'L': 00509 conf_load(); 00510 break; 00511 case 'S': 00512 conf_save(); 00513 break; 00514 } 00515 break; 00516 case 2: 00517 if (sym) 00518 show_help(submenu); 00519 else 00520 show_readme(); 00521 break; 00522 case 3: 00523 if (type == 't') { 00524 if (sym_set_tristate_value(sym, yes)) 00525 break; 00526 if (sym_set_tristate_value(sym, mod)) 00527 show_textbox(NULL, setmod_text, 6, 74); 00528 } 00529 break; 00530 case 4: 00531 if (type == 't') 00532 sym_set_tristate_value(sym, no); 00533 break; 00534 case 5: 00535 if (type == 't') 00536 sym_set_tristate_value(sym, mod); 00537 break; 00538 case 6: 00539 if (type == 't') 00540 sym_toggle_tristate_value(sym); 00541 else if (type == 'm') 00542 conf(submenu); 00543 break; 00544 } 00545 } 00546 } 00547 00548 static void show_textbox(const char *title, const char *text, int r, int c) 00549 { 00550 int fd; 00551 00552 fd = creat(".help.tmp", 0777); 00553 write(fd, text, strlen(text)); 00554 close(fd); 00555 do { 00556 cprint_init(); 00557 if (title) { 00558 cprint("--title"); 00559 cprint("%s", title); 00560 } 00561 cprint("--textbox"); 00562 cprint(".help.tmp"); 00563 cprint("%d", r); 00564 cprint("%d", c); 00565 } while (exec_conf() < 0); 00566 unlink(".help.tmp"); 00567 } 00568 00569 static void show_helptext(const char *title, const char *text) 00570 { 00571 show_textbox(title, text, rows, cols); 00572 } 00573 00574 static void show_help(struct menu *menu) 00575 { 00576 const char *help; 00577 char *helptext; 00578 struct symbol *sym = menu->sym; 00579 00580 help = sym->help; 00581 if (!help) 00582 help = nohelp_text; 00583 if (sym->name) { 00584 helptext = malloc(strlen(sym->name) + strlen(help) + 16); 00585 sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help); 00586 show_helptext(menu_get_prompt(menu), helptext); 00587 free(helptext); 00588 } else 00589 show_helptext(menu_get_prompt(menu), help); 00590 } 00591 00592 static void show_readme(void) 00593 { 00594 do { 00595 cprint_init(); 00596 cprint("--textbox"); 00597 cprint("scripts/README.Menuconfig"); 00598 cprint("%d", rows); 00599 cprint("%d", cols); 00600 } while (exec_conf() == -1); 00601 } 00602 00603 static void conf_choice(struct menu *menu) 00604 { 00605 const char *prompt = menu_get_prompt(menu); 00606 struct menu *child; 00607 struct symbol *active; 00608 int stat; 00609 00610 while (1) { 00611 cprint_init(); 00612 cprint("--title"); 00613 cprint("%s", prompt ? prompt : "Main Menu"); 00614 cprint("--radiolist"); 00615 cprint(radiolist_instructions); 00616 cprint("15"); 00617 cprint("70"); 00618 cprint("6"); 00619 00620 curr_menu = menu; 00621 active = sym_get_choice_value(menu->sym); 00622 for (child = menu->list; child; child = child->next) { 00623 if (!menu_is_visible(child)) 00624 continue; 00625 cprint("%p", child); 00626 cprint("%s", menu_get_prompt(child)); 00627 cprint(child->sym == active ? "ON" : "OFF"); 00628 } 00629 00630 stat = exec_conf(); 00631 switch (stat) { 00632 case 0: 00633 if (sscanf(input_buf, "%p", &menu) != 1) 00634 break; 00635 sym_set_tristate_value(menu->sym, yes); 00636 return; 00637 case 1: 00638 show_help(menu); 00639 break; 00640 case 255: 00641 return; 00642 } 00643 } 00644 } 00645 00646 static void conf_string(struct menu *menu) 00647 { 00648 const char *prompt = menu_get_prompt(menu); 00649 int stat; 00650 00651 while (1) { 00652 cprint_init(); 00653 cprint("--title"); 00654 cprint("%s", prompt ? prompt : "Main Menu"); 00655 cprint("--inputbox"); 00656 switch (sym_get_type(menu->sym)) { 00657 case S_INT: 00658 cprint(inputbox_instructions_int); 00659 break; 00660 case S_HEX: 00661 cprint(inputbox_instructions_hex); 00662 break; 00663 case S_STRING: 00664 cprint(inputbox_instructions_string); 00665 break; 00666 default: 00667 /* panic? */; 00668 } 00669 cprint("10"); 00670 cprint("75"); 00671 cprint("%s", sym_get_string_value(menu->sym)); 00672 stat = exec_conf(); 00673 switch (stat) { 00674 case 0: 00675 if (sym_set_string_value(menu->sym, input_buf)) 00676 return; 00677 show_textbox(NULL, "You have made an invalid entry.", 5, 43); 00678 break; 00679 case 1: 00680 show_help(menu); 00681 break; 00682 case 255: 00683 return; 00684 } 00685 } 00686 } 00687 00688 static void conf_load(void) 00689 { 00690 int stat; 00691 00692 while (1) { 00693 cprint_init(); 00694 cprint("--inputbox"); 00695 cprint(load_config_text); 00696 cprint("11"); 00697 cprint("55"); 00698 cprint("%s", filename); 00699 stat = exec_conf(); 00700 switch(stat) { 00701 case 0: 00702 if (!input_buf[0]) 00703 return; 00704 if (!conf_read(input_buf)) 00705 return; 00706 show_textbox(NULL, "File does not exist!", 5, 38); 00707 break; 00708 case 1: 00709 show_helptext("Load Alternate Configuration", load_config_help); 00710 break; 00711 case 255: 00712 return; 00713 } 00714 } 00715 } 00716 00717 static void conf_save(void) 00718 { 00719 int stat; 00720 00721 while (1) { 00722 cprint_init(); 00723 cprint("--inputbox"); 00724 cprint(save_config_text); 00725 cprint("11"); 00726 cprint("55"); 00727 cprint("%s", filename); 00728 stat = exec_conf(); 00729 switch(stat) { 00730 case 0: 00731 if (!input_buf[0]) 00732 return; 00733 if (!conf_write(input_buf)) 00734 return; 00735 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60); 00736 break; 00737 case 1: 00738 show_helptext("Save Alternate Configuration", save_config_help); 00739 break; 00740 case 255: 00741 return; 00742 } 00743 } 00744 } 00745 00746 static void conf_cleanup(void) 00747 { 00748 tcsetattr(1, TCSAFLUSH, &ios_org); 00749 unlink(".help.tmp"); 00750 unlink("lxdialog.scrltmp"); 00751 } 00752 00753 int main(int ac, char **av) 00754 { 00755 struct symbol *sym; 00756 char *mode; 00757 int stat; 00758 00759 conf_parse(av[1]); 00760 conf_read(NULL); 00761 00762 sym = sym_lookup("RTAI_VERSION", 0); 00763 sym_calc_value(sym); 00764 sprintf(menu_backtitle, "RTAI %s Configuration", 00765 sym_get_string_value(sym)); 00766 00767 mode = getenv("MENUCONFIG_MODE"); 00768 if (mode) { 00769 if (!strcasecmp(mode, "single_menu")) 00770 single_menu_mode = 1; 00771 } 00772 00773 tcgetattr(1, &ios_org); 00774 atexit(conf_cleanup); 00775 init_wsize(); 00776 conf(&rootmenu); 00777 00778 do { 00779 cprint_init(); 00780 cprint("--yesno"); 00781 cprint("Do you wish to save your new configuration?"); 00782 cprint("5"); 00783 cprint("60"); 00784 stat = exec_conf(); 00785 } while (stat < 0); 00786 00787 if (stat == 0) { 00788 conf_write(NULL); 00789 } else 00790 printf("\n\nYour RTAI configuration changes were NOT saved.\n\n"); 00791 00792 return 0; 00793 }

Generated on Thu Nov 20 11:49:48 2008 for RTAI API by doxygen 1.3.8