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