xref: /minix3/usr.bin/msgc/msg_sys.def (revision 0b79eac6423ec1e204856a6d29ce600422106cd6)
1*d44a5ed1SThomas Cort/*	$NetBSD: msg_sys.def,v 1.41 2012/03/06 16:26:01 mbalmer Exp $	*/
2*d44a5ed1SThomas Cort
3*d44a5ed1SThomas Cort/*
4*d44a5ed1SThomas Cort * Copyright 1997 Piermont Information Systems Inc.
5*d44a5ed1SThomas Cort * All rights reserved.
6*d44a5ed1SThomas Cort *
7*d44a5ed1SThomas Cort * Written by Philip A. Nelson for Piermont Information Systems Inc.
8*d44a5ed1SThomas Cort *
9*d44a5ed1SThomas Cort * Redistribution and use in source and binary forms, with or without
10*d44a5ed1SThomas Cort * modification, are permitted provided that the following conditions
11*d44a5ed1SThomas Cort * are met:
12*d44a5ed1SThomas Cort * 1. Redistributions of source code must retain the above copyright
13*d44a5ed1SThomas Cort *    notice, this list of conditions and the following disclaimer.
14*d44a5ed1SThomas Cort * 2. Redistributions in binary form must reproduce the above copyright
15*d44a5ed1SThomas Cort *    notice, this list of conditions and the following disclaimer in the
16*d44a5ed1SThomas Cort *    documentation and/or other materials provided with the distribution.
17*d44a5ed1SThomas Cort * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18*d44a5ed1SThomas Cort *    or promote products derived from this software without specific prior
19*d44a5ed1SThomas Cort *    written permission.
20*d44a5ed1SThomas Cort *
21*d44a5ed1SThomas Cort * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22*d44a5ed1SThomas Cort * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*d44a5ed1SThomas Cort * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*d44a5ed1SThomas Cort * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25*d44a5ed1SThomas Cort * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26*d44a5ed1SThomas Cort * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27*d44a5ed1SThomas Cort * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*d44a5ed1SThomas Cort * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29*d44a5ed1SThomas Cort * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30*d44a5ed1SThomas Cort * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31*d44a5ed1SThomas Cort * THE POSSIBILITY OF SUCH DAMAGE.
32*d44a5ed1SThomas Cort *
33*d44a5ed1SThomas Cort */
34*d44a5ed1SThomas Cort
35*d44a5ed1SThomas Cortstatic WINDOW *msg_win = NULL;
36*d44a5ed1SThomas Cortstatic char *cbuffer;
37*d44a5ed1SThomas Cortstatic size_t cbuffersize;
38*d44a5ed1SThomas Cort
39*d44a5ed1SThomas Cortstatic int last_i_was_nl, last_i_was_space;
40*d44a5ed1SThomas Cortstatic int last_o_was_punct, last_o_was_space;
41*d44a5ed1SThomas Cort
42*d44a5ed1SThomas Cortstatic void	_msg_beep(void);
43*d44a5ed1SThomas Cortstatic int	_msg_vprintf(int, const char *, va_list);
44*d44a5ed1SThomas Cort#define MSG_PROMPT_ECHO		1
45*d44a5ed1SThomas Cort#define MSG_PROMPT_HIDE_DFLT	2
46*d44a5ed1SThomas Cortstatic void	_msg_vprompt(const char *, int, const char *, char *,
47*d44a5ed1SThomas Cort			size_t, va_list);
48*d44a5ed1SThomas Cort
49*d44a5ed1SThomas Cortstatic char *msgmap = MAP_FAILED;
50*d44a5ed1SThomas Cortstatic size_t msgmapsz;
51*d44a5ed1SThomas Cortstatic unsigned int msgmapcount;
52*d44a5ed1SThomas Cort
53*d44a5ed1SThomas Cort/* Routines */
54*d44a5ed1SThomas Cort
55*d44a5ed1SThomas Cortstatic void
56*d44a5ed1SThomas Cort_msg_beep(void)
57*d44a5ed1SThomas Cort{
58*d44a5ed1SThomas Cort
59*d44a5ed1SThomas Cort	fprintf(stderr, "\a");
60*d44a5ed1SThomas Cort}
61*d44a5ed1SThomas Cort
62*d44a5ed1SThomas CortWINDOW *
63*d44a5ed1SThomas Cortmsg_window(WINDOW *window)
64*d44a5ed1SThomas Cort{
65*d44a5ed1SThomas Cort	size_t ncbuffersize;
66*d44a5ed1SThomas Cort	char *ncbuffer;
67*d44a5ed1SThomas Cort	WINDOW *old;
68*d44a5ed1SThomas Cort
69*d44a5ed1SThomas Cort	old = msg_win;
70*d44a5ed1SThomas Cort	if (!window)
71*d44a5ed1SThomas Cort		return old;
72*d44a5ed1SThomas Cort	msg_win = window;
73*d44a5ed1SThomas Cort
74*d44a5ed1SThomas Cort	ncbuffersize = getmaxx(window) * getmaxy(window) + 1;
75*d44a5ed1SThomas Cort	while (ncbuffersize > cbuffersize) {
76*d44a5ed1SThomas Cort		ncbuffer = malloc(ncbuffersize);
77*d44a5ed1SThomas Cort		if (ncbuffer == NULL) {
78*d44a5ed1SThomas Cort			/* we might get truncated messages... */
79*d44a5ed1SThomas Cort			ncbuffersize <<= 1;
80*d44a5ed1SThomas Cort			continue;
81*d44a5ed1SThomas Cort		}
82*d44a5ed1SThomas Cort		if (cbuffer != NULL)
83*d44a5ed1SThomas Cort			free(cbuffer);
84*d44a5ed1SThomas Cort		cbuffer = ncbuffer;
85*d44a5ed1SThomas Cort		cbuffersize = ncbuffersize;
86*d44a5ed1SThomas Cort		break;
87*d44a5ed1SThomas Cort	}
88*d44a5ed1SThomas Cort	last_o_was_punct = 0;
89*d44a5ed1SThomas Cort	last_o_was_space = 1;
90*d44a5ed1SThomas Cort	return old;
91*d44a5ed1SThomas Cort}
92*d44a5ed1SThomas Cort
93*d44a5ed1SThomas Cortint
94*d44a5ed1SThomas Cortmsg_file(const char *file)
95*d44a5ed1SThomas Cort{
96*d44a5ed1SThomas Cort	int fd;
97*d44a5ed1SThomas Cort
98*d44a5ed1SThomas Cort	if (msgmap != MAP_FAILED)
99*d44a5ed1SThomas Cort		munmap(msgmap, msgmapsz);
100*d44a5ed1SThomas Cort	msgmap = MAP_FAILED;
101*d44a5ed1SThomas Cort	if (!file)
102*d44a5ed1SThomas Cort		return 0;
103*d44a5ed1SThomas Cort	fd = open(file, O_RDONLY, 0);
104*d44a5ed1SThomas Cort	if (fd == -1)
105*d44a5ed1SThomas Cort		return -1;
106*d44a5ed1SThomas Cort	msgmapsz = lseek(fd, 0, SEEK_END);
107*d44a5ed1SThomas Cort	msgmap = mmap(0, msgmapsz, PROT_READ, MAP_SHARED, fd, 0);
108*d44a5ed1SThomas Cort	close(fd);
109*d44a5ed1SThomas Cort	if (msgmap == MAP_FAILED)
110*d44a5ed1SThomas Cort		return -1;
111*d44a5ed1SThomas Cort	/* check_magic */
112*d44a5ed1SThomas Cort	if (strcmp(msgmap, "MSGTXTS") != 0) {
113*d44a5ed1SThomas Cort		msg_file(NULL);
114*d44a5ed1SThomas Cort		return -1;
115*d44a5ed1SThomas Cort	}
116*d44a5ed1SThomas Cort	msgmapcount = atoi(msgmap + 8);
117*d44a5ed1SThomas Cort	return 0;
118*d44a5ed1SThomas Cort}
119*d44a5ed1SThomas Cort
120*d44a5ed1SThomas Cortconst char *
121*d44a5ed1SThomas Cortmsg_string(msg msg_no)
122*d44a5ed1SThomas Cort{
123*d44a5ed1SThomas Cort	uintptr_t m = (uintptr_t)msg_no;
124*d44a5ed1SThomas Cort
125*d44a5ed1SThomas Cort	if (m > sizeof msg_list / sizeof msg_list[0])
126*d44a5ed1SThomas Cort		/* guess that we were passed a text string */
127*d44a5ed1SThomas Cort		return msg_no;
128*d44a5ed1SThomas Cort
129*d44a5ed1SThomas Cort	if (msgmap != MAP_FAILED && m != 0 && m <= msgmapcount) {
130*d44a5ed1SThomas Cort		unsigned int offset = atoi(msgmap + 8 + 8 * m);
131*d44a5ed1SThomas Cort		if (offset != 0 && offset < msgmapsz)
132*d44a5ed1SThomas Cort			return msgmap + offset;
133*d44a5ed1SThomas Cort	}
134*d44a5ed1SThomas Cort
135*d44a5ed1SThomas Cort	return msg_list[m];
136*d44a5ed1SThomas Cort}
137*d44a5ed1SThomas Cort
138*d44a5ed1SThomas Cortvoid
139*d44a5ed1SThomas Cortmsg_clear(void)
140*d44a5ed1SThomas Cort{
141*d44a5ed1SThomas Cort
142*d44a5ed1SThomas Cort	wclear(msg_win);
143*d44a5ed1SThomas Cort	last_o_was_punct = 0;
144*d44a5ed1SThomas Cort	last_o_was_space = 1;
145*d44a5ed1SThomas Cort}
146*d44a5ed1SThomas Cort
147*d44a5ed1SThomas Cortvoid
148*d44a5ed1SThomas Cortmsg_standout(void)
149*d44a5ed1SThomas Cort{
150*d44a5ed1SThomas Cort
151*d44a5ed1SThomas Cort	wstandout(msg_win);
152*d44a5ed1SThomas Cort}
153*d44a5ed1SThomas Cort
154*d44a5ed1SThomas Cortvoid
155*d44a5ed1SThomas Cortmsg_standend(void)
156*d44a5ed1SThomas Cort{
157*d44a5ed1SThomas Cort
158*d44a5ed1SThomas Cort	wstandend(msg_win);
159*d44a5ed1SThomas Cort}
160*d44a5ed1SThomas Cort
161*d44a5ed1SThomas Cortstatic int
162*d44a5ed1SThomas Cort_msg_vprintf(int auto_fill, const char *fmt, va_list ap)
163*d44a5ed1SThomas Cort{
164*d44a5ed1SThomas Cort	const char *wstart, *afterw;
165*d44a5ed1SThomas Cort	int wordlen, nspaces;
166*d44a5ed1SThomas Cort	int ret;
167*d44a5ed1SThomas Cort
168*d44a5ed1SThomas Cort	ret = vsnprintf(cbuffer, cbuffersize, fmt, ap);
169*d44a5ed1SThomas Cort
170*d44a5ed1SThomas Cort	if (!auto_fill) {
171*d44a5ed1SThomas Cort		waddstr(msg_win, cbuffer);
172*d44a5ed1SThomas Cort
173*d44a5ed1SThomas Cort		/*
174*d44a5ed1SThomas Cort		 * nothing is perfect if they flow text after a table,
175*d44a5ed1SThomas Cort		 * but this may be decent.
176*d44a5ed1SThomas Cort		 */
177*d44a5ed1SThomas Cort		last_i_was_nl = last_i_was_space = 1;
178*d44a5ed1SThomas Cort		last_o_was_punct = 0;
179*d44a5ed1SThomas Cort		last_o_was_space = 1;
180*d44a5ed1SThomas Cort		goto out;
181*d44a5ed1SThomas Cort	}
182*d44a5ed1SThomas Cort
183*d44a5ed1SThomas Cort	for (wstart = afterw = cbuffer; *wstart; wstart = afterw) {
184*d44a5ed1SThomas Cort
185*d44a5ed1SThomas Cort		/* eat one space, or a whole word of non-spaces */
186*d44a5ed1SThomas Cort		if (isspace((unsigned char)*afterw))
187*d44a5ed1SThomas Cort			afterw++;
188*d44a5ed1SThomas Cort		else
189*d44a5ed1SThomas Cort			while (*afterw && !isspace((unsigned char)*afterw))
190*d44a5ed1SThomas Cort				afterw++;
191*d44a5ed1SThomas Cort
192*d44a5ed1SThomas Cort		/* this is an nl: special formatting necessary */
193*d44a5ed1SThomas Cort		if (*wstart == '\n') {
194*d44a5ed1SThomas Cort			if (last_i_was_nl || last_i_was_space) {
195*d44a5ed1SThomas Cort
196*d44a5ed1SThomas Cort				if (getcurx(msg_win) != 0)
197*d44a5ed1SThomas Cort					waddch(msg_win, '\n');
198*d44a5ed1SThomas Cort				if (last_i_was_nl) {
199*d44a5ed1SThomas Cort					/* last was an nl: paragraph break */
200*d44a5ed1SThomas Cort					waddch(msg_win, '\n');
201*d44a5ed1SThomas Cort				} else {
202*d44a5ed1SThomas Cort					/* last was space: line break */
203*d44a5ed1SThomas Cort				}
204*d44a5ed1SThomas Cort				last_o_was_punct = 0;
205*d44a5ed1SThomas Cort				last_o_was_space = 1;
206*d44a5ed1SThomas Cort			} else {
207*d44a5ed1SThomas Cort				/* last_o_was_punct unchanged */
208*d44a5ed1SThomas Cort				/* last_o_was_space unchanged */
209*d44a5ed1SThomas Cort			}
210*d44a5ed1SThomas Cort			last_i_was_space = 1;
211*d44a5ed1SThomas Cort			last_i_was_nl = 1;
212*d44a5ed1SThomas Cort			continue;
213*d44a5ed1SThomas Cort		}
214*d44a5ed1SThomas Cort
215*d44a5ed1SThomas Cort		/* this is a tab: special formatting necessary. */
216*d44a5ed1SThomas Cort		if (*wstart == '\t') {
217*d44a5ed1SThomas Cort			if (last_i_was_nl) {
218*d44a5ed1SThomas Cort				/* last was an nl: list indent */
219*d44a5ed1SThomas Cort				if (getcurx(msg_win) != 0)
220*d44a5ed1SThomas Cort					waddch(msg_win, '\n');
221*d44a5ed1SThomas Cort			} else {
222*d44a5ed1SThomas Cort				/* last was not an nl: columns */
223*d44a5ed1SThomas Cort			}
224*d44a5ed1SThomas Cort			waddch(msg_win, '\t');
225*d44a5ed1SThomas Cort			last_i_was_nl = 0;
226*d44a5ed1SThomas Cort			last_i_was_space = 1;
227*d44a5ed1SThomas Cort			last_o_was_punct = 0;
228*d44a5ed1SThomas Cort			last_o_was_space = 1;
229*d44a5ed1SThomas Cort			continue;
230*d44a5ed1SThomas Cort		}
231*d44a5ed1SThomas Cort
232*d44a5ed1SThomas Cort		/* this is a space: ignore it but set flags */
233*d44a5ed1SThomas Cort		last_i_was_nl = 0;	/* all newlines handled above */
234*d44a5ed1SThomas Cort		last_i_was_space = isspace((unsigned char)*wstart);
235*d44a5ed1SThomas Cort		if (last_i_was_space)
236*d44a5ed1SThomas Cort			continue;
237*d44a5ed1SThomas Cort
238*d44a5ed1SThomas Cort		/*
239*d44a5ed1SThomas Cort		 * we have a real "word," i.e. a sequence of non-space
240*d44a5ed1SThomas Cort		 * characters.  wstart is now the start of the word,
241*d44a5ed1SThomas Cort		 * afterw is the next character after the end.
242*d44a5ed1SThomas Cort		 */
243*d44a5ed1SThomas Cort		wordlen = afterw - wstart;
244*d44a5ed1SThomas Cort		nspaces = last_o_was_space ? 0 : (last_o_was_punct ? 2 : 1);
245*d44a5ed1SThomas Cort		if ((getcurx(msg_win) + nspaces + wordlen) >=
246*d44a5ed1SThomas Cort		      getmaxx(msg_win) &&
247*d44a5ed1SThomas Cort		    wordlen < (getmaxx(msg_win) / 3)) {
248*d44a5ed1SThomas Cort			/* wrap the line */
249*d44a5ed1SThomas Cort			waddch(msg_win, '\n');
250*d44a5ed1SThomas Cort			nspaces = 0;
251*d44a5ed1SThomas Cort		}
252*d44a5ed1SThomas Cort
253*d44a5ed1SThomas Cort		/* output the word, preceded by spaces if necessary */
254*d44a5ed1SThomas Cort		while (nspaces-- > 0)
255*d44a5ed1SThomas Cort			waddch(msg_win, ' ');
256*d44a5ed1SThomas Cort		waddbytes(msg_win, wstart, wordlen);
257*d44a5ed1SThomas Cort
258*d44a5ed1SThomas Cort		/* set up the 'last' state for the next time around */
259*d44a5ed1SThomas Cort		switch (afterw[-1]) {
260*d44a5ed1SThomas Cort		case '.':
261*d44a5ed1SThomas Cort		case '?':
262*d44a5ed1SThomas Cort		case '!':
263*d44a5ed1SThomas Cort			last_o_was_punct = 1;
264*d44a5ed1SThomas Cort			break;
265*d44a5ed1SThomas Cort		default:
266*d44a5ed1SThomas Cort			last_o_was_punct = 0;
267*d44a5ed1SThomas Cort			break;
268*d44a5ed1SThomas Cort		}
269*d44a5ed1SThomas Cort		last_o_was_space = 0;
270*d44a5ed1SThomas Cort
271*d44a5ed1SThomas Cort		/* ... and do it all again! */
272*d44a5ed1SThomas Cort	}
273*d44a5ed1SThomas Cort
274*d44a5ed1SThomas Cort	/* String ended with a newline.  They really want a line break. */
275*d44a5ed1SThomas Cort	if (last_i_was_nl) {
276*d44a5ed1SThomas Cort		if (getcurx(msg_win) != 0)
277*d44a5ed1SThomas Cort			waddch(msg_win, '\n');
278*d44a5ed1SThomas Cort		last_o_was_punct = 0;
279*d44a5ed1SThomas Cort		last_o_was_space = 1;
280*d44a5ed1SThomas Cort	}
281*d44a5ed1SThomas Cort
282*d44a5ed1SThomas Cortout:
283*d44a5ed1SThomas Cort	wrefresh(msg_win);
284*d44a5ed1SThomas Cort	return ret;
285*d44a5ed1SThomas Cort}
286*d44a5ed1SThomas Cort
287*d44a5ed1SThomas Cortvoid
288*d44a5ed1SThomas Cortmsg_display(msg msg_no, ...)
289*d44a5ed1SThomas Cort{
290*d44a5ed1SThomas Cort	va_list ap;
291*d44a5ed1SThomas Cort
292*d44a5ed1SThomas Cort	msg_clear();
293*d44a5ed1SThomas Cort
294*d44a5ed1SThomas Cort	va_start(ap, msg_no);
295*d44a5ed1SThomas Cort	(void)_msg_vprintf(1, msg_string(msg_no), ap);
296*d44a5ed1SThomas Cort	va_end(ap);
297*d44a5ed1SThomas Cort}
298*d44a5ed1SThomas Cort
299*d44a5ed1SThomas Cortvoid
300*d44a5ed1SThomas Cortmsg_display_add(msg msg_no, ...)
301*d44a5ed1SThomas Cort{
302*d44a5ed1SThomas Cort	va_list ap;
303*d44a5ed1SThomas Cort
304*d44a5ed1SThomas Cort	va_start(ap, msg_no);
305*d44a5ed1SThomas Cort	(void)_msg_vprintf(1, msg_string(msg_no), ap);
306*d44a5ed1SThomas Cort	va_end(ap);
307*d44a5ed1SThomas Cort}
308*d44a5ed1SThomas Cort
309*d44a5ed1SThomas Cortvoid
310*d44a5ed1SThomas Cortmsg_printf(const char *fmt, ...)
311*d44a5ed1SThomas Cort{
312*d44a5ed1SThomas Cort	va_list ap;
313*d44a5ed1SThomas Cort
314*d44a5ed1SThomas Cort	va_start(ap, fmt);
315*d44a5ed1SThomas Cort	(void)_msg_vprintf(1, fmt, ap);
316*d44a5ed1SThomas Cort	va_end(ap);
317*d44a5ed1SThomas Cort}
318*d44a5ed1SThomas Cort
319*d44a5ed1SThomas Cortstatic void
320*d44a5ed1SThomas Cort_msg_vprompt(const char *fmt, int flags, const char *def, char *val,
321*d44a5ed1SThomas Cort    size_t val_buf_len, va_list ap)
322*d44a5ed1SThomas Cort{
323*d44a5ed1SThomas Cort	int ch;
324*d44a5ed1SThomas Cort	int len, pos, npos, off;
325*d44a5ed1SThomas Cort	int first;
326*d44a5ed1SThomas Cort	int txt_y, txt_x;
327*d44a5ed1SThomas Cort	char *ibuf;
328*d44a5ed1SThomas Cort	int maxx;
329*d44a5ed1SThomas Cort
330*d44a5ed1SThomas Cort	if (val == NULL || val_buf_len == 0) {
331*d44a5ed1SThomas Cort		/* No answer wanted */
332*d44a5ed1SThomas Cort		val = NULL;
333*d44a5ed1SThomas Cort		val_buf_len = 1;
334*d44a5ed1SThomas Cort	}
335*d44a5ed1SThomas Cort
336*d44a5ed1SThomas Cort	ibuf = malloc(val_buf_len);
337*d44a5ed1SThomas Cort
338*d44a5ed1SThomas Cort	keypad(msg_win, TRUE);
339*d44a5ed1SThomas Cort	_msg_vprintf(0, fmt, ap);
340*d44a5ed1SThomas Cort	ibuf[0] = 0;
341*d44a5ed1SThomas Cort	if (def != NULL && *def) {
342*d44a5ed1SThomas Cort		if (flags & MSG_PROMPT_HIDE_DFLT)
343*d44a5ed1SThomas Cort			strlcpy(ibuf, def, val_buf_len);
344*d44a5ed1SThomas Cort		else {
345*d44a5ed1SThomas Cort			waddstr(msg_win, " [");
346*d44a5ed1SThomas Cort			waddstr(msg_win, def);
347*d44a5ed1SThomas Cort			waddstr(msg_win, "]");
348*d44a5ed1SThomas Cort		}
349*d44a5ed1SThomas Cort	}
350*d44a5ed1SThomas Cort	waddstr(msg_win, ": ");
351*d44a5ed1SThomas Cort	len = strlen(ibuf);
352*d44a5ed1SThomas Cort	pos = len;
353*d44a5ed1SThomas Cort	getyx(msg_win, txt_y, txt_x);
354*d44a5ed1SThomas Cort	maxx = getmaxx(msg_win) - txt_x - 1;
355*d44a5ed1SThomas Cort	off = 0;
356*d44a5ed1SThomas Cort
357*d44a5ed1SThomas Cort	for (first = 1; ; first = 0) {
358*d44a5ed1SThomas Cort
359*d44a5ed1SThomas Cort		if (flags & MSG_PROMPT_ECHO) {
360*d44a5ed1SThomas Cort			/* shift text right as we near the buffer start */
361*d44a5ed1SThomas Cort			if (pos - off < 4)
362*d44a5ed1SThomas Cort				off = pos - 4;
363*d44a5ed1SThomas Cort			/* keep offset to a minimum if we are at the end */
364*d44a5ed1SThomas Cort			if (pos == len)
365*d44a5ed1SThomas Cort				off = pos - maxx;
366*d44a5ed1SThomas Cort			if (off < 0 || len <= maxx)
367*d44a5ed1SThomas Cort				off = 0;
368*d44a5ed1SThomas Cort			/* shift text left as we near the buffer end */
369*d44a5ed1SThomas Cort			npos = pos + 4;
370*d44a5ed1SThomas Cort			if (npos > len)
371*d44a5ed1SThomas Cort				npos = len;
372*d44a5ed1SThomas Cort			if (npos - off > maxx)
373*d44a5ed1SThomas Cort				off = npos - maxx;
374*d44a5ed1SThomas Cort			/* calc. length to display */
375*d44a5ed1SThomas Cort			npos = len - off;
376*d44a5ed1SThomas Cort			if (npos > maxx)
377*d44a5ed1SThomas Cort				npos = maxx;
378*d44a5ed1SThomas Cort			mvwaddnstr(msg_win, txt_y, txt_x, ibuf + off, npos);
379*d44a5ed1SThomas Cort			wclrtoeol(msg_win);
380*d44a5ed1SThomas Cort			if (off != 0)
381*d44a5ed1SThomas Cort				mvwaddstr(msg_win, txt_y, txt_x, "+");
382*d44a5ed1SThomas Cort			wmove(msg_win, txt_y, txt_x + pos - off);
383*d44a5ed1SThomas Cort			wrefresh(msg_win);
384*d44a5ed1SThomas Cort		}
385*d44a5ed1SThomas Cort
386*d44a5ed1SThomas Cort		ch = wgetch(msg_win);
387*d44a5ed1SThomas Cort		if (ch == '\n')
388*d44a5ed1SThomas Cort			break;
389*d44a5ed1SThomas Cort
390*d44a5ed1SThomas Cort		switch (ch) {
391*d44a5ed1SThomas Cort		case KEY_BACKSPACE:
392*d44a5ed1SThomas Cort		case 'h' & 0x1f: case 0x7f:  /* bs or del - delete left */
393*d44a5ed1SThomas Cort			if (first) {
394*d44a5ed1SThomas Cort				/* delete all of default string */
395*d44a5ed1SThomas Cort				len = pos = 0;
396*d44a5ed1SThomas Cort				break;
397*d44a5ed1SThomas Cort			}
398*d44a5ed1SThomas Cort			if (pos > 0) {
399*d44a5ed1SThomas Cort				memmove(ibuf + pos - 1, ibuf + pos, len - pos);
400*d44a5ed1SThomas Cort				len--;
401*d44a5ed1SThomas Cort				pos--;
402*d44a5ed1SThomas Cort			} else
403*d44a5ed1SThomas Cort				_msg_beep();
404*d44a5ed1SThomas Cort			break;
405*d44a5ed1SThomas Cort		case 'u' & 0x1f:	/* ^U; line kill */
406*d44a5ed1SThomas Cort			/* kill line */
407*d44a5ed1SThomas Cort			len = pos = 0;
408*d44a5ed1SThomas Cort			break;
409*d44a5ed1SThomas Cort		case 'w' & 0x1f:        /* ^W; word kill */
410*d44a5ed1SThomas Cort			/*
411*d44a5ed1SThomas Cort			 * word kill kills the spaces and the 'word'
412*d44a5ed1SThomas Cort			 * (non-spaces) last typed.  the spaces before
413*d44a5ed1SThomas Cort			 * the 'word' aren't killed.
414*d44a5ed1SThomas Cort			 */
415*d44a5ed1SThomas Cort			npos = pos;
416*d44a5ed1SThomas Cort			while (npos > 0 && isspace((unsigned char)ibuf[npos - 1]))
417*d44a5ed1SThomas Cort				npos--;
418*d44a5ed1SThomas Cort			while (npos > 0 && !isspace((unsigned char)ibuf[npos - 1]))
419*d44a5ed1SThomas Cort				npos--;
420*d44a5ed1SThomas Cort			memmove(ibuf + npos, ibuf + pos, len - pos);
421*d44a5ed1SThomas Cort			len -= pos - npos;
422*d44a5ed1SThomas Cort			pos = npos;
423*d44a5ed1SThomas Cort			break;
424*d44a5ed1SThomas Cort		case KEY_LEFT:
425*d44a5ed1SThomas Cort			if (pos > 0)
426*d44a5ed1SThomas Cort				pos--;
427*d44a5ed1SThomas Cort			break;
428*d44a5ed1SThomas Cort		case KEY_RIGHT:
429*d44a5ed1SThomas Cort			if (len == 0 && pos == 0 && def != NULL) {
430*d44a5ed1SThomas Cort				/* restore default! */
431*d44a5ed1SThomas Cort				strlcpy(ibuf, def, val_buf_len);
432*d44a5ed1SThomas Cort				len = pos = strlen(ibuf);
433*d44a5ed1SThomas Cort				break;
434*d44a5ed1SThomas Cort			}
435*d44a5ed1SThomas Cort			if (pos < len)
436*d44a5ed1SThomas Cort				pos++;
437*d44a5ed1SThomas Cort			break;
438*d44a5ed1SThomas Cort		default:
439*d44a5ed1SThomas Cort			if (len < (int)(val_buf_len - 1) && isprint(ch)) {
440*d44a5ed1SThomas Cort				memmove(ibuf + pos + 1, ibuf + pos, len - pos);
441*d44a5ed1SThomas Cort				ibuf[pos++] = ch;
442*d44a5ed1SThomas Cort				len++;
443*d44a5ed1SThomas Cort			} else
444*d44a5ed1SThomas Cort				_msg_beep();
445*d44a5ed1SThomas Cort			break;
446*d44a5ed1SThomas Cort		}
447*d44a5ed1SThomas Cort	}
448*d44a5ed1SThomas Cort
449*d44a5ed1SThomas Cort	if (flags & MSG_PROMPT_ECHO) {
450*d44a5ed1SThomas Cort		mvwaddch(msg_win, txt_y, txt_x + len - off, '\n');
451*d44a5ed1SThomas Cort		last_o_was_punct = 0;
452*d44a5ed1SThomas Cort		last_o_was_space = 1;
453*d44a5ed1SThomas Cort	}
454*d44a5ed1SThomas Cort
455*d44a5ed1SThomas Cort	if (val != NULL) {
456*d44a5ed1SThomas Cort		/* copy the appropriate string to the output */
457*d44a5ed1SThomas Cort		if (len != 0 || flags & MSG_PROMPT_HIDE_DFLT) {
458*d44a5ed1SThomas Cort			ibuf[len] = '\0';
459*d44a5ed1SThomas Cort			strlcpy(val, ibuf, val_buf_len);
460*d44a5ed1SThomas Cort		} else if (def != NULL && val != def) {
461*d44a5ed1SThomas Cort			strlcpy(val, def, val_buf_len);
462*d44a5ed1SThomas Cort		}
463*d44a5ed1SThomas Cort	}
464*d44a5ed1SThomas Cort	free(ibuf);
465*d44a5ed1SThomas Cort}
466*d44a5ed1SThomas Cort
467*d44a5ed1SThomas Cortvoid
468*d44a5ed1SThomas Cortmsg_prompt(msg msg_no, const char *def, char *val, size_t val_buf_len, ...)
469*d44a5ed1SThomas Cort{
470*d44a5ed1SThomas Cort	va_list ap;
471*d44a5ed1SThomas Cort
472*d44a5ed1SThomas Cort	msg_clear();
473*d44a5ed1SThomas Cort
474*d44a5ed1SThomas Cort	va_start(ap, val_buf_len);
475*d44a5ed1SThomas Cort	_msg_vprompt(msg_string(msg_no), MSG_PROMPT_ECHO,
476*d44a5ed1SThomas Cort		def, val, val_buf_len, ap);
477*d44a5ed1SThomas Cort	va_end(ap);
478*d44a5ed1SThomas Cort}
479*d44a5ed1SThomas Cort
480*d44a5ed1SThomas Cortvoid
481*d44a5ed1SThomas Cortmsg_prompt_win(msg msg_no, int x, int y, int w, int h,
482*d44a5ed1SThomas Cort	const char *def, char *val, size_t val_buf_len, ...)
483*d44a5ed1SThomas Cort{
484*d44a5ed1SThomas Cort	va_list ap;
485*d44a5ed1SThomas Cort	WINDOW *win;
486*d44a5ed1SThomas Cort	WINDOW *svmsg = NULL, *sv_win = NULL; /* XXX -Wuninitialized [many] */
487*d44a5ed1SThomas Cort	int maxx, maxy;
488*d44a5ed1SThomas Cort	int msg_flags = MSG_PROMPT_ECHO | MSG_PROMPT_HIDE_DFLT;
489*d44a5ed1SThomas Cort
490*d44a5ed1SThomas Cort	maxx = getmaxx(msg_win);
491*d44a5ed1SThomas Cort	maxy = getmaxy(msg_win);
492*d44a5ed1SThomas Cort	if (w == 0) {
493*d44a5ed1SThomas Cort		va_start(ap, val_buf_len);
494*d44a5ed1SThomas Cort		w = vsnprintf(NULL, 0, msg_string(msg_no), ap);
495*d44a5ed1SThomas Cort		va_end(ap);
496*d44a5ed1SThomas Cort		if (def != NULL && *def != 0 && w + (int)val_buf_len * 2 < maxx) {
497*d44a5ed1SThomas Cort			w += 2 + strlen(def) + 1;
498*d44a5ed1SThomas Cort			msg_flags &= ~MSG_PROMPT_HIDE_DFLT;
499*d44a5ed1SThomas Cort		}
500*d44a5ed1SThomas Cort		w += 1 + 2 + val_buf_len + 1;
501*d44a5ed1SThomas Cort		if (w > maxx) {
502*d44a5ed1SThomas Cort			if (!(msg_flags & MSG_PROMPT_HIDE_DFLT)) {
503*d44a5ed1SThomas Cort				w -= 2 + strlen(def) + 1;
504*d44a5ed1SThomas Cort				msg_flags |= MSG_PROMPT_HIDE_DFLT;
505*d44a5ed1SThomas Cort			}
506*d44a5ed1SThomas Cort			w = maxx;
507*d44a5ed1SThomas Cort		}
508*d44a5ed1SThomas Cort	}
509*d44a5ed1SThomas Cort
510*d44a5ed1SThomas Cort	if (x == -1)
511*d44a5ed1SThomas Cort		x = (maxx - w) / 2 + 1;
512*d44a5ed1SThomas Cort	if (h < 3)
513*d44a5ed1SThomas Cort		h = 3;
514*d44a5ed1SThomas Cort	if (y < 3)
515*d44a5ed1SThomas Cort		y = (maxy - h) / 2;
516*d44a5ed1SThomas Cort	if (y + h > maxy)
517*d44a5ed1SThomas Cort		y = maxy - h;
518*d44a5ed1SThomas Cort
519*d44a5ed1SThomas Cort	win = subwin(msg_win, h, w, y, x);
520*d44a5ed1SThomas Cort	if (win == NULL)
521*d44a5ed1SThomas Cort		wprintw(msg_win, "msg_prompt_win: "
522*d44a5ed1SThomas Cort			"newwin(%d, %d, %d, %d) failed\n",
523*d44a5ed1SThomas Cort			h, w, y, x);
524*d44a5ed1SThomas Cort	else {
525*d44a5ed1SThomas Cort		/*
526*d44a5ed1SThomas Cort		 * Save screen contents from under our window
527*d44a5ed1SThomas Cort		 * Due to a mis-feature of NetBSD curses, curscr contains
528*d44a5ed1SThomas Cort		 * the data processed by doupdate() not that by wnoutrefresh().
529*d44a5ed1SThomas Cort		 * We must call doupdate() here to ensure we save the correct
530*d44a5ed1SThomas Cort		 * data.  See PR 26660
531*d44a5ed1SThomas Cort		 */
532*d44a5ed1SThomas Cort		doupdate();
533*d44a5ed1SThomas Cort		sv_win = dupwin(win);
534*d44a5ed1SThomas Cort		if (sv_win)
535*d44a5ed1SThomas Cort			overwrite(curscr, sv_win);
536*d44a5ed1SThomas Cort		wbkgd(win, getbkgd(msg_win));
537*d44a5ed1SThomas Cort		wattrset(win, getattrs(msg_win));
538*d44a5ed1SThomas Cort		box(win, 0, 0);
539*d44a5ed1SThomas Cort		wrefresh(win);
540*d44a5ed1SThomas Cort
541*d44a5ed1SThomas Cort		/* Change message window to be our little box */
542*d44a5ed1SThomas Cort		svmsg = msg_window(subwin(msg_win, h - 2, w - 2, y + 1, x + 1));
543*d44a5ed1SThomas Cort		wbkgd(msg_win, getbkgd(win));
544*d44a5ed1SThomas Cort		wattrset(msg_win, getattrs(win));
545*d44a5ed1SThomas Cort
546*d44a5ed1SThomas Cort		msg_clear();
547*d44a5ed1SThomas Cort	}
548*d44a5ed1SThomas Cort
549*d44a5ed1SThomas Cort	va_start(ap, val_buf_len);
550*d44a5ed1SThomas Cort	_msg_vprompt(msg_string(msg_no), msg_flags, def, val, val_buf_len, ap);
551*d44a5ed1SThomas Cort	va_end(ap);
552*d44a5ed1SThomas Cort
553*d44a5ed1SThomas Cort	if (win != NULL) {
554*d44a5ed1SThomas Cort		wclear(win);
555*d44a5ed1SThomas Cort		if (sv_win) {
556*d44a5ed1SThomas Cort			/* Restore original screen contents */
557*d44a5ed1SThomas Cort			overwrite(sv_win, win);
558*d44a5ed1SThomas Cort			delwin(sv_win);
559*d44a5ed1SThomas Cort		}
560*d44a5ed1SThomas Cort		wnoutrefresh(win);
561*d44a5ed1SThomas Cort		/* Restore normal message window */
562*d44a5ed1SThomas Cort		delwin(msg_window(svmsg));
563*d44a5ed1SThomas Cort		delwin(win);
564*d44a5ed1SThomas Cort	}
565*d44a5ed1SThomas Cort}
566*d44a5ed1SThomas Cort
567*d44a5ed1SThomas Cortvoid
568*d44a5ed1SThomas Cortmsg_prompt_add(msg msg_no, const char *def, char *val, size_t val_buf_len, ...)
569*d44a5ed1SThomas Cort{
570*d44a5ed1SThomas Cort	va_list ap;
571*d44a5ed1SThomas Cort
572*d44a5ed1SThomas Cort	va_start(ap, val_buf_len);
573*d44a5ed1SThomas Cort	_msg_vprompt(msg_string(msg_no), MSG_PROMPT_ECHO, def, val, val_buf_len, ap);
574*d44a5ed1SThomas Cort	va_end(ap);
575*d44a5ed1SThomas Cort}
576*d44a5ed1SThomas Cort
577*d44a5ed1SThomas Cortvoid
578*d44a5ed1SThomas Cortmsg_prompt_noecho(msg msg_no, const char *def, char *val, size_t val_buf_len, ...)
579*d44a5ed1SThomas Cort{
580*d44a5ed1SThomas Cort	va_list ap;
581*d44a5ed1SThomas Cort
582*d44a5ed1SThomas Cort	msg_clear();
583*d44a5ed1SThomas Cort
584*d44a5ed1SThomas Cort	va_start(ap, val_buf_len);
585*d44a5ed1SThomas Cort	_msg_vprompt(msg_string(msg_no), 0, def, val, val_buf_len, ap);
586*d44a5ed1SThomas Cort	va_end(ap);
587*d44a5ed1SThomas Cort}
588*d44a5ed1SThomas Cort
589*d44a5ed1SThomas Cortvoid
590*d44a5ed1SThomas Cortmsg_table_add(msg msg_no, ...)
591*d44a5ed1SThomas Cort{
592*d44a5ed1SThomas Cort	va_list ap;
593*d44a5ed1SThomas Cort
594*d44a5ed1SThomas Cort	va_start(ap, msg_no);
595*d44a5ed1SThomas Cort	(void)_msg_vprintf(0, msg_string(msg_no), ap);
596*d44a5ed1SThomas Cort	va_end(ap);
597*d44a5ed1SThomas Cort}
598*d44a5ed1SThomas Cort
599*d44a5ed1SThomas Cortint
600*d44a5ed1SThomas Cortmsg_row(void)
601*d44a5ed1SThomas Cort{
602*d44a5ed1SThomas Cort
603*d44a5ed1SThomas Cort	return getcury(msg_win) + getbegy(msg_win);
604*d44a5ed1SThomas Cort}
605