OSDN Git Service

fix #48255
[jnethack/source.git] / src / windows.c
1 /* NetHack 3.6  windows.c       $NHDT-Date: 1575245096 2019/12/02 00:04:56 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.60 $ */
2 /* Copyright (c) D. Cohrs, 1993. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #ifdef TTY_GRAPHICS
7 #include "wintty.h"
8 #endif
9 #ifdef CURSES_GRAPHICS
10 extern struct window_procs curses_procs;
11 #endif
12 #ifdef X11_GRAPHICS
13 /* Cannot just blindly include winX.h without including all of X11 stuff
14    and must get the order of include files right.  Don't bother. */
15 extern struct window_procs X11_procs;
16 extern void FDECL(win_X11_init, (int));
17 #endif
18 #ifdef QT_GRAPHICS
19 extern struct window_procs Qt_procs;
20 #endif
21 #ifdef GEM_GRAPHICS
22 #include "wingem.h"
23 #endif
24 #ifdef MAC
25 extern struct window_procs mac_procs;
26 #endif
27 #ifdef BEOS_GRAPHICS
28 extern struct window_procs beos_procs;
29 extern void FDECL(be_win_init, (int));
30 FAIL /* be_win_init doesn't exist? XXX*/
31 #endif
32 #ifdef AMIGA_INTUITION
33 extern struct window_procs amii_procs;
34 extern struct window_procs amiv_procs;
35 extern void FDECL(ami_wininit_data, (int));
36 #endif
37 #ifdef WIN32_GRAPHICS
38 extern struct window_procs win32_procs;
39 #endif
40 #ifdef GNOME_GRAPHICS
41 #include "winGnome.h"
42 extern struct window_procs Gnome_procs;
43 #endif
44 #ifdef MSWIN_GRAPHICS
45 extern struct window_procs mswin_procs;
46 #endif
47 #ifdef WINCHAIN
48 extern struct window_procs chainin_procs;
49 extern void FDECL(chainin_procs_init, (int));
50 extern void *FDECL(chainin_procs_chain, (int, int, void *, void *, void *));
51
52 extern struct chain_procs chainout_procs;
53 extern void FDECL(chainout_procs_init, (int));
54 extern void *FDECL(chainout_procs_chain, (int, int, void *, void *, void *));
55
56 extern struct chain_procs trace_procs;
57 extern void FDECL(trace_procs_init, (int));
58 extern void *FDECL(trace_procs_chain, (int, int, void *, void *, void *));
59 #endif
60
61 STATIC_DCL void FDECL(def_raw_print, (const char *s));
62 STATIC_DCL void NDECL(def_wait_synch);
63
64 #ifdef DUMPLOG
65 STATIC_DCL winid FDECL(dump_create_nhwindow, (int));
66 STATIC_DCL void FDECL(dump_clear_nhwindow, (winid));
67 STATIC_DCL void FDECL(dump_display_nhwindow, (winid, BOOLEAN_P));
68 STATIC_DCL void FDECL(dump_destroy_nhwindow, (winid));
69 STATIC_DCL void FDECL(dump_start_menu, (winid));
70 STATIC_DCL void FDECL(dump_add_menu, (winid, int, const ANY_P *, CHAR_P,
71                                       CHAR_P, int, const char *, BOOLEAN_P));
72 STATIC_DCL void FDECL(dump_end_menu, (winid, const char *));
73 STATIC_DCL int FDECL(dump_select_menu, (winid, int, MENU_ITEM_P **));
74 STATIC_DCL void FDECL(dump_putstr, (winid, int, const char *));
75 #endif /* DUMPLOG */
76
77 #ifdef HANGUPHANDLING
78 volatile
79 #endif
80     NEARDATA struct window_procs windowprocs;
81
82 #ifdef WINCHAIN
83 #define CHAINR(x) , x
84 #else
85 #define CHAINR(x)
86 #endif
87
88 static struct win_choices {
89     struct window_procs *procs;
90     void FDECL((*ini_routine), (int)); /* optional (can be 0) */
91 #ifdef WINCHAIN
92     void *FDECL((*chain_routine), (int, int, void *, void *, void *));
93 #endif
94 } winchoices[] = {
95 #ifdef TTY_GRAPHICS
96     { &tty_procs, win_tty_init CHAINR(0) },
97 #endif
98 #ifdef CURSES_GRAPHICS
99     { &curses_procs, 0 },
100 #endif
101 #ifdef X11_GRAPHICS
102     { &X11_procs, win_X11_init CHAINR(0) },
103 #endif
104 #ifdef QT_GRAPHICS
105     { &Qt_procs, 0 CHAINR(0) },
106 #endif
107 #ifdef GEM_GRAPHICS
108     { &Gem_procs, win_Gem_init CHAINR(0) },
109 #endif
110 #ifdef MAC
111     { &mac_procs, 0 CHAINR(0) },
112 #endif
113 #ifdef BEOS_GRAPHICS
114     { &beos_procs, be_win_init CHAINR(0) },
115 #endif
116 #ifdef AMIGA_INTUITION
117     { &amii_procs,
118       ami_wininit_data CHAINR(0) }, /* Old font version of the game */
119     { &amiv_procs,
120       ami_wininit_data CHAINR(0) }, /* Tile version of the game */
121 #endif
122 #ifdef WIN32_GRAPHICS
123     { &win32_procs, 0 CHAINR(0) },
124 #endif
125 #ifdef GNOME_GRAPHICS
126     { &Gnome_procs, 0 CHAINR(0) },
127 #endif
128 #ifdef MSWIN_GRAPHICS
129     { &mswin_procs, 0 CHAINR(0) },
130 #endif
131 #ifdef WINCHAIN
132     { &chainin_procs, chainin_procs_init, chainin_procs_chain },
133     { (struct window_procs *) &chainout_procs, chainout_procs_init,
134       chainout_procs_chain },
135
136     { (struct window_procs *) &trace_procs, trace_procs_init,
137       trace_procs_chain },
138 #endif
139     { 0, 0 CHAINR(0) } /* must be last */
140 };
141
142 #ifdef WINCHAIN
143 struct winlink {
144     struct winlink *nextlink;
145     struct win_choices *wincp;
146     void *linkdata;
147 };
148 /* NB: this chain does not contain the terminal real window system pointer */
149
150 static struct winlink *chain = 0;
151
152 static struct winlink *
153 wl_new()
154 {
155     struct winlink *wl = (struct winlink *) alloc(sizeof *wl);
156
157     wl->nextlink = 0;
158     wl->wincp = 0;
159     wl->linkdata = 0;
160
161     return wl;
162 }
163
164 static void
165 wl_addhead(struct winlink *wl)
166 {
167     wl->nextlink = chain;
168     chain = wl;
169 }
170
171 static void
172 wl_addtail(struct winlink *wl)
173 {
174     struct winlink *p = chain;
175
176     if (!chain) {
177         chain = wl;
178         return;
179     }
180     while (p->nextlink) {
181         p = p->nextlink;
182     }
183     p->nextlink = wl;
184     return;
185 }
186 #endif /* WINCHAIN */
187
188 static struct win_choices *last_winchoice = 0;
189
190 boolean
191 genl_can_suspend_no(VOID_ARGS)
192 {
193     return FALSE;
194 }
195
196 boolean
197 genl_can_suspend_yes(VOID_ARGS)
198 {
199     return TRUE;
200 }
201
202 STATIC_OVL
203 void
204 def_raw_print(s)
205 const char *s;
206 {
207     puts(s);
208 }
209
210 STATIC_OVL
211 void
212 def_wait_synch(VOID_ARGS)
213 {
214     /* Config file error handling routines
215      * call wait_sync() without checking to
216      * see if it actually has a value,
217      * leading to spectacular violations
218      * when you try to execute address zero.
219      * The existence of this allows early
220      * processing to have something to execute
221      * even though it essentially does nothing
222      */
223      return;
224 }
225
226 #ifdef WINCHAIN
227 static struct win_choices *
228 win_choices_find(s)
229 const char *s;
230 {
231     register int i;
232
233     for (i = 0; winchoices[i].procs; i++) {
234         if (!strcmpi(s, winchoices[i].procs->name)) {
235             return &winchoices[i];
236         }
237     }
238     return (struct win_choices *) 0;
239 }
240 #endif
241
242 void
243 choose_windows(s)
244 const char *s;
245 {
246     int i;
247     char *tmps = 0;
248
249     for (i = 0; winchoices[i].procs; i++) {
250         if ('+' == winchoices[i].procs->name[0])
251             continue;
252         if ('-' == winchoices[i].procs->name[0])
253             continue;
254         if (!strcmpi(s, winchoices[i].procs->name)) {
255             windowprocs = *winchoices[i].procs;
256
257             if (last_winchoice && last_winchoice->ini_routine)
258                 (*last_winchoice->ini_routine)(WININIT_UNDO);
259             if (winchoices[i].ini_routine)
260                 (*winchoices[i].ini_routine)(WININIT);
261             last_winchoice = &winchoices[i];
262             return;
263         }
264     }
265
266     if (!windowprocs.win_raw_print)
267         windowprocs.win_raw_print = def_raw_print;
268     if (!windowprocs.win_wait_synch)
269         /* early config file error processing routines call this */
270         windowprocs.win_wait_synch = def_wait_synch;
271
272     if (!winchoices[0].procs) {
273         raw_printf("No window types supported?");
274         nh_terminate(EXIT_FAILURE);
275     }
276     /* 50: arbitrary, no real window_type names are anywhere near that long;
277        used to prevent potential raw_printf() overflow if user supplies a
278        very long string (on the order of 1200 chars) on the command line
279        (config file options can't get that big; they're truncated at 1023) */
280 #define WINDOW_TYPE_MAXLEN 50
281     if (strlen(s) >= WINDOW_TYPE_MAXLEN) {
282         tmps = (char *) alloc(WINDOW_TYPE_MAXLEN);
283         (void) strncpy(tmps, s, WINDOW_TYPE_MAXLEN - 1);
284         tmps[WINDOW_TYPE_MAXLEN - 1] = '\0';
285         s = tmps;
286     }
287 #undef WINDOW_TYPE_MAXLEN
288
289     if (!winchoices[1].procs) {
290         config_error_add(
291                      "Window type %s not recognized.  The only choice is: %s",
292                          s, winchoices[0].procs->name);
293     } else {
294         char buf[BUFSZ];
295         boolean first = TRUE;
296
297         buf[0] = '\0';
298         for (i = 0; winchoices[i].procs; i++) {
299             if ('+' == winchoices[i].procs->name[0])
300                 continue;
301             if ('-' == winchoices[i].procs->name[0])
302                 continue;
303             Sprintf(eos(buf), "%s%s",
304                     first ? "" : ", ", winchoices[i].procs->name);
305             first = FALSE;
306         }
307         config_error_add("Window type %s not recognized.  Choices are:  %s",
308                          s, buf);
309     }
310     if (tmps)
311         free((genericptr_t) tmps) /*, tmps = 0*/ ;
312
313     if (windowprocs.win_raw_print == def_raw_print
314             || WINDOWPORT("safe-startup"))
315         nh_terminate(EXIT_SUCCESS);
316 }
317
318 #ifdef WINCHAIN
319 void
320 addto_windowchain(s)
321 const char *s;
322 {
323     register int i;
324
325     for (i = 0; winchoices[i].procs; i++) {
326         if ('+' != winchoices[i].procs->name[0])
327             continue;
328         if (!strcmpi(s, winchoices[i].procs->name)) {
329             struct winlink *p = wl_new();
330
331             p->wincp = &winchoices[i];
332             wl_addtail(p);
333             /* NB: The ini_routine() will be called during commit. */
334             return;
335         }
336     }
337
338     windowprocs.win_raw_print = def_raw_print;
339
340     raw_printf("Window processor %s not recognized.  Choices are:", s);
341     for (i = 0; winchoices[i].procs; i++) {
342         if ('+' != winchoices[i].procs->name[0])
343             continue;
344         raw_printf("        %s", winchoices[i].procs->name);
345     }
346
347     nh_terminate(EXIT_FAILURE);
348 }
349
350 void
351 commit_windowchain()
352 {
353     struct winlink *p;
354     int n;
355     int wincap, wincap2;
356
357     if (!chain)
358         return;
359
360     /* Save wincap* from the real window system - we'll restore it below. */
361     wincap = windowprocs.wincap;
362     wincap2 = windowprocs.wincap2;
363
364     /* add -chainin at head and -chainout at tail */
365     p = wl_new();
366     p->wincp = win_choices_find("-chainin");
367     if (!p->wincp) {
368         raw_printf("Can't locate processor '-chainin'");
369         exit(EXIT_FAILURE);
370     }
371     wl_addhead(p);
372
373     p = wl_new();
374     p->wincp = win_choices_find("-chainout");
375     if (!p->wincp) {
376         raw_printf("Can't locate processor '-chainout'");
377         exit(EXIT_FAILURE);
378     }
379     wl_addtail(p);
380
381     /* Now alloc() init() similar to Objective-C. */
382     for (n = 1, p = chain; p; n++, p = p->nextlink) {
383         p->linkdata = (*p->wincp->chain_routine)(WINCHAIN_ALLOC, n, 0, 0, 0);
384     }
385
386     for (n = 1, p = chain; p; n++, p = p->nextlink) {
387         if (p->nextlink) {
388             (void) (*p->wincp->chain_routine)(WINCHAIN_INIT, n, p->linkdata,
389                                               p->nextlink->wincp->procs,
390                                               p->nextlink->linkdata);
391         } else {
392             (void) (*p->wincp->chain_routine)(WINCHAIN_INIT, n, p->linkdata,
393                                               last_winchoice->procs, 0);
394         }
395     }
396
397     /* Restore the saved wincap* values.  We do it here to give the
398      * ini_routine()s a chance to change or check them. */
399     chain->wincp->procs->wincap = wincap;
400     chain->wincp->procs->wincap2 = wincap2;
401
402     /* Call the init procs.  Do not re-init the terminal real win. */
403     p = chain;
404     while (p->nextlink) {
405         if (p->wincp->ini_routine) {
406             (*p->wincp->ini_routine)(WININIT);
407         }
408         p = p->nextlink;
409     }
410
411     /* Install the chain into window procs very late so ini_routine()s
412      * can raw_print on error. */
413     windowprocs = *chain->wincp->procs;
414
415     p = chain;
416     while (p) {
417         struct winlink *np = p->nextlink;
418         free(p);
419         p = np; /* assignment, not proof */
420     }
421 }
422 #endif /* WINCHAIN */
423
424 /*
425  * tty_message_menu() provides a means to get feedback from the
426  * --More-- prompt; other interfaces generally don't need that.
427  */
428 /*ARGSUSED*/
429 char
430 genl_message_menu(let, how, mesg)
431 char let UNUSED;
432 int how UNUSED;
433 const char *mesg;
434 {
435     pline("%s", mesg);
436     return 0;
437 }
438
439 /*ARGSUSED*/
440 void
441 genl_preference_update(pref)
442 const char *pref UNUSED;
443 {
444     /* window ports are expected to provide
445        their own preference update routine
446        for the preference capabilities that
447        they support.
448        Just return in this genl one. */
449     return;
450 }
451
452 char *
453 genl_getmsghistory(init)
454 boolean init UNUSED;
455 {
456     /* window ports can provide
457        their own getmsghistory() routine to
458        preserve message history between games.
459        The routine is called repeatedly from
460        the core save routine, and the window
461        port is expected to successively return
462        each message that it wants saved, starting
463        with the oldest message first, finishing
464        with the most recent.
465        Return null pointer when finished.
466      */
467     return (char *) 0;
468 }
469
470 void
471 genl_putmsghistory(msg, is_restoring)
472 const char *msg;
473 boolean is_restoring;
474 {
475     /* window ports can provide
476        their own putmsghistory() routine to
477        load message history from a saved game.
478        The routine is called repeatedly from
479        the core restore routine, starting with
480        the oldest saved message first, and
481        finishing with the latest.
482        The window port routine is expected to
483        load the message recall buffers in such
484        a way that the ordering is preserved.
485        The window port routine should make no
486        assumptions about how many messages are
487        forthcoming, nor should it assume that
488        another message will follow this one,
489        so it should keep all pointers/indexes
490        intact at the end of each call.
491     */
492
493     /* this doesn't provide for reloading the message window with the
494        previous session's messages upon restore, but it does put the quest
495        message summary lines there by treating them as ordinary messages */
496     if (!is_restoring)
497         pline("%s", msg);
498     return;
499 }
500
501 #ifdef HANGUPHANDLING
502 /*
503  * Dummy windowing scheme used to replace current one with no-ops
504  * in order to avoid all terminal I/O after hangup/disconnect.
505  */
506
507 static int NDECL(hup_nhgetch);
508 static char FDECL(hup_yn_function, (const char *, const char *, CHAR_P));
509 static int FDECL(hup_nh_poskey, (int *, int *, int *));
510 static void FDECL(hup_getlin, (const char *, char *));
511 static void FDECL(hup_init_nhwindows, (int *, char **));
512 static void FDECL(hup_exit_nhwindows, (const char *));
513 static winid FDECL(hup_create_nhwindow, (int));
514 static int FDECL(hup_select_menu, (winid, int, MENU_ITEM_P **));
515 static void FDECL(hup_add_menu, (winid, int, const anything *, CHAR_P, CHAR_P,
516                                  int, const char *, BOOLEAN_P));
517 static void FDECL(hup_end_menu, (winid, const char *));
518 static void FDECL(hup_putstr, (winid, int, const char *));
519 static void FDECL(hup_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int));
520 static void FDECL(hup_outrip, (winid, int, time_t));
521 static void FDECL(hup_curs, (winid, int, int));
522 static void FDECL(hup_display_nhwindow, (winid, BOOLEAN_P));
523 static void FDECL(hup_display_file, (const char *, BOOLEAN_P));
524 #ifdef CLIPPING
525 static void FDECL(hup_cliparound, (int, int));
526 #endif
527 #ifdef CHANGE_COLOR
528 static void FDECL(hup_change_color, (int, long, int));
529 #ifdef MAC
530 static short FDECL(hup_set_font_name, (winid, char *));
531 #endif
532 static char *NDECL(hup_get_color_string);
533 #endif /* CHANGE_COLOR */
534 static void FDECL(hup_status_update, (int, genericptr_t, int, int, int,
535                                       unsigned long *));
536
537 static int NDECL(hup_int_ndecl);
538 static void NDECL(hup_void_ndecl);
539 static void FDECL(hup_void_fdecl_int, (int));
540 static void FDECL(hup_void_fdecl_winid, (winid));
541 static void FDECL(hup_void_fdecl_constchar_p, (const char *));
542
543 static struct window_procs hup_procs = {
544     "hup", 0L, 0L,
545     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
546     hup_init_nhwindows,
547     hup_void_ndecl,                                    /* player_selection */
548     hup_void_ndecl,                                    /* askname */
549     hup_void_ndecl,                                    /* get_nh_event */
550     hup_exit_nhwindows, hup_void_fdecl_constchar_p,    /* suspend_nhwindows */
551     hup_void_ndecl,                                    /* resume_nhwindows */
552     hup_create_nhwindow, hup_void_fdecl_winid,         /* clear_nhwindow */
553     hup_display_nhwindow, hup_void_fdecl_winid,        /* destroy_nhwindow */
554     hup_curs, hup_putstr, hup_putstr,                  /* putmixed */
555     hup_display_file, hup_void_fdecl_winid,            /* start_menu */
556     hup_add_menu, hup_end_menu, hup_select_menu, genl_message_menu,
557     hup_void_ndecl,                                    /* update_inventory */
558     hup_void_ndecl,                                    /* mark_synch */
559     hup_void_ndecl,                                    /* wait_synch */
560 #ifdef CLIPPING
561     hup_cliparound,
562 #endif
563 #ifdef POSITIONBAR
564     (void FDECL((*), (char *))) hup_void_fdecl_constchar_p,
565                                                       /* update_positionbar */
566 #endif
567     hup_print_glyph,
568     hup_void_fdecl_constchar_p,                       /* raw_print */
569     hup_void_fdecl_constchar_p,                       /* raw_print_bold */
570     hup_nhgetch, hup_nh_poskey, hup_void_ndecl,       /* nhbell  */
571     hup_int_ndecl,                                    /* doprev_message */
572     hup_yn_function, hup_getlin, hup_int_ndecl,       /* get_ext_cmd */
573     hup_void_fdecl_int,                               /* number_pad */
574     hup_void_ndecl,                                   /* delay_output  */
575 #ifdef CHANGE_COLOR
576     hup_change_color,
577 #ifdef MAC
578     hup_void_fdecl_int,                               /* change_background */
579     hup_set_font_name,
580 #endif
581     hup_get_color_string,
582 #endif /* CHANGE_COLOR */
583     hup_void_ndecl,                                   /* start_screen */
584     hup_void_ndecl,                                   /* end_screen */
585     hup_outrip, genl_preference_update, genl_getmsghistory,
586     genl_putmsghistory,
587     hup_void_ndecl,                                   /* status_init */
588     hup_void_ndecl,                                   /* status_finish */
589     genl_status_enablefield, hup_status_update,
590     genl_can_suspend_no,
591 };
592
593 static void FDECL((*previnterface_exit_nhwindows), (const char *)) = 0;
594
595 /* hangup has occurred; switch to no-op user interface */
596 void
597 nhwindows_hangup()
598 {
599     char *FDECL((*previnterface_getmsghistory), (BOOLEAN_P)) = 0;
600
601 #ifdef ALTMETA
602     /* command processor shouldn't look for 2nd char after seeing ESC */
603     iflags.altmeta = FALSE;
604 #endif
605
606     /* don't call exit_nhwindows() directly here; if a hangup occurs
607        while interface code is executing, exit_nhwindows could knock
608        the interface's active data structures out from under itself */
609     if (iflags.window_inited
610         && windowprocs.win_exit_nhwindows != hup_exit_nhwindows)
611         previnterface_exit_nhwindows = windowprocs.win_exit_nhwindows;
612
613     /* also, we have to leave the old interface's getmsghistory()
614        in place because it will be called while saving the game */
615     if (windowprocs.win_getmsghistory != hup_procs.win_getmsghistory)
616         previnterface_getmsghistory = windowprocs.win_getmsghistory;
617
618     windowprocs = hup_procs;
619
620     if (previnterface_getmsghistory)
621         windowprocs.win_getmsghistory = previnterface_getmsghistory;
622 }
623
624 static void
625 hup_exit_nhwindows(lastgasp)
626 const char *lastgasp;
627 {
628     /* core has called exit_nhwindows(); call the previous interface's
629        shutdown routine now; xxx_exit_nhwindows() needs to call other
630        xxx_ routines directly rather than through windowprocs pointers */
631     if (previnterface_exit_nhwindows) {
632         lastgasp = 0; /* don't want exit routine to attempt extra output */
633         (*previnterface_exit_nhwindows)(lastgasp);
634         previnterface_exit_nhwindows = 0;
635     }
636     iflags.window_inited = 0;
637 }
638
639 static int
640 hup_nhgetch(VOID_ARGS)
641 {
642     return '\033'; /* ESC */
643 }
644
645 /*ARGSUSED*/
646 static char
647 hup_yn_function(prompt, resp, deflt)
648 const char *prompt UNUSED, *resp UNUSED;
649 char deflt;
650 {
651     if (!deflt)
652         deflt = '\033';
653     return deflt;
654 }
655
656 /*ARGSUSED*/
657 static int
658 hup_nh_poskey(x, y, mod)
659 int *x UNUSED, *y UNUSED, *mod UNUSED;
660 {
661     return '\033';
662 }
663
664 /*ARGSUSED*/
665 static void
666 hup_getlin(prompt, outbuf)
667 const char *prompt UNUSED;
668 char *outbuf;
669 {
670     Strcpy(outbuf, "\033");
671 }
672
673 /*ARGSUSED*/
674 static void
675 hup_init_nhwindows(argc_p, argv)
676 int *argc_p UNUSED;
677 char **argv UNUSED;
678 {
679     iflags.window_inited = 1;
680 }
681
682 /*ARGUSED*/
683 static winid
684 hup_create_nhwindow(type)
685 int type UNUSED;
686 {
687     return WIN_ERR;
688 }
689
690 /*ARGSUSED*/
691 static int
692 hup_select_menu(window, how, menu_list)
693 winid window UNUSED;
694 int how UNUSED;
695 struct mi **menu_list UNUSED;
696 {
697     return -1;
698 }
699
700 /*ARGSUSED*/
701 static void
702 hup_add_menu(window, glyph, identifier, sel, grpsel, attr, txt, preselected)
703 winid window UNUSED;
704 int glyph UNUSED, attr UNUSED;
705 const anything *identifier UNUSED;
706 char sel UNUSED, grpsel UNUSED;
707 const char *txt UNUSED;
708 boolean preselected UNUSED;
709 {
710     return;
711 }
712
713 /*ARGSUSED*/
714 static void
715 hup_end_menu(window, prompt)
716 winid window UNUSED;
717 const char *prompt UNUSED;
718 {
719     return;
720 }
721
722 /*ARGSUSED*/
723 static void
724 hup_putstr(window, attr, text)
725 winid window UNUSED;
726 int attr UNUSED;
727 const char *text UNUSED;
728 {
729     return;
730 }
731
732 /*ARGSUSED*/
733 static void
734 hup_print_glyph(window, x, y, glyph, bkglyph)
735 winid window UNUSED;
736 xchar x UNUSED, y UNUSED;
737 int glyph UNUSED;
738 int bkglyph UNUSED;
739 {
740     return;
741 }
742
743 /*ARGSUSED*/
744 static void
745 hup_outrip(tmpwin, how, when)
746 winid tmpwin UNUSED;
747 int how UNUSED;
748 time_t when UNUSED;
749 {
750     return;
751 }
752
753 /*ARGSUSED*/
754 static void
755 hup_curs(window, x, y)
756 winid window UNUSED;
757 int x UNUSED, y UNUSED;
758 {
759     return;
760 }
761
762 /*ARGSUSED*/
763 static void
764 hup_display_nhwindow(window, blocking)
765 winid window UNUSED;
766 boolean blocking UNUSED;
767 {
768     return;
769 }
770
771 /*ARGSUSED*/
772 static void
773 hup_display_file(fname, complain)
774 const char *fname UNUSED;
775 boolean complain UNUSED;
776 {
777     return;
778 }
779
780 #ifdef CLIPPING
781 /*ARGSUSED*/
782 static void
783 hup_cliparound(x, y)
784 int x UNUSED, y UNUSED;
785 {
786     return;
787 }
788 #endif
789
790 #ifdef CHANGE_COLOR
791 /*ARGSUSED*/
792 static void
793 hup_change_color(color, rgb, reverse)
794 int color, reverse;
795 long rgb;
796 {
797     return;
798 }
799
800 #ifdef MAC
801 /*ARGSUSED*/
802 static short
803 hup_set_font_name(window, fontname)
804 winid window;
805 char *fontname;
806 {
807     return 0;
808 }
809 #endif /* MAC */
810
811 static char *
812 hup_get_color_string(VOID_ARGS)
813 {
814     return (char *) 0;
815 }
816 #endif /* CHANGE_COLOR */
817
818 /*ARGSUSED*/
819 static void
820 hup_status_update(idx, ptr, chg, pc, color, colormasks)
821 int idx UNUSED;
822 genericptr_t ptr UNUSED;
823 int chg UNUSED, pc UNUSED, color UNUSED;
824 unsigned long *colormasks UNUSED;
825
826 {
827     return;
828 }
829
830 /*
831  * Non-specific stubs.
832  */
833
834 static int
835 hup_int_ndecl(VOID_ARGS)
836 {
837     return -1;
838 }
839
840 static void
841 hup_void_ndecl(VOID_ARGS)
842 {
843     return;
844 }
845
846 /*ARGUSED*/
847 static void
848 hup_void_fdecl_int(arg)
849 int arg UNUSED;
850 {
851     return;
852 }
853
854 /*ARGUSED*/
855 static void
856 hup_void_fdecl_winid(window)
857 winid window UNUSED;
858 {
859     return;
860 }
861
862 /*ARGUSED*/
863 static void
864 hup_void_fdecl_constchar_p(string)
865 const char *string UNUSED;
866 {
867     return;
868 }
869
870 #endif /* HANGUPHANDLING */
871
872
873 /****************************************************************************/
874 /* genl backward compat stuff                                               */
875 /****************************************************************************/
876
877 const char *status_fieldnm[MAXBLSTATS];
878 const char *status_fieldfmt[MAXBLSTATS];
879 char *status_vals[MAXBLSTATS];
880 boolean status_activefields[MAXBLSTATS];
881
882 void
883 genl_status_init()
884 {
885     int i;
886
887     for (i = 0; i < MAXBLSTATS; ++i) {
888         status_vals[i] = (char *) alloc(MAXCO);
889         *status_vals[i] = '\0';
890         status_activefields[i] = FALSE;
891         status_fieldfmt[i] = (const char *) 0;
892     }
893     /* Use a window for the genl version; backward port compatibility */
894     WIN_STATUS = create_nhwindow(NHW_STATUS);
895     display_nhwindow(WIN_STATUS, FALSE);
896 }
897
898 void
899 genl_status_finish()
900 {
901     /* tear down routine */
902     int i;
903
904     /* free alloc'd memory here */
905     for (i = 0; i < MAXBLSTATS; ++i) {
906         if (status_vals[i])
907             free((genericptr_t) status_vals[i]), status_vals[i] = (char *) 0;
908     }
909 }
910
911 void
912 genl_status_enablefield(fieldidx, nm, fmt, enable)
913 int fieldidx;
914 const char *nm;
915 const char *fmt;
916 boolean enable;
917 {
918     status_fieldfmt[fieldidx] = fmt;
919     status_fieldnm[fieldidx] = nm;
920     status_activefields[fieldidx] = enable;
921 }
922
923 /* call once for each field, then call with BL_FLUSH to output the result */
924 void
925 genl_status_update(idx, ptr, chg, percent, color, colormasks)
926 int idx;
927 genericptr_t ptr;
928 int chg UNUSED, percent UNUSED, color UNUSED;
929 unsigned long *colormasks UNUSED;
930 {
931     char newbot1[MAXCO], newbot2[MAXCO];
932     long cond, *condptr = (long *) ptr;
933     register int i;
934     unsigned pass, lndelta;
935     enum statusfields idx1, idx2, *fieldlist;
936     char *nb, *text = (char *) ptr;
937
938     static enum statusfields fieldorder[][15] = {
939         /* line one */
940         { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
941           BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
942           BL_FLUSH },
943         /* line two, default order */
944         { BL_LEVELDESC, BL_GOLD,
945           BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
946           BL_XP, BL_EXP, BL_HD,
947           BL_TIME,
948           BL_HUNGER, BL_CAP, BL_CONDITION,
949           BL_FLUSH },
950         /* move time to the end */
951         { BL_LEVELDESC, BL_GOLD,
952           BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
953           BL_XP, BL_EXP, BL_HD,
954           BL_HUNGER, BL_CAP, BL_CONDITION,
955           BL_TIME, BL_FLUSH },
956         /* move experience and time to the end */
957         { BL_LEVELDESC, BL_GOLD,
958           BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
959           BL_HUNGER, BL_CAP, BL_CONDITION,
960           BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
961         /* move level description plus gold and experience and time to end */
962         { BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
963           BL_HUNGER, BL_CAP, BL_CONDITION,
964           BL_LEVELDESC, BL_GOLD, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
965     };
966
967     /* in case interface is using genl_status_update() but has not
968        specified WC2_FLUSH_STATUS (status_update() for field values
969        is buffered so final BL_FLUSH is needed to produce output) */
970     windowprocs.wincap2 |= WC2_FLUSH_STATUS;
971
972     if (idx >= 0) {
973         if (!status_activefields[idx])
974             return;
975         switch (idx) {
976         case BL_CONDITION:
977             cond = condptr ? *condptr : 0L;
978             nb = status_vals[idx];
979             *nb = '\0';
980             if (cond & BL_MASK_STONE)
981 /*JP
982                 Strcpy(nb = eos(nb), " Stone");
983 */
984                 Strcpy(nb = eos(nb), " \90ÃŽ\89»");
985             if (cond & BL_MASK_SLIME)
986 /*JP
987                 Strcpy(nb = eos(nb), " Slime");
988 */
989                 Strcpy(nb = eos(nb), " \82Ç\82ë\82Ç\82ë");
990             if (cond & BL_MASK_STRNGL)
991 /*JP
992                 Strcpy(nb = eos(nb), " Strngl");
993 */
994                 Strcpy(nb = eos(nb), " \92\82\91§");
995             if (cond & BL_MASK_FOODPOIS)
996 /*JP
997                 Strcpy(nb = eos(nb), " FoodPois");
998 */
999                 Strcpy(nb = eos(nb), " \90H\93Ã…");
1000             if (cond & BL_MASK_TERMILL)
1001 /*JP
1002                 Strcpy(nb = eos(nb), " TermIll");
1003 */
1004                 Strcpy(nb = eos(nb), " \95a\8bC");
1005             if (cond & BL_MASK_BLIND)
1006 /*JP
1007                 Strcpy(nb = eos(nb), " Blind");
1008 */
1009                 Strcpy(nb = eos(nb), " \96Ó\96Ú");
1010             if (cond & BL_MASK_DEAF)
1011 /*JP
1012                 Strcpy(nb = eos(nb), " Deaf");
1013 */
1014                 Strcpy(nb = eos(nb), " \8e¨\98W");
1015             if (cond & BL_MASK_STUN)
1016 /*JP
1017                 Strcpy(nb = eos(nb), " Stun");
1018 */
1019                 Strcpy(nb = eos(nb), " Ã¡Â¿\9dò");
1020             if (cond & BL_MASK_CONF)
1021 /*JP
1022                 Strcpy(nb = eos(nb), " Conf");
1023 */
1024                 Strcpy(nb = eos(nb), " \8d¬\97\90");
1025             if (cond & BL_MASK_HALLU)
1026 /*JP
1027                 Strcpy(nb = eos(nb), " Hallu");
1028 */
1029                 Strcpy(nb = eos(nb), " \8c¶\8ao");
1030             if (cond & BL_MASK_LEV)
1031 /*JP
1032                 Strcpy(nb = eos(nb), " Lev");
1033 */
1034                 Strcpy(nb = eos(nb), " \95\82\97V");
1035             if (cond & BL_MASK_FLY)
1036 /*JP
1037                 Strcpy(nb = eos(nb), " Fly");
1038 */
1039                 Strcpy(nb = eos(nb), " \94ò\8ds");
1040             if (cond & BL_MASK_RIDE)
1041 /*JP
1042                 Strcpy(nb = eos(nb), " Ride");
1043 */
1044                 Strcpy(nb = eos(nb), " \8bR\8fæ");
1045             break;
1046         default:
1047             Sprintf(status_vals[idx],
1048                     status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s",
1049                     text ? text : "");
1050             break;
1051         }
1052         return; /* processed one field other than BL_FLUSH */
1053     } /* (idx >= 0, thus not BL_FLUSH, BL_RESET, BL_CHARACTERISTICS) */
1054
1055     /* does BL_RESET require any specific code to ensure all fields ? */
1056
1057     if (!(idx == BL_FLUSH || idx == BL_RESET))
1058         return;
1059
1060     /* We've received BL_FLUSH; time to output the gathered data */
1061     nb = newbot1;
1062     *nb = '\0';
1063     /* BL_FLUSH is the only pseudo-index value we need to check for
1064        in the loop below because it is the only entry used to pad the
1065        end of the fieldorder array. We could stop on any
1066        negative (illegal) index, but this should be fine */
1067     for (i = 0; (idx1 = fieldorder[0][i]) != BL_FLUSH; ++i) {
1068         if (status_activefields[idx1])
1069             Strcpy(nb = eos(nb), status_vals[idx1]);
1070     }
1071     /* if '$' is encoded, buffer length of \GXXXXNNNN is 9 greater than
1072        single char; we want to subtract that 9 when checking display length */
1073     lndelta = (status_activefields[BL_GOLD]
1074                && strstr(status_vals[BL_GOLD], "\\G")) ? 9 : 0;
1075     /* basic bot2 formats groups of second line fields into five buffers,
1076        then decides how to order those buffers based on comparing lengths
1077        of [sub]sets of them to the width of the map; we have more control
1078        here but currently emulate that behavior */
1079     for (pass = 1; pass <= 4; pass++) {
1080         fieldlist = fieldorder[pass];
1081         nb = newbot2;
1082         *nb = '\0';
1083         for (i = 0; (idx2 = fieldlist[i]) != BL_FLUSH; ++i) {
1084             if (status_activefields[idx2]) {
1085                 const char *val = status_vals[idx2];
1086
1087                 switch (idx2) {
1088                 case BL_HP: /* for pass 4, Hp comes first; mungspaces()
1089                                will strip the unwanted leading spaces */
1090                 case BL_XP: case BL_HD:
1091                 case BL_TIME:
1092                     Strcpy(nb = eos(nb), " ");
1093                     break;
1094                 case BL_LEVELDESC:
1095                     /* leveldesc has no leading space, so if we've moved
1096                        it past the first position, provide one */
1097                     if (i != 0)
1098                         Strcpy(nb = eos(nb), " ");
1099                     break;
1100                 /*
1101                  * We want "  hunger encumbrance conditions"
1102                  *   or    "  encumbrance conditions"
1103                  *   or    "  hunger conditions"
1104                  *   or    "  conditions"
1105                  * 'hunger'      is either " " or " hunger_text";
1106                  * 'encumbrance' is either " " or " encumbrance_text";
1107                  * 'conditions'  is either ""  or " cond1 cond2...".
1108                  */
1109                 case BL_HUNGER:
1110                     /* hunger==" " - keep it, end up with " ";
1111                        hunger!=" " - insert space and get "  hunger" */
1112                     if (strcmp(val, " "))
1113                         Strcpy(nb = eos(nb), " ");
1114                     break;
1115                 case BL_CAP:
1116                     /* cap==" " - suppress it, retain "  hunger" or " ";
1117                        cap!=" " - use it, get "  hunger cap" or "  cap" */
1118                     if (!strcmp(val, " "))
1119                         ++val;
1120                     break;
1121                 default:
1122                     break;
1123                 }
1124                 Strcpy(nb = eos(nb), val); /* status_vals[idx2] */
1125             } /* status_activefields[idx2] */
1126
1127             if (idx2 == BL_CONDITION && pass < 4
1128                 && strlen(newbot2) - lndelta > COLNO)
1129                 break; /* switch to next order */
1130         } /* i */
1131
1132         if (idx2 == BL_FLUSH) { /* made it past BL_CONDITION */
1133             if (pass > 1)
1134                 mungspaces(newbot2);
1135             break;
1136         }
1137     } /* pass */
1138     curs(WIN_STATUS, 1, 0);
1139     putstr(WIN_STATUS, 0, newbot1);
1140     curs(WIN_STATUS, 1, 1);
1141     putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */
1142 }
1143
1144 STATIC_VAR struct window_procs dumplog_windowprocs_backup;
1145 STATIC_VAR FILE *dumplog_file;
1146
1147 #ifdef DUMPLOG
1148 STATIC_VAR time_t dumplog_now;
1149
1150 char *
1151 dump_fmtstr(fmt, buf, fullsubs)
1152 const char *fmt;
1153 char *buf;
1154 boolean fullsubs; /* True -> full substitution for file name, False ->
1155                    * partial substitution for '--showpaths' feedback
1156                    * where there's no game in progress when executed */
1157 {
1158     const char *fp = fmt;
1159     char *bp = buf;
1160     int slen, len = 0;
1161     char tmpbuf[BUFSZ];
1162     char verbuf[BUFSZ];
1163     long uid;
1164     time_t now;
1165
1166     now = dumplog_now;
1167     uid = (long) getuid();
1168
1169     /*
1170      * Note: %t and %T assume that time_t is a 'long int' number of
1171      * seconds since some epoch value.  That's quite iffy....  The
1172      * unit of time might be different and the datum size might be
1173      * some variant of 'long long int'.  [Their main purpose is to
1174      * construct a unique file name rather than record the date and
1175      * time; violating the 'long seconds since base-date' assumption
1176      * may or may not interfere with that usage.]
1177      */
1178
1179     while (fp && *fp && len < BUFSZ - 1) {
1180         if (*fp == '%') {
1181             fp++;
1182             switch (*fp) {
1183             default:
1184                 goto finish;
1185             case '\0': /* fallthrough */
1186             case '%':  /* literal % */
1187                 Sprintf(tmpbuf, "%%");
1188                 break;
1189             case 't': /* game start, timestamp */
1190                 if (fullsubs)
1191                     Sprintf(tmpbuf, "%lu", (unsigned long) ubirthday);
1192                 else
1193                     Strcpy(tmpbuf, "{game start cookie}");
1194                 break;
1195             case 'T': /* current time, timestamp */
1196                 if (fullsubs)
1197                     Sprintf(tmpbuf, "%lu", (unsigned long) now);
1198                 else
1199                     Strcpy(tmpbuf, "{current time cookie}");
1200                 break;
1201             case 'd': /* game start, YYYYMMDDhhmmss */
1202                 if (fullsubs)
1203                     Sprintf(tmpbuf, "%08ld%06ld",
1204                             yyyymmdd(ubirthday), hhmmss(ubirthday));
1205                 else
1206                     Strcpy(tmpbuf, "{game start date+time}");
1207                 break;
1208             case 'D': /* current time, YYYYMMDDhhmmss */
1209                 if (fullsubs)
1210                     Sprintf(tmpbuf, "%08ld%06ld", yyyymmdd(now), hhmmss(now));
1211                 else
1212                     Strcpy(tmpbuf, "{current date+time}");
1213                 break;
1214             case 'v': /* version, eg. "3.6.5-0" */
1215                 Sprintf(tmpbuf, "%s", version_string(verbuf));
1216                 break;
1217             case 'u': /* UID */
1218                 Sprintf(tmpbuf, "%ld", uid);
1219                 break;
1220             case 'n': /* player name */
1221                 if (fullsubs)
1222                     Sprintf(tmpbuf, "%s", *plname ? plname : "unknown");
1223                 else
1224                     Strcpy(tmpbuf, "{hero name}");
1225                 break;
1226             case 'N': /* first character of player name */
1227                 if (fullsubs)
1228                     Sprintf(tmpbuf, "%c", *plname ? *plname : 'u');
1229                 else
1230                     Strcpy(tmpbuf, "{hero initial}");
1231                 break;
1232             }
1233             if (fullsubs) {
1234                 /* replace potentially troublesome characters (including
1235                    <space> even though it might be an acceptable file name
1236                    character); user shouldn't be able to get ' ' or '/'
1237                    or '\\' into plname[] but play things safe */
1238                 (void) strNsubst(tmpbuf, " ", "_", 0);
1239                 (void) strNsubst(tmpbuf, "/", "_", 0);
1240                 (void) strNsubst(tmpbuf, "\\", "_", 0);
1241                 /* note: replacements are only done on field substitutions,
1242                    not on the template (from sysconf or DUMPLOG_FILE) */
1243             }
1244
1245             slen = (int) strlen(tmpbuf);
1246             if (len + slen < BUFSZ - 1) {
1247                 len += slen;
1248                 Sprintf(bp, "%s", tmpbuf);
1249                 bp += slen;
1250                 if (*fp)
1251                     fp++;
1252             } else
1253                 break;
1254         } else {
1255             *bp = *fp;
1256             bp++;
1257             fp++;
1258             len++;
1259         }
1260     }
1261  finish:
1262     *bp = '\0';
1263     return buf;
1264 }
1265 #endif /* DUMPLOG */
1266
1267 void
1268 dump_open_log(now)
1269 time_t now;
1270 {
1271 #ifdef DUMPLOG
1272     char buf[BUFSZ];
1273     char *fname;
1274
1275     dumplog_now = now;
1276 #ifdef SYSCF
1277     if (!sysopt.dumplogfile)
1278         return;
1279     fname = dump_fmtstr(sysopt.dumplogfile, buf, TRUE);
1280 #else
1281     fname = dump_fmtstr(DUMPLOG_FILE, buf, TRUE);
1282 #endif
1283     dumplog_file = fopen(fname, "w");
1284     dumplog_windowprocs_backup = windowprocs;
1285
1286 #else /*!DUMPLOG*/
1287     nhUse(now);
1288 #endif /*?DUMPLOG*/
1289 }
1290
1291 void
1292 dump_close_log()
1293 {
1294     if (dumplog_file) {
1295         (void) fclose(dumplog_file);
1296         dumplog_file = (FILE *) 0;
1297     }
1298 }
1299
1300 void
1301 dump_forward_putstr(win, attr, str, no_forward)
1302 winid win;
1303 int attr;
1304 const char *str;
1305 int no_forward;
1306 {
1307     if (dumplog_file)
1308         fprintf(dumplog_file, "%s\n", str);
1309     if (!no_forward)
1310         putstr(win, attr, str);
1311 }
1312
1313 /*ARGSUSED*/
1314 STATIC_OVL void
1315 dump_putstr(win, attr, str)
1316 winid win UNUSED;
1317 int attr UNUSED;
1318 const char *str;
1319 {
1320     if (dumplog_file)
1321         fprintf(dumplog_file, "%s\n", str);
1322 }
1323
1324 STATIC_OVL winid
1325 dump_create_nhwindow(dummy)
1326 int dummy;
1327 {
1328     return dummy;
1329 }
1330
1331 /*ARGUSED*/
1332 STATIC_OVL void
1333 dump_clear_nhwindow(win)
1334 winid win UNUSED;
1335 {
1336     return;
1337 }
1338
1339 /*ARGSUSED*/
1340 STATIC_OVL void
1341 dump_display_nhwindow(win, p)
1342 winid win UNUSED;
1343 boolean p UNUSED;
1344 {
1345     return;
1346 }
1347
1348 /*ARGUSED*/
1349 STATIC_OVL void
1350 dump_destroy_nhwindow(win)
1351 winid win UNUSED;
1352 {
1353     return;
1354 }
1355
1356 /*ARGUSED*/
1357 STATIC_OVL void
1358 dump_start_menu(win)
1359 winid win UNUSED;
1360 {
1361     return;
1362 }
1363
1364 /*ARGSUSED*/
1365 STATIC_OVL void
1366 dump_add_menu(win, glyph, identifier, ch, gch, attr, str, preselected)
1367 winid win UNUSED;
1368 int glyph;
1369 const anything *identifier UNUSED;
1370 char ch;
1371 char gch UNUSED;
1372 int attr UNUSED;
1373 const char *str;
1374 boolean preselected UNUSED;
1375 {
1376     if (dumplog_file) {
1377         if (glyph == NO_GLYPH)
1378             fprintf(dumplog_file, " %s\n", str);
1379         else
1380             fprintf(dumplog_file, "  %c - %s\n", ch, str);
1381     }
1382 }
1383
1384 /*ARGSUSED*/
1385 STATIC_OVL void
1386 dump_end_menu(win, str)
1387 winid win UNUSED;
1388 const char *str;
1389 {
1390     if (dumplog_file) {
1391         if (str)
1392             fprintf(dumplog_file, "%s\n", str);
1393         else
1394             fputs("\n", dumplog_file);
1395     }
1396 }
1397
1398 STATIC_OVL int
1399 dump_select_menu(win, how, item)
1400 winid win UNUSED;
1401 int how UNUSED;
1402 menu_item **item;
1403 {
1404     *item = (menu_item *) 0;
1405     return 0;
1406 }
1407
1408 void
1409 dump_redirect(onoff_flag)
1410 boolean onoff_flag;
1411 {
1412     if (dumplog_file) {
1413         if (onoff_flag) {
1414             windowprocs.win_create_nhwindow = dump_create_nhwindow;
1415             windowprocs.win_clear_nhwindow = dump_clear_nhwindow;
1416             windowprocs.win_display_nhwindow = dump_display_nhwindow;
1417             windowprocs.win_destroy_nhwindow = dump_destroy_nhwindow;
1418             windowprocs.win_start_menu = dump_start_menu;
1419             windowprocs.win_add_menu = dump_add_menu;
1420             windowprocs.win_end_menu = dump_end_menu;
1421             windowprocs.win_select_menu = dump_select_menu;
1422             windowprocs.win_putstr = dump_putstr;
1423         } else {
1424             windowprocs = dumplog_windowprocs_backup;
1425         }
1426         iflags.in_dumplog = onoff_flag;
1427     } else {
1428         iflags.in_dumplog = FALSE;
1429     }
1430 }
1431
1432 #ifdef TTY_GRAPHICS
1433 #ifdef TEXTCOLOR
1434 #ifdef TOS
1435 extern const char *hilites[CLR_MAX];
1436 #else
1437 extern NEARDATA char *hilites[CLR_MAX];
1438 #endif
1439 #endif
1440 #endif
1441
1442 int
1443 has_color(color)
1444 int color;
1445 {
1446     return (iflags.use_color && windowprocs.name
1447             && (windowprocs.wincap & WC_COLOR) && windowprocs.has_color[color]
1448 #ifdef TTY_GRAPHICS
1449 #if defined(TEXTCOLOR) && defined(TERMLIB) && !defined(NO_TERMS)
1450              && (hilites[color] != 0)
1451 #endif
1452 #endif
1453     );
1454 }
1455
1456 /*windows.c*/