source: branches/2.2.9/mindi-busybox/scripts/kconfig/mconf.c @ 2725

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