blob: 801cc048704a580925bc474f6d6154f55ec6b83c [file] [log] [blame]
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001/*
2 * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
3 * Released under the terms of the GNU GPL v2.0.
4 *
5 * Derived from menuconfig.
6 *
7 */
Nir Tzachara72f3e22010-08-08 16:50:06 +03008#define _GNU_SOURCE
9#include <string.h>
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020010#define LKC_DIRECT_LINK
11#include "lkc.h"
12#include "nconf.h"
Nir Tzachara72f3e22010-08-08 16:50:06 +030013#include <ctype.h>
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020014
15static const char nconf_readme[] = N_(
16"Overview\n"
17"--------\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -040018"This interface let you select features and parameters for the build.\n"
19"Features can either be built-in, modularized, or ignored. Parameters\n"
20"must be entered in as decimal or hexadecimal numbers or text.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020021"\n"
22"Menu items beginning with following braces represent features that\n"
23" [ ] can be built in or removed\n"
24" < > can be built in, modularized or removed\n"
25" { } can be built in or modularized (selected by other feature)\n"
26" - - are selected by other feature,\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +030027" XXX cannot be selected. Use Symbol Info to find out why,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020028"while *, M or whitespace inside braces means to build in, build as\n"
29"a module or to exclude the feature respectively.\n"
30"\n"
31"To change any of these features, highlight it with the cursor\n"
32"keys and press <Y> to build it in, <M> to make it a module or\n"
33"<N> to removed it. You may also press the <Space Bar> to cycle\n"
34"through the available options (ie. Y->N->M->Y).\n"
35"\n"
36"Some additional keyboard hints:\n"
37"\n"
38"Menus\n"
39"----------\n"
40"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
41" you wish to change use <Enter> or <Space>. Goto submenu by \n"
42" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
43" Submenus are designated by \"--->\".\n"
44"\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +030045" Searching: pressing '/' triggers interactive search mode.\n"
46" nconfig performs a case insensitive search for the string\n"
47" in the menu prompts (no regex support).\n"
48" Pressing the up/down keys highlights the previous/next\n"
49" matching item. Backspace removes one character from the\n"
50" match string. Pressing either '/' again or ESC exits\n"
51" search mode. All other keys behave normally.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020052"\n"
53" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
54" unseen options into view.\n"
55"\n"
56"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
57"\n"
58"o To get help with an item, press <F1>\n"
59" Shortcut: Press <h> or <?>.\n"
60"\n"
61"\n"
62"Radiolists (Choice lists)\n"
63"-----------\n"
64"o Use the cursor keys to select the option you wish to set and press\n"
65" <S> or the <SPACE BAR>.\n"
66"\n"
67" Shortcut: Press the first letter of the option you wish to set then\n"
68" press <S> or <SPACE BAR>.\n"
69"\n"
70"o To see available help for the item, press <F1>\n"
71" Shortcut: Press <H> or <?>.\n"
72"\n"
73"\n"
74"Data Entry\n"
75"-----------\n"
76"o Enter the requested information and press <ENTER>\n"
77" If you are entering hexadecimal values, it is not necessary to\n"
78" add the '0x' prefix to the entry.\n"
79"\n"
80"o For help, press <F1>.\n"
81"\n"
82"\n"
83"Text Box (Help Window)\n"
84"--------\n"
85"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
86" keys h,j,k,l function here as do <SPACE BAR> for those\n"
87" who are familiar with less and lynx.\n"
88"\n"
89"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
90"\n"
91"\n"
92"Alternate Configuration Files\n"
93"-----------------------------\n"
94"nconfig supports the use of alternate configuration files for\n"
95"those who, for various reasons, find it necessary to switch\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -040096"between different configurations.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020097"\n"
98"At the end of the main menu you will find two options. One is\n"
99"for saving the current configuration to a file of your choosing.\n"
100"The other option is for loading a previously saved alternate\n"
101"configuration.\n"
102"\n"
103"Even if you don't use alternate configuration files, but you\n"
104"find during a nconfig session that you have completely messed\n"
105"up your settings, you may use the \"Load Alternate...\" option to\n"
106"restore your previously saved settings from \".config\" without\n"
107"restarting nconfig.\n"
108"\n"
109"Other information\n"
110"-----------------\n"
111"If you use nconfig in an XTERM window make sure you have your\n"
112"$TERM variable set to point to a xterm definition which supports color.\n"
113"Otherwise, nconfig will look rather bad. nconfig will not\n"
114"display correctly in a RXVT window because rxvt displays only one\n"
115"intensity of color, bright.\n"
116"\n"
117"nconfig will display larger menus on screens or xterms which are\n"
118"set to display more than the standard 25 row by 80 column geometry.\n"
119"In order for this to work, the \"stty size\" command must be able to\n"
120"display the screen's current row and column geometry. I STRONGLY\n"
121"RECOMMEND that you make sure you do NOT have the shell variables\n"
122"LINES and COLUMNS exported into your environment. Some distributions\n"
123"export those variables via /etc/profile. Some ncurses programs can\n"
124"become confused when those variables (LINES & COLUMNS) don't reflect\n"
125"the true screen size.\n"
126"\n"
127"Optional personality available\n"
128"------------------------------\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400129"If you prefer to have all of the options listed in a single menu, rather\n"
130"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
131"environment variable set to single_menu. Example:\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200132"\n"
133"make NCONFIG_MODE=single_menu nconfig\n"
134"\n"
135"<Enter> will then unroll the appropriate category, or enfold it if it\n"
136"is already unrolled.\n"
137"\n"
138"Note that this mode can eventually be a little more CPU expensive\n"
139"(especially with a larger number of unrolled categories) than the\n"
140"default mode.\n"
141"\n"),
142menu_no_f_instructions[] = N_(
143" You do not have function keys support. Please follow the\n"
144" following instructions:\n"
145" Arrow keys navigate the menu.\n"
146" <Enter> or <right-arrow> selects submenus --->.\n"
147" Capital Letters are hotkeys.\n"
148" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300149" Pressing SpaceBar toggles between the above options.\n"
150" Press <Esc> or <left-arrow> to go back one menu,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200151" <?> or <h> for Help, </> for Search.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300152" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200153" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300154" <Esc> always leaves the current window.\n"),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200155menu_instructions[] = N_(
156" Arrow keys navigate the menu.\n"
157" <Enter> or <right-arrow> selects submenus --->.\n"
158" Capital Letters are hotkeys.\n"
159" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
160" Pressing SpaceBar toggles between the above options\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300161" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200162" <?>, <F1> or <h> for Help, </> for Search.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300163" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200164" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
165" <Esc> always leaves the current window\n"),
166radiolist_instructions[] = N_(
167" Use the arrow keys to navigate this window or\n"
168" press the hotkey of the item you wish to select\n"
169" followed by the <SPACE BAR>.\n"
170" Press <?>, <F1> or <h> for additional information about this option.\n"),
171inputbox_instructions_int[] = N_(
172"Please enter a decimal value.\n"
173"Fractions will not be accepted.\n"
174"Press <RETURN> to accept, <ESC> to cancel."),
175inputbox_instructions_hex[] = N_(
176"Please enter a hexadecimal value.\n"
177"Press <RETURN> to accept, <ESC> to cancel."),
178inputbox_instructions_string[] = N_(
179"Please enter a string value.\n"
180"Press <RETURN> to accept, <ESC> to cancel."),
181setmod_text[] = N_(
182"This feature depends on another which\n"
183"has been configured as a module.\n"
184"As a result, this feature will be built as a module."),
185nohelp_text[] = N_(
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400186"There is no help available for this option.\n"),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200187load_config_text[] = N_(
188"Enter the name of the configuration file you wish to load.\n"
189"Accept the name shown to restore the configuration you\n"
190"last retrieved. Leave blank to abort."),
191load_config_help[] = N_(
192"\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400193"For various reasons, one may wish to keep several different\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200194"configurations available on a single machine.\n"
195"\n"
196"If you have saved a previous configuration in a file other than the\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400197"default one, entering its name here will allow you to modify that\n"
198"configuration.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200199"\n"
200"If you are uncertain, then you have probably never used alternate\n"
201"configuration files. You should therefor leave this blank to abort.\n"),
202save_config_text[] = N_(
203"Enter a filename to which this configuration should be saved\n"
204"as an alternate. Leave blank to abort."),
205save_config_help[] = N_(
206"\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400207"For various reasons, one may wish to keep different configurations\n"
208"available on a single machine.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200209"\n"
210"Entering a file name here will allow you to later retrieve, modify\n"
211"and use the current configuration as an alternate to whatever\n"
212"configuration options you have selected at that time.\n"
213"\n"
214"If you are uncertain what all this means then you should probably\n"
215"leave this blank.\n"),
216search_help[] = N_(
217"\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400218"Search for symbols and display their relations. Regular expressions\n"
219"are allowed.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200220"Example: search for \"^FOO\"\n"
221"Result:\n"
222"-----------------------------------------------------------------\n"
223"Symbol: FOO [ = m]\n"
224"Prompt: Foo bus is used to drive the bar HW\n"
225"Defined at drivers/pci/Kconfig:47\n"
226"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
227"Location:\n"
228" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
229" -> PCI support (PCI [ = y])\n"
230" -> PCI access mode (<choice> [ = y])\n"
231"Selects: LIBCRC32\n"
232"Selected by: BAR\n"
233"-----------------------------------------------------------------\n"
234"o The line 'Prompt:' shows the text used in the menu structure for\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400235" this symbol\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200236"o The 'Defined at' line tell at what file / line number the symbol\n"
237" is defined\n"
238"o The 'Depends on:' line tell what symbols needs to be defined for\n"
239" this symbol to be visible in the menu (selectable)\n"
240"o The 'Location:' lines tell where in the menu structure this symbol\n"
241" is located\n"
242" A location followed by a [ = y] indicate that this is a selectable\n"
243" menu item - and current value is displayed inside brackets.\n"
244"o The 'Selects:' line tell what symbol will be automatically\n"
245" selected if this symbol is selected (y or m)\n"
246"o The 'Selected by' line tell what symbol has selected this symbol\n"
247"\n"
248"Only relevant lines are shown.\n"
249"\n\n"
250"Search examples:\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400251"Examples: USB = > find all symbols containing USB\n"
252" ^USB => find all symbols starting with USB\n"
253" USB$ => find all symbols ending with USB\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200254"\n");
255
256struct mitem {
257 char str[256];
258 char tag;
259 void *usrptr;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200260 int is_visible;
261};
262
263#define MAX_MENU_ITEMS 4096
264static int show_all_items;
265static int indent;
266static struct menu *current_menu;
267static int child_count;
268static int single_menu_mode;
269/* the window in which all information appears */
270static WINDOW *main_window;
271/* the largest size of the menu window */
272static int mwin_max_lines;
273static int mwin_max_cols;
274/* the window in which we show option buttons */
275static MENU *curses_menu;
276static ITEM *curses_menu_items[MAX_MENU_ITEMS];
277static struct mitem k_menu_items[MAX_MENU_ITEMS];
278static int items_num;
279static int global_exit;
280/* the currently selected button */
281const char *current_instructions = menu_instructions;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200282
283static void conf(struct menu *menu);
284static void conf_choice(struct menu *menu);
285static void conf_string(struct menu *menu);
286static void conf_load(void);
287static void conf_save(void);
288static void show_help(struct menu *menu);
289static int do_exit(void);
290static void setup_windows(void);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300291static void search_conf(void);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200292
293typedef void (*function_key_handler_t)(int *key, struct menu *menu);
294static void handle_f1(int *key, struct menu *current_item);
295static void handle_f2(int *key, struct menu *current_item);
296static void handle_f3(int *key, struct menu *current_item);
297static void handle_f4(int *key, struct menu *current_item);
298static void handle_f5(int *key, struct menu *current_item);
299static void handle_f6(int *key, struct menu *current_item);
300static void handle_f7(int *key, struct menu *current_item);
301static void handle_f8(int *key, struct menu *current_item);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300302static void handle_f9(int *key, struct menu *current_item);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200303
304struct function_keys {
305 const char *key_str;
306 const char *func;
307 function_key key;
308 function_key_handler_t handler;
309};
310
Nir Tzachara72f3e22010-08-08 16:50:06 +0300311static const int function_keys_num = 9;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200312struct function_keys function_keys[] = {
313 {
314 .key_str = "F1",
315 .func = "Help",
316 .key = F_HELP,
317 .handler = handle_f1,
318 },
319 {
320 .key_str = "F2",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300321 .func = "Sym Info",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200322 .key = F_SYMBOL,
323 .handler = handle_f2,
324 },
325 {
326 .key_str = "F3",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300327 .func = "Insts",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200328 .key = F_INSTS,
329 .handler = handle_f3,
330 },
331 {
332 .key_str = "F4",
333 .func = "Config",
334 .key = F_CONF,
335 .handler = handle_f4,
336 },
337 {
338 .key_str = "F5",
339 .func = "Back",
340 .key = F_BACK,
341 .handler = handle_f5,
342 },
343 {
344 .key_str = "F6",
345 .func = "Save",
346 .key = F_SAVE,
347 .handler = handle_f6,
348 },
349 {
350 .key_str = "F7",
351 .func = "Load",
352 .key = F_LOAD,
353 .handler = handle_f7,
354 },
355 {
356 .key_str = "F8",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300357 .func = "Sym Search",
358 .key = F_SEARCH,
359 .handler = handle_f8,
360 },
361 {
362 .key_str = "F9",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200363 .func = "Exit",
364 .key = F_EXIT,
Nir Tzachara72f3e22010-08-08 16:50:06 +0300365 .handler = handle_f9,
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200366 },
367};
368
369static void print_function_line(void)
370{
371 int i;
372 int offset = 1;
373 const int skip = 1;
374
375 for (i = 0; i < function_keys_num; i++) {
376 wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
377 mvwprintw(main_window, LINES-3, offset,
378 "%s",
379 function_keys[i].key_str);
380 wattrset(main_window, attributes[FUNCTION_TEXT]);
381 offset += strlen(function_keys[i].key_str);
382 mvwprintw(main_window, LINES-3,
383 offset, "%s",
384 function_keys[i].func);
385 offset += strlen(function_keys[i].func) + skip;
386 }
387 wattrset(main_window, attributes[NORMAL]);
388}
389
390/* help */
391static void handle_f1(int *key, struct menu *current_item)
392{
393 show_scroll_win(main_window,
394 _("README"), _(nconf_readme));
395 return;
396}
397
398/* symbole help */
399static void handle_f2(int *key, struct menu *current_item)
400{
401 show_help(current_item);
402 return;
403}
404
405/* instructions */
406static void handle_f3(int *key, struct menu *current_item)
407{
408 show_scroll_win(main_window,
409 _("Instructions"),
410 _(current_instructions));
411 return;
412}
413
414/* config */
415static void handle_f4(int *key, struct menu *current_item)
416{
417 int res = btn_dialog(main_window,
418 _("Show all symbols?"),
419 2,
420 " <Show All> ",
421 "<Don't show all>");
422 if (res == 0)
423 show_all_items = 1;
424 else if (res == 1)
425 show_all_items = 0;
426
427 return;
428}
429
430/* back */
431static void handle_f5(int *key, struct menu *current_item)
432{
433 *key = KEY_LEFT;
434 return;
435}
436
437/* save */
438static void handle_f6(int *key, struct menu *current_item)
439{
440 conf_save();
441 return;
442}
443
444/* load */
445static void handle_f7(int *key, struct menu *current_item)
446{
447 conf_load();
448 return;
449}
450
Nir Tzachara72f3e22010-08-08 16:50:06 +0300451/* search */
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200452static void handle_f8(int *key, struct menu *current_item)
453{
Nir Tzachara72f3e22010-08-08 16:50:06 +0300454 search_conf();
455 return;
456}
457
458/* exit */
459static void handle_f9(int *key, struct menu *current_item)
460{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200461 do_exit();
462 return;
463}
464
465/* return != 0 to indicate the key was handles */
Michal Marek851190c2010-01-07 13:59:57 +0100466static int process_special_keys(int *key, struct menu *menu)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200467{
468 int i;
469
470 if (*key == KEY_RESIZE) {
471 setup_windows();
472 return 1;
473 }
474
475 for (i = 0; i < function_keys_num; i++) {
476 if (*key == KEY_F(function_keys[i].key) ||
477 *key == '0' + function_keys[i].key){
478 function_keys[i].handler(key, menu);
479 return 1;
480 }
481 }
482
483 return 0;
484}
485
486static void clean_items(void)
487{
488 int i;
489 for (i = 0; curses_menu_items[i]; i++)
490 free_item(curses_menu_items[i]);
491 bzero(curses_menu_items, sizeof(curses_menu_items));
492 bzero(k_menu_items, sizeof(k_menu_items));
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200493 items_num = 0;
494}
495
Nir Tzachara72f3e22010-08-08 16:50:06 +0300496typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
497 FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
498
499/* return the index of the matched item, or -1 if no such item exists */
500static int get_mext_match(const char *match_str, match_f flag)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200501{
Nir Tzachara72f3e22010-08-08 16:50:06 +0300502 int match_start = item_index(current_item(curses_menu));
503 int index;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200504
Nir Tzachara72f3e22010-08-08 16:50:06 +0300505 if (flag == FIND_NEXT_MATCH_DOWN)
506 ++match_start;
507 else if (flag == FIND_NEXT_MATCH_UP)
508 --match_start;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200509
Nir Tzachara72f3e22010-08-08 16:50:06 +0300510 index = match_start;
511 index = (index + items_num) % items_num;
512 while (true) {
513 char *str = k_menu_items[index].str;
514 if (strcasestr(str, match_str) != 0)
515 return index;
516 if (flag == FIND_NEXT_MATCH_UP ||
517 flag == MATCH_TINKER_PATTERN_UP)
518 --index;
519 else
520 ++index;
521 index = (index + items_num) % items_num;
522 if (index == match_start)
523 return -1;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200524 }
525}
526
Nir Tzachara72f3e22010-08-08 16:50:06 +0300527/* Make a new item. */
Michal Marek851190c2010-01-07 13:59:57 +0100528static void item_make(struct menu *menu, char tag, const char *fmt, ...)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200529{
530 va_list ap;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200531
532 if (items_num > MAX_MENU_ITEMS-1)
533 return;
534
535 bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
536 k_menu_items[items_num].tag = tag;
537 k_menu_items[items_num].usrptr = menu;
538 if (menu != NULL)
539 k_menu_items[items_num].is_visible =
540 menu_is_visible(menu);
541 else
542 k_menu_items[items_num].is_visible = 1;
543
544 va_start(ap, fmt);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300545 vsnprintf(k_menu_items[items_num].str,
546 sizeof(k_menu_items[items_num].str),
547 fmt, ap);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200548 va_end(ap);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300549
550 if (!k_menu_items[items_num].is_visible)
551 memcpy(k_menu_items[items_num].str, "XXX", 3);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200552
553 curses_menu_items[items_num] = new_item(
554 k_menu_items[items_num].str,
555 k_menu_items[items_num].str);
556 set_item_userptr(curses_menu_items[items_num],
557 &k_menu_items[items_num]);
558 /*
559 if (!k_menu_items[items_num].is_visible)
560 item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
561 */
562
563 items_num++;
564 curses_menu_items[items_num] = NULL;
565}
566
567/* very hackish. adds a string to the last item added */
Michal Marek851190c2010-01-07 13:59:57 +0100568static void item_add_str(const char *fmt, ...)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200569{
570 va_list ap;
571 int index = items_num-1;
572 char new_str[256];
573 char tmp_str[256];
574
575 if (index < 0)
576 return;
577
578 va_start(ap, fmt);
579 vsnprintf(new_str, sizeof(new_str), fmt, ap);
580 va_end(ap);
581 snprintf(tmp_str, sizeof(tmp_str), "%s%s",
582 k_menu_items[index].str, new_str);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300583 strncpy(k_menu_items[index].str,
584 tmp_str,
585 sizeof(k_menu_items[index].str));
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200586
587 free_item(curses_menu_items[index]);
588 curses_menu_items[index] = new_item(
589 k_menu_items[index].str,
590 k_menu_items[index].str);
591 set_item_userptr(curses_menu_items[index],
592 &k_menu_items[index]);
593}
594
595/* get the tag of the currently selected item */
Michal Marek851190c2010-01-07 13:59:57 +0100596static char item_tag(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200597{
598 ITEM *cur;
599 struct mitem *mcur;
600
601 cur = current_item(curses_menu);
602 if (cur == NULL)
603 return 0;
604 mcur = (struct mitem *) item_userptr(cur);
605 return mcur->tag;
606}
607
Michal Marek851190c2010-01-07 13:59:57 +0100608static int curses_item_index(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200609{
610 return item_index(current_item(curses_menu));
611}
612
Michal Marek851190c2010-01-07 13:59:57 +0100613static void *item_data(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200614{
615 ITEM *cur;
616 struct mitem *mcur;
617
618 cur = current_item(curses_menu);
Andrej Gelenberg866af402010-08-02 11:59:31 +0200619 if (!cur)
620 return NULL;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200621 mcur = (struct mitem *) item_userptr(cur);
622 return mcur->usrptr;
623
624}
625
Michal Marek851190c2010-01-07 13:59:57 +0100626static int item_is_tag(char tag)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200627{
628 return item_tag() == tag;
629}
630
631static char filename[PATH_MAX+1];
632static char menu_backtitle[PATH_MAX+128];
Michal Marek851190c2010-01-07 13:59:57 +0100633static const char *set_config_filename(const char *config_filename)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200634{
635 int size;
636 struct symbol *sym;
637
638 sym = sym_lookup("KERNELVERSION", 0);
639 sym_calc_value(sym);
640 size = snprintf(menu_backtitle, sizeof(menu_backtitle),
641 _("%s - Linux Kernel v%s Configuration"),
642 config_filename, sym_get_string_value(sym));
643 if (size >= sizeof(menu_backtitle))
644 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
645
646 size = snprintf(filename, sizeof(filename), "%s", config_filename);
647 if (size >= sizeof(filename))
648 filename[sizeof(filename)-1] = '\0';
649 return menu_backtitle;
650}
651
652/* command = 0 is supress, 1 is restore */
653static void supress_stdout(int command)
654{
655 static FILE *org_stdout;
656 static FILE *org_stderr;
657
658 if (command == 0) {
659 org_stdout = stdout;
660 org_stderr = stderr;
661 stdout = fopen("/dev/null", "a");
662 stderr = fopen("/dev/null", "a");
663 } else {
664 fclose(stdout);
665 fclose(stderr);
666 stdout = org_stdout;
667 stderr = org_stderr;
668 }
669}
670
671/* return = 0 means we are successful.
672 * -1 means go on doing what you were doing
673 */
674static int do_exit(void)
675{
676 int res;
677 if (!conf_get_changed()) {
678 global_exit = 1;
679 return 0;
680 }
681 res = btn_dialog(main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400682 _("Do you wish to save your new configuration?\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200683 "<ESC> to cancel and resume nconfig."),
684 2,
685 " <save> ",
686 "<don't save>");
687 if (res == KEY_EXIT) {
688 global_exit = 0;
689 return -1;
690 }
691
692 /* if we got here, the user really wants to exit */
693 switch (res) {
694 case 0:
695 supress_stdout(0);
696 res = conf_write(filename);
697 supress_stdout(1);
698 if (res)
699 btn_dialog(
700 main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400701 _("Error during writing of configuration.\n"
702 "Your configuration changes were NOT saved."),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200703 1,
704 "<OK>");
705 else {
706 char buf[1024];
707 snprintf(buf, 1024,
708 _("Configuration written to %s\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400709 "End of the configuration.\n"
710 "Execute 'make' to start the build or try"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200711 " 'make help'."), filename);
712 btn_dialog(
713 main_window,
714 buf,
715 1,
716 "<OK>");
717 }
718 break;
719 default:
720 btn_dialog(
721 main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400722 _("Your configuration changes were NOT saved."),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200723 1,
724 "<OK>");
725 break;
726 }
727 global_exit = 1;
728 return 0;
729}
730
731
732static void search_conf(void)
733{
734 struct symbol **sym_arr;
735 struct gstr res;
736 char dialog_input_result[100];
737 char *dialog_input;
738 int dres;
739again:
740 dres = dialog_inputbox(main_window,
741 _("Search Configuration Parameter"),
Arnaud Lacombeffb59572010-08-14 23:57:43 -0400742 _("Enter " CONFIG_ " (sub)string to search for "
743 "(with or without \"" CONFIG_ "\")"),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200744 "", dialog_input_result, 99);
745 switch (dres) {
746 case 0:
747 break;
748 case 1:
749 show_scroll_win(main_window,
750 _("Search Configuration"), search_help);
751 goto again;
752 default:
753 return;
754 }
755
Arnaud Lacombeffb59572010-08-14 23:57:43 -0400756 /* strip the prefix if necessary */
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200757 dialog_input = dialog_input_result;
Arnaud Lacombeffb59572010-08-14 23:57:43 -0400758 if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
759 dialog_input += strlen(CONFIG_);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200760
761 sym_arr = sym_re_search(dialog_input);
762 res = get_relations_str(sym_arr);
763 free(sym_arr);
764 show_scroll_win(main_window,
765 _("Search Results"), str_get(&res));
766 str_free(&res);
767}
768
769
770static void build_conf(struct menu *menu)
771{
772 struct symbol *sym;
773 struct property *prop;
774 struct menu *child;
775 int type, tmp, doint = 2;
776 tristate val;
777 char ch;
778
779 if (!menu || (!show_all_items && !menu_is_visible(menu)))
780 return;
781
782 sym = menu->sym;
783 prop = menu->prompt;
784 if (!sym) {
785 if (prop && menu != current_menu) {
786 const char *prompt = menu_get_prompt(menu);
787 enum prop_type ptype;
788 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
789 switch (ptype) {
790 case P_MENU:
791 child_count++;
792 prompt = _(prompt);
793 if (single_menu_mode) {
794 item_make(menu, 'm',
795 "%s%*c%s",
796 menu->data ? "-->" : "++>",
797 indent + 1, ' ', prompt);
798 } else
799 item_make(menu, 'm',
800 " %*c%s --->",
801 indent + 1,
802 ' ', prompt);
803
804 if (single_menu_mode && menu->data)
805 goto conf_childs;
806 return;
807 case P_COMMENT:
808 if (prompt) {
809 child_count++;
810 item_make(menu, ':',
811 " %*c*** %s ***",
812 indent + 1, ' ',
813 _(prompt));
814 }
815 break;
816 default:
817 if (prompt) {
818 child_count++;
819 item_make(menu, ':', "---%*c%s",
820 indent + 1, ' ',
821 _(prompt));
822 }
823 }
824 } else
825 doint = 0;
826 goto conf_childs;
827 }
828
829 type = sym_get_type(sym);
830 if (sym_is_choice(sym)) {
831 struct symbol *def_sym = sym_get_choice_value(sym);
832 struct menu *def_menu = NULL;
833
834 child_count++;
835 for (child = menu->list; child; child = child->next) {
836 if (menu_is_visible(child) && child->sym == def_sym)
837 def_menu = child;
838 }
839
840 val = sym_get_tristate_value(sym);
841 if (sym_is_changable(sym)) {
842 switch (type) {
843 case S_BOOLEAN:
844 item_make(menu, 't', "[%c]",
845 val == no ? ' ' : '*');
846 break;
847 case S_TRISTATE:
848 switch (val) {
849 case yes:
850 ch = '*';
851 break;
852 case mod:
853 ch = 'M';
854 break;
855 default:
856 ch = ' ';
857 break;
858 }
859 item_make(menu, 't', "<%c>", ch);
860 break;
861 }
862 } else {
863 item_make(menu, def_menu ? 't' : ':', " ");
864 }
865
866 item_add_str("%*c%s", indent + 1,
867 ' ', _(menu_get_prompt(menu)));
868 if (val == yes) {
869 if (def_menu) {
870 item_add_str(" (%s)",
871 _(menu_get_prompt(def_menu)));
872 item_add_str(" --->");
873 if (def_menu->list) {
874 indent += 2;
875 build_conf(def_menu);
876 indent -= 2;
877 }
878 }
879 return;
880 }
881 } else {
882 if (menu == current_menu) {
883 item_make(menu, ':',
884 "---%*c%s", indent + 1,
885 ' ', _(menu_get_prompt(menu)));
886 goto conf_childs;
887 }
888 child_count++;
889 val = sym_get_tristate_value(sym);
890 if (sym_is_choice_value(sym) && val == yes) {
891 item_make(menu, ':', " ");
892 } else {
893 switch (type) {
894 case S_BOOLEAN:
895 if (sym_is_changable(sym))
896 item_make(menu, 't', "[%c]",
897 val == no ? ' ' : '*');
898 else
899 item_make(menu, 't', "-%c-",
900 val == no ? ' ' : '*');
901 break;
902 case S_TRISTATE:
903 switch (val) {
904 case yes:
905 ch = '*';
906 break;
907 case mod:
908 ch = 'M';
909 break;
910 default:
911 ch = ' ';
912 break;
913 }
914 if (sym_is_changable(sym)) {
915 if (sym->rev_dep.tri == mod)
916 item_make(menu,
917 't', "{%c}", ch);
918 else
919 item_make(menu,
920 't', "<%c>", ch);
921 } else
922 item_make(menu, 't', "-%c-", ch);
923 break;
924 default:
925 tmp = 2 + strlen(sym_get_string_value(sym));
Nir Tzachar68c16ed2010-01-13 07:32:35 +0200926 item_make(menu, 's', " (%s)",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200927 sym_get_string_value(sym));
928 tmp = indent - tmp + 4;
929 if (tmp < 0)
930 tmp = 0;
931 item_add_str("%*c%s%s", tmp, ' ',
932 _(menu_get_prompt(menu)),
933 (sym_has_value(sym) ||
934 !sym_is_changable(sym)) ? "" :
935 _(" (NEW)"));
936 goto conf_childs;
937 }
938 }
939 item_add_str("%*c%s%s", indent + 1, ' ',
940 _(menu_get_prompt(menu)),
941 (sym_has_value(sym) || !sym_is_changable(sym)) ?
942 "" : _(" (NEW)"));
943 if (menu->prompt && menu->prompt->type == P_MENU) {
944 item_add_str(" --->");
945 return;
946 }
947 }
948
949conf_childs:
950 indent += doint;
951 for (child = menu->list; child; child = child->next)
952 build_conf(child);
953 indent -= doint;
954}
955
956static void reset_menu(void)
957{
958 unpost_menu(curses_menu);
959 clean_items();
960}
961
962/* adjust the menu to show this item.
963 * prefer not to scroll the menu if possible*/
964static void center_item(int selected_index, int *last_top_row)
965{
966 int toprow;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200967
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200968 set_top_row(curses_menu, *last_top_row);
969 toprow = top_row(curses_menu);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300970 if (selected_index < toprow ||
971 selected_index >= toprow+mwin_max_lines) {
972 toprow = max(selected_index-mwin_max_lines/2, 0);
973 if (toprow >= item_count(curses_menu)-mwin_max_lines)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200974 toprow = item_count(curses_menu)-mwin_max_lines;
975 set_top_row(curses_menu, toprow);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200976 }
Nir Tzachara72f3e22010-08-08 16:50:06 +0300977 set_current_item(curses_menu,
978 curses_menu_items[selected_index]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200979 *last_top_row = toprow;
980 post_menu(curses_menu);
981 refresh_all_windows(main_window);
982}
983
984/* this function assumes reset_menu has been called before */
985static void show_menu(const char *prompt, const char *instructions,
986 int selected_index, int *last_top_row)
987{
988 int maxx, maxy;
989 WINDOW *menu_window;
990
991 current_instructions = instructions;
992
993 clear();
994 wattrset(main_window, attributes[NORMAL]);
995 print_in_middle(stdscr, 1, 0, COLS,
996 menu_backtitle,
997 attributes[MAIN_HEADING]);
998
999 wattrset(main_window, attributes[MAIN_MENU_BOX]);
1000 box(main_window, 0, 0);
1001 wattrset(main_window, attributes[MAIN_MENU_HEADING]);
1002 mvwprintw(main_window, 0, 3, " %s ", prompt);
1003 wattrset(main_window, attributes[NORMAL]);
1004
1005 set_menu_items(curses_menu, curses_menu_items);
1006
1007 /* position the menu at the middle of the screen */
1008 scale_menu(curses_menu, &maxy, &maxx);
Nir Tzachar68c16ed2010-01-13 07:32:35 +02001009 maxx = min(maxx, mwin_max_cols-2);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001010 maxy = mwin_max_lines;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001011 menu_window = derwin(main_window,
1012 maxy,
1013 maxx,
1014 2,
1015 (mwin_max_cols-maxx)/2);
1016 keypad(menu_window, TRUE);
1017 set_menu_win(curses_menu, menu_window);
1018 set_menu_sub(curses_menu, menu_window);
1019
1020 /* must reassert this after changing items, otherwise returns to a
1021 * default of 16
1022 */
1023 set_menu_format(curses_menu, maxy, 1);
1024 center_item(selected_index, last_top_row);
1025 set_menu_format(curses_menu, maxy, 1);
1026
1027 print_function_line();
1028
1029 /* Post the menu */
1030 post_menu(curses_menu);
1031 refresh_all_windows(main_window);
1032}
1033
Nir Tzachara72f3e22010-08-08 16:50:06 +03001034static void adj_match_dir(match_f *match_direction)
1035{
1036 if (*match_direction == FIND_NEXT_MATCH_DOWN)
1037 *match_direction =
1038 MATCH_TINKER_PATTERN_DOWN;
1039 else if (*match_direction == FIND_NEXT_MATCH_UP)
1040 *match_direction =
1041 MATCH_TINKER_PATTERN_UP;
1042 /* else, do no change.. */
1043}
1044
1045struct match_state
1046{
1047 int in_search;
1048 match_f match_direction;
1049 char pattern[256];
1050};
1051
1052/* Return 0 means I have handled the key. In such a case, ans should hold the
1053 * item to center, or -1 otherwise.
1054 * Else return -1 .
1055 */
1056static int do_match(int key, struct match_state *state, int *ans)
1057{
1058 char c = (char) key;
1059 int terminate_search = 0;
1060 *ans = -1;
1061 if (key == '/' || (state->in_search && key == 27)) {
1062 move(0, 0);
1063 refresh();
1064 clrtoeol();
1065 state->in_search = 1-state->in_search;
1066 bzero(state->pattern, sizeof(state->pattern));
1067 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1068 return 0;
1069 } else if (!state->in_search)
1070 return 1;
1071
1072 if (isalnum(c) || isgraph(c) || c == ' ') {
1073 state->pattern[strlen(state->pattern)] = c;
1074 state->pattern[strlen(state->pattern)] = '\0';
1075 adj_match_dir(&state->match_direction);
1076 *ans = get_mext_match(state->pattern,
1077 state->match_direction);
1078 } else if (key == KEY_DOWN) {
1079 state->match_direction = FIND_NEXT_MATCH_DOWN;
1080 *ans = get_mext_match(state->pattern,
1081 state->match_direction);
1082 } else if (key == KEY_UP) {
1083 state->match_direction = FIND_NEXT_MATCH_UP;
1084 *ans = get_mext_match(state->pattern,
1085 state->match_direction);
1086 } else if (key == KEY_BACKSPACE || key == 127) {
1087 state->pattern[strlen(state->pattern)-1] = '\0';
1088 adj_match_dir(&state->match_direction);
1089 } else
1090 terminate_search = 1;
1091
1092 if (terminate_search) {
1093 state->in_search = 0;
1094 bzero(state->pattern, sizeof(state->pattern));
1095 move(0, 0);
1096 refresh();
1097 clrtoeol();
1098 return -1;
1099 }
1100 return 0;
1101}
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001102
1103static void conf(struct menu *menu)
1104{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001105 struct menu *submenu = 0;
1106 const char *prompt = menu_get_prompt(menu);
1107 struct symbol *sym;
1108 struct menu *active_menu = NULL;
1109 int res;
1110 int current_index = 0;
1111 int last_top_row = 0;
Nir Tzachara72f3e22010-08-08 16:50:06 +03001112 struct match_state match_state = {
1113 .in_search = 0,
1114 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1115 .pattern = "",
1116 };
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001117
1118 while (!global_exit) {
1119 reset_menu();
1120 current_menu = menu;
1121 build_conf(menu);
1122 if (!child_count)
1123 break;
1124
1125 show_menu(prompt ? _(prompt) : _("Main Menu"),
1126 _(menu_instructions),
1127 current_index, &last_top_row);
1128 keypad((menu_win(curses_menu)), TRUE);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001129 while (!global_exit) {
1130 if (match_state.in_search) {
1131 mvprintw(0, 0,
1132 "searching: %s", match_state.pattern);
1133 clrtoeol();
1134 }
1135 refresh_all_windows(main_window);
1136 res = wgetch(menu_win(curses_menu));
1137 if (!res)
1138 break;
1139 if (do_match(res, &match_state, &current_index) == 0) {
1140 if (current_index != -1)
1141 center_item(current_index,
1142 &last_top_row);
1143 continue;
1144 }
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001145 if (process_special_keys(&res,
1146 (struct menu *) item_data()))
1147 break;
1148 switch (res) {
1149 case KEY_DOWN:
1150 menu_driver(curses_menu, REQ_DOWN_ITEM);
1151 break;
1152 case KEY_UP:
1153 menu_driver(curses_menu, REQ_UP_ITEM);
1154 break;
1155 case KEY_NPAGE:
1156 menu_driver(curses_menu, REQ_SCR_DPAGE);
1157 break;
1158 case KEY_PPAGE:
1159 menu_driver(curses_menu, REQ_SCR_UPAGE);
1160 break;
1161 case KEY_HOME:
1162 menu_driver(curses_menu, REQ_FIRST_ITEM);
1163 break;
1164 case KEY_END:
1165 menu_driver(curses_menu, REQ_LAST_ITEM);
1166 break;
1167 case 'h':
1168 case '?':
1169 show_help((struct menu *) item_data());
1170 break;
1171 }
1172 if (res == 10 || res == 27 ||
1173 res == 32 || res == 'n' || res == 'y' ||
1174 res == KEY_LEFT || res == KEY_RIGHT ||
Nir Tzachara72f3e22010-08-08 16:50:06 +03001175 res == 'm')
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001176 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001177 refresh_all_windows(main_window);
1178 }
1179
1180 refresh_all_windows(main_window);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001181 /* if ESC or left*/
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001182 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1183 break;
1184
1185 /* remember location in the menu */
1186 last_top_row = top_row(curses_menu);
1187 current_index = curses_item_index();
1188
1189 if (!item_tag())
1190 continue;
1191
1192 submenu = (struct menu *) item_data();
1193 active_menu = (struct menu *)item_data();
1194 if (!submenu || !menu_is_visible(submenu))
1195 continue;
1196 if (submenu)
1197 sym = submenu->sym;
1198 else
1199 sym = NULL;
1200
1201 switch (res) {
1202 case ' ':
1203 if (item_is_tag('t'))
1204 sym_toggle_tristate_value(sym);
1205 else if (item_is_tag('m'))
1206 conf(submenu);
1207 break;
1208 case KEY_RIGHT:
1209 case 10: /* ENTER WAS PRESSED */
1210 switch (item_tag()) {
1211 case 'm':
1212 if (single_menu_mode)
1213 submenu->data =
1214 (void *) (long) !submenu->data;
1215 else
1216 conf(submenu);
1217 break;
1218 case 't':
1219 if (sym_is_choice(sym) &&
1220 sym_get_tristate_value(sym) == yes)
1221 conf_choice(submenu);
1222 else if (submenu->prompt &&
1223 submenu->prompt->type == P_MENU)
1224 conf(submenu);
1225 else if (res == 10)
1226 sym_toggle_tristate_value(sym);
1227 break;
1228 case 's':
1229 conf_string(submenu);
1230 break;
1231 }
1232 break;
1233 case 'y':
1234 if (item_is_tag('t')) {
1235 if (sym_set_tristate_value(sym, yes))
1236 break;
1237 if (sym_set_tristate_value(sym, mod))
1238 btn_dialog(main_window, setmod_text, 0);
1239 }
1240 break;
1241 case 'n':
1242 if (item_is_tag('t'))
1243 sym_set_tristate_value(sym, no);
1244 break;
1245 case 'm':
1246 if (item_is_tag('t'))
1247 sym_set_tristate_value(sym, mod);
1248 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001249 }
1250 }
1251}
1252
1253static void show_help(struct menu *menu)
1254{
1255 struct gstr help = str_new();
1256
1257 if (menu && menu->sym && menu_has_help(menu)) {
1258 if (menu->sym->name) {
Arnaud Lacombeffb59572010-08-14 23:57:43 -04001259 str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001260 str_append(&help, _(menu_get_help(menu)));
1261 str_append(&help, "\n");
1262 get_symbol_str(&help, menu->sym);
1263 }
1264 } else {
1265 str_append(&help, nohelp_text);
1266 }
1267 show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1268 str_free(&help);
1269}
1270
1271static void conf_choice(struct menu *menu)
1272{
1273 const char *prompt = _(menu_get_prompt(menu));
1274 struct menu *child = 0;
1275 struct symbol *active;
1276 int selected_index = 0;
1277 int last_top_row = 0;
1278 int res, i = 0;
Nir Tzachara72f3e22010-08-08 16:50:06 +03001279 struct match_state match_state = {
1280 .in_search = 0,
1281 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1282 .pattern = "",
1283 };
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001284
1285 active = sym_get_choice_value(menu->sym);
1286 /* this is mostly duplicated from the conf() function. */
1287 while (!global_exit) {
1288 reset_menu();
1289
1290 for (i = 0, child = menu->list; child; child = child->next) {
1291 if (!show_all_items && !menu_is_visible(child))
1292 continue;
1293
1294 if (child->sym == sym_get_choice_value(menu->sym))
1295 item_make(child, ':', "<X> %s",
1296 _(menu_get_prompt(child)));
1297 else
1298 item_make(child, ':', " %s",
1299 _(menu_get_prompt(child)));
1300 if (child->sym == active){
1301 last_top_row = top_row(curses_menu);
1302 selected_index = i;
1303 }
1304 i++;
1305 }
1306 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1307 _(radiolist_instructions),
1308 selected_index,
1309 &last_top_row);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001310 while (!global_exit) {
1311 if (match_state.in_search) {
1312 mvprintw(0, 0, "searching: %s",
1313 match_state.pattern);
1314 clrtoeol();
1315 }
1316 refresh_all_windows(main_window);
1317 res = wgetch(menu_win(curses_menu));
1318 if (!res)
1319 break;
1320 if (do_match(res, &match_state, &selected_index) == 0) {
1321 if (selected_index != -1)
1322 center_item(selected_index,
1323 &last_top_row);
1324 continue;
1325 }
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001326 if (process_special_keys(
1327 &res,
1328 (struct menu *) item_data()))
1329 break;
1330 switch (res) {
1331 case KEY_DOWN:
1332 menu_driver(curses_menu, REQ_DOWN_ITEM);
1333 break;
1334 case KEY_UP:
1335 menu_driver(curses_menu, REQ_UP_ITEM);
1336 break;
1337 case KEY_NPAGE:
1338 menu_driver(curses_menu, REQ_SCR_DPAGE);
1339 break;
1340 case KEY_PPAGE:
1341 menu_driver(curses_menu, REQ_SCR_UPAGE);
1342 break;
1343 case KEY_HOME:
1344 menu_driver(curses_menu, REQ_FIRST_ITEM);
1345 break;
1346 case KEY_END:
1347 menu_driver(curses_menu, REQ_LAST_ITEM);
1348 break;
1349 case 'h':
1350 case '?':
1351 show_help((struct menu *) item_data());
1352 break;
1353 }
1354 if (res == 10 || res == 27 || res == ' ' ||
Nir Tzachara72f3e22010-08-08 16:50:06 +03001355 res == KEY_LEFT){
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001356 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001357 }
1358 refresh_all_windows(main_window);
1359 }
1360 /* if ESC or left */
1361 if (res == 27 || res == KEY_LEFT)
1362 break;
1363
1364 child = item_data();
1365 if (!child || !menu_is_visible(child))
1366 continue;
1367 switch (res) {
1368 case ' ':
1369 case 10:
1370 case KEY_RIGHT:
1371 sym_set_tristate_value(child->sym, yes);
1372 return;
1373 case 'h':
1374 case '?':
1375 show_help(child);
1376 active = child->sym;
1377 break;
1378 case KEY_EXIT:
1379 return;
1380 }
1381 }
1382}
1383
1384static void conf_string(struct menu *menu)
1385{
1386 const char *prompt = menu_get_prompt(menu);
1387 char dialog_input_result[256];
1388
1389 while (1) {
1390 int res;
1391 const char *heading;
1392
1393 switch (sym_get_type(menu->sym)) {
1394 case S_INT:
1395 heading = _(inputbox_instructions_int);
1396 break;
1397 case S_HEX:
1398 heading = _(inputbox_instructions_hex);
1399 break;
1400 case S_STRING:
1401 heading = _(inputbox_instructions_string);
1402 break;
1403 default:
1404 heading = _("Internal nconf error!");
1405 }
1406 res = dialog_inputbox(main_window,
1407 prompt ? _(prompt) : _("Main Menu"),
1408 heading,
1409 sym_get_string_value(menu->sym),
1410 dialog_input_result,
1411 sizeof(dialog_input_result));
1412 switch (res) {
1413 case 0:
1414 if (sym_set_string_value(menu->sym,
1415 dialog_input_result))
1416 return;
1417 btn_dialog(main_window,
1418 _("You have made an invalid entry."), 0);
1419 break;
1420 case 1:
1421 show_help(menu);
1422 break;
1423 case KEY_EXIT:
1424 return;
1425 }
1426 }
1427}
1428
1429static void conf_load(void)
1430{
1431 char dialog_input_result[256];
1432 while (1) {
1433 int res;
1434 res = dialog_inputbox(main_window,
1435 NULL, load_config_text,
1436 filename,
1437 dialog_input_result,
1438 sizeof(dialog_input_result));
1439 switch (res) {
1440 case 0:
1441 if (!dialog_input_result[0])
1442 return;
1443 if (!conf_read(dialog_input_result)) {
1444 set_config_filename(dialog_input_result);
1445 sym_set_change_count(1);
1446 return;
1447 }
1448 btn_dialog(main_window, _("File does not exist!"), 0);
1449 break;
1450 case 1:
1451 show_scroll_win(main_window,
1452 _("Load Alternate Configuration"),
1453 load_config_help);
1454 break;
1455 case KEY_EXIT:
1456 return;
1457 }
1458 }
1459}
1460
1461static void conf_save(void)
1462{
1463 char dialog_input_result[256];
1464 while (1) {
1465 int res;
1466 res = dialog_inputbox(main_window,
1467 NULL, save_config_text,
1468 filename,
1469 dialog_input_result,
1470 sizeof(dialog_input_result));
1471 switch (res) {
1472 case 0:
1473 if (!dialog_input_result[0])
1474 return;
1475 supress_stdout(0);
1476 res = conf_write(dialog_input_result);
1477 supress_stdout(1);
1478 if (!res) {
1479 char buf[1024];
1480 sprintf(buf, "%s %s",
1481 _("configuration file saved to: "),
1482 dialog_input_result);
1483 btn_dialog(main_window,
1484 buf, 1, "<OK>");
1485 set_config_filename(dialog_input_result);
1486 return;
1487 }
1488 btn_dialog(main_window, _("Can't create file! "
1489 "Probably a nonexistent directory."),
1490 1, "<OK>");
1491 break;
1492 case 1:
1493 show_scroll_win(main_window,
1494 _("Save Alternate Configuration"),
1495 save_config_help);
1496 break;
1497 case KEY_EXIT:
1498 return;
1499 }
1500 }
1501}
1502
1503void setup_windows(void)
1504{
1505 if (main_window != NULL)
1506 delwin(main_window);
1507
1508 /* set up the menu and menu window */
1509 main_window = newwin(LINES-2, COLS-2, 2, 1);
1510 keypad(main_window, TRUE);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001511 mwin_max_lines = LINES-7;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001512 mwin_max_cols = COLS-6;
1513
1514 /* panels order is from bottom to top */
1515 new_panel(main_window);
1516}
1517
1518int main(int ac, char **av)
1519{
1520 char *mode;
1521
1522 setlocale(LC_ALL, "");
1523 bindtextdomain(PACKAGE, LOCALEDIR);
1524 textdomain(PACKAGE);
1525
1526 conf_parse(av[1]);
1527 conf_read(NULL);
1528
1529 mode = getenv("NCONFIG_MODE");
1530 if (mode) {
1531 if (!strcasecmp(mode, "single_menu"))
1532 single_menu_mode = 1;
1533 }
1534
1535 /* Initialize curses */
1536 initscr();
1537 /* set color theme */
1538 set_colors();
1539
1540 cbreak();
1541 noecho();
1542 keypad(stdscr, TRUE);
1543 curs_set(0);
1544
1545 if (COLS < 75 || LINES < 20) {
1546 endwin();
1547 printf("Your terminal should have at "
1548 "least 20 lines and 75 columns\n");
1549 return 1;
1550 }
1551
1552 notimeout(stdscr, FALSE);
1553 ESCDELAY = 1;
1554
1555 /* set btns menu */
1556 curses_menu = new_menu(curses_menu_items);
1557 menu_opts_off(curses_menu, O_SHOWDESC);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001558 menu_opts_on(curses_menu, O_SHOWMATCH);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001559 menu_opts_on(curses_menu, O_ONEVALUE);
1560 menu_opts_on(curses_menu, O_NONCYCLIC);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001561 menu_opts_on(curses_menu, O_IGNORECASE);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001562 set_menu_mark(curses_menu, " ");
1563 set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1564 set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1565 set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1566
1567 set_config_filename(conf_get_configname());
1568 setup_windows();
1569
1570 /* check for KEY_FUNC(1) */
1571 if (has_key(KEY_F(1)) == FALSE) {
1572 show_scroll_win(main_window,
1573 _("Instructions"),
1574 _(menu_no_f_instructions));
1575 }
1576
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001577 /* do the work */
1578 while (!global_exit) {
1579 conf(&rootmenu);
1580 if (!global_exit && do_exit() == 0)
1581 break;
1582 }
1583 /* ok, we are done */
1584 unpost_menu(curses_menu);
1585 free_menu(curses_menu);
1586 delwin(main_window);
1587 clear();
1588 refresh();
1589 endwin();
1590 return 0;
1591}
1592