1/* SCCS Id: @(#)topl.c 3.4 1996/10/24 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7#ifdef TTY_GRAPHICS 8 9#include "tcap.h" 10#include "wintty.h" 11#include <ctype.h> 12 13#ifndef C /* this matches src/cmd.c */ 14#define C(c) (0x1f & (c)) 15#endif 16 17STATIC_DCL void FDECL(redotoplin, (const char*)); 18STATIC_DCL void FDECL(topl_putsym, (CHAR_P)); 19STATIC_DCL void NDECL(remember_topl); 20STATIC_DCL void FDECL(removetopl, (int)); 21 22#ifdef OVLB 23 24int 25tty_doprev_message() 26{ 27 register struct WinDesc *cw = wins[WIN_MESSAGE]; 28 29 winid prevmsg_win; 30 int i; 31 if ((iflags.prevmsg_window != 's') && !ttyDisplay->inread) { /* not single */ 32 if(iflags.prevmsg_window == 'f') { /* full */ 33 prevmsg_win = create_nhwindow(NHW_MENU); 34 putstr(prevmsg_win, 0, "Message History"); 35 putstr(prevmsg_win, 0, ""); 36 cw->maxcol = cw->maxrow; 37 i = cw->maxcol; 38 do { 39 if(cw->data[i] && strcmp(cw->data[i], "") ) 40 putstr(prevmsg_win, 0, cw->data[i]); 41 i = (i + 1) % cw->rows; 42 } while (i != cw->maxcol); 43 putstr(prevmsg_win, 0, toplines); 44 display_nhwindow(prevmsg_win, TRUE); 45 destroy_nhwindow(prevmsg_win); 46 } else if (iflags.prevmsg_window == 'c') { /* combination */ 47 do { 48 morc = 0; 49 if (cw->maxcol == cw->maxrow) { 50 ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */ 51 redotoplin(toplines); 52 cw->maxcol--; 53 if (cw->maxcol < 0) cw->maxcol = cw->rows-1; 54 if (!cw->data[cw->maxcol]) 55 cw->maxcol = cw->maxrow; 56 } else if (cw->maxcol == (cw->maxrow - 1)){ 57 ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */ 58 redotoplin(cw->data[cw->maxcol]); 59 cw->maxcol--; 60 if (cw->maxcol < 0) cw->maxcol = cw->rows-1; 61 if (!cw->data[cw->maxcol]) 62 cw->maxcol = cw->maxrow; 63 } else { 64 prevmsg_win = create_nhwindow(NHW_MENU); 65 putstr(prevmsg_win, 0, "Message History"); 66 putstr(prevmsg_win, 0, ""); 67 cw->maxcol = cw->maxrow; 68 i = cw->maxcol; 69 do { 70 if(cw->data[i] && strcmp(cw->data[i], "") ) 71 putstr(prevmsg_win, 0, cw->data[i]); 72 i = (i + 1) % cw->rows; 73 } while (i != cw->maxcol); 74 putstr(prevmsg_win, 0, toplines); 75 display_nhwindow(prevmsg_win, TRUE); 76 destroy_nhwindow(prevmsg_win); 77 } 78 79 } while (morc == C('p')); 80 ttyDisplay->dismiss_more = 0; 81 } else { /* reversed */ 82 morc = 0; 83 prevmsg_win = create_nhwindow(NHW_MENU); 84 putstr(prevmsg_win, 0, "Message History"); 85 putstr(prevmsg_win, 0, ""); 86 putstr(prevmsg_win, 0, toplines); 87 cw->maxcol=cw->maxrow-1; 88 if(cw->maxcol < 0) cw->maxcol = cw->rows-1; 89 do { 90 putstr(prevmsg_win, 0, cw->data[cw->maxcol]); 91 cw->maxcol--; 92 if (cw->maxcol < 0) cw->maxcol = cw->rows-1; 93 if (!cw->data[cw->maxcol]) 94 cw->maxcol = cw->maxrow; 95 } while (cw->maxcol != cw->maxrow); 96 97 display_nhwindow(prevmsg_win, TRUE); 98 destroy_nhwindow(prevmsg_win); 99 cw->maxcol = cw->maxrow; 100 ttyDisplay->dismiss_more = 0; 101 } 102 } else if(iflags.prevmsg_window == 's') { /* single */ 103 ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */ 104 do { 105 morc = 0; 106 if (cw->maxcol == cw->maxrow) 107 redotoplin(toplines); 108 else if (cw->data[cw->maxcol]) 109 redotoplin(cw->data[cw->maxcol]); 110 cw->maxcol--; 111 if (cw->maxcol < 0) cw->maxcol = cw->rows-1; 112 if (!cw->data[cw->maxcol]) 113 cw->maxcol = cw->maxrow; 114 } while (morc == C('p')); 115 ttyDisplay->dismiss_more = 0; 116 } 117 return 0; 118} 119 120#endif /* OVLB */ 121#ifdef OVL1 122 123STATIC_OVL void 124redotoplin(str) 125 const char *str; 126{ 127 int otoplin = ttyDisplay->toplin; 128 home(); 129 if(*str & 0x80) { 130 /* kludge for the / command, the only time we ever want a */ 131 /* graphics character on the top line */ 132 g_putch((int)*str++); 133 ttyDisplay->curx++; 134 } 135 end_glyphout(); /* in case message printed during graphics output */ 136 putsyms(str); 137 cl_end(); 138 ttyDisplay->toplin = 1; 139 if(ttyDisplay->cury && otoplin != 3) 140 more(); 141} 142 143STATIC_OVL void 144remember_topl() 145{ 146 register struct WinDesc *cw = wins[WIN_MESSAGE]; 147 int idx = cw->maxrow; 148 unsigned len = strlen(toplines) + 1; 149 150 if (len > (unsigned)cw->datlen[idx]) { 151 if (cw->data[idx]) free(cw->data[idx]); 152 len += (8 - (len & 7)); /* pad up to next multiple of 8 */ 153 cw->data[idx] = (char *)alloc(len); 154 cw->datlen[idx] = (short)len; 155 } 156 Strcpy(cw->data[idx], toplines); 157 cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; 158} 159 160void 161addtopl(s) 162const char *s; 163{ 164 register struct WinDesc *cw = wins[WIN_MESSAGE]; 165 166 tty_curs(BASE_WINDOW,cw->curx+1,cw->cury); 167 putsyms(s); 168 cl_end(); 169 ttyDisplay->toplin = 1; 170} 171 172#endif /* OVL1 */ 173#ifdef OVL2 174 175void 176more() 177{ 178 struct WinDesc *cw = wins[WIN_MESSAGE]; 179 180 /* avoid recursion -- only happens from interrupts */ 181 if(ttyDisplay->inmore++) 182 return; 183 184 if(ttyDisplay->toplin) { 185 tty_curs(BASE_WINDOW, cw->curx+1, cw->cury); 186 if(cw->curx >= CO - 8) topl_putsym('\n'); 187 } 188 189 if(flags.standout) 190 standoutbeg(); 191 putsyms(defmorestr); 192 if(flags.standout) 193 standoutend(); 194 195 xwaitforspace("\033 "); 196 197 if(morc == '\033') 198 cw->flags |= WIN_STOP; 199 200 if(ttyDisplay->toplin && cw->cury) { 201 docorner(1, cw->cury+1); 202 cw->curx = cw->cury = 0; 203 home(); 204 } else if(morc == '\033') { 205 cw->curx = cw->cury = 0; 206 home(); 207 cl_end(); 208 } 209 ttyDisplay->toplin = 0; 210 ttyDisplay->inmore = 0; 211} 212 213void 214update_topl(bp) 215 register const char *bp; 216{ 217 register char *tl, *otl; 218 register int n0; 219 int notdied = 1; 220 struct WinDesc *cw = wins[WIN_MESSAGE]; 221 222 /* If there is room on the line, print message on same line */ 223 /* But messages like "You die..." deserve their own line */ 224 n0 = strlen(bp); 225 if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) && 226 cw->cury == 0 && 227 n0 + (int)strlen(toplines) + 3 < CO-8 && /* room for --More-- */ 228 (notdied = strncmp(bp, "You die", 7))) { 229 Strcat(toplines, " "); 230 Strcat(toplines, bp); 231 cw->curx += 2; 232 if(!(cw->flags & WIN_STOP)) 233 addtopl(bp); 234 return; 235 } else if (!(cw->flags & WIN_STOP)) { 236 if(ttyDisplay->toplin == 1) more(); 237 else if(cw->cury) { /* for when flags.toplin == 2 && cury > 1 */ 238 docorner(1, cw->cury+1); /* reset cury = 0 if redraw screen */ 239 cw->curx = cw->cury = 0;/* from home--cls() & docorner(1,n) */ 240 } 241 } 242 remember_topl(); 243 (void) strncpy(toplines, bp, TBUFSZ); 244 toplines[TBUFSZ - 1] = 0; 245 246 for(tl = toplines; n0 >= CO; ){ 247 otl = tl; 248 for(tl+=CO-1; tl != otl && !isspace(*tl); --tl) ; 249 if(tl == otl) { 250 /* Eek! A huge token. Try splitting after it. */ 251 tl = index(otl, ' '); 252 if (!tl) break; /* No choice but to spit it out whole. */ 253 } 254 *tl++ = '\n'; 255 n0 = strlen(tl); 256 } 257 if(!notdied) cw->flags &= ~WIN_STOP; 258 if(!(cw->flags & WIN_STOP)) redotoplin(toplines); 259} 260 261STATIC_OVL 262void 263topl_putsym(c) 264 char c; 265{ 266 register struct WinDesc *cw = wins[WIN_MESSAGE]; 267 268 if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant"); 269 270 switch(c) { 271 case '\b': 272 if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0) 273 tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1); 274 backsp(); 275 ttyDisplay->curx--; 276 cw->curx = ttyDisplay->curx; 277 return; 278 case '\n': 279 cl_end(); 280 ttyDisplay->curx = 0; 281 ttyDisplay->cury++; 282 cw->cury = ttyDisplay->cury; 283#ifdef WIN32CON 284 (void) putchar(c); 285#endif 286 break; 287 default: 288 if(ttyDisplay->curx == CO-1) 289 topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */ 290#ifdef WIN32CON 291 (void) putchar(c); 292#endif 293 ttyDisplay->curx++; 294 } 295 cw->curx = ttyDisplay->curx; 296 if(cw->curx == 0) cl_end(); 297#ifndef WIN32CON 298 (void) putchar(c); 299#endif 300} 301 302void 303putsyms(str) 304 const char *str; 305{ 306 while(*str) 307 topl_putsym(*str++); 308} 309 310STATIC_OVL void 311removetopl(n) 312register int n; 313{ 314 /* assume addtopl() has been done, so ttyDisplay->toplin is already set */ 315 while (n-- > 0) putsyms("\b \b"); 316} 317 318extern char erase_char; /* from xxxtty.c; don't need kill_char */ 319 320char 321tty_yn_function(query,resp, def) 322const char *query,*resp; 323char def; 324/* 325 * Generic yes/no function. 'def' is the default (returned by space or 326 * return; 'esc' returns 'q', or 'n', or the default, depending on 327 * what's in the string. The 'query' string is printed before the user 328 * is asked about the string. 329 * If resp is NULL, any single character is accepted and returned. 330 * If not-NULL, only characters in it are allowed (exceptions: the 331 * quitchars are always allowed, and if it contains '#' then digits 332 * are allowed); if it includes an <esc>, anything beyond that won't 333 * be shown in the prompt to the user but will be acceptable as input. 334 */ 335{ 336 register char q; 337 char rtmp[40]; 338 boolean digit_ok, allow_num; 339 struct WinDesc *cw = wins[WIN_MESSAGE]; 340 boolean doprev = 0; 341 char prompt[QBUFSZ]; 342 343 if(ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); 344 cw->flags &= ~WIN_STOP; 345 ttyDisplay->toplin = 3; /* special prompt state */ 346 ttyDisplay->inread++; 347 if (resp) { 348 char *rb, respbuf[QBUFSZ]; 349 350 allow_num = (index(resp, '#') != 0); 351 Strcpy(respbuf, resp); 352 /* any acceptable responses that follow <esc> aren't displayed */ 353 if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; 354 Sprintf(prompt, "%s [%s] ", query, respbuf); 355 if (def) Sprintf(eos(prompt), "(%c) ", def); 356 pline("%s", prompt); 357 } else { 358 pline("%s ", query); 359 q = readchar(); 360 goto clean_up; 361 } 362 363 do { /* loop until we get valid input */ 364 q = lowc(readchar()); 365 if (q == '\020') { /* ctrl-P */ 366 if (iflags.prevmsg_window != 's') { 367 int sav = ttyDisplay->inread; 368 ttyDisplay->inread = 0; 369 (void) tty_doprev_message(); 370 ttyDisplay->inread = sav; 371 tty_clear_nhwindow(WIN_MESSAGE); 372 cw->maxcol = cw->maxrow; 373 addtopl(prompt); 374 } else { 375 if(!doprev) 376 (void) tty_doprev_message(); /* need two initially */ 377 (void) tty_doprev_message(); 378 doprev = 1; 379 } 380 q = '\0'; /* force another loop iteration */ 381 continue; 382 } else if (doprev) { 383 /* BUG[?]: this probably ought to check whether the 384 character which has just been read is an acceptable 385 response; if so, skip the reprompt and use it. */ 386 tty_clear_nhwindow(WIN_MESSAGE); 387 cw->maxcol = cw->maxrow; 388 doprev = 0; 389 addtopl(prompt); 390 q = '\0'; /* force another loop iteration */ 391 continue; 392 } 393 digit_ok = allow_num && digit(q); 394 if (q == '\033') { 395 if (index(resp, 'q')) 396 q = 'q'; 397 else if (index(resp, 'n')) 398 q = 'n'; 399 else 400 q = def; 401 break; 402 } else if (index(quitchars, q)) { 403 q = def; 404 break; 405 } 406 if (!index(resp, q) && !digit_ok) { 407 tty_nhbell(); 408 q = (char)0; 409 } else if (q == '#' || digit_ok) { 410 char z, digit_string[2]; 411 int n_len = 0; 412 long value = 0; 413 addtopl("#"), n_len++; 414 digit_string[1] = '\0'; 415 if (q != '#') { 416 digit_string[0] = q; 417 addtopl(digit_string), n_len++; 418 value = q - '0'; 419 q = '#'; 420 } 421 do { /* loop until we get a non-digit */ 422 z = lowc(readchar()); 423 if (digit(z)) { 424 value = (10 * value) + (z - '0'); 425 if (value < 0) break; /* overflow: try again */ 426 digit_string[0] = z; 427 addtopl(digit_string), n_len++; 428 } else if (z == 'y' || index(quitchars, z)) { 429 if (z == '\033') value = -1; /* abort */ 430 z = '\n'; /* break */ 431 } else if (z == erase_char || z == '\b') { 432 if (n_len <= 1) { value = -1; break; } 433 else { value /= 10; removetopl(1), n_len--; } 434 } else { 435 value = -1; /* abort */ 436 tty_nhbell(); 437 break; 438 } 439 } while (z != '\n'); 440 if (value > 0) yn_number = value; 441 else if (value == 0) q = 'n'; /* 0 => "no" */ 442 else { /* remove number from top line, then try again */ 443 removetopl(n_len), n_len = 0; 444 q = '\0'; 445 } 446 } 447 } while(!q); 448 449 if (q != '#') { 450 Sprintf(rtmp, "%c", q); 451 addtopl(rtmp); 452 } 453 clean_up: 454 ttyDisplay->inread--; 455 ttyDisplay->toplin = 2; 456 if (ttyDisplay->intr) ttyDisplay->intr--; 457 if(wins[WIN_MESSAGE]->cury) 458 tty_clear_nhwindow(WIN_MESSAGE); 459 460 return q; 461} 462 463#endif /* OVL2 */ 464 465#endif /* TTY_GRAPHICS */ 466 467/*topl.c*/ 468