kconfig: add the nconf frontend
author"Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Thu May 12 19:45:30 2011 +0200 (2011-05-12)
changeset 2454c70da6c50bdb
parent 2453 3f3774e7e3b4
child 2455 c6655f80a217
kconfig: add the nconf frontend

The nconf frontend is the new hot topic in the kconfig land! :-)

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
.hgignore
kconfig/kconfig.mk
kconfig/nconf.c
kconfig/nconf.gui.c
kconfig/nconf.h
     1.1 --- a/.hgignore	Mon May 09 20:15:39 2011 +0200
     1.2 +++ b/.hgignore	Thu May 12 19:45:30 2011 +0200
     1.3 @@ -10,7 +10,7 @@
     1.4  scripts/saveSample.sh
     1.5  scripts/showTuple.sh
     1.6  kconfig/conf
     1.7 -kconfig/mconf
     1.8 +kconfig/?conf
     1.9  kconfig/**.o
    1.10  kconfig/**.dep
    1.11  config.gen/
     2.1 --- a/kconfig/kconfig.mk	Mon May 09 20:15:39 2011 +0200
     2.2 +++ b/kconfig/kconfig.mk	Thu May 12 19:45:30 2011 +0200
     2.3 @@ -11,7 +11,7 @@
     2.4  #-----------------------------------------------------------
     2.5  # The configurators rules
     2.6  
     2.7 -configurators = menuconfig oldconfig
     2.8 +configurators = menuconfig nconfig oldconfig
     2.9  PHONY += $(configurators)
    2.10  
    2.11  $(configurators): config_files
    2.12 @@ -20,6 +20,10 @@
    2.13  	@$(ECHO) "  CONF  $(KCONFIG_TOP)"
    2.14  	$(SILENT)$< $(KCONFIG_TOP)
    2.15  
    2.16 +nconfig: $(obj)/nconf
    2.17 +	@$(ECHO) "  CONF  $(KCONFIG_TOP)"
    2.18 +	$(SILENT)$< $(KCONFIG_TOP)
    2.19 +
    2.20  oldconfig: $(obj)/conf .config
    2.21  	@$(ECHO) "  CONF  $(KCONFIG_TOP)"
    2.22  	$(SILENT)$< --silent$@ $(KCONFIG_TOP)
    2.23 @@ -103,13 +107,24 @@
    2.24  mconf_DEP = $(patsubst %.c,%.dep,$(mconf_SRC))
    2.25  $(mconf_OBJ) $(mconf_DEP): CFLAGS += $(NCURSES_CFLAGS) $(INTL_CFLAGS)
    2.26  $(obj)/mconf: LDFLAGS += $(NCURSES_LDFLAGS)
    2.27 +
    2.28 +# What's needed to build 'nconf'
    2.29 +nconf_SRC = kconfig/nconf.c kconfig/nconf.gui.c
    2.30 +nconf_OBJ = $(patsubst %.c,%.o,$(nconf_SRC))
    2.31 +nconf_DEP = $(patsubst %.c,%.dep,$(nconf_SRC))
    2.32 +$(nconf_OBJ) $(nconf_DEP): CFLAGS += $(INTL_CFLAGS)
    2.33 +$(obj)/nconf: LDFLAGS += -lmenu -lpanel -lncurses
    2.34 +
    2.35 +# Under Cygwin, we need to auto-import some libs (which ones, exactly?)
    2.36 +# for mconf and nconf to lin properly.
    2.37  ifeq ($(shell uname -o 2>/dev/null || echo unknown),Cygwin)
    2.38  $(obj)/mconf: LDFLAGS += -Wl,--enable-auto-import
    2.39 +$(obj)/nconf: LDFLAGS += -Wl,--enable-auto-import
    2.40  endif
    2.41  
    2.42  # These are generated files:
    2.43 -ALL_OBJS = $(sort $(COMMON_OBJ) $(LX_OBJ) $(conf_OBJ) $(mconf_OBJ))
    2.44 -ALL_DEPS = $(sort $(COMMON_DEP) $(LX_DEP) $(conf_DEP) $(mconf_DEP))
    2.45 +ALL_OBJS = $(sort $(COMMON_OBJ) $(LX_OBJ) $(conf_OBJ) $(mconf_OBJ) $(nconf_OBJ))
    2.46 +ALL_DEPS = $(sort $(COMMON_DEP) $(LX_DEP) $(conf_DEP) $(mconf_DEP) $(nconf_DEP))
    2.47  
    2.48  # Cheesy auto-dependencies
    2.49  # Only parse the following if a configurator was called, to avoid building
    2.50 @@ -133,6 +148,9 @@
    2.51  $(LX_OBJ) $(LX_DEP): |dochecklxdialog
    2.52  $(mconf_OBJ) $(mconf_DEP): |dochecklxdialog
    2.53  endif
    2.54 +ifneq ($(strip $(filter nconfig,$(MAKECMDGOALS))),)
    2.55 +DEPS += $(nconf_DEP)
    2.56 +endif
    2.57  
    2.58  -include $(DEPS)
    2.59  
    2.60 @@ -170,6 +188,10 @@
    2.61  	@$(ECHO) '  LD    $@'
    2.62  	$(SILENT)$(HOST_LD) -o $@ $^ $(LDFLAGS) $(EXTRA_LDFLAGS)
    2.63  
    2.64 +$(obj)/nconf: $(COMMON_OBJ) $(nconf_OBJ)
    2.65 +	@$(ECHO) '  LD    $@'
    2.66 +	$(SILENT)$(HOST_LD) -o $@ $^ $(LDFLAGS) $(EXTRA_LDFLAGS)
    2.67 +
    2.68  $(obj)/conf: $(COMMON_OBJ) $(conf_OBJ)
    2.69  	@$(ECHO) '  LD    $@'
    2.70  	$(SILENT)$(HOST_LD) -o $@ $^ $(LDFLAGS) $(EXTRA_LDFLAGS)
    2.71 @@ -179,5 +201,5 @@
    2.72  
    2.73  clean::
    2.74  	@$(ECHO) "  CLEAN kconfig"
    2.75 -	$(SILENT)rm -f kconfig/{,m}conf{,.exe} $(ALL_OBJS) $(ALL_DEPS)
    2.76 +	$(SILENT)rm -f kconfig/{,m,n}conf{,.exe} $(ALL_OBJS) $(ALL_DEPS)
    2.77  	$(SILENT)rmdir --ignore-fail-on-non-empty kconfig{/lxdialog,} 2>/dev/null || true
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/kconfig/nconf.c	Thu May 12 19:45:30 2011 +0200
     3.3 @@ -0,0 +1,1561 @@
     3.4 +/*
     3.5 + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
     3.6 + * Released under the terms of the GNU GPL v2.0.
     3.7 + *
     3.8 + * Derived from menuconfig.
     3.9 + *
    3.10 + */
    3.11 +#define _GNU_SOURCE
    3.12 +#include <string.h>
    3.13 +#define LKC_DIRECT_LINK
    3.14 +#include "lkc.h"
    3.15 +#include "nconf.h"
    3.16 +#include <ctype.h>
    3.17 +
    3.18 +static const char nconf_readme[] = N_(
    3.19 +"Overview\n"
    3.20 +"--------\n"
    3.21 +"This interface let you select features and parameters for the build.\n"
    3.22 +"Features can either be built-in, modularized, or ignored. Parameters\n"
    3.23 +"must be entered in as decimal or hexadecimal numbers or text.\n"
    3.24 +"\n"
    3.25 +"Menu items beginning with following braces represent features that\n"
    3.26 +"  [ ] can be built in or removed\n"
    3.27 +"  < > can be built in, modularized or removed\n"
    3.28 +"  { } can be built in or modularized (selected by other feature)\n"
    3.29 +"  - - are selected by other feature,\n"
    3.30 +"  XXX cannot be selected. Use Symbol Info to find out why,\n"
    3.31 +"while *, M or whitespace inside braces means to build in, build as\n"
    3.32 +"a module or to exclude the feature respectively.\n"
    3.33 +"\n"
    3.34 +"To change any of these features, highlight it with the cursor\n"
    3.35 +"keys and press <Y> to build it in, <M> to make it a module or\n"
    3.36 +"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
    3.37 +"through the available options (ie. Y->N->M->Y).\n"
    3.38 +"\n"
    3.39 +"Some additional keyboard hints:\n"
    3.40 +"\n"
    3.41 +"Menus\n"
    3.42 +"----------\n"
    3.43 +"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
    3.44 +"   you wish to change use <Enter> or <Space>. Goto submenu by \n"
    3.45 +"   pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
    3.46 +"   Submenus are designated by \"--->\".\n"
    3.47 +"\n"
    3.48 +"   Searching: pressing '/' triggers interactive search mode.\n"
    3.49 +"              nconfig performs a case insensitive search for the string\n"
    3.50 +"              in the menu prompts (no regex support).\n"
    3.51 +"              Pressing the up/down keys highlights the previous/next\n"
    3.52 +"              matching item. Backspace removes one character from the\n"
    3.53 +"              match string. Pressing either '/' again or ESC exits\n"
    3.54 +"              search mode. All other keys behave normally.\n"
    3.55 +"\n"
    3.56 +"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
    3.57 +"   unseen options into view.\n"
    3.58 +"\n"
    3.59 +"o  To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
    3.60 +"\n"
    3.61 +"o  To get help with an item, press <F1>\n"
    3.62 +"   Shortcut: Press <h> or <?>.\n"
    3.63 +"\n"
    3.64 +"\n"
    3.65 +"Radiolists  (Choice lists)\n"
    3.66 +"-----------\n"
    3.67 +"o  Use the cursor keys to select the option you wish to set and press\n"
    3.68 +"   <S> or the <SPACE BAR>.\n"
    3.69 +"\n"
    3.70 +"   Shortcut: Press the first letter of the option you wish to set then\n"
    3.71 +"             press <S> or <SPACE BAR>.\n"
    3.72 +"\n"
    3.73 +"o  To see available help for the item, press <F1>\n"
    3.74 +"   Shortcut: Press <H> or <?>.\n"
    3.75 +"\n"
    3.76 +"\n"
    3.77 +"Data Entry\n"
    3.78 +"-----------\n"
    3.79 +"o  Enter the requested information and press <ENTER>\n"
    3.80 +"   If you are entering hexadecimal values, it is not necessary to\n"
    3.81 +"   add the '0x' prefix to the entry.\n"
    3.82 +"\n"
    3.83 +"o  For help, press <F1>.\n"
    3.84 +"\n"
    3.85 +"\n"
    3.86 +"Text Box    (Help Window)\n"
    3.87 +"--------\n"
    3.88 +"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
    3.89 +"   keys h,j,k,l function here as do <SPACE BAR> for those\n"
    3.90 +"   who are familiar with less and lynx.\n"
    3.91 +"\n"
    3.92 +"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
    3.93 +"\n"
    3.94 +"\n"
    3.95 +"Alternate Configuration Files\n"
    3.96 +"-----------------------------\n"
    3.97 +"nconfig supports the use of alternate configuration files for\n"
    3.98 +"those who, for various reasons, find it necessary to switch\n"
    3.99 +"between different configurations.\n"
   3.100 +"\n"
   3.101 +"At the end of the main menu you will find two options.  One is\n"
   3.102 +"for saving the current configuration to a file of your choosing.\n"
   3.103 +"The other option is for loading a previously saved alternate\n"
   3.104 +"configuration.\n"
   3.105 +"\n"
   3.106 +"Even if you don't use alternate configuration files, but you\n"
   3.107 +"find during a nconfig session that you have completely messed\n"
   3.108 +"up your settings, you may use the \"Load Alternate...\" option to\n"
   3.109 +"restore your previously saved settings from \".config\" without\n"
   3.110 +"restarting nconfig.\n"
   3.111 +"\n"
   3.112 +"Other information\n"
   3.113 +"-----------------\n"
   3.114 +"If you use nconfig in an XTERM window make sure you have your\n"
   3.115 +"$TERM variable set to point to a xterm definition which supports color.\n"
   3.116 +"Otherwise, nconfig will look rather bad.  nconfig will not\n"
   3.117 +"display correctly in a RXVT window because rxvt displays only one\n"
   3.118 +"intensity of color, bright.\n"
   3.119 +"\n"
   3.120 +"nconfig will display larger menus on screens or xterms which are\n"
   3.121 +"set to display more than the standard 25 row by 80 column geometry.\n"
   3.122 +"In order for this to work, the \"stty size\" command must be able to\n"
   3.123 +"display the screen's current row and column geometry.  I STRONGLY\n"
   3.124 +"RECOMMEND that you make sure you do NOT have the shell variables\n"
   3.125 +"LINES and COLUMNS exported into your environment.  Some distributions\n"
   3.126 +"export those variables via /etc/profile.  Some ncurses programs can\n"
   3.127 +"become confused when those variables (LINES & COLUMNS) don't reflect\n"
   3.128 +"the true screen size.\n"
   3.129 +"\n"
   3.130 +"Optional personality available\n"
   3.131 +"------------------------------\n"
   3.132 +"If you prefer to have all of the options listed in a single menu, rather\n"
   3.133 +"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
   3.134 +"environment variable set to single_menu. Example:\n"
   3.135 +"\n"
   3.136 +"make NCONFIG_MODE=single_menu nconfig\n"
   3.137 +"\n"
   3.138 +"<Enter> will then unroll the appropriate category, or enfold it if it\n"
   3.139 +"is already unrolled.\n"
   3.140 +"\n"
   3.141 +"Note that this mode can eventually be a little more CPU expensive\n"
   3.142 +"(especially with a larger number of unrolled categories) than the\n"
   3.143 +"default mode.\n"
   3.144 +"\n"),
   3.145 +menu_no_f_instructions[] = N_(
   3.146 +" You do not have function keys support. Please follow the\n"
   3.147 +" following instructions:\n"
   3.148 +" Arrow keys navigate the menu.\n"
   3.149 +" <Enter> or <right-arrow> selects submenus --->.\n"
   3.150 +" Capital Letters are hotkeys.\n"
   3.151 +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
   3.152 +" Pressing SpaceBar toggles between the above options.\n"
   3.153 +" Press <Esc> or <left-arrow> to go back one menu,\n"
   3.154 +" <?> or <h> for Help, </> for Search.\n"
   3.155 +" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
   3.156 +" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
   3.157 +" <Esc> always leaves the current window.\n"),
   3.158 +menu_instructions[] = N_(
   3.159 +" Arrow keys navigate the menu.\n"
   3.160 +" <Enter> or <right-arrow> selects submenus --->.\n"
   3.161 +" Capital Letters are hotkeys.\n"
   3.162 +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
   3.163 +" Pressing SpaceBar toggles between the above options\n"
   3.164 +" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
   3.165 +" <?>, <F1> or <h> for Help, </> for Search.\n"
   3.166 +" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
   3.167 +" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
   3.168 +" <Esc> always leaves the current window\n"),
   3.169 +radiolist_instructions[] = N_(
   3.170 +" Use the arrow keys to navigate this window or\n"
   3.171 +" press the hotkey of the item you wish to select\n"
   3.172 +" followed by the <SPACE BAR>.\n"
   3.173 +" Press <?>, <F1> or <h> for additional information about this option.\n"),
   3.174 +inputbox_instructions_int[] = N_(
   3.175 +"Please enter a decimal value.\n"
   3.176 +"Fractions will not be accepted.\n"
   3.177 +"Press <RETURN> to accept, <ESC> to cancel."),
   3.178 +inputbox_instructions_hex[] = N_(
   3.179 +"Please enter a hexadecimal value.\n"
   3.180 +"Press <RETURN> to accept, <ESC> to cancel."),
   3.181 +inputbox_instructions_string[] = N_(
   3.182 +"Please enter a string value.\n"
   3.183 +"Press <RETURN> to accept, <ESC> to cancel."),
   3.184 +setmod_text[] = N_(
   3.185 +"This feature depends on another which\n"
   3.186 +"has been configured as a module.\n"
   3.187 +"As a result, this feature will be built as a module."),
   3.188 +nohelp_text[] = N_(
   3.189 +"There is no help available for this option.\n"),
   3.190 +load_config_text[] = N_(
   3.191 +"Enter the name of the configuration file you wish to load.\n"
   3.192 +"Accept the name shown to restore the configuration you\n"
   3.193 +"last retrieved.  Leave blank to abort."),
   3.194 +load_config_help[] = N_(
   3.195 +"\n"
   3.196 +"For various reasons, one may wish to keep several different\n"
   3.197 +"configurations available on a single machine.\n"
   3.198 +"\n"
   3.199 +"If you have saved a previous configuration in a file other than the\n"
   3.200 +"default one, entering its name here will allow you to modify that\n"
   3.201 +"configuration.\n"
   3.202 +"\n"
   3.203 +"If you are uncertain, then you have probably never used alternate\n"
   3.204 +"configuration files.  You should therefor leave this blank to abort.\n"),
   3.205 +save_config_text[] = N_(
   3.206 +"Enter a filename to which this configuration should be saved\n"
   3.207 +"as an alternate.  Leave blank to abort."),
   3.208 +save_config_help[] = N_(
   3.209 +"\n"
   3.210 +"For various reasons, one may wish to keep different configurations\n"
   3.211 +"available on a single machine.\n"
   3.212 +"\n"
   3.213 +"Entering a file name here will allow you to later retrieve, modify\n"
   3.214 +"and use the current configuration as an alternate to whatever\n"
   3.215 +"configuration options you have selected at that time.\n"
   3.216 +"\n"
   3.217 +"If you are uncertain what all this means then you should probably\n"
   3.218 +"leave this blank.\n"),
   3.219 +search_help[] = N_(
   3.220 +"\n"
   3.221 +"Search for symbols and display their relations. Regular expressions\n"
   3.222 +"are allowed.\n"
   3.223 +"Example: search for \"^FOO\"\n"
   3.224 +"Result:\n"
   3.225 +"-----------------------------------------------------------------\n"
   3.226 +"Symbol: FOO [ = m]\n"
   3.227 +"Prompt: Foo bus is used to drive the bar HW\n"
   3.228 +"Defined at drivers/pci/Kconfig:47\n"
   3.229 +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
   3.230 +"Location:\n"
   3.231 +"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
   3.232 +"    -> PCI support (PCI [ = y])\n"
   3.233 +"      -> PCI access mode (<choice> [ = y])\n"
   3.234 +"Selects: LIBCRC32\n"
   3.235 +"Selected by: BAR\n"
   3.236 +"-----------------------------------------------------------------\n"
   3.237 +"o The line 'Prompt:' shows the text used in the menu structure for\n"
   3.238 +"  this symbol\n"
   3.239 +"o The 'Defined at' line tell at what file / line number the symbol\n"
   3.240 +"  is defined\n"
   3.241 +"o The 'Depends on:' line tell what symbols needs to be defined for\n"
   3.242 +"  this symbol to be visible in the menu (selectable)\n"
   3.243 +"o The 'Location:' lines tell where in the menu structure this symbol\n"
   3.244 +"  is located\n"
   3.245 +"    A location followed by a [ = y] indicate that this is a selectable\n"
   3.246 +"    menu item - and current value is displayed inside brackets.\n"
   3.247 +"o The 'Selects:' line tell what symbol will be automatically\n"
   3.248 +"  selected if this symbol is selected (y or m)\n"
   3.249 +"o The 'Selected by' line tell what symbol has selected this symbol\n"
   3.250 +"\n"
   3.251 +"Only relevant lines are shown.\n"
   3.252 +"\n\n"
   3.253 +"Search examples:\n"
   3.254 +"Examples: USB  => find all symbols containing USB\n"
   3.255 +"          ^USB => find all symbols starting with USB\n"
   3.256 +"          USB$ => find all symbols ending with USB\n"
   3.257 +"\n");
   3.258 +
   3.259 +struct mitem {
   3.260 +	char str[256];
   3.261 +	char tag;
   3.262 +	void *usrptr;
   3.263 +	int is_visible;
   3.264 +};
   3.265 +
   3.266 +#define MAX_MENU_ITEMS 4096
   3.267 +static int show_all_items;
   3.268 +static int indent;
   3.269 +static struct menu *current_menu;
   3.270 +static int child_count;
   3.271 +static int single_menu_mode;
   3.272 +/* the window in which all information appears */
   3.273 +static WINDOW *main_window;
   3.274 +/* the largest size of the menu window */
   3.275 +static int mwin_max_lines;
   3.276 +static int mwin_max_cols;
   3.277 +/* the window in which we show option buttons */
   3.278 +static MENU *curses_menu;
   3.279 +static ITEM *curses_menu_items[MAX_MENU_ITEMS];
   3.280 +static struct mitem k_menu_items[MAX_MENU_ITEMS];
   3.281 +static int items_num;
   3.282 +static int global_exit;
   3.283 +/* the currently selected button */
   3.284 +const char *current_instructions = menu_instructions;
   3.285 +
   3.286 +static void conf(struct menu *menu);
   3.287 +static void conf_choice(struct menu *menu);
   3.288 +static void conf_string(struct menu *menu);
   3.289 +static void conf_load(void);
   3.290 +static void conf_save(void);
   3.291 +static void show_help(struct menu *menu);
   3.292 +static int do_exit(void);
   3.293 +static void setup_windows(void);
   3.294 +static void search_conf(void);
   3.295 +
   3.296 +typedef void (*function_key_handler_t)(int *key, struct menu *menu);
   3.297 +static void handle_f1(int *key, struct menu *current_item);
   3.298 +static void handle_f2(int *key, struct menu *current_item);
   3.299 +static void handle_f3(int *key, struct menu *current_item);
   3.300 +static void handle_f4(int *key, struct menu *current_item);
   3.301 +static void handle_f5(int *key, struct menu *current_item);
   3.302 +static void handle_f6(int *key, struct menu *current_item);
   3.303 +static void handle_f7(int *key, struct menu *current_item);
   3.304 +static void handle_f8(int *key, struct menu *current_item);
   3.305 +static void handle_f9(int *key, struct menu *current_item);
   3.306 +
   3.307 +struct function_keys {
   3.308 +	const char *key_str;
   3.309 +	const char *func;
   3.310 +	function_key key;
   3.311 +	function_key_handler_t handler;
   3.312 +};
   3.313 +
   3.314 +static const int function_keys_num = 9;
   3.315 +struct function_keys function_keys[] = {
   3.316 +	{
   3.317 +		.key_str = "F1",
   3.318 +		.func = "Help",
   3.319 +		.key = F_HELP,
   3.320 +		.handler = handle_f1,
   3.321 +	},
   3.322 +	{
   3.323 +		.key_str = "F2",
   3.324 +		.func = "Sym Info",
   3.325 +		.key = F_SYMBOL,
   3.326 +		.handler = handle_f2,
   3.327 +	},
   3.328 +	{
   3.329 +		.key_str = "F3",
   3.330 +		.func = "Insts",
   3.331 +		.key = F_INSTS,
   3.332 +		.handler = handle_f3,
   3.333 +	},
   3.334 +	{
   3.335 +		.key_str = "F4",
   3.336 +		.func = "Config",
   3.337 +		.key = F_CONF,
   3.338 +		.handler = handle_f4,
   3.339 +	},
   3.340 +	{
   3.341 +		.key_str = "F5",
   3.342 +		.func = "Back",
   3.343 +		.key = F_BACK,
   3.344 +		.handler = handle_f5,
   3.345 +	},
   3.346 +	{
   3.347 +		.key_str = "F6",
   3.348 +		.func = "Save",
   3.349 +		.key = F_SAVE,
   3.350 +		.handler = handle_f6,
   3.351 +	},
   3.352 +	{
   3.353 +		.key_str = "F7",
   3.354 +		.func = "Load",
   3.355 +		.key = F_LOAD,
   3.356 +		.handler = handle_f7,
   3.357 +	},
   3.358 +	{
   3.359 +		.key_str = "F8",
   3.360 +		.func = "Sym Search",
   3.361 +		.key = F_SEARCH,
   3.362 +		.handler = handle_f8,
   3.363 +	},
   3.364 +	{
   3.365 +		.key_str = "F9",
   3.366 +		.func = "Exit",
   3.367 +		.key = F_EXIT,
   3.368 +		.handler = handle_f9,
   3.369 +	},
   3.370 +};
   3.371 +
   3.372 +static void print_function_line(void)
   3.373 +{
   3.374 +	int i;
   3.375 +	int offset = 1;
   3.376 +	const int skip = 1;
   3.377 +
   3.378 +	for (i = 0; i < function_keys_num; i++) {
   3.379 +		(void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
   3.380 +		mvwprintw(main_window, LINES-3, offset,
   3.381 +				"%s",
   3.382 +				function_keys[i].key_str);
   3.383 +		(void) wattrset(main_window, attributes[FUNCTION_TEXT]);
   3.384 +		offset += strlen(function_keys[i].key_str);
   3.385 +		mvwprintw(main_window, LINES-3,
   3.386 +				offset, "%s",
   3.387 +				function_keys[i].func);
   3.388 +		offset += strlen(function_keys[i].func) + skip;
   3.389 +	}
   3.390 +	(void) wattrset(main_window, attributes[NORMAL]);
   3.391 +}
   3.392 +
   3.393 +/* help */
   3.394 +static void handle_f1(int *key, struct menu *current_item)
   3.395 +{
   3.396 +	show_scroll_win(main_window,
   3.397 +			_("README"), _(nconf_readme));
   3.398 +	return;
   3.399 +}
   3.400 +
   3.401 +/* symbole help */
   3.402 +static void handle_f2(int *key, struct menu *current_item)
   3.403 +{
   3.404 +	show_help(current_item);
   3.405 +	return;
   3.406 +}
   3.407 +
   3.408 +/* instructions */
   3.409 +static void handle_f3(int *key, struct menu *current_item)
   3.410 +{
   3.411 +	show_scroll_win(main_window,
   3.412 +			_("Instructions"),
   3.413 +			_(current_instructions));
   3.414 +	return;
   3.415 +}
   3.416 +
   3.417 +/* config */
   3.418 +static void handle_f4(int *key, struct menu *current_item)
   3.419 +{
   3.420 +	int res = btn_dialog(main_window,
   3.421 +			_("Show all symbols?"),
   3.422 +			2,
   3.423 +			"   <Show All>   ",
   3.424 +			"<Don't show all>");
   3.425 +	if (res == 0)
   3.426 +		show_all_items = 1;
   3.427 +	else if (res == 1)
   3.428 +		show_all_items = 0;
   3.429 +
   3.430 +	return;
   3.431 +}
   3.432 +
   3.433 +/* back */
   3.434 +static void handle_f5(int *key, struct menu *current_item)
   3.435 +{
   3.436 +	*key = KEY_LEFT;
   3.437 +	return;
   3.438 +}
   3.439 +
   3.440 +/* save */
   3.441 +static void handle_f6(int *key, struct menu *current_item)
   3.442 +{
   3.443 +	conf_save();
   3.444 +	return;
   3.445 +}
   3.446 +
   3.447 +/* load */
   3.448 +static void handle_f7(int *key, struct menu *current_item)
   3.449 +{
   3.450 +	conf_load();
   3.451 +	return;
   3.452 +}
   3.453 +
   3.454 +/* search */
   3.455 +static void handle_f8(int *key, struct menu *current_item)
   3.456 +{
   3.457 +	search_conf();
   3.458 +	return;
   3.459 +}
   3.460 +
   3.461 +/* exit */
   3.462 +static void handle_f9(int *key, struct menu *current_item)
   3.463 +{
   3.464 +	do_exit();
   3.465 +	return;
   3.466 +}
   3.467 +
   3.468 +/* return != 0 to indicate the key was handles */
   3.469 +static int process_special_keys(int *key, struct menu *menu)
   3.470 +{
   3.471 +	int i;
   3.472 +
   3.473 +	if (*key == KEY_RESIZE) {
   3.474 +		setup_windows();
   3.475 +		return 1;
   3.476 +	}
   3.477 +
   3.478 +	for (i = 0; i < function_keys_num; i++) {
   3.479 +		if (*key == KEY_F(function_keys[i].key) ||
   3.480 +		    *key == '0' + function_keys[i].key){
   3.481 +			function_keys[i].handler(key, menu);
   3.482 +			return 1;
   3.483 +		}
   3.484 +	}
   3.485 +
   3.486 +	return 0;
   3.487 +}
   3.488 +
   3.489 +static void clean_items(void)
   3.490 +{
   3.491 +	int i;
   3.492 +	for (i = 0; curses_menu_items[i]; i++)
   3.493 +		free_item(curses_menu_items[i]);
   3.494 +	bzero(curses_menu_items, sizeof(curses_menu_items));
   3.495 +	bzero(k_menu_items, sizeof(k_menu_items));
   3.496 +	items_num = 0;
   3.497 +}
   3.498 +
   3.499 +typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
   3.500 +	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
   3.501 +
   3.502 +/* return the index of the matched item, or -1 if no such item exists */
   3.503 +static int get_mext_match(const char *match_str, match_f flag)
   3.504 +{
   3.505 +	int match_start = item_index(current_item(curses_menu));
   3.506 +	int index;
   3.507 +
   3.508 +	if (flag == FIND_NEXT_MATCH_DOWN)
   3.509 +		++match_start;
   3.510 +	else if (flag == FIND_NEXT_MATCH_UP)
   3.511 +		--match_start;
   3.512 +
   3.513 +	index = match_start;
   3.514 +	index = (index + items_num) % items_num;
   3.515 +	while (true) {
   3.516 +		char *str = k_menu_items[index].str;
   3.517 +		if (strcasestr(str, match_str) != 0)
   3.518 +			return index;
   3.519 +		if (flag == FIND_NEXT_MATCH_UP ||
   3.520 +		    flag == MATCH_TINKER_PATTERN_UP)
   3.521 +			--index;
   3.522 +		else
   3.523 +			++index;
   3.524 +		index = (index + items_num) % items_num;
   3.525 +		if (index == match_start)
   3.526 +			return -1;
   3.527 +	}
   3.528 +}
   3.529 +
   3.530 +/* Make a new item. */
   3.531 +static void item_make(struct menu *menu, char tag, const char *fmt, ...)
   3.532 +{
   3.533 +	va_list ap;
   3.534 +
   3.535 +	if (items_num > MAX_MENU_ITEMS-1)
   3.536 +		return;
   3.537 +
   3.538 +	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
   3.539 +	k_menu_items[items_num].tag = tag;
   3.540 +	k_menu_items[items_num].usrptr = menu;
   3.541 +	if (menu != NULL)
   3.542 +		k_menu_items[items_num].is_visible =
   3.543 +			menu_is_visible(menu);
   3.544 +	else
   3.545 +		k_menu_items[items_num].is_visible = 1;
   3.546 +
   3.547 +	va_start(ap, fmt);
   3.548 +	vsnprintf(k_menu_items[items_num].str,
   3.549 +		  sizeof(k_menu_items[items_num].str),
   3.550 +		  fmt, ap);
   3.551 +	va_end(ap);
   3.552 +
   3.553 +	if (!k_menu_items[items_num].is_visible)
   3.554 +		memcpy(k_menu_items[items_num].str, "XXX", 3);
   3.555 +
   3.556 +	curses_menu_items[items_num] = new_item(
   3.557 +			k_menu_items[items_num].str,
   3.558 +			k_menu_items[items_num].str);
   3.559 +	set_item_userptr(curses_menu_items[items_num],
   3.560 +			&k_menu_items[items_num]);
   3.561 +	/*
   3.562 +	if (!k_menu_items[items_num].is_visible)
   3.563 +		item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
   3.564 +	*/
   3.565 +
   3.566 +	items_num++;
   3.567 +	curses_menu_items[items_num] = NULL;
   3.568 +}
   3.569 +
   3.570 +/* very hackish. adds a string to the last item added */
   3.571 +static void item_add_str(const char *fmt, ...)
   3.572 +{
   3.573 +	va_list ap;
   3.574 +	int index = items_num-1;
   3.575 +	char new_str[256];
   3.576 +	char tmp_str[256];
   3.577 +
   3.578 +	if (index < 0)
   3.579 +		return;
   3.580 +
   3.581 +	va_start(ap, fmt);
   3.582 +	vsnprintf(new_str, sizeof(new_str), fmt, ap);
   3.583 +	va_end(ap);
   3.584 +	snprintf(tmp_str, sizeof(tmp_str), "%s%s",
   3.585 +			k_menu_items[index].str, new_str);
   3.586 +	strncpy(k_menu_items[index].str,
   3.587 +		tmp_str,
   3.588 +		sizeof(k_menu_items[index].str));
   3.589 +
   3.590 +	free_item(curses_menu_items[index]);
   3.591 +	curses_menu_items[index] = new_item(
   3.592 +			k_menu_items[index].str,
   3.593 +			k_menu_items[index].str);
   3.594 +	set_item_userptr(curses_menu_items[index],
   3.595 +			&k_menu_items[index]);
   3.596 +}
   3.597 +
   3.598 +/* get the tag of the currently selected item */
   3.599 +static char item_tag(void)
   3.600 +{
   3.601 +	ITEM *cur;
   3.602 +	struct mitem *mcur;
   3.603 +
   3.604 +	cur = current_item(curses_menu);
   3.605 +	if (cur == NULL)
   3.606 +		return 0;
   3.607 +	mcur = (struct mitem *) item_userptr(cur);
   3.608 +	return mcur->tag;
   3.609 +}
   3.610 +
   3.611 +static int curses_item_index(void)
   3.612 +{
   3.613 +	return  item_index(current_item(curses_menu));
   3.614 +}
   3.615 +
   3.616 +static void *item_data(void)
   3.617 +{
   3.618 +	ITEM *cur;
   3.619 +	struct mitem *mcur;
   3.620 +
   3.621 +	cur = current_item(curses_menu);
   3.622 +	if (!cur)
   3.623 +		return NULL;
   3.624 +	mcur = (struct mitem *) item_userptr(cur);
   3.625 +	return mcur->usrptr;
   3.626 +
   3.627 +}
   3.628 +
   3.629 +static int item_is_tag(char tag)
   3.630 +{
   3.631 +	return item_tag() == tag;
   3.632 +}
   3.633 +
   3.634 +static char filename[PATH_MAX+1];
   3.635 +static char menu_backtitle[PATH_MAX+128];
   3.636 +static const char *set_config_filename(const char *config_filename)
   3.637 +{
   3.638 +	int size;
   3.639 +
   3.640 +	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
   3.641 +			"%s - %s", config_filename, rootmenu.prompt->text);
   3.642 +	if (size >= sizeof(menu_backtitle))
   3.643 +		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
   3.644 +
   3.645 +	size = snprintf(filename, sizeof(filename), "%s", config_filename);
   3.646 +	if (size >= sizeof(filename))
   3.647 +		filename[sizeof(filename)-1] = '\0';
   3.648 +	return menu_backtitle;
   3.649 +}
   3.650 +
   3.651 +/* return = 0 means we are successful.
   3.652 + * -1 means go on doing what you were doing
   3.653 + */
   3.654 +static int do_exit(void)
   3.655 +{
   3.656 +	int res;
   3.657 +	if (!conf_get_changed()) {
   3.658 +		global_exit = 1;
   3.659 +		return 0;
   3.660 +	}
   3.661 +	res = btn_dialog(main_window,
   3.662 +			_("Do you wish to save your new configuration?\n"
   3.663 +				"<ESC> to cancel and resume nconfig."),
   3.664 +			2,
   3.665 +			"   <save>   ",
   3.666 +			"<don't save>");
   3.667 +	if (res == KEY_EXIT) {
   3.668 +		global_exit = 0;
   3.669 +		return -1;
   3.670 +	}
   3.671 +
   3.672 +	/* if we got here, the user really wants to exit */
   3.673 +	switch (res) {
   3.674 +	case 0:
   3.675 +		res = conf_write(filename);
   3.676 +		if (res)
   3.677 +			btn_dialog(
   3.678 +				main_window,
   3.679 +				_("Error during writing of configuration.\n"
   3.680 +				  "Your configuration changes were NOT saved."),
   3.681 +				  1,
   3.682 +				  "<OK>");
   3.683 +		break;
   3.684 +	default:
   3.685 +		btn_dialog(
   3.686 +			main_window,
   3.687 +			_("Your configuration changes were NOT saved."),
   3.688 +			1,
   3.689 +			"<OK>");
   3.690 +		break;
   3.691 +	}
   3.692 +	global_exit = 1;
   3.693 +	return 0;
   3.694 +}
   3.695 +
   3.696 +
   3.697 +static void search_conf(void)
   3.698 +{
   3.699 +	struct symbol **sym_arr;
   3.700 +	struct gstr res;
   3.701 +	char dialog_input_result[100];
   3.702 +	char *dialog_input;
   3.703 +	int dres;
   3.704 +again:
   3.705 +	dres = dialog_inputbox(main_window,
   3.706 +			_("Search Configuration Parameter"),
   3.707 +			_("Enter " CONFIG_ " (sub)string to search for "
   3.708 +				"(with or without \"" CONFIG_ "\")"),
   3.709 +			"", dialog_input_result, 99);
   3.710 +	switch (dres) {
   3.711 +	case 0:
   3.712 +		break;
   3.713 +	case 1:
   3.714 +		show_scroll_win(main_window,
   3.715 +				_("Search Configuration"), search_help);
   3.716 +		goto again;
   3.717 +	default:
   3.718 +		return;
   3.719 +	}
   3.720 +
   3.721 +	/* strip the prefix if necessary */
   3.722 +	dialog_input = dialog_input_result;
   3.723 +	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
   3.724 +		dialog_input += strlen(CONFIG_);
   3.725 +
   3.726 +	sym_arr = sym_re_search(dialog_input);
   3.727 +	res = get_relations_str(sym_arr);
   3.728 +	free(sym_arr);
   3.729 +	show_scroll_win(main_window,
   3.730 +			_("Search Results"), str_get(&res));
   3.731 +	str_free(&res);
   3.732 +}
   3.733 +
   3.734 +
   3.735 +static void build_conf(struct menu *menu)
   3.736 +{
   3.737 +	struct symbol *sym;
   3.738 +	struct property *prop;
   3.739 +	struct menu *child;
   3.740 +	int type, tmp, doint = 2;
   3.741 +	tristate val;
   3.742 +	char ch;
   3.743 +
   3.744 +	if (!menu || (!show_all_items && !menu_is_visible(menu)))
   3.745 +		return;
   3.746 +
   3.747 +	sym = menu->sym;
   3.748 +	prop = menu->prompt;
   3.749 +	if (!sym) {
   3.750 +		if (prop && menu != current_menu) {
   3.751 +			const char *prompt = menu_get_prompt(menu);
   3.752 +			enum prop_type ptype;
   3.753 +			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
   3.754 +			switch (ptype) {
   3.755 +			case P_MENU:
   3.756 +				child_count++;
   3.757 +				prompt = _(prompt);
   3.758 +				if (single_menu_mode) {
   3.759 +					item_make(menu, 'm',
   3.760 +						"%s%*c%s",
   3.761 +						menu->data ? "-->" : "++>",
   3.762 +						indent + 1, ' ', prompt);
   3.763 +				} else
   3.764 +					item_make(menu, 'm',
   3.765 +						"   %*c%s  --->",
   3.766 +						indent + 1,
   3.767 +						' ', prompt);
   3.768 +
   3.769 +				if (single_menu_mode && menu->data)
   3.770 +					goto conf_childs;
   3.771 +				return;
   3.772 +			case P_COMMENT:
   3.773 +				if (prompt) {
   3.774 +					child_count++;
   3.775 +					item_make(menu, ':',
   3.776 +						"   %*c*** %s ***",
   3.777 +						indent + 1, ' ',
   3.778 +						_(prompt));
   3.779 +				}
   3.780 +				break;
   3.781 +			default:
   3.782 +				if (prompt) {
   3.783 +					child_count++;
   3.784 +					item_make(menu, ':', "---%*c%s",
   3.785 +						indent + 1, ' ',
   3.786 +						_(prompt));
   3.787 +				}
   3.788 +			}
   3.789 +		} else
   3.790 +			doint = 0;
   3.791 +		goto conf_childs;
   3.792 +	}
   3.793 +
   3.794 +	type = sym_get_type(sym);
   3.795 +	if (sym_is_choice(sym)) {
   3.796 +		struct symbol *def_sym = sym_get_choice_value(sym);
   3.797 +		struct menu *def_menu = NULL;
   3.798 +
   3.799 +		child_count++;
   3.800 +		for (child = menu->list; child; child = child->next) {
   3.801 +			if (menu_is_visible(child) && child->sym == def_sym)
   3.802 +				def_menu = child;
   3.803 +		}
   3.804 +
   3.805 +		val = sym_get_tristate_value(sym);
   3.806 +		if (sym_is_changable(sym)) {
   3.807 +			switch (type) {
   3.808 +			case S_BOOLEAN:
   3.809 +				item_make(menu, 't', "[%c]",
   3.810 +						val == no ? ' ' : '*');
   3.811 +				break;
   3.812 +			case S_TRISTATE:
   3.813 +				switch (val) {
   3.814 +				case yes:
   3.815 +					ch = '*';
   3.816 +					break;
   3.817 +				case mod:
   3.818 +					ch = 'M';
   3.819 +					break;
   3.820 +				default:
   3.821 +					ch = ' ';
   3.822 +					break;
   3.823 +				}
   3.824 +				item_make(menu, 't', "<%c>", ch);
   3.825 +				break;
   3.826 +			}
   3.827 +		} else {
   3.828 +			item_make(menu, def_menu ? 't' : ':', "   ");
   3.829 +		}
   3.830 +
   3.831 +		item_add_str("%*c%s", indent + 1,
   3.832 +				' ', _(menu_get_prompt(menu)));
   3.833 +		if (val == yes) {
   3.834 +			if (def_menu) {
   3.835 +				item_add_str(" (%s)",
   3.836 +					_(menu_get_prompt(def_menu)));
   3.837 +				item_add_str("  --->");
   3.838 +				if (def_menu->list) {
   3.839 +					indent += 2;
   3.840 +					build_conf(def_menu);
   3.841 +					indent -= 2;
   3.842 +				}
   3.843 +			}
   3.844 +			return;
   3.845 +		}
   3.846 +	} else {
   3.847 +		if (menu == current_menu) {
   3.848 +			item_make(menu, ':',
   3.849 +				"---%*c%s", indent + 1,
   3.850 +				' ', _(menu_get_prompt(menu)));
   3.851 +			goto conf_childs;
   3.852 +		}
   3.853 +		child_count++;
   3.854 +		val = sym_get_tristate_value(sym);
   3.855 +		if (sym_is_choice_value(sym) && val == yes) {
   3.856 +			item_make(menu, ':', "   ");
   3.857 +		} else {
   3.858 +			switch (type) {
   3.859 +			case S_BOOLEAN:
   3.860 +				if (sym_is_changable(sym))
   3.861 +					item_make(menu, 't', "[%c]",
   3.862 +						val == no ? ' ' : '*');
   3.863 +				else
   3.864 +					item_make(menu, 't', "-%c-",
   3.865 +						val == no ? ' ' : '*');
   3.866 +				break;
   3.867 +			case S_TRISTATE:
   3.868 +				switch (val) {
   3.869 +				case yes:
   3.870 +					ch = '*';
   3.871 +					break;
   3.872 +				case mod:
   3.873 +					ch = 'M';
   3.874 +					break;
   3.875 +				default:
   3.876 +					ch = ' ';
   3.877 +					break;
   3.878 +				}
   3.879 +				if (sym_is_changable(sym)) {
   3.880 +					if (sym->rev_dep.tri == mod)
   3.881 +						item_make(menu,
   3.882 +							't', "{%c}", ch);
   3.883 +					else
   3.884 +						item_make(menu,
   3.885 +							't', "<%c>", ch);
   3.886 +				} else
   3.887 +					item_make(menu, 't', "-%c-", ch);
   3.888 +				break;
   3.889 +			default:
   3.890 +				tmp = 2 + strlen(sym_get_string_value(sym));
   3.891 +				item_make(menu, 's', "    (%s)",
   3.892 +						sym_get_string_value(sym));
   3.893 +				tmp = indent - tmp + 4;
   3.894 +				if (tmp < 0)
   3.895 +					tmp = 0;
   3.896 +				item_add_str("%*c%s%s", tmp, ' ',
   3.897 +						_(menu_get_prompt(menu)),
   3.898 +						(sym_has_value(sym) ||
   3.899 +						 !sym_is_changable(sym)) ? "" :
   3.900 +						_(" (NEW)"));
   3.901 +				goto conf_childs;
   3.902 +			}
   3.903 +		}
   3.904 +		item_add_str("%*c%s%s", indent + 1, ' ',
   3.905 +				_(menu_get_prompt(menu)),
   3.906 +				(sym_has_value(sym) || !sym_is_changable(sym)) ?
   3.907 +				"" : _(" (NEW)"));
   3.908 +		if (menu->prompt && menu->prompt->type == P_MENU) {
   3.909 +			item_add_str("  --->");
   3.910 +			return;
   3.911 +		}
   3.912 +	}
   3.913 +
   3.914 +conf_childs:
   3.915 +	indent += doint;
   3.916 +	for (child = menu->list; child; child = child->next)
   3.917 +		build_conf(child);
   3.918 +	indent -= doint;
   3.919 +}
   3.920 +
   3.921 +static void reset_menu(void)
   3.922 +{
   3.923 +	unpost_menu(curses_menu);
   3.924 +	clean_items();
   3.925 +}
   3.926 +
   3.927 +/* adjust the menu to show this item.
   3.928 + * prefer not to scroll the menu if possible*/
   3.929 +static void center_item(int selected_index, int *last_top_row)
   3.930 +{
   3.931 +	int toprow;
   3.932 +
   3.933 +	set_top_row(curses_menu, *last_top_row);
   3.934 +	toprow = top_row(curses_menu);
   3.935 +	if (selected_index < toprow ||
   3.936 +	    selected_index >= toprow+mwin_max_lines) {
   3.937 +		toprow = max(selected_index-mwin_max_lines/2, 0);
   3.938 +		if (toprow >= item_count(curses_menu)-mwin_max_lines)
   3.939 +			toprow = item_count(curses_menu)-mwin_max_lines;
   3.940 +		set_top_row(curses_menu, toprow);
   3.941 +	}
   3.942 +	set_current_item(curses_menu,
   3.943 +			curses_menu_items[selected_index]);
   3.944 +	*last_top_row = toprow;
   3.945 +	post_menu(curses_menu);
   3.946 +	refresh_all_windows(main_window);
   3.947 +}
   3.948 +
   3.949 +/* this function assumes reset_menu has been called before */
   3.950 +static void show_menu(const char *prompt, const char *instructions,
   3.951 +		int selected_index, int *last_top_row)
   3.952 +{
   3.953 +	int maxx, maxy;
   3.954 +	WINDOW *menu_window;
   3.955 +
   3.956 +	current_instructions = instructions;
   3.957 +
   3.958 +	clear();
   3.959 +	(void) wattrset(main_window, attributes[NORMAL]);
   3.960 +	print_in_middle(stdscr, 1, 0, COLS,
   3.961 +			menu_backtitle,
   3.962 +			attributes[MAIN_HEADING]);
   3.963 +
   3.964 +	(void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
   3.965 +	box(main_window, 0, 0);
   3.966 +	(void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
   3.967 +	mvwprintw(main_window, 0, 3, " %s ", prompt);
   3.968 +	(void) wattrset(main_window, attributes[NORMAL]);
   3.969 +
   3.970 +	set_menu_items(curses_menu, curses_menu_items);
   3.971 +
   3.972 +	/* position the menu at the middle of the screen */
   3.973 +	scale_menu(curses_menu, &maxy, &maxx);
   3.974 +	maxx = min(maxx, mwin_max_cols-2);
   3.975 +	maxy = mwin_max_lines;
   3.976 +	menu_window = derwin(main_window,
   3.977 +			maxy,
   3.978 +			maxx,
   3.979 +			2,
   3.980 +			(mwin_max_cols-maxx)/2);
   3.981 +	keypad(menu_window, TRUE);
   3.982 +	set_menu_win(curses_menu, menu_window);
   3.983 +	set_menu_sub(curses_menu, menu_window);
   3.984 +
   3.985 +	/* must reassert this after changing items, otherwise returns to a
   3.986 +	 * default of 16
   3.987 +	 */
   3.988 +	set_menu_format(curses_menu, maxy, 1);
   3.989 +	center_item(selected_index, last_top_row);
   3.990 +	set_menu_format(curses_menu, maxy, 1);
   3.991 +
   3.992 +	print_function_line();
   3.993 +
   3.994 +	/* Post the menu */
   3.995 +	post_menu(curses_menu);
   3.996 +	refresh_all_windows(main_window);
   3.997 +}
   3.998 +
   3.999 +static void adj_match_dir(match_f *match_direction)
  3.1000 +{
  3.1001 +	if (*match_direction == FIND_NEXT_MATCH_DOWN)
  3.1002 +		*match_direction =
  3.1003 +			MATCH_TINKER_PATTERN_DOWN;
  3.1004 +	else if (*match_direction == FIND_NEXT_MATCH_UP)
  3.1005 +		*match_direction =
  3.1006 +			MATCH_TINKER_PATTERN_UP;
  3.1007 +	/* else, do no change.. */
  3.1008 +}
  3.1009 +
  3.1010 +struct match_state
  3.1011 +{
  3.1012 +	int in_search;
  3.1013 +	match_f match_direction;
  3.1014 +	char pattern[256];
  3.1015 +};
  3.1016 +
  3.1017 +/* Return 0 means I have handled the key. In such a case, ans should hold the
  3.1018 + * item to center, or -1 otherwise.
  3.1019 + * Else return -1 .
  3.1020 + */
  3.1021 +static int do_match(int key, struct match_state *state, int *ans)
  3.1022 +{
  3.1023 +	char c = (char) key;
  3.1024 +	int terminate_search = 0;
  3.1025 +	*ans = -1;
  3.1026 +	if (key == '/' || (state->in_search && key == 27)) {
  3.1027 +		move(0, 0);
  3.1028 +		refresh();
  3.1029 +		clrtoeol();
  3.1030 +		state->in_search = 1-state->in_search;
  3.1031 +		bzero(state->pattern, sizeof(state->pattern));
  3.1032 +		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
  3.1033 +		return 0;
  3.1034 +	} else if (!state->in_search)
  3.1035 +		return 1;
  3.1036 +
  3.1037 +	if (isalnum(c) || isgraph(c) || c == ' ') {
  3.1038 +		state->pattern[strlen(state->pattern)] = c;
  3.1039 +		state->pattern[strlen(state->pattern)] = '\0';
  3.1040 +		adj_match_dir(&state->match_direction);
  3.1041 +		*ans = get_mext_match(state->pattern,
  3.1042 +				state->match_direction);
  3.1043 +	} else if (key == KEY_DOWN) {
  3.1044 +		state->match_direction = FIND_NEXT_MATCH_DOWN;
  3.1045 +		*ans = get_mext_match(state->pattern,
  3.1046 +				state->match_direction);
  3.1047 +	} else if (key == KEY_UP) {
  3.1048 +		state->match_direction = FIND_NEXT_MATCH_UP;
  3.1049 +		*ans = get_mext_match(state->pattern,
  3.1050 +				state->match_direction);
  3.1051 +	} else if (key == KEY_BACKSPACE || key == 127) {
  3.1052 +		state->pattern[strlen(state->pattern)-1] = '\0';
  3.1053 +		adj_match_dir(&state->match_direction);
  3.1054 +	} else
  3.1055 +		terminate_search = 1;
  3.1056 +
  3.1057 +	if (terminate_search) {
  3.1058 +		state->in_search = 0;
  3.1059 +		bzero(state->pattern, sizeof(state->pattern));
  3.1060 +		move(0, 0);
  3.1061 +		refresh();
  3.1062 +		clrtoeol();
  3.1063 +		return -1;
  3.1064 +	}
  3.1065 +	return 0;
  3.1066 +}
  3.1067 +
  3.1068 +static void conf(struct menu *menu)
  3.1069 +{
  3.1070 +	struct menu *submenu = 0;
  3.1071 +	const char *prompt = menu_get_prompt(menu);
  3.1072 +	struct symbol *sym;
  3.1073 +	struct menu *active_menu = NULL;
  3.1074 +	int res;
  3.1075 +	int current_index = 0;
  3.1076 +	int last_top_row = 0;
  3.1077 +	struct match_state match_state = {
  3.1078 +		.in_search = 0,
  3.1079 +		.match_direction = MATCH_TINKER_PATTERN_DOWN,
  3.1080 +		.pattern = "",
  3.1081 +	};
  3.1082 +
  3.1083 +	while (!global_exit) {
  3.1084 +		reset_menu();
  3.1085 +		current_menu = menu;
  3.1086 +		build_conf(menu);
  3.1087 +		if (!child_count)
  3.1088 +			break;
  3.1089 +
  3.1090 +		show_menu(prompt ? _(prompt) : _("Main Menu"),
  3.1091 +				_(menu_instructions),
  3.1092 +				current_index, &last_top_row);
  3.1093 +		keypad((menu_win(curses_menu)), TRUE);
  3.1094 +		while (!global_exit) {
  3.1095 +			if (match_state.in_search) {
  3.1096 +				mvprintw(0, 0,
  3.1097 +					"searching: %s", match_state.pattern);
  3.1098 +				clrtoeol();
  3.1099 +			}
  3.1100 +			refresh_all_windows(main_window);
  3.1101 +			res = wgetch(menu_win(curses_menu));
  3.1102 +			if (!res)
  3.1103 +				break;
  3.1104 +			if (do_match(res, &match_state, &current_index) == 0) {
  3.1105 +				if (current_index != -1)
  3.1106 +					center_item(current_index,
  3.1107 +						    &last_top_row);
  3.1108 +				continue;
  3.1109 +			}
  3.1110 +			if (process_special_keys(&res,
  3.1111 +						(struct menu *) item_data()))
  3.1112 +				break;
  3.1113 +			switch (res) {
  3.1114 +			case KEY_DOWN:
  3.1115 +				menu_driver(curses_menu, REQ_DOWN_ITEM);
  3.1116 +				break;
  3.1117 +			case KEY_UP:
  3.1118 +				menu_driver(curses_menu, REQ_UP_ITEM);
  3.1119 +				break;
  3.1120 +			case KEY_NPAGE:
  3.1121 +				menu_driver(curses_menu, REQ_SCR_DPAGE);
  3.1122 +				break;
  3.1123 +			case KEY_PPAGE:
  3.1124 +				menu_driver(curses_menu, REQ_SCR_UPAGE);
  3.1125 +				break;
  3.1126 +			case KEY_HOME:
  3.1127 +				menu_driver(curses_menu, REQ_FIRST_ITEM);
  3.1128 +				break;
  3.1129 +			case KEY_END:
  3.1130 +				menu_driver(curses_menu, REQ_LAST_ITEM);
  3.1131 +				break;
  3.1132 +			case 'h':
  3.1133 +			case '?':
  3.1134 +				show_help((struct menu *) item_data());
  3.1135 +				break;
  3.1136 +			}
  3.1137 +			if (res == 10 || res == 27 ||
  3.1138 +				res == 32 || res == 'n' || res == 'y' ||
  3.1139 +				res == KEY_LEFT || res == KEY_RIGHT ||
  3.1140 +				res == 'm')
  3.1141 +				break;
  3.1142 +			refresh_all_windows(main_window);
  3.1143 +		}
  3.1144 +
  3.1145 +		refresh_all_windows(main_window);
  3.1146 +		/* if ESC or left*/
  3.1147 +		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
  3.1148 +			break;
  3.1149 +
  3.1150 +		/* remember location in the menu */
  3.1151 +		last_top_row = top_row(curses_menu);
  3.1152 +		current_index = curses_item_index();
  3.1153 +
  3.1154 +		if (!item_tag())
  3.1155 +			continue;
  3.1156 +
  3.1157 +		submenu = (struct menu *) item_data();
  3.1158 +		active_menu = (struct menu *)item_data();
  3.1159 +		if (!submenu || !menu_is_visible(submenu))
  3.1160 +			continue;
  3.1161 +		if (submenu)
  3.1162 +			sym = submenu->sym;
  3.1163 +		else
  3.1164 +			sym = NULL;
  3.1165 +
  3.1166 +		switch (res) {
  3.1167 +		case ' ':
  3.1168 +			if (item_is_tag('t'))
  3.1169 +				sym_toggle_tristate_value(sym);
  3.1170 +			else if (item_is_tag('m'))
  3.1171 +				conf(submenu);
  3.1172 +			break;
  3.1173 +		case KEY_RIGHT:
  3.1174 +		case 10: /* ENTER WAS PRESSED */
  3.1175 +			switch (item_tag()) {
  3.1176 +			case 'm':
  3.1177 +				if (single_menu_mode)
  3.1178 +					submenu->data =
  3.1179 +						(void *) (long) !submenu->data;
  3.1180 +				else
  3.1181 +					conf(submenu);
  3.1182 +				break;
  3.1183 +			case 't':
  3.1184 +				if (sym_is_choice(sym) &&
  3.1185 +				    sym_get_tristate_value(sym) == yes)
  3.1186 +					conf_choice(submenu);
  3.1187 +				else if (submenu->prompt &&
  3.1188 +					 submenu->prompt->type == P_MENU)
  3.1189 +					conf(submenu);
  3.1190 +				else if (res == 10)
  3.1191 +					sym_toggle_tristate_value(sym);
  3.1192 +				break;
  3.1193 +			case 's':
  3.1194 +				conf_string(submenu);
  3.1195 +				break;
  3.1196 +			}
  3.1197 +			break;
  3.1198 +		case 'y':
  3.1199 +			if (item_is_tag('t')) {
  3.1200 +				if (sym_set_tristate_value(sym, yes))
  3.1201 +					break;
  3.1202 +				if (sym_set_tristate_value(sym, mod))
  3.1203 +					btn_dialog(main_window, setmod_text, 0);
  3.1204 +			}
  3.1205 +			break;
  3.1206 +		case 'n':
  3.1207 +			if (item_is_tag('t'))
  3.1208 +				sym_set_tristate_value(sym, no);
  3.1209 +			break;
  3.1210 +		case 'm':
  3.1211 +			if (item_is_tag('t'))
  3.1212 +				sym_set_tristate_value(sym, mod);
  3.1213 +			break;
  3.1214 +		}
  3.1215 +	}
  3.1216 +}
  3.1217 +
  3.1218 +static void conf_message_callback(const char *fmt, va_list ap)
  3.1219 +{
  3.1220 +	char buf[1024];
  3.1221 +
  3.1222 +	vsnprintf(buf, sizeof(buf), fmt, ap);
  3.1223 +	btn_dialog(main_window, buf, 1, "<OK>");
  3.1224 +}
  3.1225 +
  3.1226 +static void show_help(struct menu *menu)
  3.1227 +{
  3.1228 +	struct gstr help = str_new();
  3.1229 +
  3.1230 +	if (menu && menu->sym && menu_has_help(menu)) {
  3.1231 +		if (menu->sym->name) {
  3.1232 +			str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
  3.1233 +			str_append(&help, _(menu_get_help(menu)));
  3.1234 +			str_append(&help, "\n");
  3.1235 +			get_symbol_str(&help, menu->sym);
  3.1236 +		} else {
  3.1237 +			str_append(&help, _(menu_get_help(menu)));
  3.1238 +		}
  3.1239 +	} else {
  3.1240 +		str_append(&help, nohelp_text);
  3.1241 +	}
  3.1242 +	show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
  3.1243 +	str_free(&help);
  3.1244 +}
  3.1245 +
  3.1246 +static void conf_choice(struct menu *menu)
  3.1247 +{
  3.1248 +	const char *prompt = _(menu_get_prompt(menu));
  3.1249 +	struct menu *child = 0;
  3.1250 +	struct symbol *active;
  3.1251 +	int selected_index = 0;
  3.1252 +	int last_top_row = 0;
  3.1253 +	int res, i = 0;
  3.1254 +	struct match_state match_state = {
  3.1255 +		.in_search = 0,
  3.1256 +		.match_direction = MATCH_TINKER_PATTERN_DOWN,
  3.1257 +		.pattern = "",
  3.1258 +	};
  3.1259 +
  3.1260 +	active = sym_get_choice_value(menu->sym);
  3.1261 +	/* this is mostly duplicated from the conf() function. */
  3.1262 +	while (!global_exit) {
  3.1263 +		reset_menu();
  3.1264 +
  3.1265 +		for (i = 0, child = menu->list; child; child = child->next) {
  3.1266 +			if (!show_all_items && !menu_is_visible(child))
  3.1267 +				continue;
  3.1268 +
  3.1269 +			if (child->sym == sym_get_choice_value(menu->sym))
  3.1270 +				item_make(child, ':', "<X> %s",
  3.1271 +						_(menu_get_prompt(child)));
  3.1272 +			else if (child->sym)
  3.1273 +				item_make(child, ':', "    %s",
  3.1274 +						_(menu_get_prompt(child)));
  3.1275 +			else
  3.1276 +				item_make(child, ':', "*** %s ***",
  3.1277 +						_(menu_get_prompt(child)));
  3.1278 +
  3.1279 +			if (child->sym == active){
  3.1280 +				last_top_row = top_row(curses_menu);
  3.1281 +				selected_index = i;
  3.1282 +			}
  3.1283 +			i++;
  3.1284 +		}
  3.1285 +		show_menu(prompt ? _(prompt) : _("Choice Menu"),
  3.1286 +				_(radiolist_instructions),
  3.1287 +				selected_index,
  3.1288 +				&last_top_row);
  3.1289 +		while (!global_exit) {
  3.1290 +			if (match_state.in_search) {
  3.1291 +				mvprintw(0, 0, "searching: %s",
  3.1292 +					 match_state.pattern);
  3.1293 +				clrtoeol();
  3.1294 +			}
  3.1295 +			refresh_all_windows(main_window);
  3.1296 +			res = wgetch(menu_win(curses_menu));
  3.1297 +			if (!res)
  3.1298 +				break;
  3.1299 +			if (do_match(res, &match_state, &selected_index) == 0) {
  3.1300 +				if (selected_index != -1)
  3.1301 +					center_item(selected_index,
  3.1302 +						    &last_top_row);
  3.1303 +				continue;
  3.1304 +			}
  3.1305 +			if (process_special_keys(
  3.1306 +						&res,
  3.1307 +						(struct menu *) item_data()))
  3.1308 +				break;
  3.1309 +			switch (res) {
  3.1310 +			case KEY_DOWN:
  3.1311 +				menu_driver(curses_menu, REQ_DOWN_ITEM);
  3.1312 +				break;
  3.1313 +			case KEY_UP:
  3.1314 +				menu_driver(curses_menu, REQ_UP_ITEM);
  3.1315 +				break;
  3.1316 +			case KEY_NPAGE:
  3.1317 +				menu_driver(curses_menu, REQ_SCR_DPAGE);
  3.1318 +				break;
  3.1319 +			case KEY_PPAGE:
  3.1320 +				menu_driver(curses_menu, REQ_SCR_UPAGE);
  3.1321 +				break;
  3.1322 +			case KEY_HOME:
  3.1323 +				menu_driver(curses_menu, REQ_FIRST_ITEM);
  3.1324 +				break;
  3.1325 +			case KEY_END:
  3.1326 +				menu_driver(curses_menu, REQ_LAST_ITEM);
  3.1327 +				break;
  3.1328 +			case 'h':
  3.1329 +			case '?':
  3.1330 +				show_help((struct menu *) item_data());
  3.1331 +				break;
  3.1332 +			}
  3.1333 +			if (res == 10 || res == 27 || res == ' ' ||
  3.1334 +					res == KEY_LEFT){
  3.1335 +				break;
  3.1336 +			}
  3.1337 +			refresh_all_windows(main_window);
  3.1338 +		}
  3.1339 +		/* if ESC or left */
  3.1340 +		if (res == 27 || res == KEY_LEFT)
  3.1341 +			break;
  3.1342 +
  3.1343 +		child = item_data();
  3.1344 +		if (!child || !menu_is_visible(child) || !child->sym)
  3.1345 +			continue;
  3.1346 +		switch (res) {
  3.1347 +		case ' ':
  3.1348 +		case  10:
  3.1349 +		case KEY_RIGHT:
  3.1350 +			sym_set_tristate_value(child->sym, yes);
  3.1351 +			return;
  3.1352 +		case 'h':
  3.1353 +		case '?':
  3.1354 +			show_help(child);
  3.1355 +			active = child->sym;
  3.1356 +			break;
  3.1357 +		case KEY_EXIT:
  3.1358 +			return;
  3.1359 +		}
  3.1360 +	}
  3.1361 +}
  3.1362 +
  3.1363 +static void conf_string(struct menu *menu)
  3.1364 +{
  3.1365 +	const char *prompt = menu_get_prompt(menu);
  3.1366 +	char dialog_input_result[256];
  3.1367 +
  3.1368 +	while (1) {
  3.1369 +		int res;
  3.1370 +		const char *heading;
  3.1371 +
  3.1372 +		switch (sym_get_type(menu->sym)) {
  3.1373 +		case S_INT:
  3.1374 +			heading = _(inputbox_instructions_int);
  3.1375 +			break;
  3.1376 +		case S_HEX:
  3.1377 +			heading = _(inputbox_instructions_hex);
  3.1378 +			break;
  3.1379 +		case S_STRING:
  3.1380 +			heading = _(inputbox_instructions_string);
  3.1381 +			break;
  3.1382 +		default:
  3.1383 +			heading = _("Internal nconf error!");
  3.1384 +		}
  3.1385 +		res = dialog_inputbox(main_window,
  3.1386 +				prompt ? _(prompt) : _("Main Menu"),
  3.1387 +				heading,
  3.1388 +				sym_get_string_value(menu->sym),
  3.1389 +				dialog_input_result,
  3.1390 +				sizeof(dialog_input_result));
  3.1391 +		switch (res) {
  3.1392 +		case 0:
  3.1393 +			if (sym_set_string_value(menu->sym,
  3.1394 +						dialog_input_result))
  3.1395 +				return;
  3.1396 +			btn_dialog(main_window,
  3.1397 +				_("You have made an invalid entry."), 0);
  3.1398 +			break;
  3.1399 +		case 1:
  3.1400 +			show_help(menu);
  3.1401 +			break;
  3.1402 +		case KEY_EXIT:
  3.1403 +			return;
  3.1404 +		}
  3.1405 +	}
  3.1406 +}
  3.1407 +
  3.1408 +static void conf_load(void)
  3.1409 +{
  3.1410 +	char dialog_input_result[256];
  3.1411 +	while (1) {
  3.1412 +		int res;
  3.1413 +		res = dialog_inputbox(main_window,
  3.1414 +				NULL, load_config_text,
  3.1415 +				filename,
  3.1416 +				dialog_input_result,
  3.1417 +				sizeof(dialog_input_result));
  3.1418 +		switch (res) {
  3.1419 +		case 0:
  3.1420 +			if (!dialog_input_result[0])
  3.1421 +				return;
  3.1422 +			if (!conf_read(dialog_input_result)) {
  3.1423 +				set_config_filename(dialog_input_result);
  3.1424 +				sym_set_change_count(1);
  3.1425 +				return;
  3.1426 +			}
  3.1427 +			btn_dialog(main_window, _("File does not exist!"), 0);
  3.1428 +			break;
  3.1429 +		case 1:
  3.1430 +			show_scroll_win(main_window,
  3.1431 +					_("Load Alternate Configuration"),
  3.1432 +					load_config_help);
  3.1433 +			break;
  3.1434 +		case KEY_EXIT:
  3.1435 +			return;
  3.1436 +		}
  3.1437 +	}
  3.1438 +}
  3.1439 +
  3.1440 +static void conf_save(void)
  3.1441 +{
  3.1442 +	char dialog_input_result[256];
  3.1443 +	while (1) {
  3.1444 +		int res;
  3.1445 +		res = dialog_inputbox(main_window,
  3.1446 +				NULL, save_config_text,
  3.1447 +				filename,
  3.1448 +				dialog_input_result,
  3.1449 +				sizeof(dialog_input_result));
  3.1450 +		switch (res) {
  3.1451 +		case 0:
  3.1452 +			if (!dialog_input_result[0])
  3.1453 +				return;
  3.1454 +			res = conf_write(dialog_input_result);
  3.1455 +			if (!res) {
  3.1456 +				set_config_filename(dialog_input_result);
  3.1457 +				return;
  3.1458 +			}
  3.1459 +			btn_dialog(main_window, _("Can't create file! "
  3.1460 +				"Probably a nonexistent directory."),
  3.1461 +				1, "<OK>");
  3.1462 +			break;
  3.1463 +		case 1:
  3.1464 +			show_scroll_win(main_window,
  3.1465 +				_("Save Alternate Configuration"),
  3.1466 +				save_config_help);
  3.1467 +			break;
  3.1468 +		case KEY_EXIT:
  3.1469 +			return;
  3.1470 +		}
  3.1471 +	}
  3.1472 +}
  3.1473 +
  3.1474 +void setup_windows(void)
  3.1475 +{
  3.1476 +	if (main_window != NULL)
  3.1477 +		delwin(main_window);
  3.1478 +
  3.1479 +	/* set up the menu and menu window */
  3.1480 +	main_window = newwin(LINES-2, COLS-2, 2, 1);
  3.1481 +	keypad(main_window, TRUE);
  3.1482 +	mwin_max_lines = LINES-7;
  3.1483 +	mwin_max_cols = COLS-6;
  3.1484 +
  3.1485 +	/* panels order is from bottom to top */
  3.1486 +	new_panel(main_window);
  3.1487 +}
  3.1488 +
  3.1489 +int main(int ac, char **av)
  3.1490 +{
  3.1491 +	char *mode;
  3.1492 +
  3.1493 +	setlocale(LC_ALL, "");
  3.1494 +	bindtextdomain(PACKAGE, LOCALEDIR);
  3.1495 +	textdomain(PACKAGE);
  3.1496 +
  3.1497 +	conf_parse(av[1]);
  3.1498 +	conf_read(NULL);
  3.1499 +
  3.1500 +	mode = getenv("NCONFIG_MODE");
  3.1501 +	if (mode) {
  3.1502 +		if (!strcasecmp(mode, "single_menu"))
  3.1503 +			single_menu_mode = 1;
  3.1504 +	}
  3.1505 +
  3.1506 +	/* Initialize curses */
  3.1507 +	initscr();
  3.1508 +	/* set color theme */
  3.1509 +	set_colors();
  3.1510 +
  3.1511 +	cbreak();
  3.1512 +	noecho();
  3.1513 +	keypad(stdscr, TRUE);
  3.1514 +	curs_set(0);
  3.1515 +
  3.1516 +	if (COLS < 75 || LINES < 20) {
  3.1517 +		endwin();
  3.1518 +		printf("Your terminal should have at "
  3.1519 +			"least 20 lines and 75 columns\n");
  3.1520 +		return 1;
  3.1521 +	}
  3.1522 +
  3.1523 +	notimeout(stdscr, FALSE);
  3.1524 +	ESCDELAY = 1;
  3.1525 +
  3.1526 +	/* set btns menu */
  3.1527 +	curses_menu = new_menu(curses_menu_items);
  3.1528 +	menu_opts_off(curses_menu, O_SHOWDESC);
  3.1529 +	menu_opts_on(curses_menu, O_SHOWMATCH);
  3.1530 +	menu_opts_on(curses_menu, O_ONEVALUE);
  3.1531 +	menu_opts_on(curses_menu, O_NONCYCLIC);
  3.1532 +	menu_opts_on(curses_menu, O_IGNORECASE);
  3.1533 +	set_menu_mark(curses_menu, " ");
  3.1534 +	set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
  3.1535 +	set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
  3.1536 +	set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
  3.1537 +
  3.1538 +	set_config_filename(conf_get_configname());
  3.1539 +	setup_windows();
  3.1540 +
  3.1541 +	/* check for KEY_FUNC(1) */
  3.1542 +	if (has_key(KEY_F(1)) == FALSE) {
  3.1543 +		show_scroll_win(main_window,
  3.1544 +				_("Instructions"),
  3.1545 +				_(menu_no_f_instructions));
  3.1546 +	}
  3.1547 +
  3.1548 +	conf_set_message_callback(conf_message_callback);
  3.1549 +	/* do the work */
  3.1550 +	while (!global_exit) {
  3.1551 +		conf(&rootmenu);
  3.1552 +		if (!global_exit && do_exit() == 0)
  3.1553 +			break;
  3.1554 +	}
  3.1555 +	/* ok, we are done */
  3.1556 +	unpost_menu(curses_menu);
  3.1557 +	free_menu(curses_menu);
  3.1558 +	delwin(main_window);
  3.1559 +	clear();
  3.1560 +	refresh();
  3.1561 +	endwin();
  3.1562 +	return 0;
  3.1563 +}
  3.1564 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/kconfig/nconf.gui.c	Thu May 12 19:45:30 2011 +0200
     4.3 @@ -0,0 +1,617 @@
     4.4 +/*
     4.5 + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
     4.6 + * Released under the terms of the GNU GPL v2.0.
     4.7 + *
     4.8 + * Derived from menuconfig.
     4.9 + *
    4.10 + */
    4.11 +#include "nconf.h"
    4.12 +
    4.13 +/* a list of all the different widgets we use */
    4.14 +attributes_t attributes[ATTR_MAX+1] = {0};
    4.15 +
    4.16 +/* available colors:
    4.17 +   COLOR_BLACK   0
    4.18 +   COLOR_RED     1
    4.19 +   COLOR_GREEN   2
    4.20 +   COLOR_YELLOW  3
    4.21 +   COLOR_BLUE    4
    4.22 +   COLOR_MAGENTA 5
    4.23 +   COLOR_CYAN    6
    4.24 +   COLOR_WHITE   7
    4.25 +   */
    4.26 +static void set_normal_colors(void)
    4.27 +{
    4.28 +	init_pair(NORMAL, -1, -1);
    4.29 +	init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
    4.30 +
    4.31 +	/* FORE is for the selected item */
    4.32 +	init_pair(MAIN_MENU_FORE, -1, -1);
    4.33 +	/* BACK for all the rest */
    4.34 +	init_pair(MAIN_MENU_BACK, -1, -1);
    4.35 +	init_pair(MAIN_MENU_GREY, -1, -1);
    4.36 +	init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
    4.37 +	init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
    4.38 +
    4.39 +	init_pair(SCROLLWIN_TEXT, -1, -1);
    4.40 +	init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
    4.41 +	init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
    4.42 +
    4.43 +	init_pair(DIALOG_TEXT, -1, -1);
    4.44 +	init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
    4.45 +	init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
    4.46 +	init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
    4.47 +
    4.48 +	init_pair(INPUT_BOX, COLOR_YELLOW, -1);
    4.49 +	init_pair(INPUT_HEADING, COLOR_GREEN, -1);
    4.50 +	init_pair(INPUT_TEXT, -1, -1);
    4.51 +	init_pair(INPUT_FIELD, -1, -1);
    4.52 +
    4.53 +	init_pair(FUNCTION_HIGHLIGHT, -1, -1);
    4.54 +	init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
    4.55 +}
    4.56 +
    4.57 +/* available attributes:
    4.58 +   A_NORMAL        Normal display (no highlight)
    4.59 +   A_STANDOUT      Best highlighting mode of the terminal.
    4.60 +   A_UNDERLINE     Underlining
    4.61 +   A_REVERSE       Reverse video
    4.62 +   A_BLINK         Blinking
    4.63 +   A_DIM           Half bright
    4.64 +   A_BOLD          Extra bright or bold
    4.65 +   A_PROTECT       Protected mode
    4.66 +   A_INVIS         Invisible or blank mode
    4.67 +   A_ALTCHARSET    Alternate character set
    4.68 +   A_CHARTEXT      Bit-mask to extract a character
    4.69 +   COLOR_PAIR(n)   Color-pair number n
    4.70 +   */
    4.71 +static void normal_color_theme(void)
    4.72 +{
    4.73 +	/* automatically add color... */
    4.74 +#define mkattr(name, attr) do { \
    4.75 +attributes[name] = attr | COLOR_PAIR(name); } while (0)
    4.76 +	mkattr(NORMAL, NORMAL);
    4.77 +	mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
    4.78 +
    4.79 +	mkattr(MAIN_MENU_FORE, A_REVERSE);
    4.80 +	mkattr(MAIN_MENU_BACK, A_NORMAL);
    4.81 +	mkattr(MAIN_MENU_GREY, A_NORMAL);
    4.82 +	mkattr(MAIN_MENU_HEADING, A_BOLD);
    4.83 +	mkattr(MAIN_MENU_BOX, A_NORMAL);
    4.84 +
    4.85 +	mkattr(SCROLLWIN_TEXT, A_NORMAL);
    4.86 +	mkattr(SCROLLWIN_HEADING, A_BOLD);
    4.87 +	mkattr(SCROLLWIN_BOX, A_BOLD);
    4.88 +
    4.89 +	mkattr(DIALOG_TEXT, A_BOLD);
    4.90 +	mkattr(DIALOG_BOX, A_BOLD);
    4.91 +	mkattr(DIALOG_MENU_FORE, A_STANDOUT);
    4.92 +	mkattr(DIALOG_MENU_BACK, A_NORMAL);
    4.93 +
    4.94 +	mkattr(INPUT_BOX, A_NORMAL);
    4.95 +	mkattr(INPUT_HEADING, A_BOLD);
    4.96 +	mkattr(INPUT_TEXT, A_NORMAL);
    4.97 +	mkattr(INPUT_FIELD, A_UNDERLINE);
    4.98 +
    4.99 +	mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
   4.100 +	mkattr(FUNCTION_TEXT, A_REVERSE);
   4.101 +}
   4.102 +
   4.103 +static void no_colors_theme(void)
   4.104 +{
   4.105 +	/* automatically add highlight, no color */
   4.106 +#define mkattrn(name, attr) { attributes[name] = attr; }
   4.107 +
   4.108 +	mkattrn(NORMAL, NORMAL);
   4.109 +	mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
   4.110 +
   4.111 +	mkattrn(MAIN_MENU_FORE, A_STANDOUT);
   4.112 +	mkattrn(MAIN_MENU_BACK, A_NORMAL);
   4.113 +	mkattrn(MAIN_MENU_GREY, A_NORMAL);
   4.114 +	mkattrn(MAIN_MENU_HEADING, A_BOLD);
   4.115 +	mkattrn(MAIN_MENU_BOX, A_NORMAL);
   4.116 +
   4.117 +	mkattrn(SCROLLWIN_TEXT, A_NORMAL);
   4.118 +	mkattrn(SCROLLWIN_HEADING, A_BOLD);
   4.119 +	mkattrn(SCROLLWIN_BOX, A_BOLD);
   4.120 +
   4.121 +	mkattrn(DIALOG_TEXT, A_NORMAL);
   4.122 +	mkattrn(DIALOG_BOX, A_BOLD);
   4.123 +	mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
   4.124 +	mkattrn(DIALOG_MENU_BACK, A_NORMAL);
   4.125 +
   4.126 +	mkattrn(INPUT_BOX, A_BOLD);
   4.127 +	mkattrn(INPUT_HEADING, A_BOLD);
   4.128 +	mkattrn(INPUT_TEXT, A_NORMAL);
   4.129 +	mkattrn(INPUT_FIELD, A_UNDERLINE);
   4.130 +
   4.131 +	mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
   4.132 +	mkattrn(FUNCTION_TEXT, A_REVERSE);
   4.133 +}
   4.134 +
   4.135 +void set_colors()
   4.136 +{
   4.137 +	start_color();
   4.138 +	use_default_colors();
   4.139 +	set_normal_colors();
   4.140 +	if (has_colors()) {
   4.141 +		normal_color_theme();
   4.142 +	} else {
   4.143 +		/* give defaults */
   4.144 +		no_colors_theme();
   4.145 +	}
   4.146 +}
   4.147 +
   4.148 +
   4.149 +/* this changes the windows attributes !!! */
   4.150 +void print_in_middle(WINDOW *win,
   4.151 +		int starty,
   4.152 +		int startx,
   4.153 +		int width,
   4.154 +		const char *string,
   4.155 +		chtype color)
   4.156 +{      int length, x, y;
   4.157 +	float temp;
   4.158 +
   4.159 +
   4.160 +	if (win == NULL)
   4.161 +		win = stdscr;
   4.162 +	getyx(win, y, x);
   4.163 +	if (startx != 0)
   4.164 +		x = startx;
   4.165 +	if (starty != 0)
   4.166 +		y = starty;
   4.167 +	if (width == 0)
   4.168 +		width = 80;
   4.169 +
   4.170 +	length = strlen(string);
   4.171 +	temp = (width - length) / 2;
   4.172 +	x = startx + (int)temp;
   4.173 +	(void) wattrset(win, color);
   4.174 +	mvwprintw(win, y, x, "%s", string);
   4.175 +	refresh();
   4.176 +}
   4.177 +
   4.178 +int get_line_no(const char *text)
   4.179 +{
   4.180 +	int i;
   4.181 +	int total = 1;
   4.182 +
   4.183 +	if (!text)
   4.184 +		return 0;
   4.185 +
   4.186 +	for (i = 0; text[i] != '\0'; i++)
   4.187 +		if (text[i] == '\n')
   4.188 +			total++;
   4.189 +	return total;
   4.190 +}
   4.191 +
   4.192 +const char *get_line(const char *text, int line_no)
   4.193 +{
   4.194 +	int i;
   4.195 +	int lines = 0;
   4.196 +
   4.197 +	if (!text)
   4.198 +		return 0;
   4.199 +
   4.200 +	for (i = 0; text[i] != '\0' && lines < line_no; i++)
   4.201 +		if (text[i] == '\n')
   4.202 +			lines++;
   4.203 +	return text+i;
   4.204 +}
   4.205 +
   4.206 +int get_line_length(const char *line)
   4.207 +{
   4.208 +	int res = 0;
   4.209 +	while (*line != '\0' && *line != '\n') {
   4.210 +		line++;
   4.211 +		res++;
   4.212 +	}
   4.213 +	return res;
   4.214 +}
   4.215 +
   4.216 +/* print all lines to the window. */
   4.217 +void fill_window(WINDOW *win, const char *text)
   4.218 +{
   4.219 +	int x, y;
   4.220 +	int total_lines = get_line_no(text);
   4.221 +	int i;
   4.222 +
   4.223 +	getmaxyx(win, y, x);
   4.224 +	/* do not go over end of line */
   4.225 +	total_lines = min(total_lines, y);
   4.226 +	for (i = 0; i < total_lines; i++) {
   4.227 +		char tmp[x+10];
   4.228 +		const char *line = get_line(text, i);
   4.229 +		int len = get_line_length(line);
   4.230 +		strncpy(tmp, line, min(len, x));
   4.231 +		tmp[len] = '\0';
   4.232 +		mvwprintw(win, i, 0, "%s", tmp);
   4.233 +	}
   4.234 +}
   4.235 +
   4.236 +/* get the message, and buttons.
   4.237 + * each button must be a char*
   4.238 + * return the selected button
   4.239 + *
   4.240 + * this dialog is used for 2 different things:
   4.241 + * 1) show a text box, no buttons.
   4.242 + * 2) show a dialog, with horizontal buttons
   4.243 + */
   4.244 +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
   4.245 +{
   4.246 +	va_list ap;
   4.247 +	char *btn;
   4.248 +	int btns_width = 0;
   4.249 +	int msg_lines = 0;
   4.250 +	int msg_width = 0;
   4.251 +	int total_width;
   4.252 +	int win_rows = 0;
   4.253 +	WINDOW *win;
   4.254 +	WINDOW *msg_win;
   4.255 +	WINDOW *menu_win;
   4.256 +	MENU *menu;
   4.257 +	ITEM *btns[btn_num+1];
   4.258 +	int i, x, y;
   4.259 +	int res = -1;
   4.260 +
   4.261 +
   4.262 +	va_start(ap, btn_num);
   4.263 +	for (i = 0; i < btn_num; i++) {
   4.264 +		btn = va_arg(ap, char *);
   4.265 +		btns[i] = new_item(btn, "");
   4.266 +		btns_width += strlen(btn)+1;
   4.267 +	}
   4.268 +	va_end(ap);
   4.269 +	btns[btn_num] = NULL;
   4.270 +
   4.271 +	/* find the widest line of msg: */
   4.272 +	msg_lines = get_line_no(msg);
   4.273 +	for (i = 0; i < msg_lines; i++) {
   4.274 +		const char *line = get_line(msg, i);
   4.275 +		int len = get_line_length(line);
   4.276 +		if (msg_width < len)
   4.277 +			msg_width = len;
   4.278 +	}
   4.279 +
   4.280 +	total_width = max(msg_width, btns_width);
   4.281 +	/* place dialog in middle of screen */
   4.282 +	y = (LINES-(msg_lines+4))/2;
   4.283 +	x = (COLS-(total_width+4))/2;
   4.284 +
   4.285 +
   4.286 +	/* create the windows */
   4.287 +	if (btn_num > 0)
   4.288 +		win_rows = msg_lines+4;
   4.289 +	else
   4.290 +		win_rows = msg_lines+2;
   4.291 +
   4.292 +	win = newwin(win_rows, total_width+4, y, x);
   4.293 +	keypad(win, TRUE);
   4.294 +	menu_win = derwin(win, 1, btns_width, win_rows-2,
   4.295 +			1+(total_width+2-btns_width)/2);
   4.296 +	menu = new_menu(btns);
   4.297 +	msg_win = derwin(win, win_rows-2, msg_width, 1,
   4.298 +			1+(total_width+2-msg_width)/2);
   4.299 +
   4.300 +	set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
   4.301 +	set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
   4.302 +
   4.303 +	(void) wattrset(win, attributes[DIALOG_BOX]);
   4.304 +	box(win, 0, 0);
   4.305 +
   4.306 +	/* print message */
   4.307 +	(void) wattrset(msg_win, attributes[DIALOG_TEXT]);
   4.308 +	fill_window(msg_win, msg);
   4.309 +
   4.310 +	set_menu_win(menu, win);
   4.311 +	set_menu_sub(menu, menu_win);
   4.312 +	set_menu_format(menu, 1, btn_num);
   4.313 +	menu_opts_off(menu, O_SHOWDESC);
   4.314 +	menu_opts_off(menu, O_SHOWMATCH);
   4.315 +	menu_opts_on(menu, O_ONEVALUE);
   4.316 +	menu_opts_on(menu, O_NONCYCLIC);
   4.317 +	set_menu_mark(menu, "");
   4.318 +	post_menu(menu);
   4.319 +
   4.320 +
   4.321 +	touchwin(win);
   4.322 +	refresh_all_windows(main_window);
   4.323 +	while ((res = wgetch(win))) {
   4.324 +		switch (res) {
   4.325 +		case KEY_LEFT:
   4.326 +			menu_driver(menu, REQ_LEFT_ITEM);
   4.327 +			break;
   4.328 +		case KEY_RIGHT:
   4.329 +			menu_driver(menu, REQ_RIGHT_ITEM);
   4.330 +			break;
   4.331 +		case 10: /* ENTER */
   4.332 +		case 27: /* ESCAPE */
   4.333 +		case ' ':
   4.334 +		case KEY_F(F_BACK):
   4.335 +		case KEY_F(F_EXIT):
   4.336 +			break;
   4.337 +		}
   4.338 +		touchwin(win);
   4.339 +		refresh_all_windows(main_window);
   4.340 +
   4.341 +		if (res == 10 || res == ' ') {
   4.342 +			res = item_index(current_item(menu));
   4.343 +			break;
   4.344 +		} else if (res == 27 || res == KEY_F(F_BACK) ||
   4.345 +				res == KEY_F(F_EXIT)) {
   4.346 +			res = KEY_EXIT;
   4.347 +			break;
   4.348 +		}
   4.349 +	}
   4.350 +
   4.351 +	unpost_menu(menu);
   4.352 +	free_menu(menu);
   4.353 +	for (i = 0; i < btn_num; i++)
   4.354 +		free_item(btns[i]);
   4.355 +
   4.356 +	delwin(win);
   4.357 +	return res;
   4.358 +}
   4.359 +
   4.360 +int dialog_inputbox(WINDOW *main_window,
   4.361 +		const char *title, const char *prompt,
   4.362 +		const char *init, char *result, int result_len)
   4.363 +{
   4.364 +	int prompt_lines = 0;
   4.365 +	int prompt_width = 0;
   4.366 +	WINDOW *win;
   4.367 +	WINDOW *prompt_win;
   4.368 +	WINDOW *form_win;
   4.369 +	PANEL *panel;
   4.370 +	int i, x, y;
   4.371 +	int res = -1;
   4.372 +	int cursor_position = strlen(init);
   4.373 +
   4.374 +
   4.375 +	/* find the widest line of msg: */
   4.376 +	prompt_lines = get_line_no(prompt);
   4.377 +	for (i = 0; i < prompt_lines; i++) {
   4.378 +		const char *line = get_line(prompt, i);
   4.379 +		int len = get_line_length(line);
   4.380 +		prompt_width = max(prompt_width, len);
   4.381 +	}
   4.382 +
   4.383 +	if (title)
   4.384 +		prompt_width = max(prompt_width, strlen(title));
   4.385 +
   4.386 +	/* place dialog in middle of screen */
   4.387 +	y = (LINES-(prompt_lines+4))/2;
   4.388 +	x = (COLS-(prompt_width+4))/2;
   4.389 +
   4.390 +	strncpy(result, init, result_len);
   4.391 +
   4.392 +	/* create the windows */
   4.393 +	win = newwin(prompt_lines+6, prompt_width+7, y, x);
   4.394 +	prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
   4.395 +	form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
   4.396 +	keypad(form_win, TRUE);
   4.397 +
   4.398 +	(void) wattrset(form_win, attributes[INPUT_FIELD]);
   4.399 +
   4.400 +	(void) wattrset(win, attributes[INPUT_BOX]);
   4.401 +	box(win, 0, 0);
   4.402 +	(void) wattrset(win, attributes[INPUT_HEADING]);
   4.403 +	if (title)
   4.404 +		mvwprintw(win, 0, 3, "%s", title);
   4.405 +
   4.406 +	/* print message */
   4.407 +	(void) wattrset(prompt_win, attributes[INPUT_TEXT]);
   4.408 +	fill_window(prompt_win, prompt);
   4.409 +
   4.410 +	mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
   4.411 +	mvwprintw(form_win, 0, 0, "%s", result);
   4.412 +
   4.413 +	/* create panels */
   4.414 +	panel = new_panel(win);
   4.415 +
   4.416 +	/* show the cursor */
   4.417 +	curs_set(1);
   4.418 +
   4.419 +	touchwin(win);
   4.420 +	refresh_all_windows(main_window);
   4.421 +	while ((res = wgetch(form_win))) {
   4.422 +		int len = strlen(result);
   4.423 +		switch (res) {
   4.424 +		case 10: /* ENTER */
   4.425 +		case 27: /* ESCAPE */
   4.426 +		case KEY_F(F_HELP):
   4.427 +		case KEY_F(F_EXIT):
   4.428 +		case KEY_F(F_BACK):
   4.429 +			break;
   4.430 +		case 127:
   4.431 +		case KEY_BACKSPACE:
   4.432 +			if (cursor_position > 0) {
   4.433 +				memmove(&result[cursor_position-1],
   4.434 +						&result[cursor_position],
   4.435 +						len-cursor_position+1);
   4.436 +				cursor_position--;
   4.437 +			}
   4.438 +			break;
   4.439 +		case KEY_DC:
   4.440 +			if (cursor_position >= 0 && cursor_position < len) {
   4.441 +				memmove(&result[cursor_position],
   4.442 +						&result[cursor_position+1],
   4.443 +						len-cursor_position+1);
   4.444 +			}
   4.445 +			break;
   4.446 +		case KEY_UP:
   4.447 +		case KEY_RIGHT:
   4.448 +			if (cursor_position < len &&
   4.449 +			    cursor_position < min(result_len, prompt_width))
   4.450 +				cursor_position++;
   4.451 +			break;
   4.452 +		case KEY_DOWN:
   4.453 +		case KEY_LEFT:
   4.454 +			if (cursor_position > 0)
   4.455 +				cursor_position--;
   4.456 +			break;
   4.457 +		default:
   4.458 +			if ((isgraph(res) || isspace(res)) &&
   4.459 +					len-2 < result_len) {
   4.460 +				/* insert the char at the proper position */
   4.461 +				memmove(&result[cursor_position+1],
   4.462 +						&result[cursor_position],
   4.463 +						len+1);
   4.464 +				result[cursor_position] = res;
   4.465 +				cursor_position++;
   4.466 +			} else {
   4.467 +				mvprintw(0, 0, "unknow key: %d\n", res);
   4.468 +			}
   4.469 +			break;
   4.470 +		}
   4.471 +		wmove(form_win, 0, 0);
   4.472 +		wclrtoeol(form_win);
   4.473 +		mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
   4.474 +		mvwprintw(form_win, 0, 0, "%s", result);
   4.475 +		wmove(form_win, 0, cursor_position);
   4.476 +		touchwin(win);
   4.477 +		refresh_all_windows(main_window);
   4.478 +
   4.479 +		if (res == 10) {
   4.480 +			res = 0;
   4.481 +			break;
   4.482 +		} else if (res == 27 || res == KEY_F(F_BACK) ||
   4.483 +				res == KEY_F(F_EXIT)) {
   4.484 +			res = KEY_EXIT;
   4.485 +			break;
   4.486 +		} else if (res == KEY_F(F_HELP)) {
   4.487 +			res = 1;
   4.488 +			break;
   4.489 +		}
   4.490 +	}
   4.491 +
   4.492 +	/* hide the cursor */
   4.493 +	curs_set(0);
   4.494 +	del_panel(panel);
   4.495 +	delwin(prompt_win);
   4.496 +	delwin(form_win);
   4.497 +	delwin(win);
   4.498 +	return res;
   4.499 +}
   4.500 +
   4.501 +/* refresh all windows in the correct order */
   4.502 +void refresh_all_windows(WINDOW *main_window)
   4.503 +{
   4.504 +	update_panels();
   4.505 +	touchwin(main_window);
   4.506 +	refresh();
   4.507 +}
   4.508 +
   4.509 +/* layman's scrollable window... */
   4.510 +void show_scroll_win(WINDOW *main_window,
   4.511 +		const char *title,
   4.512 +		const char *text)
   4.513 +{
   4.514 +	int res;
   4.515 +	int total_lines = get_line_no(text);
   4.516 +	int x, y;
   4.517 +	int start_x = 0, start_y = 0;
   4.518 +	int text_lines = 0, text_cols = 0;
   4.519 +	int total_cols = 0;
   4.520 +	int win_cols = 0;
   4.521 +	int win_lines = 0;
   4.522 +	int i = 0;
   4.523 +	WINDOW *win;
   4.524 +	WINDOW *pad;
   4.525 +	PANEL *panel;
   4.526 +
   4.527 +	/* find the widest line of msg: */
   4.528 +	total_lines = get_line_no(text);
   4.529 +	for (i = 0; i < total_lines; i++) {
   4.530 +		const char *line = get_line(text, i);
   4.531 +		int len = get_line_length(line);
   4.532 +		total_cols = max(total_cols, len+2);
   4.533 +	}
   4.534 +
   4.535 +	/* create the pad */
   4.536 +	pad = newpad(total_lines+10, total_cols+10);
   4.537 +	(void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
   4.538 +	fill_window(pad, text);
   4.539 +
   4.540 +	win_lines = min(total_lines+4, LINES-2);
   4.541 +	win_cols = min(total_cols+2, COLS-2);
   4.542 +	text_lines = max(win_lines-4, 0);
   4.543 +	text_cols = max(win_cols-2, 0);
   4.544 +
   4.545 +	/* place window in middle of screen */
   4.546 +	y = (LINES-win_lines)/2;
   4.547 +	x = (COLS-win_cols)/2;
   4.548 +
   4.549 +	win = newwin(win_lines, win_cols, y, x);
   4.550 +	keypad(win, TRUE);
   4.551 +	/* show the help in the help window, and show the help panel */
   4.552 +	(void) wattrset(win, attributes[SCROLLWIN_BOX]);
   4.553 +	box(win, 0, 0);
   4.554 +	(void) wattrset(win, attributes[SCROLLWIN_HEADING]);
   4.555 +	mvwprintw(win, 0, 3, " %s ", title);
   4.556 +	panel = new_panel(win);
   4.557 +
   4.558 +	/* handle scrolling */
   4.559 +	do {
   4.560 +
   4.561 +		copywin(pad, win, start_y, start_x, 2, 2, text_lines,
   4.562 +				text_cols, 0);
   4.563 +		print_in_middle(win,
   4.564 +				text_lines+2,
   4.565 +				0,
   4.566 +				text_cols,
   4.567 +				"<OK>",
   4.568 +				attributes[DIALOG_MENU_FORE]);
   4.569 +		wrefresh(win);
   4.570 +
   4.571 +		res = wgetch(win);
   4.572 +		switch (res) {
   4.573 +		case KEY_NPAGE:
   4.574 +		case ' ':
   4.575 +			start_y += text_lines-2;
   4.576 +			break;
   4.577 +		case KEY_PPAGE:
   4.578 +			start_y -= text_lines+2;
   4.579 +			break;
   4.580 +		case KEY_HOME:
   4.581 +			start_y = 0;
   4.582 +			break;
   4.583 +		case KEY_END:
   4.584 +			start_y = total_lines-text_lines;
   4.585 +			break;
   4.586 +		case KEY_DOWN:
   4.587 +		case 'j':
   4.588 +			start_y++;
   4.589 +			break;
   4.590 +		case KEY_UP:
   4.591 +		case 'k':
   4.592 +			start_y--;
   4.593 +			break;
   4.594 +		case KEY_LEFT:
   4.595 +		case 'h':
   4.596 +			start_x--;
   4.597 +			break;
   4.598 +		case KEY_RIGHT:
   4.599 +		case 'l':
   4.600 +			start_x++;
   4.601 +			break;
   4.602 +		}
   4.603 +		if (res == 10 || res == 27 || res == 'q'
   4.604 +		    || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
   4.605 +			break;
   4.606 +		}
   4.607 +		if (start_y < 0)
   4.608 +			start_y = 0;
   4.609 +		if (start_y >= total_lines-text_lines)
   4.610 +			start_y = total_lines-text_lines;
   4.611 +		if (start_x < 0)
   4.612 +			start_x = 0;
   4.613 +		if (start_x >= total_cols-text_cols)
   4.614 +			start_x = total_cols-text_cols;
   4.615 +	} while (res);
   4.616 +
   4.617 +	del_panel(panel);
   4.618 +	delwin(win);
   4.619 +	refresh_all_windows(main_window);
   4.620 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/kconfig/nconf.h	Thu May 12 19:45:30 2011 +0200
     5.3 @@ -0,0 +1,96 @@
     5.4 +/*
     5.5 + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
     5.6 + * Released under the terms of the GNU GPL v2.0.
     5.7 + *
     5.8 + * Derived from menuconfig.
     5.9 + *
    5.10 + */
    5.11 +
    5.12 +#include <ctype.h>
    5.13 +#include <errno.h>
    5.14 +#include <fcntl.h>
    5.15 +#include <limits.h>
    5.16 +#include <stdarg.h>
    5.17 +#include <stdlib.h>
    5.18 +#include <string.h>
    5.19 +#include <unistd.h>
    5.20 +#include <locale.h>
    5.21 +#include <curses.h>
    5.22 +#include <menu.h>
    5.23 +#include <panel.h>
    5.24 +#include <form.h>
    5.25 +
    5.26 +#include <stdio.h>
    5.27 +#include <time.h>
    5.28 +#include <sys/time.h>
    5.29 +
    5.30 +#include "ncurses.h"
    5.31 +
    5.32 +#define max(a, b) ({\
    5.33 +		typeof(a) _a = a;\
    5.34 +		typeof(b) _b = b;\
    5.35 +		_a > _b ? _a : _b; })
    5.36 +
    5.37 +#define min(a, b) ({\
    5.38 +		typeof(a) _a = a;\
    5.39 +		typeof(b) _b = b;\
    5.40 +		_a < _b ? _a : _b; })
    5.41 +
    5.42 +typedef enum {
    5.43 +	NORMAL = 1,
    5.44 +	MAIN_HEADING,
    5.45 +	MAIN_MENU_BOX,
    5.46 +	MAIN_MENU_FORE,
    5.47 +	MAIN_MENU_BACK,
    5.48 +	MAIN_MENU_GREY,
    5.49 +	MAIN_MENU_HEADING,
    5.50 +	SCROLLWIN_TEXT,
    5.51 +	SCROLLWIN_HEADING,
    5.52 +	SCROLLWIN_BOX,
    5.53 +	DIALOG_TEXT,
    5.54 +	DIALOG_MENU_FORE,
    5.55 +	DIALOG_MENU_BACK,
    5.56 +	DIALOG_BOX,
    5.57 +	INPUT_BOX,
    5.58 +	INPUT_HEADING,
    5.59 +	INPUT_TEXT,
    5.60 +	INPUT_FIELD,
    5.61 +	FUNCTION_TEXT,
    5.62 +	FUNCTION_HIGHLIGHT,
    5.63 +	ATTR_MAX
    5.64 +} attributes_t;
    5.65 +extern attributes_t attributes[];
    5.66 +
    5.67 +typedef enum {
    5.68 +	F_HELP = 1,
    5.69 +	F_SYMBOL = 2,
    5.70 +	F_INSTS = 3,
    5.71 +	F_CONF = 4,
    5.72 +	F_BACK = 5,
    5.73 +	F_SAVE = 6,
    5.74 +	F_LOAD = 7,
    5.75 +	F_SEARCH = 8,
    5.76 +	F_EXIT = 9,
    5.77 +} function_key;
    5.78 +
    5.79 +void set_colors(void);
    5.80 +
    5.81 +/* this changes the windows attributes !!! */
    5.82 +void print_in_middle(WINDOW *win,
    5.83 +		int starty,
    5.84 +		int startx,
    5.85 +		int width,
    5.86 +		const char *string,
    5.87 +		chtype color);
    5.88 +int get_line_length(const char *line);
    5.89 +int get_line_no(const char *text);
    5.90 +const char *get_line(const char *text, int line_no);
    5.91 +void fill_window(WINDOW *win, const char *text);
    5.92 +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
    5.93 +int dialog_inputbox(WINDOW *main_window,
    5.94 +		const char *title, const char *prompt,
    5.95 +		const char *init, char *result, int result_len);
    5.96 +void refresh_all_windows(WINDOW *main_window);
    5.97 +void show_scroll_win(WINDOW *main_window,
    5.98 +		const char *title,
    5.99 +		const char *text);