183cbb37nwhitehorn/*
2f8604a5bapt *  $Id: util.c,v 1.272 2018/06/21 23:47:10 tom Exp $
383cbb37nwhitehorn *
483cbb37nwhitehorn *  util.c -- miscellaneous utilities for dialog
583cbb37nwhitehorn *
6f8604a5bapt *  Copyright 2000-2016,2018	Thomas E. Dickey
783cbb37nwhitehorn *
883cbb37nwhitehorn *  This program is free software; you can redistribute it and/or modify
983cbb37nwhitehorn *  it under the terms of the GNU Lesser General Public License, version 2.1
1083cbb37nwhitehorn *  as published by the Free Software Foundation.
1183cbb37nwhitehorn *
1283cbb37nwhitehorn *  This program is distributed in the hope that it will be useful, but
1383cbb37nwhitehorn *  WITHOUT ANY WARRANTY; without even the implied warranty of
1483cbb37nwhitehorn *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1583cbb37nwhitehorn *  Lesser General Public License for more details.
1683cbb37nwhitehorn *
1783cbb37nwhitehorn *  You should have received a copy of the GNU Lesser General Public
1883cbb37nwhitehorn *  License along with this program; if not, write to
1983cbb37nwhitehorn *	Free Software Foundation, Inc.
2083cbb37nwhitehorn *	51 Franklin St., Fifth Floor
2183cbb37nwhitehorn *	Boston, MA 02110, USA.
2283cbb37nwhitehorn *
2383cbb37nwhitehorn *  An earlier version of this program lists as authors
2483cbb37nwhitehorn *	Savio Lam (lam836@cs.cuhk.hk)
2583cbb37nwhitehorn */
2683cbb37nwhitehorn
2783cbb37nwhitehorn#include <dialog.h>
2883cbb37nwhitehorn#include <dlg_keys.h>
2983cbb37nwhitehorn
30a94245bnwhitehorn#ifdef HAVE_SETLOCALE
31a94245bnwhitehorn#include <locale.h>
32a94245bnwhitehorn#endif
33a94245bnwhitehorn
34a94245bnwhitehorn#ifdef NEED_WCHAR_H
35a94245bnwhitehorn#include <wchar.h>
36a94245bnwhitehorn#endif
37a94245bnwhitehorn
3883cbb37nwhitehorn#ifdef NCURSES_VERSION
3983cbb37nwhitehorn#if defined(HAVE_NCURSESW_TERM_H)
4083cbb37nwhitehorn#include <ncursesw/term.h>
4183cbb37nwhitehorn#elif defined(HAVE_NCURSES_TERM_H)
4283cbb37nwhitehorn#include <ncurses/term.h>
4383cbb37nwhitehorn#else
4483cbb37nwhitehorn#include <term.h>
4583cbb37nwhitehorn#endif
4683cbb37nwhitehorn#endif
4783cbb37nwhitehorn
4894f19e0nwhitehorn#if defined(HAVE_WCHGAT)
4994f19e0nwhitehorn#  if defined(NCURSES_VERSION_PATCH)
5094f19e0nwhitehorn#    if NCURSES_VERSION_PATCH >= 20060715
5194f19e0nwhitehorn#      define USE_WCHGAT 1
5294f19e0nwhitehorn#    else
5394f19e0nwhitehorn#      define USE_WCHGAT 0
5494f19e0nwhitehorn#    endif
5594f19e0nwhitehorn#  else
5694f19e0nwhitehorn#    define USE_WCHGAT 1
5794f19e0nwhitehorn#  endif
5894f19e0nwhitehorn#else
5994f19e0nwhitehorn#  define USE_WCHGAT 0
6094f19e0nwhitehorn#endif
6194f19e0nwhitehorn
6283cbb37nwhitehorn/* globals */
6383cbb37nwhitehornDIALOG_STATE dialog_state;
6483cbb37nwhitehornDIALOG_VARS dialog_vars;
6583cbb37nwhitehorn
66a94245bnwhitehorn#if !(defined(HAVE_WGETPARENT) && defined(HAVE_WINDOW__PARENT))
67a94245bnwhitehorn#define NEED_WGETPARENT 1
68a94245bnwhitehorn#else
69a94245bnwhitehorn#undef NEED_WGETPARENT
70a94245bnwhitehorn#endif
71a94245bnwhitehorn
7283cbb37nwhitehorn#define concat(a,b) a##b
7383cbb37nwhitehorn
7483cbb37nwhitehorn#ifdef HAVE_RC_FILE
7583cbb37nwhitehorn#define RC_DATA(name,comment) , #name "_color", comment " color"
7683cbb37nwhitehorn#else
7783cbb37nwhitehorn#define RC_DATA(name,comment)	/*nothing */
7883cbb37nwhitehorn#endif
7983cbb37nwhitehorn
8083cbb37nwhitehorn#ifdef HAVE_COLOR
8183cbb37nwhitehorn#include <dlg_colors.h>
8283cbb37nwhitehorn#define COLOR_DATA(upr) , \
8383cbb37nwhitehorn	concat(DLGC_FG_,upr), \
8483cbb37nwhitehorn	concat(DLGC_BG_,upr), \
8583cbb37nwhitehorn	concat(DLGC_HL_,upr)
8683cbb37nwhitehorn#else
8783cbb37nwhitehorn#define COLOR_DATA(upr)		/*nothing */
8883cbb37nwhitehorn#endif
8983cbb37nwhitehorn
9083cbb37nwhitehorn#define DATA(atr,upr,lwr,cmt) { atr COLOR_DATA(upr) RC_DATA(lwr,cmt) }
9183cbb37nwhitehorn
9294f19e0nwhitehorn#define UseShadow(dw) ((dw) != 0 && (dw)->normal != 0 && (dw)->shadow != 0)
9394f19e0nwhitehorn
9483cbb37nwhitehorn/*
9583cbb37nwhitehorn * Table of color and attribute values, default is for mono display.
96a94245bnwhitehorn * The order matches the DIALOG_ATR() values.
9783cbb37nwhitehorn */
9883cbb37nwhitehorn/* *INDENT-OFF* */
9983cbb37nwhitehornDIALOG_COLORS dlg_color_table[] =
10083cbb37nwhitehorn{
10183cbb37nwhitehorn    DATA(A_NORMAL,	SCREEN,			screen, "Screen"),
10283cbb37nwhitehorn    DATA(A_NORMAL,	SHADOW,			shadow, "Shadow"),
10383cbb37nwhitehorn    DATA(A_REVERSE,	DIALOG,			dialog, "Dialog box"),
10483cbb37nwhitehorn    DATA(A_REVERSE,	TITLE,			title, "Dialog box title"),
10583cbb37nwhitehorn    DATA(A_REVERSE,	BORDER,			border, "Dialog box border"),
10683cbb37nwhitehorn    DATA(A_BOLD,	BUTTON_ACTIVE,		button_active, "Active button"),
10783cbb37nwhitehorn    DATA(A_DIM,		BUTTON_INACTIVE,	button_inactive, "Inactive button"),
10883cbb37nwhitehorn    DATA(A_UNDERLINE,	BUTTON_KEY_ACTIVE,	button_key_active, "Active button key"),
10983cbb37nwhitehorn    DATA(A_UNDERLINE,	BUTTON_KEY_INACTIVE,	button_key_inactive, "Inactive button key"),
11083cbb37nwhitehorn    DATA(A_NORMAL,	BUTTON_LABEL_ACTIVE,	button_label_active, "Active button label"),
11183cbb37nwhitehorn    DATA(A_NORMAL,	BUTTON_LABEL_INACTIVE,	button_label_inactive, "Inactive button label"),
11283cbb37nwhitehorn    DATA(A_REVERSE,	INPUTBOX,		inputbox, "Input box"),
11383cbb37nwhitehorn    DATA(A_REVERSE,	INPUTBOX_BORDER,	inputbox_border, "Input box border"),
11483cbb37nwhitehorn    DATA(A_REVERSE,	SEARCHBOX,		searchbox, "Search box"),
11583cbb37nwhitehorn    DATA(A_REVERSE,	SEARCHBOX_TITLE,	searchbox_title, "Search box title"),
11683cbb37nwhitehorn    DATA(A_REVERSE,	SEARCHBOX_BORDER,	searchbox_border, "Search box border"),
11783cbb37nwhitehorn    DATA(A_REVERSE,	POSITION_INDICATOR,	position_indicator, "File position indicator"),
11883cbb37nwhitehorn    DATA(A_REVERSE,	MENUBOX,		menubox, "Menu box"),
11983cbb37nwhitehorn    DATA(A_REVERSE,	MENUBOX_BORDER,		menubox_border, "Menu box border"),
12083cbb37nwhitehorn    DATA(A_REVERSE,	ITEM,			item, "Item"),
12183cbb37nwhitehorn    DATA(A_NORMAL,	ITEM_SELECTED,		item_selected, "Selected item"),
12283cbb37nwhitehorn    DATA(A_REVERSE,	TAG,			tag, "Tag"),
12383cbb37nwhitehorn    DATA(A_REVERSE,	TAG_SELECTED,		tag_selected, "Selected tag"),
12483cbb37nwhitehorn    DATA(A_NORMAL,	TAG_KEY,		tag_key, "Tag key"),
12583cbb37nwhitehorn    DATA(A_BOLD,	TAG_KEY_SELECTED,	tag_key_selected, "Selected tag key"),
12683cbb37nwhitehorn    DATA(A_REVERSE,	CHECK,			check, "Check box"),
12783cbb37nwhitehorn    DATA(A_REVERSE,	CHECK_SELECTED,		check_selected, "Selected check box"),
12883cbb37nwhitehorn    DATA(A_REVERSE,	UARROW,			uarrow, "Up arrow"),
12983cbb37nwhitehorn    DATA(A_REVERSE,	DARROW,			darrow, "Down arrow"),
13083cbb37nwhitehorn    DATA(A_NORMAL,	ITEMHELP,		itemhelp, "Item help-text"),
13183cbb37nwhitehorn    DATA(A_BOLD,	FORM_ACTIVE_TEXT,	form_active_text, "Active form text"),
13283cbb37nwhitehorn    DATA(A_REVERSE,	FORM_TEXT,		form_text, "Form text"),
1339904759nwhitehorn    DATA(A_NORMAL,	FORM_ITEM_READONLY,	form_item_readonly, "Readonly form item"),
134a94245bnwhitehorn    DATA(A_REVERSE,	GAUGE,			gauge, "Dialog box gauge"),
135a94245bnwhitehorn    DATA(A_REVERSE,	BORDER2,		border2, "Dialog box border2"),
136a94245bnwhitehorn    DATA(A_REVERSE,	INPUTBOX_BORDER2,	inputbox_border2, "Input box border2"),
137a94245bnwhitehorn    DATA(A_REVERSE,	SEARCHBOX_BORDER2,	searchbox_border2, "Search box border2"),
138a94245bnwhitehorn    DATA(A_REVERSE,	MENUBOX_BORDER2,	menubox_border2, "Menu box border2")
13983cbb37nwhitehorn};
14083cbb37nwhitehorn/* *INDENT-ON* */
14183cbb37nwhitehorn
14283cbb37nwhitehorn/*
143a94245bnwhitehorn * Maintain a list of subwindows so that we can delete them to cleanup.
144a94245bnwhitehorn * More important, this provides a fallback when wgetparent() is not available.
145a94245bnwhitehorn */
146a94245bnwhitehornstatic void
147a94245bnwhitehornadd_subwindow(WINDOW *parent, WINDOW *child)
148a94245bnwhitehorn{
149a94245bnwhitehorn    DIALOG_WINDOWS *p = dlg_calloc(DIALOG_WINDOWS, 1);
150a94245bnwhitehorn
151a94245bnwhitehorn    if (p != 0) {
152a94245bnwhitehorn	p->normal = parent;
153a94245bnwhitehorn	p->shadow = child;
154a94245bnwhitehorn	p->next = dialog_state.all_subwindows;
155a94245bnwhitehorn	dialog_state.all_subwindows = p;
156a94245bnwhitehorn    }
157a94245bnwhitehorn}
158a94245bnwhitehorn
159a94245bnwhitehornstatic void
160a94245bnwhitehorndel_subwindows(WINDOW *parent)
161a94245bnwhitehorn{
162a94245bnwhitehorn    DIALOG_WINDOWS *p = dialog_state.all_subwindows;
163a94245bnwhitehorn    DIALOG_WINDOWS *q = 0;
164a94245bnwhitehorn    DIALOG_WINDOWS *r;
165a94245bnwhitehorn
166a94245bnwhitehorn    while (p != 0) {
167a94245bnwhitehorn	if (p->normal == parent) {
168a94245bnwhitehorn	    delwin(p->shadow);
169a94245bnwhitehorn	    r = p->next;
170a94245bnwhitehorn	    if (q == 0) {
171a94245bnwhitehorn		dialog_state.all_subwindows = r;
172a94245bnwhitehorn	    } else {
173a94245bnwhitehorn		q->next = r;
174a94245bnwhitehorn	    }
175a94245bnwhitehorn	    free(p);
176a94245bnwhitehorn	    p = r;
177a94245bnwhitehorn	} else {
178a94245bnwhitehorn	    q = p;
179a94245bnwhitehorn	    p = p->next;
180a94245bnwhitehorn	}
181a94245bnwhitehorn    }
182a94245bnwhitehorn}
183a94245bnwhitehorn
184a94245bnwhitehorn/*
18583cbb37nwhitehorn * Display background title if it exists ...
18683cbb37nwhitehorn */
18783cbb37nwhitehornvoid
18883cbb37nwhitehorndlg_put_backtitle(void)
18983cbb37nwhitehorn{
19083cbb37nwhitehorn    int i;
19183cbb37nwhitehorn
19283cbb37nwhitehorn    if (dialog_vars.backtitle != NULL) {
19383cbb37nwhitehorn	chtype attr = A_NORMAL;
19483cbb37nwhitehorn	int backwidth = dlg_count_columns(dialog_vars.backtitle);
19583cbb37nwhitehorn
196f8604a5bapt	dlg_attrset(stdscr, screen_attr);
19783cbb37nwhitehorn	(void) wmove(stdscr, 0, 1);
19883cbb37nwhitehorn	dlg_print_text(stdscr, dialog_vars.backtitle, COLS - 2, &attr);
19983cbb37nwhitehorn	for (i = 0; i < COLS - backwidth; i++)
20083cbb37nwhitehorn	    (void) waddch(stdscr, ' ');
20183cbb37nwhitehorn	(void) wmove(stdscr, 1, 1);
20283cbb37nwhitehorn	for (i = 0; i < COLS - 2; i++)
20383cbb37nwhitehorn	    (void) waddch(stdscr, dlg_boxchar(ACS_HLINE));
20483cbb37nwhitehorn    }
20583cbb37nwhitehorn
20683cbb37nwhitehorn    (void) wnoutrefresh(stdscr);
20783cbb37nwhitehorn}
20883cbb37nwhitehorn
20983cbb37nwhitehorn/*
21083cbb37nwhitehorn * Set window to attribute 'attr'.  There are more efficient ways to do this,
21183cbb37nwhitehorn * but will not work on older/buggy ncurses versions.
21283cbb37nwhitehorn */
21383cbb37nwhitehornvoid
21483cbb37nwhitehorndlg_attr_clear(WINDOW *win, int height, int width, chtype attr)
21583cbb37nwhitehorn{
21683cbb37nwhitehorn    int i, j;
21783cbb37nwhitehorn
218f8604a5bapt    dlg_attrset(win, attr);
21983cbb37nwhitehorn    for (i = 0; i < height; i++) {
22083cbb37nwhitehorn	(void) wmove(win, i, 0);
22183cbb37nwhitehorn	for (j = 0; j < width; j++)
22283cbb37nwhitehorn	    (void) waddch(win, ' ');
22383cbb37nwhitehorn    }
22483cbb37nwhitehorn    (void) touchwin(win);
22583cbb37nwhitehorn}
22683cbb37nwhitehorn
22783cbb37nwhitehornvoid
22883cbb37nwhitehorndlg_clear(void)
22983cbb37nwhitehorn{
23083cbb37nwhitehorn    dlg_attr_clear(stdscr, LINES, COLS, screen_attr);
23183cbb37nwhitehorn}
23283cbb37nwhitehorn
23383cbb37nwhitehorn#define isprivate(s) ((s) != 0 && strstr(s, "\033[?") != 0)
23483cbb37nwhitehorn
23583cbb37nwhitehorn#define TTY_DEVICE "/dev/tty"
23683cbb37nwhitehorn
23783cbb37nwhitehorn/*
23883cbb37nwhitehorn * If $DIALOG_TTY exists, allow the program to try to open the terminal
23983cbb37nwhitehorn * directly when stdout is redirected.  By default we require the "--stdout"
24083cbb37nwhitehorn * option to be given, but some scripts were written making use of the
24183cbb37nwhitehorn * behavior of dialog which tried opening the terminal anyway.
24283cbb37nwhitehorn */
24383cbb37nwhitehornstatic char *
24483cbb37nwhitehorndialog_tty(void)
24583cbb37nwhitehorn{
24683cbb37nwhitehorn    char *result = getenv("DIALOG_TTY");
24783cbb37nwhitehorn    if (result != 0 && atoi(result) == 0)
24883cbb37nwhitehorn	result = 0;
24983cbb37nwhitehorn    return result;
25083cbb37nwhitehorn}
25183cbb37nwhitehorn
25283cbb37nwhitehorn/*
25383cbb37nwhitehorn * Open the terminal directly.  If one of stdin, stdout or stderr really points
25483cbb37nwhitehorn * to a tty, use it.  Otherwise give up and open /dev/tty.
25583cbb37nwhitehorn */
25683cbb37nwhitehornstatic int
25783cbb37nwhitehornopen_terminal(char **result, int mode)
25883cbb37nwhitehorn{
25983cbb37nwhitehorn    const char *device = TTY_DEVICE;
26083cbb37nwhitehorn    if (!isatty(fileno(stderr))
26183cbb37nwhitehorn	|| (device = ttyname(fileno(stderr))) == 0) {
26283cbb37nwhitehorn	if (!isatty(fileno(stdout))
26383cbb37nwhitehorn	    || (device = ttyname(fileno(stdout))) == 0) {
26483cbb37nwhitehorn	    if (!isatty(fileno(stdin))
26583cbb37nwhitehorn		|| (device = ttyname(fileno(stdin))) == 0) {
26683cbb37nwhitehorn		device = TTY_DEVICE;
26783cbb37nwhitehorn	    }
26883cbb37nwhitehorn	}
26983cbb37nwhitehorn    }
27083cbb37nwhitehorn    *result = dlg_strclone(device);
27183cbb37nwhitehorn    return open(device, mode);
27283cbb37nwhitehorn}
27383cbb37nwhitehorn
2742b5579cbapt#ifdef NCURSES_VERSION
2752b5579cbaptstatic int
2762b5579cbaptmy_putc(int ch)
2772b5579cbapt{
2782b5579cbapt    char buffer[2];
2792b5579cbapt    int fd = fileno(dialog_state.screen_output);
2802b5579cbapt
2812b5579cbapt    buffer[0] = (char) ch;
2822b5579cbapt    return (int) write(fd, buffer, (size_t) 1);
2832b5579cbapt}
2842b5579cbapt#endif
2852b5579cbapt
28683cbb37nwhitehorn/*
28783cbb37nwhitehorn * Do some initialization for dialog.
28883cbb37nwhitehorn *
28983cbb37nwhitehorn * 'input' is the real tty input of dialog.  Usually it is stdin, but if
29083cbb37nwhitehorn * --input-fd option is used, it may be anything.
29183cbb37nwhitehorn *
29283cbb37nwhitehorn * 'output' is where dialog will send its result.  Usually it is stderr, but
29383cbb37nwhitehorn * if --stdout or --output-fd is used, it may be anything.  We are concerned
29483cbb37nwhitehorn * mainly with the case where it happens to be the same as stdout.
29583cbb37nwhitehorn */
29683cbb37nwhitehornvoid
29783cbb37nwhitehorninit_dialog(FILE *input, FILE *output)
29883cbb37nwhitehorn{
29983cbb37nwhitehorn    int fd1, fd2;
30083cbb37nwhitehorn    char *device = 0;
30183cbb37nwhitehorn
302a94245bnwhitehorn    setlocale(LC_ALL, "");
303a94245bnwhitehorn
30483cbb37nwhitehorn    dialog_state.output = output;
30583cbb37nwhitehorn    dialog_state.tab_len = TAB_LEN;
30683cbb37nwhitehorn    dialog_state.aspect_ratio = DEFAULT_ASPECT_RATIO;
30783cbb37nwhitehorn#ifdef HAVE_COLOR
30883cbb37nwhitehorn    dialog_state.use_colors = USE_COLORS;	/* use colors by default? */
30983cbb37nwhitehorn    dialog_state.use_shadow = USE_SHADOW;	/* shadow dialog boxes by default? */
31083cbb37nwhitehorn#endif
31183cbb37nwhitehorn
31283cbb37nwhitehorn#ifdef HAVE_RC_FILE
31383cbb37nwhitehorn    if (dlg_parse_rc() == -1)	/* Read the configuration file */
31483cbb37nwhitehorn	dlg_exiterr("init_dialog: dlg_parse_rc");
31583cbb37nwhitehorn#endif
31683cbb37nwhitehorn
31783cbb37nwhitehorn    /*
31883cbb37nwhitehorn     * Some widgets (such as gauge) may read from the standard input.  Pipes
31983cbb37nwhitehorn     * only connect stdout/stdin, so there is not much choice.  But reading a
32083cbb37nwhitehorn     * pipe would get in the way of curses' normal reading stdin for getch.
32183cbb37nwhitehorn     *
32283cbb37nwhitehorn     * As in the --stdout (see below), reopening the terminal does not always
32383cbb37nwhitehorn     * work properly.  dialog provides a --pipe-fd option for this purpose.  We
32483cbb37nwhitehorn     * test that case first (differing fileno's for input/stdin).  If the
32583cbb37nwhitehorn     * fileno's are equal, but we're not reading from a tty, see if we can open
32683cbb37nwhitehorn     * /dev/tty.
32783cbb37nwhitehorn     */
32883cbb37nwhitehorn    dialog_state.pipe_input = stdin;
32983cbb37nwhitehorn    if (fileno(input) != fileno(stdin)) {
3302b5579cbapt	if ((fd1 = dup(fileno(input))) >= 0
33183cbb37nwhitehorn	    && (fd2 = dup(fileno(stdin))) >= 0) {
33283cbb37nwhitehorn	    (void) dup2(fileno(input), fileno(stdin));
33383cbb37nwhitehorn	    dialog_state.pipe_input = fdopen(fd2, "r");
33483cbb37nwhitehorn	    if (fileno(stdin) != 0)	/* some functions may read fd #0 */
33583cbb37nwhitehorn		(void) dup2(fileno(stdin), 0);
3362b5579cbapt	} else {
33783cbb37nwhitehorn	    dlg_exiterr("cannot open tty-input");
3382b5579cbapt	}
3392b5579cbapt	close(fd1);
34083cbb37nwhitehorn    } else if (!isatty(fileno(stdin))) {
3412b5579cbapt	if ((fd1 = open_terminal(&device, O_RDONLY)) >= 0) {
3422b5579cbapt	    if ((fd2 = dup(fileno(stdin))) >= 0) {
3432b5579cbapt		dialog_state.pipe_input = fdopen(fd2, "r");
3442b5579cbapt		if (freopen(device, "r", stdin) == 0)
3452b5579cbapt		    dlg_exiterr("cannot open tty-input");
3462b5579cbapt		if (fileno(stdin) != 0)		/* some functions may read fd #0 */
3472b5579cbapt		    (void) dup2(fileno(stdin), 0);
3482b5579cbapt	    }
3492b5579cbapt	    close(fd1);
35083cbb37nwhitehorn	}
35183cbb37nwhitehorn	free(device);
35283cbb37nwhitehorn    }
35383cbb37nwhitehorn
35483cbb37nwhitehorn    /*
35583cbb37nwhitehorn     * If stdout is not a tty and dialog is called with the --stdout option, we
35683cbb37nwhitehorn     * have to provide for a way to write to the screen.
35783cbb37nwhitehorn     *
35883cbb37nwhitehorn     * The curses library normally writes its output to stdout, leaving stderr
35983cbb37nwhitehorn     * free for scripting.  Scripts are simpler when stdout is redirected.  The
36083cbb37nwhitehorn     * newterm function is useful; it allows us to specify where the output
36183cbb37nwhitehorn     * goes.  Reopening the terminal is not portable since several
36283cbb37nwhitehorn     * configurations do not allow this to work properly:
36383cbb37nwhitehorn     *
36483cbb37nwhitehorn     * a) some getty implementations (and possibly broken tty drivers, e.g., on
36583cbb37nwhitehorn     *    HPUX 10 and 11) cause stdin to act as if it is still in cooked mode
36683cbb37nwhitehorn     *    even though results from ioctl's state that it is successfully
36783cbb37nwhitehorn     *    altered to raw mode.  Broken is the proper term.
36883cbb37nwhitehorn     *
36983cbb37nwhitehorn     * b) the user may not have permissions on the device, e.g., if one su's
37083cbb37nwhitehorn     *    from the login user to another non-privileged user.
37183cbb37nwhitehorn     */
37283cbb37nwhitehorn    if (!isatty(fileno(stdout))
37383cbb37nwhitehorn	&& (fileno(stdout) == fileno(output) || dialog_tty())) {
37483cbb37nwhitehorn	if ((fd1 = open_terminal(&device, O_WRONLY)) >= 0
37583cbb37nwhitehorn	    && (dialog_state.screen_output = fdopen(fd1, "w")) != 0) {
37683cbb37nwhitehorn	    if (newterm(NULL, dialog_state.screen_output, stdin) == 0) {
37783cbb37nwhitehorn		dlg_exiterr("cannot initialize curses");
37883cbb37nwhitehorn	    }
37983cbb37nwhitehorn	    free(device);
38083cbb37nwhitehorn	} else {
38183cbb37nwhitehorn	    dlg_exiterr("cannot open tty-output");
38283cbb37nwhitehorn	}
38383cbb37nwhitehorn    } else {
38483cbb37nwhitehorn	dialog_state.screen_output = stdout;
38583cbb37nwhitehorn	(void) initscr();
38683cbb37nwhitehorn    }
38783cbb37nwhitehorn#ifdef NCURSES_VERSION
38883cbb37nwhitehorn    /*
38983cbb37nwhitehorn     * Cancel xterm's alternate-screen mode.
39083cbb37nwhitehorn     */
39183cbb37nwhitehorn    if (!dialog_vars.keep_tite
3922b5579cbapt	&& (fileno(dialog_state.screen_output) != fileno(stdout)
39383cbb37nwhitehorn	    || isatty(fileno(dialog_state.screen_output)))
39483cbb37nwhitehorn	&& key_mouse != 0	/* xterm and kindred */
39583cbb37nwhitehorn	&& isprivate(enter_ca_mode)
39683cbb37nwhitehorn	&& isprivate(exit_ca_mode)) {
39783cbb37nwhitehorn	/*
3982b5579cbapt	 * initscr() or newterm() already wrote enter_ca_mode as a side
39983cbb37nwhitehorn	 * effect of initializing the screen.  It would be nice to not even
40083cbb37nwhitehorn	 * do that, but we do not really have access to the correct copy of
40183cbb37nwhitehorn	 * the terminfo description until those functions have been invoked.
40283cbb37nwhitehorn	 */
4032b5579cbapt	(void) refresh();
4042b5579cbapt	(void) tputs(exit_ca_mode, 0, my_putc);
4052b5579cbapt	(void) tputs(clear_screen, 0, my_putc);
40683cbb37nwhitehorn	/*
40783cbb37nwhitehorn	 * Prevent ncurses from switching "back" to the normal screen when
40883cbb37nwhitehorn	 * exiting from dialog.  That would move the cursor to the original
40983cbb37nwhitehorn	 * location saved in xterm.  Normally curses sets the cursor position
41083cbb37nwhitehorn	 * to the first line after the display, but the alternate screen
41183cbb37nwhitehorn	 * switching is done after that point.
41283cbb37nwhitehorn	 *
41383cbb37nwhitehorn	 * Cancelling the strings altogether also works around the buggy
41483cbb37nwhitehorn	 * implementation of alternate-screen in rxvt, etc., which clear
41583cbb37nwhitehorn	 * more of the display than they should.
41683cbb37nwhitehorn	 */
41783cbb37nwhitehorn	enter_ca_mode = 0;
41883cbb37nwhitehorn	exit_ca_mode = 0;
41983cbb37nwhitehorn    }
42083cbb37nwhitehorn#endif
42183cbb37nwhitehorn#ifdef HAVE_FLUSHINP
42283cbb37nwhitehorn    (void) flushinp();
42383cbb37nwhitehorn#endif
42483cbb37nwhitehorn    (void) keypad(stdscr, TRUE);
42583cbb37nwhitehorn    (void) cbreak();
42683cbb37nwhitehorn    (void) noecho();
4279904759nwhitehorn
4289904759nwhitehorn    if (!dialog_state.no_mouse) {
4299904759nwhitehorn	mouse_open();
4309904759nwhitehorn    }
4319904759nwhitehorn
43283cbb37nwhitehorn    dialog_state.screen_initialized = TRUE;
43383cbb37nwhitehorn
43483cbb37nwhitehorn#ifdef HAVE_COLOR
43583cbb37nwhitehorn    if (dialog_state.use_colors || dialog_state.use_shadow)
43683cbb37nwhitehorn	dlg_color_setup();	/* Set up colors */
43783cbb37nwhitehorn#endif
43883cbb37nwhitehorn
43983cbb37nwhitehorn    /* Set screen to screen attribute */
44083cbb37nwhitehorn    dlg_clear();
44183cbb37nwhitehorn}
44283cbb37nwhitehorn
44383cbb37nwhitehorn#ifdef HAVE_COLOR
44483cbb37nwhitehornstatic int defined_colors = 1;	/* pair-0 is reserved */
44583cbb37nwhitehorn/*
44683cbb37nwhitehorn * Setup for color display
44783cbb37nwhitehorn */
44883cbb37nwhitehornvoid
44983cbb37nwhitehorndlg_color_setup(void)
45083cbb37nwhitehorn{
45183cbb37nwhitehorn    unsigned i;
45283cbb37nwhitehorn
45383cbb37nwhitehorn    if (has_colors()) {		/* Terminal supports color? */
45483cbb37nwhitehorn	(void) start_color();
45583cbb37nwhitehorn
45683cbb37nwhitehorn#if defined(HAVE_USE_DEFAULT_COLORS)
45783cbb37nwhitehorn	use_default_colors();
45883cbb37nwhitehorn#endif
45983cbb37nwhitehorn
46083cbb37nwhitehorn#if defined(__NetBSD__) && defined(_CURSES_)
46183cbb37nwhitehorn#define C_ATTR(x,y) (((x) != 0 ? A_BOLD :  0) | COLOR_PAIR((y)))
46283cbb37nwhitehorn	/* work around bug in NetBSD curses */
46383cbb37nwhitehorn	for (i = 0; i < sizeof(dlg_color_table) /
46483cbb37nwhitehorn	     sizeof(dlg_color_table[0]); i++) {
46583cbb37nwhitehorn
46683cbb37nwhitehorn	    /* Initialize color pairs */
46783cbb37nwhitehorn	    (void) init_pair(i + 1,
46883cbb37nwhitehorn			     dlg_color_table[i].fg,
46983cbb37nwhitehorn			     dlg_color_table[i].bg);
47083cbb37nwhitehorn
47183cbb37nwhitehorn	    /* Setup color attributes */
47283cbb37nwhitehorn	    dlg_color_table[i].atr = C_ATTR(dlg_color_table[i].hilite, i + 1);
47383cbb37nwhitehorn	}
47483cbb37nwhitehorn	defined_colors = i + 1;
47583cbb37nwhitehorn#else
47683cbb37nwhitehorn	for (i = 0; i < sizeof(dlg_color_table) /
47783cbb37nwhitehorn	     sizeof(dlg_color_table[0]); i++) {
47883cbb37nwhitehorn
47983cbb37nwhitehorn	    /* Initialize color pairs */
48083cbb37nwhitehorn	    chtype color = dlg_color_pair(dlg_color_table[i].fg,
48183cbb37nwhitehorn					  dlg_color_table[i].bg);
48283cbb37nwhitehorn
48383cbb37nwhitehorn	    /* Setup color attributes */
48483cbb37nwhitehorn	    dlg_color_table[i].atr = ((dlg_color_table[i].hilite
48583cbb37nwhitehorn				       ? A_BOLD
48683cbb37nwhitehorn				       : 0)
48783cbb37nwhitehorn				      | color);
48883cbb37nwhitehorn	}
48983cbb37nwhitehorn#endif
49083cbb37nwhitehorn    } else {
49183cbb37nwhitehorn	dialog_state.use_colors = FALSE;
49283cbb37nwhitehorn	dialog_state.use_shadow = FALSE;
49383cbb37nwhitehorn    }
49483cbb37nwhitehorn}
49583cbb37nwhitehorn
49683cbb37nwhitehornint
49783cbb37nwhitehorndlg_color_count(void)
49883cbb37nwhitehorn{
49983cbb37nwhitehorn    return sizeof(dlg_color_table) / sizeof(dlg_color_table[0]);
50083cbb37nwhitehorn}
50183cbb37nwhitehorn
50283cbb37nwhitehorn/*
5039904759nwhitehorn * Wrapper for getattrs(), or the more cumbersome X/Open wattr_get().
5049904759nwhitehorn */
5059904759nwhitehornchtype
5069904759nwhitehorndlg_get_attrs(WINDOW *win)
5079904759nwhitehorn{
5089904759nwhitehorn    chtype result;
5099904759nwhitehorn#ifdef HAVE_GETATTRS
51094f19e0nwhitehorn    result = (chtype) getattrs(win);
5119904759nwhitehorn#else
5129904759nwhitehorn    attr_t my_result;
5139904759nwhitehorn    short my_pair;
5149904759nwhitehorn    wattr_get(win, &my_result, &my_pair, NULL);
5159904759nwhitehorn    result = my_result;
5169904759nwhitehorn#endif
5179904759nwhitehorn    return result;
5189904759nwhitehorn}
5199904759nwhitehorn
5209904759nwhitehorn/*
52183cbb37nwhitehorn * Reuse color pairs (they are limited), returning a COLOR_PAIR() value if we
52283cbb37nwhitehorn * have (or can) define a pair with the given color as foreground on the
52383cbb37nwhitehorn * window's defined background.
52483cbb37nwhitehorn */
52583cbb37nwhitehornchtype
52683cbb37nwhitehorndlg_color_pair(int foreground, int background)
52783cbb37nwhitehorn{
52883cbb37nwhitehorn    chtype result = 0;
52983cbb37nwhitehorn    int pair;
53083cbb37nwhitehorn    short fg, bg;
53183cbb37nwhitehorn    bool found = FALSE;
53283cbb37nwhitehorn
53383cbb37nwhitehorn    for (pair = 1; pair < defined_colors; ++pair) {
53483cbb37nwhitehorn	if (pair_content((short) pair, &fg, &bg) != ERR
53583cbb37nwhitehorn	    && fg == foreground
53683cbb37nwhitehorn	    && bg == background) {
53783cbb37nwhitehorn	    result = (chtype) COLOR_PAIR(pair);
53883cbb37nwhitehorn	    found = TRUE;
53983cbb37nwhitehorn	    break;
54083cbb37nwhitehorn	}
54183cbb37nwhitehorn    }
54283cbb37nwhitehorn    if (!found && (defined_colors + 1) < COLOR_PAIRS) {
54383cbb37nwhitehorn	pair = defined_colors++;
54483cbb37nwhitehorn	(void) init_pair((short) pair, (short) foreground, (short) background);
54583cbb37nwhitehorn	result = (chtype) COLOR_PAIR(pair);
54683cbb37nwhitehorn    }
54783cbb37nwhitehorn    return result;
54883cbb37nwhitehorn}
54983cbb37nwhitehorn
55083cbb37nwhitehorn/*
55183cbb37nwhitehorn * Reuse color pairs (they are limited), returning a COLOR_PAIR() value if we
55283cbb37nwhitehorn * have (or can) define a pair with the given color as foreground on the
55383cbb37nwhitehorn * window's defined background.
55483cbb37nwhitehorn */
55583cbb37nwhitehornstatic chtype
55683cbb37nwhitehorndefine_color(WINDOW *win, int foreground)
55783cbb37nwhitehorn{
55883cbb37nwhitehorn    int pair;
55983cbb37nwhitehorn    short fg, bg, background;
560f8604a5bapt    if (dialog_state.text_only) {
56183cbb37nwhitehorn	background = COLOR_BLACK;
562f8604a5bapt    } else {
563f8604a5bapt	chtype attrs = dlg_get_attrs(win);
564f8604a5bapt
565f8604a5bapt	if ((pair = PAIR_NUMBER(attrs)) != 0
566f8604a5bapt	    && pair_content((short) pair, &fg, &bg) != ERR) {
567f8604a5bapt	    background = bg;
568f8604a5bapt	} else {
569f8604a5bapt	    background = COLOR_BLACK;
570f8604a5bapt	}
57183cbb37nwhitehorn    }
57283cbb37nwhitehorn    return dlg_color_pair(foreground, background);
57383cbb37nwhitehorn}
57483cbb37nwhitehorn#endif
57583cbb37nwhitehorn
57683cbb37nwhitehorn/*
57783cbb37nwhitehorn * End using dialog functions.
57883cbb37nwhitehorn */
57983cbb37nwhitehornvoid
58083cbb37nwhitehornend_dialog(void)
58183cbb37nwhitehorn{
58283cbb37nwhitehorn    if (dialog_state.screen_initialized) {
58383cbb37nwhitehorn	dialog_state.screen_initialized = FALSE;
58483cbb37nwhitehorn	mouse_close();
58583cbb37nwhitehorn	(void) endwin();
58683cbb37nwhitehorn	(void) fflush(stdout);
58783cbb37nwhitehorn    }
58883cbb37nwhitehorn}
58983cbb37nwhitehorn
59094f19e0nwhitehorn#define ESCAPE_LEN 3
59183cbb37nwhitehorn#define isOurEscape(p) (((p)[0] == '\\') && ((p)[1] == 'Z') && ((p)[2] != 0))
59283cbb37nwhitehorn
593a94245bnwhitehornint
594a94245bnwhitehorndlg_count_real_columns(const char *text)
595a94245bnwhitehorn{
596e53d5c4dteske    int result = 0;
597e53d5c4dteske    if (*text) {
598e53d5c4dteske	result = dlg_count_columns(text);
599e53d5c4dteske	if (result && dialog_vars.colors) {
600e53d5c4dteske	    int hidden = 0;
601e53d5c4dteske	    while (*text) {
602e53d5c4dteske		if (dialog_vars.colors && isOurEscape(text)) {
603e53d5c4dteske		    hidden += ESCAPE_LEN;
604e53d5c4dteske		    text += ESCAPE_LEN;
605e53d5c4dteske		} else {
606e53d5c4dteske		    ++text;
607e53d5c4dteske		}
608a94245bnwhitehorn	    }
609e53d5c4dteske	    result -= hidden;
610a94245bnwhitehorn	}
611a94245bnwhitehorn    }
612a94245bnwhitehorn    return result;
613a94245bnwhitehorn}
614a94245bnwhitehorn
61583cbb37nwhitehornstatic int
61683cbb37nwhitehorncentered(int width, const char *string)
61783cbb37nwhitehorn{
618a94245bnwhitehorn    int need = dlg_count_real_columns(string);
61983cbb37nwhitehorn    int left;
62083cbb37nwhitehorn
621a94245bnwhitehorn    left = (width - need) / 2 - 1;
62283cbb37nwhitehorn    if (left < 0)
62383cbb37nwhitehorn	left = 0;
62483cbb37nwhitehorn    return left;
62583cbb37nwhitehorn}
62683cbb37nwhitehorn
6279904759nwhitehorn#ifdef USE_WIDE_CURSES
6289904759nwhitehornstatic bool
6299904759nwhitehornis_combining(const char *txt, int *combined)
6309904759nwhitehorn{
6319904759nwhitehorn    bool result = FALSE;
6329904759nwhitehorn
6339904759nwhitehorn    if (*combined == 0) {
6349904759nwhitehorn	if (UCH(*txt) >= 128) {
6359904759nwhitehorn	    wchar_t wch;
6369904759nwhitehorn	    mbstate_t state;
6379904759nwhitehorn	    size_t given = strlen(txt);
6389904759nwhitehorn	    size_t len;
6399904759nwhitehorn
6409904759nwhitehorn	    memset(&state, 0, sizeof(state));
6419904759nwhitehorn	    len = mbrtowc(&wch, txt, given, &state);
6429904759nwhitehorn	    if ((int) len > 0 && wcwidth(wch) == 0) {
6439904759nwhitehorn		*combined = (int) len - 1;
6449904759nwhitehorn		result = TRUE;
6459904759nwhitehorn	    }
6469904759nwhitehorn	}
6479904759nwhitehorn    } else {
6489904759nwhitehorn	result = TRUE;
6499904759nwhitehorn	*combined -= 1;
6509904759nwhitehorn    }
6519904759nwhitehorn    return result;
6529904759nwhitehorn}
6539904759nwhitehorn#endif
6549904759nwhitehorn
65583cbb37nwhitehorn/*
6562b5579cbapt * Print the name (tag) or text from a DIALOG_LISTITEM, highlighting the
6572b5579cbapt * first character if selected.
6582b5579cbapt */
6592b5579cbaptvoid
6602b5579cbaptdlg_print_listitem(WINDOW *win,
6612b5579cbapt		   const char *text,
6622b5579cbapt		   int climit,
6632b5579cbapt		   bool first,
6642b5579cbapt		   int selected)
6652b5579cbapt{
6662b5579cbapt    chtype attr = A_NORMAL;
6672b5579cbapt    int limit;
6682b5579cbapt    const int *cols;
6692b5579cbapt    chtype attrs[4];
6702b5579cbapt
6712b5579cbapt    if (text == 0)
6722b5579cbapt	text = "";
6732b5579cbapt
6742b5579cbapt    if (first) {
6752b5579cbapt	const int *indx = dlg_index_wchars(text);
6762b5579cbapt	attrs[3] = tag_key_selected_attr;
6772b5579cbapt	attrs[2] = tag_key_attr;
6782b5579cbapt	attrs[1] = tag_selected_attr;
6792b5579cbapt	attrs[0] = tag_attr;
6802b5579cbapt
681f8604a5bapt	dlg_attrset(win, selected ? attrs[3] : attrs[2]);
6822b5579cbapt	(void) waddnstr(win, text, indx[1]);
6832b5579cbapt
6842b5579cbapt	if ((int) strlen(text) > indx[1]) {
6852b5579cbapt	    limit = dlg_limit_columns(text, climit, 1);
6862b5579cbapt	    if (limit > 1) {
687f8604a5bapt		dlg_attrset(win, selected ? attrs[1] : attrs[0]);
6882b5579cbapt		(void) waddnstr(win,
6892b5579cbapt				text + indx[1],
6902b5579cbapt				indx[limit] - indx[1]);
6912b5579cbapt	    }
6922b5579cbapt	}
6932b5579cbapt    } else {
6942b5579cbapt	attrs[1] = item_selected_attr;
6952b5579cbapt	attrs[0] = item_attr;
6962b5579cbapt
6972b5579cbapt	cols = dlg_index_columns(text);
6982b5579cbapt	limit = dlg_limit_columns(text, climit, 0);
6992b5579cbapt
7002b5579cbapt	if (limit > 0) {
701f8604a5bapt	    dlg_attrset(win, selected ? attrs[1] : attrs[0]);
7022b5579cbapt	    dlg_print_text(win, text, cols[limit], &attr);
7032b5579cbapt	}
7042b5579cbapt    }
7052b5579cbapt}
7062b5579cbapt
7072b5579cbapt/*
70883cbb37nwhitehorn * Print up to 'cols' columns from 'text', optionally rendering our escape
70983cbb37nwhitehorn * sequence for attributes and color.
71083cbb37nwhitehorn */
71183cbb37nwhitehornvoid
71283cbb37nwhitehorndlg_print_text(WINDOW *win, const char *txt, int cols, chtype *attr)
71383cbb37nwhitehorn{
71483cbb37nwhitehorn    int y_origin, x_origin;
71583cbb37nwhitehorn    int y_before, x_before = 0;
71683cbb37nwhitehorn    int y_after, x_after;
71783cbb37nwhitehorn    int tabbed = 0;
71883cbb37nwhitehorn    bool thisTab;
71983cbb37nwhitehorn    bool ended = FALSE;
72083cbb37nwhitehorn    chtype useattr;
7219904759nwhitehorn#ifdef USE_WIDE_CURSES
7229904759nwhitehorn    int combined = 0;
7239904759nwhitehorn#endif
72483cbb37nwhitehorn
725f8604a5bapt    if (dialog_state.text_only) {
726f8604a5bapt	y_origin = y_after = 0;
727f8604a5bapt	x_origin = x_after = 0;
728f8604a5bapt    } else {
729f8604a5bapt	getyx(win, y_origin, x_origin);
730f8604a5bapt    }
73183cbb37nwhitehorn    while (cols > 0 && (*txt != '\0')) {
73283cbb37nwhitehorn	if (dialog_vars.colors) {
73383cbb37nwhitehorn	    while (isOurEscape(txt)) {
73483cbb37nwhitehorn		int code;
73583cbb37nwhitehorn
73683cbb37nwhitehorn		txt += 2;
73783cbb37nwhitehorn		switch (code = CharOf(*txt)) {
73883cbb37nwhitehorn#ifdef HAVE_COLOR
73983cbb37nwhitehorn		case '0':
74083cbb37nwhitehorn		case '1':
74183cbb37nwhitehorn		case '2':
74283cbb37nwhitehorn		case '3':
74383cbb37nwhitehorn		case '4':
74483cbb37nwhitehorn		case '5':
74583cbb37nwhitehorn		case '6':
74683cbb37nwhitehorn		case '7':
74783cbb37nwhitehorn		    *attr &= ~A_COLOR;
74883cbb37nwhitehorn		    *attr |= define_color(win, code - '0');
74983cbb37nwhitehorn		    break;
75083cbb37nwhitehorn#endif
75183cbb37nwhitehorn		case 'B':
75283cbb37nwhitehorn		    *attr &= ~A_BOLD;
75383cbb37nwhitehorn		    break;
75483cbb37nwhitehorn		case 'b':
75583cbb37nwhitehorn		    *attr |= A_BOLD;
75683cbb37nwhitehorn		    break;
75783cbb37nwhitehorn		case 'R':
75883cbb37nwhitehorn		    *attr &= ~A_REVERSE;
75983cbb37nwhitehorn		    break;
76083cbb37nwhitehorn		case 'r':
76183cbb37nwhitehorn		    *attr |= A_REVERSE;
76283cbb37nwhitehorn		    break;
76383cbb37nwhitehorn		case 'U':
76483cbb37nwhitehorn		    *attr &= ~A_UNDERLINE;
76583cbb37nwhitehorn		    break;
76683cbb37nwhitehorn		case 'u':
76783cbb37nwhitehorn		    *attr |= A_UNDERLINE;
76883cbb37nwhitehorn		    break;
76983cbb37nwhitehorn		case 'n':
77083cbb37nwhitehorn		    *attr = A_NORMAL;
77183cbb37nwhitehorn		    break;
77283cbb37nwhitehorn		}
77383cbb37nwhitehorn		++txt;
77483cbb37nwhitehorn	    }
77583cbb37nwhitehorn	}
77683cbb37nwhitehorn	if (ended || *txt == '\n' || *txt == '\0')
77783cbb37nwhitehorn	    break;
77883cbb37nwhitehorn	useattr = (*attr) & A_ATTRIBUTES;
77983cbb37nwhitehorn#ifdef HAVE_COLOR
78083cbb37nwhitehorn	/*
78183cbb37nwhitehorn	 * Prevent this from making text invisible when the foreground and
78283cbb37nwhitehorn	 * background colors happen to be the same, and there's no bold
78383cbb37nwhitehorn	 * attribute.
78483cbb37nwhitehorn	 */
78583cbb37nwhitehorn	if ((useattr & A_COLOR) != 0 && (useattr & A_BOLD) == 0) {
78683cbb37nwhitehorn	    short pair = (short) PAIR_NUMBER(useattr);
78783cbb37nwhitehorn	    short fg, bg;
78883cbb37nwhitehorn	    if (pair_content(pair, &fg, &bg) != ERR
78983cbb37nwhitehorn		&& fg == bg) {
79083cbb37nwhitehorn		useattr &= ~A_COLOR;
79183cbb37nwhitehorn		useattr |= dlg_color_pair(fg, ((bg == COLOR_BLACK)
79283cbb37nwhitehorn					       ? COLOR_WHITE
79383cbb37nwhitehorn					       : COLOR_BLACK));
79483cbb37nwhitehorn	    }
79583cbb37nwhitehorn	}
79683cbb37nwhitehorn#endif
79783cbb37nwhitehorn	/*
79883cbb37nwhitehorn	 * Write the character, using curses to tell exactly how wide it
79983cbb37nwhitehorn	 * is.  If it is a tab, discount that, since the caller thinks
80083cbb37nwhitehorn	 * tabs are nonprinting, and curses will expand tabs to one or
80183cbb37nwhitehorn	 * more blanks.
80283cbb37nwhitehorn	 */
80383cbb37nwhitehorn	thisTab = (CharOf(*txt) == TAB);
804f8604a5bapt	if (dialog_state.text_only) {
805f8604a5bapt	    y_before = y_after;
806f8604a5bapt	    x_before = x_after;
807f8604a5bapt	} else {
808f8604a5bapt	    if (thisTab) {
809f8604a5bapt		getyx(win, y_before, x_before);
810f8604a5bapt		(void) y_before;
811f8604a5bapt	    }
812f8604a5bapt	}
813f8604a5bapt	if (dialog_state.text_only) {
814f8604a5bapt	    int ch = CharOf(*txt++);
815f8604a5bapt	    if (thisTab) {
816f8604a5bapt		while ((x_after++) % 8) {
817f8604a5bapt		    fputc(' ', dialog_state.output);
818f8604a5bapt		}
819f8604a5bapt	    } else {
820f8604a5bapt		fputc(ch, dialog_state.output);
821f8604a5bapt		x_after++;	/* FIXME: handle meta per locale */
822f8604a5bapt	    }
823f8604a5bapt	} else {
824f8604a5bapt	    (void) waddch(win, CharOf(*txt++) | useattr);
825f8604a5bapt	    getyx(win, y_after, x_after);
826a94245bnwhitehorn	}
82783cbb37nwhitehorn	if (thisTab && (y_after == y_origin))
82883cbb37nwhitehorn	    tabbed += (x_after - x_before);
8299904759nwhitehorn	if ((y_after != y_origin) ||
8309904759nwhitehorn	    (x_after >= (cols + tabbed + x_origin)
8319904759nwhitehorn#ifdef USE_WIDE_CURSES
8329904759nwhitehorn	     && !is_combining(txt, &combined)
8339904759nwhitehorn#endif
8349904759nwhitehorn	    )) {
83583cbb37nwhitehorn	    ended = TRUE;
83683cbb37nwhitehorn	}
83783cbb37nwhitehorn    }
838f8604a5bapt    if (dialog_state.text_only) {
839f8604a5bapt	fputc('\n', dialog_state.output);
840f8604a5bapt    }
84183cbb37nwhitehorn}
84283cbb37nwhitehorn
84383cbb37nwhitehorn/*
84483cbb37nwhitehorn * Print one line of the prompt in the window within the limits of the
84583cbb37nwhitehorn * specified right margin.  The line will end on a word boundary and a pointer
84683cbb37nwhitehorn * to the start of the next line is returned, or a NULL pointer if the end of
84783cbb37nwhitehorn * *prompt is reached.
84883cbb37nwhitehorn */
84983cbb37nwhitehornconst char *
85083cbb37nwhitehorndlg_print_line(WINDOW *win,
85183cbb37nwhitehorn	       chtype *attr,
85283cbb37nwhitehorn	       const char *prompt,
85383cbb37nwhitehorn	       int lm, int rm, int *x)
85483cbb37nwhitehorn{
8552b5579cbapt    const char *wrap_ptr;
8562b5579cbapt    const char *test_ptr;
85794f19e0nwhitehorn    const char *hide_ptr = 0;
85883cbb37nwhitehorn    const int *cols = dlg_index_columns(prompt);
85983cbb37nwhitehorn    const int *indx = dlg_index_wchars(prompt);
86083cbb37nwhitehorn    int wrap_inx = 0;
86183cbb37nwhitehorn    int test_inx = 0;
86283cbb37nwhitehorn    int cur_x = lm;
86383cbb37nwhitehorn    int hidden = 0;
86483cbb37nwhitehorn    int limit = dlg_count_wchars(prompt);
86583cbb37nwhitehorn    int n;
86683cbb37nwhitehorn    int tabbed = 0;
86783cbb37nwhitehorn
86883cbb37nwhitehorn    *x = 1;
86983cbb37nwhitehorn
87083cbb37nwhitehorn    /*
87183cbb37nwhitehorn     * Set *test_ptr to the end of the line or the right margin (rm), whichever
87283cbb37nwhitehorn     * is less, and set wrap_ptr to the end of the last word in the line.
87383cbb37nwhitehorn     */
87483cbb37nwhitehorn    for (n = 0; n < limit; ++n) {
875f8604a5bapt	int ch = *(test_ptr = prompt + indx[test_inx]);
876f8604a5bapt	if (ch == '\n' || ch == '\0' || cur_x >= (rm + hidden))
87783cbb37nwhitehorn	    break;
878f8604a5bapt	if (ch == TAB && n == 0) {
87983cbb37nwhitehorn	    tabbed = 8;		/* workaround for leading tabs */
880f8604a5bapt	} else if (isblank(UCH(ch))
881f8604a5bapt		   && n != 0
882f8604a5bapt		   && !isblank(UCH(prompt[indx[n - 1]]))) {
88383cbb37nwhitehorn	    wrap_inx = n;
88483cbb37nwhitehorn	    *x = cur_x;
885a94245bnwhitehorn	} else if (dialog_vars.colors && isOurEscape(test_ptr)) {
88694f19e0nwhitehorn	    hide_ptr = test_ptr;
88794f19e0nwhitehorn	    hidden += ESCAPE_LEN;
88894f19e0nwhitehorn	    n += (ESCAPE_LEN - 1);
88983cbb37nwhitehorn	}
89083cbb37nwhitehorn	cur_x = lm + tabbed + cols[n + 1];
89183cbb37nwhitehorn	if (cur_x > (rm + hidden))
89283cbb37nwhitehorn	    break;
89383cbb37nwhitehorn	test_inx = n + 1;
89483cbb37nwhitehorn    }
89583cbb37nwhitehorn
89683cbb37nwhitehorn    /*
89783cbb37nwhitehorn     * If the line doesn't reach the right margin in the middle of a word, then
89883cbb37nwhitehorn     * we don't have to wrap it at the end of the previous word.
89983cbb37nwhitehorn     */
90083cbb37nwhitehorn    test_ptr = prompt + indx[test_inx];
901f8604a5bapt    if (*test_ptr == '\n' || isblank(UCH(*test_ptr)) || *test_ptr == '\0') {
90283cbb37nwhitehorn	wrap_inx = test_inx;
903f8604a5bapt	while (wrap_inx > 0 && isblank(UCH(prompt[indx[wrap_inx - 1]]))) {
90483cbb37nwhitehorn	    wrap_inx--;
90583cbb37nwhitehorn	}
90683cbb37nwhitehorn	*x = lm + indx[wrap_inx];
90783cbb37nwhitehorn    } else if (*x == 1 && cur_x >= rm) {
90883cbb37nwhitehorn	/*
90983cbb37nwhitehorn	 * If the line has no spaces, then wrap it anyway at the right margin
91083cbb37nwhitehorn	 */
91183cbb37nwhitehorn	*x = rm;
91283cbb37nwhitehorn	wrap_inx = test_inx;
91383cbb37nwhitehorn    }
91483cbb37nwhitehorn    wrap_ptr = prompt + indx[wrap_inx];
9159904759nwhitehorn#ifdef USE_WIDE_CURSES
9169904759nwhitehorn    if (UCH(*wrap_ptr) >= 128) {
9179904759nwhitehorn	int combined = 0;
9189904759nwhitehorn	while (is_combining(wrap_ptr, &combined)) {
9199904759nwhitehorn	    ++wrap_ptr;
9209904759nwhitehorn	}
9219904759nwhitehorn    }
9229904759nwhitehorn#endif
92383cbb37nwhitehorn
92483cbb37nwhitehorn    /*
92594f19e0nwhitehorn     * If we found hidden text past the last point that we will display,
92694f19e0nwhitehorn     * discount that from the displayed length.
92794f19e0nwhitehorn     */
92894f19e0nwhitehorn    if ((hide_ptr != 0) && (hide_ptr >= wrap_ptr)) {
92994f19e0nwhitehorn	hidden -= ESCAPE_LEN;
93094f19e0nwhitehorn	test_ptr = wrap_ptr;
93194f19e0nwhitehorn	while (test_ptr < wrap_ptr) {
932a94245bnwhitehorn	    if (dialog_vars.colors && isOurEscape(test_ptr)) {
93394f19e0nwhitehorn		hidden -= ESCAPE_LEN;
93494f19e0nwhitehorn		test_ptr += ESCAPE_LEN;
93594f19e0nwhitehorn	    } else {
93694f19e0nwhitehorn		++test_ptr;
93794f19e0nwhitehorn	    }
93894f19e0nwhitehorn	}
93994f19e0nwhitehorn    }
94094f19e0nwhitehorn
94194f19e0nwhitehorn    /*
94283cbb37nwhitehorn     * Print the line if we have a window pointer.  Otherwise this routine
94383cbb37nwhitehorn     * is just being called for sizing the window.
94483cbb37nwhitehorn     */
945f8604a5bapt    if (dialog_state.text_only || win) {
94683cbb37nwhitehorn	dlg_print_text(win, prompt, (cols[wrap_inx] - hidden), attr);
94783cbb37nwhitehorn    }
94883cbb37nwhitehorn
94983cbb37nwhitehorn    /* *x tells the calling function how long the line was */
950f8604a5bapt    if (*x == 1) {
95183cbb37nwhitehorn	*x = rm;
952f8604a5bapt    }
95383cbb37nwhitehorn
95494f19e0nwhitehorn    *x -= hidden;
95594f19e0nwhitehorn
95683cbb37nwhitehorn    /* Find the start of the next line and return a pointer to it */
95783cbb37nwhitehorn    test_ptr = wrap_ptr;
958f8604a5bapt    while (isblank(UCH(*test_ptr)))
95983cbb37nwhitehorn	test_ptr++;
96083cbb37nwhitehorn    if (*test_ptr == '\n')
96183cbb37nwhitehorn	test_ptr++;
962e53d5c4dteske    dlg_finish_string(prompt);
96383cbb37nwhitehorn    return (test_ptr);
96483cbb37nwhitehorn}
96583cbb37nwhitehorn
96683cbb37nwhitehornstatic void
96783cbb37nwhitehornjustify_text(WINDOW *win,
96883cbb37nwhitehorn	     const char *prompt,
96983cbb37nwhitehorn	     int limit_y,
97083cbb37nwhitehorn	     int limit_x,
97183cbb37nwhitehorn	     int *high, int *wide)
97283cbb37nwhitehorn{
97383cbb37nwhitehorn    chtype attr = A_NORMAL;
97483cbb37nwhitehorn    int x = (2 * MARGIN);
97583cbb37nwhitehorn    int y = MARGIN;
97683cbb37nwhitehorn    int max_x = 2;
97783cbb37nwhitehorn    int lm = (2 * MARGIN);	/* left margin (box-border plus a space) */
97883cbb37nwhitehorn    int rm = limit_x;		/* right margin */
97983cbb37nwhitehorn    int bm = limit_y;		/* bottom margin */
98083cbb37nwhitehorn    int last_y = 0, last_x = 0;
98183cbb37nwhitehorn
982f8604a5bapt    dialog_state.text_height = 0;
983f8604a5bapt    dialog_state.text_width = 0;
984f8604a5bapt    if (dialog_state.text_only || win) {
98583cbb37nwhitehorn	rm -= (2 * MARGIN);
98683cbb37nwhitehorn	bm -= (2 * MARGIN);
98783cbb37nwhitehorn    }
98883cbb37nwhitehorn    if (prompt == 0)
98983cbb37nwhitehorn	prompt = "";
99083cbb37nwhitehorn
99183cbb37nwhitehorn    if (win != 0)
99283cbb37nwhitehorn	getyx(win, last_y, last_x);
99383cbb37nwhitehorn    while (y <= bm && *prompt) {
99483cbb37nwhitehorn	x = lm;
99583cbb37nwhitehorn
99683cbb37nwhitehorn	if (*prompt == '\n') {
99783cbb37nwhitehorn	    while (*prompt == '\n' && y < bm) {
99883cbb37nwhitehorn		if (*(prompt + 1) != '\0') {
99983cbb37nwhitehorn		    ++y;
100083cbb37nwhitehorn		    if (win != 0)
100183cbb37nwhitehorn			(void) wmove(win, y, lm);
100283cbb37nwhitehorn		}
100383cbb37nwhitehorn		prompt++;
100483cbb37nwhitehorn	    }
100583cbb37nwhitehorn	} else if (win != 0)
100683cbb37nwhitehorn	    (void) wmove(win, y, lm);
100783cbb37nwhitehorn
100883cbb37nwhitehorn	if (*prompt) {
100983cbb37nwhitehorn	    prompt = dlg_print_line(win, &attr, prompt, lm, rm, &x);
101083cbb37nwhitehorn	    if (win != 0)
101183cbb37nwhitehorn		getyx(win, last_y, last_x);
101283cbb37nwhitehorn	}
101383cbb37nwhitehorn	if (*prompt) {
101483cbb37nwhitehorn	    ++y;
101583cbb37nwhitehorn	    if (win != 0)
101683cbb37nwhitehorn		(void) wmove(win, y, lm);
101783cbb37nwhitehorn	}
101883cbb37nwhitehorn	max_x = MAX(max_x, x);
101983cbb37nwhitehorn    }
102083cbb37nwhitehorn    /* Move back to the last position after drawing prompt, for msgbox. */
102183cbb37nwhitehorn    if (win != 0)
102283cbb37nwhitehorn	(void) wmove(win, last_y, last_x);
102383cbb37nwhitehorn
102483cbb37nwhitehorn    /* Set the final height and width for the calling function */
102583cbb37nwhitehorn    if (high != 0)
102683cbb37nwhitehorn	*high = y;
102783cbb37nwhitehorn    if (wide != 0)
102883cbb37nwhitehorn	*wide = max_x;
102983cbb37nwhitehorn}
103083cbb37nwhitehorn
103183cbb37nwhitehorn/*
103283cbb37nwhitehorn * Print a string of text in a window, automatically wrap around to the next
103383cbb37nwhitehorn * line if the string is too long to fit on one line.  Note that the string may
103483cbb37nwhitehorn * contain embedded newlines.
103583cbb37nwhitehorn */
103683cbb37nwhitehornvoid
103783cbb37nwhitehorndlg_print_autowrap(WINDOW *win, const char *prompt, int height, int width)
103883cbb37nwhitehorn{
103983cbb37nwhitehorn    justify_text(win, prompt,
104083cbb37nwhitehorn		 height,
104183cbb37nwhitehorn		 width,
104283cbb37nwhitehorn		 (int *) 0, (int *) 0);
104383cbb37nwhitehorn}
104483cbb37nwhitehorn
104583cbb37nwhitehorn/*
104683cbb37nwhitehorn * Display the message in a scrollable window.  Actually the way it works is
104783cbb37nwhitehorn * that we create a "tall" window of the proper width, let the text wrap within
104883cbb37nwhitehorn * that, and copy a slice of the result to the dialog.
104983cbb37nwhitehorn *
105083cbb37nwhitehorn * It works for ncurses.  Other curses implementations show only blanks (Tru64)
105183cbb37nwhitehorn * or garbage (NetBSD).
105283cbb37nwhitehorn */
105383cbb37nwhitehornint
105483cbb37nwhitehorndlg_print_scrolled(WINDOW *win,
105583cbb37nwhitehorn		   const char *prompt,
105683cbb37nwhitehorn		   int offset,
105783cbb37nwhitehorn		   int height,
105883cbb37nwhitehorn		   int width,
105983cbb37nwhitehorn		   int pauseopt)
106083cbb37nwhitehorn{
106183cbb37nwhitehorn    int oldy, oldx;
106283cbb37nwhitehorn    int last = 0;
106383cbb37nwhitehorn
10649904759nwhitehorn    (void) pauseopt;		/* used only for ncurses */
10659904759nwhitehorn
106683cbb37nwhitehorn    getyx(win, oldy, oldx);
106783cbb37nwhitehorn#ifdef NCURSES_VERSION
106883cbb37nwhitehorn    if (pauseopt) {
106983cbb37nwhitehorn	int wide = width - (2 * MARGIN);
107083cbb37nwhitehorn	int high = LINES;
107183cbb37nwhitehorn	int y, x;
107283cbb37nwhitehorn	int len;
107383cbb37nwhitehorn	int percent;
107483cbb37nwhitehorn	WINDOW *dummy;
107583cbb37nwhitehorn	char buffer[5];
107683cbb37nwhitehorn
107783cbb37nwhitehorn#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20040417
107883cbb37nwhitehorn	/*
107983cbb37nwhitehorn	 * If we're not limited by the screensize, allow text to possibly be
108083cbb37nwhitehorn	 * one character per line.
108183cbb37nwhitehorn	 */
108283cbb37nwhitehorn	if ((len = dlg_count_columns(prompt)) > high)
108383cbb37nwhitehorn	    high = len;
108483cbb37nwhitehorn#endif
108583cbb37nwhitehorn	dummy = newwin(high, width, 0, 0);
108694f19e0nwhitehorn	if (dummy == 0) {
1087f8604a5bapt	    dlg_attrset(win, dialog_attr);
108894f19e0nwhitehorn	    dlg_print_autowrap(win, prompt, height + 1 + (3 * MARGIN), width);
108994f19e0nwhitehorn	    last = 0;
109094f19e0nwhitehorn	} else {
109194f19e0nwhitehorn	    wbkgdset(dummy, dialog_attr | ' ');
1092f8604a5bapt	    dlg_attrset(dummy, dialog_attr);
109394f19e0nwhitehorn	    werase(dummy);
109494f19e0nwhitehorn	    dlg_print_autowrap(dummy, prompt, high, width);
109594f19e0nwhitehorn	    getyx(dummy, y, x);
1096a94245bnwhitehorn	    (void) x;
109794f19e0nwhitehorn
109894f19e0nwhitehorn	    copywin(dummy,	/* srcwin */
109994f19e0nwhitehorn		    win,	/* dstwin */
110094f19e0nwhitehorn		    offset + MARGIN,	/* sminrow */
110194f19e0nwhitehorn		    MARGIN,	/* smincol */
110294f19e0nwhitehorn		    MARGIN,	/* dminrow */
110394f19e0nwhitehorn		    MARGIN,	/* dmincol */
110494f19e0nwhitehorn		    height,	/* dmaxrow */
110594f19e0nwhitehorn		    wide,	/* dmaxcol */
110694f19e0nwhitehorn		    FALSE);
110794f19e0nwhitehorn
110894f19e0nwhitehorn	    delwin(dummy);
110994f19e0nwhitehorn
111094f19e0nwhitehorn	    /* if the text is incomplete, or we have scrolled, show the percentage */
111194f19e0nwhitehorn	    if (y > 0 && wide > 4) {
111294f19e0nwhitehorn		percent = (int) ((height + offset) * 100.0 / y);
111394f19e0nwhitehorn		if (percent < 0)
111494f19e0nwhitehorn		    percent = 0;
111594f19e0nwhitehorn		if (percent > 100)
111694f19e0nwhitehorn		    percent = 100;
111794f19e0nwhitehorn		if (offset != 0 || percent != 100) {
1118f8604a5bapt		    dlg_attrset(win, position_indicator_attr);
111994f19e0nwhitehorn		    (void) wmove(win, MARGIN + height, wide - 4);
112094f19e0nwhitehorn		    (void) sprintf(buffer, "%d%%", percent);
112194f19e0nwhitehorn		    (void) waddstr(win, buffer);
112294f19e0nwhitehorn		    if ((len = (int) strlen(buffer)) < 4) {
1123f8604a5bapt			dlg_attrset(win, border_attr);
112494f19e0nwhitehorn			whline(win, dlg_boxchar(ACS_HLINE), 4 - len);
112594f19e0nwhitehorn		    }
112683cbb37nwhitehorn		}
112783cbb37nwhitehorn	    }
112894f19e0nwhitehorn	    last = (y - height);
112983cbb37nwhitehorn	}
113083cbb37nwhitehorn    } else
113183cbb37nwhitehorn#endif
113283cbb37nwhitehorn    {
113383cbb37nwhitehorn	(void) offset;
1134f8604a5bapt	dlg_attrset(win, dialog_attr);
113583cbb37nwhitehorn	dlg_print_autowrap(win, prompt, height + 1 + (3 * MARGIN), width);
113683cbb37nwhitehorn	last = 0;
113783cbb37nwhitehorn    }
113883cbb37nwhitehorn    wmove(win, oldy, oldx);
113983cbb37nwhitehorn    return last;
114083cbb37nwhitehorn}
114183cbb37nwhitehorn
114283cbb37nwhitehornint
114383cbb37nwhitehorndlg_check_scrolled(int key, int last, int page, bool * show, int *offset)
114483cbb37nwhitehorn{
114583cbb37nwhitehorn    int code = 0;
114683cbb37nwhitehorn
114783cbb37nwhitehorn    *show = FALSE;
114883cbb37nwhitehorn
114983cbb37nwhitehorn    switch (key) {
115083cbb37nwhitehorn    case DLGK_PAGE_FIRST:
115183cbb37nwhitehorn	if (*offset > 0) {
115283cbb37nwhitehorn	    *offset = 0;
115383cbb37nwhitehorn	    *show = TRUE;
115483cbb37nwhitehorn	}
115583cbb37nwhitehorn	break;
115683cbb37nwhitehorn    case DLGK_PAGE_LAST:
115783cbb37nwhitehorn	if (*offset < last) {
115883cbb37nwhitehorn	    *offset = last;
115983cbb37nwhitehorn	    *show = TRUE;
116083cbb37nwhitehorn	}
116183cbb37nwhitehorn	break;
116283cbb37nwhitehorn    case DLGK_GRID_UP:
116383cbb37nwhitehorn	if (*offset > 0) {
116483cbb37nwhitehorn	    --(*offset);
116583cbb37nwhitehorn	    *show = TRUE;
116683cbb37nwhitehorn	}
116783cbb37nwhitehorn	break;
116883cbb37nwhitehorn    case DLGK_GRID_DOWN:
116983cbb37nwhitehorn	if (*offset < last) {
117083cbb37nwhitehorn	    ++(*offset);
117183cbb37nwhitehorn	    *show = TRUE;
117283cbb37nwhitehorn	}
117383cbb37nwhitehorn	break;
117483cbb37nwhitehorn    case DLGK_PAGE_PREV:
117583cbb37nwhitehorn	if (*offset > 0) {
117683cbb37nwhitehorn	    *offset -= page;
117783cbb37nwhitehorn	    if (*offset < 0)
117883cbb37nwhitehorn		*offset = 0;
117983cbb37nwhitehorn	    *show = TRUE;
118083cbb37nwhitehorn	}
118183cbb37nwhitehorn	break;
118283cbb37nwhitehorn    case DLGK_PAGE_NEXT:
118383cbb37nwhitehorn	if (*offset < last) {
118483cbb37nwhitehorn	    *offset += page;
118583cbb37nwhitehorn	    if (*offset > last)
118683cbb37nwhitehorn		*offset = last;
118783cbb37nwhitehorn	    *show = TRUE;
118883cbb37nwhitehorn	}
118983cbb37nwhitehorn	break;
119083cbb37nwhitehorn    default:
119183cbb37nwhitehorn	code = -1;
119283cbb37nwhitehorn	break;
119383cbb37nwhitehorn    }
119483cbb37nwhitehorn    return code;
119583cbb37nwhitehorn}
119683cbb37nwhitehorn
119783cbb37nwhitehorn/*
119883cbb37nwhitehorn * Calculate the window size for preformatted text.  This will calculate box
119983cbb37nwhitehorn * dimensions that are at or close to the specified aspect ratio for the prompt
120083cbb37nwhitehorn * string with all spaces and newlines preserved and additional newlines added
120183cbb37nwhitehorn * as necessary.
120283cbb37nwhitehorn */
120383cbb37nwhitehornstatic void
120483cbb37nwhitehornauto_size_preformatted(const char *prompt, int *height, int *width)
120583cbb37nwhitehorn{
120683cbb37nwhitehorn    int high = 0, wide = 0;
120783cbb37nwhitehorn    float car;			/* Calculated Aspect Ratio */
120883cbb37nwhitehorn    float diff;
120983cbb37nwhitehorn    int max_y = SLINES - 1;
121083cbb37nwhitehorn    int max_x = SCOLS - 2;
121183cbb37nwhitehorn    int max_width = max_x;
121283cbb37nwhitehorn    int ar = dialog_state.aspect_ratio;
121383cbb37nwhitehorn
121483cbb37nwhitehorn    /* Get the initial dimensions */
121583cbb37nwhitehorn    justify_text((WINDOW *) 0, prompt, max_y, max_x, &high, &wide);
121683cbb37nwhitehorn    car = (float) (wide / high);
121783cbb37nwhitehorn
121883cbb37nwhitehorn    /*
121983cbb37nwhitehorn     * If the aspect ratio is greater than it should be, then decrease the
122083cbb37nwhitehorn     * width proportionately.
122183cbb37nwhitehorn     */
122283cbb37nwhitehorn    if (car > ar) {
122383cbb37nwhitehorn	diff = car / (float) ar;
122483cbb37nwhitehorn	max_x = (int) ((float) wide / diff + 4);
122583cbb37nwhitehorn	justify_text((WINDOW *) 0, prompt, max_y, max_x, &high, &wide);
122683cbb37nwhitehorn	car = (float) wide / (float) high;
122783cbb37nwhitehorn    }
122883cbb37nwhitehorn
122983cbb37nwhitehorn    /*
123083cbb37nwhitehorn     * If the aspect ratio is too small after decreasing the width, then
123183cbb37nwhitehorn     * incrementally increase the width until the aspect ratio is equal to or
123283cbb37nwhitehorn     * greater than the specified aspect ratio.
123383cbb37nwhitehorn     */
123483cbb37nwhitehorn    while (car < ar && max_x < max_width) {
123583cbb37nwhitehorn	max_x += 4;
123683cbb37nwhitehorn	justify_text((WINDOW *) 0, prompt, max_y, max_x, &high, &wide);
123783cbb37nwhitehorn	car = (float) (wide / high);
123883cbb37nwhitehorn    }
123983cbb37nwhitehorn
124083cbb37nwhitehorn    *height = high;
124183cbb37nwhitehorn    *width = wide;
124283cbb37nwhitehorn}
124383cbb37nwhitehorn
124483cbb37nwhitehorn/*
124583cbb37nwhitehorn * Find the length of the longest "word" in the given string.  By setting the
124683cbb37nwhitehorn * widget width at least this long, we can avoid splitting a word on the
124783cbb37nwhitehorn * margin.
124883cbb37nwhitehorn */
124983cbb37nwhitehornstatic int
125083cbb37nwhitehornlongest_word(const char *string)
125183cbb37nwhitehorn{
125283cbb37nwhitehorn    int length, result = 0;
125383cbb37nwhitehorn
125483cbb37nwhitehorn    while (*string != '\0') {
125583cbb37nwhitehorn	length = 0;
125683cbb37nwhitehorn	while (*string != '\0' && !isspace(UCH(*string))) {
125783cbb37nwhitehorn	    length++;
125883cbb37nwhitehorn	    string++;
125983cbb37nwhitehorn	}
126083cbb37nwhitehorn	result = MAX(result, length);
126183cbb37nwhitehorn	if (*string != '\0')
126283cbb37nwhitehorn	    string++;
126383cbb37nwhitehorn    }
126483cbb37nwhitehorn    return result;
126583cbb37nwhitehorn}
126683cbb37nwhitehorn
126783cbb37nwhitehorn/*
126883cbb37nwhitehorn * if (height or width == -1) Maximize()
126983cbb37nwhitehorn * if (height or width == 0), justify and return actual limits.
127083cbb37nwhitehorn */
127183cbb37nwhitehornstatic void
127283cbb37nwhitehornreal_auto_size(const char *title,
127383cbb37nwhitehorn	       const char *prompt,
127483cbb37nwhitehorn	       int *height, int *width,
127583cbb37nwhitehorn	       int boxlines, int mincols)
127683cbb37nwhitehorn{
127783cbb37nwhitehorn    int x = (dialog_vars.begin_set ? dialog_vars.begin_x : 2);
127883cbb37nwhitehorn    int y = (dialog_vars.begin_set ? dialog_vars.begin_y : 1);
127983cbb37nwhitehorn    int title_length = title ? dlg_count_columns(title) : 0;
128083cbb37nwhitehorn    int high;
128183cbb37nwhitehorn    int wide;
128283cbb37nwhitehorn    int save_high = *height;
128383cbb37nwhitehorn    int save_wide = *width;
1284f8604a5bapt    int max_high;
1285f8604a5bapt    int max_wide;
128683cbb37nwhitehorn
128783cbb37nwhitehorn    if (prompt == 0) {
128883cbb37nwhitehorn	if (*height == 0)
128983cbb37nwhitehorn	    *height = -1;
129083cbb37nwhitehorn	if (*width == 0)
129183cbb37nwhitehorn	    *width = -1;
129283cbb37nwhitehorn    }
129383cbb37nwhitehorn
1294f8604a5bapt    max_high = (*height < 0);
1295f8604a5bapt    max_wide = (*width < 0);
1296f8604a5bapt
129783cbb37nwhitehorn    if (*height > 0) {
129883cbb37nwhitehorn	high = *height;
129983cbb37nwhitehorn    } else {
130083cbb37nwhitehorn	high = SLINES - y;
130183cbb37nwhitehorn    }
130283cbb37nwhitehorn
1303a94245bnwhitehorn    if (*width <= 0) {
1304a94245bnwhitehorn	if (prompt != 0) {
1305a94245bnwhitehorn	    wide = MAX(title_length, mincols);
1306a94245bnwhitehorn	    if (strchr(prompt, '\n') == 0) {
1307a94245bnwhitehorn		double val = (dialog_state.aspect_ratio *
1308a94245bnwhitehorn			      dlg_count_real_columns(prompt));
1309a94245bnwhitehorn		double xxx = sqrt(val);
1310a94245bnwhitehorn		int tmp = (int) xxx;
1311a94245bnwhitehorn		wide = MAX(wide, tmp);
1312a94245bnwhitehorn		wide = MAX(wide, longest_word(prompt));
1313a94245bnwhitehorn		justify_text((WINDOW *) 0, prompt, high, wide, height, width);
1314a94245bnwhitehorn	    } else {
1315a94245bnwhitehorn		auto_size_preformatted(prompt, height, width);
1316a94245bnwhitehorn	    }
131783cbb37nwhitehorn	} else {
1318a94245bnwhitehorn	    wide = SCOLS - x;
1319a94245bnwhitehorn	    justify_text((WINDOW *) 0, prompt, high, wide, height, width);
132083cbb37nwhitehorn	}
132183cbb37nwhitehorn    }
132283cbb37nwhitehorn
132383cbb37nwhitehorn    if (*width < title_length) {
132483cbb37nwhitehorn	justify_text((WINDOW *) 0, prompt, high, title_length, height, width);
132583cbb37nwhitehorn	*width = title_length;
132683cbb37nwhitehorn    }
132783cbb37nwhitehorn
1328f8604a5bapt    dialog_state.text_height = *height;
1329f8604a5bapt    dialog_state.text_width = *width;
1330f8604a5bapt
133183cbb37nwhitehorn    if (*width < mincols && save_wide == 0)
133283cbb37nwhitehorn	*width = mincols;
133383cbb37nwhitehorn    if (prompt != 0) {
1334f8604a5bapt	*width += ((2 * MARGIN) + SHADOW_COLS);
1335f8604a5bapt	*height += boxlines + (2 * MARGIN);
133683cbb37nwhitehorn    }
1337f8604a5bapt
133883cbb37nwhitehorn    if (save_high > 0)
133983cbb37nwhitehorn	*height = save_high;
134083cbb37nwhitehorn    if (save_wide > 0)
134183cbb37nwhitehorn	*width = save_wide;
1342f8604a5bapt
1343f8604a5bapt    if (max_high)
1344f8604a5bapt	*height = SLINES - (dialog_vars.begin_set ? dialog_vars.begin_y : 0);
1345f8604a5bapt    if (max_wide)
1346f8604a5bapt	*width = SCOLS - (dialog_vars.begin_set ? dialog_vars.begin_x : 0);
134783cbb37nwhitehorn}
134883cbb37nwhitehorn
134983cbb37nwhitehorn/* End of real_auto_size() */
135083cbb37nwhitehorn
135183cbb37nwhitehornvoid
135283cbb37nwhitehorndlg_auto_size(const char *title,
135383cbb37nwhitehorn	      const char *prompt,
135483cbb37nwhitehorn	      int *height,
135583cbb37nwhitehorn	      int *width,
135683cbb37nwhitehorn	      int boxlines,
135783cbb37nwhitehorn	      int mincols)
135883cbb37nwhitehorn{
1359f8604a5bapt    DLG_TRACE(("# dlg_auto_size(%d,%d) limits %d,%d\n",
1360f8604a5bapt	       *height, *width,
1361f8604a5bapt	       boxlines, mincols));
1362f8604a5bapt
136383cbb37nwhitehorn    real_auto_size(title, prompt, height, width, boxlines, mincols);
136483cbb37nwhitehorn
136583cbb37nwhitehorn    if (*width > SCOLS) {
136683cbb37nwhitehorn	(*height)++;
136783cbb37nwhitehorn	*width = SCOLS;
136883cbb37nwhitehorn    }
136983cbb37nwhitehorn
1370f8604a5bapt    if (*height > SLINES) {
137183cbb37nwhitehorn	*height = SLINES;
1372f8604a5bapt    }
1373f8604a5bapt    DLG_TRACE(("# ...dlg_auto_size(%d,%d) also %d,%d\n",
1374f8604a5bapt	       *height, *width,
1375f8604a5bapt	       dialog_state.text_height, dialog_state.text_width));
137683cbb37nwhitehorn}
137783cbb37nwhitehorn
137883cbb37nwhitehorn/*
137983cbb37nwhitehorn * if (height or width == -1) Maximize()
138083cbb37nwhitehorn * if (height or width == 0)
138183cbb37nwhitehorn *    height=MIN(SLINES, num.lines in fd+n);
138283cbb37nwhitehorn *    width=MIN(SCOLS, MAX(longer line+n, mincols));
138383cbb37nwhitehorn */
138483cbb37nwhitehornvoid
138583cbb37nwhitehorndlg_auto_sizefile(const char *title,
138683cbb37nwhitehorn		  const char *file,
138783cbb37nwhitehorn		  int *height,
138883cbb37nwhitehorn		  int *width,
138983cbb37nwhitehorn		  int boxlines,
139083cbb37nwhitehorn		  int mincols)
139183cbb37nwhitehorn{
139283cbb37nwhitehorn    int count = 0;
139383cbb37nwhitehorn    int len = title ? dlg_count_columns(title) : 0;
139483cbb37nwhitehorn    int nc = 4;
139583cbb37nwhitehorn    int numlines = 2;
139683cbb37nwhitehorn    long offset;
139783cbb37nwhitehorn    int ch;
139883cbb37nwhitehorn    FILE *fd;
139983cbb37nwhitehorn
140083cbb37nwhitehorn    /* Open input file for reading */
140183cbb37nwhitehorn    if ((fd = fopen(file, "rb")) == NULL)
140283cbb37nwhitehorn	dlg_exiterr("dlg_auto_sizefile: Cannot open input file %s", file);
140383cbb37nwhitehorn
140483cbb37nwhitehorn    if ((*height == -1) || (*width == -1)) {
140583cbb37nwhitehorn	*height = SLINES - (dialog_vars.begin_set ? dialog_vars.begin_y : 0);
140683cbb37nwhitehorn	*width = SCOLS - (dialog_vars.begin_set ? dialog_vars.begin_x : 0);
140783cbb37nwhitehorn    }
140883cbb37nwhitehorn    if ((*height != 0) && (*width != 0)) {
140983cbb37nwhitehorn	(void) fclose(fd);
141083cbb37nwhitehorn	if (*width > SCOLS)
141183cbb37nwhitehorn	    *width = SCOLS;
141283cbb37nwhitehorn	if (*height > SLINES)
141383cbb37nwhitehorn	    *height = SLINES;
141483cbb37nwhitehorn	return;
141583cbb37nwhitehorn    }
141683cbb37nwhitehorn
141783cbb37nwhitehorn    while (!feof(fd)) {
1418f8604a5bapt	if (ferror(fd))
1419f8604a5bapt	    break;
142083cbb37nwhitehorn	offset = 0;
1421f8604a5bapt	while (((ch = getc(fd)) != '\n') && !feof(fd)) {
1422f8604a5bapt	    if ((ch == TAB) && (dialog_vars.tab_correct)) {
142383cbb37nwhitehorn		offset += dialog_state.tab_len - (offset % dialog_state.tab_len);
1424f8604a5bapt	    } else {
142583cbb37nwhitehorn		offset++;
1426f8604a5bapt	    }
1427f8604a5bapt	}
142883cbb37nwhitehorn
142983cbb37nwhitehorn	if (offset > len)
14309904759nwhitehorn	    len = (int) offset;
143183cbb37nwhitehorn
143283cbb37nwhitehorn	count++;
143383cbb37nwhitehorn    }
143483cbb37nwhitehorn
14359904759nwhitehorn    /* now 'count' has the number of lines of fd and 'len' the max length */
143683cbb37nwhitehorn
143783cbb37nwhitehorn    *height = MIN(SLINES, count + numlines + boxlines);
143883cbb37nwhitehorn    *width = MIN(SCOLS, MAX((len + nc), mincols));
143983cbb37nwhitehorn    /* here width and height can be maximized if > SCOLS|SLINES because
144083cbb37nwhitehorn       textbox-like widgets don't put all <file> on the screen.
144183cbb37nwhitehorn       Msgbox-like widget instead have to put all <text> correctly. */
144283cbb37nwhitehorn
144383cbb37nwhitehorn    (void) fclose(fd);
144483cbb37nwhitehorn}
144583cbb37nwhitehorn
144683cbb37nwhitehorn/*
144783cbb37nwhitehorn * Draw a rectangular box with line drawing characters.
144883cbb37nwhitehorn *
144983cbb37nwhitehorn * borderchar is used to color the upper/left edges.
145083cbb37nwhitehorn *
145183cbb37nwhitehorn * boxchar is used to color the right/lower edges.  It also is fill-color used
145283cbb37nwhitehorn * for the box contents.
145383cbb37nwhitehorn *
145483cbb37nwhitehorn * Normally, if you are drawing a scrollable box, use menubox_border_attr for
145583cbb37nwhitehorn * boxchar, and menubox_attr for borderchar since the scroll-arrows are drawn
145683cbb37nwhitehorn * with menubox_attr at the top, and menubox_border_attr at the bottom.  That
145783cbb37nwhitehorn * also (given the default color choices) produces a recessed effect.
145883cbb37nwhitehorn *
145983cbb37nwhitehorn * If you want a raised effect (and are not going to use the scroll-arrows),
146083cbb37nwhitehorn * reverse this choice.
146183cbb37nwhitehorn */
146283cbb37nwhitehornvoid
1463a94245bnwhitehorndlg_draw_box2(WINDOW *win, int y, int x, int height, int width,
1464a94245bnwhitehorn	      chtype boxchar, chtype borderchar, chtype borderchar2)
146583cbb37nwhitehorn{
146683cbb37nwhitehorn    int i, j;
14679904759nwhitehorn    chtype save = dlg_get_attrs(win);
146883cbb37nwhitehorn
1469f8604a5bapt    dlg_attrset(win, 0);
147083cbb37nwhitehorn    for (i = 0; i < height; i++) {
147183cbb37nwhitehorn	(void) wmove(win, y + i, x);
147283cbb37nwhitehorn	for (j = 0; j < width; j++)
147383cbb37nwhitehorn	    if (!i && !j)
147483cbb37nwhitehorn		(void) waddch(win, borderchar | dlg_boxchar(ACS_ULCORNER));
147583cbb37nwhitehorn	    else if (i == height - 1 && !j)
147683cbb37nwhitehorn		(void) waddch(win, borderchar | dlg_boxchar(ACS_LLCORNER));
147783cbb37nwhitehorn	    else if (!i && j == width - 1)
1478a94245bnwhitehorn		(void) waddch(win, borderchar2 | dlg_boxchar(ACS_URCORNER));
147983cbb37nwhitehorn	    else if (i == height - 1 && j == width - 1)
1480a94245bnwhitehorn		(void) waddch(win, borderchar2 | dlg_boxchar(ACS_LRCORNER));
148183cbb37nwhitehorn	    else if (!i)
148283cbb37nwhitehorn		(void) waddch(win, borderchar | dlg_boxchar(ACS_HLINE));
148383cbb37nwhitehorn	    else if (i == height - 1)
1484a94245bnwhitehorn		(void) waddch(win, borderchar2 | dlg_boxchar(ACS_HLINE));
148583cbb37nwhitehorn	    else if (!j)
148683cbb37nwhitehorn		(void) waddch(win, borderchar | dlg_boxchar(ACS_VLINE));
148783cbb37nwhitehorn	    else if (j == width - 1)
1488a94245bnwhitehorn		(void) waddch(win, borderchar2 | dlg_boxchar(ACS_VLINE));
148983cbb37nwhitehorn	    else
149083cbb37nwhitehorn		(void) waddch(win, boxchar | ' ');
149183cbb37nwhitehorn    }
1492f8604a5bapt    dlg_attrset(win, save);
149383cbb37nwhitehorn}
149483cbb37nwhitehorn
1495a94245bnwhitehornvoid
1496a94245bnwhitehorndlg_draw_box(WINDOW *win, int y, int x, int height, int width,
1497a94245bnwhitehorn	     chtype boxchar, chtype borderchar)
1498a94245bnwhitehorn{
1499a94245bnwhitehorn    dlg_draw_box2(win, y, x, height, width, boxchar, borderchar, boxchar);
1500a94245bnwhitehorn}
1501a94245bnwhitehorn
150294f19e0nwhitehornstatic DIALOG_WINDOWS *
150394f19e0nwhitehornfind_window(WINDOW *win)
150494f19e0nwhitehorn{
150594f19e0nwhitehorn    DIALOG_WINDOWS *result = 0;
150694f19e0nwhitehorn    DIALOG_WINDOWS *p;
150794f19e0nwhitehorn
150894f19e0nwhitehorn    for (p = dialog_state.all_windows; p != 0; p = p->next) {
150994f19e0nwhitehorn	if (p->normal == win) {
151094f19e0nwhitehorn	    result = p;
151194f19e0nwhitehorn	    break;
151294f19e0nwhitehorn	}
151394f19e0nwhitehorn    }
151494f19e0nwhitehorn    return result;
151594f19e0nwhitehorn}
151694f19e0nwhitehorn
151783cbb37nwhitehorn#ifdef HAVE_COLOR
151883cbb37nwhitehorn/*
151994f19e0nwhitehorn * If we have wchgat(), use that for updating shadow attributes, to work with
152094f19e0nwhitehorn * wide-character data.
152183cbb37nwhitehorn */
152294f19e0nwhitehorn
152394f19e0nwhitehorn/*
152494f19e0nwhitehorn * Check if the given point is "in" the given window.  If so, return the window
152594f19e0nwhitehorn * pointer, otherwise null.
152694f19e0nwhitehorn */
152794f19e0nwhitehornstatic WINDOW *
152894f19e0nwhitehornin_window(WINDOW *win, int y, int x)
152983cbb37nwhitehorn{
153094f19e0nwhitehorn    WINDOW *result = 0;
153194f19e0nwhitehorn    int y_base = getbegy(win);
153294f19e0nwhitehorn    int x_base = getbegx(win);
153394f19e0nwhitehorn    int y_last = getmaxy(win) + y_base;
153494f19e0nwhitehorn    int x_last = getmaxx(win) + x_base;
153594f19e0nwhitehorn
153694f19e0nwhitehorn    if (y >= y_base && y <= y_last && x >= x_base && x <= x_last)
153794f19e0nwhitehorn	result = win;
153894f19e0nwhitehorn    return result;
153994f19e0nwhitehorn}
154083cbb37nwhitehorn
154194f19e0nwhitehornstatic WINDOW *
154294f19e0nwhitehornwindow_at_cell(DIALOG_WINDOWS * dw, int y, int x)
154394f19e0nwhitehorn{
154494f19e0nwhitehorn    WINDOW *result = 0;
154594f19e0nwhitehorn    DIALOG_WINDOWS *p;
154694f19e0nwhitehorn    int y_want = y + getbegy(dw->shadow);
154794f19e0nwhitehorn    int x_want = x + getbegx(dw->shadow);
154894f19e0nwhitehorn
154994f19e0nwhitehorn    for (p = dialog_state.all_windows; p != 0; p = p->next) {
155094f19e0nwhitehorn	if (dw->normal != p->normal
155194f19e0nwhitehorn	    && dw->shadow != p->normal
155294f19e0nwhitehorn	    && (result = in_window(p->normal, y_want, x_want)) != 0) {
155394f19e0nwhitehorn	    break;
155494f19e0nwhitehorn	}
155583cbb37nwhitehorn    }
155694f19e0nwhitehorn    if (result == 0) {
155794f19e0nwhitehorn	result = stdscr;
155894f19e0nwhitehorn    }
155994f19e0nwhitehorn    return result;
156094f19e0nwhitehorn}
156194f19e0nwhitehorn
156294f19e0nwhitehornstatic bool
156394f19e0nwhitehornin_shadow(WINDOW *normal, WINDOW *shadow, int y, int x)
156494f19e0nwhitehorn{
156594f19e0nwhitehorn    bool result = FALSE;
156694f19e0nwhitehorn    int ybase = getbegy(normal);
156794f19e0nwhitehorn    int ylast = getmaxy(normal) + ybase;
156894f19e0nwhitehorn    int xbase = getbegx(normal);
156994f19e0nwhitehorn    int xlast = getmaxx(normal) + xbase;
157094f19e0nwhitehorn
157194f19e0nwhitehorn    y += getbegy(shadow);
157294f19e0nwhitehorn    x += getbegx(shadow);
157394f19e0nwhitehorn
157494f19e0nwhitehorn    if (y >= ybase + SHADOW_ROWS
157594f19e0nwhitehorn	&& y < ylast + SHADOW_ROWS
157694f19e0nwhitehorn	&& x >= xlast
157794f19e0nwhitehorn	&& x < xlast + SHADOW_COLS) {
157894f19e0nwhitehorn	/* in the right-side */
157994f19e0nwhitehorn	result = TRUE;
158094f19e0nwhitehorn    } else if (y >= ylast
158194f19e0nwhitehorn	       && y < ylast + SHADOW_ROWS
158294f19e0nwhitehorn	       && x >= ybase + SHADOW_COLS
158394f19e0nwhitehorn	       && x < ylast + SHADOW_COLS) {
158494f19e0nwhitehorn	/* check the bottom */
158594f19e0nwhitehorn	result = TRUE;
158694f19e0nwhitehorn    }
158794f19e0nwhitehorn
158894f19e0nwhitehorn    return result;
158983cbb37nwhitehorn}
159083cbb37nwhitehorn
159183cbb37nwhitehorn/*
159294f19e0nwhitehorn * When erasing a shadow, check each cell to make sure that it is not part of
159394f19e0nwhitehorn * another box's shadow.  This is a little complicated since most shadows are
159494f19e0nwhitehorn * merged onto stdscr.
159583cbb37nwhitehorn */
159694f19e0nwhitehornstatic bool
159794f19e0nwhitehornlast_shadow(DIALOG_WINDOWS * dw, int y, int x)
159894f19e0nwhitehorn{
159994f19e0nwhitehorn    DIALOG_WINDOWS *p;
160094f19e0nwhitehorn    bool result = TRUE;
160194f19e0nwhitehorn
160294f19e0nwhitehorn    for (p = dialog_state.all_windows; p != 0; p = p->next) {
160394f19e0nwhitehorn	if (p->normal != dw->normal
160494f19e0nwhitehorn	    && in_shadow(p->normal, dw->shadow, y, x)) {
160594f19e0nwhitehorn	    result = FALSE;
160694f19e0nwhitehorn	    break;
160794f19e0nwhitehorn	}
160894f19e0nwhitehorn    }
160994f19e0nwhitehorn    return result;
161094f19e0nwhitehorn}
161194f19e0nwhitehorn
161294f19e0nwhitehornstatic void
161394f19e0nwhitehornrepaint_cell(DIALOG_WINDOWS * dw, bool draw, int y, int x)
161494f19e0nwhitehorn{
161594f19e0nwhitehorn    WINDOW *win = dw->shadow;
161694f19e0nwhitehorn    WINDOW *cellwin;
161794f19e0nwhitehorn    int y2, x2;
161894f19e0nwhitehorn
161994f19e0nwhitehorn    if ((cellwin = window_at_cell(dw, y, x)) != 0
162094f19e0nwhitehorn	&& (draw || last_shadow(dw, y, x))
162194f19e0nwhitehorn	&& (y2 = (y + getbegy(win) - getbegy(cellwin))) >= 0
162294f19e0nwhitehorn	&& (x2 = (x + getbegx(win) - getbegx(cellwin))) >= 0
162394f19e0nwhitehorn	&& wmove(cellwin, y2, x2) != ERR) {
162494f19e0nwhitehorn	chtype the_cell = dlg_get_attrs(cellwin);
162594f19e0nwhitehorn	chtype the_attr = (draw ? shadow_attr : the_cell);
162694f19e0nwhitehorn
1627f8604a5bapt	if (winch(cellwin) & A_ALTCHARSET) {
162894f19e0nwhitehorn	    the_attr |= A_ALTCHARSET;
162994f19e0nwhitehorn	}
163094f19e0nwhitehorn#if USE_WCHGAT
163194f19e0nwhitehorn	wchgat(cellwin, 1,
163294f19e0nwhitehorn	       the_attr & (chtype) (~A_COLOR),
1633a94245bnwhitehorn	       (short) PAIR_NUMBER(the_attr),
163494f19e0nwhitehorn	       NULL);
163594f19e0nwhitehorn#else
163694f19e0nwhitehorn	{
163794f19e0nwhitehorn	    chtype the_char = ((winch(cellwin) & A_CHARTEXT) | the_attr);
163894f19e0nwhitehorn	    (void) waddch(cellwin, the_char);
163994f19e0nwhitehorn	}
164094f19e0nwhitehorn#endif
164194f19e0nwhitehorn	wnoutrefresh(cellwin);
164294f19e0nwhitehorn    }
164394f19e0nwhitehorn}
164494f19e0nwhitehorn
164594f19e0nwhitehorn#define RepaintCell(dw, draw, y, x) repaint_cell(dw, draw, y, x)
164694f19e0nwhitehorn
164794f19e0nwhitehornstatic void
164894f19e0nwhitehornrepaint_shadow(DIALOG_WINDOWS * dw, bool draw, int y, int x, int height, int width)
164983cbb37nwhitehorn{
165083cbb37nwhitehorn    int i, j;
165183cbb37nwhitehorn
165294f19e0nwhitehorn    if (UseShadow(dw)) {
165394f19e0nwhitehorn#if !USE_WCHGAT
165494f19e0nwhitehorn	chtype save = dlg_get_attrs(dw->shadow);
1655f8604a5bapt	dlg_attrset(dw->shadow, draw ? shadow_attr : screen_attr);
165694f19e0nwhitehorn#endif
165783cbb37nwhitehorn	for (i = 0; i < SHADOW_ROWS; ++i) {
165883cbb37nwhitehorn	    for (j = 0; j < width; ++j) {
165994f19e0nwhitehorn		RepaintCell(dw, draw, i + y + height, j + x + SHADOW_COLS);
166083cbb37nwhitehorn	    }
166183cbb37nwhitehorn	}
166283cbb37nwhitehorn	for (i = 0; i < height; i++) {
166383cbb37nwhitehorn	    for (j = 0; j < SHADOW_COLS; ++j) {
166494f19e0nwhitehorn		RepaintCell(dw, draw, i + y + SHADOW_ROWS, j + x + width);
166583cbb37nwhitehorn	    }
166683cbb37nwhitehorn	}
166794f19e0nwhitehorn	(void) wnoutrefresh(dw->shadow);
166894f19e0nwhitehorn#if !USE_WCHGAT
1669f8604a5bapt	dlg_attrset(dw->shadow, save);
167094f19e0nwhitehorn#endif
167194f19e0nwhitehorn    }
167294f19e0nwhitehorn}
167394f19e0nwhitehorn
167494f19e0nwhitehorn/*
167594f19e0nwhitehorn * Draw a shadow on the parent window corresponding to the right- and
167694f19e0nwhitehorn * bottom-edge of the child window, to give a 3-dimensional look.
167794f19e0nwhitehorn */
167894f19e0nwhitehornstatic void
167994f19e0nwhitehorndraw_childs_shadow(DIALOG_WINDOWS * dw)
168094f19e0nwhitehorn{
168194f19e0nwhitehorn    if (UseShadow(dw)) {
168294f19e0nwhitehorn	repaint_shadow(dw,
168394f19e0nwhitehorn		       TRUE,
168494f19e0nwhitehorn		       getbegy(dw->normal) - getbegy(dw->shadow),
168594f19e0nwhitehorn		       getbegx(dw->normal) - getbegx(dw->shadow),
168694f19e0nwhitehorn		       getmaxy(dw->normal),
168794f19e0nwhitehorn		       getmaxx(dw->normal));
168883cbb37nwhitehorn    }
168983cbb37nwhitehorn}
169094f19e0nwhitehorn
169194f19e0nwhitehorn/*
169294f19e0nwhitehorn * Erase a shadow on the parent window corresponding to the right- and
169394f19e0nwhitehorn * bottom-edge of the child window.
169494f19e0nwhitehorn */
169594f19e0nwhitehornstatic void
169694f19e0nwhitehornerase_childs_shadow(DIALOG_WINDOWS * dw)
169794f19e0nwhitehorn{
169894f19e0nwhitehorn    if (UseShadow(dw)) {
169994f19e0nwhitehorn	repaint_shadow(dw,
170094f19e0nwhitehorn		       FALSE,
170194f19e0nwhitehorn		       getbegy(dw->normal) - getbegy(dw->shadow),
170294f19e0nwhitehorn		       getbegx(dw->normal) - getbegx(dw->shadow),
170394f19e0nwhitehorn		       getmaxy(dw->normal),
170494f19e0nwhitehorn		       getmaxx(dw->normal));
170594f19e0nwhitehorn    }
170694f19e0nwhitehorn}
170794f19e0nwhitehorn
170894f19e0nwhitehorn/*
170994f19e0nwhitehorn * Draw shadows along the right and bottom edge to give a more 3D look
171094f19e0nwhitehorn * to the boxes.
171194f19e0nwhitehorn */
171294f19e0nwhitehornvoid
171394f19e0nwhitehorndlg_draw_shadow(WINDOW *win, int y, int x, int height, int width)
171494f19e0nwhitehorn{
171594f19e0nwhitehorn    repaint_shadow(find_window(win), TRUE, y, x, height, width);
171694f19e0nwhitehorn}
171783cbb37nwhitehorn#endif /* HAVE_COLOR */
171883cbb37nwhitehorn
171983cbb37nwhitehorn/*
172083cbb37nwhitehorn * Allow shell scripts to remap the exit codes so they can distinguish ESC
172183cbb37nwhitehorn * from ERROR.
172283cbb37nwhitehorn */
172383cbb37nwhitehornvoid
172483cbb37nwhitehorndlg_exit(int code)
172583cbb37nwhitehorn{
172683cbb37nwhitehorn    /* *INDENT-OFF* */
172783cbb37nwhitehorn    static const struct {
172883cbb37nwhitehorn	int code;
172983cbb37nwhitehorn	const char *name;
173083cbb37nwhitehorn    } table[] = {
173183cbb37nwhitehorn	{ DLG_EXIT_CANCEL, 	"DIALOG_CANCEL" },
173283cbb37nwhitehorn	{ DLG_EXIT_ERROR,  	"DIALOG_ERROR" },
173383cbb37nwhitehorn	{ DLG_EXIT_ESC,	   	"DIALOG_ESC" },
173483cbb37nwhitehorn	{ DLG_EXIT_EXTRA,  	"DIALOG_EXTRA" },
173583cbb37nwhitehorn	{ DLG_EXIT_HELP,   	"DIALOG_HELP" },
173683cbb37nwhitehorn	{ DLG_EXIT_OK,	   	"DIALOG_OK" },
173783cbb37nwhitehorn	{ DLG_EXIT_ITEM_HELP,	"DIALOG_ITEM_HELP" },
173883cbb37nwhitehorn    };
173983cbb37nwhitehorn    /* *INDENT-ON* */
174083cbb37nwhitehorn
174183cbb37nwhitehorn    unsigned n;
174283cbb37nwhitehorn    char *name;
174383cbb37nwhitehorn    char *temp;
174483cbb37nwhitehorn    long value;
174583cbb37nwhitehorn    bool overridden = FALSE;
174683cbb37nwhitehorn
174783cbb37nwhitehorn  retry:
174883cbb37nwhitehorn    for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) {
174983cbb37nwhitehorn	if (table[n].code == code) {
175083cbb37nwhitehorn	    if ((name = getenv(table[n].name)) != 0) {
175183cbb37nwhitehorn		value = strtol(name, &temp, 0);
175283cbb37nwhitehorn		if (temp != 0 && temp != name && *temp == '\0') {
17539904759nwhitehorn		    code = (int) value;
175483cbb37nwhitehorn		    overridden = TRUE;
175583cbb37nwhitehorn		}
175683cbb37nwhitehorn	    }
175783cbb37nwhitehorn	    break;
175883cbb37nwhitehorn	}
175983cbb37nwhitehorn    }
176083cbb37nwhitehorn
176183cbb37nwhitehorn    /*
176283cbb37nwhitehorn     * Prior to 2004/12/19, a widget using --item-help would exit with "OK"
176383cbb37nwhitehorn     * if the help button were selected.  Now we want to exit with "HELP",
176483cbb37nwhitehorn     * but allow the environment variable to override.
176583cbb37nwhitehorn     */
176683cbb37nwhitehorn    if (code == DLG_EXIT_ITEM_HELP && !overridden) {
176783cbb37nwhitehorn	code = DLG_EXIT_HELP;
176883cbb37nwhitehorn	goto retry;
176983cbb37nwhitehorn    }
177094f19e0nwhitehorn#ifdef HAVE_DLG_TRACE
177194f19e0nwhitehorn    dlg_trace((const char *) 0);	/* close it */
177294f19e0nwhitehorn#endif
177394f19e0nwhitehorn
177483cbb37nwhitehorn#ifdef NO_LEAKS
177583cbb37nwhitehorn    _dlg_inputstr_leaks();
177683cbb37nwhitehorn#if defined(NCURSES_VERSION) && defined(HAVE__NC_FREE_AND_EXIT)
177783cbb37nwhitehorn    _nc_free_and_exit(code);
177883cbb37nwhitehorn#endif
177983cbb37nwhitehorn#endif
178083cbb37nwhitehorn
178183cbb37nwhitehorn    if (dialog_state.input == stdin) {
178283cbb37nwhitehorn	exit(code);
178383cbb37nwhitehorn    } else {
178483cbb37nwhitehorn	/*
178583cbb37nwhitehorn	 * Just in case of using --input-fd option, do not
178683cbb37nwhitehorn	 * call atexit functions of ncurses which may hang.
178783cbb37nwhitehorn	 */
178883cbb37nwhitehorn	if (dialog_state.input) {
178983cbb37nwhitehorn	    fclose(dialog_state.input);
179083cbb37nwhitehorn	    dialog_state.input = 0;
179183cbb37nwhitehorn	}
179283cbb37nwhitehorn	if (dialog_state.pipe_input) {
179383cbb37nwhitehorn	    if (dialog_state.pipe_input != stdin) {
179483cbb37nwhitehorn		fclose(dialog_state.pipe_input);
179583cbb37nwhitehorn		dialog_state.pipe_input = 0;
179683cbb37nwhitehorn	    }
179783cbb37nwhitehorn	}
179883cbb37nwhitehorn	_exit(code);
179983cbb37nwhitehorn    }
180083cbb37nwhitehorn}
180183cbb37nwhitehorn
180283cbb37nwhitehorn/* quit program killing all tailbg */
180383cbb37nwhitehornvoid
180483cbb37nwhitehorndlg_exiterr(const char *fmt,...)
180583cbb37nwhitehorn{
180683cbb37nwhitehorn    int retval;
180783cbb37nwhitehorn    va_list ap;
180883cbb37nwhitehorn
180983cbb37nwhitehorn    end_dialog();
181083cbb37nwhitehorn
181183cbb37nwhitehorn    (void) fputc('\n', stderr);
181283cbb37nwhitehorn    va_start(ap, fmt);
181383cbb37nwhitehorn    (void) vfprintf(stderr, fmt, ap);
181483cbb37nwhitehorn    va_end(ap);
181583cbb37nwhitehorn    (void) fputc('\n', stderr);
181683cbb37nwhitehorn
181783cbb37nwhitehorn    dlg_killall_bg(&retval);
181883cbb37nwhitehorn
181983cbb37nwhitehorn    (void) fflush(stderr);
182083cbb37nwhitehorn    (void) fflush(stdout);
182183cbb37nwhitehorn    dlg_exit(DLG_EXIT_ERROR);
182283cbb37nwhitehorn}
182383cbb37nwhitehorn
182483cbb37nwhitehornvoid
182583cbb37nwhitehorndlg_beeping(void)
182683cbb37nwhitehorn{
182783cbb37nwhitehorn    if (dialog_vars.beep_signal) {
182883cbb37nwhitehorn	(void) beep();
182983cbb37nwhitehorn	dialog_vars.beep_signal = 0;
183083cbb37nwhitehorn    }
183183cbb37nwhitehorn}
183283cbb37nwhitehorn
183383cbb37nwhitehornvoid
183483cbb37nwhitehorndlg_print_size(int height, int width)
183583cbb37nwhitehorn{
1836f8604a5bapt    if (dialog_vars.print_siz) {
183783cbb37nwhitehorn	fprintf(dialog_state.output, "Size: %d, %d\n", height, width);
1838f8604a5bapt	DLG_TRACE(("# print size: %dx%d\n", height, width));
1839f8604a5bapt    }
184083cbb37nwhitehorn}
184183cbb37nwhitehorn
184283cbb37nwhitehornvoid
184383cbb37nwhitehorndlg_ctl_size(int height, int width)
184483cbb37nwhitehorn{
184583cbb37nwhitehorn    if (dialog_vars.size_err) {
184683cbb37nwhitehorn	if ((width > COLS) || (height > LINES)) {
184783cbb37nwhitehorn	    dlg_exiterr("Window too big. (height, width) = (%d, %d). Max allowed (%d, %d).",
184883cbb37nwhitehorn			height, width, LINES, COLS);
184983cbb37nwhitehorn	}
185083cbb37nwhitehorn#ifdef HAVE_COLOR
185183cbb37nwhitehorn	else if ((dialog_state.use_shadow)
185283cbb37nwhitehorn		 && ((width > SCOLS || height > SLINES))) {
185383cbb37nwhitehorn	    if ((width <= COLS) && (height <= LINES)) {
185483cbb37nwhitehorn		/* try again, without shadows */
185583cbb37nwhitehorn		dialog_state.use_shadow = 0;
185683cbb37nwhitehorn	    } else {
185783cbb37nwhitehorn		dlg_exiterr("Window+Shadow too big. (height, width) = (%d, %d). Max allowed (%d, %d).",
185883cbb37nwhitehorn			    height, width, SLINES, SCOLS);
185983cbb37nwhitehorn	    }
186083cbb37nwhitehorn	}
186183cbb37nwhitehorn#endif
186283cbb37nwhitehorn    }
186383cbb37nwhitehorn}
186483cbb37nwhitehorn
186583cbb37nwhitehorn/*
186683cbb37nwhitehorn * If the --tab-correct was not selected, convert tabs to single spaces.
186783cbb37nwhitehorn */
186883cbb37nwhitehornvoid
186983cbb37nwhitehorndlg_tab_correct_str(char *prompt)
187083cbb37nwhitehorn{
187183cbb37nwhitehorn    char *ptr;
187283cbb37nwhitehorn
187383cbb37nwhitehorn    if (dialog_vars.tab_correct) {
187483cbb37nwhitehorn	while ((ptr = strchr(prompt, TAB)) != NULL) {
187583cbb37nwhitehorn	    *ptr = ' ';
187683cbb37nwhitehorn	    prompt = ptr;
187783cbb37nwhitehorn	}
187883cbb37nwhitehorn    }
187983cbb37nwhitehorn}
188083cbb37nwhitehorn
188183cbb37nwhitehornvoid
188283cbb37nwhitehorndlg_calc_listh(int *height, int *list_height, int item_no)
188383cbb37nwhitehorn{
188483cbb37nwhitehorn    /* calculate new height and list_height */
188583cbb37nwhitehorn    int rows = SLINES - (dialog_vars.begin_set ? dialog_vars.begin_y : 0);
188683cbb37nwhitehorn    if (rows - (*height) > 0) {
188783cbb37nwhitehorn	if (rows - (*height) > item_no)
188883cbb37nwhitehorn	    *list_height = item_no;
188983cbb37nwhitehorn	else
189083cbb37nwhitehorn	    *list_height = rows - (*height);
189183cbb37nwhitehorn    }
189283cbb37nwhitehorn    (*height) += (*list_height);
189383cbb37nwhitehorn}
189483cbb37nwhitehorn
189583cbb37nwhitehorn/* obsolete */
189683cbb37nwhitehornint
189783cbb37nwhitehorndlg_calc_listw(int item_no, char **items, int group)
189883cbb37nwhitehorn{
189983cbb37nwhitehorn    int n, i, len1 = 0, len2 = 0;
190083cbb37nwhitehorn    for (i = 0; i < (item_no * group); i += group) {
190183cbb37nwhitehorn	if ((n = dlg_count_columns(items[i])) > len1)
190283cbb37nwhitehorn	    len1 = n;
190383cbb37nwhitehorn	if ((n = dlg_count_columns(items[i + 1])) > len2)
190483cbb37nwhitehorn	    len2 = n;
190583cbb37nwhitehorn    }
190683cbb37nwhitehorn    return len1 + len2;
190783cbb37nwhitehorn}
190883cbb37nwhitehorn
190983cbb37nwhitehornint
191083cbb37nwhitehorndlg_calc_list_width(int item_no, DIALOG_LISTITEM * items)
191183cbb37nwhitehorn{
191283cbb37nwhitehorn    int n, i, len1 = 0, len2 = 0;
19132b5579cbapt    int bits = ((dialog_vars.no_tags ? 1 : 0)
19142b5579cbapt		+ (dialog_vars.no_items ? 2 : 0));
19152b5579cbapt
191683cbb37nwhitehorn    for (i = 0; i < item_no; ++i) {
19172b5579cbapt	switch (bits) {
19182b5579cbapt	case 0:
19192b5579cbapt	    /* FALLTHRU */
19202b5579cbapt	case 1:
19212b5579cbapt	    if ((n = dlg_count_columns(items[i].name)) > len1)
19222b5579cbapt		len1 = n;
19232b5579cbapt	    if ((n = dlg_count_columns(items[i].text)) > len2)
19242b5579cbapt		len2 = n;
19252b5579cbapt	    break;
19262b5579cbapt	case 2:
19272b5579cbapt	    /* FALLTHRU */
19282b5579cbapt	case 3:
19292b5579cbapt	    if ((n = dlg_count_columns(items[i].name)) > len1)
19302b5579cbapt		len1 = n;
19312b5579cbapt	    break;
19322b5579cbapt	}
193383cbb37nwhitehorn    }
193483cbb37nwhitehorn    return len1 + len2;
193583cbb37nwhitehorn}
193683cbb37nwhitehorn
193783cbb37nwhitehornchar *
193883cbb37nwhitehorndlg_strempty(void)
193983cbb37nwhitehorn{
194083cbb37nwhitehorn    static char empty[] = "";
194183cbb37nwhitehorn    return empty;
194283cbb37nwhitehorn}
194383cbb37nwhitehorn
194483cbb37nwhitehornchar *
194583cbb37nwhitehorndlg_strclone(const char *cprompt)
194683cbb37nwhitehorn{
1947f8604a5bapt    char *prompt = 0;
1948f8604a5bapt    if (cprompt != 0) {
1949f8604a5bapt	prompt = dlg_malloc(char, strlen(cprompt) + 1);
1950f8604a5bapt	assert_ptr(prompt, "dlg_strclone");
1951f8604a5bapt	strcpy(prompt, cprompt);
1952f8604a5bapt    }
195383cbb37nwhitehorn    return prompt;
195483cbb37nwhitehorn}
195583cbb37nwhitehorn
195683cbb37nwhitehornchtype
195783cbb37nwhitehorndlg_asciibox(chtype ch)
195883cbb37nwhitehorn{
195983cbb37nwhitehorn    chtype result = 0;
196083cbb37nwhitehorn
196183cbb37nwhitehorn    if (ch == ACS_ULCORNER)
196283cbb37nwhitehorn	result = '+';
196383cbb37nwhitehorn    else if (ch == ACS_LLCORNER)
196483cbb37nwhitehorn	result = '+';
196583cbb37nwhitehorn    else if (ch == ACS_URCORNER)
196683cbb37nwhitehorn	result = '+';
196783cbb37nwhitehorn    else if (ch == ACS_LRCORNER)
196883cbb37nwhitehorn	result = '+';
196983cbb37nwhitehorn    else if (ch == ACS_HLINE)
197083cbb37nwhitehorn	result = '-';
197183cbb37nwhitehorn    else if (ch == ACS_VLINE)
197283cbb37nwhitehorn	result = '|';
197383cbb37nwhitehorn    else if (ch == ACS_LTEE)
197483cbb37nwhitehorn	result = '+';
197583cbb37nwhitehorn    else if (ch == ACS_RTEE)
197683cbb37nwhitehorn	result = '+';
197783cbb37nwhitehorn    else if (ch == ACS_UARROW)
197883cbb37nwhitehorn	result = '^';
197983cbb37nwhitehorn    else if (ch == ACS_DARROW)
198083cbb37nwhitehorn	result = 'v';
198183cbb37nwhitehorn
198283cbb37nwhitehorn    return result;
198383cbb37nwhitehorn}
198483cbb37nwhitehorn
198583cbb37nwhitehornchtype
198683cbb37nwhitehorndlg_boxchar(chtype ch)
198783cbb37nwhitehorn{
198883cbb37nwhitehorn    chtype result = dlg_asciibox(ch);
198983cbb37nwhitehorn
199083cbb37nwhitehorn    if (result != 0) {
199183cbb37nwhitehorn	if (dialog_vars.ascii_lines)
199283cbb37nwhitehorn	    ch = result;
199383cbb37nwhitehorn	else if (dialog_vars.no_lines)
199483cbb37nwhitehorn	    ch = ' ';
199583cbb37nwhitehorn    }
199683cbb37nwhitehorn    return ch;
199783cbb37nwhitehorn}
199883cbb37nwhitehorn
199983cbb37nwhitehornint
200083cbb37nwhitehorndlg_box_x_ordinate(int width)
200183cbb37nwhitehorn{
200283cbb37nwhitehorn    int x;
200383cbb37nwhitehorn
200483cbb37nwhitehorn    if (dialog_vars.begin_set == 1) {
200583cbb37nwhitehorn	x = dialog_vars.begin_x;
200683cbb37nwhitehorn    } else {
200783cbb37nwhitehorn	/* center dialog box on screen unless --begin-set */
200883cbb37nwhitehorn	x = (SCOLS - width) / 2;
200983cbb37nwhitehorn    }
201083cbb37nwhitehorn    return x;
201183cbb37nwhitehorn}
201283cbb37nwhitehorn
201383cbb37nwhitehornint
201483cbb37nwhitehorndlg_box_y_ordinate(int height)
201583cbb37nwhitehorn{
201683cbb37nwhitehorn    int y;
201783cbb37nwhitehorn
201883cbb37nwhitehorn    if (dialog_vars.begin_set == 1) {
201983cbb37nwhitehorn	y = dialog_vars.begin_y;
202083cbb37nwhitehorn    } else {
202183cbb37nwhitehorn	/* center dialog box on screen unless --begin-set */
202283cbb37nwhitehorn	y = (SLINES - height) / 2;
202383cbb37nwhitehorn    }
202483cbb37nwhitehorn    return y;
202583cbb37nwhitehorn}
202683cbb37nwhitehorn
202783cbb37nwhitehornvoid
202883cbb37nwhitehorndlg_draw_title(WINDOW *win, const char *title)
202983cbb37nwhitehorn{
203083cbb37nwhitehorn    if (title != NULL) {
203183cbb37nwhitehorn	chtype attr = A_NORMAL;
20329904759nwhitehorn	chtype save = dlg_get_attrs(win);
203383cbb37nwhitehorn	int x = centered(getmaxx(win), title);
203483cbb37nwhitehorn
2035f8604a5bapt	dlg_attrset(win, title_attr);
203683cbb37nwhitehorn	wmove(win, 0, x);
203783cbb37nwhitehorn	dlg_print_text(win, title, getmaxx(win) - x, &attr);
2038f8604a5bapt	dlg_attrset(win, save);
2039e53d5c4dteske	dlg_finish_string(title);
204083cbb37nwhitehorn    }
204183cbb37nwhitehorn}
204283cbb37nwhitehorn
204383cbb37nwhitehornvoid
2044a94245bnwhitehorndlg_draw_bottom_box2(WINDOW *win, chtype on_left, chtype on_right, chtype on_inside)
204583cbb37nwhitehorn{
204683cbb37nwhitehorn    int width = getmaxx(win);
204783cbb37nwhitehorn    int height = getmaxy(win);
204883cbb37nwhitehorn    int i;
204983cbb37nwhitehorn
2050f8604a5bapt    dlg_attrset(win, on_left);
205183cbb37nwhitehorn    (void) wmove(win, height - 3, 0);
205283cbb37nwhitehorn    (void) waddch(win, dlg_boxchar(ACS_LTEE));
205383cbb37nwhitehorn    for (i = 0; i < width - 2; i++)
205483cbb37nwhitehorn	(void) waddch(win, dlg_boxchar(ACS_HLINE));
2055f8604a5bapt    dlg_attrset(win, on_right);
205683cbb37nwhitehorn    (void) waddch(win, dlg_boxchar(ACS_RTEE));
2057f8604a5bapt    dlg_attrset(win, on_inside);
205883cbb37nwhitehorn    (void) wmove(win, height - 2, 1);
205983cbb37nwhitehorn    for (i = 0; i < width - 2; i++)
206083cbb37nwhitehorn	(void) waddch(win, ' ');
206183cbb37nwhitehorn}
206283cbb37nwhitehorn
2063a94245bnwhitehornvoid
2064a94245bnwhitehorndlg_draw_bottom_box(WINDOW *win)
2065a94245bnwhitehorn{
2066a94245bnwhitehorn    dlg_draw_bottom_box2(win, border_attr, dialog_attr, dialog_attr);
2067a94245bnwhitehorn}
2068a94245bnwhitehorn
206983cbb37nwhitehorn/*
207083cbb37nwhitehorn * Remove a window, repainting everything else.  This would be simpler if we
207183cbb37nwhitehorn * used the panel library, but that is not _always_ available.
207283cbb37nwhitehorn */
207383cbb37nwhitehornvoid
207483cbb37nwhitehorndlg_del_window(WINDOW *win)
207583cbb37nwhitehorn{
207683cbb37nwhitehorn    DIALOG_WINDOWS *p, *q, *r;
207783cbb37nwhitehorn
207883cbb37nwhitehorn    /*
207983cbb37nwhitehorn     * If --keep-window was set, do not delete/repaint the windows.
208083cbb37nwhitehorn     */
208183cbb37nwhitehorn    if (dialog_vars.keep_window)
208283cbb37nwhitehorn	return;
208383cbb37nwhitehorn
208483cbb37nwhitehorn    /* Leave the main window untouched if there are no background windows.
208583cbb37nwhitehorn     * We do this so the current window will not be cleared on exit, allowing
208683cbb37nwhitehorn     * things like the infobox demo to run without flicker.
208783cbb37nwhitehorn     */
208883cbb37nwhitehorn    if (dialog_state.getc_callbacks != 0) {
208983cbb37nwhitehorn	touchwin(stdscr);
209083cbb37nwhitehorn	wnoutrefresh(stdscr);
209183cbb37nwhitehorn    }
209283cbb37nwhitehorn
209383cbb37nwhitehorn    for (p = dialog_state.all_windows, q = r = 0; p != 0; r = p, p = p->next) {
209483cbb37nwhitehorn	if (p->normal == win) {
209583cbb37nwhitehorn	    q = p;		/* found a match - should be only one */
209683cbb37nwhitehorn	    if (r == 0) {
209783cbb37nwhitehorn		dialog_state.all_windows = p->next;
209883cbb37nwhitehorn	    } else {
209983cbb37nwhitehorn		r->next = p->next;
210083cbb37nwhitehorn	    }
210183cbb37nwhitehorn	} else {
210283cbb37nwhitehorn	    if (p->shadow != 0) {
210383cbb37nwhitehorn		touchwin(p->shadow);
210483cbb37nwhitehorn		wnoutrefresh(p->shadow);
210583cbb37nwhitehorn	    }
210683cbb37nwhitehorn	    touchwin(p->normal);
210783cbb37nwhitehorn	    wnoutrefresh(p->normal);
210883cbb37nwhitehorn	}
210983cbb37nwhitehorn    }
211083cbb37nwhitehorn
211183cbb37nwhitehorn    if (q) {
211294f19e0nwhitehorn	if (dialog_state.all_windows != 0)
211394f19e0nwhitehorn	    erase_childs_shadow(q);
2114a94245bnwhitehorn	del_subwindows(q->normal);
211583cbb37nwhitehorn	dlg_unregister_window(q->normal);
21162b5579cbapt	delwin(q->normal);
211783cbb37nwhitehorn	free(q);
211883cbb37nwhitehorn    }
211983cbb37nwhitehorn    doupdate();
212083cbb37nwhitehorn}
212183cbb37nwhitehorn
212283cbb37nwhitehorn/*
212383cbb37nwhitehorn * Create a window, optionally with a shadow.
212483cbb37nwhitehorn */
212583cbb37nwhitehornWINDOW *
212683cbb37nwhitehorndlg_new_window(int height, int width, int y, int x)
212783cbb37nwhitehorn{
212894f19e0nwhitehorn    return dlg_new_modal_window(stdscr, height, width, y, x);
212983cbb37nwhitehorn}
213083cbb37nwhitehorn
213194f19e0nwhitehorn/*
213294f19e0nwhitehorn * "Modal" windows differ from normal ones by having a shadow in a window
213394f19e0nwhitehorn * separate from the standard screen.
213494f19e0nwhitehorn */
213583cbb37nwhitehornWINDOW *
213683cbb37nwhitehorndlg_new_modal_window(WINDOW *parent, int height, int width, int y, int x)
213783cbb37nwhitehorn{
213883cbb37nwhitehorn    WINDOW *win;
213983cbb37nwhitehorn    DIALOG_WINDOWS *p = dlg_calloc(DIALOG_WINDOWS, 1);
214083cbb37nwhitehorn
214183cbb37nwhitehorn    (void) parent;
21422b5579cbapt    if (p == 0
21432b5579cbapt	|| (win = newwin(height, width, y, x)) == 0) {
214483cbb37nwhitehorn	dlg_exiterr("Can't make new window at (%d,%d), size (%d,%d).\n",
214583cbb37nwhitehorn		    y, x, height, width);
214683cbb37nwhitehorn    }
214783cbb37nwhitehorn    p->next = dialog_state.all_windows;
214883cbb37nwhitehorn    p->normal = win;
214983cbb37nwhitehorn    dialog_state.all_windows = p;
215083cbb37nwhitehorn#ifdef HAVE_COLOR
215183cbb37nwhitehorn    if (dialog_state.use_shadow) {
215294f19e0nwhitehorn	p->shadow = parent;
215394f19e0nwhitehorn	draw_childs_shadow(p);
215483cbb37nwhitehorn    }
215583cbb37nwhitehorn#endif
215683cbb37nwhitehorn
215783cbb37nwhitehorn    (void) keypad(win, TRUE);
215883cbb37nwhitehorn    return win;
215983cbb37nwhitehorn}
216083cbb37nwhitehorn
216183cbb37nwhitehorn/*
216283cbb37nwhitehorn * Move/Resize a window, optionally with a shadow.
216383cbb37nwhitehorn */
216483cbb37nwhitehorn#ifdef KEY_RESIZE
216583cbb37nwhitehornvoid
216683cbb37nwhitehorndlg_move_window(WINDOW *win, int height, int width, int y, int x)
216783cbb37nwhitehorn{
216894f19e0nwhitehorn    DIALOG_WINDOWS *p;
216983cbb37nwhitehorn
217083cbb37nwhitehorn    if (win != 0) {
217183cbb37nwhitehorn	dlg_ctl_size(height, width);
217283cbb37nwhitehorn
217394f19e0nwhitehorn	if ((p = find_window(win)) != 0) {
217483cbb37nwhitehorn	    (void) wresize(win, height, width);
217583cbb37nwhitehorn	    (void) mvwin(win, y, x);
217683cbb37nwhitehorn#ifdef HAVE_COLOR
217783cbb37nwhitehorn	    if (p->shadow != 0) {
217883cbb37nwhitehorn		if (dialog_state.use_shadow) {
217983cbb37nwhitehorn		    (void) mvwin(p->shadow, y + SHADOW_ROWS, x + SHADOW_COLS);
218083cbb37nwhitehorn		} else {
218183cbb37nwhitehorn		    p->shadow = 0;
218283cbb37nwhitehorn		}
218383cbb37nwhitehorn	    }
218483cbb37nwhitehorn#endif
218583cbb37nwhitehorn	    (void) refresh();
218683cbb37nwhitehorn
218783cbb37nwhitehorn#ifdef HAVE_COLOR
218894f19e0nwhitehorn	    draw_childs_shadow(p);
218983cbb37nwhitehorn#endif
219083cbb37nwhitehorn	}
219183cbb37nwhitehorn    }
219283cbb37nwhitehorn}
2193f8604a5bapt
2194f8604a5bapt/*
2195f8604a5bapt * Having just received a KEY_RESIZE, wait a short time to ignore followup
2196f8604a5bapt * KEY_RESIZE events.
2197f8604a5bapt */
2198f8604a5baptvoid
2199f8604a5baptdlg_will_resize(WINDOW *win)
2200f8604a5bapt{
2201f8604a5bapt    int n, ch, base;
2202f8604a5bapt    int caught = 0;
2203f8604a5bapt
2204f8604a5bapt    dlg_trace_win(win);
2205f8604a5bapt    wtimeout(win, 20);
2206f8604a5bapt    for (n = base = 0; n < base + 10; ++n) {
2207f8604a5bapt	if ((ch = wgetch(win)) != ERR) {
2208f8604a5bapt	    if (ch == KEY_RESIZE) {
2209f8604a5bapt		base = n;
2210f8604a5bapt		++caught;
2211f8604a5bapt	    } else {
2212f8604a5bapt		ungetch(ch);
2213f8604a5bapt		break;
2214f8604a5bapt	    }
2215f8604a5bapt	}
2216f8604a5bapt    }
2217f8604a5bapt    dlg_trace_msg("# caught %d KEY_RESIZE key%s\n",
2218f8604a5bapt		  1 + caught,
2219f8604a5bapt		  caught == 1 ? "" : "s");
2220f8604a5bapt}
222183cbb37nwhitehorn#endif /* KEY_RESIZE */
222283cbb37nwhitehorn
222383cbb37nwhitehornWINDOW *
222483cbb37nwhitehorndlg_sub_window(WINDOW *parent, int height, int width, int y, int x)
222583cbb37nwhitehorn{
222683cbb37nwhitehorn    WINDOW *win;
222783cbb37nwhitehorn
222883cbb37nwhitehorn    if ((win = subwin(parent, height, width, y, x)) == 0) {
222983cbb37nwhitehorn	dlg_exiterr("Can't make sub-window at (%d,%d), size (%d,%d).\n",
223083cbb37nwhitehorn		    y, x, height, width);
223183cbb37nwhitehorn    }
223283cbb37nwhitehorn
2233a94245bnwhitehorn    add_subwindow(parent, win);
223483cbb37nwhitehorn    (void) keypad(win, TRUE);
223583cbb37nwhitehorn    return win;
223683cbb37nwhitehorn}
223783cbb37nwhitehorn
223883cbb37nwhitehorn/* obsolete */
223983cbb37nwhitehornint
224083cbb37nwhitehorndlg_default_item(char **items, int llen)
224183cbb37nwhitehorn{
224283cbb37nwhitehorn    int result = 0;
224383cbb37nwhitehorn
224483cbb37nwhitehorn    if (dialog_vars.default_item != 0) {
224583cbb37nwhitehorn	int count = 0;
224683cbb37nwhitehorn	while (*items != 0) {
224783cbb37nwhitehorn	    if (!strcmp(dialog_vars.default_item, *items)) {
224883cbb37nwhitehorn		result = count;
224983cbb37nwhitehorn		break;
225083cbb37nwhitehorn	    }
225183cbb37nwhitehorn	    items += llen;
225283cbb37nwhitehorn	    count++;
225383cbb37nwhitehorn	}
225483cbb37nwhitehorn    }
225583cbb37nwhitehorn    return result;
225683cbb37nwhitehorn}
225783cbb37nwhitehorn
225883cbb37nwhitehornint
225983cbb37nwhitehorndlg_default_listitem(DIALOG_LISTITEM * items)
226083cbb37nwhitehorn{
226183cbb37nwhitehorn    int result = 0;
226283cbb37nwhitehorn
226383cbb37nwhitehorn    if (dialog_vars.default_item != 0) {
226483cbb37nwhitehorn	int count = 0;
226583cbb37nwhitehorn	while (items->name != 0) {
226683cbb37nwhitehorn	    if (!strcmp(dialog_vars.default_item, items->name)) {
226783cbb37nwhitehorn		result = count;
226883cbb37nwhitehorn		break;
226983cbb37nwhitehorn	    }
227083cbb37nwhitehorn	    ++items;
227183cbb37nwhitehorn	    count++;
227283cbb37nwhitehorn	}
227383cbb37nwhitehorn    }
227483cbb37nwhitehorn    return result;
227583cbb37nwhitehorn}
227683cbb37nwhitehorn
227783cbb37nwhitehorn/*
227883cbb37nwhitehorn * Draw the string for item_help
227983cbb37nwhitehorn */
228083cbb37nwhitehornvoid
228183cbb37nwhitehorndlg_item_help(const char *txt)
228283cbb37nwhitehorn{
228383cbb37nwhitehorn    if (USE_ITEM_HELP(txt)) {
228483cbb37nwhitehorn	chtype attr = A_NORMAL;
228583cbb37nwhitehorn	int y, x;
228683cbb37nwhitehorn
2287f8604a5bapt	dlg_attrset(stdscr, itemhelp_attr);
228883cbb37nwhitehorn	(void) wmove(stdscr, LINES - 1, 0);
228983cbb37nwhitehorn	(void) wclrtoeol(stdscr);
229083cbb37nwhitehorn	(void) addch(' ');
229183cbb37nwhitehorn	dlg_print_text(stdscr, txt, COLS - 1, &attr);
229283cbb37nwhitehorn	if (itemhelp_attr & A_COLOR) {
229383cbb37nwhitehorn	    /* fill the remainder of the line with the window's attributes */
229483cbb37nwhitehorn	    getyx(stdscr, y, x);
2295a94245bnwhitehorn	    (void) y;
229683cbb37nwhitehorn	    while (x < COLS) {
229783cbb37nwhitehorn		(void) addch(' ');
229883cbb37nwhitehorn		++x;
229983cbb37nwhitehorn	    }
230083cbb37nwhitehorn	}
230183cbb37nwhitehorn	(void) wnoutrefresh(stdscr);
230283cbb37nwhitehorn    }
230383cbb37nwhitehorn}
230483cbb37nwhitehorn
230583cbb37nwhitehorn#ifndef HAVE_STRCASECMP
230683cbb37nwhitehornint
230783cbb37nwhitehorndlg_strcmp(const char *a, const char *b)
230883cbb37nwhitehorn{
230983cbb37nwhitehorn    int ac, bc, cmp;
231083cbb37nwhitehorn
231183cbb37nwhitehorn    for (;;) {
231283cbb37nwhitehorn	ac = UCH(*a++);
231383cbb37nwhitehorn	bc = UCH(*b++);
231483cbb37nwhitehorn	if (isalpha(ac) && islower(ac))
231583cbb37nwhitehorn	    ac = _toupper(ac);
231683cbb37nwhitehorn	if (isalpha(bc) && islower(bc))
231783cbb37nwhitehorn	    bc = _toupper(bc);
231883cbb37nwhitehorn	cmp = ac - bc;
231983cbb37nwhitehorn	if (ac == 0 || bc == 0 || cmp != 0)
232083cbb37nwhitehorn	    break;
232183cbb37nwhitehorn    }
232283cbb37nwhitehorn    return cmp;
232383cbb37nwhitehorn}
232483cbb37nwhitehorn#endif
232583cbb37nwhitehorn
232683cbb37nwhitehorn/*
232783cbb37nwhitehorn * Returns true if 'dst' points to a blank which follows another blank which
232883cbb37nwhitehorn * is not a leading blank on a line.
232983cbb37nwhitehorn */
233083cbb37nwhitehornstatic bool
233183cbb37nwhitehorntrim_blank(char *base, char *dst)
233283cbb37nwhitehorn{
2333f8604a5bapt    int count = isblank(UCH(*dst));
233483cbb37nwhitehorn
233583cbb37nwhitehorn    while (dst-- != base) {
233683cbb37nwhitehorn	if (*dst == '\n') {
2337f8604a5bapt	    break;
2338f8604a5bapt	} else if (isblank(UCH(*dst))) {
233983cbb37nwhitehorn	    count++;
2340f8604a5bapt	} else {
2341f8604a5bapt	    break;
234283cbb37nwhitehorn	}
234383cbb37nwhitehorn    }
2344f8604a5bapt    return (count > 1);
234583cbb37nwhitehorn}
234683cbb37nwhitehorn
234783cbb37nwhitehorn/*
234883cbb37nwhitehorn * Change embedded "\n" substrings to '\n' characters and tabs to single
234983cbb37nwhitehorn * spaces.  If there are no "\n"s, it will strip all extra spaces, for
235083cbb37nwhitehorn * justification.  If it has "\n"'s, it will preserve extra spaces.  If cr_wrap
235183cbb37nwhitehorn * is set, it will preserve '\n's.
235283cbb37nwhitehorn */
235383cbb37nwhitehornvoid
235483cbb37nwhitehorndlg_trim_string(char *s)
235583cbb37nwhitehorn{
235683cbb37nwhitehorn    char *base = s;
235783cbb37nwhitehorn    char *p1;
235883cbb37nwhitehorn    char *p = s;
235994f19e0nwhitehorn    int has_newlines = !dialog_vars.no_nl_expand && (strstr(s, "\\n") != 0);
236083cbb37nwhitehorn
236183cbb37nwhitehorn    while (*p != '\0') {
236283cbb37nwhitehorn	if (*p == TAB && !dialog_vars.nocollapse)
236383cbb37nwhitehorn	    *p = ' ';
236483cbb37nwhitehorn
236583cbb37nwhitehorn	if (has_newlines) {	/* If prompt contains "\n" strings */
236683cbb37nwhitehorn	    if (*p == '\\' && *(p + 1) == 'n') {
236783cbb37nwhitehorn		*s++ = '\n';
236883cbb37nwhitehorn		p += 2;
236983cbb37nwhitehorn		p1 = p;
237083cbb37nwhitehorn		/*
237183cbb37nwhitehorn		 * Handle end of lines intelligently.  If '\n' follows "\n"
237283cbb37nwhitehorn		 * then ignore the '\n'.  This eliminates the need to escape
237383cbb37nwhitehorn		 * the '\n' character (no need to use "\n\").
237483cbb37nwhitehorn		 */
2375f8604a5bapt		while (isblank(UCH(*p1)))
237683cbb37nwhitehorn		    p1++;
237783cbb37nwhitehorn		if (*p1 == '\n')
237883cbb37nwhitehorn		    p = p1 + 1;
237983cbb37nwhitehorn	    } else if (*p == '\n') {
238083cbb37nwhitehorn		if (dialog_vars.cr_wrap)
238183cbb37nwhitehorn		    *s++ = *p++;
238283cbb37nwhitehorn		else {
238383cbb37nwhitehorn		    /* Replace the '\n' with a space if cr_wrap is not set */
2384f8604a5bapt		    if (!trim_blank(base, p))
238583cbb37nwhitehorn			*s++ = ' ';
238683cbb37nwhitehorn		    p++;
238783cbb37nwhitehorn		}
238883cbb37nwhitehorn	    } else		/* If *p != '\n' */
238983cbb37nwhitehorn		*s++ = *p++;
239083cbb37nwhitehorn	} else if (dialog_vars.trim_whitespace) {
2391f8604a5bapt	    if (isblank(UCH(*p))) {
2392f8604a5bapt		if (!isblank(UCH(*(s - 1)))) {
239383cbb37nwhitehorn		    *s++ = ' ';
239483cbb37nwhitehorn		    p++;
239583cbb37nwhitehorn		} else
239683cbb37nwhitehorn		    p++;
239783cbb37nwhitehorn	    } else if (*p == '\n') {
239883cbb37nwhitehorn		if (dialog_vars.cr_wrap)
239983cbb37nwhitehorn		    *s++ = *p++;
2400f8604a5bapt		else if (!isblank(UCH(*(s - 1)))) {
240183cbb37nwhitehorn		    /* Strip '\n's if cr_wrap is not set. */
240283cbb37nwhitehorn		    *s++ = ' ';
240383cbb37nwhitehorn		    p++;
240483cbb37nwhitehorn		} else
240583cbb37nwhitehorn		    p++;
240683cbb37nwhitehorn	    } else
240783cbb37nwhitehorn		*s++ = *p++;
240883cbb37nwhitehorn	} else {		/* If there are no "\n" strings */
2409f8604a5bapt	    if (isblank(UCH(*p)) && !dialog_vars.nocollapse) {
2410f8604a5bapt		if (!trim_blank(base, p))
241183cbb37nwhitehorn		    *s++ = *p;
241283cbb37nwhitehorn		p++;
241383cbb37nwhitehorn	    } else
241483cbb37nwhitehorn		*s++ = *p++;
241583cbb37nwhitehorn	}
241683cbb37nwhitehorn    }
241783cbb37nwhitehorn
241883cbb37nwhitehorn    *s = '\0';
241983cbb37nwhitehorn}
242083cbb37nwhitehorn
242183cbb37nwhitehornvoid
242283cbb37nwhitehorndlg_set_focus(WINDOW *parent, WINDOW *win)
242383cbb37nwhitehorn{
242483cbb37nwhitehorn    if (win != 0) {
242583cbb37nwhitehorn	(void) wmove(parent,
242683cbb37nwhitehorn		     getpary(win) + getcury(win),
242783cbb37nwhitehorn		     getparx(win) + getcurx(win));
242883cbb37nwhitehorn	(void) wnoutrefresh(win);
242983cbb37nwhitehorn	(void) doupdate();
243083cbb37nwhitehorn    }
243183cbb37nwhitehorn}
243283cbb37nwhitehorn
243383cbb37nwhitehorn/*
243483cbb37nwhitehorn * Returns the nominal maximum buffer size.
243583cbb37nwhitehorn */
243683cbb37nwhitehornint
243783cbb37nwhitehorndlg_max_input(int max_len)
243883cbb37nwhitehorn{
243983cbb37nwhitehorn    if (dialog_vars.max_input != 0 && dialog_vars.max_input < MAX_LEN)
244083cbb37nwhitehorn	max_len = dialog_vars.max_input;
244183cbb37nwhitehorn
244283cbb37nwhitehorn    return max_len;
244383cbb37nwhitehorn}
244483cbb37nwhitehorn
244583cbb37nwhitehorn/*
244683cbb37nwhitehorn * Free storage used for the result buffer.
244783cbb37nwhitehorn */
244883cbb37nwhitehornvoid
244983cbb37nwhitehorndlg_clr_result(void)
245083cbb37nwhitehorn{
245183cbb37nwhitehorn    if (dialog_vars.input_length) {
245283cbb37nwhitehorn	dialog_vars.input_length = 0;
245383cbb37nwhitehorn	if (dialog_vars.input_result)
245483cbb37nwhitehorn	    free(dialog_vars.input_result);
245583cbb37nwhitehorn    }
245683cbb37nwhitehorn    dialog_vars.input_result = 0;
245783cbb37nwhitehorn}
245883cbb37nwhitehorn
245983cbb37nwhitehorn/*
246083cbb37nwhitehorn * Setup a fixed-buffer for the result.
246183cbb37nwhitehorn */
246283cbb37nwhitehornchar *
246383cbb37nwhitehorndlg_set_result(const char *string)
246483cbb37nwhitehorn{
24659904759nwhitehorn    unsigned need = string ? (unsigned) strlen(string) + 1 : 0;
246683cbb37nwhitehorn
246783cbb37nwhitehorn    /* inputstr.c needs a fixed buffer */
246883cbb37nwhitehorn    if (need < MAX_LEN)
246983cbb37nwhitehorn	need = MAX_LEN;
247083cbb37nwhitehorn
247183cbb37nwhitehorn    /*
247283cbb37nwhitehorn     * If the buffer is not big enough, allocate a new one.
247383cbb37nwhitehorn     */
247483cbb37nwhitehorn    if (dialog_vars.input_length != 0
247583cbb37nwhitehorn	|| dialog_vars.input_result == 0
247683cbb37nwhitehorn	|| need > MAX_LEN) {
247783cbb37nwhitehorn
247883cbb37nwhitehorn	dlg_clr_result();
247983cbb37nwhitehorn
248083cbb37nwhitehorn	dialog_vars.input_length = need;
248183cbb37nwhitehorn	dialog_vars.input_result = dlg_malloc(char, need);
248283cbb37nwhitehorn	assert_ptr(dialog_vars.input_result, "dlg_set_result");
248383cbb37nwhitehorn    }
248483cbb37nwhitehorn
248583cbb37nwhitehorn    strcpy(dialog_vars.input_result, string ? string : "");
248683cbb37nwhitehorn
248783cbb37nwhitehorn    return dialog_vars.input_result;
248883cbb37nwhitehorn}
248983cbb37nwhitehorn
249083cbb37nwhitehorn/*
249183cbb37nwhitehorn * Accumulate results in dynamically allocated buffer.
249283cbb37nwhitehorn * If input_length is zero, it is a MAX_LEN buffer belonging to the caller.
249383cbb37nwhitehorn */
249483cbb37nwhitehornvoid
249583cbb37nwhitehorndlg_add_result(const char *string)
249683cbb37nwhitehorn{
249783cbb37nwhitehorn    unsigned have = (dialog_vars.input_result
24989904759nwhitehorn		     ? (unsigned) strlen(dialog_vars.input_result)
249983cbb37nwhitehorn		     : 0);
25009904759nwhitehorn    unsigned want = (unsigned) strlen(string) + 1 + have;
250183cbb37nwhitehorn
250283cbb37nwhitehorn    if ((want >= MAX_LEN)
250383cbb37nwhitehorn	|| (dialog_vars.input_length != 0)
250483cbb37nwhitehorn	|| (dialog_vars.input_result == 0)) {
250583cbb37nwhitehorn
250683cbb37nwhitehorn	if (dialog_vars.input_length == 0
250783cbb37nwhitehorn	    || dialog_vars.input_result == 0) {
250883cbb37nwhitehorn
25099904759nwhitehorn	    char *save_result = dialog_vars.input_result;
251083cbb37nwhitehorn
251183cbb37nwhitehorn	    dialog_vars.input_length = want * 2;
251283cbb37nwhitehorn	    dialog_vars.input_result = dlg_malloc(char, dialog_vars.input_length);
251383cbb37nwhitehorn	    assert_ptr(dialog_vars.input_result, "dlg_add_result malloc");
25149904759nwhitehorn	    dialog_vars.input_result[0] = '\0';
25159904759nwhitehorn	    if (save_result != 0)
25169904759nwhitehorn		strcpy(dialog_vars.input_result, save_result);
251783cbb37nwhitehorn	} else if (want >= dialog_vars.input_length) {
251883cbb37nwhitehorn	    dialog_vars.input_length = want * 2;
251983cbb37nwhitehorn	    dialog_vars.input_result = dlg_realloc(char,
252083cbb37nwhitehorn						   dialog_vars.input_length,
252183cbb37nwhitehorn						   dialog_vars.input_result);
252283cbb37nwhitehorn	    assert_ptr(dialog_vars.input_result, "dlg_add_result realloc");
252383cbb37nwhitehorn	}
252483cbb37nwhitehorn    }
252583cbb37nwhitehorn    strcat(dialog_vars.input_result, string);
252683cbb37nwhitehorn}
252783cbb37nwhitehorn
252883cbb37nwhitehorn/*
252983cbb37nwhitehorn * These are characters that (aside from the quote-delimiter) will have to
253083cbb37nwhitehorn * be escaped in a single- or double-quoted string.
253183cbb37nwhitehorn */
253283cbb37nwhitehorn#define FIX_SINGLE "\n\\"
253383cbb37nwhitehorn#define FIX_DOUBLE FIX_SINGLE "[]{}?*;`~#$^&()|<>"
253483cbb37nwhitehorn
253583cbb37nwhitehorn/*
253683cbb37nwhitehorn * Returns the quote-delimiter.
253783cbb37nwhitehorn */
253883cbb37nwhitehornstatic const char *
253983cbb37nwhitehornquote_delimiter(void)
254083cbb37nwhitehorn{
254183cbb37nwhitehorn    return dialog_vars.single_quoted ? "'" : "\"";
254283cbb37nwhitehorn}
254383cbb37nwhitehorn
254483cbb37nwhitehorn/*
254583cbb37nwhitehorn * Returns true if we should quote the given string.
254683cbb37nwhitehorn */
254783cbb37nwhitehornstatic bool
254883cbb37nwhitehornmust_quote(char *string)
254983cbb37nwhitehorn{
255083cbb37nwhitehorn    bool code = FALSE;
255183cbb37nwhitehorn
255283cbb37nwhitehorn    if (*string != '\0') {
25539904759nwhitehorn	size_t len = strlen(string);
255483cbb37nwhitehorn	if (strcspn(string, quote_delimiter()) != len)
255583cbb37nwhitehorn	    code = TRUE;
255683cbb37nwhitehorn	else if (strcspn(string, "\n\t ") != len)
255783cbb37nwhitehorn	    code = TRUE;
255883cbb37nwhitehorn	else
255983cbb37nwhitehorn	    code = (strcspn(string, FIX_DOUBLE) != len);
256083cbb37nwhitehorn    } else {
256183cbb37nwhitehorn	code = TRUE;
256283cbb37nwhitehorn    }
256383cbb37nwhitehorn
256483cbb37nwhitehorn    return code;
256583cbb37nwhitehorn}
256683cbb37nwhitehorn
256783cbb37nwhitehorn/*
256883cbb37nwhitehorn * Add a quoted string to the result buffer.
256983cbb37nwhitehorn */
257083cbb37nwhitehornvoid
257183cbb37nwhitehorndlg_add_quoted(char *string)
257283cbb37nwhitehorn{
257383cbb37nwhitehorn    char temp[2];
257483cbb37nwhitehorn    const char *my_quote = quote_delimiter();
257583cbb37nwhitehorn    const char *must_fix = (dialog_vars.single_quoted
257683cbb37nwhitehorn			    ? FIX_SINGLE
257783cbb37nwhitehorn			    : FIX_DOUBLE);
257883cbb37nwhitehorn
2579a94245bnwhitehorn    if (must_quote(string)) {
258083cbb37nwhitehorn	temp[1] = '\0';
258183cbb37nwhitehorn	dlg_add_result(my_quote);
258283cbb37nwhitehorn	while (*string != '\0') {
258383cbb37nwhitehorn	    temp[0] = *string++;
2584f8604a5bapt	    if ((strchr) (my_quote, *temp) || (strchr) (must_fix, *temp))
258583cbb37nwhitehorn		dlg_add_result("\\");
258683cbb37nwhitehorn	    dlg_add_result(temp);
258783cbb37nwhitehorn	}
258883cbb37nwhitehorn	dlg_add_result(my_quote);
258983cbb37nwhitehorn    } else {
259083cbb37nwhitehorn	dlg_add_result(string);
259183cbb37nwhitehorn    }
259283cbb37nwhitehorn}
259383cbb37nwhitehorn
259483cbb37nwhitehorn/*
259583cbb37nwhitehorn * When adding a result, make that depend on whether "--quoted" is used.
259683cbb37nwhitehorn */
259783cbb37nwhitehornvoid
259883cbb37nwhitehorndlg_add_string(char *string)
259983cbb37nwhitehorn{
260083cbb37nwhitehorn    if (dialog_vars.quoted) {
260183cbb37nwhitehorn	dlg_add_quoted(string);
260283cbb37nwhitehorn    } else {
260383cbb37nwhitehorn	dlg_add_result(string);
260483cbb37nwhitehorn    }
260583cbb37nwhitehorn}
260683cbb37nwhitehorn
260783cbb37nwhitehornbool
260883cbb37nwhitehorndlg_need_separator(void)
260983cbb37nwhitehorn{
261083cbb37nwhitehorn    bool result = FALSE;
261183cbb37nwhitehorn
261283cbb37nwhitehorn    if (dialog_vars.output_separator) {
261383cbb37nwhitehorn	result = TRUE;
261483cbb37nwhitehorn    } else if (dialog_vars.input_result && *(dialog_vars.input_result)) {
261583cbb37nwhitehorn	result = TRUE;
261683cbb37nwhitehorn    }
261783cbb37nwhitehorn    return result;
261883cbb37nwhitehorn}
261983cbb37nwhitehorn
262083cbb37nwhitehornvoid
262183cbb37nwhitehorndlg_add_separator(void)
262283cbb37nwhitehorn{
262383cbb37nwhitehorn    const char *separator = (dialog_vars.separate_output) ? "\n" : " ";
262483cbb37nwhitehorn
262583cbb37nwhitehorn    if (dialog_vars.output_separator)
262683cbb37nwhitehorn	separator = dialog_vars.output_separator;
262783cbb37nwhitehorn
262883cbb37nwhitehorn    dlg_add_result(separator);
262983cbb37nwhitehorn}
263083cbb37nwhitehorn
2631e53d5c4dteske#define HELP_PREFIX		"HELP "
2632e53d5c4dteske
2633e53d5c4dteskevoid
2634e53d5c4dteskedlg_add_help_listitem(int *result, char **tag, DIALOG_LISTITEM * item)
2635e53d5c4dteske{
2636e53d5c4dteske    dlg_add_result(HELP_PREFIX);
2637e53d5c4dteske    if (USE_ITEM_HELP(item->help)) {
2638e53d5c4dteske	*tag = dialog_vars.help_tags ? item->name : item->help;
2639e53d5c4dteske	*result = DLG_EXIT_ITEM_HELP;
2640e53d5c4dteske    } else {
2641e53d5c4dteske	*tag = item->name;
2642e53d5c4dteske    }
2643e53d5c4dteske}
2644e53d5c4dteske
2645e53d5c4dteskevoid
2646e53d5c4dteskedlg_add_help_formitem(int *result, char **tag, DIALOG_FORMITEM * item)
2647e53d5c4dteske{
2648e53d5c4dteske    dlg_add_result(HELP_PREFIX);
2649e53d5c4dteske    if (USE_ITEM_HELP(item->help)) {
2650e53d5c4dteske	*tag = dialog_vars.help_tags ? item->name : item->help;
2651e53d5c4dteske	*result = DLG_EXIT_ITEM_HELP;
2652e53d5c4dteske    } else {
2653e53d5c4dteske	*tag = item->name;
2654e53d5c4dteske    }
2655e53d5c4dteske}
2656e53d5c4dteske
265783cbb37nwhitehorn/*
265883cbb37nwhitehorn * Some widgets support only one value of a given variable - save/restore the
265983cbb37nwhitehorn * global dialog_vars so we can override it consistently.
266083cbb37nwhitehorn */
266183cbb37nwhitehornvoid
266283cbb37nwhitehorndlg_save_vars(DIALOG_VARS * vars)
266383cbb37nwhitehorn{
266483cbb37nwhitehorn    *vars = dialog_vars;
266583cbb37nwhitehorn}
266683cbb37nwhitehorn
26679904759nwhitehorn/*
26689904759nwhitehorn * Most of the data in DIALOG_VARS is normally set by command-line options.
26699904759nwhitehorn * The input_result member is an exception; it is normally set by the dialog
26709904759nwhitehorn * library to return result values.
26719904759nwhitehorn */
267283cbb37nwhitehornvoid
267383cbb37nwhitehorndlg_restore_vars(DIALOG_VARS * vars)
267483cbb37nwhitehorn{
26759904759nwhitehorn    char *save_result = dialog_vars.input_result;
26769904759nwhitehorn    unsigned save_length = dialog_vars.input_length;
26779904759nwhitehorn
267883cbb37nwhitehorn    dialog_vars = *vars;
26799904759nwhitehorn    dialog_vars.input_result = save_result;
26809904759nwhitehorn    dialog_vars.input_length = save_length;
268183cbb37nwhitehorn}
268283cbb37nwhitehorn
268383cbb37nwhitehorn/*
268483cbb37nwhitehorn * Called each time a widget is invoked which may do output, increment a count.
268583cbb37nwhitehorn */
268683cbb37nwhitehornvoid
268783cbb37nwhitehorndlg_does_output(void)
268883cbb37nwhitehorn{
268983cbb37nwhitehorn    dialog_state.output_count += 1;
269083cbb37nwhitehorn}
269183cbb37nwhitehorn
269283cbb37nwhitehorn/*
269383cbb37nwhitehorn * Compatibility for different versions of curses.
269483cbb37nwhitehorn */
269583cbb37nwhitehorn#if !(defined(HAVE_GETBEGX) && defined(HAVE_GETBEGY))
269683cbb37nwhitehornint
2697a94245bnwhitehorndlg_getbegx(WINDOW *win)
269883cbb37nwhitehorn{
269983cbb37nwhitehorn    int y, x;
270083cbb37nwhitehorn    getbegyx(win, y, x);
270183cbb37nwhitehorn    return x;
270283cbb37nwhitehorn}
270383cbb37nwhitehornint
2704a94245bnwhitehorndlg_getbegy(WINDOW *win)
270583cbb37nwhitehorn{
270683cbb37nwhitehorn    int y, x;
270783cbb37nwhitehorn    getbegyx(win, y, x);
270883cbb37nwhitehorn    return y;
270983cbb37nwhitehorn}
271083cbb37nwhitehorn#endif
271183cbb37nwhitehorn
271283cbb37nwhitehorn#if !(defined(HAVE_GETCURX) && defined(HAVE_GETCURY))
271383cbb37nwhitehornint
2714a94245bnwhitehorndlg_getcurx(WINDOW *win)
271583cbb37nwhitehorn{
271683cbb37nwhitehorn    int y, x;
271783cbb37nwhitehorn    getyx(win, y, x);
271883cbb37nwhitehorn    return x;
271983cbb37nwhitehorn}
272083cbb37nwhitehornint
2721a94245bnwhitehorndlg_getcury(WINDOW *win)
272283cbb37nwhitehorn{
272383cbb37nwhitehorn    int y, x;
272483cbb37nwhitehorn    getyx(win, y, x);
272583cbb37nwhitehorn    return y;
272683cbb37nwhitehorn}
272783cbb37nwhitehorn#endif
272883cbb37nwhitehorn
272983cbb37nwhitehorn#if !(defined(HAVE_GETMAXX) && defined(HAVE_GETMAXY))
273083cbb37nwhitehornint
2731a94245bnwhitehorndlg_getmaxx(WINDOW *win)
273283cbb37nwhitehorn{
273383cbb37nwhitehorn    int y, x;
273483cbb37nwhitehorn    getmaxyx(win, y, x);
273583cbb37nwhitehorn    return x;
273683cbb37nwhitehorn}
273783cbb37nwhitehornint
2738a94245bnwhitehorndlg_getmaxy(WINDOW *win)
273983cbb37nwhitehorn{
274083cbb37nwhitehorn    int y, x;
274183cbb37nwhitehorn    getmaxyx(win, y, x);
274283cbb37nwhitehorn    return y;
274383cbb37nwhitehorn}
274483cbb37nwhitehorn#endif
274583cbb37nwhitehorn
274683cbb37nwhitehorn#if !(defined(HAVE_GETPARX) && defined(HAVE_GETPARY))
274783cbb37nwhitehornint
2748a94245bnwhitehorndlg_getparx(WINDOW *win)
274983cbb37nwhitehorn{
275083cbb37nwhitehorn    int y, x;
275183cbb37nwhitehorn    getparyx(win, y, x);
275283cbb37nwhitehorn    return x;
275383cbb37nwhitehorn}
275483cbb37nwhitehornint
2755a94245bnwhitehorndlg_getpary(WINDOW *win)
275683cbb37nwhitehorn{
275783cbb37nwhitehorn    int y, x;
275883cbb37nwhitehorn    getparyx(win, y, x);
275983cbb37nwhitehorn    return y;
276083cbb37nwhitehorn}
276183cbb37nwhitehorn#endif
2762a94245bnwhitehorn
2763a94245bnwhitehorn#ifdef NEED_WGETPARENT
2764a94245bnwhitehornWINDOW *
2765a94245bnwhitehorndlg_wgetparent(WINDOW *win)
2766a94245bnwhitehorn{
2767a94245bnwhitehorn#undef wgetparent
2768a94245bnwhitehorn    WINDOW *result = 0;
2769a94245bnwhitehorn    DIALOG_WINDOWS *p;
2770a94245bnwhitehorn
2771a94245bnwhitehorn    for (p = dialog_state.all_subwindows; p != 0; p = p->next) {
2772a94245bnwhitehorn	if (p->shadow == win) {
2773a94245bnwhitehorn	    result = p->normal;
2774a94245bnwhitehorn	    break;
2775a94245bnwhitehorn	}
2776a94245bnwhitehorn    }
2777a94245bnwhitehorn    return result;
2778a94245bnwhitehorn}
2779a94245bnwhitehorn#endif
2780