1 /* aNetHack 0.0.1 topl.c $ANH-Date: 1463787697 2016/05/20 23:41:37 $ $ANH-Branch: aNetHack-3.6.0 $:$ANH-Revision: 1.33 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
12 #ifndef C /* this matches src/cmd.c */
13 #define C(c) (0x1f & (c))
16 STATIC_DCL
void FDECL(redotoplin
, (const char *));
17 STATIC_DCL
void FDECL(topl_putsym
, (CHAR_P
));
18 STATIC_DCL
void NDECL(remember_topl
);
19 STATIC_DCL
void FDECL(removetopl
, (int));
20 STATIC_DCL
void FDECL(msghistory_snapshot
, (BOOLEAN_P
));
21 STATIC_DCL
void FDECL(free_msghistory_snapshot
, (BOOLEAN_P
));
26 register struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
30 if ((iflags
.prevmsg_window
!= 's')
31 && !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
;
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 */
49 if (cw
->maxcol
== cw
->maxrow
) {
50 ttyDisplay
->dismiss_more
= C('p'); /* ^P ok at --More-- */
54 cw
->maxcol
= cw
->rows
- 1;
55 if (!cw
->data
[cw
->maxcol
])
56 cw
->maxcol
= cw
->maxrow
;
57 } else if (cw
->maxcol
== (cw
->maxrow
- 1)) {
58 ttyDisplay
->dismiss_more
= C('p'); /* ^P ok at --More-- */
59 redotoplin(cw
->data
[cw
->maxcol
]);
62 cw
->maxcol
= cw
->rows
- 1;
63 if (!cw
->data
[cw
->maxcol
])
64 cw
->maxcol
= cw
->maxrow
;
66 prevmsg_win
= create_nhwindow(NHW_MENU
);
67 putstr(prevmsg_win
, 0, "Message History");
68 putstr(prevmsg_win
, 0, "");
69 cw
->maxcol
= cw
->maxrow
;
72 if (cw
->data
[i
] && strcmp(cw
->data
[i
], ""))
73 putstr(prevmsg_win
, 0, cw
->data
[i
]);
74 i
= (i
+ 1) % cw
->rows
;
75 } while (i
!= cw
->maxcol
);
76 putstr(prevmsg_win
, 0, toplines
);
77 display_nhwindow(prevmsg_win
, TRUE
);
78 destroy_nhwindow(prevmsg_win
);
81 } while (morc
== C('p'));
82 ttyDisplay
->dismiss_more
= 0;
83 } else { /* reversed */
85 prevmsg_win
= create_nhwindow(NHW_MENU
);
86 putstr(prevmsg_win
, 0, "Message History");
87 putstr(prevmsg_win
, 0, "");
88 putstr(prevmsg_win
, 0, toplines
);
89 cw
->maxcol
= cw
->maxrow
- 1;
91 cw
->maxcol
= cw
->rows
- 1;
93 putstr(prevmsg_win
, 0, cw
->data
[cw
->maxcol
]);
96 cw
->maxcol
= cw
->rows
- 1;
97 if (!cw
->data
[cw
->maxcol
])
98 cw
->maxcol
= cw
->maxrow
;
99 } while (cw
->maxcol
!= cw
->maxrow
);
101 display_nhwindow(prevmsg_win
, TRUE
);
102 destroy_nhwindow(prevmsg_win
);
103 cw
->maxcol
= cw
->maxrow
;
104 ttyDisplay
->dismiss_more
= 0;
106 } else if (iflags
.prevmsg_window
== 's') { /* single */
107 ttyDisplay
->dismiss_more
= C('p'); /* <ctrl/P> allowed at --More-- */
110 if (cw
->maxcol
== cw
->maxrow
)
111 redotoplin(toplines
);
112 else if (cw
->data
[cw
->maxcol
])
113 redotoplin(cw
->data
[cw
->maxcol
]);
116 cw
->maxcol
= cw
->rows
- 1;
117 if (!cw
->data
[cw
->maxcol
])
118 cw
->maxcol
= cw
->maxrow
;
119 } while (morc
== C('p'));
120 ttyDisplay
->dismiss_more
= 0;
129 int otoplin
= ttyDisplay
->toplin
;
133 /* kludge for the / command, the only time we ever want a */
134 /* graphics character on the top line */
135 g_putch((int) *str
++);
138 end_glyphout(); /* in case message printed during graphics output */
141 ttyDisplay
->toplin
= 1;
142 if (ttyDisplay
->cury
&& otoplin
!= 3)
149 register struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
150 int idx
= cw
->maxrow
;
151 unsigned len
= strlen(toplines
) + 1;
153 if ((cw
->flags
& WIN_LOCKHISTORY
) || !*toplines
)
156 if (len
> (unsigned) cw
->datlen
[idx
]) {
159 len
+= (8 - (len
& 7)); /* pad up to next multiple of 8 */
160 cw
->data
[idx
] = (char *) alloc(len
);
161 cw
->datlen
[idx
] = (short) len
;
163 Strcpy(cw
->data
[idx
], toplines
);
165 cw
->maxcol
= cw
->maxrow
= (idx
+ 1) % cw
->rows
;
172 register struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
174 tty_curs(BASE_WINDOW
, cw
->curx
+ 1, cw
->cury
);
177 ttyDisplay
->toplin
= 1;
183 struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
185 /* avoid recursion -- only happens from interrupts */
186 if (ttyDisplay
->inmore
++)
189 if (ttyDisplay
->toplin
) {
190 tty_curs(BASE_WINDOW
, cw
->curx
+ 1, cw
->cury
);
191 if (cw
->curx
>= CO
- 8)
201 xwaitforspace("\033 ");
204 cw
->flags
|= WIN_STOP
;
206 if (ttyDisplay
->toplin
&& cw
->cury
) {
207 docorner(1, cw
->cury
+ 1);
208 cw
->curx
= cw
->cury
= 0;
210 } else if (morc
== '\033') {
211 cw
->curx
= cw
->cury
= 0;
215 ttyDisplay
->toplin
= 0;
216 ttyDisplay
->inmore
= 0;
221 register const char *bp
;
223 register char *tl
, *otl
;
226 struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
228 /* If there is room on the line, print message on same line */
229 /* But messages like "You die..." deserve their own line */
231 if ((ttyDisplay
->toplin
== 1 || (cw
->flags
& WIN_STOP
)) && cw
->cury
== 0
232 && n0
+ (int) strlen(toplines
) + 3 < CO
- 8 /* room for --More-- */
233 && (notdied
= strncmp(bp
, "You die", 7)) != 0) {
234 Strcat(toplines
, " ");
235 Strcat(toplines
, bp
);
237 if (!(cw
->flags
& WIN_STOP
))
240 } else if (!(cw
->flags
& WIN_STOP
)) {
241 if (ttyDisplay
->toplin
== 1) {
243 } else if (cw
->cury
) { /* for when flags.toplin == 2 && cury > 1 */
244 docorner(1, cw
->cury
+ 1); /* reset cury = 0 if redraw screen */
245 cw
->curx
= cw
->cury
= 0; /* from home--cls() & docorner(1,n) */
249 (void) strncpy(toplines
, bp
, TBUFSZ
);
250 toplines
[TBUFSZ
- 1] = 0;
252 for (tl
= toplines
; n0
>= CO
; ) {
254 for (tl
+= CO
- 1; tl
!= otl
; --tl
)
258 /* Eek! A huge token. Try splitting after it. */
259 tl
= index(otl
, ' ');
261 break; /* No choice but to spit it out whole. */
267 cw
->flags
&= ~WIN_STOP
;
268 if (!(cw
->flags
& WIN_STOP
))
269 redotoplin(toplines
);
277 register struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
279 if (cw
== (struct WinDesc
*) 0)
280 panic("Putsym window MESSAGE nonexistant");
284 if (ttyDisplay
->curx
== 0 && ttyDisplay
->cury
> 0)
285 tty_curs(BASE_WINDOW
, CO
, (int) ttyDisplay
->cury
- 1);
288 cw
->curx
= ttyDisplay
->curx
;
292 ttyDisplay
->curx
= 0;
294 cw
->cury
= ttyDisplay
->cury
;
300 if (ttyDisplay
->curx
== CO
- 1)
301 topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */
307 cw
->curx
= ttyDisplay
->curx
;
327 /* assume addtopl() has been done, so ttyDisplay->toplin is already set */
332 extern char erase_char
; /* from xxxtty.c; don't need kill_char */
335 tty_yn_function(query
, resp
, def
)
336 const char *query
, *resp
;
339 * Generic yes/no function. 'def' is the default (returned by space or
340 * return; 'esc' returns 'q', or 'n', or the default, depending on
341 * what's in the string. The 'query' string is printed before the user
342 * is asked about the string.
343 * If resp is NULL, any single character is accepted and returned.
344 * If not-NULL, only characters in it are allowed (exceptions: the
345 * quitchars are always allowed, and if it contains '#' then digits
346 * are allowed); if it includes an <esc>, anything beyond that won't
347 * be shown in the prompt to the user but will be acceptable as input.
352 boolean digit_ok
, allow_num
, preserve_case
= FALSE
;
353 struct WinDesc
*cw
= wins
[WIN_MESSAGE
];
357 if (ttyDisplay
->toplin
== 1 && !(cw
->flags
& WIN_STOP
))
359 cw
->flags
&= ~WIN_STOP
;
360 ttyDisplay
->toplin
= 3; /* special prompt state */
361 ttyDisplay
->inread
++;
363 char *rb
, respbuf
[QBUFSZ
];
365 allow_num
= (index(resp
, '#') != 0);
366 Strcpy(respbuf
, resp
);
367 /* normally we force lowercase, but if any uppercase letters
368 are present in the allowed response, preserve case;
369 check this before stripping the hidden choices */
370 for (rb
= respbuf
; *rb
; ++rb
)
371 if ('A' <= *rb
&& *rb
<= 'Z') {
372 preserve_case
= TRUE
;
375 /* any acceptable responses that follow <esc> aren't displayed */
376 if ((rb
= index(respbuf
, '\033')) != 0)
378 (void) strncpy(prompt
, query
, QBUFSZ
- 1);
379 prompt
[QBUFSZ
- 1] = '\0';
380 Sprintf(eos(prompt
), " [%s]", respbuf
);
382 Sprintf(eos(prompt
), " (%c)", def
);
383 /* not pline("%s ", prompt);
384 trailing space is wanted here in case of reprompt */
388 /* no restriction on allowed response, so always preserve case */
389 /* preserve_case = TRUE; -- moot since we're jumping to the end */
395 do { /* loop until we get valid input */
399 if (q
== '\020') { /* ctrl-P */
400 if (iflags
.prevmsg_window
!= 's') {
401 int sav
= ttyDisplay
->inread
;
402 ttyDisplay
->inread
= 0;
403 (void) tty_doprev_message();
404 ttyDisplay
->inread
= sav
;
405 tty_clear_nhwindow(WIN_MESSAGE
);
406 cw
->maxcol
= cw
->maxrow
;
410 (void) tty_doprev_message(); /* need two initially */
411 (void) tty_doprev_message();
414 q
= '\0'; /* force another loop iteration */
417 /* BUG[?]: this probably ought to check whether the
418 character which has just been read is an acceptable
419 response; if so, skip the reprompt and use it. */
420 tty_clear_nhwindow(WIN_MESSAGE
);
421 cw
->maxcol
= cw
->maxrow
;
424 q
= '\0'; /* force another loop iteration */
427 digit_ok
= allow_num
&& digit(q
);
429 if (index(resp
, 'q'))
431 else if (index(resp
, 'n'))
436 } else if (index(quitchars
, q
)) {
440 if (!index(resp
, q
) && !digit_ok
) {
443 } else if (q
== '#' || digit_ok
) {
444 char z
, digit_string
[2];
447 addtopl("#"), n_len
++;
448 digit_string
[1] = '\0';
451 addtopl(digit_string
), n_len
++;
455 do { /* loop until we get a non-digit */
460 value
= (10 * value
) + (z
- '0');
462 break; /* overflow: try again */
464 addtopl(digit_string
), n_len
++;
465 } else if (z
== 'y' || index(quitchars
, z
)) {
467 value
= -1; /* abort */
468 z
= '\n'; /* break */
469 } else if (z
== erase_char
|| z
== '\b') {
475 removetopl(1), n_len
--;
478 value
= -1; /* abort */
486 q
= 'n'; /* 0 => "no" */
487 else { /* remove number from top line, then try again */
488 removetopl(n_len
), n_len
= 0;
495 Sprintf(rtmp
, "%c", q
);
499 ttyDisplay
->inread
--;
500 ttyDisplay
->toplin
= 2;
501 if (ttyDisplay
->intr
)
503 if (wins
[WIN_MESSAGE
]->cury
)
504 tty_clear_nhwindow(WIN_MESSAGE
);
509 /* shared by tty_getmsghistory() and tty_putmsghistory() */
510 static char **snapshot_mesgs
= 0;
512 /* collect currently available message history data into a sequential array;
513 optionally, purge that data from the active circular buffer set as we go */
515 msghistory_snapshot(purge
)
516 boolean purge
; /* clear message history buffer as we copy it */
519 int i
, inidx
, outidx
;
522 /* paranoia (too early or too late panic save attempt?) */
523 if (WIN_MESSAGE
== WIN_ERR
|| !wins
[WIN_MESSAGE
])
525 cw
= wins
[WIN_MESSAGE
];
527 /* flush toplines[], moving most recent message to history */
530 /* for a passive snapshot, we just copy pointers, so can't allow further
531 history updating to take place because that could clobber them */
533 cw
->flags
|= WIN_LOCKHISTORY
;
535 snapshot_mesgs
= (char **) alloc((cw
->rows
+ 1) * sizeof(char *));
538 for (i
= 0; i
< cw
->rows
; ++i
) {
539 snapshot_mesgs
[i
] = (char *) 0;
540 mesg
= cw
->data
[inidx
];
542 snapshot_mesgs
[outidx
++] = mesg
;
544 /* we're taking this pointer away; subsequest history
545 updates will eventually allocate a new one to replace it */
546 cw
->data
[inidx
] = (char *) 0;
547 cw
->datlen
[inidx
] = 0;
550 inidx
= (inidx
+ 1) % cw
->rows
;
552 snapshot_mesgs
[cw
->rows
] = (char *) 0; /* sentinel */
554 /* for a destructive snapshot, history is now completely empty */
556 cw
->maxcol
= cw
->maxrow
= 0;
559 /* release memory allocated to message history snapshot */
561 free_msghistory_snapshot(purged
)
562 boolean purged
; /* True: took history's pointers, False: just cloned them */
564 if (snapshot_mesgs
) {
565 /* snapshot pointers are no longer in use */
569 for (i
= 0; snapshot_mesgs
[i
]; ++i
)
570 free((genericptr_t
) snapshot_mesgs
[i
]);
573 free((genericptr_t
) snapshot_mesgs
), snapshot_mesgs
= (char **) 0;
575 /* history can resume being updated at will now... */
577 wins
[WIN_MESSAGE
]->flags
&= ~WIN_LOCKHISTORY
;
582 * This is called by the core save routines.
583 * Each time we are called, we return one string from the
584 * message history starting with the oldest message first.
585 * When none are left, we return a final null string.
587 * History is collected at the time of the first call.
588 * Any new messages issued after that point will not be
589 * included among the output of the subsequent calls.
592 tty_getmsghistory(init
)
600 msghistory_snapshot(FALSE
);
604 if (snapshot_mesgs
) {
605 nextmesg
= snapshot_mesgs
[nxtidx
++];
607 result
= (char *) nextmesg
;
609 free_msghistory_snapshot(FALSE
);
616 * This is called by the core savefile restore routines.
617 * Each time we are called, we stuff the string into our message
618 * history recall buffer. The core will send the oldest message
619 * first (actually it sends them in the order they exist in the
620 * save file, but that is supposed to be the oldest first).
621 * These messages get pushed behind any which have been issued
622 * since this session with the program has been started, since
623 * they come from a previous session and logically precede
624 * anything (like "Restoring save file...") that's happened now.
626 * Called with a null pointer to finish up restoration.
628 * It's also called by the quest pager code when a block message
629 * has a one-line summary specified. We put that line directly
630 * message history for ^P recall without having displayed it.
633 tty_putmsghistory(msg
, restoring_msghist
)
635 boolean restoring_msghist
;
637 static boolean initd
= FALSE
;
640 if (restoring_msghist
&& !initd
) {
641 /* we're restoring history from the previous session, but new
642 messages have already been issued this session ("Restoring...",
643 for instance); collect current history (ie, those new messages),
644 and also clear it out so that nothing will be present when the
645 restored ones are being put into place */
646 msghistory_snapshot(TRUE
);
651 /* move most recent message to history, make this become most recent
654 Strcpy(toplines
, msg
);
655 } else if (snapshot_mesgs
) {
656 /* done putting arbitrary messages in; put the snapshot ones back */
657 for (idx
= 0; snapshot_mesgs
[idx
]; ++idx
) {
659 Strcpy(toplines
, snapshot_mesgs
[idx
]);
661 /* now release the snapshot */
662 free_msghistory_snapshot(TRUE
);
663 initd
= FALSE
; /* reset */
667 #endif /* TTY_GRAPHICS */