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 39static WINDOW *msg_win = NULL; 40static char *cbuffer; 41static size_t cbuffersize; 42 43static int last_i_was_nl, last_i_was_space; 44static int last_o_was_punct, last_o_was_space; 45 46static void _msg_beep(void); 47static int _msg_vprintf(int auto_fill, const char *fmt, va_list ap); 48static 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 53static void 54_msg_beep(void) 55{ 56 fprintf(stderr, "\a"); 57} 58 59WINDOW * 60msg_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 90const 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 100void 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 108void msg_standout(void) 109{ 110 wstandout(msg_win); 111} 112 113void msg_standend(void) 114{ 115 wstandend(msg_win); 116} 117 118static 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 239out: 240 wrefresh (msg_win); 241 return ret; 242} 243 244void 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 255void 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 264static 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 276static 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 347void 348msg_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 359void 360msg_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 419void 420msg_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 429void 430msg_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 441void 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