69cd56f13897f70e618ce666826efcd7101840b2
[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 built in, modularized or removed respectively.\n"
38 "Pointed brackets <> represent module capable features.\n"
39 "\n"
40 "To change any of these features, highlight it with the cursor\n"
41 "keys and press <Y> to build it in, <M> to make it a module or\n"
42 "<N> to removed it. You may also press the <Space Bar> to cycle\n"
43 "through the available options (ie. Y->N->M->Y).\n"
44 "\n"
45 "Some additional keyboard hints:\n"
46 "\n"
47 "Menus\n"
48 "----------\n"
49 "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
50 " you wish to change or submenu wish to select and press <Enter>.\n"
51 " Submenus are designated by \"--->\".\n"
52 "\n"
53 " Shortcut: Press the option's highlighted letter (hotkey).\n"
54 " Pressing a hotkey more than once will sequence\n"
55 " through all visible items which use that hotkey.\n"
56 "\n"
57 " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
58 " unseen options into view.\n"
59 "\n"
60 "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
61 " and press <ENTER>.\n"
62 "\n"
63 " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
64 " using those letters. You may press a single <ESC>, but\n"
65 " there is a delayed response which you may find annoying.\n"
66 "\n"
67 " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
68 " <Exit> and <Help>\n"
69 "\n"
70 "o To get help with an item, use the cursor keys to highlight <Help>\n"
71 " and Press <ENTER>.\n"
72 "\n"
73 " Shortcut: Press <H> or <?>.\n"
74 "\n"
75 "\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> modularizes features. "
166 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
167 "Legend: [*] built-in [ ] excluded <M> module < > module 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 module.\n"
185 "As a result, this feature will be built as a module."),
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("L");
741 cprint(_(" Load an Alternate Configuration File"));
742 cprint("S");
743 cprint(_(" Save Configuration to an Alternate File"));
744 }
745 stat = exec_conf();
746 if (stat < 0)
747 continue;
748
749 if (stat == 1 || stat == 255)
750 break;
751
752 type = input_buf[0];
753 if (!type)
754 continue;
755
756 for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
757 ;
758 if (i >= sizeof(active_entry))
759 i = sizeof(active_entry) - 1;
760 input_buf[i] = 0;
761 strcpy(active_entry, input_buf);
762
763 sym = NULL;
764 submenu = NULL;
765 if (sscanf(input_buf + 1, "%p", &submenu) == 1)
766 sym = submenu->sym;
767
768 switch (stat) {
769 case 0:
770 switch (type) {
771 case 'm':
772 if (single_menu_mode)
773 submenu->data = (void *) (long) !submenu->data;
774 else
775 conf(submenu);
776 break;
777 case 't':
778 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
779 conf_choice(submenu);
780 else if (submenu->prompt->type == P_MENU)
781 conf(submenu);
782 break;
783 case 's':
784 conf_string(submenu);
785 break;
786 case 'L':
787 conf_load();
788 break;
789 case 'S':
790 conf_save();
791 break;
792 }
793 break;
794 case 2:
795 if (sym)
796 show_help(submenu);
797 else
798 show_helptext("README", _(mconf_readme));
799 break;
800 case 3:
801 if (type == 't') {
802 if (sym_set_tristate_value(sym, yes))
803 break;
804 if (sym_set_tristate_value(sym, mod))
805 show_textbox(NULL, setmod_text, 6, 74);
806 }
807 break;
808 case 4:
809 if (type == 't')
810 sym_set_tristate_value(sym, no);
811 break;
812 case 5:
813 if (type == 't')
814 sym_set_tristate_value(sym, mod);
815 break;
816 case 6:
817 if (type == 't')
818 sym_toggle_tristate_value(sym);
819 else if (type == 'm')
820 conf(submenu);
821 break;
822 case 7:
823 search_conf();
824 break;
825 }
826 }
827 }
828
829 static void show_textbox(const char *title, const char *text, int r, int c)
830 {
831 int fd;
832
833 fd = creat(".help.tmp", 0777);
834 write(fd, text, strlen(text));
835 close(fd);
836 show_file(".help.tmp", title, r, c);
837 unlink(".help.tmp");
838 }
839
840 static void show_helptext(const char *title, const char *text)
841 {
842 show_textbox(title, text, 0, 0);
843 }
844
845 static void show_help(struct menu *menu)
846 {
847 struct gstr help = str_new();
848 struct symbol *sym = menu->sym;
849
850 if (sym->help)
851 {
852 if (sym->name) {
853 str_printf(&help, "CONFIG_%s:\n\n", sym->name);
854 str_append(&help, _(sym->help));
855 str_append(&help, "\n");
856 }
857 } else {
858 str_append(&help, nohelp_text);
859 }
860 get_symbol_str(&help, sym);
861 show_helptext(menu_get_prompt(menu), str_get(&help));
862 str_free(&help);
863 }
864
865 static void show_file(const char *filename, const char *title, int r, int c)
866 {
867 do {
868 cprint_init();
869 if (title) {
870 cprint("--title");
871 cprint("%s", title);
872 }
873 cprint("--textbox");
874 cprint("%s", filename);
875 cprint("%d", r ? r : rows);
876 cprint("%d", c ? c : cols);
877 } while (exec_conf() < 0);
878 }
879
880 static void conf_choice(struct menu *menu)
881 {
882 const char *prompt = menu_get_prompt(menu);
883 struct menu *child;
884 struct symbol *active;
885 int stat;
886
887 active = sym_get_choice_value(menu->sym);
888 while (1) {
889 cprint_init();
890 cprint("--title");
891 cprint("%s", prompt ? prompt : _("Main Menu"));
892 cprint("--radiolist");
893 cprint(_(radiolist_instructions));
894 cprint("15");
895 cprint("70");
896 cprint("6");
897
898 current_menu = menu;
899 for (child = menu->list; child; child = child->next) {
900 if (!menu_is_visible(child))
901 continue;
902 cprint("%p", child);
903 cprint("%s", menu_get_prompt(child));
904 if (child->sym == sym_get_choice_value(menu->sym))
905 cprint("ON");
906 else if (child->sym == active)
907 cprint("SELECTED");
908 else
909 cprint("OFF");
910 }
911
912 stat = exec_conf();
913 switch (stat) {
914 case 0:
915 if (sscanf(input_buf, "%p", &child) != 1)
916 break;
917 sym_set_tristate_value(child->sym, yes);
918 return;
919 case 1:
920 if (sscanf(input_buf, "%p", &child) == 1) {
921 show_help(child);
922 active = child->sym;
923 } else
924 show_help(menu);
925 break;
926 case 255:
927 return;
928 }
929 }
930 }
931
932 static void conf_string(struct menu *menu)
933 {
934 const char *prompt = menu_get_prompt(menu);
935 int stat;
936
937 while (1) {
938 cprint_init();
939 cprint("--title");
940 cprint("%s", prompt ? prompt : _("Main Menu"));
941 cprint("--inputbox");
942 switch (sym_get_type(menu->sym)) {
943 case S_INT:
944 cprint(_(inputbox_instructions_int));
945 break;
946 case S_HEX:
947 cprint(_(inputbox_instructions_hex));
948 break;
949 case S_STRING:
950 cprint(_(inputbox_instructions_string));
951 break;
952 default:
953 /* panic? */;
954 }
955 cprint("10");
956 cprint("75");
957 cprint("%s", sym_get_string_value(menu->sym));
958 stat = exec_conf();
959 switch (stat) {
960 case 0:
961 if (sym_set_string_value(menu->sym, input_buf))
962 return;
963 show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
964 break;
965 case 1:
966 show_help(menu);
967 break;
968 case 255:
969 return;
970 }
971 }
972 }
973
974 static void conf_load(void)
975 {
976 int stat;
977
978 while (1) {
979 cprint_init();
980 cprint("--inputbox");
981 cprint(load_config_text);
982 cprint("11");
983 cprint("55");
984 cprint("%s", filename);
985 stat = exec_conf();
986 switch(stat) {
987 case 0:
988 if (!input_buf[0])
989 return;
990 if (!conf_read(input_buf))
991 return;
992 show_textbox(NULL, _("File does not exist!"), 5, 38);
993 break;
994 case 1:
995 show_helptext(_("Load Alternate Configuration"), load_config_help);
996 break;
997 case 255:
998 return;
999 }
1000 }
1001 }
1002
1003 static void conf_save(void)
1004 {
1005 int stat;
1006
1007 while (1) {
1008 cprint_init();
1009 cprint("--inputbox");
1010 cprint(save_config_text);
1011 cprint("11");
1012 cprint("55");
1013 cprint("%s", filename);
1014 stat = exec_conf();
1015 switch(stat) {
1016 case 0:
1017 if (!input_buf[0])
1018 return;
1019 if (!conf_write(input_buf))
1020 return;
1021 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1022 break;
1023 case 1:
1024 show_helptext(_("Save Alternate Configuration"), save_config_help);
1025 break;
1026 case 255:
1027 return;
1028 }
1029 }
1030 }
1031
1032 static void conf_cleanup(void)
1033 {
1034 tcsetattr(1, TCSAFLUSH, &ios_org);
1035 unlink(".help.tmp");
1036 unlink("lxdialog.scrltmp");
1037 }
1038
1039 int main(int ac, char **av)
1040 {
1041 struct symbol *sym;
1042 char *mode;
1043 int stat;
1044
1045 setlocale(LC_ALL, "");
1046 bindtextdomain(PACKAGE, LOCALEDIR);
1047 textdomain(PACKAGE);
1048
1049 conf_parse(av[1]);
1050 conf_read(NULL);
1051
1052 sym = sym_lookup("OPENWRTVERSION", 0);
1053 sym_calc_value(sym);
1054 sprintf(menu_backtitle, _("OpenWrt %s Configuration"),
1055 sym_get_string_value(sym));
1056
1057 mode = getenv("MENUCONFIG_MODE");
1058 if (mode) {
1059 if (!strcasecmp(mode, "single_menu"))
1060 single_menu_mode = 1;
1061 }
1062
1063 tcgetattr(1, &ios_org);
1064 atexit(conf_cleanup);
1065 init_wsize();
1066 conf(&rootmenu);
1067
1068 do {
1069 cprint_init();
1070 cprint("--yesno");
1071 cprint(_("Do you wish to save your new OpenWrt configuration?"));
1072 cprint("5");
1073 cprint("60");
1074 stat = exec_conf();
1075 } while (stat < 0);
1076
1077 if (stat == 0) {
1078 if (conf_write(NULL)) {
1079 fprintf(stderr, _("\n\n"
1080 "Error during writing of the OpenWrt configuration.\n"
1081 "Your configuration changes were NOT saved."
1082 "\n\n"));
1083 return 1;
1084 }
1085 printf(_("\n\n"
1086 "*** End of OpenWrt configuration.\n"
1087 "*** Execute 'make' to build the OpenWrt or try 'make help'."
1088 "\n\n"));
1089 } else {
1090 fprintf(stderr, _("\n\n"
1091 "Your configuration changes were NOT saved."
1092 "\n\n"));
1093 }
1094
1095 return 0;
1096 }
This page took 0.105764 seconds and 3 git commands to generate.