blob: ce93e879a29c8fcd71458889b632c8ea43c654db [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>
Yann E. MORIN9a926d42012-10-20 01:06:25 +020010#include <stdlib.h>
Arnaud Lacombe5a6f8d22011-06-01 16:14:47 -040011
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020012#include "lkc.h"
13#include "nconf.h"
Nir Tzachara72f3e22010-08-08 16:50:06 +030014#include <ctype.h>
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020015
16static const char nconf_readme[] = N_(
17"Overview\n"
18"--------\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -040019"This interface let you select features and parameters for the build.\n"
20"Features can either be built-in, modularized, or ignored. Parameters\n"
21"must be entered in as decimal or hexadecimal numbers or text.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020022"\n"
23"Menu items beginning with following braces represent features that\n"
24" [ ] can be built in or removed\n"
25" < > can be built in, modularized or removed\n"
26" { } can be built in or modularized (selected by other feature)\n"
27" - - are selected by other feature,\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +030028" XXX cannot be selected. Use Symbol Info to find out why,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020029"while *, M or whitespace inside braces means to build in, build as\n"
30"a module or to exclude the feature respectively.\n"
31"\n"
32"To change any of these features, highlight it with the cursor\n"
33"keys and press <Y> to build it in, <M> to make it a module or\n"
34"<N> to removed it. You may also press the <Space Bar> to cycle\n"
35"through the available options (ie. Y->N->M->Y).\n"
36"\n"
37"Some additional keyboard hints:\n"
38"\n"
39"Menus\n"
40"----------\n"
41"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
42" you wish to change use <Enter> or <Space>. Goto submenu by \n"
43" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
44" Submenus are designated by \"--->\".\n"
45"\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +030046" Searching: pressing '/' triggers interactive search mode.\n"
47" nconfig performs a case insensitive search for the string\n"
48" in the menu prompts (no regex support).\n"
49" Pressing the up/down keys highlights the previous/next\n"
50" matching item. Backspace removes one character from the\n"
51" match string. Pressing either '/' again or ESC exits\n"
52" search mode. All other keys behave normally.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020053"\n"
54" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
55" unseen options into view.\n"
56"\n"
57"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
58"\n"
59"o To get help with an item, press <F1>\n"
60" Shortcut: Press <h> or <?>.\n"
61"\n"
62"\n"
63"Radiolists (Choice lists)\n"
64"-----------\n"
65"o Use the cursor keys to select the option you wish to set and press\n"
66" <S> or the <SPACE BAR>.\n"
67"\n"
68" Shortcut: Press the first letter of the option you wish to set then\n"
69" press <S> or <SPACE BAR>.\n"
70"\n"
71"o To see available help for the item, press <F1>\n"
72" Shortcut: Press <H> or <?>.\n"
73"\n"
74"\n"
75"Data Entry\n"
76"-----------\n"
77"o Enter the requested information and press <ENTER>\n"
78" If you are entering hexadecimal values, it is not necessary to\n"
79" add the '0x' prefix to the entry.\n"
80"\n"
81"o For help, press <F1>.\n"
82"\n"
83"\n"
84"Text Box (Help Window)\n"
85"--------\n"
86"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
Benjamin Poirierd68e8182012-07-24 16:12:03 -040087" keys h,j,k,l function here as do <u>, <d> and <SPACE BAR> for\n"
88" those who are familiar with less and lynx.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020089"\n"
Benjamin Poirierd68e8182012-07-24 16:12:03 -040090"o Press <Enter>, <F1>, <F5>, <F9>, <q> or <Esc> to exit.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020091"\n"
92"\n"
93"Alternate Configuration Files\n"
94"-----------------------------\n"
95"nconfig supports the use of alternate configuration files for\n"
96"those who, for various reasons, find it necessary to switch\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -040097"between different configurations.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +020098"\n"
99"At the end of the main menu you will find two options. One is\n"
100"for saving the current configuration to a file of your choosing.\n"
101"The other option is for loading a previously saved alternate\n"
102"configuration.\n"
103"\n"
104"Even if you don't use alternate configuration files, but you\n"
105"find during a nconfig session that you have completely messed\n"
106"up your settings, you may use the \"Load Alternate...\" option to\n"
107"restore your previously saved settings from \".config\" without\n"
108"restarting nconfig.\n"
109"\n"
110"Other information\n"
111"-----------------\n"
112"If you use nconfig in an XTERM window make sure you have your\n"
113"$TERM variable set to point to a xterm definition which supports color.\n"
114"Otherwise, nconfig will look rather bad. nconfig will not\n"
115"display correctly in a RXVT window because rxvt displays only one\n"
116"intensity of color, bright.\n"
117"\n"
118"nconfig will display larger menus on screens or xterms which are\n"
119"set to display more than the standard 25 row by 80 column geometry.\n"
120"In order for this to work, the \"stty size\" command must be able to\n"
121"display the screen's current row and column geometry. I STRONGLY\n"
122"RECOMMEND that you make sure you do NOT have the shell variables\n"
123"LINES and COLUMNS exported into your environment. Some distributions\n"
124"export those variables via /etc/profile. Some ncurses programs can\n"
125"become confused when those variables (LINES & COLUMNS) don't reflect\n"
126"the true screen size.\n"
127"\n"
128"Optional personality available\n"
129"------------------------------\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400130"If you prefer to have all of the options listed in a single menu, rather\n"
131"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
132"environment variable set to single_menu. Example:\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200133"\n"
134"make NCONFIG_MODE=single_menu nconfig\n"
135"\n"
136"<Enter> will then unroll the appropriate category, or enfold it if it\n"
137"is already unrolled.\n"
138"\n"
139"Note that this mode can eventually be a little more CPU expensive\n"
140"(especially with a larger number of unrolled categories) than the\n"
141"default mode.\n"
142"\n"),
143menu_no_f_instructions[] = N_(
144" You do not have function keys support. Please follow the\n"
145" following instructions:\n"
146" Arrow keys navigate the menu.\n"
147" <Enter> or <right-arrow> selects submenus --->.\n"
148" Capital Letters are hotkeys.\n"
149" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300150" Pressing SpaceBar toggles between the above options.\n"
151" Press <Esc> or <left-arrow> to go back one menu,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200152" <?> or <h> for Help, </> for Search.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300153" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200154" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300155" <Esc> always leaves the current window.\n"),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200156menu_instructions[] = N_(
157" Arrow keys navigate the menu.\n"
158" <Enter> or <right-arrow> selects submenus --->.\n"
159" Capital Letters are hotkeys.\n"
160" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
161" Pressing SpaceBar toggles between the above options\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300162" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200163" <?>, <F1> or <h> for Help, </> for Search.\n"
Nir Tzachara72f3e22010-08-08 16:50:06 +0300164" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200165" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
166" <Esc> always leaves the current window\n"),
167radiolist_instructions[] = N_(
168" Use the arrow keys to navigate this window or\n"
169" press the hotkey of the item you wish to select\n"
170" followed by the <SPACE BAR>.\n"
171" Press <?>, <F1> or <h> for additional information about this option.\n"),
172inputbox_instructions_int[] = N_(
173"Please enter a decimal value.\n"
174"Fractions will not be accepted.\n"
175"Press <RETURN> to accept, <ESC> to cancel."),
176inputbox_instructions_hex[] = N_(
177"Please enter a hexadecimal value.\n"
178"Press <RETURN> to accept, <ESC> to cancel."),
179inputbox_instructions_string[] = N_(
180"Please enter a string value.\n"
181"Press <RETURN> to accept, <ESC> to cancel."),
182setmod_text[] = N_(
183"This feature depends on another which\n"
184"has been configured as a module.\n"
185"As a result, this feature will be built as a module."),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200186load_config_text[] = N_(
187"Enter the name of the configuration file you wish to load.\n"
188"Accept the name shown to restore the configuration you\n"
189"last retrieved. Leave blank to abort."),
190load_config_help[] = N_(
191"\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400192"For various reasons, one may wish to keep several different\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200193"configurations available on a single machine.\n"
194"\n"
195"If you have saved a previous configuration in a file other than the\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400196"default one, entering its name here will allow you to modify that\n"
197"configuration.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200198"\n"
199"If you are uncertain, then you have probably never used alternate\n"
200"configuration files. You should therefor leave this blank to abort.\n"),
201save_config_text[] = N_(
202"Enter a filename to which this configuration should be saved\n"
203"as an alternate. Leave blank to abort."),
204save_config_help[] = N_(
205"\n"
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400206"For various reasons, one may wish to keep different configurations\n"
207"available on a single machine.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200208"\n"
209"Entering a file name here will allow you to later retrieve, modify\n"
210"and use the current configuration as an alternate to whatever\n"
211"configuration options you have selected at that time.\n"
212"\n"
213"If you are uncertain what all this means then you should probably\n"
214"leave this blank.\n"),
215search_help[] = N_(
216"\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400217"Search for symbols and display their relations. Regular expressions\n"
218"are allowed.\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200219"Example: search for \"^FOO\"\n"
220"Result:\n"
221"-----------------------------------------------------------------\n"
222"Symbol: FOO [ = m]\n"
223"Prompt: Foo bus is used to drive the bar HW\n"
224"Defined at drivers/pci/Kconfig:47\n"
225"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
226"Location:\n"
Paul Gortmakerbb8187d2012-05-17 19:06:13 -0400227" -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200228" -> PCI support (PCI [ = y])\n"
229" -> PCI access mode (<choice> [ = y])\n"
230"Selects: LIBCRC32\n"
231"Selected by: BAR\n"
232"-----------------------------------------------------------------\n"
233"o The line 'Prompt:' shows the text used in the menu structure for\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400234" this symbol\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200235"o The 'Defined at' line tell at what file / line number the symbol\n"
236" is defined\n"
237"o The 'Depends on:' line tell what symbols needs to be defined for\n"
238" this symbol to be visible in the menu (selectable)\n"
239"o The 'Location:' lines tell where in the menu structure this symbol\n"
240" is located\n"
241" A location followed by a [ = y] indicate that this is a selectable\n"
242" menu item - and current value is displayed inside brackets.\n"
243"o The 'Selects:' line tell what symbol will be automatically\n"
244" selected if this symbol is selected (y or m)\n"
245"o The 'Selected by' line tell what symbol has selected this symbol\n"
246"\n"
247"Only relevant lines are shown.\n"
248"\n\n"
249"Search examples:\n"
Arnaud Lacombefe04ce02010-12-05 01:41:14 -0500250"Examples: USB => find all symbols containing USB\n"
Arnaud Lacombe59dfa242010-08-21 00:43:46 -0400251" ^USB => find all symbols starting with USB\n"
252" USB$ => find all symbols ending with USB\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200253"\n");
254
255struct mitem {
256 char str[256];
257 char tag;
258 void *usrptr;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200259 int is_visible;
260};
261
262#define MAX_MENU_ITEMS 4096
263static int show_all_items;
264static int indent;
265static struct menu *current_menu;
266static int child_count;
267static int single_menu_mode;
268/* the window in which all information appears */
269static WINDOW *main_window;
270/* the largest size of the menu window */
271static int mwin_max_lines;
272static int mwin_max_cols;
273/* the window in which we show option buttons */
274static MENU *curses_menu;
275static ITEM *curses_menu_items[MAX_MENU_ITEMS];
276static struct mitem k_menu_items[MAX_MENU_ITEMS];
277static int items_num;
278static int global_exit;
279/* the currently selected button */
280const char *current_instructions = menu_instructions;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200281
Cheng Renquan5ea9f642011-09-01 10:52:20 -0700282static char *dialog_input_result;
283static int dialog_input_result_len;
284
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200285static void conf(struct menu *menu);
286static void conf_choice(struct menu *menu);
287static void conf_string(struct menu *menu);
288static void conf_load(void);
289static void conf_save(void);
290static void show_help(struct menu *menu);
291static int do_exit(void);
292static void setup_windows(void);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300293static void search_conf(void);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200294
295typedef void (*function_key_handler_t)(int *key, struct menu *menu);
296static void handle_f1(int *key, struct menu *current_item);
297static void handle_f2(int *key, struct menu *current_item);
298static void handle_f3(int *key, struct menu *current_item);
299static void handle_f4(int *key, struct menu *current_item);
300static void handle_f5(int *key, struct menu *current_item);
301static void handle_f6(int *key, struct menu *current_item);
302static void handle_f7(int *key, struct menu *current_item);
303static void handle_f8(int *key, struct menu *current_item);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300304static void handle_f9(int *key, struct menu *current_item);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200305
306struct function_keys {
307 const char *key_str;
308 const char *func;
309 function_key key;
310 function_key_handler_t handler;
311};
312
Nir Tzachara72f3e22010-08-08 16:50:06 +0300313static const int function_keys_num = 9;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200314struct function_keys function_keys[] = {
315 {
316 .key_str = "F1",
317 .func = "Help",
318 .key = F_HELP,
319 .handler = handle_f1,
320 },
321 {
322 .key_str = "F2",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300323 .func = "Sym Info",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200324 .key = F_SYMBOL,
325 .handler = handle_f2,
326 },
327 {
328 .key_str = "F3",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300329 .func = "Insts",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200330 .key = F_INSTS,
331 .handler = handle_f3,
332 },
333 {
334 .key_str = "F4",
335 .func = "Config",
336 .key = F_CONF,
337 .handler = handle_f4,
338 },
339 {
340 .key_str = "F5",
341 .func = "Back",
342 .key = F_BACK,
343 .handler = handle_f5,
344 },
345 {
346 .key_str = "F6",
347 .func = "Save",
348 .key = F_SAVE,
349 .handler = handle_f6,
350 },
351 {
352 .key_str = "F7",
353 .func = "Load",
354 .key = F_LOAD,
355 .handler = handle_f7,
356 },
357 {
358 .key_str = "F8",
Nir Tzachara72f3e22010-08-08 16:50:06 +0300359 .func = "Sym Search",
360 .key = F_SEARCH,
361 .handler = handle_f8,
362 },
363 {
364 .key_str = "F9",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200365 .func = "Exit",
366 .key = F_EXIT,
Nir Tzachara72f3e22010-08-08 16:50:06 +0300367 .handler = handle_f9,
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200368 },
369};
370
371static void print_function_line(void)
372{
373 int i;
374 int offset = 1;
375 const int skip = 1;
376
377 for (i = 0; i < function_keys_num; i++) {
Stephen Boyd10175ba2011-04-06 15:07:49 -0700378 (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200379 mvwprintw(main_window, LINES-3, offset,
380 "%s",
381 function_keys[i].key_str);
Stephen Boyd10175ba2011-04-06 15:07:49 -0700382 (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200383 offset += strlen(function_keys[i].key_str);
384 mvwprintw(main_window, LINES-3,
385 offset, "%s",
386 function_keys[i].func);
387 offset += strlen(function_keys[i].func) + skip;
388 }
Stephen Boyd10175ba2011-04-06 15:07:49 -0700389 (void) wattrset(main_window, attributes[NORMAL]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200390}
391
392/* help */
393static void handle_f1(int *key, struct menu *current_item)
394{
395 show_scroll_win(main_window,
396 _("README"), _(nconf_readme));
397 return;
398}
399
400/* symbole help */
401static void handle_f2(int *key, struct menu *current_item)
402{
403 show_help(current_item);
404 return;
405}
406
407/* instructions */
408static void handle_f3(int *key, struct menu *current_item)
409{
410 show_scroll_win(main_window,
411 _("Instructions"),
412 _(current_instructions));
413 return;
414}
415
416/* config */
417static void handle_f4(int *key, struct menu *current_item)
418{
419 int res = btn_dialog(main_window,
420 _("Show all symbols?"),
421 2,
422 " <Show All> ",
423 "<Don't show all>");
424 if (res == 0)
425 show_all_items = 1;
426 else if (res == 1)
427 show_all_items = 0;
428
429 return;
430}
431
432/* back */
433static void handle_f5(int *key, struct menu *current_item)
434{
435 *key = KEY_LEFT;
436 return;
437}
438
439/* save */
440static void handle_f6(int *key, struct menu *current_item)
441{
442 conf_save();
443 return;
444}
445
446/* load */
447static void handle_f7(int *key, struct menu *current_item)
448{
449 conf_load();
450 return;
451}
452
Nir Tzachara72f3e22010-08-08 16:50:06 +0300453/* search */
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200454static void handle_f8(int *key, struct menu *current_item)
455{
Nir Tzachara72f3e22010-08-08 16:50:06 +0300456 search_conf();
457 return;
458}
459
460/* exit */
461static void handle_f9(int *key, struct menu *current_item)
462{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200463 do_exit();
464 return;
465}
466
467/* return != 0 to indicate the key was handles */
Michal Marek851190c2010-01-07 13:59:57 +0100468static int process_special_keys(int *key, struct menu *menu)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200469{
470 int i;
471
472 if (*key == KEY_RESIZE) {
473 setup_windows();
474 return 1;
475 }
476
477 for (i = 0; i < function_keys_num; i++) {
478 if (*key == KEY_F(function_keys[i].key) ||
479 *key == '0' + function_keys[i].key){
480 function_keys[i].handler(key, menu);
481 return 1;
482 }
483 }
484
485 return 0;
486}
487
488static void clean_items(void)
489{
490 int i;
491 for (i = 0; curses_menu_items[i]; i++)
492 free_item(curses_menu_items[i]);
493 bzero(curses_menu_items, sizeof(curses_menu_items));
494 bzero(k_menu_items, sizeof(k_menu_items));
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200495 items_num = 0;
496}
497
Nir Tzachara72f3e22010-08-08 16:50:06 +0300498typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
499 FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
500
501/* return the index of the matched item, or -1 if no such item exists */
502static int get_mext_match(const char *match_str, match_f flag)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200503{
Nir Tzachara72f3e22010-08-08 16:50:06 +0300504 int match_start = item_index(current_item(curses_menu));
505 int index;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200506
Nir Tzachara72f3e22010-08-08 16:50:06 +0300507 if (flag == FIND_NEXT_MATCH_DOWN)
508 ++match_start;
509 else if (flag == FIND_NEXT_MATCH_UP)
510 --match_start;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200511
Nir Tzachara72f3e22010-08-08 16:50:06 +0300512 index = match_start;
513 index = (index + items_num) % items_num;
514 while (true) {
515 char *str = k_menu_items[index].str;
516 if (strcasestr(str, match_str) != 0)
517 return index;
518 if (flag == FIND_NEXT_MATCH_UP ||
519 flag == MATCH_TINKER_PATTERN_UP)
520 --index;
521 else
522 ++index;
523 index = (index + items_num) % items_num;
524 if (index == match_start)
525 return -1;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200526 }
527}
528
Nir Tzachara72f3e22010-08-08 16:50:06 +0300529/* Make a new item. */
Michal Marek851190c2010-01-07 13:59:57 +0100530static void item_make(struct menu *menu, char tag, const char *fmt, ...)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200531{
532 va_list ap;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200533
534 if (items_num > MAX_MENU_ITEMS-1)
535 return;
536
537 bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
538 k_menu_items[items_num].tag = tag;
539 k_menu_items[items_num].usrptr = menu;
540 if (menu != NULL)
541 k_menu_items[items_num].is_visible =
542 menu_is_visible(menu);
543 else
544 k_menu_items[items_num].is_visible = 1;
545
546 va_start(ap, fmt);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300547 vsnprintf(k_menu_items[items_num].str,
548 sizeof(k_menu_items[items_num].str),
549 fmt, ap);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200550 va_end(ap);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300551
552 if (!k_menu_items[items_num].is_visible)
553 memcpy(k_menu_items[items_num].str, "XXX", 3);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200554
555 curses_menu_items[items_num] = new_item(
556 k_menu_items[items_num].str,
557 k_menu_items[items_num].str);
558 set_item_userptr(curses_menu_items[items_num],
559 &k_menu_items[items_num]);
560 /*
561 if (!k_menu_items[items_num].is_visible)
562 item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
563 */
564
565 items_num++;
566 curses_menu_items[items_num] = NULL;
567}
568
569/* very hackish. adds a string to the last item added */
Michal Marek851190c2010-01-07 13:59:57 +0100570static void item_add_str(const char *fmt, ...)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200571{
572 va_list ap;
573 int index = items_num-1;
574 char new_str[256];
575 char tmp_str[256];
576
577 if (index < 0)
578 return;
579
580 va_start(ap, fmt);
581 vsnprintf(new_str, sizeof(new_str), fmt, ap);
582 va_end(ap);
583 snprintf(tmp_str, sizeof(tmp_str), "%s%s",
584 k_menu_items[index].str, new_str);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300585 strncpy(k_menu_items[index].str,
586 tmp_str,
587 sizeof(k_menu_items[index].str));
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200588
589 free_item(curses_menu_items[index]);
590 curses_menu_items[index] = new_item(
591 k_menu_items[index].str,
592 k_menu_items[index].str);
593 set_item_userptr(curses_menu_items[index],
594 &k_menu_items[index]);
595}
596
597/* get the tag of the currently selected item */
Michal Marek851190c2010-01-07 13:59:57 +0100598static char item_tag(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200599{
600 ITEM *cur;
601 struct mitem *mcur;
602
603 cur = current_item(curses_menu);
604 if (cur == NULL)
605 return 0;
606 mcur = (struct mitem *) item_userptr(cur);
607 return mcur->tag;
608}
609
Michal Marek851190c2010-01-07 13:59:57 +0100610static int curses_item_index(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200611{
612 return item_index(current_item(curses_menu));
613}
614
Michal Marek851190c2010-01-07 13:59:57 +0100615static void *item_data(void)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200616{
617 ITEM *cur;
618 struct mitem *mcur;
619
620 cur = current_item(curses_menu);
Andrej Gelenberg866af402010-08-02 11:59:31 +0200621 if (!cur)
622 return NULL;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200623 mcur = (struct mitem *) item_userptr(cur);
624 return mcur->usrptr;
625
626}
627
Michal Marek851190c2010-01-07 13:59:57 +0100628static int item_is_tag(char tag)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200629{
630 return item_tag() == tag;
631}
632
633static char filename[PATH_MAX+1];
634static char menu_backtitle[PATH_MAX+128];
Michal Marek851190c2010-01-07 13:59:57 +0100635static const char *set_config_filename(const char *config_filename)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200636{
637 int size;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200638
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200639 size = snprintf(menu_backtitle, sizeof(menu_backtitle),
Arnaud Lacombe09548282010-08-18 01:57:13 -0400640 "%s - %s", config_filename, rootmenu.prompt->text);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200641 if (size >= sizeof(menu_backtitle))
642 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
643
644 size = snprintf(filename, sizeof(filename), "%s", config_filename);
645 if (size >= sizeof(filename))
646 filename[sizeof(filename)-1] = '\0';
647 return menu_backtitle;
648}
649
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200650/* return = 0 means we are successful.
651 * -1 means go on doing what you were doing
652 */
653static int do_exit(void)
654{
655 int res;
656 if (!conf_get_changed()) {
657 global_exit = 1;
658 return 0;
659 }
660 res = btn_dialog(main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400661 _("Do you wish to save your new configuration?\n"
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200662 "<ESC> to cancel and resume nconfig."),
663 2,
664 " <save> ",
665 "<don't save>");
666 if (res == KEY_EXIT) {
667 global_exit = 0;
668 return -1;
669 }
670
671 /* if we got here, the user really wants to exit */
672 switch (res) {
673 case 0:
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200674 res = conf_write(filename);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200675 if (res)
676 btn_dialog(
677 main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400678 _("Error during writing of configuration.\n"
679 "Your configuration changes were NOT saved."),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200680 1,
681 "<OK>");
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200682 break;
683 default:
684 btn_dialog(
685 main_window,
Arnaud Lacombe652cf982010-08-14 23:51:40 -0400686 _("Your configuration changes were NOT saved."),
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200687 1,
688 "<OK>");
689 break;
690 }
691 global_exit = 1;
692 return 0;
693}
694
695
696static void search_conf(void)
697{
698 struct symbol **sym_arr;
699 struct gstr res;
Yann E. MORIN337a2752012-10-20 01:06:23 +0200700 struct gstr title;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200701 char *dialog_input;
702 int dres;
Yann E. MORIN337a2752012-10-20 01:06:23 +0200703
704 title = str_new();
705 str_printf( &title, _("Enter %s (sub)string to search for "
706 "(with or without \"%s\")"), CONFIG_, CONFIG_);
707
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200708again:
709 dres = dialog_inputbox(main_window,
710 _("Search Configuration Parameter"),
Yann E. MORIN337a2752012-10-20 01:06:23 +0200711 str_get(&title),
Cheng Renquan5ea9f642011-09-01 10:52:20 -0700712 "", &dialog_input_result, &dialog_input_result_len);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200713 switch (dres) {
714 case 0:
715 break;
716 case 1:
717 show_scroll_win(main_window,
718 _("Search Configuration"), search_help);
719 goto again;
720 default:
Yann E. MORIN337a2752012-10-20 01:06:23 +0200721 str_free(&title);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200722 return;
723 }
724
Arnaud Lacombeffb59572010-08-14 23:57:43 -0400725 /* strip the prefix if necessary */
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200726 dialog_input = dialog_input_result;
Arnaud Lacombeffb59572010-08-14 23:57:43 -0400727 if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
728 dialog_input += strlen(CONFIG_);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200729
730 sym_arr = sym_re_search(dialog_input);
Benjamin Poirier5e609ad2012-08-23 14:55:06 -0400731 res = get_relations_str(sym_arr, NULL);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200732 free(sym_arr);
733 show_scroll_win(main_window,
734 _("Search Results"), str_get(&res));
735 str_free(&res);
Yann E. MORIN337a2752012-10-20 01:06:23 +0200736 str_free(&title);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200737}
738
739
740static void build_conf(struct menu *menu)
741{
742 struct symbol *sym;
743 struct property *prop;
744 struct menu *child;
745 int type, tmp, doint = 2;
746 tristate val;
747 char ch;
748
749 if (!menu || (!show_all_items && !menu_is_visible(menu)))
750 return;
751
752 sym = menu->sym;
753 prop = menu->prompt;
754 if (!sym) {
755 if (prop && menu != current_menu) {
756 const char *prompt = menu_get_prompt(menu);
757 enum prop_type ptype;
758 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
759 switch (ptype) {
760 case P_MENU:
761 child_count++;
762 prompt = _(prompt);
763 if (single_menu_mode) {
764 item_make(menu, 'm',
765 "%s%*c%s",
766 menu->data ? "-->" : "++>",
767 indent + 1, ' ', prompt);
768 } else
769 item_make(menu, 'm',
770 " %*c%s --->",
771 indent + 1,
772 ' ', prompt);
773
774 if (single_menu_mode && menu->data)
775 goto conf_childs;
776 return;
777 case P_COMMENT:
778 if (prompt) {
779 child_count++;
780 item_make(menu, ':',
781 " %*c*** %s ***",
782 indent + 1, ' ',
783 _(prompt));
784 }
785 break;
786 default:
787 if (prompt) {
788 child_count++;
789 item_make(menu, ':', "---%*c%s",
790 indent + 1, ' ',
791 _(prompt));
792 }
793 }
794 } else
795 doint = 0;
796 goto conf_childs;
797 }
798
799 type = sym_get_type(sym);
800 if (sym_is_choice(sym)) {
801 struct symbol *def_sym = sym_get_choice_value(sym);
802 struct menu *def_menu = NULL;
803
804 child_count++;
805 for (child = menu->list; child; child = child->next) {
806 if (menu_is_visible(child) && child->sym == def_sym)
807 def_menu = child;
808 }
809
810 val = sym_get_tristate_value(sym);
811 if (sym_is_changable(sym)) {
812 switch (type) {
813 case S_BOOLEAN:
814 item_make(menu, 't', "[%c]",
815 val == no ? ' ' : '*');
816 break;
817 case S_TRISTATE:
818 switch (val) {
819 case yes:
820 ch = '*';
821 break;
822 case mod:
823 ch = 'M';
824 break;
825 default:
826 ch = ' ';
827 break;
828 }
829 item_make(menu, 't', "<%c>", ch);
830 break;
831 }
832 } else {
833 item_make(menu, def_menu ? 't' : ':', " ");
834 }
835
836 item_add_str("%*c%s", indent + 1,
837 ' ', _(menu_get_prompt(menu)));
838 if (val == yes) {
839 if (def_menu) {
840 item_add_str(" (%s)",
841 _(menu_get_prompt(def_menu)));
842 item_add_str(" --->");
843 if (def_menu->list) {
844 indent += 2;
845 build_conf(def_menu);
846 indent -= 2;
847 }
848 }
849 return;
850 }
851 } else {
852 if (menu == current_menu) {
853 item_make(menu, ':',
854 "---%*c%s", indent + 1,
855 ' ', _(menu_get_prompt(menu)));
856 goto conf_childs;
857 }
858 child_count++;
859 val = sym_get_tristate_value(sym);
860 if (sym_is_choice_value(sym) && val == yes) {
861 item_make(menu, ':', " ");
862 } else {
863 switch (type) {
864 case S_BOOLEAN:
865 if (sym_is_changable(sym))
866 item_make(menu, 't', "[%c]",
867 val == no ? ' ' : '*');
868 else
869 item_make(menu, 't', "-%c-",
870 val == no ? ' ' : '*');
871 break;
872 case S_TRISTATE:
873 switch (val) {
874 case yes:
875 ch = '*';
876 break;
877 case mod:
878 ch = 'M';
879 break;
880 default:
881 ch = ' ';
882 break;
883 }
884 if (sym_is_changable(sym)) {
885 if (sym->rev_dep.tri == mod)
886 item_make(menu,
887 't', "{%c}", ch);
888 else
889 item_make(menu,
890 't', "<%c>", ch);
891 } else
892 item_make(menu, 't', "-%c-", ch);
893 break;
894 default:
895 tmp = 2 + strlen(sym_get_string_value(sym));
Nir Tzachar68c16ed2010-01-13 07:32:35 +0200896 item_make(menu, 's', " (%s)",
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200897 sym_get_string_value(sym));
898 tmp = indent - tmp + 4;
899 if (tmp < 0)
900 tmp = 0;
901 item_add_str("%*c%s%s", tmp, ' ',
902 _(menu_get_prompt(menu)),
903 (sym_has_value(sym) ||
904 !sym_is_changable(sym)) ? "" :
905 _(" (NEW)"));
906 goto conf_childs;
907 }
908 }
909 item_add_str("%*c%s%s", indent + 1, ' ',
910 _(menu_get_prompt(menu)),
911 (sym_has_value(sym) || !sym_is_changable(sym)) ?
912 "" : _(" (NEW)"));
913 if (menu->prompt && menu->prompt->type == P_MENU) {
914 item_add_str(" --->");
915 return;
916 }
917 }
918
919conf_childs:
920 indent += doint;
921 for (child = menu->list; child; child = child->next)
922 build_conf(child);
923 indent -= doint;
924}
925
926static void reset_menu(void)
927{
928 unpost_menu(curses_menu);
929 clean_items();
930}
931
932/* adjust the menu to show this item.
933 * prefer not to scroll the menu if possible*/
934static void center_item(int selected_index, int *last_top_row)
935{
936 int toprow;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200937
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200938 set_top_row(curses_menu, *last_top_row);
939 toprow = top_row(curses_menu);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300940 if (selected_index < toprow ||
941 selected_index >= toprow+mwin_max_lines) {
942 toprow = max(selected_index-mwin_max_lines/2, 0);
943 if (toprow >= item_count(curses_menu)-mwin_max_lines)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200944 toprow = item_count(curses_menu)-mwin_max_lines;
945 set_top_row(curses_menu, toprow);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200946 }
Nir Tzachara72f3e22010-08-08 16:50:06 +0300947 set_current_item(curses_menu,
948 curses_menu_items[selected_index]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200949 *last_top_row = toprow;
950 post_menu(curses_menu);
951 refresh_all_windows(main_window);
952}
953
954/* this function assumes reset_menu has been called before */
955static void show_menu(const char *prompt, const char *instructions,
956 int selected_index, int *last_top_row)
957{
958 int maxx, maxy;
959 WINDOW *menu_window;
960
961 current_instructions = instructions;
962
963 clear();
Stephen Boyd10175ba2011-04-06 15:07:49 -0700964 (void) wattrset(main_window, attributes[NORMAL]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200965 print_in_middle(stdscr, 1, 0, COLS,
966 menu_backtitle,
967 attributes[MAIN_HEADING]);
968
Stephen Boyd10175ba2011-04-06 15:07:49 -0700969 (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200970 box(main_window, 0, 0);
Stephen Boyd10175ba2011-04-06 15:07:49 -0700971 (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200972 mvwprintw(main_window, 0, 3, " %s ", prompt);
Stephen Boyd10175ba2011-04-06 15:07:49 -0700973 (void) wattrset(main_window, attributes[NORMAL]);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200974
975 set_menu_items(curses_menu, curses_menu_items);
976
977 /* position the menu at the middle of the screen */
978 scale_menu(curses_menu, &maxy, &maxx);
Nir Tzachar68c16ed2010-01-13 07:32:35 +0200979 maxx = min(maxx, mwin_max_cols-2);
Nir Tzachara72f3e22010-08-08 16:50:06 +0300980 maxy = mwin_max_lines;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +0200981 menu_window = derwin(main_window,
982 maxy,
983 maxx,
984 2,
985 (mwin_max_cols-maxx)/2);
986 keypad(menu_window, TRUE);
987 set_menu_win(curses_menu, menu_window);
988 set_menu_sub(curses_menu, menu_window);
989
990 /* must reassert this after changing items, otherwise returns to a
991 * default of 16
992 */
993 set_menu_format(curses_menu, maxy, 1);
994 center_item(selected_index, last_top_row);
995 set_menu_format(curses_menu, maxy, 1);
996
997 print_function_line();
998
999 /* Post the menu */
1000 post_menu(curses_menu);
1001 refresh_all_windows(main_window);
1002}
1003
Nir Tzachara72f3e22010-08-08 16:50:06 +03001004static void adj_match_dir(match_f *match_direction)
1005{
1006 if (*match_direction == FIND_NEXT_MATCH_DOWN)
1007 *match_direction =
1008 MATCH_TINKER_PATTERN_DOWN;
1009 else if (*match_direction == FIND_NEXT_MATCH_UP)
1010 *match_direction =
1011 MATCH_TINKER_PATTERN_UP;
1012 /* else, do no change.. */
1013}
1014
1015struct match_state
1016{
1017 int in_search;
1018 match_f match_direction;
1019 char pattern[256];
1020};
1021
1022/* Return 0 means I have handled the key. In such a case, ans should hold the
1023 * item to center, or -1 otherwise.
1024 * Else return -1 .
1025 */
1026static int do_match(int key, struct match_state *state, int *ans)
1027{
1028 char c = (char) key;
1029 int terminate_search = 0;
1030 *ans = -1;
1031 if (key == '/' || (state->in_search && key == 27)) {
1032 move(0, 0);
1033 refresh();
1034 clrtoeol();
1035 state->in_search = 1-state->in_search;
1036 bzero(state->pattern, sizeof(state->pattern));
1037 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1038 return 0;
1039 } else if (!state->in_search)
1040 return 1;
1041
1042 if (isalnum(c) || isgraph(c) || c == ' ') {
1043 state->pattern[strlen(state->pattern)] = c;
1044 state->pattern[strlen(state->pattern)] = '\0';
1045 adj_match_dir(&state->match_direction);
1046 *ans = get_mext_match(state->pattern,
1047 state->match_direction);
1048 } else if (key == KEY_DOWN) {
1049 state->match_direction = FIND_NEXT_MATCH_DOWN;
1050 *ans = get_mext_match(state->pattern,
1051 state->match_direction);
1052 } else if (key == KEY_UP) {
1053 state->match_direction = FIND_NEXT_MATCH_UP;
1054 *ans = get_mext_match(state->pattern,
1055 state->match_direction);
1056 } else if (key == KEY_BACKSPACE || key == 127) {
1057 state->pattern[strlen(state->pattern)-1] = '\0';
1058 adj_match_dir(&state->match_direction);
1059 } else
1060 terminate_search = 1;
1061
1062 if (terminate_search) {
1063 state->in_search = 0;
1064 bzero(state->pattern, sizeof(state->pattern));
1065 move(0, 0);
1066 refresh();
1067 clrtoeol();
1068 return -1;
1069 }
1070 return 0;
1071}
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001072
1073static void conf(struct menu *menu)
1074{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001075 struct menu *submenu = 0;
1076 const char *prompt = menu_get_prompt(menu);
1077 struct symbol *sym;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001078 int res;
1079 int current_index = 0;
1080 int last_top_row = 0;
Nir Tzachara72f3e22010-08-08 16:50:06 +03001081 struct match_state match_state = {
1082 .in_search = 0,
1083 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1084 .pattern = "",
1085 };
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001086
1087 while (!global_exit) {
1088 reset_menu();
1089 current_menu = menu;
1090 build_conf(menu);
1091 if (!child_count)
1092 break;
1093
1094 show_menu(prompt ? _(prompt) : _("Main Menu"),
1095 _(menu_instructions),
1096 current_index, &last_top_row);
1097 keypad((menu_win(curses_menu)), TRUE);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001098 while (!global_exit) {
1099 if (match_state.in_search) {
1100 mvprintw(0, 0,
1101 "searching: %s", match_state.pattern);
1102 clrtoeol();
1103 }
1104 refresh_all_windows(main_window);
1105 res = wgetch(menu_win(curses_menu));
1106 if (!res)
1107 break;
1108 if (do_match(res, &match_state, &current_index) == 0) {
1109 if (current_index != -1)
1110 center_item(current_index,
1111 &last_top_row);
1112 continue;
1113 }
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001114 if (process_special_keys(&res,
1115 (struct menu *) item_data()))
1116 break;
1117 switch (res) {
1118 case KEY_DOWN:
1119 menu_driver(curses_menu, REQ_DOWN_ITEM);
1120 break;
1121 case KEY_UP:
1122 menu_driver(curses_menu, REQ_UP_ITEM);
1123 break;
1124 case KEY_NPAGE:
1125 menu_driver(curses_menu, REQ_SCR_DPAGE);
1126 break;
1127 case KEY_PPAGE:
1128 menu_driver(curses_menu, REQ_SCR_UPAGE);
1129 break;
1130 case KEY_HOME:
1131 menu_driver(curses_menu, REQ_FIRST_ITEM);
1132 break;
1133 case KEY_END:
1134 menu_driver(curses_menu, REQ_LAST_ITEM);
1135 break;
1136 case 'h':
1137 case '?':
1138 show_help((struct menu *) item_data());
1139 break;
1140 }
1141 if (res == 10 || res == 27 ||
1142 res == 32 || res == 'n' || res == 'y' ||
1143 res == KEY_LEFT || res == KEY_RIGHT ||
Nir Tzachara72f3e22010-08-08 16:50:06 +03001144 res == 'm')
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001145 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001146 refresh_all_windows(main_window);
1147 }
1148
1149 refresh_all_windows(main_window);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001150 /* if ESC or left*/
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001151 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1152 break;
1153
1154 /* remember location in the menu */
1155 last_top_row = top_row(curses_menu);
1156 current_index = curses_item_index();
1157
1158 if (!item_tag())
1159 continue;
1160
1161 submenu = (struct menu *) item_data();
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001162 if (!submenu || !menu_is_visible(submenu))
1163 continue;
Arnaud Lacombea1e80652011-07-10 03:27:33 -04001164 sym = submenu->sym;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001165
1166 switch (res) {
1167 case ' ':
1168 if (item_is_tag('t'))
1169 sym_toggle_tristate_value(sym);
1170 else if (item_is_tag('m'))
1171 conf(submenu);
1172 break;
1173 case KEY_RIGHT:
1174 case 10: /* ENTER WAS PRESSED */
1175 switch (item_tag()) {
1176 case 'm':
1177 if (single_menu_mode)
1178 submenu->data =
1179 (void *) (long) !submenu->data;
1180 else
1181 conf(submenu);
1182 break;
1183 case 't':
1184 if (sym_is_choice(sym) &&
1185 sym_get_tristate_value(sym) == yes)
1186 conf_choice(submenu);
1187 else if (submenu->prompt &&
1188 submenu->prompt->type == P_MENU)
1189 conf(submenu);
1190 else if (res == 10)
1191 sym_toggle_tristate_value(sym);
1192 break;
1193 case 's':
1194 conf_string(submenu);
1195 break;
1196 }
1197 break;
1198 case 'y':
1199 if (item_is_tag('t')) {
1200 if (sym_set_tristate_value(sym, yes))
1201 break;
1202 if (sym_set_tristate_value(sym, mod))
1203 btn_dialog(main_window, setmod_text, 0);
1204 }
1205 break;
1206 case 'n':
1207 if (item_is_tag('t'))
1208 sym_set_tristate_value(sym, no);
1209 break;
1210 case 'm':
1211 if (item_is_tag('t'))
1212 sym_set_tristate_value(sym, mod);
1213 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001214 }
1215 }
1216}
1217
Michal Marek42368c32010-08-17 10:21:19 +02001218static void conf_message_callback(const char *fmt, va_list ap)
1219{
1220 char buf[1024];
1221
1222 vsnprintf(buf, sizeof(buf), fmt, ap);
1223 btn_dialog(main_window, buf, 1, "<OK>");
1224}
1225
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001226static void show_help(struct menu *menu)
1227{
Arnaud Lacombef98ee762011-07-10 03:27:05 -04001228 struct gstr help;
1229
1230 if (!menu)
1231 return;
1232
1233 help = str_new();
Arnaud Lacombe54168572011-07-10 03:27:04 -04001234 menu_get_ext_help(menu, &help);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001235 show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1236 str_free(&help);
1237}
1238
1239static void conf_choice(struct menu *menu)
1240{
1241 const char *prompt = _(menu_get_prompt(menu));
1242 struct menu *child = 0;
1243 struct symbol *active;
1244 int selected_index = 0;
1245 int last_top_row = 0;
1246 int res, i = 0;
Nir Tzachara72f3e22010-08-08 16:50:06 +03001247 struct match_state match_state = {
1248 .in_search = 0,
1249 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1250 .pattern = "",
1251 };
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001252
1253 active = sym_get_choice_value(menu->sym);
1254 /* this is mostly duplicated from the conf() function. */
1255 while (!global_exit) {
1256 reset_menu();
1257
1258 for (i = 0, child = menu->list; child; child = child->next) {
1259 if (!show_all_items && !menu_is_visible(child))
1260 continue;
1261
1262 if (child->sym == sym_get_choice_value(menu->sym))
1263 item_make(child, ':', "<X> %s",
1264 _(menu_get_prompt(child)));
Peter Korsgaard39177ec2011-01-06 16:42:45 +01001265 else if (child->sym)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001266 item_make(child, ':', " %s",
1267 _(menu_get_prompt(child)));
Peter Korsgaard39177ec2011-01-06 16:42:45 +01001268 else
1269 item_make(child, ':', "*** %s ***",
1270 _(menu_get_prompt(child)));
1271
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001272 if (child->sym == active){
1273 last_top_row = top_row(curses_menu);
1274 selected_index = i;
1275 }
1276 i++;
1277 }
1278 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1279 _(radiolist_instructions),
1280 selected_index,
1281 &last_top_row);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001282 while (!global_exit) {
1283 if (match_state.in_search) {
1284 mvprintw(0, 0, "searching: %s",
1285 match_state.pattern);
1286 clrtoeol();
1287 }
1288 refresh_all_windows(main_window);
1289 res = wgetch(menu_win(curses_menu));
1290 if (!res)
1291 break;
1292 if (do_match(res, &match_state, &selected_index) == 0) {
1293 if (selected_index != -1)
1294 center_item(selected_index,
1295 &last_top_row);
1296 continue;
1297 }
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001298 if (process_special_keys(
1299 &res,
1300 (struct menu *) item_data()))
1301 break;
1302 switch (res) {
1303 case KEY_DOWN:
1304 menu_driver(curses_menu, REQ_DOWN_ITEM);
1305 break;
1306 case KEY_UP:
1307 menu_driver(curses_menu, REQ_UP_ITEM);
1308 break;
1309 case KEY_NPAGE:
1310 menu_driver(curses_menu, REQ_SCR_DPAGE);
1311 break;
1312 case KEY_PPAGE:
1313 menu_driver(curses_menu, REQ_SCR_UPAGE);
1314 break;
1315 case KEY_HOME:
1316 menu_driver(curses_menu, REQ_FIRST_ITEM);
1317 break;
1318 case KEY_END:
1319 menu_driver(curses_menu, REQ_LAST_ITEM);
1320 break;
1321 case 'h':
1322 case '?':
1323 show_help((struct menu *) item_data());
1324 break;
1325 }
1326 if (res == 10 || res == 27 || res == ' ' ||
Nir Tzachara72f3e22010-08-08 16:50:06 +03001327 res == KEY_LEFT){
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001328 break;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001329 }
1330 refresh_all_windows(main_window);
1331 }
1332 /* if ESC or left */
1333 if (res == 27 || res == KEY_LEFT)
1334 break;
1335
1336 child = item_data();
Peter Korsgaard39177ec2011-01-06 16:42:45 +01001337 if (!child || !menu_is_visible(child) || !child->sym)
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001338 continue;
1339 switch (res) {
1340 case ' ':
1341 case 10:
1342 case KEY_RIGHT:
1343 sym_set_tristate_value(child->sym, yes);
1344 return;
1345 case 'h':
1346 case '?':
1347 show_help(child);
1348 active = child->sym;
1349 break;
1350 case KEY_EXIT:
1351 return;
1352 }
1353 }
1354}
1355
1356static void conf_string(struct menu *menu)
1357{
1358 const char *prompt = menu_get_prompt(menu);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001359
1360 while (1) {
1361 int res;
1362 const char *heading;
1363
1364 switch (sym_get_type(menu->sym)) {
1365 case S_INT:
1366 heading = _(inputbox_instructions_int);
1367 break;
1368 case S_HEX:
1369 heading = _(inputbox_instructions_hex);
1370 break;
1371 case S_STRING:
1372 heading = _(inputbox_instructions_string);
1373 break;
1374 default:
1375 heading = _("Internal nconf error!");
1376 }
1377 res = dialog_inputbox(main_window,
1378 prompt ? _(prompt) : _("Main Menu"),
1379 heading,
1380 sym_get_string_value(menu->sym),
Cheng Renquan5ea9f642011-09-01 10:52:20 -07001381 &dialog_input_result,
1382 &dialog_input_result_len);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001383 switch (res) {
1384 case 0:
1385 if (sym_set_string_value(menu->sym,
1386 dialog_input_result))
1387 return;
1388 btn_dialog(main_window,
1389 _("You have made an invalid entry."), 0);
1390 break;
1391 case 1:
1392 show_help(menu);
1393 break;
1394 case KEY_EXIT:
1395 return;
1396 }
1397 }
1398}
1399
1400static void conf_load(void)
1401{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001402 while (1) {
1403 int res;
1404 res = dialog_inputbox(main_window,
1405 NULL, load_config_text,
1406 filename,
Cheng Renquan5ea9f642011-09-01 10:52:20 -07001407 &dialog_input_result,
1408 &dialog_input_result_len);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001409 switch (res) {
1410 case 0:
1411 if (!dialog_input_result[0])
1412 return;
1413 if (!conf_read(dialog_input_result)) {
1414 set_config_filename(dialog_input_result);
1415 sym_set_change_count(1);
1416 return;
1417 }
1418 btn_dialog(main_window, _("File does not exist!"), 0);
1419 break;
1420 case 1:
1421 show_scroll_win(main_window,
1422 _("Load Alternate Configuration"),
1423 load_config_help);
1424 break;
1425 case KEY_EXIT:
1426 return;
1427 }
1428 }
1429}
1430
1431static void conf_save(void)
1432{
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001433 while (1) {
1434 int res;
1435 res = dialog_inputbox(main_window,
1436 NULL, save_config_text,
1437 filename,
Cheng Renquan5ea9f642011-09-01 10:52:20 -07001438 &dialog_input_result,
1439 &dialog_input_result_len);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001440 switch (res) {
1441 case 0:
1442 if (!dialog_input_result[0])
1443 return;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001444 res = conf_write(dialog_input_result);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001445 if (!res) {
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001446 set_config_filename(dialog_input_result);
1447 return;
1448 }
1449 btn_dialog(main_window, _("Can't create file! "
1450 "Probably a nonexistent directory."),
1451 1, "<OK>");
1452 break;
1453 case 1:
1454 show_scroll_win(main_window,
1455 _("Save Alternate Configuration"),
1456 save_config_help);
1457 break;
1458 case KEY_EXIT:
1459 return;
1460 }
1461 }
1462}
1463
1464void setup_windows(void)
1465{
1466 if (main_window != NULL)
1467 delwin(main_window);
1468
1469 /* set up the menu and menu window */
1470 main_window = newwin(LINES-2, COLS-2, 2, 1);
1471 keypad(main_window, TRUE);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001472 mwin_max_lines = LINES-7;
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001473 mwin_max_cols = COLS-6;
1474
1475 /* panels order is from bottom to top */
1476 new_panel(main_window);
1477}
1478
1479int main(int ac, char **av)
1480{
1481 char *mode;
1482
1483 setlocale(LC_ALL, "");
1484 bindtextdomain(PACKAGE, LOCALEDIR);
1485 textdomain(PACKAGE);
1486
1487 conf_parse(av[1]);
1488 conf_read(NULL);
1489
1490 mode = getenv("NCONFIG_MODE");
1491 if (mode) {
1492 if (!strcasecmp(mode, "single_menu"))
1493 single_menu_mode = 1;
1494 }
1495
1496 /* Initialize curses */
1497 initscr();
1498 /* set color theme */
1499 set_colors();
1500
1501 cbreak();
1502 noecho();
1503 keypad(stdscr, TRUE);
1504 curs_set(0);
1505
1506 if (COLS < 75 || LINES < 20) {
1507 endwin();
1508 printf("Your terminal should have at "
1509 "least 20 lines and 75 columns\n");
1510 return 1;
1511 }
1512
1513 notimeout(stdscr, FALSE);
Yaakov Selkowitzd7c67a22012-06-11 19:29:41 -05001514#if NCURSES_REENTRANT
1515 set_escdelay(1);
1516#else
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001517 ESCDELAY = 1;
Yaakov Selkowitzd7c67a22012-06-11 19:29:41 -05001518#endif
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001519
1520 /* set btns menu */
1521 curses_menu = new_menu(curses_menu_items);
1522 menu_opts_off(curses_menu, O_SHOWDESC);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001523 menu_opts_on(curses_menu, O_SHOWMATCH);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001524 menu_opts_on(curses_menu, O_ONEVALUE);
1525 menu_opts_on(curses_menu, O_NONCYCLIC);
Nir Tzachara72f3e22010-08-08 16:50:06 +03001526 menu_opts_on(curses_menu, O_IGNORECASE);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001527 set_menu_mark(curses_menu, " ");
1528 set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1529 set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1530 set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1531
1532 set_config_filename(conf_get_configname());
1533 setup_windows();
1534
1535 /* check for KEY_FUNC(1) */
1536 if (has_key(KEY_F(1)) == FALSE) {
1537 show_scroll_win(main_window,
1538 _("Instructions"),
1539 _(menu_no_f_instructions));
1540 }
1541
Michal Marek42368c32010-08-17 10:21:19 +02001542 conf_set_message_callback(conf_message_callback);
nir.tzachar@gmail.com692d97c2009-11-25 12:28:43 +02001543 /* do the work */
1544 while (!global_exit) {
1545 conf(&rootmenu);
1546 if (!global_exit && do_exit() == 0)
1547 break;
1548 }
1549 /* ok, we are done */
1550 unpost_menu(curses_menu);
1551 free_menu(curses_menu);
1552 delwin(main_window);
1553 clear();
1554 refresh();
1555 endwin();
1556 return 0;
1557}
1558