History

kconfig: new configuration interface (nconfig)

This patch was inspired by the kernel projects page, where an ncurses replacement for menuconfig was mentioned (by Sam Ravnborg). Building on menuconfig, this patch implements a more modern look interface using ncurses and ncurses' satellite libraries (menu, panel, form). The implementation does not depend on lxdialog, which is currently distributed with the kernel.

nir.tzachar@gmail.com committed 16 years ago

Commit 692d97c1 parent c64152b10 files · +2314 −20Browse files

Showing the changes to scripts (10 of 10 files). Show all

Unified · Split

10 files
  1. scripts/kconfig/Makefile +14 −2
  2. scripts/kconfig/lkc.h +1 −1
  3. scripts/kconfig/lkc_proto.h +2 −1
  4. scripts/kconfig/mconf.c +0 −13
  5. scripts/kconfig/menu.c +15 −1
  6. scripts/kconfig/nconf.c +1568 −0
  7. scripts/kconfig/nconf.gui.c +617 −0
  8. scripts/kconfig/nconf.h +95 −0
  9. scripts/kconfig/zconf.tab.c_shipped +1 −1
  10. scripts/kconfig/zconf.y +1 −1
scripts/kconfig/Makefile+14−2
@@ -23,6 +23,9 @@ menuconfig: $(obj)/mconf · 22 unmodified lines
2323 config: $(obj)/conf
2424 $< $(Kconfig)
2525
26+nconfig: $(obj)/nconf
27+ $< $(Kconfig)
28+
2629 oldconfig: $(obj)/conf
2730 $< -o $(Kconfig)
2831
@@ -110,6 +113,7 @@ endif · 81 unmodified lines
110113 # Help text used by make help
111114 help:
112115 @echo ' config - Update current config utilising a line-oriented program'
116+ @echo ' nconfig - Update current config utilising a ncurses menu based program'
113117 @echo ' menuconfig - Update current config utilising a menu based program'
114118 @echo ' xconfig - Update current config utilising a QT based front-end'
115119 @echo ' gconfig - Update current config utilising a GTK based front-end'
@@ -137,6 +141,8 @@ HOST_EXTRACFLAGS += -DLOCALE · 21 unmodified lines
137141 # ===========================================================================
138142 # Shared Makefile for the various kconfig executables:
139143 # conf: Used for defconfig, oldconfig and related targets
144+# nconf: Used for the nconfig target.
145+# Utilizes ncurses
140146 # mconf: Used for the menuconfig target
141147 # Utilizes the lxdialog package
142148 # qconf: Used for the xconfig target
@@ -149,11 +155,16 @@ lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o · 6 unmodified lines
149155 lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
150156
151157 conf-objs := conf.o zconf.tab.o
152−mconf-objs := mconf.o zconf.tab.o $(lxdialog)
158+mconf-objs := mconf.o zconf.tab.o $(lxdialog)
159+nconf-objs := nconf.o zconf.tab.o nconf.gui.o
153160 kxgettext-objs := kxgettext.o zconf.tab.o
154161
155162 hostprogs-y := conf qconf gconf kxgettext
156163
164+ifeq ($(MAKECMDGOALS),nconfig)
165+ hostprogs-y += nconf
166+endif
167+
157168 ifeq ($(MAKECMDGOALS),menuconfig)
158169 hostprogs-y += mconf
159170 endif
@@ -177,7 +188,7 @@ endif · 17 unmodified lines
177188
178189 clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
179190 .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
180−clean-files += mconf qconf gconf
191+clean-files += mconf qconf gconf nconf
181192 clean-files += config.pot linux.pot
182193
183194 # Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
@@ -202,6 +213,7 @@ HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` · 18 unmodified lines
202213 HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
203214 -D LKC_DIRECT_LINK
204215
216+HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses
205217 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
206218
207219 ifeq ($(qconf-target),1)
scripts/kconfig/lkc.h+1−1
@@ -84,7 +84,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode); · 83 unmodified lines
8484 void kconfig_load(void);
8585
8686 /* menu.c */
87−void menu_init(void);
87+void _menu_init(void);
8888 void menu_warn(struct menu *menu, const char *fmt, ...);
8989 struct menu *menu_add_menu(void);
9090 void menu_end_menu(void);
scripts/kconfig/lkc_proto.h+2−1
@@ -17,7 +17,8 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); · 16 unmodified lines
1717 P(menu_get_parent_menu,struct menu *,(struct menu *menu));
1818 P(menu_has_help,bool,(struct menu *menu));
1919 P(menu_get_help,const char *,(struct menu *menu));
20−P(get_symbol_str,void,(struct gstr *r, struct symbol *sym));
20+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
21+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
2122 P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
2223
2324 /* symbol.c */
scripts/kconfig/mconf.c+0−13
@@ -282,19 +282,6 @@ static void show_textbox(const char *title, const char *text, int r, int c); · 281 unmodified lines
282282 static void show_helptext(const char *title, const char *text);
283283 static void show_help(struct menu *menu);
284284
285−static struct gstr get_relations_str(struct symbol **sym_arr)
286−{
287− struct symbol *sym;
288− struct gstr res = str_new();
289− int i;
290−
291− for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
292− get_symbol_str(&res, sym);
293− if (!i)
294− str_append(&res, _("No matches found.\n"));
295− return res;
296−}
297−
298285 static char filename[PATH_MAX+1];
299286 static void set_config_filename(const char *config_filename)
300287 {
scripts/kconfig/menu.c+15−1
@@ -38,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...) · 37 unmodified lines
3838 va_end(ap);
3939 }
4040
41−void menu_init(void)
41+void _menu_init(void)
4242 {
4343 current_entry = current_menu = &rootmenu;
4444 last_entry_ptr = &rootmenu.list;
@@ -515,6 +515,20 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) · 470 unmodified lines
515515 str_append(r, "\n\n");
516516 }
517517
518+struct gstr get_relations_str(struct symbol **sym_arr)
519+{
520+ struct symbol *sym;
521+ struct gstr res = str_new();
522+ int i;
523+
524+ for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
525+ get_symbol_str(&res, sym);
526+ if (!i)
527+ str_append(&res, _("No matches found.\n"));
528+ return res;
529+}
530+
531+
518532 void menu_get_ext_help(struct menu *menu, struct gstr *help)
519533 {
520534 struct symbol *sym = menu->sym;
scripts/kconfig/nconf.c+1568−0
@@ -0,0 +1,1568 @@
1+/*
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+ */
8+#define LKC_DIRECT_LINK
9+#include "lkc.h"
10+#include "nconf.h"
11+
12+static const char nconf_readme[] = N_(
13+"Overview\n"
14+"--------\n"
15+"Some kernel features may be built directly into the kernel.\n"
16+"Some may be made into loadable runtime modules. Some features\n"
17+"may be completely removed altogether. There are also certain\n"
18+"kernel parameters which are not really features, but must be\n"
19+"entered in as decimal or hexadecimal numbers or possibly text.\n"
20+"\n"
21+"Menu items beginning with following braces represent features that\n"
22+" [ ] can be built in or removed\n"
23+" < > can be built in, modularized or removed\n"
24+" { } can be built in or modularized (selected by other feature)\n"
25+" - - are selected by other feature,\n"
26+" XXX cannot be selected. use Symbol Info to find out why,\n"
27+"while *, M or whitespace inside braces means to build in, build as\n"
28+"a module or to exclude the feature respectively.\n"
29+"\n"
30+"To change any of these features, highlight it with the cursor\n"
31+"keys and press <Y> to build it in, <M> to make it a module or\n"
32+"<N> to removed it. You may also press the <Space Bar> to cycle\n"
33+"through the available options (ie. Y->N->M->Y).\n"
34+"\n"
35+"Some additional keyboard hints:\n"
36+"\n"
37+"Menus\n"
38+"----------\n"
39+"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
40+" you wish to change use <Enter> or <Space>. Goto submenu by \n"
41+" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
42+" Submenus are designated by \"--->\".\n"
43+"\n"
44+" Shortcut: Press the option's highlighted letter (hotkey).\n"
45+" Pressing a hotkey more than once will sequence\n"
46+" through all visible items which use that hotkey.\n"
47+"\n"
48+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
49+" unseen options into view.\n"
50+"\n"
51+"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
52+"\n"
53+"o To get help with an item, press <F1>\n"
54+" Shortcut: Press <h> or <?>.\n"
55+"\n"
56+"\n"
57+"Radiolists (Choice lists)\n"
58+"-----------\n"
59+"o Use the cursor keys to select the option you wish to set and press\n"
60+" <S> or the <SPACE BAR>.\n"
61+"\n"
62+" Shortcut: Press the first letter of the option you wish to set then\n"
63+" press <S> or <SPACE BAR>.\n"
64+"\n"
65+"o To see available help for the item, press <F1>\n"
66+" Shortcut: Press <H> or <?>.\n"
67+"\n"
68+"\n"
69+"Data Entry\n"
70+"-----------\n"
71+"o Enter the requested information and press <ENTER>\n"
72+" If you are entering hexadecimal values, it is not necessary to\n"
73+" add the '0x' prefix to the entry.\n"
74+"\n"
75+"o For help, press <F1>.\n"
76+"\n"
77+"\n"
78+"Text Box (Help Window)\n"
79+"--------\n"
80+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
81+" keys h,j,k,l function here as do <SPACE BAR> for those\n"
82+" who are familiar with less and lynx.\n"
83+"\n"
84+"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
85+"\n"
86+"\n"
87+"Alternate Configuration Files\n"
88+"-----------------------------\n"
89+"nconfig supports the use of alternate configuration files for\n"
90+"those who, for various reasons, find it necessary to switch\n"
91+"between different kernel configurations.\n"
92+"\n"
93+"At the end of the main menu you will find two options. One is\n"
94+"for saving the current configuration to a file of your choosing.\n"
95+"The other option is for loading a previously saved alternate\n"
96+"configuration.\n"
97+"\n"
98+"Even if you don't use alternate configuration files, but you\n"
99+"find during a nconfig session that you have completely messed\n"
100+"up your settings, you may use the \"Load Alternate...\" option to\n"
101+"restore your previously saved settings from \".config\" without\n"
102+"restarting nconfig.\n"
103+"\n"
104+"Other information\n"
105+"-----------------\n"
106+"If you use nconfig in an XTERM window make sure you have your\n"
107+"$TERM variable set to point to a xterm definition which supports color.\n"
108+"Otherwise, nconfig will look rather bad. nconfig will not\n"
109+"display correctly in a RXVT window because rxvt displays only one\n"
110+"intensity of color, bright.\n"
111+"\n"
112+"nconfig will display larger menus on screens or xterms which are\n"
113+"set to display more than the standard 25 row by 80 column geometry.\n"
114+"In order for this to work, the \"stty size\" command must be able to\n"
115+"display the screen's current row and column geometry. I STRONGLY\n"
116+"RECOMMEND that you make sure you do NOT have the shell variables\n"
117+"LINES and COLUMNS exported into your environment. Some distributions\n"
118+"export those variables via /etc/profile. Some ncurses programs can\n"
119+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
120+"the true screen size.\n"
121+"\n"
122+"Optional personality available\n"
123+"------------------------------\n"
124+"If you prefer to have all of the kernel options listed in a single\n"
125+"menu, rather than the default multimenu hierarchy, run the nconfig\n"
126+"with NCONFIG_MODE environment variable set to single_menu. Example:\n"
127+"\n"
128+"make NCONFIG_MODE=single_menu nconfig\n"
129+"\n"
130+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
131+"is already unrolled.\n"
132+"\n"
133+"Note that this mode can eventually be a little more CPU expensive\n"
134+"(especially with a larger number of unrolled categories) than the\n"
135+"default mode.\n"
136+"\n"),
137+menu_no_f_instructions[] = N_(
138+" You do not have function keys support. Please follow the\n"
139+" following instructions:\n"
140+" Arrow keys navigate the menu.\n"
141+" <Enter> or <right-arrow> selects submenus --->.\n"
142+" Capital Letters are hotkeys.\n"
143+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
144+" Pressing SpaceBar toggles between the above options\n"
145+" Press <Esc> or <left-arrow> to go back one menu, \n"
146+" <?> or <h> for Help, </> for Search.\n"
147+" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
148+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
149+" <Esc> always leaves the current window\n"),
150+menu_instructions[] = N_(
151+" Arrow keys navigate the menu.\n"
152+" <Enter> or <right-arrow> selects submenus --->.\n"
153+" Capital Letters are hotkeys.\n"
154+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
155+" Pressing SpaceBar toggles between the above options\n"
156+" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n"
157+" <?>, <F1> or <h> for Help, </> for Search.\n"
158+" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
159+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
160+" <Esc> always leaves the current window\n"),
161+radiolist_instructions[] = N_(
162+" Use the arrow keys to navigate this window or\n"
163+" press the hotkey of the item you wish to select\n"
164+" followed by the <SPACE BAR>.\n"
165+" Press <?>, <F1> or <h> for additional information about this option.\n"),
166+inputbox_instructions_int[] = N_(
167+"Please enter a decimal value.\n"
168+"Fractions will not be accepted.\n"
169+"Press <RETURN> to accept, <ESC> to cancel."),
170+inputbox_instructions_hex[] = N_(
171+"Please enter a hexadecimal value.\n"
172+"Press <RETURN> to accept, <ESC> to cancel."),
173+inputbox_instructions_string[] = N_(
174+"Please enter a string value.\n"
175+"Press <RETURN> to accept, <ESC> to cancel."),
176+setmod_text[] = N_(
177+"This feature depends on another which\n"
178+"has been configured as a module.\n"
179+"As a result, this feature will be built as a module."),
180+nohelp_text[] = N_(
181+"There is no help available for this kernel option.\n"),
182+load_config_text[] = N_(
183+"Enter the name of the configuration file you wish to load.\n"
184+"Accept the name shown to restore the configuration you\n"
185+"last retrieved. Leave blank to abort."),
186+load_config_help[] = N_(
187+"\n"
188+"For various reasons, one may wish to keep several different kernel\n"
189+"configurations available on a single machine.\n"
190+"\n"
191+"If you have saved a previous configuration in a file other than the\n"
192+"kernel's default, entering the name of the file here will allow you\n"
193+"to modify that configuration.\n"
194+"\n"
195+"If you are uncertain, then you have probably never used alternate\n"
196+"configuration files. You should therefor leave this blank to abort.\n"),
197+save_config_text[] = N_(
198+"Enter a filename to which this configuration should be saved\n"
199+"as an alternate. Leave blank to abort."),
200+save_config_help[] = N_(
201+"\n"
202+"For various reasons, one may wish to keep different kernel\n"
203+"configurations available on a single machine.\n"
204+"\n"
205+"Entering a file name here will allow you to later retrieve, modify\n"
206+"and use the current configuration as an alternate to whatever\n"
207+"configuration options you have selected at that time.\n"
208+"\n"
209+"If you are uncertain what all this means then you should probably\n"
210+"leave this blank.\n"),
211+search_help[] = N_(
212+"\n"
213+"Search for CONFIG_ symbols and display their relations.\n"
214+"Regular expressions are allowed.\n"
215+"Example: search for \"^FOO\"\n"
216+"Result:\n"
217+"-----------------------------------------------------------------\n"
218+"Symbol: FOO [ = m]\n"
219+"Prompt: Foo bus is used to drive the bar HW\n"
220+"Defined at drivers/pci/Kconfig:47\n"
221+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
222+"Location:\n"
223+" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
224+" -> PCI support (PCI [ = y])\n"
225+" -> PCI access mode (<choice> [ = y])\n"
226+"Selects: LIBCRC32\n"
227+"Selected by: BAR\n"
228+"-----------------------------------------------------------------\n"
229+"o The line 'Prompt:' shows the text used in the menu structure for\n"
230+" this CONFIG_ symbol\n"
231+"o The 'Defined at' line tell at what file / line number the symbol\n"
232+" is defined\n"
233+"o The 'Depends on:' line tell what symbols needs to be defined for\n"
234+" this symbol to be visible in the menu (selectable)\n"
235+"o The 'Location:' lines tell where in the menu structure this symbol\n"
236+" is located\n"
237+" A location followed by a [ = y] indicate that this is a selectable\n"
238+" menu item - and current value is displayed inside brackets.\n"
239+"o The 'Selects:' line tell what symbol will be automatically\n"
240+" selected if this symbol is selected (y or m)\n"
241+"o The 'Selected by' line tell what symbol has selected this symbol\n"
242+"\n"
243+"Only relevant lines are shown.\n"
244+"\n\n"
245+"Search examples:\n"
246+"Examples: USB = > find all CONFIG_ symbols containing USB\n"
247+" ^USB => find all CONFIG_ symbols starting with USB\n"
248+" USB$ => find all CONFIG_ symbols ending with USB\n"
249+"\n");
250+
251+struct mitem {
252+ char str[256];
253+ char tag;
254+ void *usrptr;
255+ int is_hot;
256+ int is_visible;
257+};
258+
259+#define MAX_MENU_ITEMS 4096
260+static int show_all_items;
261+static int indent;
262+static struct menu *current_menu;
263+static int child_count;
264+static int single_menu_mode;
265+/* the window in which all information appears */
266+static WINDOW *main_window;
267+/* the largest size of the menu window */
268+static int mwin_max_lines;
269+static int mwin_max_cols;
270+/* the window in which we show option buttons */
271+static MENU *curses_menu;
272+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
273+static struct mitem k_menu_items[MAX_MENU_ITEMS];
274+static int items_num;
275+static int global_exit;
276+/* the currently selected button */
277+const char *current_instructions = menu_instructions;
278+/* this array is used to implement hot keys. it is updated in item_make and
279+ * resetted in clean_items. It would be better to use a hash, but lets keep it
280+ * simple... */
281+#define MAX_SAME_KEY MAX_MENU_ITEMS
282+struct {
283+ int count;
284+ int ptrs[MAX_MENU_ITEMS];
285+} hotkeys[1<<(sizeof(char)*8)];
286+
287+static void conf(struct menu *menu);
288+static void conf_choice(struct menu *menu);
289+static void conf_string(struct menu *menu);
290+static void conf_load(void);
291+static void conf_save(void);
292+static void show_help(struct menu *menu);
293+static int do_exit(void);
294+static void setup_windows(void);
295+
296+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
297+static void handle_f1(int *key, struct menu *current_item);
298+static void handle_f2(int *key, struct menu *current_item);
299+static void handle_f3(int *key, struct menu *current_item);
300+static void handle_f4(int *key, struct menu *current_item);
301+static void handle_f5(int *key, struct menu *current_item);
302+static void handle_f6(int *key, struct menu *current_item);
303+static void handle_f7(int *key, struct menu *current_item);
304+static void handle_f8(int *key, struct menu *current_item);
305+
306+struct function_keys {
307+ const char *key_str;
308+ const char *func;
309+ function_key key;
310+ function_key_handler_t handler;
311+};
312+
313+static const int function_keys_num = 8;
314+struct 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",
323+ .func = "Symbol Info",
324+ .key = F_SYMBOL,
325+ .handler = handle_f2,
326+ },
327+ {
328+ .key_str = "F3",
329+ .func = "Instructions",
330+ .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",
359+ .func = "Exit",
360+ .key = F_EXIT,
361+ .handler = handle_f8,
362+ },
363+};
364+
365+static void print_function_line(void)
366+{
367+ int i;
368+ int offset = 1;
369+ const int skip = 1;
370+
371+ for (i = 0; i < function_keys_num; i++) {
372+ wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
373+ mvwprintw(main_window, LINES-3, offset,
374+ "%s",
375+ function_keys[i].key_str);
376+ wattrset(main_window, attributes[FUNCTION_TEXT]);
377+ offset += strlen(function_keys[i].key_str);
378+ mvwprintw(main_window, LINES-3,
379+ offset, "%s",
380+ function_keys[i].func);
381+ offset += strlen(function_keys[i].func) + skip;
382+ }
383+ wattrset(main_window, attributes[NORMAL]);
384+}
385+
386+/* help */
387+static void handle_f1(int *key, struct menu *current_item)
388+{
389+ show_scroll_win(main_window,
390+ _("README"), _(nconf_readme));
391+ return;
392+}
393+
394+/* symbole help */
395+static void handle_f2(int *key, struct menu *current_item)
396+{
397+ show_help(current_item);
398+ return;
399+}
400+
401+/* instructions */
402+static void handle_f3(int *key, struct menu *current_item)
403+{
404+ show_scroll_win(main_window,
405+ _("Instructions"),
406+ _(current_instructions));
407+ return;
408+}
409+
410+/* config */
411+static void handle_f4(int *key, struct menu *current_item)
412+{
413+ int res = btn_dialog(main_window,
414+ _("Show all symbols?"),
415+ 2,
416+ " <Show All> ",
417+ "<Don't show all>");
418+ if (res == 0)
419+ show_all_items = 1;
420+ else if (res == 1)
421+ show_all_items = 0;
422+
423+ return;
424+}
425+
426+/* back */
427+static void handle_f5(int *key, struct menu *current_item)
428+{
429+ *key = KEY_LEFT;
430+ return;
431+}
432+
433+/* save */
434+static void handle_f6(int *key, struct menu *current_item)
435+{
436+ conf_save();
437+ return;
438+}
439+
440+/* load */
441+static void handle_f7(int *key, struct menu *current_item)
442+{
443+ conf_load();
444+ return;
445+}
446+
447+/* exit */
448+static void handle_f8(int *key, struct menu *current_item)
449+{
450+ do_exit();
451+ return;
452+}
453+
454+/* return != 0 to indicate the key was handles */
455+int process_special_keys(int *key, struct menu *menu)
456+{
457+ int i;
458+
459+ if (*key == KEY_RESIZE) {
460+ setup_windows();
461+ return 1;
462+ }
463+
464+ for (i = 0; i < function_keys_num; i++) {
465+ if (*key == KEY_F(function_keys[i].key) ||
466+ *key == '0' + function_keys[i].key){
467+ function_keys[i].handler(key, menu);
468+ return 1;
469+ }
470+ }
471+
472+ return 0;
473+}
474+
475+static void clean_items(void)
476+{
477+ int i;
478+ for (i = 0; curses_menu_items[i]; i++)
479+ free_item(curses_menu_items[i]);
480+ bzero(curses_menu_items, sizeof(curses_menu_items));
481+ bzero(k_menu_items, sizeof(k_menu_items));
482+ bzero(hotkeys, sizeof(hotkeys));
483+ items_num = 0;
484+}
485+
486+/* return the index of the next hot item, or -1 if no such item exists */
487+int get_next_hot(int c)
488+{
489+ static int hot_index;
490+ static int hot_char;
491+
492+ if (c < 0 || c > 255 || hotkeys[c].count <= 0)
493+ return -1;
494+
495+ if (hot_char == c) {
496+ hot_index = (hot_index+1)%hotkeys[c].count;
497+ return hotkeys[c].ptrs[hot_index];
498+ } else {
499+ hot_char = c;
500+ hot_index = 0;
501+ return hotkeys[c].ptrs[0];
502+ }
503+}
504+
505+/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */
506+int canbhot(char c)
507+{
508+ c = tolower(c);
509+ return isalnum(c) && c != 'y' && c != 'm' && c != 'h' &&
510+ c != 'n' && c != '?';
511+}
512+
513+/* check if str already contains a hot key. */
514+int is_hot(int index)
515+{
516+ return k_menu_items[index].is_hot;
517+}
518+
519+/* find the first possible hot key, and mark it.
520+ * index is the index of the item in the menu
521+ * return 0 on success*/
522+int make_hot(char *dest, int len, const char *org, int index)
523+{
524+ int position = -1;
525+ int i;
526+ int tmp;
527+ int c;
528+ int org_len = strlen(org);
529+
530+ if (org == NULL || is_hot(index))
531+ return 1;
532+
533+ /* make sure not to make hot keys out of markers.
534+ * find where to start looking for a hot key
535+ */
536+ i = 0;
537+ /* skip white space */
538+ while (i < org_len && org[i] == ' ')
539+ i++;
540+ if (i == org_len)
541+ return -1;
542+ /* if encountering '(' or '<' or '[', find the match and look from there
543+ **/
544+ if (org[i] == '[' || org[i] == '<' || org[i] == '(') {
545+ i++;
546+ for (; i < org_len; i++)
547+ if (org[i] == ']' || org[i] == '>' || org[i] == ')')
548+ break;
549+ }
550+ if (i == org_len)
551+ return -1;
552+ for (; i < org_len; i++) {
553+ if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') {
554+ position = i;
555+ break;
556+ }
557+ }
558+ if (position == -1)
559+ return 1;
560+
561+ /* ok, char at org[position] should be a hot key to this item */
562+ c = tolower(org[position]);
563+ tmp = hotkeys[c].count;
564+ hotkeys[c].ptrs[tmp] = index;
565+ hotkeys[c].count++;
566+ /*
567+ snprintf(dest, len, "%.*s(%c)%s", position, org, org[position],
568+ &org[position+1]);
569+ */
570+ /* make org[position] uppercase, and all leading letter small case */
571+ strncpy(dest, org, len);
572+ for (i = 0; i < position; i++)
573+ dest[i] = tolower(dest[i]);
574+ dest[position] = toupper(dest[position]);
575+ k_menu_items[index].is_hot = 1;
576+ return 0;
577+}
578+
579+/* Make a new item. Add a hotkey mark in the first possible letter.
580+ * As ncurses does not allow any attributes inside menue item, we mark the
581+ * hot key as the first capitalized letter in the string */
582+void item_make(struct menu *menu, char tag, const char *fmt, ...)
583+{
584+ va_list ap;
585+ char tmp_str[256];
586+
587+ if (items_num > MAX_MENU_ITEMS-1)
588+ return;
589+
590+ bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
591+ k_menu_items[items_num].tag = tag;
592+ k_menu_items[items_num].usrptr = menu;
593+ if (menu != NULL)
594+ k_menu_items[items_num].is_visible =
595+ menu_is_visible(menu);
596+ else
597+ k_menu_items[items_num].is_visible = 1;
598+
599+ va_start(ap, fmt);
600+ vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap);
601+ if (!k_menu_items[items_num].is_visible)
602+ memcpy(tmp_str, "XXX", 3);
603+ va_end(ap);
604+ if (make_hot(
605+ k_menu_items[items_num].str,
606+ sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0)
607+ strncpy(k_menu_items[items_num].str,
608+ tmp_str,
609+ sizeof(k_menu_items[items_num].str));
610+
611+ curses_menu_items[items_num] = new_item(
612+ k_menu_items[items_num].str,
613+ k_menu_items[items_num].str);
614+ set_item_userptr(curses_menu_items[items_num],
615+ &k_menu_items[items_num]);
616+ /*
617+ if (!k_menu_items[items_num].is_visible)
618+ item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
619+ */
620+
621+ items_num++;
622+ curses_menu_items[items_num] = NULL;
623+}
624+
625+/* very hackish. adds a string to the last item added */
626+void item_add_str(const char *fmt, ...)
627+{
628+ va_list ap;
629+ int index = items_num-1;
630+ char new_str[256];
631+ char tmp_str[256];
632+
633+ if (index < 0)
634+ return;
635+
636+ va_start(ap, fmt);
637+ vsnprintf(new_str, sizeof(new_str), fmt, ap);
638+ va_end(ap);
639+ snprintf(tmp_str, sizeof(tmp_str), "%s%s",
640+ k_menu_items[index].str, new_str);
641+ if (make_hot(k_menu_items[index].str,
642+ sizeof(k_menu_items[index].str), tmp_str, index) != 0)
643+ strncpy(k_menu_items[index].str,
644+ tmp_str,
645+ sizeof(k_menu_items[index].str));
646+
647+ free_item(curses_menu_items[index]);
648+ curses_menu_items[index] = new_item(
649+ k_menu_items[index].str,
650+ k_menu_items[index].str);
651+ set_item_userptr(curses_menu_items[index],
652+ &k_menu_items[index]);
653+}
654+
655+/* get the tag of the currently selected item */
656+char item_tag(void)
657+{
658+ ITEM *cur;
659+ struct mitem *mcur;
660+
661+ cur = current_item(curses_menu);
662+ if (cur == NULL)
663+ return 0;
664+ mcur = (struct mitem *) item_userptr(cur);
665+ return mcur->tag;
666+}
667+
668+int curses_item_index(void)
669+{
670+ return item_index(current_item(curses_menu));
671+}
672+
673+void *item_data(void)
674+{
675+ ITEM *cur;
676+ struct mitem *mcur;
677+
678+ cur = current_item(curses_menu);
679+ mcur = (struct mitem *) item_userptr(cur);
680+ return mcur->usrptr;
681+
682+}
683+
684+int item_is_tag(char tag)
685+{
686+ return item_tag() == tag;
687+}
688+
689+static char filename[PATH_MAX+1];
690+static char menu_backtitle[PATH_MAX+128];
691+const char *set_config_filename(const char *config_filename)
692+{
693+ int size;
694+ struct symbol *sym;
695+
696+ sym = sym_lookup("KERNELVERSION", 0);
697+ sym_calc_value(sym);
698+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
699+ _("%s - Linux Kernel v%s Configuration"),
700+ config_filename, sym_get_string_value(sym));
701+ if (size >= sizeof(menu_backtitle))
702+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
703+
704+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
705+ if (size >= sizeof(filename))
706+ filename[sizeof(filename)-1] = '\0';
707+ return menu_backtitle;
708+}
709+
710+/* command = 0 is supress, 1 is restore */
711+static void supress_stdout(int command)
712+{
713+ static FILE *org_stdout;
714+ static FILE *org_stderr;
715+
716+ if (command == 0) {
717+ org_stdout = stdout;
718+ org_stderr = stderr;
719+ stdout = fopen("/dev/null", "a");
720+ stderr = fopen("/dev/null", "a");
721+ } else {
722+ fclose(stdout);
723+ fclose(stderr);
724+ stdout = org_stdout;
725+ stderr = org_stderr;
726+ }
727+}
728+
729+/* return = 0 means we are successful.
730+ * -1 means go on doing what you were doing
731+ */
732+static int do_exit(void)
733+{
734+ int res;
735+ if (!conf_get_changed()) {
736+ global_exit = 1;
737+ return 0;
738+ }
739+ res = btn_dialog(main_window,
740+ _("Do you wish to save your "
741+ "new kernel configuration?\n"
742+ "<ESC> to cancel and resume nconfig."),
743+ 2,
744+ " <save> ",
745+ "<don't save>");
746+ if (res == KEY_EXIT) {
747+ global_exit = 0;
748+ return -1;
749+ }
750+
751+ /* if we got here, the user really wants to exit */
752+ switch (res) {
753+ case 0:
754+ supress_stdout(0);
755+ res = conf_write(filename);
756+ supress_stdout(1);
757+ if (res)
758+ btn_dialog(
759+ main_window,
760+ _("Error during writing of the kernel "
761+ "configuration.\n"
762+ "Your kernel configuration "
763+ "changes were NOT saved."),
764+ 1,
765+ "<OK>");
766+ else {
767+ char buf[1024];
768+ snprintf(buf, 1024,
769+ _("Configuration written to %s\n"
770+ "End of Linux kernel configuration.\n"
771+ "Execute 'make' to build the kernel or try"
772+ " 'make help'."), filename);
773+ btn_dialog(
774+ main_window,
775+ buf,
776+ 1,
777+ "<OK>");
778+ }
779+ break;
780+ default:
781+ btn_dialog(
782+ main_window,
783+ _("Your kernel configuration changes were NOT saved."),
784+ 1,
785+ "<OK>");
786+ break;
787+ }
788+ global_exit = 1;
789+ return 0;
790+}
791+
792+
793+static void search_conf(void)
794+{
795+ struct symbol **sym_arr;
796+ struct gstr res;
797+ char dialog_input_result[100];
798+ char *dialog_input;
799+ int dres;
800+again:
801+ dres = dialog_inputbox(main_window,
802+ _("Search Configuration Parameter"),
803+ _("Enter CONFIG_ (sub)string to search for "
804+ "(with or without \"CONFIG\")"),
805+ "", dialog_input_result, 99);
806+ switch (dres) {
807+ case 0:
808+ break;
809+ case 1:
810+ show_scroll_win(main_window,
811+ _("Search Configuration"), search_help);
812+ goto again;
813+ default:
814+ return;
815+ }
816+
817+ /* strip CONFIG_ if necessary */
818+ dialog_input = dialog_input_result;
819+ if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
820+ dialog_input += 7;
821+
822+ sym_arr = sym_re_search(dialog_input);
823+ res = get_relations_str(sym_arr);
824+ free(sym_arr);
825+ show_scroll_win(main_window,
826+ _("Search Results"), str_get(&res));
827+ str_free(&res);
828+}
829+
830+
831+static void build_conf(struct menu *menu)
832+{
833+ struct symbol *sym;
834+ struct property *prop;
835+ struct menu *child;
836+ int type, tmp, doint = 2;
837+ tristate val;
838+ char ch;
839+
840+ if (!menu || (!show_all_items && !menu_is_visible(menu)))
841+ return;
842+
843+ sym = menu->sym;
844+ prop = menu->prompt;
845+ if (!sym) {
846+ if (prop && menu != current_menu) {
847+ const char *prompt = menu_get_prompt(menu);
848+ enum prop_type ptype;
849+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
850+ switch (ptype) {
851+ case P_MENU:
852+ child_count++;
853+ prompt = _(prompt);
854+ if (single_menu_mode) {
855+ item_make(menu, 'm',
856+ "%s%*c%s",
857+ menu->data ? "-->" : "++>",
858+ indent + 1, ' ', prompt);
859+ } else
860+ item_make(menu, 'm',
861+ " %*c%s --->",
862+ indent + 1,
863+ ' ', prompt);
864+
865+ if (single_menu_mode && menu->data)
866+ goto conf_childs;
867+ return;
868+ case P_COMMENT:
869+ if (prompt) {
870+ child_count++;
871+ item_make(menu, ':',
872+ " %*c*** %s ***",
873+ indent + 1, ' ',
874+ _(prompt));
875+ }
876+ break;
877+ default:
878+ if (prompt) {
879+ child_count++;
880+ item_make(menu, ':', "---%*c%s",
881+ indent + 1, ' ',
882+ _(prompt));
883+ }
884+ }
885+ } else
886+ doint = 0;
887+ goto conf_childs;
888+ }
889+
890+ type = sym_get_type(sym);
891+ if (sym_is_choice(sym)) {
892+ struct symbol *def_sym = sym_get_choice_value(sym);
893+ struct menu *def_menu = NULL;
894+
895+ child_count++;
896+ for (child = menu->list; child; child = child->next) {
897+ if (menu_is_visible(child) && child->sym == def_sym)
898+ def_menu = child;
899+ }
900+
901+ val = sym_get_tristate_value(sym);
902+ if (sym_is_changable(sym)) {
903+ switch (type) {
904+ case S_BOOLEAN:
905+ item_make(menu, 't', "[%c]",
906+ val == no ? ' ' : '*');
907+ break;
908+ case S_TRISTATE:
909+ switch (val) {
910+ case yes:
911+ ch = '*';
912+ break;
913+ case mod:
914+ ch = 'M';
915+ break;
916+ default:
917+ ch = ' ';
918+ break;
919+ }
920+ item_make(menu, 't', "<%c>", ch);
921+ break;
922+ }
923+ } else {
924+ item_make(menu, def_menu ? 't' : ':', " ");
925+ }
926+
927+ item_add_str("%*c%s", indent + 1,
928+ ' ', _(menu_get_prompt(menu)));
929+ if (val == yes) {
930+ if (def_menu) {
931+ item_add_str(" (%s)",
932+ _(menu_get_prompt(def_menu)));
933+ item_add_str(" --->");
934+ if (def_menu->list) {
935+ indent += 2;
936+ build_conf(def_menu);
937+ indent -= 2;
938+ }
939+ }
940+ return;
941+ }
942+ } else {
943+ if (menu == current_menu) {
944+ item_make(menu, ':',
945+ "---%*c%s", indent + 1,
946+ ' ', _(menu_get_prompt(menu)));
947+ goto conf_childs;
948+ }
949+ child_count++;
950+ val = sym_get_tristate_value(sym);
951+ if (sym_is_choice_value(sym) && val == yes) {
952+ item_make(menu, ':', " ");
953+ } else {
954+ switch (type) {
955+ case S_BOOLEAN:
956+ if (sym_is_changable(sym))
957+ item_make(menu, 't', "[%c]",
958+ val == no ? ' ' : '*');
959+ else
960+ item_make(menu, 't', "-%c-",
961+ val == no ? ' ' : '*');
962+ break;
963+ case S_TRISTATE:
964+ switch (val) {
965+ case yes:
966+ ch = '*';
967+ break;
968+ case mod:
969+ ch = 'M';
970+ break;
971+ default:
972+ ch = ' ';
973+ break;
974+ }
975+ if (sym_is_changable(sym)) {
976+ if (sym->rev_dep.tri == mod)
977+ item_make(menu,
978+ 't', "{%c}", ch);
979+ else
980+ item_make(menu,
981+ 't', "<%c>", ch);
982+ } else
983+ item_make(menu, 't', "-%c-", ch);
984+ break;
985+ default:
986+ tmp = 2 + strlen(sym_get_string_value(sym));
987+ item_make(menu, 's', "(%s)",
988+ sym_get_string_value(sym));
989+ tmp = indent - tmp + 4;
990+ if (tmp < 0)
991+ tmp = 0;
992+ item_add_str("%*c%s%s", tmp, ' ',
993+ _(menu_get_prompt(menu)),
994+ (sym_has_value(sym) ||
995+ !sym_is_changable(sym)) ? "" :
996+ _(" (NEW)"));
997+ goto conf_childs;
998+ }
999+ }
1000+ item_add_str("%*c%s%s", indent + 1, ' ',
1001+ _(menu_get_prompt(menu)),
1002+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
1003+ "" : _(" (NEW)"));
1004+ if (menu->prompt && menu->prompt->type == P_MENU) {
1005+ item_add_str(" --->");
1006+ return;
1007+ }
1008+ }
1009+
1010+conf_childs:
1011+ indent += doint;
1012+ for (child = menu->list; child; child = child->next)
1013+ build_conf(child);
1014+ indent -= doint;
1015+}
1016+
1017+static void reset_menu(void)
1018+{
1019+ unpost_menu(curses_menu);
1020+ clean_items();
1021+}
1022+
1023+/* adjust the menu to show this item.
1024+ * prefer not to scroll the menu if possible*/
1025+static void center_item(int selected_index, int *last_top_row)
1026+{
1027+ int toprow;
1028+ int maxy, maxx;
1029+
1030+ scale_menu(curses_menu, &maxy, &maxx);
1031+ set_top_row(curses_menu, *last_top_row);
1032+ toprow = top_row(curses_menu);
1033+ if (selected_index >= toprow && selected_index < toprow+maxy) {
1034+ /* we can only move the selected item. no need to scroll */
1035+ set_current_item(curses_menu,
1036+ curses_menu_items[selected_index]);
1037+ } else {
1038+ toprow = max(selected_index-maxy/2, 0);
1039+ if (toprow >= item_count(curses_menu)-maxy)
1040+ toprow = item_count(curses_menu)-mwin_max_lines;
1041+ set_top_row(curses_menu, toprow);
1042+ set_current_item(curses_menu,
1043+ curses_menu_items[selected_index]);
1044+ }
1045+ *last_top_row = toprow;
1046+ post_menu(curses_menu);
1047+ refresh_all_windows(main_window);
1048+}
1049+
1050+/* this function assumes reset_menu has been called before */
1051+static void show_menu(const char *prompt, const char *instructions,
1052+ int selected_index, int *last_top_row)
1053+{
1054+ int maxx, maxy;
1055+ WINDOW *menu_window;
1056+
1057+ current_instructions = instructions;
1058+
1059+ clear();
1060+ wattrset(main_window, attributes[NORMAL]);
1061+ print_in_middle(stdscr, 1, 0, COLS,
1062+ menu_backtitle,
1063+ attributes[MAIN_HEADING]);
1064+
1065+ wattrset(main_window, attributes[MAIN_MENU_BOX]);
1066+ box(main_window, 0, 0);
1067+ wattrset(main_window, attributes[MAIN_MENU_HEADING]);
1068+ mvwprintw(main_window, 0, 3, " %s ", prompt);
1069+ wattrset(main_window, attributes[NORMAL]);
1070+
1071+ set_menu_items(curses_menu, curses_menu_items);
1072+
1073+ /* position the menu at the middle of the screen */
1074+ scale_menu(curses_menu, &maxy, &maxx);
1075+ maxx = min(maxx, mwin_max_cols);
1076+ maxy = mwin_max_lines-1;
1077+ menu_window = derwin(main_window,
1078+ maxy,
1079+ maxx,
1080+ 2,
1081+ (mwin_max_cols-maxx)/2);
1082+ keypad(menu_window, TRUE);
1083+ set_menu_win(curses_menu, menu_window);
1084+ set_menu_sub(curses_menu, menu_window);
1085+
1086+ /* must reassert this after changing items, otherwise returns to a
1087+ * default of 16
1088+ */
1089+ set_menu_format(curses_menu, maxy, 1);
1090+ center_item(selected_index, last_top_row);
1091+ set_menu_format(curses_menu, maxy, 1);
1092+
1093+ print_function_line();
1094+
1095+ /* Post the menu */
1096+ post_menu(curses_menu);
1097+ refresh_all_windows(main_window);
1098+}
1099+
1100+
1101+static void conf(struct menu *menu)
1102+{
1103+ char pattern[256];
1104+ struct menu *submenu = 0;
1105+ const char *prompt = menu_get_prompt(menu);
1106+ struct symbol *sym;
1107+ struct menu *active_menu = NULL;
1108+ int res;
1109+ int current_index = 0;
1110+ int last_top_row = 0;
1111+
1112+ bzero(pattern, sizeof(pattern));
1113+
1114+ while (!global_exit) {
1115+ reset_menu();
1116+ current_menu = menu;
1117+ build_conf(menu);
1118+ if (!child_count)
1119+ break;
1120+
1121+ show_menu(prompt ? _(prompt) : _("Main Menu"),
1122+ _(menu_instructions),
1123+ current_index, &last_top_row);
1124+ keypad((menu_win(curses_menu)), TRUE);
1125+ while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1126+ if (process_special_keys(&res,
1127+ (struct menu *) item_data()))
1128+ break;
1129+ switch (res) {
1130+ case KEY_DOWN:
1131+ menu_driver(curses_menu, REQ_DOWN_ITEM);
1132+ break;
1133+ case KEY_UP:
1134+ menu_driver(curses_menu, REQ_UP_ITEM);
1135+ break;
1136+ case KEY_NPAGE:
1137+ menu_driver(curses_menu, REQ_SCR_DPAGE);
1138+ break;
1139+ case KEY_PPAGE:
1140+ menu_driver(curses_menu, REQ_SCR_UPAGE);
1141+ break;
1142+ case KEY_HOME:
1143+ menu_driver(curses_menu, REQ_FIRST_ITEM);
1144+ break;
1145+ case KEY_END:
1146+ menu_driver(curses_menu, REQ_LAST_ITEM);
1147+ break;
1148+ case 'h':
1149+ case '?':
1150+ show_help((struct menu *) item_data());
1151+ break;
1152+ }
1153+ if (res == 10 || res == 27 ||
1154+ res == 32 || res == 'n' || res == 'y' ||
1155+ res == KEY_LEFT || res == KEY_RIGHT ||
1156+ res == 'm' || res == '/')
1157+ break;
1158+ else if (canbhot(res)) {
1159+ /* check for hot keys: */
1160+ int tmp = get_next_hot(res);
1161+ if (tmp != -1)
1162+ center_item(tmp, &last_top_row);
1163+ }
1164+ refresh_all_windows(main_window);
1165+ }
1166+
1167+ refresh_all_windows(main_window);
1168+ /* if ESC or left*/
1169+ if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1170+ break;
1171+
1172+ /* remember location in the menu */
1173+ last_top_row = top_row(curses_menu);
1174+ current_index = curses_item_index();
1175+
1176+ if (!item_tag())
1177+ continue;
1178+
1179+ submenu = (struct menu *) item_data();
1180+ active_menu = (struct menu *)item_data();
1181+ if (!submenu || !menu_is_visible(submenu))
1182+ continue;
1183+ if (submenu)
1184+ sym = submenu->sym;
1185+ else
1186+ sym = NULL;
1187+
1188+ switch (res) {
1189+ case ' ':
1190+ if (item_is_tag('t'))
1191+ sym_toggle_tristate_value(sym);
1192+ else if (item_is_tag('m'))
1193+ conf(submenu);
1194+ break;
1195+ case KEY_RIGHT:
1196+ case 10: /* ENTER WAS PRESSED */
1197+ switch (item_tag()) {
1198+ case 'm':
1199+ if (single_menu_mode)
1200+ submenu->data =
1201+ (void *) (long) !submenu->data;
1202+ else
1203+ conf(submenu);
1204+ break;
1205+ case 't':
1206+ if (sym_is_choice(sym) &&
1207+ sym_get_tristate_value(sym) == yes)
1208+ conf_choice(submenu);
1209+ else if (submenu->prompt &&
1210+ submenu->prompt->type == P_MENU)
1211+ conf(submenu);
1212+ else if (res == 10)
1213+ sym_toggle_tristate_value(sym);
1214+ break;
1215+ case 's':
1216+ conf_string(submenu);
1217+ break;
1218+ }
1219+ break;
1220+ case 'y':
1221+ if (item_is_tag('t')) {
1222+ if (sym_set_tristate_value(sym, yes))
1223+ break;
1224+ if (sym_set_tristate_value(sym, mod))
1225+ btn_dialog(main_window, setmod_text, 0);
1226+ }
1227+ break;
1228+ case 'n':
1229+ if (item_is_tag('t'))
1230+ sym_set_tristate_value(sym, no);
1231+ break;
1232+ case 'm':
1233+ if (item_is_tag('t'))
1234+ sym_set_tristate_value(sym, mod);
1235+ break;
1236+ case '/':
1237+ search_conf();
1238+ break;
1239+ }
1240+ }
1241+}
1242+
1243+static void show_help(struct menu *menu)
1244+{
1245+ struct gstr help = str_new();
1246+
1247+ if (menu && menu->sym && menu_has_help(menu)) {
1248+ if (menu->sym->name) {
1249+ str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name);
1250+ str_append(&help, _(menu_get_help(menu)));
1251+ str_append(&help, "\n");
1252+ get_symbol_str(&help, menu->sym);
1253+ }
1254+ } else {
1255+ str_append(&help, nohelp_text);
1256+ }
1257+ show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1258+ str_free(&help);
1259+}
1260+
1261+static void conf_choice(struct menu *menu)
1262+{
1263+ const char *prompt = _(menu_get_prompt(menu));
1264+ struct menu *child = 0;
1265+ struct symbol *active;
1266+ int selected_index = 0;
1267+ int last_top_row = 0;
1268+ int res, i = 0;
1269+
1270+ active = sym_get_choice_value(menu->sym);
1271+ /* this is mostly duplicated from the conf() function. */
1272+ while (!global_exit) {
1273+ reset_menu();
1274+
1275+ for (i = 0, child = menu->list; child; child = child->next) {
1276+ if (!show_all_items && !menu_is_visible(child))
1277+ continue;
1278+
1279+ if (child->sym == sym_get_choice_value(menu->sym))
1280+ item_make(child, ':', "<X> %s",
1281+ _(menu_get_prompt(child)));
1282+ else
1283+ item_make(child, ':', " %s",
1284+ _(menu_get_prompt(child)));
1285+ if (child->sym == active){
1286+ last_top_row = top_row(curses_menu);
1287+ selected_index = i;
1288+ }
1289+ i++;
1290+ }
1291+ show_menu(prompt ? _(prompt) : _("Choice Menu"),
1292+ _(radiolist_instructions),
1293+ selected_index,
1294+ &last_top_row);
1295+ while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1296+ if (process_special_keys(
1297+ &res,
1298+ (struct menu *) item_data()))
1299+ break;
1300+ switch (res) {
1301+ case KEY_DOWN:
1302+ menu_driver(curses_menu, REQ_DOWN_ITEM);
1303+ break;
1304+ case KEY_UP:
1305+ menu_driver(curses_menu, REQ_UP_ITEM);
1306+ break;
1307+ case KEY_NPAGE:
1308+ menu_driver(curses_menu, REQ_SCR_DPAGE);
1309+ break;
1310+ case KEY_PPAGE:
1311+ menu_driver(curses_menu, REQ_SCR_UPAGE);
1312+ break;
1313+ case KEY_HOME:
1314+ menu_driver(curses_menu, REQ_FIRST_ITEM);
1315+ break;
1316+ case KEY_END:
1317+ menu_driver(curses_menu, REQ_LAST_ITEM);
1318+ break;
1319+ case 'h':
1320+ case '?':
1321+ show_help((struct menu *) item_data());
1322+ break;
1323+ }
1324+ if (res == 10 || res == 27 || res == ' ' ||
1325+ res == KEY_LEFT)
1326+ break;
1327+ else if (canbhot(res)) {
1328+ /* check for hot keys: */
1329+ int tmp = get_next_hot(res);
1330+ if (tmp != -1)
1331+ center_item(tmp, &last_top_row);
1332+ }
1333+ refresh_all_windows(main_window);
1334+ }
1335+ /* if ESC or left */
1336+ if (res == 27 || res == KEY_LEFT)
1337+ break;
1338+
1339+ child = item_data();
1340+ if (!child || !menu_is_visible(child))
1341+ continue;
1342+ switch (res) {
1343+ case ' ':
1344+ case 10:
1345+ case KEY_RIGHT:
1346+ sym_set_tristate_value(child->sym, yes);
1347+ return;
1348+ case 'h':
1349+ case '?':
1350+ show_help(child);
1351+ active = child->sym;
1352+ break;
1353+ case KEY_EXIT:
1354+ return;
1355+ }
1356+ }
1357+}
1358+
1359+static void conf_string(struct menu *menu)
1360+{
1361+ const char *prompt = menu_get_prompt(menu);
1362+ char dialog_input_result[256];
1363+
1364+ while (1) {
1365+ int res;
1366+ const char *heading;
1367+
1368+ switch (sym_get_type(menu->sym)) {
1369+ case S_INT:
1370+ heading = _(inputbox_instructions_int);
1371+ break;
1372+ case S_HEX:
1373+ heading = _(inputbox_instructions_hex);
1374+ break;
1375+ case S_STRING:
1376+ heading = _(inputbox_instructions_string);
1377+ break;
1378+ default:
1379+ heading = _("Internal nconf error!");
1380+ }
1381+ res = dialog_inputbox(main_window,
1382+ prompt ? _(prompt) : _("Main Menu"),
1383+ heading,
1384+ sym_get_string_value(menu->sym),
1385+ dialog_input_result,
1386+ sizeof(dialog_input_result));
1387+ switch (res) {
1388+ case 0:
1389+ if (sym_set_string_value(menu->sym,
1390+ dialog_input_result))
1391+ return;
1392+ btn_dialog(main_window,
1393+ _("You have made an invalid entry."), 0);
1394+ break;
1395+ case 1:
1396+ show_help(menu);
1397+ break;
1398+ case KEY_EXIT:
1399+ return;
1400+ }
1401+ }
1402+}
1403+
1404+static void conf_load(void)
1405+{
1406+ char dialog_input_result[256];
1407+ while (1) {
1408+ int res;
1409+ res = dialog_inputbox(main_window,
1410+ NULL, load_config_text,
1411+ filename,
1412+ dialog_input_result,
1413+ sizeof(dialog_input_result));
1414+ switch (res) {
1415+ case 0:
1416+ if (!dialog_input_result[0])
1417+ return;
1418+ if (!conf_read(dialog_input_result)) {
1419+ set_config_filename(dialog_input_result);
1420+ sym_set_change_count(1);
1421+ return;
1422+ }
1423+ btn_dialog(main_window, _("File does not exist!"), 0);
1424+ break;
1425+ case 1:
1426+ show_scroll_win(main_window,
1427+ _("Load Alternate Configuration"),
1428+ load_config_help);
1429+ break;
1430+ case KEY_EXIT:
1431+ return;
1432+ }
1433+ }
1434+}
1435+
1436+static void conf_save(void)
1437+{
1438+ char dialog_input_result[256];
1439+ while (1) {
1440+ int res;
1441+ res = dialog_inputbox(main_window,
1442+ NULL, save_config_text,
1443+ filename,
1444+ dialog_input_result,
1445+ sizeof(dialog_input_result));
1446+ switch (res) {
1447+ case 0:
1448+ if (!dialog_input_result[0])
1449+ return;
1450+ supress_stdout(0);
1451+ res = conf_write(dialog_input_result);
1452+ supress_stdout(1);
1453+ if (!res) {
1454+ char buf[1024];
1455+ sprintf(buf, "%s %s",
1456+ _("configuration file saved to: "),
1457+ dialog_input_result);
1458+ btn_dialog(main_window,
1459+ buf, 1, "<OK>");
1460+ set_config_filename(dialog_input_result);
1461+ return;
1462+ }
1463+ btn_dialog(main_window, _("Can't create file! "
1464+ "Probably a nonexistent directory."),
1465+ 1, "<OK>");
1466+ break;
1467+ case 1:
1468+ show_scroll_win(main_window,
1469+ _("Save Alternate Configuration"),
1470+ save_config_help);
1471+ break;
1472+ case KEY_EXIT:
1473+ return;
1474+ }
1475+ }
1476+}
1477+
1478+void setup_windows(void)
1479+{
1480+ if (main_window != NULL)
1481+ delwin(main_window);
1482+
1483+ /* set up the menu and menu window */
1484+ main_window = newwin(LINES-2, COLS-2, 2, 1);
1485+ keypad(main_window, TRUE);
1486+ mwin_max_lines = LINES-6;
1487+ mwin_max_cols = COLS-6;
1488+
1489+ /* panels order is from bottom to top */
1490+ new_panel(main_window);
1491+}
1492+
1493+int main(int ac, char **av)
1494+{
1495+ char *mode;
1496+
1497+ setlocale(LC_ALL, "");
1498+ bindtextdomain(PACKAGE, LOCALEDIR);
1499+ textdomain(PACKAGE);
1500+
1501+ conf_parse(av[1]);
1502+ conf_read(NULL);
1503+
1504+ mode = getenv("NCONFIG_MODE");
1505+ if (mode) {
1506+ if (!strcasecmp(mode, "single_menu"))
1507+ single_menu_mode = 1;
1508+ }
1509+
1510+ /* Initialize curses */
1511+ initscr();
1512+ /* set color theme */
1513+ set_colors();
1514+
1515+ cbreak();
1516+ noecho();
1517+ keypad(stdscr, TRUE);
1518+ curs_set(0);
1519+
1520+ if (COLS < 75 || LINES < 20) {
1521+ endwin();
1522+ printf("Your terminal should have at "
1523+ "least 20 lines and 75 columns\n");
1524+ return 1;
1525+ }
1526+
1527+ notimeout(stdscr, FALSE);
1528+ ESCDELAY = 1;
1529+
1530+ /* set btns menu */
1531+ curses_menu = new_menu(curses_menu_items);
1532+ menu_opts_off(curses_menu, O_SHOWDESC);
1533+ menu_opts_off(curses_menu, O_SHOWMATCH);
1534+ menu_opts_on(curses_menu, O_ONEVALUE);
1535+ menu_opts_on(curses_menu, O_NONCYCLIC);
1536+ set_menu_mark(curses_menu, " ");
1537+ set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1538+ set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1539+ set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1540+
1541+ set_config_filename(conf_get_configname());
1542+ setup_windows();
1543+
1544+ /* check for KEY_FUNC(1) */
1545+ if (has_key(KEY_F(1)) == FALSE) {
1546+ show_scroll_win(main_window,
1547+ _("Instructions"),
1548+ _(menu_no_f_instructions));
1549+ }
1550+
1551+
1552+
1553+ /* do the work */
1554+ while (!global_exit) {
1555+ conf(&rootmenu);
1556+ if (!global_exit && do_exit() == 0)
1557+ break;
1558+ }
1559+ /* ok, we are done */
1560+ unpost_menu(curses_menu);
1561+ free_menu(curses_menu);
1562+ delwin(main_window);
1563+ clear();
1564+ refresh();
1565+ endwin();
1566+ return 0;
1567+}
1568+
scripts/kconfig/nconf.gui.c+617−0
@@ -0,0 +1,617 @@
1+/*
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+ */
8+#include "nconf.h"
9+
10+/* a list of all the different widgets we use */
11+attributes_t attributes[ATTR_MAX+1] = {0};
12+
13+/* available colors:
14+ COLOR_BLACK 0
15+ COLOR_RED 1
16+ COLOR_GREEN 2
17+ COLOR_YELLOW 3
18+ COLOR_BLUE 4
19+ COLOR_MAGENTA 5
20+ COLOR_CYAN 6
21+ COLOR_WHITE 7
22+ */
23+void set_normal_colors(void)
24+{
25+ init_pair(NORMAL, -1, -1);
26+ init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
27+
28+ /* FORE is for the selected item */
29+ init_pair(MAIN_MENU_FORE, -1, -1);
30+ /* BACK for all the rest */
31+ init_pair(MAIN_MENU_BACK, -1, -1);
32+ init_pair(MAIN_MENU_GREY, -1, -1);
33+ init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
34+ init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
35+
36+ init_pair(SCROLLWIN_TEXT, -1, -1);
37+ init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
38+ init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
39+
40+ init_pair(DIALOG_TEXT, -1, -1);
41+ init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
42+ init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
43+ init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
44+
45+ init_pair(INPUT_BOX, COLOR_YELLOW, -1);
46+ init_pair(INPUT_HEADING, COLOR_GREEN, -1);
47+ init_pair(INPUT_TEXT, -1, -1);
48+ init_pair(INPUT_FIELD, -1, -1);
49+
50+ init_pair(FUNCTION_HIGHLIGHT, -1, -1);
51+ init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
52+}
53+
54+/* available attributes:
55+ A_NORMAL Normal display (no highlight)
56+ A_STANDOUT Best highlighting mode of the terminal.
57+ A_UNDERLINE Underlining
58+ A_REVERSE Reverse video
59+ A_BLINK Blinking
60+ A_DIM Half bright
61+ A_BOLD Extra bright or bold
62+ A_PROTECT Protected mode
63+ A_INVIS Invisible or blank mode
64+ A_ALTCHARSET Alternate character set
65+ A_CHARTEXT Bit-mask to extract a character
66+ COLOR_PAIR(n) Color-pair number n
67+ */
68+void normal_color_theme(void)
69+{
70+ /* automatically add color... */
71+#define mkattr(name, attr) do { \
72+attributes[name] = attr | COLOR_PAIR(name); } while (0)
73+ mkattr(NORMAL, NORMAL);
74+ mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
75+
76+ mkattr(MAIN_MENU_FORE, A_REVERSE);
77+ mkattr(MAIN_MENU_BACK, A_NORMAL);
78+ mkattr(MAIN_MENU_GREY, A_NORMAL);
79+ mkattr(MAIN_MENU_HEADING, A_BOLD);
80+ mkattr(MAIN_MENU_BOX, A_NORMAL);
81+
82+ mkattr(SCROLLWIN_TEXT, A_NORMAL);
83+ mkattr(SCROLLWIN_HEADING, A_BOLD);
84+ mkattr(SCROLLWIN_BOX, A_BOLD);
85+
86+ mkattr(DIALOG_TEXT, A_BOLD);
87+ mkattr(DIALOG_BOX, A_BOLD);
88+ mkattr(DIALOG_MENU_FORE, A_STANDOUT);
89+ mkattr(DIALOG_MENU_BACK, A_NORMAL);
90+
91+ mkattr(INPUT_BOX, A_NORMAL);
92+ mkattr(INPUT_HEADING, A_BOLD);
93+ mkattr(INPUT_TEXT, A_NORMAL);
94+ mkattr(INPUT_FIELD, A_UNDERLINE);
95+
96+ mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
97+ mkattr(FUNCTION_TEXT, A_REVERSE);
98+}
99+
100+void no_colors_theme(void)
101+{
102+ /* automatically add highlight, no color */
103+#define mkattrn(name, attr) { attributes[name] = attr; }
104+
105+ mkattrn(NORMAL, NORMAL);
106+ mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
107+
108+ mkattrn(MAIN_MENU_FORE, A_STANDOUT);
109+ mkattrn(MAIN_MENU_BACK, A_NORMAL);
110+ mkattrn(MAIN_MENU_GREY, A_NORMAL);
111+ mkattrn(MAIN_MENU_HEADING, A_BOLD);
112+ mkattrn(MAIN_MENU_BOX, A_NORMAL);
113+
114+ mkattrn(SCROLLWIN_TEXT, A_NORMAL);
115+ mkattrn(SCROLLWIN_HEADING, A_BOLD);
116+ mkattrn(SCROLLWIN_BOX, A_BOLD);
117+
118+ mkattrn(DIALOG_TEXT, A_NORMAL);
119+ mkattrn(DIALOG_BOX, A_BOLD);
120+ mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
121+ mkattrn(DIALOG_MENU_BACK, A_NORMAL);
122+
123+ mkattrn(INPUT_BOX, A_BOLD);
124+ mkattrn(INPUT_HEADING, A_BOLD);
125+ mkattrn(INPUT_TEXT, A_NORMAL);
126+ mkattrn(INPUT_FIELD, A_UNDERLINE);
127+
128+ mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
129+ mkattrn(FUNCTION_TEXT, A_REVERSE);
130+}
131+
132+void set_colors()
133+{
134+ start_color();
135+ use_default_colors();
136+ set_normal_colors();
137+ if (has_colors()) {
138+ normal_color_theme();
139+ } else {
140+ /* give deafults */
141+ no_colors_theme();
142+ }
143+}
144+
145+
146+/* this changes the windows attributes !!! */
147+void print_in_middle(WINDOW *win,
148+ int starty,
149+ int startx,
150+ int width,
151+ const char *string,
152+ chtype color)
153+{ int length, x, y;
154+ float temp;
155+
156+
157+ if (win == NULL)
158+ win = stdscr;
159+ getyx(win, y, x);
160+ if (startx != 0)
161+ x = startx;
162+ if (starty != 0)
163+ y = starty;
164+ if (width == 0)
165+ width = 80;
166+
167+ length = strlen(string);
168+ temp = (width - length) / 2;
169+ x = startx + (int)temp;
170+ wattrset(win, color);
171+ mvwprintw(win, y, x, "%s", string);
172+ refresh();
173+}
174+
175+int get_line_no(const char *text)
176+{
177+ int i;
178+ int total = 1;
179+
180+ if (!text)
181+ return 0;
182+
183+ for (i = 0; text[i] != '\0'; i++)
184+ if (text[i] == '\n')
185+ total++;
186+ return total;
187+}
188+
189+const char *get_line(const char *text, int line_no)
190+{
191+ int i;
192+ int lines = 0;
193+
194+ if (!text)
195+ return 0;
196+
197+ for (i = 0; text[i] != '\0' && lines < line_no; i++)
198+ if (text[i] == '\n')
199+ lines++;
200+ return text+i;
201+}
202+
203+int get_line_length(const char *line)
204+{
205+ int res = 0;
206+ while (*line != '\0' && *line != '\n') {
207+ line++;
208+ res++;
209+ }
210+ return res;
211+}
212+
213+/* print all lines to the window. */
214+void fill_window(WINDOW *win, const char *text)
215+{
216+ int x, y;
217+ int total_lines = get_line_no(text);
218+ int i;
219+
220+ getmaxyx(win, y, x);
221+ /* do not go over end of line */
222+ total_lines = min(total_lines, y);
223+ for (i = 0; i < total_lines; i++) {
224+ char tmp[x+10];
225+ const char *line = get_line(text, i);
226+ int len = get_line_length(line);
227+ strncpy(tmp, line, min(len, x));
228+ tmp[len] = '\0';
229+ mvwprintw(win, i, 0, tmp);
230+ }
231+}
232+
233+/* get the message, and buttons.
234+ * each button must be a char*
235+ * return the selected button
236+ *
237+ * this dialog is used for 2 different things:
238+ * 1) show a text box, no buttons.
239+ * 2) show a dialog, with horizontal buttons
240+ */
241+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
242+{
243+ va_list ap;
244+ char *btn;
245+ int btns_width = 0;
246+ int msg_lines = 0;
247+ int msg_width = 0;
248+ int total_width;
249+ int win_rows = 0;
250+ WINDOW *win;
251+ WINDOW *msg_win;
252+ WINDOW *menu_win;
253+ MENU *menu;
254+ ITEM *btns[btn_num+1];
255+ int i, x, y;
256+ int res = -1;
257+
258+
259+ va_start(ap, btn_num);
260+ for (i = 0; i < btn_num; i++) {
261+ btn = va_arg(ap, char *);
262+ btns[i] = new_item(btn, "");
263+ btns_width += strlen(btn)+1;
264+ }
265+ va_end(ap);
266+ btns[btn_num] = NULL;
267+
268+ /* find the widest line of msg: */
269+ msg_lines = get_line_no(msg);
270+ for (i = 0; i < msg_lines; i++) {
271+ const char *line = get_line(msg, i);
272+ int len = get_line_length(line);
273+ if (msg_width < len)
274+ msg_width = len;
275+ }
276+
277+ total_width = max(msg_width, btns_width);
278+ /* place dialog in middle of screen */
279+ y = (LINES-(msg_lines+4))/2;
280+ x = (COLS-(total_width+4))/2;
281+
282+
283+ /* create the windows */
284+ if (btn_num > 0)
285+ win_rows = msg_lines+4;
286+ else
287+ win_rows = msg_lines+2;
288+
289+ win = newwin(win_rows, total_width+4, y, x);
290+ keypad(win, TRUE);
291+ menu_win = derwin(win, 1, btns_width, win_rows-2,
292+ 1+(total_width+2-btns_width)/2);
293+ menu = new_menu(btns);
294+ msg_win = derwin(win, win_rows-2, msg_width, 1,
295+ 1+(total_width+2-msg_width)/2);
296+
297+ set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
298+ set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
299+
300+ wattrset(win, attributes[DIALOG_BOX]);
301+ box(win, 0, 0);
302+
303+ /* print message */
304+ wattrset(msg_win, attributes[DIALOG_TEXT]);
305+ fill_window(msg_win, msg);
306+
307+ set_menu_win(menu, win);
308+ set_menu_sub(menu, menu_win);
309+ set_menu_format(menu, 1, btn_num);
310+ menu_opts_off(menu, O_SHOWDESC);
311+ menu_opts_off(menu, O_SHOWMATCH);
312+ menu_opts_on(menu, O_ONEVALUE);
313+ menu_opts_on(menu, O_NONCYCLIC);
314+ set_menu_mark(menu, "");
315+ post_menu(menu);
316+
317+
318+ touchwin(win);
319+ refresh_all_windows(main_window);
320+ while ((res = wgetch(win))) {
321+ switch (res) {
322+ case KEY_LEFT:
323+ menu_driver(menu, REQ_LEFT_ITEM);
324+ break;
325+ case KEY_RIGHT:
326+ menu_driver(menu, REQ_RIGHT_ITEM);
327+ break;
328+ case 10: /* ENTER */
329+ case 27: /* ESCAPE */
330+ case ' ':
331+ case KEY_F(F_BACK):
332+ case KEY_F(F_EXIT):
333+ break;
334+ }
335+ touchwin(win);
336+ refresh_all_windows(main_window);
337+
338+ if (res == 10 || res == ' ') {
339+ res = item_index(current_item(menu));
340+ break;
341+ } else if (res == 27 || res == KEY_F(F_BACK) ||
342+ res == KEY_F(F_EXIT)) {
343+ res = KEY_EXIT;
344+ break;
345+ }
346+ }
347+
348+ unpost_menu(menu);
349+ free_menu(menu);
350+ for (i = 0; i < btn_num; i++)
351+ free_item(btns[i]);
352+
353+ delwin(win);
354+ return res;
355+}
356+
357+int dialog_inputbox(WINDOW *main_window,
358+ const char *title, const char *prompt,
359+ const char *init, char *result, int result_len)
360+{
361+ int prompt_lines = 0;
362+ int prompt_width = 0;
363+ WINDOW *win;
364+ WINDOW *prompt_win;
365+ WINDOW *form_win;
366+ PANEL *panel;
367+ int i, x, y;
368+ int res = -1;
369+ int cursor_position = strlen(init);
370+
371+
372+ /* find the widest line of msg: */
373+ prompt_lines = get_line_no(prompt);
374+ for (i = 0; i < prompt_lines; i++) {
375+ const char *line = get_line(prompt, i);
376+ int len = get_line_length(line);
377+ prompt_width = max(prompt_width, len);
378+ }
379+
380+ if (title)
381+ prompt_width = max(prompt_width, strlen(title));
382+
383+ /* place dialog in middle of screen */
384+ y = (LINES-(prompt_lines+4))/2;
385+ x = (COLS-(prompt_width+4))/2;
386+
387+ strncpy(result, init, result_len);
388+
389+ /* create the windows */
390+ win = newwin(prompt_lines+6, prompt_width+7, y, x);
391+ prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
392+ form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
393+ keypad(form_win, TRUE);
394+
395+ wattrset(form_win, attributes[INPUT_FIELD]);
396+
397+ wattrset(win, attributes[INPUT_BOX]);
398+ box(win, 0, 0);
399+ wattrset(win, attributes[INPUT_HEADING]);
400+ if (title)
401+ mvwprintw(win, 0, 3, "%s", title);
402+
403+ /* print message */
404+ wattrset(prompt_win, attributes[INPUT_TEXT]);
405+ fill_window(prompt_win, prompt);
406+
407+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
408+ mvwprintw(form_win, 0, 0, "%s", result);
409+
410+ /* create panels */
411+ panel = new_panel(win);
412+
413+ /* show the cursor */
414+ curs_set(1);
415+
416+ touchwin(win);
417+ refresh_all_windows(main_window);
418+ while ((res = wgetch(form_win))) {
419+ int len = strlen(result);
420+ switch (res) {
421+ case 10: /* ENTER */
422+ case 27: /* ESCAPE */
423+ case KEY_F(F_HELP):
424+ case KEY_F(F_EXIT):
425+ case KEY_F(F_BACK):
426+ break;
427+ case 127:
428+ case KEY_BACKSPACE:
429+ if (cursor_position > 0) {
430+ memmove(&result[cursor_position-1],
431+ &result[cursor_position],
432+ len-cursor_position+1);
433+ cursor_position--;
434+ }
435+ break;
436+ case KEY_DC:
437+ if (cursor_position >= 0 && cursor_position < len) {
438+ memmove(&result[cursor_position],
439+ &result[cursor_position+1],
440+ len-cursor_position+1);
441+ }
442+ break;
443+ case KEY_UP:
444+ case KEY_RIGHT:
445+ if (cursor_position < len &&
446+ cursor_position < min(result_len, prompt_width))
447+ cursor_position++;
448+ break;
449+ case KEY_DOWN:
450+ case KEY_LEFT:
451+ if (cursor_position > 0)
452+ cursor_position--;
453+ break;
454+ default:
455+ if ((isgraph(res) || isspace(res)) &&
456+ len-2 < result_len) {
457+ /* insert the char at the proper position */
458+ memmove(&result[cursor_position+1],
459+ &result[cursor_position],
460+ len+1);
461+ result[cursor_position] = res;
462+ cursor_position++;
463+ } else {
464+ mvprintw(0, 0, "unknow key: %d\n", res);
465+ }
466+ break;
467+ }
468+ wmove(form_win, 0, 0);
469+ wclrtoeol(form_win);
470+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
471+ mvwprintw(form_win, 0, 0, "%s", result);
472+ wmove(form_win, 0, cursor_position);
473+ touchwin(win);
474+ refresh_all_windows(main_window);
475+
476+ if (res == 10) {
477+ res = 0;
478+ break;
479+ } else if (res == 27 || res == KEY_F(F_BACK) ||
480+ res == KEY_F(F_EXIT)) {
481+ res = KEY_EXIT;
482+ break;
483+ } else if (res == KEY_F(F_HELP)) {
484+ res = 1;
485+ break;
486+ }
487+ }
488+
489+ /* hide the cursor */
490+ curs_set(0);
491+ del_panel(panel);
492+ delwin(prompt_win);
493+ delwin(form_win);
494+ delwin(win);
495+ return res;
496+}
497+
498+/* refresh all windows in the correct order */
499+void refresh_all_windows(WINDOW *main_window)
500+{
501+ update_panels();
502+ touchwin(main_window);
503+ refresh();
504+}
505+
506+/* layman's scrollable window... */
507+void show_scroll_win(WINDOW *main_window,
508+ const char *title,
509+ const char *text)
510+{
511+ int res;
512+ int total_lines = get_line_no(text);
513+ int x, y;
514+ int start_x = 0, start_y = 0;
515+ int text_lines = 0, text_cols = 0;
516+ int total_cols = 0;
517+ int win_cols = 0;
518+ int win_lines = 0;
519+ int i = 0;
520+ WINDOW *win;
521+ WINDOW *pad;
522+ PANEL *panel;
523+
524+ /* find the widest line of msg: */
525+ total_lines = get_line_no(text);
526+ for (i = 0; i < total_lines; i++) {
527+ const char *line = get_line(text, i);
528+ int len = get_line_length(line);
529+ total_cols = max(total_cols, len+2);
530+ }
531+
532+ /* create the pad */
533+ pad = newpad(total_lines+10, total_cols+10);
534+ wattrset(pad, attributes[SCROLLWIN_TEXT]);
535+ fill_window(pad, text);
536+
537+ win_lines = min(total_lines+4, LINES-2);
538+ win_cols = min(total_cols+2, COLS-2);
539+ text_lines = max(win_lines-4, 0);
540+ text_cols = max(win_cols-2, 0);
541+
542+ /* place window in middle of screen */
543+ y = (LINES-win_lines)/2;
544+ x = (COLS-win_cols)/2;
545+
546+ win = newwin(win_lines, win_cols, y, x);
547+ keypad(win, TRUE);
548+ /* show the help in the help window, and show the help panel */
549+ wattrset(win, attributes[SCROLLWIN_BOX]);
550+ box(win, 0, 0);
551+ wattrset(win, attributes[SCROLLWIN_HEADING]);
552+ mvwprintw(win, 0, 3, " %s ", title);
553+ panel = new_panel(win);
554+
555+ /* handle scrolling */
556+ do {
557+
558+ copywin(pad, win, start_y, start_x, 2, 2, text_lines,
559+ text_cols, 0);
560+ print_in_middle(win,
561+ text_lines+2,
562+ 0,
563+ text_cols,
564+ "<OK>",
565+ attributes[DIALOG_MENU_FORE]);
566+ wrefresh(win);
567+
568+ res = wgetch(win);
569+ switch (res) {
570+ case KEY_NPAGE:
571+ case ' ':
572+ start_y += text_lines-2;
573+ break;
574+ case KEY_PPAGE:
575+ start_y -= text_lines+2;
576+ break;
577+ case KEY_HOME:
578+ start_y = 0;
579+ break;
580+ case KEY_END:
581+ start_y = total_lines-text_lines;
582+ break;
583+ case KEY_DOWN:
584+ case 'j':
585+ start_y++;
586+ break;
587+ case KEY_UP:
588+ case 'k':
589+ start_y--;
590+ break;
591+ case KEY_LEFT:
592+ case 'h':
593+ start_x--;
594+ break;
595+ case KEY_RIGHT:
596+ case 'l':
597+ start_x++;
598+ break;
599+ }
600+ if (res == 10 || res == 27 || res == 'q'
601+ || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
602+ break;
603+ }
604+ if (start_y < 0)
605+ start_y = 0;
606+ if (start_y >= total_lines-text_lines)
607+ start_y = total_lines-text_lines;
608+ if (start_x < 0)
609+ start_x = 0;
610+ if (start_x >= total_cols-text_cols)
611+ start_x = total_cols-text_cols;
612+ } while (res);
613+
614+ del_panel(panel);
615+ delwin(win);
616+ refresh_all_windows(main_window);
617+}
scripts/kconfig/nconf.h+95−0
@@ -0,0 +1,95 @@
1+/*
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+ */
8+
9+#include <ctype.h>
10+#include <errno.h>
11+#include <fcntl.h>
12+#include <limits.h>
13+#include <stdarg.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include <unistd.h>
17+#include <locale.h>
18+#include <curses.h>
19+#include <menu.h>
20+#include <panel.h>
21+#include <form.h>
22+
23+#include <stdio.h>
24+#include <time.h>
25+#include <sys/time.h>
26+
27+#include "ncurses.h"
28+
29+#define max(a, b) ({\
30+ typeof(a) _a = a;\
31+ typeof(b) _b = b;\
32+ _a > _b ? _a : _b; })
33+
34+#define min(a, b) ({\
35+ typeof(a) _a = a;\
36+ typeof(b) _b = b;\
37+ _a < _b ? _a : _b; })
38+
39+typedef enum {
40+ NORMAL = 1,
41+ MAIN_HEADING,
42+ MAIN_MENU_BOX,
43+ MAIN_MENU_FORE,
44+ MAIN_MENU_BACK,
45+ MAIN_MENU_GREY,
46+ MAIN_MENU_HEADING,
47+ SCROLLWIN_TEXT,
48+ SCROLLWIN_HEADING,
49+ SCROLLWIN_BOX,
50+ DIALOG_TEXT,
51+ DIALOG_MENU_FORE,
52+ DIALOG_MENU_BACK,
53+ DIALOG_BOX,
54+ INPUT_BOX,
55+ INPUT_HEADING,
56+ INPUT_TEXT,
57+ INPUT_FIELD,
58+ FUNCTION_TEXT,
59+ FUNCTION_HIGHLIGHT,
60+ ATTR_MAX
61+} attributes_t;
62+extern attributes_t attributes[];
63+
64+typedef enum {
65+ F_HELP = 1,
66+ F_SYMBOL = 2,
67+ F_INSTS = 3,
68+ F_CONF = 4,
69+ F_BACK = 5,
70+ F_SAVE = 6,
71+ F_LOAD = 7,
72+ F_EXIT = 8
73+} function_key;
74+
75+void set_colors(void);
76+
77+/* this changes the windows attributes !!! */
78+void print_in_middle(WINDOW *win,
79+ int starty,
80+ int startx,
81+ int width,
82+ const char *string,
83+ chtype color);
84+int get_line_length(const char *line);
85+int get_line_no(const char *text);
86+const char *get_line(const char *text, int line_no);
87+void fill_window(WINDOW *win, const char *text);
88+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
89+int dialog_inputbox(WINDOW *main_window,
90+ const char *title, const char *prompt,
91+ const char *init, char *result, int result_len);
92+void refresh_all_windows(WINDOW *main_window);
93+void show_scroll_win(WINDOW *main_window,
94+ const char *title,
95+ const char *text);
scripts/kconfig/zconf.tab.c_shipped+1−1
@@ -2220,7 +2220,7 @@ void conf_parse(const char *name) · 2219 unmodified lines
22202220 zconf_initscan(name);
22212221
22222222 sym_init();
2223− menu_init();
2223+ _menu_init();
22242224 modules_sym = sym_lookup(NULL, 0);
22252225 modules_sym->type = S_BOOLEAN;
22262226 modules_sym->flags |= SYMBOL_AUTO;
scripts/kconfig/zconf.y+1−1
@@ -475,7 +475,7 @@ void conf_parse(const char *name) · 474 unmodified lines
475475 zconf_initscan(name);
476476
477477 sym_init();
478− menu_init();
478+ _menu_init();
479479 modules_sym = sym_lookup(NULL, 0);
480480 modules_sym->type = S_BOOLEAN;
481481 modules_sym->flags |= SYMBOL_AUTO;