667 lines
18 KiB
C
667 lines
18 KiB
C
/* NetHack 3.6 pline.c $NHDT-Date: 1461437814 2016/04/23 18:56:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \
|
|
*/
|
|
#include "hack.h"
|
|
|
|
static boolean no_repeat = FALSE;
|
|
static char prevmsg[BUFSZ];
|
|
|
|
static char *FDECL(You_buf, (int));
|
|
#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
|
|
static void FDECL(execplinehandler, (const char *));
|
|
#endif
|
|
|
|
/*VARARGS1*/
|
|
/* Note that these declarations rely on knowledge of the internals
|
|
* of the variable argument handling stuff in "tradstdc.h"
|
|
*/
|
|
|
|
#if defined(USE_STDARG) || defined(USE_VARARGS)
|
|
static void FDECL(vpline, (const char *, va_list));
|
|
|
|
void pline
|
|
VA_DECL(const char *, line)
|
|
{
|
|
VA_START(line);
|
|
VA_INIT(line, char *);
|
|
vpline(line, VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
# ifdef USE_STDARG
|
|
static void
|
|
vpline(const char *line, va_list the_args)
|
|
# else
|
|
static void
|
|
vpline(line, the_args)
|
|
const char *line;
|
|
va_list the_args;
|
|
# endif
|
|
|
|
#else /* USE_STDARG | USE_VARARG */
|
|
|
|
# define vpline pline
|
|
|
|
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];
|
|
int ln;
|
|
xchar msgtyp;
|
|
/* Do NOT use VA_START and VA_END in here... see above */
|
|
|
|
if (!line || !*line)
|
|
return;
|
|
#ifdef HANGUPHANDLING
|
|
if (program_state.done_hup)
|
|
return;
|
|
#endif
|
|
if (program_state.wizkit_wishing)
|
|
return;
|
|
|
|
if (index(line, '%')) {
|
|
Vsprintf(pbuf, line, VA_ARGS);
|
|
line = pbuf;
|
|
}
|
|
if ((ln = (int) strlen(line)) > BUFSZ - 1) {
|
|
if (line != pbuf) /* no '%' was present */
|
|
(void) strncpy(pbuf, line, BUFSZ - 1); /* caveat: unterminated */
|
|
/* truncate, preserving the final 3 characters:
|
|
"___ extremely long text" -> "___ extremely l...ext"
|
|
(this may be suboptimal if overflow is less than 3) */
|
|
(void) strncpy(pbuf + BUFSZ - 1 - 6, "...", 3);
|
|
/* avoid strncpy; buffers could overlap if excess is small */
|
|
pbuf[BUFSZ - 1 - 3] = line[ln - 3];
|
|
pbuf[BUFSZ - 1 - 2] = line[ln - 2];
|
|
pbuf[BUFSZ - 1 - 1] = line[ln - 1];
|
|
pbuf[BUFSZ - 1] = '\0';
|
|
line = pbuf;
|
|
}
|
|
if (!iflags.window_inited) {
|
|
raw_print(line);
|
|
iflags.last_msg = PLNMSG_UNKNOWN;
|
|
return;
|
|
}
|
|
|
|
msgtyp = msgtype_type(line, no_repeat);
|
|
if (msgtyp == MSGTYP_NOSHOW
|
|
|| (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)))
|
|
return;
|
|
if (vision_full_recalc)
|
|
vision_recalc(0);
|
|
if (u.ux)
|
|
flush_screen(1); /* %% */
|
|
|
|
putstr(WIN_MESSAGE, 0, 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), prevmsg[BUFSZ - 1] = '\0';
|
|
if (msgtyp == MSGTYP_STOP)
|
|
display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
|
|
|
|
#if !(defined(USE_STDARG) || defined(USE_VARARGS))
|
|
/* provide closing brace for the nested block
|
|
which immediately follows USE_OLDARGS's VA_DECL() */
|
|
VA_END();
|
|
#endif
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void Norep
|
|
VA_DECL(const char *, line)
|
|
{
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
no_repeat = TRUE;
|
|
vpline(line, VA_ARGS);
|
|
no_repeat = FALSE;
|
|
VA_END();
|
|
return;
|
|
}
|
|
|
|
/* work buffer for You(), &c and verbalize() */
|
|
static char *you_buf = 0;
|
|
static int you_buf_siz = 0;
|
|
|
|
static char *
|
|
You_buf(siz)
|
|
int siz;
|
|
{
|
|
if (siz > you_buf_siz) {
|
|
if (you_buf)
|
|
free((genericptr_t) you_buf);
|
|
you_buf_siz = siz + 10;
|
|
you_buf = (char *) alloc((unsigned) you_buf_siz);
|
|
}
|
|
return you_buf;
|
|
}
|
|
|
|
void
|
|
free_youbuf()
|
|
{
|
|
if (you_buf)
|
|
free((genericptr_t) you_buf), you_buf = (char *) 0;
|
|
you_buf_siz = 0;
|
|
}
|
|
|
|
/* `prefix' must be a string literal, not a pointer */
|
|
#define YouPrefix(pointer, prefix, text) \
|
|
Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix)
|
|
|
|
#define YouMessage(pointer, prefix, text) \
|
|
strcat((YouPrefix(pointer, prefix, text), pointer), text)
|
|
|
|
/*VARARGS1*/
|
|
void You
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
vpline(YouMessage(tmp, "You ", line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void Your
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void You_feel
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
if (Unaware)
|
|
YouPrefix(tmp, "You dream that you feel ", line);
|
|
else
|
|
YouPrefix(tmp, "You feel ", line);
|
|
vpline(strcat(tmp, line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void You_cant
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void pline_The
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
vpline(YouMessage(tmp, "The ", line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void There
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
vpline(YouMessage(tmp, "There ", line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void You_hear
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
|
|
if (Deaf || !flags.acoustics)
|
|
return;
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
if (Underwater)
|
|
YouPrefix(tmp, "You barely hear ", line);
|
|
else if (Unaware)
|
|
YouPrefix(tmp, "You dream that you hear ", line);
|
|
else
|
|
YouPrefix(tmp, "You hear ", line);
|
|
vpline(strcat(tmp, line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void You_see
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
if (Unaware)
|
|
YouPrefix(tmp, "You dream that you see ", line);
|
|
else if (Blind) /* caller should have caught this... */
|
|
YouPrefix(tmp, "You sense ", line);
|
|
else
|
|
YouPrefix(tmp, "You see ", line);
|
|
vpline(strcat(tmp, line), VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/* Print a message inside double-quotes.
|
|
* The caller is responsible for checking deafness.
|
|
* Gods can speak directly to you in spite of deafness.
|
|
*/
|
|
/*VARARGS1*/
|
|
void verbalize
|
|
VA_DECL(const char *, line)
|
|
{
|
|
char *tmp;
|
|
|
|
VA_START(line);
|
|
VA_INIT(line, const char *);
|
|
tmp = You_buf((int) strlen(line) + sizeof "\"\"");
|
|
Strcpy(tmp, "\"");
|
|
Strcat(tmp, line);
|
|
Strcat(tmp, "\"");
|
|
vpline(tmp, VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
/* Note that these declarations rely on knowledge of the internals
|
|
* of the variable argument handling stuff in "tradstdc.h"
|
|
*/
|
|
|
|
#if defined(USE_STDARG) || defined(USE_VARARGS)
|
|
static void FDECL(vraw_printf, (const char *, va_list));
|
|
|
|
void raw_printf
|
|
VA_DECL(const char *, line)
|
|
{
|
|
VA_START(line);
|
|
VA_INIT(line, char *);
|
|
vraw_printf(line, VA_ARGS);
|
|
VA_END();
|
|
}
|
|
|
|
# ifdef USE_STDARG
|
|
static void
|
|
vraw_printf(const char *line, va_list the_args)
|
|
# else
|
|
static void
|
|
vraw_printf(line, the_args)
|
|
const char *line;
|
|
va_list the_args;
|
|
# endif
|
|
|
|
#else /* USE_STDARG | USE_VARARG */
|
|
|
|
void raw_printf
|
|
VA_DECL(const char *, line)
|
|
#endif
|
|
{
|
|
char pbuf[3 * BUFSZ];
|
|
int ln;
|
|
/* Do NOT use VA_START and VA_END in here... see above */
|
|
|
|
if (index(line, '%')) {
|
|
Vsprintf(pbuf, line, VA_ARGS);
|
|
line = pbuf;
|
|
}
|
|
if ((ln = (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(USE_STDARG) || defined(USE_VARARGS))
|
|
VA_END(); /* (see vpline) */
|
|
#endif
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
void impossible
|
|
VA_DECL(const char *, s)
|
|
{
|
|
char pbuf[2 * BUFSZ];
|
|
VA_START(s);
|
|
VA_INIT(s, const char *);
|
|
if (program_state.in_impossible)
|
|
panic("impossible called impossible");
|
|
|
|
program_state.in_impossible = 1;
|
|
Vsprintf(pbuf, s, VA_ARGS);
|
|
pbuf[BUFSZ - 1] = '\0'; /* sanity */
|
|
paniclog("impossible", pbuf);
|
|
pline("%s", pbuf);
|
|
pline("Program in disorder - perhaps you'd better #quit.");
|
|
program_state.in_impossible = 0;
|
|
VA_END();
|
|
}
|
|
|
|
const char *
|
|
align_str(alignment)
|
|
aligntyp alignment;
|
|
{
|
|
switch ((int) alignment) {
|
|
case A_CHAOTIC:
|
|
return "chaotic";
|
|
case A_NEUTRAL:
|
|
return "neutral";
|
|
case A_LAWFUL:
|
|
return "lawful";
|
|
case A_NONE:
|
|
return "unaligned";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
void
|
|
mstatusline(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
aligntyp alignment = mon_aligntyp(mtmp);
|
|
char info[BUFSZ], monnambuf[BUFSZ];
|
|
|
|
info[0] = 0;
|
|
if (mtmp->mtame) {
|
|
Strcat(info, ", tame");
|
|
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)
|
|
Strcat(info, ", peaceful");
|
|
|
|
if (mtmp->data == &mons[PM_LONG_WORM]) {
|
|
int segndx, nsegs = count_wsegs(mtmp);
|
|
|
|
/* the worm code internals don't consider the head of be one of
|
|
the worm's segments, but we count it as such when presenting
|
|
worm feedback to the player */
|
|
if (!nsegs) {
|
|
Strcat(info, ", single segment");
|
|
} else {
|
|
++nsegs; /* include head in the segment count */
|
|
segndx = wseg_at(mtmp, bhitpos.x, bhitpos.y);
|
|
Sprintf(eos(info), ", %d%s of %d segments",
|
|
segndx, ordin(segndx), nsegs);
|
|
}
|
|
}
|
|
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 */
|
|
Strcat(info, ", shapechanger");
|
|
/* pets eating mimic corpses mimic while eating, so this comes first */
|
|
if (mtmp->meating)
|
|
Strcat(info, ", eating");
|
|
/* a stethoscope exposes mimic before getting here so this
|
|
won't be relevant for it, but wand of probing doesn't */
|
|
if (mtmp->mundetected || mtmp->m_ap_type)
|
|
mhidden_description(mtmp, TRUE, eos(info));
|
|
if (mtmp->mcan)
|
|
Strcat(info, ", cancelled");
|
|
if (mtmp->mconf)
|
|
Strcat(info, ", confused");
|
|
if (mtmp->mblinded || !mtmp->mcansee)
|
|
Strcat(info, ", blind");
|
|
if (mtmp->mstun)
|
|
Strcat(info, ", stunned");
|
|
if (mtmp->msleeping)
|
|
Strcat(info, ", asleep");
|
|
#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)
|
|
Strcat(info, ", can't move");
|
|
#endif
|
|
/* [arbitrary reason why it isn't moving] */
|
|
else if (mtmp->mstrategy & STRAT_WAITMASK)
|
|
Strcat(info, ", meditating");
|
|
if (mtmp->mflee)
|
|
Strcat(info, ", scared");
|
|
if (mtmp->mtrapped)
|
|
Strcat(info, ", trapped");
|
|
if (mtmp->mspeed)
|
|
Strcat(info, mtmp->mspeed == MFAST ? ", fast" : mtmp->mspeed == MSLOW
|
|
? ", slow"
|
|
: ", ???? speed");
|
|
if (mtmp->minvis)
|
|
Strcat(info, ", invisible");
|
|
if (mtmp == u.ustuck)
|
|
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");
|
|
if (mtmp == u.usteed)
|
|
Strcat(info, ", carrying you");
|
|
|
|
/* 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));
|
|
|
|
pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", monnambuf,
|
|
align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
|
|
find_mac(mtmp), info);
|
|
}
|
|
|
|
void
|
|
ustatusline()
|
|
{
|
|
char info[BUFSZ];
|
|
|
|
info[0] = '\0';
|
|
if (Sick) {
|
|
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");
|
|
}
|
|
}
|
|
if (Stoned)
|
|
Strcat(info, ", solidifying");
|
|
if (Slimed)
|
|
Strcat(info, ", becoming slimy");
|
|
if (Strangled)
|
|
Strcat(info, ", being strangled");
|
|
if (Vomiting)
|
|
Strcat(info, ", nauseated"); /* !"nauseous" */
|
|
if (Confusion)
|
|
Strcat(info, ", confused");
|
|
if (Blind) {
|
|
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 */
|
|
}
|
|
if (Stunned)
|
|
Strcat(info, ", stunned");
|
|
if (!u.usteed && Wounded_legs) {
|
|
const char *what = body_part(LEG);
|
|
if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
|
|
what = makeplural(what);
|
|
Sprintf(eos(info), ", injured %s", what);
|
|
}
|
|
if (Glib)
|
|
Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
|
|
if (u.utrap)
|
|
Strcat(info, ", trapped");
|
|
if (Fast)
|
|
Strcat(info, Very_fast ? ", very fast" : ", fast");
|
|
if (u.uundetected)
|
|
Strcat(info, ", concealed");
|
|
if (Invis)
|
|
Strcat(info, ", invisible");
|
|
if (u.ustuck) {
|
|
if (sticks(youmonst.data))
|
|
Strcat(info, ", holding ");
|
|
else
|
|
Strcat(info, ", held by ");
|
|
Strcat(info, mon_nam(u.ustuck));
|
|
}
|
|
|
|
pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", plname,
|
|
piousness(FALSE, 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()
|
|
{
|
|
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");
|
|
}
|
|
|
|
char *
|
|
piousness(showneg, suffix)
|
|
boolean showneg;
|
|
const char *suffix;
|
|
{
|
|
static char buf[32]; /* bigger than "insufficiently neutral" */
|
|
const char *pio;
|
|
|
|
/* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
|
|
if (u.ualign.record >= 20)
|
|
pio = "piously";
|
|
else if (u.ualign.record > 13)
|
|
pio = "devoutly";
|
|
else if (u.ualign.record > 8)
|
|
pio = "fervently";
|
|
else if (u.ualign.record > 3)
|
|
pio = "stridently";
|
|
else if (u.ualign.record == 3)
|
|
pio = "";
|
|
else if (u.ualign.record > 0)
|
|
pio = "haltingly";
|
|
else if (u.ualign.record == 0)
|
|
pio = "nominally";
|
|
else if (!showneg)
|
|
pio = "insufficiently";
|
|
else if (u.ualign.record >= -3)
|
|
pio = "strayed";
|
|
else if (u.ualign.record >= -8)
|
|
pio = "sinned";
|
|
else
|
|
pio = "transgressed";
|
|
|
|
Sprintf(buf, "%s", pio);
|
|
if (suffix && (!showneg || u.ualign.record >= 0)) {
|
|
if (u.ualign.record != 3)
|
|
Strcat(buf, " ");
|
|
Strcat(buf, suffix);
|
|
}
|
|
return 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) {
|
|
You_see("parts of the floor melting!");
|
|
} else if (inpack) {
|
|
Your("pack reaches out and grabs something!");
|
|
}
|
|
/* 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) {
|
|
pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)),
|
|
inpack ? " inside your pack" : "");
|
|
}
|
|
} else {
|
|
You_hear("a faint sloshing sound.");
|
|
}
|
|
}
|
|
|
|
#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
|
|
static boolean use_pline_handler = TRUE;
|
|
static void
|
|
execplinehandler(line)
|
|
const char *line;
|
|
{
|
|
int f;
|
|
const char *args[3];
|
|
char *env;
|
|
|
|
if (!use_pline_handler)
|
|
return;
|
|
|
|
if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) {
|
|
use_pline_handler = FALSE;
|
|
return;
|
|
}
|
|
|
|
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);
|
|
terminate(EXIT_FAILURE);
|
|
} else if (f == -1) {
|
|
perror((char *) 0);
|
|
use_pline_handler = FALSE;
|
|
pline("Fork to message handler failed.");
|
|
}
|
|
}
|
|
#endif /* defined(POSIX_TYPES) || defined(__GNUC__) */
|
|
|
|
/*pline.c*/
|