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

Archive Download this file



interactive