parent
4870d7e887
commit
43ebd5a027
@ -0,0 +1,49 @@ |
||||
# ===========================================================================
|
||||
# Kernel configuration targets
|
||||
# These targets are used from top-level makefile
|
||||
|
||||
# ===========================================================================
|
||||
# Shared Makefile for the various kconfig executables:
|
||||
# conf: Used for defconfig, oldconfig and related targets
|
||||
# mconf: Used for the mconfig target.
|
||||
# Utilizes the lxdialog package
|
||||
# object files used by all kconfig flavours
|
||||
|
||||
conf-objs := conf.o zconf.tab.o
|
||||
mconf-objs := mconf.o zconf.tab.o
|
||||
|
||||
clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
|
||||
.tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
|
||||
|
||||
all: conf mconf lxdialog |
||||
|
||||
.PHONY: lxdialog |
||||
lxdialog: |
||||
$(MAKE) -C lxdialog
|
||||
|
||||
conf: $(conf-objs) |
||||
mconf: $(mconf-objs) |
||||
|
||||
clean: |
||||
rm -f *.o $(clean-files) conf mconf
|
||||
$(MAKE) -C lxdialog clean
|
||||
|
||||
zconf.tab.o: lex.zconf.c zconf.hash.c |
||||
|
||||
kconfig_load.o: lkc_defs.h |
||||
|
||||
lkc_defs.h: $(src)/lkc_proto.h |
||||
sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
|
||||
|
||||
zconf.tab.c: zconf.y |
||||
lex.zconf.c: zconf.l |
||||
zconf.hash.c: zconf.gperf |
||||
|
||||
%.tab.c: %.y |
||||
bison -l -b $* -p $(notdir $*) $< && cp $@ $@_shipped || cp $@_shipped $@
|
||||
|
||||
lex.%.c: %.l |
||||
flex -L -P$(notdir $*) -o$@ $< && cp $@ $@_shipped || cp $@_shipped $@
|
||||
|
||||
%.hash.c: %.gperf |
||||
gperf < $< > $@ && cp $@ $@_shipped || cp $@_shipped $@
|
@ -0,0 +1,626 @@ |
||||
/*
|
||||
* 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 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 char *fgets_check_stream(char *s, int size, FILE *stream) |
||||
{ |
||||
char *ret = fgets(s, size, stream); |
||||
|
||||
if (ret == NULL && feof(stream)) { |
||||
printf(_("aborted!\n\n")); |
||||
printf(_("Console input is closed. ")); |
||||
printf(_("Run 'make oldconfig' to update configuration.\n\n")); |
||||
exit(1); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
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_check_stream(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_check_stream(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 '?': |
||||
printf("%s [-o|-s] config\n", av[0]); |
||||
exit(0); |
||||
} |
||||
} |
||||
name = av[i]; |
||||
if (!name) { |
||||
printf(_("%s: Kconfig 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 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); |
||||
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); |
||||
else if (!stat("all.config", &tmpstat)) |
||||
conf_read_simple("all.config"); |
||||
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 kernel configuration.\n\n")); |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,530 @@ |
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <sys/stat.h> |
||||
#include <ctype.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
#define LKC_DIRECT_LINK |
||||
#include "lkc.h" |
||||
|
||||
static void conf_warning(const char *fmt, ...) |
||||
__attribute__ ((format (printf, 1, 2))); |
||||
|
||||
static const char *conf_filename; |
||||
static int conf_lineno, conf_warnings, conf_unsaved; |
||||
|
||||
const char conf_def_filename[] = ".config"; |
||||
|
||||
const char conf_defname[] = "arch/$ARCH/defconfig"; |
||||
|
||||
const char *conf_confnames[] = { |
||||
".config", |
||||
"/lib/modules/$UNAME_RELEASE/.config", |
||||
"/etc/kernel-config", |
||||
"/boot/config-$UNAME_RELEASE", |
||||
conf_defname, |
||||
NULL, |
||||
}; |
||||
|
||||
static void conf_warning(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
va_start(ap, fmt); |
||||
fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
va_end(ap); |
||||
conf_warnings++; |
||||
} |
||||
|
||||
static char *conf_expand_value(const char *in) |
||||
{ |
||||
struct symbol *sym; |
||||
const char *src; |
||||
static char res_value[SYMBOL_MAXLENGTH]; |
||||
char *dst, name[SYMBOL_MAXLENGTH]; |
||||
|
||||
res_value[0] = 0; |
||||
dst = name; |
||||
while ((src = strchr(in, '$'))) { |
||||
strncat(res_value, in, src - in); |
||||
src++; |
||||
dst = name; |
||||
while (isalnum(*src) || *src == '_') |
||||
*dst++ = *src++; |
||||
*dst = 0; |
||||
sym = sym_lookup(name, 0); |
||||
sym_calc_value(sym); |
||||
strcat(res_value, sym_get_string_value(sym)); |
||||
in = src; |
||||
} |
||||
strcat(res_value, in); |
||||
|
||||
return res_value; |
||||
} |
||||
|
||||
char *conf_get_default_confname(void) |
||||
{ |
||||
struct stat buf; |
||||
static char fullname[PATH_MAX+1]; |
||||
char *env, *name; |
||||
|
||||
name = conf_expand_value(conf_defname); |
||||
env = getenv(SRCTREE); |
||||
if (env) { |
||||
sprintf(fullname, "%s/%s", env, name); |
||||
if (!stat(fullname, &buf)) |
||||
return fullname; |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
int conf_read_simple(const char *name) |
||||
{ |
||||
FILE *in = NULL; |
||||
char line[1024]; |
||||
char *p, *p2; |
||||
struct symbol *sym; |
||||
int i; |
||||
|
||||
if (name) { |
||||
in = zconf_fopen(name); |
||||
} else { |
||||
const char **names = conf_confnames; |
||||
while ((name = *names++)) { |
||||
name = conf_expand_value(name); |
||||
in = zconf_fopen(name); |
||||
if (in) { |
||||
printf(_("#\n" |
||||
"# using defaults found in %s\n" |
||||
"#\n"), name); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (!in) |
||||
return 1; |
||||
|
||||
conf_filename = name; |
||||
conf_lineno = 0; |
||||
conf_warnings = 0; |
||||
conf_unsaved = 0; |
||||
|
||||
for_all_symbols(i, sym) { |
||||
sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; |
||||
if (sym_is_choice(sym)) |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
sym->flags &= ~SYMBOL_VALID; |
||||
switch (sym->type) { |
||||
case S_INT: |
||||
case S_HEX: |
||||
case S_STRING: |
||||
if (sym->user.val) |
||||
free(sym->user.val); |
||||
default: |
||||
sym->user.val = NULL; |
||||
sym->user.tri = no; |
||||
} |
||||
} |
||||
|
||||
while (fgets(line, sizeof(line), in)) { |
||||
conf_lineno++; |
||||
sym = NULL; |
||||
switch (line[0]) { |
||||
case '#': |
||||
if (memcmp(line + 2, "CONFIG_", 7)) |
||||
continue; |
||||
p = strchr(line + 9, ' '); |
||||
if (!p) |
||||
continue; |
||||
*p++ = 0; |
||||
if (strncmp(p, "is not set", 10)) |
||||
continue; |
||||
sym = sym_find(line + 9); |
||||
if (!sym) { |
||||
conf_warning("trying to assign nonexistent symbol %s", line + 9); |
||||
break; |
||||
} else if (!(sym->flags & SYMBOL_NEW)) { |
||||
conf_warning("trying to reassign symbol %s", sym->name); |
||||
break; |
||||
} |
||||
switch (sym->type) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
sym->user.tri = no; |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
break; |
||||
case 'C': |
||||
if (memcmp(line, "CONFIG_", 7)) { |
||||
conf_warning("unexpected data"); |
||||
continue; |
||||
} |
||||
p = strchr(line + 7, '='); |
||||
if (!p) |
||||
continue; |
||||
*p++ = 0; |
||||
p2 = strchr(p, '\n'); |
||||
if (p2) |
||||
*p2 = 0; |
||||
sym = sym_find(line + 7); |
||||
if (!sym) { |
||||
conf_warning("trying to assign nonexistent symbol %s", line + 7); |
||||
break; |
||||
} else if (!(sym->flags & SYMBOL_NEW)) { |
||||
conf_warning("trying to reassign symbol %s", sym->name); |
||||
break; |
||||
} |
||||
switch (sym->type) { |
||||
case S_TRISTATE: |
||||
if (p[0] == 'm') { |
||||
sym->user.tri = mod; |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
break; |
||||
} |
||||
case S_BOOLEAN: |
||||
if (p[0] == 'y') { |
||||
sym->user.tri = yes; |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
break; |
||||
} |
||||
if (p[0] == 'n') { |
||||
sym->user.tri = no; |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
break; |
||||
} |
||||
conf_warning("symbol value '%s' invalid for %s", p, sym->name); |
||||
break; |
||||
case S_STRING: |
||||
if (*p++ != '"') |
||||
break; |
||||
for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { |
||||
if (*p2 == '"') { |
||||
*p2 = 0; |
||||
break; |
||||
} |
||||
memmove(p2, p2 + 1, strlen(p2)); |
||||
} |
||||
if (!p2) { |
||||
conf_warning("invalid string found"); |
||||
continue; |
||||
} |
||||
case S_INT: |
||||
case S_HEX: |
||||
if (sym_string_valid(sym, p)) { |
||||
sym->user.val = strdup(p); |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
} else { |
||||
conf_warning("symbol value '%s' invalid for %s", p, sym->name); |
||||
continue; |
||||
} |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
break; |
||||
case '\n': |
||||
break; |
||||
default: |
||||
conf_warning("unexpected data"); |
||||
continue; |
||||
} |
||||
if (sym && sym_is_choice_value(sym)) { |
||||
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); |
||||
switch (sym->user.tri) { |
||||
case no: |
||||
break; |
||||
case mod: |
||||
if (cs->user.tri == yes) { |
||||
conf_warning("%s creates inconsistent choice state", sym->name); |
||||
cs->flags |= SYMBOL_NEW; |
||||
} |
||||
break; |
||||
case yes: |
||||
if (cs->user.tri != no) { |
||||
conf_warning("%s creates inconsistent choice state", sym->name); |
||||
cs->flags |= SYMBOL_NEW; |
||||
} else |
||||
cs->user.val = sym; |
||||
break; |
||||
} |
||||
cs->user.tri = E_OR(cs->user.tri, sym->user.tri); |
||||
} |
||||
} |
||||
fclose(in); |
||||
|
||||
if (modules_sym) |
||||
sym_calc_value(modules_sym); |
||||
return 0; |
||||
} |
||||
|
||||
int conf_read(const char *name) |
||||
{ |
||||
struct symbol *sym; |
||||
struct property *prop; |
||||
struct expr *e; |
||||
int i; |
||||
|
||||
if (conf_read_simple(name)) |
||||
return 1; |
||||
|
||||
for_all_symbols(i, sym) { |
||||
sym_calc_value(sym); |
||||
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) |
||||
goto sym_ok; |
||||
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { |
||||
/* check that calculated value agrees with saved value */ |
||||
switch (sym->type) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
if (sym->user.tri != sym_get_tristate_value(sym)) |
||||
break; |
||||
if (!sym_is_choice(sym)) |
||||
goto sym_ok; |
||||
default: |
||||
if (!strcmp(sym->curr.val, sym->user.val)) |
||||
goto sym_ok; |
||||
break; |
||||
} |
||||
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) |
||||
/* no previous value and not saved */ |
||||
goto sym_ok; |
||||
conf_unsaved++; |
||||
/* maybe print value in verbose mode... */ |
||||
sym_ok: |
||||
if (sym_has_value(sym) && !sym_is_choice_value(sym)) { |
||||
if (sym->visible == no) |
||||
sym->flags |= SYMBOL_NEW; |
||||
switch (sym->type) { |
||||
case S_STRING: |
||||
case S_INT: |
||||
case S_HEX: |
||||
if (!sym_string_within_range(sym, sym->user.val)) { |
||||
sym->flags |= SYMBOL_NEW; |
||||
sym->flags &= ~SYMBOL_VALID; |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
if (!sym_is_choice(sym)) |
||||
continue; |
||||
prop = sym_get_choice_prop(sym); |
||||
for (e = prop->expr; e; e = e->left.expr) |
||||
if (e->right.sym->visible != no) |
||||
sym->flags |= e->right.sym->flags & SYMBOL_NEW; |
||||
} |
||||
|
||||
sym_change_count = conf_warnings && conf_unsaved; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int conf_write(const char *name) |
||||
{ |
||||
FILE *out, *out_h; |
||||
struct symbol *sym; |
||||
struct menu *menu; |
||||
const char *basename; |
||||
char dirname[128], tmpname[128], newname[128]; |
||||
int type, l; |
||||
const char *str; |
||||
time_t now; |
||||
int use_timestamp = 1; |
||||
char *env; |
||||
|
||||
dirname[0] = 0; |
||||
if (name && name[0]) { |
||||
struct stat st; |
||||
char *slash; |
||||
|
||||
if (!stat(name, &st) && S_ISDIR(st.st_mode)) { |
||||
strcpy(dirname, name); |
||||
strcat(dirname, "/"); |
||||
basename = conf_def_filename; |
||||
} else if ((slash = strrchr(name, '/'))) { |
||||
int size = slash - name + 1; |
||||
memcpy(dirname, name, size); |
||||
dirname[size] = 0; |
||||
if (slash[1]) |
||||
basename = slash + 1; |
||||
else |
||||
basename = conf_def_filename; |
||||
} else |
||||
basename = name; |
||||
} else |
||||
basename = conf_def_filename; |
||||
|
||||
sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid()); |
||||
out = fopen(newname, "w"); |
||||
if (!out) |
||||
return 1; |
||||
out_h = NULL; |
||||
if (!name) { |
||||
out_h = fopen(".tmpconfig.h", "w"); |
||||
if (!out_h) |
||||
return 1; |
||||
} |
||||
sym = sym_lookup("KERNELVERSION", 0); |
||||
sym_calc_value(sym); |
||||
time(&now); |
||||
env = getenv("KCONFIG_NOTIMESTAMP"); |
||||
if (env && *env) |
||||
use_timestamp = 0; |
||||
|
||||
fprintf(out, _("#\n" |
||||
"# Automatically generated make config: don't edit\n" |
||||
"# Linux kernel version: %s\n" |
||||
"%s%s" |
||||
"#\n"), |
||||
sym_get_string_value(sym), |
||||
use_timestamp ? "# " : "", |
||||
use_timestamp ? ctime(&now) : ""); |
||||
if (out_h) |
||||
fprintf(out_h, "/*\n" |
||||
" * Automatically generated C config: don't edit\n" |
||||
" * Linux kernel version: %s\n" |
||||
"%s%s" |
||||
" */\n" |
||||
"#define AUTOCONF_INCLUDED\n", |
||||
sym_get_string_value(sym), |
||||
use_timestamp ? " * " : "", |
||||
use_timestamp ? ctime(&now) : ""); |
||||
|
||||
if (!sym_change_count) |
||||
sym_clear_all_valid(); |
||||
|
||||
menu = rootmenu.list; |
||||
while (menu) { |
||||
sym = menu->sym; |
||||
if (!sym) { |
||||
if (!menu_is_visible(menu)) |
||||
goto next; |
||||
str = menu_get_prompt(menu); |
||||
fprintf(out, "\n" |
||||
"#\n" |
||||
"# %s\n" |
||||
"#\n", str); |
||||
if (out_h) |
||||
fprintf(out_h, "\n" |
||||
"/*\n" |
||||
" * %s\n" |
||||
" */\n", str); |
||||
} else if (!(sym->flags & SYMBOL_CHOICE)) { |
||||
sym_calc_value(sym); |
||||
if (!(sym->flags & SYMBOL_WRITE)) |
||||
goto next; |
||||
sym->flags &= ~SYMBOL_WRITE; |
||||
type = sym->type; |
||||
if (type == S_TRISTATE) { |
||||
sym_calc_value(modules_sym); |
||||
if (modules_sym->curr.tri == no) |
||||
type = S_BOOLEAN; |
||||
} |
||||
switch (type) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
switch (sym_get_tristate_value(sym)) { |
||||
case no: |
||||
fprintf(out, "# CONFIG_%s is not set\n", sym->name); |
||||
if (out_h) |
||||
fprintf(out_h, "#undef CONFIG_%s\n", sym->name); |
||||
break; |
||||
case mod: |
||||
fprintf(out, "CONFIG_%s=m\n", sym->name); |
||||
if (out_h) |
||||
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); |
||||
break; |
||||
case yes: |
||||
fprintf(out, "CONFIG_%s=y\n", sym->name); |
||||
if (out_h) |
||||
fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); |
||||
break; |
||||
} |
||||
break; |
||||
case S_STRING: |
||||
// fix me
|
||||
str = sym_get_string_value(sym); |
||||
fprintf(out, "CONFIG_%s=\"", sym->name); |
||||
if (out_h) |
||||
fprintf(out_h, "#define CONFIG_%s \"", sym->name); |
||||
do { |
||||
l = strcspn(str, "\"\\"); |
||||
if (l) { |
||||
fwrite(str, l, 1, out); |
||||
if (out_h) |
||||
fwrite(str, l, 1, out_h); |
||||
} |
||||
str += l; |
||||
while (*str == '\\' || *str == '"') { |
||||
fprintf(out, "\\%c", *str); |
||||
if (out_h) |
||||
fprintf(out_h, "\\%c", *str); |
||||
str++; |
||||
} |
||||
} while (*str); |
||||
fputs("\"\n", out); |
||||
if (out_h) |
||||
fputs("\"\n", out_h); |
||||
break; |
||||
case S_HEX: |
||||
str = sym_get_string_value(sym); |
||||
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { |
||||
fprintf(out, "CONFIG_%s=%s\n", sym->name, str); |
||||
if (out_h) |
||||
fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); |
||||
break; |
||||
} |
||||
case S_INT: |
||||
str = sym_get_string_value(sym); |
||||
fprintf(out, "CONFIG_%s=%s\n", sym->name, str); |
||||
if (out_h) |
||||
fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
next: |
||||
if (menu->list) { |
||||
menu = menu->list; |
||||
continue; |
||||
} |
||||
if (menu->next) |
||||
menu = menu->next; |
||||
else while ((menu = menu->parent)) { |
||||
if (menu->next) { |
||||
menu = menu->next; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
fclose(out); |
||||
if (out_h) { |
||||
fclose(out_h); |
||||
rename(".tmpconfig.h", "include/linux/autoconf.h"); |
||||
file_write_dep(NULL); |
||||
} |
||||
if (!name || basename != conf_def_filename) { |
||||
if (!name) |
||||
name = conf_def_filename; |
||||
sprintf(tmpname, "%s.old", name); |
||||
rename(name, tmpname); |
||||
} |
||||
sprintf(tmpname, "%s%s", dirname, basename); |
||||
if (rename(newname, tmpname)) |
||||
return 1; |
||||
|
||||
sym_change_count = 0; |
||||
|
||||
return 0; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,194 @@ |
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#ifndef EXPR_H |
||||
#define EXPR_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#ifndef __cplusplus |
||||
#include <stdbool.h> |
||||
#endif |
||||
|
||||
struct file { |
||||
struct file *next; |
||||
struct file *parent; |
||||
char *name; |
||||
int lineno; |
||||
int flags; |
||||
}; |
||||
|
||||
#define FILE_BUSY 0x0001 |
||||
#define FILE_SCANNED 0x0002 |
||||
#define FILE_PRINTED 0x0004 |
||||
|
||||
typedef enum tristate { |
||||
no, mod, yes |
||||
} tristate; |
||||
|
||||
enum expr_type { |
||||
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE |
||||
}; |
||||
|
||||
union expr_data { |
||||
struct expr *expr; |
||||
struct symbol *sym; |
||||
}; |
||||
|
||||
struct expr { |
||||
enum expr_type type; |
||||
union expr_data left, right; |
||||
}; |
||||
|
||||
#define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) |
||||
#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) |
||||
#define E_NOT(dep) (2-(dep)) |
||||
|
||||
struct expr_value { |
||||
struct expr *expr; |
||||
tristate tri; |
||||
}; |
||||
|
||||
struct symbol_value { |
||||
void *val; |
||||
tristate tri; |
||||
}; |
||||
|
||||
enum symbol_type { |
||||
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER |
||||
}; |
||||
|
||||
struct symbol { |
||||
struct symbol *next; |
||||
char *name; |
||||
char *help; |
||||
enum symbol_type type; |
||||
struct symbol_value curr, user; |
||||
tristate visible; |
||||
int flags; |
||||
struct property *prop; |
||||
struct expr *dep, *dep2; |
||||
struct expr_value rev_dep; |
||||
}; |
||||
|
||||
#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) |
||||
|
||||
#define SYMBOL_YES 0x0001 |
||||
#define SYMBOL_MOD 0x0002 |
||||
#define SYMBOL_NO 0x0004 |
||||
#define SYMBOL_CONST 0x0007 |
||||
#define SYMBOL_CHECK 0x0008 |
||||
#define SYMBOL_CHOICE 0x0010 |
||||
#define SYMBOL_CHOICEVAL 0x0020 |
||||
#define SYMBOL_PRINTED 0x0040 |
||||
#define SYMBOL_VALID 0x0080 |
||||
#define SYMBOL_OPTIONAL 0x0100 |
||||
#define SYMBOL_WRITE 0x0200 |
||||
#define SYMBOL_CHANGED 0x0400 |
||||
#define SYMBOL_NEW 0x0800 |
||||
#define SYMBOL_AUTO 0x1000 |
||||
#define SYMBOL_CHECKED 0x2000 |
||||
#define SYMBOL_WARNED 0x8000 |
||||
|
||||
#define SYMBOL_MAXLENGTH 256 |
||||
#define SYMBOL_HASHSIZE 257 |
||||
#define SYMBOL_HASHMASK 0xff |
||||
|
||||
enum prop_type { |
||||
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE |
||||
}; |
||||
|
||||
struct property { |
||||
struct property *next; |
||||
struct symbol *sym; |
||||
enum prop_type type; |
||||
const char *text; |
||||
struct expr_value visible; |
||||
struct expr *expr; |
||||
struct menu *menu; |
||||
struct file *file; |
||||
int lineno; |
||||
}; |
||||
|
||||
#define for_all_properties(sym, st, tok) \ |
||||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->type == (tok)) |
||||
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) |
||||
#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) |
||||
#define for_all_prompts(sym, st) \ |
||||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->text) |
||||
|
||||
struct menu { |
||||
struct menu *next; |
||||
struct menu *parent; |
||||
struct menu *list; |
||||
struct symbol *sym; |
||||
struct property *prompt; |
||||
struct expr *dep; |
||||
unsigned int flags; |
||||
//char *help;
|
||||
struct file *file; |
||||
int lineno; |
||||
void *data; |
||||
}; |
||||
|
||||
#define MENU_CHANGED 0x0001 |
||||
#define MENU_ROOT 0x0002 |
||||
|
||||
#ifndef SWIG |
||||
|
||||
extern struct file *file_list; |
||||
extern struct file *current_file; |
||||
struct file *lookup_file(const char *name); |
||||
|
||||
extern struct symbol symbol_yes, symbol_no, symbol_mod; |
||||
extern struct symbol *modules_sym; |
||||
extern int cdebug; |
||||
struct expr *expr_alloc_symbol(struct symbol *sym); |
||||
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); |
||||
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); |
||||
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); |
||||
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); |
||||
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); |
||||
struct expr *expr_copy(struct expr *org); |
||||
void expr_free(struct expr *e); |
||||
int expr_eq(struct expr *e1, struct expr *e2); |
||||
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); |
||||
tristate expr_calc_value(struct expr *e); |
||||
struct expr *expr_eliminate_yn(struct expr *e); |
||||
struct expr *expr_trans_bool(struct expr *e); |
||||
struct expr *expr_eliminate_dups(struct expr *e); |
||||
struct expr *expr_transform(struct expr *e); |
||||
int expr_contains_symbol(struct expr *dep, struct symbol *sym); |
||||
bool expr_depends_symbol(struct expr *dep, struct symbol *sym); |
||||
struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); |
||||
struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); |
||||
void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); |
||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); |
||||
|
||||
void expr_fprint(struct expr *e, FILE *out); |
||||
struct gstr; /* forward */ |
||||
void expr_gstr_print(struct expr *e, struct gstr *gs); |
||||
|
||||
static inline int expr_is_yes(struct expr *e) |
||||
{ |
||||
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); |
||||
} |
||||
|
||||
static inline int expr_is_no(struct expr *e) |
||||
{ |
||||
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); |
||||
} |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* EXPR_H */ |
@ -0,0 +1,35 @@ |
||||
#include <dlfcn.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "lkc.h" |
||||
|
||||
#define P(name,type,arg) type (*name ## _p) arg |
||||
#include "lkc_proto.h" |
||||
#undef P |
||||
|
||||
void kconfig_load(void) |
||||
{ |
||||
void *handle; |
||||
char *error; |
||||
|
||||
handle = dlopen("./libkconfig.so", RTLD_LAZY); |
||||
if (!handle) { |
||||
handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY); |
||||
if (!handle) { |
||||
fprintf(stderr, "%s\n", dlerror()); |
||||
exit(1); |
||||
} |
||||
} |
||||
|
||||
#define P(name,type,arg) \ |
||||
{ \
|
||||
name ## _p = dlsym(handle, #name); \
|
||||
if ((error = dlerror())) { \
|
||||
fprintf(stderr, "%s\n", error); \
|
||||
exit(1); \
|
||||
} \
|
||||
} |
||||
#include "lkc_proto.h" |
||||
#undef P |
||||
} |
@ -0,0 +1 @@ |
||||
No backing up. |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,147 @@ |
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#ifndef LKC_H |
||||
#define LKC_H |
||||
|
||||
#include "expr.h" |
||||
|
||||
#ifndef KBUILD_NO_NLS |
||||
# include <libintl.h> |
||||
#else |
||||
# define gettext(Msgid) ((const char *) (Msgid)) |
||||
# define textdomain(Domainname) ((const char *) (Domainname)) |
||||
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifdef LKC_DIRECT_LINK |
||||
#define P(name,type,arg) extern type name arg |
||||
#else |
||||
#include "lkc_defs.h" |
||||
#define P(name,type,arg) extern type (*name ## _p) arg |
||||
#endif |
||||
#include "lkc_proto.h" |
||||
#undef P |
||||
|
||||
#define SRCTREE "srctree" |
||||
|
||||
#define PACKAGE "linux" |
||||
#define LOCALEDIR "/usr/share/locale" |
||||
|
||||
#define _(text) gettext(text) |
||||
#define N_(text) (text) |
||||
|
||||
|
||||
#define TF_COMMAND 0x0001 |
||||
#define TF_PARAM 0x0002 |
||||
|
||||
struct kconf_id { |
||||
int name; |
||||
int token; |
||||
unsigned int flags; |
||||
enum symbol_type stype; |
||||
}; |
||||
|
||||
int zconfparse(void); |
||||
void zconfdump(FILE *out); |
||||
|
||||
extern int zconfdebug; |
||||
void zconf_starthelp(void); |
||||
FILE *zconf_fopen(const char *name); |
||||
void zconf_initscan(const char *name); |
||||
void zconf_nextfile(const char *name); |
||||
int zconf_lineno(void); |
||||
char *zconf_curname(void); |
||||
|
||||
/* confdata.c */ |
||||
extern const char conf_def_filename[]; |
||||
|
||||
char *conf_get_default_confname(void); |
||||
|
||||
/* kconfig_load.c */ |
||||
void kconfig_load(void); |
||||
|
||||
/* menu.c */ |
||||
void menu_init(void); |
||||
struct menu *menu_add_menu(void); |
||||
void menu_end_menu(void); |
||||
void menu_add_entry(struct symbol *sym); |
||||
void menu_end_entry(void); |
||||
void menu_add_dep(struct expr *dep); |
||||
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); |
||||
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); |
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); |
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); |
||||
void menu_finalize(struct menu *parent); |
||||
void menu_set_type(int type); |
||||
|
||||
/* util.c */ |
||||
struct file *file_lookup(const char *name); |
||||
int file_write_dep(const char *name); |
||||
|
||||
struct gstr { |
||||
size_t len; |
||||
char *s; |
||||
}; |
||||
struct gstr str_new(void); |
||||
struct gstr str_assign(const char *s); |
||||
void str_free(struct gstr *gs); |
||||
void str_append(struct gstr *gs, const char *s); |
||||
void str_printf(struct gstr *gs, const char *fmt, ...); |
||||
const char *str_get(struct gstr *gs); |
||||
|
||||
/* symbol.c */ |
||||
void sym_init(void); |
||||
void sym_clear_all_valid(void); |
||||
void sym_set_changed(struct symbol *sym); |
||||
struct symbol *sym_check_deps(struct symbol *sym); |
||||
struct property *prop_alloc(enum prop_type type, struct symbol *sym); |
||||
struct symbol *prop_get_symbol(struct property *prop); |
||||
|
||||
static inline tristate sym_get_tristate_value(struct symbol *sym) |
||||
{ |
||||
return sym->curr.tri; |
||||
} |
||||
|
||||
|
||||
static inline struct symbol *sym_get_choice_value(struct symbol *sym) |
||||
{ |
||||
return (struct symbol *)sym->curr.val; |
||||
} |
||||
|
||||
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) |
||||
{ |
||||
return sym_set_tristate_value(chval, yes); |
||||
} |
||||
|
||||
static inline bool sym_is_choice(struct symbol *sym) |
||||
{ |
||||
return sym->flags & SYMBOL_CHOICE ? true : false; |
||||
} |
||||
|
||||
static inline bool sym_is_choice_value(struct symbol *sym) |
||||
{ |
||||
return sym->flags & SYMBOL_CHOICEVAL ? true : false; |
||||
} |
||||
|
||||
static inline bool sym_is_optional(struct symbol *sym) |
||||
{ |
||||
return sym->flags & SYMBOL_OPTIONAL ? true : false; |
||||
} |
||||
|
||||
static inline bool sym_has_value(struct symbol *sym) |
||||
{ |
||||
return sym->flags & SYMBOL_NEW ? false : true; |
||||
} |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* LKC_H */ |
@ -0,0 +1,41 @@ |
||||
|
||||
/* confdata.c */ |
||||
P(conf_parse,void,(const char *name)); |
||||
P(conf_read,int,(const char *name)); |
||||
P(conf_read_simple,int,(const char *name)); |
||||
P(conf_write,int,(const char *name)); |
||||
|
||||
/* menu.c */ |
||||
P(rootmenu,struct menu,); |
||||
|
||||
P(menu_is_visible,bool,(struct menu *menu)); |
||||
P(menu_get_prompt,const char *,(struct menu *menu)); |
||||
P(menu_get_root_menu,struct menu *,(struct menu *menu)); |
||||
P(menu_get_parent_menu,struct menu *,(struct menu *menu)); |
||||
|
||||
/* symbol.c */ |
||||
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); |
||||
P(sym_change_count,int,); |
||||
|
||||
P(sym_lookup,struct symbol *,(const char *name, int isconst)); |
||||
P(sym_find,struct symbol *,(const char *name)); |
||||
P(sym_re_search,struct symbol **,(const char *pattern)); |
||||
P(sym_type_name,const char *,(enum symbol_type type)); |
||||
P(sym_calc_value,void,(struct symbol *sym)); |
||||
P(sym_get_type,enum symbol_type,(struct symbol *sym)); |
||||
P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); |
||||
P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); |
||||
P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); |
||||
P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); |
||||
P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); |
||||
P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); |
||||
P(sym_is_changable,bool,(struct symbol *sym)); |
||||
P(sym_get_choice_prop,struct property *,(struct symbol *sym)); |
||||
P(sym_get_default_prop,struct property *,(struct symbol *sym)); |
||||
P(sym_get_string_value,const char *,(struct symbol *sym)); |
||||
|
||||
P(prop_get_type_name,const char *,(enum prop_type type)); |
||||
|
||||
/* expr.c */ |
||||
P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); |
||||
P(expr_print,void,(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)); |
@ -0,0 +1,4 @@ |
||||
This is NOT the official version of dialog. This version has been |
||||
significantly modified from the original. It is for use by the Linux |
||||
kernel configuration script. Please do not bother Savio Lam with |
||||
questions about this program. |
@ -0,0 +1,20 @@ |
||||
# Makefile to build lxdialog package
|
||||
#
|
||||
|
||||
all: lxdialog |
||||
|
||||
# Use reursively expanded variables so we do not call gcc unless
|
||||
# we really need to do so. (Do not call gcc as part of make mrproper)
|
||||
CFLAGS := $(shell sh check-lxdialog.sh -ccflags)
|
||||
LIBS := $(shell sh check-lxdialog.sh -ldflags gcc)
|
||||
|
||||
always := $(hostprogs-y) dochecklxdialog
|
||||
|
||||
%.o: %.c |
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
lxdialog: checklist.o menubox.o textbox.o yesno.o inputbox.o util.o lxdialog.o msgbox.o |
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
clean: |
||||
rm -f *.o lxdialog
|
@ -0,0 +1,84 @@ |
||||
#!/bin/sh |
||||
# Check ncurses compatibility |
||||
|
||||
# What library to link |
||||
ldflags() |
||||
{ |
||||
$cc -print-file-name=libncursesw.so | grep -q / |
||||
if [ $? -eq 0 ]; then |
||||
echo '-lncursesw' |
||||
exit |
||||
fi |
||||
$cc -print-file-name=libncurses.so | grep -q / |
||||
if [ $? -eq 0 ]; then |
||||
echo '-lncurses' |
||||
exit |
||||
fi |
||||
$cc -print-file-name=libcurses.so | grep -q / |
||||
if [ $? -eq 0 ]; then |
||||
echo '-lcurses' |
||||
exit |
||||
fi |
||||
exit 1 |
||||
} |
||||
|
||||
# Where is ncurses.h? |
||||
ccflags() |
||||
{ |
||||
if [ -f /usr/include/ncurses/ncurses.h ]; then |
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"' |
||||
elif [ -f /usr/include/ncurses/curses.h ]; then |
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"' |
||||
elif [ -f /usr/include/ncurses.h ]; then |
||||
echo '-DCURSES_LOC="<ncurses.h>"' |
||||
else |
||||
echo '-DCURSES_LOC="<curses.h>"' |
||||
fi |
||||
} |
||||
|
||||
# Temp file, try to clean up after us |
||||
tmp=.lxdialog.tmp |
||||
trap "rm -f $tmp" 0 1 2 3 15 |
||||
|
||||
# Check if we can link to ncurses |
||||
check() { |
||||
echo "main() {}" | $cc -xc - -o $tmp 2> /dev/null |
||||
if [ $? != 0 ]; then |
||||
echo " *** Unable to find the ncurses libraries." 1>&2 |
||||
echo " *** make menuconfig require the ncurses libraries" 1>&2 |
||||
echo " *** " 1>&2 |
||||
echo " *** Install ncurses (ncurses-devel) and try again" 1>&2 |
||||
echo " *** " 1>&2 |
||||
exit 1 |
||||
fi |
||||
} |
||||
|
||||
usage() { |
||||
printf "Usage: $0 [-check compiler options|-header|-library]\n" |
||||
} |
||||
|
||||
if [ $# == 0 ]; then |
||||
usage |
||||
exit 1 |
||||
fi |
||||
|
||||
cc="" |
||||
case "$1" in |
||||
"-check") |
||||
shift |
||||
cc="$@" |
||||
check |
||||
;; |
||||
"-ccflags") |
||||
ccflags |
||||
;; |
||||
"-ldflags") |
||||
shift |
||||
cc="$@" |
||||
ldflags |
||||
;; |
||||
"*") |
||||
usage |
||||
exit 1 |
||||
;; |
||||
esac |
@ -0,0 +1,334 @@ |
||||
/*
|
||||
* checklist.c -- implements the checklist box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension |
||||
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
static int list_width, check_x, item_x; |
||||
|
||||
/*
|
||||
* Print list item |
||||
*/ |
||||
static void print_item(WINDOW * win, const char *item, int status, int choice, |
||||
int selected) |
||||
{ |
||||
int i; |
||||
|
||||
/* Clear 'residue' of last item */ |
||||
wattrset(win, menubox_attr); |
||||
wmove(win, choice, 0); |
||||
for (i = 0; i < list_width; i++) |
||||
waddch(win, ' '); |
||||
|
||||
wmove(win, choice, check_x); |
||||
wattrset(win, selected ? check_selected_attr : check_attr); |
||||
wprintw(win, "(%c)", status ? 'X' : ' '); |
||||
|
||||
wattrset(win, selected ? tag_selected_attr : tag_attr); |
||||
mvwaddch(win, choice, item_x, item[0]); |
||||
wattrset(win, selected ? item_selected_attr : item_attr); |
||||
waddstr(win, (char *)item + 1); |
||||
if (selected) { |
||||
wmove(win, choice, check_x + 1); |
||||
wrefresh(win); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Print the scroll indicators. |
||||
*/ |
||||
static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, |
||||
int y, int x, int height) |
||||
{ |
||||
wmove(win, y, x); |
||||
|
||||
if (scroll > 0) { |
||||
wattrset(win, uarrow_attr); |
||||
waddch(win, ACS_UARROW); |
||||
waddstr(win, "(-)"); |
||||
} else { |
||||
wattrset(win, menubox_attr); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
} |
||||
|
||||
y = y + height + 1; |
||||
wmove(win, y, x); |
||||
|
||||
if ((height < item_no) && (scroll + choice < item_no - 1)) { |
||||
wattrset(win, darrow_attr); |
||||
waddch(win, ACS_DARROW); |
||||
waddstr(win, "(+)"); |
||||
} else { |
||||
wattrset(win, menubox_border_attr); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Display the termination buttons |
||||
*/ |
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected) |
||||
{ |
||||
int x = width / 2 - 11; |
||||
int y = height - 2; |
||||
|
||||
print_button(dialog, "Select", y, x, selected == 0); |
||||
print_button(dialog, " Help ", y, x + 14, selected == 1); |
||||
|
||||
wmove(dialog, y, x + 1 + 14 * selected); |
||||
wrefresh(dialog); |
||||
} |
||||
|
||||
/*
|
||||
* Display a dialog box with a list of options that can be turned on or off |
||||
* in the style of radiolist (only one option turned on at a time). |
||||
*/ |
||||
int dialog_checklist(const char *title, const char *prompt, int height, |
||||
int width, int list_height, int item_no, |
||||
const char *const *items) |
||||
{ |
||||
int i, x, y, box_x, box_y; |
||||
int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status; |
||||
WINDOW *dialog, *list; |
||||
|
||||
/* Allocate space for storing item on/off status */ |
||||
if ((status = malloc(sizeof(int) * item_no)) == NULL) { |
||||
endwin(); |
||||
fprintf(stderr, |
||||
"\nCan't allocate memory in dialog_checklist().\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
/* Initializes status */ |
||||
for (i = 0; i < item_no; i++) { |
||||
status[i] = !strcasecmp(items[i * 3 + 2], "on"); |
||||
if ((!choice && status[i]) |
||||
|| !strcasecmp(items[i * 3 + 2], "selected")) |
||||
choice = i + 1; |
||||
} |
||||
if (choice) |
||||
choice--; |
||||
|
||||
max_choice = MIN(list_height, item_no); |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
wattrset(dialog, dialog_attr); |
||||
print_autowrap(dialog, prompt, width - 2, 1, 3); |
||||
|
||||
list_width = width - 6; |
||||
box_y = height - list_height - 5; |
||||
box_x = (width - list_width) / 2 - 1; |
||||
|
||||
/* create new window for the list */ |
||||
list = subwin(dialog, list_height, list_width, y + box_y + 1, |
||||
x + box_x + 1); |
||||
|
||||
keypad(list, TRUE); |
||||
|
||||
/* draw a box around the list items */ |
||||
draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, |
||||
menubox_border_attr, menubox_attr); |
||||
|
||||
/* Find length of longest item in order to center checklist */ |
||||
check_x = 0; |
||||
for (i = 0; i < item_no; i++) |
||||
check_x = MAX(check_x, +strlen(items[i * 3 + 1]) + 4); |
||||
|
||||
check_x = (list_width - check_x) / 2; |
||||
item_x = check_x + 4; |
||||
|
||||
if (choice >= list_height) { |
||||
scroll = choice - list_height + 1; |
||||
choice -= scroll; |
||||
} |
||||
|
||||
/* Print the list */ |
||||
for (i = 0; i < max_choice; i++) { |
||||
print_item(list, items[(scroll + i) * 3 + 1], |
||||
status[i + scroll], i, i == choice); |
||||
} |
||||
|
||||
print_arrows(dialog, choice, item_no, scroll, |
||||
box_y, box_x + check_x + 5, list_height); |
||||
|
||||
print_buttons(dialog, height, width, 0); |
||||
|
||||
wnoutrefresh(list); |
||||
wnoutrefresh(dialog); |
||||
doupdate(); |
||||
|
||||
while (key != ESC) { |
||||
key = wgetch(dialog); |
||||
|
||||
for (i = 0; i < max_choice; i++) |
||||
if (toupper(key) == |
||||
toupper(items[(scroll + i) * 3 + 1][0])) |
||||
break; |
||||
|
||||
if (i < max_choice || key == KEY_UP || key == KEY_DOWN || |
||||
key == '+' || key == '-') { |
||||
if (key == KEY_UP || key == '-') { |
||||
if (!choice) { |
||||
if (!scroll) |
||||
continue; |
||||
/* Scroll list down */ |
||||
if (list_height > 1) { |
||||
/* De-highlight current first item */ |
||||
print_item(list, items[scroll * 3 + 1], |
||||
status[scroll], 0, FALSE); |
||||
scrollok(list, TRUE); |
||||
wscrl(list, -1); |
||||
scrollok(list, FALSE); |
||||
} |
||||
scroll--; |
||||
print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE); |
||||
wnoutrefresh(list); |
||||
|
||||
print_arrows(dialog, choice, item_no, |
||||
scroll, box_y, box_x + check_x + 5, list_height); |
||||
|
||||
wrefresh(dialog); |
||||
|
||||
continue; /* wait for another key press */ |
||||
} else |
||||
i = choice - 1; |
||||
} else if (key == KEY_DOWN || key == '+') { |
||||
if (choice == max_choice - 1) { |
||||
if (scroll + choice >= item_no - 1) |
||||
continue; |
||||
/* Scroll list up */ |
||||
if (list_height > 1) { |
||||
/* De-highlight current last item before scrolling up */ |
||||
print_item(list, items[(scroll + max_choice - 1) * 3 + 1], |
||||
status[scroll + max_choice - 1], |
||||
max_choice - 1, FALSE); |
||||
scrollok(list, TRUE); |
||||
wscrl(list, 1); |
||||
scrollok(list, FALSE); |
||||
} |
||||
scroll++; |
||||
print_item(list, items[(scroll + max_choice - 1) * 3 + 1], |
||||
status[scroll + max_choice - 1], max_choice - 1, TRUE); |
||||
wnoutrefresh(list); |
||||
|
||||
print_arrows(dialog, choice, item_no, |
||||
scroll, box_y, box_x + check_x + 5, list_height); |
||||
|
||||
wrefresh(dialog); |
||||
|
||||
continue; /* wait for another key press */ |
||||
} else |
||||
i = choice + 1; |
||||
} |
||||
if (i != choice) { |
||||
/* De-highlight current item */ |
||||
print_item(list, items[(scroll + choice) * 3 + 1], |
||||
status[scroll + choice], choice, FALSE); |
||||
/* Highlight new item */ |
||||
choice = i; |
||||
print_item(list, items[(scroll + choice) * 3 + 1], |
||||
status[scroll + choice], choice, TRUE); |
||||
wnoutrefresh(list); |
||||
wrefresh(dialog); |
||||
} |
||||
continue; /* wait for another key press */ |
||||
} |
||||
switch (key) { |
||||
case 'H': |
||||
case 'h': |
||||
case '?': |
||||
fprintf(stderr, "%s", items[(scroll + choice) * 3]); |
||||
delwin(dialog); |
||||
free(status); |
||||
return 1; |
||||
case TAB: |
||||
case KEY_LEFT: |
||||
case KEY_RIGHT: |
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0) |
||||
? 1 : (button > 1 ? 0 : button); |
||||
|
||||
print_buttons(dialog, height, width, button); |
||||
wrefresh(dialog); |
||||
break; |
||||
case 'S': |
||||
case 's': |
||||
case ' ': |
||||
case '\n': |
||||
if (!button) { |
||||
if (!status[scroll + choice]) { |
||||
for (i = 0; i < item_no; i++) |
||||
status[i] = 0; |
||||
status[scroll + choice] = 1; |
||||
for (i = 0; i < max_choice; i++) |
||||
print_item(list, items[(scroll + i) * 3 + 1], |
||||
status[scroll + i], i, i == choice); |
||||
} |
||||
wnoutrefresh(list); |
||||
wrefresh(dialog); |
||||
|
||||
for (i = 0; i < item_no; i++) |
||||
if (status[i]) |
||||
fprintf(stderr, "%s", items[i * 3]); |
||||
} else |
||||
fprintf(stderr, "%s", items[(scroll + choice) * 3]); |
||||
delwin(dialog); |
||||
free(status); |
||||
return button; |
||||
case 'X': |
||||
case 'x': |
||||
key = ESC; |
||||
case ESC: |
||||
break; |
||||
} |
||||
|
||||
/* Now, update everything... */ |
||||
doupdate(); |
||||
} |
||||
|
||||
delwin(dialog); |
||||
free(status); |
||||
return -1; /* ESC pressed */ |
||||
} |
@ -0,0 +1,154 @@ |
||||
/*
|
||||
* colors.h -- color attribute definitions |
||||
* |
||||
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
/*
|
||||
* Default color definitions |
||||
* |
||||
* *_FG = foreground |
||||
* *_BG = background |
||||
* *_HL = highlight? |
||||
*/ |
||||
#define SCREEN_FG COLOR_CYAN |
||||
#define SCREEN_BG COLOR_BLUE |
||||
#define SCREEN_HL TRUE |
||||
|
||||
#define SHADOW_FG COLOR_BLACK |
||||
#define SHADOW_BG COLOR_BLACK |
||||
#define SHADOW_HL TRUE |
||||
|
||||
#define DIALOG_FG COLOR_BLACK |
||||
#define DIALOG_BG COLOR_WHITE |
||||
#define DIALOG_HL FALSE |
||||
|
||||
#define TITLE_FG COLOR_YELLOW |
||||
#define TITLE_BG COLOR_WHITE |
||||
#define TITLE_HL TRUE |
||||
|
||||
#define BORDER_FG COLOR_WHITE |
||||
#define BORDER_BG COLOR_WHITE |
||||
#define BORDER_HL TRUE |
||||
|
||||
#define BUTTON_ACTIVE_FG COLOR_WHITE |
||||
#define BUTTON_ACTIVE_BG COLOR_BLUE |
||||
#define BUTTON_ACTIVE_HL TRUE |
||||
|
||||
#define BUTTON_INACTIVE_FG COLOR_BLACK |
||||
#define BUTTON_INACTIVE_BG COLOR_WHITE |
||||
#define BUTTON_INACTIVE_HL FALSE |
||||
|
||||
#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE |
||||
#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE |
||||
#define BUTTON_KEY_ACTIVE_HL TRUE |
||||
|
||||
#define BUTTON_KEY_INACTIVE_FG COLOR_RED |
||||
#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE |
||||
#define BUTTON_KEY_INACTIVE_HL FALSE |
||||
|
||||
#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW |
||||
#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE |
||||
#define BUTTON_LABEL_ACTIVE_HL TRUE |
||||
|
||||
#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK |
||||
#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE |
||||
#define BUTTON_LABEL_INACTIVE_HL TRUE |
||||
|
||||
#define INPUTBOX_FG COLOR_BLACK |
||||
#define INPUTBOX_BG COLOR_WHITE |
||||
#define INPUTBOX_HL FALSE |
||||
|
||||
#define INPUTBOX_BORDER_FG COLOR_BLACK |
||||
#define INPUTBOX_BORDER_BG COLOR_WHITE |
||||
#define INPUTBOX_BORDER_HL FALSE |
||||
|
||||
#define SEARCHBOX_FG COLOR_BLACK |
||||
#define SEARCHBOX_BG COLOR_WHITE |
||||
#define SEARCHBOX_HL FALSE |
||||
|
||||
#define SEARCHBOX_TITLE_FG COLOR_YELLOW |
||||
#define SEARCHBOX_TITLE_BG COLOR_WHITE |
||||
#define SEARCHBOX_TITLE_HL TRUE |
||||
|
||||
#define SEARCHBOX_BORDER_FG COLOR_WHITE |
||||
#define SEARCHBOX_BORDER_BG COLOR_WHITE |
||||
#define SEARCHBOX_BORDER_HL TRUE |
||||
|
||||
#define POSITION_INDICATOR_FG COLOR_YELLOW |
||||
#define POSITION_INDICATOR_BG COLOR_WHITE |
||||
#define POSITION_INDICATOR_HL TRUE |
||||
|
||||
#define MENUBOX_FG COLOR_BLACK |
||||
#define MENUBOX_BG COLOR_WHITE |
||||
#define MENUBOX_HL FALSE |
||||
|
||||
#define MENUBOX_BORDER_FG COLOR_WHITE |
||||
#define MENUBOX_BORDER_BG COLOR_WHITE |
||||
#define MENUBOX_BORDER_HL TRUE |
||||
|
||||
#define ITEM_FG COLOR_BLACK |
||||
#define ITEM_BG COLOR_WHITE |
||||
#define ITEM_HL FALSE |
||||
|
||||
#define ITEM_SELECTED_FG COLOR_WHITE |
||||
#define ITEM_SELECTED_BG COLOR_BLUE |
||||
#define ITEM_SELECTED_HL TRUE |
||||
|
||||
#define TAG_FG COLOR_YELLOW |
||||
#define TAG_BG COLOR_WHITE |
||||
#define TAG_HL TRUE |
||||
|
||||
#define TAG_SELECTED_FG COLOR_YELLOW |
||||
#define TAG_SELECTED_BG COLOR_BLUE |
||||
#define TAG_SELECTED_HL TRUE |
||||
|
||||
#define TAG_KEY_FG COLOR_YELLOW |
||||
#define TAG_KEY_BG COLOR_WHITE |
||||
#define TAG_KEY_HL TRUE |
||||
|
||||
#define TAG_KEY_SELECTED_FG COLOR_YELLOW |
||||
#define TAG_KEY_SELECTED_BG COLOR_BLUE |
||||
#define TAG_KEY_SELECTED_HL TRUE |
||||
|
||||
#define CHECK_FG COLOR_BLACK |
||||
#define CHECK_BG COLOR_WHITE |
||||
#define CHECK_HL FALSE |
||||
|
||||
#define CHECK_SELECTED_FG COLOR_WHITE |
||||
#define CHECK_SELECTED_BG COLOR_BLUE |
||||
#define CHECK_SELECTED_HL TRUE |
||||
|
||||
#define UARROW_FG COLOR_GREEN |
||||
#define UARROW_BG COLOR_WHITE |
||||
#define UARROW_HL TRUE |
||||
|
||||
#define DARROW_FG COLOR_GREEN |
||||
#define DARROW_BG COLOR_WHITE |
||||
#define DARROW_HL TRUE |
||||
|
||||
/* End of default color definitions */ |
||||
|
||||
#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y))) |
||||
#define COLOR_NAME_LEN 10 |
||||
#define COLOR_COUNT 8 |
||||
|
||||
/*
|
||||
* Global variables |
||||
*/ |
||||
|
||||
extern int color_table[][3]; |
@ -0,0 +1,177 @@ |
||||
/*
|
||||
* dialog.h -- common declarations for all dialog modules |
||||
* |
||||
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include <sys/types.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <ctype.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#ifdef __sun__ |
||||
#define CURS_MACROS |
||||
#endif |
||||
#include CURSES_LOC |
||||
|
||||
/*
|
||||
* Colors in ncurses 1.9.9e do not work properly since foreground and |
||||
* background colors are OR'd rather than separately masked. This version |
||||
* of dialog was hacked to work with ncurses 1.9.9e, making it incompatible |
||||
* with standard curses. The simplest fix (to make this work with standard |
||||
* curses) uses the wbkgdset() function, not used in the original hack. |
||||
* Turn it off if we're building with 1.9.9e, since it just confuses things. |
||||
*/ |
||||
#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) |
||||
#define OLD_NCURSES 1 |
||||
#undef wbkgdset |
||||
#define wbkgdset(w,p) /*nothing */ |
||||
#else |
||||
#define OLD_NCURSES 0 |
||||
#endif |
||||
|
||||
#define TR(params) _tracef params |
||||
|
||||
#define ESC 27 |
||||
#define TAB 9 |
||||
#define MAX_LEN 2048 |
||||
#define BUF_SIZE (10*1024) |
||||
#define MIN(x,y) (x < y ? x : y) |
||||
#define MAX(x,y) (x > y ? x : y) |
||||
|
||||
#ifndef ACS_ULCORNER |
||||
#define ACS_ULCORNER '+' |
||||
#endif |
||||
#ifndef ACS_LLCORNER |
||||
#define ACS_LLCORNER '+' |
||||
#endif |
||||
#ifndef ACS_URCORNER |
||||
#define ACS_URCORNER '+' |
||||
#endif |
||||
#ifndef ACS_LRCORNER |
||||
#define ACS_LRCORNER '+' |
||||
#endif |
||||
#ifndef ACS_HLINE |
||||
#define ACS_HLINE '-' |
||||
#endif |
||||
#ifndef ACS_VLINE |
||||
#define ACS_VLINE '|' |
||||
#endif |
||||
#ifndef ACS_LTEE |
||||
#define ACS_LTEE '+' |
||||
#endif |
||||
#ifndef ACS_RTEE |
||||
#define ACS_RTEE '+' |
||||
#endif |
||||
#ifndef ACS_UARROW |
||||
#define ACS_UARROW '^' |
||||
#endif |
||||
#ifndef ACS_DARROW |
||||
#define ACS_DARROW 'v' |
||||
#endif |
||||
|
||||
/*
|
||||
* Attribute names |
||||
*/ |
||||
#define screen_attr attributes[0] |
||||
#define shadow_attr attributes[1] |
||||
#define dialog_attr attributes[2] |
||||
#define title_attr attributes[3] |
||||
#define border_attr attributes[4] |
||||
#define button_active_attr attributes[5] |
||||
#define button_inactive_attr attributes[6] |
||||
#define button_key_active_attr attributes[7] |
||||
#define button_key_inactive_attr attributes[8] |
||||
#define button_label_active_attr attributes[9] |
||||
#define button_label_inactive_attr attributes[10] |
||||
#define inputbox_attr attributes[11] |
||||
#define inputbox_border_attr attributes[12] |
||||
#define searchbox_attr attributes[13] |
||||
#define searchbox_title_attr attributes[14] |
||||
#define searchbox_border_attr attributes[15] |
||||
#define position_indicator_attr attributes[16] |
||||
#define menubox_attr attributes[17] |
||||
#define menubox_border_attr attributes[18] |
||||
#define item_attr attributes[19] |
||||
#define item_selected_attr attributes[20] |
||||
#define tag_attr attributes[21] |
||||
#define tag_selected_attr attributes[22] |
||||
#define tag_key_attr attributes[23] |
||||
#define tag_key_selected_attr attributes[24] |
||||
#define check_attr attributes[25] |
||||
#define check_selected_attr attributes[26] |
||||
#define uarrow_attr attributes[27] |
||||
#define darrow_attr attributes[28] |
||||
|
||||
/* number of attributes */ |
||||
#define ATTRIBUTE_COUNT 29 |
||||
|
||||
/*
|
||||
* Global variables |
||||
*/ |
||||
extern bool use_colors; |
||||
extern bool use_shadow; |
||||
|
||||
extern chtype attributes[]; |
||||
|
||||
extern const char *backtitle; |
||||
|
||||
/*
|
||||
* Function prototypes |
||||
*/ |
||||
extern void create_rc(const char *filename); |
||||
extern int parse_rc(void); |
||||
|
||||
void init_dialog(void); |
||||
void end_dialog(void); |
||||
void attr_clear(WINDOW * win, int height, int width, chtype attr); |
||||
void dialog_clear(void); |
||||
void color_setup(void); |
||||
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); |
||||
void print_button(WINDOW * win, const char *label, int y, int x, int selected); |
||||
void print_title(WINDOW *dialog, const char *title, int width); |
||||
void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, |
||||
chtype border); |
||||
void draw_shadow(WINDOW * win, int y, int x, int height, int width); |
||||
|
||||
int first_alpha(const char *string, const char *exempt); |
||||
int dialog_yesno(const char *title, const char *prompt, int height, int width); |
||||
int dialog_msgbox(const char *title, const char *prompt, int height, |
||||
int width, int pause); |
||||
int dialog_textbox(const char *title, const char *file, int height, int width); |
||||
int dialog_menu(const char *title, const char *prompt, int height, int width, |
||||
int menu_height, const char *choice, int item_no, |
||||
const char *const *items); |
||||
int dialog_checklist(const char *title, const char *prompt, int height, |
||||
int width, int list_height, int item_no, |
||||
const char *const *items); |
||||
extern char dialog_input_result[]; |
||||
int dialog_inputbox(const char *title, const char *prompt, int height, |
||||
int width, const char *init); |
||||
|
||||
/*
|
||||
* This is the base for fictitious keys, which activate |
||||
* the buttons. |
||||
* |
||||
* Mouse-generated keys are the following: |
||||
* -- the first 32 are used as numbers, in addition to '0'-'9' |
||||
* -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') |
||||
* -- uppercase chars are used to invoke the button (M_EVENT + 'O') |
||||
*/ |
||||
#define M_EVENT (KEY_MAX+1) |
@ -0,0 +1,224 @@ |
||||
/*
|
||||
* inputbox.c -- implements the input box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
char dialog_input_result[MAX_LEN + 1]; |
||||
|
||||
/*
|
||||
* Print the termination buttons |
||||
*/ |
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected) |
||||
{ |
||||
int x = width / 2 - 11; |
||||
int y = height - 2; |
||||
|
||||
print_button(dialog, " Ok ", y, x, selected == 0); |
||||
print_button(dialog, " Help ", y, x + 14, selected == 1); |
||||
|
||||
wmove(dialog, y, x + 1 + 14 * selected); |
||||
wrefresh(dialog); |
||||
} |
||||
|
||||
/*
|
||||
* Display a dialog box for inputing a string |
||||
*/ |
||||
int dialog_inputbox(const char *title, const char *prompt, int height, int width, |
||||
const char *init) |
||||
{ |
||||
int i, x, y, box_y, box_x, box_width; |
||||
int input_x = 0, scroll = 0, key = 0, button = -1; |
||||
char *instr = dialog_input_result; |
||||
WINDOW *dialog; |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
wattrset(dialog, dialog_attr); |
||||
print_autowrap(dialog, prompt, width - 2, 1, 3); |
||||
|
||||
/* Draw the input field box */ |
||||
box_width = width - 6; |
||||
getyx(dialog, y, x); |
||||
box_y = y + 2; |
||||
box_x = (width - box_width) / 2; |
||||
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, border_attr, dialog_attr); |
||||
|
||||
print_buttons(dialog, height, width, 0); |
||||
|
||||
/* Set up the initial value */ |
||||
wmove(dialog, box_y, box_x); |
||||
wattrset(dialog, inputbox_attr); |
||||
|
||||
if (!init) |
||||
instr[0] = '\0'; |
||||
else |
||||
strcpy(instr, init); |
||||
|
||||
input_x = strlen(instr); |
||||
|
||||
if (input_x >= box_width) { |
||||
scroll = input_x - box_width + 1; |
||||
input_x = box_width - 1; |
||||
for (i = 0; i < box_width - 1; i++) |
||||
waddch(dialog, instr[scroll + i]); |
||||
} else { |
||||
waddstr(dialog, instr); |
||||
} |
||||
|
||||
wmove(dialog, box_y, box_x + input_x); |
||||
|
||||
wrefresh(dialog); |
||||
|
||||
while (key != ESC) { |
||||
key = wgetch(dialog); |
||||
|
||||
if (button == -1) { /* Input box selected */ |
||||
switch (key) { |
||||
case TAB: |
||||
case KEY_UP: |
||||
case KEY_DOWN: |
||||
break; |
||||
case KEY_LEFT: |
||||
continue; |
||||
case KEY_RIGHT: |
||||
continue; |
||||
case KEY_BACKSPACE: |
||||
case 127: |
||||
if (input_x || scroll) { |
||||
wattrset(dialog, inputbox_attr); |
||||
if (!input_x) { |
||||
scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1); |
||||
wmove(dialog, box_y, box_x); |
||||
for (i = 0; i < box_width; i++) |
||||
waddch(dialog, |
||||
instr[scroll + input_x + i] ? |
||||
instr[scroll + input_x + i] : ' '); |
||||
input_x = strlen(instr) - scroll; |
||||
} else |
||||
input_x--; |
||||
instr[scroll + input_x] = '\0'; |
||||
mvwaddch(dialog, box_y, input_x + box_x, ' '); |
||||
wmove(dialog, box_y, input_x + box_x); |
||||
wrefresh(dialog); |
||||
} |
||||
continue; |
||||
default: |
||||
if (key < 0x100 && isprint(key)) { |
||||
if (scroll + input_x < MAX_LEN) { |
||||
wattrset(dialog, inputbox_attr); |
||||
instr[scroll + input_x] = key; |
||||
instr[scroll + input_x + 1] = '\0'; |
||||
if (input_x == box_width - 1) { |
||||
scroll++; |
||||
wmove(dialog, box_y, box_x); |
||||
for (i = 0; i < box_width - 1; i++) |
||||
waddch(dialog, instr [scroll + i]); |
||||
} else { |
||||
wmove(dialog, box_y, input_x++ + box_x); |
||||
waddch(dialog, key); |
||||
} |
||||
wrefresh(dialog); |
||||
} else |
||||
flash(); /* Alarm user about overflow */ |
||||
continue; |
||||
} |
||||
} |
||||
} |
||||
switch (key) { |
||||
case 'O': |
||||
case 'o': |
||||
delwin(dialog); |
||||
return 0; |
||||
case 'H': |
||||
case 'h': |
||||
delwin(dialog); |
||||
return 1; |
||||
case KEY_UP: |
||||
case KEY_LEFT: |
||||
switch (button) { |
||||
case -1: |
||||
button = 1; /* Indicates "Cancel" button is selected */ |
||||
print_buttons(dialog, height, width, 1); |
||||
break; |
||||
case 0: |
||||
button = -1; /* Indicates input box is selected */ |
||||
print_buttons(dialog, height, width, 0); |
||||
wmove(dialog, box_y, box_x + input_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
case 1: |
||||
button = 0; /* Indicates "OK" button is selected */ |
||||
print_buttons(dialog, height, width, 0); |
||||
break; |
||||
} |
||||
break; |
||||
case TAB: |
||||
case KEY_DOWN: |
||||
case KEY_RIGHT: |
||||
switch (button) { |
||||
case -1: |
||||
button = 0; /* Indicates "OK" button is selected */ |
||||
print_buttons(dialog, height, width, 0); |
||||
break; |
||||
case 0: |
||||
button = 1; /* Indicates "Cancel" button is selected */ |
||||
print_buttons(dialog, height, width, 1); |
||||
break; |
||||
case 1: |
||||
button = -1; /* Indicates input box is selected */ |
||||
print_buttons(dialog, height, width, 0); |
||||
wmove(dialog, box_y, box_x + input_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
} |
||||
break; |
||||
case ' ': |
||||
case '\n': |
||||
delwin(dialog); |
||||
return (button == -1 ? 0 : button); |
||||
case 'X': |
||||
case 'x': |
||||
key = ESC; |
||||
case ESC: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delwin(dialog); |
||||
return -1; /* ESC pressed */ |
||||
} |
@ -0,0 +1,204 @@ |
||||
/*
|
||||
* dialog - Display simple dialog boxes from shell scripts |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
static void Usage(const char *name); |
||||
|
||||
typedef int (jumperFn) (const char *title, int argc, const char *const *argv); |
||||
|
||||
struct Mode { |
||||
char *name; |
||||
int argmin, argmax, argmod; |
||||
jumperFn *jumper; |
||||
}; |
||||
|
||||
jumperFn j_menu, j_radiolist, j_yesno, j_textbox, j_inputbox; |
||||
jumperFn j_msgbox, j_infobox; |
||||
|
||||
static struct Mode modes[] = { |
||||
{"--menu", 9, 0, 3, j_menu}, |
||||
{"--radiolist", 9, 0, 3, j_radiolist}, |
||||
{"--yesno", 5, 5, 1, j_yesno}, |
||||
{"--textbox", 5, 5, 1, j_textbox}, |
||||
{"--inputbox", 5, 6, 1, j_inputbox}, |
||||
{"--msgbox", 5, 5, 1, j_msgbox}, |
||||
{"--infobox", 5, 5, 1, j_infobox}, |
||||
{NULL, 0, 0, 0, NULL} |
||||
}; |
||||
|
||||
static struct Mode *modePtr; |
||||
|
||||
#ifdef LOCALE |
||||
#include <locale.h> |
||||
#endif |
||||
|
||||
int main(int argc, const char *const *argv) |
||||
{ |
||||
int offset = 0, opt_clear = 0, end_common_opts = 0, retval; |
||||
const char *title = NULL; |
||||
|
||||
#ifdef LOCALE |
||||
(void)setlocale(LC_ALL, ""); |
||||
#endif |
||||
|
||||
#ifdef TRACE |
||||
trace(TRACE_CALLS | TRACE_UPDATE); |
||||
#endif |
||||
if (argc < 2) { |
||||
Usage(argv[0]); |
||||
exit(-1); |
||||
} |
||||
|
||||
while (offset < argc - 1 && !end_common_opts) { /* Common options */ |
||||
if (!strcmp(argv[offset + 1], "--title")) { |
||||
if (argc - offset < 3 || title != NULL) { |
||||
Usage(argv[0]); |
||||
exit(-1); |
||||
} else { |
||||
title = argv[offset + 2]; |
||||
offset += 2; |
||||
} |
||||
} else if (!strcmp(argv[offset + 1], "--backtitle")) { |
||||
if (backtitle != NULL) { |
||||
Usage(argv[0]); |
||||
exit(-1); |
||||
} else { |
||||
backtitle = argv[offset + 2]; |
||||
offset += 2; |
||||
} |
||||
} else if (!strcmp(argv[offset + 1], "--clear")) { |
||||
if (opt_clear) { /* Hey, "--clear" can't appear twice! */ |
||||
Usage(argv[0]); |
||||
exit(-1); |
||||
} else if (argc == 2) { /* we only want to clear the screen */ |
||||
init_dialog(); |
||||
refresh(); /* init_dialog() will clear the screen for us */ |
||||
end_dialog(); |
||||
return 0; |
||||
} else { |
||||
opt_clear = 1; |
||||
offset++; |
||||
} |
||||
} else /* no more common options */ |
||||
end_common_opts = 1; |
||||
} |
||||
|
||||
if (argc - 1 == offset) { /* no more options */ |
||||
Usage(argv[0]); |
||||
exit(-1); |
||||
} |
||||
/* use a table to look for the requested mode, to avoid code duplication */ |
||||
|
||||
for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */ |
||||
if (!strcmp(argv[offset + 1], modePtr->name)) |
||||
break; |
||||
|
||||
if (!modePtr->name) |
||||
Usage(argv[0]); |
||||
if (argc - offset < modePtr->argmin) |
||||
Usage(argv[0]); |
||||
if (modePtr->argmax && argc - offset > modePtr->argmax) |
||||
Usage(argv[0]); |
||||
|
||||
init_dialog(); |
||||
retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset); |
||||
|
||||
if (opt_clear) { /* clear screen before exit */ |
||||
attr_clear(stdscr, LINES, COLS, screen_attr); |
||||
refresh(); |
||||
} |
||||
end_dialog(); |
||||
|
||||
exit(retval); |
||||
} |
||||
|
||||
/*
|
||||
* Print program usage |
||||
*/ |
||||
static void Usage(const char *name) |
||||
{ |
||||
fprintf(stderr, "\
|
||||
\ndialog, by Savio Lam (lam836@cs.cuhk.hk).\
|
||||
\n patched by Stuart Herbert (S.Herbert@shef.ac.uk)\
|
||||
\n modified/gutted for use as a Linux kernel config tool by \
|
||||
\n William Roadcap (roadcapw@cfw.com)\
|
||||
\n\
|
||||
\n* Display dialog boxes from shell scripts *\
|
||||
\n\
|
||||
\nUsage: %s --clear\
|
||||
\n %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
|
||||
\n\
|
||||
\nBox options:\
|
||||
\n\
|
||||
\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\
|
||||
\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
|
||||
\n --textbox <file> <height> <width>\
|
||||
\n --inputbox <text> <height> <width> [<init>]\
|
||||
\n --yesno <text> <height> <width>\
|
||||
\n", name, name); |
||||
exit(-1); |
||||
} |
||||
|
||||
/*
|
||||
* These are the program jumpers |
||||
*/ |
||||
|
||||
int j_menu(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_menu(t, av[2], atoi(av[3]), atoi(av[4]), |
||||
atoi(av[5]), av[6], (ac - 6) / 2, av + 7); |
||||
} |
||||
|
||||
int j_radiolist(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_checklist(t, av[2], atoi(av[3]), atoi(av[4]), |
||||
atoi(av[5]), (ac - 6) / 3, av + 6); |
||||
} |
||||
|
||||
int j_textbox(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_textbox(t, av[2], atoi(av[3]), atoi(av[4])); |
||||
} |
||||
|
||||
int j_yesno(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_yesno(t, av[2], atoi(av[3]), atoi(av[4])); |
||||
} |
||||
|
||||
int j_inputbox(const char *t, int ac, const char *const *av) |
||||
{ |
||||
int ret = dialog_inputbox(t, av[2], atoi(av[3]), atoi(av[4]), |
||||
ac == 6 ? av[5] : (char *)NULL); |
||||
if (ret == 0) |
||||
fprintf(stderr, dialog_input_result); |
||||
return ret; |
||||
} |
||||
|
||||
int j_msgbox(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 1); |
||||
} |
||||
|
||||
int j_infobox(const char *t, int ac, const char *const *av) |
||||
{ |
||||
return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 0); |
||||
} |
@ -0,0 +1,425 @@ |
||||
/*
|
||||
* menubox.c -- implements the menu box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
/*
|
||||
* Changes by Clifford Wolf (god@clifford.at) |
||||
* |
||||
* [ 1998-06-13 ] |
||||
* |
||||
* *) A bugfix for the Page-Down problem |
||||
* |
||||
* *) Formerly when I used Page Down and Page Up, the cursor would be set
|
||||
* to the first position in the menu box. Now lxdialog is a bit |
||||
* smarter and works more like other menu systems (just have a look at |
||||
* it). |
||||
* |
||||
* *) Formerly if I selected something my scrolling would be broken because |
||||
* lxdialog is re-invoked by the Menuconfig shell script, can't |
||||
* remember the last scrolling position, and just sets it so that the |
||||
* cursor is at the bottom of the box. Now it writes the temporary file |
||||
* lxdialog.scrltmp which contains this information. The file is |
||||
* deleted by lxdialog if the user leaves a submenu or enters a new |
||||
* one, but it would be nice if Menuconfig could make another "rm -f" |
||||
* just to be sure. Just try it out - you will recognise a difference! |
||||
* |
||||
* [ 1998-06-14 ] |
||||
* |
||||
* *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files |
||||
* and menus change their size on the fly. |
||||
* |
||||
* *) If for some reason the last scrolling position is not saved by |
||||
* lxdialog, it sets the scrolling so that the selected item is in the |
||||
* middle of the menu box, not at the bottom. |
||||
* |
||||
* 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) |
||||
* Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. |
||||
* This fixes a bug in Menuconfig where using ' ' to descend into menus |
||||
* would leave mis-synchronized lxdialog.scrltmp files lying around, |
||||
* fscanf would read in 'scroll', and eventually that value would get used. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
#define ITEM_IDENT 1 /* Indent of menu entries. Fixed for all menus */ |
||||
static int menu_width; |
||||
|
||||
/*
|
||||
* Print menu item |
||||
*/ |
||||
static void do_print_item(WINDOW * win, const char *item, int choice, |
||||
int selected, int hotkey) |
||||
{ |
||||
int j; |
||||
char *menu_item = malloc(menu_width + 1); |
||||
|
||||
strncpy(menu_item, item, menu_width - ITEM_IDENT); |
||||
menu_item[menu_width] = 0; |
||||
j = first_alpha(menu_item, "YyNnMmHh"); |
||||
|
||||
/* Clear 'residue' of last item */ |
||||
wattrset(win, menubox_attr); |
||||
wmove(win, choice, 0); |
||||
#if OLD_NCURSES |
||||
{ |
||||
int i; |
||||
for (i = 0; i < menu_width; i++) |
||||
waddch(win, ' '); |
||||
} |
||||
#else |
||||
wclrtoeol(win); |
||||
#endif |
||||
wattrset(win, selected ? item_selected_attr : item_attr); |
||||
mvwaddstr(win, choice, ITEM_IDENT, menu_item); |
||||
if (hotkey) { |
||||
wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); |
||||
mvwaddch(win, choice, ITEM_IDENT + j, menu_item[j]); |
||||
} |
||||
if (selected) { |
||||
wmove(win, choice, ITEM_IDENT + 1); |
||||
} |
||||
free(menu_item); |
||||
wrefresh(win); |
||||
} |
||||
|
||||
#define print_item(index, choice, selected) \ |
||||
do {\
|
||||
int hotkey = (items[(index) * 2][0] != ':'); \
|
||||
do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
|
||||
} while (0) |
||||
|
||||
/*
|
||||
* Print the scroll indicators. |
||||
*/ |
||||
static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, |
||||
int height) |
||||
{ |
||||
int cur_y, cur_x; |
||||
|
||||
getyx(win, cur_y, cur_x); |
||||
|
||||
wmove(win, y, x); |
||||
|
||||
if (scroll > 0) { |
||||
wattrset(win, uarrow_attr); |
||||
waddch(win, ACS_UARROW); |
||||
waddstr(win, "(-)"); |
||||
} else { |
||||
wattrset(win, menubox_attr); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
} |
||||
|
||||
y = y + height + 1; |
||||
wmove(win, y, x); |
||||
wrefresh(win); |
||||
|
||||
if ((height < item_no) && (scroll + height < item_no)) { |
||||
wattrset(win, darrow_attr); |
||||
waddch(win, ACS_DARROW); |
||||
waddstr(win, "(+)"); |
||||
} else { |
||||
wattrset(win, menubox_border_attr); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
waddch(win, ACS_HLINE); |
||||
} |
||||
|
||||
wmove(win, cur_y, cur_x); |
||||
wrefresh(win); |
||||
} |
||||
|
||||
/*
|
||||
* Display the termination buttons. |
||||
*/ |
||||
static void print_buttons(WINDOW * win, int height, int width, int selected) |
||||
{ |
||||
int x = width / 2 - 16; |
||||
int y = height - 2; |
||||
|
||||
print_button(win, "Select", y, x, selected == 0); |
||||
print_button(win, " Exit ", y, x + 12, selected == 1); |
||||
print_button(win, " Help ", y, x + 24, selected == 2); |
||||
|
||||
wmove(win, y, x + 1 + 12 * selected); |
||||
wrefresh(win); |
||||
} |
||||
|
||||
/* scroll up n lines (n may be negative) */ |
||||
static void do_scroll(WINDOW *win, int *scroll, int n) |
||||
{ |
||||
/* Scroll menu up */ |
||||
scrollok(win, TRUE); |
||||
wscrl(win, n); |
||||
scrollok(win, FALSE); |
||||
*scroll = *scroll + n; |
||||
wrefresh(win); |
||||
} |
||||
|
||||
/*
|
||||
* Display a menu for choosing among a number of options |
||||
*/ |
||||
int dialog_menu(const char *title, const char *prompt, int height, int width, |
||||
int menu_height, const char *current, int item_no, |
||||
const char *const *items) |
||||
{ |
||||
int i, j, x, y, box_x, box_y; |
||||
int key = 0, button = 0, scroll = 0, choice = 0; |
||||
int first_item = 0, max_choice; |
||||
WINDOW *dialog, *menu; |
||||
FILE *f; |
||||
|
||||
max_choice = MIN(menu_height, item_no); |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
wbkgdset(dialog, dialog_attr & A_COLOR); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
wattrset(dialog, dialog_attr); |
||||
print_autowrap(dialog, prompt, width - 2, 1, 3); |
||||
|
||||
menu_width = width - 6; |
||||
box_y = height - menu_height - 5; |
||||
box_x = (width - menu_width) / 2 - 1; |
||||
|
||||
/* create new window for the menu */ |
||||
menu = subwin(dialog, menu_height, menu_width, |
||||
y + box_y + 1, x + box_x + 1); |
||||
keypad(menu, TRUE); |
||||
|
||||
/* draw a box around the menu items */ |
||||
draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, |
||||
menubox_border_attr, menubox_attr); |
||||
|
||||
/* Set choice to default item */ |
||||
for (i = 0; i < item_no; i++) |
||||
if (strcmp(current, items[i * 2]) == 0) |
||||
choice = i; |
||||
|
||||
/* get the scroll info from the temp file */ |
||||
if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) { |
||||
if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) && |
||||
(scroll + max_choice > choice) && (scroll >= 0) && |
||||
(scroll + max_choice <= item_no)) { |
||||
first_item = scroll; |
||||
choice = choice - scroll; |
||||
fclose(f); |
||||
} else { |
||||
scroll = 0; |
||||
remove("lxdialog.scrltmp"); |
||||
fclose(f); |
||||
f = NULL; |
||||
} |
||||
} |
||||
if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) { |
||||
if (choice >= item_no - max_choice / 2) |
||||
scroll = first_item = item_no - max_choice; |
||||
else |
||||
scroll = first_item = choice - max_choice / 2; |
||||
choice = choice - scroll; |
||||
} |
||||
|
||||
/* Print the menu */ |
||||
for (i = 0; i < max_choice; i++) { |
||||
print_item(first_item + i, i, i == choice); |
||||
} |
||||
|
||||
wnoutrefresh(menu); |
||||
|
||||
print_arrows(dialog, item_no, scroll, |
||||
box_y, box_x + ITEM_IDENT + 1, menu_height); |
||||
|
||||
print_buttons(dialog, height, width, 0); |
||||
wmove(menu, choice, ITEM_IDENT + 1); |
||||
wrefresh(menu); |
||||
|
||||
while (key != ESC) { |
||||
key = wgetch(menu); |
||||
|
||||
if (key < 256 && isalpha(key)) |
||||
key = tolower(key); |
||||
|
||||
if (strchr("ynmh", key)) |
||||
i = max_choice; |
||||
else { |
||||
for (i = choice + 1; i < max_choice; i++) { |
||||
j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh"); |
||||
if (key == tolower(items[(scroll + i) * 2 + 1][j])) |
||||
break; |
||||
} |
||||
if (i == max_choice) |
||||
for (i = 0; i < max_choice; i++) { |
||||
j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh"); |
||||
if (key == tolower(items[(scroll + i) * 2 + 1][j])) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (i < max_choice || |
||||
key == KEY_UP || key == KEY_DOWN || |
||||
key == '-' || key == '+' || |
||||
key == KEY_PPAGE || key == KEY_NPAGE) { |
||||
/* Remove highligt of current item */ |
||||
print_item(scroll + choice, choice, FALSE); |
||||
|
||||
if (key == KEY_UP || key == '-') { |
||||
if (choice < 2 && scroll) { |
||||
/* Scroll menu down */ |
||||
do_scroll(menu, &scroll, -1); |
||||
|
||||
print_item(scroll, 0, FALSE); |
||||
} else |
||||
choice = MAX(choice - 1, 0); |
||||
|
||||
} else if (key == KEY_DOWN || key == '+') { |
||||
print_item(scroll+choice, choice, FALSE); |
||||
|
||||
if ((choice > max_choice - 3) && |
||||
(scroll + max_choice < item_no)) { |
||||
/* Scroll menu up */ |
||||
do_scroll(menu, &scroll, 1); |
||||
|
||||
print_item(scroll+max_choice - 1, |
||||
max_choice - 1, FALSE); |
||||
} else |
||||
choice = MIN(choice + 1, max_choice - 1); |
||||
|
||||
} else if (key == KEY_PPAGE) { |
||||
scrollok(menu, TRUE); |
||||
for (i = 0; (i < max_choice); i++) { |
||||
if (scroll > 0) { |
||||
do_scroll(menu, &scroll, -1); |
||||
print_item(scroll, 0, FALSE); |
||||
} else { |
||||
if (choice > 0) |
||||
choice--; |
||||
} |
||||
} |
||||
|
||||
} else if (key == KEY_NPAGE) { |
||||
for (i = 0; (i < max_choice); i++) { |
||||
if (scroll + max_choice < item_no) { |
||||
do_scroll(menu, &scroll, 1); |
||||
print_item(scroll+max_choice-1, |
||||
max_choice - 1, FALSE); |
||||
} else { |
||||
if (choice + 1 < max_choice) |
||||
choice++; |
||||
} |
||||
} |
||||
} else |
||||
choice = i; |
||||
|
||||
print_item(scroll + choice, choice, TRUE); |
||||
|
||||
print_arrows(dialog, item_no, scroll, |
||||
box_y, box_x + ITEM_IDENT + 1, menu_height); |
||||
|
||||
wnoutrefresh(dialog); |
||||
wrefresh(menu); |
||||
|
||||
continue; /* wait for another key press */ |
||||
} |
||||
|
||||
switch (key) { |
||||
case KEY_LEFT: |
||||
case TAB: |
||||
case KEY_RIGHT: |
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0) |
||||
? 2 : (button > 2 ? 0 : button); |
||||
|
||||
print_buttons(dialog, height, width, button); |
||||
wrefresh(menu); |
||||
break; |
||||
case ' ': |
||||
case 's': |
||||
case 'y': |
||||
case 'n': |
||||
case 'm': |
||||
case '/': |
||||
/* save scroll info */ |
||||
if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) { |
||||
fprintf(f, "%d\n", scroll); |
||||
fclose(f); |
||||
} |
||||
delwin(dialog); |
||||
fprintf(stderr, "%s\n", items[(scroll + choice) * 2]); |
||||
switch (key) { |
||||
case 's': |
||||
return 3; |
||||
case 'y': |
||||
return 3; |
||||
case 'n': |
||||
return 4; |
||||
case 'm': |
||||
return 5; |
||||
case ' ': |
||||
return 6; |
||||
case '/': |
||||
return 7; |
||||
} |
||||
return 0; |
||||
case 'h': |
||||
case '?': |
||||
button = 2; |
||||
case '\n': |
||||
delwin(dialog); |
||||
if (button == 2) |
||||
fprintf(stderr, "%s \"%s\"\n", |
||||
items[(scroll + choice) * 2], |
||||
items[(scroll + choice) * 2 + 1] + |
||||
first_alpha(items [(scroll + choice) * 2 + 1], "")); |
||||
else |
||||
fprintf(stderr, "%s\n", |
||||
items[(scroll + choice) * 2]); |
||||
|
||||
remove("lxdialog.scrltmp"); |
||||
return button; |
||||
case 'e': |
||||
case 'x': |
||||
key = ESC; |
||||
case ESC: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delwin(dialog); |
||||
remove("lxdialog.scrltmp"); |
||||
return -1; /* ESC pressed */ |
||||
} |
@ -0,0 +1,71 @@ |
||||
/*
|
||||
* msgbox.c -- implements the message box and info box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
/*
|
||||
* Display a message box. Program will pause and display an "OK" button |
||||
* if the parameter 'pause' is non-zero. |
||||
*/ |
||||
int dialog_msgbox(const char *title, const char *prompt, int height, int width, |
||||
int pause) |
||||
{ |
||||
int i, x, y, key = 0; |
||||
WINDOW *dialog; |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
wattrset(dialog, dialog_attr); |
||||
print_autowrap(dialog, prompt, width - 2, 1, 2); |
||||
|
||||
if (pause) { |
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_button(dialog, " Ok ", height - 2, width / 2 - 4, TRUE); |
||||
|
||||
wrefresh(dialog); |
||||
while (key != ESC && key != '\n' && key != ' ' && |
||||
key != 'O' && key != 'o' && key != 'X' && key != 'x') |
||||
key = wgetch(dialog); |
||||
} else { |
||||
key = '\n'; |
||||
wrefresh(dialog); |
||||
} |
||||
|
||||
delwin(dialog); |
||||
return key == ESC ? -1 : 0; |
||||
} |
@ -0,0 +1,533 @@ |
||||
/*
|
||||
* textbox.c -- implements the text box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
static void back_lines(int n); |
||||
static void print_page(WINDOW * win, int height, int width); |
||||
static void print_line(WINDOW * win, int row, int width); |
||||
static char *get_line(void); |
||||
static void print_position(WINDOW * win, int height, int width); |
||||
|
||||
static int hscroll, fd, file_size, bytes_read; |
||||
static int begin_reached = 1, end_reached, page_length; |
||||
static char *buf, *page; |
||||
|
||||
/*
|
||||
* Display text from a file in a dialog box. |
||||
*/ |
||||
int dialog_textbox(const char *title, const char *file, int height, int width) |
||||
{ |
||||
int i, x, y, cur_x, cur_y, fpos, key = 0; |
||||
int passed_end; |
||||
char search_term[MAX_LEN + 1]; |
||||
WINDOW *dialog, *text; |
||||
|
||||
search_term[0] = '\0'; /* no search term entered yet */ |
||||
|
||||
/* Open input file for reading */ |
||||
if ((fd = open(file, O_RDONLY)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nCan't open input file in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
/* Get file size. Actually, 'file_size' is the real file size - 1,
|
||||
since it's only the last byte offset from the beginning */ |
||||
if ((file_size = lseek(fd, 0, SEEK_END)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError getting file size in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
/* Restore file pointer to beginning of file after getting file size */ |
||||
if (lseek(fd, 0, SEEK_SET) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
/* Allocate space for read buffer */ |
||||
if ((buf = malloc(BUF_SIZE + 1)) == NULL) { |
||||
endwin(); |
||||
fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; /* mark end of valid data */ |
||||
page = buf; /* page is pointer to start of page to be displayed */ |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
/* Create window for text region, used for scrolling text */ |
||||
text = subwin(dialog, height - 4, width - 2, y + 1, x + 1); |
||||
wattrset(text, dialog_attr); |
||||
wbkgdset(text, dialog_attr & A_COLOR); |
||||
|
||||
keypad(text, TRUE); |
||||
|
||||
/* register the new window, along with its borders */ |
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
|
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
wbkgdset(dialog, dialog_attr & A_COLOR); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE); |
||||
wnoutrefresh(dialog); |
||||
getyx(dialog, cur_y, cur_x); /* Save cursor position */ |
||||
|
||||
/* Print first page of text */ |
||||
attr_clear(text, height - 4, width - 2, dialog_attr); |
||||
print_page(text, height - 4, width - 2); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
||||
wrefresh(dialog); |
||||
|
||||
while ((key != ESC) && (key != '\n')) { |
||||
key = wgetch(dialog); |
||||
switch (key) { |
||||
case 'E': /* Exit */ |
||||
case 'e': |
||||
case 'X': |
||||
case 'x': |
||||
delwin(dialog); |
||||
free(buf); |
||||
close(fd); |
||||
return 0; |
||||
case 'g': /* First page */ |
||||
case KEY_HOME: |
||||
if (!begin_reached) { |
||||
begin_reached = 1; |
||||
/* First page not in buffer? */ |
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
if (fpos > bytes_read) { /* Yes, we have to read it in */ |
||||
if (lseek(fd, 0, SEEK_SET) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in " |
||||
"dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
if ((bytes_read = |
||||
read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; |
||||
} |
||||
page = buf; |
||||
print_page(text, height - 4, width - 2); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
||||
wrefresh(dialog); |
||||
} |
||||
break; |
||||
case 'G': /* Last page */ |
||||
case KEY_END: |
||||
|
||||
end_reached = 1; |
||||
/* Last page not in buffer? */ |
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
if (fpos < file_size) { /* Yes, we have to read it in */ |
||||
if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
if ((bytes_read = |
||||
read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in dialog_textbox().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; |
||||
} |
||||
page = buf + bytes_read; |
||||
back_lines(height - 4); |
||||
print_page(text, height - 4, width - 2); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
||||
wrefresh(dialog); |
||||
break; |
||||
case 'K': /* Previous line */ |
||||
case 'k': |
||||
case KEY_UP: |
||||
if (!begin_reached) { |
||||
back_lines(page_length + 1); |
||||
|
||||
/* We don't call print_page() here but use scrolling to ensure
|
||||
faster screen update. However, 'end_reached' and |
||||
'page_length' should still be updated, and 'page' should |
||||
point to start of next page. This is done by calling |
||||
get_line() in the following 'for' loop. */ |
||||
scrollok(text, TRUE); |
||||
wscrl(text, -1); /* Scroll text region down one line */ |
||||
scrollok(text, FALSE); |
||||
page_length = 0; |
||||
passed_end = 0; |
||||
for (i = 0; i < height - 4; i++) { |
||||
if (!i) { |
||||
/* print first line of page */ |
||||
print_line(text, 0, width - 2); |
||||
wnoutrefresh(text); |
||||
} else |
||||
/* Called to update 'end_reached' and 'page' */ |
||||
get_line(); |
||||
if (!passed_end) |
||||
page_length++; |
||||
if (end_reached && !passed_end) |
||||
passed_end = 1; |
||||
} |
||||
|
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
||||
wrefresh(dialog); |
||||
} |
||||
break; |
||||
case 'B': /* Previous page */ |
||||
case 'b': |
||||
case KEY_PPAGE: |
||||
if (begin_reached) |
||||
break; |
||||
back_lines(page_length + height - 4); |
||||
print_page(text, height - 4, width - 2); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
case 'J': /* Next line */ |
||||
case 'j': |
||||
case KEY_DOWN: |
||||
if (!end_reached) { |
||||
begin_reached = 0; |
||||
scrollok(text, TRUE); |
||||
scroll(text); /* Scroll text region up one line */ |
||||
scrollok(text, FALSE); |
||||
print_line(text, height - 5, width - 2); |
||||
wnoutrefresh(text); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
||||
wrefresh(dialog); |
||||
} |
||||
break; |
||||
case KEY_NPAGE: /* Next page */ |
||||
case ' ': |
||||
if (end_reached) |
||||
break; |
||||
|
||||
begin_reached = 0; |
||||
print_page(text, height - 4, width - 2); |
||||
print_position(dialog, height, width); |
||||
wmove(dialog, cur_y, cur_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
case '0': /* Beginning of line */ |
||||
case 'H': /* Scroll left */ |
||||
case 'h': |
||||
case KEY_LEFT: |
||||
if (hscroll <= 0) |
||||
break; |
||||
|
||||
if (key == '0') |
||||
hscroll = 0; |
||||
else |
||||
hscroll--; |
||||
/* Reprint current page to scroll horizontally */ |
||||
back_lines(page_length); |
||||
print_page(text, height - 4, width - 2); |
||||
wmove(dialog, cur_y, cur_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
case 'L': /* Scroll right */ |
||||
case 'l': |
||||
case KEY_RIGHT: |
||||
if (hscroll >= MAX_LEN) |
||||
break; |
||||
hscroll++; |
||||
/* Reprint current page to scroll horizontally */ |
||||
back_lines(page_length); |
||||
print_page(text, height - 4, width - 2); |
||||
wmove(dialog, cur_y, cur_x); |
||||
wrefresh(dialog); |
||||
break; |
||||
case ESC: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delwin(dialog); |
||||
free(buf); |
||||
close(fd); |
||||
return -1; /* ESC pressed */ |
||||
} |
||||
|
||||
/*
|
||||
* Go back 'n' lines in text file. Called by dialog_textbox(). |
||||
* 'page' will be updated to point to the desired line in 'buf'. |
||||
*/ |
||||
static void back_lines(int n) |
||||
{ |
||||
int i, fpos; |
||||
|
||||
begin_reached = 0; |
||||
/* We have to distinguish between end_reached and !end_reached
|
||||
since at end of file, the line is not ended by a '\n'. |
||||
The code inside 'if' basically does a '--page' to move one |
||||
character backward so as to skip '\n' of the previous line */ |
||||
if (!end_reached) { |
||||
/* Either beginning of buffer or beginning of file reached? */ |
||||
if (page == buf) { |
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in " |
||||
"back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
if (fpos > bytes_read) { /* Not beginning of file yet */ |
||||
/* We've reached beginning of buffer, but not beginning of
|
||||
file yet, so read previous part of file into buffer. |
||||
Note that we only move backward for BUF_SIZE/2 bytes, |
||||
but not BUF_SIZE bytes to avoid re-reading again in |
||||
print_page() later */ |
||||
/* Really possible to move backward BUF_SIZE/2 bytes? */ |
||||
if (fpos < BUF_SIZE / 2 + bytes_read) { |
||||
/* No, move less then */ |
||||
if (lseek(fd, 0, SEEK_SET) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in " |
||||
"back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
page = buf + fpos - bytes_read; |
||||
} else { /* Move backward BUF_SIZE/2 bytes */ |
||||
if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer " |
||||
"in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
page = buf + BUF_SIZE / 2; |
||||
} |
||||
if ((bytes_read = |
||||
read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; |
||||
} else { /* Beginning of file reached */ |
||||
begin_reached = 1; |
||||
return; |
||||
} |
||||
} |
||||
if (*(--page) != '\n') { /* '--page' here */ |
||||
/* Something's wrong... */ |
||||
endwin(); |
||||
fprintf(stderr, "\nInternal error in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
} |
||||
/* Go back 'n' lines */ |
||||
for (i = 0; i < n; i++) |
||||
do { |
||||
if (page == buf) { |
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
if (fpos > bytes_read) { |
||||
/* Really possible to move backward BUF_SIZE/2 bytes? */ |
||||
if (fpos < BUF_SIZE / 2 + bytes_read) { |
||||
/* No, move less then */ |
||||
if (lseek(fd, 0, SEEK_SET) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer " |
||||
"in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
page = buf + fpos - bytes_read; |
||||
} else { /* Move backward BUF_SIZE/2 bytes */ |
||||
if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer" |
||||
" in back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
page = buf + BUF_SIZE / 2; |
||||
} |
||||
if ((bytes_read = |
||||
read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in " |
||||
"back_lines().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; |
||||
} else { /* Beginning of file reached */ |
||||
begin_reached = 1; |
||||
return; |
||||
} |
||||
} |
||||
} while (*(--page) != '\n'); |
||||
page++; |
||||
} |
||||
|
||||
/*
|
||||
* Print a new page of text. Called by dialog_textbox(). |
||||
*/ |
||||
static void print_page(WINDOW * win, int height, int width) |
||||
{ |
||||
int i, passed_end = 0; |
||||
|
||||
page_length = 0; |
||||
for (i = 0; i < height; i++) { |
||||
print_line(win, i, width); |
||||
if (!passed_end) |
||||
page_length++; |
||||
if (end_reached && !passed_end) |
||||
passed_end = 1; |
||||
} |
||||
wnoutrefresh(win); |
||||
} |
||||
|
||||
/*
|
||||
* Print a new line of text. Called by dialog_textbox() and print_page(). |
||||
*/ |
||||
static void print_line(WINDOW * win, int row, int width) |
||||
{ |
||||
int y, x; |
||||
char *line; |
||||
|
||||
line = get_line(); |
||||
line += MIN(strlen(line), hscroll); /* Scroll horizontally */ |
||||
wmove(win, row, 0); /* move cursor to correct line */ |
||||
waddch(win, ' '); |
||||
waddnstr(win, line, MIN(strlen(line), width - 2)); |
||||
|
||||
getyx(win, y, x); |
||||
/* Clear 'residue' of previous line */ |
||||
#if OLD_NCURSES |
||||
{ |
||||
int i; |
||||
for (i = 0; i < width - x; i++) |
||||
waddch(win, ' '); |
||||
} |
||||
#else |
||||
wclrtoeol(win); |
||||
#endif |
||||
} |
||||
|
||||
/*
|
||||
* Return current line of text. Called by dialog_textbox() and print_line(). |
||||
* 'page' should point to start of current line before calling, and will be |
||||
* updated to point to start of next line. |
||||
*/ |
||||
static char *get_line(void) |
||||
{ |
||||
int i = 0, fpos; |
||||
static char line[MAX_LEN + 1]; |
||||
|
||||
end_reached = 0; |
||||
while (*page != '\n') { |
||||
if (*page == '\0') { |
||||
/* Either end of file or end of buffer reached */ |
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in " |
||||
"get_line().\n"); |
||||
exit(-1); |
||||
} |
||||
if (fpos < file_size) { /* Not end of file yet */ |
||||
/* We've reached end of buffer, but not end of file yet,
|
||||
so read next part of file into buffer */ |
||||
if ((bytes_read = |
||||
read(fd, buf, BUF_SIZE)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError reading file in get_line().\n"); |
||||
exit(-1); |
||||
} |
||||
buf[bytes_read] = '\0'; |
||||
page = buf; |
||||
} else { |
||||
if (!end_reached) |
||||
end_reached = 1; |
||||
break; |
||||
} |
||||
} else if (i < MAX_LEN) |
||||
line[i++] = *(page++); |
||||
else { |
||||
/* Truncate lines longer than MAX_LEN characters */ |
||||
if (i == MAX_LEN) |
||||
line[i++] = '\0'; |
||||
page++; |
||||
} |
||||
} |
||||
if (i <= MAX_LEN) |
||||
line[i] = '\0'; |
||||
if (!end_reached) |
||||
page++; /* move pass '\n' */ |
||||
|
||||
return line; |
||||
} |
||||
|
||||
/*
|
||||
* Print current position |
||||
*/ |
||||
static void print_position(WINDOW * win, int height, int width) |
||||
{ |
||||
int fpos, percent; |
||||
|
||||
if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { |
||||
endwin(); |
||||
fprintf(stderr, "\nError moving file pointer in print_position().\n"); |
||||
exit(-1); |
||||
} |
||||
wattrset(win, position_indicator_attr); |
||||
wbkgdset(win, position_indicator_attr & A_COLOR); |
||||
percent = !file_size ? |
||||
100 : ((fpos - bytes_read + page - buf) * 100) / file_size; |
||||
wmove(win, height - 3, width - 9); |
||||
wprintw(win, "(%3d%%)", percent); |
||||
} |
@ -0,0 +1,362 @@ |
||||
/*
|
||||
* util.c |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
/* use colors by default? */ |
||||
bool use_colors = 1; |
||||
|
||||
const char *backtitle = NULL; |
||||
|
||||
/*
|
||||
* Attribute values, default is for mono display |
||||
*/ |
||||
chtype attributes[] = { |
||||
A_NORMAL, /* screen_attr */ |
||||
A_NORMAL, /* shadow_attr */ |
||||
A_NORMAL, /* dialog_attr */ |
||||
A_BOLD, /* title_attr */ |
||||
A_NORMAL, /* border_attr */ |
||||
A_REVERSE, /* button_active_attr */ |
||||
A_DIM, /* button_inactive_attr */ |
||||
A_REVERSE, /* button_key_active_attr */ |
||||
A_BOLD, /* button_key_inactive_attr */ |
||||
A_REVERSE, /* button_label_active_attr */ |
||||
A_NORMAL, /* button_label_inactive_attr */ |
||||
A_NORMAL, /* inputbox_attr */ |
||||
A_NORMAL, /* inputbox_border_attr */ |
||||
A_NORMAL, /* searchbox_attr */ |
||||
A_BOLD, /* searchbox_title_attr */ |
||||
A_NORMAL, /* searchbox_border_attr */ |
||||
A_BOLD, /* position_indicator_attr */ |
||||
A_NORMAL, /* menubox_attr */ |
||||
A_NORMAL, /* menubox_border_attr */ |
||||
A_NORMAL, /* item_attr */ |
||||
A_REVERSE, /* item_selected_attr */ |
||||
A_BOLD, /* tag_attr */ |
||||
A_REVERSE, /* tag_selected_attr */ |
||||
A_BOLD, /* tag_key_attr */ |
||||
A_REVERSE, /* tag_key_selected_attr */ |
||||
A_BOLD, /* check_attr */ |
||||
A_REVERSE, /* check_selected_attr */ |
||||
A_BOLD, /* uarrow_attr */ |
||||
A_BOLD /* darrow_attr */ |
||||
}; |
||||
|
||||
#include "colors.h" |
||||
|
||||
/*
|
||||
* Table of color values |
||||
*/ |
||||
int color_table[][3] = { |
||||
{SCREEN_FG, SCREEN_BG, SCREEN_HL}, |
||||
{SHADOW_FG, SHADOW_BG, SHADOW_HL}, |
||||
{DIALOG_FG, DIALOG_BG, DIALOG_HL}, |
||||
{TITLE_FG, TITLE_BG, TITLE_HL}, |
||||
{BORDER_FG, BORDER_BG, BORDER_HL}, |
||||
{BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL}, |
||||
{BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL}, |
||||
{BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL}, |
||||
{BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, |
||||
BUTTON_KEY_INACTIVE_HL}, |
||||
{BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, |
||||
BUTTON_LABEL_ACTIVE_HL}, |
||||
{BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG, |
||||
BUTTON_LABEL_INACTIVE_HL}, |
||||
{INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL}, |
||||
{INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL}, |
||||
{SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL}, |
||||
{SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL}, |
||||
{SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL}, |
||||
{POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL}, |
||||
{MENUBOX_FG, MENUBOX_BG, MENUBOX_HL}, |
||||
{MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL}, |
||||
{ITEM_FG, ITEM_BG, ITEM_HL}, |
||||
{ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL}, |
||||
{TAG_FG, TAG_BG, TAG_HL}, |
||||
{TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL}, |
||||
{TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL}, |
||||
{TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL}, |
||||
{CHECK_FG, CHECK_BG, CHECK_HL}, |
||||
{CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL}, |
||||
{UARROW_FG, UARROW_BG, UARROW_HL}, |
||||
{DARROW_FG, DARROW_BG, DARROW_HL}, |
||||
}; /* color_table */ |
||||
|
||||
/*
|
||||
* Set window to attribute 'attr' |
||||
*/ |
||||
void attr_clear(WINDOW * win, int height, int width, chtype attr) |
||||
{ |
||||
int i, j; |
||||
|
||||
wattrset(win, attr); |
||||
for (i = 0; i < height; i++) { |
||||
wmove(win, i, 0); |
||||
for (j = 0; j < width; j++) |
||||
waddch(win, ' '); |
||||
} |
||||
touchwin(win); |
||||
} |
||||
|
||||
void dialog_clear(void) |
||||
{ |
||||
attr_clear(stdscr, LINES, COLS, screen_attr); |
||||
/* Display background title if it exists ... - SLH */ |
||||
if (backtitle != NULL) { |
||||
int i; |
||||
|
||||
wattrset(stdscr, screen_attr); |
||||
mvwaddstr(stdscr, 0, 1, (char *)backtitle); |
||||
wmove(stdscr, 1, 1); |
||||
for (i = 1; i < COLS - 1; i++) |
||||
waddch(stdscr, ACS_HLINE); |
||||
} |
||||
wnoutrefresh(stdscr); |
||||
} |
||||
|
||||
/*
|
||||
* Do some initialization for dialog |
||||
*/ |
||||
void init_dialog(void) |
||||
{ |
||||
initscr(); /* Init curses */ |
||||
keypad(stdscr, TRUE); |
||||
cbreak(); |
||||
noecho(); |
||||
|
||||
if (use_colors) /* Set up colors */ |
||||
color_setup(); |
||||
|
||||
dialog_clear(); |
||||
} |
||||
|
||||
/*
|
||||
* Setup for color display |
||||
*/ |
||||
void color_setup(void) |
||||
{ |
||||
int i; |
||||
|
||||
if (has_colors()) { /* Terminal supports color? */ |
||||
start_color(); |
||||
|
||||
/* Initialize color pairs */ |
||||
for (i = 0; i < ATTRIBUTE_COUNT; i++) |
||||
init_pair(i + 1, color_table[i][0], color_table[i][1]); |
||||
|
||||
/* Setup color attributes */ |
||||
for (i = 0; i < ATTRIBUTE_COUNT; i++) |
||||
attributes[i] = C_ATTR(color_table[i][2], i + 1); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* End using dialog functions. |
||||
*/ |
||||
void end_dialog(void) |
||||
{ |
||||
endwin(); |
||||
} |
||||
|
||||
/* Print the title of the dialog. Center the title and truncate
|
||||
* tile if wider than dialog (- 2 chars). |
||||
**/ |
||||
void print_title(WINDOW *dialog, const char *title, int width) |
||||
{ |
||||
if (title) { |
||||
int tlen = MIN(width - 2, strlen(title)); |
||||
wattrset(dialog, title_attr); |
||||
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); |
||||
mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); |
||||
waddch(dialog, ' '); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Print a string of text in a window, automatically wrap around to the |
||||
* next line if the string is too long to fit on one line. Newline |
||||
* characters '\n' are replaced by spaces. We start on a new line |
||||
* if there is no room for at least 4 nonblanks following a double-space. |
||||
*/ |
||||
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) |
||||
{ |
||||
int newl, cur_x, cur_y; |
||||
int i, prompt_len, room, wlen; |
||||
char tempstr[MAX_LEN + 1], *word, *sp, *sp2; |
||||
|
||||
strcpy(tempstr, prompt); |
||||
|
||||
prompt_len = strlen(tempstr); |
||||
|
||||
/*
|
||||
* Remove newlines |
||||
*/ |
||||
for (i = 0; i < prompt_len; i++) { |
||||
if (tempstr[i] == '\n') |
||||
tempstr[i] = ' '; |
||||
} |
||||
|
||||
if (prompt_len <= width - x * 2) { /* If prompt is short */ |
||||
wmove(win, y, (width - prompt_len) / 2); |
||||
waddstr(win, tempstr); |
||||
} else { |
||||
cur_x = x; |
||||
cur_y = y; |
||||
newl = 1; |
||||
word = tempstr; |
||||
while (word && *word) { |
||||
sp = index(word, ' '); |
||||
if (sp) |
||||
*sp++ = 0; |
||||
|
||||
/* Wrap to next line if either the word does not fit,
|
||||
or it is the first word of a new sentence, and it is |
||||
short, and the next word does not fit. */ |
||||
room = width - cur_x; |
||||
wlen = strlen(word); |
||||
if (wlen > room || |
||||
(newl && wlen < 4 && sp |
||||
&& wlen + 1 + strlen(sp) > room |
||||
&& (!(sp2 = index(sp, ' ')) |
||||
|| wlen + 1 + (sp2 - sp) > room))) { |
||||
cur_y++; |
||||
cur_x = x; |
||||
} |
||||
wmove(win, cur_y, cur_x); |
||||
waddstr(win, word); |
||||
getyx(win, cur_y, cur_x); |
||||
cur_x++; |
||||
if (sp && *sp == ' ') { |
||||
cur_x++; /* double space */ |
||||
while (*++sp == ' ') ; |
||||
newl = 1; |
||||
} else |
||||
newl = 0; |
||||
word = sp; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Print a button |
||||
*/ |
||||
void print_button(WINDOW * win, const char *label, int y, int x, int selected) |
||||
{ |
||||
int i, temp; |
||||
|
||||
wmove(win, y, x); |
||||
wattrset(win, selected ? button_active_attr : button_inactive_attr); |
||||
waddstr(win, "<"); |
||||
temp = strspn(label, " "); |
||||
label += temp; |
||||
wattrset(win, selected ? button_label_active_attr |
||||
: button_label_inactive_attr); |
||||
for (i = 0; i < temp; i++) |
||||
waddch(win, ' '); |
||||
wattrset(win, selected ? button_key_active_attr |
||||
: button_key_inactive_attr); |
||||
waddch(win, label[0]); |
||||
wattrset(win, selected ? button_label_active_attr |
||||
: button_label_inactive_attr); |
||||
waddstr(win, (char *)label + 1); |
||||
wattrset(win, selected ? button_active_attr : button_inactive_attr); |
||||
waddstr(win, ">"); |
||||
wmove(win, y, x + temp + 1); |
||||
} |
||||
|
||||
/*
|
||||
* Draw a rectangular box with line drawing characters |
||||
*/ |
||||
void |
||||
draw_box(WINDOW * win, int y, int x, int height, int width, |
||||
chtype box, chtype border) |
||||
{ |
||||
int i, j; |
||||
|
||||
wattrset(win, 0); |
||||
for (i = 0; i < height; i++) { |
||||
wmove(win, y + i, x); |
||||
for (j = 0; j < width; j++) |
||||
if (!i && !j) |
||||
waddch(win, border | ACS_ULCORNER); |
||||
else if (i == height - 1 && !j) |
||||
waddch(win, border | ACS_LLCORNER); |
||||
else if (!i && j == width - 1) |
||||
waddch(win, box | ACS_URCORNER); |
||||
else if (i == height - 1 && j == width - 1) |
||||
waddch(win, box | ACS_LRCORNER); |
||||
else if (!i) |
||||
waddch(win, border | ACS_HLINE); |
||||
else if (i == height - 1) |
||||
waddch(win, box | ACS_HLINE); |
||||
else if (!j) |
||||
waddch(win, border | ACS_VLINE); |
||||
else if (j == width - 1) |
||||
waddch(win, box | ACS_VLINE); |
||||
else |
||||
waddch(win, box | ' '); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Draw shadows along the right and bottom edge to give a more 3D look |
||||
* to the boxes |
||||
*/ |
||||
void draw_shadow(WINDOW * win, int y, int x, int height, int width) |
||||
{ |
||||
int i; |
||||
|
||||
if (has_colors()) { /* Whether terminal supports color? */ |
||||
wattrset(win, shadow_attr); |
||||
wmove(win, y + height, x + 2); |
||||
for (i = 0; i < width; i++) |
||||
waddch(win, winch(win) & A_CHARTEXT); |
||||
for (i = y + 1; i < y + height + 1; i++) { |
||||
wmove(win, i, x + width); |
||||
waddch(win, winch(win) & A_CHARTEXT); |
||||
waddch(win, winch(win) & A_CHARTEXT); |
||||
} |
||||
wnoutrefresh(win); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Return the position of the first alphabetic character in a string. |
||||
*/ |
||||
int first_alpha(const char *string, const char *exempt) |
||||
{ |
||||
int i, in_paren = 0, c; |
||||
|
||||
for (i = 0; i < strlen(string); i++) { |
||||
c = tolower(string[i]); |
||||
|
||||
if (strchr("<[(", c)) |
||||
++in_paren; |
||||
if (strchr(">])", c) && in_paren > 0) |
||||
--in_paren; |
||||
|
||||
if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) |
||||
return i; |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,102 @@ |
||||
/*
|
||||
* yesno.c -- implements the yes/no box |
||||
* |
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) |
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include "dialog.h" |
||||
|
||||
/*
|
||||
* Display termination buttons |
||||
*/ |
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected) |
||||
{ |
||||
int x = width / 2 - 10; |
||||
int y = height - 2; |
||||
|
||||
print_button(dialog, " Yes ", y, x, selected == 0); |
||||
print_button(dialog, " No ", y, x + 13, selected == 1); |
||||
|
||||
wmove(dialog, y, x + 1 + 13 * selected); |
||||
wrefresh(dialog); |
||||
} |
||||
|
||||
/*
|
||||
* Display a dialog box with two buttons - Yes and No |
||||
*/ |
||||
int dialog_yesno(const char *title, const char *prompt, int height, int width) |
||||
{ |
||||
int i, x, y, key = 0, button = 0; |
||||
WINDOW *dialog; |
||||
|
||||
/* center dialog box on screen */ |
||||
x = (COLS - width) / 2; |
||||
y = (LINES - height) / 2; |
||||
|
||||
draw_shadow(stdscr, y, x, height, width); |
||||
|
||||
dialog = newwin(height, width, y, x); |
||||
keypad(dialog, TRUE); |
||||
|
||||
draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); |
||||
wattrset(dialog, border_attr); |
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
||||
for (i = 0; i < width - 2; i++) |
||||
waddch(dialog, ACS_HLINE); |
||||
wattrset(dialog, dialog_attr); |
||||
waddch(dialog, ACS_RTEE); |
||||
|
||||
print_title(dialog, title, width); |
||||
|
||||
wattrset(dialog, dialog_attr); |
||||
print_autowrap(dialog, prompt, width - 2, 1, 3); |
||||
|
||||
print_buttons(dialog, height, width, 0); |
||||
|
||||
while (key != ESC) { |
||||
key = wgetch(dialog); |
||||
switch (key) { |
||||
case 'Y': |
||||
case 'y': |
||||
delwin(dialog); |
||||
return 0; |
||||
case 'N': |
||||
case 'n': |
||||
delwin(dialog); |
||||
return 1; |
||||
|
||||
case TAB: |
||||
case KEY_LEFT: |
||||
case KEY_RIGHT: |
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); |
||||
|
||||
print_buttons(dialog, height, width, button); |
||||
wrefresh(dialog); |
||||
break; |
||||
case ' ': |
||||
case '\n': |
||||
delwin(dialog); |
||||
return button; |
||||
case ESC: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delwin(dialog); |
||||
return -1; /* ESC pressed */ |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,397 @@ |
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#define LKC_DIRECT_LINK |
||||
#include "lkc.h" |
||||
|
||||
struct menu rootmenu; |
||||
static struct menu **last_entry_ptr; |
||||
|
||||
struct file *file_list; |
||||
struct file *current_file; |
||||
|
||||
static void menu_warn(struct menu *menu, const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
va_start(ap, fmt); |
||||
fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
va_end(ap); |
||||
} |
||||
|
||||
static void prop_warn(struct property *prop, const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
va_start(ap, fmt); |
||||
fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
va_end(ap); |
||||
} |
||||
|
||||
void menu_init(void) |
||||
{ |
||||
current_entry = current_menu = &rootmenu; |
||||
last_entry_ptr = &rootmenu.list; |
||||
} |
||||
|
||||
void menu_add_entry(struct symbol *sym) |
||||
{ |
||||
struct menu *menu; |
||||
|
||||
menu = malloc(sizeof(*menu)); |
||||
memset(menu, 0, sizeof(*menu)); |
||||
menu->sym = sym; |
||||
menu->parent = current_menu; |
||||
menu->file = current_file; |
||||
menu->lineno = zconf_lineno(); |
||||
|
||||
*last_entry_ptr = menu; |
||||
last_entry_ptr = &menu->next; |
||||
current_entry = menu; |
||||
} |
||||
|
||||
void menu_end_entry(void) |
||||
{ |
||||
} |
||||
|
||||
struct menu *menu_add_menu(void) |
||||
{ |
||||
menu_end_entry(); |
||||
last_entry_ptr = ¤t_entry->list; |
||||
return current_menu = current_entry; |
||||
} |
||||
|
||||
void menu_end_menu(void) |
||||
{ |
||||
last_entry_ptr = ¤t_menu->next; |
||||
current_menu = current_menu->parent; |
||||
} |
||||
|
||||
struct expr *menu_check_dep(struct expr *e) |
||||
{ |
||||
if (!e) |
||||
return e; |
||||
|
||||
switch (e->type) { |
||||
case E_NOT: |
||||
e->left.expr = menu_check_dep(e->left.expr); |
||||
break; |
||||
case E_OR: |
||||
case E_AND: |
||||
e->left.expr = menu_check_dep(e->left.expr); |
||||
e->right.expr = menu_check_dep(e->right.expr); |
||||
break; |
||||
case E_SYMBOL: |
||||
/* change 'm' into 'm' && MODULES */ |
||||
if (e->left.sym == &symbol_mod) |
||||
return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return e; |
||||
} |
||||
|
||||
void menu_add_dep(struct expr *dep) |
||||
{ |
||||
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); |
||||
} |
||||
|
||||
void menu_set_type(int type) |
||||
{ |
||||
struct symbol *sym = current_entry->sym; |
||||
|
||||
if (sym->type == type) |
||||
return; |
||||
if (sym->type == S_UNKNOWN) { |
||||
sym->type = type; |
||||
return; |
||||
} |
||||
menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n", |
||||
sym->name ? sym->name : "<choice>", |
||||
sym_type_name(sym->type), sym_type_name(type)); |
||||
} |
||||
|
||||
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) |
||||
{ |
||||
struct property *prop = prop_alloc(type, current_entry->sym); |
||||
|
||||
prop->menu = current_entry; |
||||
prop->text = prompt; |
||||
prop->expr = expr; |
||||
prop->visible.expr = menu_check_dep(dep); |
||||
|
||||
if (prompt) { |
||||
if (current_entry->prompt) |
||||
menu_warn(current_entry, "prompt redefined\n"); |
||||
current_entry->prompt = prop; |
||||
} |
||||
|
||||
return prop; |
||||
} |
||||
|
||||
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) |
||||
{ |
||||
return menu_add_prop(type, prompt, NULL, dep); |
||||
} |
||||
|
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) |
||||
{ |
||||
menu_add_prop(type, NULL, expr, dep); |
||||
} |
||||
|
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) |
||||
{ |
||||
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); |
||||
} |
||||
|
||||
static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2) |
||||
{ |
||||
return sym2->type == S_INT || sym2->type == S_HEX || |
||||
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); |
||||
} |
||||
|
||||
void sym_check_prop(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
struct symbol *sym2; |
||||
for (prop = sym->prop; prop; prop = prop->next) { |
||||
switch (prop->type) { |
||||
case P_DEFAULT: |
||||
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && |
||||
prop->expr->type != E_SYMBOL) |
||||
prop_warn(prop, |
||||
"default for config symbol '%'" |
||||
" must be a single symbol", sym->name); |
||||
break; |
||||
case P_SELECT: |
||||
sym2 = prop_get_symbol(prop); |
||||
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) |
||||
prop_warn(prop, |
||||
"config symbol '%s' uses select, but is " |
||||
"not boolean or tristate", sym->name); |
||||
else if (sym2->type == S_UNKNOWN) |
||||
prop_warn(prop, |
||||
"'select' used by config symbol '%s' " |
||||
"refer to undefined symbol '%s'", |
||||
sym->name, sym2->name); |
||||
else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE) |
||||
prop_warn(prop, |
||||
"'%s' has wrong type. 'select' only " |
||||
"accept arguments of boolean and " |
||||
"tristate type", sym2->name); |
||||
break; |
||||
case P_RANGE: |
||||
if (sym->type != S_INT && sym->type != S_HEX) |
||||
prop_warn(prop, "range is only allowed " |
||||
"for int or hex symbols"); |
||||
if (!menu_range_valid_sym(sym, prop->expr->left.sym) || |
||||
!menu_range_valid_sym(sym, prop->expr->right.sym)) |
||||
prop_warn(prop, "range is invalid"); |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void menu_finalize(struct menu *parent) |
||||
{ |
||||
struct menu *menu, *last_menu; |
||||
struct symbol *sym; |
||||
struct property *prop; |
||||
struct expr *parentdep, *basedep, *dep, *dep2, **ep; |
||||
|
||||
sym = parent->sym; |
||||
if (parent->list) { |
||||
if (sym && sym_is_choice(sym)) { |
||||
/* find the first choice value and find out choice type */ |
||||
for (menu = parent->list; menu; menu = menu->next) { |
||||
if (menu->sym) { |
||||
current_entry = parent; |
||||
menu_set_type(menu->sym->type); |
||||
current_entry = menu; |
||||
menu_set_type(sym->type); |
||||
break; |
||||
} |
||||
} |
||||
parentdep = expr_alloc_symbol(sym); |
||||
} else if (parent->prompt) |
||||
parentdep = parent->prompt->visible.expr; |
||||
else |
||||
parentdep = parent->dep; |
||||
|
||||
for (menu = parent->list; menu; menu = menu->next) { |
||||
basedep = expr_transform(menu->dep); |
||||
basedep = expr_alloc_and(expr_copy(parentdep), basedep); |
||||
basedep = expr_eliminate_dups(basedep); |
||||
menu->dep = basedep; |
||||
if (menu->sym) |
||||
prop = menu->sym->prop; |
||||
else |
||||
prop = menu->prompt; |
||||
for (; prop; prop = prop->next) { |
||||
if (prop->menu != menu) |
||||
continue; |
||||
dep = expr_transform(prop->visible.expr); |
||||
dep = expr_alloc_and(expr_copy(basedep), dep); |
||||
dep = expr_eliminate_dups(dep); |
||||
if (menu->sym && menu->sym->type != S_TRISTATE) |
||||
dep = expr_trans_bool(dep); |
||||
prop->visible.expr = dep; |
||||
if (prop->type == P_SELECT) { |
||||
struct symbol *es = prop_get_symbol(prop); |
||||
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, |
||||
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); |
||||
} |
||||
} |
||||
} |
||||
for (menu = parent->list; menu; menu = menu->next) |
||||
menu_finalize(menu); |
||||
} else if (sym) { |
||||
basedep = parent->prompt ? parent->prompt->visible.expr : NULL; |
||||
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); |
||||
basedep = expr_eliminate_dups(expr_transform(basedep)); |
||||
last_menu = NULL; |
||||
for (menu = parent->next; menu; menu = menu->next) { |
||||
dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; |
||||
if (!expr_contains_symbol(dep, sym)) |
||||
break; |
||||
if (expr_depends_symbol(dep, sym)) |
||||
goto next; |
||||
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); |
||||
dep = expr_eliminate_dups(expr_transform(dep)); |
||||
dep2 = expr_copy(basedep); |
||||
expr_eliminate_eq(&dep, &dep2); |
||||
expr_free(dep); |
||||
if (!expr_is_yes(dep2)) { |
||||
expr_free(dep2); |
||||
break; |
||||
} |
||||
expr_free(dep2); |
||||
next: |
||||
menu_finalize(menu); |
||||
menu->parent = parent; |
||||
last_menu = menu; |
||||
} |
||||
if (last_menu) { |
||||
parent->list = parent->next; |
||||
parent->next = last_menu->next; |
||||
last_menu->next = NULL; |
||||
} |
||||
} |
||||
for (menu = parent->list; menu; menu = menu->next) { |
||||
if (sym && sym_is_choice(sym) && menu->sym) { |
||||
menu->sym->flags |= SYMBOL_CHOICEVAL; |
||||
if (!menu->prompt) |
||||
menu_warn(menu, "choice value must have a prompt"); |
||||
for (prop = menu->sym->prop; prop; prop = prop->next) { |
||||
if (prop->type == P_PROMPT && prop->menu != menu) { |
||||
prop_warn(prop, "choice values " |
||||
"currently only support a " |
||||
"single prompt"); |
||||
} |
||||
if (prop->type == P_DEFAULT) |
||||
prop_warn(prop, "defaults for choice " |
||||
"values not supported"); |
||||
} |
||||
current_entry = menu; |
||||
menu_set_type(sym->type); |
||||
menu_add_symbol(P_CHOICE, sym, NULL); |
||||
prop = sym_get_choice_prop(sym); |
||||
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) |
||||
; |
||||
*ep = expr_alloc_one(E_CHOICE, NULL); |
||||
(*ep)->right.sym = menu->sym; |
||||
} |
||||
if (menu->list && (!menu->prompt || !menu->prompt->text)) { |
||||
for (last_menu = menu->list; ; last_menu = last_menu->next) { |
||||
last_menu->parent = parent; |
||||
if (!last_menu->next) |
||||
break; |
||||
} |
||||
last_menu->next = menu->next; |
||||
menu->next = menu->list; |
||||
menu->list = NULL; |
||||
} |
||||
} |
||||
|
||||
if (sym && !(sym->flags & SYMBOL_WARNED)) { |
||||
if (sym->type == S_UNKNOWN) |
||||
menu_warn(parent, "config symbol defined " |
||||
"without type\n"); |
||||
|
||||
if (sym_is_choice(sym) && !parent->prompt) |
||||
menu_warn(parent, "choice must have a prompt\n"); |
||||
|
||||
/* Check properties connected to this symbol */ |
||||
sym_check_prop(sym); |
||||
sym->flags |= SYMBOL_WARNED; |
||||
} |
||||
|
||||
if (sym && !sym_is_optional(sym) && parent->prompt) { |
||||
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, |
||||
expr_alloc_and(parent->prompt->visible.expr, |
||||
expr_alloc_symbol(&symbol_mod))); |
||||
} |
||||
} |
||||
|
||||
bool menu_is_visible(struct menu *menu) |
||||
{ |
||||
struct menu *child; |
||||
struct symbol *sym; |
||||
tristate visible; |
||||
|
||||
if (!menu->prompt) |
||||
return false; |
||||
sym = menu->sym; |
||||
if (sym) { |
||||
sym_calc_value(sym); |
||||
visible = menu->prompt->visible.tri; |
||||
} else |
||||
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); |
||||
|
||||
if (visible != no) |
||||
return true; |
||||
if (!sym || sym_get_tristate_value(menu->sym) == no) |
||||
return false; |
||||
|
||||
for (child = menu->list; child; child = child->next) |
||||
if (menu_is_visible(child)) |
||||
return true; |
||||
return false; |
||||
} |
||||
|
||||
const char *menu_get_prompt(struct menu *menu) |
||||
{ |
||||
if (menu->prompt) |
||||
return _(menu->prompt->text); |
||||
else if (menu->sym) |
||||
return _(menu->sym->name); |
||||
return NULL; |
||||
} |
||||
|
||||
struct menu *menu_get_root_menu(struct menu *menu) |
||||
{ |
||||
return &rootmenu; |
||||
} |
||||
|
||||
struct menu *menu_get_parent_menu(struct menu *menu) |
||||
{ |
||||
enum prop_type type; |
||||
|
||||
for (; menu != &rootmenu; menu = menu->parent) { |
||||
type = menu->prompt ? menu->prompt->type : 0; |
||||
if (type == P_MENU) |
||||
break; |
||||
} |
||||
return menu; |
||||
} |
||||
|
@ -0,0 +1,882 @@ |
||||
/*
|
||||
* 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 <regex.h> |
||||
#include <sys/utsname.h> |
||||
|
||||
#define LKC_DIRECT_LINK |
||||
#include "lkc.h" |
||||
|
||||
struct symbol symbol_yes = { |
||||
.name = "y", |
||||
.curr = { "y", yes }, |
||||
.flags = SYMBOL_YES|SYMBOL_VALID, |
||||
}, symbol_mod = { |
||||
.name = "m", |
||||
.curr = { "m", mod }, |
||||
.flags = SYMBOL_MOD|SYMBOL_VALID, |
||||
}, symbol_no = { |
||||
.name = "n", |
||||
.curr = { "n", no }, |
||||
.flags = SYMBOL_NO|SYMBOL_VALID, |
||||
}, symbol_empty = { |
||||
.name = "", |
||||
.curr = { "", no }, |
||||
.flags = SYMBOL_VALID, |
||||
}; |
||||
|
||||
int sym_change_count; |
||||
struct symbol *modules_sym; |
||||
tristate modules_val; |
||||
|
||||
void sym_add_default(struct symbol *sym, const char *def) |
||||
{ |
||||
struct property *prop = prop_alloc(P_DEFAULT, sym); |
||||
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(def, 1)); |
||||
} |
||||
|
||||
void sym_init(void) |
||||
{ |
||||
struct symbol *sym; |
||||
struct utsname uts; |
||||
char *p; |
||||
static bool inited = false; |
||||
|
||||
if (inited) |
||||
return; |
||||
inited = true; |
||||
|
||||
uname(&uts); |
||||
|
||||
sym = sym_lookup("ARCH", 0); |
||||
sym->type = S_STRING; |
||||
sym->flags |= SYMBOL_AUTO; |
||||
p = getenv("ARCH"); |
||||
if (p) |
||||
sym_add_default(sym, p); |
||||
|
||||
sym = sym_lookup("KERNELVERSION", 0); |
||||
sym->type = S_STRING; |
||||
sym->flags |= SYMBOL_AUTO; |
||||
p = getenv("KERNELVERSION"); |
||||
if (p) |
||||
sym_add_default(sym, p); |
||||
|
||||
sym = sym_lookup("UNAME_RELEASE", 0); |
||||
sym->type = S_STRING; |
||||
sym->flags |= SYMBOL_AUTO; |
||||
sym_add_default(sym, uts.release); |
||||
} |
||||
|
||||
enum symbol_type sym_get_type(struct symbol *sym) |
||||
{ |
||||
enum symbol_type type = sym->type; |
||||
|
||||
if (type == S_TRISTATE) { |
||||
if (sym_is_choice_value(sym) && sym->visible == yes) |
||||
type = S_BOOLEAN; |
||||
else if (modules_val == no) |
||||
type = S_BOOLEAN; |
||||
} |
||||
return type; |
||||
} |
||||
|
||||
const char *sym_type_name(enum symbol_type type) |
||||
{ |
||||
switch (type) { |
||||
case S_BOOLEAN: |
||||
return "boolean"; |
||||
case S_TRISTATE: |
||||
return "tristate"; |
||||
case S_INT: |
||||
return "integer"; |
||||
case S_HEX: |
||||
return "hex"; |
||||
case S_STRING: |
||||
return "string"; |
||||
case S_UNKNOWN: |
||||
return "unknown"; |
||||
case S_OTHER: |
||||
break; |
||||
} |
||||
return "???"; |
||||
} |
||||
|
||||
struct property *sym_get_choice_prop(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
|
||||
for_all_choices(sym, prop) |
||||
return prop; |
||||
return NULL; |
||||
} |
||||
|
||||
struct property *sym_get_default_prop(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
|
||||
for_all_defaults(sym, prop) { |
||||
prop->visible.tri = expr_calc_value(prop->visible.expr); |
||||
if (prop->visible.tri != no) |
||||
return prop; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
struct property *sym_get_range_prop(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
|
||||
for_all_properties(sym, prop, P_RANGE) { |
||||
prop->visible.tri = expr_calc_value(prop->visible.expr); |
||||
if (prop->visible.tri != no) |
||||
return prop; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static int sym_get_range_val(struct symbol *sym, int base) |
||||
{ |
||||
sym_calc_value(sym); |
||||
switch (sym->type) { |
||||
case S_INT: |
||||
base = 10; |
||||
break; |
||||
case S_HEX: |
||||
base = 16; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return strtol(sym->curr.val, NULL, base); |
||||
} |
||||
|
||||
static void sym_validate_range(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
int base, val, val2; |
||||
char str[64]; |
||||
|
||||
switch (sym->type) { |
||||
case S_INT: |
||||
base = 10; |
||||
break; |
||||
case S_HEX: |
||||
base = 16; |
||||
break; |
||||
default: |
||||
return; |
||||
} |
||||
prop = sym_get_range_prop(sym); |
||||
if (!prop) |
||||
return; |
||||
val = strtol(sym->curr.val, NULL, base); |
||||
val2 = sym_get_range_val(prop->expr->left.sym, base); |
||||
if (val >= val2) { |
||||
val2 = sym_get_range_val(prop->expr->right.sym, base); |
||||
if (val <= val2) |
||||
return; |
||||
} |
||||
if (sym->type == S_INT) |
||||
sprintf(str, "%d", val2); |
||||
else |
||||
sprintf(str, "0x%x", val2); |
||||
sym->curr.val = strdup(str); |
||||
} |
||||
|
||||
static void sym_calc_visibility(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
tristate tri; |
||||
|
||||
/* any prompt visible? */ |
||||
tri = no; |
||||
for_all_prompts(sym, prop) { |
||||
prop->visible.tri = expr_calc_value(prop->visible.expr); |
||||
tri = E_OR(tri, prop->visible.tri); |
||||
} |
||||
if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) |
||||
tri = yes; |
||||
if (sym->visible != tri) { |
||||
sym->visible = tri; |
||||
sym_set_changed(sym); |
||||
} |
||||
if (sym_is_choice_value(sym)) |
||||
return; |
||||
tri = no; |
||||
if (sym->rev_dep.expr) |
||||
tri = expr_calc_value(sym->rev_dep.expr); |
||||
if (tri == mod && sym_get_type(sym) == S_BOOLEAN) |
||||
tri = yes; |
||||
if (sym->rev_dep.tri != tri) { |
||||
sym->rev_dep.tri = tri; |
||||
sym_set_changed(sym); |
||||
} |
||||
} |
||||
|
||||
static struct symbol *sym_calc_choice(struct symbol *sym) |
||||
{ |
||||
struct symbol *def_sym; |
||||
struct property *prop; |
||||
struct expr *e; |
||||
|
||||
/* is the user choice visible? */ |
||||
def_sym = sym->user.val; |
||||
if (def_sym) { |
||||
sym_calc_visibility(def_sym); |
||||
if (def_sym->visible != no) |
||||
return def_sym; |
||||
} |
||||
|
||||
/* any of the defaults visible? */ |
||||
for_all_defaults(sym, prop) { |
||||
prop->visible.tri = expr_calc_value(prop->visible.expr); |
||||
if (prop->visible.tri == no) |
||||
continue; |
||||
def_sym = prop_get_symbol(prop); |
||||
sym_calc_visibility(def_sym); |
||||
if (def_sym->visible != no) |
||||
return def_sym; |
||||
} |
||||
|
||||
/* just get the first visible value */ |
||||
prop = sym_get_choice_prop(sym); |
||||
for (e = prop->expr; e; e = e->left.expr) { |
||||
def_sym = e->right.sym; |
||||
sym_calc_visibility(def_sym); |
||||
if (def_sym->visible != no) |
||||
return def_sym; |
||||
} |
||||
|
||||
/* no choice? reset tristate value */ |
||||
sym->curr.tri = no; |
||||
return NULL; |
||||
} |
||||
|
||||
void sym_calc_value(struct symbol *sym) |
||||
{ |
||||
struct symbol_value newval, oldval; |
||||
struct property *prop; |
||||
struct expr *e; |
||||
|
||||
if (!sym) |
||||
return; |
||||
|
||||
if (sym->flags & SYMBOL_VALID) |
||||
return; |
||||
sym->flags |= SYMBOL_VALID; |
||||
|
||||
oldval = sym->curr; |
||||
|
||||
switch (sym->type) { |
||||
case S_INT: |
||||
case S_HEX: |
||||
case S_STRING: |
||||
newval = symbol_empty.curr; |
||||
break; |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
newval = symbol_no.curr; |
||||
break; |
||||
default: |
||||
sym->curr.val = sym->name; |
||||
sym->curr.tri = no; |
||||
return; |
||||
} |
||||
if (!sym_is_choice_value(sym)) |
||||
sym->flags &= ~SYMBOL_WRITE; |
||||
|
||||
sym_calc_visibility(sym); |
||||
|
||||
/* set default if recursively called */ |
||||
sym->curr = newval; |
||||
|
||||
switch (sym_get_type(sym)) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
if (sym_is_choice_value(sym) && sym->visible == yes) { |
||||
prop = sym_get_choice_prop(sym); |
||||
newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; |
||||
} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) { |
||||
sym->flags |= SYMBOL_WRITE; |
||||
if (sym_has_value(sym)) |
||||
newval.tri = sym->user.tri; |
||||
else if (!sym_is_choice(sym)) { |
||||
prop = sym_get_default_prop(sym); |
||||
if (prop) |
||||
newval.tri = expr_calc_value(prop->expr); |
||||
} |
||||
newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri); |
||||
} else if (!sym_is_choice(sym)) { |
||||
prop = sym_get_default_prop(sym); |
||||
if (prop) { |
||||
sym->flags |= SYMBOL_WRITE; |
||||
newval.tri = expr_calc_value(prop->expr); |
||||
} |
||||
} |
||||
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) |
||||
newval.tri = yes; |
||||
break; |
||||
case S_STRING: |
||||
case S_HEX: |
||||
case S_INT: |
||||
if (sym->visible != no) { |
||||
sym->flags |= SYMBOL_WRITE; |
||||
if (sym_has_value(sym)) { |
||||
newval.val = sym->user.val; |
||||
break; |
||||
} |
||||
} |
||||
prop = sym_get_default_prop(sym); |
||||
if (prop) { |
||||
struct symbol *ds = prop_get_symbol(prop); |
||||
if (ds) { |
||||
sym->flags |= SYMBOL_WRITE; |
||||
sym_calc_value(ds); |
||||
newval.val = ds->curr.val; |
||||
} |
||||
} |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
|
||||
sym->curr = newval; |
||||
if (sym_is_choice(sym) && newval.tri == yes) |
||||
sym->curr.val = sym_calc_choice(sym); |
||||
sym_validate_range(sym); |
||||
|
||||
if (memcmp(&oldval, &sym->curr, sizeof(oldval))) |
||||
sym_set_changed(sym); |
||||
if (modules_sym == sym) |
||||
modules_val = modules_sym->curr.tri; |
||||
|
||||
if (sym_is_choice(sym)) { |
||||
int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); |
||||
prop = sym_get_choice_prop(sym); |
||||
for (e = prop->expr; e; e = e->left.expr) { |
||||
e->right.sym->flags |= flags; |
||||
if (flags & SYMBOL_CHANGED) |
||||
sym_set_changed(e->right.sym); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void sym_clear_all_valid(void) |
||||
{ |
||||
struct symbol *sym; |
||||
int i; |
||||
|
||||
for_all_symbols(i, sym) |
||||
sym->flags &= ~SYMBOL_VALID; |
||||
sym_change_count++; |
||||
if (modules_sym) |
||||
sym_calc_value(modules_sym); |
||||
} |
||||
|
||||
void sym_set_changed(struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
|
||||
sym->flags |= SYMBOL_CHANGED; |
||||
for (prop = sym->prop; prop; prop = prop->next) { |
||||
if (prop->menu) |
||||
prop->menu->flags |= MENU_CHANGED; |
||||
} |
||||
} |
||||
|
||||
void sym_set_all_changed(void) |
||||
{ |
||||
struct symbol *sym; |
||||
int i; |
||||
|
||||
for_all_symbols(i, sym) |
||||
sym_set_changed(sym); |
||||
} |
||||
|
||||
bool sym_tristate_within_range(struct symbol *sym, tristate val) |
||||
{ |
||||
int type = sym_get_type(sym); |
||||
|
||||
if (sym->visible == no) |
||||
return false; |
||||
|
||||
if (type != S_BOOLEAN && type != S_TRISTATE) |
||||
return false; |
||||
|
||||
if (type == S_BOOLEAN && val == mod) |
||||
return false; |
||||
if (sym->visible <= sym->rev_dep.tri) |
||||
return false; |
||||
if (sym_is_choice_value(sym) && sym->visible == yes) |
||||
return val == yes; |
||||
return val >= sym->rev_dep.tri && val <= sym->visible; |
||||
} |
||||
|
||||
bool sym_set_tristate_value(struct symbol *sym, tristate val) |
||||
{ |
||||
tristate oldval = sym_get_tristate_value(sym); |
||||
|
||||
if (oldval != val && !sym_tristate_within_range(sym, val)) |
||||
return false; |
||||
|
||||
if (sym->flags & SYMBOL_NEW) { |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
sym_set_changed(sym); |
||||
} |
||||
/*
|
||||
* setting a choice value also resets the new flag of the choice |
||||
* symbol and all other choice values. |
||||
*/ |
||||
if (sym_is_choice_value(sym) && val == yes) { |
||||
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); |
||||
struct property *prop; |
||||
struct expr *e; |
||||
|
||||
cs->user.val = sym; |
||||
cs->flags &= ~SYMBOL_NEW; |
||||
prop = sym_get_choice_prop(cs); |
||||
for (e = prop->expr; e; e = e->left.expr) { |
||||
if (e->right.sym->visible != no) |
||||
e->right.sym->flags &= ~SYMBOL_NEW; |
||||
} |
||||
} |
||||
|
||||
sym->user.tri = val; |
||||
if (oldval != val) { |
||||
sym_clear_all_valid(); |
||||
if (sym == modules_sym) |
||||
sym_set_all_changed(); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
tristate sym_toggle_tristate_value(struct symbol *sym) |
||||
{ |
||||
tristate oldval, newval; |
||||
|
||||
oldval = newval = sym_get_tristate_value(sym); |
||||
do { |
||||
switch (newval) { |
||||
case no: |
||||
newval = mod; |
||||
break; |
||||
case mod: |
||||
newval = yes; |
||||
break; |
||||
case yes: |
||||
newval = no; |
||||
break; |
||||
} |
||||
if (sym_set_tristate_value(sym, newval)) |
||||
break; |
||||
} while (oldval != newval); |
||||
return newval; |
||||
} |
||||
|
||||
bool sym_string_valid(struct symbol *sym, const char *str) |
||||
{ |
||||
signed char ch; |
||||
|
||||
switch (sym->type) { |
||||
case S_STRING: |
||||
return true; |
||||
case S_INT: |
||||
ch = *str++; |
||||
if (ch == '-') |
||||
ch = *str++; |
||||
if (!isdigit(ch)) |
||||
return false; |
||||
if (ch == '0' && *str != 0) |
||||
return false; |
||||
while ((ch = *str++)) { |
||||
if (!isdigit(ch)) |
||||
return false; |
||||
} |
||||
return true; |
||||
case S_HEX: |
||||
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) |
||||
str += 2; |
||||
ch = *str++; |
||||
do { |
||||
if (!isxdigit(ch)) |
||||
return false; |
||||
} while ((ch = *str++)); |
||||
return true; |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
switch (str[0]) { |
||||
case 'y': case 'Y': |
||||
case 'm': case 'M': |
||||
case 'n': case 'N': |
||||
return true; |
||||
} |
||||
return false; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str) |
||||
{ |
||||
struct property *prop; |
||||
int val; |
||||
|
||||
switch (sym->type) { |
||||
case S_STRING: |
||||
return sym_string_valid(sym, str); |
||||
case S_INT: |
||||
if (!sym_string_valid(sym, str)) |
||||
return false; |
||||
prop = sym_get_range_prop(sym); |
||||
if (!prop) |
||||
return true; |
||||
val = strtol(str, NULL, 10); |
||||
return val >= sym_get_range_val(prop->expr->left.sym, 10) && |
||||
val <= sym_get_range_val(prop->expr->right.sym, 10); |
||||
case S_HEX: |
||||
if (!sym_string_valid(sym, str)) |
||||
return false; |
||||
prop = sym_get_range_prop(sym); |
||||
if (!prop) |
||||
return true; |
||||
val = strtol(str, NULL, 16); |
||||
return val >= sym_get_range_val(prop->expr->left.sym, 16) && |
||||
val <= sym_get_range_val(prop->expr->right.sym, 16); |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
switch (str[0]) { |
||||
case 'y': case 'Y': |
||||
return sym_tristate_within_range(sym, yes); |
||||
case 'm': case 'M': |
||||
return sym_tristate_within_range(sym, mod); |
||||
case 'n': case 'N': |
||||
return sym_tristate_within_range(sym, no); |
||||
} |
||||
return false; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool sym_set_string_value(struct symbol *sym, const char *newval) |
||||
{ |
||||
const char *oldval; |
||||
char *val; |
||||
int size; |
||||
|
||||
switch (sym->type) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
switch (newval[0]) { |
||||
case 'y': case 'Y': |
||||
return sym_set_tristate_value(sym, yes); |
||||
case 'm': case 'M': |
||||
return sym_set_tristate_value(sym, mod); |
||||
case 'n': case 'N': |
||||
return sym_set_tristate_value(sym, no); |
||||
} |
||||
return false; |
||||
default: |
||||
; |
||||
} |
||||
|
||||
if (!sym_string_within_range(sym, newval)) |
||||
return false; |
||||
|
||||
if (sym->flags & SYMBOL_NEW) { |
||||
sym->flags &= ~SYMBOL_NEW; |
||||
sym_set_changed(sym); |
||||
} |
||||
|
||||
oldval = sym->user.val; |
||||
size = strlen(newval) + 1; |
||||
if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { |
||||
size += 2; |
||||
sym->user.val = val = malloc(size); |
||||
*val++ = '0'; |
||||
*val++ = 'x'; |
||||
} else if (!oldval || strcmp(oldval, newval)) |
||||
sym->user.val = val = malloc(size); |
||||
else |
||||
return true; |
||||
|
||||
strcpy(val, newval); |
||||
free((void *)oldval); |
||||
sym_clear_all_valid(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
const char *sym_get_string_value(struct symbol *sym) |
||||
{ |
||||
tristate val; |
||||
|
||||
switch (sym->type) { |
||||
case S_BOOLEAN: |
||||
case S_TRISTATE: |
||||
val = sym_get_tristate_value(sym); |
||||
switch (val) { |
||||
case no: |
||||
return "n"; |
||||
case mod: |
||||
return "m"; |
||||
case yes: |
||||
return "y"; |
||||
} |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
return (const char *)sym->curr.val; |
||||
} |
||||
|
||||
bool sym_is_changable(struct symbol *sym) |
||||
{ |
||||
return sym->visible > sym->rev_dep.tri; |
||||
} |
||||
|
||||
struct symbol *sym_lookup(const char *name, int isconst) |
||||
{ |
||||
struct symbol *symbol; |
||||
const char *ptr; |
||||
char *new_name; |
||||
int hash = 0; |
||||
|
||||
if (name) { |
||||
if (name[0] && !name[1]) { |
||||
switch (name[0]) { |
||||
case 'y': return &symbol_yes; |
||||
case 'm': return &symbol_mod; |
||||
case 'n': return &symbol_no; |
||||
} |
||||
} |
||||
for (ptr = name; *ptr; ptr++) |
||||
hash += *ptr; |
||||
hash &= 0xff; |
||||
|
||||
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
||||
if (!strcmp(symbol->name, name)) { |
||||
if ((isconst && symbol->flags & SYMBOL_CONST) || |
||||
(!isconst && !(symbol->flags & SYMBOL_CONST))) |
||||
return symbol; |
||||
} |
||||
} |
||||
new_name = strdup(name); |
||||
} else { |
||||
new_name = NULL; |
||||
hash = 256; |
||||
} |
||||
|
||||
symbol = malloc(sizeof(*symbol)); |
||||
memset(symbol, 0, sizeof(*symbol)); |
||||
symbol->name = new_name; |
||||
symbol->type = S_UNKNOWN; |
||||
symbol->flags = SYMBOL_NEW; |
||||
if (isconst) |
||||
symbol->flags |= SYMBOL_CONST; |
||||
|
||||
symbol->next = symbol_hash[hash]; |
||||
symbol_hash[hash] = symbol; |
||||
|
||||
return symbol; |
||||
} |
||||
|
||||
struct symbol *sym_find(const char *name) |
||||
{ |
||||
struct symbol *symbol = NULL; |
||||
const char *ptr; |
||||
int hash = 0; |
||||
|
||||
if (!name) |
||||
return NULL; |
||||
|
||||
if (name[0] && !name[1]) { |
||||
switch (name[0]) { |
||||
case 'y': return &symbol_yes; |
||||
case 'm': return &symbol_mod; |
||||
case 'n': return &symbol_no; |
||||
} |
||||
} |
||||
for (ptr = name; *ptr; ptr++) |
||||
hash += *ptr; |
||||
hash &= 0xff; |
||||
|
||||
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
||||
if (!strcmp(symbol->name, name) && |
||||
!(symbol->flags & SYMBOL_CONST)) |
||||
break; |
||||
} |
||||
|
||||
return symbol; |
||||
} |
||||
|
||||
struct symbol **sym_re_search(const char *pattern) |
||||
{ |
||||
struct symbol *sym, **sym_arr = NULL; |
||||
int i, cnt, size; |
||||
regex_t re; |
||||
|
||||
cnt = size = 0; |
||||
/* Skip if empty */ |
||||
if (strlen(pattern) == 0) |
||||
return NULL; |
||||
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) |
||||
return NULL; |
||||
|
||||
for_all_symbols(i, sym) { |
||||
if (sym->flags & SYMBOL_CONST || !sym->name) |
||||
continue; |
||||
if (regexec(&re, sym->name, 0, NULL, 0)) |
||||
continue; |
||||
if (cnt + 1 >= size) { |
||||
void *tmp = sym_arr; |
||||
size += 16; |
||||
sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); |
||||
if (!sym_arr) { |
||||
free(tmp); |
||||
return NULL; |
||||
} |
||||
} |
||||
sym_arr[cnt++] = sym; |
||||
} |
||||
if (sym_arr) |
||||
sym_arr[cnt] = NULL; |
||||
regfree(&re); |
||||
|
||||
return sym_arr; |
||||
} |
||||
|
||||
|
||||
struct symbol *sym_check_deps(struct symbol *sym); |
||||
|
||||
static struct symbol *sym_check_expr_deps(struct expr *e) |
||||
{ |
||||
struct symbol *sym; |
||||
|
||||
if (!e) |
||||
return NULL; |
||||
switch (e->type) { |
||||
case E_OR: |
||||
case E_AND: |
||||
sym = sym_check_expr_deps(e->left.expr); |
||||
if (sym) |
||||
return sym; |
||||
return sym_check_expr_deps(e->right.expr); |
||||
case E_NOT: |
||||
return sym_check_expr_deps(e->left.expr); |
||||
case E_EQUAL: |
||||
case E_UNEQUAL: |
||||
sym = sym_check_deps(e->left.sym); |
||||
if (sym) |
||||
return sym; |
||||
return sym_check_deps(e->right.sym); |
||||
case E_SYMBOL: |
||||
return sym_check_deps(e->left.sym); |
||||
default: |
||||
break; |
||||
} |
||||
printf("Oops! How to check %d?\n", e->type); |
||||
return NULL; |
||||
} |
||||
|
||||
struct symbol *sym_check_deps(struct symbol *sym) |
||||
{ |
||||
struct symbol *sym2; |
||||
struct property *prop; |
||||
|
||||
if (sym->flags & SYMBOL_CHECK) { |
||||
printf("Warning! Found recursive dependency: %s", sym->name); |
||||
return sym; |
||||
} |
||||
if (sym->flags & SYMBOL_CHECKED) |
||||
return NULL; |
||||
|
||||
sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
||||
sym2 = sym_check_expr_deps(sym->rev_dep.expr); |
||||
if (sym2) |
||||
goto out; |
||||
|
||||
for (prop = sym->prop; prop; prop = prop->next) { |
||||
if (prop->type == P_CHOICE || prop->type == P_SELECT) |
||||
continue; |
||||
sym2 = sym_check_expr_deps(prop->visible.expr); |
||||
if (sym2) |
||||
goto out; |
||||
if (prop->type != P_DEFAULT || sym_is_choice(sym)) |
||||
continue; |
||||
sym2 = sym_check_expr_deps(prop->expr); |
||||
if (sym2) |
||||
goto out; |
||||
} |
||||
out: |
||||
if (sym2) { |
||||
printf(" %s", sym->name); |
||||
if (sym2 == sym) { |
||||
printf("\n"); |
||||
sym2 = NULL; |
||||
} |
||||
} |
||||
sym->flags &= ~SYMBOL_CHECK; |
||||
return sym2; |
||||
} |
||||
|
||||
struct property *prop_alloc(enum prop_type type, struct symbol *sym) |
||||
{ |
||||
struct property *prop; |
||||
struct property **propp; |
||||
|
||||
prop = malloc(sizeof(*prop)); |
||||
memset(prop, 0, sizeof(*prop)); |
||||
prop->type = type; |
||||
prop->sym = sym; |
||||
prop->file = current_file; |
||||
prop->lineno = zconf_lineno(); |
||||
|
||||
/* append property to the prop list of symbol */ |
||||
if (sym) { |
||||
for (propp = &sym->prop; *propp; propp = &(*propp)->next) |
||||
; |
||||
*propp = prop; |
||||
} |
||||
|
||||
return prop; |
||||
} |
||||
|
||||
struct symbol *prop_get_symbol(struct property *prop) |
||||
{ |
||||
if (prop->expr && (prop->expr->type == E_SYMBOL || |
||||
prop->expr->type == E_CHOICE)) |
||||
return prop->expr->left.sym; |
||||
return NULL; |
||||
} |
||||
|
||||
const char *prop_get_type_name(enum prop_type type) |
||||
{ |
||||
switch (type) { |
||||
case P_PROMPT: |
||||
return "prompt"; |
||||
case P_COMMENT: |
||||
return "comment"; |
||||
case P_MENU: |
||||
return "menu"; |
||||
case P_DEFAULT: |
||||
return "default"; |
||||
case P_CHOICE: |
||||
return "choice"; |
||||
case P_SELECT: |
||||
return "select"; |
||||
case P_RANGE: |
||||
return "range"; |
||||
case P_UNKNOWN: |
||||
break; |
||||
} |
||||
return "unknown"; |
||||
} |
@ -0,0 +1,109 @@ |
||||
/*
|
||||
* Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org> |
||||
* Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org> |
||||
* |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include "lkc.h" |
||||
|
||||
/* file already present in list? If not add it */ |
||||
struct file *file_lookup(const char *name) |
||||
{ |
||||
struct file *file; |
||||
|
||||
for (file = file_list; file; file = file->next) { |
||||
if (!strcmp(name, file->name)) |
||||
return file; |
||||
} |
||||
|
||||
file = malloc(sizeof(*file)); |
||||
memset(file, 0, sizeof(*file)); |
||||
file->name = strdup(name); |
||||
file->next = file_list; |
||||
file_list = file; |
||||
return file; |
||||
} |
||||
|
||||
/* write a dependency file as used by kbuild to track dependencies */ |
||||
int file_write_dep(const char *name) |
||||
{ |
||||
struct file *file; |
||||
FILE *out; |
||||
|
||||
if (!name) |
||||
name = ".kconfig.d"; |
||||
out = fopen("..config.tmp", "w"); |
||||
if (!out) |
||||
return 1; |
||||
fprintf(out, "deps_config := \\\n"); |
||||
for (file = file_list; file; file = file->next) { |
||||
if (file->next) |
||||
fprintf(out, "\t%s \\\n", file->name); |
||||
else |
||||
fprintf(out, "\t%s\n", file->name); |
||||
} |
||||
fprintf(out, "\n.config include/linux/autoconf.h: $(deps_config)\n\n$(deps_config):\n"); |
||||
fclose(out); |
||||
rename("..config.tmp", name); |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/* Allocate initial growable sting */ |
||||
struct gstr str_new(void) |
||||
{ |
||||
struct gstr gs; |
||||
gs.s = malloc(sizeof(char) * 64); |
||||
gs.len = 16; |
||||
strcpy(gs.s, "\0"); |
||||
return gs; |
||||
} |
||||
|
||||
/* Allocate and assign growable string */ |
||||
struct gstr str_assign(const char *s) |
||||
{ |
||||
struct gstr gs; |
||||
gs.s = strdup(s); |
||||
gs.len = strlen(s) + 1; |
||||
return gs; |
||||
} |
||||
|
||||
/* Free storage for growable string */ |
||||
void str_free(struct gstr *gs) |
||||
{ |
||||
if (gs->s) |
||||
free(gs->s); |
||||
gs->s = NULL; |
||||
gs->len = 0; |
||||
} |
||||
|
||||
/* Append to growable string */ |
||||
void str_append(struct gstr *gs, const char *s) |
||||
{ |
||||
size_t l = strlen(gs->s) + strlen(s) + 1; |
||||
if (l > gs->len) { |
||||
gs->s = realloc(gs->s, l); |
||||
gs->len = l; |
||||
} |
||||
strcat(gs->s, s); |
||||
} |
||||
|
||||
/* Append printf formatted string to growable string */ |
||||
void str_printf(struct gstr *gs, const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
char s[10000]; /* big enough... */ |
||||
va_start(ap, fmt); |
||||
vsnprintf(s, sizeof(s), fmt, ap); |
||||
str_append(gs, s); |
||||
va_end(ap); |
||||
} |
||||
|
||||
/* Retrieve value of growable string */ |
||||
const char *str_get(struct gstr *gs) |
||||
{ |
||||
return gs->s; |
||||
} |
||||
|
@ -0,0 +1,43 @@ |
||||
%language=ANSI-C |
||||
%define hash-function-name kconf_id_hash |
||||
%define lookup-function-name kconf_id_lookup |
||||
%define string-pool-name kconf_id_strings |
||||
%compare-strncmp |
||||
%enum |
||||
%pic |
||||
%struct-type |
||||
|
||||
struct kconf_id; |
||||
|
||||
%% |
||||
mainmenu, T_MAINMENU, TF_COMMAND |
||||
menu, T_MENU, TF_COMMAND |
||||
endmenu, T_ENDMENU, TF_COMMAND |
||||
source, T_SOURCE, TF_COMMAND |
||||
choice, T_CHOICE, TF_COMMAND |
||||
endchoice, T_ENDCHOICE, TF_COMMAND |
||||
comment, T_COMMENT, TF_COMMAND |
||||
config, T_CONFIG, TF_COMMAND |
||||
menuconfig, T_MENUCONFIG, TF_COMMAND |
||||
help, T_HELP, TF_COMMAND |
||||
if, T_IF, TF_COMMAND|TF_PARAM |
||||
endif, T_ENDIF, TF_COMMAND |
||||
depends, T_DEPENDS, TF_COMMAND |
||||
requires, T_REQUIRES, TF_COMMAND |
||||
optional, T_OPTIONAL, TF_COMMAND |
||||
default, T_DEFAULT, TF_COMMAND, S_UNKNOWN |
||||
prompt, T_PROMPT, TF_COMMAND |
||||
tristate, T_TYPE, TF_COMMAND, S_TRISTATE |
||||
def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE |
||||
bool, T_TYPE, TF_COMMAND, S_BOOLEAN |
||||
boolean, T_TYPE, TF_COMMAND, S_BOOLEAN |
||||
def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN |
||||
def_boolean, T_DEFAULT, TF_COMMAND, S_BOOLEAN |
||||
int, T_TYPE, TF_COMMAND, S_INT |
||||
hex, T_TYPE, TF_COMMAND, S_HEX |
||||
string, T_TYPE, TF_COMMAND, S_STRING |
||||
select, T_SELECT, TF_COMMAND |
||||
enable, T_SELECT, TF_COMMAND |
||||
range, T_RANGE, TF_COMMAND |
||||
on, T_ON, TF_PARAM |
||||
%% |
@ -0,0 +1,231 @@ |
||||
/* ANSI-C code produced by gperf version 3.0.1 */ |
||||
/* Command-line: gperf */ |
||||
/* Computed positions: -k'1,3' */ |
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ |
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ |
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ |
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ |
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ |
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ |
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ |
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ |
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ |
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ |
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ |
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ |
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ |
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ |
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ |
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ |
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ |
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ |
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ |
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ |
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ |
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ |
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) |
||||
/* The character set is not based on ISO-646. */ |
||||
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." |
||||
#endif |
||||
|
||||
struct kconf_id; |
||||
/* maximum key range = 45, duplicates = 0 */ |
||||
|
||||
#ifdef __GNUC__ |
||||
__inline |
||||
#else |
||||
#ifdef __cplusplus |
||||
inline |
||||
#endif |
||||
#endif |
||||
static unsigned int |
||||
kconf_id_hash (register const char *str, register unsigned int len) |
||||
{ |
||||
static unsigned char asso_values[] = |
||||
{ |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 25, 10, 15, |
||||
0, 0, 5, 47, 0, 0, 47, 47, 0, 10, |
||||
0, 20, 20, 20, 5, 0, 0, 20, 47, 47, |
||||
20, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, |
||||
47, 47, 47, 47, 47, 47 |
||||
}; |
||||
register int hval = len; |
||||
|
||||
switch (hval) |
||||
{ |
||||
default: |
||||
hval += asso_values[(unsigned char)str[2]]; |
||||
/*FALLTHROUGH*/ |
||||
case 2: |
||||
case 1: |
||||
hval += asso_values[(unsigned char)str[0]]; |
||||
break; |
||||
} |
||||
return hval; |
||||
} |
||||
|
||||
struct kconf_id_strings_t |
||||
{ |
||||
char kconf_id_strings_str2[sizeof("if")]; |
||||
char kconf_id_strings_str3[sizeof("int")]; |
||||
char kconf_id_strings_str4[sizeof("help")]; |
||||
char kconf_id_strings_str5[sizeof("endif")]; |
||||
char kconf_id_strings_str6[sizeof("select")]; |
||||
char kconf_id_strings_str7[sizeof("endmenu")]; |
||||
char kconf_id_strings_str8[sizeof("tristate")]; |
||||
char kconf_id_strings_str9[sizeof("endchoice")]; |
||||
char kconf_id_strings_str10[sizeof("range")]; |
||||
char kconf_id_strings_str11[sizeof("string")]; |
||||
char kconf_id_strings_str12[sizeof("default")]; |
||||
char kconf_id_strings_str13[sizeof("def_bool")]; |
||||
char kconf_id_strings_str14[sizeof("menu")]; |
||||
char kconf_id_strings_str16[sizeof("def_boolean")]; |
||||
char kconf_id_strings_str17[sizeof("def_tristate")]; |
||||
char kconf_id_strings_str18[sizeof("mainmenu")]; |
||||
char kconf_id_strings_str20[sizeof("menuconfig")]; |
||||
char kconf_id_strings_str21[sizeof("config")]; |
||||
char kconf_id_strings_str22[sizeof("on")]; |
||||
char kconf_id_strings_str23[sizeof("hex")]; |
||||
char kconf_id_strings_str26[sizeof("source")]; |
||||
char kconf_id_strings_str27[sizeof("depends")]; |
||||
char kconf_id_strings_str28[sizeof("optional")]; |
||||
char kconf_id_strings_str31[sizeof("enable")]; |
||||
char kconf_id_strings_str32[sizeof("comment")]; |
||||
char kconf_id_strings_str33[sizeof("requires")]; |
||||
char kconf_id_strings_str34[sizeof("bool")]; |
||||
char kconf_id_strings_str37[sizeof("boolean")]; |
||||
char kconf_id_strings_str41[sizeof("choice")]; |
||||
char kconf_id_strings_str46[sizeof("prompt")]; |
||||
}; |
||||
static struct kconf_id_strings_t kconf_id_strings_contents = |
||||
{ |
||||
"if", |
||||
"int", |
||||
"help", |
||||
"endif", |
||||
"select", |
||||
"endmenu", |
||||
"tristate", |
||||
"endchoice", |
||||
"range", |
||||
"string", |
||||
"default", |
||||
"def_bool", |
||||
"menu", |
||||
"def_boolean", |
||||
"def_tristate", |
||||
"mainmenu", |
||||
"menuconfig", |
||||
"config", |
||||
"on", |
||||
"hex", |
||||
"source", |
||||
"depends", |
||||
"optional", |
||||
"enable", |
||||
"comment", |
||||
"requires", |
||||
"bool", |
||||
"boolean", |
||||
"choice", |
||||
"prompt" |
||||
}; |
||||
#define kconf_id_strings ((const char *) &kconf_id_strings_contents) |
||||
#ifdef __GNUC__ |
||||
__inline |
||||
#endif |
||||
struct kconf_id * |
||||
kconf_id_lookup (register const char *str, register unsigned int len) |
||||
{ |
||||
enum |
||||
{ |
||||
TOTAL_KEYWORDS = 30, |
||||
MIN_WORD_LENGTH = 2, |
||||
MAX_WORD_LENGTH = 12, |
||||
MIN_HASH_VALUE = 2, |
||||
MAX_HASH_VALUE = 46 |
||||
}; |
||||
|
||||
static struct kconf_id wordlist[] = |
||||
{ |
||||
{-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND}, |
||||
{-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND}, |
||||
{-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX}, |
||||
{-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND}, |
||||
{-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN}, |
||||
{-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN}, |
||||
{-1}, {-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND}, |
||||
{-1}, {-1}, {-1}, {-1}, |
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND} |
||||
}; |
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) |
||||
{ |
||||
register int key = kconf_id_hash (str, len); |
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0) |
||||
{ |
||||
register int o = wordlist[key].name; |
||||
if (o >= 0) |
||||
{ |
||||
register const char *s = o + kconf_id_strings; |
||||
|
||||
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') |
||||
return &wordlist[key]; |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
@ -0,0 +1,350 @@ |
||||
%option backup nostdinit noyywrap never-interactive full ecs |
||||
%option 8bit backup nodefault perf-report perf-report |
||||
%x COMMAND HELP STRING PARAM |
||||
%{ |
||||
/* |
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <limits.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#define LKC_DIRECT_LINK |
||||
#include "lkc.h" |
||||
|
||||
#define START_STRSIZE 16 |
||||
|
||||
static struct { |
||||
struct file *file; |
||||
int lineno; |
||||
} current_pos; |
||||
|
||||
static char *text; |
||||
static int text_size, text_asize; |
||||
|
||||
struct buffer { |
||||
struct buffer *parent; |
||||
YY_BUFFER_STATE state; |
||||
}; |
||||
|
||||
struct buffer *current_buf; |
||||
|
||||
static int last_ts, first_ts; |
||||
|
||||
static void zconf_endhelp(void); |
||||
static void zconf_endfile(void); |
||||
|
||||
void new_string(void) |
||||
{ |
||||
text = malloc(START_STRSIZE); |
||||
text_asize = START_STRSIZE; |
||||
text_size = 0; |
||||
*text = 0; |
||||
} |
||||
|
||||
void append_string(const char *str, int size) |
||||
{ |
||||
int new_size = text_size + size + 1; |
||||
if (new_size > text_asize) { |
||||
new_size += START_STRSIZE - 1; |
||||
new_size &= -START_STRSIZE; |
||||
text = realloc(text, new_size); |
||||
text_asize = new_size; |
||||
} |
||||
memcpy(text + text_size, str, size); |
||||
text_size += size; |
||||
text[text_size] = 0; |
||||
} |
||||
|
||||
void alloc_string(const char *str, int size) |
||||
{ |
||||
text = malloc(size + 1); |
||||
memcpy(text, str, size); |
||||
text[size] = 0; |
||||
} |
||||
%} |
||||
|
||||
ws [ \n\t] |
||||
n [A-Za-z0-9_] |
||||
|
||||
%% |
||||
int str = 0; |
||||
int ts, i; |
||||
|
||||
[ \t]*#.*\n | |
||||
[ \t]*\n { |
||||
current_file->lineno++; |
||||
return T_EOL; |
||||
} |
||||
[ \t]*#.* |
||||
|
||||
|
||||
[ \t]+ { |
||||
BEGIN(COMMAND); |
||||
} |
||||
|
||||
. { |
||||
unput(yytext[0]); |
||||
BEGIN(COMMAND); |
||||
} |
||||
|
||||
|
||||
<COMMAND>{ |
||||
{n}+ { |
||||
struct kconf_id *id = kconf_id_lookup(yytext, yyleng); |
||||
BEGIN(PARAM); |
||||
current_pos.file = current_file; |
||||
current_pos.lineno = current_file->lineno; |
||||
if (id && id->flags & TF_COMMAND) { |
||||
zconflval.id = id; |
||||
return id->token; |
||||
} |
||||
alloc_string(yytext, yyleng); |
||||
zconflval.string = text; |
||||
return T_WORD; |
||||
} |
||||
. |
||||
\n { |
||||
BEGIN(INITIAL); |
||||
current_file->lineno++; |
||||
return T_EOL; |
||||
} |
||||
} |
||||
|
||||
<PARAM>{ |
||||
"&&" return T_AND; |
||||
"||" return T_OR; |
||||
"(" return T_OPEN_PAREN; |
||||
")" return T_CLOSE_PAREN; |
||||
"!" return T_NOT; |
||||
"=" return T_EQUAL; |
||||
"!=" return T_UNEQUAL; |
||||
\"|\' { |
||||
str = yytext[0]; |
||||
new_string(); |
||||
BEGIN(STRING); |
||||
} |
||||
\n BEGIN(INITIAL); current_file->lineno++; return T_EOL; |
||||
--- /* ignore */ |
||||
({n}|[-/.])+ { |
||||
struct kconf_id *id = kconf_id_lookup(yytext, yyleng); |
||||
if (id && id->flags & TF_PARAM) { |
||||
zconflval.id = id; |
||||
return id->token; |
||||
} |
||||
alloc_string(yytext, yyleng); |
||||
zconflval.string = text; |
||||
return T_WORD; |
||||
} |
||||
#.* /* comment */ |
||||
\\\n current_file->lineno++; |
||||
. |
||||
<<EOF>> { |
||||
BEGIN(INITIAL); |
||||
} |
||||
} |
||||
|
||||
<STRING>{ |
||||
[^'"\\\n]+/\n { |
||||
append_string(yytext, yyleng); |
||||
zconflval.string = text; |
||||
return T_WORD_QUOTE; |
||||
} |
||||
[^'"\\\n]+ { |
||||
append_string(yytext, yyleng); |
||||
} |
||||
\\.?/\n { |
||||
append_string(yytext + 1, yyleng - 1); |
||||
zconflval.string = text; |
||||
return T_WORD_QUOTE; |
||||
} |
||||
\\.? { |
||||
append_string(yytext + 1, yyleng - 1); |
||||
} |
||||
\'|\" { |
||||
if (str == yytext[0]) { |
||||
BEGIN(PARAM); |
||||
zconflval.string = text; |
||||
return T_WORD_QUOTE; |
||||
} else |
||||
append_string(yytext, 1); |
||||
} |
||||
\n { |
||||
printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); |
||||
current_file->lineno++; |
||||
BEGIN(INITIAL); |
||||
return T_EOL; |
||||
} |
||||
<<EOF>> { |
||||
BEGIN(INITIAL); |
||||
} |
||||
} |
||||
|
||||
<HELP>{ |
||||
[ \t]+ { |
||||
ts = 0; |
||||
for (i = 0; i < yyleng; i++) { |
||||
if (yytext[i] == '\t') |
||||
ts = (ts & ~7) + 8; |
||||
else |
||||
ts++; |
||||
} |
||||
last_ts = ts; |
||||
if (first_ts) { |
||||
if (ts < first_ts) { |
||||
zconf_endhelp(); |
||||
return T_HELPTEXT; |
||||
} |
||||
ts -= first_ts; |
||||
while (ts > 8) { |
||||
append_string(" ", 8); |
||||
ts -= 8; |
||||
} |
||||
append_string(" ", ts); |
||||
} |
||||
} |
||||
[ \t]*\n/[^ \t\n] { |
||||
current_file->lineno++; |
||||
zconf_endhelp(); |
||||
return T_HELPTEXT; |
||||
} |
||||
[ \t]*\n { |
||||
current_file->lineno++; |
||||
append_string("\n", 1); |
||||
} |
||||
[^ \t\n].* { |
||||
append_string(yytext, yyleng); |
||||
if (!first_ts) |
||||
first_ts = last_ts; |
||||
} |
||||
<<EOF>> { |
||||
zconf_endhelp(); |
||||
return T_HELPTEXT; |
||||
} |
||||
} |
||||
|
||||
<<EOF>> { |
||||
if (current_file) { |
||||
zconf_endfile(); |
||||
return T_EOL; |
||||
} |
||||
fclose(yyin); |
||||
yyterminate(); |
||||
} |
||||
|
||||
%% |
||||
void zconf_starthelp(void) |
||||
{ |
||||
new_string(); |
||||
last_ts = first_ts = 0; |
||||
BEGIN(HELP); |
||||
} |
||||
|
||||
static void zconf_endhelp(void) |
||||
{ |
||||
zconflval.string = text; |
||||
BEGIN(INITIAL); |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Try to open specified file with following names: |
||||
* ./name |
||||
* $(srctree)/name |
||||
* The latter is used when srctree is separate from objtree |
||||
* when compiling the kernel. |
||||
* Return NULL if file is not found. |
||||
*/ |
||||
FILE *zconf_fopen(const char *name) |
||||
{ |
||||
char *env, fullname[PATH_MAX+1]; |
||||
FILE *f; |
||||
|
||||
f = fopen(name, "r"); |
||||
if (!f && name[0] != '/') { |
||||
env = getenv(SRCTREE); |
||||
if (env) { |
||||
sprintf(fullname, "%s/%s", env, name); |
||||
f = fopen(fullname, "r"); |
||||
} |
||||
} |
||||
return f; |
||||
} |
||||
|
||||
void zconf_initscan(const char *name) |
||||
{ |
||||
yyin = zconf_fopen(name); |
||||
if (!yyin) { |
||||
printf("can't find file %s\n", name); |
||||
exit(1); |
||||
} |
||||
|
||||
current_buf = malloc(sizeof(*current_buf)); |
||||
memset(current_buf, 0, sizeof(*current_buf)); |
||||
|
||||
current_file = file_lookup(name); |
||||
current_file->lineno = 1; |
||||
current_file->flags = FILE_BUSY; |
||||
} |
||||
|
||||
void zconf_nextfile(const char *name) |
||||
{ |
||||
struct file *file = file_lookup(name); |
||||
struct buffer *buf = malloc(sizeof(*buf)); |
||||
memset(buf, 0, sizeof(*buf)); |
||||
|
||||
current_buf->state = YY_CURRENT_BUFFER; |
||||
yyin = zconf_fopen(name); |
||||
if (!yyin) { |
||||
printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); |
||||
exit(1); |
||||
} |
||||
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); |
||||
buf->parent = current_buf; |
||||
current_buf = buf; |
||||
|
||||
if (file->flags & FILE_BUSY) { |
||||
printf("recursive scan (%s)?\n", name); |
||||
exit(1); |
||||
} |
||||
if (file->flags & FILE_SCANNED) { |
||||
printf("file %s already scanned?\n", name); |
||||
exit(1); |
||||
} |
||||
file->flags |= FILE_BUSY; |
||||
file->lineno = 1; |
||||
file->parent = current_file; |
||||
current_file = file; |
||||
} |
||||
|
||||
static void zconf_endfile(void) |
||||
{ |
||||
struct buffer *parent; |
||||
|
||||
current_file->flags |= FILE_SCANNED; |
||||
current_file->flags &= ~FILE_BUSY; |
||||
current_file = current_file->parent; |
||||
|
||||
parent = current_buf->parent; |
||||
if (parent) { |
||||
fclose(yyin); |
||||
yy_delete_buffer(YY_CURRENT_BUFFER); |
||||
yy_switch_to_buffer(parent->state); |
||||
} |
||||
free(current_buf); |
||||
current_buf = parent; |
||||
} |
||||
|
||||
int zconf_lineno(void) |
||||
{ |
||||
return current_pos.lineno; |
||||
} |
||||
|
||||
char *zconf_curname(void) |
||||
{ |
||||
return current_pos.file ? current_pos.file->name : "<none>"; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,681 @@ |
||||
%{ |
||||
/* |
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <ctype.h> |
||||
#include <stdarg.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdbool.h> |
||||
|
||||
#define LKC_DIRECT_LINK |
||||
#include "lkc.h" |
||||
|
||||
#include "zconf.hash.c" |
||||
|
||||
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) |
||||
|
||||
#define PRINTD 0x0001 |
||||
#define DEBUG_PARSE 0x0002 |
||||
|
||||
int cdebug = PRINTD; |
||||
|
||||
extern int zconflex(void); |
||||
static void zconfprint(const char *err, ...); |
||||
static void zconf_error(const char *err, ...); |
||||
static void zconferror(const char *err); |
||||
static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); |
||||
|
||||
struct symbol *symbol_hash[257]; |
||||
|
||||
static struct menu *current_menu, *current_entry; |
||||
|
||||
#define YYDEBUG 0 |
||||
#if YYDEBUG |
||||
#define YYERROR_VERBOSE |
||||
#endif |
||||
%} |
||||
%expect 26 |
||||
|
||||
%union |
||||
{ |
||||
char *string; |
||||
struct file *file; |
||||
struct symbol *symbol; |
||||
struct expr *expr; |
||||
struct menu *menu; |
||||
struct kconf_id *id; |
||||
} |
||||
|
||||
%token <id>T_MAINMENU |
||||
%token <id>T_MENU |
||||
%token <id>T_ENDMENU |
||||
%token <id>T_SOURCE |
||||
%token <id>T_CHOICE |
||||
%token <id>T_ENDCHOICE |
||||
%token <id>T_COMMENT |
||||
%token <id>T_CONFIG |
||||
%token <id>T_MENUCONFIG |
||||
%token <id>T_HELP |
||||
%token <string> T_HELPTEXT |
||||
%token <id>T_IF |
||||
%token <id>T_ENDIF |
||||
%token <id>T_DEPENDS |
||||
%token <id>T_REQUIRES |
||||
%token <id>T_OPTIONAL |
||||
%token <id>T_PROMPT |
||||
%token <id>T_TYPE |
||||
%token <id>T_DEFAULT |
||||
%token <id>T_SELECT |
||||
%token <id>T_RANGE |
||||
%token <id>T_ON |
||||
%token <string> T_WORD |
||||
%token <string> T_WORD_QUOTE |
||||
%token T_UNEQUAL |
||||
%token T_CLOSE_PAREN |
||||
%token T_OPEN_PAREN |
||||
%token T_EOL |
||||
|
||||
%left T_OR |
||||
%left T_AND |
||||
%left T_EQUAL T_UNEQUAL |
||||
%nonassoc T_NOT |
||||
|
||||
%type <string> prompt |
||||
%type <symbol> symbol |
||||
%type <expr> expr |
||||
%type <expr> if_expr |
||||
%type <id> end |
||||
%type <id> option_name |
||||
%type <menu> if_entry menu_entry choice_entry |
||||
|
||||
%destructor { |
||||
fprintf(stderr, "%s:%d: missing end statement for this entry\n", |
||||
$$->file->name, $$->lineno); |
||||
if (current_menu == $$) |
||||
menu_end_menu(); |
||||
} if_entry menu_entry choice_entry |
||||
|
||||
%% |
||||
input: stmt_list; |
||||
|
||||
stmt_list: |
||||
/* empty */ |
||||
| stmt_list common_stmt |
||||
| stmt_list choice_stmt |
||||
| stmt_list menu_stmt |
||||
| stmt_list T_MAINMENU prompt nl |
||||
| stmt_list end { zconf_error("unexpected end statement"); } |
||||
| stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } |
||||
| stmt_list option_name error T_EOL |
||||
{ |
||||
zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); |
||||
} |
||||
| stmt_list error T_EOL { zconf_error("invalid statement"); } |
||||
; |
||||
|
||||
option_name: |
||||
T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT |
||||
; |
||||
|
||||
common_stmt: |
||||
T_EOL |
||||
| if_stmt |
||||
| comment_stmt |
||||
| config_stmt |
||||
| menuconfig_stmt |
||||
| source_stmt |
||||
; |
||||
|
||||
option_error: |
||||
T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } |
||||
| error T_EOL { zconf_error("invalid option"); } |
||||
; |
||||
|
||||
|
||||
/* config/menuconfig entry */ |
||||
|
||||
config_entry_start: T_CONFIG T_WORD T_EOL |
||||
{ |
||||
struct symbol *sym = sym_lookup($2, 0); |
||||
sym->flags |= SYMBOL_OPTIONAL; |
||||
menu_add_entry(sym); |
||||
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); |
||||
}; |
||||
|
||||
config_stmt: config_entry_start config_option_list |
||||
{ |
||||
menu_end_entry(); |
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL |
||||
{ |
||||
struct symbol *sym = sym_lookup($2, 0); |
||||
sym->flags |= SYMBOL_OPTIONAL; |
||||
menu_add_entry(sym); |
||||
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); |
||||
}; |
||||
|
||||
menuconfig_stmt: menuconfig_entry_start config_option_list |
||||
{ |
||||
if (current_entry->prompt) |
||||
current_entry->prompt->type = P_MENU; |
||||
else |
||||
zconfprint("warning: menuconfig statement without prompt"); |
||||
menu_end_entry(); |
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
config_option_list: |
||||
/* empty */ |
||||
| config_option_list config_option |
||||
| config_option_list depends |
||||
| config_option_list help |
||||
| config_option_list option_error |
||||
| config_option_list T_EOL |
||||
; |
||||
|
||||
config_option: T_TYPE prompt_stmt_opt T_EOL |
||||
{ |
||||
menu_set_type($1->stype); |
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", |
||||
zconf_curname(), zconf_lineno(), |
||||
$1->stype); |
||||
}; |
||||
|
||||
config_option: T_PROMPT prompt if_expr T_EOL |
||||
{ |
||||
menu_add_prompt(P_PROMPT, $2, $3); |
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
config_option: T_DEFAULT expr if_expr T_EOL |
||||
{ |
||||
menu_add_expr(P_DEFAULT, $2, $3); |
||||
if ($1->stype != S_UNKNOWN) |
||||
menu_set_type($1->stype); |
||||
printd(DEBUG_PARSE, "%s:%d:default(%u)\n", |
||||
zconf_curname(), zconf_lineno(), |
||||
$1->stype); |
||||
}; |
||||
|
||||
config_option: T_SELECT T_WORD if_expr T_EOL |
||||
{ |
||||
menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); |
||||
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
config_option: T_RANGE symbol symbol if_expr T_EOL |
||||
{ |
||||
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); |
||||
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
/* choice entry */ |
||||
|
||||
choice: T_CHOICE T_EOL |
||||
{ |
||||
struct symbol *sym = sym_lookup(NULL, 0); |
||||
sym->flags |= SYMBOL_CHOICE; |
||||
menu_add_entry(sym); |
||||
menu_add_expr(P_CHOICE, NULL, NULL); |
||||
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
choice_entry: choice choice_option_list |
||||
{ |
||||
$$ = menu_add_menu(); |
||||
}; |
||||
|
||||
choice_end: end |
||||
{ |
||||
if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { |
||||
menu_end_menu(); |
||||
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); |
||||
} |
||||
}; |
||||
|
||||
choice_stmt: choice_entry choice_block choice_end |
||||
; |
||||
|
||||
choice_option_list: |
||||
/* empty */ |
||||
| choice_option_list choice_option |
||||
| choice_option_list depends |
||||
| choice_option_list help |
||||
| choice_option_list T_EOL |
||||
| choice_option_list option_error |
||||
; |
||||
|
||||
choice_option: T_PROMPT prompt if_expr T_EOL |
||||
{ |
||||
menu_add_prompt(P_PROMPT, $2, $3); |
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
choice_option: T_TYPE prompt_stmt_opt T_EOL |
||||
{ |
||||
if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { |
||||
menu_set_type($1->stype); |
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n", |
||||
zconf_curname(), zconf_lineno(), |
||||
$1->stype); |
||||
} else |
||||
YYERROR; |
||||
}; |
||||
|
||||
choice_option: T_OPTIONAL T_EOL |
||||
{ |
||||
current_entry->sym->flags |= SYMBOL_OPTIONAL; |
||||
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
choice_option: T_DEFAULT T_WORD if_expr T_EOL |
||||
{ |
||||
if ($1->stype == S_UNKNOWN) { |
||||
menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); |
||||
printd(DEBUG_PARSE, "%s:%d:default\n", |
||||
zconf_curname(), zconf_lineno()); |
||||
} else |
||||
YYERROR; |
||||
}; |
||||
|
||||
choice_block: |
||||
/* empty */ |
||||
| choice_block common_stmt |
||||
; |
||||
|
||||
/* if entry */ |
||||
|
||||
if_entry: T_IF expr nl |
||||
{ |
||||
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); |
||||
menu_add_entry(NULL); |
||||
menu_add_dep($2); |
||||
$$ = menu_add_menu(); |
||||
}; |
||||
|
||||
if_end: end |
||||
{ |
||||
if (zconf_endtoken($1, T_IF, T_ENDIF)) { |
||||
menu_end_menu(); |
||||
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); |
||||
} |
||||
}; |
||||
|
||||
if_stmt: if_entry if_block if_end |
||||
; |
||||
|
||||
if_block: |
||||
/* empty */ |
||||
| if_block common_stmt |
||||
| if_block menu_stmt |
||||
| if_block choice_stmt |
||||
; |
||||
|
||||
/* menu entry */ |
||||
|
||||
menu: T_MENU prompt T_EOL |
||||
{ |
||||
menu_add_entry(NULL); |
||||
menu_add_prompt(P_MENU, $2, NULL); |
||||
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
menu_entry: menu depends_list |
||||
{ |
||||
$$ = menu_add_menu(); |
||||
}; |
||||
|
||||
menu_end: end |
||||
{ |
||||
if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { |
||||
menu_end_menu(); |
||||
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); |
||||
} |
||||
}; |
||||
|
||||
menu_stmt: menu_entry menu_block menu_end |
||||
; |
||||
|
||||
menu_block: |
||||
/* empty */ |
||||
| menu_block common_stmt |
||||
| menu_block menu_stmt |
||||
| menu_block choice_stmt |
||||
; |
||||
|
||||
source_stmt: T_SOURCE prompt T_EOL |
||||
{ |
||||
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); |
||||
zconf_nextfile($2); |
||||
}; |
||||
|
||||
/* comment entry */ |
||||
|
||||
comment: T_COMMENT prompt T_EOL |
||||
{ |
||||
menu_add_entry(NULL); |
||||
menu_add_prompt(P_COMMENT, $2, NULL); |
||||
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
comment_stmt: comment depends_list |
||||
{ |
||||
menu_end_entry(); |
||||
}; |
||||
|
||||
/* help option */ |
||||
|
||||
help_start: T_HELP T_EOL |
||||
{ |
||||
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); |
||||
zconf_starthelp(); |
||||
}; |
||||
|
||||
help: help_start T_HELPTEXT |
||||
{ |
||||
current_entry->sym->help = $2; |
||||
}; |
||||
|
||||
/* depends option */ |
||||
|
||||
depends_list: |
||||
/* empty */ |
||||
| depends_list depends |
||||
| depends_list T_EOL |
||||
| depends_list option_error |
||||
; |
||||
|
||||
depends: T_DEPENDS T_ON expr T_EOL |
||||
{ |
||||
menu_add_dep($3); |
||||
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); |
||||
} |
||||
| T_DEPENDS expr T_EOL |
||||
{ |
||||
menu_add_dep($2); |
||||
printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); |
||||
} |
||||
| T_REQUIRES expr T_EOL |
||||
{ |
||||
menu_add_dep($2); |
||||
printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); |
||||
}; |
||||
|
||||
/* prompt statement */ |
||||
|
||||
prompt_stmt_opt: |
||||
/* empty */ |
||||
| prompt if_expr |
||||
{ |
||||
menu_add_prompt(P_PROMPT, $1, $2); |
||||
}; |
||||
|
||||
prompt: T_WORD |
||||
| T_WORD_QUOTE |
||||
; |
||||
|
||||
end: T_ENDMENU T_EOL { $$ = $1; } |
||||
| T_ENDCHOICE T_EOL { $$ = $1; } |
||||
| T_ENDIF T_EOL { $$ = $1; } |
||||
; |
||||
|
||||
nl: |
||||
T_EOL |
||||
| nl T_EOL |
||||
; |
||||
|
||||
if_expr: /* empty */ { $$ = NULL; } |
||||
| T_IF expr { $$ = $2; } |
||||
; |
||||
|
||||
expr: symbol { $$ = expr_alloc_symbol($1); } |
||||
| symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } |
||||
| symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } |
||||
| T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } |
||||
| T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } |
||||
| expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } |
||||
| expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } |
||||
; |
||||
|
||||
symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } |
||||
| T_WORD_QUOTE { $$ = sym_lookup($1, 1); free($1); } |
||||
; |
||||
|
||||
%% |
||||
|
||||
void conf_parse(const char *name) |
||||
{ |
||||
struct symbol *sym; |
||||
int i; |
||||
|
||||
zconf_initscan(name); |
||||
|
||||
sym_init(); |
||||
menu_init(); |
||||
modules_sym = sym_lookup("MODULES", 0); |
||||
rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); |
||||
|
||||
#if YYDEBUG |
||||
if (getenv("ZCONF_DEBUG")) |
||||
zconfdebug = 1; |
||||
#endif |
||||
zconfparse(); |
||||
if (zconfnerrs) |
||||
exit(1); |
||||
menu_finalize(&rootmenu); |
||||
for_all_symbols(i, sym) { |
||||
sym_check_deps(sym); |
||||
} |
||||
|
||||
sym_change_count = 1; |
||||
} |
||||
|
||||
const char *zconf_tokenname(int token) |
||||
{ |
||||
switch (token) { |
||||
case T_MENU: return "menu"; |
||||
case T_ENDMENU: return "endmenu"; |
||||
case T_CHOICE: return "choice"; |
||||
case T_ENDCHOICE: return "endchoice"; |
||||
case T_IF: return "if"; |
||||
case T_ENDIF: return "endif"; |
||||
case T_DEPENDS: return "depends"; |
||||
} |
||||
return "<token>"; |
||||
} |
||||
|
||||
static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) |
||||
{ |
||||
if (id->token != endtoken) { |
||||
zconf_error("unexpected '%s' within %s block", |
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken)); |
||||
zconfnerrs++; |
||||
return false; |
||||
} |
||||
if (current_menu->file != current_file) { |
||||
zconf_error("'%s' in different file than '%s'", |
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken)); |
||||
fprintf(stderr, "%s:%d: location of the '%s'\n", |
||||
current_menu->file->name, current_menu->lineno, |
||||
zconf_tokenname(starttoken)); |
||||
zconfnerrs++; |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static void zconfprint(const char *err, ...) |
||||
{ |
||||
va_list ap; |
||||
|
||||
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); |
||||
va_start(ap, err); |
||||
vfprintf(stderr, err, ap); |
||||
va_end(ap); |
||||
fprintf(stderr, "\n"); |
||||
} |
||||
|
||||
static void zconf_error(const char *err, ...) |
||||
{ |
||||
va_list ap; |
||||
|
||||
zconfnerrs++; |
||||
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); |
||||
va_start(ap, err); |
||||
vfprintf(stderr, err, ap); |
||||
va_end(ap); |
||||
fprintf(stderr, "\n"); |
||||
} |
||||
|
||||
static void zconferror(const char *err) |
||||
{ |
||||
#if YYDEBUG |
||||
fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); |
||||
#endif |
||||
} |
||||
|
||||
void print_quoted_string(FILE *out, const char *str) |
||||
{ |
||||
const char *p; |
||||
int len; |
||||
|
||||
putc('"', out); |
||||
while ((p = strchr(str, '"'))) { |
||||
len = p - str; |
||||
if (len) |
||||
fprintf(out, "%.*s", len, str); |
||||
fputs("\\\"", out); |
||||
str = p + 1; |
||||
} |
||||
fputs(str, out); |
||||
putc('"', out); |
||||
} |
||||
|
||||
void print_symbol(FILE *out, struct menu *menu) |
||||
{ |
||||
struct symbol *sym = menu->sym; |
||||
struct property *prop; |
||||
|
||||
if (sym_is_choice(sym)) |
||||
fprintf(out, "choice\n"); |
||||
else |
||||
fprintf(out, "config %s\n", sym->name); |
||||
switch (sym->type) { |
||||
case S_BOOLEAN: |
||||
fputs(" boolean\n", out); |
||||
break; |
||||
case S_TRISTATE: |
||||
fputs(" tristate\n", out); |
||||
break; |
||||
case S_STRING: |
||||
fputs(" string\n", out); |
||||
break; |
||||
case S_INT: |
||||
fputs(" integer\n", out); |
||||
break; |
||||
case S_HEX: |
||||
fputs(" hex\n", out); |
||||
break; |
||||
default: |
||||
fputs(" ???\n", out); |
||||
break; |
||||
} |
||||
for (prop = sym->prop; prop; prop = prop->next) { |
||||
if (prop->menu != menu) |
||||
continue; |
||||
switch (prop->type) { |
||||
case P_PROMPT: |
||||
fputs(" prompt ", out); |
||||
print_quoted_string(out, prop->text); |
||||
if (!expr_is_yes(prop->visible.expr)) { |
||||
fputs(" if ", out); |
||||
expr_fprint(prop->visible.expr, out); |
||||
} |
||||
fputc('\n', out); |
||||
break; |
||||
case P_DEFAULT: |
||||
fputs( " default ", out); |
||||
expr_fprint(prop->expr, out); |
||||
if (!expr_is_yes(prop->visible.expr)) { |
||||
fputs(" if ", out); |
||||
expr_fprint(prop->visible.expr, out); |
||||
} |
||||
fputc('\n', out); |
||||
break; |
||||
case P_CHOICE: |
||||
fputs(" #choice value\n", out); |
||||
break; |
||||
default: |
||||
fprintf(out, " unknown prop %d!\n", prop->type); |
||||
break; |
||||
} |
||||
} |
||||
if (sym->help) { |
||||
int len = strlen(sym->help); |
||||
while (sym->help[--len] == '\n') |
||||
sym->help[len] = 0; |
||||
fprintf(out, " help\n%s\n", sym->help); |
||||
} |
||||
fputc('\n', out); |
||||
} |
||||
|
||||
void zconfdump(FILE *out) |
||||
{ |
||||
struct property *prop; |
||||
struct symbol *sym; |
||||
struct menu *menu; |
||||
|
||||
menu = rootmenu.list; |
||||
while (menu) { |
||||
if ((sym = menu->sym)) |
||||
print_symbol(out, menu); |
||||
else if ((prop = menu->prompt)) { |
||||
switch (prop->type) { |
||||
case P_COMMENT: |
||||
fputs("\ncomment ", out); |
||||
print_quoted_string(out, prop->text); |
||||
fputs("\n", out); |
||||
break; |
||||
case P_MENU: |
||||
fputs("\nmenu ", out); |
||||
print_quoted_string(out, prop->text); |
||||
fputs("\n", out); |
||||
break; |
||||
default: |
||||
; |
||||
} |
||||
if (!expr_is_yes(prop->visible.expr)) { |
||||
fputs(" depends ", out); |
||||
expr_fprint(prop->visible.expr, out); |
||||
fputc('\n', out); |
||||
} |
||||
fputs("\n", out); |
||||
} |
||||
|
||||
if (menu->list) |
||||
menu = menu->list; |
||||
else if (menu->next) |
||||
menu = menu->next; |
||||
else while ((menu = menu->parent)) { |
||||
if (menu->prompt && menu->prompt->type == P_MENU) |
||||
fputs("\nendmenu\n", out); |
||||
if (menu->next) { |
||||
menu = menu->next; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
#include "lex.zconf.c" |
||||
#include "util.c" |
||||
#include "confdata.c" |
||||
#include "expr.c" |
||||
#include "symbol.c" |
||||
#include "menu.c" |
Loading…
Reference in new issue