kconfig/mconf.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Jul 28 21:32:33 2008 +0000 (2008-07-28)
changeset 747 d3e603e7c17c
parent 39 af42eec9d383
child 943 1cca90ce0481
permissions -rw-r--r--
Fourth step at renaming patches: renumber all patches with a 10-step.
yann@1
     1
/*
yann@1
     2
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
yann@1
     3
 * Released under the terms of the GNU GPL v2.0.
yann@1
     4
 *
yann@1
     5
 * Introduced single menu mode (show all sub-menus in one large tree).
yann@1
     6
 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
yann@1
     7
 *
yann@1
     8
 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
yann@1
     9
 */
yann@1
    10
yann@1
    11
#include <sys/ioctl.h>
yann@1
    12
#include <sys/wait.h>
yann@1
    13
#include <ctype.h>
yann@1
    14
#include <errno.h>
yann@1
    15
#include <fcntl.h>
yann@1
    16
#include <limits.h>
yann@1
    17
#include <signal.h>
yann@1
    18
#include <stdarg.h>
yann@1
    19
#include <stdlib.h>
yann@1
    20
#include <string.h>
yann@1
    21
#include <termios.h>
yann@1
    22
#include <unistd.h>
yann@1
    23
#include <locale.h>
yann@1
    24
yann@1
    25
#define LKC_DIRECT_LINK
yann@1
    26
#include "lkc.h"
yann@1
    27
#include "lxdialog/dialog.h"
yann@1
    28
yann@1
    29
static char menu_backtitle[128];
yann@1
    30
static const char mconf_readme[] = N_(
yann@1
    31
"Overview\n"
yann@1
    32
"--------\n"
yann@1
    33
"Some kernel features may be built directly into the kernel.\n"
yann@1
    34
"Some may be made into loadable runtime modules.  Some features\n"
yann@1
    35
"may be completely removed altogether.  There are also certain\n"
yann@1
    36
"kernel parameters which are not really features, but must be\n"
yann@1
    37
"entered in as decimal or hexadecimal numbers or possibly text.\n"
yann@1
    38
"\n"
yann@1
    39
"Menu items beginning with [*], <M> or [ ] represent features\n"
yann@1
    40
"configured to be built in, modularized or removed respectively.\n"
yann@1
    41
"Pointed brackets <> represent module capable features.\n"
yann@1
    42
"\n"
yann@1
    43
"To change any of these features, highlight it with the cursor\n"
yann@1
    44
"keys and press <Y> to build it in, <M> to make it a module or\n"
yann@1
    45
"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
yann@1
    46
"through the available options (ie. Y->N->M->Y).\n"
yann@1
    47
"\n"
yann@1
    48
"Some additional keyboard hints:\n"
yann@1
    49
"\n"
yann@1
    50
"Menus\n"
yann@1
    51
"----------\n"
yann@1
    52
"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
yann@1
    53
"   you wish to change or submenu wish to select and press <Enter>.\n"
yann@1
    54
"   Submenus are designated by \"--->\".\n"
yann@1
    55
"\n"
yann@1
    56
"   Shortcut: Press the option's highlighted letter (hotkey).\n"
yann@1
    57
"             Pressing a hotkey more than once will sequence\n"
yann@1
    58
"             through all visible items which use that hotkey.\n"
yann@1
    59
"\n"
yann@1
    60
"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
yann@1
    61
"   unseen options into view.\n"
yann@1
    62
"\n"
yann@1
    63
"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
yann@1
    64
"   and press <ENTER>.\n"
yann@1
    65
"\n"
yann@1
    66
"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
yann@1
    67
"             using those letters.  You may press a single <ESC>, but\n"
yann@1
    68
"             there is a delayed response which you may find annoying.\n"
yann@1
    69
"\n"
yann@1
    70
"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
yann@1
    71
"   <Exit> and <Help>\n"
yann@1
    72
"\n"
yann@1
    73
"o  To get help with an item, use the cursor keys to highlight <Help>\n"
yann@1
    74
"   and Press <ENTER>.\n"
yann@1
    75
"\n"
yann@1
    76
"   Shortcut: Press <H> or <?>.\n"
yann@1
    77
"\n"
yann@1
    78
"\n"
yann@1
    79
"Radiolists  (Choice lists)\n"
yann@1
    80
"-----------\n"
yann@1
    81
"o  Use the cursor keys to select the option you wish to set and press\n"
yann@1
    82
"   <S> or the <SPACE BAR>.\n"
yann@1
    83
"\n"
yann@1
    84
"   Shortcut: Press the first letter of the option you wish to set then\n"
yann@1
    85
"             press <S> or <SPACE BAR>.\n"
yann@1
    86
"\n"
yann@1
    87
"o  To see available help for the item, use the cursor keys to highlight\n"
yann@1
    88
"   <Help> and Press <ENTER>.\n"
yann@1
    89
"\n"
yann@1
    90
"   Shortcut: Press <H> or <?>.\n"
yann@1
    91
"\n"
yann@1
    92
"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
yann@1
    93
"   <Help>\n"
yann@1
    94
"\n"
yann@1
    95
"\n"
yann@1
    96
"Data Entry\n"
yann@1
    97
"-----------\n"
yann@1
    98
"o  Enter the requested information and press <ENTER>\n"
yann@1
    99
"   If you are entering hexadecimal values, it is not necessary to\n"
yann@1
   100
"   add the '0x' prefix to the entry.\n"
yann@1
   101
"\n"
yann@1
   102
"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
yann@1
   103
"   and press <ENTER>.  You can try <TAB><H> as well.\n"
yann@1
   104
"\n"
yann@1
   105
"\n"
yann@1
   106
"Text Box    (Help Window)\n"
yann@1
   107
"--------\n"
yann@1
   108
"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
yann@1
   109
"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
yann@1
   110
"   who are familiar with less and lynx.\n"
yann@1
   111
"\n"
yann@1
   112
"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
yann@1
   113
"\n"
yann@1
   114
"\n"
yann@1
   115
"Alternate Configuration Files\n"
yann@1
   116
"-----------------------------\n"
yann@1
   117
"Menuconfig supports the use of alternate configuration files for\n"
yann@1
   118
"those who, for various reasons, find it necessary to switch\n"
yann@1
   119
"between different kernel configurations.\n"
yann@1
   120
"\n"
yann@1
   121
"At the end of the main menu you will find two options.  One is\n"
yann@1
   122
"for saving the current configuration to a file of your choosing.\n"
yann@1
   123
"The other option is for loading a previously saved alternate\n"
yann@1
   124
"configuration.\n"
yann@1
   125
"\n"
yann@1
   126
"Even if you don't use alternate configuration files, but you\n"
yann@1
   127
"find during a Menuconfig session that you have completely messed\n"
yann@1
   128
"up your settings, you may use the \"Load Alternate...\" option to\n"
yann@1
   129
"restore your previously saved settings from \".config\" without\n"
yann@1
   130
"restarting Menuconfig.\n"
yann@1
   131
"\n"
yann@1
   132
"Other information\n"
yann@1
   133
"-----------------\n"
yann@1
   134
"If you use Menuconfig in an XTERM window make sure you have your\n"
yann@1
   135
"$TERM variable set to point to a xterm definition which supports color.\n"
yann@1
   136
"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
yann@1
   137
"display correctly in a RXVT window because rxvt displays only one\n"
yann@1
   138
"intensity of color, bright.\n"
yann@1
   139
"\n"
yann@1
   140
"Menuconfig will display larger menus on screens or xterms which are\n"
yann@1
   141
"set to display more than the standard 25 row by 80 column geometry.\n"
yann@1
   142
"In order for this to work, the \"stty size\" command must be able to\n"
yann@1
   143
"display the screen's current row and column geometry.  I STRONGLY\n"
yann@1
   144
"RECOMMEND that you make sure you do NOT have the shell variables\n"
yann@1
   145
"LINES and COLUMNS exported into your environment.  Some distributions\n"
yann@1
   146
"export those variables via /etc/profile.  Some ncurses programs can\n"
yann@1
   147
"become confused when those variables (LINES & COLUMNS) don't reflect\n"
yann@1
   148
"the true screen size.\n"
yann@1
   149
"\n"
yann@1
   150
"Optional personality available\n"
yann@1
   151
"------------------------------\n"
yann@1
   152
"If you prefer to have all of the kernel options listed in a single\n"
yann@1
   153
"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
yann@1
   154
"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
yann@1
   155
"\n"
yann@1
   156
"make MENUCONFIG_MODE=single_menu menuconfig\n"
yann@1
   157
"\n"
yann@1
   158
"<Enter> will then unroll the appropriate category, or enfold it if it\n"
yann@1
   159
"is already unrolled.\n"
yann@1
   160
"\n"
yann@1
   161
"Note that this mode can eventually be a little more CPU expensive\n"
yann@1
   162
"(especially with a larger number of unrolled categories) than the\n"
yann@1
   163
"default mode.\n"
yann@1
   164
"\n"
yann@1
   165
"Different color themes available\n"
yann@1
   166
"--------------------------------\n"
yann@1
   167
"It is possible to select different color themes using the variable\n"
yann@1
   168
"MENUCONFIG_COLOR. To select a theme use:\n"
yann@1
   169
"\n"
yann@1
   170
"make MENUCONFIG_COLOR=<theme> menuconfig\n"
yann@1
   171
"\n"
yann@1
   172
"Available themes are\n"
yann@1
   173
" mono       => selects colors suitable for monochrome displays\n"
yann@1
   174
" blackbg    => selects a color scheme with black background\n"
yann@1
   175
" classic    => theme with blue background. The classic look\n"
yann@1
   176
" bluetitle  => a LCD friendly version of classic. (default)\n"
yann@1
   177
"\n"),
yann@1
   178
menu_instructions[] = N_(
yann@1
   179
	"Arrow keys navigate the menu.  "
yann@1
   180
	"<Enter> selects submenus --->.  "
yann@1
   181
	"Highlighted letters are hotkeys.  "
yann@1
   182
	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
yann@1
   183
	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
yann@1
   184
	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
yann@1
   185
radiolist_instructions[] = N_(
yann@1
   186
	"Use the arrow keys to navigate this window or "
yann@1
   187
	"press the hotkey of the item you wish to select "
yann@1
   188
	"followed by the <SPACE BAR>. "
yann@1
   189
	"Press <?> for additional information about this option."),
yann@1
   190
inputbox_instructions_int[] = N_(
yann@1
   191
	"Please enter a decimal value. "
yann@1
   192
	"Fractions will not be accepted.  "
yann@1
   193
	"Use the <TAB> key to move from the input field to the buttons below it."),
yann@1
   194
inputbox_instructions_hex[] = N_(
yann@1
   195
	"Please enter a hexadecimal value. "
yann@1
   196
	"Use the <TAB> key to move from the input field to the buttons below it."),
yann@1
   197
inputbox_instructions_string[] = N_(
yann@1
   198
	"Please enter a string value. "
yann@1
   199
	"Use the <TAB> key to move from the input field to the buttons below it."),
yann@1
   200
setmod_text[] = N_(
yann@1
   201
	"This feature depends on another which has been configured as a module.\n"
yann@1
   202
	"As a result, this feature will be built as a module."),
yann@1
   203
nohelp_text[] = N_(
yann@1
   204
	"There is no help available for this kernel option.\n"),
yann@1
   205
load_config_text[] = N_(
yann@1
   206
	"Enter the name of the configuration file you wish to load.  "
yann@1
   207
	"Accept the name shown to restore the configuration you "
yann@1
   208
	"last retrieved.  Leave blank to abort."),
yann@1
   209
load_config_help[] = N_(
yann@1
   210
	"\n"
yann@1
   211
	"For various reasons, one may wish to keep several different kernel\n"
yann@1
   212
	"configurations available on a single machine.\n"
yann@1
   213
	"\n"
yann@1
   214
	"If you have saved a previous configuration in a file other than the\n"
yann@1
   215
	"kernel's default, entering the name of the file here will allow you\n"
yann@1
   216
	"to modify that configuration.\n"
yann@1
   217
	"\n"
yann@1
   218
	"If you are uncertain, then you have probably never used alternate\n"
yann@1
   219
	"configuration files.  You should therefor leave this blank to abort.\n"),
yann@1
   220
save_config_text[] = N_(
yann@1
   221
	"Enter a filename to which this configuration should be saved "
yann@1
   222
	"as an alternate.  Leave blank to abort."),
yann@1
   223
save_config_help[] = N_(
yann@1
   224
	"\n"
yann@1
   225
	"For various reasons, one may wish to keep different kernel\n"
yann@1
   226
	"configurations available on a single machine.\n"
yann@1
   227
	"\n"
yann@1
   228
	"Entering a file name here will allow you to later retrieve, modify\n"
yann@1
   229
	"and use the current configuration as an alternate to whatever\n"
yann@1
   230
	"configuration options you have selected at that time.\n"
yann@1
   231
	"\n"
yann@1
   232
	"If you are uncertain what all this means then you should probably\n"
yann@1
   233
	"leave this blank.\n"),
yann@1
   234
search_help[] = N_(
yann@1
   235
	"\n"
yann@1
   236
	"Search for CT_ symbols and display their relations.\n"
yann@1
   237
	"Regular expressions are allowed.\n"
yann@1
   238
	"Example: search for \"^FOO\"\n"
yann@1
   239
	"Result:\n"
yann@1
   240
	"-----------------------------------------------------------------\n"
yann@1
   241
	"Symbol: FOO [=m]\n"
yann@1
   242
	"Prompt: Foo bus is used to drive the bar HW\n"
yann@1
   243
	"Defined at drivers/pci/Kconfig:47\n"
yann@1
   244
	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
yann@1
   245
	"Location:\n"
yann@1
   246
	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
yann@1
   247
	"    -> PCI support (PCI [=y])\n"
yann@1
   248
	"      -> PCI access mode (<choice> [=y])\n"
yann@1
   249
	"Selects: LIBCRC32\n"
yann@1
   250
	"Selected by: BAR\n"
yann@1
   251
	"-----------------------------------------------------------------\n"
yann@1
   252
	"o The line 'Prompt:' shows the text used in the menu structure for\n"
yann@1
   253
	"  this CT_ symbol\n"
yann@1
   254
	"o The 'Defined at' line tell at what file / line number the symbol\n"
yann@1
   255
	"  is defined\n"
yann@1
   256
	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
yann@1
   257
	"  this symbol to be visible in the menu (selectable)\n"
yann@1
   258
	"o The 'Location:' lines tell where in the menu structure this symbol\n"
yann@1
   259
	"  is located\n"
yann@1
   260
	"    A location followed by a [=y] indicate that this is a selectable\n"
yann@1
   261
	"    menu item - and current value is displayed inside brackets.\n"
yann@1
   262
	"o The 'Selects:' line tell what symbol will be automatically\n"
yann@1
   263
	"  selected if this symbol is selected (y or m)\n"
yann@1
   264
	"o The 'Selected by' line tell what symbol has selected this symbol\n"
yann@1
   265
	"\n"
yann@1
   266
	"Only relevant lines are shown.\n"
yann@1
   267
	"\n\n"
yann@1
   268
	"Search examples:\n"
yann@1
   269
	"Examples: USB	=> find all CT_ symbols containing USB\n"
yann@1
   270
	"          ^USB => find all CT_ symbols starting with USB\n"
yann@1
   271
	"          USB$ => find all CT_ symbols ending with USB\n"
yann@1
   272
	"\n");
yann@1
   273
yann@1
   274
static char filename[PATH_MAX+1] = ".config";
yann@1
   275
static int indent;
yann@1
   276
static struct termios ios_org;
yann@1
   277
static int rows = 0, cols = 0;
yann@1
   278
static struct menu *current_menu;
yann@1
   279
static int child_count;
yann@1
   280
static int single_menu_mode;
yann@1
   281
yann@1
   282
static void conf(struct menu *menu);
yann@1
   283
static void conf_choice(struct menu *menu);
yann@1
   284
static void conf_string(struct menu *menu);
yann@1
   285
static void conf_load(void);
yann@1
   286
static void conf_save(void);
yann@1
   287
static void show_textbox(const char *title, const char *text, int r, int c);
yann@1
   288
static void show_helptext(const char *title, const char *text);
yann@1
   289
static void show_help(struct menu *menu);
yann@1
   290
yann@1
   291
static void init_wsize(void)
yann@1
   292
{
yann@1
   293
	struct winsize ws;
yann@1
   294
	char *env;
yann@1
   295
yann@1
   296
	if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
yann@1
   297
		rows = ws.ws_row;
yann@1
   298
		cols = ws.ws_col;
yann@1
   299
	}
yann@1
   300
yann@1
   301
	if (!rows) {
yann@1
   302
		env = getenv("LINES");
yann@1
   303
		if (env)
yann@1
   304
			rows = atoi(env);
yann@1
   305
		if (!rows)
yann@1
   306
			rows = 24;
yann@1
   307
	}
yann@1
   308
	if (!cols) {
yann@1
   309
		env = getenv("COLUMNS");
yann@1
   310
		if (env)
yann@1
   311
			cols = atoi(env);
yann@1
   312
		if (!cols)
yann@1
   313
			cols = 80;
yann@1
   314
	}
yann@1
   315
yann@1
   316
	if (rows < 19 || cols < 80) {
yann@1
   317
		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
yann@1
   318
		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
yann@1
   319
		exit(1);
yann@1
   320
	}
yann@1
   321
yann@1
   322
	rows -= 4;
yann@1
   323
	cols -= 5;
yann@1
   324
}
yann@1
   325
yann@1
   326
static void get_prompt_str(struct gstr *r, struct property *prop)
yann@1
   327
{
yann@1
   328
	int i, j;
yann@1
   329
	struct menu *submenu[8], *menu;
yann@1
   330
yann@1
   331
	str_printf(r, "Prompt: %s\n", prop->text);
yann@1
   332
	str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
yann@1
   333
		prop->menu->lineno);
yann@1
   334
	if (!expr_is_yes(prop->visible.expr)) {
yann@1
   335
		str_append(r, "  Depends on: ");
yann@1
   336
		expr_gstr_print(prop->visible.expr, r);
yann@1
   337
		str_append(r, "\n");
yann@1
   338
	}
yann@1
   339
	menu = prop->menu->parent;
yann@1
   340
	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
yann@1
   341
		submenu[i++] = menu;
yann@1
   342
	if (i > 0) {
yann@1
   343
		str_printf(r, "  Location:\n");
yann@1
   344
		for (j = 4; --i >= 0; j += 2) {
yann@1
   345
			menu = submenu[i];
yann@1
   346
			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
yann@1
   347
			if (menu->sym) {
yann@1
   348
				str_printf(r, " (%s [=%s])", menu->sym->name ?
yann@1
   349
					menu->sym->name : "<choice>",
yann@1
   350
					sym_get_string_value(menu->sym));
yann@1
   351
			}
yann@1
   352
			str_append(r, "\n");
yann@1
   353
		}
yann@1
   354
	}
yann@1
   355
}
yann@1
   356
yann@1
   357
static void get_symbol_str(struct gstr *r, struct symbol *sym)
yann@1
   358
{
yann@1
   359
	bool hit;
yann@1
   360
	struct property *prop;
yann@1
   361
yann@1
   362
	str_printf(r, "Symbol: %s [=%s]\n", sym->name,
yann@1
   363
	                               sym_get_string_value(sym));
yann@1
   364
	for_all_prompts(sym, prop)
yann@1
   365
		get_prompt_str(r, prop);
yann@1
   366
	hit = false;
yann@1
   367
	for_all_properties(sym, prop, P_SELECT) {
yann@1
   368
		if (!hit) {
yann@1
   369
			str_append(r, "  Selects: ");
yann@1
   370
			hit = true;
yann@1
   371
		} else
yann@1
   372
			str_printf(r, " && ");
yann@1
   373
		expr_gstr_print(prop->expr, r);
yann@1
   374
	}
yann@1
   375
	if (hit)
yann@1
   376
		str_append(r, "\n");
yann@1
   377
	if (sym->rev_dep.expr) {
yann@1
   378
		str_append(r, "  Selected by: ");
yann@1
   379
		expr_gstr_print(sym->rev_dep.expr, r);
yann@1
   380
		str_append(r, "\n");
yann@1
   381
	}
yann@1
   382
	str_append(r, "\n\n");
yann@1
   383
}
yann@1
   384
yann@1
   385
static struct gstr get_relations_str(struct symbol **sym_arr)
yann@1
   386
{
yann@1
   387
	struct symbol *sym;
yann@1
   388
	struct gstr res = str_new();
yann@1
   389
	int i;
yann@1
   390
yann@1
   391
	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
yann@1
   392
		get_symbol_str(&res, sym);
yann@1
   393
	if (!i)
yann@1
   394
		str_append(&res, "No matches found.\n");
yann@1
   395
	return res;
yann@1
   396
}
yann@1
   397
yann@1
   398
static void search_conf(void)
yann@1
   399
{
yann@1
   400
	struct symbol **sym_arr;
yann@1
   401
	struct gstr res;
yann@1
   402
	int dres;
yann@1
   403
again:
yann@1
   404
	dialog_clear();
yann@1
   405
	dres = dialog_inputbox(_("Search Configuration Parameter"),
yann@1
   406
			      _("Enter CT_ (sub)string to search for (omit CT_)"),
yann@1
   407
			      10, 75, "");
yann@1
   408
	switch (dres) {
yann@1
   409
	case 0:
yann@1
   410
		break;
yann@1
   411
	case 1:
yann@1
   412
		show_helptext(_("Search Configuration"), search_help);
yann@1
   413
		goto again;
yann@1
   414
	default:
yann@1
   415
		return;
yann@1
   416
	}
yann@1
   417
yann@1
   418
	sym_arr = sym_re_search(dialog_input_result);
yann@1
   419
	res = get_relations_str(sym_arr);
yann@1
   420
	free(sym_arr);
yann@1
   421
	show_textbox(_("Search Results"), str_get(&res), 0, 0);
yann@1
   422
	str_free(&res);
yann@1
   423
}
yann@1
   424
yann@1
   425
static void build_conf(struct menu *menu)
yann@1
   426
{
yann@1
   427
	struct symbol *sym;
yann@1
   428
	struct property *prop;
yann@1
   429
	struct menu *child;
yann@1
   430
	int type, tmp, doint = 2;
yann@1
   431
	tristate val;
yann@1
   432
	char ch;
yann@1
   433
yann@1
   434
	if (!menu_is_visible(menu))
yann@1
   435
		return;
yann@1
   436
yann@1
   437
	sym = menu->sym;
yann@1
   438
	prop = menu->prompt;
yann@1
   439
	if (!sym) {
yann@1
   440
		if (prop && menu != current_menu) {
yann@1
   441
			const char *prompt = menu_get_prompt(menu);
yann@1
   442
			switch (prop->type) {
yann@1
   443
			case P_MENU:
yann@1
   444
				child_count++;
yann@1
   445
				if (single_menu_mode) {
yann@1
   446
					item_make("%s%*c%s",
yann@1
   447
						  menu->data ? "-->" : "++>",
yann@1
   448
						  indent + 1, ' ', prompt);
yann@1
   449
				} else
yann@1
   450
					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
yann@1
   451
yann@1
   452
				item_set_tag('m');
yann@1
   453
				item_set_data(menu);
yann@1
   454
				if (single_menu_mode && menu->data)
yann@1
   455
					goto conf_childs;
yann@1
   456
				return;
yann@1
   457
			default:
yann@1
   458
				if (prompt) {
yann@1
   459
					child_count++;
yann@1
   460
					item_make("---%*c%s", indent + 1, ' ', prompt);
yann@1
   461
					item_set_tag(':');
yann@1
   462
					item_set_data(menu);
yann@1
   463
				}
yann@1
   464
			}
yann@1
   465
		} else
yann@1
   466
			doint = 0;
yann@1
   467
		goto conf_childs;
yann@1
   468
	}
yann@1
   469
yann@1
   470
	type = sym_get_type(sym);
yann@1
   471
	if (sym_is_choice(sym)) {
yann@1
   472
		struct symbol *def_sym = sym_get_choice_value(sym);
yann@1
   473
		struct menu *def_menu = NULL;
yann@1
   474
yann@1
   475
		child_count++;
yann@1
   476
		for (child = menu->list; child; child = child->next) {
yann@1
   477
			if (menu_is_visible(child) && child->sym == def_sym)
yann@1
   478
				def_menu = child;
yann@1
   479
		}
yann@1
   480
yann@1
   481
		val = sym_get_tristate_value(sym);
yann@1
   482
		if (sym_is_changable(sym)) {
yann@1
   483
			switch (type) {
yann@1
   484
			case S_BOOLEAN:
yann@1
   485
				item_make("[%c]", val == no ? ' ' : '*');
yann@1
   486
				break;
yann@1
   487
			case S_TRISTATE:
yann@1
   488
				switch (val) {
yann@1
   489
				case yes: ch = '*'; break;
yann@1
   490
				case mod: ch = 'M'; break;
yann@1
   491
				default:  ch = ' '; break;
yann@1
   492
				}
yann@1
   493
				item_make("<%c>", ch);
yann@1
   494
				break;
yann@1
   495
			}
yann@1
   496
			item_set_tag('t');
yann@1
   497
			item_set_data(menu);
yann@1
   498
		} else {
yann@1
   499
			item_make("   ");
yann@1
   500
			item_set_tag(def_menu ? 't' : ':');
yann@1
   501
			item_set_data(menu);
yann@1
   502
		}
yann@1
   503
yann@1
   504
		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
yann@1
   505
		if (val == yes) {
yann@1
   506
			if (def_menu) {
yann@1
   507
				item_add_str(" (%s)", menu_get_prompt(def_menu));
yann@1
   508
				item_add_str("  --->");
yann@1
   509
				if (def_menu->list) {
yann@1
   510
					indent += 2;
yann@1
   511
					build_conf(def_menu);
yann@1
   512
					indent -= 2;
yann@1
   513
				}
yann@1
   514
			}
yann@1
   515
			return;
yann@1
   516
		}
yann@1
   517
	} else {
yann@1
   518
		if (menu == current_menu) {
yann@1
   519
			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
yann@1
   520
			item_set_tag(':');
yann@1
   521
			item_set_data(menu);
yann@1
   522
			goto conf_childs;
yann@1
   523
		}
yann@1
   524
		child_count++;
yann@1
   525
		val = sym_get_tristate_value(sym);
yann@1
   526
		if (sym_is_choice_value(sym) && val == yes) {
yann@1
   527
			item_make("   ");
yann@1
   528
			item_set_tag(':');
yann@1
   529
			item_set_data(menu);
yann@1
   530
		} else {
yann@1
   531
			switch (type) {
yann@1
   532
			case S_BOOLEAN:
yann@1
   533
				if (sym_is_changable(sym))
yann@1
   534
					item_make("[%c]", val == no ? ' ' : '*');
yann@1
   535
				else
yann@1
   536
					item_make("---");
yann@1
   537
				item_set_tag('t');
yann@1
   538
				item_set_data(menu);
yann@1
   539
				break;
yann@1
   540
			case S_TRISTATE:
yann@1
   541
				switch (val) {
yann@1
   542
				case yes: ch = '*'; break;
yann@1
   543
				case mod: ch = 'M'; break;
yann@1
   544
				default:  ch = ' '; break;
yann@1
   545
				}
yann@1
   546
				if (sym_is_changable(sym))
yann@1
   547
					item_make("<%c>", ch);
yann@1
   548
				else
yann@1
   549
					item_make("---");
yann@1
   550
				item_set_tag('t');
yann@1
   551
				item_set_data(menu);
yann@1
   552
				break;
yann@1
   553
			default:
yann@1
   554
				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
yann@1
   555
				item_make("(%s)", sym_get_string_value(sym));
yann@1
   556
				tmp = indent - tmp + 4;
yann@1
   557
				if (tmp < 0)
yann@1
   558
					tmp = 0;
yann@1
   559
				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
yann@1
   560
					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
yann@1
   561
					     "" : " (NEW)");
yann@1
   562
				item_set_tag('s');
yann@1
   563
				item_set_data(menu);
yann@1
   564
				goto conf_childs;
yann@1
   565
			}
yann@1
   566
		}
yann@1
   567
		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
yann@1
   568
			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
yann@1
   569
			  "" : " (NEW)");
yann@1
   570
		if (menu->prompt->type == P_MENU) {
yann@1
   571
			item_add_str("  --->");
yann@1
   572
			return;
yann@1
   573
		}
yann@1
   574
	}
yann@1
   575
yann@1
   576
conf_childs:
yann@1
   577
	indent += doint;
yann@1
   578
	for (child = menu->list; child; child = child->next)
yann@1
   579
		build_conf(child);
yann@1
   580
	indent -= doint;
yann@1
   581
}
yann@1
   582
yann@1
   583
static void conf(struct menu *menu)
yann@1
   584
{
yann@1
   585
	struct menu *submenu;
yann@1
   586
	const char *prompt = menu_get_prompt(menu);
yann@1
   587
	struct symbol *sym;
yann@1
   588
	struct menu *active_menu = NULL;
yann@1
   589
	int res;
yann@1
   590
	int s_scroll = 0;
yann@1
   591
yann@1
   592
	while (1) {
yann@1
   593
		item_reset();
yann@1
   594
		current_menu = menu;
yann@1
   595
		build_conf(menu);
yann@1
   596
		if (!child_count)
yann@1
   597
			break;
yann@1
   598
		if (menu == &rootmenu) {
yann@1
   599
			item_make("--- ");
yann@1
   600
			item_set_tag(':');
yann@1
   601
			item_make(_("    Load an Alternate Configuration File"));
yann@1
   602
			item_set_tag('L');
yann@1
   603
			item_make(_("    Save an Alternate Configuration File"));
yann@1
   604
			item_set_tag('S');
yann@1
   605
		}
yann@1
   606
		dialog_clear();
yann@1
   607
		res = dialog_menu(prompt ? prompt : _("Main Menu"),
yann@1
   608
				  _(menu_instructions),
yann@1
   609
				  active_menu, &s_scroll);
yann@1
   610
		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
yann@1
   611
			break;
yann@1
   612
		if (!item_activate_selected())
yann@1
   613
			continue;
yann@1
   614
		if (!item_tag())
yann@1
   615
			continue;
yann@1
   616
yann@1
   617
		submenu = item_data();
yann@1
   618
		active_menu = item_data();
yann@1
   619
		if (submenu)
yann@1
   620
			sym = submenu->sym;
yann@1
   621
		else
yann@1
   622
			sym = NULL;
yann@1
   623
yann@1
   624
		switch (res) {
yann@1
   625
		case 0:
yann@1
   626
			switch (item_tag()) {
yann@1
   627
			case 'm':
yann@1
   628
				if (single_menu_mode)
yann@1
   629
					submenu->data = (void *) (long) !submenu->data;
yann@1
   630
				else
yann@1
   631
					conf(submenu);
yann@1
   632
				break;
yann@1
   633
			case 't':
yann@1
   634
				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
yann@1
   635
					conf_choice(submenu);
yann@1
   636
				else if (submenu->prompt->type == P_MENU)
yann@1
   637
					conf(submenu);
yann@1
   638
				break;
yann@1
   639
			case 's':
yann@1
   640
				conf_string(submenu);
yann@1
   641
				break;
yann@1
   642
			case 'L':
yann@1
   643
				conf_load();
yann@1
   644
				break;
yann@1
   645
			case 'S':
yann@1
   646
				conf_save();
yann@1
   647
				break;
yann@1
   648
			}
yann@1
   649
			break;
yann@1
   650
		case 2:
yann@1
   651
			if (sym)
yann@1
   652
				show_help(submenu);
yann@1
   653
			else
yann@1
   654
				show_helptext("README", _(mconf_readme));
yann@1
   655
			break;
yann@1
   656
		case 3:
yann@1
   657
			if (item_is_tag('t')) {
yann@1
   658
				if (sym_set_tristate_value(sym, yes))
yann@1
   659
					break;
yann@1
   660
				if (sym_set_tristate_value(sym, mod))
yann@1
   661
					show_textbox(NULL, setmod_text, 6, 74);
yann@1
   662
			}
yann@1
   663
			break;
yann@1
   664
		case 4:
yann@1
   665
			if (item_is_tag('t'))
yann@1
   666
				sym_set_tristate_value(sym, no);
yann@1
   667
			break;
yann@1
   668
		case 5:
yann@1
   669
			if (item_is_tag('t'))
yann@1
   670
				sym_set_tristate_value(sym, mod);
yann@1
   671
			break;
yann@1
   672
		case 6:
yann@1
   673
			if (item_is_tag('t'))
yann@1
   674
				sym_toggle_tristate_value(sym);
yann@1
   675
			else if (item_is_tag('m'))
yann@1
   676
				conf(submenu);
yann@1
   677
			break;
yann@1
   678
		case 7:
yann@1
   679
			search_conf();
yann@1
   680
			break;
yann@1
   681
		}
yann@1
   682
	}
yann@1
   683
}
yann@1
   684
yann@1
   685
static void show_textbox(const char *title, const char *text, int r, int c)
yann@1
   686
{
yann@1
   687
	dialog_clear();
yann@1
   688
	dialog_textbox(title, text, r, c);
yann@1
   689
}
yann@1
   690
yann@1
   691
static void show_helptext(const char *title, const char *text)
yann@1
   692
{
yann@1
   693
	show_textbox(title, text, 0, 0);
yann@1
   694
}
yann@1
   695
yann@1
   696
static void show_help(struct menu *menu)
yann@1
   697
{
yann@1
   698
	struct gstr help = str_new();
yann@1
   699
	struct symbol *sym = menu->sym;
yann@1
   700
yann@1
   701
	if (sym->help)
yann@1
   702
	{
yann@1
   703
		if (sym->name) {
yann@1
   704
			str_printf(&help, "CT_%s:\n\n", sym->name);
yann@1
   705
			str_append(&help, _(sym->help));
yann@1
   706
			str_append(&help, "\n");
yann@1
   707
		}
yann@1
   708
	} else {
yann@1
   709
		str_append(&help, nohelp_text);
yann@1
   710
	}
yann@1
   711
	get_symbol_str(&help, sym);
yann@1
   712
	show_helptext(menu_get_prompt(menu), str_get(&help));
yann@1
   713
	str_free(&help);
yann@1
   714
}
yann@1
   715
yann@1
   716
static void conf_choice(struct menu *menu)
yann@1
   717
{
yann@1
   718
	const char *prompt = menu_get_prompt(menu);
yann@1
   719
	struct menu *child;
yann@1
   720
	struct symbol *active;
yann@1
   721
yann@1
   722
	active = sym_get_choice_value(menu->sym);
yann@1
   723
	while (1) {
yann@1
   724
		int res;
yann@1
   725
		int selected;
yann@1
   726
		item_reset();
yann@1
   727
yann@1
   728
		current_menu = menu;
yann@1
   729
		for (child = menu->list; child; child = child->next) {
yann@1
   730
			if (!menu_is_visible(child))
yann@1
   731
				continue;
yann@1
   732
			item_make("%s", menu_get_prompt(child));
yann@1
   733
			item_set_data(child);
yann@1
   734
			if (child->sym == active)
yann@1
   735
				item_set_selected(1);
yann@1
   736
			if (child->sym == sym_get_choice_value(menu->sym))
yann@1
   737
				item_set_tag('X');
yann@1
   738
		}
yann@1
   739
		dialog_clear();
yann@1
   740
		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
yann@1
   741
					_(radiolist_instructions),
yann@1
   742
					 15, 70, 6);
yann@1
   743
		selected = item_activate_selected();
yann@1
   744
		switch (res) {
yann@1
   745
		case 0:
yann@1
   746
			if (selected) {
yann@1
   747
				child = item_data();
yann@1
   748
				sym_set_tristate_value(child->sym, yes);
yann@1
   749
			}
yann@1
   750
			return;
yann@1
   751
		case 1:
yann@1
   752
			if (selected) {
yann@1
   753
				child = item_data();
yann@1
   754
				show_help(child);
yann@1
   755
				active = child->sym;
yann@1
   756
			} else
yann@1
   757
				show_help(menu);
yann@1
   758
			break;
yann@1
   759
		case KEY_ESC:
yann@1
   760
			return;
yann@1
   761
		case -ERRDISPLAYTOOSMALL:
yann@1
   762
			return;
yann@1
   763
		}
yann@1
   764
	}
yann@1
   765
}
yann@1
   766
yann@1
   767
static void conf_string(struct menu *menu)
yann@1
   768
{
yann@1
   769
	const char *prompt = menu_get_prompt(menu);
yann@1
   770
yann@1
   771
	while (1) {
yann@1
   772
		int res;
yann@1
   773
		char *heading;
yann@1
   774
yann@1
   775
		switch (sym_get_type(menu->sym)) {
yann@1
   776
		case S_INT:
yann@1
   777
			heading = _(inputbox_instructions_int);
yann@1
   778
			break;
yann@1
   779
		case S_HEX:
yann@1
   780
			heading = _(inputbox_instructions_hex);
yann@1
   781
			break;
yann@1
   782
		case S_STRING:
yann@1
   783
			heading = _(inputbox_instructions_string);
yann@1
   784
			break;
yann@1
   785
		default:
yann@1
   786
			heading = "Internal mconf error!";
yann@1
   787
		}
yann@1
   788
		dialog_clear();
yann@1
   789
		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
yann@1
   790
				      heading, 10, 75,
yann@1
   791
				      sym_get_string_value(menu->sym));
yann@1
   792
		switch (res) {
yann@1
   793
		case 0:
yann@1
   794
			if (sym_set_string_value(menu->sym, dialog_input_result))
yann@1
   795
				return;
yann@1
   796
			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
yann@1
   797
			break;
yann@1
   798
		case 1:
yann@1
   799
			show_help(menu);
yann@1
   800
			break;
yann@1
   801
		case KEY_ESC:
yann@1
   802
			return;
yann@1
   803
		}
yann@1
   804
	}
yann@1
   805
}
yann@1
   806
yann@1
   807
static void conf_load(void)
yann@1
   808
{
yann@1
   809
yann@1
   810
	while (1) {
yann@1
   811
		int res;
yann@1
   812
		dialog_clear();
yann@1
   813
		res = dialog_inputbox(NULL, load_config_text,
yann@1
   814
				      11, 55, filename);
yann@1
   815
		switch(res) {
yann@1
   816
		case 0:
yann@1
   817
			if (!dialog_input_result[0])
yann@1
   818
				return;
yann@1
   819
			if (!conf_read(dialog_input_result))
yann@1
   820
				return;
yann@1
   821
			show_textbox(NULL, _("File does not exist!"), 5, 38);
yann@1
   822
			break;
yann@1
   823
		case 1:
yann@1
   824
			show_helptext(_("Load Alternate Configuration"), load_config_help);
yann@1
   825
			break;
yann@1
   826
		case KEY_ESC:
yann@1
   827
			return;
yann@1
   828
		}
yann@1
   829
	}
yann@1
   830
}
yann@1
   831
yann@1
   832
static void conf_save(void)
yann@1
   833
{
yann@1
   834
	while (1) {
yann@1
   835
		int res;
yann@1
   836
		dialog_clear();
yann@1
   837
		res = dialog_inputbox(NULL, save_config_text,
yann@1
   838
				      11, 55, filename);
yann@1
   839
		switch(res) {
yann@1
   840
		case 0:
yann@1
   841
			if (!dialog_input_result[0])
yann@1
   842
				return;
yann@1
   843
			if (!conf_write(dialog_input_result))
yann@1
   844
				return;
yann@1
   845
			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
yann@1
   846
			break;
yann@1
   847
		case 1:
yann@1
   848
			show_helptext(_("Save Alternate Configuration"), save_config_help);
yann@1
   849
			break;
yann@1
   850
		case KEY_ESC:
yann@1
   851
			return;
yann@1
   852
		}
yann@1
   853
	}
yann@1
   854
}
yann@1
   855
yann@1
   856
static void conf_cleanup(void)
yann@1
   857
{
yann@1
   858
	tcsetattr(1, TCSAFLUSH, &ios_org);
yann@1
   859
}
yann@1
   860
yann@1
   861
int main(int ac, char **av)
yann@1
   862
{
yann@1
   863
	struct symbol *sym;
yann@1
   864
	char *mode;
yann@1
   865
	int res;
yann@1
   866
yann@1
   867
	setlocale(LC_ALL, "");
yann@1
   868
	bindtextdomain(PACKAGE, LOCALEDIR);
yann@1
   869
	textdomain(PACKAGE);
yann@1
   870
yann@39
   871
	conf_parse(av[1]);
yann@1
   872
	conf_read(NULL);
yann@1
   873
yann@1
   874
	sym = sym_lookup("PROJECTVERSION", 0);
yann@1
   875
	sym_calc_value(sym);
yann@1
   876
	sprintf(menu_backtitle, _(PROJECT_NAME" v%s Configuration"),
yann@1
   877
		sym_get_string_value(sym));
yann@1
   878
yann@1
   879
	mode = getenv("MENUCONFIG_MODE");
yann@1
   880
	if (mode) {
yann@1
   881
		if (!strcasecmp(mode, "single_menu"))
yann@1
   882
			single_menu_mode = 1;
yann@1
   883
	}
yann@1
   884
yann@1
   885
	tcgetattr(1, &ios_org);
yann@1
   886
	atexit(conf_cleanup);
yann@1
   887
	init_wsize();
yann@1
   888
	reset_dialog();
yann@1
   889
	init_dialog(menu_backtitle);
yann@1
   890
	do {
yann@1
   891
		conf(&rootmenu);
yann@1
   892
		dialog_clear();
yann@39
   893
		if (conf_get_changed())
yann@39
   894
			res = dialog_yesno(NULL,
yann@39
   895
					   _("Do you wish to save your "
yann@39
   896
					     "new "PROJECT_NAME" configuration?\n"
yann@39
   897
					     "<ESC><ESC> to continue."),
yann@39
   898
					   6, 60);
yann@39
   899
		else
yann@39
   900
			res = -1;
yann@1
   901
	} while (res == KEY_ESC);
yann@1
   902
	end_dialog();
yann@39
   903
yann@39
   904
	switch (res) {
yann@39
   905
	case 0:
yann@1
   906
		if (conf_write(NULL)) {
yann@94
   907
			fprintf(stderr,
yann@94
   908
				_( "Error during writing of "PROJECT_NAME" configuration.\n"
yann@94
   909
				   "Your configuration changes were NOT saved.\n"));
yann@1
   910
			return 1;
yann@1
   911
		}
yann@39
   912
	case -1:
yann@39
   913
		break;
yann@39
   914
	default:
yann@94
   915
		fprintf(stderr, _( "Your configuration changes were NOT saved.\n"));
yann@1
   916
	}
yann@1
   917
yann@1
   918
	return 0;
yann@1
   919
}