source: MondoRescue/branches/stable/mindi-busybox/scripts/config/mconf.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 25.1 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 * Directly use liblxdialog library routines.
9 * 2002-11-14 Petr Baudis <pasky@ucw.cz>
10 */
11
12#include <sys/ioctl.h>
13#include <sys/wait.h>
14#include <ctype.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <limits.h>
18#include <signal.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <string.h>
22#include <termios.h>
23#include <unistd.h>
24
25#include "lxdialog/dialog.h"
26
27#define LKC_DIRECT_LINK
28#include "lkc.h"
29
30static char menu_backtitle[128];
31static const char mconf_readme[] =
32"Overview\n"
33"--------\n"
34"Some features may be built directly into BusyBox.  Some features\n"
35"may be completely removed altogether.  There are also certain\n"
36"parameters which are not really features, but must be\n"
37"entered in as decimal or hexadecimal numbers or possibly text.\n"
38"\n"
39"Menu items beginning with [*] or [ ] represent features\n"
40"configured to be built in or removed respectively.\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 or <N> to removed it.\n"
44"You may also press the <Space Bar> to cycle\n"
45"through the available options (ie. Y->N->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[] =
164    "Arrow keys navigate the menu.  "
165    "<Enter> selects submenus --->.  "
166    "Highlighted letters are hotkeys.  "
167    "Pressing <Y> selectes a feature, while <N> will exclude a feature.  "
168    "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
169    "Legend: [*] feature is selected  [ ] feature is excluded",
170radiolist_instructions[] =
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[] =
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[] =
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[] =
183    "Please enter a string value. "
184    "Use the <TAB> key to move from the input field to the buttons below it.",
185setmod_text[] =
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[] =
189    "There is no help available for this option.\n",
190load_config_text[] =
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[] =
195    "\n"
196    "For various reasons, one may wish to keep several different BusyBox\n"
197    "configurations available on a single machine.\n"
198    "\n"
199    "If you have saved a previous configuration in a file other than the\n"
200    "BusyBox's 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[] =
206    "Enter a filename to which this configuration should be saved "
207    "as an alternate.  Leave blank to abort.",
208save_config_help[] =
209    "\n"
210    "For various reasons, one may wish to keep different BusyBox\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[] =
220    "\n"
221    "Search for CONFIG_ symbols and display their relations.\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 filename[PATH_MAX+1] = ".config";
259static int indent;
260static struct termios ios_org;
261static int rows = 0, cols = 0;
262static struct menu *current_menu;
263static int child_count;
264static int single_menu_mode;
265
266static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
267static int item_no;
268
269static void conf(struct menu *menu);
270static void conf_choice(struct menu *menu);
271static void conf_string(struct menu *menu);
272static void conf_load(void);
273static void conf_save(void);
274static void show_textbox(const char *title, const char *text, int r, int c);
275static void show_helptext(const char *title, const char *text);
276static void show_help(struct menu *menu);
277static void show_file(const char *filename, const char *title, int r, int c);
278
279static void init_wsize(void)
280{
281    struct winsize ws;
282    char *env;
283
284    if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
285        rows = ws.ws_row;
286        cols = ws.ws_col;
287    }
288
289    if (!rows) {
290        env = getenv("LINES");
291        if (env)
292            rows = atoi(env);
293        if (!rows)
294            rows = 24;
295    }
296    if (!cols) {
297        env = getenv("COLUMNS");
298        if (env)
299            cols = atoi(env);
300        if (!cols)
301            cols = 80;
302    }
303
304    if (rows < 19 || cols < 80) {
305        fprintf(stderr, "Your display is too small to run Menuconfig!\n");
306        fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
307        exit(1);
308    }
309
310    rows -= 4;
311    cols -= 5;
312}
313
314static void cinit(void)
315{
316    item_no = 0;
317}
318
319static void cmake(void)
320{
321    items[item_no] = malloc(sizeof(struct dialog_list_item));
322    memset(items[item_no], 0, sizeof(struct dialog_list_item));
323    items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0;
324    items[item_no]->name = malloc(512); items[item_no]->name[0] = 0;
325    items[item_no]->namelen = 0;
326    item_no++;
327}
328
329static int cprint_name(const char *fmt, ...)
330{
331    va_list ap;
332    int res;
333
334    if (!item_no)
335        cmake();
336    va_start(ap, fmt);
337    res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
338            512 - items[item_no - 1]->namelen, fmt, ap);
339    if (res > 0)
340        items[item_no - 1]->namelen += res;
341    va_end(ap);
342
343    return res;
344}
345
346static int cprint_tag(const char *fmt, ...)
347{
348    va_list ap;
349    int res;
350
351    if (!item_no)
352        cmake();
353    va_start(ap, fmt);
354    res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
355    va_end(ap);
356
357    return res;
358}
359
360static void cdone(void)
361{
362    int i;
363
364    for (i = 0; i < item_no; i++) {
365        free(items[i]->tag);
366        free(items[i]->name);
367        free(items[i]);
368    }
369
370    item_no = 0;
371}
372
373static void get_prompt_str(struct gstr *r, struct property *prop)
374{
375    int i, j;
376    struct menu *submenu[8], *menu;
377
378    str_printf(r, "Prompt: %s\n", prop->text);
379    str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
380        prop->menu->lineno);
381    if (!expr_is_yes(prop->visible.expr)) {
382        str_append(r, "  Depends on: ");
383        expr_gstr_print(prop->visible.expr, r);
384        str_append(r, "\n");
385    }
386    menu = prop->menu->parent;
387    for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
388        submenu[i++] = menu;
389    if (i > 0) {
390        str_printf(r, "  Location:\n");
391        for (j = 4; --i >= 0; j += 2) {
392            menu = submenu[i];
393            str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
394            if (menu->sym) {
395                str_printf(r, " (%s [=%s])", menu->sym->name ?
396                    menu->sym->name : "<choice>",
397                    sym_get_string_value(menu->sym));
398            }
399            str_append(r, "\n");
400        }
401    }
402}
403
404static void get_symbol_str(struct gstr *r, struct symbol *sym)
405{
406    bool hit;
407    struct property *prop;
408
409    str_printf(r, "Symbol: %s [=%s]\n", sym->name,
410                                   sym_get_string_value(sym));
411    for_all_prompts(sym, prop)
412        get_prompt_str(r, prop);
413    hit = false;
414    for_all_properties(sym, prop, P_SELECT) {
415        if (!hit) {
416            str_append(r, "  Selects: ");
417            hit = true;
418        } else
419            str_printf(r, " && ");
420        expr_gstr_print(prop->expr, r);
421    }
422    if (hit)
423        str_append(r, "\n");
424    if (sym->rev_dep.expr) {
425        str_append(r, "  Selected by: ");
426        expr_gstr_print(sym->rev_dep.expr, r);
427        str_append(r, "\n");
428    }
429    str_append(r, "\n\n");
430}
431
432static struct gstr get_relations_str(struct symbol **sym_arr)
433{
434    struct symbol *sym;
435    struct gstr res = str_new();
436    int i;
437
438    for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
439        get_symbol_str(&res, sym);
440    if (!i)
441        str_append(&res, "No matches found.\n");
442    return res;
443}
444
445static void search_conf(void)
446{
447    struct symbol **sym_arr;
448    struct gstr res;
449
450again:
451    switch (dialog_inputbox("Search Configuration Parameter",
452                "Enter Keyword", 10, 75,
453                NULL)) {
454    case 0:
455        break;
456    case 1:
457        show_helptext("Search Configuration", search_help);
458        goto again;
459    default:
460        return;
461    }
462
463    sym_arr = sym_re_search(dialog_input_result);
464    res = get_relations_str(sym_arr);
465    free(sym_arr);
466    show_textbox("Search Results", str_get(&res), 0, 0);
467    str_free(&res);
468}
469
470static void build_conf(struct menu *menu)
471{
472    struct symbol *sym;
473    struct property *prop;
474    struct menu *child;
475    int type, tmp, doint = 2;
476    tristate val;
477    char ch;
478
479    if (!menu_is_visible(menu))
480        return;
481
482    sym = menu->sym;
483    prop = menu->prompt;
484    if (!sym) {
485        if (prop && menu != current_menu) {
486            const char *prompt = menu_get_prompt(menu);
487            switch (prop->type) {
488            case P_MENU:
489                child_count++;
490                cmake();
491                cprint_tag("m%p", menu);
492
493                if (single_menu_mode) {
494                    cprint_name("%s%*c%s",
495                        menu->data ? "-->" : "++>",
496                        indent + 1, ' ', prompt);
497                } else {
498                    cprint_name("   %*c%s  --->", indent + 1, ' ', prompt);
499                }
500
501                if (single_menu_mode && menu->data)
502                    goto conf_childs;
503                return;
504            default:
505                if (prompt) {
506                    child_count++;
507                    cmake();
508                    cprint_tag(":%p", menu);
509                    cprint_name("---%*c%s", indent + 1, ' ', prompt);
510                }
511            }
512        } else
513            doint = 0;
514        goto conf_childs;
515    }
516
517    cmake();
518    type = sym_get_type(sym);
519    if (sym_is_choice(sym)) {
520        struct symbol *def_sym = sym_get_choice_value(sym);
521        struct menu *def_menu = NULL;
522
523        child_count++;
524        for (child = menu->list; child; child = child->next) {
525            if (menu_is_visible(child) && child->sym == def_sym)
526                def_menu = child;
527        }
528
529        val = sym_get_tristate_value(sym);
530        if (sym_is_changable(sym)) {
531            cprint_tag("t%p", menu);
532            switch (type) {
533            case S_BOOLEAN:
534                cprint_name("[%c]", val == no ? ' ' : '*');
535                break;
536            case S_TRISTATE:
537                switch (val) {
538                case yes: ch = '*'; break;
539                case mod: ch = 'M'; break;
540                default:  ch = ' '; break;
541                }
542                cprint_name("<%c>", ch);
543                break;
544            }
545        } else {
546            cprint_tag("%c%p", def_menu ? 't' : ':', menu);
547            cprint_name("   ");
548        }
549
550        cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
551        if (val == yes) {
552            if (def_menu) {
553                cprint_name(" (%s)", menu_get_prompt(def_menu));
554                cprint_name("  --->");
555                if (def_menu->list) {
556                    indent += 2;
557                    build_conf(def_menu);
558                    indent -= 2;
559                }
560            }
561            return;
562        }
563    } else {
564        if (menu == current_menu) {
565            cprint_tag(":%p", menu);
566            cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
567            goto conf_childs;
568        }
569        child_count++;
570        val = sym_get_tristate_value(sym);
571        if (sym_is_choice_value(sym) && val == yes) {
572            cprint_tag(":%p", menu);
573            cprint_name("   ");
574        } else {
575            switch (type) {
576            case S_BOOLEAN:
577                cprint_tag("t%p", menu);
578                if (sym_is_changable(sym))
579                    cprint_name("[%c]", val == no ? ' ' : '*');
580                else
581                    cprint_name("---");
582                break;
583            case S_TRISTATE:
584                cprint_tag("t%p", menu);
585                switch (val) {
586                case yes: ch = '*'; break;
587                case mod: ch = 'M'; break;
588                default:  ch = ' '; break;
589                }
590                if (sym_is_changable(sym))
591                    cprint_name("<%c>", ch);
592                else
593                    cprint_name("---");
594                break;
595            default:
596                cprint_tag("s%p", menu);
597                tmp = cprint_name("(%s)", sym_get_string_value(sym));
598                tmp = indent - tmp + 4;
599                if (tmp < 0)
600                    tmp = 0;
601                cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
602                    (sym_has_value(sym) || !sym_is_changable(sym)) ?
603                    "" : " (NEW)");
604                goto conf_childs;
605            }
606        }
607        cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
608            (sym_has_value(sym) || !sym_is_changable(sym)) ?
609            "" : " (NEW)");
610        if (menu->prompt->type == P_MENU) {
611            cprint_name("  --->");
612            return;
613        }
614    }
615
616conf_childs:
617    indent += doint;
618    for (child = menu->list; child; child = child->next)
619        build_conf(child);
620    indent -= doint;
621}
622
623static void conf(struct menu *menu)
624{
625    struct dialog_list_item *active_item = NULL;
626    struct menu *submenu;
627    const char *prompt = menu_get_prompt(menu);
628    struct symbol *sym;
629    char active_entry[40];
630    int stat, type;
631
632    unlink("lxdialog.scrltmp");
633    active_entry[0] = 0;
634    while (1) {
635        indent = 0;
636        child_count = 0;
637        current_menu = menu;
638        cdone(); cinit();
639        build_conf(menu);
640        if (!child_count)
641            break;
642        if (menu == &rootmenu) {
643            cmake(); cprint_tag(":"); cprint_name("--- ");
644            cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
645            cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
646        }
647        dialog_clear();
648        stat = dialog_menu(prompt ? prompt : "Main Menu",
649                menu_instructions, rows, cols, rows - 10,
650                active_entry, item_no, items);
651        if (stat < 0)
652            return;
653
654        if (stat == 1 || stat == 255)
655            break;
656
657        active_item = first_sel_item(item_no, items);
658        if (!active_item)
659            continue;
660        active_item->selected = 0;
661        strncpy(active_entry, active_item->tag, sizeof(active_entry));
662        active_entry[sizeof(active_entry)-1] = 0;
663        type = active_entry[0];
664        if (!type)
665            continue;
666
667        sym = NULL;
668        submenu = NULL;
669        if (sscanf(active_entry + 1, "%p", &submenu) == 1)
670            sym = submenu->sym;
671
672        switch (stat) {
673        case 0:
674            switch (type) {
675            case 'm':
676                if (single_menu_mode)
677                    submenu->data = (void *) (long) !submenu->data;
678                else
679                    conf(submenu);
680                break;
681            case 't':
682                if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
683                    conf_choice(submenu);
684                else if (submenu->prompt->type == P_MENU)
685                    conf(submenu);
686                break;
687            case 's':
688                conf_string(submenu);
689                break;
690            case 'L':
691                conf_load();
692                break;
693            case 'S':
694                conf_save();
695                break;
696            }
697            break;
698        case 2:
699            if (sym)
700                show_help(submenu);
701            else
702                show_helptext("README", mconf_readme);
703            break;
704        case 3:
705            if (type == 't') {
706                if (sym_set_tristate_value(sym, yes))
707                    break;
708                if (sym_set_tristate_value(sym, mod))
709                    show_textbox(NULL, setmod_text, 6, 74);
710            }
711            break;
712        case 4:
713            if (type == 't')
714                sym_set_tristate_value(sym, no);
715            break;
716        case 5:
717            if (type == 't')
718                sym_set_tristate_value(sym, mod);
719            break;
720        case 6:
721            if (type == 't')
722                sym_toggle_tristate_value(sym);
723            else if (type == 'm')
724                conf(submenu);
725            break;
726        case 7:
727            search_conf();
728            break;
729        }
730    }
731}
732
733static void show_textbox(const char *title, const char *text, int r, int c)
734{
735    int fd;
736
737    fd = creat(".help.tmp", 0777);
738    write(fd, text, strlen(text));
739    close(fd);
740    show_file(".help.tmp", title, r, c);
741    unlink(".help.tmp");
742}
743
744static void show_helptext(const char *title, const char *text)
745{
746    show_textbox(title, text, 0, 0);
747}
748
749static void show_help(struct menu *menu)
750{
751    struct gstr help = str_new();
752    struct symbol *sym = menu->sym;
753
754    if (sym->help)
755    {
756        if (sym->name) {
757            str_printf(&help, "%s:\n\n", sym->name);
758            str_append(&help, sym->help);
759            str_append(&help, "\n");
760        }
761    } else {
762        str_append(&help, nohelp_text);
763    }
764    get_symbol_str(&help, sym);
765    show_helptext(menu_get_prompt(menu), str_get(&help));
766    str_free(&help);
767}
768
769static void show_file(const char *filename, const char *title, int r, int c)
770{
771    while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
772        ;
773}
774
775static void conf_choice(struct menu *menu)
776{
777    const char *prompt = menu_get_prompt(menu);
778    struct menu *child;
779    struct symbol *active;
780
781    active = sym_get_choice_value(menu->sym);
782    while (1) {
783        current_menu = menu;
784        cdone(); cinit();
785        for (child = menu->list; child; child = child->next) {
786            if (!menu_is_visible(child))
787                continue;
788            cmake();
789            cprint_tag("%p", child);
790            cprint_name("%s", menu_get_prompt(child));
791            if (child->sym == sym_get_choice_value(menu->sym))
792                items[item_no - 1]->selected = 1; /* ON */
793            else if (child->sym == active)
794                items[item_no - 1]->selected = 2; /* SELECTED */
795            else
796                items[item_no - 1]->selected = 0; /* OFF */
797        }
798
799        switch (dialog_checklist(prompt ? prompt : "Main Menu",
800                    radiolist_instructions, 15, 70, 6,
801                    item_no, items, FLAG_RADIO)) {
802        case 0:
803            if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
804                break;
805            sym_set_tristate_value(child->sym, yes);
806            return;
807        case 1:
808            if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
809                show_help(child);
810                active = child->sym;
811            } else
812                show_help(menu);
813            break;
814        case 255:
815            return;
816        }
817    }
818}
819
820static void conf_string(struct menu *menu)
821{
822    const char *prompt = menu_get_prompt(menu);
823
824    while (1) {
825        char *heading;
826
827        switch (sym_get_type(menu->sym)) {
828        case S_INT:
829            heading = (char *) inputbox_instructions_int;
830            break;
831        case S_HEX:
832            heading = (char *) inputbox_instructions_hex;
833            break;
834        case S_STRING:
835            heading = (char *) inputbox_instructions_string;
836            break;
837        default:
838            heading = "Internal mconf error!";
839            /* panic? */;
840        }
841
842        switch (dialog_inputbox(prompt ? prompt : "Main Menu",
843                    heading, 10, 75,
844                    sym_get_string_value(menu->sym))) {
845        case 0:
846            if (sym_set_string_value(menu->sym, dialog_input_result))
847                return;
848            show_textbox(NULL, "You have made an invalid entry.", 5, 43);
849            break;
850        case 1:
851            show_help(menu);
852            break;
853        case 255:
854            return;
855        }
856    }
857}
858
859static void conf_load(void)
860{
861    while (1) {
862        switch (dialog_inputbox(NULL, load_config_text, 11, 55,
863                    filename)) {
864        case 0:
865            if (!dialog_input_result[0])
866                return;
867            if (!conf_read(dialog_input_result))
868                return;
869            show_textbox(NULL, "File does not exist!", 5, 38);
870            break;
871        case 1:
872            show_helptext("Load Alternate Configuration", load_config_help);
873            break;
874        case 255:
875            return;
876        }
877    }
878}
879
880static void conf_save(void)
881{
882    while (1) {
883        switch (dialog_inputbox(NULL, save_config_text, 11, 55,
884                    filename)) {
885        case 0:
886            if (!dialog_input_result[0])
887                return;
888            if (!conf_write(dialog_input_result))
889                return;
890            show_textbox(NULL, "Can't create file!  Probably a nonexistent directory.", 5, 60);
891            break;
892        case 1:
893            show_helptext("Save Alternate Configuration", save_config_help);
894            break;
895        case 255:
896            return;
897        }
898    }
899}
900
901static void conf_cleanup(void)
902{
903    tcsetattr(1, TCSAFLUSH, &ios_org);
904    unlink(".help.tmp");
905}
906
907static void winch_handler(int sig)
908{
909    struct winsize ws;
910
911    if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
912        rows = 24;
913        cols = 80;
914    } else {
915        rows = ws.ws_row;
916        cols = ws.ws_col;
917    }
918
919    if (rows < 19 || cols < 80) {
920        end_dialog();
921        fprintf(stderr, "Your display is too small to run Menuconfig!\n");
922        fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
923        exit(1);
924    }
925
926    rows -= 4;
927    cols -= 5;
928
929}
930
931int main(int ac, char **av)
932{
933    struct symbol *sym;
934    char *mode;
935    int stat;
936
937    conf_parse(av[1]);
938    conf_read(NULL);
939
940    sym = sym_lookup("VERSION", 0);
941    sym_calc_value(sym);
942    snprintf(menu_backtitle, 128, "BusyBox v%s Configuration",
943        sym_get_string_value(sym));
944
945    mode = getenv("MENUCONFIG_MODE");
946    if (mode) {
947        if (!strcasecmp(mode, "single_menu"))
948            single_menu_mode = 1;
949    }
950
951    tcgetattr(1, &ios_org);
952    atexit(conf_cleanup);
953    init_wsize();
954    init_dialog();
955    signal(SIGWINCH, winch_handler);
956    conf(&rootmenu);
957    end_dialog();
958
959    /* Restart dialog to act more like when lxdialog was still separate */
960    init_dialog();
961    do {
962        stat = dialog_yesno(NULL,
963                    "Do you wish to save your new BusyBox configuration?", 5, 60);
964    } while (stat < 0);
965    end_dialog();
966
967    if (stat == 0) {
968        conf_write(NULL);
969        printf("\n"
970            "*** End of BusyBox configuration.\n");
971    } else
972        printf("\n\nYour BusyBox configuration changes were NOT saved.\n\n");
973
974    return 0;
975}
Note: See TracBrowser for help on using the repository browser.