OSDN Git Service

use const
[jnethack/source.git] / src / windows.c
index 1423f8c..7a62582 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 windows.c       $NHDT-Date: 1448013599 2015/11/20 09:59:59 $  $NHDT-Branch: master $:$NHDT-Revision: 1.35 $ */
+/* NetHack 3.6 windows.c       $NHDT-Date: 1495232365 2017/05/19 22:19:25 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */
 /* Copyright (c) D. Cohrs, 1993. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -57,6 +57,18 @@ extern void *FDECL(trace_procs_chain, (int, int, void *, void *, void *));
 
 STATIC_DCL void FDECL(def_raw_print, (const char *s));
 
+#ifdef DUMPLOG
+STATIC_DCL winid FDECL(dump_create_nhwindow, (int));
+STATIC_DCL void FDECL(dump_clear_nhwindow, (winid));
+STATIC_DCL void FDECL(dump_display_nhwindow, (winid, BOOLEAN_P));
+STATIC_DCL void FDECL(dump_destroy_nhwindow, (winid));
+STATIC_DCL void FDECL(dump_start_menu, (winid));
+STATIC_DCL void FDECL(dump_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P));
+STATIC_DCL void FDECL(dump_end_menu, (winid, const char *));
+STATIC_DCL int FDECL(dump_select_menu, (winid, int, MENU_ITEM_P **));
+STATIC_DCL void FDECL(dump_putstr, (winid, int, const char *));
+#endif /* DUMPLOG */
+
 #ifdef HANGUPHANDLING
 volatile
 #endif
@@ -226,22 +238,25 @@ const char *s;
         exit(EXIT_FAILURE);
     }
     if (!winchoices[1].procs) {
-        raw_printf("Window type %s not recognized.  The only choice is: %s.",
+        config_error_add("Window type %s not recognized.  The only choice is: %s",
                    s, winchoices[0].procs->name);
     } else {
-        raw_printf("Window type %s not recognized.  Choices are:", s);
+        char buf[BUFSZ];
+        boolean first = TRUE;
+        buf[0] = '\0';
         for (i = 0; winchoices[i].procs; i++) {
             if ('+' == winchoices[i].procs->name[0])
                 continue;
             if ('-' == winchoices[i].procs->name[0])
                 continue;
-            raw_printf("        %s", winchoices[i].procs->name);
+            Sprintf(eos(buf), "%s%s", first ? "" : ",", winchoices[i].procs->name);
+            first = FALSE;
         }
+        config_error_add("Window type %s not recognized.  Choices are: %s", s, buf);
     }
 
     if (windowprocs.win_raw_print == def_raw_print)
-        terminate(EXIT_SUCCESS);
-    wait_synch();
+        nh_terminate(EXIT_SUCCESS);
 }
 
 #ifdef WINCHAIN
@@ -459,9 +474,7 @@ static short FDECL(hup_set_font_name, (winid, char *));
 #endif
 static char *NDECL(hup_get_color_string);
 #endif /* CHANGE_COLOR */
-#ifdef STATUS_VIA_WINDOWPORT
-static void FDECL(hup_status_update, (int, genericptr_t, int, int));
-#endif
+static void FDECL(hup_status_update, (int, genericptr_t, int, int, int, unsigned long *));
 
 static int NDECL(hup_int_ndecl);
 static void NDECL(hup_void_ndecl);
@@ -511,14 +524,9 @@ static struct window_procs hup_procs = {
     hup_void_ndecl,                                   /* end_screen */
     hup_outrip, genl_preference_update, genl_getmsghistory,
     genl_putmsghistory,
-#ifdef STATUS_VIA_WINDOWPORT
     hup_void_ndecl,                                   /* status_init */
     hup_void_ndecl,                                   /* status_finish */
     genl_status_enablefield, hup_status_update,
-#ifdef STATUS_HILITES
-    genl_status_threshold,
-#endif
-#endif /* STATUS_VIA_WINDOWPORT */
     genl_can_suspend_no,
 };
 
@@ -747,16 +755,17 @@ hup_get_color_string(VOID_ARGS)
 }
 #endif /* CHANGE_COLOR */
 
-#ifdef STATUS_VIA_WINDOWPORT
 /*ARGSUSED*/
 static void
-hup_status_update(idx, ptr, chg, percent)
-int idx UNUSED, chg UNUSED, percent UNUSED;
+hup_status_update(idx, ptr, chg, pc, color, colormasks)
+int idx UNUSED;
 genericptr_t ptr UNUSED;
+int chg UNUSED, pc UNUSED, color UNUSED;
+unsigned long *colormasks UNUSED;
+
 {
     return;
 }
-#endif /* STATUS_VIA_WINDOWPORT */
 
 /*
  * Non-specific stubs.
@@ -800,7 +809,6 @@ const char *string UNUSED;
 
 #endif /* HANGUPHANDLING */
 
-#ifdef STATUS_VIA_WINDOWPORT
 
 /****************************************************************************/
 /* genl backward compat stuff                                               */
@@ -816,6 +824,7 @@ void
 genl_status_init()
 {
     int i;
+
     for (i = 0; i < MAXBLSTATS; ++i) {
         status_vals[i] = (char *) alloc(MAXCO);
         *status_vals[i] = '\0';
@@ -836,8 +845,7 @@ genl_status_finish()
     /* free alloc'd memory here */
     for (i = 0; i < MAXBLSTATS; ++i) {
         if (status_vals[i])
-            free((genericptr_t) status_vals[i]);
-        status_vals[i] = (char *) 0;
+            free((genericptr_t) status_vals[i]), status_vals[i] = (char *) 0;
     }
 }
 
@@ -853,83 +861,434 @@ boolean enable;
     status_activefields[fieldidx] = enable;
 }
 
+/* call once for each field, then call with BL_FLUSH to output the result */
 void
-genl_status_update(idx, ptr, chg, percent)
-int idx, chg, percent;
+genl_status_update(idx, ptr, chg, percent, color, colormasks)
+int idx;
 genericptr_t ptr;
+int chg UNUSED, percent UNUSED, color UNUSED;
+unsigned long *colormasks UNUSED;
 {
     char newbot1[MAXCO], newbot2[MAXCO];
     long cond, *condptr = (long *) ptr;
     register int i;
-    char *text = (char *) ptr;
+    unsigned pass, lndelta;
+    enum statusfields idx1, idx2, *fieldlist;
+    char *nb, *text = (char *) ptr;
 
-    enum statusfields fieldorder[2][15] = {
+    static enum statusfields fieldorder[][15] = {
+        /* line one */
         { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
           BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
           BL_FLUSH },
-        { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
-          BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
-          BL_CAP, BL_CONDITION, BL_FLUSH }
+        /* line two, default order */
+        { BL_LEVELDESC, BL_GOLD,
+          BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+          BL_XP, BL_EXP, BL_HD,
+          BL_TIME,
+          BL_HUNGER, BL_CAP, BL_CONDITION,
+          BL_FLUSH },
+        /* move time to the end */
+        { BL_LEVELDESC, BL_GOLD,
+          BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+          BL_XP, BL_EXP, BL_HD,
+          BL_HUNGER, BL_CAP, BL_CONDITION,
+          BL_TIME, BL_FLUSH },
+        /* move experience and time to the end */
+        { BL_LEVELDESC, BL_GOLD,
+          BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+          BL_HUNGER, BL_CAP, BL_CONDITION,
+          BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
+        /* move level description plus gold and experience and time to end */
+        { BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+          BL_HUNGER, BL_CAP, BL_CONDITION,
+          BL_LEVELDESC, BL_GOLD, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
     };
 
+    /* in case interface is using genl_status_update() but has not
+       specified WC2_FLUSH_STATUS (status_update() for field values
+       is buffered so final BL_FLUSH is needed to produce output) */
+    windowprocs.wincap2 |= WC2_FLUSH_STATUS;
+
     if (idx != BL_FLUSH) {
         if (!status_activefields[idx])
             return;
         switch (idx) {
         case BL_CONDITION:
-            cond = *condptr;
-            *status_vals[idx] = '\0';
+            cond = condptr ? *condptr : 0L;
+            nb = status_vals[idx];
+            *nb = '\0';
+            if (cond & BL_MASK_STONE)
+                Strcpy(nb = eos(nb), " Stone");
+            if (cond & BL_MASK_SLIME)
+                Strcpy(nb = eos(nb), " Slime");
+            if (cond & BL_MASK_STRNGL)
+                Strcpy(nb = eos(nb), " Strngl");
+            if (cond & BL_MASK_FOODPOIS)
+                Strcpy(nb = eos(nb), " FoodPois");
+            if (cond & BL_MASK_TERMILL)
+                Strcpy(nb = eos(nb), " TermIll");
             if (cond & BL_MASK_BLIND)
-                Strcat(status_vals[idx], " Blind");
+                Strcpy(nb = eos(nb), " Blind");
+            if (cond & BL_MASK_DEAF)
+                Strcpy(nb = eos(nb), " Deaf");
+            if (cond & BL_MASK_STUN)
+                Strcpy(nb = eos(nb), " Stun");
             if (cond & BL_MASK_CONF)
-                Strcat(status_vals[idx], " Conf");
-            if (cond & BL_MASK_FOODPOIS)
-                Strcat(status_vals[idx], " FoodPois");
-            if (cond & BL_MASK_ILL)
-                Strcat(status_vals[idx], " Ill");
-            if (cond & BL_MASK_STUNNED)
-                Strcat(status_vals[idx], " Stun");
+                Strcpy(nb = eos(nb), " Conf");
             if (cond & BL_MASK_HALLU)
-                Strcat(status_vals[idx], " Hallu");
-            if (cond & BL_MASK_SLIMED)
-                Strcat(status_vals[idx], " Slime");
+                Strcpy(nb = eos(nb), " Hallu");
+            if (cond & BL_MASK_LEV)
+                Strcpy(nb = eos(nb), " Lev");
+            if (cond & BL_MASK_FLY)
+                Strcpy(nb = eos(nb), " Fly");
+            if (cond & BL_MASK_RIDE)
+                Strcpy(nb = eos(nb), " Ride");
             break;
         default:
             Sprintf(status_vals[idx],
-                    status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s", text);
+                    status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s",
+                    text ? text : "");
             break;
         }
-    }
+        return; /* processed one field other than BL_FLUSH */
+    } /* (idx != BL_FLUSH) */
 
-    /* This genl version updates everything on the display, everytime */
-    newbot1[0] = '\0';
-    for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) {
-        int idx1 = fieldorder[0][i];
+    /* We've received BL_FLUSH; time to output the gathered data */
+    nb = newbot1;
+    *nb = '\0';
+    for (i = 0; (idx1 = fieldorder[0][i]) != BL_FLUSH; ++i) {
         if (status_activefields[idx1])
-            Strcat(newbot1, status_vals[idx1]);
-    }
-    newbot2[0] = '\0';
-    for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) {
-        int idx2 = fieldorder[1][i];
-        if (status_activefields[idx2])
-            Strcat(newbot2, status_vals[idx2]);
+            Strcpy(nb = eos(nb), status_vals[idx1]);
     }
+    /* if '$' is encoded, buffer length of \GXXXXNNNN is 9 greater than
+       single char; we want to subtract that 9 when checking display length */
+    lndelta = (status_activefields[BL_GOLD]
+               && strstr(status_vals[BL_GOLD], "\\G")) ? 9 : 0;
+    /* basic bot2 formats groups of second line fields into five buffers,
+       then decides how to order those buffers based on comparing lengths
+       of [sub]sets of them to the width of the map; we have more control
+       here but currently emulate that behavior */
+    for (pass = 1; pass <= 4; pass++) {
+        fieldlist = fieldorder[pass];
+        nb = newbot2;
+        *nb = '\0';
+        for (i = 0; (idx2 = fieldlist[i]) != BL_FLUSH; ++i) {
+            if (status_activefields[idx2]) {
+                const char *val = status_vals[idx2];
+
+                switch (idx2) {
+                case BL_HP: /* for pass 4, Hp comes first; mungspaces()
+                               will strip the unwanted leading spaces */
+                case BL_XP: case BL_HD:
+                case BL_TIME:
+                    Strcpy(nb = eos(nb), " ");
+                    break;
+                case BL_LEVELDESC:
+                    /* leveldesc has no leading space, so if we've moved
+                       it past the first position, provide one */
+                    if (i != 0)
+                        Strcpy(nb = eos(nb), " ");
+                    break;
+                /*
+                 * We want "  hunger encumbrance conditions"
+                 *   or    "  encumbrance conditions"
+                 *   or    "  hunger conditions"
+                 *   or    "  conditions"
+                 * 'hunger'      is either " " or " hunger_text";
+                 * 'encumbrance' is either " " or " encumbrance_text";
+                 * 'conditions'  is either ""  or " cond1 cond2...".
+                 */
+                case BL_HUNGER:
+                    /* hunger==" " - keep it, end up with " ";
+                       hunger!=" " - insert space and get "  hunger" */
+                    if (strcmp(val, " "))
+                        Strcpy(nb = eos(nb), " ");
+                    break;
+                case BL_CAP:
+                    /* cap==" " - suppress it, retain "  hunger" or " ";
+                       cap!=" " - use it, get "  hunger cap" or "  cap" */
+                    if (!strcmp(val, " "))
+                        ++val;
+                    break;
+                default:
+                    break;
+                }
+                Strcpy(nb = eos(nb), val); /* status_vals[idx2] */
+            } /* status_activefields[idx2] */
+
+            if (idx2 == BL_CONDITION && pass < 4
+                && strlen(newbot2) - lndelta > COLNO)
+                break; /* switch to next order */
+        } /* i */
+
+        if (idx2 == BL_FLUSH) { /* made it past BL_CONDITION */
+            if (pass > 1)
+                mungspaces(newbot2);
+            break;
+        }
+    } /* pass */
     curs(WIN_STATUS, 1, 0);
     putstr(WIN_STATUS, 0, newbot1);
     curs(WIN_STATUS, 1, 1);
     putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */
 }
 
-#ifdef STATUS_HILITES
+STATIC_VAR struct window_procs dumplog_windowprocs_backup;
+STATIC_VAR FILE *dumplog_file;
+
+#ifdef DUMPLOG
+STATIC_VAR time_t dumplog_now;
+
+STATIC_DCL char *FDECL(dump_fmtstr, (const char *, char *));
+
+STATIC_OVL char *
+dump_fmtstr(fmt, buf)
+const char *fmt;
+char *buf;
+{
+    const char *fp = fmt;
+    char *bp = buf;
+    int slen, len = 0;
+    char tmpbuf[BUFSZ];
+    char verbuf[BUFSZ];
+    long uid;
+    time_t now;
+
+    now = dumplog_now;
+    uid = (long) getuid();
+
+    /*
+     * Note: %t and %T assume that time_t is a 'long int' number of
+     * seconds since some epoch value.  That's quite iffy....  The
+     * unit of time might be different and the datum size might be
+     * some variant of 'long long int'.  [Their main purpose is to
+     * construct a unique file name rather than record the date and
+     * time; violating the 'long seconds since base-date' assumption
+     * may or may not interfere with that usage.]
+     */
+
+    while (fp && *fp && len < BUFSZ-1) {
+        if (*fp == '%') {
+            fp++;
+            switch (*fp) {
+            default:
+                goto finish;
+            case '\0': /* fallthrough */
+            case '%':  /* literal % */
+                Sprintf(tmpbuf, "%%");
+                break;
+            case 't': /* game start, timestamp */
+                Sprintf(tmpbuf, "%lu", (unsigned long) ubirthday);
+                break;
+            case 'T': /* current time, timestamp */
+                Sprintf(tmpbuf, "%lu", (unsigned long) now);
+                break;
+            case 'd': /* game start, YYYYMMDDhhmmss */
+                Sprintf(tmpbuf, "%08ld%06ld",
+                        yyyymmdd(ubirthday), hhmmss(ubirthday));
+                break;
+            case 'D': /* current time, YYYYMMDDhhmmss */
+                Sprintf(tmpbuf, "%08ld%06ld", yyyymmdd(now), hhmmss(now));
+                break;
+            case 'v': /* version, eg. "3.6.1-0" */
+                Sprintf(tmpbuf, "%s", version_string(verbuf));
+                break;
+            case 'u': /* UID */
+                Sprintf(tmpbuf, "%ld", uid);
+                break;
+            case 'n': /* player name */
+                Sprintf(tmpbuf, "%s", *plname ? plname : "unknown");
+                break;
+            case 'N': /* first character of player name */
+                Sprintf(tmpbuf, "%c", *plname ? *plname : 'u');
+                break;
+            }
+
+            slen = strlen(tmpbuf);
+            if (len + slen < BUFSZ-1) {
+                len += slen;
+                Sprintf(bp, "%s", tmpbuf);
+                bp += slen;
+                if (*fp) fp++;
+            } else
+                break;
+        } else {
+            *bp = *fp;
+            bp++;
+            fp++;
+            len++;
+        }
+    }
+ finish:
+    *bp = '\0';
+    return buf;
+}
+#endif /* DUMPLOG */
+
+void
+dump_open_log(now)
+time_t now;
+{
+#ifdef DUMPLOG
+    char buf[BUFSZ];
+    char *fname;
+
+    dumplog_now = now;
+#ifdef SYSCF
+    if (!sysopt.dumplogfile)
+        return;
+    fname = dump_fmtstr(sysopt.dumplogfile, buf);
+#else
+    fname = dump_fmtstr(DUMPLOG_FILE, buf);
+#endif
+    dumplog_file = fopen(fname, "w");
+    dumplog_windowprocs_backup = windowprocs;
+
+#else /*!DUMPLOG*/
+    nhUse(now);
+#endif /*?DUMPLOG*/
+}
+
 void
-genl_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over)
-int fldidx, thresholdtype;
-int behavior, under, over;
-anything threshold;
+dump_close_log()
+{
+    if (dumplog_file) {
+        (void) fclose(dumplog_file);
+        dumplog_file = (FILE *) 0;
+    }
+}
+
+void
+dump_forward_putstr(win, attr, str, no_forward)
+winid win;
+int attr;
+const char *str;
+int no_forward;
+{
+    if (dumplog_file)
+        fprintf(dumplog_file, "%s\n", str);
+    if (!no_forward)
+        putstr(win, attr, str);
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_putstr(win, attr, str)
+winid win UNUSED;
+int attr UNUSED;
+const char *str;
+{
+    if (dumplog_file)
+        fprintf(dumplog_file, "%s\n", str);
+}
+
+STATIC_OVL winid
+dump_create_nhwindow(dummy)
+int dummy;
+{
+    return dummy;
+}
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_clear_nhwindow(win)
+winid win UNUSED;
+{
+    return;
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_display_nhwindow(win, p)
+winid win UNUSED;
+boolean p UNUSED;
 {
     return;
 }
-#endif /* STATUS_HILITES */
-#endif /* STATUS_VIA_WINDOWPORT */
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_destroy_nhwindow(win)
+winid win UNUSED;
+{
+    return;
+}
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_start_menu(win)
+winid win UNUSED;
+{
+    return;
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_add_menu(win, glyph, identifier, ch, gch, attr, str, preselected)
+winid win UNUSED;
+int glyph UNUSED;
+const anything *identifier UNUSED;
+char ch;
+char gch UNUSED;
+int attr UNUSED;
+const char *str;
+boolean preselected UNUSED;
+{
+    if (dumplog_file) {
+        if (glyph == NO_GLYPH)
+            fprintf(dumplog_file, " %s\n", str);
+        else
+            fprintf(dumplog_file, "  %c - %s\n", ch, str);
+    }
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_end_menu(win, str)
+winid win UNUSED;
+const char *str;
+{
+    if (dumplog_file) {
+        if (str)
+            fprintf(dumplog_file, "%s\n", str);
+        else
+            fputs("\n", dumplog_file);
+    }
+}
+
+STATIC_OVL int
+dump_select_menu(win, how, item)
+winid win UNUSED;
+int how UNUSED;
+menu_item **item;
+{
+    *item = (menu_item *) 0;
+    return 0;
+}
+
+void
+dump_redirect(onoff_flag)
+boolean onoff_flag;
+{
+    if (dumplog_file) {
+        if (onoff_flag) {
+            windowprocs.win_create_nhwindow = dump_create_nhwindow;
+            windowprocs.win_clear_nhwindow = dump_clear_nhwindow;
+            windowprocs.win_display_nhwindow = dump_display_nhwindow;
+            windowprocs.win_destroy_nhwindow = dump_destroy_nhwindow;
+            windowprocs.win_start_menu = dump_start_menu;
+            windowprocs.win_add_menu = dump_add_menu;
+            windowprocs.win_end_menu = dump_end_menu;
+            windowprocs.win_select_menu = dump_select_menu;
+            windowprocs.win_putstr = dump_putstr;
+        } else {
+            windowprocs = dumplog_windowprocs_backup;
+        }
+        iflags.in_dumplog = onoff_flag;
+    } else {
+        iflags.in_dumplog = FALSE;
+    }
+}
 
 /*windows.c*/