Home | History | Annotate | Line # | Download | only in msgc
msg_sys.def revision 1.20
      1 /*	$NetBSD: msg_sys.def,v 1.20 2003/06/10 17:24:17 dsl Exp $	*/
      2 
      3 /*
      4  * Copyright 1997 Piermont Information Systems Inc.
      5  * All rights reserved.
      6  *
      7  * Written by Philip A. Nelson for Piermont Information Systems Inc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *      This product includes software develooped for the NetBSD Project by
     20  *      Piermont Information Systems Inc.
     21  * 4. The name of Piermont Information Systems Inc. may not be used to endorse
     22  *    or promote products derived from this software without specific prior
     23  *    written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
     26  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
     29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     35  * THE POSSIBILITY OF SUCH DAMAGE.
     36  *
     37  */
     38 
     39 static WINDOW *msg_win = NULL;
     40 static char *cbuffer;
     41 static size_t cbuffersize;
     42 
     43 static int last_i_was_nl, last_i_was_space;
     44 static int last_o_was_punct, last_o_was_space;
     45 
     46 static void	_msg_beep(void);
     47 static int	_msg_vprintf(int auto_fill, const char *fmt, va_list ap);
     48 static void	_msg_vprompt(const char *msg, int do_echo, const char *def,
     49 		    char *val, size_t max_chars, va_list ap);
     50 
     51 /* Routines */
     52 
     53 static void
     54 _msg_beep(void)
     55 {
     56 	fprintf(stderr, "\a");
     57 }
     58 
     59 WINDOW *
     60 msg_window(WINDOW *window)
     61 {
     62 	size_t ncbuffersize;
     63 	char *ncbuffer;
     64 	WINDOW *old;
     65 
     66 	old = msg_win;
     67 	if (!window)
     68 		return old;
     69 	msg_win = window;
     70 
     71 	ncbuffersize = getmaxx(window) * getmaxy(window) + 1;
     72 	while (ncbuffersize > cbuffersize) {
     73 		ncbuffer = malloc(ncbuffersize);
     74 		if (ncbuffer == NULL) {
     75 			/* we might get truncated messages... */
     76 			ncbuffersize <<= 1;
     77 			continue;
     78 		}
     79 		if (cbuffer != NULL)
     80 			free(cbuffer);
     81 		cbuffer = ncbuffer;
     82 		cbuffersize = ncbuffersize;
     83 		break;
     84 	}
     85 	last_o_was_punct = 0;
     86 	last_o_was_space = 1;
     87 	return old;
     88 }
     89 
     90 const char *msg_string (msg msg_no)
     91 {
     92 	int m = (intptr_t)msg_no;
     93 
     94 	if (m > sizeof msg_list / sizeof msg_list[0])
     95 		/* guess that we were passed a text string */
     96 		return msg_no;
     97 	return msg_list[m];
     98 }
     99 
    100 void msg_clear(void)
    101 {
    102 	wclear (msg_win);
    103 	wrefresh (msg_win);
    104 	last_o_was_punct = 0;
    105 	last_o_was_space = 1;
    106 }
    107 
    108 void msg_standout(void)
    109 {
    110 	wstandout(msg_win);
    111 }
    112 
    113 void msg_standend(void)
    114 {
    115 	wstandend(msg_win);
    116 }
    117 
    118 static int
    119 _msg_vprintf(int auto_fill, const char *fmt, va_list ap)
    120 {
    121 	const char *wstart, *afterw;
    122 	int wordlen, nspaces;
    123 	int ret;
    124 
    125 	ret = vsnprintf (cbuffer, cbuffersize, fmt, ap);
    126 
    127 	if (!auto_fill) {
    128 		waddstr(msg_win, cbuffer);
    129 
    130 		/*
    131 		 * nothing is perfect if they flow text after a table,
    132 		 * but this may be decent.
    133 		 */
    134 		last_i_was_nl = last_i_was_space = 1;
    135 		last_o_was_punct = 0;
    136 		last_o_was_space = 1;
    137 		goto out;
    138 	}
    139 
    140 	for (wstart = afterw = cbuffer; *wstart; wstart = afterw) {
    141 
    142 		/* eat one space, or a whole word of non-spaces */
    143 		if (isspace(*afterw))
    144 			afterw++;
    145 		else
    146 			while (*afterw && !isspace(*afterw))
    147 				afterw++;
    148 
    149 		/* this is an nl: special formatting necessary */
    150 		if (*wstart == '\n') {
    151 			if (last_i_was_nl || last_i_was_space) {
    152 
    153 				if (getcurx(msg_win) != 0)
    154 					waddch(msg_win, '\n');
    155 				if (last_i_was_nl) {
    156 					/* last was an nl: paragraph break */
    157 					waddch(msg_win, '\n');
    158 				} else {
    159 					/* last was space: line break */
    160 				}
    161 				last_o_was_punct = 0;
    162 				last_o_was_space = 1;
    163 			} else {
    164 				/* last_o_was_punct unchanged */
    165 				/* last_o_was_space unchanged */
    166 			}
    167 			last_i_was_space = 1;
    168 			last_i_was_nl = 1;
    169 			continue;
    170 		}
    171 
    172 		/* this is a tab: special formatting necessary. */
    173 		if (*wstart == '\t') {
    174 			if (last_i_was_nl) {
    175 				/* last was an nl: list indent */
    176 				if (getcurx(msg_win) != 0)
    177 					waddch(msg_win, '\n');
    178 			} else {
    179 				/* last was not an nl: columns */
    180 			}
    181 			waddch(msg_win, '\t');
    182 			last_i_was_nl = 0;
    183 			last_i_was_space = 1;
    184 			last_o_was_punct = 0;
    185 			last_o_was_space = 1;
    186 			continue;
    187 		}
    188 
    189 		/* this is a space: ignore it but set flags */
    190 		last_i_was_nl = 0;	/* all newlines handled above */
    191 		last_i_was_space = isspace(*wstart);
    192 		if (last_i_was_space)
    193 			continue;
    194 
    195 		/*
    196 		 * we have a real "word," i.e. a sequence of non-space
    197 		 * characters.  wstart is now the start of the word,
    198 		 * afterw is the next character after the end.
    199 		 */
    200 		wordlen = afterw - wstart;
    201 		nspaces = last_o_was_space ? 0 : (last_o_was_punct ? 2 : 1);
    202 		if ((getcurx(msg_win) + nspaces + wordlen) >=
    203 		      getmaxx(msg_win) &&
    204 		    wordlen < (getmaxx(msg_win) / 3)) {
    205 			/* wrap the line */
    206 			waddch(msg_win, '\n');
    207 			nspaces = 0;
    208 		}
    209 
    210 		/* output the word, preceded by spaces if necessary */
    211 		while (nspaces-- > 0)
    212 			waddch(msg_win, ' ');
    213 		waddbytes(msg_win, wstart, wordlen);
    214 
    215 		/* set up the 'last' state for the next time around */
    216 		switch (afterw[-1]) {
    217 		case '.':
    218 		case '?':
    219 		case '!':
    220 			last_o_was_punct = 1;
    221 			break;
    222 		default:
    223 			last_o_was_punct = 0;
    224 			break;
    225 		}
    226 		last_o_was_space = 0;
    227 
    228 		/* ... and do it all again! */
    229 	}
    230 
    231 	/* String ended with a newline.  They really want a line break. */
    232 	if (last_i_was_nl) {
    233 		if (getcurx(msg_win) != 0)
    234 			waddch(msg_win, '\n');
    235 		last_o_was_punct = 0;
    236 		last_o_was_space = 1;
    237 	}
    238 
    239 out:
    240 	wrefresh (msg_win);
    241 	return ret;
    242 }
    243 
    244 void msg_display(msg msg_no, ...)
    245 {
    246 	va_list ap;
    247 
    248 	msg_clear();
    249 
    250 	va_start(ap, msg_no);
    251 	(void)_msg_vprintf(1, msg_string(msg_no), ap);
    252 	va_end(ap);
    253 }
    254 
    255 void msg_display_add(msg msg_no, ...)
    256 {
    257 	va_list ap;
    258 
    259 	va_start (ap, msg_no);
    260 	(void)_msg_vprintf(1, msg_string(msg_no), ap);
    261 	va_end (ap);
    262 }
    263 
    264 static void
    265 _erase_ch(void)
    266 {
    267 	int y, x;
    268 
    269 	getyx(msg_win, y, x);
    270 	x--;
    271 	wmove(msg_win, y, x);
    272 	waddch(msg_win, ' ');
    273 	wmove(msg_win, y, x);
    274 }
    275 
    276 static void
    277 _msg_vprompt(const char *msg, int do_echo, const char *def, char *val,
    278     size_t max_chars, va_list ap)
    279 {
    280 	int ch;
    281 	int count = 0;
    282 	char *ibuf = alloca(max_chars);
    283 
    284 	_msg_vprintf(0, msg, ap);
    285 	if (def != NULL && *def) {
    286 		waddstr (msg_win, " [");
    287 		waddstr (msg_win, def);
    288 		waddstr (msg_win, "]");
    289 	}
    290 	waddstr (msg_win, ": ");
    291 	wrefresh (msg_win);
    292 
    293 	while ((ch = wgetch(msg_win)) != '\n') {
    294 		if (ch == 0x08 || ch == 0x7f) {  /* bs or del */
    295 			if (count > 0) {
    296 				count--;
    297 				if (do_echo)
    298 					_erase_ch();
    299 			} else
    300 				_msg_beep();
    301 		} else if (ch == 0x15) {	/* ^U; line kill */
    302 			while (count > 0) {
    303 				count--;
    304 				if (do_echo)
    305 					_erase_ch();
    306 			}
    307 		} else if (ch == 0x17) {        /* ^W; word kill */
    308 			/*
    309 			 * word kill kills the spaces and the 'word'
    310 			 * (non-spaces) last typed.  the spaces before
    311 			 * the 'word' aren't killed.
    312 			 */
    313 			while (count > 0 && isspace(ibuf[count - 1])) {
    314 				count--;
    315 				if (do_echo)
    316 					_erase_ch();
    317 			}
    318 			while (count > 0 && !isspace(ibuf[count - 1])) {
    319 				count--;
    320 				if (do_echo)
    321 					_erase_ch();
    322 			}
    323 		} else if (count < (max_chars - 1) && isprint(ch)) {
    324 			if (do_echo)
    325 				waddch (msg_win, ch);
    326 			ibuf[count++] = ch;
    327 		} else
    328 			_msg_beep();
    329 		if (do_echo)
    330 			wrefresh(msg_win);
    331 	}
    332 	if (do_echo) {
    333 		waddch(msg_win, '\n');
    334 		last_o_was_punct = 0;
    335 		last_o_was_space = 1;
    336 	}
    337 
    338 	/* copy the appropriate string to the output */
    339 	if (count != 0) {
    340 		ibuf[count] = '\0';
    341 		strcpy(val, ibuf);		/* size known to be OK */
    342 	} else if (def != NULL && val != def) {
    343 		strlcpy(val, def, max_chars);
    344 	}
    345 }
    346 
    347 void
    348 msg_prompt(msg msg_no, const char *def, char *val, size_t max_chars, ...)
    349 {
    350 	va_list ap;
    351 
    352 	msg_clear();
    353 
    354 	va_start (ap, max_chars);
    355 	_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
    356 	va_end (ap);
    357 }
    358 
    359 void
    360 msg_prompt_win(msg msg_no, int x, int y, int w, int h,
    361 	const char *def, char *val, size_t max_chars, ...)
    362 {
    363 	va_list ap;
    364 	WINDOW *win, *svwin;
    365 	int maxx, maxy;
    366 
    367 	maxx = getmaxx(stdscr);
    368 	maxy = getmaxy(stdscr);
    369 	if (w == 0) {
    370 		va_start(ap, max_chars);
    371 		w = vsnprintf(NULL, 0, msg_string(msg_no), ap);
    372 		va_end(ap);
    373 		if (def != NULL && *def != 0)
    374 			w += 2 + strlen(def);
    375 		w += 1 + 2 + max_chars + 1;
    376 		if (w > maxx)
    377 			w = maxx;
    378 	}
    379 
    380 	if (x == -1)
    381 		x = (maxx - w) / 2;
    382 	if (h < 3)
    383 		h = 3;
    384 	if (y < 3)
    385 		y = (maxy - h) / 2;
    386 	if (y + h > maxy)
    387 		y = maxy - h;
    388 
    389 	win = newwin(h, w, y, x);
    390 	if (win == NULL)
    391 		wprintw(msg_win, "msg_prompt_win: "
    392 			"newwin(%d, %d, %d, %d) failed\n",
    393 			h, w, y, x);
    394 	else {
    395 		wbkgd(win, getbkgd(msg_win));
    396 		wattrset(win, getattrs(msg_win));
    397 		box(win, 0, 0);
    398 		wrefresh(win);
    399 
    400 		svwin = msg_window(derwin(win, -1, -1, 1, 1));
    401 		wbkgd(msg_win, getbkgd(win));
    402 		wattrset(msg_win, getattrs(win));
    403 
    404 		msg_clear();
    405 	}
    406 
    407 	va_start(ap, max_chars);
    408 	_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
    409 	va_end(ap);
    410 
    411 	if (win != NULL) {
    412 		wclear(win);
    413 		wrefresh(win);
    414 		delwin(msg_window(svwin));
    415 		delwin(win);
    416 	}
    417 }
    418 
    419 void
    420 msg_prompt_add(msg msg_no, const char *def, char *val, size_t max_chars, ...)
    421 {
    422 	va_list ap;
    423 
    424 	va_start (ap, max_chars);
    425 	_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
    426 	va_end(ap);
    427 }
    428 
    429 void
    430 msg_prompt_noecho(msg msg_no, const char *def, char *val, size_t max_chars, ...)
    431 {
    432 	va_list ap;
    433 
    434 	msg_clear();
    435 
    436 	va_start (ap, max_chars);
    437 	_msg_vprompt(msg_string(msg_no), 0, def, val, max_chars, ap);
    438 	va_end (ap);
    439 }
    440 
    441 void msg_table_add(msg msg_no, ...)
    442 {
    443 	va_list ap;
    444 
    445 	va_start (ap, msg_no);
    446 	(void)_msg_vprintf(0, msg_string(msg_no), ap);
    447 	va_end (ap);
    448 }
    449 
    450