OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / win / tty / termcap.c
1 /* NetHack 3.6  termcap.c       $NHDT-Date: 1456907853 2016/03/02 08:37:33 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2018. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 #include "hack.h"
7
8 #if defined(TTY_GRAPHICS) && !defined(NO_TERMS)
9
10 #include "wintty.h"
11 #include "tcap.h"
12
13 #ifdef MICROPORT_286_BUG
14 #define Tgetstr(key) (tgetstr(key, tbuf))
15 #else
16 #define Tgetstr(key) (tgetstr(key, &tbufptr))
17 #endif /* MICROPORT_286_BUG **/
18
19 static char *FDECL(s_atr2str, (int));
20 static char *FDECL(e_atr2str, (int));
21
22 void FDECL(cmov, (int, int));
23 void FDECL(nocmov, (int, int));
24 #if defined(TEXTCOLOR) && defined(TERMLIB)
25 #if !defined(UNIX) || !defined(TERMINFO)
26 #ifndef TOS
27 static void FDECL(analyze_seq, (char *, int *, int *));
28 #endif
29 #endif
30 static void NDECL(init_hilite);
31 static void NDECL(kill_hilite);
32 #endif
33
34 /* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE, ul_hack */
35 struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0, 0, 0, 0, FALSE };
36
37 STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE;
38 STATIC_VAR char *VS, *VE;
39 STATIC_VAR char *ME;
40 STATIC_VAR char *MR;
41 #if 0
42 STATIC_VAR char *MB, *MH;
43 STATIC_VAR char *MD;     /* may already be in use below */
44 #endif
45
46 #ifdef TERMLIB
47 boolean dynamic_HIHE = FALSE;
48 #ifdef TEXTCOLOR
49 STATIC_VAR char *MD;
50 #endif
51 STATIC_VAR int SG;
52 STATIC_OVL char PC = '\0';
53 STATIC_VAR char tbuf[512];
54 #endif /*TERMLIB*/
55
56 #ifdef TEXTCOLOR
57 #ifdef TOS
58 const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */
59 #else
60 char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */
61 #endif
62 #endif
63
64 static char *KS = (char *) 0, *KE = (char *) 0; /* keypad sequences */
65 static char nullstr[] = "";
66
67 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
68 extern boolean HE_resets_AS;
69 #endif
70
71 #ifndef TERMLIB
72 STATIC_VAR char tgotobuf[20];
73 #ifdef TOS
74 #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + ' ', x + ' '), tgotobuf)
75 #else
76 #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + 1, x + 1), tgotobuf)
77 #endif
78 #endif /* TERMLIB */
79
80 void
81 tty_startup(wid, hgt)
82 int *wid, *hgt;
83 {
84     register int i;
85 #ifdef TERMLIB
86     register const char *term;
87     register char *tptr;
88     char *tbufptr, *pc;
89
90 #ifdef VMS
91     term = verify_termcap();
92     if (!term)
93 #endif
94         term = getenv("TERM");
95
96 #if defined(TOS) && defined(__GNUC__)
97     if (!term)
98         term = "builtin"; /* library has a default */
99 #endif
100     if (!term)
101 #endif
102 #ifndef ANSI_DEFAULT
103         error("Can't get TERM.");
104 #else
105 #ifdef TOS
106     {
107         CO = 80;
108         LI = 25;
109         TI = VS = VE = TE = nullstr;
110         HO = "\033H";
111         CE = "\033K"; /* the VT52 termcap */
112         UP = "\033A";
113         nh_CM = "\033Y%c%c"; /* used with function tgoto() */
114         nh_ND = "\033C";
115         XD = "\033B";
116         BC = "\033D";
117         SO = "\033p";
118         SE = "\033q";
119         /* HI and HE will be updated in init_hilite if we're using color */
120         nh_HI = "\033p";
121         nh_HE = "\033q";
122         *wid = CO;
123         *hgt = LI;
124         CL = "\033E"; /* last thing set */
125         return;
126     }
127 #else /* TOS */
128     {
129 #ifdef MICRO
130         get_scr_size();
131 #ifdef CLIPPING
132         if (CO < COLNO || LI < ROWNO + 3)
133             setclipped();
134 #endif
135 #endif
136         HO = "\033[H";
137         /*              nh_CD = "\033[J"; */
138         CE = "\033[K"; /* the ANSI termcap */
139 #ifndef TERMLIB
140         nh_CM = "\033[%d;%dH";
141 #else
142         nh_CM = "\033[%i%d;%dH";
143 #endif
144         UP = "\033[A";
145         nh_ND = "\033[C";
146         XD = "\033[B";
147 #ifdef MICRO /* backspaces are non-destructive */
148         BC = "\b";
149 #else
150         BC = "\033[D";
151 #endif
152         nh_HI = SO = "\033[1m";
153         nh_US = "\033[4m";
154         MR = "\033[7m";
155         TI = nh_HE = ME = SE = nh_UE = "\033[0m";
156         /* strictly, SE should be 2, and nh_UE should be 24,
157            but we can't trust all ANSI emulators to be
158            that complete.  -3. */
159 #ifndef MICRO
160         AS = "\016";
161         AE = "\017";
162 #endif
163         TE = VS = VE = nullstr;
164 #ifdef TEXTCOLOR
165         for (i = 0; i < CLR_MAX / 2; i++)
166             if (i != CLR_BLACK) {
167                 hilites[i | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
168                 Sprintf(hilites[i | BRIGHT], "\033[1;3%dm", i);
169                 if (i != CLR_GRAY)
170 #ifdef MICRO
171                     if (i == CLR_BLUE)
172                         hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
173                     else
174 #endif
175                     {
176                         hilites[i] = (char *) alloc(sizeof("\033[0;3%dm"));
177                         Sprintf(hilites[i], "\033[0;3%dm", i);
178                     }
179             }
180 #endif
181         *wid = CO;
182         *hgt = LI;
183         CL = "\033[2J"; /* last thing set */
184         return;
185     }
186 #endif /* TOS */
187 #endif /* ANSI_DEFAULT */
188
189 #ifdef TERMLIB
190     tptr = (char *) alloc(1024);
191
192     tbufptr = tbuf;
193     if (!strncmp(term, "5620", 4))
194         flags.null = FALSE; /* this should be a termcap flag */
195     if (tgetent(tptr, term) < 1) {
196         char buf[BUFSZ];
197         (void) strncpy(buf, term,
198                        (BUFSZ - 1) - (sizeof("Unknown terminal type: .  ")));
199         buf[BUFSZ - 1] = '\0';
200         error("Unknown terminal type: %s.", term);
201     }
202     if ((pc = Tgetstr("pc")) != 0)
203         PC = *pc;
204
205     if (!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */
206 #ifdef TERMINFO
207         error("Terminal must backspace.");
208 #else
209         if (!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */
210 #ifndef MINIMAL_TERM
211             if (!tgetflag("bs"))
212                 error("Terminal must backspace.");
213 #endif
214             BC = tbufptr;
215             tbufptr += 2;
216             *BC = '\b';
217         }
218 #endif
219
220 #ifdef MINIMAL_TERM
221     HO = (char *) 0;
222 #else
223     HO = Tgetstr("ho");
224 #endif
225     /*
226      * LI and CO are set in ioctl.c via a TIOCGWINSZ if available.  If
227      * the kernel has values for either we should use them rather than
228      * the values from TERMCAP ...
229      */
230 #ifndef MICRO
231     if (!CO)
232         CO = tgetnum("co");
233     if (!LI)
234         LI = tgetnum("li");
235 #else
236 #if defined(TOS) && defined(__GNUC__)
237     if (!strcmp(term, "builtin")) {
238         get_scr_size();
239     } else
240 #endif
241     {
242         CO = tgetnum("co");
243         LI = tgetnum("li");
244         if (!LI || !CO) /* if we don't override it */
245             get_scr_size();
246     }
247 #endif /* ?MICRO */
248 #ifdef CLIPPING
249     if (CO < COLNO || LI < ROWNO + 3)
250         setclipped();
251 #endif
252     nh_ND = Tgetstr("nd");
253     if (tgetflag("os"))
254         error("NetHack can't have OS.");
255     if (tgetflag("ul"))
256         ul_hack = TRUE;
257     CE = Tgetstr("ce");
258     UP = Tgetstr("up");
259     /* It seems that xd is no longer supported, and we should use
260        a linefeed instead; unfortunately this requires resetting
261        CRMOD, and many output routines will have to be modified
262        slightly. Let's leave that till the next release. */
263     XD = Tgetstr("xd");
264     /* not:             XD = Tgetstr("do"); */
265     if (!(nh_CM = Tgetstr("cm"))) {
266         if (!UP && !HO)
267             error("NetHack needs CM or UP or HO.");
268         tty_raw_print("Playing NetHack on terminals without CM is suspect.");
269         tty_wait_synch();
270     }
271     SO = Tgetstr("so");
272     SE = Tgetstr("se");
273     nh_US = Tgetstr("us");
274     nh_UE = Tgetstr("ue");
275     SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */
276     if (!SO || !SE || (SG > 0))
277         SO = SE = nh_US = nh_UE = nullstr;
278     TI = Tgetstr("ti");
279     TE = Tgetstr("te");
280     VS = VE = nullstr;
281 #ifdef TERMINFO
282     VS = Tgetstr("eA"); /* enable graphics */
283 #endif
284     KS = Tgetstr("ks"); /* keypad start (special mode) */
285     KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */
286     MR = Tgetstr("mr"); /* reverse */
287 #if 0
288     MB = Tgetstr("mb"); /* blink */
289     MD = Tgetstr("md"); /* boldface */
290     MH = Tgetstr("mh"); /* dim */
291 #endif
292     ME = Tgetstr("me"); /* turn off all attributes */
293     if (!ME || (SE == nullstr))
294         ME = SE; /* default to SE value */
295
296     /* Get rid of padding numbers for nh_HI and nh_HE.  Hope they
297      * aren't really needed!!!  nh_HI and nh_HE are outputted to the
298      * pager as a string - so how can you send it NULs???
299      *  -jsb
300      */
301     for (i = 0; digit(SO[i]); ++i)
302         continue;
303     nh_HI = dupstr(&SO[i]);
304     for (i = 0; digit(ME[i]); ++i)
305         continue;
306     nh_HE = dupstr(&ME[i]);
307     dynamic_HIHE = TRUE;
308
309     AS = Tgetstr("as");
310     AE = Tgetstr("ae");
311     nh_CD = Tgetstr("cd");
312 #ifdef TEXTCOLOR
313     MD = Tgetstr("md");
314 #endif
315 #ifdef TEXTCOLOR
316 #if defined(TOS) && defined(__GNUC__)
317     if (!strcmp(term, "builtin") || !strcmp(term, "tw52")
318         || !strcmp(term, "st52")) {
319         init_hilite();
320     }
321 #else
322     init_hilite();
323 #endif
324 #endif
325     *wid = CO;
326     *hgt = LI;
327     if (!(CL = Tgetstr("cl"))) /* last thing set */
328         error("NetHack needs CL.");
329     if ((int) (tbufptr - tbuf) > (int) (sizeof tbuf))
330         error("TERMCAP entry too big...\n");
331     free((genericptr_t) tptr);
332 #endif /* TERMLIB */
333 }
334
335 /* note: at present, this routine is not part of the formal window interface
336  */
337 /* deallocate resources prior to final termination */
338 void
339 tty_shutdown()
340 {
341     /* we only attempt to clean up a few individual termcap variables */
342 #ifdef TERMLIB
343 #ifdef TEXTCOLOR
344     kill_hilite();
345 #endif
346     if (dynamic_HIHE) {
347         free((genericptr_t) nh_HI), nh_HI = (char *) 0;
348         free((genericptr_t) nh_HE), nh_HE = (char *) 0;
349         dynamic_HIHE = FALSE;
350     }
351 #endif
352     return;
353 }
354
355 void
356 tty_number_pad(state)
357 int state;
358 {
359     switch (state) {
360     case -1: /* activate keypad mode (escape sequences) */
361         if (KS && *KS)
362             xputs(KS);
363         break;
364     case 1: /* activate numeric mode for keypad (digits) */
365         if (KE && *KE)
366             xputs(KE);
367         break;
368     case 0: /* don't need to do anything--leave terminal as-is */
369     default:
370         break;
371     }
372 }
373
374 #ifdef TERMLIB
375 extern void NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */
376 static void NDECL(tty_decgraphics_termcap_fixup);
377
378 /*
379    We call this routine whenever DECgraphics mode is enabled, even if it
380    has been previously set, in case the user manages to reset the fonts.
381    The actual termcap fixup only needs to be done once, but we can't
382    call xputs() from the option setting or graphics assigning routines,
383    so this is a convenient hook.
384  */
385 static void
386 tty_decgraphics_termcap_fixup()
387 {
388     static char ctrlN[] = "\016";
389     static char ctrlO[] = "\017";
390     static char appMode[] = "\033=";
391     static char numMode[] = "\033>";
392
393     /* these values are missing from some termcaps */
394     if (!AS)
395         AS = ctrlN; /* ^N (shift-out [graphics font]) */
396     if (!AE)
397         AE = ctrlO; /* ^O (shift-in  [regular font])  */
398     if (!KS)
399         KS = appMode; /* ESC= (application keypad mode) */
400     if (!KE)
401         KE = numMode; /* ESC> (numeric keypad mode) */
402     /*
403      * Select the line-drawing character set as the alternate font.
404      * Do not select NA ASCII as the primary font since people may
405      * reasonably be using the UK character set.
406      */
407     if (SYMHANDLING(H_DEC))
408         xputs("\033)0");
409 #ifdef PC9800
410     init_hilite();
411 #endif
412
413 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
414     /* some termcaps suffer from the bizarre notion that resetting
415        video attributes should also reset the chosen character set */
416     {
417         const char *nh_he = nh_HE, *ae = AE;
418         int he_limit, ae_length;
419
420         if (digit(*ae)) { /* skip over delay prefix, if any */
421             do
422                 ++ae;
423             while (digit(*ae));
424             if (*ae == '.') {
425                 ++ae;
426                 if (digit(*ae))
427                     ++ae;
428             }
429             if (*ae == '*')
430                 ++ae;
431         }
432         /* can't use nethack's case-insensitive strstri() here, and some old
433            systems don't have strstr(), so use brute force substring search */
434         ae_length = strlen(ae), he_limit = strlen(nh_he);
435         while (he_limit >= ae_length) {
436             if (strncmp(nh_he, ae, ae_length) == 0) {
437                 HE_resets_AS = TRUE;
438                 break;
439             }
440             ++nh_he, --he_limit;
441         }
442     }
443 #endif
444 }
445 #endif /* TERMLIB */
446
447 #if defined(ASCIIGRAPH) && defined(PC9800)
448 extern void NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */
449 #endif
450
451 #ifdef PC9800
452 extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */
453 static void NDECL(tty_ascgraphics_hilite_fixup);
454
455 static void
456 tty_ascgraphics_hilite_fixup()
457 {
458     register int c;
459
460     for (c = 0; c < CLR_MAX / 2; c++)
461         if (c != CLR_BLACK) {
462             hilites[c | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
463             Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c);
464             if (c != CLR_GRAY) {
465                 hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
466                 Sprintf(hilites[c], "\033[0;3%dm", c);
467             }
468         }
469 }
470 #endif /* PC9800 */
471
472 void
473 tty_start_screen()
474 {
475     xputs(TI);
476     xputs(VS);
477 #ifdef PC9800
478     if (!SYMHANDLING(H_IBM))
479         tty_ascgraphics_hilite_fixup();
480     /* set up callback in case option is not set yet but toggled later */
481     ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
482 #ifdef ASCIIGRAPH
483     if (SYMHANDLING(H_IBM))
484         init_hilite();
485     /* set up callback in case option is not set yet but toggled later */
486     ibmgraphics_mode_callback = init_hilite;
487 #endif
488 #endif /* PC9800 */
489
490 #ifdef TERMLIB
491     if (SYMHANDLING(H_DEC))
492         tty_decgraphics_termcap_fixup();
493     /* set up callback in case option is not set yet but toggled later */
494     decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
495 #endif
496     if (Cmd.num_pad)
497         tty_number_pad(1); /* make keypad send digits */
498 }
499
500 void
501 tty_end_screen()
502 {
503     clear_screen();
504     xputs(VE);
505     xputs(TE);
506 }
507
508 /* Cursor movements */
509
510 /* Note to overlay tinkerers.  The placement of this overlay controls the
511    location
512    of the function xputc().  This function is not currently in trampoli.[ch]
513    files for what is deemed to be performance reasons.  If this define is
514    moved
515    and or xputc() is taken out of the ROOT overlay, then action must be taken
516    in trampoli.[ch]. */
517
518 void
519 nocmov(x, y)
520 int x, y;
521 {
522     if ((int) ttyDisplay->cury > y) {
523         if (UP) {
524             while ((int) ttyDisplay->cury > y) { /* Go up. */
525                 xputs(UP);
526                 ttyDisplay->cury--;
527             }
528         } else if (nh_CM) {
529             cmov(x, y);
530         } else if (HO) {
531             home();
532             tty_curs(BASE_WINDOW, x + 1, y);
533         } /* else impossible("..."); */
534     } else if ((int) ttyDisplay->cury < y) {
535         if (XD) {
536             while ((int) ttyDisplay->cury < y) {
537                 xputs(XD);
538                 ttyDisplay->cury++;
539             }
540         } else if (nh_CM) {
541             cmov(x, y);
542         } else {
543             while ((int) ttyDisplay->cury < y) {
544                 xputc('\n');
545                 ttyDisplay->curx = 0;
546                 ttyDisplay->cury++;
547             }
548         }
549     }
550     if ((int) ttyDisplay->curx < x) { /* Go to the right. */
551         if (!nh_ND) {
552             cmov(x, y);
553         } else { /* bah */
554              /* should instead print what is there already */
555             while ((int) ttyDisplay->curx < x) {
556                 xputs(nh_ND);
557                 ttyDisplay->curx++;
558             }
559         }
560     } else if ((int) ttyDisplay->curx > x) {
561         while ((int) ttyDisplay->curx > x) { /* Go to the left. */
562             xputs(BC);
563             ttyDisplay->curx--;
564         }
565     }
566 }
567
568 void
569 cmov(x, y)
570 register int x, y;
571 {
572     xputs(tgoto(nh_CM, x, y));
573     ttyDisplay->cury = y;
574     ttyDisplay->curx = x;
575 }
576
577 /* See note above. xputc() is a special function. */
578 void
579 xputc(c)
580 #if defined(apollo)
581     int c;
582 #else
583     char c;
584 #endif
585 {
586 /*JP
587     (void) putchar(c);
588 */
589     (void) cputchar(c);
590 }
591
592 void
593 xputs(s)
594 const char *s;
595 {
596 #ifndef TERMLIB
597 #if 1 /*JP*/
598     (void) jputchar('\0');
599 #endif
600     (void) fputs(s, stdout);
601 #else
602 #if defined(NHSTDC) || defined(ULTRIX_PROTO)
603     tputs(s, 1, (int (*) ()) xputc);
604 #else
605     tputs(s, 1, xputc);
606 #endif
607 #endif
608 }
609
610 void
611 cl_end()
612 {
613     if (CE) {
614         xputs(CE);
615     } else { /* no-CE fix - free after Harold Rynes */
616         register int cx = ttyDisplay->curx + 1;
617
618         /* this looks terrible, especially on a slow terminal
619            but is better than nothing */
620         while (cx < CO) {
621             xputc(' ');
622             cx++;
623         }
624         tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
625                  (int) ttyDisplay->cury);
626     }
627 }
628
629 void
630 clear_screen()
631 {
632     /* note: if CL is null, then termcap initialization failed,
633             so don't attempt screen-oriented I/O during final cleanup.
634      */
635     if (CL) {
636         xputs(CL);
637         home();
638     }
639 }
640
641 void
642 home()
643 {
644     if (HO)
645         xputs(HO);
646     else if (nh_CM)
647         xputs(tgoto(nh_CM, 0, 0));
648     else
649         tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */
650     ttyDisplay->curx = ttyDisplay->cury = 0;
651 }
652
653 void
654 standoutbeg()
655 {
656     if (SO)
657         xputs(SO);
658 }
659
660 void
661 standoutend()
662 {
663     if (SE)
664         xputs(SE);
665 }
666
667 #if 0 /* if you need one of these, uncomment it (here and in extern.h) */
668 void
669 revbeg()
670 {
671     if (MR)
672         xputs(MR);
673 }
674
675 void
676 boldbeg()
677 {
678     if (MD)
679         xputs(MD);
680 }
681
682 void
683 blinkbeg()
684 {
685     if (MB)
686         xputs(MB);
687 }
688
689 void
690 dimbeg()
691 {
692     /* not in most termcap entries */
693     if (MH)
694         xputs(MH);
695 }
696
697 void
698 m_end()
699 {
700     if (ME)
701         xputs(ME);
702 }
703 #endif /*0*/
704
705 void
706 backsp()
707 {
708     xputs(BC);
709 }
710
711 void
712 tty_nhbell()
713 {
714     if (flags.silent)
715         return;
716 #if 0 /*JP*/
717     (void) putchar('\007'); /* curx does not change */
718 #else
719     (void) cputchar('\007'); /* curx does not change */
720 #endif
721     (void) fflush(stdout);
722 }
723
724 #ifdef ASCIIGRAPH
725 void
726 graph_on()
727 {
728     if (AS)
729         xputs(AS);
730 }
731
732 void
733 graph_off()
734 {
735     if (AE)
736         xputs(AE);
737 }
738 #endif
739
740 #if !defined(MICRO)
741 #ifdef VMS
742 static const short tmspc10[] = { /* from termcap */
743                                  0, 2000, 1333, 909, 743, 666, 333, 166, 83,
744                                  55, 50, 41, 27, 20, 13, 10, 5
745 };
746 #else
747 static const short tmspc10[] = { /* from termcap */
748                                  0, 2000, 1333, 909, 743, 666, 500, 333, 166,
749                                  83, 55, 41, 20, 10, 5
750 };
751 #endif
752 #endif
753
754 /* delay 50 ms */
755 void
756 tty_delay_output()
757 {
758 #if defined(MICRO)
759     register int i;
760 #endif
761 #ifdef TIMED_DELAY
762     if (flags.nap) {
763         (void) fflush(stdout);
764         msleep(50); /* sleep for 50 milliseconds */
765         return;
766     }
767 #endif
768 #if defined(MICRO)
769     /* simulate the delay with "cursor here" */
770 #if 1 /*JP*//*JPTB need?*/
771         {
772         register int i;
773 #endif
774     for (i = 0; i < 3; i++) {
775         cmov(ttyDisplay->curx, ttyDisplay->cury);
776         (void) fflush(stdout);
777     }
778 #if 1 /*JP*/
779         }
780 #endif
781 #else /* MICRO */
782     /* BUG: if the padding character is visible, as it is on the 5620
783        then this looks terrible. */
784     if (flags.null) {
785 #ifdef TERMINFO
786 /* cbosgd!cbcephus!pds for SYS V R2 */
787 #ifdef NHSTDC
788         tputs("$<50>", 1, (int (*) ()) xputc);
789 #else
790         tputs("$<50>", 1, xputc);
791 #endif
792 #else
793 #if defined(NHSTDC) || defined(ULTRIX_PROTO)
794         tputs("50", 1, (int (*) ()) xputc);
795 #else
796         tputs("50", 1, xputc);
797 #endif
798 #endif
799
800     } else if (ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
801         /* delay by sending cm(here) an appropriate number of times */
802         register int cmlen =
803             strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury));
804         register int i = 500 + tmspc10[ospeed] / 2;
805
806         while (i > 0) {
807             cmov((int) ttyDisplay->curx, (int) ttyDisplay->cury);
808             i -= cmlen * tmspc10[ospeed];
809         }
810     }
811 #endif /* MICRO */
812 }
813
814 /* must only be called with curx = 1 */
815 void
816 cl_eos() /* free after Robert Viduya */
817 {
818     if (nh_CD) {
819         xputs(nh_CD);
820     } else {
821         register int cy = ttyDisplay->cury + 1;
822
823         while (cy <= LI - 2) {
824             cl_end();
825             xputc('\n');
826             cy++;
827         }
828         cl_end();
829         tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
830                  (int) ttyDisplay->cury);
831     }
832 }
833
834 #if defined(TEXTCOLOR) && defined(TERMLIB)
835 #if defined(UNIX) && defined(TERMINFO)
836 /*
837  * Sets up color highlighting, using terminfo(4) escape sequences.
838  *
839  * Having never seen a terminfo system without curses, we assume this
840  * inclusion is safe.  On systems with color terminfo, it should define
841  * the 8 COLOR_FOOs, and avoid us having to guess whether this particular
842  * terminfo uses BGR or RGB for its indexes.
843  *
844  * If we don't get the definitions, then guess.  Original color terminfos
845  * used BGR for the original Sf (setf, Standard foreground) codes, but
846  * there was a near-total lack of user documentation, so some subsequent
847  * terminfos, such as early Linux ncurses and SCO UNIX, used RGB.  Possibly
848  * as a result of the confusion, AF (setaf, ANSI Foreground) codes were
849  * introduced, but this caused yet more confusion.  Later Linux ncurses
850  * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
851  * standard.  We could switch the colors around when using Sf with ncurses,
852  * which would help things on later ncurses and hurt things on early ncurses.
853  * We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
854  * and falling back to Sf if AF isn't defined.
855  *
856  * In any case, treat black specially so we don't try to display black
857  * characters on the assumed black background.
858  */
859
860 /* `curses' is aptly named; various versions don't like these
861     macros used elsewhere within nethack; fortunately they're
862     not needed beyond this point, so we don't need to worry
863     about reconstructing them after the header file inclusion. */
864 #undef delay_output
865 #undef TRUE
866 #undef FALSE
867 #define m_move curses_m_move /* Some curses.h decl m_move(), not used here \
868                                 */
869
870 #include <curses.h>
871
872 #if !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL)
873 extern char *tparm();
874 #endif
875
876 #ifndef COLOR_BLACK /* trust include file */
877 #ifndef _M_UNIX     /* guess BGR */
878 #define COLOR_BLACK 0
879 #define COLOR_BLUE 1
880 #define COLOR_GREEN 2
881 #define COLOR_CYAN 3
882 #define COLOR_RED 4
883 #define COLOR_MAGENTA 5
884 #define COLOR_YELLOW 6
885 #define COLOR_WHITE 7
886 #else /* guess RGB */
887 #define COLOR_BLACK 0
888 #define COLOR_RED 1
889 #define COLOR_GREEN 2
890 #define COLOR_YELLOW 3
891 #define COLOR_BLUE 4
892 #define COLOR_MAGENTA 5
893 #define COLOR_CYAN 6
894 #define COLOR_WHITE 7
895 #endif
896 #endif
897
898 /* Mapping data for the six terminfo colors that resolve to pairs of nethack
899  * colors.  Black and white are handled specially.
900  */
901 const struct {
902     int ti_color, nh_color, nh_bright_color;
903 } ti_map[6] = { { COLOR_RED, CLR_RED, CLR_ORANGE },
904                 { COLOR_GREEN, CLR_GREEN, CLR_BRIGHT_GREEN },
905                 { COLOR_YELLOW, CLR_BROWN, CLR_YELLOW },
906                 { COLOR_BLUE, CLR_BLUE, CLR_BRIGHT_BLUE },
907                 { COLOR_MAGENTA, CLR_MAGENTA, CLR_BRIGHT_MAGENTA },
908                 { COLOR_CYAN, CLR_CYAN, CLR_BRIGHT_CYAN } };
909
910 static char nilstring[] = "";
911
912 static void
913 init_hilite()
914 {
915     register int c;
916     char *setf, *scratch;
917     int md_len;
918
919     if (tgetnum("Co") < 8 || (MD == NULL) || (strlen(MD) == 0)
920         || ((setf = tgetstr("AF", (char **) 0)) == (char *) 0
921             && (setf = tgetstr("Sf", (char **) 0)) == (char *) 0)) {
922         /* Fallback when colors not available
923          * It's arbitrary to collapse all colors except gray
924          * together, but that's what the previous code did.
925          */
926         hilites[CLR_BLACK] = nh_HI;
927         hilites[CLR_RED] = nh_HI;
928         hilites[CLR_GREEN] = nh_HI;
929         hilites[CLR_BROWN] = nh_HI;
930         hilites[CLR_BLUE] = nh_HI;
931         hilites[CLR_MAGENTA] = nh_HI;
932         hilites[CLR_CYAN] = nh_HI;
933         hilites[CLR_GRAY] = nilstring;
934         hilites[NO_COLOR] = nilstring;
935         hilites[CLR_ORANGE] = nh_HI;
936         hilites[CLR_BRIGHT_GREEN] = nh_HI;
937         hilites[CLR_YELLOW] = nh_HI;
938         hilites[CLR_BRIGHT_BLUE] = nh_HI;
939         hilites[CLR_BRIGHT_MAGENTA] = nh_HI;
940         hilites[CLR_BRIGHT_CYAN] = nh_HI;
941         hilites[CLR_WHITE] = nh_HI;
942         return;
943     }
944
945     md_len = strlen(MD);
946
947     c = 6;
948     while (c--) {
949         char *work;
950         scratch = tparm(setf, ti_map[c].ti_color);
951         work = (char *) alloc(strlen(scratch) + md_len + 1);
952         Strcpy(work, MD);
953         hilites[ti_map[c].nh_bright_color] = work;
954         work += md_len;
955         Strcpy(work, scratch);
956         hilites[ti_map[c].nh_color] = work;
957     }
958
959     scratch = tparm(setf, COLOR_WHITE);
960     hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1);
961     Strcpy(hilites[CLR_WHITE], MD);
962     Strcat(hilites[CLR_WHITE], scratch);
963
964     hilites[CLR_GRAY] = nilstring;
965     hilites[NO_COLOR] = nilstring;
966
967     if (iflags.wc2_darkgray) {
968         /* On many terminals, esp. those using classic PC CGA/EGA/VGA
969          * textmode, specifying "hilight" and "black" simultaneously
970          * produces a dark shade of gray that is visible against a
971          * black background.  We can use it to represent black objects.
972          */
973         scratch = tparm(setf, COLOR_BLACK);
974         hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1);
975         Strcpy(hilites[CLR_BLACK], MD);
976         Strcat(hilites[CLR_BLACK], scratch);
977     } else {
978         /* But it's concievable that hilighted black-on-black could
979          * still be invisible on many others.  We substitute blue for
980          * black.
981          */
982         hilites[CLR_BLACK] = hilites[CLR_BLUE];
983     }
984 }
985
986 static void
987 kill_hilite()
988 {
989     /* if colors weren't available, no freeing needed */
990     if (hilites[CLR_BLACK] == nh_HI)
991         return;
992
993     if (hilites[CLR_BLACK] != hilites[CLR_BLUE])
994         free(hilites[CLR_BLACK]);
995
996     /* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */
997     /* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */
998     /* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */
999     /* CLR_RED overlaps CLR_ORANGE, do not free */
1000     /* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */
1001     /* CLR_BROWN overlaps CLR_YELLOW, do not free */
1002     /* CLR_GRAY is static 'nilstring', do not free */
1003     /* NO_COLOR is static 'nilstring', do not free */
1004     free(hilites[CLR_BRIGHT_BLUE]);
1005     free(hilites[CLR_BRIGHT_GREEN]);
1006     free(hilites[CLR_BRIGHT_CYAN]);
1007     free(hilites[CLR_YELLOW]);
1008     free(hilites[CLR_ORANGE]);
1009     free(hilites[CLR_BRIGHT_MAGENTA]);
1010     free(hilites[CLR_WHITE]);
1011 }
1012
1013 #else /* UNIX && TERMINFO */
1014
1015 #ifndef TOS
1016 /* find the foreground and background colors set by nh_HI or nh_HE */
1017 static void
1018 analyze_seq(str, fg, bg)
1019 char *str;
1020 int *fg, *bg;
1021 {
1022     register int c, code;
1023     int len;
1024
1025 #ifdef MICRO
1026     *fg = CLR_GRAY;
1027     *bg = CLR_BLACK;
1028 #else
1029     *fg = *bg = NO_COLOR;
1030 #endif
1031
1032     c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */
1033     len = strlen(str) - 1;          /* length excluding attrib suffix */
1034     if ((c != 1 && (str[0] != '\033' || str[1] != '[')) || (len - c) < 1
1035         || str[len] != 'm')
1036         return;
1037
1038     while (c < len) {
1039         if ((code = atoi(&str[c])) == 0) { /* reset */
1040             /* this also catches errors */
1041 #ifdef MICRO
1042             *fg = CLR_GRAY;
1043             *bg = CLR_BLACK;
1044 #else
1045             *fg = *bg = NO_COLOR;
1046 #endif
1047         } else if (code == 1) { /* bold */
1048             *fg |= BRIGHT;
1049 #if 0
1050         /* I doubt we'll ever resort to using blinking characters,
1051            unless we want a pulsing glow for something.  But, in case
1052            we do... -3. */
1053         } else if (code == 5) { /* blinking */
1054             *fg |= BLINK;
1055         } else if (code == 25) { /* stop blinking */
1056             *fg &= ~BLINK;
1057 #endif
1058         } else if (code == 7 || code == 27) { /* reverse */
1059             code = *fg & ~BRIGHT;
1060             *fg = *bg | (*fg & BRIGHT);
1061             *bg = code;
1062         } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
1063             *fg = code - 30;
1064         } else if (code >= 40 && code <= 47) { /* hi_background RGB */
1065             *bg = code - 40;
1066         }
1067         while (digit(str[++c]))
1068             ;
1069         c++;
1070     }
1071 }
1072 #endif
1073
1074 /*
1075  * Sets up highlighting sequences, using ANSI escape sequences (highlight code
1076  * found in print.c).  The nh_HI and nh_HE sequences (usually from SO) are
1077  * scanned to find foreground and background colors.
1078  */
1079
1080 static void
1081 init_hilite()
1082 {
1083     register int c;
1084 #ifdef TOS
1085     extern unsigned long tos_numcolors; /* in tos.c */
1086     static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
1087
1088     if (tos_numcolors <= 2) {
1089         return;
1090     }
1091     /* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
1092      * on the Falcon the dim colors are *really* dim; so we make most
1093      * of the colors the bright versions, with a few exceptions where
1094      * the dim ones look OK.
1095      */
1096     hilites[0] = NOCOL;
1097     for (c = 1; c < SIZE(hilites); c++) {
1098         char *foo;
1099         foo = (char *) alloc(sizeof("\033b0"));
1100         if (tos_numcolors > 4)
1101             Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0');
1102         else
1103             Strcpy(foo, "\033b0");
1104         hilites[c] = foo;
1105     }
1106
1107     if (tos_numcolors == 4) {
1108         TI = "\033b0\033c3\033E\033e";
1109         TE = "\033b3\033c0\033J";
1110         nh_HE = COLHE;
1111         hilites[CLR_GREEN] = hilites[CLR_GREEN | BRIGHT] = "\033b2";
1112         hilites[CLR_RED] = hilites[CLR_RED | BRIGHT] = "\033b1";
1113     } else {
1114         sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN ^ BRIGHT) + '0');
1115         sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN ^ BRIGHT) + '0');
1116
1117         TI = "\033b0\033c\017\033E\033e";
1118         TE = "\033b\017\033c0\033J";
1119         nh_HE = COLHE;
1120         hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
1121         hilites[NO_COLOR] = hilites[CLR_GRAY];
1122     }
1123
1124 #else /* TOS */
1125
1126     int backg, foreg, hi_backg, hi_foreg;
1127
1128     for (c = 0; c < SIZE(hilites); c++)
1129         hilites[c] = nh_HI;
1130     hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *) 0;
1131
1132     analyze_seq(nh_HI, &hi_foreg, &hi_backg);
1133     analyze_seq(nh_HE, &foreg, &backg);
1134
1135     for (c = 0; c < SIZE(hilites); c++)
1136         /* avoid invisibility */
1137         if ((backg & ~BRIGHT) != c) {
1138 #ifdef MICRO
1139             if (c == CLR_BLUE)
1140                 continue;
1141 #endif
1142             if (c == foreg)
1143                 hilites[c] = (char *) 0;
1144             else if (c != hi_foreg || backg != hi_backg) {
1145                 hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
1146                 Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
1147                 if ((c | BRIGHT) != (foreg | BRIGHT))
1148                     Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
1149                 if (backg != CLR_BLACK)
1150                     Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
1151                 Strcat(hilites[c], "m");
1152             }
1153         }
1154
1155 #ifdef MICRO
1156     /* brighten low-visibility colors */
1157     hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
1158 #endif
1159 #endif /* TOS */
1160 }
1161
1162 static void
1163 kill_hilite()
1164 {
1165 #ifndef TOS
1166     register int c;
1167
1168     for (c = 0; c < CLR_MAX / 2; c++) {
1169         if (hilites[c | BRIGHT] == hilites[c])
1170             hilites[c | BRIGHT] = 0;
1171         if (hilites[c] && (hilites[c] != nh_HI))
1172             free((genericptr_t) hilites[c]), hilites[c] = 0;
1173         if (hilites[c | BRIGHT] && (hilites[c | BRIGHT] != nh_HI))
1174             free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0;
1175     }
1176 #endif
1177     return;
1178 }
1179 #endif /* UNIX */
1180 #endif /* TEXTCOLOR */
1181
1182 static char nulstr[] = "";
1183
1184 static char *
1185 s_atr2str(n)
1186 int n;
1187 {
1188     switch (n) {
1189     case ATR_ULINE:
1190         if (nh_US)
1191             return nh_US;
1192         /*FALLTHRU*/
1193     case ATR_BOLD:
1194     case ATR_BLINK:
1195 #if defined(TERMLIB) && defined(TEXTCOLOR)
1196         if (MD)
1197             return MD;
1198 #endif
1199         return nh_HI;
1200     case ATR_INVERSE:
1201         return MR;
1202     }
1203     return nulstr;
1204 }
1205
1206 static char *
1207 e_atr2str(n)
1208 int n;
1209 {
1210     switch (n) {
1211     case ATR_ULINE:
1212         if (nh_UE)
1213             return nh_UE;
1214         /*FALLTHRU*/
1215     case ATR_BOLD:
1216     case ATR_BLINK:
1217         return nh_HE;
1218     case ATR_INVERSE:
1219         return ME;
1220     }
1221     return nulstr;
1222 }
1223
1224 void
1225 term_start_attr(attr)
1226 int attr;
1227 {
1228     if (attr) {
1229         xputs(s_atr2str(attr));
1230     }
1231 }
1232
1233 void
1234 term_end_attr(attr)
1235 int attr;
1236 {
1237     if (attr) {
1238         xputs(e_atr2str(attr));
1239     }
1240 }
1241
1242 void
1243 term_start_raw_bold()
1244 {
1245     xputs(nh_HI);
1246 }
1247
1248 void
1249 term_end_raw_bold()
1250 {
1251     xputs(nh_HE);
1252 }
1253
1254 #ifdef TEXTCOLOR
1255
1256 void
1257 term_end_color()
1258 {
1259     xputs(nh_HE);
1260 }
1261
1262 void
1263 term_start_color(color)
1264 int color;
1265 {
1266     xputs(hilites[color]);
1267 }
1268
1269 /* not to be confused with has_colors() in unixtty.c */
1270 int
1271 has_color(color)
1272 int color;
1273 {
1274 #ifdef X11_GRAPHICS
1275     /* XXX has_color() should be added to windowprocs */
1276     if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "X11"))
1277         return 1;
1278 #endif
1279 #ifdef GEM_GRAPHICS
1280     /* XXX has_color() should be added to windowprocs */
1281     if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Gem"))
1282         return 1;
1283 #endif
1284 #ifdef QT_GRAPHICS
1285     /* XXX has_color() should be added to windowprocs */
1286     if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Qt"))
1287         return 1;
1288 #endif
1289 #ifdef AMII_GRAPHICS
1290     /* hilites[] not used */
1291     return iflags.use_color ? 1 : 0;
1292 #else
1293     return hilites[color] != (char *) 0;
1294 #endif
1295 }
1296
1297 #endif /* TEXTCOLOR */
1298
1299 #endif /* TTY_GRAPHICS */
1300
1301 /*termcap.c*/