source: debwrt/trunk/config/mconf/mconf.c @ 1

Last change on this file since 1 was 1, checked in by amain, 13 years ago

Initial import of the build environment for DebWrt

File size: 27.5 KB
Line 
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("./config/mconf/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, _("DebWrt %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 DebWrt 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 DebWrt configuration.\n"
1114                                "Your configuration changes were NOT saved."
1115                                "\n\n"));
1116                        return 1;
1117                }
1118                printf(_("\n\n"
1119                        "*** End of DebWrt configuration.\n"
1120                        "*** Execute 'make' to build the DebWrt 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}
Note: See TracBrowser for help on using the repository browser.