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