1 /* NetHack 3.6 topl.c $NHDT-Date: 1431192777 2015/05/09 17:32:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
13 #ifndef C /* this matches src/cmd.c */
14 #define C(c) (0x1f & (c))
17 STATIC_DCL void FDECL(redotoplin, (const char *));
18 STATIC_DCL void FDECL(topl_putsym, (CHAR_P));
19 STATIC_DCL void NDECL(remember_topl);
20 STATIC_DCL void FDECL(removetopl, (int));
21 STATIC_DCL void FDECL(msghistory_snapshot, (BOOLEAN_P));
22 STATIC_DCL void FDECL(free_msghistory_snapshot, (BOOLEAN_P));
27 register struct WinDesc *cw = wins[WIN_MESSAGE];
31 if ((iflags.prevmsg_window != 's')
32 && !ttyDisplay->inread) { /* not single */
33 if (iflags.prevmsg_window == 'f') { /* full */
34 prevmsg_win = create_nhwindow(NHW_MENU);
35 putstr(prevmsg_win, 0, "Message History");
36 putstr(prevmsg_win, 0, "");
37 cw->maxcol = cw->maxrow;
40 if (cw->data[i] && strcmp(cw->data[i], ""))
41 putstr(prevmsg_win, 0, cw->data[i]);
42 i = (i + 1) % cw->rows;
43 } while (i != cw->maxcol);
44 putstr(prevmsg_win, 0, toplines);
45 display_nhwindow(prevmsg_win, TRUE);
46 destroy_nhwindow(prevmsg_win);
47 } else if (iflags.prevmsg_window == 'c') { /* combination */
50 if (cw->maxcol == cw->maxrow) {
51 ttyDisplay->dismiss_more =
52 C('p'); /* <ctrl/P> allowed at --More-- */
56 cw->maxcol = cw->rows - 1;
57 if (!cw->data[cw->maxcol])
58 cw->maxcol = cw->maxrow;
59 } else if (cw->maxcol == (cw->maxrow - 1)) {
60 ttyDisplay->dismiss_more =
61 C('p'); /* <ctrl/P> allowed at --More-- */
62 redotoplin(cw->data[cw->maxcol]);
65 cw->maxcol = cw->rows - 1;
66 if (!cw->data[cw->maxcol])
67 cw->maxcol = cw->maxrow;
69 prevmsg_win = create_nhwindow(NHW_MENU);
70 putstr(prevmsg_win, 0, "Message History");
71 putstr(prevmsg_win, 0, "");
72 cw->maxcol = cw->maxrow;
75 if (cw->data[i] && strcmp(cw->data[i], ""))
76 putstr(prevmsg_win, 0, cw->data[i]);
77 i = (i + 1) % cw->rows;
78 } while (i != cw->maxcol);
79 putstr(prevmsg_win, 0, toplines);
80 display_nhwindow(prevmsg_win, TRUE);
81 destroy_nhwindow(prevmsg_win);
84 } while (morc == C('p'));
85 ttyDisplay->dismiss_more = 0;
86 } else { /* reversed */
88 prevmsg_win = create_nhwindow(NHW_MENU);
89 putstr(prevmsg_win, 0, "Message History");
90 putstr(prevmsg_win, 0, "");
91 putstr(prevmsg_win, 0, toplines);
92 cw->maxcol = cw->maxrow - 1;
94 cw->maxcol = cw->rows - 1;
96 putstr(prevmsg_win, 0, cw->data[cw->maxcol]);
99 cw->maxcol = cw->rows - 1;
100 if (!cw->data[cw->maxcol])
101 cw->maxcol = cw->maxrow;
102 } while (cw->maxcol != cw->maxrow);
104 display_nhwindow(prevmsg_win, TRUE);
105 destroy_nhwindow(prevmsg_win);
106 cw->maxcol = cw->maxrow;
107 ttyDisplay->dismiss_more = 0;
109 } else if (iflags.prevmsg_window == 's') { /* single */
110 ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
113 if (cw->maxcol == cw->maxrow)
114 redotoplin(toplines);
115 else if (cw->data[cw->maxcol])
116 redotoplin(cw->data[cw->maxcol]);
119 cw->maxcol = cw->rows - 1;
120 if (!cw->data[cw->maxcol])
121 cw->maxcol = cw->maxrow;
122 } while (morc == C('p'));
123 ttyDisplay->dismiss_more = 0;
132 int otoplin = ttyDisplay->toplin;
136 /* kludge for the / command, the only time we ever want a */
137 /* graphics character on the top line */
138 g_putch((int) *str++);
142 end_glyphout(); /* in case message printed during graphics output */
145 ttyDisplay->toplin = 1;
146 if (ttyDisplay->cury && otoplin != 3)
153 register struct WinDesc *cw = wins[WIN_MESSAGE];
154 int idx = cw->maxrow;
155 unsigned len = strlen(toplines) + 1;
157 if ((cw->flags & WIN_LOCKHISTORY) || !*toplines)
160 if (len > (unsigned) cw->datlen[idx]) {
163 len += (8 - (len & 7)); /* pad up to next multiple of 8 */
164 cw->data[idx] = (char *) alloc(len);
165 cw->datlen[idx] = (short) len;
167 Strcpy(cw->data[idx], toplines);
169 cw->maxcol = cw->maxrow = (idx + 1) % cw->rows;
176 register struct WinDesc *cw = wins[WIN_MESSAGE];
178 tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury);
181 ttyDisplay->toplin = 1;
187 struct WinDesc *cw = wins[WIN_MESSAGE];
189 /* avoid recursion -- only happens from interrupts */
190 if (ttyDisplay->inmore++)
193 if (ttyDisplay->toplin) {
194 tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury);
195 if (cw->curx >= CO - 8)
205 xwaitforspace("\033 ");
208 cw->flags |= WIN_STOP;
210 if (ttyDisplay->toplin && cw->cury) {
211 docorner(1, cw->cury + 1);
212 cw->curx = cw->cury = 0;
214 } else if (morc == '\033') {
215 cw->curx = cw->cury = 0;
219 ttyDisplay->toplin = 0;
220 ttyDisplay->inmore = 0;
224 folding_japanese( str, pos )
228 char ss[1024],s1[1024],s2[1024];
229 static char newstr[1024]; /* may be enough */
234 split_japanese(ss, s1, s2, pos);
238 Strcat(newstr, "\n");
248 register const char *bp;
251 register char *tl, *otl;
255 struct WinDesc *cw = wins[WIN_MESSAGE];
257 /* If there is room on the line, print message on same line */
258 /* But messages like "You die..." deserve their own line */
260 if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) && cw->cury == 0
261 && n0 + (int) strlen(toplines) + 3 < CO - 8 && /* room for --More-- */
262 (notdied = strncmp(bp, "You die", 7))) {
263 Strcat(toplines, " ");
264 Strcat(toplines, bp);
266 if (!(cw->flags & WIN_STOP))
269 } else if (!(cw->flags & WIN_STOP)) {
270 if (ttyDisplay->toplin == 1)
272 else if (cw->cury) { /* for when flags.toplin == 2 && cury > 1 */
273 docorner(1, cw->cury + 1); /* reset cury = 0 if redraw screen */
274 cw->curx = cw->cury = 0; /* from home--cls() & docorner(1,n) */
280 Strcpy(toplines, bp);
282 Strcpy(toplines,folding_japanese(bp, CO-2));
284 (void) strncpy(toplines, bp, TBUFSZ);
285 toplines[TBUFSZ - 1] = 0;
287 for (tl = toplines; n0 >= CO;) {
289 for (tl += CO - 1; tl != otl && !isspace(*tl); --tl)
292 /* Eek! A huge token. Try splitting after it. */
293 tl = index(otl, ' ');
295 break; /* No choice but to spit it out whole. */
302 cw->flags &= ~WIN_STOP;
303 if (!(cw->flags & WIN_STOP))
304 redotoplin(toplines);
312 register struct WinDesc *cw = wins[WIN_MESSAGE];
314 unsigned char uc = *((unsigned char *)(&c));
317 if (cw == (struct WinDesc *) 0)
318 panic("Putsym window MESSAGE nonexistant");
322 if (ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
323 tty_curs(BASE_WINDOW, CO, (int) ttyDisplay->cury - 1);
326 cw->curx = ttyDisplay->curx;
331 (void) jputchar('\r'); /* raw mode
\82Ã…
\95K
\97v? */
332 (void) jputchar('\n');
334 ttyDisplay->curx = 0;
336 cw->cury = ttyDisplay->cury;
344 if (ttyDisplay->curx == CO - 1)
345 topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
352 cw->curx = ttyDisplay->curx;
353 if(cw->curx == 0) cl_end();
354 (void) jputchar((unsigned char)uc);
360 cw->curx = ttyDisplay->curx;
378 ** do not translate kcode this function(see topl_putsym)
385 register struct WinDesc *cw = wins[WIN_MESSAGE];
387 if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant");
391 if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
392 tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1);
395 cw->curx = ttyDisplay->curx;
400 (void) cputchar('\r'); /* raw mode
\82Ã…
\95K
\97v? */
401 (void) cputchar('\n');
403 ttyDisplay->curx = 0;
405 cw->cury = ttyDisplay->cury;
408 if(ttyDisplay->curx == CO-1)
409 topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
413 cw->curx = ttyDisplay->curx;
414 if(cw->curx == 0) cl_end();
422 ** do not translate kcode this function(see putsym)
429 raw_topl_putsym(*str++);
436 /* assume addtopl() has been done, so ttyDisplay->toplin is already set */
441 extern char erase_char; /* from xxxtty.c; don't need kill_char */
444 tty_yn_function(query, resp, def)
445 const char *query, *resp;
448 * Generic yes/no function. 'def' is the default (returned by space or
449 * return; 'esc' returns 'q', or 'n', or the default, depending on
450 * what's in the string. The 'query' string is printed before the user
451 * is asked about the string.
452 * If resp is NULL, any single character is accepted and returned.
453 * If not-NULL, only characters in it are allowed (exceptions: the
454 * quitchars are always allowed, and if it contains '#' then digits
455 * are allowed); if it includes an <esc>, anything beyond that won't
456 * be shown in the prompt to the user but will be acceptable as input.
461 boolean digit_ok, allow_num, preserve_case = FALSE;
462 struct WinDesc *cw = wins[WIN_MESSAGE];
466 if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP))
468 cw->flags &= ~WIN_STOP;
469 ttyDisplay->toplin = 3; /* special prompt state */
470 ttyDisplay->inread++;
472 char *rb, respbuf[QBUFSZ];
474 allow_num = (index(resp, '#') != 0);
475 Strcpy(respbuf, resp);
476 /* normally we force lowercase, but if any uppercase letters
477 are present in the allowed response, preserve case;
478 check this before stripping the hidden choices */
479 for (rb = respbuf; *rb; ++rb)
480 if ('A' <= *rb && *rb <= 'Z') {
481 preserve_case = TRUE;
484 /* any acceptable responses that follow <esc> aren't displayed */
485 if ((rb = index(respbuf, '\033')) != 0)
487 (void) strncpy(prompt, query, QBUFSZ - 1);
488 prompt[QBUFSZ - 1] = '\0';
489 Sprintf(eos(prompt), " [%s]", respbuf);
491 Sprintf(eos(prompt), " (%c)", def);
492 /* not pline("%s ", prompt);
493 trailing space is wanted here in case of reprompt */
497 /* no restriction on allowed response, so always preserve case */
498 /* preserve_case = TRUE; -- moot since we're jumping to the end */
504 do { /* loop until we get valid input */
508 if (q == '\020') { /* ctrl-P */
509 if (iflags.prevmsg_window != 's') {
510 int sav = ttyDisplay->inread;
511 ttyDisplay->inread = 0;
512 (void) tty_doprev_message();
513 ttyDisplay->inread = sav;
514 tty_clear_nhwindow(WIN_MESSAGE);
515 cw->maxcol = cw->maxrow;
519 (void) tty_doprev_message(); /* need two initially */
520 (void) tty_doprev_message();
523 q = '\0'; /* force another loop iteration */
526 /* BUG[?]: this probably ought to check whether the
527 character which has just been read is an acceptable
528 response; if so, skip the reprompt and use it. */
529 tty_clear_nhwindow(WIN_MESSAGE);
530 cw->maxcol = cw->maxrow;
533 q = '\0'; /* force another loop iteration */
536 digit_ok = allow_num && digit(q);
538 if (index(resp, 'q'))
540 else if (index(resp, 'n'))
545 } else if (index(quitchars, q)) {
549 if (!index(resp, q) && !digit_ok) {
552 } else if (q == '#' || digit_ok) {
553 char z, digit_string[2];
556 addtopl("#"), n_len++;
557 digit_string[1] = '\0';
560 addtopl(digit_string), n_len++;
564 do { /* loop until we get a non-digit */
569 value = (10 * value) + (z - '0');
571 break; /* overflow: try again */
573 addtopl(digit_string), n_len++;
574 } else if (z == 'y' || index(quitchars, z)) {
576 value = -1; /* abort */
577 z = '\n'; /* break */
578 } else if (z == erase_char || z == '\b') {
584 removetopl(1), n_len--;
587 value = -1; /* abort */
595 q = 'n'; /* 0 => "no" */
596 else { /* remove number from top line, then try again */
597 removetopl(n_len), n_len = 0;
604 Sprintf(rtmp, "%c", q);
608 ttyDisplay->inread--;
609 ttyDisplay->toplin = 2;
610 if (ttyDisplay->intr)
612 if (wins[WIN_MESSAGE]->cury)
613 tty_clear_nhwindow(WIN_MESSAGE);
618 /* shared by tty_getmsghistory() and tty_putmsghistory() */
619 static char **snapshot_mesgs = 0;
621 /* collect currently available message history data into a sequential array;
622 optionally, purge that data from the active circular buffer set as we go */
624 msghistory_snapshot(purge)
625 boolean purge; /* clear message history buffer as we copy it */
628 int i, inidx, outidx;
631 /* paranoia (too early or too late panic save attempt?) */
632 if (WIN_MESSAGE == WIN_ERR || !wins[WIN_MESSAGE])
634 cw = wins[WIN_MESSAGE];
636 /* flush toplines[], moving most recent message to history */
639 /* for a passive snapshot, we just copy pointers, so can't allow further
640 history updating to take place because that could clobber them */
642 cw->flags |= WIN_LOCKHISTORY;
644 snapshot_mesgs = (char **) alloc((cw->rows + 1) * sizeof(char *));
647 for (i = 0; i < cw->rows; ++i) {
648 snapshot_mesgs[i] = (char *) 0;
649 mesg = cw->data[inidx];
651 snapshot_mesgs[outidx++] = mesg;
653 /* we're taking this pointer away; subsequest history
654 updates will eventually allocate a new one to replace it */
655 cw->data[inidx] = (char *) 0;
656 cw->datlen[inidx] = 0;
659 inidx = (inidx + 1) % cw->rows;
661 snapshot_mesgs[cw->rows] = (char *) 0; /* sentinel */
663 /* for a destructive snapshot, history is now completely empty */
665 cw->maxcol = cw->maxrow = 0;
668 /* release memory allocated to message history snapshot */
670 free_msghistory_snapshot(purged)
671 boolean purged; /* True: took history's pointers, False: just cloned them */
673 if (snapshot_mesgs) {
674 /* snapshot pointers are no longer in use */
678 for (i = 0; snapshot_mesgs[i]; ++i)
679 free((genericptr_t) snapshot_mesgs[i]);
682 free((genericptr_t) snapshot_mesgs), snapshot_mesgs = (char **) 0;
684 /* history can resume being updated at will now... */
686 wins[WIN_MESSAGE]->flags &= ~WIN_LOCKHISTORY;
691 * This is called by the core save routines.
692 * Each time we are called, we return one string from the
693 * message history starting with the oldest message first.
694 * When none are left, we return a final null string.
696 * History is collected at the time of the first call.
697 * Any new messages issued after that point will not be
698 * included among the output of the subsequent calls.
701 tty_getmsghistory(init)
709 msghistory_snapshot(FALSE);
713 if (snapshot_mesgs) {
714 nextmesg = snapshot_mesgs[nxtidx++];
716 result = (char *) nextmesg;
718 free_msghistory_snapshot(FALSE);
725 * This is called by the core savefile restore routines.
726 * Each time we are called, we stuff the string into our message
727 * history recall buffer. The core will send the oldest message
728 * first (actually it sends them in the order they exist in the
729 * save file, but that is supposed to be the oldest first).
730 * These messages get pushed behind any which have been issued
731 * since this session with the program has been started, since
732 * they come from a previous session and logically precede
733 * anything (like "Restoring save file...") that's happened now.
735 * Called with a null pointer to finish up restoration.
737 * It's also called by the quest pager code when a block message
738 * has a one-line summary specified. We put that line directly
739 * message history for ^P recall without having displayed it.
742 tty_putmsghistory(msg, restoring_msghist)
744 boolean restoring_msghist;
746 static boolean initd = FALSE;
749 if (restoring_msghist && !initd) {
750 /* we're restoring history from the previous session, but new
751 messages have already been issued this session ("Restoring...",
752 for instance); collect current history (ie, those new messages),
753 and also clear it out so that nothing will be present when the
754 restored ones are being put into place */
755 msghistory_snapshot(TRUE);
760 /* move most recent message to history, make this become most recent
763 Strcpy(toplines, msg);
764 } else if (snapshot_mesgs) {
765 /* done putting arbitrary messages in; put the snapshot ones back */
766 for (idx = 0; snapshot_mesgs[idx]; ++idx) {
768 Strcpy(toplines, snapshot_mesgs[idx]);
770 /* now release the snapshot */
771 free_msghistory_snapshot(TRUE);
772 initd = FALSE; /* reset */
776 #endif /* TTY_GRAPHICS */