1 /* 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 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
9 /* JNetHack may be freely redistributed. See license for details. */
11 #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers */
14 static unsigned pline_flags = 0;
15 static char prevmsg[BUFSZ];
17 static void FDECL(putmesg, (const char *));
18 static char *FDECL(You_buf, (int));
19 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
20 static void FDECL(execplinehandler, (const char *));
24 /* also used in end.c */
25 unsigned saved_pline_index = 0; /* slot in saved_plines[] to use next */
26 char *saved_plines[DUMPLOG_MSG_COUNT] = { (char *) 0 };
28 /* keep the most recent DUMPLOG_MSG_COUNT messages */
35 * This essentially duplicates message history, which is
36 * currently implemented in an interface-specific manner.
37 * The core should take responsibility for that and have
40 unsigned indx = saved_pline_index; /* next slot to use */
41 char *oldest = saved_plines[indx]; /* current content of that slot */
43 if (oldest && strlen(oldest) >= strlen(line)) {
44 /* this buffer will gradually shrink until the 'else' is needed;
45 there's no pressing need to track allocation size instead */
49 free((genericptr_t) oldest);
50 saved_plines[indx] = dupstr(line);
52 saved_pline_index = (indx + 1) % DUMPLOG_MSG_COUNT;
55 /* called during save (unlike the interface-specific message history,
56 this data isn't saved and restored); end-of-game releases saved_pline[]
57 while writing its contents to the final dump log */
63 for (indx = 0; indx < DUMPLOG_MSG_COUNT; ++indx)
64 if (saved_plines[indx])
65 free((genericptr_t) saved_plines[indx]), saved_plines[indx] = 0;
66 saved_pline_index = 0;
70 /* keeps windowprocs usage out of pline() */
77 if ((pline_flags & URGENT_MESSAGE) != 0
78 && (windowprocs.wincap2 & WC2_URGENT_MESG) != 0)
80 if ((pline_flags & SUPPRESS_HISTORY) != 0
81 && (windowprocs.wincap2 & WC2_SUPPRESS_HIST) != 0)
82 attr |= ATR_NOHISTORY;
84 putstr(WIN_MESSAGE, attr, line);
87 /* Note that these declarations rely on knowledge of the internals
88 * of the variable argument handling stuff in "tradstdc.h"
91 #if defined(USE_STDARG) || defined(USE_VARARGS)
92 static void FDECL(vpline, (const char *, va_list));
97 VA_DECL(const char *, line)
100 VA_INIT(line, char *);
101 vpline(line, VA_ARGS);
107 vpline(const char *line, va_list the_args)
110 vpline(line, the_args)
115 #else /* USE_STDARG | USE_VARARG */
117 # define vpline pline
122 VA_DECL(const char *, line)
123 #endif /* USE_STDARG | USE_VARARG */
124 { /* start of vpline() or of nested block in USE_OLDARG's pline() */
125 static int in_pline = 0;
126 char pbuf[3 * BUFSZ];
130 /* Do NOT use VA_START and VA_END in here... see above */
134 #ifdef HANGUPHANDLING
135 if (program_state.done_hup)
138 if (program_state.wizkit_wishing)
141 if (index(line, '%')) {
142 Vsprintf(pbuf, line, VA_ARGS);
145 if ((ln = (int) strlen(line)) > BUFSZ - 1) {
146 if (line != pbuf) /* no '%' was present */
147 (void) strncpy(pbuf, line, BUFSZ - 1); /* caveat: unterminated */
148 /* truncate, preserving the final 3 characters:
149 "___ extremely long text" -> "___ extremely l...ext"
150 (this may be suboptimal if overflow is less than 3) */
151 (void) strncpy(pbuf + BUFSZ - 1 - 6, "...", 3);
152 /* avoid strncpy; buffers could overlap if excess is small */
153 pbuf[BUFSZ - 1 - 3] = line[ln - 3];
154 pbuf[BUFSZ - 1 - 2] = line[ln - 2];
155 pbuf[BUFSZ - 1 - 1] = line[ln - 1];
156 pbuf[BUFSZ - 1] = '\0';
161 /* We hook here early to have options-agnostic output.
162 * Unfortunately, that means Norep() isn't honored (general issue) and
163 * that short lines aren't combined into one longer one (tty behavior).
165 if ((pline_flags & SUPPRESS_HISTORY) == 0)
168 /* use raw_print() if we're called too early (or perhaps too late
169 during shutdown) or if we're being called recursively (probably
170 via debugpline() in the interface code) */
171 if (in_pline++ || !iflags.window_inited) {
172 /* [we should probably be using raw_printf("\n%s", line) here] */
174 iflags.last_msg = PLNMSG_UNKNOWN;
178 msgtyp = MSGTYP_NORMAL;
179 no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE;
180 if ((pline_flags & OVERRIDE_MSGTYPE) == 0) {
181 msgtyp = msgtype_type(line, no_repeat);
182 if ((pline_flags & URGENT_MESSAGE) == 0
183 && (msgtyp == MSGTYP_NOSHOW
184 || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))))
185 /* FIXME: we need a way to tell our caller that this message
186 * was suppressed so that caller doesn't set iflags.last_msg
187 * for something that hasn't been shown, otherwise a subsequent
188 * message which uses alternate wording based on that would be
189 * doing so out of context and probably end up seeming silly.
190 * (Not an issue for no-repeat but matters for no-show.)
195 if (vision_full_recalc)
198 flush_screen(1); /* %% */
202 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
203 execplinehandler(line);
206 /* this gets cleared after every pline message */
207 iflags.last_msg = PLNMSG_UNKNOWN;
208 (void) strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0';
209 if (msgtyp == MSGTYP_STOP)
210 display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
216 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
217 /* provide closing brace for the nested block
218 which immediately follows USE_OLDARGS's VA_DECL() */
223 /* pline() variant which can override MSGTYPE handling or suppress
224 message history (tty interface uses pline() to issue prompts and
225 they shouldn't be blockable via MSGTYPE=hide) */
228 VA_DECL2(unsigned, pflags, const char *, line)
231 VA_INIT(line, const char *);
232 pline_flags = pflags;
233 vpline(line, VA_ARGS);
241 VA_DECL(const char *, line)
244 VA_INIT(line, const char *);
245 pline_flags = PLINE_NOREPEAT;
246 vpline(line, VA_ARGS);
252 /* work buffer for You(), &c and verbalize() */
253 static char *you_buf = 0;
254 static int you_buf_siz = 0;
260 if (siz > you_buf_siz) {
262 free((genericptr_t) you_buf);
263 you_buf_siz = siz + 10;
264 you_buf = (char *) alloc((unsigned) you_buf_siz);
273 free((genericptr_t) you_buf), you_buf = (char *) 0;
277 /* `prefix' must be a string literal, not a pointer */
278 #define YouPrefix(pointer, prefix, text) \
279 Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix)
281 #define YouMessage(pointer, prefix, text) \
282 strcat((YouPrefix(pointer, prefix, text), pointer), text)
286 VA_DECL(const char *, line)
291 VA_INIT(line, const char *);
293 vpline(YouMessage(tmp, "You ", line), VA_ARGS);
295 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Í", line), VA_ARGS);
301 VA_DECL(const char *, line)
306 VA_INIT(line, const char *);
308 vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
310 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Ì", line), VA_ARGS);
316 VA_DECL(const char *, line)
321 VA_INIT(line, const char *);
324 YouPrefix(tmp, "You dream that you feel ", line);
326 YouPrefix(tmp, "
\82 \82È
\82½
\82Í
\96²
\82Ì
\92\86\82Å", line);
329 YouPrefix(tmp, "You feel ", line);
331 YouPrefix(tmp, "
\82 \82È
\82½
\82Í", line);
332 vpline(strcat(tmp, line), VA_ARGS);
338 VA_DECL(const char *, line)
343 VA_INIT(line, const char *);
345 vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
347 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Í", line), VA_ARGS);
353 VA_DECL(const char *, line)
358 VA_INIT(line, const char *);
360 vpline(YouMessage(tmp, "The ", line), VA_ARGS);
362 vpline(YouMessage(tmp, "", line), VA_ARGS);
368 VA_DECL(const char *, line)
373 VA_INIT(line, const char *);
375 vpline(YouMessage(tmp, "There ", line), VA_ARGS);
377 vpline(YouMessage(tmp, "", line), VA_ARGS);
383 VA_DECL(const char *, line)
391 if (Deaf || !flags.acoustics)
394 VA_INIT(line, const char *);
397 YouPrefix(tmp, "You barely hear ", line);
399 YouPrefix(tmp, "You dream that you hear ", line);
401 YouPrefix(tmp, "You hear ", line);
402 vpline(strcat(tmp, line), VA_ARGS);
405 adj = "
\82©
\82·
\82©
\82É";
407 adj = "
\96²
\82Ì
\92\86\82Å";
410 tmp = You_buf(strlen(adj) + strlen(line) + sizeof("
\82 \82È
\82½
\82Í "));
412 p = (char *)strstr(line, "
\95·
\82±") ;
414 Strcpy(tmp, "
\82 \82È
\82½
\82Í");
417 if (p != NULL || (p = (char *)strstr(line, "
\95·
\82¢")) != NULL){
418 strncat(tmp, line, (p - line));
424 vpline(tmp, VA_ARGS);
431 VA_DECL(const char *, line)
436 VA_INIT(line, const char *);
439 YouPrefix(tmp, "You dream that you see ", line);
441 YouPrefix(tmp, "
\82 \82È
\82½
\82Í
\96²
\82Ì
\92\86\82Å", line);
442 #if 0 /*JP*//*
\82±
\82±
\82Í
\8cÄ
\82Ñ
\8fo
\82µ
\8c³
\82Å
\8f\88\97\9d\82·
\82é?*/
443 else if (Blind) /* caller should have caught this... */
444 YouPrefix(tmp, "You sense ", line);
448 YouPrefix(tmp, "You see ", line);
450 YouPrefix(tmp, "
\82 \82È
\82½
\82Í", line);
451 vpline(strcat(tmp, line), VA_ARGS);
455 /* Print a message inside double-quotes.
456 * The caller is responsible for checking deafness.
457 * Gods can speak directly to you in spite of deafness.
461 VA_DECL(const char *, line)
466 VA_INIT(line, const char *);
468 tmp = You_buf((int) strlen(line) + sizeof "\"\"");
473 tmp = You_buf((int) strlen(line) + sizeof "
\81u
\81v");
478 vpline(tmp, VA_ARGS);
483 /* Note that these declarations rely on knowledge of the internals
484 * of the variable argument handling stuff in "tradstdc.h"
487 #if defined(USE_STDARG) || defined(USE_VARARGS)
488 static void FDECL(vraw_printf, (const char *, va_list));
491 VA_DECL(const char *, line)
494 VA_INIT(line, char *);
495 vraw_printf(line, VA_ARGS);
501 vraw_printf(const char *line, va_list the_args)
504 vraw_printf(line, the_args)
509 #else /* USE_STDARG | USE_VARARG */
512 VA_DECL(const char *, line)
515 char pbuf[3 * BUFSZ];
517 /* Do NOT use VA_START and VA_END in here... see above */
519 if (index(line, '%')) {
520 Vsprintf(pbuf, line, VA_ARGS);
523 if ((ln = (int) strlen(line)) > BUFSZ - 1) {
525 line = strncpy(pbuf, line, BUFSZ - 1);
526 /* unlike pline, we don't futz around to keep last few chars */
527 pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */
530 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
531 execplinehandler(line);
533 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
534 VA_END(); /* (see vpline) */
540 VA_DECL(const char *, s)
542 char pbuf[2 * BUFSZ];
545 VA_INIT(s, const char *);
546 if (program_state.in_impossible)
547 panic("impossible called impossible");
549 program_state.in_impossible = 1;
550 Vsprintf(pbuf, s, VA_ARGS);
551 pbuf[BUFSZ - 1] = '\0'; /* sanity */
552 paniclog("impossible", pbuf);
553 if (iflags.debug_fuzzer)
555 pline("%s", VA_PASS1(pbuf));
558 Strcpy(pbuf, "Program in disorder!");
560 Strcpy(pbuf, "
\83v
\83\8d\83O
\83\89\83\80\82É
\8fá
\8aQ
\94
\90¶
\81I");
561 if (program_state.something_worth_saving)
563 Strcat(pbuf, " (Saving and reloading may fix this problem.)");
565 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)");
566 pline("%s", VA_PASS1(pbuf));
568 program_state.in_impossible = 0;
572 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
573 static boolean use_pline_handler = TRUE;
576 execplinehandler(line)
583 if (!use_pline_handler)
586 if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) {
587 use_pline_handler = FALSE;
592 if (f == 0) { /* child */
596 (void) setgid(getgid());
597 (void) setuid(getuid());
598 (void) execv(args[0], (char *const *) args);
600 (void) fprintf(stderr, "Exec to message handler %s failed.\n", env);
601 nh_terminate(EXIT_FAILURE);
605 waitpid(f, &status, 0);
606 } else if (f == -1) {
608 use_pline_handler = FALSE;
609 pline("%s", VA_PASS1("Fork to message handler failed."));
612 #endif /* MSGHANDLER && (POSIX_TYPES || __GNUC__) */
615 * varargs handling for files.c
617 #if defined(USE_STDARG) || defined(USE_VARARGS)
618 static void FDECL(vconfig_error_add, (const char *, va_list));
623 VA_DECL(const char *, str)
626 VA_INIT(str, char *);
627 vconfig_error_add(str, VA_ARGS);
633 vconfig_error_add(const char *str, va_list the_args)
636 vconfig_error_add(str, the_args)
641 #else /* !(USE_STDARG || USE_VARARG) => USE_OLDARGS */
646 VA_DECL(const char *, str)
647 #endif /* ?(USE_STDARG || USE_VARARG) */
648 { /* start of vconf...() or of nested block in USE_OLDARG's conf...() */
651 Vsprintf(buf, str, VA_ARGS);
652 buf[BUFSZ - 1] = '\0';
655 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
656 VA_END(); /* (see pline/vpline -- ends nested block for USE_OLDARGS) */