1 /* NetHack 3.6 termcap.c $NHDT-Date: 1562056615 2019/07/02 08:36:55 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.31 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
8 #if defined(TTY_GRAPHICS) && !defined(NO_TERMS)
13 #ifdef MICROPORT_286_BUG
14 #define Tgetstr(key) (tgetstr(key, tbuf))
16 #define Tgetstr(key) (tgetstr(key, &tbufptr))
17 #endif /* MICROPORT_286_BUG **/
19 static char *FDECL(s_atr2str, (int));
20 static char *FDECL(e_atr2str, (int));
22 void FDECL(cmov, (int, int));
23 void FDECL(nocmov, (int, int));
24 #if defined(TEXTCOLOR) && defined(TERMLIB)
25 #if !defined(UNIX) || !defined(TERMINFO)
27 static void FDECL(analyze_seq, (char *, int *, int *));
30 static void NDECL(init_hilite);
31 static void NDECL(kill_hilite);
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 };
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, *MR, *MB, *MH, *MD;
42 boolean dynamic_HIHE = FALSE;
44 STATIC_OVL char PC = '\0';
45 STATIC_VAR char tbuf[512];
50 const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */
52 char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */
56 static char *KS = (char *) 0, *KE = (char *) 0; /* keypad sequences */
57 static char nullstr[] = "";
59 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
60 extern boolean HE_resets_AS;
64 STATIC_VAR char tgotobuf[20];
66 #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + ' ', x + ' '), tgotobuf)
68 #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + 1, x + 1), tgotobuf)
78 register const char *term;
83 term = verify_termcap();
86 term = getenv("TERM");
88 #if defined(TOS) && defined(__GNUC__)
90 term = "builtin"; /* library has a default */
95 error("Can't get TERM.");
101 TI = VS = VE = TE = nullstr;
103 CE = "\033K"; /* the VT52 termcap */
105 nh_CM = "\033Y%c%c"; /* used with function tgoto() */
111 /* HI and HE will be updated in init_hilite if we're using color */
116 CL = "\033E"; /* last thing set */
124 if (CO < COLNO || LI < ROWNO + 3)
129 /* nh_CD = "\033[J"; */
130 CE = "\033[K"; /* the ANSI termcap */
132 nh_CM = "\033[%d;%dH";
134 nh_CM = "\033[%i%d;%dH";
139 #ifdef MICRO /* backspaces are non-destructive */
144 nh_HI = SO = "\033[1m";
147 TI = nh_HE = ME = SE = nh_UE = "\033[0m";
148 /* strictly, SE should be 2, and nh_UE should be 24,
149 but we can't trust all ANSI emulators to be
150 that complete. -3. */
155 TE = VS = VE = nullstr;
157 for (i = 0; i < CLR_MAX / 2; i++)
158 if (i != CLR_BLACK) {
159 hilites[i | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
160 Sprintf(hilites[i | BRIGHT], "\033[1;3%dm", i);
164 hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
168 hilites[i] = (char *) alloc(sizeof("\033[0;3%dm"));
169 Sprintf(hilites[i], "\033[0;3%dm", i);
172 #endif /* TEXTCOLOR */
175 CL = "\033[2J"; /* last thing set */
179 #endif /* ANSI_DEFAULT */
182 tptr = (char *) alloc(1024);
185 if (!strncmp(term, "5620", 4))
186 flags.null = FALSE; /* this should be a termcap flag */
187 if (tgetent(tptr, term) < 1) {
189 (void) strncpy(buf, term,
190 (BUFSZ - 1) - (sizeof("Unknown terminal type: . ")));
191 buf[BUFSZ - 1] = '\0';
192 error("Unknown terminal type: %s.", term);
194 if ((pc = Tgetstr("pc")) != 0)
197 if (!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */
199 error("Terminal must backspace.");
201 if (!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */
204 error("Terminal must backspace.");
218 * LI and CO are set in ioctl.c via a TIOCGWINSZ if available. If
219 * the kernel has values for either we should use them rather than
220 * the values from TERMCAP ...
228 #if defined(TOS) && defined(__GNUC__)
229 if (!strcmp(term, "builtin")) {
236 if (!LI || !CO) /* if we don't override it */
241 if (CO < COLNO || LI < ROWNO + 3)
244 nh_ND = Tgetstr("nd");
246 error("NetHack can't have OS.");
251 /* It seems that xd is no longer supported, and we should use
252 a linefeed instead; unfortunately this requires resetting
253 CRMOD, and many output routines will have to be modified
254 slightly. Let's leave that till the next release. */
256 /* not: XD = Tgetstr("do"); */
257 if (!(nh_CM = Tgetstr("cm"))) {
259 error("NetHack needs CM or UP or HO.");
260 tty_raw_print("Playing NetHack on terminals without CM is suspect.");
265 nh_US = Tgetstr("us");
266 nh_UE = Tgetstr("ue");
267 SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */
268 if (!SO || !SE || (SG > 0))
269 SO = SE = nh_US = nh_UE = nullstr;
274 VS = Tgetstr("eA"); /* enable graphics */
276 KS = Tgetstr("ks"); /* keypad start (special mode) */
277 KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */
278 MR = Tgetstr("mr"); /* reverse */
279 MB = Tgetstr("mb"); /* blink */
280 MD = Tgetstr("md"); /* boldface */
281 MH = Tgetstr("mh"); /* dim */
282 ME = Tgetstr("me"); /* turn off all attributes */
284 ME = SE ? SE : nullstr; /* default to SE value */
286 /* Get rid of padding numbers for nh_HI and nh_HE. Hope they
287 * aren't really needed!!! nh_HI and nh_HE are outputted to the
288 * pager as a string - so how can you send it NULs???
291 for (i = 0; digit(SO[i]); ++i)
293 nh_HI = dupstr(&SO[i]);
294 for (i = 0; digit(ME[i]); ++i)
296 nh_HE = dupstr(&ME[i]);
301 nh_CD = Tgetstr("cd");
303 #if defined(TOS) && defined(__GNUC__)
304 if (!strcmp(term, "builtin") || !strcmp(term, "tw52")
305 || !strcmp(term, "st52")) {
314 if (!(CL = Tgetstr("cl"))) /* last thing set */
315 error("NetHack needs CL.");
316 if ((int) (tbufptr - tbuf) > (int) (sizeof tbuf))
317 error("TERMCAP entry too big...\n");
318 free((genericptr_t) tptr);
322 /* note: at present, this routine is not part of the formal window interface
324 /* deallocate resources prior to final termination */
328 /* we only attempt to clean up a few individual termcap variables */
334 free((genericptr_t) nh_HI), nh_HI = (char *) 0;
335 free((genericptr_t) nh_HE), nh_HE = (char *) 0;
336 dynamic_HIHE = FALSE;
343 tty_number_pad(state)
347 case -1: /* activate keypad mode (escape sequences) */
351 case 1: /* activate numeric mode for keypad (digits) */
355 case 0: /* don't need to do anything--leave terminal as-is */
362 extern void NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */
363 static void NDECL(tty_decgraphics_termcap_fixup);
366 We call this routine whenever DECgraphics mode is enabled, even if it
367 has been previously set, in case the user manages to reset the fonts.
368 The actual termcap fixup only needs to be done once, but we can't
369 call xputs() from the option setting or graphics assigning routines,
370 so this is a convenient hook.
373 tty_decgraphics_termcap_fixup()
375 static char ctrlN[] = "\016";
376 static char ctrlO[] = "\017";
377 static char appMode[] = "\033=";
378 static char numMode[] = "\033>";
380 /* these values are missing from some termcaps */
382 AS = ctrlN; /* ^N (shift-out [graphics font]) */
384 AE = ctrlO; /* ^O (shift-in [regular font]) */
386 KS = appMode; /* ESC= (application keypad mode) */
388 KE = numMode; /* ESC> (numeric keypad mode) */
390 * Select the line-drawing character set as the alternate font.
391 * Do not select NA ASCII as the primary font since people may
392 * reasonably be using the UK character set.
394 if (SYMHANDLING(H_DEC))
400 #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
401 /* some termcaps suffer from the bizarre notion that resetting
402 video attributes should also reset the chosen character set */
404 const char *nh_he = nh_HE, *ae = AE;
405 int he_limit, ae_length;
407 if (digit(*ae)) { /* skip over delay prefix, if any */
419 /* can't use nethack's case-insensitive strstri() here, and some old
420 systems don't have strstr(), so use brute force substring search */
421 ae_length = strlen(ae), he_limit = strlen(nh_he);
422 while (he_limit >= ae_length) {
423 if (strncmp(nh_he, ae, ae_length) == 0) {
434 #if defined(ASCIIGRAPH) && defined(PC9800)
435 extern void NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */
439 extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */
440 static void NDECL(tty_ascgraphics_hilite_fixup);
443 tty_ascgraphics_hilite_fixup()
447 for (c = 0; c < CLR_MAX / 2; c++)
448 if (c != CLR_BLACK) {
449 hilites[c | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
450 Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c);
452 hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
453 Sprintf(hilites[c], "\033[0;3%dm", c);
465 if (!SYMHANDLING(H_IBM))
466 tty_ascgraphics_hilite_fixup();
467 /* set up callback in case option is not set yet but toggled later */
468 ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
470 if (SYMHANDLING(H_IBM))
472 /* set up callback in case option is not set yet but toggled later */
473 ibmgraphics_mode_callback = init_hilite;
478 if (SYMHANDLING(H_DEC))
479 tty_decgraphics_termcap_fixup();
480 /* set up callback in case option is not set yet but toggled later */
481 decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
484 tty_number_pad(1); /* make keypad send digits */
495 /* Cursor movements */
497 /* Note to overlay tinkerers. The placement of this overlay controls the
498 location of the function xputc(). This function is not currently in
499 trampoli.[ch] files for what is deemed to be performance reasons. If
500 this define is moved and or xputc() is taken out of the ROOT overlay,
501 then action must be taken in trampoli.[ch]. */
507 if ((int) ttyDisplay->cury > y) {
509 while ((int) ttyDisplay->cury > y) { /* Go up. */
517 tty_curs(BASE_WINDOW, x + 1, y);
518 } /* else impossible("..."); */
519 } else if ((int) ttyDisplay->cury < y) {
521 while ((int) ttyDisplay->cury < y) {
528 while ((int) ttyDisplay->cury < y) {
530 ttyDisplay->curx = 0;
535 if ((int) ttyDisplay->curx < x) { /* Go to the right. */
539 /* should instead print what is there already */
540 while ((int) ttyDisplay->curx < x) {
545 } else if ((int) ttyDisplay->curx > x) {
546 while ((int) ttyDisplay->curx > x) { /* Go to the left. */
557 xputs(tgoto(nh_CM, x, y));
558 ttyDisplay->cury = y;
559 ttyDisplay->curx = x;
562 /* See note above. xputc() is a special function for overlays. */
565 int c; /* actually char, but explicitly specify its widened type */
568 * Note: xputc() as a direct all to putchar() doesn't make any
569 * sense _if_ putchar() is a function. But if it is a macro, an
570 * overlay configuration would want to avoid hidden code bloat
571 * from multiple putchar() expansions. And it gets passed as an
572 * argument to tputs() so we have to guarantee an actual function
573 * (while possibly lacking ANSI's (func) syntax to override macro).
575 * xputc() used to be declared as 'void xputc(c) char c; {}' but
576 * avoiding the proper type 'int' just to avoid (void) casts when
577 * ignoring the result can't have been sufficent reason to add it.
578 * It also had '#if apollo' conditional to have the arg be int.
579 * Matching putchar()'s declaration and using explicit casts where
580 * warranted is more robust, so we're just a jacket around that.
596 (void) jputchar('\0');
598 (void) fputs(s, stdout);
609 } else { /* no-CE fix - free after Harold Rynes */
610 register int cx = ttyDisplay->curx + 1;
612 /* this looks terrible, especially on a slow terminal
613 but is better than nothing */
618 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
619 (int) ttyDisplay->cury);
626 /* note: if CL is null, then termcap initialization failed,
627 so don't attempt screen-oriented I/O during final cleanup.
641 xputs(tgoto(nh_CM, 0, 0));
643 tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */
644 ttyDisplay->curx = ttyDisplay->cury = 0;
661 #if 0 /* if you need one of these, uncomment it (here and in extern.h) */
686 /* not in most termcap entries */
711 (void) putchar('\007'); /* curx does not change */
713 (void) cputchar('\007'); /* curx does not change */
715 (void) fflush(stdout);
736 static const short tmspc10[] = { /* from termcap */
737 0, 2000, 1333, 909, 743, 666, 333, 166, 83,
738 55, 50, 41, 27, 20, 13, 10, 5
741 static const short tmspc10[] = { /* from termcap */
742 0, 2000, 1333, 909, 743, 666, 500, 333, 166,
743 83, 55, 41, 20, 10, 5
755 if (iflags.debug_fuzzer)
759 (void) fflush(stdout);
760 msleep(50); /* sleep for 50 milliseconds */
765 /* simulate the delay with "cursor here" */
766 #if 1 /*JP*//*JPTB need?*/
770 for (i = 0; i < 3; i++) {
771 cmov(ttyDisplay->curx, ttyDisplay->cury);
772 (void) fflush(stdout);
778 /* BUG: if the padding character is visible, as it is on the 5620
779 then this looks terrible. */
789 } else if (ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
790 /* delay by sending cm(here) an appropriate number of times */
792 (int) strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury));
793 register int i = 500 + tmspc10[ospeed] / 2;
796 cmov((int) ttyDisplay->curx, (int) ttyDisplay->cury);
797 i -= cmlen * tmspc10[ospeed];
803 /* must only be called with curx = 1 */
805 cl_eos() /* free after Robert Viduya */
810 register int cy = ttyDisplay->cury + 1;
812 while (cy <= LI - 2) {
818 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
819 (int) ttyDisplay->cury);
823 #if defined(TEXTCOLOR) && defined(TERMLIB)
824 #if defined(UNIX) && defined(TERMINFO)
826 * Sets up color highlighting, using terminfo(4) escape sequences.
828 * Having never seen a terminfo system without curses, we assume this
829 * inclusion is safe. On systems with color terminfo, it should define
830 * the 8 COLOR_FOOs, and avoid us having to guess whether this particular
831 * terminfo uses BGR or RGB for its indexes.
833 * If we don't get the definitions, then guess. Original color terminfos
834 * used BGR for the original Sf (setf, Standard foreground) codes, but
835 * there was a near-total lack of user documentation, so some subsequent
836 * terminfos, such as early Linux ncurses and SCO UNIX, used RGB. Possibly
837 * as a result of the confusion, AF (setaf, ANSI Foreground) codes were
838 * introduced, but this caused yet more confusion. Later Linux ncurses
839 * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
840 * standard. We could switch the colors around when using Sf with ncurses,
841 * which would help things on later ncurses and hurt things on early ncurses.
842 * We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
843 * and falling back to Sf if AF isn't defined.
845 * In any case, treat black specially so we don't try to display black
846 * characters on the assumed black background.
849 /* `curses' is aptly named; various versions don't like these
850 macros used elsewhere within nethack; fortunately they're
851 not needed beyond this point, so we don't need to worry
852 about reconstructing them after the header file inclusion. */
856 #define m_move curses_m_move /* Some curses.h decl m_move(), not used here */
860 #if !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL)
861 extern char *tparm();
864 #ifndef COLOR_BLACK /* trust include file */
865 #ifndef _M_UNIX /* guess BGR */
866 #define COLOR_BLACK 0
868 #define COLOR_GREEN 2
871 #define COLOR_MAGENTA 5
872 #define COLOR_YELLOW 6
873 #define COLOR_WHITE 7
874 #else /* guess RGB */
875 #define COLOR_BLACK 0
877 #define COLOR_GREEN 2
878 #define COLOR_YELLOW 3
880 #define COLOR_MAGENTA 5
882 #define COLOR_WHITE 7
886 /* Mapping data for the six terminfo colors that resolve to pairs of nethack
887 * colors. Black and white are handled specially.
890 int ti_color, nh_color, nh_bright_color;
891 } ti_map[6] = { { COLOR_RED, CLR_RED, CLR_ORANGE },
892 { COLOR_GREEN, CLR_GREEN, CLR_BRIGHT_GREEN },
893 { COLOR_YELLOW, CLR_BROWN, CLR_YELLOW },
894 { COLOR_BLUE, CLR_BLUE, CLR_BRIGHT_BLUE },
895 { COLOR_MAGENTA, CLR_MAGENTA, CLR_BRIGHT_MAGENTA },
896 { COLOR_CYAN, CLR_CYAN, CLR_BRIGHT_CYAN } };
898 static char nilstring[] = "";
904 char *setf, *scratch;
907 if (tgetnum("Co") < 8 || (MD == NULL) || (strlen(MD) == 0)
908 || ((setf = tgetstr("AF", (char **) 0)) == (char *) 0
909 && (setf = tgetstr("Sf", (char **) 0)) == (char *) 0)) {
910 /* Fallback when colors not available
911 * It's arbitrary to collapse all colors except gray
912 * together, but that's what the previous code did.
914 hilites[CLR_BLACK] = nh_HI;
915 hilites[CLR_RED] = nh_HI;
916 hilites[CLR_GREEN] = nh_HI;
917 hilites[CLR_BROWN] = nh_HI;
918 hilites[CLR_BLUE] = nh_HI;
919 hilites[CLR_MAGENTA] = nh_HI;
920 hilites[CLR_CYAN] = nh_HI;
921 hilites[CLR_GRAY] = nilstring;
922 hilites[NO_COLOR] = nilstring;
923 hilites[CLR_ORANGE] = nh_HI;
924 hilites[CLR_BRIGHT_GREEN] = nh_HI;
925 hilites[CLR_YELLOW] = nh_HI;
926 hilites[CLR_BRIGHT_BLUE] = nh_HI;
927 hilites[CLR_BRIGHT_MAGENTA] = nh_HI;
928 hilites[CLR_BRIGHT_CYAN] = nh_HI;
929 hilites[CLR_WHITE] = nh_HI;
939 scratch = tparm(setf, ti_map[c].ti_color);
940 work = (char *) alloc(strlen(scratch) + md_len + 1);
942 hilites[ti_map[c].nh_bright_color] = work;
944 Strcpy(work, scratch);
945 hilites[ti_map[c].nh_color] = work;
948 scratch = tparm(setf, COLOR_WHITE);
949 hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1);
950 Strcpy(hilites[CLR_WHITE], MD);
951 Strcat(hilites[CLR_WHITE], scratch);
953 hilites[CLR_GRAY] = nilstring;
954 hilites[NO_COLOR] = nilstring;
956 if (iflags.wc2_darkgray) {
957 /* On many terminals, esp. those using classic PC CGA/EGA/VGA
958 * textmode, specifying "hilight" and "black" simultaneously
959 * produces a dark shade of gray that is visible against a
960 * black background. We can use it to represent black objects.
962 scratch = tparm(setf, COLOR_BLACK);
963 hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1);
964 Strcpy(hilites[CLR_BLACK], MD);
965 Strcat(hilites[CLR_BLACK], scratch);
967 /* But it's concievable that hilighted black-on-black could
968 * still be invisible on many others. We substitute blue for
971 hilites[CLR_BLACK] = hilites[CLR_BLUE];
978 /* if colors weren't available, no freeing needed */
979 if (hilites[CLR_BLACK] == nh_HI)
982 if (hilites[CLR_BLACK] != hilites[CLR_BLUE])
983 free(hilites[CLR_BLACK]);
985 /* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */
986 /* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */
987 /* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */
988 /* CLR_RED overlaps CLR_ORANGE, do not free */
989 /* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */
990 /* CLR_BROWN overlaps CLR_YELLOW, do not free */
991 /* CLR_GRAY is static 'nilstring', do not free */
992 /* NO_COLOR is static 'nilstring', do not free */
993 free(hilites[CLR_BRIGHT_BLUE]);
994 free(hilites[CLR_BRIGHT_GREEN]);
995 free(hilites[CLR_BRIGHT_CYAN]);
996 free(hilites[CLR_YELLOW]);
997 free(hilites[CLR_ORANGE]);
998 free(hilites[CLR_BRIGHT_MAGENTA]);
999 free(hilites[CLR_WHITE]);
1002 #else /* UNIX && TERMINFO */
1005 /* find the foreground and background colors set by nh_HI or nh_HE */
1007 analyze_seq(str, fg, bg)
1011 register int c, code;
1018 *fg = *bg = NO_COLOR;
1021 c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */
1022 len = strlen(str) - 1; /* length excluding attrib suffix */
1023 if ((c != 1 && (str[0] != '\033' || str[1] != '[')) || (len - c) < 1
1028 if ((code = atoi(&str[c])) == 0) { /* reset */
1029 /* this also catches errors */
1034 *fg = *bg = NO_COLOR;
1036 } else if (code == 1) { /* bold */
1039 /* I doubt we'll ever resort to using blinking characters,
1040 unless we want a pulsing glow for something. But, in case
1042 } else if (code == 5) { /* blinking */
1044 } else if (code == 25) { /* stop blinking */
1047 } else if (code == 7 || code == 27) { /* reverse */
1048 code = *fg & ~BRIGHT;
1049 *fg = *bg | (*fg & BRIGHT);
1051 } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
1053 } else if (code >= 40 && code <= 47) { /* hi_background RGB */
1056 while (digit(str[++c]))
1064 * Sets up highlighting sequences, using ANSI escape sequences (highlight code
1065 * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are
1066 * scanned to find foreground and background colors.
1074 extern unsigned long tos_numcolors; /* in tos.c */
1075 static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
1077 if (tos_numcolors <= 2) {
1080 /* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
1081 * on the Falcon the dim colors are *really* dim; so we make most
1082 * of the colors the bright versions, with a few exceptions where
1083 * the dim ones look OK.
1086 for (c = 1; c < SIZE(hilites); c++) {
1088 foo = (char *) alloc(sizeof("\033b0"));
1089 if (tos_numcolors > 4)
1090 Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0');
1092 Strcpy(foo, "\033b0");
1096 if (tos_numcolors == 4) {
1097 TI = "\033b0\033c3\033E\033e";
1098 TE = "\033b3\033c0\033J";
1100 hilites[CLR_GREEN] = hilites[CLR_GREEN | BRIGHT] = "\033b2";
1101 hilites[CLR_RED] = hilites[CLR_RED | BRIGHT] = "\033b1";
1103 sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN ^ BRIGHT) + '0');
1104 sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN ^ BRIGHT) + '0');
1106 TI = "\033b0\033c\017\033E\033e";
1107 TE = "\033b\017\033c0\033J";
1109 hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
1110 hilites[NO_COLOR] = hilites[CLR_GRAY];
1115 int backg, foreg, hi_backg, hi_foreg;
1117 for (c = 0; c < SIZE(hilites); c++)
1119 hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *) 0;
1121 analyze_seq(nh_HI, &hi_foreg, &hi_backg);
1122 analyze_seq(nh_HE, &foreg, &backg);
1124 for (c = 0; c < SIZE(hilites); c++)
1125 /* avoid invisibility */
1126 if ((backg & ~BRIGHT) != c) {
1132 hilites[c] = (char *) 0;
1133 else if (c != hi_foreg || backg != hi_backg) {
1134 hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
1135 Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
1136 if ((c | BRIGHT) != (foreg | BRIGHT))
1137 Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
1138 if (backg != CLR_BLACK)
1139 Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
1140 Strcat(hilites[c], "m");
1145 /* brighten low-visibility colors */
1146 hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
1157 for (c = 0; c < CLR_MAX / 2; c++) {
1158 if (hilites[c | BRIGHT] == hilites[c])
1159 hilites[c | BRIGHT] = 0;
1160 if (hilites[c] && (hilites[c] != nh_HI))
1161 free((genericptr_t) hilites[c]), hilites[c] = 0;
1162 if (hilites[c | BRIGHT] && (hilites[c | BRIGHT] != nh_HI))
1163 free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0;
1169 #endif /* TEXTCOLOR */
1171 static char nulstr[] = "";
1180 if (n == ATR_BLINK) {
1183 } else { /* Underline */
1184 if (nh_US && *nh_US)
1191 if (nh_HI && *nh_HI)
1212 if (nh_UE && *nh_UE)
1217 if (nh_HE && *nh_HE)
1229 /* suppress nonfunctional highlights so render_status() might be able to
1230 optimize more; keep this in sync with s_atr2str() */
1232 term_attr_fixup(msk)
1235 /* underline is converted to bold if its start sequence isn't available */
1236 if ((msk & HL_ULINE) && (!nh_US || !*nh_US)) {
1240 /* blink used to be converted to bold unconditionally; now depends on MB */
1241 if ((msk & HL_BLINK) && (!MB || !*MB)) {
1245 /* dim is ignored if its start sequence isn't available */
1246 if ((msk & HL_DIM) && (!MH || !*MH)) {
1253 term_start_attr(attr)
1257 const char *astr = s_atr2str(attr);
1269 const char *astr = e_atr2str(attr);
1277 term_start_raw_bold()
1297 term_start_color(color)
1300 if (color < CLR_MAX)
1301 xputs(hilites[color]);
1304 #endif /* TEXTCOLOR */
1306 #endif /* TTY_GRAPHICS && !NO_TERMS */