Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mconf.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002 Roman Zippel <[email protected]>
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 <[email protected]>
7  *
8  * i18n, 2005, Arnaldo Carvalho de Melo <[email protected]>
9  */
10 
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <locale.h>
21 
22 #include "lkc.h"
23 #include "lxdialog/dialog.h"
24 
25 static const char mconf_readme[] = N_(
26 "Overview\n"
27 "--------\n"
28 "This interface let you select features and parameters for the build.\n"
29 "Features can either be built-in, modularized, or ignored. Parameters\n"
30 "must be entered in as decimal or hexadecimal numbers or text.\n"
31 "\n"
32 "Menu items beginning with following braces represent features that\n"
33 " [ ] can be built in or removed\n"
34 " < > can be built in, modularized or removed\n"
35 " { } can be built in or modularized (selected by other feature)\n"
36 " - - are selected by other feature,\n"
37 "while *, M or whitespace inside braces means to build in, build as\n"
38 "a module or to exclude the feature respectively.\n"
39 "\n"
40 "To change any of these features, highlight it with the cursor\n"
41 "keys and press <Y> to build it in, <M> to make it a module or\n"
42 "<N> to removed it. You may also press the <Space Bar> to cycle\n"
43 "through the available options (ie. Y->N->M->Y).\n"
44 "\n"
45 "Some additional keyboard hints:\n"
46 "\n"
47 "Menus\n"
48 "----------\n"
49 "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
50 " you wish to change or submenu wish to select and press <Enter>.\n"
51 " Submenus are designated by \"--->\".\n"
52 "\n"
53 " Shortcut: Press the option's highlighted letter (hotkey).\n"
54 " Pressing a hotkey more than once will sequence\n"
55 " through all visible items which use that hotkey.\n"
56 "\n"
57 " You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
58 " unseen options into view.\n"
59 "\n"
60 "o To exit a menu use the cursor keys to highlight the <Exit> button\n"
61 " and press <ENTER>.\n"
62 "\n"
63 " Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
64 " using those letters. You may press a single <ESC>, but\n"
65 " there is a delayed response which you may find annoying.\n"
66 "\n"
67 " Also, the <TAB> and cursor keys will cycle between <Select>,\n"
68 " <Exit> and <Help>.\n"
69 "\n"
70 "o To get help with an item, use the cursor keys to highlight <Help>\n"
71 " and press <ENTER>.\n"
72 "\n"
73 " Shortcut: Press <H> or <?>.\n"
74 "\n"
75 "o To toggle the display of hidden options, press <Z>.\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 <u>, <d>, <SPACE BAR> and <B> for \n"
109 " those who are familiar with less and lynx.\n"
110 "\n"
111 "o Press <E>, <X>, <q>, <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 menu, rather\n"
152 "than the default multimenu hierarchy, run the menuconfig with\n"
153 "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"
163 "\n"
164 "Different color themes available\n"
165 "--------------------------------\n"
166 "It is possible to select different color themes using the variable\n"
167 "MENUCONFIG_COLOR. To select a theme use:\n"
168 "\n"
169 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
170 "\n"
171 "Available themes are\n"
172 " mono => selects colors suitable for monochrome displays\n"
173 " blackbg => selects a color scheme with black background\n"
174 " classic => theme with blue background. The classic look\n"
175 " bluetitle => a LCD friendly version of classic. (default)\n"
176 "\n"),
177 menu_instructions[] = N_(
178  "Arrow keys navigate the menu. "
179  "<Enter> selects submenus --->. "
180  "Highlighted letters are hotkeys. "
181  "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
182  "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
183  "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
184 radiolist_instructions[] = N_(
185  "Use the arrow keys to navigate this window or "
186  "press the hotkey of the item you wish to select "
187  "followed by the <SPACE BAR>. "
188  "Press <?> for additional information about this option."),
189 inputbox_instructions_int[] = N_(
190  "Please enter a decimal value. "
191  "Fractions will not be accepted. "
192  "Use the <TAB> key to move from the input field to the buttons below it."),
193 inputbox_instructions_hex[] = N_(
194  "Please enter a hexadecimal value. "
195  "Use the <TAB> key to move from the input field to the buttons below it."),
196 inputbox_instructions_string[] = N_(
197  "Please enter a string value. "
198  "Use the <TAB> key to move from the input field to the buttons below it."),
199 setmod_text[] = N_(
200  "This feature depends on another which has been configured as a module.\n"
201  "As a result, this feature will be built as a module."),
202 load_config_text[] = N_(
203  "Enter the name of the configuration file you wish to load. "
204  "Accept the name shown to restore the configuration you "
205  "last retrieved. Leave blank to abort."),
206 load_config_help[] = N_(
207  "\n"
208  "For various reasons, one may wish to keep several different\n"
209  "configurations available on a single machine.\n"
210  "\n"
211  "If you have saved a previous configuration in a file other than the\n"
212  "default one, entering its name here will allow you to modify that\n"
213  "configuration.\n"
214  "\n"
215  "If you are uncertain, then you have probably never used alternate\n"
216  "configuration files. You should therefore leave this blank to abort.\n"),
217 save_config_text[] = N_(
218  "Enter a filename to which this configuration should be saved "
219  "as an alternate. Leave blank to abort."),
220 save_config_help[] = N_(
221  "\n"
222  "For various reasons, one may wish to keep different configurations\n"
223  "available on a single machine.\n"
224  "\n"
225  "Entering a file name here will allow you to later retrieve, modify\n"
226  "and use the current configuration as an alternate to whatever\n"
227  "configuration options you have selected at that time.\n"
228  "\n"
229  "If you are uncertain what all this means then you should probably\n"
230  "leave this blank.\n"),
231 search_help[] = N_(
232  "\n"
233  "Search for symbols and display their relations.\n"
234  "Regular expressions are allowed.\n"
235  "Example: search for \"^FOO\"\n"
236  "Result:\n"
237  "-----------------------------------------------------------------\n"
238  "Symbol: FOO [=m]\n"
239  "Type : tristate\n"
240  "Prompt: Foo bus is used to drive the bar HW\n"
241  " Defined at drivers/pci/Kconfig:47\n"
242  " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
243  " Location:\n"
244  " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
245  " -> PCI support (PCI [=y])\n"
246  "(1) -> PCI access mode (<choice> [=y])\n"
247  " Selects: LIBCRC32\n"
248  " Selected by: BAR\n"
249  "-----------------------------------------------------------------\n"
250  "o The line 'Type:' shows the type of the configuration option for\n"
251  " this symbol (boolean, tristate, string, ...)\n"
252  "o The line 'Prompt:' shows the text used in the menu structure for\n"
253  " this 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] indicates that this is a\n"
261  " selectable menu item - and the current value is displayed inside\n"
262  " brackets.\n"
263  " Press the key in the (#) prefix to jump directly to that\n"
264  " location. You will be returned to the current search results\n"
265  " after exiting this new menu.\n"
266  "o The 'Selects:' line tell what symbol will be automatically\n"
267  " selected if this symbol is selected (y or m)\n"
268  "o The 'Selected by' line tell what symbol has selected this symbol\n"
269  "\n"
270  "Only relevant lines are shown.\n"
271  "\n\n"
272  "Search examples:\n"
273  "Examples: USB => find all symbols containing USB\n"
274  " ^USB => find all symbols starting with USB\n"
275  " USB$ => find all symbols ending with USB\n"
276  "\n");
277 
278 static int indent;
279 static struct menu *current_menu;
280 static int child_count;
281 static int single_menu_mode;
282 static int show_all_options;
283 
284 static void conf(struct menu *menu, struct menu *active_menu);
285 static void conf_choice(struct menu *menu);
286 static void conf_string(struct menu *menu);
287 static void conf_load(void);
288 static void conf_save(void);
289 static int show_textbox_ext(const char *title, char *text, int r, int c,
290  int *keys, int *vscroll, int *hscroll,
291  update_text_fn update_text, void *data);
292 static void show_textbox(const char *title, const char *text, int r, int c);
293 static void show_helptext(const char *title, const char *text);
294 static void show_help(struct menu *menu);
295 
296 static char filename[PATH_MAX+1];
297 static void set_config_filename(const char *config_filename)
298 {
299  static char menu_backtitle[PATH_MAX+128];
300  int size;
301 
302  size = snprintf(menu_backtitle, sizeof(menu_backtitle),
303  "%s - %s", config_filename, rootmenu.prompt->text);
304  if (size >= sizeof(menu_backtitle))
305  menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
306  set_dialog_backtitle(menu_backtitle);
307 
308  size = snprintf(filename, sizeof(filename), "%s", config_filename);
309  if (size >= sizeof(filename))
310  filename[sizeof(filename)-1] = '\0';
311 }
312 
313 
314 struct search_data {
315  struct list_head *head;
316  struct menu **targets;
317  int *keys;
318 };
319 
320 static void update_text(char *buf, size_t start, size_t end, void *_data)
321 {
322  struct search_data *data = _data;
323  struct jump_key *pos;
324  int k = 0;
325 
326  list_for_each_entry(pos, data->head, entries) {
327  if (pos->offset >= start && pos->offset < end) {
328  char header[4];
329 
330  if (k < JUMP_NB) {
331  int key = '0' + (pos->index % JUMP_NB) + 1;
332 
333  sprintf(header, "(%c)", key);
334  data->keys[k] = key;
335  data->targets[k] = pos->target;
336  k++;
337  } else {
338  sprintf(header, " ");
339  }
340 
341  memcpy(buf + pos->offset, header, sizeof(header) - 1);
342  }
343  }
344  data->keys[k] = 0;
345 }
346 
347 static void search_conf(void)
348 {
349  struct symbol **sym_arr;
350  struct gstr res;
351  char *dialog_input;
352  int dres, vscroll = 0, hscroll = 0;
353  bool again;
354 
355 again:
356  dialog_clear();
357  dres = dialog_inputbox(_("Search Configuration Parameter"),
358  _("Enter " CONFIG_ " (sub)string to search for "
359  "(with or without \"" CONFIG_ "\")"),
360  10, 75, "");
361  switch (dres) {
362  case 0:
363  break;
364  case 1:
365  show_helptext(_("Search Configuration"), search_help);
366  goto again;
367  default:
368  return;
369  }
370 
371  /* strip the prefix if necessary */
372  dialog_input = dialog_input_result;
374  dialog_input += strlen(CONFIG_);
375 
376  sym_arr = sym_re_search(dialog_input);
377  do {
378  LIST_HEAD(head);
379  struct menu *targets[JUMP_NB];
380  int keys[JUMP_NB + 1], i;
381  struct search_data data = {
382  .head = &head,
383  .targets = targets,
384  .keys = keys,
385  };
386 
387  res = get_relations_str(sym_arr, &head);
388  dres = show_textbox_ext(_("Search Results"), (char *)
389  str_get(&res), 0, 0, keys, &vscroll,
390  &hscroll, &update_text, (void *)
391  &data);
392  again = false;
393  for (i = 0; i < JUMP_NB && keys[i]; i++)
394  if (dres == keys[i]) {
395  conf(targets[i]->parent, targets[i]);
396  again = true;
397  }
398  str_free(&res);
399  } while (again);
400  free(sym_arr);
401 }
402 
403 static void build_conf(struct menu *menu)
404 {
405  struct symbol *sym;
406  struct property *prop;
407  struct menu *child;
408  int type, tmp, doint = 2;
409  tristate val;
410  char ch;
411  bool visible;
412 
413  /*
414  * note: menu_is_visible() has side effect that it will
415  * recalc the value of the symbol.
416  */
417  visible = menu_is_visible(menu);
418  if (show_all_options && !menu_has_prompt(menu))
419  return;
420  else if (!show_all_options && !visible)
421  return;
422 
423  sym = menu->sym;
424  prop = menu->prompt;
425  if (!sym) {
426  if (prop && menu != current_menu) {
427  const char *prompt = menu_get_prompt(menu);
428  switch (prop->type) {
429  case P_MENU:
430  child_count++;
431  prompt = _(prompt);
432  if (single_menu_mode) {
433  item_make("%s%*c%s",
434  menu->data ? "-->" : "++>",
435  indent + 1, ' ', prompt);
436  } else
437  item_make(" %*c%s --->", indent + 1, ' ', prompt);
438 
439  item_set_tag('m');
440  item_set_data(menu);
441  if (single_menu_mode && menu->data)
442  goto conf_childs;
443  return;
444  case P_COMMENT:
445  if (prompt) {
446  child_count++;
447  item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt));
448  item_set_tag(':');
449  item_set_data(menu);
450  }
451  break;
452  default:
453  if (prompt) {
454  child_count++;
455  item_make("---%*c%s", indent + 1, ' ', _(prompt));
456  item_set_tag(':');
457  item_set_data(menu);
458  }
459  }
460  } else
461  doint = 0;
462  goto conf_childs;
463  }
464 
465  type = sym_get_type(sym);
466  if (sym_is_choice(sym)) {
467  struct symbol *def_sym = sym_get_choice_value(sym);
468  struct menu *def_menu = NULL;
469 
470  child_count++;
471  for (child = menu->list; child; child = child->next) {
472  if (menu_is_visible(child) && child->sym == def_sym)
473  def_menu = child;
474  }
475 
476  val = sym_get_tristate_value(sym);
477  if (sym_is_changable(sym)) {
478  switch (type) {
479  case S_BOOLEAN:
480  item_make("[%c]", val == no ? ' ' : '*');
481  break;
482  case S_TRISTATE:
483  switch (val) {
484  case yes: ch = '*'; break;
485  case mod: ch = 'M'; break;
486  default: ch = ' '; break;
487  }
488  item_make("<%c>", ch);
489  break;
490  }
491  item_set_tag('t');
492  item_set_data(menu);
493  } else {
494  item_make(" ");
495  item_set_tag(def_menu ? 't' : ':');
496  item_set_data(menu);
497  }
498 
499  item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
500  if (val == yes) {
501  if (def_menu) {
502  item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
503  item_add_str(" --->");
504  if (def_menu->list) {
505  indent += 2;
506  build_conf(def_menu);
507  indent -= 2;
508  }
509  }
510  return;
511  }
512  } else {
513  if (menu == current_menu) {
514  item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
515  item_set_tag(':');
516  item_set_data(menu);
517  goto conf_childs;
518  }
519  child_count++;
520  val = sym_get_tristate_value(sym);
521  if (sym_is_choice_value(sym) && val == yes) {
522  item_make(" ");
523  item_set_tag(':');
524  item_set_data(menu);
525  } else {
526  switch (type) {
527  case S_BOOLEAN:
528  if (sym_is_changable(sym))
529  item_make("[%c]", val == no ? ' ' : '*');
530  else
531  item_make("-%c-", val == no ? ' ' : '*');
532  item_set_tag('t');
533  item_set_data(menu);
534  break;
535  case S_TRISTATE:
536  switch (val) {
537  case yes: ch = '*'; break;
538  case mod: ch = 'M'; break;
539  default: ch = ' '; break;
540  }
541  if (sym_is_changable(sym)) {
542  if (sym->rev_dep.tri == mod)
543  item_make("{%c}", ch);
544  else
545  item_make("<%c>", ch);
546  } else
547  item_make("-%c-", ch);
548  item_set_tag('t');
549  item_set_data(menu);
550  break;
551  default:
552  tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
553  item_make("(%s)", sym_get_string_value(sym));
554  tmp = indent - tmp + 4;
555  if (tmp < 0)
556  tmp = 0;
557  item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
558  (sym_has_value(sym) || !sym_is_changable(sym)) ?
559  "" : _(" (NEW)"));
560  item_set_tag('s');
561  item_set_data(menu);
562  goto conf_childs;
563  }
564  }
565  item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
566  (sym_has_value(sym) || !sym_is_changable(sym)) ?
567  "" : _(" (NEW)"));
568  if (menu->prompt->type == P_MENU) {
569  item_add_str(" --->");
570  return;
571  }
572  }
573 
574 conf_childs:
575  indent += doint;
576  for (child = menu->list; child; child = child->next)
577  build_conf(child);
578  indent -= doint;
579 }
580 
581 static void conf(struct menu *menu, struct menu *active_menu)
582 {
583  struct menu *submenu;
584  const char *prompt = menu_get_prompt(menu);
585  struct symbol *sym;
586  int res;
587  int s_scroll = 0;
588 
589  while (1) {
590  item_reset();
591  current_menu = menu;
592  build_conf(menu);
593  if (!child_count)
594  break;
595  if (menu == &rootmenu) {
596  item_make("--- ");
597  item_set_tag(':');
598  item_make(_(" Load an Alternate Configuration File"));
599  item_set_tag('L');
600  item_make(_(" Save an Alternate Configuration File"));
601  item_set_tag('S');
602  }
603  dialog_clear();
604  res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
605  _(menu_instructions),
606  active_menu, &s_scroll);
607  if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
608  break;
609  if (!item_activate_selected())
610  continue;
611  if (!item_tag())
612  continue;
613 
614  submenu = item_data();
615  active_menu = item_data();
616  if (submenu)
617  sym = submenu->sym;
618  else
619  sym = NULL;
620 
621  switch (res) {
622  case 0:
623  switch (item_tag()) {
624  case 'm':
625  if (single_menu_mode)
626  submenu->data = (void *) (long) !submenu->data;
627  else
628  conf(submenu, NULL);
629  break;
630  case 't':
631  if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
632  conf_choice(submenu);
633  else if (submenu->prompt->type == P_MENU)
634  conf(submenu, NULL);
635  break;
636  case 's':
637  conf_string(submenu);
638  break;
639  case 'L':
640  conf_load();
641  break;
642  case 'S':
643  conf_save();
644  break;
645  }
646  break;
647  case 2:
648  if (sym)
649  show_help(submenu);
650  else
651  show_helptext(_("README"), _(mconf_readme));
652  break;
653  case 3:
654  if (item_is_tag('t')) {
655  if (sym_set_tristate_value(sym, yes))
656  break;
657  if (sym_set_tristate_value(sym, mod))
658  show_textbox(NULL, setmod_text, 6, 74);
659  }
660  break;
661  case 4:
662  if (item_is_tag('t'))
664  break;
665  case 5:
666  if (item_is_tag('t'))
668  break;
669  case 6:
670  if (item_is_tag('t'))
672  else if (item_is_tag('m'))
673  conf(submenu, NULL);
674  break;
675  case 7:
676  search_conf();
677  break;
678  case 8:
679  show_all_options = !show_all_options;
680  break;
681  }
682  }
683 }
684 
685 static int show_textbox_ext(const char *title, char *text, int r, int c, int
686  *keys, int *vscroll, int *hscroll, update_text_fn
687  update_text, void *data)
688 {
689  dialog_clear();
690  return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
691  update_text, data);
692 }
693 
694 static void show_textbox(const char *title, const char *text, int r, int c)
695 {
696  show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
697  NULL, NULL);
698 }
699 
700 static void show_helptext(const char *title, const char *text)
701 {
702  show_textbox(title, text, 0, 0);
703 }
704 
705 static void show_help(struct menu *menu)
706 {
707  struct gstr help = str_new();
708 
709  help.max_width = getmaxx(stdscr) - 10;
710  menu_get_ext_help(menu, &help);
711 
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  if (child->sym)
733  item_make("%s", _(menu_get_prompt(child)));
734  else {
735  item_make("*** %s ***", _(menu_get_prompt(child)));
736  item_set_tag(':');
737  }
738  item_set_data(child);
739  if (child->sym == active)
741  if (child->sym == sym_get_choice_value(menu->sym))
742  item_set_tag('X');
743  }
744  dialog_clear();
745  res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
746  _(radiolist_instructions),
747  15, 70, 6);
748  selected = item_activate_selected();
749  switch (res) {
750  case 0:
751  if (selected) {
752  child = item_data();
753  if (!child->sym)
754  break;
755 
756  sym_set_tristate_value(child->sym, yes);
757  }
758  return;
759  case 1:
760  if (selected) {
761  child = item_data();
762  show_help(child);
763  active = child->sym;
764  } else
765  show_help(menu);
766  break;
767  case KEY_ESC:
768  return;
769  case -ERRDISPLAYTOOSMALL:
770  return;
771  }
772  }
773 }
774 
775 static void conf_string(struct menu *menu)
776 {
777  const char *prompt = menu_get_prompt(menu);
778 
779  while (1) {
780  int res;
781  const char *heading;
782 
783  switch (sym_get_type(menu->sym)) {
784  case S_INT:
785  heading = _(inputbox_instructions_int);
786  break;
787  case S_HEX:
788  heading = _(inputbox_instructions_hex);
789  break;
790  case S_STRING:
791  heading = _(inputbox_instructions_string);
792  break;
793  default:
794  heading = _("Internal mconf error!");
795  }
796  dialog_clear();
797  res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
798  heading, 10, 75,
799  sym_get_string_value(menu->sym));
800  switch (res) {
801  case 0:
803  return;
804  show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
805  break;
806  case 1:
807  show_help(menu);
808  break;
809  case KEY_ESC:
810  return;
811  }
812  }
813 }
814 
815 static void conf_load(void)
816 {
817 
818  while (1) {
819  int res;
820  dialog_clear();
821  res = dialog_inputbox(NULL, load_config_text,
822  11, 55, filename);
823  switch(res) {
824  case 0:
825  if (!dialog_input_result[0])
826  return;
828  set_config_filename(dialog_input_result);
830  return;
831  }
832  show_textbox(NULL, _("File does not exist!"), 5, 38);
833  break;
834  case 1:
835  show_helptext(_("Load Alternate Configuration"), load_config_help);
836  break;
837  case KEY_ESC:
838  return;
839  }
840  }
841 }
842 
843 static void conf_save(void)
844 {
845  while (1) {
846  int res;
847  dialog_clear();
848  res = dialog_inputbox(NULL, save_config_text,
849  11, 55, filename);
850  switch(res) {
851  case 0:
852  if (!dialog_input_result[0])
853  return;
855  set_config_filename(dialog_input_result);
856  return;
857  }
858  show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
859  break;
860  case 1:
861  show_helptext(_("Save Alternate Configuration"), save_config_help);
862  break;
863  case KEY_ESC:
864  return;
865  }
866  }
867 }
868 
869 static int handle_exit(void)
870 {
871  int res;
872 
873  dialog_clear();
874  if (conf_get_changed())
875  res = dialog_yesno(NULL,
876  _("Do you wish to save your new configuration ?\n"
877  "<ESC><ESC> to continue."),
878  6, 60);
879  else
880  res = -1;
881 
883 
884  switch (res) {
885  case 0:
886  if (conf_write(filename)) {
887  fprintf(stderr, _("\n\n"
888  "Error while writing of the configuration.\n"
889  "Your configuration changes were NOT saved."
890  "\n\n"));
891  return 1;
892  }
893  /* fall through */
894  case -1:
895  printf(_("\n\n"
896  "*** End of the configuration.\n"
897  "*** Execute 'make' to start the build or try 'make help'."
898  "\n\n"));
899  res = 0;
900  break;
901  default:
902  fprintf(stderr, _("\n\n"
903  "Your configuration changes were NOT saved."
904  "\n\n"));
905  if (res != KEY_ESC)
906  res = 0;
907  }
908 
909  return res;
910 }
911 
912 static void sig_handler(int signo)
913 {
914  exit(handle_exit());
915 }
916 
917 int main(int ac, char **av)
918 {
919  char *mode;
920  int res;
921 
922  setlocale(LC_ALL, "");
923  bindtextdomain(PACKAGE, LOCALEDIR);
924  textdomain(PACKAGE);
925 
926  signal(SIGINT, sig_handler);
927 
928  conf_parse(av[1]);
929  conf_read(NULL);
930 
931  mode = getenv("MENUCONFIG_MODE");
932  if (mode) {
933  if (!strcasecmp(mode, "single_menu"))
934  single_menu_mode = 1;
935  }
936 
937  if (init_dialog(NULL)) {
938  fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
939  fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
940  return 1;
941  }
942 
943  set_config_filename(conf_get_configname());
944  do {
945  conf(&rootmenu, NULL);
946  res = handle_exit();
947  } while (res == KEY_ESC);
948 
949  return res;
950 }
951