OSDN Git Service

update lgtm.yml
[jnethack/source.git] / win / tty / topl.c
1 /* NetHack 3.6  topl.c  $NHDT-Date: 1560608320 2019/06/15 14:18:40 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.47 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2009. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 #include "hack.h"
7
8 #ifdef TTY_GRAPHICS
9
10 #include "tcap.h"
11 #include "wintty.h"
12
13 #ifndef C /* this matches src/cmd.c */
14 #define C(c) (0x1f & (c))
15 #endif
16
17 STATIC_DCL void FDECL(redotoplin, (const char *));
18 STATIC_DCL void FDECL(topl_putsym, (CHAR_P));
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));
22
23 int
24 tty_doprev_message()
25 {
26     register struct WinDesc *cw = wins[WIN_MESSAGE];
27     winid prevmsg_win;
28     int i;
29
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;
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'); /* ^P ok at --More-- */
51                     redotoplin(toplines);
52                     cw->maxcol--;
53                     if (cw->maxcol < 0)
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]);
60                     cw->maxcol--;
61                     if (cw->maxcol < 0)
62                         cw->maxcol = cw->rows - 1;
63                     if (!cw->data[cw->maxcol])
64                         cw->maxcol = cw->maxrow;
65                 } else {
66                     prevmsg_win = create_nhwindow(NHW_MENU);
67                     putstr(prevmsg_win, 0, "Message History");
68                     putstr(prevmsg_win, 0, "");
69                     cw->maxcol = cw->maxrow;
70                     i = cw->maxcol;
71                     do {
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);
79                 }
80
81             } while (morc == C('p'));
82             ttyDisplay->dismiss_more = 0;
83         } else { /* reversed */
84             morc = 0;
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;
90             if (cw->maxcol < 0)
91                 cw->maxcol = cw->rows - 1;
92             do {
93                 putstr(prevmsg_win, 0, cw->data[cw->maxcol]);
94                 cw->maxcol--;
95                 if (cw->maxcol < 0)
96                     cw->maxcol = cw->rows - 1;
97                 if (!cw->data[cw->maxcol])
98                     cw->maxcol = cw->maxrow;
99             } while (cw->maxcol != cw->maxrow);
100
101             display_nhwindow(prevmsg_win, TRUE);
102             destroy_nhwindow(prevmsg_win);
103             cw->maxcol = cw->maxrow;
104             ttyDisplay->dismiss_more = 0;
105         }
106     } else if (iflags.prevmsg_window == 's') { /* single */
107         ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
108         do {
109             morc = 0;
110             if (cw->maxcol == cw->maxrow)
111                 redotoplin(toplines);
112             else if (cw->data[cw->maxcol])
113                 redotoplin(cw->data[cw->maxcol]);
114             cw->maxcol--;
115             if (cw->maxcol < 0)
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;
121     }
122     return 0;
123 }
124
125 STATIC_OVL void
126 redotoplin(str)
127 const char *str;
128 {
129     int otoplin = ttyDisplay->toplin;
130
131     home();
132 #if 0 /*JP*/
133     if (*str & 0x80) {
134         /* kludge for the / command, the only time we ever want a */
135         /* graphics character on the top line */
136         g_putch((int) *str++);
137         ttyDisplay->curx++;
138     }
139 #endif
140     end_glyphout(); /* in case message printed during graphics output */
141     putsyms(str);
142     cl_end();
143     ttyDisplay->toplin = 1;
144     if (ttyDisplay->cury && otoplin != 3)
145         more();
146 }
147
148 /* for use by tty_putstr() */
149 void
150 show_topl(str)
151 const char *str;
152 {
153     struct WinDesc *cw = wins[WIN_MESSAGE];
154
155     if (!(cw->flags & WIN_STOP)) {
156         if (ttyDisplay->cury && ttyDisplay->toplin == 2)
157             tty_clear_nhwindow(WIN_MESSAGE);
158
159         cw->curx = cw->cury = 0;
160         home();
161         cl_end();
162         addtopl(str);
163
164         if (ttyDisplay->cury && ttyDisplay->toplin != 3)
165             ttyDisplay->toplin = 2;
166     }
167 }
168
169 /* used by update_topl(); also by tty_putstr() */
170 void
171 remember_topl()
172 {
173     register struct WinDesc *cw = wins[WIN_MESSAGE];
174     int idx = cw->maxrow;
175     unsigned len = strlen(toplines) + 1;
176
177     if ((cw->flags & WIN_LOCKHISTORY) || !*toplines)
178         return;
179
180     if (len > (unsigned) cw->datlen[idx]) {
181         if (cw->data[idx])
182             free(cw->data[idx]);
183         len += (8 - (len & 7)); /* pad up to next multiple of 8 */
184         cw->data[idx] = (char *) alloc(len);
185         cw->datlen[idx] = (short) len;
186     }
187     Strcpy(cw->data[idx], toplines);
188     *toplines = '\0';
189     cw->maxcol = cw->maxrow = (idx + 1) % cw->rows;
190 }
191
192 void
193 addtopl(s)
194 const char *s;
195 {
196     register struct WinDesc *cw = wins[WIN_MESSAGE];
197
198     tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury);
199     putsyms(s);
200     cl_end();
201     ttyDisplay->toplin = 1;
202 }
203
204 void
205 more()
206 {
207     struct WinDesc *cw = wins[WIN_MESSAGE];
208
209     /* avoid recursion -- only happens from interrupts */
210     if (ttyDisplay->inmore++)
211         return;
212     if (iflags.debug_fuzzer)
213         return;
214
215     if (ttyDisplay->toplin) {
216         tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury);
217         if (cw->curx >= CO - 8)
218             topl_putsym('\n');
219     }
220
221     if (flags.standout)
222         standoutbeg();
223     putsyms(defmorestr);
224     if (flags.standout)
225         standoutend();
226
227     xwaitforspace("\033 ");
228
229     if (morc == '\033')
230         cw->flags |= WIN_STOP;
231
232     if (ttyDisplay->toplin && cw->cury) {
233         docorner(1, cw->cury + 1);
234         cw->curx = cw->cury = 0;
235         home();
236     } else if (morc == '\033') {
237         cw->curx = cw->cury = 0;
238         home();
239         cl_end();
240     }
241     ttyDisplay->toplin = 0;
242     ttyDisplay->inmore = 0;
243 }
244 #if 1 /*JP*/
245 static char *
246 folding_japanese( str, pos )
247      const char *str;
248      int pos;
249 {
250   char ss[1024],s1[1024],s2[1024];
251   static char newstr[1024];             /* may be enough */
252
253   newstr[0] = '\0';
254   Strcpy(ss, str);
255   while(1){
256     split_japanese(ss, s1, s2, pos);
257     Strcat(newstr, s1);
258     if(!*s2)
259       break;
260     Strcat(newstr, "\n");
261     Strcpy(ss,s2);
262   }
263
264   return newstr;
265 }
266 #endif
267
268 void
269 update_topl(bp)
270 register const char *bp;
271 {
272 #if 0 /*JP*/
273     register char *tl, *otl;
274 #endif
275     register int n0;
276     int notdied = 1;
277     struct WinDesc *cw = wins[WIN_MESSAGE];
278
279     /* If there is room on the line, print message on same line */
280     /* But messages like "You die..." deserve their own line */
281     n0 = strlen(bp);
282     if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP))
283         && cw->cury == 0
284         && n0 + (int) strlen(toplines) + 3 < CO - 8 /* room for --More-- */
285         && (notdied = strncmp(bp, "You die", 7)) != 0) {
286         Strcat(toplines, "  ");
287         Strcat(toplines, bp);
288         cw->curx += 2;
289         if (!(cw->flags & WIN_STOP))
290             addtopl(bp);
291         return;
292     } else if (!(cw->flags & WIN_STOP)) {
293         if (ttyDisplay->toplin == 1) {
294             more();
295         } else if (cw->cury) { /* for when flags.toplin == 2 && cury > 1 */
296             docorner(1, cw->cury + 1); /* reset cury = 0 if redraw screen */
297             cw->curx = cw->cury = 0;   /* from home--cls() & docorner(1,n) */
298         }
299     }
300     remember_topl();
301 #if 1 /*JP*/
302     if( n0<CO )
303       Strcpy(toplines, bp);
304     else
305       Strcpy(toplines,folding_japanese(bp, CO-2));
306 #else
307     (void) strncpy(toplines, bp, TBUFSZ);
308     toplines[TBUFSZ - 1] = 0;
309
310     for (tl = toplines; n0 >= CO; ) {
311         otl = tl;
312         for (tl += CO - 1; tl != otl; --tl)
313             if (*tl == ' ')
314                 break;
315         if (tl == otl) {
316             /* Eek!  A huge token.  Try splitting after it. */
317             tl = index(otl, ' ');
318             if (!tl)
319                 break; /* No choice but to spit it out whole. */
320         }
321         *tl++ = '\n';
322         n0 = strlen(tl);
323     }
324 #endif
325     if (!notdied)
326         cw->flags &= ~WIN_STOP;
327     if (!(cw->flags & WIN_STOP))
328         redotoplin(toplines);
329 }
330
331 STATIC_OVL
332 void
333 topl_putsym(c)
334 char c;
335 {
336     register struct WinDesc *cw = wins[WIN_MESSAGE];
337 #if 1 /*JP*/
338     unsigned char uc = *((unsigned char *)(&c));
339 #endif
340
341     if (cw == (struct WinDesc *) 0)
342         panic("Putsym window MESSAGE nonexistent");
343
344     switch (c) {
345     case '\b':
346         if (ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
347             tty_curs(BASE_WINDOW, CO, (int) ttyDisplay->cury - 1);
348         backsp();
349         ttyDisplay->curx--;
350         cw->curx = ttyDisplay->curx;
351         return;
352     case '\n':
353         cl_end();
354 #if 1 /*JP*/
355         (void) jputchar('\r'); /* raw mode \82Ã…\95K\97v? */
356         (void) jputchar('\n');
357 #endif
358         ttyDisplay->curx = 0;
359         ttyDisplay->cury++;
360         cw->cury = ttyDisplay->cury;
361 #if 0 /*JP*/
362 #ifdef WIN32CON
363         (void) putchar(c);
364 #endif
365 #endif
366         break;
367     default:
368         if (ttyDisplay->curx == CO - 1)
369             topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */
370 #if 0 /*JP*/
371 #ifdef WIN32CON
372         (void) putchar(c);
373 #endif
374 #endif
375 #if 1 /*JP*/
376         cw->curx = ttyDisplay->curx;
377         if(cw->curx == 0) cl_end();
378         (void) jputchar((unsigned char)uc);
379         cw->curx++;
380 #endif
381         ttyDisplay->curx++;
382     }
383 #if 0 /*JP*/
384     cw->curx = ttyDisplay->curx;
385     if (cw->curx == 0)
386         cl_end();
387 #ifndef WIN32CON
388     (void) putchar(c);
389 #endif
390 #endif
391 }
392
393 void
394 putsyms(str)
395 const char *str;
396 {
397     while (*str)
398         topl_putsym(*str++);
399 }
400
401 #if 1 /*JP*/
402 /* JP
403 ** do not translate kcode this function(see topl_putsym)
404 */
405 STATIC_OVL
406 void
407 raw_topl_putsym(c)
408     char c;
409 {
410     register struct WinDesc *cw = wins[WIN_MESSAGE];
411
412     if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant");
413
414     switch(c) {
415     case '\b':
416         if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
417             tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1);
418         backsp();
419         ttyDisplay->curx--;
420         cw->curx = ttyDisplay->curx;
421         return;
422     case '\n':
423         cl_end();
424 #if 1 /*JP*/
425         (void) cputchar('\r'); /* raw mode \82Ã…\95K\97v? */
426         (void) cputchar('\n');
427 #endif
428         ttyDisplay->curx = 0;
429         ttyDisplay->cury++;
430         cw->cury = ttyDisplay->cury;
431         break;
432     default:
433         if(ttyDisplay->curx == CO-1)
434             topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
435 #if 0 /*JP*/
436         ttyDisplay->curx++;
437 #else
438     cw->curx = ttyDisplay->curx;
439     if(cw->curx == 0) cl_end();
440         (void) cputchar(c);
441         ++cw->curx;
442         ++ttyDisplay->curx;
443 #endif
444     }
445 }
446 /* JP
447 ** do not translate kcode this function(see putsym)
448 */
449 void
450 raw_putsyms(str)
451     const char *str;
452 {
453     while(*str)
454         raw_topl_putsym(*str++);
455 }
456 #endif
457
458 STATIC_OVL void
459 removetopl(n)
460 register int n;
461 {
462     /* assume addtopl() has been done, so ttyDisplay->toplin is already set */
463     while (n-- > 0)
464         putsyms("\b \b");
465 }
466
467 extern char erase_char; /* from xxxtty.c; don't need kill_char */
468
469 /* returns a single keystroke; also sets 'yn_number' */
470 char
471 tty_yn_function(query, resp, def)
472 const char *query, *resp;
473 char def;
474 /*
475  *   Generic yes/no function. 'def' is the default (returned by space or
476  *   return; 'esc' returns 'q', or 'n', or the default, depending on
477  *   what's in the string. The 'query' string is printed before the user
478  *   is asked about the string.
479  *   If resp is NULL, any single character is accepted and returned.
480  *   If not-NULL, only characters in it are allowed (exceptions:  the
481  *   quitchars are always allowed, and if it contains '#' then digits
482  *   are allowed); if it includes an <esc>, anything beyond that won't
483  *   be shown in the prompt to the user but will be acceptable as input.
484  */
485 {
486     register char q;
487     char rtmp[40];
488     boolean digit_ok, allow_num, preserve_case = FALSE;
489     struct WinDesc *cw = wins[WIN_MESSAGE];
490     boolean doprev = 0;
491     char prompt[BUFSZ];
492
493     yn_number = 0L;
494     if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP))
495         more();
496     cw->flags &= ~WIN_STOP;
497     ttyDisplay->toplin = 3; /* special prompt state */
498     ttyDisplay->inread++;
499     if (resp) {
500         char *rb, respbuf[QBUFSZ];
501
502         allow_num = (index(resp, '#') != 0);
503         Strcpy(respbuf, resp);
504         /* normally we force lowercase, but if any uppercase letters
505            are present in the allowed response, preserve case;
506            check this before stripping the hidden choices */
507         for (rb = respbuf; *rb; ++rb)
508             if ('A' <= *rb && *rb <= 'Z') {
509                 preserve_case = TRUE;
510                 break;
511             }
512         /* any acceptable responses that follow <esc> aren't displayed */
513         if ((rb = index(respbuf, '\033')) != 0)
514             *rb = '\0';
515         (void) strncpy(prompt, query, QBUFSZ - 1);
516         prompt[QBUFSZ - 1] = '\0';
517         Sprintf(eos(prompt), " [%s]", respbuf);
518         if (def)
519             Sprintf(eos(prompt), " (%c)", def);
520         /* not pline("%s ", prompt);
521            trailing space is wanted here in case of reprompt */
522         Strcat(prompt, " ");
523         custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s", prompt);
524     } else {
525         /* no restriction on allowed response, so always preserve case */
526         /* preserve_case = TRUE; -- moot since we're jumping to the end */
527         Sprintf(prompt, "%s ", query);
528         custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s", prompt);
529         q = readchar();
530         goto clean_up;
531     }
532
533     do { /* loop until we get valid input */
534         q = readchar();
535         if (!preserve_case)
536             q = lowc(q);
537         if (q == '\020') { /* ctrl-P */
538             if (iflags.prevmsg_window != 's') {
539                 int sav = ttyDisplay->inread;
540                 ttyDisplay->inread = 0;
541                 (void) tty_doprev_message();
542                 ttyDisplay->inread = sav;
543                 tty_clear_nhwindow(WIN_MESSAGE);
544                 cw->maxcol = cw->maxrow;
545                 addtopl(prompt);
546             } else {
547                 if (!doprev)
548                     (void) tty_doprev_message(); /* need two initially */
549                 (void) tty_doprev_message();
550                 doprev = 1;
551             }
552             q = '\0'; /* force another loop iteration */
553             continue;
554         } else if (doprev) {
555             /* BUG[?]: this probably ought to check whether the
556                character which has just been read is an acceptable
557                response; if so, skip the reprompt and use it. */
558             tty_clear_nhwindow(WIN_MESSAGE);
559             cw->maxcol = cw->maxrow;
560             doprev = 0;
561             addtopl(prompt);
562             q = '\0'; /* force another loop iteration */
563             continue;
564         }
565         digit_ok = allow_num && digit(q);
566         if (q == '\033') {
567             if (index(resp, 'q'))
568                 q = 'q';
569             else if (index(resp, 'n'))
570                 q = 'n';
571             else
572                 q = def;
573             break;
574         } else if (index(quitchars, q)) {
575             q = def;
576             break;
577         }
578         if (!index(resp, q) && !digit_ok) {
579             tty_nhbell();
580             q = (char) 0;
581         } else if (q == '#' || digit_ok) {
582             char z, digit_string[2];
583             int n_len = 0;
584             long value = 0;
585
586             addtopl("#"), n_len++;
587             digit_string[1] = '\0';
588             if (q != '#') {
589                 digit_string[0] = q;
590                 addtopl(digit_string), n_len++;
591                 value = q - '0';
592                 q = '#';
593             }
594             do { /* loop until we get a non-digit */
595                 z = readchar();
596                 if (!preserve_case)
597                     z = lowc(z);
598                 if (digit(z)) {
599                     value = (10 * value) + (z - '0');
600                     if (value < 0)
601                         break; /* overflow: try again */
602                     digit_string[0] = z;
603                     addtopl(digit_string), n_len++;
604                 } else if (z == 'y' || index(quitchars, z)) {
605                     if (z == '\033')
606                         value = -1; /* abort */
607                     z = '\n';       /* break */
608                 } else if (z == erase_char || z == '\b') {
609                     if (n_len <= 1) {
610                         value = -1;
611                         break;
612                     } else {
613                         value /= 10;
614                         removetopl(1), n_len--;
615                     }
616                 } else {
617                     value = -1; /* abort */
618                     tty_nhbell();
619                     break;
620                 }
621             } while (z != '\n');
622             if (value > 0)
623                 yn_number = value;
624             else if (value == 0)
625                 q = 'n'; /* 0 => "no" */
626             else {       /* remove number from top line, then try again */
627                 removetopl(n_len), n_len = 0;
628                 q = '\0';
629             }
630         }
631     } while (!q);
632
633  clean_up:
634     if (yn_number)
635         Sprintf(rtmp, "#%ld", yn_number);
636     else
637         (void) key2txt(q, rtmp);
638     /* addtopl(rtmp); -- rewrite toplines instead */
639     Sprintf(toplines, "%s%s", prompt, rtmp);
640 #ifdef DUMPLOG
641     dumplogmsg(toplines);
642 #endif
643     ttyDisplay->inread--;
644     ttyDisplay->toplin = 2;
645     if (ttyDisplay->intr)
646         ttyDisplay->intr--;
647     if (wins[WIN_MESSAGE]->cury)
648         tty_clear_nhwindow(WIN_MESSAGE);
649
650     return q;
651 }
652
653 /* shared by tty_getmsghistory() and tty_putmsghistory() */
654 static char **snapshot_mesgs = 0;
655
656 /* collect currently available message history data into a sequential array;
657    optionally, purge that data from the active circular buffer set as we go */
658 STATIC_OVL void
659 msghistory_snapshot(purge)
660 boolean purge; /* clear message history buffer as we copy it */
661 {
662     char *mesg;
663     int i, inidx, outidx;
664     struct WinDesc *cw;
665
666     /* paranoia (too early or too late panic save attempt?) */
667     if (WIN_MESSAGE == WIN_ERR || !wins[WIN_MESSAGE])
668         return;
669     cw = wins[WIN_MESSAGE];
670
671     /* flush toplines[], moving most recent message to history */
672     remember_topl();
673
674     /* for a passive snapshot, we just copy pointers, so can't allow further
675        history updating to take place because that could clobber them */
676     if (!purge)
677         cw->flags |= WIN_LOCKHISTORY;
678
679     snapshot_mesgs = (char **) alloc((cw->rows + 1) * sizeof(char *));
680     outidx = 0;
681     inidx = cw->maxrow;
682     for (i = 0; i < cw->rows; ++i) {
683         snapshot_mesgs[i] = (char *) 0;
684         mesg = cw->data[inidx];
685         if (mesg && *mesg) {
686             snapshot_mesgs[outidx++] = mesg;
687             if (purge) {
688                 /* we're taking this pointer away; subsequest history
689                    updates will eventually allocate a new one to replace it */
690                 cw->data[inidx] = (char *) 0;
691                 cw->datlen[inidx] = 0;
692             }
693         }
694         inidx = (inidx + 1) % cw->rows;
695     }
696     snapshot_mesgs[cw->rows] = (char *) 0; /* sentinel */
697
698     /* for a destructive snapshot, history is now completely empty */
699     if (purge)
700         cw->maxcol = cw->maxrow = 0;
701 }
702
703 /* release memory allocated to message history snapshot */
704 STATIC_OVL void
705 free_msghistory_snapshot(purged)
706 boolean purged; /* True: took history's pointers, False: just cloned them */
707 {
708     if (snapshot_mesgs) {
709         /* snapshot pointers are no longer in use */
710         if (purged) {
711             int i;
712
713             for (i = 0; snapshot_mesgs[i]; ++i)
714                 free((genericptr_t) snapshot_mesgs[i]);
715         }
716
717         free((genericptr_t) snapshot_mesgs), snapshot_mesgs = (char **) 0;
718
719         /* history can resume being updated at will now... */
720         if (!purged)
721             wins[WIN_MESSAGE]->flags &= ~WIN_LOCKHISTORY;
722     }
723 }
724
725 /*
726  * This is called by the core save routines.
727  * Each time we are called, we return one string from the
728  * message history starting with the oldest message first.
729  * When none are left, we return a final null string.
730  *
731  * History is collected at the time of the first call.
732  * Any new messages issued after that point will not be
733  * included among the output of the subsequent calls.
734  */
735 char *
736 tty_getmsghistory(init)
737 boolean init;
738 {
739     static int nxtidx;
740     char *nextmesg;
741     char *result = 0;
742
743     if (init) {
744         msghistory_snapshot(FALSE);
745         nxtidx = 0;
746     }
747
748     if (snapshot_mesgs) {
749         nextmesg = snapshot_mesgs[nxtidx++];
750         if (nextmesg) {
751             result = (char *) nextmesg;
752         } else {
753             free_msghistory_snapshot(FALSE);
754         }
755     }
756     return result;
757 }
758
759 /*
760  * This is called by the core savefile restore routines.
761  * Each time we are called, we stuff the string into our message
762  * history recall buffer. The core will send the oldest message
763  * first (actually it sends them in the order they exist in the
764  * save file, but that is supposed to be the oldest first).
765  * These messages get pushed behind any which have been issued
766  * since this session with the program has been started, since
767  * they come from a previous session and logically precede
768  * anything (like "Restoring save file...") that's happened now.
769  *
770  * Called with a null pointer to finish up restoration.
771  *
772  * It's also called by the quest pager code when a block message
773  * has a one-line summary specified.  We put that line directly
774  * into message history for ^P recall without having displayed it.
775  */
776 void
777 tty_putmsghistory(msg, restoring_msghist)
778 const char *msg;
779 boolean restoring_msghist;
780 {
781     static boolean initd = FALSE;
782     int idx;
783 #ifdef DUMPLOG
784     extern unsigned saved_pline_index; /* pline.c */
785 #endif
786
787     if (restoring_msghist && !initd) {
788         /* we're restoring history from the previous session, but new
789            messages have already been issued this session ("Restoring...",
790            for instance); collect current history (ie, those new messages),
791            and also clear it out so that nothing will be present when the
792            restored ones are being put into place */
793         msghistory_snapshot(TRUE);
794         initd = TRUE;
795 #ifdef DUMPLOG
796         /* this suffices; there's no need to scrub saved_pline[] pointers */
797         saved_pline_index = 0;
798 #endif
799     }
800
801     if (msg) {
802         /* move most recent message to history, make this become most recent */
803         remember_topl();
804         Strcpy(toplines, msg);
805 #ifdef DUMPLOG
806         dumplogmsg(toplines);
807 #endif
808     } else if (snapshot_mesgs) {
809         /* done putting arbitrary messages in; put the snapshot ones back */
810         for (idx = 0; snapshot_mesgs[idx]; ++idx) {
811             remember_topl();
812             Strcpy(toplines, snapshot_mesgs[idx]);
813 #ifdef DUMPLOG
814             dumplogmsg(toplines);
815 #endif
816         }
817         /* now release the snapshot */
818         free_msghistory_snapshot(TRUE);
819         initd = FALSE; /* reset */
820     }
821 }
822
823 #endif /* TTY_GRAPHICS */
824
825 /*topl.c*/