OSDN Git Service

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