Mercurial > hg > toybox
comparison kconfig/mconf.c @ 10:4d21d59f3206
Add menuconfig, plus some basic Config info, lots of which is just future
plans for toysh. Nothing's currently _using_ this config info, but at least
it's being generated now.
author | landley@driftwood |
---|---|
date | Tue, 31 Oct 2006 23:30:06 -0500 |
parents | |
children | 261736dafd2e |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 10:4d21d59f3206 |
---|---|
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 #include "lxdialog/dialog.h" | |
28 | |
29 static char menu_backtitle[128]; | |
30 static const char mconf_readme[] = N_( | |
31 "Overview\n" | |
32 "--------\n" | |
33 "Some kernel features may be built directly into the kernel.\n" | |
34 "Some may be made into loadable runtime modules. Some features\n" | |
35 "may be completely removed altogether. There are also certain\n" | |
36 "kernel 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 [*], <M> or [ ] represent features\n" | |
40 "configured to be built in, modularized or removed respectively.\n" | |
41 "Pointed brackets <> represent module capable features.\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, <M> to make it a module or\n" | |
45 "<N> to removed it. You may also press the <Space Bar> to cycle\n" | |
46 "through the available options (ie. Y->N->M->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 kernel 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 kernel 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 "\n" | |
165 "Different color themes available\n" | |
166 "--------------------------------\n" | |
167 "It is possible to select different color themes using the variable\n" | |
168 "MENUCONFIG_COLOR. To select a theme use:\n" | |
169 "\n" | |
170 "make MENUCONFIG_COLOR=<theme> menuconfig\n" | |
171 "\n" | |
172 "Available themes are\n" | |
173 " mono => selects colors suitable for monochrome displays\n" | |
174 " blackbg => selects a color scheme with black background\n" | |
175 " classic => theme with blue background. The classic look\n" | |
176 " bluetitle => a LCD friendly version of classic. (default)\n" | |
177 "\n"), | |
178 menu_instructions[] = N_( | |
179 "Arrow keys navigate the menu. " | |
180 "<Enter> selects submenus --->. " | |
181 "Highlighted letters are hotkeys. " | |
182 "Pressing <Y> includes, <N> excludes, <M> modularizes features. " | |
183 "Press <Esc><Esc> to exit, <?> for Help, </> for Search. " | |
184 "Legend: [*] built-in [ ] excluded <M> module < > module capable"), | |
185 radiolist_instructions[] = N_( | |
186 "Use the arrow keys to navigate this window or " | |
187 "press the hotkey of the item you wish to select " | |
188 "followed by the <SPACE BAR>. " | |
189 "Press <?> for additional information about this option."), | |
190 inputbox_instructions_int[] = N_( | |
191 "Please enter a decimal value. " | |
192 "Fractions will not be accepted. " | |
193 "Use the <TAB> key to move from the input field to the buttons below it."), | |
194 inputbox_instructions_hex[] = N_( | |
195 "Please enter a hexadecimal value. " | |
196 "Use the <TAB> key to move from the input field to the buttons below it."), | |
197 inputbox_instructions_string[] = N_( | |
198 "Please enter a string value. " | |
199 "Use the <TAB> key to move from the input field to the buttons below it."), | |
200 setmod_text[] = N_( | |
201 "This feature depends on another which has been configured as a module.\n" | |
202 "As a result, this feature will be built as a module."), | |
203 nohelp_text[] = N_( | |
204 "There is no help available for this kernel option.\n"), | |
205 load_config_text[] = N_( | |
206 "Enter the name of the configuration file you wish to load. " | |
207 "Accept the name shown to restore the configuration you " | |
208 "last retrieved. Leave blank to abort."), | |
209 load_config_help[] = N_( | |
210 "\n" | |
211 "For various reasons, one may wish to keep several different kernel\n" | |
212 "configurations available on a single machine.\n" | |
213 "\n" | |
214 "If you have saved a previous configuration in a file other than the\n" | |
215 "kernel's default, entering the name of the file here will allow you\n" | |
216 "to modify that configuration.\n" | |
217 "\n" | |
218 "If you are uncertain, then you have probably never used alternate\n" | |
219 "configuration files. You should therefor leave this blank to abort.\n"), | |
220 save_config_text[] = N_( | |
221 "Enter a filename to which this configuration should be saved " | |
222 "as an alternate. Leave blank to abort."), | |
223 save_config_help[] = N_( | |
224 "\n" | |
225 "For various reasons, one may wish to keep different kernel\n" | |
226 "configurations available on a single machine.\n" | |
227 "\n" | |
228 "Entering a file name here will allow you to later retrieve, modify\n" | |
229 "and use the current configuration as an alternate to whatever\n" | |
230 "configuration options you have selected at that time.\n" | |
231 "\n" | |
232 "If you are uncertain what all this means then you should probably\n" | |
233 "leave this blank.\n"), | |
234 search_help[] = N_( | |
235 "\n" | |
236 "Search for CONFIG_ symbols and display their relations.\n" | |
237 "Regular expressions are allowed.\n" | |
238 "Example: search for \"^FOO\"\n" | |
239 "Result:\n" | |
240 "-----------------------------------------------------------------\n" | |
241 "Symbol: FOO [=m]\n" | |
242 "Prompt: Foo bus is used to drive the bar HW\n" | |
243 "Defined at drivers/pci/Kconfig:47\n" | |
244 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" | |
245 "Location:\n" | |
246 " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" | |
247 " -> PCI support (PCI [=y])\n" | |
248 " -> PCI access mode (<choice> [=y])\n" | |
249 "Selects: LIBCRC32\n" | |
250 "Selected by: BAR\n" | |
251 "-----------------------------------------------------------------\n" | |
252 "o The line 'Prompt:' shows the text used in the menu structure for\n" | |
253 " this CONFIG_ symbol\n" | |
254 "o The 'Defined at' line tell at what file / line number the symbol\n" | |
255 " is defined\n" | |
256 "o The 'Depends on:' line tell what symbols needs to be defined for\n" | |
257 " this symbol to be visible in the menu (selectable)\n" | |
258 "o The 'Location:' lines tell where in the menu structure this symbol\n" | |
259 " is located\n" | |
260 " A location followed by a [=y] indicate that this is a selectable\n" | |
261 " menu item - and current value is displayed inside brackets.\n" | |
262 "o The 'Selects:' line tell what symbol will be automatically\n" | |
263 " selected if this symbol is selected (y or m)\n" | |
264 "o The 'Selected by' line tell what symbol has selected this symbol\n" | |
265 "\n" | |
266 "Only relevant lines are shown.\n" | |
267 "\n\n" | |
268 "Search examples:\n" | |
269 "Examples: USB => find all CONFIG_ symbols containing USB\n" | |
270 " ^USB => find all CONFIG_ symbols starting with USB\n" | |
271 " USB$ => find all CONFIG_ symbols ending with USB\n" | |
272 "\n"); | |
273 | |
274 static char filename[PATH_MAX+1] = ".config"; | |
275 static int indent; | |
276 static struct termios ios_org; | |
277 static int rows = 0, cols = 0; | |
278 static struct menu *current_menu; | |
279 static int child_count; | |
280 static int single_menu_mode; | |
281 | |
282 static void conf(struct menu *menu); | |
283 static void conf_choice(struct menu *menu); | |
284 static void conf_string(struct menu *menu); | |
285 static void conf_load(void); | |
286 static void conf_save(void); | |
287 static void show_textbox(const char *title, const char *text, int r, int c); | |
288 static void show_helptext(const char *title, const char *text); | |
289 static void show_help(struct menu *menu); | |
290 | |
291 static void init_wsize(void) | |
292 { | |
293 struct winsize ws; | |
294 char *env; | |
295 | |
296 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) { | |
297 rows = ws.ws_row; | |
298 cols = ws.ws_col; | |
299 } | |
300 | |
301 if (!rows) { | |
302 env = getenv("LINES"); | |
303 if (env) | |
304 rows = atoi(env); | |
305 if (!rows) | |
306 rows = 24; | |
307 } | |
308 if (!cols) { | |
309 env = getenv("COLUMNS"); | |
310 if (env) | |
311 cols = atoi(env); | |
312 if (!cols) | |
313 cols = 80; | |
314 } | |
315 | |
316 if (rows < 19 || cols < 80) { | |
317 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); | |
318 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); | |
319 exit(1); | |
320 } | |
321 | |
322 rows -= 4; | |
323 cols -= 5; | |
324 } | |
325 | |
326 static void get_prompt_str(struct gstr *r, struct property *prop) | |
327 { | |
328 int i, j; | |
329 struct menu *submenu[8], *menu; | |
330 | |
331 str_printf(r, "Prompt: %s\n", prop->text); | |
332 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, | |
333 prop->menu->lineno); | |
334 if (!expr_is_yes(prop->visible.expr)) { | |
335 str_append(r, " Depends on: "); | |
336 expr_gstr_print(prop->visible.expr, r); | |
337 str_append(r, "\n"); | |
338 } | |
339 menu = prop->menu->parent; | |
340 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) | |
341 submenu[i++] = menu; | |
342 if (i > 0) { | |
343 str_printf(r, " Location:\n"); | |
344 for (j = 4; --i >= 0; j += 2) { | |
345 menu = submenu[i]; | |
346 str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); | |
347 if (menu->sym) { | |
348 str_printf(r, " (%s [=%s])", menu->sym->name ? | |
349 menu->sym->name : "<choice>", | |
350 sym_get_string_value(menu->sym)); | |
351 } | |
352 str_append(r, "\n"); | |
353 } | |
354 } | |
355 } | |
356 | |
357 static void get_symbol_str(struct gstr *r, struct symbol *sym) | |
358 { | |
359 bool hit; | |
360 struct property *prop; | |
361 | |
362 str_printf(r, "Symbol: %s [=%s]\n", sym->name, | |
363 sym_get_string_value(sym)); | |
364 for_all_prompts(sym, prop) | |
365 get_prompt_str(r, prop); | |
366 hit = false; | |
367 for_all_properties(sym, prop, P_SELECT) { | |
368 if (!hit) { | |
369 str_append(r, " Selects: "); | |
370 hit = true; | |
371 } else | |
372 str_printf(r, " && "); | |
373 expr_gstr_print(prop->expr, r); | |
374 } | |
375 if (hit) | |
376 str_append(r, "\n"); | |
377 if (sym->rev_dep.expr) { | |
378 str_append(r, " Selected by: "); | |
379 expr_gstr_print(sym->rev_dep.expr, r); | |
380 str_append(r, "\n"); | |
381 } | |
382 str_append(r, "\n\n"); | |
383 } | |
384 | |
385 static struct gstr get_relations_str(struct symbol **sym_arr) | |
386 { | |
387 struct symbol *sym; | |
388 struct gstr res = str_new(); | |
389 int i; | |
390 | |
391 for (i = 0; sym_arr && (sym = sym_arr[i]); i++) | |
392 get_symbol_str(&res, sym); | |
393 if (!i) | |
394 str_append(&res, "No matches found.\n"); | |
395 return res; | |
396 } | |
397 | |
398 static void search_conf(void) | |
399 { | |
400 struct symbol **sym_arr; | |
401 struct gstr res; | |
402 int dres; | |
403 again: | |
404 dialog_clear(); | |
405 dres = dialog_inputbox(_("Search Configuration Parameter"), | |
406 _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"), | |
407 10, 75, ""); | |
408 switch (dres) { | |
409 case 0: | |
410 break; | |
411 case 1: | |
412 show_helptext(_("Search Configuration"), search_help); | |
413 goto again; | |
414 default: | |
415 return; | |
416 } | |
417 | |
418 sym_arr = sym_re_search(dialog_input_result); | |
419 res = get_relations_str(sym_arr); | |
420 free(sym_arr); | |
421 show_textbox(_("Search Results"), str_get(&res), 0, 0); | |
422 str_free(&res); | |
423 } | |
424 | |
425 static void build_conf(struct menu *menu) | |
426 { | |
427 struct symbol *sym; | |
428 struct property *prop; | |
429 struct menu *child; | |
430 int type, tmp, doint = 2; | |
431 tristate val; | |
432 char ch; | |
433 | |
434 if (!menu_is_visible(menu)) | |
435 return; | |
436 | |
437 sym = menu->sym; | |
438 prop = menu->prompt; | |
439 if (!sym) { | |
440 if (prop && menu != current_menu) { | |
441 const char *prompt = menu_get_prompt(menu); | |
442 switch (prop->type) { | |
443 case P_MENU: | |
444 child_count++; | |
445 if (single_menu_mode) { | |
446 item_make("%s%*c%s", | |
447 menu->data ? "-->" : "++>", | |
448 indent + 1, ' ', prompt); | |
449 } else | |
450 item_make(" %*c%s --->", indent + 1, ' ', prompt); | |
451 | |
452 item_set_tag('m'); | |
453 item_set_data(menu); | |
454 if (single_menu_mode && menu->data) | |
455 goto conf_childs; | |
456 return; | |
457 default: | |
458 if (prompt) { | |
459 child_count++; | |
460 item_make("---%*c%s", indent + 1, ' ', prompt); | |
461 item_set_tag(':'); | |
462 item_set_data(menu); | |
463 } | |
464 } | |
465 } else | |
466 doint = 0; | |
467 goto conf_childs; | |
468 } | |
469 | |
470 type = sym_get_type(sym); | |
471 if (sym_is_choice(sym)) { | |
472 struct symbol *def_sym = sym_get_choice_value(sym); | |
473 struct menu *def_menu = NULL; | |
474 | |
475 child_count++; | |
476 for (child = menu->list; child; child = child->next) { | |
477 if (menu_is_visible(child) && child->sym == def_sym) | |
478 def_menu = child; | |
479 } | |
480 | |
481 val = sym_get_tristate_value(sym); | |
482 if (sym_is_changable(sym)) { | |
483 switch (type) { | |
484 case S_BOOLEAN: | |
485 item_make("[%c]", val == no ? ' ' : '*'); | |
486 break; | |
487 case S_TRISTATE: | |
488 switch (val) { | |
489 case yes: ch = '*'; break; | |
490 case mod: ch = 'M'; break; | |
491 default: ch = ' '; break; | |
492 } | |
493 item_make("<%c>", ch); | |
494 break; | |
495 } | |
496 item_set_tag('t'); | |
497 item_set_data(menu); | |
498 } else { | |
499 item_make(" "); | |
500 item_set_tag(def_menu ? 't' : ':'); | |
501 item_set_data(menu); | |
502 } | |
503 | |
504 item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); | |
505 if (val == yes) { | |
506 if (def_menu) { | |
507 item_add_str(" (%s)", menu_get_prompt(def_menu)); | |
508 item_add_str(" --->"); | |
509 if (def_menu->list) { | |
510 indent += 2; | |
511 build_conf(def_menu); | |
512 indent -= 2; | |
513 } | |
514 } | |
515 return; | |
516 } | |
517 } else { | |
518 if (menu == current_menu) { | |
519 item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); | |
520 item_set_tag(':'); | |
521 item_set_data(menu); | |
522 goto conf_childs; | |
523 } | |
524 child_count++; | |
525 val = sym_get_tristate_value(sym); | |
526 if (sym_is_choice_value(sym) && val == yes) { | |
527 item_make(" "); | |
528 item_set_tag(':'); | |
529 item_set_data(menu); | |
530 } else { | |
531 switch (type) { | |
532 case S_BOOLEAN: | |
533 if (sym_is_changable(sym)) | |
534 item_make("[%c]", val == no ? ' ' : '*'); | |
535 else | |
536 item_make("---"); | |
537 item_set_tag('t'); | |
538 item_set_data(menu); | |
539 break; | |
540 case S_TRISTATE: | |
541 switch (val) { | |
542 case yes: ch = '*'; break; | |
543 case mod: ch = 'M'; break; | |
544 default: ch = ' '; break; | |
545 } | |
546 if (sym_is_changable(sym)) | |
547 item_make("<%c>", ch); | |
548 else | |
549 item_make("---"); | |
550 item_set_tag('t'); | |
551 item_set_data(menu); | |
552 break; | |
553 default: | |
554 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ | |
555 item_make("(%s)", sym_get_string_value(sym)); | |
556 tmp = indent - tmp + 4; | |
557 if (tmp < 0) | |
558 tmp = 0; | |
559 item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), | |
560 (sym_has_value(sym) || !sym_is_changable(sym)) ? | |
561 "" : " (NEW)"); | |
562 item_set_tag('s'); | |
563 item_set_data(menu); | |
564 goto conf_childs; | |
565 } | |
566 } | |
567 item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), | |
568 (sym_has_value(sym) || !sym_is_changable(sym)) ? | |
569 "" : " (NEW)"); | |
570 if (menu->prompt->type == P_MENU) { | |
571 item_add_str(" --->"); | |
572 return; | |
573 } | |
574 } | |
575 | |
576 conf_childs: | |
577 indent += doint; | |
578 for (child = menu->list; child; child = child->next) | |
579 build_conf(child); | |
580 indent -= doint; | |
581 } | |
582 | |
583 static void conf(struct menu *menu) | |
584 { | |
585 struct menu *submenu; | |
586 const char *prompt = menu_get_prompt(menu); | |
587 struct symbol *sym; | |
588 struct menu *active_menu = NULL; | |
589 int res; | |
590 int s_scroll = 0; | |
591 | |
592 while (1) { | |
593 item_reset(); | |
594 current_menu = menu; | |
595 build_conf(menu); | |
596 if (!child_count) | |
597 break; | |
598 if (menu == &rootmenu) { | |
599 item_make("--- "); | |
600 item_set_tag(':'); | |
601 item_make(_(" Load an Alternate Configuration File")); | |
602 item_set_tag('L'); | |
603 item_make(_(" Save an Alternate Configuration File")); | |
604 item_set_tag('S'); | |
605 } | |
606 dialog_clear(); | |
607 res = dialog_menu(prompt ? prompt : _("Main Menu"), | |
608 _(menu_instructions), | |
609 active_menu, &s_scroll); | |
610 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) | |
611 break; | |
612 if (!item_activate_selected()) | |
613 continue; | |
614 if (!item_tag()) | |
615 continue; | |
616 | |
617 submenu = item_data(); | |
618 active_menu = item_data(); | |
619 if (submenu) | |
620 sym = submenu->sym; | |
621 else | |
622 sym = NULL; | |
623 | |
624 switch (res) { | |
625 case 0: | |
626 switch (item_tag()) { | |
627 case 'm': | |
628 if (single_menu_mode) | |
629 submenu->data = (void *) (long) !submenu->data; | |
630 else | |
631 conf(submenu); | |
632 break; | |
633 case 't': | |
634 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) | |
635 conf_choice(submenu); | |
636 else if (submenu->prompt->type == P_MENU) | |
637 conf(submenu); | |
638 break; | |
639 case 's': | |
640 conf_string(submenu); | |
641 break; | |
642 case 'L': | |
643 conf_load(); | |
644 break; | |
645 case 'S': | |
646 conf_save(); | |
647 break; | |
648 } | |
649 break; | |
650 case 2: | |
651 if (sym) | |
652 show_help(submenu); | |
653 else | |
654 show_helptext("README", _(mconf_readme)); | |
655 break; | |
656 case 3: | |
657 if (item_is_tag('t')) { | |
658 if (sym_set_tristate_value(sym, yes)) | |
659 break; | |
660 if (sym_set_tristate_value(sym, mod)) | |
661 show_textbox(NULL, setmod_text, 6, 74); | |
662 } | |
663 break; | |
664 case 4: | |
665 if (item_is_tag('t')) | |
666 sym_set_tristate_value(sym, no); | |
667 break; | |
668 case 5: | |
669 if (item_is_tag('t')) | |
670 sym_set_tristate_value(sym, mod); | |
671 break; | |
672 case 6: | |
673 if (item_is_tag('t')) | |
674 sym_toggle_tristate_value(sym); | |
675 else if (item_is_tag('m')) | |
676 conf(submenu); | |
677 break; | |
678 case 7: | |
679 search_conf(); | |
680 break; | |
681 } | |
682 } | |
683 } | |
684 | |
685 static void show_textbox(const char *title, const char *text, int r, int c) | |
686 { | |
687 dialog_clear(); | |
688 dialog_textbox(title, text, r, c); | |
689 } | |
690 | |
691 static void show_helptext(const char *title, const char *text) | |
692 { | |
693 show_textbox(title, text, 0, 0); | |
694 } | |
695 | |
696 static void show_help(struct menu *menu) | |
697 { | |
698 struct gstr help = str_new(); | |
699 struct symbol *sym = menu->sym; | |
700 | |
701 if (sym->help) | |
702 { | |
703 if (sym->name) { | |
704 str_printf(&help, "CONFIG_%s:\n\n", sym->name); | |
705 str_append(&help, _(sym->help)); | |
706 str_append(&help, "\n"); | |
707 } | |
708 } else { | |
709 str_append(&help, nohelp_text); | |
710 } | |
711 get_symbol_str(&help, sym); | |
712 show_helptext(menu_get_prompt(menu), str_get(&help)); | |
713 str_free(&help); | |
714 } | |
715 | |
716 static void conf_choice(struct menu *menu) | |
717 { | |
718 const char *prompt = menu_get_prompt(menu); | |
719 struct menu *child; | |
720 struct symbol *active; | |
721 | |
722 active = sym_get_choice_value(menu->sym); | |
723 while (1) { | |
724 int res; | |
725 int selected; | |
726 item_reset(); | |
727 | |
728 current_menu = menu; | |
729 for (child = menu->list; child; child = child->next) { | |
730 if (!menu_is_visible(child)) | |
731 continue; | |
732 item_make("%s", menu_get_prompt(child)); | |
733 item_set_data(child); | |
734 if (child->sym == active) | |
735 item_set_selected(1); | |
736 if (child->sym == sym_get_choice_value(menu->sym)) | |
737 item_set_tag('X'); | |
738 } | |
739 dialog_clear(); | |
740 res = dialog_checklist(prompt ? prompt : _("Main Menu"), | |
741 _(radiolist_instructions), | |
742 15, 70, 6); | |
743 selected = item_activate_selected(); | |
744 switch (res) { | |
745 case 0: | |
746 if (selected) { | |
747 child = item_data(); | |
748 sym_set_tristate_value(child->sym, yes); | |
749 } | |
750 return; | |
751 case 1: | |
752 if (selected) { | |
753 child = item_data(); | |
754 show_help(child); | |
755 active = child->sym; | |
756 } else | |
757 show_help(menu); | |
758 break; | |
759 case KEY_ESC: | |
760 return; | |
761 case -ERRDISPLAYTOOSMALL: | |
762 return; | |
763 } | |
764 } | |
765 } | |
766 | |
767 static void conf_string(struct menu *menu) | |
768 { | |
769 const char *prompt = menu_get_prompt(menu); | |
770 | |
771 while (1) { | |
772 int res; | |
773 char *heading; | |
774 | |
775 switch (sym_get_type(menu->sym)) { | |
776 case S_INT: | |
777 heading = _(inputbox_instructions_int); | |
778 break; | |
779 case S_HEX: | |
780 heading = _(inputbox_instructions_hex); | |
781 break; | |
782 case S_STRING: | |
783 heading = _(inputbox_instructions_string); | |
784 break; | |
785 default: | |
786 heading = "Internal mconf error!"; | |
787 } | |
788 dialog_clear(); | |
789 res = dialog_inputbox(prompt ? prompt : _("Main Menu"), | |
790 heading, 10, 75, | |
791 sym_get_string_value(menu->sym)); | |
792 switch (res) { | |
793 case 0: | |
794 if (sym_set_string_value(menu->sym, dialog_input_result)) | |
795 return; | |
796 show_textbox(NULL, _("You have made an invalid entry."), 5, 43); | |
797 break; | |
798 case 1: | |
799 show_help(menu); | |
800 break; | |
801 case KEY_ESC: | |
802 return; | |
803 } | |
804 } | |
805 } | |
806 | |
807 static void conf_load(void) | |
808 { | |
809 | |
810 while (1) { | |
811 int res; | |
812 dialog_clear(); | |
813 res = dialog_inputbox(NULL, load_config_text, | |
814 11, 55, filename); | |
815 switch(res) { | |
816 case 0: | |
817 if (!dialog_input_result[0]) | |
818 return; | |
819 if (!conf_read(dialog_input_result)) | |
820 return; | |
821 show_textbox(NULL, _("File does not exist!"), 5, 38); | |
822 break; | |
823 case 1: | |
824 show_helptext(_("Load Alternate Configuration"), load_config_help); | |
825 break; | |
826 case KEY_ESC: | |
827 return; | |
828 } | |
829 } | |
830 } | |
831 | |
832 static void conf_save(void) | |
833 { | |
834 while (1) { | |
835 int res; | |
836 dialog_clear(); | |
837 res = dialog_inputbox(NULL, save_config_text, | |
838 11, 55, filename); | |
839 switch(res) { | |
840 case 0: | |
841 if (!dialog_input_result[0]) | |
842 return; | |
843 if (!conf_write(dialog_input_result)) | |
844 return; | |
845 show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); | |
846 break; | |
847 case 1: | |
848 show_helptext(_("Save Alternate Configuration"), save_config_help); | |
849 break; | |
850 case KEY_ESC: | |
851 return; | |
852 } | |
853 } | |
854 } | |
855 | |
856 static void conf_cleanup(void) | |
857 { | |
858 tcsetattr(1, TCSAFLUSH, &ios_org); | |
859 } | |
860 | |
861 int main(int ac, char **av) | |
862 { | |
863 struct symbol *sym; | |
864 char *mode; | |
865 int res; | |
866 | |
867 setlocale(LC_ALL, ""); | |
868 bindtextdomain(PACKAGE, LOCALEDIR); | |
869 textdomain(PACKAGE); | |
870 | |
871 conf_parse(av[1] ? av[1] : ""); | |
872 conf_read(NULL); | |
873 | |
874 sym = sym_lookup("KERNELVERSION", 0); | |
875 sym_calc_value(sym); | |
876 sprintf(menu_backtitle, _(PROJECT_NAME" v%s Configuration"), | |
877 sym_get_string_value(sym)); | |
878 | |
879 mode = getenv("MENUCONFIG_MODE"); | |
880 if (mode) { | |
881 if (!strcasecmp(mode, "single_menu")) | |
882 single_menu_mode = 1; | |
883 } | |
884 | |
885 tcgetattr(1, &ios_org); | |
886 atexit(conf_cleanup); | |
887 init_wsize(); | |
888 reset_dialog(); | |
889 init_dialog(menu_backtitle); | |
890 do { | |
891 conf(&rootmenu); | |
892 dialog_clear(); | |
893 res = dialog_yesno(NULL, | |
894 _("Do you wish to save your " | |
895 "new "PROJECT_NAME" configuration?\n" | |
896 "<ESC><ESC> to continue."), | |
897 6, 60); | |
898 } while (res == KEY_ESC); | |
899 end_dialog(); | |
900 if (res == 0) { | |
901 if (conf_write(NULL)) { | |
902 fprintf(stderr, _("\n\n" | |
903 "Error writing "PROJECT_NAME" configuration.\n" | |
904 "Your configuration changes were NOT saved." | |
905 "\n\n")); | |
906 return 1; | |
907 } | |
908 printf(_("\n\n" | |
909 "*** End of "PROJECT_NAME" configuration.\n" | |
910 "*** Execute 'make' to build, or try 'make help'." | |
911 "\n\n")); | |
912 } else { | |
913 fprintf(stderr, _("\n\n" | |
914 "Your configuration changes were NOT saved." | |
915 "\n\n")); | |
916 } | |
917 | |
918 return 0; | |
919 } |