OSDN Git Service

add missing "#ifdef X11LARGETILE"
[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                 Strcpy(nb = eos(nb), " Stone");
982             if (cond & BL_MASK_SLIME)
983                 Strcpy(nb = eos(nb), " Slime");
984             if (cond & BL_MASK_STRNGL)
985                 Strcpy(nb = eos(nb), " Strngl");
986             if (cond & BL_MASK_FOODPOIS)
987                 Strcpy(nb = eos(nb), " FoodPois");
988             if (cond & BL_MASK_TERMILL)
989                 Strcpy(nb = eos(nb), " TermIll");
990             if (cond & BL_MASK_BLIND)
991                 Strcpy(nb = eos(nb), " Blind");
992             if (cond & BL_MASK_DEAF)
993                 Strcpy(nb = eos(nb), " Deaf");
994             if (cond & BL_MASK_STUN)
995                 Strcpy(nb = eos(nb), " Stun");
996             if (cond & BL_MASK_CONF)
997                 Strcpy(nb = eos(nb), " Conf");
998             if (cond & BL_MASK_HALLU)
999                 Strcpy(nb = eos(nb), " Hallu");
1000             if (cond & BL_MASK_LEV)
1001                 Strcpy(nb = eos(nb), " Lev");
1002             if (cond & BL_MASK_FLY)
1003                 Strcpy(nb = eos(nb), " Fly");
1004             if (cond & BL_MASK_RIDE)
1005                 Strcpy(nb = eos(nb), " Ride");
1006             break;
1007         default:
1008             Sprintf(status_vals[idx],
1009                     status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s",
1010                     text ? text : "");
1011             break;
1012         }
1013         return; /* processed one field other than BL_FLUSH */
1014     } /* (idx >= 0, thus not BL_FLUSH, BL_RESET, BL_CHARACTERISTICS) */
1015
1016     /* does BL_RESET require any specific code to ensure all fields ? */
1017
1018     if (!(idx == BL_FLUSH || idx == BL_RESET))
1019         return;
1020
1021     /* We've received BL_FLUSH; time to output the gathered data */
1022     nb = newbot1;
1023     *nb = '\0';
1024     /* BL_FLUSH is the only pseudo-index value we need to check for
1025        in the loop below because it is the only entry used to pad the
1026        end of the fieldorder array. We could stop on any
1027        negative (illegal) index, but this should be fine */
1028     for (i = 0; (idx1 = fieldorder[0][i]) != BL_FLUSH; ++i) {
1029         if (status_activefields[idx1])
1030             Strcpy(nb = eos(nb), status_vals[idx1]);
1031     }
1032     /* if '$' is encoded, buffer length of \GXXXXNNNN is 9 greater than
1033        single char; we want to subtract that 9 when checking display length */
1034     lndelta = (status_activefields[BL_GOLD]
1035                && strstr(status_vals[BL_GOLD], "\\G")) ? 9 : 0;
1036     /* basic bot2 formats groups of second line fields into five buffers,
1037        then decides how to order those buffers based on comparing lengths
1038        of [sub]sets of them to the width of the map; we have more control
1039        here but currently emulate that behavior */
1040     for (pass = 1; pass <= 4; pass++) {
1041         fieldlist = fieldorder[pass];
1042         nb = newbot2;
1043         *nb = '\0';
1044         for (i = 0; (idx2 = fieldlist[i]) != BL_FLUSH; ++i) {
1045             if (status_activefields[idx2]) {
1046                 const char *val = status_vals[idx2];
1047
1048                 switch (idx2) {
1049                 case BL_HP: /* for pass 4, Hp comes first; mungspaces()
1050                                will strip the unwanted leading spaces */
1051                 case BL_XP: case BL_HD:
1052                 case BL_TIME:
1053                     Strcpy(nb = eos(nb), " ");
1054                     break;
1055                 case BL_LEVELDESC:
1056                     /* leveldesc has no leading space, so if we've moved
1057                        it past the first position, provide one */
1058                     if (i != 0)
1059                         Strcpy(nb = eos(nb), " ");
1060                     break;
1061                 /*
1062                  * We want "  hunger encumbrance conditions"
1063                  *   or    "  encumbrance conditions"
1064                  *   or    "  hunger conditions"
1065                  *   or    "  conditions"
1066                  * 'hunger'      is either " " or " hunger_text";
1067                  * 'encumbrance' is either " " or " encumbrance_text";
1068                  * 'conditions'  is either ""  or " cond1 cond2...".
1069                  */
1070                 case BL_HUNGER:
1071                     /* hunger==" " - keep it, end up with " ";
1072                        hunger!=" " - insert space and get "  hunger" */
1073                     if (strcmp(val, " "))
1074                         Strcpy(nb = eos(nb), " ");
1075                     break;
1076                 case BL_CAP:
1077                     /* cap==" " - suppress it, retain "  hunger" or " ";
1078                        cap!=" " - use it, get "  hunger cap" or "  cap" */
1079                     if (!strcmp(val, " "))
1080                         ++val;
1081                     break;
1082                 default:
1083                     break;
1084                 }
1085                 Strcpy(nb = eos(nb), val); /* status_vals[idx2] */
1086             } /* status_activefields[idx2] */
1087
1088             if (idx2 == BL_CONDITION && pass < 4
1089                 && strlen(newbot2) - lndelta > COLNO)
1090                 break; /* switch to next order */
1091         } /* i */
1092
1093         if (idx2 == BL_FLUSH) { /* made it past BL_CONDITION */
1094             if (pass > 1)
1095                 mungspaces(newbot2);
1096             break;
1097         }
1098     } /* pass */
1099     curs(WIN_STATUS, 1, 0);
1100     putstr(WIN_STATUS, 0, newbot1);
1101     curs(WIN_STATUS, 1, 1);
1102     putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */
1103 }
1104
1105 STATIC_VAR struct window_procs dumplog_windowprocs_backup;
1106 STATIC_VAR FILE *dumplog_file;
1107
1108 #ifdef DUMPLOG
1109 STATIC_VAR time_t dumplog_now;
1110
1111 char *
1112 dump_fmtstr(fmt, buf, fullsubs)
1113 const char *fmt;
1114 char *buf;
1115 boolean fullsubs; /* True -> full substitution for file name, False ->
1116                    * partial substitution for '--showpaths' feedback
1117                    * where there's no game in progress when executed */
1118 {
1119     const char *fp = fmt;
1120     char *bp = buf;
1121     int slen, len = 0;
1122     char tmpbuf[BUFSZ];
1123     char verbuf[BUFSZ];
1124     long uid;
1125     time_t now;
1126
1127     now = dumplog_now;
1128     uid = (long) getuid();
1129
1130     /*
1131      * Note: %t and %T assume that time_t is a 'long int' number of
1132      * seconds since some epoch value.  That's quite iffy....  The
1133      * unit of time might be different and the datum size might be
1134      * some variant of 'long long int'.  [Their main purpose is to
1135      * construct a unique file name rather than record the date and
1136      * time; violating the 'long seconds since base-date' assumption
1137      * may or may not interfere with that usage.]
1138      */
1139
1140     while (fp && *fp && len < BUFSZ - 1) {
1141         if (*fp == '%') {
1142             fp++;
1143             switch (*fp) {
1144             default:
1145                 goto finish;
1146             case '\0': /* fallthrough */
1147             case '%':  /* literal % */
1148                 Sprintf(tmpbuf, "%%");
1149                 break;
1150             case 't': /* game start, timestamp */
1151                 if (fullsubs)
1152                     Sprintf(tmpbuf, "%lu", (unsigned long) ubirthday);
1153                 else
1154                     Strcpy(tmpbuf, "{game start cookie}");
1155                 break;
1156             case 'T': /* current time, timestamp */
1157                 if (fullsubs)
1158                     Sprintf(tmpbuf, "%lu", (unsigned long) now);
1159                 else
1160                     Strcpy(tmpbuf, "{current time cookie}");
1161                 break;
1162             case 'd': /* game start, YYYYMMDDhhmmss */
1163                 if (fullsubs)
1164                     Sprintf(tmpbuf, "%08ld%06ld",
1165                             yyyymmdd(ubirthday), hhmmss(ubirthday));
1166                 else
1167                     Strcpy(tmpbuf, "{game start date+time}");
1168                 break;
1169             case 'D': /* current time, YYYYMMDDhhmmss */
1170                 if (fullsubs)
1171                     Sprintf(tmpbuf, "%08ld%06ld", yyyymmdd(now), hhmmss(now));
1172                 else
1173                     Strcpy(tmpbuf, "{current date+time}");
1174                 break;
1175             case 'v': /* version, eg. "3.6.5-0" */
1176                 Sprintf(tmpbuf, "%s", version_string(verbuf));
1177                 break;
1178             case 'u': /* UID */
1179                 Sprintf(tmpbuf, "%ld", uid);
1180                 break;
1181             case 'n': /* player name */
1182                 if (fullsubs)
1183                     Sprintf(tmpbuf, "%s", *plname ? plname : "unknown");
1184                 else
1185                     Strcpy(tmpbuf, "{hero name}");
1186                 break;
1187             case 'N': /* first character of player name */
1188                 if (fullsubs)
1189                     Sprintf(tmpbuf, "%c", *plname ? *plname : 'u');
1190                 else
1191                     Strcpy(tmpbuf, "{hero initial}");
1192                 break;
1193             }
1194             if (fullsubs) {
1195                 /* replace potentially troublesome characters (including
1196                    <space> even though it might be an acceptable file name
1197                    character); user shouldn't be able to get ' ' or '/'
1198                    or '\\' into plname[] but play things safe */
1199                 (void) strNsubst(tmpbuf, " ", "_", 0);
1200                 (void) strNsubst(tmpbuf, "/", "_", 0);
1201                 (void) strNsubst(tmpbuf, "\\", "_", 0);
1202                 /* note: replacements are only done on field substitutions,
1203                    not on the template (from sysconf or DUMPLOG_FILE) */
1204             }
1205
1206             slen = (int) strlen(tmpbuf);
1207             if (len + slen < BUFSZ - 1) {
1208                 len += slen;
1209                 Sprintf(bp, "%s", tmpbuf);
1210                 bp += slen;
1211                 if (*fp)
1212                     fp++;
1213             } else
1214                 break;
1215         } else {
1216             *bp = *fp;
1217             bp++;
1218             fp++;
1219             len++;
1220         }
1221     }
1222  finish:
1223     *bp = '\0';
1224     return buf;
1225 }
1226 #endif /* DUMPLOG */
1227
1228 void
1229 dump_open_log(now)
1230 time_t now;
1231 {
1232 #ifdef DUMPLOG
1233     char buf[BUFSZ];
1234     char *fname;
1235
1236     dumplog_now = now;
1237 #ifdef SYSCF
1238     if (!sysopt.dumplogfile)
1239         return;
1240     fname = dump_fmtstr(sysopt.dumplogfile, buf, TRUE);
1241 #else
1242     fname = dump_fmtstr(DUMPLOG_FILE, buf, TRUE);
1243 #endif
1244     dumplog_file = fopen(fname, "w");
1245     dumplog_windowprocs_backup = windowprocs;
1246
1247 #else /*!DUMPLOG*/
1248     nhUse(now);
1249 #endif /*?DUMPLOG*/
1250 }
1251
1252 void
1253 dump_close_log()
1254 {
1255     if (dumplog_file) {
1256         (void) fclose(dumplog_file);
1257         dumplog_file = (FILE *) 0;
1258     }
1259 }
1260
1261 void
1262 dump_forward_putstr(win, attr, str, no_forward)
1263 winid win;
1264 int attr;
1265 const char *str;
1266 int no_forward;
1267 {
1268     if (dumplog_file)
1269         fprintf(dumplog_file, "%s\n", str);
1270     if (!no_forward)
1271         putstr(win, attr, str);
1272 }
1273
1274 /*ARGSUSED*/
1275 STATIC_OVL void
1276 dump_putstr(win, attr, str)
1277 winid win UNUSED;
1278 int attr UNUSED;
1279 const char *str;
1280 {
1281     if (dumplog_file)
1282         fprintf(dumplog_file, "%s\n", str);
1283 }
1284
1285 STATIC_OVL winid
1286 dump_create_nhwindow(dummy)
1287 int dummy;
1288 {
1289     return dummy;
1290 }
1291
1292 /*ARGUSED*/
1293 STATIC_OVL void
1294 dump_clear_nhwindow(win)
1295 winid win UNUSED;
1296 {
1297     return;
1298 }
1299
1300 /*ARGSUSED*/
1301 STATIC_OVL void
1302 dump_display_nhwindow(win, p)
1303 winid win UNUSED;
1304 boolean p UNUSED;
1305 {
1306     return;
1307 }
1308
1309 /*ARGUSED*/
1310 STATIC_OVL void
1311 dump_destroy_nhwindow(win)
1312 winid win UNUSED;
1313 {
1314     return;
1315 }
1316
1317 /*ARGUSED*/
1318 STATIC_OVL void
1319 dump_start_menu(win)
1320 winid win UNUSED;
1321 {
1322     return;
1323 }
1324
1325 /*ARGSUSED*/
1326 STATIC_OVL void
1327 dump_add_menu(win, glyph, identifier, ch, gch, attr, str, preselected)
1328 winid win UNUSED;
1329 int glyph;
1330 const anything *identifier UNUSED;
1331 char ch;
1332 char gch UNUSED;
1333 int attr UNUSED;
1334 const char *str;
1335 boolean preselected UNUSED;
1336 {
1337     if (dumplog_file) {
1338         if (glyph == NO_GLYPH)
1339             fprintf(dumplog_file, " %s\n", str);
1340         else
1341             fprintf(dumplog_file, "  %c - %s\n", ch, str);
1342     }
1343 }
1344
1345 /*ARGSUSED*/
1346 STATIC_OVL void
1347 dump_end_menu(win, str)
1348 winid win UNUSED;
1349 const char *str;
1350 {
1351     if (dumplog_file) {
1352         if (str)
1353             fprintf(dumplog_file, "%s\n", str);
1354         else
1355             fputs("\n", dumplog_file);
1356     }
1357 }
1358
1359 STATIC_OVL int
1360 dump_select_menu(win, how, item)
1361 winid win UNUSED;
1362 int how UNUSED;
1363 menu_item **item;
1364 {
1365     *item = (menu_item *) 0;
1366     return 0;
1367 }
1368
1369 void
1370 dump_redirect(onoff_flag)
1371 boolean onoff_flag;
1372 {
1373     if (dumplog_file) {
1374         if (onoff_flag) {
1375             windowprocs.win_create_nhwindow = dump_create_nhwindow;
1376             windowprocs.win_clear_nhwindow = dump_clear_nhwindow;
1377             windowprocs.win_display_nhwindow = dump_display_nhwindow;
1378             windowprocs.win_destroy_nhwindow = dump_destroy_nhwindow;
1379             windowprocs.win_start_menu = dump_start_menu;
1380             windowprocs.win_add_menu = dump_add_menu;
1381             windowprocs.win_end_menu = dump_end_menu;
1382             windowprocs.win_select_menu = dump_select_menu;
1383             windowprocs.win_putstr = dump_putstr;
1384         } else {
1385             windowprocs = dumplog_windowprocs_backup;
1386         }
1387         iflags.in_dumplog = onoff_flag;
1388     } else {
1389         iflags.in_dumplog = FALSE;
1390     }
1391 }
1392
1393 #ifdef TTY_GRAPHICS
1394 #ifdef TEXTCOLOR
1395 #ifdef TOS
1396 extern const char *hilites[CLR_MAX];
1397 #else
1398 extern NEARDATA char *hilites[CLR_MAX];
1399 #endif
1400 #endif
1401 #endif
1402
1403 int
1404 has_color(color)
1405 int color;
1406 {
1407     return (iflags.use_color && windowprocs.name
1408             && (windowprocs.wincap & WC_COLOR) && windowprocs.has_color[color]
1409 #ifdef TTY_GRAPHICS
1410 #if defined(TEXTCOLOR) && defined(TERMLIB) && !defined(NO_TERMS)
1411              && (hilites[color] != 0)
1412 #endif
1413 #endif
1414     );
1415 }
1416
1417 /*windows.c*/