dslinux/user/pixil/scripts/config .cvsignore Kconfig-language.txt Makefile checklist.c colors.h conf.c confdata.c dialog.h expr.c expr.h inputbox.c lex.zconf.c_shipped lkc.h lkc_proto.h mconf.c menu.c menubox.c msgbox.c symbol.c textbox.c util.c yesno.c zconf.l zconf.tab.c_shipped zconf.tab.h_shipped zconf.y

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:27:06 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/scripts/config
In directory antilope:/tmp/cvs-serv11916/scripts/config

Added Files:
	.cvsignore Kconfig-language.txt Makefile checklist.c colors.h 
	conf.c confdata.c dialog.h expr.c expr.h inputbox.c 
	lex.zconf.c_shipped lkc.h lkc_proto.h mconf.c menu.c menubox.c 
	msgbox.c symbol.c textbox.c util.c yesno.c zconf.l 
	zconf.tab.c_shipped zconf.tab.h_shipped zconf.y 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: .cvsignore ---
conf
mconf
lkc_defs.h
lex.zconf.c
zconf.tab.h
zconf.tab.c
lex.backup
zconf.output

--- NEW FILE: confdata.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 *
 * Allow 'n' as a symbol value.
 * 2002-11-05 Petr Baudis <pasky at ucw.cz>
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define LKC_DIRECT_LINK
#include "lkc.h"

const char conf_def_filename[] = "config";

const char conf_defname[] = "sysdep/defconfig";

const char *conf_confnames[] = {
    "config",
    conf_defname,
    NULL,
};

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((int) *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)
{
    return conf_expand_value(conf_defname);
}

int
conf_read(const char *name)
{
    FILE *in = NULL;
    char line[1024];
    char *p, *p2;
    int lineno = 0;
    struct symbol *sym;
    struct property *prop;
    struct expr *e;
    int i;

    if (name) {
	in = fopen(name, "r");
    } else {
	const char **names = conf_confnames;
	while ((name = *names++)) {
	    name = conf_expand_value(name);
	    in = fopen(name, "r");
	    if (in) {
		printf("#\n" "# using defaults found in %s\n" "#\n", name);
		break;
	    }
	}
    }

    if (!in)
	return 1;

    for_all_symbols(i, sym) {
	sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
	sym->flags &= ~SYMBOL_VALID;
	switch (sym->type) {
	case S_INT:
	case S_HEX:
	case S_STRING:
	    if (S_VAL(sym->def))
		free(S_VAL(sym->def));
	default:
	    S_VAL(sym->def) = NULL;
	    S_TRI(sym->def) = no;
	    ;
	}
    }

    while (fgets(line, sizeof(line), in)) {
	lineno++;
	switch (line[0]) {
	case '\n':
	    break;
	case ' ':
	    break;
	case '#':
	    p = strchr(line, ' ');
	    if (!p)
		continue;
	    *p++ = 0;
	    p = strchr(p, ' ');
	    if (!p)
		continue;
	    *p++ = 0;
	    if (strncmp(p, "is not set", 10))
		continue;
	    sym = sym_lookup(line + 2, 0);
	    switch (sym->type) {
	    case S_BOOLEAN:
	    case S_TRISTATE:
		sym->def = symbol_no.curr;
		sym->flags &= ~SYMBOL_NEW;
		break;
	    default:
		;
	    }
	    break;
	case 'A'...'Z':
	    p = strchr(line, '=');
	    if (!p)
		continue;
	    *p++ = 0;
	    p2 = strchr(p, '\n');
	    if (p2)
		*p2 = 0;
	    sym = sym_find(line);
	    if (!sym) {
		fprintf(stderr,
			"%s:%d: trying to assign nonexistent symbol %s\n",
			name, lineno, line);
		break;
	    }
	    switch (sym->type) {
	    case S_TRISTATE:
		if (p[0] == 'm') {
		    S_TRI(sym->def) = mod;
		    sym->flags &= ~SYMBOL_NEW;
		    break;
		}
	    case S_BOOLEAN:
		if (p[0] == 'y') {
		    S_TRI(sym->def) = yes;
		    sym->flags &= ~SYMBOL_NEW;
		    break;
		}
		if (p[0] == 'n') {
		    S_TRI(sym->def) = no;
		    sym->flags &= ~SYMBOL_NEW;
		    break;
		}
		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));
		}
	    case S_INT:
	    case S_HEX:
		if (sym_string_valid(sym, p)) {
		    S_VAL(sym->def) = strdup(p);
		    sym->flags &= ~SYMBOL_NEW;
		} else
		    fprintf(stderr,
			    "%s:%d:symbol value '%s' invalid for %s\n", name,
			    lineno, p, sym->name);
		break;
	    default:
		;
	    }
	    if (sym_is_choice_value(sym)) {
		prop = sym_get_choice_prop(sym);
		switch (S_TRI(sym->def)) {
		case mod:
		    if (S_TRI(prop->def->def) == yes)
			/* warn? */ ;
		    break;
		case yes:
		    if (S_TRI(prop->def->def) != no)
			/* warn? */ ;
		    S_VAL(prop->def->def) = sym;
		    break;
		case no:
		    break;
		}
		S_TRI(prop->def->def) = S_TRI(sym->def);
	    }
	    break;
	default:
	    continue;
	}
    }
    fclose(in);

    for_all_symbols(i, sym) {
	if (!sym_is_choice(sym))
	    continue;
	prop = sym_get_choice_prop(sym);
	for (e = prop->dep; e; e = e->left.expr)
	    sym->flags |= e->right.sym->flags & SYMBOL_NEW;
	sym->flags &= ~SYMBOL_NEW;
    }

    sym_change_count = 1;

    return 0;
}

int
conf_write(const char *name)
{
    FILE *out, *out_h;
    struct symbol *sym;
    struct menu *menu;
    char oldname[128];
    int type, l;
    const char *str;

    out = fopen(".tmpconfig", "w");
    if (!out)
	return 1;
#ifndef PIXIL_DEMO
    out_h = fopen(".tmpconfig.h", "w");
    if (!out_h)
	return 1;
#endif

    fprintf(out, "#\n"
	    "# Automatically generated make config: don't edit\n" "#\n");

#ifndef PIXIL_DEMO
    fprintf(out_h, "/*\n"
	    " * Automatically generated header file: don't edit\n"
	    " */\n\n"
	    "#define AUTOCONF_INCLUDED\n\n"
	    "/* Version Number */\n"
	    "#define BB_VER \"%s\"\n"
	    "#define BB_BT \"%s\"\n\n", getenv("VERSION"), getenv("BUILDTIME")
	);
#endif

    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);
#ifndef PIXIL_DEMO
	    fprintf(out_h, "\n" "/*\n" " * %s\n" " */\n", str);
#endif
	} 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 (S_TRI(modules_sym->curr) == no)
		    type = S_BOOLEAN;
	    }
	    switch (type) {
	    case S_BOOLEAN:
	    case S_TRISTATE:
		switch (sym_get_tristate_value(sym)) {
		case no:
		    fprintf(out, "# %s is not set\n", sym->name);
#ifndef PIXIL_DEMO
		    fprintf(out_h, "#undef %s\n", sym->name);
#endif
		    break;
		case mod:
#if 0
		    fprintf(out, "%s=m\n", sym->name);
		    fprintf(out_h, "#define __%s__MODULE 1\n", sym->name);
#endif
		    break;
		case yes:
		    fprintf(out, "%s=y\n", sym->name);
#ifndef PIXIL_DEMO
		    fprintf(out_h, "#define %s 1\n", sym->name);
#endif
		    break;
		}
		break;
	    case S_STRING:
		// fix me
		str = sym_get_string_value(sym);
		fprintf(out, "%s=\"", sym->name);
#ifndef PIXIL_DEMO
		fprintf(out_h, "#define %s \"", sym->name);
#endif
		do {
		    l = strcspn(str, "\"\\");
		    if (l) {
			fwrite(str, l, 1, out);
#ifndef PIXIL_DEMO
			fwrite(str, l, 1, out_h);
#endif
		    }
		    str += l;
		    while (*str == '\\' || *str == '"') {
			fprintf(out, "\\%c", *str);
#ifndef PIXIL_DEMO
			fprintf(out_h, "\\%c", *str);
#endif
			str++;
		    }
		} while (*str);
		fputs("\"\n", out);
#ifndef PIXIL_DEMO
		fputs("\"\n", out_h);
#endif
		break;
	    case S_HEX:
		str = sym_get_string_value(sym);
		if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
		    fprintf(out, "%s=%s\n", sym->name, str);
#ifndef PIXIL_DEMO
		    fprintf(out_h, "#define %s 0x%s\n", sym->name, str);
#endif
		    break;
		}
	    case S_INT:
		str = sym_get_string_value(sym);
		fprintf(out, "%s=%s\n", sym->name, str);
#ifndef PIXIL_DEMO
		fprintf(out_h, "#define %s %s\n", sym->name, str);
#endif
		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);
#ifndef PIXIL_DEMO
    fclose(out_h);
#endif

    if (!name) {
	rename(".tmpconfig.h", "include/config.h");
	name = conf_def_filename;

#ifndef PIXIL_DEMO
	file_write_dep(NULL);
#endif
    } else
	unlink(".tmpconfig.h");

#ifndef PIXIL_DEMO
    sprintf(oldname, "%s.old", name);
    rename(name, oldname);
#endif

    if (rename(".tmpconfig", name))
	return 1;

    sym_change_count = 0;

    return 0;
}

--- NEW FILE: zconf.tab.h_shipped ---
/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */

/* Skeleton parser for Yacc-like parsing with Bison,
   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.

   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, 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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

/* As a special exception, when this file is copied by Bison into a
   Bison output file, you may use that output file without restriction.
   This special exception was added by the Free Software Foundation
   in version 1.24 of Bison.  */

#ifndef BISON_ZCONF_TAB_H
# define BISON_ZCONF_TAB_H

/* Tokens.  */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
   /* Put the tokens into the symbol table, so that GDB and other debuggers
      know about them.  */
   enum yytokentype {
     T_MAINMENU = 258,
     T_MENU = 259,
     T_ENDMENU = 260,
     T_SOURCE = 261,
     T_CHOICE = 262,
     T_ENDCHOICE = 263,
     T_COMMENT = 264,
     T_CONFIG = 265,
     T_HELP = 266,
     T_HELPTEXT = 267,
     T_IF = 268,
     T_ENDIF = 269,
     T_DEPENDS = 270,
     T_REQUIRES = 271,
     T_OPTIONAL = 272,
     T_PROMPT = 273,
     T_DEFAULT = 274,
     T_TRISTATE = 275,
     T_BOOLEAN = 276,
     T_INT = 277,
     T_HEX = 278,
     T_WORD = 279,
     T_STRING = 280,
     T_UNEQUAL = 281,
     T_EOF = 282,
     T_EOL = 283,
     T_CLOSE_PAREN = 284,
     T_OPEN_PAREN = 285,
     T_ON = 286,
     T_OR = 287,
     T_AND = 288,
     T_EQUAL = 289,
     T_NOT = 290
   };
#endif
#define T_MAINMENU 258
#define T_MENU 259
#define T_ENDMENU 260
#define T_SOURCE 261
#define T_CHOICE 262
#define T_ENDCHOICE 263
#define T_COMMENT 264
#define T_CONFIG 265
#define T_HELP 266
#define T_HELPTEXT 267
#define T_IF 268
#define T_ENDIF 269
#define T_DEPENDS 270
#define T_REQUIRES 271
#define T_OPTIONAL 272
#define T_PROMPT 273
#define T_DEFAULT 274
#define T_TRISTATE 275
#define T_BOOLEAN 276
#define T_INT 277
#define T_HEX 278
#define T_WORD 279
#define T_STRING 280
#define T_UNEQUAL 281
#define T_EOF 282
#define T_EOL 283
#define T_CLOSE_PAREN 284
#define T_OPEN_PAREN 285
#define T_ON 286
#define T_OR 287
#define T_AND 288
#define T_EQUAL 289
#define T_NOT 290




#ifndef YYSTYPE
#line 33 "zconf.y"
typedef union {
	int token;
	char *string;
	struct symbol *symbol;
	struct expr *expr;
	struct menu *menu;
} yystype;
/* Line 1281 of /usr/share/bison/yacc.c.  */
#line 118 "zconf.tab.h"
# define YYSTYPE yystype
#endif

extern YYSTYPE zconflval;


#endif /* not BISON_ZCONF_TAB_H */


--- NEW FILE: zconf.tab.c_shipped ---
/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */

/* Skeleton parser for Yacc-like parsing with Bison,
   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.

   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, 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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
[...1978 lines suppressed...]
			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 "confdata.c"
#include "expr.c"
#include "symbol.c"
#include "menu.c"


--- NEW FILE: lkc.h ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 */

#ifndef LKC_H
#define LKC_H

#include "expr.h"

#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

    void symbol_end(char *help);
    int zconfparse(void);
    void zconfdump(FILE * out);

    extern int zconfdebug;
    void zconf_starthelp(void);
    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[];
    extern char conf_filename[];

    char *conf_get_default_confname(void);

/* kconfig_load.c */
    void kconfig_load(void);

/* menu.c */
    void menu_init(void);
    void menu_add_menu(void);
    void menu_end_menu(void);
    void menu_add_entry(struct symbol *sym);
    void menu_end_entry(void);
    struct property *create_prop(enum prop_type type);
    void menu_add_dep(struct expr *dep);
    struct property *menu_add_prop(int token, char *prompt,
				   struct symbol *def, struct expr *dep);
    void menu_finalize(struct menu *parent);
    void menu_set_type(int type);
    struct file *file_lookup(const char *name);
    int file_write_dep(const char *name);

    extern struct menu *current_entry;
    extern struct menu *current_menu;

/* symbol.c */
    void sym_init(void);
    void sym_clear_all_valid(void);

    static inline tristate sym_get_tristate_value(struct symbol *sym)
    {
	return S_TRI(sym->curr);
    }


    static inline struct symbol *sym_get_choice_value(struct symbol *sym)
    {
	return (struct symbol *) S_VAL(sym->curr);
    }

    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 S_VAL(sym->def) != NULL;
	return sym->flags & SYMBOL_NEW ? false : true;
    }

#ifdef __cplusplus
}
#endif

#endif /* LKC_H */

--- NEW FILE: Makefile ---
# Makefile for Pixil config 
# Originally from Busybox

TOPDIR=../../
HOSTCC=gcc

all: ncurses conf mconf

HOSTCFLAGS += -g -O0 -DPIXIL_DEMO
LIBS = -lncurses
ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
	HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
else
ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
	HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
else
ifeq (/usr/local/include/ncurses/ncurses.h, $(wildcard /usr/local/include/ncurses/ncurses.h))
	HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="<ncurses.h>"
else
ifeq (/usr/local/include/ncurses/curses.h, $(wildcard /usr/local/include/ncurses/curses.h))
	HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
else
ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
	HOSTNCURSES += -DCURSES_LOC="<ncurses.h>"
else
	HOSTNCURSES += -DCURSES_LOC="<curses.h>"
endif
endif
endif
endif
endif

CONF_SRC  =conf.c
MCONF_SRC =mconf.c checklist.c menubox.c textbox.c yesno.c inputbox.c util.c msgbox.c
SHARED_SRC=zconf.tab.c
SHARED_DEPS:=lkc.h lkc_proto.h lkc_defs.h expr.h zconf.tab.h
CONF_OBJS =$(patsubst %.c,%.o, $(CONF_SRC))
MCONF_OBJS=$(patsubst %.c,%.o, $(MCONF_SRC))
SHARED_OBJS=$(patsubst %.c,%.o, $(SHARED_SRC))

conf: $(CONF_OBJS) $(SHARED_OBJS) 
	$(HOSTCC) $(NATIVE_LDFLAGS) $^ -o $@

mconf: $(MCONF_OBJS) $(SHARED_OBJS)
	$(HOSTCC) $(NATIVE_LDFLAGS) $^ -o $@ $(LIBS)

$(CONF_OBJS): %.o : %.c $(SHARED_DEPS)
	$(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@

$(MCONF_OBJS): %.o : %.c $(SHARED_DEPS)
	$(HOSTCC) $(HOSTCFLAGS) $(HOSTNCURSES) -I. -c $< -o $@

lkc_defs.h: lkc_proto.h
	@sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'

###
# The following requires flex/bison
# By default we use the _shipped versions, uncomment the 
# following line if you are modifying the flex/bison src.
#LKC_GENPARSER := 1

ifdef LKC_GENPARSER

%.tab.c %.tab.h: %.y
	bison -t -d -v -b $* -p $(notdir $*) $<

lex.%.c: %.l
	flex -P$(notdir $*) -o$@ $<
else

lex.zconf.o: lex.zconf.c $(SHARED_DEPS)
	$(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@

lex.zconf.c: lex.zconf.c_shipped
	cp lex.zconf.c_shipped lex.zconf.c

zconf.tab.o: zconf.tab.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(SHARED_DEPS)
	$(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@

zconf.tab.c: zconf.tab.c_shipped
	cp zconf.tab.c_shipped zconf.tab.c

zconf.tab.h: zconf.tab.h_shipped
	cp zconf.tab.h_shipped zconf.tab.h
endif

.PHONY: ncurses

ncurses:
	@echo "main() {}" > lxtemp.c
	@if $(HOSTCC) lxtemp.c $(LIBS) ; then \
		rm -f lxtemp.c a.out; \
	else \
		rm -f lxtemp.c; \
		echo -e "\007" ;\
		echo ">> Unable to find the Ncurses libraries." ;\
		echo ">>" ;\
		echo ">> You must have Ncurses installed in order" ;\
		echo ">> to use 'make menuconfig'" ;\
		echo ;\
		exit 1 ;\
	fi

clean:
	@ rm -f *.o *~ core $(TARGETS) $(MCONF_OBJS) $(CONF_OBJS) \
		conf mconf zconf.tab.c zconf.tab.h lex.zconf.c lkc_defs.h


--- NEW FILE: zconf.l ---
%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 at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define LKC_DIRECT_LINK
#include "lkc.h"
#include "zconf.tab.h"

#define START_STRSIZE	16

char *text;
static char *text_ptr;
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 struct buffer *zconf_endfile(void);

void new_string(void)
{
	text = malloc(START_STRSIZE);
	text_asize = START_STRSIZE;
	text_ptr = text;
	text_size = 0;
	*text_ptr = 0;
}

void append_string(const char *str, int size)
{
	int new_size = text_size + size + 1;
	if (new_size > text_asize) {
		text = realloc(text, new_size);
		text_asize = new_size;
		text_ptr = text + text_size;
	}
	memcpy(text_ptr, str, size);
	text_ptr += size;
	text_size += size;
	*text_ptr = 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	current_file->lineno++;
[ \t]*#.*

[ \t]*\n	current_file->lineno++; return T_EOL;

[ \t]+	{
	BEGIN(COMMAND);
}

.	{
	unput(yytext[0]);
	BEGIN(COMMAND);
}


<COMMAND>{
	"mainmenu"		BEGIN(PARAM); return T_MAINMENU;
	"menu"			BEGIN(PARAM); return T_MENU;
	"endmenu"		BEGIN(PARAM); return T_ENDMENU;
	"source"		BEGIN(PARAM); return T_SOURCE;
	"choice"		BEGIN(PARAM); return T_CHOICE;
	"endchoice"		BEGIN(PARAM); return T_ENDCHOICE;
	"comment"		BEGIN(PARAM); return T_COMMENT;
	"config"		BEGIN(PARAM); return T_CONFIG;
	"help"			BEGIN(PARAM); return T_HELP;
	"if"			BEGIN(PARAM); return T_IF;
	"endif"			BEGIN(PARAM); return T_ENDIF;
	"depends"		BEGIN(PARAM); return T_DEPENDS;
	"requires"		BEGIN(PARAM); return T_REQUIRES;
	"optional"		BEGIN(PARAM); return T_OPTIONAL;
	"default"		BEGIN(PARAM); return T_DEFAULT;
	"prompt"		BEGIN(PARAM); return T_PROMPT;
	"tristate"		BEGIN(PARAM); return T_TRISTATE;
	"bool"			BEGIN(PARAM); return T_BOOLEAN;
	"boolean"		BEGIN(PARAM); return T_BOOLEAN;
	"int"			BEGIN(PARAM); return T_INT;
	"hex"			BEGIN(PARAM); return T_HEX;
	"string"		BEGIN(PARAM); return T_STRING;
	{n}+	{
		alloc_string(yytext, yyleng);
		zconflval.string = text;
		return T_WORD;
	}
	.
	\n	current_file->lineno++; BEGIN(INITIAL);
}

<PARAM>{
	"&&"	return T_AND;
	"||"	return T_OR;
	"("	return T_OPEN_PAREN;
	")"	return T_CLOSE_PAREN;
	"!"	return T_NOT;
	"="	return T_EQUAL;
	"!="	return T_UNEQUAL;
	"if"	return T_IF;
	"on"	return T_ON;
	\"|\'	{
		str = yytext[0];
		new_string();
		BEGIN(STRING);
	}
	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
	---	/* ignore */
	({n}|[-/.])+	{
		alloc_string(yytext, yyleng);
		zconflval.string = text;
		return T_WORD;
	}
	.
	<<EOF>> {
		BEGIN(INITIAL);
	}
}

<STRING>{
	[^'"\\\n]+/\n	{
		append_string(yytext, yyleng);
		zconflval.string = text;
		return T_STRING;
	}
	[^'"\\\n]+	{
		append_string(yytext, yyleng);
	}
	\\.?/\n	{
		append_string(yytext+1, yyleng);
		zconflval.string = text;
		return T_STRING;
	}
	\\.?	{
		append_string(yytext+1, yyleng);
	}
	\'|\"	{
		if (str == yytext[0]) {
			BEGIN(PARAM);
			zconflval.string = text;
			return T_STRING;
		} else
			append_string(yytext, 1);
	}
	\n	{
		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_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);
		}
		
	}
	\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_buf) {
		zconf_endfile();
		return T_EOF;
	}
	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); 
}

void zconf_initscan(const char *name)
{
	yyin = fopen(name, "r");
	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 = fopen(name, "r");
	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 struct buffer *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;

	return parent;
}

int zconf_lineno(void)
{
	if (current_buf)
		return current_file->lineno;
	else
		return 0;
}

char *zconf_curname(void)
{
	if (current_buf)
		return current_file->name;
	else
		return "<none>";
}

--- NEW FILE: inputbox.c ---
/*
 *  inputbox.c -- implements the input box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at 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"

unsigned 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;
    unsigned 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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }

    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 */
}

--- NEW FILE: textbox.c ---
/*
 *  textbox.c -- implements the text box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at 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 = 0, fd, file_size, bytes_read;
static int begin_reached = 1, end_reached = 0, 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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }
    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);
}

--- NEW FILE: util.c ---
/*
 *  util.c
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at 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;

const char *dialog_result;

/* 
 * 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 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;
}

/*
 * Get the first selected item in the dialog_list_item list.
 */
struct dialog_list_item *
first_sel_item(int item_no, struct dialog_list_item **items)
{
    int i;

    for (i = 0; i < item_no; i++) {
	if (items[i]->selected)
	    return items[i];
    }

    return NULL;
}

--- NEW FILE: expr.h ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at 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;
#ifdef CML1
	struct statement *stmt;
	struct statement *last_stmt;
#endif
	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
    };

    union expr_data
    {
	struct expr *expr;
	struct symbol *sym;
    };

    struct expr
    {
#ifdef CML1
	int token;
#else
	enum expr_type type;
#endif
	union expr_data left, right;
    };

#define E_TRI(ev)	((ev).tri)
#define E_EXPR(ev)	((ev).expr)
#define E_CALC(ev)	(E_TRI(ev) = expr_calc_value(E_EXPR(ev)))

#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;
    };

#define S_VAL(sv)	((sv).value)
#define S_TRI(sv)	((sv).tri)
#define S_EQ(sv1, sv2)	(S_VAL(sv1) == S_VAL(sv2) || !strcmp(S_VAL(sv1), S_VAL(sv2)))

    struct symbol_value
    {
	void *value;
	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;
#ifdef CML1
	int type;
#else
	enum symbol_type type;
#endif
	struct symbol_value curr, def;
	tristate visible;
	int flags;
	struct property *prop;
	struct expr *dep, *dep2;
	struct menu *menu;
    };

#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)

#ifdef CML1
#define SYMBOL_UNKNOWN		S_UNKNOWN
#define SYMBOL_BOOLEAN		S_BOOLEAN
#define SYMBOL_TRISTATE		S_TRISTATE
#define SYMBOL_INT		S_INT
#define SYMBOL_HEX		S_HEX
#define SYMBOL_STRING		S_STRING
#define SYMBOL_OTHER		S_OTHER
#endif

#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_MAXLENGTH	256
#define SYMBOL_HASHSIZE		257
#define SYMBOL_HASHMASK		0xff

    enum prop_type
    {
	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT,
	P_CHOICE
    };

    struct property
    {
	struct property *next;
	struct symbol *sym;
#ifdef CML1
	int token;
#else
	enum prop_type type;
#endif
	const char *text;
	struct symbol *def;
	struct expr_value visible;
	struct expr *dep;
	struct expr *dep2;
	struct menu *menu;
	struct file *file;
	int lineno;
#ifdef CML1
	struct property *next_pos;
#endif
    };

#define for_all_properties(sym, st, tok) \
	for (st = sym->prop; st; st = st->next) \
		if (st->type == (tok))
#define for_all_prompts(sym, st) for_all_properties(sym, st, P_PROMPT)
#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)

    struct menu
    {
	struct menu *next;
	struct menu *parent;
	struct menu *list;
	struct symbol *sym;
	struct property *prompt;
	struct expr *dep;
	//char *help;
	struct file *file;
	int lineno;
	void *data;
    };

#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;
    extern int print_type;
    struct expr *expr_alloc_symbol(struct symbol *sym);
#ifdef CML1
    struct expr *expr_alloc_one(int token, struct expr *ce);
    struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2);
    struct expr *expr_alloc_comp(int token, struct symbol *s1,
				 struct symbol *s2);
#else
    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);
#endif
    struct expr *expr_alloc_and(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);
    void print_expr(int mask, struct expr *e, int prevtoken);

#ifdef CML1
    static inline int expr_is_yes(struct expr *e)
    {
	return !e || (e->token == WORD && e->left.sym == &symbol_yes);
    }

    static inline int expr_is_no(struct expr *e)
    {
	return e && (e->token == WORD && e->left.sym == &symbol_no);
    }
#else
    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
#endif

#ifdef __cplusplus
}
#endif

#endif /* EXPR_H */

--- NEW FILE: colors.h ---
/*
 *  colors.h -- color attribute definitions
 *
 *  AUTHOR: Savio Lam (lam836 at 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
 */

typedef struct
{
    char name[COLOR_NAME_LEN];
    int value;
}
color_names_st;

extern color_names_st color_names[];
extern int color_table[][3];

--- NEW FILE: zconf.y ---
%{
/*
 * Copyright (C) 2002 Roman Zippel <zippel at 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 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 zconferror(const char *err);
static bool zconf_endtoken(int token, int starttoken, int endtoken);

struct symbol *symbol_hash[257];

#define YYERROR_VERBOSE
%}
%expect 36

%union
{
	int token;
	char *string;
	struct symbol *symbol;
	struct expr *expr;
	struct menu *menu;
}

%token T_MAINMENU
%token T_MENU
%token T_ENDMENU
%token T_SOURCE
%token T_CHOICE
%token T_ENDCHOICE
%token T_COMMENT
%token T_CONFIG
%token T_HELP
%token <string> T_HELPTEXT
%token T_IF
%token T_ENDIF
%token T_DEPENDS
%token T_REQUIRES
%token T_OPTIONAL
%token T_PROMPT
%token T_DEFAULT
%token T_TRISTATE
%token T_BOOLEAN
%token T_INT
%token T_HEX
%token <string> T_WORD
%token <string> T_STRING
%token T_UNEQUAL
%token T_EOF
%token T_EOL
%token T_CLOSE_PAREN
%token T_OPEN_PAREN
%token T_ON

%left T_OR
%left T_AND
%left T_EQUAL T_UNEQUAL
%nonassoc T_NOT

%type <string> prompt
%type <string> source
%type <symbol> symbol
%type <expr> expr
%type <expr> if_expr
%type <token> end

%{
#define LKC_DIRECT_LINK
#include "lkc.h"
%}
%%
input:	  /* empty */
	| input block
;

block:	  common_block
	| choice_stmt
	| menu_stmt
	| T_MAINMENU prompt nl_or_eof
	| T_ENDMENU		{ zconfprint("unexpected 'endmenu' statement"); }
	| T_ENDIF		{ zconfprint("unexpected 'endif' statement"); }
	| T_ENDCHOICE		{ zconfprint("unexpected 'endchoice' statement"); }
	| error nl_or_eof	{ zconfprint("syntax error"); yyerrok; }
;

common_block:
	  if_stmt
	| comment_stmt
	| config_stmt
	| source_stmt
	| nl_or_eof
;


/* config entry */

config_entry_start: T_CONFIG T_WORD
{
	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 T_EOL config_option_list
{
	menu_end_entry();
	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
};

config_option_list:
	  /* empty */
	| config_option_list config_option T_EOL
	| config_option_list depends T_EOL
	| config_option_list help
	| config_option_list T_EOL
{ };

config_option: T_TRISTATE prompt_stmt_opt
{
	menu_set_type(S_TRISTATE);
	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
};

config_option: T_BOOLEAN prompt_stmt_opt
{
	menu_set_type(S_BOOLEAN);
	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
};

config_option: T_INT prompt_stmt_opt
{
	menu_set_type(S_INT);
	printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
};

config_option: T_HEX prompt_stmt_opt
{
	menu_set_type(S_HEX);
	printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
};

config_option: T_STRING prompt_stmt_opt
{
	menu_set_type(S_STRING);
	printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
};

config_option: T_PROMPT prompt if_expr
{
	menu_add_prop(P_PROMPT, $2, NULL, $3);
	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
};

config_option: T_DEFAULT symbol if_expr
{
	menu_add_prop(P_DEFAULT, NULL, $2, $3);
	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
};

/* choice entry */

choice: T_CHOICE
{
	struct symbol *sym = sym_lookup(NULL, 0);
	sym->flags |= SYMBOL_CHOICE;
	menu_add_entry(sym);
	menu_add_prop(P_CHOICE, NULL, NULL, NULL);
	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
};

choice_entry: choice T_EOL choice_option_list
{
	menu_end_entry();
	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 T_EOL
	| choice_entry choice_block
{
	printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
	zconfnerrs++;
};

choice_option_list:
	  /* empty */
	| choice_option_list choice_option T_EOL
	| choice_option_list depends T_EOL
	| choice_option_list help
	| choice_option_list T_EOL
;

choice_option: T_PROMPT prompt if_expr
{
	menu_add_prop(P_PROMPT, $2, NULL, $3);
	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
};

choice_option: T_OPTIONAL
{
	current_entry->sym->flags |= SYMBOL_OPTIONAL;
	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
};

choice_option: T_DEFAULT symbol
{
	menu_add_prop(P_DEFAULT, NULL, $2, NULL);
	//current_choice->prop->def = $2;
	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
};

choice_block:
	  /* empty */
	| choice_block common_block
;

/* if entry */

if: T_IF expr
{
	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
	menu_add_entry(NULL);
	//current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, $2);
	menu_add_dep($2);
	menu_end_entry();
	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 T_EOL if_block if_end T_EOL
	| if T_EOL if_block
{
	printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
	zconfnerrs++;
};

if_block:
	  /* empty */
	| if_block common_block
	| if_block menu_stmt
	| if_block choice_stmt
;

/* menu entry */

menu: T_MENU prompt
{
	menu_add_entry(NULL);
	menu_add_prop(P_MENU, $2, NULL, NULL);
	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
};

menu_entry: menu T_EOL depends_list
{
	menu_end_entry();
	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 T_EOL
	| menu_entry menu_block
{
	printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
	zconfnerrs++;
};

menu_block:
	  /* empty */
	| menu_block common_block
	| menu_block menu_stmt
	| menu_block choice_stmt
	| menu_block error T_EOL		{ zconfprint("invalid menu option"); yyerrok; }
;

source: T_SOURCE prompt
{
	$$ = $2;
	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
};

source_stmt: source T_EOL
{
	zconf_nextfile($1);
};

/* comment entry */

comment: T_COMMENT prompt
{
	menu_add_entry(NULL);
	menu_add_prop(P_COMMENT, $2, NULL, NULL);
	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
};

comment_stmt: comment T_EOL 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 T_EOL
		| depends_list T_EOL
{ };

depends: T_DEPENDS T_ON expr
{
	menu_add_dep($3);
	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
}
	| T_DEPENDS expr
{
	menu_add_dep($2);
	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
}
	| T_REQUIRES expr
{
	menu_add_dep($2);
	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
};

/* prompt statement */

prompt_stmt_opt:
	  /* empty */
	| prompt
{
	menu_add_prop(P_PROMPT, $1, NULL, NULL);
}
	| prompt T_IF expr
{
	menu_add_prop(P_PROMPT, $1, NULL, $3);
};

prompt:	  T_WORD
	| T_STRING
;

end:	  T_ENDMENU		{ $$ = T_ENDMENU; }
	| T_ENDCHOICE		{ $$ = T_ENDCHOICE; }
	| T_ENDIF		{ $$ = T_ENDIF; }
;

nl_or_eof:
	T_EOL | T_EOF;

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_STRING	{ $$ = sym_lookup($1, 1); free($1); }
;

%%

void conf_parse(const char *name)
{
	zconf_initscan(name);

	sym_init();
	menu_init();
	rootmenu.prompt = menu_add_prop(P_MENU, "Pixil Configuration", NULL, NULL);

	//zconfdebug = 1;
	zconfparse();
	if (zconfnerrs)
		exit(1);
	menu_finalize(&rootmenu);

	modules_sym = sym_lookup("MODULES", 0);

	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";
	}
	return "<token>";
} 

static bool zconf_endtoken(int token, int starttoken, int endtoken)
{
	if (token != endtoken) {
		zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
		zconfnerrs++;
		return false;
	}
	if (current_menu->file != current_file) {
		zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
		zconfprint("location of the '%s'", 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 zconferror(const char *err)
{
	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err);
}

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;

	//sym->flags |= SYMBOL_PRINTED;

	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;
	}
#if 0
	if (!expr_is_yes(sym->dep)) {
		fputs("  depends ", out);
		expr_fprint(sym->dep, out);
		fputc('\n', out);
	}
#endif
	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 (prop->def) {
				fputc(' ', out);
				if (prop->def->flags & SYMBOL_CONST)
					print_quoted_string(out, prop->def->name);
				else
					fputs(prop->def->name, out);
			}
			if (!expr_is_yes(E_EXPR(prop->visible))) {
				fputs(" if ", out);
				expr_fprint(E_EXPR(prop->visible), out);
			}
			fputc('\n', out);
			break;
		case P_DEFAULT:
			fputs( "  default ", out);
			print_quoted_string(out, prop->def->name);
			if (!expr_is_yes(E_EXPR(prop->visible))) {
				fputs(" if ", out);
				expr_fprint(E_EXPR(prop->visible), 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 file *file;
	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 T_MAINMENU:
			//	fputs("\nmainmenu ", out);
			//	print_quoted_string(out, prop->text);
			//	fputs("\n", out);
			//	break;
			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;
			//case T_SOURCE:
			//	fputs("\nsource ", out);
			//	print_quoted_string(out, prop->text);
			//	fputs("\n", out);
			//	break;
			//case T_IF:
			//	fputs("\nif\n", out);
			default:
				;
			}
			if (!expr_is_yes(E_EXPR(prop->visible))) {
				fputs("  depends ", out);
				expr_fprint(E_EXPR(prop->visible), 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 "confdata.c"
#include "expr.c"
#include "symbol.c"
#include "menu.c"

--- NEW FILE: Kconfig-language.txt ---
Introduction
------------

The configuration database is collection of configuration options
organized in a tree structure:

	+- Code maturity level options
	|  +- Prompt for development and/or incomplete code/drivers
	+- General setup
	|  +- Networking support
	|  +- System V IPC
	|  +- BSD Process Accounting
	|  +- Sysctl support
	+- Loadable module support
	|  +- Enable loadable module support
	|     +- Set version information on all module symbols
	|     +- Kernel module loader
	+- ...

Every entry has its own dependencies. These dependencies are used
to determine the visible of an entry. Any child entry is only
visible if its parent entry is also visible.

Menu entries
------------

Most entries define a config option, all other entries help to organize
them. A single configuration option is defined like this:

config MODVERSIONS
	bool "Set version information on all module symbols"
	depends MODULES
	help
	  Usually, modules have to be recompiled whenever you switch to a new
	  kernel.  ...

Every line starts with a key word and can be followed by multiple
arguments.  "config" starts a new config entry. The following lines
define attributes for this config option. Attributes can be the type of
the config option, input prompt, dependencies, help text and default
values. A config option can be defined multiple times with the same
name, but every definition can have only a single input prompt and the
type must not conflict.

Menu attributes
---------------

A menu entry can have a number of attributes. Not all of them are
applicable everywhere (see syntax).

- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
  Every config option must have a type. There are only two basic types:
  tristate and string, the other types base on these two. The type
  definition optionally accepts an input prompt, so these two examples
  are equivalent:

	bool "Networking support"
  and
	bool
	prompt "Networking support"

- input prompt: "prompt" <prompt> ["if" <expr>]
  Every menu entry can have at most one prompt, which is used to display
  to the user. Optionally dependencies only for this prompt can be added
  with "if".

- default value: "default" <symbol> ["if" <expr>]
  A config option can have any number of default values. If multiple
  default values are visible, only the first defined one is active.
  Default values are not limited to the menu entry, where they are
  defined, this means the default can be defined somewhere else or be
  overriden by an earlier definition.
  The default value is only assigned to the config symbol if no other
  value was set by the user (via the input prompt above). If an input
  prompt is visible the default value is presented to the user and can
  be overridden by him.
  Optionally dependencies only for this default value can be added with
  "if".

- dependencies: "depends on"/"requires" <expr>
  This defines a dependency for this menu entry. If multiple
  dependencies are defined they are connected with '&&'. Dependencies
  are applied to all other options within this menu entry (which also
  accept "if" expression), so these two examples are equivalent:

	bool "foo" if BAR
	default y if BAR
  and
	depends on BAR
	bool "foo"
	default y

- help text: "help"
  This defines a help text. The end of the help text is determined by
  the level indentation, this means it ends at the first line which has
  a smaller indentation than the first line of the help text.


Menu dependencies
-----------------

Dependencies define the visibility of a menu entry and can also reduce
the input range of tristate symbols. The tristate logic used in the
expressions uses one more state than normal boolean logic to express the
module state. Dependency expressions have the following syntax:

<expr> ::= <symbol>                             (1)
           <symbol> '=' <symbol>                (2)
           <symbol> '!=' <symbol>               (3)
           '(' <expr> ')'                       (4)
           '!' <expr>                           (5)
           <expr> '||' <expr>                   (6)
           <expr> '&&' <expr>                   (7)

Expressions are listed in decreasing order of precedence. 

(1) Convert the symbol into an expression. Boolean and tristate symbols
    are simply converted into the respective expression values. All
    other symbol types result in 'n'.
(2) If the values of both symbols are equal, it returns 'y',
    otherwise 'n'.
(3) If the values of both symbols are equal, it returns 'n',
    otherwise 'y'.
(4) Returns the value of the expression. Used to override precedence.
(5) Returns the result of (2-/expr/).
(6) Returns the result of min(/expr/, /expr/).
(7) Returns the result of max(/expr/, /expr/).

An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
respectively for calculations). A menu entry becomes visible when it's
expression evaluates to 'm' or 'y'.

There are two type of symbols: constant and nonconstant symbols.
Nonconstant symbols are the most common ones and are defined with the
'config' statement. Nonconstant symbols consist entirely of alphanumeric
characters or underscores.
Constant symbols are only part of expressions. Constant symbols are
always surrounded by single or double quotes. Within the quote any
other character is allowed and the quotes can be escaped using '\'.

Menu structure
--------------

The position of a menu entry in the tree is determined in two ways. First
it can be specified explicitely:

menu "Network device support"
	depends NET

config NETDEVICES
	...

endmenu

All entries within the "menu" ... "endmenu" block become a submenu of
"Network device support". All subentries inherit the dependencies from
the menu entry, e.g. this means the dependency "NET" is added to the
dependency list of the config option NETDEVICES.

The other way to generate the menu structure is done by analyzing the
dependencies. If a menu entry somehow depends on the previous entry, it
can be made a submenu of it. First the the previous (parent) symbol must
be part of the dependency list and then one of these two condititions
must be true:
- the child entry must become invisible, if the parent is set to 'n'
- the child entry must only be visible, if the parent is visible

config MODULES
	bool "Enable loadable module support"

config MODVERSIONS
	bool "Set version information on all module symbols"
	depends MODULES

comment "module support disabled"
	depends !MODULES

MODVERSIONS directly depends on MODULES, this means it's only visible if
MODULES is different from 'n'. The comment on the other hand is always
visible when MODULES it's visible (the (empty) dependency of MODULES is
also part of the comment dependencies).


Kconfig syntax
--------------

The configuration file describes a series of menu entries, where every
line starts with a keyword (except help texts). The following keywords
end a menu entry:
- config
- choice/endchoice
- comment
- menu/endmenu
- if/endif
- source
The first four also start the definition of a menu entry.

config:

	"config" <symbol>
	<config options>

This defines a config symbol <symbol> and accepts any of above
attributes as options.

choices:

	"choice"
	<choice options>
	<choice block>
	"endchoice"

This defines a choice group and accepts any of above attributes as
options. A choice can only be of type bool or tristate, while a boolean
choice only allows a single config entry to be selected, a tristate
choice also allows any number of config entries to be set to 'm'. This
can be used if multiple drivers for a single hardware exists and only a
single driver can be compiled/loaded into the kernel, but all drivers
can be compiled as modules.
A choice accepts another option "optional", which allows to set the
choice to 'n' and no entry needs to be selected.

comment:

	"comment" <prompt>
	<comment options>

This defines a comment which is displayed to the user during the
configuration process and is also echoed to the output files. The only
possible options are dependencies.

menu:

	"menu" <prompt>
	<menu options>
	<menu block>
	"endmenu"

This defines a menu block, see "Menu structure" above for more
information. The only possible options are dependencies.

if:

	"if" <expr>
	<if block>
	"endif"

This defines an if block. The dependency expression <expr> is appended
to all enclosed menu entries.

source:

	"source" <prompt>

This reads the specified configuration file. This file is always parsed.

--- NEW FILE: dialog.h ---

/*
 *  dialog.h -- common declarations for all dialog modules
 *
 *  AUTHOR: Savio Lam (lam836 at 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 CURSES_LOC
#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[];
#endif

extern const char *backtitle;

struct dialog_list_item
{
    char *name;
    int namelen;
    char *tag;
    int selected;		/* Set to 1 by dialog_*() function. */
};

/*
 * Function prototypes
 */
extern void create_rc(const char *filename);
extern int parse_rc(void);


void init_dialog(void);
void end_dialog(void);
void dialog_clear(void);
#ifdef CURSES_LOC
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 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);
#endif

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,
		struct dialog_list_item **items);
int dialog_checklist(const char *title, const char *prompt, int height,
		     int width, int list_height, int item_no,
		     struct dialog_list_item **items, int flag);
extern unsigned char dialog_input_result[];
int dialog_inputbox(const char *title, const char *prompt, int height,
		    int width, const char *init);

struct dialog_list_item *first_sel_item(int item_no,
					struct dialog_list_item **items);

/*
 * 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')
 */
#ifdef CURSES_LOC
#define M_EVENT (KEY_MAX+1)
#endif


/*
 * The `flag' parameter in checklist is used to select between
 * radiolist and checklist
 */
#define FLAG_CHECK 1
#define FLAG_RADIO 0

--- NEW FILE: expr.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LKC_DIRECT_LINK
#include "lkc.h"

struct expr *
expr_alloc_symbol(struct symbol *sym)
{
    struct expr *e = malloc(sizeof(*e));
    memset(e, 0, sizeof(*e));
    e->type = E_SYMBOL;
    e->left.sym = sym;
[...1082 lines suppressed...]

static void
expr_print_file_helper(void *data, const char *str)
{
    fwrite(str, strlen(str), 1, data);
}

void
expr_fprint(struct expr *e, FILE * out)
{
    expr_print(e, expr_print_file_helper, out, E_NONE);
}

void
print_expr(int mask, struct expr *e, int prevtoken)
{
    if (!(cdebug & mask))
	return;
    expr_fprint(e, stdout);
}

--- NEW FILE: lex.zconf.c_shipped ---
#define yy_create_buffer zconf_create_buffer
#define yy_delete_buffer zconf_delete_buffer
#define yy_scan_buffer zconf_scan_buffer
#define yy_scan_string zconf_scan_string
#define yy_scan_bytes zconf_scan_bytes
#define yy_flex_debug zconf_flex_debug
#define yy_init_buffer zconf_init_buffer
#define yy_flush_buffer zconf_flush_buffer
#define yy_load_buffer_state zconf_load_buffer_state
#define yy_switch_to_buffer zconf_switch_to_buffer
#define yyin zconfin
#define yyleng zconfleng
#define yylex zconflex
#define yyout zconfout
#define yyrestart zconfrestart
#define yytext zconftext

/* A lexical scanner generated by flex */

[...3241 lines suppressed...]
	current_buf = parent;

	return parent;
}

int zconf_lineno(void)
{
	if (current_buf)
		return current_file->lineno;
	else
		return 0;
}

char *zconf_curname(void)
{
	if (current_buf)
		return current_file->name;
	else
		return "<none>";
}

--- NEW FILE: mconf.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 *
 * Introduced single menu mode (show all sub-menus in one large tree).
 * 2002-11-06 Petr Baudis <pasky at ucw.cz>
 *
 * Directly use liblxdialog library routines.
 * 2002-11-14 Petr Baudis <pasky at ucw.cz>
 */

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/termios.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include "dialog.h"

#define LKC_DIRECT_LINK
#include "lkc.h"

static const char menu_instructions[] =
    "Arrow keys navigate the menu.  "
    "<Enter> selects submenus --->.  "
    "Highlighted letters are hotkeys.  "
    "Pressing <Y> selectes a feature, while <N> will exclude a feature.  "
    "Press <Esc><Esc> to exit, <?> for Help.  "
    "Legend: [*] feature is selected  [ ] feature is excluded",
    radiolist_instructions[] =
    "Use the arrow keys to navigate this window or "
    "press the hotkey of the item you wish to select "
    "followed by the <SPACE BAR>. "
    "Press <?> for additional information about this option.",
    inputbox_instructions_int[] =
    "Please enter a decimal value. "
    "Fractions will not be accepted.  "
    "Use the <TAB> key to move from the input field to the buttons below it.",
    inputbox_instructions_hex[] =
    "Please enter a hexadecimal value. "
    "Use the <TAB> key to move from the input field to the buttons below it.",
    inputbox_instructions_string[] =
    "Please enter a string value. "
    "Use the <TAB> key to move from the input field to the buttons below it.",
    setmod_text[] =
    "This feature depends on another which has been configured as a module.\n"
    "As a result, this feature will be built as a module.",
    nohelp_text[] =
    "There is no help available for this option.\n",
    load_config_text[] =
    "Enter the name of the configuration file you wish to load.  "
    "Accept the name shown to restore the configuration you "
    "last retrieved.  Leave blank to abort.",
    load_config_help[] =
    "\n"
    "For various reasons, one may wish to keep several different Pixil\n"
    "configurations available on a single machine.\n"
    "\n"
    "If you have saved a previous configuration in a file other than the\n"
    "Pixil default, entering the name of the file here will allow you\n"
    "to modify that configuration.\n"
    "\n"
    "If you are uncertain, then you have probably never used alternate\n"
    "configuration files.  You should therefor leave this blank to abort.\n",
    save_config_text[] =
    "Enter a filename to which this configuration should be saved "
    "as an alternate.  Leave blank to abort.",
    save_config_help[] =
    "\n"
    "For various reasons, one may wish to keep different Pixil\n"
    "configurations available on a single machine.\n"
    "\n"
    "Entering a file name here will allow you to later retrieve, modify\n"
    "and use the current configuration as an alternate to whatever\n"
    "configuration options you have selected at that time.\n"
    "\n"
    "If you are uncertain what all this means then you should probably\n"
    "leave this blank.\n";

static char filename[PATH_MAX + 1] = "config";
static int indent = 0;
static struct termios ios_org;
static int rows, cols;
static struct menu *current_menu;
static int child_count;
static int single_menu_mode;

static struct dialog_list_item *items[16384];	/* FIXME: This ought to be dynamic. */
static int item_no;

static void conf(struct menu *menu);
static void conf_choice(struct menu *menu);
static void conf_string(struct menu *menu);
static void conf_load(void);
static void conf_save(void);
static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
static void show_readme(void);

static void
init_wsize(void)
{
    struct winsize ws;

    if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
	rows = 24;
	cols = 80;
    } else {
	rows = ws.ws_row;
	cols = ws.ws_col;
    }

    if (rows < 19 || cols < 80) {
	fprintf(stderr, "Your display is too small to run Menuconfig!\n");
	fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
	exit(1);
    }

    rows -= 4;
    cols -= 5;
}

static void
cinit(void)
{
    item_no = 0;
}

static void
cmake(void)
{
    items[item_no] = malloc(sizeof(struct dialog_list_item));
    memset(items[item_no], 0, sizeof(struct dialog_list_item));
    items[item_no]->tag = malloc(32);
    items[item_no]->tag[0] = 0;
    items[item_no]->name = malloc(512);
    items[item_no]->name[0] = 0;
    items[item_no]->namelen = 0;
    item_no++;
}

static int
cprint_name(const char *fmt, ...)
{
    va_list ap;
    int res;

    if (!item_no)
	cmake();
    va_start(ap, fmt);
    res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
		    512 - items[item_no - 1]->namelen, fmt, ap);
    if (res > 0)
	items[item_no - 1]->namelen += res;
    va_end(ap);

    return res;
}

static int
cprint_tag(const char *fmt, ...)
{
    va_list ap;
    int res;

    if (!item_no)
	cmake();
    va_start(ap, fmt);
    res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
    va_end(ap);

    return res;
}

static void
cdone(void)
{
    int i;

    for (i = 0; i < item_no; i++) {
	free(items[i]->tag);
	free(items[i]->name);
	free(items[i]);
    }

    item_no = 0;
}

static void
build_conf(struct menu *menu)
{
    struct symbol *sym;
    struct property *prop;
    struct menu *child;
    int type, tmp, doint = 2;
    tristate val;
    char ch;

    if (!menu_is_visible(menu))
	return;

    sym = menu->sym;
    prop = menu->prompt;
    if (!sym) {
	if (prop && menu != current_menu) {
	    const char *prompt = menu_get_prompt(menu);
	    switch (prop->type) {
	    case P_MENU:
		child_count++;
		cmake();
		cprint_tag("m%p", menu);

		if (single_menu_mode) {
		    cprint_name("%s%*c%s",
				menu->data ? "-->" : "++>",
				indent + 1, ' ', prompt);
		} else {
		    if (menu->parent != &rootmenu)
			cprint_name("   %*c", indent + 1, ' ');
		    cprint_name("%s  --->", prompt);
		}

		if (single_menu_mode && menu->data)
		    goto conf_childs;
		return;
	    default:
		if (prompt) {
		    child_count++;
		    cmake();
		    cprint_tag(":%p", menu);
		    cprint_name("---%*c%s", indent + 1, ' ', prompt);
		}
	    }
	} else
	    doint = 0;
	goto conf_childs;
    }

    cmake();
    type = sym_get_type(sym);
    if (sym_is_choice(sym)) {
	struct symbol *def_sym = sym_get_choice_value(sym);
	struct menu *def_menu = NULL;

	child_count++;
	for (child = menu->list; child; child = child->next) {
	    if (menu_is_visible(child) && child->sym == def_sym)
		def_menu = child;
	}

	val = sym_get_tristate_value(sym);
	if (sym_is_changable(sym)) {
	    cprint_tag("t%p", menu);
	    switch (type) {
	    case S_BOOLEAN:
		cprint_name("[%c]", val == no ? ' ' : '*');
		break;
	    case S_TRISTATE:
		switch (val) {
		case yes:
		    ch = '*';
		    break;
		case mod:
		    ch = 'M';
		    break;
		default:
		    ch = ' ';
		    break;
		}
		cprint_name("<%c>", ch);
		break;
	    }
	} else {
	    cprint_tag("%c%p", def_menu ? 't' : ':', menu);
	    cprint_name("   ");
	}

	cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
	if (val == yes) {
	    if (def_menu) {
		cprint_name(" (%s)", menu_get_prompt(def_menu));
		cprint_name("  --->");
		if (def_menu->list) {
		    indent += 2;
		    build_conf(def_menu);
		    indent -= 2;
		}
	    }
	    return;
	}
    } else {
	child_count++;
	val = sym_get_tristate_value(sym);
	if (sym_is_choice_value(sym) && val == yes) {
	    cprint_tag(":%p", menu);
	    cprint_name("   ");
	} else {
	    switch (type) {
	    case S_BOOLEAN:
		cprint_tag("t%p", menu);
		cprint_name("[%c]", val == no ? ' ' : '*');
		break;
	    case S_TRISTATE:
		cprint_tag("t%p", menu);
		switch (val) {
		case yes:
		    ch = '*';
		    break;
		case mod:
		    ch = 'M';
		    break;
		default:
		    ch = ' ';
		    break;
		}
		cprint_name("<%c>", ch);
		break;
	    default:
		cprint_tag("s%p", menu);
		tmp = cprint_name("(%s)", sym_get_string_value(sym));
		tmp = indent - tmp + 4;
		if (tmp < 0)
		    tmp = 0;
		cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
			    sym_has_value(sym) ? "" : " (NEW)");
		goto conf_childs;
	    }
	}
	cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
		    sym_has_value(sym) ? "" : " (NEW)");
    }

  conf_childs:
    indent += doint;
    for (child = menu->list; child; child = child->next)
	build_conf(child);
    indent -= doint;
}

static void
conf(struct menu *menu)
{
    struct dialog_list_item *active_item = NULL;
    struct menu *submenu;
    const char *prompt = menu_get_prompt(menu);
    struct symbol *sym;
    char active_entry[40];
    int stat, type;

    unlink("lxdialog.scrltmp");
    active_entry[0] = 0;
    while (1) {
	indent = 0;
	child_count = 0;
	current_menu = menu;
	cdone();
	cinit();
	build_conf(menu);
	if (!child_count)
	    break;
	if (menu == &rootmenu) {
	    cmake();
	    cprint_tag(":");
	    cprint_name("--- ");
	    cmake();
	    cprint_tag("L");
	    cprint_name("Load an Alternate Configuration File");
	    cmake();
	    cprint_tag("S");
	    cprint_name("Save Configuration to an Alternate File");
	}
	dialog_clear();
	stat = dialog_menu(prompt ? prompt : "Main Menu",
			   menu_instructions, rows, cols, rows - 10,
			   active_entry, item_no, items);
	if (stat < 0)
	    return;

	if (stat == 1 || stat == 255)
	    break;

	active_item = first_sel_item(item_no, items);
	if (!active_item)
	    continue;
	active_item->selected = 0;
	strncpy(active_entry, active_item->tag, sizeof(active_entry));
	active_entry[sizeof(active_entry) - 1] = 0;
	type = active_entry[0];
	if (!type)
	    continue;

	sym = NULL;
	submenu = NULL;
	if (sscanf(active_entry + 1, "%p", &submenu) == 1)
	    sym = submenu->sym;

	switch (stat) {
	case 0:
	    switch (type) {
	    case 'm':
		if (single_menu_mode)
		    submenu->data = (submenu->data) ? NULL : (void *) 1;
		else
		    conf(submenu);
		break;
	    case 't':
		if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
		    conf_choice(submenu);
		break;
	    case 's':
		conf_string(submenu);
		break;
	    case 'L':
		conf_load();
		break;
	    case 'S':
		conf_save();
		break;
	    }
	    break;
	case 2:
	    if (sym)
		show_help(submenu);
	    else
		show_readme();
	    break;
	case 3:
	    if (type == 't') {
		if (sym_set_tristate_value(sym, yes))
		    break;
		if (sym_set_tristate_value(sym, mod))
		    show_textbox(NULL, setmod_text, 6, 74);
	    }
	    break;
	case 4:
	    if (type == 't')
		sym_set_tristate_value(sym, no);
	    break;
	case 5:
	    if (type == 't')
		sym_set_tristate_value(sym, mod);
	    break;
	case 6:
	    if (type == 't')
		sym_toggle_tristate_value(sym);
	    else if (type == 'm')
		conf(submenu);
	    break;
	}
    }
}

static void
show_textbox(const char *title, const char *text, int r, int c)
{
    int fd;

    fd = creat(".help.tmp", 0777);
    write(fd, text, strlen(text));
    close(fd);
    while (dialog_textbox(title, ".help.tmp", r, c) < 0);
    unlink(".help.tmp");
}

static void
show_helptext(const char *title, const char *text)
{
    show_textbox(title, text, rows, cols);
}

static void
show_help(struct menu *menu)
{
    const char *help;
    char *helptext;
    struct symbol *sym = menu->sym;

    help = sym->help;
    if (!help)
	help = nohelp_text;
    if (sym->name) {
	helptext = malloc(strlen(sym->name) + strlen(help) + 16);
	sprintf(helptext, "%s:\n\n%s", sym->name, help);
	show_helptext(menu_get_prompt(menu), helptext);
	free(helptext);
    } else
	show_helptext(menu_get_prompt(menu), help);
}

static void
show_readme(void)
{
    while (dialog_textbox(NULL, "scripts/README.Menuconfig", rows, cols) < 0);
}

static void
conf_choice(struct menu *menu)
{
    const char *prompt = menu_get_prompt(menu);
    struct menu *child;
    struct symbol *active;

    while (1) {
	current_menu = menu;
	active = sym_get_choice_value(menu->sym);
	cdone();
	cinit();
	for (child = menu->list; child; child = child->next) {
	    if (!menu_is_visible(child))
		continue;
	    cmake();
	    cprint_tag("%p", child);
	    cprint_name("%s", menu_get_prompt(child));
	    items[item_no - 1]->selected = (child->sym == active);
	}

	switch (dialog_checklist(prompt ? prompt : "Main Menu",
				 radiolist_instructions, 15, 70, 6,
				 item_no, items, FLAG_RADIO)) {
	case 0:
	    if (sscanf(first_sel_item(item_no, items)->tag, "%p", &menu) != 1)
		break;
	    sym_set_tristate_value(menu->sym, yes);
	    return;
	case 1:
	    show_help(menu);
	    break;
	case 255:
	    return;
	}
    }
}

static void
conf_string(struct menu *menu)
{
    const char *prompt = menu_get_prompt(menu);

    while (1) {
	char *heading;

	switch (sym_get_type(menu->sym)) {
	case S_INT:
	    heading = (char *) inputbox_instructions_int;
	    break;
	case S_HEX:
	    heading = (char *) inputbox_instructions_hex;
	    break;
	case S_STRING:
	    heading = (char *) inputbox_instructions_string;
	    break;
	default:
	    heading = "Internal mconf error!";
	    /* panic? */ ;
	}

	switch (dialog_inputbox(prompt ? prompt : "Main Menu",
				heading, 10, 75,
				sym_get_string_value(menu->sym))) {
	case 0:
	    if (sym_set_string_value(menu->sym, dialog_input_result))
		return;
	    show_textbox(NULL, "You have made an invalid entry.", 5, 43);
	    break;
	case 1:
	    show_help(menu);
	    break;
	case 255:
	    return;
	}
    }
}

static void
conf_load(void)
{
    while (1) {
	switch (dialog_inputbox(NULL, load_config_text, 11, 55, filename)) {
	case 0:
	    if (!dialog_input_result[0])
		return;
	    if (!conf_read(dialog_input_result))
		return;
	    show_textbox(NULL, "File does not exist!", 5, 38);
	    break;
	case 1:
	    show_helptext("Load Alternate Configuration", load_config_help);
	    break;
	case 255:
	    return;
	}
    }
}

static void
conf_save(void)
{
    while (1) {
	switch (dialog_inputbox(NULL, save_config_text, 11, 55, filename)) {
	case 0:
	    if (!dialog_input_result[0])
		return;
	    if (!conf_write(dialog_input_result))
		return;
	    show_textbox(NULL,
			 "Can't create file!  Probably a nonexistent directory.",
			 5, 60);
	    break;
	case 1:
	    show_helptext("Save Alternate Configuration", save_config_help);
	    break;
	case 255:
	    return;
	}
    }
}

static void
conf_cleanup(void)
{
    tcsetattr(1, TCSAFLUSH, &ios_org);
    unlink(".help.tmp");
    unlink("lxdialog.scrltmp");
}

static void
winch_handler(int sig)
{
    struct winsize ws;

    if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
	rows = 24;
	cols = 80;
    } else {
	rows = ws.ws_row;
	cols = ws.ws_col;
    }

    if (rows < 19 || cols < 80) {
	end_dialog();
	fprintf(stderr, "Your display is too small to run Menuconfig!\n");
	fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
	exit(1);
    }

    rows -= 4;
    cols -= 5;

}

int
main(int ac, char **av)
{
    int stat;
    char *mode;
    struct symbol *sym;

    conf_parse(av[1]);
    conf_read(NULL);

    backtitle = malloc(128);
    sym = sym_lookup("VERSION", 0);
    sym_calc_value(sym);
    snprintf(backtitle, 128, "Pixil Configuration",
	     sym_get_string_value(sym));

    mode = getenv("MENUCONFIG_MODE");
    if (mode) {
	if (!strcasecmp(mode, "single_menu"))
	    single_menu_mode = 1;
    }

    tcgetattr(1, &ios_org);
    atexit(conf_cleanup);
    init_wsize();
    init_dialog();
    signal(SIGWINCH, winch_handler);
    conf(&rootmenu);
    end_dialog();

    /* Restart dialog to act more like when lxdialog was still separate */
    init_dialog();
    do {
	stat = dialog_yesno(NULL,
			    "Do you wish to save your new Pixil configuration?",
			    5, 60);
    } while (stat < 0);
    end_dialog();

    if (stat == 0) {
	conf_write(NULL);
	printf("\n\n"
	       "*** End of Pixil configuration.\n"
	       "*** Check the top-level Makefile for additional configuration options.\n\n");
    } else
	printf("\n\nYour Pixil configuration changes were NOT saved.\n\n");

    return 0;
}

--- NEW FILE: checklist.c ---
/*
 *  checklist.c -- implements the checklist box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *     Stuart Herbert - S.Herbert at sheffield.ac.uk: radiolist extension
 *     Alessandro Rubini - rubini at ipvvis.unipv.it: merged the two
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at 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, checkflag;

/*
 * 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);
    if (checkflag == FLAG_CHECK)
	wprintw(win, "[%c]", status ? 'X' : ' ');
    else
	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
 * The `flag' parameter is used to select between radiolist and checklist.
 */
int
dialog_checklist(const char *title, const char *prompt, int height, int width,
		 int list_height, int item_no,
		 struct dialog_list_item **items, int flag)
{
    int i, x, y, box_x, box_y;
    int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
    WINDOW *dialog, *list;

    checkflag = flag;

    /* 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] = items[i]->selected;
	if (!choice && status[i])
	    choice = i;
    }

    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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }

    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]->name) + 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]->name,
		   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]->name[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]->name,
				   status[scroll], 0, FALSE);
			scrollok(list, TRUE);
			wscrl(list, -1);
			scrollok(list, FALSE);
		    }
		    scroll--;
		    print_item(list, items[scroll]->name,
			       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]->name,
				   status[scroll + max_choice - 1],
				   max_choice - 1, FALSE);
			scrollok(list, TRUE);
			scroll(list);
			scrollok(list, FALSE);
		    }
		    scroll++;
		    print_item(list, items[scroll + max_choice - 1]->name,
			       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]->name,
			   status[scroll + choice], choice, FALSE);
		/* Highlight new item */
		choice = i;
		print_item(list, items[scroll + choice]->name,
			   status[scroll + choice], choice, TRUE);
		wnoutrefresh(list);
		wrefresh(dialog);
	    }
	    continue;		/* wait for another key press */
	}
	switch (key) {
	case 'H':
	case 'h':
	case '?':
	    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 (flag == FLAG_CHECK) {
		    status[scroll + choice] = !status[scroll + choice];
		    wmove(list, choice, check_x);
		    wattrset(list, check_selected_attr);
		    wprintw(list, "[%c]",
			    status[scroll + choice] ? 'X' : ' ');
		} else {
		    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]->name,
				       status[scroll + i], i, i == choice);
		    }
		}
		wnoutrefresh(list);
		wrefresh(dialog);

		for (i = 0; i < item_no; i++) {
		    items[i]->selected = status[i];
		}
	    }
	    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 */
}

--- NEW FILE: msgbox.c ---
/*
 *  msgbox.c -- implements the message box and info box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw at 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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }
    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;
}

--- NEW FILE: conf.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at 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;

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[] = "Sorry, no help available for this option yet.\n";

#if 0
static void
printc(int ch)
{
    static int sep = 0;

    if (!sep) {
	putchar('[');
	sep = 1;
    } else if (ch)
	putchar('/');
    if (!ch) {
	putchar(']');
	putchar(' ');
	sep = 0;
    } else
	putchar(ch);
}
#endif

static void
printo(const char *o)
{
    static int sep = 0;

    if (!sep) {
	putchar('(');
	sep = 1;
    } else if (o) {
	putchar(',');
	putchar(' ');
    }
    if (!o) {
	putchar(')');
	putchar(' ');
	sep = 0;
    } else
	printf("%s", o);
}

static void
strip(char *str)
{
    char *p = str;
    int l;

    while ((isspace((int) *p)))
	p++;
    l = strlen(p);
    if (p != str)
	memmove(str, p, l + 1);
    if (!l)
	return;
    p = str + l - 1;
    while ((isspace((int) *p)))
	*p-- = 0;
}

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;

    switch (input_mode) {
    case ask_new:
    case ask_silent:
	if (sym_has_value(sym)) {
	    printf("%s\n", def);
	    return;
	}
	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);
	}
    case ask_all:
	fflush(stdout);
	fgets(line, 128, stdin);
	return;
    case set_default:
	printf("%s\n", def);
	return;
    default:
	break;
    }

    switch (type) {
    case S_INT:
    case S_HEX:
    case S_STRING:
	printf("%s\n", def);
	return;
    default:
	;
    }
    switch (input_mode) {
    case set_yes:
	if (sym_tristate_within_range(sym, yes)) {
	    line[0] = 'y';
	    line[1] = '\n';
	    line[2] = 0;
	    break;
	}
    case set_mod:
	if (type == S_TRISTATE) {
	    if (sym_tristate_within_range(sym, mod)) {
		line[0] = 'm';
		line[1] = '\n';
		line[2] = 0;
		break;
	    }
	} else {
	    if (sym_tristate_within_range(sym, yes)) {
		line[0] = 'y';
		line[1] = '\n';
		line[2] = 0;
		break;
	    }
	}
    case set_no:
	if (sym_tristate_within_range(sym, no)) {
	    line[0] = 'n';
	    line[1] = '\n';
	    line[2] = 0;
	    break;
	}
    case set_random:
	do {
	    val = (tristate) (random() % 3);
	} while (!sym_tristate_within_range(sym, val));
	switch (val) {
	case no:
	    line[0] = 'n';
	    break;
	case mod:
	    line[0] = 'm';
	    break;
	case yes:
	    line[0] = 'y';
	    break;
	}
	line[1] = '\n';
	line[2] = 0;
	break;
    default:
	break;
    }
    printf("%s", line);
}

int
conf_string(struct menu *menu)
{
    struct symbol *sym = menu->sym;
    const char *def, *help;

    while (1) {
	printf("%*s%s ", indent - 1, "", menu->prompt->text);
	printf("(%s) ", sym->name);
	def = sym_get_string_value(sym);
	if (sym_get_string_value(sym))
	    printf("[%s] ", def);
	conf_askvalue(sym, def);
	switch (line[0]) {
	case '\n':
	    break;
	case '?':
	    /* print help */
	    if (line[1] == 0) {
		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 *cmenu, *def_menu;
    const char *help;
    int type, len;
    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 {
	sym->def = sym->curr;
	if (S_TRI(sym->curr) == mod) {
	    printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
	    return 0;
	}
    }

    while (1) {
	printf("%*s%s ", indent - 1, "", menu_get_prompt(menu));
	def_sym = sym_get_choice_value(sym);
	def_menu = NULL;
	for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
	    if (!menu_is_visible(cmenu))
		continue;
	    printo(menu_get_prompt(cmenu));
	    if (cmenu->sym == def_sym)
		def_menu = cmenu;
	}
	printo(NULL);
	if (def_menu)
	    printf("[%s] ", menu_get_prompt(def_menu));
	else {
	    printf("\n");
	    return 1;
	}
	switch (input_mode) {
	case ask_new:
	case ask_silent:
	case ask_all:
	    conf_askvalue(sym, menu_get_prompt(def_menu));
	    strip(line);
	    break;
	default:
	    line[0] = 0;
	    printf("\n");
	}
	if (line[0] == '?' && !line[1]) {
	    help = nohelp_text;
	    if (menu->sym->help)
		help = menu->sym->help;
	    printf("\n%s\n", help);
	    continue;
	}
	if (line[0]) {
	    len = strlen(line);
	    line[len] = 0;

	    def_menu = NULL;
	    for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
		if (!cmenu->sym || !menu_is_visible(cmenu))
		    continue;
		if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
		    def_menu = cmenu;
		    break;
		}
	    }
	}
	if (def_menu) {
	    sym_set_choice_value(sym, def_menu->sym);
	    if (def_menu->list) {
		indent += 2;
		conf(def_menu->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 (S_TRI(sym->curr) != 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)
	goto conf_childs;

    if (sym_is_choice(sym)) {
	if (!sym_has_value(sym)) {
	    if (!conf_cnt++)
		printf("*\n* Restart config...\n*\n");
	    rootEntry = menu_get_parent_menu(menu);
	    conf(rootEntry);
	}
	if (sym_get_tristate_value(sym) != mod)
	    return;
	goto conf_childs;
    }

    if (!sym_has_value(sym)) {
	if (!conf_cnt++)
	    printf("*\n* Restart config...\n*\n");
	rootEntry = menu_get_parent_menu(menu);
	conf(rootEntry);
    }

  conf_childs:
    for (child = menu->list; child; child = child->next)
	check_conf(child);
}

int
main(int ac, char **av)
{
    const char *name;
    struct stat tmpstat;

    if (ac > 1 && av[1][0] == '-') {
	switch (av[1][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 '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[2];
    } else
	name = av[1];
    conf_parse(name);
    //zconfdump(stdout);
    switch (input_mode) {
    case set_default:
	name = conf_get_default_confname();
	if (conf_read(name)) {
	    printf("***\n"
		   "*** Can't find default configuration \"%s\"!\n"
		   "***\n", name);
	    exit(1);
	}
	break;
    case ask_silent:
	if (stat("config", &tmpstat)) {
	    printf("***\n"
		   "*** You have not yet configured Pixil!\n"
		   "***\n"
		   "*** Please run some configurator (e.g. \"make oldconfig\"\n"
		   "*** or \"make menuconfig\").\n" "***\n");
	    exit(1);
	}
    case ask_all:
    case ask_new:
	conf_read(NULL);
	break;
    default:
	break;
    }

    if (input_mode != ask_silent) {
	rootEntry = &rootmenu;
	conf(&rootmenu);
	if (input_mode == ask_all) {
	    input_mode = ask_silent;
	    valid_stdin = 1;
	}
    }
    do {
	conf_cnt = 0;
	check_conf(&rootmenu);
    } while (conf_cnt);
    conf_write(NULL);
    return 0;
}

--- NEW FILE: yesno.c ---
/*
 *  yesno.c -- implements the yes/no box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at 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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }

    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 */
}

--- NEW FILE: symbol.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 */

#include <ctype.h>
#include <stdlib.h>
#include <string.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;

void
sym_add_default(struct symbol *sym, const char *def)
{
    struct property *prop = create_prop(P_DEFAULT);
    struct property **propp;

    prop->sym = sym;
    prop->def = sym_lookup(def, 1);

    /* append property to the prop list of symbol */
    if (prop->sym) {
	for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next);
	*propp = prop;
    }
}

void
sym_init(void)
{
    struct symbol *sym;
    struct utsname uts;
    char *p;
    static bool inited = false;

    if (inited)
	return;
    inited = true;

    uname(&uts);

#if 0
    sym = sym_lookup("ARCH", 0);
    sym->type = S_STRING;
    sym->flags |= SYMBOL_AUTO;
    p = getenv("ARCH");
    if (p)
	sym_add_default(sym, p);
#endif

    sym = sym_lookup("VERSION", 0);
    sym->type = S_STRING;
    sym->flags |= SYMBOL_AUTO;
    p = getenv("VERSION");
    if (p)
	sym_add_default(sym, p);

#if 0
    sym = sym_lookup("UNAME_RELEASE", 0);
    sym->type = S_STRING;
    sym->flags |= SYMBOL_AUTO;
    sym_add_default(sym, uts.release);
#endif

    sym = sym_lookup("TARGET_ARCH", 0);
    sym->type = S_STRING;
    sym->flags |= SYMBOL_AUTO;
    p = getenv("TARGET_ARCH");
    if (p)
	sym_add_default(sym, p);
}

int
sym_get_type(struct symbol *sym)
{
    int type = sym->type;
    if (type == S_TRISTATE) {
	if (sym_is_choice_value(sym) && sym->visible == yes)
	    type = S_BOOLEAN;
	else {
	    sym_calc_value(modules_sym);
	    if (S_TRI(modules_sym->curr) == no)
		type = S_BOOLEAN;
	}
    }
    return type;
}

const char *
sym_type_name(int 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";
    }
    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;
    tristate visible;

    for_all_defaults(sym, prop) {
	visible = E_CALC(prop->visible);
	if (visible != no)
	    return prop;
    }
    return NULL;
}

void
sym_calc_visibility(struct symbol *sym)
{
    struct property *prop;
    tristate visible, oldvisible;

    /* any prompt visible? */
    oldvisible = sym->visible;
    visible = no;
    for_all_prompts(sym, prop)
	visible = E_OR(visible, E_CALC(prop->visible));
    if (oldvisible != visible) {
	sym->visible = visible;
	sym->flags |= SYMBOL_CHANGED;
    }
}

void
sym_calc_value(struct symbol *sym)
{
    struct symbol_value newval, oldval;
    struct property *prop, *def_prop;
    struct symbol *def_sym;
    struct expr *e;

    if (sym->flags & SYMBOL_VALID)
	return;

    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:
	S_VAL(newval) = sym->name;
	S_TRI(newval) = no;
	if (sym->flags & SYMBOL_CONST) {
	    goto out;
	}
	//newval = symbol_empty.curr;
	// generate warning somewhere here later
	//S_TRI(newval) = yes;
	goto out;
    }
    sym->flags |= SYMBOL_VALID;
    if (!sym_is_choice_value(sym))
	sym->flags &= ~SYMBOL_WRITE;

    sym_calc_visibility(sym);

    /* set default if recursively called */
    sym->curr = newval;

    if (sym->visible != no) {
	sym->flags |= SYMBOL_WRITE;
	if (!sym_has_value(sym)) {
	    if (!sym_is_choice(sym)) {
		prop = sym_get_default_prop(sym);
		if (prop) {
		    sym_calc_value(prop->def);
		    newval = prop->def->curr;
		}
	    }
	} else
	    newval = sym->def;

	S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);
	/* if the symbol is visible and not optionial,
	 * possibly ignore old user choice. */
	if (!sym_is_optional(sym) && S_TRI(newval) == no)
	    S_TRI(newval) = sym->visible;
	if (sym_is_choice_value(sym) && sym->visible == yes) {
	    prop = sym_get_choice_prop(sym);
	    S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;
	}
    } else {
	prop = sym_get_default_prop(sym);
	if (prop) {
	    sym->flags |= SYMBOL_WRITE;
	    sym_calc_value(prop->def);
	    newval = prop->def->curr;
	}
    }

    switch (sym_get_type(sym)) {
    case S_TRISTATE:
	if (S_TRI(newval) != mod)
	    break;
	sym_calc_value(modules_sym);
	if (S_TRI(modules_sym->curr) == no)
	    S_TRI(newval) = yes;
	break;
    case S_BOOLEAN:
	if (S_TRI(newval) == mod)
	    S_TRI(newval) = yes;
    }

  out:
    sym->curr = newval;

    if (sym_is_choice(sym) && S_TRI(newval) == yes) {
	def_sym = S_VAL(sym->def);
	if (def_sym) {
	    sym_calc_visibility(def_sym);
	    if (def_sym->visible == no)
		def_sym = NULL;
	}
	if (!def_sym) {
	    for_all_defaults(sym, def_prop) {
		if (E_CALC(def_prop->visible) == no)
		    continue;
		sym_calc_visibility(def_prop->def);
		if (def_prop->def->visible != no) {
		    def_sym = def_prop->def;
		    break;
		}
	    }
	}

	if (!def_sym) {
	    prop = sym_get_choice_prop(sym);
	    for (e = prop->dep; e; e = e->left.expr) {
		sym_calc_visibility(e->right.sym);
		if (e->right.sym->visible != no) {
		    def_sym = e->right.sym;
		    break;
		}
	    }
	}

	S_VAL(newval) = def_sym;
    }

    if (memcmp(&oldval, &newval, sizeof(newval)))
	sym->flags |= SYMBOL_CHANGED;
    sym->curr = newval;

    if (sym_is_choice(sym)) {
	int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
	prop = sym_get_choice_prop(sym);
	for (e = prop->dep; e; e = e->left.expr)
	    e->right.sym->flags |= flags;
    }
}

void
sym_clear_all_valid(void)
{
    struct symbol *sym;
    int i;

    for_all_symbols(i, sym)
	sym->flags &= ~SYMBOL_VALID;
    sym_change_count++;
}

void
sym_set_all_changed(void)
{
    struct symbol *sym;
    int i;

    for_all_symbols(i, sym)
	sym->flags |= SYMBOL_CHANGED;
}

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;

    switch (val) {
    case no:
	if (sym_is_choice_value(sym) && sym->visible == yes)
	    return false;
	return sym_is_optional(sym);
    case mod:
	if (sym_is_choice_value(sym) && sym->visible == yes)
	    return false;
	return type == S_TRISTATE;
    case yes:
	return type == S_BOOLEAN || sym->visible == yes;
    }
    return false;
}

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->flags |= SYMBOL_CHANGED;
    }
    if (sym_is_choice_value(sym) && val == yes) {
	struct property *prop = sym_get_choice_prop(sym);

	S_VAL(prop->def->def) = sym;
	prop->def->flags &= ~SYMBOL_NEW;
    }

    S_TRI(sym->def) = 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)
{
    char ch;

    switch (sym->type) {
    case S_STRING:
	return true;
    case S_INT:
	ch = *str++;
	if (ch == '-')
	    ch = *str++;
	if (!isdigit((int) ch))
	    return false;
	if (ch == '0' && *str != 0)
	    return false;
	while ((ch = *str++)) {
	    if (!isdigit((int) 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((int) ch))
		return false;
	} while ((ch = *str++));
	return true;
    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_valid(sym, newval))
	return false;

    if (sym->flags & SYMBOL_NEW) {
	sym->flags &= ~SYMBOL_NEW;
	sym->flags |= SYMBOL_CHANGED;
    }

    oldval = S_VAL(sym->def);
    size = strlen(newval) + 1;
    if (sym->type == S_HEX
	&& (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
	size += 2;
	S_VAL(sym->def) = val = malloc(size);
	*val++ = '0';
	*val++ = 'x';
    } else if (!oldval || strcmp(oldval, newval))
	S_VAL(sym->def) = 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 *) S_VAL(sym->curr);
}

bool
sym_is_changable(struct symbol *sym)
{
    if (sym->visible == no)
	return false;
    /* at least 'n' and 'y'/'m' is selectable */
    if (sym_is_optional(sym))
	return true;
    /* no 'n', so 'y' and 'm' must be selectable */
    if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
	return true;
    return false;
}

struct symbol *
sym_lookup(const char *name, int isconst)
{
    struct symbol *symbol;
    const char *ptr;
    char *new_name;
    int hash = 0;

    //printf("lookup: %s -> ", name);
    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))) {
		    //printf("h:%p\n", symbol);
		    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;

    //printf("n:%p\n", 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;
}

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_ROOTMENU:
	return "rootmenu";
    case P_DEFAULT:
	return "default";
    case P_CHOICE:
	return "choice";
    default:
	return "unknown";
    }
}

--- NEW FILE: menu.c ---
/*
 * Copyright (C) 2002 Roman Zippel <zippel at 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;
struct menu *current_menu, *current_entry;
static struct menu **last_entry_ptr;

struct file *file_list;
struct file *current_file;

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)
{
}

void
menu_add_menu(void)
{
    current_menu = current_entry;
    last_entry_ptr = &current_entry->list;
}

void
menu_end_menu(void)
{
    last_entry_ptr = &current_menu->next;
    current_menu = current_menu->parent;
}

void
menu_add_dep(struct expr *dep)
{
    current_entry->dep = expr_alloc_and(current_entry->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;
    }
    fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n",
	    current_entry->file->name, current_entry->lineno,
	    sym->name ? sym->name : "<choice>", sym_type_name(sym->type),
	    sym_type_name(type));
}

struct property *
create_prop(enum prop_type type)
{
    struct property *prop;

    prop = malloc(sizeof(*prop));
    memset(prop, 0, sizeof(*prop));
    prop->type = type;
    prop->file = current_file;
    prop->lineno = zconf_lineno();

    return prop;
}

struct property *
menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
{
    struct property *prop = create_prop(token);
    struct property **propp;

    prop->sym = current_entry->sym;
    prop->menu = current_entry;
    prop->text = prompt;
    prop->def = def;
    E_EXPR(prop->visible) = dep;

    if (prompt)
	current_entry->prompt = prop;

    /* append property to the prop list of symbol */
    if (prop->sym) {
	for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next);
	*propp = prop;
    }

    return prop;
}

void
menu_add_prompt(int token, char *prompt, struct expr *dep)
{
    current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
}

void
menu_add_default(int token, struct symbol *def, struct expr *dep)
{
    current_entry->prompt = menu_add_prop(token, NULL, def, dep);
}

void
menu_finalize(struct menu *parent)
{
    struct menu *menu, *last_menu;
    struct symbol *sym;
    struct property *prop;
    struct expr *parentdep, *basedep, *dep, *dep2;

    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 = E_EXPR(parent->prompt->visible);
	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(E_EXPR(prop->visible));
		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);
		E_EXPR(prop->visible) = dep;
	    }
	}
	for (menu = parent->list; menu; menu = menu->next)
	    menu_finalize(menu);
    } else if (sym && parent->prompt) {
	basedep = E_EXPR(parent->prompt->visible);
	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 ? E_EXPR(menu->prompt->visible) : 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;
	    current_entry = menu;
	    menu_set_type(sym->type);
	    menu_add_prop(P_CHOICE, NULL, parent->sym, NULL);
	    prop = sym_get_choice_prop(parent->sym);
	    //dep = expr_alloc_one(E_CHOICE, dep);
	    //dep->right.sym = menu->sym;
	    prop->dep = expr_alloc_one(E_CHOICE, prop->dep);
	    prop->dep->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;
	}
    }
}

bool
menu_is_visible(struct menu *menu)
{
    tristate visible;

    if (!menu->prompt)
	return false;
    if (menu->sym) {
	sym_calc_value(menu->sym);
	visible = E_TRI(menu->prompt->visible);
    } else
	visible = E_CALC(menu->prompt->visible);
    return visible != no;
}

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;

    while (menu != &rootmenu) {
	menu = menu->parent;
	type = menu->prompt ? menu->prompt->type : 0;
	if (type == P_MENU || type == P_ROOTMENU)
	    break;
    }
    return menu;
}

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;
}

int
file_write_dep(const char *name)
{
    struct file *file;
    FILE *out;

    if (!name)
	name = ".config.cmd";
    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/config.h: $(deps_config)\n\n$(deps_config):\n");
    fclose(out);
    rename(".config.tmp", name);
    return 0;
}

--- NEW FILE: menubox.c ---
/*
 *  menubox.c -- implements the menu box
 *
 *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw at 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 at 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 at 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"

static int menu_width, item_x;

/*
 * Print menu item
 */
static void
print_item(WINDOW * win, const char *item, int choice, int selected,
	   int hotkey)
{
    int j;
    char menu_item[menu_width + 1];

    strncpy(menu_item, item, menu_width);
    menu_item[menu_width] = 0;
    j = first_alpha(menu_item, "YyNnMm");

    /* 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_x, menu_item);
    if (hotkey) {
	wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
	mvwaddch(win, choice, item_x + j, menu_item[j]);
    }
    if (selected) {
	wmove(win, choice, item_x + 1);
	wrefresh(win);
    }
}

/*
 * 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);

    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);
}

/*
 * 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);
}

/*
 * 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,
	    struct dialog_list_item **items)
{
    int i, j, x, y, box_x, box_y;
    int key = 0, button = 0, scroll = 0, choice = 0, 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);

    if (title != NULL && strlen(title) >= width - 2) {
	/* truncate long title -- mec */
	char *title2 = malloc(width - 2 + 1);
	memcpy(title2, title, width - 2);
	title2[width - 2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset(dialog, title_attr);
	mvwaddch(dialog, 0, (width - strlen(title)) / 2 - 1, ' ');
	waddstr(dialog, (char *) title);
	waddch(dialog, ' ');
    }

    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);

    /*
     * Find length of longest item in order to center menu.
     * Set 'choice' to default item. 
     */
    item_x = 0;
    for (i = 0; i < item_no; i++) {
	item_x = MAX(item_x, MIN(menu_width, strlen(items[i]->name) + 2));
	if (strcmp(current, items[i]->tag) == 0)
	    choice = i;
    }

    item_x = (menu_width - item_x) / 2;

    /* 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(menu, items[first_item + i]->name, i, i == choice,
		   (items[first_item + i]->tag[0] != ':'));
    }

    //wnoutrefresh(menu);
    wrefresh(menu);

    print_arrows(dialog, item_no, scroll,
		 box_y, box_x + item_x + 1, menu_height);

    print_buttons(dialog, height, width, 0);
    wmove(menu, choice, item_x + 1);
    wrefresh(menu);

    while (key != ESC) {
	key = wgetch(menu);

	if (key < 256 && isalpha(key))
	    key = tolower(key);

	if (strchr("ynm", key))
	    i = max_choice;
	else {
	    for (i = choice + 1; i < max_choice; i++) {
		j = first_alpha(items[scroll + i]->name, "YyNnMm>");
		if (key == tolower(items[scroll + i]->name[j]))
		    break;
	    }
	    if (i == max_choice)
		for (i = 0; i < max_choice; i++) {
		    j = first_alpha(items[scroll + i]->name, "YyNnMm>");
		    if (key == tolower(items[scroll + i]->name[j]))
			break;
		}
	}

	if (i < max_choice ||
	    key == KEY_UP || key == KEY_DOWN ||
	    key == '-' || key == '+' ||
	    key == KEY_PPAGE || key == KEY_NPAGE) {

	    print_item(menu, items[scroll + choice]->name, choice, FALSE,
		       (items[scroll + choice]->tag[0] != ':'));

	    if (key == KEY_UP || key == '-') {
		if (choice < 2 && scroll) {
		    /* Scroll menu down */
		    scrollok(menu, TRUE);
		    wscrl(menu, -1);
		    scrollok(menu, FALSE);

		    scroll--;

		    print_item(menu, items[scroll]->name, 0, FALSE,
			       (items[scroll]->tag[0] != ':'));
		} else
		    choice = MAX(choice - 1, 0);

	    } else if (key == KEY_DOWN || key == '+') {

		print_item(menu, items[scroll + choice]->name, choice, FALSE,
			   (items[scroll + choice]->tag[0] != ':'));

		if ((choice > max_choice - 3) &&
		    (scroll + max_choice < item_no)
		    ) {
		    /* Scroll menu up */
		    scrollok(menu, TRUE);
		    scroll(menu);
		    scrollok(menu, FALSE);

		    scroll++;

		    print_item(menu, items[scroll + max_choice - 1]->name,
			       max_choice - 1, FALSE,
			       (items[scroll + max_choice - 1]->tag[0] !=
				':'));
		} 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) {
			wscrl(menu, -1);
			scroll--;
			print_item(menu, items[scroll]->name, 0, FALSE,
				   (items[scroll]->tag[0] != ':'));
		    } else {
			if (choice > 0)
			    choice--;
		    }
		}
		scrollok(menu, FALSE);

	    } else if (key == KEY_NPAGE) {
		for (i = 0; (i < max_choice); i++) {
		    if (scroll + max_choice < item_no) {
			scrollok(menu, TRUE);
			scroll(menu);
			scrollok(menu, FALSE);
			scroll++;
			print_item(menu, items[scroll + max_choice - 1]->name,
				   max_choice - 1, FALSE,
				   (items[scroll + max_choice - 1]->tag[0] !=
				    ':'));
		    } else {
			if (choice + 1 < max_choice)
			    choice++;
		    }
		}

	    } else
		choice = i;

	    print_item(menu, items[scroll + choice]->name, choice, TRUE,
		       (items[scroll + choice]->tag[0] != ':'));

	    print_arrows(dialog, item_no, scroll,
			 box_y, box_x + item_x + 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':
	    /* save scroll info */
	    if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
		fprintf(f, "%d\n", scroll);
		fclose(f);
	    }
	    delwin(dialog);
	    items[scroll + choice]->selected = 1;
	    switch (key) {
	    case 's':
		return 3;
	    case 'y':
		return 3;
	    case 'n':
		return 4;
	    case 'm':
		return 5;
	    case ' ':
		return 6;
	    }
	    return 0;
	case 'h':
	case '?':
	    button = 2;
	case '\n':
	    delwin(dialog);
	    items[scroll + choice]->selected = 1;

	    remove("lxdialog.scrltmp");
	    return button;
	case 'e':
	case 'x':
	    key = ESC;
	case ESC:
	    break;
	}
    }

    delwin(dialog);
    remove("lxdialog.scrltmp");
    return -1;			/* ESC pressed */
}

--- NEW FILE: lkc_proto.h ---

/* confdata.c */
P(conf_parse, void, (const char *name));
P(conf_read, 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_type_name, const char *, (int type));
P(sym_calc_value, void, (struct symbol * sym));
P(sym_get_type, int, (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_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));




More information about the dslinux-commit mailing list