1 /* NetHack 3.6 pline.c $NHDT-Date: 1520964541 2018/03/13 18:09:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.66 $ */
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 \
15 static unsigned pline_flags = 0;
16 static char prevmsg[BUFSZ];
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;
71 /* Note that these declarations rely on knowledge of the internals
72 * of the variable argument handling stuff in "tradstdc.h"
75 #if defined(USE_STDARG) || defined(USE_VARARGS)
76 static void FDECL(vpline, (const char *, va_list));
79 VA_DECL(const char *, line)
82 VA_INIT(line, char *);
83 vpline(line, VA_ARGS);
89 vpline(const char *line, va_list the_args)
92 vpline(line, the_args)
97 #else /* USE_STDARG | USE_VARARG */
102 VA_DECL(const char *, line)
103 #endif /* USE_STDARG | USE_VARARG */
104 { /* start of vpline() or of nested block in USE_OLDARG's pline() */
105 static int in_pline = 0;
106 char pbuf[3 * BUFSZ];
110 /* Do NOT use VA_START and VA_END in here... see above */
114 #ifdef HANGUPHANDLING
115 if (program_state.done_hup)
118 if (program_state.wizkit_wishing)
121 if (index(line, '%')) {
122 Vsprintf(pbuf, line, VA_ARGS);
125 if ((ln = (int) strlen(line)) > BUFSZ - 1) {
126 if (line != pbuf) /* no '%' was present */
127 (void) strncpy(pbuf, line, BUFSZ - 1); /* caveat: unterminated */
128 /* truncate, preserving the final 3 characters:
129 "___ extremely long text" -> "___ extremely l...ext"
130 (this may be suboptimal if overflow is less than 3) */
131 (void) strncpy(pbuf + BUFSZ - 1 - 6, "...", 3);
132 /* avoid strncpy; buffers could overlap if excess is small */
133 pbuf[BUFSZ - 1 - 3] = line[ln - 3];
134 pbuf[BUFSZ - 1 - 2] = line[ln - 2];
135 pbuf[BUFSZ - 1 - 1] = line[ln - 1];
136 pbuf[BUFSZ - 1] = '\0';
141 /* We hook here early to have options-agnostic output.
142 * Unfortunately, that means Norep() isn't honored (general issue) and
143 * that short lines aren't combined into one longer one (tty behavior).
145 if ((pline_flags & SUPPRESS_HISTORY) == 0)
148 /* use raw_print() if we're called too early (or perhaps too late
149 during shutdown) or if we're being called recursively (probably
150 via debugpline() in the interface code) */
151 if (in_pline++ || !iflags.window_inited) {
152 /* [we should probably be using raw_printf("\n%s", line) here] */
154 iflags.last_msg = PLNMSG_UNKNOWN;
158 msgtyp = MSGTYP_NORMAL;
159 no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE;
160 if ((pline_flags & OVERRIDE_MSGTYPE) == 0) {
161 msgtyp = msgtype_type(line, no_repeat);
162 if (msgtyp == MSGTYP_NOSHOW
163 || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)))
164 /* FIXME: we need a way to tell our caller that this message
165 * was suppressed so that caller doesn't set iflags.last_msg
166 * for something that hasn't been shown, otherwise a subsequent
167 * message which uses alternate wording based on that would be
168 * doing so out of context and probably end up seeming silly.
169 * (Not an issue for no-repeat but matters for no-show.)
174 if (vision_full_recalc)
177 flush_screen(1); /* %% */
179 putstr(WIN_MESSAGE, 0, line);
181 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
182 execplinehandler(line);
185 /* this gets cleared after every pline message */
186 iflags.last_msg = PLNMSG_UNKNOWN;
187 (void) strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0';
188 if (msgtyp == MSGTYP_STOP)
189 display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
195 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
196 /* provide closing brace for the nested block
197 which immediately follows USE_OLDARGS's VA_DECL() */
202 /* pline() variant which can override MSGTYPE handling or suppress
203 message history (tty interface uses pline() to issue prompts and
204 they shouldn't be blockable via MSGTYPE=hide) */
207 VA_DECL2(unsigned, pflags, const char *, line)
210 VA_INIT(line, const char *);
211 pline_flags = pflags;
212 vpline(line, VA_ARGS);
220 VA_DECL(const char *, line)
223 VA_INIT(line, const char *);
224 pline_flags = PLINE_NOREPEAT;
225 vpline(line, VA_ARGS);
231 /* work buffer for You(), &c and verbalize() */
232 static char *you_buf = 0;
233 static int you_buf_siz = 0;
239 if (siz > you_buf_siz) {
241 free((genericptr_t) you_buf);
242 you_buf_siz = siz + 10;
243 you_buf = (char *) alloc((unsigned) you_buf_siz);
252 free((genericptr_t) you_buf), you_buf = (char *) 0;
256 /* `prefix' must be a string literal, not a pointer */
257 #define YouPrefix(pointer, prefix, text) \
258 Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix)
260 #define YouMessage(pointer, prefix, text) \
261 strcat((YouPrefix(pointer, prefix, text), pointer), text)
265 VA_DECL(const char *, line)
269 VA_INIT(line, const char *);
271 vpline(YouMessage(tmp, "You ", line), VA_ARGS);
273 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Í", line), VA_ARGS);
279 VA_DECL(const char *, line)
283 VA_INIT(line, const char *);
285 vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
287 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Ì", line), VA_ARGS);
293 VA_DECL(const char *, line)
297 VA_INIT(line, const char *);
300 YouPrefix(tmp, "You dream that you feel ", line);
302 YouPrefix(tmp, "
\82 \82È
\82½
\82Í
\96²
\82Ì
\92\86\82Å", line);
305 YouPrefix(tmp, "You feel ", line);
307 YouPrefix(tmp, "
\82 \82È
\82½
\82Í", line);
308 vpline(strcat(tmp, line), VA_ARGS);
314 VA_DECL(const char *, line)
318 VA_INIT(line, const char *);
320 vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
322 vpline(YouMessage(tmp, "
\82 \82È
\82½
\82Í", line), VA_ARGS);
328 VA_DECL(const char *, line)
332 VA_INIT(line, const char *);
334 vpline(YouMessage(tmp, "The ", line), VA_ARGS);
336 vpline(YouMessage(tmp, "", line), VA_ARGS);
342 VA_DECL(const char *, line)
346 VA_INIT(line, const char *);
348 vpline(YouMessage(tmp, "There ", line), VA_ARGS);
350 vpline(YouMessage(tmp, "", line), VA_ARGS);
356 VA_DECL(const char *, line)
364 if (Deaf || !flags.acoustics)
367 VA_INIT(line, const char *);
370 YouPrefix(tmp, "You barely hear ", line);
372 YouPrefix(tmp, "You dream that you hear ", line);
374 YouPrefix(tmp, "You hear ", line);
375 vpline(strcat(tmp, line), VA_ARGS);
378 adj = "
\82©
\82·
\82©
\82É";
380 adj = "
\96²
\82Ì
\92\86\82Å";
383 tmp = You_buf(strlen(adj) + strlen(line) + sizeof("
\82 \82È
\82½
\82Í "));
385 p = (char *)strstr(line, "
\95·
\82±") ;
387 Strcpy(tmp, "
\82 \82È
\82½
\82Í");
390 if (p != NULL || (p = (char *)strstr(line, "
\95·
\82¢")) != NULL){
391 strncat(tmp, line, (p - line));
397 vpline(tmp, VA_ARGS);
404 VA_DECL(const char *, line)
409 VA_INIT(line, const char *);
412 YouPrefix(tmp, "You dream that you see ", line);
414 YouPrefix(tmp, "
\82 \82È
\82½
\82Í
\96²
\82Ì
\92\86\82Å", line);
415 #if 0 /*JP*//*
\82±
\82±
\82Í
\8cÄ
\82Ñ
\8fo
\82µ
\8c³
\82Å
\8f\88\97\9d\82·
\82é?*/
416 else if (Blind) /* caller should have caught this... */
417 YouPrefix(tmp, "You sense ", line);
421 YouPrefix(tmp, "You see ", line);
423 YouPrefix(tmp, "
\82 \82È
\82½
\82Í", line);
424 vpline(strcat(tmp, line), VA_ARGS);
428 /* Print a message inside double-quotes.
429 * The caller is responsible for checking deafness.
430 * Gods can speak directly to you in spite of deafness.
434 VA_DECL(const char *, line)
439 VA_INIT(line, const char *);
441 tmp = You_buf((int) strlen(line) + sizeof "\"\"");
446 tmp = You_buf((int) strlen(line) + sizeof "
\81u
\81v");
451 vpline(tmp, VA_ARGS);
456 /* Note that these declarations rely on knowledge of the internals
457 * of the variable argument handling stuff in "tradstdc.h"
460 #if defined(USE_STDARG) || defined(USE_VARARGS)
461 static void FDECL(vraw_printf, (const char *, va_list));
464 VA_DECL(const char *, line)
467 VA_INIT(line, char *);
468 vraw_printf(line, VA_ARGS);
474 vraw_printf(const char *line, va_list the_args)
477 vraw_printf(line, the_args)
482 #else /* USE_STDARG | USE_VARARG */
485 VA_DECL(const char *, line)
488 char pbuf[3 * BUFSZ];
490 /* Do NOT use VA_START and VA_END in here... see above */
492 if (index(line, '%')) {
493 Vsprintf(pbuf, line, VA_ARGS);
496 if ((ln = (int) strlen(line)) > BUFSZ - 1) {
498 line = strncpy(pbuf, line, BUFSZ - 1);
499 /* unlike pline, we don't futz around to keep last few chars */
500 pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */
503 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
504 execplinehandler(line);
506 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
507 VA_END(); /* (see vpline) */
513 VA_DECL(const char *, s)
515 char pbuf[2 * BUFSZ];
517 VA_INIT(s, const char *);
518 if (program_state.in_impossible)
519 panic("impossible called impossible");
521 program_state.in_impossible = 1;
522 Vsprintf(pbuf, s, VA_ARGS);
523 pbuf[BUFSZ - 1] = '\0'; /* sanity */
524 paniclog("impossible", pbuf);
525 pline("%s", VA_PASS1(pbuf));
528 "Program in disorder! (Saving and reloading may fix this problem.)"));
531 "
\83v
\83\8d\83O
\83\89\83\80\82É
\8fá
\8aQ
\94
\90¶
\81I (
\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)"));
533 program_state.in_impossible = 0;
537 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
538 static boolean use_pline_handler = TRUE;
540 execplinehandler(line)
547 if (!use_pline_handler)
550 if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) {
551 use_pline_handler = FALSE;
556 if (f == 0) { /* child */
560 (void) setgid(getgid());
561 (void) setuid(getuid());
562 (void) execv(args[0], (char *const *) args);
564 (void) fprintf(stderr, "Exec to message handler %s failed.\n", env);
565 nh_terminate(EXIT_FAILURE);
569 waitpid(f, &status, 0);
570 } else if (f == -1) {
572 use_pline_handler = FALSE;
573 pline("%s", VA_PASS1("Fork to message handler failed."));
576 #endif /* defined(POSIX_TYPES) || defined(__GNUC__) */