source: menu/mconf.c@ 3d48216

new_features
Last change on this file since 3d48216 was 8010030, checked in by Pierre Labastie <pierre@…>, 8 years ago

Merge trunk rev 3916:
Add the possibility to install BLFS tools to a running LFS from the jhalfs
menu:

  • Add the possibility to choose BOOK_BLFS from menu. That hides all the irrelevant parameters
  • Adapt install-blfs-tools.sh
  • Change slightly mconf.c so that there is a better alignement in menus
  • Property mode set to 100644
File size: 25.4 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 <sys/termios.h>
15#include <ctype.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <limits.h>
19#include <signal.h>
20#include <stdarg.h>
21#include <stdlib.h>
22#include <string.h>
23#include <termios.h>
24#include <unistd.h>
25
26#include "lxdialog/dialog.h"
27
28#define LKC_DIRECT_LINK
29#include "lkc.h"
30
31static char menu_backtitle[128];
32static const char mconf_readme[] =
33"Overview\n"
34"--------\n"
35"Some features may be built directly into JHALFS. Some features\n"
36"may be completely removed altogether. There are also certain\n"
37"parameters which are not really features, but must be\n"
38"entered in as decimal or hexadecimal numbers or possibly text.\n"
39"\n"
40"Menu items beginning with [*] or [ ] represent features\n"
41"configured to be built in or removed respectively.\n"
42"\n"
43"To change any of these features, highlight it with the cursor\n"
44"keys and press <Y> to build it in or <N> to removed it.\n"
45"You may also press the <Space Bar> to cycle\n"
46"through the available options (ie. Y->N->Y).\n"
47"\n"
48"Some additional keyboard hints:\n"
49"\n"
50"Menus\n"
51"----------\n"
52"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
53" you wish to change or submenu wish to select and press <Enter>.\n"
54" Submenus are designated by \"--->\".\n"
55"\n"
56" Shortcut: Press the option's highlighted letter (hotkey).\n"
57" Pressing a hotkey more than once will sequence\n"
58" through all visible items which use that hotkey.\n"
59"\n"
60" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
61" unseen options into view.\n"
62"\n"
63"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
64" and press <ENTER>.\n"
65"\n"
66" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
67" using those letters. You may press a single <ESC>, but\n"
68" there is a delayed response which you may find annoying.\n"
69"\n"
70" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
71" <Exit> and <Help>\n"
72"\n"
73"o To get help with an item, use the cursor keys to highlight <Help>\n"
74" and Press <ENTER>.\n"
75"\n"
76" Shortcut: Press <H> or <?>.\n"
77"\n"
78"\n"
79"Radiolists (Choice lists)\n"
80"-----------\n"
81"o Use the cursor keys to select the option you wish to set and press\n"
82" <S> or the <SPACE BAR>.\n"
83"\n"
84" Shortcut: Press the first letter of the option you wish to set then\n"
85" press <S> or <SPACE BAR>.\n"
86"\n"
87"o To see available help for the item, use the cursor keys to highlight\n"
88" <Help> and Press <ENTER>.\n"
89"\n"
90" Shortcut: Press <H> or <?>.\n"
91"\n"
92" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
93" <Help>\n"
94"\n"
95"\n"
96"Data Entry\n"
97"-----------\n"
98"o Enter the requested information and press <ENTER>\n"
99" If you are entering hexadecimal values, it is not necessary to\n"
100" add the '0x' prefix to the entry.\n"
101"\n"
102"o For help, use the <TAB> or cursor keys to highlight the help option\n"
103" and press <ENTER>. You can try <TAB><H> as well.\n"
104"\n"
105"\n"
106"Text Box (Help Window)\n"
107"--------\n"
108"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
109" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
110" who are familiar with less and lynx.\n"
111"\n"
112"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
113"\n"
114"\n"
115"Alternate Configuration Files\n"
116"-----------------------------\n"
117"Menuconfig supports the use of alternate configuration files for\n"
118"those who, for various reasons, find it necessary to switch\n"
119"between different configurations.\n"
120"\n"
121"At the end of the main menu you will find two options. One is\n"
122"for saving the current configuration to a file of your choosing.\n"
123"The other option is for loading a previously saved alternate\n"
124"configuration.\n"
125"\n"
126"Even if you don't use alternate configuration files, but you\n"
127"find during a Menuconfig session that you have completely messed\n"
128"up your settings, you may use the \"Load Alternate...\" option to\n"
129"restore your previously saved settings from \".config\" without\n"
130"restarting Menuconfig.\n"
131"\n"
132"Other information\n"
133"-----------------\n"
134"If you use Menuconfig in an XTERM window make sure you have your\n"
135"$TERM variable set to point to a xterm definition which supports color.\n"
136"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
137"display correctly in a RXVT window because rxvt displays only one\n"
138"intensity of color, bright.\n"
139"\n"
140"Menuconfig will display larger menus on screens or xterms which are\n"
141"set to display more than the standard 25 row by 80 column geometry.\n"
142"In order for this to work, the \"stty size\" command must be able to\n"
143"display the screen's current row and column geometry. I STRONGLY\n"
144"RECOMMEND that you make sure you do NOT have the shell variables\n"
145"LINES and COLUMNS exported into your environment. Some distributions\n"
146"export those variables via /etc/profile. Some ncurses programs can\n"
147"become confused when those variables (LINES & COLUMNS) don't reflect\n"
148"the true screen size.\n"
149"\n"
150"Optional personality available\n"
151"------------------------------\n"
152"If you prefer to have all of the options listed in a single\n"
153"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
154"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
155"\n"
156"make MENUCONFIG_MODE=single_menu menuconfig\n"
157"\n"
158"<Enter> will then unroll the appropriate category, or enfold it if it\n"
159"is already unrolled.\n"
160"\n"
161"Note that this mode can eventually be a little more CPU expensive\n"
162"(especially with a larger number of unrolled categories) than the\n"
163"default mode.\n",
164menu_instructions[] =
165 "Arrow keys navigate the menu. "
166 "<Enter> selects submenus --->. "
167 "Highlighted letters are hotkeys. "
168 "Pressing <Y> selectes a feature, while <N> will exclude a feature. "
169 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
170 "Legend: [*] feature is selected [ ] feature is excluded",
171radiolist_instructions[] =
172 "Use the arrow keys to navigate this window or "
173 "press the hotkey of the item you wish to select "
174 "followed by the <SPACE BAR>. "
175 "Press <?> for additional information about this option.",
176inputbox_instructions_int[] =
177 "Please enter a decimal value. "
178 "Fractions will not be accepted. "
179 "Use the <TAB> key to move from the input field to the buttons below it.",
180inputbox_instructions_hex[] =
181 "Please enter a hexadecimal value. "
182 "Use the <TAB> key to move from the input field to the buttons below it.",
183inputbox_instructions_string[] =
184 "Please enter a string value. "
185 "Use the <TAB> key to move from the input field to the buttons below it.",
186setmod_text[] =
187 "This feature depends on another which has been configured as a module.\n"
188 "As a result, this feature will be built as a module.",
189nohelp_text[] =
190 "There is no help available for this option.\n",
191load_config_text[] =
192 "Enter the name of the configuration file you wish to load. "
193 "Accept the name shown to restore the configuration you "
194 "last retrieved. Leave blank to abort.",
195load_config_help[] =
196 "\n"
197 "For various reasons, one may wish to keep several different JHALFS\n"
198 "configurations available on a single machine.\n"
199 "\n"
200 "If you have saved a previous configuration in a file other than the\n"
201 "JHALFS's default, entering the name of the file here will allow you\n"
202 "to modify that configuration.\n"
203 "\n"
204 "If you are uncertain, then you have probably never used alternate\n"
205 "configuration files. You should therefor leave this blank to abort.\n",
206save_config_text[] =
207 "Enter a filename to which this configuration should be saved "
208 "as an alternate. Leave blank to abort.",
209save_config_help[] =
210 "\n"
211 "For various reasons, one may wish to keep different JHALFS\n"
212 "configurations available on a single machine.\n"
213 "\n"
214 "Entering a file name here will allow you to later retrieve, modify\n"
215 "and use the current configuration as an alternate to whatever\n"
216 "configuration options you have selected at that time.\n"
217 "\n"
218 "If you are uncertain what all this means then you should probably\n"
219 "leave this blank.\n",
220search_help[] =
221 "\n"
222 "Search for CONFIG_ symbols and display their relations.\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 filename[PATH_MAX+1] = ".config";
260static int indent;
261static struct termios ios_org;
262static int rows = 0, cols = 0;
263static struct menu *current_menu;
264static int child_count;
265static int single_menu_mode;
266
267static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
268static int item_no;
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 init_wsize(void)
281{
282 struct winsize ws;
283 char *env;
284
285 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
286 rows = ws.ws_row;
287 cols = ws.ws_col;
288 }
289
290 if (!rows) {
291 env = getenv("LINES");
292 if (env)
293 rows = atoi(env);
294 if (!rows)
295 rows = 24;
296 }
297 if (!cols) {
298 env = getenv("COLUMNS");
299 if (env)
300 cols = atoi(env);
301 if (!cols)
302 cols = 80;
303 }
304
305 if (rows < 19 || cols < 80) {
306 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
307 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
308 exit(1);
309 }
310
311 rows -= 4;
312 cols -= 5;
313}
314
315static void cinit(void)
316{
317 item_no = 0;
318}
319
320static void cmake(void)
321{
322 items[item_no] = malloc(sizeof(struct dialog_list_item));
323 memset(items[item_no], 0, sizeof(struct dialog_list_item));
324 items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0;
325 items[item_no]->name = malloc(512); items[item_no]->name[0] = 0;
326 items[item_no]->namelen = 0;
327 item_no++;
328}
329
330static int cprint_name(const char *fmt, ...)
331{
332 va_list ap;
333 int res;
334
335 if (!item_no)
336 cmake();
337 va_start(ap, fmt);
338 res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
339 512 - items[item_no - 1]->namelen, fmt, ap);
340 if (res > 0)
341 items[item_no - 1]->namelen += res;
342 va_end(ap);
343
344 return res;
345}
346
347static int cprint_tag(const char *fmt, ...)
348{
349 va_list ap;
350 int res;
351
352 if (!item_no)
353 cmake();
354 va_start(ap, fmt);
355 res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
356 va_end(ap);
357
358 return res;
359}
360
361static void cdone(void)
362{
363 int i;
364
365 for (i = 0; i < item_no; i++) {
366 free(items[i]->tag);
367 free(items[i]->name);
368 free(items[i]);
369 }
370
371 item_no = 0;
372}
373
374static void get_prompt_str(struct gstr *r, struct property *prop)
375{
376 int i, j;
377 struct menu *submenu[8], *menu;
378
379 str_printf(r, "Prompt: %s\n", prop->text);
380 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
381 prop->menu->lineno);
382 if (!expr_is_yes(prop->visible.expr)) {
383 str_append(r, " Depends on: ");
384 expr_gstr_print(prop->visible.expr, r);
385 str_append(r, "\n");
386 }
387 menu = prop->menu->parent;
388 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
389 submenu[i++] = menu;
390 if (i > 0) {
391 str_printf(r, " Location:\n");
392 for (j = 4; --i >= 0; j += 2) {
393 menu = submenu[i];
394 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
395 if (menu->sym) {
396 str_printf(r, " (%s [=%s])", menu->sym->name ?
397 menu->sym->name : "<choice>",
398 sym_get_string_value(menu->sym));
399 }
400 str_append(r, "\n");
401 }
402 }
403}
404
405static void get_symbol_str(struct gstr *r, struct symbol *sym)
406{
407 bool hit;
408 struct property *prop;
409
410 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
411 sym_get_string_value(sym));
412 for_all_prompts(sym, prop)
413 get_prompt_str(r, prop);
414 hit = false;
415 for_all_properties(sym, prop, P_SELECT) {
416 if (!hit) {
417 str_append(r, " Selects: ");
418 hit = true;
419 } else
420 str_printf(r, " && ");
421 expr_gstr_print(prop->expr, r);
422 }
423 if (hit)
424 str_append(r, "\n");
425 if (sym->rev_dep.expr) {
426 str_append(r, " Selected by: ");
427 expr_gstr_print(sym->rev_dep.expr, r);
428 str_append(r, "\n");
429 }
430 str_append(r, "\n\n");
431}
432
433static struct gstr get_relations_str(struct symbol **sym_arr)
434{
435 struct symbol *sym;
436 struct gstr res = str_new();
437 int i;
438
439 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
440 get_symbol_str(&res, sym);
441 if (!i)
442 str_append(&res, "No matches found.\n");
443 return res;
444}
445
446static void search_conf(void)
447{
448 struct symbol **sym_arr;
449 struct gstr res;
450
451again:
452 switch (dialog_inputbox("Search Configuration Parameter",
453 "Enter Keyword", 10, 75,
454 NULL)) {
455 case 0:
456 break;
457 case 1:
458 show_helptext("Search Configuration", search_help);
459 goto again;
460 default:
461 return;
462 }
463
464 sym_arr = sym_re_search(dialog_input_result);
465 res = get_relations_str(sym_arr);
466 free(sym_arr);
467 show_textbox("Search Results", str_get(&res), 0, 0);
468 str_free(&res);
469}
470
471static void build_conf(struct menu *menu)
472{
473 struct symbol *sym;
474 struct property *prop;
475 struct menu *child;
476/* int type, tmp, doint = 2; */
477 int type, doint = 2;
478 tristate val;
479 char ch;
480
481 if (!menu_is_visible(menu))
482 return;
483
484 sym = menu->sym;
485 prop = menu->prompt;
486 if (!sym) {
487 if (prop && menu != current_menu) {
488 const char *prompt = menu_get_prompt(menu);
489 switch (prop->type) {
490 case P_MENU:
491 child_count++;
492 cmake();
493 cprint_tag("m%p", menu);
494
495 if (single_menu_mode) {
496 cprint_name("%s%*c%s",
497 menu->data ? "-->" : "++>",
498 indent + 1, ' ', prompt);
499 } else {
500 cprint_name(" %*c%s --->", indent + 1, ' ', prompt);
501 }
502
503 if (single_menu_mode && menu->data)
504 goto conf_childs;
505 return;
506 default:
507 if (prompt) {
508 child_count++;
509 cmake();
510 cprint_tag(":%p", menu);
511 cprint_name("---%*c%s", indent + 1, ' ', prompt);
512 }
513 }
514 } else
515 doint = 0;
516 goto conf_childs;
517 }
518
519 cmake();
520 type = sym_get_type(sym);
521 if (sym_is_choice(sym)) {
522 struct symbol *def_sym = sym_get_choice_value(sym);
523 struct menu *def_menu = NULL;
524
525 child_count++;
526 for (child = menu->list; child; child = child->next) {
527 if (menu_is_visible(child) && child->sym == def_sym)
528 def_menu = child;
529 }
530
531 val = sym_get_tristate_value(sym);
532 if (sym_is_changable(sym)) {
533 cprint_tag("t%p", menu);
534 switch (type) {
535 case S_BOOLEAN:
536 cprint_name("[%c]", val == no ? ' ' : '*');
537 break;
538 case S_TRISTATE:
539 switch (val) {
540 case yes: ch = '*'; break;
541 case mod: ch = 'M'; break;
542 default: ch = ' '; break;
543 }
544 cprint_name("<%c>", ch);
545 break;
546 }
547 } else {
548 cprint_tag("%c%p", def_menu ? 't' : ':', menu);
549 cprint_name(" ");
550 }
551
552 cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
553 if (val == yes) {
554 if (def_menu) {
555 cprint_name(" (%s)", menu_get_prompt(def_menu));
556 cprint_name(" --->");
557 if (def_menu->list) {
558 indent += 2;
559 build_conf(def_menu);
560 indent -= 2;
561 }
562 }
563 return;
564 }
565 } else {
566 if (menu == current_menu) {
567 cprint_tag(":%p", menu);
568 cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
569 goto conf_childs;
570 }
571 child_count++;
572 val = sym_get_tristate_value(sym);
573 if (sym_is_choice_value(sym) && val == yes) {
574 cprint_tag(":%p", menu);
575 cprint_name(" ");
576 } else {
577 switch (type) {
578 case S_BOOLEAN:
579 cprint_tag("t%p", menu);
580 if (sym_is_changable(sym))
581 cprint_name("[%c]", val == no ? ' ' : '*');
582 else
583 cprint_name("---");
584 break;
585 case S_TRISTATE:
586 cprint_tag("t%p", menu);
587 switch (val) {
588 case yes: ch = '*'; break;
589 case mod: ch = 'M'; break;
590 default: ch = ' '; break;
591 }
592 if (sym_is_changable(sym))
593 cprint_name("<%c>", ch);
594 else
595 cprint_name("---");
596 break;
597 default:
598 cprint_tag("s%p", menu);
599/* tmp = cprint_name("(%s)", sym_get_string_value(sym));
600 tmp = indent - tmp + 4;
601 if (tmp < 0)
602 tmp = 0; */
603 cprint_name(" %*c%s (%s)%s",
604 indent+1, ' ',
605 menu_get_prompt(menu),
606 sym_get_string_value(sym),
607 (sym_has_value(sym) || !sym_is_changable(sym)) ?
608 "" : " (NEW)");
609 goto conf_childs;
610 }
611 }
612 cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
613 (sym_has_value(sym) || !sym_is_changable(sym)) ?
614 "" : " (NEW)");
615 if (menu->prompt->type == P_MENU) {
616 cprint_name(" --->");
617 return;
618 }
619 }
620
621conf_childs:
622 indent += doint;
623 for (child = menu->list; child; child = child->next)
624 build_conf(child);
625 indent -= doint;
626}
627
628static void conf(struct menu *menu)
629{
630 struct dialog_list_item *active_item = NULL;
631 struct menu *submenu;
632 const char *prompt = menu_get_prompt(menu);
633 struct symbol *sym;
634 char active_entry[40];
635 int stat, type;
636
637 unlink("lxdialog.scrltmp");
638 active_entry[0] = 0;
639 while (1) {
640 indent = 0;
641 child_count = 0;
642 current_menu = menu;
643 cdone(); cinit();
644 build_conf(menu);
645 if (!child_count)
646 break;
647 if (menu == &rootmenu) {
648 cmake(); cprint_tag(":"); cprint_name("--- ");
649 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
650 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
651 }
652 dialog_clear();
653 stat = dialog_menu(prompt ? prompt : "Main Menu",
654 menu_instructions, rows, cols, rows - 10,
655 active_entry, item_no, items);
656 if (stat < 0)
657 return;
658
659 if (stat == 1 || stat == 255)
660 break;
661
662 active_item = first_sel_item(item_no, items);
663 if (!active_item)
664 continue;
665 active_item->selected = 0;
666 strncpy(active_entry, active_item->tag, sizeof(active_entry));
667 active_entry[sizeof(active_entry)-1] = 0;
668 type = active_entry[0];
669 if (!type)
670 continue;
671
672 sym = NULL;
673 submenu = NULL;
674 if (sscanf(active_entry + 1, "%p", &submenu) == 1)
675 sym = submenu->sym;
676
677 switch (stat) {
678 case 0:
679 switch (type) {
680 case 'm':
681 if (single_menu_mode)
682 submenu->data = (void *) (long) !submenu->data;
683 else
684 conf(submenu);
685 break;
686 case 't':
687 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
688 conf_choice(submenu);
689 else if (submenu->prompt->type == P_MENU)
690 conf(submenu);
691 break;
692 case 's':
693 conf_string(submenu);
694 break;
695 case 'L':
696 conf_load();
697 break;
698 case 'S':
699 conf_save();
700 break;
701 }
702 break;
703 case 2:
704 if (sym)
705 show_help(submenu);
706 else
707 show_helptext("README", mconf_readme);
708 break;
709 case 3:
710 if (type == 't') {
711 if (sym_set_tristate_value(sym, yes))
712 break;
713 if (sym_set_tristate_value(sym, mod))
714 show_textbox(NULL, setmod_text, 6, 74);
715 }
716 break;
717 case 4:
718 if (type == 't')
719 sym_set_tristate_value(sym, no);
720 break;
721 case 5:
722 if (type == 't')
723 sym_set_tristate_value(sym, mod);
724 break;
725 case 6:
726 if (type == 't')
727 sym_toggle_tristate_value(sym);
728 else if (type == 'm')
729 conf(submenu);
730 break;
731 case 7:
732 search_conf();
733 break;
734 }
735 }
736}
737
738static void show_textbox(const char *title, const char *text, int r, int c)
739{
740 int fd;
741
742 fd = creat(".help.tmp", 0777);
743 write(fd, text, strlen(text));
744 close(fd);
745 show_file(".help.tmp", title, r, c);
746 unlink(".help.tmp");
747}
748
749static void show_helptext(const char *title, const char *text)
750{
751 show_textbox(title, text, 0, 0);
752}
753
754static void show_help(struct menu *menu)
755{
756 struct gstr help = str_new();
757 struct symbol *sym = menu->sym;
758
759 if (sym->help)
760 {
761 if (sym->name) {
762 str_printf(&help, "%s:\n\n", sym->name);
763 str_append(&help, sym->help);
764 str_append(&help, "\n");
765 }
766 } else {
767 str_append(&help, nohelp_text);
768 }
769 get_symbol_str(&help, sym);
770 show_helptext(menu_get_prompt(menu), str_get(&help));
771 str_free(&help);
772}
773
774static void show_file(const char *filename, const char *title, int r, int c)
775{
776 while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
777 ;
778}
779
780static void conf_choice(struct menu *menu)
781{
782 const char *prompt = menu_get_prompt(menu);
783 struct menu *child;
784 struct symbol *active;
785
786 active = sym_get_choice_value(menu->sym);
787 while (1) {
788 current_menu = menu;
789 cdone(); cinit();
790 for (child = menu->list; child; child = child->next) {
791 if (!menu_is_visible(child))
792 continue;
793 cmake();
794 cprint_tag("%p", child);
795 cprint_name("%s", menu_get_prompt(child));
796 if (child->sym == sym_get_choice_value(menu->sym))
797 items[item_no - 1]->selected = 1; /* ON */
798 else if (child->sym == active)
799 items[item_no - 1]->selected = 2; /* SELECTED */
800 else
801 items[item_no - 1]->selected = 0; /* OFF */
802 }
803
804 switch (dialog_checklist(prompt ? prompt : "Main Menu",
805 radiolist_instructions, 15, 70, 6,
806 item_no, items, FLAG_RADIO)) {
807 case 0:
808 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
809 break;
810 sym_set_tristate_value(child->sym, yes);
811 return;
812 case 1:
813 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
814 show_help(child);
815 active = child->sym;
816 } else
817 show_help(menu);
818 break;
819 case 255:
820 return;
821 }
822 }
823}
824
825static void conf_string(struct menu *menu)
826{
827 const char *prompt = menu_get_prompt(menu);
828
829 while (1) {
830 char *heading;
831
832 switch (sym_get_type(menu->sym)) {
833 case S_INT:
834 heading = (char *) inputbox_instructions_int;
835 break;
836 case S_HEX:
837 heading = (char *) inputbox_instructions_hex;
838 break;
839 case S_STRING:
840 heading = (char *) inputbox_instructions_string;
841 break;
842 default:
843 heading = "Internal mconf error!";
844 /* panic? */;
845 }
846
847 switch (dialog_inputbox(prompt ? prompt : "Main Menu",
848 heading, 10, 75,
849 sym_get_string_value(menu->sym))) {
850 case 0:
851 if (sym_set_string_value(menu->sym, dialog_input_result))
852 return;
853 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
854 break;
855 case 1:
856 show_help(menu);
857 break;
858 case 255:
859 return;
860 }
861 }
862}
863
864static void conf_load(void)
865{
866 while (1) {
867 switch (dialog_inputbox(NULL, load_config_text, 11, 55,
868 filename)) {
869 case 0:
870 if (!dialog_input_result[0])
871 return;
872 if (!conf_read(dialog_input_result))
873 return;
874 show_textbox(NULL, "File does not exist!", 5, 38);
875 break;
876 case 1:
877 show_helptext("Load Alternate Configuration", load_config_help);
878 break;
879 case 255:
880 return;
881 }
882 }
883}
884
885static void conf_save(void)
886{
887 while (1) {
888 switch (dialog_inputbox(NULL, save_config_text, 11, 55,
889 filename)) {
890 case 0:
891 if (!dialog_input_result[0])
892 return;
893 if (!conf_write(dialog_input_result))
894 return;
895 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
896 break;
897 case 1:
898 show_helptext("Save Alternate Configuration", save_config_help);
899 break;
900 case 255:
901 return;
902 }
903 }
904}
905
906static void conf_cleanup(void)
907{
908 tcsetattr(1, TCSAFLUSH, &ios_org);
909 unlink(".help.tmp");
910}
911
912static void winch_handler(int sig)
913{
914 struct winsize ws;
915
916 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
917 rows = 24;
918 cols = 80;
919 } else {
920 rows = ws.ws_row;
921 cols = ws.ws_col;
922 }
923
924 if (rows < 19 || cols < 80) {
925 end_dialog();
926 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
927 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
928 exit(1);
929 }
930
931 rows -= 4;
932 cols -= 5;
933
934}
935
936int main(int ac, char **av)
937{
938 struct symbol *sym;
939 char *mode;
940 int stat;
941
942 conf_parse(av[1]);
943 conf_read(NULL);
944
945 sym = sym_lookup("VERSION", 0);
946 sym_calc_value(sym);
947 snprintf(menu_backtitle, 128, "JHALFS v%s Configuration",
948 sym_get_string_value(sym));
949
950 mode = getenv("MENUCONFIG_MODE");
951 if (mode) {
952 if (!strcasecmp(mode, "single_menu"))
953 single_menu_mode = 1;
954 }
955
956 tcgetattr(1, &ios_org);
957 atexit(conf_cleanup);
958 init_wsize();
959 init_dialog();
960 signal(SIGWINCH, winch_handler);
961 conf(&rootmenu);
962 end_dialog();
963
964 /* Restart dialog to act more like when lxdialog was still separate */
965 init_dialog();
966 do {
967 stat = dialog_yesno(NULL,
968 "Do you wish to save your new JHALFS configuration?", 5, 60);
969 } while (stat < 0);
970 end_dialog();
971
972 if (stat == 0) {
973 conf_write(NULL);
974 printf("\n"
975 "*** End of JHALFS configuration.\n");
976 } else
977 printf("\n\nYour JHALFS configuration changes were NOT saved.\n\n");
978
979 return 0;
980}
Note: See TracBrowser for help on using the repository browser.