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    help.max_width = cols - 10;
876
877    if (sym->help)
878    {
879        if (sym->name) {
880            str_printf(&help, "CONFIG_%s:\n\n", sym->name);
881            str_append(&help, _(sym->help));
882            str_append(&help, "\n");
883        }
884    } else {
885        str_append(&help, nohelp_text);
886    }
887    get_symbol_str(&help, sym);
888    show_helptext(menu_get_prompt(menu), str_get(&help));
889    str_free(&help);
890}
891
892static void show_file(const char *filename, const char *title, int r, int c)
893{
894    do {
895        cprint_init();
896        if (title) {
897            cprint("--title");
898            cprint("%s", title);
899        }
900        cprint("--textbox");
901        cprint("%s", filename);
902        cprint("%d", r ? r : rows);
903        cprint("%d", c ? c : cols);
904    } while (exec_conf() < 0);
905}
906
907static void conf_choice(struct menu *menu)
908{
909    const char *prompt = menu_get_prompt(menu);
910    struct menu *child;
911    struct symbol *active;
912    struct property *prop;
913    int stat;
914
915    active = sym_get_choice_value(menu->sym);
916    while (1) {
917        cprint_init();
918        cprint("--title");
919        cprint("%s", prompt ? prompt : _("Main Menu"));
920        cprint("--radiolist");
921        cprint(_(radiolist_instructions));
922        cprint("15");
923        cprint("70");
924        cprint("6");
925
926        current_menu = menu;
927        for (child = menu->list; child; child = child->next) {
928            if (!menu_is_visible(child))
929                continue;
930            cprint("%p", child);
931            cprint("%s", menu_get_prompt(child));
932            if (child->sym == sym_get_choice_value(menu->sym))
933                cprint("ON");
934            else if (child->sym == active)
935                cprint("SELECTED");
936            else
937                cprint("OFF");
938        }
939
940        stat = exec_conf();
941        switch (stat) {
942        case 0:
943            if (sscanf(input_buf, "%p", &child) != 1)
944                break;
945            
946            if (sym_get_tristate_value(child->sym) != yes) {
947                for_all_properties(menu->sym, prop, P_RESET) {
948                    if (expr_calc_value(prop->visible.expr) != no)
949                        conf_reset();
950                }
951            }
952            sym_set_tristate_value(child->sym, yes);
953            return;
954        case 1:
955            if (sscanf(input_buf, "%p", &child) == 1) {
956                show_help(child);
957                active = child->sym;
958            } else
959                show_help(menu);
960            break;
961        case 255:
962            return;
963        }
964    }
965}
966
967static void conf_string(struct menu *menu)
968{
969    const char *prompt = menu_get_prompt(menu);
970    int stat;
971
972    while (1) {
973        cprint_init();
974        cprint("--title");
975        cprint("%s", prompt ? prompt : _("Main Menu"));
976        cprint("--inputbox");
977        switch (sym_get_type(menu->sym)) {
978        case S_INT:
979            cprint(_(inputbox_instructions_int));
980            break;
981        case S_HEX:
982            cprint(_(inputbox_instructions_hex));
983            break;
984        case S_STRING:
985            cprint(_(inputbox_instructions_string));
986            break;
987        default:
988            /* panic? */;
989        }
990        cprint("10");
991        cprint("75");
992        cprint("%s", sym_get_string_value(menu->sym));
993        stat = exec_conf();
994        switch (stat) {
995        case 0:
996            if (sym_set_string_value(menu->sym, input_buf))
997                return;
998            show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
999            break;
1000        case 1:
1001            show_help(menu);
1002            break;
1003        case 255:
1004            return;
1005        }
1006    }
1007}
1008
1009static void conf_load(void)
1010{
1011    int stat;
1012
1013    while (1) {
1014        cprint_init();
1015        cprint("--inputbox");
1016        cprint(load_config_text);
1017        cprint("11");
1018        cprint("55");
1019        cprint("%s", filename);
1020        stat = exec_conf();
1021        switch(stat) {
1022        case 0:
1023            if (!input_buf[0])
1024                return;
1025            if (!conf_read(input_buf))
1026                return;
1027            show_textbox(NULL, _("File does not exist!"), 5, 38);
1028            break;
1029        case 1:
1030            show_helptext(_("Load Alternate Configuration"), load_config_help);
1031            break;
1032        case 255:
1033            return;
1034        }
1035    }
1036}
1037
1038static void conf_save(void)
1039{
1040    int stat;
1041
1042    while (1) {
1043        cprint_init();
1044        cprint("--inputbox");
1045        cprint(save_config_text);
1046        cprint("11");
1047        cprint("55");
1048        cprint("%s", filename);
1049        stat = exec_conf();
1050        switch(stat) {
1051        case 0:
1052            if (!input_buf[0])
1053                return;
1054            if (!conf_write(input_buf))
1055                return;
1056            show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
1057            break;
1058        case 1:
1059            show_helptext(_("Save Alternate Configuration"), save_config_help);
1060            break;
1061        case 255:
1062            return;
1063        }
1064    }
1065}
1066
1067static void conf_cleanup(void)
1068{
1069    tcsetattr(1, TCSAFLUSH, &ios_org);
1070    unlink(".help.tmp");
1071    unlink("lxdialog.scrltmp");
1072}
1073
1074int main(int ac, char **av)
1075{
1076    struct symbol *sym;
1077    char *mode;
1078    int stat;
1079
1080    setlocale(LC_ALL, "");
1081    bindtextdomain(PACKAGE, LOCALEDIR);
1082    textdomain(PACKAGE);
1083
1084    conf_parse(av[1]);
1085    conf_read(NULL);
1086
1087    sym = sym_lookup("OPENWRTVERSION", 0);
1088    sym_calc_value(sym);
1089    sprintf(menu_backtitle, _("OpenWrt %s Configuration"),
1090        sym_get_string_value(sym));
1091
1092    mode = getenv("MENUCONFIG_MODE");
1093    if (mode) {
1094        if (!strcasecmp(mode, "single_menu"))
1095            single_menu_mode = 1;
1096    }
1097
1098    tcgetattr(1, &ios_org);
1099    atexit(conf_cleanup);
1100    init_wsize();
1101    conf(&rootmenu);
1102
1103    do {
1104        cprint_init();
1105        cprint("--yesno");
1106        cprint(_("Do you wish to save your new OpenWrt configuration?"));
1107        cprint("5");
1108        cprint("60");
1109        stat = exec_conf();
1110    } while (stat < 0);
1111
1112    if (stat == 0) {
1113        if (conf_write(NULL)) {
1114            fprintf(stderr, _("\n\n"
1115                "Error during writing of the OpenWrt configuration.\n"
1116                "Your configuration changes were NOT saved."
1117                "\n\n"));
1118            return 1;
1119        }
1120        printf(_("\n\n"
1121            "*** End of OpenWrt configuration.\n"
1122            "*** Execute 'make' to build the OpenWrt or try 'make help'."
1123            "\n\n"));
1124    } else {
1125        fprintf(stderr, _("\n\n"
1126            "Your configuration changes were NOT saved."
1127            "\n\n"));
1128    }
1129
1130    return 0;
1131}
1132

Archive Download this file



interactive