kconfig/menuconfig: lxdialog is now built-in

lxdialog was previously called as an external program causing screen
to flicker when used. With this patch lxdialog is now built-in.
It is loosly based om previous work by:  Petr Baudis <pasky@ucw.cz>

Following is a list of changes:
o Moved build of dialog routings to kconfig Makefile
o menubox + checklist uses a new item list to hold all menu items
o in util.c implmented helper function to deal with item list
o menubox now uses parameters to save scroll state (avoids temp file)
o textbox now get text to be displayed as parameter and not a file
o make sure to properly delete subwin's before main windows
o killed unused files: lxdialog.c msgbox.c
o modified return value for ESC to match direct calling
o in a few places the code has been adjusted to 80 char wide
o in textbox a small refactoring was made to make code remotely readable
o in mconf removed all unused stuff (functions/variables)

Following is a list of know short comings:
a) pressing ESC twice will be interpreted as two ESC presses
b) resize does not work. menuconfig needs to be restarted to be adjusted

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 5992673..b1ad9a0 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -24,6 +24,7 @@
 
 #define LKC_DIRECT_LINK
 #include "lkc.h"
+#include "lxdialog/dialog.h"
 
 static char menu_backtitle[128];
 static const char mconf_readme[] = N_(
@@ -270,16 +271,12 @@
 	"          USB$ => find all CONFIG_ symbols ending with USB\n"
 	"\n");
 
-static char buf[4096], *bufptr = buf;
-static char input_buf[4096];
 static char filename[PATH_MAX+1] = ".config";
-static char *args[1024], **argptr = args;
 static int indent;
 static struct termios ios_org;
 static int rows = 0, cols = 0;
 static struct menu *current_menu;
 static int child_count;
-static int do_resize;
 static int single_menu_mode;
 
 static void conf(struct menu *menu);
@@ -290,12 +287,6 @@
 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_file(const char *filename, const char *title, int r, int c);
-
-static void cprint_init(void);
-static int cprint1(const char *fmt, ...);
-static void cprint_done(void);
-static int cprint(const char *fmt, ...);
 
 static void init_wsize(void)
 {
@@ -332,54 +323,6 @@
 	cols -= 5;
 }
 
-static void cprint_init(void)
-{
-	bufptr = buf;
-	argptr = args;
-	memset(args, 0, sizeof(args));
-	indent = 0;
-	child_count = 0;
-	cprint("./scripts/kconfig/lxdialog/lxdialog");
-	cprint("--backtitle");
-	cprint(menu_backtitle);
-}
-
-static int cprint1(const char *fmt, ...)
-{
-	va_list ap;
-	int res;
-
-	if (!*argptr)
-		*argptr = bufptr;
-	va_start(ap, fmt);
-	res = vsprintf(bufptr, fmt, ap);
-	va_end(ap);
-	bufptr += res;
-
-	return res;
-}
-
-static void cprint_done(void)
-{
-	*bufptr++ = 0;
-	argptr++;
-}
-
-static int cprint(const char *fmt, ...)
-{
-	va_list ap;
-	int res;
-
-	*argptr++ = bufptr;
-	va_start(ap, fmt);
-	res = vsprintf(bufptr, fmt, ap);
-	va_end(ap);
-	bufptr += res;
-	*bufptr++ = 0;
-
-	return res;
-}
-
 static void get_prompt_str(struct gstr *r, struct property *prop)
 {
 	int i, j;
@@ -452,108 +395,17 @@
 	return res;
 }
 
-pid_t pid;
-
-static void winch_handler(int sig)
-{
-	if (!do_resize) {
-		kill(pid, SIGINT);
-		do_resize = 1;
-	}
-}
-
-static int exec_conf(void)
-{
-	int pipefd[2], stat, size;
-	struct sigaction sa;
-	sigset_t sset, osset;
-
-	sigemptyset(&sset);
-	sigaddset(&sset, SIGINT);
-	sigprocmask(SIG_BLOCK, &sset, &osset);
-
-	signal(SIGINT, SIG_DFL);
-
-	sa.sa_handler = winch_handler;
-	sigemptyset(&sa.sa_mask);
-	sa.sa_flags = SA_RESTART;
-	sigaction(SIGWINCH, &sa, NULL);
-
-	*argptr++ = NULL;
-
-	pipe(pipefd);
-	pid = fork();
-	if (pid == 0) {
-		sigprocmask(SIG_SETMASK, &osset, NULL);
-		dup2(pipefd[1], 2);
-		close(pipefd[0]);
-		close(pipefd[1]);
-		execv(args[0], args);
-		_exit(EXIT_FAILURE);
-	}
-
-	close(pipefd[1]);
-	bufptr = input_buf;
-	while (1) {
-		size = input_buf + sizeof(input_buf) - bufptr;
-		size = read(pipefd[0], bufptr, size);
-		if (size <= 0) {
-			if (size < 0) {
-				if (errno == EINTR || errno == EAGAIN)
-					continue;
-				perror("read");
-			}
-			break;
-		}
-		bufptr += size;
-	}
-	*bufptr++ = 0;
-	close(pipefd[0]);
-	waitpid(pid, &stat, 0);
-
-	if (do_resize) {
-		init_wsize();
-		do_resize = 0;
-		sigprocmask(SIG_SETMASK, &osset, NULL);
-		return -1;
-	}
-	if (WIFSIGNALED(stat)) {
-		printf("\finterrupted(%d)\n", WTERMSIG(stat));
-		exit(1);
-	}
-#if 0
-	printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
-	sleep(1);
-#endif
-	sigpending(&sset);
-	if (sigismember(&sset, SIGINT)) {
-		printf("\finterrupted\n");
-		exit(1);
-	}
-	sigprocmask(SIG_SETMASK, &osset, NULL);
-
-	return WEXITSTATUS(stat);
-}
-
 static void search_conf(void)
 {
 	struct symbol **sym_arr;
-	int stat;
 	struct gstr res;
-
+	int dres;
 again:
-	cprint_init();
-	cprint("--title");
-	cprint(_("Search Configuration Parameter"));
-	cprint("--inputbox");
-	cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
-	cprint("10");
-	cprint("75");
-	cprint("");
-	stat = exec_conf();
-	if (stat < 0)
-		goto again;
-	switch (stat) {
+	reset_dialog();
+	dres = dialog_inputbox(_("Search Configuration Parameter"),
+			      _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
+			      10, 75, "");
+	switch (dres) {
 	case 0:
 		break;
 	case 1:
@@ -563,7 +415,7 @@
 		return;
 	}
 
-	sym_arr = sym_re_search(input_buf);
+	sym_arr = sym_re_search(dialog_input_result);
 	res = get_relations_str(sym_arr);
 	free(sym_arr);
 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
@@ -590,24 +442,24 @@
 			switch (prop->type) {
 			case P_MENU:
 				child_count++;
-				cprint("m%p", menu);
-
 				if (single_menu_mode) {
-					cprint1("%s%*c%s",
-						menu->data ? "-->" : "++>",
-						indent + 1, ' ', prompt);
+					item_make("%s%*c%s",
+						  menu->data ? "-->" : "++>",
+						  indent + 1, ' ', prompt);
 				} else
-					cprint1("   %*c%s  --->", indent + 1, ' ', prompt);
+					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
 
-				cprint_done();
+				item_set_tag('m');
+				item_set_data(menu);
 				if (single_menu_mode && menu->data)
 					goto conf_childs;
 				return;
 			default:
 				if (prompt) {
 					child_count++;
-					cprint(":%p", menu);
-					cprint("---%*c%s", indent + 1, ' ', prompt);
+					item_make("---%*c%s", indent + 1, ' ', prompt);
+					item_set_tag(':');
+					item_set_data(menu);
 				}
 			}
 		} else
@@ -628,10 +480,9 @@
 
 		val = sym_get_tristate_value(sym);
 		if (sym_is_changable(sym)) {
-			cprint("t%p", menu);
 			switch (type) {
 			case S_BOOLEAN:
-				cprint1("[%c]", val == no ? ' ' : '*');
+				item_make("[%c]", val == no ? ' ' : '*');
 				break;
 			case S_TRISTATE:
 				switch (val) {
@@ -639,84 +490,87 @@
 				case mod: ch = 'M'; break;
 				default:  ch = ' '; break;
 				}
-				cprint1("<%c>", ch);
+				item_make("<%c>", ch);
 				break;
 			}
+			item_set_tag('t');
+			item_set_data(menu);
 		} else {
-			cprint("%c%p", def_menu ? 't' : ':', menu);
-			cprint1("   ");
+			item_make("   ");
+			item_set_tag(def_menu ? 't' : ':');
+			item_set_data(menu);
 		}
 
-		cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
 		if (val == yes) {
 			if (def_menu) {
-				cprint1(" (%s)", menu_get_prompt(def_menu));
-				cprint1("  --->");
-				cprint_done();
+				item_add_str(" (%s)", menu_get_prompt(def_menu));
+				item_add_str("  --->");
 				if (def_menu->list) {
 					indent += 2;
 					build_conf(def_menu);
 					indent -= 2;
 				}
-			} else
-				cprint_done();
+			}
 			return;
 		}
-		cprint_done();
 	} else {
 		if (menu == current_menu) {
-			cprint(":%p", menu);
-			cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+			item_set_tag(':');
+			item_set_data(menu);
 			goto conf_childs;
 		}
 		child_count++;
 		val = sym_get_tristate_value(sym);
 		if (sym_is_choice_value(sym) && val == yes) {
-			cprint(":%p", menu);
-			cprint1("   ");
+			item_make("   ");
+			item_set_tag(':');
+			item_set_data(menu);
 		} else {
 			switch (type) {
 			case S_BOOLEAN:
-				cprint("t%p", menu);
 				if (sym_is_changable(sym))
-					cprint1("[%c]", val == no ? ' ' : '*');
+					item_make("[%c]", val == no ? ' ' : '*');
 				else
-					cprint1("---");
+					item_make("---");
+				item_set_tag('t');
+				item_set_data(menu);
 				break;
 			case S_TRISTATE:
-				cprint("t%p", menu);
 				switch (val) {
 				case yes: ch = '*'; break;
 				case mod: ch = 'M'; break;
 				default:  ch = ' '; break;
 				}
 				if (sym_is_changable(sym))
-					cprint1("<%c>", ch);
+					item_make("<%c>", ch);
 				else
-					cprint1("---");
+					item_make("---");
+				item_set_tag('t');
+				item_set_data(menu);
 				break;
 			default:
-				cprint("s%p", menu);
-				tmp = cprint1("(%s)", sym_get_string_value(sym));
+				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+				item_make("(%s)", sym_get_string_value(sym));
 				tmp = indent - tmp + 4;
 				if (tmp < 0)
 					tmp = 0;
-				cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
-					(sym_has_value(sym) || !sym_is_changable(sym)) ?
-					"" : " (NEW)");
-				cprint_done();
+				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
+					     "" : " (NEW)");
+				item_set_tag('s');
+				item_set_data(menu);
 				goto conf_childs;
 			}
 		}
-		cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
-			(sym_has_value(sym) || !sym_is_changable(sym)) ?
-			"" : " (NEW)");
+		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
+			  "" : " (NEW)");
 		if (menu->prompt->type == P_MENU) {
-			cprint1("  --->");
-			cprint_done();
+			item_add_str("  --->");
 			return;
 		}
-		cprint_done();
 	}
 
 conf_childs:
@@ -731,59 +585,43 @@
 	struct menu *submenu;
 	const char *prompt = menu_get_prompt(menu);
 	struct symbol *sym;
-	char active_entry[40];
-	int stat, type, i;
+	struct menu *active_menu = NULL;
+	int res;
+	int s_scroll = 0;
 
-	unlink("lxdialog.scrltmp");
-	active_entry[0] = 0;
 	while (1) {
-		cprint_init();
-		cprint("--title");
-		cprint("%s", prompt ? prompt : _("Main Menu"));
-		cprint("--menu");
-		cprint(_(menu_instructions));
-		cprint("%d", rows);
-		cprint("%d", cols);
-		cprint("%d", rows - 10);
-		cprint("%s", active_entry);
+		item_reset();
 		current_menu = menu;
 		build_conf(menu);
 		if (!child_count)
 			break;
 		if (menu == &rootmenu) {
-			cprint(":");
-			cprint("--- ");
-			cprint("L");
-			cprint(_("    Load an Alternate Configuration File"));
-			cprint("S");
-			cprint(_("    Save Configuration to an Alternate File"));
+			item_make("--- ");
+			item_set_tag(':');
+			item_make(_("    Load an Alternate Configuration File"));
+			item_set_tag('L');
+			item_make(_("    Save an Alternate Configuration File"));
+			item_set_tag('S');
 		}
-		stat = exec_conf();
-		if (stat < 0)
-			continue;
-
-		if (stat == 1 || stat == 255)
+		reset_dialog();
+		res = dialog_menu(prompt ? prompt : _("Main Menu"),
+				  _(menu_instructions),
+				  rows, cols, rows - 10,
+				  active_menu, &s_scroll);
+		if (res == 1 || res == 255)
 			break;
-
-		type = input_buf[0];
-		if (!type)
+		if (!item_activate_selected())
+			continue;
+		if (!item_tag())
 			continue;
 
-		for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
-			;
-		if (i >= sizeof(active_entry))
-			i = sizeof(active_entry) - 1;
-		input_buf[i] = 0;
-		strcpy(active_entry, input_buf);
+		submenu = item_data();
+		active_menu = item_data();
+		sym = submenu->sym;
 
-		sym = NULL;
-		submenu = NULL;
-		if (sscanf(input_buf + 1, "%p", &submenu) == 1)
-			sym = submenu->sym;
-
-		switch (stat) {
+		switch (res) {
 		case 0:
-			switch (type) {
+			switch (item_tag()) {
 			case 'm':
 				if (single_menu_mode)
 					submenu->data = (void *) (long) !submenu->data;
@@ -814,7 +652,7 @@
 				show_helptext("README", _(mconf_readme));
 			break;
 		case 3:
-			if (type == 't') {
+			if (item_is_tag('t')) {
 				if (sym_set_tristate_value(sym, yes))
 					break;
 				if (sym_set_tristate_value(sym, mod))
@@ -822,17 +660,17 @@
 			}
 			break;
 		case 4:
-			if (type == 't')
+			if (item_is_tag('t'))
 				sym_set_tristate_value(sym, no);
 			break;
 		case 5:
-			if (type == 't')
+			if (item_is_tag('t'))
 				sym_set_tristate_value(sym, mod);
 			break;
 		case 6:
-			if (type == 't')
+			if (item_is_tag('t'))
 				sym_toggle_tristate_value(sym);
-			else if (type == 'm')
+			else if (item_is_tag('m'))
 				conf(submenu);
 			break;
 		case 7:
@@ -844,13 +682,8 @@
 
 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);
-	show_file(".help.tmp", title, r, c);
-	unlink(".help.tmp");
+	reset_dialog();
+	dialog_textbox(title, text, r ? r : rows, c ? c : cols);
 }
 
 static void show_helptext(const char *title, const char *text)
@@ -878,62 +711,44 @@
 	str_free(&help);
 }
 
-static void show_file(const char *filename, const char *title, int r, int c)
-{
-	do {
-		cprint_init();
-		if (title) {
-			cprint("--title");
-			cprint("%s", title);
-		}
-		cprint("--textbox");
-		cprint("%s", filename);
-		cprint("%d", r ? r : rows);
-		cprint("%d", c ? c : cols);
-	} while (exec_conf() < 0);
-}
-
 static void conf_choice(struct menu *menu)
 {
 	const char *prompt = menu_get_prompt(menu);
 	struct menu *child;
 	struct symbol *active;
-	int stat;
 
 	active = sym_get_choice_value(menu->sym);
 	while (1) {
-		cprint_init();
-		cprint("--title");
-		cprint("%s", prompt ? prompt : _("Main Menu"));
-		cprint("--radiolist");
-		cprint(_(radiolist_instructions));
-		cprint("15");
-		cprint("70");
-		cprint("6");
+		int res;
+		int selected;
+		item_reset();
 
 		current_menu = menu;
 		for (child = menu->list; child; child = child->next) {
 			if (!menu_is_visible(child))
 				continue;
-			cprint("%p", child);
-			cprint("%s", menu_get_prompt(child));
+			item_make("%s", menu_get_prompt(child));
+			item_set_data(child);
+			if (child->sym == active)
+				item_set_selected(1);
 			if (child->sym == sym_get_choice_value(menu->sym))
-				cprint("ON");
-			else if (child->sym == active)
-				cprint("SELECTED");
-			else
-				cprint("OFF");
+				item_set_tag('X');
 		}
-
-		stat = exec_conf();
-		switch (stat) {
+		reset_dialog();
+		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
+					_(radiolist_instructions),
+					 15, 70, 6);
+		selected = item_activate_selected();
+		switch (res) {
 		case 0:
-			if (sscanf(input_buf, "%p", &child) != 1)
-				break;
-			sym_set_tristate_value(child->sym, yes);
+			if (selected) {
+				child = item_data();
+				sym_set_tristate_value(child->sym, yes);
+			}
 			return;
 		case 1:
-			if (sscanf(input_buf, "%p", &child) == 1) {
+			if (selected) {
+				child = item_data();
 				show_help(child);
 				active = child->sym;
 			} else
@@ -948,33 +763,31 @@
 static void conf_string(struct menu *menu)
 {
 	const char *prompt = menu_get_prompt(menu);
-	int stat;
 
 	while (1) {
-		cprint_init();
-		cprint("--title");
-		cprint("%s", prompt ? prompt : _("Main Menu"));
-		cprint("--inputbox");
+		int res;
+		char *heading;
+
 		switch (sym_get_type(menu->sym)) {
 		case S_INT:
-			cprint(_(inputbox_instructions_int));
+			heading = _(inputbox_instructions_int);
 			break;
 		case S_HEX:
-			cprint(_(inputbox_instructions_hex));
+			heading = _(inputbox_instructions_hex);
 			break;
 		case S_STRING:
-			cprint(_(inputbox_instructions_string));
+			heading = _(inputbox_instructions_string);
 			break;
 		default:
-			/* panic? */;
+			heading = "Internal mconf error!";
 		}
-		cprint("10");
-		cprint("75");
-		cprint("%s", sym_get_string_value(menu->sym));
-		stat = exec_conf();
-		switch (stat) {
+		reset_dialog();
+		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
+				      heading, 10, 75,
+				      sym_get_string_value(menu->sym));
+		switch (res) {
 		case 0:
-			if (sym_set_string_value(menu->sym, input_buf))
+			if (sym_set_string_value(menu->sym, dialog_input_result))
 				return;
 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
 			break;
@@ -989,21 +802,17 @@
 
 static void conf_load(void)
 {
-	int stat;
 
 	while (1) {
-		cprint_init();
-		cprint("--inputbox");
-		cprint(load_config_text);
-		cprint("11");
-		cprint("55");
-		cprint("%s", filename);
-		stat = exec_conf();
-		switch(stat) {
+		int res;
+		reset_dialog();
+		res = dialog_inputbox(NULL, load_config_text,
+				      11, 55, filename);
+		switch(res) {
 		case 0:
-			if (!input_buf[0])
+			if (!dialog_input_result[0])
 				return;
-			if (!conf_read(input_buf))
+			if (!conf_read(dialog_input_result))
 				return;
 			show_textbox(NULL, _("File does not exist!"), 5, 38);
 			break;
@@ -1018,21 +827,16 @@
 
 static void conf_save(void)
 {
-	int stat;
-
 	while (1) {
-		cprint_init();
-		cprint("--inputbox");
-		cprint(save_config_text);
-		cprint("11");
-		cprint("55");
-		cprint("%s", filename);
-		stat = exec_conf();
-		switch(stat) {
+		int res;
+		reset_dialog();
+		res = dialog_inputbox(NULL, save_config_text,
+				      11, 55, filename);
+		switch(res) {
 		case 0:
-			if (!input_buf[0])
+			if (!dialog_input_result[0])
 				return;
-			if (!conf_write(input_buf))
+			if (!conf_write(dialog_input_result))
 				return;
 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 			break;
@@ -1048,15 +852,13 @@
 static void conf_cleanup(void)
 {
 	tcsetattr(1, TCSAFLUSH, &ios_org);
-	unlink(".help.tmp");
-	unlink("lxdialog.scrltmp");
 }
 
 int main(int ac, char **av)
 {
 	struct symbol *sym;
 	char *mode;
-	int stat;
+	int res;
 
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1079,18 +881,16 @@
 	tcgetattr(1, &ios_org);
 	atexit(conf_cleanup);
 	init_wsize();
+	reset_dialog();
+	init_dialog(menu_backtitle);
 	conf(&rootmenu);
-
-	do {
-		cprint_init();
-		cprint("--yesno");
-		cprint(_("Do you wish to save your new kernel configuration?"));
-		cprint("5");
-		cprint("60");
-		stat = exec_conf();
-	} while (stat < 0);
-
-	if (stat == 0) {
+	reset_dialog();
+	res = dialog_yesno(NULL,
+			   _("Do you wish to save your "
+			     "new kernel configuration?"),
+			   5, 60);
+	end_dialog();
+	if (res == 0) {
 		if (conf_write(NULL)) {
 			fprintf(stderr, _("\n\n"
 				"Error during writing of the kernel configuration.\n"