Rework LuCI build system
[project/luci.git] / libs / luci-lib-nixio / axTLS / config / scripts / config / mconf.c
1 /*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 *
5 * Introduced single menu mode (show all sub-menus in one large tree).
6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7 *
8 * 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
31 static char menu_backtitle[128];
32 static const char mconf_readme[] =
33 "Overview\n"
34 "--------\n"
35 "Some features may be built directly into axTLS. 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",
164 menu_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",
171 radiolist_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.",
176 inputbox_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.",
180 inputbox_instructions_hex[] =
181 "Please enter a hexadecimal value. "
182 "Use the <TAB> key to move from the input field to the buttons below it.",
183 inputbox_instructions_string[] =
184 "Please enter a string value. "
185 "Use the <TAB> key to move from the input field to the buttons below it.",
186 setmod_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.",
189 nohelp_text[] =
190 "There is no help available for this option.\n",
191 load_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.",
195 load_config_help[] =
196 "\n"
197 "For various reasons, one may wish to keep several different axTLS\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 "axTLS'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",
206 save_config_text[] =
207 "Enter a filename to which this configuration should be saved "
208 "as an alternate. Leave blank to abort.",
209 save_config_help[] =
210 "\n"
211 "For various reasons, one may wish to keep different axTLS\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",
220 search_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
259 static char filename[PATH_MAX+1] = ".config";
260 static int indent;
261 static struct termios ios_org;
262 static int rows = 0, cols = 0;
263 static struct menu *current_menu;
264 static int child_count;
265 static int single_menu_mode;
266
267 static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
268 static int item_no;
269
270 static void conf(struct menu *menu);
271 static void conf_choice(struct menu *menu);
272 static void conf_string(struct menu *menu);
273 static void conf_load(void);
274 static void conf_save(void);
275 static void show_textbox(const char *title, const char *text, int r, int c);
276 static void show_helptext(const char *title, const char *text);
277 static void show_help(struct menu *menu);
278 static void show_file(const char *filename, const char *title, int r, int c);
279
280 static 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
315 static void cinit(void)
316 {
317 item_no = 0;
318 }
319
320 static 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
330 static 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
347 static 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
361 static 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
374 static 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
405 static 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
433 static 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
446 static void search_conf(void)
447 {
448 struct symbol **sym_arr;
449 struct gstr res;
450
451 again:
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
471 static 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 tristate val;
478 char ch;
479
480 if (!menu_is_visible(menu))
481 return;
482
483 sym = menu->sym;
484 prop = menu->prompt;
485 if (!sym) {
486 if (prop && menu != current_menu) {
487 const char *prompt = menu_get_prompt(menu);
488 switch (prop->type) {
489 case P_MENU:
490 child_count++;
491 cmake();
492 cprint_tag("m%p", menu);
493
494 if (single_menu_mode) {
495 cprint_name("%s%*c%s",
496 menu->data ? "-->" : "++>",
497 indent + 1, ' ', prompt);
498 } else {
499 cprint_name(" %*c%s --->", indent + 1, ' ', prompt);
500 }
501
502 if (single_menu_mode && menu->data)
503 goto conf_childs;
504 return;
505 default:
506 if (prompt) {
507 child_count++;
508 cmake();
509 cprint_tag(":%p", menu);
510 cprint_name("---%*c%s", indent + 1, ' ', prompt);
511 }
512 }
513 } else
514 doint = 0;
515 goto conf_childs;
516 }
517
518 cmake();
519 type = sym_get_type(sym);
520 if (sym_is_choice(sym)) {
521 struct symbol *def_sym = sym_get_choice_value(sym);
522 struct menu *def_menu = NULL;
523
524 child_count++;
525 for (child = menu->list; child; child = child->next) {
526 if (menu_is_visible(child) && child->sym == def_sym)
527 def_menu = child;
528 }
529
530 val = sym_get_tristate_value(sym);
531 if (sym_is_changable(sym)) {
532 cprint_tag("t%p", menu);
533 switch (type) {
534 case S_BOOLEAN:
535 cprint_name("[%c]", val == no ? ' ' : '*');
536 break;
537 case S_TRISTATE:
538 switch (val) {
539 case yes: ch = '*'; break;
540 case mod: ch = 'M'; break;
541 default: ch = ' '; break;
542 }
543 cprint_name("<%c>", ch);
544 break;
545 }
546 } else {
547 cprint_tag("%c%p", def_menu ? 't' : ':', menu);
548 cprint_name(" ");
549 }
550
551 cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
552 if (val == yes) {
553 if (def_menu) {
554 cprint_name(" (%s)", menu_get_prompt(def_menu));
555 cprint_name(" --->");
556 if (def_menu->list) {
557 indent += 2;
558 build_conf(def_menu);
559 indent -= 2;
560 }
561 }
562 return;
563 }
564 } else {
565 if (menu == current_menu) {
566 cprint_tag(":%p", menu);
567 cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
568 goto conf_childs;
569 }
570 child_count++;
571 val = sym_get_tristate_value(sym);
572 if (sym_is_choice_value(sym) && val == yes) {
573 cprint_tag(":%p", menu);
574 cprint_name(" ");
575 } else {
576 switch (type) {
577 case S_BOOLEAN:
578 cprint_tag("t%p", menu);
579 if (sym_is_changable(sym))
580 cprint_name("[%c]", val == no ? ' ' : '*');
581 else
582 cprint_name("---");
583 break;
584 case S_TRISTATE:
585 cprint_tag("t%p", menu);
586 switch (val) {
587 case yes: ch = '*'; break;
588 case mod: ch = 'M'; break;
589 default: ch = ' '; break;
590 }
591 if (sym_is_changable(sym))
592 cprint_name("<%c>", ch);
593 else
594 cprint_name("---");
595 break;
596 default:
597 cprint_tag("s%p", menu);
598 tmp = cprint_name("(%s)", sym_get_string_value(sym));
599 tmp = indent - tmp + 4;
600 if (tmp < 0)
601 tmp = 0;
602 cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
603 (sym_has_value(sym) || !sym_is_changable(sym)) ?
604 "" : " (NEW)");
605 goto conf_childs;
606 }
607 }
608 cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
609 (sym_has_value(sym) || !sym_is_changable(sym)) ?
610 "" : " (NEW)");
611 if (menu->prompt->type == P_MENU) {
612 cprint_name(" --->");
613 return;
614 }
615 }
616
617 conf_childs:
618 indent += doint;
619 for (child = menu->list; child; child = child->next)
620 build_conf(child);
621 indent -= doint;
622 }
623
624 static void conf(struct menu *menu)
625 {
626 struct dialog_list_item *active_item = NULL;
627 struct menu *submenu;
628 const char *prompt = menu_get_prompt(menu);
629 struct symbol *sym;
630 char active_entry[40];
631 int stat, type;
632
633 unlink("lxdialog.scrltmp");
634 active_entry[0] = 0;
635 while (1) {
636 indent = 0;
637 child_count = 0;
638 current_menu = menu;
639 cdone(); cinit();
640 build_conf(menu);
641 if (!child_count)
642 break;
643 if (menu == &rootmenu) {
644 cmake(); cprint_tag(":"); cprint_name("--- ");
645 cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
646 cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
647 }
648 dialog_clear();
649 stat = dialog_menu(prompt ? prompt : "Main Menu",
650 menu_instructions, rows, cols, rows - 10,
651 active_entry, item_no, items);
652 if (stat < 0)
653 return;
654
655 if (stat == 1 || stat == 255)
656 break;
657
658 active_item = first_sel_item(item_no, items);
659 if (!active_item)
660 continue;
661 active_item->selected = 0;
662 strncpy(active_entry, active_item->tag, sizeof(active_entry));
663 active_entry[sizeof(active_entry)-1] = 0;
664 type = active_entry[0];
665 if (!type)
666 continue;
667
668 sym = NULL;
669 submenu = NULL;
670 if (sscanf(active_entry + 1, "%p", &submenu) == 1)
671 sym = submenu->sym;
672
673 switch (stat) {
674 case 0:
675 switch (type) {
676 case 'm':
677 if (single_menu_mode)
678 submenu->data = (void *) (long) !submenu->data;
679 else
680 conf(submenu);
681 break;
682 case 't':
683 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
684 conf_choice(submenu);
685 else if (submenu->prompt->type == P_MENU)
686 conf(submenu);
687 break;
688 case 's':
689 conf_string(submenu);
690 break;
691 case 'L':
692 conf_load();
693 break;
694 case 'S':
695 conf_save();
696 break;
697 }
698 break;
699 case 2:
700 if (sym)
701 show_help(submenu);
702 else
703 show_helptext("README", mconf_readme);
704 break;
705 case 3:
706 if (type == 't') {
707 if (sym_set_tristate_value(sym, yes))
708 break;
709 if (sym_set_tristate_value(sym, mod))
710 show_textbox(NULL, setmod_text, 6, 74);
711 }
712 break;
713 case 4:
714 if (type == 't')
715 sym_set_tristate_value(sym, no);
716 break;
717 case 5:
718 if (type == 't')
719 sym_set_tristate_value(sym, mod);
720 break;
721 case 6:
722 if (type == 't')
723 sym_toggle_tristate_value(sym);
724 else if (type == 'm')
725 conf(submenu);
726 break;
727 case 7:
728 search_conf();
729 break;
730 }
731 }
732 }
733
734 static void show_textbox(const char *title, const char *text, int r, int c)
735 {
736 int fd;
737
738 fd = creat(".help.tmp", 0777);
739 write(fd, text, strlen(text));
740 close(fd);
741 show_file(".help.tmp", title, r, c);
742 unlink(".help.tmp");
743 }
744
745 static void show_helptext(const char *title, const char *text)
746 {
747 show_textbox(title, text, 0, 0);
748 }
749
750 static void show_help(struct menu *menu)
751 {
752 struct gstr help = str_new();
753 struct symbol *sym = menu->sym;
754
755 if (sym->help)
756 {
757 if (sym->name) {
758 str_printf(&help, "%s:\n\n", sym->name);
759 str_append(&help, sym->help);
760 str_append(&help, "\n");
761 }
762 } else {
763 str_append(&help, nohelp_text);
764 }
765 get_symbol_str(&help, sym);
766 show_helptext(menu_get_prompt(menu), str_get(&help));
767 str_free(&help);
768 }
769
770 static void show_file(const char *filename, const char *title, int r, int c)
771 {
772 while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
773 ;
774 }
775
776 static void conf_choice(struct menu *menu)
777 {
778 const char *prompt = menu_get_prompt(menu);
779 struct menu *child;
780 struct symbol *active;
781
782 active = sym_get_choice_value(menu->sym);
783 while (1) {
784 current_menu = menu;
785 cdone(); cinit();
786 for (child = menu->list; child; child = child->next) {
787 if (!menu_is_visible(child))
788 continue;
789 cmake();
790 cprint_tag("%p", child);
791 cprint_name("%s", menu_get_prompt(child));
792 if (child->sym == sym_get_choice_value(menu->sym))
793 items[item_no - 1]->selected = 1; /* ON */
794 else if (child->sym == active)
795 items[item_no - 1]->selected = 2; /* SELECTED */
796 else
797 items[item_no - 1]->selected = 0; /* OFF */
798 }
799
800 switch (dialog_checklist(prompt ? prompt : "Main Menu",
801 radiolist_instructions, 15, 70, 6,
802 item_no, items, FLAG_RADIO)) {
803 case 0:
804 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
805 break;
806 sym_set_tristate_value(child->sym, yes);
807 return;
808 case 1:
809 if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
810 show_help(child);
811 active = child->sym;
812 } else
813 show_help(menu);
814 break;
815 case 255:
816 return;
817 }
818 }
819 }
820
821 static void conf_string(struct menu *menu)
822 {
823 const char *prompt = menu_get_prompt(menu);
824
825 while (1) {
826 char *heading;
827
828 switch (sym_get_type(menu->sym)) {
829 case S_INT:
830 heading = (char *) inputbox_instructions_int;
831 break;
832 case S_HEX:
833 heading = (char *) inputbox_instructions_hex;
834 break;
835 case S_STRING:
836 heading = (char *) inputbox_instructions_string;
837 break;
838 default:
839 heading = "Internal mconf error!";
840 /* panic? */;
841 }
842
843 switch (dialog_inputbox(prompt ? prompt : "Main Menu",
844 heading, 10, 75,
845 sym_get_string_value(menu->sym))) {
846 case 0:
847 if (sym_set_string_value(menu->sym, dialog_input_result))
848 return;
849 show_textbox(NULL, "You have made an invalid entry.", 5, 43);
850 break;
851 case 1:
852 show_help(menu);
853 break;
854 case 255:
855 return;
856 }
857 }
858 }
859
860 static void conf_load(void)
861 {
862 while (1) {
863 switch (dialog_inputbox(NULL, load_config_text, 11, 55,
864 filename)) {
865 case 0:
866 if (!dialog_input_result[0])
867 return;
868 if (!conf_read(dialog_input_result))
869 return;
870 show_textbox(NULL, "File does not exist!", 5, 38);
871 break;
872 case 1:
873 show_helptext("Load Alternate Configuration", load_config_help);
874 break;
875 case 255:
876 return;
877 }
878 }
879 }
880
881 static void conf_save(void)
882 {
883 while (1) {
884 switch (dialog_inputbox(NULL, save_config_text, 11, 55,
885 filename)) {
886 case 0:
887 if (!dialog_input_result[0])
888 return;
889 if (!conf_write(dialog_input_result))
890 return;
891 show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
892 break;
893 case 1:
894 show_helptext("Save Alternate Configuration", save_config_help);
895 break;
896 case 255:
897 return;
898 }
899 }
900 }
901
902 static void conf_cleanup(void)
903 {
904 tcsetattr(1, TCSAFLUSH, &ios_org);
905 unlink(".help.tmp");
906 }
907
908 static void winch_handler(int sig)
909 {
910 struct winsize ws;
911
912 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
913 rows = 24;
914 cols = 80;
915 } else {
916 rows = ws.ws_row;
917 cols = ws.ws_col;
918 }
919
920 if (rows < 19 || cols < 80) {
921 end_dialog();
922 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
923 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
924 exit(1);
925 }
926
927 rows -= 4;
928 cols -= 5;
929
930 }
931
932 int main(int ac, char **av)
933 {
934 struct symbol *sym;
935 char *mode;
936 int stat;
937
938 conf_parse(av[1]);
939 conf_read(NULL);
940
941 sym = sym_lookup("VERSION", 0);
942 sym_calc_value(sym);
943 snprintf(menu_backtitle, 128, "axTLS v%s Configuration",
944 sym_get_string_value(sym));
945
946 mode = getenv("MENUCONFIG_MODE");
947 if (mode) {
948 if (!strcasecmp(mode, "single_menu"))
949 single_menu_mode = 1;
950 }
951
952 tcgetattr(1, &ios_org);
953 atexit(conf_cleanup);
954 init_wsize();
955 init_dialog();
956 signal(SIGWINCH, winch_handler);
957 conf(&rootmenu);
958 end_dialog();
959
960 /* Restart dialog to act more like when lxdialog was still separate */
961 init_dialog();
962 do {
963 stat = dialog_yesno(NULL,
964 "Do you wish to save your new axTLS configuration?", 5, 60);
965 } while (stat < 0);
966 end_dialog();
967
968 if (stat == 0) {
969 conf_write(NULL);
970 printf("\n\n"
971 "*** End of axTLS configuration.\n"
972 "*** Check the top-level Makefile for additional configuration options.\n\n");
973 } else
974 printf("\n\nYour axTLS configuration changes were NOT saved.\n\n");
975
976 return 0;
977 }