OSDN Git Service

GCC says embedding a directive within macro arguments is not portable
[jnethack/source.git] / src / pline.c
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. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \
12                                        */
13 #include "hack.h"
14
15 static unsigned pline_flags = 0;
16 static char prevmsg[BUFSZ];
17
18 static char *FDECL(You_buf, (int));
19 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
20 static void FDECL(execplinehandler, (const char *));
21 #endif
22
23 #ifdef DUMPLOG
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 };
27
28 /* keep the most recent DUMPLOG_MSG_COUNT messages */
29 void
30 dumplogmsg(line)
31 const char *line;
32 {
33     /*
34      * TODO:
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
38      *  this share it.
39      */
40     unsigned indx = saved_pline_index; /* next slot to use */
41     char *oldest = saved_plines[indx]; /* current content of that slot */
42
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 */
46         Strcpy(oldest, line);
47     } else {
48         if (oldest)
49             free((genericptr_t) oldest);
50         saved_plines[indx] = dupstr(line);
51     }
52     saved_pline_index = (indx + 1) % DUMPLOG_MSG_COUNT;
53 }
54
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 */
58 void
59 dumplogfreemessages()
60 {
61     unsigned indx;
62
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;
67 }
68 #endif
69
70 /*VARARGS1*/
71 /* Note that these declarations rely on knowledge of the internals
72  * of the variable argument handling stuff in "tradstdc.h"
73  */
74
75 #if defined(USE_STDARG) || defined(USE_VARARGS)
76 static void FDECL(vpline, (const char *, va_list));
77
78 void pline
79 VA_DECL(const char *, line)
80 {
81     VA_START(line);
82     VA_INIT(line, char *);
83     vpline(line, VA_ARGS);
84     VA_END();
85 }
86
87 # ifdef USE_STDARG
88 static void
89 vpline(const char *line, va_list the_args)
90 # else
91 static void
92 vpline(line, the_args)
93 const char *line;
94 va_list the_args;
95 # endif
96
97 #else /* USE_STDARG | USE_VARARG */
98
99 # define vpline pline
100
101 void pline
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];
107     int ln;
108     int msgtyp;
109     boolean no_repeat;
110     /* Do NOT use VA_START and VA_END in here... see above */
111
112     if (!line || !*line)
113         return;
114 #ifdef HANGUPHANDLING
115     if (program_state.done_hup)
116         return;
117 #endif
118     if (program_state.wizkit_wishing)
119         return;
120
121     if (index(line, '%')) {
122         Vsprintf(pbuf, line, VA_ARGS);
123         line = pbuf;
124     }
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';
137         line = pbuf;
138     }
139
140 #ifdef DUMPLOG
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).
144      */
145     if ((pline_flags & SUPPRESS_HISTORY) == 0)
146         dumplogmsg(line);
147 #endif
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] */
153         raw_print(line);
154         iflags.last_msg = PLNMSG_UNKNOWN;
155         goto pline_done;
156     }
157
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.)
170              */
171             goto pline_done;
172     }
173
174     if (vision_full_recalc)
175         vision_recalc(0);
176     if (u.ux)
177         flush_screen(1); /* %% */
178
179     putstr(WIN_MESSAGE, 0, line);
180
181 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
182     execplinehandler(line);
183 #endif
184
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-- */
190
191  pline_done:
192     --in_pline;
193     return;
194
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() */
198     VA_END();
199 #endif
200 }
201
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) */
205 /*VARARGS2*/
206 void custompline
207 VA_DECL2(unsigned, pflags, const char *, line)
208 {
209     VA_START(line);
210     VA_INIT(line, const char *);
211     pline_flags = pflags;
212     vpline(line, VA_ARGS);
213     pline_flags = 0;
214     VA_END();
215     return;
216 }
217
218 /*VARARGS1*/
219 void Norep
220 VA_DECL(const char *, line)
221 {
222     VA_START(line);
223     VA_INIT(line, const char *);
224     pline_flags = PLINE_NOREPEAT;
225     vpline(line, VA_ARGS);
226     pline_flags = 0;
227     VA_END();
228     return;
229 }
230
231 /* work buffer for You(), &c and verbalize() */
232 static char *you_buf = 0;
233 static int you_buf_siz = 0;
234
235 static char *
236 You_buf(siz)
237 int siz;
238 {
239     if (siz > you_buf_siz) {
240         if (you_buf)
241             free((genericptr_t) you_buf);
242         you_buf_siz = siz + 10;
243         you_buf = (char *) alloc((unsigned) you_buf_siz);
244     }
245     return you_buf;
246 }
247
248 void
249 free_youbuf()
250 {
251     if (you_buf)
252         free((genericptr_t) you_buf), you_buf = (char *) 0;
253     you_buf_siz = 0;
254 }
255
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)
259
260 #define YouMessage(pointer, prefix, text) \
261     strcat((YouPrefix(pointer, prefix, text), pointer), text)
262
263 /*VARARGS1*/
264 void You
265 VA_DECL(const char *, line)
266 {
267     char *tmp;
268     VA_START(line);
269     VA_INIT(line, const char *);
270 /*JP
271     vpline(YouMessage(tmp, "You ", line), VA_ARGS);
272 */
273     vpline(YouMessage(tmp, "\82 \82È\82½\82Í", line), VA_ARGS);
274     VA_END();
275 }
276
277 /*VARARGS1*/
278 void Your
279 VA_DECL(const char *, line)
280 {
281     char *tmp;
282     VA_START(line);
283     VA_INIT(line, const char *);
284 /*JP
285     vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
286 */
287     vpline(YouMessage(tmp, "\82 \82È\82½\82Ì", line), VA_ARGS);
288     VA_END();
289 }
290
291 /*VARARGS1*/
292 void You_feel
293 VA_DECL(const char *, line)
294 {
295     char *tmp;
296     VA_START(line);
297     VA_INIT(line, const char *);
298     if (Unaware)
299 /*JP
300         YouPrefix(tmp, "You dream that you feel ", line);
301 */
302         YouPrefix(tmp, "\82 \82È\82½\82Í\96²\82Ì\92\86\82Å", line);
303     else
304 /*JP
305         YouPrefix(tmp, "You feel ", line);
306 */
307         YouPrefix(tmp, "\82 \82È\82½\82Í", line);
308     vpline(strcat(tmp, line), VA_ARGS);
309     VA_END();
310 }
311
312 /*VARARGS1*/
313 void You_cant
314 VA_DECL(const char *, line)
315 {
316     char *tmp;
317     VA_START(line);
318     VA_INIT(line, const char *);
319 /*JP
320     vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
321 */
322     vpline(YouMessage(tmp, "\82 \82È\82½\82Í", line), VA_ARGS);
323     VA_END();
324 }
325
326 /*VARARGS1*/
327 void pline_The
328 VA_DECL(const char *, line)
329 {
330     char *tmp;
331     VA_START(line);
332     VA_INIT(line, const char *);
333 /*JP
334     vpline(YouMessage(tmp, "The ", line), VA_ARGS);
335 */
336     vpline(YouMessage(tmp, "", line), VA_ARGS);
337     VA_END();
338 }
339
340 /*VARARGS1*/
341 void There
342 VA_DECL(const char *, line)
343 {
344     char *tmp;
345     VA_START(line);
346     VA_INIT(line, const char *);
347 /*JP
348     vpline(YouMessage(tmp, "There ", line), VA_ARGS);
349 */
350     vpline(YouMessage(tmp, "", line), VA_ARGS);
351     VA_END();
352 }
353
354 /*VARARGS1*/
355 void You_hear
356 VA_DECL(const char *, line)
357 {
358     char *tmp;
359 #if 1 /*JP*/
360         const char *adj;
361         char *p;
362 #endif
363
364     if (Deaf || !flags.acoustics)
365         return;
366     VA_START(line);
367     VA_INIT(line, const char *);
368 #if 0 /*JP*/
369     if (Underwater)
370         YouPrefix(tmp, "You barely hear ", line);
371     else if (Unaware)
372         YouPrefix(tmp, "You dream that you hear ", line);
373     else
374         YouPrefix(tmp, "You hear ", line);
375     vpline(strcat(tmp, line), VA_ARGS);
376 #else
377     if (Underwater)
378         adj = "\82©\82·\82©\82É";
379     else if (Unaware)
380         adj = "\96²\82Ì\92\86\82Å";
381     else
382         adj = "";
383     tmp = You_buf(strlen(adj) + strlen(line) + sizeof("\82 \82È\82½\82Í   "));
384
385     p = (char *)strstr(line, "\95·\82±") ;
386     if (p == NULL)
387         Strcpy(tmp, "\82 \82È\82½\82Í");
388     else
389         Strcpy(tmp, "");
390     if (p != NULL || (p = (char *)strstr(line, "\95·\82¢")) != NULL){
391         strncat(tmp, line, (p - line));
392         strcat(tmp, adj);
393         strcat(tmp, p);
394     } else {
395         Strcat(tmp, line);
396     }
397     vpline(tmp, VA_ARGS);
398 #endif
399     VA_END();
400 }
401
402 /*VARARGS1*/
403 void You_see
404 VA_DECL(const char *, line)
405 {
406     char *tmp;
407
408     VA_START(line);
409     VA_INIT(line, const char *);
410     if (Unaware)
411 /*JP
412         YouPrefix(tmp, "You dream that you see ", line);
413 */
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);
418 #endif
419     else
420 /*JP
421         YouPrefix(tmp, "You see ", line);
422 */
423         YouPrefix(tmp, "\82 \82È\82½\82Í", line);
424     vpline(strcat(tmp, line), VA_ARGS);
425     VA_END();
426 }
427
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.
431  */
432 /*VARARGS1*/
433 void verbalize
434 VA_DECL(const char *, line)
435 {
436     char *tmp;
437
438     VA_START(line);
439     VA_INIT(line, const char *);
440 #if 0 /*JP*/
441     tmp = You_buf((int) strlen(line) + sizeof "\"\"");
442     Strcpy(tmp, "\"");
443     Strcat(tmp, line);
444     Strcat(tmp, "\"");
445 #else
446     tmp = You_buf((int) strlen(line) + sizeof "\81u\81v");
447     Strcpy(tmp, "\81u");
448     Strcat(tmp, line);
449     Strcat(tmp, "\81v");
450 #endif
451     vpline(tmp, VA_ARGS);
452     VA_END();
453 }
454
455 /*VARARGS1*/
456 /* Note that these declarations rely on knowledge of the internals
457  * of the variable argument handling stuff in "tradstdc.h"
458  */
459
460 #if defined(USE_STDARG) || defined(USE_VARARGS)
461 static void FDECL(vraw_printf, (const char *, va_list));
462
463 void raw_printf
464 VA_DECL(const char *, line)
465 {
466     VA_START(line);
467     VA_INIT(line, char *);
468     vraw_printf(line, VA_ARGS);
469     VA_END();
470 }
471
472 # ifdef USE_STDARG
473 static void
474 vraw_printf(const char *line, va_list the_args)
475 # else
476 static void
477 vraw_printf(line, the_args)
478 const char *line;
479 va_list the_args;
480 # endif
481
482 #else /* USE_STDARG | USE_VARARG */
483
484 void raw_printf
485 VA_DECL(const char *, line)
486 #endif
487 {
488     char pbuf[3 * BUFSZ];
489     int ln;
490     /* Do NOT use VA_START and VA_END in here... see above */
491
492     if (index(line, '%')) {
493         Vsprintf(pbuf, line, VA_ARGS);
494         line = pbuf;
495     }
496     if ((ln = (int) strlen(line)) > BUFSZ - 1) {
497         if (line != pbuf)
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 */
501     }
502     raw_print(line);
503 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
504     execplinehandler(line);
505 #endif
506 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
507     VA_END(); /* (see vpline) */
508 #endif
509 }
510
511 /*VARARGS1*/
512 void impossible
513 VA_DECL(const char *, s)
514 {
515     char pbuf[2 * BUFSZ];
516     VA_START(s);
517     VA_INIT(s, const char *);
518     if (program_state.in_impossible)
519         panic("impossible called impossible");
520
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));
526 #if 0 /*JP:T*/
527     pline(VA_PASS1(
528        "Program in disorder!  (Saving and reloading may fix this problem.)"));
529 #else
530     pline(VA_PASS1(
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)"));
532 #endif
533     program_state.in_impossible = 0;
534     VA_END();
535 }
536
537 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
538 static boolean use_pline_handler = TRUE;
539 static void
540 execplinehandler(line)
541 const char *line;
542 {
543     int f;
544     const char *args[3];
545     char *env;
546
547     if (!use_pline_handler)
548         return;
549
550     if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) {
551         use_pline_handler = FALSE;
552         return;
553     }
554
555     f = fork();
556     if (f == 0) { /* child */
557         args[0] = env;
558         args[1] = line;
559         args[2] = NULL;
560         (void) setgid(getgid());
561         (void) setuid(getuid());
562         (void) execv(args[0], (char *const *) args);
563         perror((char *) 0);
564         (void) fprintf(stderr, "Exec to message handler %s failed.\n", env);
565         nh_terminate(EXIT_FAILURE);
566     } else if (f > 0) {
567         int status;
568
569         waitpid(f, &status, 0);
570     } else if (f == -1) {
571         perror((char *) 0);
572         use_pline_handler = FALSE;
573         pline("%s", VA_PASS1("Fork to message handler failed."));
574     }
575 }
576 #endif /* defined(POSIX_TYPES) || defined(__GNUC__) */
577
578 /*pline.c*/