OSDN Git Service

update year to 2020
[jnethack/source.git] / src / pline.c
index 1c0aaa9..5d9015a 100644 (file)
@@ -1,22 +1,93 @@
-/* NetHack 3.6 pline.c $NHDT-Date: 1432512770 2015/05/25 00:12:50 $  $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ */
+/* NetHack 3.6 pline.c $NHDT-Date: 1549327495 2019/02/05 00:44:55 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.73 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2018. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 /* JNetHack Copyright */
 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
 /* JNetHack may be freely redistributed.  See license for details. */
 
-#define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \
-                                       */
+#define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers */
 #include "hack.h"
 
-static boolean no_repeat = FALSE;
+#define BIGBUFSZ (5 * BUFSZ) /* big enough to format a 4*BUFSZ string (from
+                              * config file parsing) with modest decoration;
+                              * result will then be truncated to BUFSZ-1 */
+
+static unsigned pline_flags = 0;
 static char prevmsg[BUFSZ];
 
+static void FDECL(putmesg, (const char *));
 static char *FDECL(You_buf, (int));
+#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
+static void FDECL(execplinehandler, (const char *));
+#endif
+
+#ifdef DUMPLOG
+/* also used in end.c */
+unsigned saved_pline_index = 0; /* slot in saved_plines[] to use next */
+char *saved_plines[DUMPLOG_MSG_COUNT] = { (char *) 0 };
+
+/* keep the most recent DUMPLOG_MSG_COUNT messages */
+void
+dumplogmsg(line)
+const char *line;
+{
+    /*
+     * TODO:
+     *  This essentially duplicates message history, which is
+     *  currently implemented in an interface-specific manner.
+     *  The core should take responsibility for that and have
+     *  this share it.
+     */
+    unsigned indx = saved_pline_index; /* next slot to use */
+    char *oldest = saved_plines[indx]; /* current content of that slot */
+
+    if (oldest && strlen(oldest) >= strlen(line)) {
+        /* this buffer will gradually shrink until the 'else' is needed;
+           there's no pressing need to track allocation size instead */
+        Strcpy(oldest, line);
+    } else {
+        if (oldest)
+            free((genericptr_t) oldest);
+        saved_plines[indx] = dupstr(line);
+    }
+    saved_pline_index = (indx + 1) % DUMPLOG_MSG_COUNT;
+}
+
+/* called during save (unlike the interface-specific message history,
+   this data isn't saved and restored); end-of-game releases saved_pline[]
+   while writing its contents to the final dump log */
+void
+dumplogfreemessages()
+{
+    unsigned indx;
+
+    for (indx = 0; indx < DUMPLOG_MSG_COUNT; ++indx)
+        if (saved_plines[indx])
+            free((genericptr_t) saved_plines[indx]), saved_plines[indx] = 0;
+    saved_pline_index = 0;
+}
+#endif
+
+/* keeps windowprocs usage out of pline() */
+static void
+putmesg(line)
+const char *line;
+{
+    int attr = ATR_NONE;
+
+    if ((pline_flags & URGENT_MESSAGE) != 0
+        && (windowprocs.wincap2 & WC2_URGENT_MESG) != 0)
+        attr |= ATR_URGENT;
+    if ((pline_flags & SUPPRESS_HISTORY) != 0
+        && (windowprocs.wincap2 & WC2_SUPPRESS_HIST) != 0)
+        attr |= ATR_NOHISTORY;
+
+    putstr(WIN_MESSAGE, attr, line);
+}
 
-/*VARARGS1*/
 /* Note that these declarations rely on knowledge of the internals
  * of the variable argument handling stuff in "tradstdc.h"
  */
@@ -24,7 +95,9 @@ static char *FDECL(You_buf, (int));
 #if defined(USE_STDARG) || defined(USE_VARARGS)
 static void FDECL(vpline, (const char *, va_list));
 
-void pline
+/*VARARGS1*/
+void
+pline
 VA_DECL(const char *, line)
 {
     VA_START(line);
@@ -47,13 +120,22 @@ va_list the_args;
 
 # define vpline pline
 
-void pline
+/*VARARGS1*/
+void
+pline
 VA_DECL(const char *, line)
 #endif /* USE_STDARG | USE_VARARG */
 {       /* start of vpline() or of nested block in USE_OLDARG's pline() */
-    char pbuf[3 * BUFSZ];
+    static int in_pline = 0;
+    char pbuf[BIGBUFSZ]; /* will get chopped down to BUFSZ-1 if longer */
     int ln;
-    xchar msgtyp;
+    int msgtyp;
+#if !defined(NO_VSNPRINTF)
+#if 0 /*JP*/
+    int vlen = 0;
+#endif
+#endif
+    boolean no_repeat;
     /* Do NOT use VA_START and VA_END in here... see above */
 
     if (!line || !*line)
@@ -66,7 +148,20 @@ VA_DECL(const char *, line)
         return;
 
     if (index(line, '%')) {
+#if !defined(NO_VSNPRINTF)
+#if 0 /*JP*/
+        vlen = vsnprintf(pbuf, sizeof pbuf, line, VA_ARGS);
+#else
+        vsnprintf(pbuf, sizeof pbuf, line, VA_ARGS);
+#endif
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) && defined(DEBUG)
+        if (vlen >= (int) sizeof pbuf)
+            panic("%s: truncation of buffer at %zu of %d bytes",
+                  "pline", sizeof pbuf, vlen);
+#endif
+#else
         Vsprintf(pbuf, line, VA_ARGS);
+#endif
         line = pbuf;
     }
     if ((ln = (int) strlen(line)) > BUFSZ - 1) {
@@ -83,27 +178,62 @@ VA_DECL(const char *, line)
         pbuf[BUFSZ - 1] = '\0';
         line = pbuf;
     }
-    if (!iflags.window_inited) {
+
+#ifdef DUMPLOG
+    /* We hook here early to have options-agnostic output.
+     * Unfortunately, that means Norep() isn't honored (general issue) and
+     * that short lines aren't combined into one longer one (tty behavior).
+     */
+    if ((pline_flags & SUPPRESS_HISTORY) == 0)
+        dumplogmsg(line);
+#endif
+    /* use raw_print() if we're called too early (or perhaps too late
+       during shutdown) or if we're being called recursively (probably
+       via debugpline() in the interface code) */
+    if (in_pline++ || !iflags.window_inited) {
+        /* [we should probably be using raw_printf("\n%s", line) here] */
         raw_print(line);
         iflags.last_msg = PLNMSG_UNKNOWN;
-        return;
+        goto pline_done;
     }
-#ifndef MAC
-    if (no_repeat && !strcmp(line, toplines))
-        return;
-#endif /* MAC */
+
+    msgtyp = MSGTYP_NORMAL;
+    no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE;
+    if ((pline_flags & OVERRIDE_MSGTYPE) == 0) {
+        msgtyp = msgtype_type(line, no_repeat);
+        if ((pline_flags & URGENT_MESSAGE) == 0
+            && (msgtyp == MSGTYP_NOSHOW
+                || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))))
+            /* FIXME: we need a way to tell our caller that this message
+             * was suppressed so that caller doesn't set iflags.last_msg
+             * for something that hasn't been shown, otherwise a subsequent
+             * message which uses alternate wording based on that would be
+             * doing so out of context and probably end up seeming silly.
+             * (Not an issue for no-repeat but matters for no-show.)
+             */
+            goto pline_done;
+    }
+
     if (vision_full_recalc)
         vision_recalc(0);
     if (u.ux)
         flush_screen(1); /* %% */
-    msgtyp = msgtype_type(line);
-    if (msgtyp == MSGTYP_NOSHOW) return;
-    if (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)) return;
-    putstr(WIN_MESSAGE, 0, line);
+
+    putmesg(line);
+
+#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
+    execplinehandler(line);
+#endif
+
     /* this gets cleared after every pline message */
     iflags.last_msg = PLNMSG_UNKNOWN;
-    strncpy(prevmsg, line, BUFSZ);
-    if (msgtyp == MSGTYP_STOP) display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
+    (void) strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0';
+    if (msgtyp == MSGTYP_STOP)
+        display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
+
+ pline_done:
+    --in_pline;
+    return;
 
 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
     /* provide closing brace for the nested block
@@ -112,15 +242,31 @@ VA_DECL(const char *, line)
 #endif
 }
 
+/* pline() variant which can override MSGTYPE handling or suppress
+   message history (tty interface uses pline() to issue prompts and
+   they shouldn't be blockable via MSGTYPE=hide) */
+/*VARARGS2*/
+void custompline
+VA_DECL2(unsigned, pflags, const char *, line)
+{
+    VA_START(line);
+    VA_INIT(line, const char *);
+    pline_flags = pflags;
+    vpline(line, VA_ARGS);
+    pline_flags = 0;
+    VA_END();
+    return;
+}
+
 /*VARARGS1*/
 void Norep
 VA_DECL(const char *, line)
 {
     VA_START(line);
     VA_INIT(line, const char *);
-    no_repeat = TRUE;
+    pline_flags = PLINE_NOREPEAT;
     vpline(line, VA_ARGS);
-    no_repeat = FALSE;
+    pline_flags = 0;
     VA_END();
     return;
 }
@@ -162,6 +308,7 @@ void You
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
 /*JP
@@ -176,6 +323,7 @@ void Your
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
 /*JP
@@ -190,6 +338,7 @@ void You_feel
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
     if (Unaware)
@@ -211,6 +360,7 @@ void You_cant
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
 /*JP
@@ -225,6 +375,7 @@ void pline_The
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
 /*JP
@@ -239,6 +390,7 @@ void There
 VA_DECL(const char *, line)
 {
     char *tmp;
+
     VA_START(line);
     VA_INIT(line, const char *);
 /*JP
@@ -254,7 +406,7 @@ VA_DECL(const char *, line)
 {
     char *tmp;
 #if 1 /*JP*/
-        char *adj;
+        const char *adj;
         char *p;
 #endif
 
@@ -268,7 +420,7 @@ VA_DECL(const char *, line)
     else if (Unaware)
         YouPrefix(tmp, "You dream that you hear ", line);
     else
-        YouPrefix(tmp, "You hear ", line);
+        YouPrefix(tmp, "You hear ", line);  /* Deaf-aware */
     vpline(strcat(tmp, line), VA_ARGS);
 #else
     if (Underwater)
@@ -382,21 +534,27 @@ void raw_printf
 VA_DECL(const char *, line)
 #endif
 {
-    char pbuf[3 * BUFSZ];
-    int ln;
+    char pbuf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */
     /* Do NOT use VA_START and VA_END in here... see above */
 
     if (index(line, '%')) {
+#if !defined(NO_VSNPRINTF)
+        (void) vsnprintf(pbuf, sizeof pbuf, line, VA_ARGS);
+#else
         Vsprintf(pbuf, line, VA_ARGS);
+#endif
         line = pbuf;
     }
-    if ((ln = (int) strlen(line)) > BUFSZ - 1) {
+    if ((int) strlen(line) > BUFSZ - 1) {
         if (line != pbuf)
             line = strncpy(pbuf, line, BUFSZ - 1);
         /* unlike pline, we don't futz around to keep last few chars */
         pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */
     }
     raw_print(line);
+#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
+    execplinehandler(line);
+#endif
 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
     VA_END(); /* (see vpline) */
 #endif
@@ -406,467 +564,144 @@ VA_DECL(const char *, line)
 void impossible
 VA_DECL(const char *, s)
 {
-    char pbuf[2 * BUFSZ];
+    char pbuf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */
+
     VA_START(s);
     VA_INIT(s, const char *);
     if (program_state.in_impossible)
         panic("impossible called impossible");
 
     program_state.in_impossible = 1;
+#if !defined(NO_VSNPRINTF)
+    (void) vsnprintf(pbuf, sizeof pbuf, s, VA_ARGS);
+#else
     Vsprintf(pbuf, s, VA_ARGS);
+#endif
     pbuf[BUFSZ - 1] = '\0'; /* sanity */
     paniclog("impossible", pbuf);
-    pline("%s", pbuf);
+    if (iflags.debug_fuzzer)
+        panic("%s", pbuf);
+    pline("%s", VA_PASS1(pbuf));
+    /* reuse pbuf[] */
+/*JP
+    Strcpy(pbuf, "Program in disorder!");
+*/
+    Strcpy(pbuf, "\83v\83\8d\83O\83\89\83\80\82É\8fá\8aQ\94­\90\81I");
+    if (program_state.something_worth_saving)
 /*JP
-    pline("Program in disorder - perhaps you'd better #quit.");
+        Strcat(pbuf, "  (Saving and reloading may fix this problem.)");
 */
-    pline("\83v\83\8d\83O\83\89\83\80\82É\8fá\8aQ\94­\90¶ - #quit\82µ\82½\82Ù\82¤\82ª\82æ\82³\82»\82¤\82¾\81D");
+        Strcat(pbuf, "  (\95Û\91\82µ\82Ä\8dÄ\93Ç\82Ý\8d\9e\82Ý\82·\82ê\82Î\96â\91è\89ð\8c\88\82·\82é\82©\82à\82µ\82ê\82È\82¢\81D)");
+    pline("%s", VA_PASS1(pbuf));
+
     program_state.in_impossible = 0;
     VA_END();
 }
 
-const char *
-align_str(alignment)
-aligntyp alignment;
-{
-    switch ((int) alignment) {
-    case A_CHAOTIC:
-/*JP
-        return "chaotic";
-*/
-        return "\8d¬\93×";
-    case A_NEUTRAL:
-/*JP
-        return "neutral";
-*/
-        return "\92\86\97§";
-    case A_LAWFUL:
-/*JP
-        return "lawful";
-*/
-        return "\92\81\8f\98";
-    case A_NONE:
-/*JP
-        return "unaligned";
-*/
-        return "\96³\90S";
-    }
-/*JP
-    return "unknown";
-*/
-    return "\95s\96¾";
-}
+#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
+static boolean use_pline_handler = TRUE;
 
-void
-mstatusline(mtmp)
-register struct monst *mtmp;
+static void
+execplinehandler(line)
+const char *line;
 {
-    aligntyp alignment = mon_aligntyp(mtmp);
-    char info[BUFSZ], monnambuf[BUFSZ];
+    int f;
+    const char *args[3];
+    char *env;
 
-    info[0] = 0;
-    if (mtmp->mtame) {
-/*JP
-        Strcat(info, ", tame");
-*/
-        Strcat(info, ", \8e\94\82¢\82È\82ç\82³\82ê\82Ä\82¢\82é");
-        if (wizard) {
-            Sprintf(eos(info), " (%d", mtmp->mtame);
-            if (!mtmp->isminion)
-                Sprintf(eos(info), "; hungry %ld; apport %d",
-                        EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
-            Strcat(info, ")");
-        }
-    } else if (mtmp->mpeaceful)
-/*JP
-        Strcat(info, ", peaceful");
-*/
-        Strcat(info, ", \97F\8dD\93I");
-    if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham])
-        /* don't reveal the innate form (chameleon, vampire, &c),
-           just expose the fact that this current form isn't it */
-/*JP
-        Strcat(info, ", shapechanger");
-*/
-        Strcat(info, ", \95Ï\89»");
-      
-    /* pets eating mimic corpses mimic while eating, so this comes first */
-    if (mtmp->meating)
-/*JP
-        Strcat(info, ", eating");
-*/
-        Strcat(info, ", \90H\8e\96\92\86");
-    /* a stethoscope exposes mimic before getting here so this
-       won't be relevant for it, but wand of probing doesn't */
-    if (mtmp->m_ap_type)
-#if 0 /*JP*/
-        Sprintf(eos(info), ", mimicking %s",
-                (mtmp->m_ap_type == M_AP_FURNITURE)
-                    ? an(defsyms[mtmp->mappearance].explanation)
-                    : (mtmp->m_ap_type == M_AP_OBJECT)
-                          ? ((mtmp->mappearance == GOLD_PIECE)
-                                 ? "gold"
-                                 : an(simple_typename(mtmp->mappearance)))
-                          : (mtmp->m_ap_type == M_AP_MONSTER)
-                                ? an(mons[mtmp->mappearance].mname)
-                                : something); /* impossible... */
-#else
-        Sprintf(eos(info), ", %s\82Ì\82Ü\82Ë\82ð\82µ\82Ä\82¢\82é",
-                (mtmp->m_ap_type == M_AP_FURNITURE)
-                    ? an(defsyms[mtmp->mappearance].explanation)
-                    : (mtmp->m_ap_type == M_AP_OBJECT)
-                          ? ((mtmp->mappearance == GOLD_PIECE)
-                                 ? "\8bà\89Ý"
-                                 : an(simple_typename(mtmp->mappearance)))
-                          : (mtmp->m_ap_type == M_AP_MONSTER)
-                                ? an(mons[mtmp->mappearance].mname)
-                                : something); /* impossible... */
-#endif
-    if (mtmp->mcan)
-/*JP
-        Strcat(info, ", cancelled");
-*/
-        Strcat(info, ", \96³\97Í");
-    if (mtmp->mconf)
-/*JP
-        Strcat(info, ", confused");
-*/
-        Strcat(info, ", \8d¬\97\90\8fó\91Ô");
-    if (mtmp->mblinded || !mtmp->mcansee)
-/*JP
-        Strcat(info, ", blind");
-*/
-        Strcat(info, ", \96Ó\96Ú");
-    if (mtmp->mstun)
-/*JP
-        Strcat(info, ", stunned");
-*/
-        Strcat(info, ", \82­\82ç\82­\82ç\8fó\91Ô");
-    if (mtmp->msleeping)
-/*JP
-        Strcat(info, ", asleep");
-*/
-        Strcat(info, ", \90\87\96°\8fó\91Ô");
-#if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
-         (donning armor, for instance) as well as paralysis */
-       else if (mtmp->mfrozen)   Strcat(info, ", paralyzed");
-#else
-    else if (mtmp->mfrozen || !mtmp->mcanmove)
-/*JP
-        Strcat(info, ", can't move");
-*/
-        Strcat(info, ", \93®\82¯\82È\82¢");
-#endif
-    /* [arbitrary reason why it isn't moving] */
-    else if (mtmp->mstrategy & STRAT_WAITMASK)
-/*JP
-        Strcat(info, ", meditating");
-*/
-        Strcat(info, ", \96»\91z\92\86");
-    if (mtmp->mflee)
-/*JP
-        Strcat(info, ", scared");
-*/
-        Strcat(info, ", \8b¯\82¦\82Ä\82¢\82é");
-    if (mtmp->mtrapped)
-/*JP
-        Strcat(info, ", trapped");
-*/
-        Strcat(info, ", ã©\82É\82©\82©\82Á\82Ä\82¢\82é");
-    if (mtmp->mspeed)
-#if 0 /*JP:T*/
-        Strcat(info, mtmp->mspeed == MFAST ? ", fast" : mtmp->mspeed == MSLOW
-                                                            ? ", slow"
-                                                            : ", ???? speed");
-#else
-        Strcat(info, mtmp->mspeed == MFAST ? ", \91f\91\81\82¢" : mtmp->mspeed == MSLOW
-                                                            ? ", \92x\82¢"
-                                                            : ", \91¬\93x\95s\96¾");
-#endif
-    if (mtmp->mundetected)
-/*JP
-        Strcat(info, ", concealed");
-*/
-        Strcat(info, ", \89B\82ê\82Ä\82¢\82é");
-    if (mtmp->minvis)
-/*JP
-        Strcat(info, ", invisible");
-*/
-        Strcat(info, ", \95s\89Â\8e\8b");
-    if (mtmp == u.ustuck)
-#if 0 /*JP:T*/
-        Strcat(info, sticks(youmonst.data)
-                         ? ", held by you"
-                         : !u.uswallow ? ", holding you"
-                                       : attacktype_fordmg(u.ustuck->data,
-                                                           AT_ENGL, AD_DGST)
-                                             ? ", digesting you"
-                                             : is_animal(u.ustuck->data)
-                                                   ? ", swallowing you"
-                                                   : ", engulfing you");
-#else
-      Strcat(info,  sticks(youmonst.data)
-                         ? ", \82 \82È\82½\82ª\92Í\82Ü\82¦\82Ä\82¢\82é"
-                         : !u.uswallow ? ", \92Í\82Ü\82¦\82Ä\82¢\82é"
-                                       : attacktype_fordmg(u.ustuck->data,
-                                                           AT_ENGL, AD_DGST)
-                                             ? ", \8fÁ\89»\82µ\82Ä\82¢\82é"
-                                             : is_animal(u.ustuck->data)
-                                                   ? ", \88ù\82Ý\8d\9e\82ñ\82Å\82¢\82é"
-                                                   : ", \8aª\82«\8d\9e\82ñ\82Å\82¢\82é");
-#endif
-    if (mtmp == u.usteed)
-/*JP
-        Strcat(info, ", carrying you");
-*/
-        Strcat(info, ", \82 \82È\82½\82ð\8fæ\82¹\82Ä\82¢\82é");
+    if (!use_pline_handler)
+        return;
 
-    /* avoid "Status of the invisible newt ..., invisible" */
-    /* and unlike a normal mon_nam, use "saddled" even if it has a name */
-    Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
-                               (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE));
+    if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) {
+        use_pline_handler = FALSE;
+        return;
+    }
 
-/*JP
-    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", monnambuf,
-*/
-    pline("%s\82Ì\8fó\91Ô (%s)\81F Level %d  HP %d(%d)  AC %d%s", monnambuf,
-          align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
-          find_mac(mtmp), info);
+    f = fork();
+    if (f == 0) { /* child */
+        args[0] = env;
+        args[1] = line;
+        args[2] = NULL;
+        (void) setgid(getgid());
+        (void) setuid(getuid());
+        (void) execv(args[0], (char *const *) args);
+        perror((char *) 0);
+        (void) fprintf(stderr, "Exec to message handler %s failed.\n", env);
+        nh_terminate(EXIT_FAILURE);
+    } else if (f > 0) {
+        int status;
+
+        waitpid(f, &status, 0);
+    } else if (f == -1) {
+        perror((char *) 0);
+        use_pline_handler = FALSE;
+        pline("%s", VA_PASS1("Fork to message handler failed."));
+    }
 }
+#endif /* MSGHANDLER && (POSIX_TYPES || __GNUC__) */
 
+/*
+ * varargs handling for files.c
+ */
+#if defined(USE_STDARG) || defined(USE_VARARGS)
+static void FDECL(vconfig_error_add, (const char *, va_list));
+
+/*VARARGS1*/
 void
-ustatusline()
+config_error_add
+VA_DECL(const char *, str)
 {
-    char info[BUFSZ];
+    VA_START(str);
+    VA_INIT(str, char *);
+    vconfig_error_add(str, VA_ARGS);
+    VA_END();
+}
+
+# ifdef USE_STDARG
+static void
+vconfig_error_add(const char *str, va_list the_args)
+# else
+static void
+vconfig_error_add(str, the_args)
+const char *str;
+va_list the_args;
+# endif
+
+#else /* !(USE_STDARG || USE_VARARG) => USE_OLDARGS */
 
-    info[0] = '\0';
-    if (Sick) {
+/*VARARGS1*/
+void
+config_error_add
+VA_DECL(const char *, str)
+#endif /* ?(USE_STDARG || USE_VARARG) */
+{       /* start of vconf...() or of nested block in USE_OLDARG's conf...() */
+#if !defined(NO_VSNPRINTF)
 #if 0 /*JP*/
-        Strcat(info, ", dying from");
-        if (u.usick_type & SICK_VOMITABLE)
-            Strcat(info, " food poisoning");
-        if (u.usick_type & SICK_NONVOMITABLE) {
-            if (u.usick_type & SICK_VOMITABLE)
-                Strcat(info, " and");
-            Strcat(info, " illness");
-        }
-#else
-        Strcat(info, ", ");
-        if (u.usick_type & SICK_VOMITABLE)
-            Strcat(info, "\90H\92\86\93Å");
-        if (u.usick_type & SICK_NONVOMITABLE) {
-            if (u.usick_type & SICK_VOMITABLE)
-                Strcat(info, "\82Æ");
-            Strcat(info, "\95a\8bC");
-        }
-        Strcat(info, "\82Å\8e\80\82É\82Â\82Â\82 \82é");
+    int vlen = 0;
 #endif
-    }
-    if (Stoned)
-/*JP
-        Strcat(info, ", solidifying");
-*/
-        Strcat(info, ", \90Î\89»\82µ\82Â\82Â\82 \82é");
-    if (Slimed)
-/*JP
-        Strcat(info, ", becoming slimy");
-*/
-        Strcat(info, ", \83X\83\89\83C\83\80\82É\82È\82è\82Â\82Â\82 \82é");
-    if (Strangled)
-/*JP
-        Strcat(info, ", being strangled");
-*/
-        Strcat(info, ", \8eñ\82ð\8di\82ß\82ç\82ê\82Ä\82¢\82é");
-    if (Vomiting)
-#if 0 /*JP*/
-        Strcat(info, ", nauseated"); /* !"nauseous" */
-#else
-        Strcat(info, ", \93f\82«\8bC\82ª\82·\82é");
 #endif
-    if (Confusion)
-/*JP
-        Strcat(info, ", confused");
-*/
-        Strcat(info, ", \8d¬\97\90\8fó\91Ô");
-    if (Blind) {
+    char buf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */
+
+#if !defined(NO_VSNPRINTF)
 #if 0 /*JP*/
-        Strcat(info, ", blind");
-        if (u.ucreamed) {
-            if ((long) u.ucreamed < Blinded || Blindfolded
-                || !haseyes(youmonst.data))
-                Strcat(info, ", cover");
-            Strcat(info, "ed by sticky goop");
-        } /* note: "goop" == "glop"; variation is intentional */
+    vlen = vsnprintf(buf, sizeof buf, str, VA_ARGS);
 #else
-        Strcat(info, ", ");
-        if (u.ucreamed) {
-            Strcat(info, "\82Ë\82Î\82Ë\82Î\82×\82Æ\82Â\82­\82à\82Ì\82Å");
-            if ((long)u.ucreamed < Blinded || Blindfolded
-                || !haseyes(youmonst.data))
-              Strcat(info, "\95¢\82í\82ê\82Ä");
-        }
-        Strcat(info, "\96Ó\96Ú\8fó\91Ô");
+    vsnprintf(buf, sizeof buf, str, VA_ARGS);
 #endif
-    }
-    if (Stunned)
-/*JP
-        Strcat(info, ", stunned");
-*/
-        Strcat(info, ", \82­\82ç\82­\82ç\8fó\91Ô");
-    if (!u.usteed && Wounded_legs) {
-        const char *what = body_part(LEG);
-        if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
-            what = makeplural(what);
-/*JP
-        Sprintf(eos(info), ", injured %s", what);
-*/
-        Sprintf(eos(info), ", %s\82É\82¯\82ª\82ð\82µ\82Ä\82¢\82é", what);
-    }
-    if (Glib)
-/*JP
-        Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
-*/
-        Sprintf(eos(info), ", %s\82ª\82Ê\82é\82Ê\82é", makeplural(body_part(HAND)));
-    if (u.utrap)
-/*JP
-        Strcat(info, ", trapped");
-*/
-        Strcat(info, ", ã©\82É\82©\82©\82Á\82Ä\82¢\82é");
-    if (Fast)
-/*JP
-        Strcat(info, Very_fast ? ", very fast" : ", fast");
-*/
-        Strcat(info, Very_fast ? ", \82Æ\82Ä\82à\91f\91\81\82¢" : ", \91f\91\81\82¢");
-    if (u.uundetected)
-/*JP
-        Strcat(info, ", concealed");
-*/
-        Strcat(info, ", \89B\82ê\82Ä\82¢\82é");
-    if (Invis)
-/*JP
-        Strcat(info, ", invisible");
-*/
-        Strcat(info, ", \95s\89Â\8e\8b");
-    if (u.ustuck) {
-#if 0 /*JP*/
-        if (sticks(youmonst.data))
-            Strcat(info, ", holding ");
-        else
-            Strcat(info, ", held by ");
-        Strcat(info, mon_nam(u.ustuck));
-#else
-        Strcat(info, ", ");
-        Strcat(info, mon_nam(u.ustuck));
-        if (sticks(youmonst.data))
-            Strcat(info, "\82ð\92Í\82Ü\82¦\82Ä\82¢\82é");
-        else
-            Strcat(info, "\82É\92Í\82Ü\82¦\82ç\82ê\82Ä\82¢\82é");
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) && defined(DEBUG)
+    if (vlen >= (int) sizeof buf)
+        panic("%s: truncation of buffer at %zu of %d bytes",
+              "config_error_add", sizeof buf, vlen);
 #endif
-    }
-
-/*JP
-    pline("Status of %s (%s%s):  Level %d  HP %d(%d)  AC %d%s.", plname,
-*/
-    pline("%s\82Ì\8fó\91Ô (%s %s)\81F Level %d  HP %d(%d)  AC %d%s", plname,
-          (u.ualign.record >= 20)
-/*JP
-              ? "piously "
-*/
-              ? "\8chåi" 
-              : (u.ualign.record > 13)
-/*JP
-                    ? "devoutly "
-*/
-                    ? "\90M\90S\90[\82¢" 
-                    : (u.ualign.record > 8)
-/*JP
-                          ? "fervently "
-*/
-                          ? "\94M\97ó" 
-                          : (u.ualign.record > 3)
-/*JP
-                                ? "stridently "
-*/
-                                ? "\90º\82Ì\82©\82ñ\8d\82\82¢" 
-                                : (u.ualign.record == 3)
-                                      ? ""
-                                      : (u.ualign.record >= 1)
-/*JP
-                                            ? "haltingly "
-*/
-                                            ? "\97L\96¼\96³\8eÀ" 
-                                            : (u.ualign.record == 0)
-/*JP
-                                                  ? "nominally "
-*/
-                                                  ? "\96À\98f" 
-/*JP
-                                                  : "insufficiently ",
-*/
-                                                  : "\95s\93K\93\96",
-          align_str(u.ualign.type),
-          Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
-          Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
-}
-
-void
-self_invis_message()
-{
-#if 0 /*JP:T*/
-    pline("%s %s.",
-          Hallucination ? "Far out, man!  You" : "Gee!  All of a sudden, you",
-          See_invisible ? "can see right through yourself"
-                        : "can't see yourself");
 #else
-    pline("%s\82 \82È\82½\82Í%s\81D",
-          Hallucination ? "\83\8f\81[\83I\81I" : "\82°\81I\93Ë\91R",
-          See_invisible ? "\8e©\95ª\8e©\90g\82ª\82¿\82á\82ñ\82Æ\8c©\82¦\82È\82­\82È\82Á\82½"
-                        : "\8e©\95ª\8e©\90g\82ª\8c©\82¦\82È\82­\82È\82Á\82½");
+    Vsprintf(buf, str, VA_ARGS);
 #endif
-}
+    buf[BUFSZ - 1] = '\0';
+    config_erradd(buf);
 
-void
-pudding_merge_message(otmp, otmp2)
-struct obj *otmp;
-struct obj *otmp2;
-{
-    boolean visible =
-        cansee(otmp->ox, otmp->oy) || cansee(otmp2->ox, otmp2->oy);
-    boolean onfloor = otmp->where == OBJ_FLOOR || otmp2->where == OBJ_FLOOR;
-    boolean inpack = carried(otmp) || carried(otmp2);
-
-    /* the player will know something happened inside his own inventory */
-    if ((!Blind && visible) || inpack) {
-        if (Hallucination) {
-            if (onfloor) {
-/*JP
-                You_see("parts of the floor melting!");
-*/
-                You_see("\8f°\82Ì\88ê\95\94\82ª\97n\82¯\82Ä\82¢\82é\82Ì\82ð\8c©\82½\81I");
-            } else if (inpack) {
-/*JP
-                Your("pack reaches out and grabs something!");
-*/
-                Your("\82©\82Î\82ñ\82ª\8eè\82ð\90L\82Î\82µ\82Ä\89½\82©\82ð\82Â\82©\82ñ\82¾\81I");
-            }
-            /* even though we can see where they should be,
-             * they'll be out of our view (minvent or container)
-             * so don't actually show anything */
-        } else if (onfloor || inpack) {
-#if 0 /*JP*/
-            pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)),
-                  inpack ? " inside your pack" : "");
-#else
-            pline("%s\82ª%s\8d\87\91Ì\82µ\82½\81D", obj_typename(otmp->otyp),
-                  inpack ? "\82 \82È\82½\82Ì\82©\82Î\82ñ\82Ì\92\86\82Å" : "");
+#if !(defined(USE_STDARG) || defined(USE_VARARGS))
+    VA_END(); /* (see pline/vpline -- ends nested block for USE_OLDARGS) */
 #endif
-        }
-    } else {
-/*JP
-        You_hear("a faint sloshing sound.");
-*/
-        You_hear("\82©\82·\82©\82È\83o\83V\83\83\83o\83V\83\83\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D");
-    }
 }
 
 /*pline.c*/