You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
11 KiB
583 lines
11 KiB
/* |
|
* 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 <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 signed char line[128]; |
|
static struct menu *rootEntry; |
|
|
|
static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; |
|
|
|
static void strip(signed char *str) |
|
{ |
|
signed 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 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'; |
|
line[1] = 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) { |
|
if (sym_is_changable(sym) && !sym_has_value(sym)) { |
|
if (!conf_cnt++) |
|
printf("*\n* Restart config...\n*\n"); |
|
rootEntry = menu_get_parent_menu(menu); |
|
conf(rootEntry); |
|
} |
|
if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod) |
|
return; |
|
} |
|
|
|
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 '?': |
|
printf("%s [-o|-s] config\n", av[0]); |
|
exit(0); |
|
} |
|
} |
|
name = av[i]; |
|
if (!name) { |
|
printf("%s: configuration file missing\n", av[0]); |
|
} |
|
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 Buildroot!\n" |
|
"***\n" |
|
"*** Please run some configurator (e.g. \"make oldconfig\" or\n" |
|
"*** \"make menuconfig\" or \"make config\").\n" |
|
"***\n"); |
|
exit(1); |
|
} |
|
case ask_all: |
|
case ask_new: |
|
conf_read(NULL); |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
if (input_mode != ask_silent) { |
|
rootEntry = &rootmenu; |
|
conf(&rootmenu); |
|
if (input_mode == ask_all) { |
|
input_mode = ask_silent; |
|
valid_stdin = 1; |
|
} |
|
} |
|
do { |
|
conf_cnt = 0; |
|
check_conf(&rootmenu); |
|
} while (conf_cnt); |
|
if (conf_write(NULL)) { |
|
fprintf(stderr, "\n*** Error during writing of the Buildroot configuration.\n\n"); |
|
return 1; |
|
} |
|
return 0; |
|
}
|
|
|