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