b321429325
Run "make xconfig" on a freshly untarred kernel-tree. Look at the floppy disk icon of the qt application, that has just started: Its in a normal, active state. Mouse click on it: .config is being saved. This patch series changes things so taht after the mouse click on the floppy disk icon, the icon is greyed out. If you mouse click on it now, nothing happens. If you change some CONFIG_*, the floppy disk icon returns to "active state", that is, if you mouse click it now, .config is written. This patch: Returns sym_change_count to reflect the .config's change state. All read only accesses of sym_change_count are replaced by calls to conf_get_changed() . mconfig.c is manipulated to ask for saving only when conf_get_changed() returned true. Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Roman Zippel <zippel@linux-m68k.org> Acked-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
627 lines
12 KiB
C
627 lines
12 KiB
C
/*
|
|
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
|
* Released under the terms of the GNU GPL v2.0.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
|
|
#define LKC_DIRECT_LINK
|
|
#include "lkc.h"
|
|
|
|
static void conf(struct menu *menu);
|
|
static void check_conf(struct menu *menu);
|
|
|
|
enum {
|
|
ask_all,
|
|
ask_new,
|
|
ask_silent,
|
|
set_default,
|
|
set_yes,
|
|
set_mod,
|
|
set_no,
|
|
set_random
|
|
} input_mode = ask_all;
|
|
char *defconfig_file;
|
|
|
|
static int indent = 1;
|
|
static int valid_stdin = 1;
|
|
static int conf_cnt;
|
|
static char line[128];
|
|
static struct menu *rootEntry;
|
|
|
|
static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
|
|
|
|
static void strip(char *str)
|
|
{
|
|
char *p = str;
|
|
int l;
|
|
|
|
while ((isspace(*p)))
|
|
p++;
|
|
l = strlen(p);
|
|
if (p != str)
|
|
memmove(str, p, l + 1);
|
|
if (!l)
|
|
return;
|
|
p = str + l - 1;
|
|
while ((isspace(*p)))
|
|
*p-- = 0;
|
|
}
|
|
|
|
static void check_stdin(void)
|
|
{
|
|
if (!valid_stdin && input_mode == ask_silent) {
|
|
printf(_("aborted!\n\n"));
|
|
printf(_("Console input/output is redirected. "));
|
|
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static void conf_askvalue(struct symbol *sym, const char *def)
|
|
{
|
|
enum symbol_type type = sym_get_type(sym);
|
|
tristate val;
|
|
|
|
if (!sym_has_value(sym))
|
|
printf("(NEW) ");
|
|
|
|
line[0] = '\n';
|
|
line[1] = 0;
|
|
|
|
if (!sym_is_changable(sym)) {
|
|
printf("%s\n", def);
|
|
line[0] = '\n';
|
|
line[1] = 0;
|
|
return;
|
|
}
|
|
|
|
switch (input_mode) {
|
|
case set_no:
|
|
case set_mod:
|
|
case set_yes:
|
|
case set_random:
|
|
if (sym_has_value(sym)) {
|
|
printf("%s\n", def);
|
|
return;
|
|
}
|
|
break;
|
|
case ask_new:
|
|
case ask_silent:
|
|
if (sym_has_value(sym)) {
|
|
printf("%s\n", def);
|
|
return;
|
|
}
|
|
check_stdin();
|
|
case ask_all:
|
|
fflush(stdout);
|
|
fgets(line, 128, stdin);
|
|
return;
|
|
case set_default:
|
|
printf("%s\n", def);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
printf("%s\n", def);
|
|
return;
|
|
default:
|
|
;
|
|
}
|
|
switch (input_mode) {
|
|
case set_yes:
|
|
if (sym_tristate_within_range(sym, yes)) {
|
|
line[0] = 'y';
|
|
line[1] = '\n';
|
|
line[2] = 0;
|
|
break;
|
|
}
|
|
case set_mod:
|
|
if (type == S_TRISTATE) {
|
|
if (sym_tristate_within_range(sym, mod)) {
|
|
line[0] = 'm';
|
|
line[1] = '\n';
|
|
line[2] = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
if (sym_tristate_within_range(sym, yes)) {
|
|
line[0] = 'y';
|
|
line[1] = '\n';
|
|
line[2] = 0;
|
|
break;
|
|
}
|
|
}
|
|
case set_no:
|
|
if (sym_tristate_within_range(sym, no)) {
|
|
line[0] = 'n';
|
|
line[1] = '\n';
|
|
line[2] = 0;
|
|
break;
|
|
}
|
|
case set_random:
|
|
do {
|
|
val = (tristate)(random() % 3);
|
|
} while (!sym_tristate_within_range(sym, val));
|
|
switch (val) {
|
|
case no: line[0] = 'n'; break;
|
|
case mod: line[0] = 'm'; break;
|
|
case yes: line[0] = 'y'; break;
|
|
}
|
|
line[1] = '\n';
|
|
line[2] = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
printf("%s", line);
|
|
}
|
|
|
|
int conf_string(struct menu *menu)
|
|
{
|
|
struct symbol *sym = menu->sym;
|
|
const char *def, *help;
|
|
|
|
while (1) {
|
|
printf("%*s%s ", indent - 1, "", menu->prompt->text);
|
|
printf("(%s) ", sym->name);
|
|
def = sym_get_string_value(sym);
|
|
if (sym_get_string_value(sym))
|
|
printf("[%s] ", def);
|
|
conf_askvalue(sym, def);
|
|
switch (line[0]) {
|
|
case '\n':
|
|
break;
|
|
case '?':
|
|
/* print help */
|
|
if (line[1] == '\n') {
|
|
help = nohelp_text;
|
|
if (menu->sym->help)
|
|
help = menu->sym->help;
|
|
printf("\n%s\n", menu->sym->help);
|
|
def = NULL;
|
|
break;
|
|
}
|
|
default:
|
|
line[strlen(line)-1] = 0;
|
|
def = line;
|
|
}
|
|
if (def && sym_set_string_value(sym, def))
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int conf_sym(struct menu *menu)
|
|
{
|
|
struct symbol *sym = menu->sym;
|
|
int type;
|
|
tristate oldval, newval;
|
|
const char *help;
|
|
|
|
while (1) {
|
|
printf("%*s%s ", indent - 1, "", menu->prompt->text);
|
|
if (sym->name)
|
|
printf("(%s) ", sym->name);
|
|
type = sym_get_type(sym);
|
|
putchar('[');
|
|
oldval = sym_get_tristate_value(sym);
|
|
switch (oldval) {
|
|
case no:
|
|
putchar('N');
|
|
break;
|
|
case mod:
|
|
putchar('M');
|
|
break;
|
|
case yes:
|
|
putchar('Y');
|
|
break;
|
|
}
|
|
if (oldval != no && sym_tristate_within_range(sym, no))
|
|
printf("/n");
|
|
if (oldval != mod && sym_tristate_within_range(sym, mod))
|
|
printf("/m");
|
|
if (oldval != yes && sym_tristate_within_range(sym, yes))
|
|
printf("/y");
|
|
if (sym->help)
|
|
printf("/?");
|
|
printf("] ");
|
|
conf_askvalue(sym, sym_get_string_value(sym));
|
|
strip(line);
|
|
|
|
switch (line[0]) {
|
|
case 'n':
|
|
case 'N':
|
|
newval = no;
|
|
if (!line[1] || !strcmp(&line[1], "o"))
|
|
break;
|
|
continue;
|
|
case 'm':
|
|
case 'M':
|
|
newval = mod;
|
|
if (!line[1])
|
|
break;
|
|
continue;
|
|
case 'y':
|
|
case 'Y':
|
|
newval = yes;
|
|
if (!line[1] || !strcmp(&line[1], "es"))
|
|
break;
|
|
continue;
|
|
case 0:
|
|
newval = oldval;
|
|
break;
|
|
case '?':
|
|
goto help;
|
|
default:
|
|
continue;
|
|
}
|
|
if (sym_set_tristate_value(sym, newval))
|
|
return 0;
|
|
help:
|
|
help = nohelp_text;
|
|
if (sym->help)
|
|
help = sym->help;
|
|
printf("\n%s\n", help);
|
|
}
|
|
}
|
|
|
|
static int conf_choice(struct menu *menu)
|
|
{
|
|
struct symbol *sym, *def_sym;
|
|
struct menu *child;
|
|
int type;
|
|
bool is_new;
|
|
|
|
sym = menu->sym;
|
|
type = sym_get_type(sym);
|
|
is_new = !sym_has_value(sym);
|
|
if (sym_is_changable(sym)) {
|
|
conf_sym(menu);
|
|
sym_calc_value(sym);
|
|
switch (sym_get_tristate_value(sym)) {
|
|
case no:
|
|
return 1;
|
|
case mod:
|
|
return 0;
|
|
case yes:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (sym_get_tristate_value(sym)) {
|
|
case no:
|
|
return 1;
|
|
case mod:
|
|
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
|
|
return 0;
|
|
case yes:
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (1) {
|
|
int cnt, def;
|
|
|
|
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
|
|
def_sym = sym_get_choice_value(sym);
|
|
cnt = def = 0;
|
|
line[0] = 0;
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (!menu_is_visible(child))
|
|
continue;
|
|
if (!child->sym) {
|
|
printf("%*c %s\n", indent, '*', menu_get_prompt(child));
|
|
continue;
|
|
}
|
|
cnt++;
|
|
if (child->sym == def_sym) {
|
|
def = cnt;
|
|
printf("%*c", indent, '>');
|
|
} else
|
|
printf("%*c", indent, ' ');
|
|
printf(" %d. %s", cnt, menu_get_prompt(child));
|
|
if (child->sym->name)
|
|
printf(" (%s)", child->sym->name);
|
|
if (!sym_has_value(child->sym))
|
|
printf(" (NEW)");
|
|
printf("\n");
|
|
}
|
|
printf("%*schoice", indent - 1, "");
|
|
if (cnt == 1) {
|
|
printf("[1]: 1\n");
|
|
goto conf_childs;
|
|
}
|
|
printf("[1-%d", cnt);
|
|
if (sym->help)
|
|
printf("?");
|
|
printf("]: ");
|
|
switch (input_mode) {
|
|
case ask_new:
|
|
case ask_silent:
|
|
if (!is_new) {
|
|
cnt = def;
|
|
printf("%d\n", cnt);
|
|
break;
|
|
}
|
|
check_stdin();
|
|
case ask_all:
|
|
fflush(stdout);
|
|
fgets(line, 128, stdin);
|
|
strip(line);
|
|
if (line[0] == '?') {
|
|
printf("\n%s\n", menu->sym->help ?
|
|
menu->sym->help : nohelp_text);
|
|
continue;
|
|
}
|
|
if (!line[0])
|
|
cnt = def;
|
|
else if (isdigit(line[0]))
|
|
cnt = atoi(line);
|
|
else
|
|
continue;
|
|
break;
|
|
case set_random:
|
|
def = (random() % cnt) + 1;
|
|
case set_default:
|
|
case set_yes:
|
|
case set_mod:
|
|
case set_no:
|
|
cnt = def;
|
|
printf("%d\n", cnt);
|
|
break;
|
|
}
|
|
|
|
conf_childs:
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (!child->sym || !menu_is_visible(child))
|
|
continue;
|
|
if (!--cnt)
|
|
break;
|
|
}
|
|
if (!child)
|
|
continue;
|
|
if (line[strlen(line) - 1] == '?') {
|
|
printf("\n%s\n", child->sym->help ?
|
|
child->sym->help : nohelp_text);
|
|
continue;
|
|
}
|
|
sym_set_choice_value(sym, child->sym);
|
|
if (child->list) {
|
|
indent += 2;
|
|
conf(child->list);
|
|
indent -= 2;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static void conf(struct menu *menu)
|
|
{
|
|
struct symbol *sym;
|
|
struct property *prop;
|
|
struct menu *child;
|
|
|
|
if (!menu_is_visible(menu))
|
|
return;
|
|
|
|
sym = menu->sym;
|
|
prop = menu->prompt;
|
|
if (prop) {
|
|
const char *prompt;
|
|
|
|
switch (prop->type) {
|
|
case P_MENU:
|
|
if (input_mode == ask_silent && rootEntry != menu) {
|
|
check_conf(menu);
|
|
return;
|
|
}
|
|
case P_COMMENT:
|
|
prompt = menu_get_prompt(menu);
|
|
if (prompt)
|
|
printf("%*c\n%*c %s\n%*c\n",
|
|
indent, '*',
|
|
indent, '*', prompt,
|
|
indent, '*');
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
if (!sym)
|
|
goto conf_childs;
|
|
|
|
if (sym_is_choice(sym)) {
|
|
conf_choice(menu);
|
|
if (sym->curr.tri != mod)
|
|
return;
|
|
goto conf_childs;
|
|
}
|
|
|
|
switch (sym->type) {
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
conf_string(menu);
|
|
break;
|
|
default:
|
|
conf_sym(menu);
|
|
break;
|
|
}
|
|
|
|
conf_childs:
|
|
if (sym)
|
|
indent += 2;
|
|
for (child = menu->list; child; child = child->next)
|
|
conf(child);
|
|
if (sym)
|
|
indent -= 2;
|
|
}
|
|
|
|
static void check_conf(struct menu *menu)
|
|
{
|
|
struct symbol *sym;
|
|
struct menu *child;
|
|
|
|
if (!menu_is_visible(menu))
|
|
return;
|
|
|
|
sym = menu->sym;
|
|
if (sym && !sym_has_value(sym)) {
|
|
if (sym_is_changable(sym) ||
|
|
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
|
|
if (!conf_cnt++)
|
|
printf(_("*\n* Restart config...\n*\n"));
|
|
rootEntry = menu_get_parent_menu(menu);
|
|
conf(rootEntry);
|
|
}
|
|
}
|
|
|
|
for (child = menu->list; child; child = child->next)
|
|
check_conf(child);
|
|
}
|
|
|
|
int main(int ac, char **av)
|
|
{
|
|
int i = 1;
|
|
const char *name;
|
|
struct stat tmpstat;
|
|
|
|
if (ac > i && av[i][0] == '-') {
|
|
switch (av[i++][1]) {
|
|
case 'o':
|
|
input_mode = ask_new;
|
|
break;
|
|
case 's':
|
|
input_mode = ask_silent;
|
|
valid_stdin = isatty(0) && isatty(1) && isatty(2);
|
|
break;
|
|
case 'd':
|
|
input_mode = set_default;
|
|
break;
|
|
case 'D':
|
|
input_mode = set_default;
|
|
defconfig_file = av[i++];
|
|
if (!defconfig_file) {
|
|
printf(_("%s: No default config file specified\n"),
|
|
av[0]);
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'n':
|
|
input_mode = set_no;
|
|
break;
|
|
case 'm':
|
|
input_mode = set_mod;
|
|
break;
|
|
case 'y':
|
|
input_mode = set_yes;
|
|
break;
|
|
case 'r':
|
|
input_mode = set_random;
|
|
srandom(time(NULL));
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
fprintf(stderr, "See README for usage info\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
name = av[i];
|
|
if (!name) {
|
|
printf(_("%s: Kconfig file missing\n"), av[0]);
|
|
exit(1);
|
|
}
|
|
conf_parse(name);
|
|
//zconfdump(stdout);
|
|
switch (input_mode) {
|
|
case set_default:
|
|
if (!defconfig_file)
|
|
defconfig_file = conf_get_default_confname();
|
|
if (conf_read(defconfig_file)) {
|
|
printf("***\n"
|
|
"*** Can't find default configuration \"%s\"!\n"
|
|
"***\n", defconfig_file);
|
|
exit(1);
|
|
}
|
|
break;
|
|
case ask_silent:
|
|
if (stat(".config", &tmpstat)) {
|
|
printf(_("***\n"
|
|
"*** You have not yet configured your kernel!\n"
|
|
"***\n"
|
|
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
|
|
"*** \"make menuconfig\" or \"make xconfig\").\n"
|
|
"***\n"));
|
|
exit(1);
|
|
}
|
|
case ask_all:
|
|
case ask_new:
|
|
conf_read(NULL);
|
|
break;
|
|
case set_no:
|
|
case set_mod:
|
|
case set_yes:
|
|
case set_random:
|
|
name = getenv("KCONFIG_ALLCONFIG");
|
|
if (name && !stat(name, &tmpstat)) {
|
|
conf_read_simple(name, S_DEF_USER);
|
|
break;
|
|
}
|
|
switch (input_mode) {
|
|
case set_no: name = "allno.config"; break;
|
|
case set_mod: name = "allmod.config"; break;
|
|
case set_yes: name = "allyes.config"; break;
|
|
case set_random: name = "allrandom.config"; break;
|
|
default: break;
|
|
}
|
|
if (!stat(name, &tmpstat))
|
|
conf_read_simple(name, S_DEF_USER);
|
|
else if (!stat("all.config", &tmpstat))
|
|
conf_read_simple("all.config", S_DEF_USER);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (input_mode != ask_silent) {
|
|
rootEntry = &rootmenu;
|
|
conf(&rootmenu);
|
|
if (input_mode == ask_all) {
|
|
input_mode = ask_silent;
|
|
valid_stdin = 1;
|
|
}
|
|
} else if (conf_get_changed()) {
|
|
name = getenv("KCONFIG_NOSILENTUPDATE");
|
|
if (name && *name) {
|
|
fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
|
|
return 1;
|
|
}
|
|
} else
|
|
goto skip_check;
|
|
|
|
do {
|
|
conf_cnt = 0;
|
|
check_conf(&rootmenu);
|
|
} while (conf_cnt);
|
|
if (conf_write(NULL)) {
|
|
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
|
|
return 1;
|
|
}
|
|
skip_check:
|
|
if (input_mode == ask_silent && conf_write_autoconf()) {
|
|
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|