Terminals supporting more than 8 colors can directly display the bright colors (upper 8 colors of the 16 color palette). The tty port now only uses bold for displaying bright colors as a fallback to previous behavior for terminals with 8 colors.
1397 lines
37 KiB
C
1397 lines
37 KiB
C
/* NetHack 3.7 termcap.c $NHDT-Date: 1609459769 2021/01/01 00:09:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.41 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/*-Copyright (c) Pasi Kallinen, 2018. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
#if defined(TTY_GRAPHICS) && !defined(NO_TERMS)
|
|
|
|
#include "wintty.h"
|
|
#include "tcap.h"
|
|
|
|
#define Tgetstr(key) (tgetstr(key, &tbufptr))
|
|
|
|
static char *s_atr2str(int);
|
|
static char *e_atr2str(int);
|
|
|
|
void cmov(int, int);
|
|
void nocmov(int, int);
|
|
#if defined(TEXTCOLOR) && defined(TERMLIB)
|
|
#if (!defined(UNIX) || !defined(TERMINFO)) && !defined(TOS)
|
|
static void analyze_seq(char *, int *, int *);
|
|
#endif
|
|
#endif
|
|
#if defined(TEXTCOLOR) && (defined(TERMLIB) || defined(ANSI_DEFAULT))
|
|
static void init_hilite(void);
|
|
static void kill_hilite(void);
|
|
#endif
|
|
|
|
/* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE, ul_hack */
|
|
struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0, 0, 0, 0, FALSE };
|
|
|
|
static char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE;
|
|
static char *VS, *VE;
|
|
static char *ME, *MR, *MB, *MH, *MD;
|
|
|
|
#ifdef TERMLIB
|
|
boolean dynamic_HIHE = FALSE;
|
|
static int SG;
|
|
static char PC = '\0';
|
|
static char tbuf[512];
|
|
#endif /*TERMLIB*/
|
|
|
|
#ifdef TEXTCOLOR
|
|
#ifdef TOS
|
|
const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */
|
|
#else
|
|
char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */
|
|
#endif
|
|
#endif
|
|
|
|
static char *KS = (char *) 0, *KE = (char *) 0; /* keypad sequences */
|
|
static char nullstr[] = "";
|
|
|
|
#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
|
|
extern boolean HE_resets_AS;
|
|
#endif
|
|
|
|
#ifndef TERMLIB
|
|
static char tgotobuf[20];
|
|
#ifdef TOS
|
|
#define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + ' ', x + ' '), tgotobuf)
|
|
#else
|
|
#define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + 1, x + 1), tgotobuf)
|
|
#endif
|
|
#endif /* TERMLIB */
|
|
|
|
void
|
|
tty_startup(int *wid, int *hgt)
|
|
{
|
|
#ifdef TERMLIB
|
|
register const char *term;
|
|
register char *tptr;
|
|
char *tbufptr, *pc;
|
|
int i;
|
|
|
|
#ifdef VMS
|
|
term = verify_termcap();
|
|
if (!term)
|
|
#endif
|
|
term = getenv("TERM");
|
|
|
|
#if defined(TOS) && defined(__GNUC__)
|
|
if (!term)
|
|
term = "builtin"; /* library has a default */
|
|
#endif
|
|
if (!term)
|
|
#endif /* TERMLIB */
|
|
#ifndef ANSI_DEFAULT
|
|
error("Can't get TERM.");
|
|
#else
|
|
#ifdef TOS
|
|
{
|
|
CO = 80;
|
|
LI = 25;
|
|
TI = VS = VE = TE = nullstr;
|
|
/*
|
|
* FIXME: These variables ought to be declared 'const' (instead
|
|
* of using nhStr() to cast away const) to avoid '-Wwrite-sttings'
|
|
* warnings about assigning string literals to them.
|
|
*/
|
|
HO = nhStr("\033H");
|
|
CE = nhStr("\033K"); /* the VT52 termcap */
|
|
UP = nhStr("\033A");
|
|
nh_CM = nhStr("\033Y%c%c"); /* used with function tgoto() */
|
|
nh_ND = nhStr("\033C");
|
|
XD = nhStr("\033B");
|
|
BC = nhStr("\033D");
|
|
SO = nhStr("\033p");
|
|
SE = nhStr("\033q");
|
|
/* HI and HE will be updated in init_hilite if we're using color */
|
|
nh_HI = nhStr("\033p");
|
|
nh_HE = nhStr("\033q");
|
|
*wid = CO;
|
|
*hgt = LI;
|
|
CL = nhStr("\033E"); /* last thing set */
|
|
return;
|
|
}
|
|
#else /* TOS */
|
|
{
|
|
#ifdef MICRO
|
|
get_scr_size();
|
|
#ifdef CLIPPING
|
|
if (CO < COLNO || LI < ROWNO + 3)
|
|
setclipped();
|
|
#endif
|
|
#endif
|
|
HO = nhStr("\033[H");
|
|
/* nh_CD = nhStr("\033[J"); */
|
|
CE = nhStr("\033[K"); /* the ANSI termcap */
|
|
#ifndef TERMLIB
|
|
nh_CM = nhStr("\033[%d;%dH");
|
|
#else
|
|
nh_CM = nhStr("\033[%i%d;%dH");
|
|
#endif
|
|
UP = nhStr("\033[A");
|
|
nh_ND = nhStr("\033[C");
|
|
XD = nhStr("\033[B");
|
|
#ifdef MICRO /* backspaces are non-destructive */
|
|
BC = nhStr("\b");
|
|
#else
|
|
BC = nhStr("\033[D");
|
|
#endif
|
|
nh_HI = SO = nhStr("\033[1m");
|
|
nh_US = nhStr("\033[4m");
|
|
MR = nhStr("\033[7m");
|
|
TI = nh_HE = ME = SE = nh_UE = nhStr("\033[0m");
|
|
/* strictly, SE should be 2, and nh_UE should be 24,
|
|
but we can't trust all ANSI emulators to be
|
|
that complete. -3. */
|
|
#ifndef MICRO
|
|
AS = nhStr("\016");
|
|
AE = nhStr("\017");
|
|
#endif
|
|
TE = VS = VE = nullstr;
|
|
#ifdef TEXTCOLOR
|
|
init_hilite();
|
|
#endif /* TEXTCOLOR */
|
|
*wid = CO;
|
|
*hgt = LI;
|
|
CL = nhStr("\033[2J"); /* last thing set */
|
|
return;
|
|
}
|
|
#endif /* TOS */
|
|
#endif /* ANSI_DEFAULT */
|
|
|
|
#ifdef TERMLIB
|
|
tptr = (char *) alloc(1024);
|
|
|
|
tbufptr = tbuf;
|
|
if (!strncmp(term, "5620", 4))
|
|
flags.null = FALSE; /* this should be a termcap flag */
|
|
if (tgetent(tptr, term) < 1) {
|
|
char buf[BUFSZ];
|
|
(void) strncpy(buf, term,
|
|
(BUFSZ - 1) - (sizeof("Unknown terminal type: . ")));
|
|
buf[BUFSZ - 1] = '\0';
|
|
error("Unknown terminal type: %s.", term);
|
|
}
|
|
if ((pc = Tgetstr("pc")) != 0)
|
|
PC = *pc;
|
|
|
|
if (!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */
|
|
#ifdef TERMINFO
|
|
error("Terminal must backspace.");
|
|
#else
|
|
if (!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */
|
|
#ifndef MINIMAL_TERM
|
|
if (!tgetflag("bs"))
|
|
error("Terminal must backspace.");
|
|
#endif
|
|
BC = tbufptr;
|
|
tbufptr += 2;
|
|
*BC = '\b';
|
|
}
|
|
#endif
|
|
|
|
#ifdef MINIMAL_TERM
|
|
HO = (char *) 0;
|
|
#else
|
|
HO = Tgetstr("ho");
|
|
#endif
|
|
/*
|
|
* LI and CO are set in ioctl.c via a TIOCGWINSZ if available. If
|
|
* the kernel has values for either we should use them rather than
|
|
* the values from TERMCAP ...
|
|
*/
|
|
#ifndef MICRO
|
|
if (!CO)
|
|
CO = tgetnum("co");
|
|
if (!LI)
|
|
LI = tgetnum("li");
|
|
#else
|
|
#if defined(TOS) && defined(__GNUC__)
|
|
if (!strcmp(term, "builtin")) {
|
|
get_scr_size();
|
|
} else
|
|
#endif
|
|
{
|
|
CO = tgetnum("co");
|
|
LI = tgetnum("li");
|
|
if (!LI || !CO) /* if we don't override it */
|
|
get_scr_size();
|
|
}
|
|
#endif /* ?MICRO */
|
|
#ifdef CLIPPING
|
|
if (CO < COLNO || LI < ROWNO + 3)
|
|
setclipped();
|
|
#endif
|
|
nh_ND = Tgetstr("nd");
|
|
if (tgetflag("os"))
|
|
error("NetHack can't have OS.");
|
|
if (tgetflag("ul"))
|
|
ul_hack = TRUE;
|
|
CE = Tgetstr("ce");
|
|
UP = Tgetstr("up");
|
|
/* It seems that xd is no longer supported, and we should use
|
|
a linefeed instead; unfortunately this requires resetting
|
|
CRMOD, and many output routines will have to be modified
|
|
slightly. Let's leave that till the next release. */
|
|
XD = Tgetstr("xd");
|
|
/* not: XD = Tgetstr("do"); */
|
|
if (!(nh_CM = Tgetstr("cm"))) {
|
|
if (!UP && !HO)
|
|
error("NetHack needs CM or UP or HO.");
|
|
tty_raw_print("Playing NetHack on terminals without CM is suspect.");
|
|
tty_wait_synch();
|
|
}
|
|
SO = Tgetstr("so");
|
|
SE = Tgetstr("se");
|
|
nh_US = Tgetstr("us");
|
|
nh_UE = Tgetstr("ue");
|
|
SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */
|
|
if (!SO || !SE || (SG > 0))
|
|
SO = SE = nh_US = nh_UE = nullstr;
|
|
TI = Tgetstr("ti");
|
|
TE = Tgetstr("te");
|
|
VS = VE = nullstr;
|
|
#ifdef TERMINFO
|
|
VS = Tgetstr("eA"); /* enable graphics */
|
|
#endif
|
|
KS = Tgetstr("ks"); /* keypad start (special mode) */
|
|
KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */
|
|
MR = Tgetstr("mr"); /* reverse */
|
|
MB = Tgetstr("mb"); /* blink */
|
|
MD = Tgetstr("md"); /* boldface */
|
|
MH = Tgetstr("mh"); /* dim */
|
|
ME = Tgetstr("me"); /* turn off all attributes */
|
|
if (!ME)
|
|
ME = SE ? SE : nullstr; /* default to SE value */
|
|
|
|
/* Get rid of padding numbers for nh_HI and nh_HE. Hope they
|
|
* aren't really needed!!! nh_HI and nh_HE are outputted to the
|
|
* pager as a string - so how can you send it NULs???
|
|
* -jsb
|
|
*/
|
|
for (i = 0; digit(SO[i]); ++i)
|
|
continue;
|
|
nh_HI = dupstr(&SO[i]);
|
|
for (i = 0; digit(ME[i]); ++i)
|
|
continue;
|
|
nh_HE = dupstr(&ME[i]);
|
|
dynamic_HIHE = TRUE;
|
|
|
|
AS = Tgetstr("as");
|
|
AE = Tgetstr("ae");
|
|
nh_CD = Tgetstr("cd");
|
|
#ifdef TEXTCOLOR
|
|
#if defined(TOS) && defined(__GNUC__)
|
|
if (!strcmp(term, "builtin") || !strcmp(term, "tw52")
|
|
|| !strcmp(term, "st52")) {
|
|
init_hilite();
|
|
}
|
|
#else
|
|
init_hilite();
|
|
#endif
|
|
#endif
|
|
*wid = CO;
|
|
*hgt = LI;
|
|
if (!(CL = Tgetstr("cl"))) /* last thing set */
|
|
error("NetHack needs CL.");
|
|
if ((int) (tbufptr - tbuf) > (int) (sizeof tbuf))
|
|
error("TERMCAP entry too big...\n");
|
|
free((genericptr_t) tptr);
|
|
#endif /* TERMLIB */
|
|
}
|
|
|
|
/* note: at present, this routine is not part of the formal window interface
|
|
*/
|
|
/* deallocate resources prior to final termination */
|
|
void
|
|
tty_shutdown(void)
|
|
{
|
|
/* we only attempt to clean up a few individual termcap variables */
|
|
#if defined(TEXTCOLOR) && (defined(TERMLIB) || defined(ANSI_DEFAULT))
|
|
kill_hilite();
|
|
#endif
|
|
#ifdef TERMLIB
|
|
if (dynamic_HIHE) {
|
|
free((genericptr_t) nh_HI), nh_HI = (char *) 0;
|
|
free((genericptr_t) nh_HE), nh_HE = (char *) 0;
|
|
dynamic_HIHE = FALSE;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void
|
|
tty_number_pad(int state)
|
|
{
|
|
switch (state) {
|
|
case -1: /* activate keypad mode (escape sequences) */
|
|
if (KS && *KS)
|
|
xputs(KS);
|
|
break;
|
|
case 1: /* activate numeric mode for keypad (digits) */
|
|
if (KE && *KE)
|
|
xputs(KE);
|
|
break;
|
|
case 0: /* don't need to do anything--leave terminal as-is */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef TERMLIB
|
|
extern void (*decgraphics_mode_callback)(void); /* defined in symbols.c */
|
|
static void tty_decgraphics_termcap_fixup(void);
|
|
|
|
/*
|
|
We call this routine whenever DECgraphics mode is enabled, even if it
|
|
has been previously set, in case the user manages to reset the fonts.
|
|
The actual termcap fixup only needs to be done once, but we can't
|
|
call xputs() from the option setting or graphics assigning routines,
|
|
so this is a convenient hook.
|
|
*/
|
|
static void
|
|
tty_decgraphics_termcap_fixup(void)
|
|
{
|
|
static char ctrlN[] = "\016";
|
|
static char ctrlO[] = "\017";
|
|
static char appMode[] = "\033=";
|
|
static char numMode[] = "\033>";
|
|
|
|
/* these values are missing from some termcaps */
|
|
if (!AS)
|
|
AS = ctrlN; /* ^N (shift-out [graphics font]) */
|
|
if (!AE)
|
|
AE = ctrlO; /* ^O (shift-in [regular font]) */
|
|
if (!KS)
|
|
KS = appMode; /* ESC= (application keypad mode) */
|
|
if (!KE)
|
|
KE = numMode; /* ESC> (numeric keypad mode) */
|
|
/*
|
|
* Select the line-drawing character set as the alternate font.
|
|
* Do not select NA ASCII as the primary font since people may
|
|
* reasonably be using the UK character set.
|
|
*/
|
|
if (SYMHANDLING(H_DEC))
|
|
xputs("\033)0");
|
|
#ifdef PC9800
|
|
init_hilite();
|
|
#endif
|
|
|
|
#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
|
|
/* some termcaps suffer from the bizarre notion that resetting
|
|
video attributes should also reset the chosen character set */
|
|
{
|
|
const char *nh_he = nh_HE, *ae = AE;
|
|
int he_limit, ae_length;
|
|
|
|
if (digit(*ae)) { /* skip over delay prefix, if any */
|
|
do
|
|
++ae;
|
|
while (digit(*ae));
|
|
if (*ae == '.') {
|
|
++ae;
|
|
if (digit(*ae))
|
|
++ae;
|
|
}
|
|
if (*ae == '*')
|
|
++ae;
|
|
}
|
|
/* can't use nethack's case-insensitive strstri() here, and some old
|
|
systems don't have strstr(), so use brute force substring search */
|
|
ae_length = strlen(ae), he_limit = strlen(nh_he);
|
|
while (he_limit >= ae_length) {
|
|
if (strncmp(nh_he, ae, ae_length) == 0) {
|
|
HE_resets_AS = TRUE;
|
|
break;
|
|
}
|
|
++nh_he, --he_limit;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif /* TERMLIB */
|
|
|
|
#if defined(ASCIIGRAPH) && defined(PC9800)
|
|
extern void (*ibmgraphics_mode_callback)(void); /* defined in drawing.c */
|
|
#endif
|
|
|
|
#ifdef PC9800
|
|
extern void (*ascgraphics_mode_callback)(void); /* defined in drawing.c */
|
|
static void tty_ascgraphics_hilite_fixup(void);
|
|
|
|
static void
|
|
tty_ascgraphics_hilite_fixup(void)
|
|
{
|
|
register int c;
|
|
|
|
for (c = 0; c < CLR_MAX / 2; c++)
|
|
if (c != CLR_BLACK) {
|
|
hilites[c | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
|
|
Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c);
|
|
if (c != CLR_GRAY) {
|
|
hilites[c] = (char *) alloc(sizeof("\033[0;3%dm"));
|
|
Sprintf(hilites[c], "\033[0;3%dm", c);
|
|
}
|
|
}
|
|
}
|
|
#endif /* PC9800 */
|
|
|
|
void
|
|
tty_start_screen(void)
|
|
{
|
|
xputs(TI);
|
|
xputs(VS);
|
|
#ifdef PC9800
|
|
if (!SYMHANDLING(H_IBM))
|
|
tty_ascgraphics_hilite_fixup();
|
|
/* set up callback in case option is not set yet but toggled later */
|
|
ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup;
|
|
#ifdef ASCIIGRAPH
|
|
if (SYMHANDLING(H_IBM))
|
|
init_hilite();
|
|
/* set up callback in case option is not set yet but toggled later */
|
|
ibmgraphics_mode_callback = init_hilite;
|
|
#endif
|
|
#endif /* PC9800 */
|
|
|
|
#ifdef TERMLIB
|
|
if (SYMHANDLING(H_DEC))
|
|
tty_decgraphics_termcap_fixup();
|
|
/* set up callback in case option is not set yet but toggled later */
|
|
decgraphics_mode_callback = tty_decgraphics_termcap_fixup;
|
|
#endif
|
|
if (g.Cmd.num_pad)
|
|
tty_number_pad(1); /* make keypad send digits */
|
|
}
|
|
|
|
void
|
|
tty_end_screen(void)
|
|
{
|
|
clear_screen();
|
|
xputs(VE);
|
|
xputs(TE);
|
|
}
|
|
|
|
/* Cursor movements */
|
|
|
|
/* Note to overlay tinkerers. The placement of this overlay controls the
|
|
location of the function xputc(). This function is not currently in
|
|
trampoli.[ch] files for what is deemed to be performance reasons. If
|
|
this define is moved and or xputc() is taken out of the ROOT overlay,
|
|
then action must be taken in trampoli.[ch]. */
|
|
|
|
void
|
|
nocmov(int x, int y)
|
|
{
|
|
if ((int) ttyDisplay->cury > y) {
|
|
if (UP) {
|
|
while ((int) ttyDisplay->cury > y) { /* Go up. */
|
|
xputs(UP);
|
|
ttyDisplay->cury--;
|
|
}
|
|
} else if (nh_CM) {
|
|
cmov(x, y);
|
|
} else if (HO) {
|
|
home();
|
|
tty_curs(BASE_WINDOW, x + 1, y);
|
|
} /* else impossible("..."); */
|
|
} else if ((int) ttyDisplay->cury < y) {
|
|
if (XD) {
|
|
while ((int) ttyDisplay->cury < y) {
|
|
xputs(XD);
|
|
ttyDisplay->cury++;
|
|
}
|
|
} else if (nh_CM) {
|
|
cmov(x, y);
|
|
} else {
|
|
while ((int) ttyDisplay->cury < y) {
|
|
(void) xputc('\n');
|
|
ttyDisplay->curx = 0;
|
|
ttyDisplay->cury++;
|
|
}
|
|
}
|
|
}
|
|
if ((int) ttyDisplay->curx < x) { /* Go to the right. */
|
|
if (!nh_ND) {
|
|
cmov(x, y);
|
|
} else { /* bah */
|
|
/* should instead print what is there already */
|
|
while ((int) ttyDisplay->curx < x) {
|
|
xputs(nh_ND);
|
|
ttyDisplay->curx++;
|
|
}
|
|
}
|
|
} else if ((int) ttyDisplay->curx > x) {
|
|
while ((int) ttyDisplay->curx > x) { /* Go to the left. */
|
|
xputs(BC);
|
|
ttyDisplay->curx--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cmov(register int x, register int y)
|
|
{
|
|
xputs(tgoto(nh_CM, x, y));
|
|
ttyDisplay->cury = y;
|
|
ttyDisplay->curx = x;
|
|
}
|
|
|
|
/* See note above. xputc() is a special function for overlays. */
|
|
int
|
|
xputc(int c) /* actually char, but explicitly specify its widened type */
|
|
{
|
|
/*
|
|
* Note: xputc() as a direct all to putchar() doesn't make any
|
|
* sense _if_ putchar() is a function. But if it is a macro, an
|
|
* overlay configuration would want to avoid hidden code bloat
|
|
* from multiple putchar() expansions. And it gets passed as an
|
|
* argument to tputs() so we have to guarantee an actual function
|
|
* (while possibly lacking ANSI's (func) syntax to override macro).
|
|
*
|
|
* xputc() used to be declared as 'void xputc(c) char c; {}' but
|
|
* avoiding the proper type 'int' just to avoid (void) casts when
|
|
* ignoring the result can't have been sufficent reason to add it.
|
|
* It also had '#if apollo' conditional to have the arg be int.
|
|
* Matching putchar()'s declaration and using explicit casts where
|
|
* warranted is more robust, so we're just a jacket around that.
|
|
*/
|
|
return putchar(c);
|
|
}
|
|
|
|
void
|
|
xputs(const char *s)
|
|
{
|
|
#ifndef TERMLIB
|
|
(void) fputs(s, stdout);
|
|
#else
|
|
tputs(s, 1, xputc);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
cl_end(void)
|
|
{
|
|
if (CE) {
|
|
xputs(CE);
|
|
} else { /* no-CE fix - free after Harold Rynes */
|
|
register int cx = ttyDisplay->curx + 1;
|
|
|
|
/* this looks terrible, especially on a slow terminal
|
|
but is better than nothing */
|
|
while (cx < CO) {
|
|
(void) xputc(' ');
|
|
cx++;
|
|
}
|
|
tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
|
|
(int) ttyDisplay->cury);
|
|
}
|
|
}
|
|
|
|
void
|
|
clear_screen(void)
|
|
{
|
|
/* note: if CL is null, then termcap initialization failed,
|
|
so don't attempt screen-oriented I/O during final cleanup.
|
|
*/
|
|
if (CL) {
|
|
xputs(CL);
|
|
home();
|
|
}
|
|
}
|
|
|
|
void
|
|
home(void)
|
|
{
|
|
if (HO)
|
|
xputs(HO);
|
|
else if (nh_CM)
|
|
xputs(tgoto(nh_CM, 0, 0));
|
|
else
|
|
tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */
|
|
ttyDisplay->curx = ttyDisplay->cury = 0;
|
|
}
|
|
|
|
void
|
|
standoutbeg(void)
|
|
{
|
|
if (SO)
|
|
xputs(SO);
|
|
}
|
|
|
|
void
|
|
standoutend(void)
|
|
{
|
|
if (SE)
|
|
xputs(SE);
|
|
}
|
|
|
|
#if 0 /* if you need one of these, uncomment it (here and in extern.h) */
|
|
void
|
|
revbeg(void)
|
|
{
|
|
if (MR)
|
|
xputs(MR);
|
|
}
|
|
|
|
void
|
|
boldbeg(void)
|
|
{
|
|
if (MD)
|
|
xputs(MD);
|
|
}
|
|
|
|
void
|
|
blinkbeg(void)
|
|
{
|
|
if (MB)
|
|
xputs(MB);
|
|
}
|
|
|
|
void
|
|
dimbeg(void)
|
|
{
|
|
/* not in most termcap entries */
|
|
if (MH)
|
|
xputs(MH);
|
|
}
|
|
|
|
void
|
|
m_end(void)
|
|
{
|
|
if (ME)
|
|
xputs(ME);
|
|
}
|
|
#endif /*0*/
|
|
|
|
void
|
|
backsp(void)
|
|
{
|
|
xputs(BC);
|
|
}
|
|
|
|
void
|
|
tty_nhbell(void)
|
|
{
|
|
if (flags.silent)
|
|
return;
|
|
(void) putchar('\007'); /* curx does not change */
|
|
(void) fflush(stdout);
|
|
}
|
|
|
|
#ifdef ASCIIGRAPH
|
|
void
|
|
graph_on(void)
|
|
{
|
|
if (AS)
|
|
xputs(AS);
|
|
}
|
|
|
|
void
|
|
graph_off(void)
|
|
{
|
|
if (AE)
|
|
xputs(AE);
|
|
}
|
|
#endif
|
|
|
|
#if !defined(MICRO)
|
|
#ifdef VMS
|
|
static const short tmspc10[] = { /* from termcap */
|
|
0, 2000, 1333, 909, 743, 666, 333, 166, 83,
|
|
55, 50, 41, 27, 20, 13, 10, 5
|
|
};
|
|
#else
|
|
static const short tmspc10[] = { /* from termcap */
|
|
0, 2000, 1333, 909, 743, 666, 500, 333, 166,
|
|
83, 55, 41, 20, 10, 5
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
/* delay 50 ms */
|
|
void
|
|
tty_delay_output(void)
|
|
{
|
|
#if defined(MICRO)
|
|
register int i;
|
|
#endif
|
|
if (iflags.debug_fuzzer)
|
|
return;
|
|
#ifdef TIMED_DELAY
|
|
if (flags.nap) {
|
|
(void) fflush(stdout);
|
|
msleep(50); /* sleep for 50 milliseconds */
|
|
return;
|
|
}
|
|
#endif
|
|
#if defined(MICRO)
|
|
/* simulate the delay with "cursor here" */
|
|
for (i = 0; i < 3; i++) {
|
|
cmov(ttyDisplay->curx, ttyDisplay->cury);
|
|
(void) fflush(stdout);
|
|
}
|
|
#else /* MICRO */
|
|
/* BUG: if the padding character is visible, as it is on the 5620
|
|
then this looks terrible. */
|
|
if (flags.null) {
|
|
tputs(
|
|
#ifdef TERMINFO
|
|
"$<50>",
|
|
#else
|
|
"50",
|
|
#endif
|
|
1, xputc);
|
|
|
|
} else if (ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
|
|
/* delay by sending cm(here) an appropriate number of times */
|
|
register int cmlen =
|
|
(int) strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury));
|
|
register int i = 500 + tmspc10[ospeed] / 2;
|
|
|
|
while (i > 0) {
|
|
cmov((int) ttyDisplay->curx, (int) ttyDisplay->cury);
|
|
i -= cmlen * tmspc10[ospeed];
|
|
}
|
|
}
|
|
#endif /* MICRO */
|
|
}
|
|
|
|
/* must only be called with curx = 1 */
|
|
void
|
|
cl_eos(void) /* free after Robert Viduya */
|
|
{
|
|
if (nh_CD) {
|
|
xputs(nh_CD);
|
|
} else {
|
|
register int cy = ttyDisplay->cury + 1;
|
|
|
|
while (cy <= LI - 2) {
|
|
cl_end();
|
|
(void) xputc('\n');
|
|
cy++;
|
|
}
|
|
cl_end();
|
|
tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1,
|
|
(int) ttyDisplay->cury);
|
|
}
|
|
}
|
|
|
|
#if defined(TEXTCOLOR) && defined(TERMLIB)
|
|
#if defined(UNIX) && defined(TERMINFO)
|
|
/*
|
|
* Sets up color highlighting, using terminfo(4) escape sequences.
|
|
*
|
|
* Having never seen a terminfo system without curses, we assume this
|
|
* inclusion is safe. On systems with color terminfo, it should define
|
|
* the 8 COLOR_FOOs, and avoid us having to guess whether this particular
|
|
* terminfo uses BGR or RGB for its indexes.
|
|
*
|
|
* If we don't get the definitions, then guess. Original color terminfos
|
|
* used BGR for the original Sf (setf, Standard foreground) codes, but
|
|
* there was a near-total lack of user documentation, so some subsequent
|
|
* terminfos, such as early Linux ncurses and SCO UNIX, used RGB. Possibly
|
|
* as a result of the confusion, AF (setaf, ANSI Foreground) codes were
|
|
* introduced, but this caused yet more confusion. Later Linux ncurses
|
|
* have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4
|
|
* standard. We could switch the colors around when using Sf with ncurses,
|
|
* which would help things on later ncurses and hurt things on early ncurses.
|
|
* We'll try just preferring AF and hoping it always agrees with COLOR_FOO,
|
|
* and falling back to Sf if AF isn't defined.
|
|
*
|
|
* In any case, treat black specially so we don't try to display black
|
|
* characters on the assumed black background.
|
|
*/
|
|
|
|
/* `curses' is aptly named; various versions don't like these
|
|
macros used elsewhere within nethack; fortunately they're
|
|
not needed beyond this point, so we don't need to worry
|
|
about reconstructing them after the header file inclusion. */
|
|
#undef delay_output
|
|
#undef TRUE
|
|
#undef FALSE
|
|
#define m_move curses_m_move /* Some curses.h decl m_move(), not used here */
|
|
|
|
#include <curses.h>
|
|
|
|
#if !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL)
|
|
extern char *tparm();
|
|
#endif
|
|
|
|
#ifndef COLOR_BLACK /* trust include file */
|
|
#ifndef _M_UNIX /* guess BGR */
|
|
#define COLOR_BLACK 0
|
|
#define COLOR_BLUE 1
|
|
#define COLOR_GREEN 2
|
|
#define COLOR_CYAN 3
|
|
#define COLOR_RED 4
|
|
#define COLOR_MAGENTA 5
|
|
#define COLOR_YELLOW 6
|
|
#define COLOR_WHITE 7
|
|
#else /* guess RGB */
|
|
#define COLOR_BLACK 0
|
|
#define COLOR_RED 1
|
|
#define COLOR_GREEN 2
|
|
#define COLOR_YELLOW 3
|
|
#define COLOR_BLUE 4
|
|
#define COLOR_MAGENTA 5
|
|
#define COLOR_CYAN 6
|
|
#define COLOR_WHITE 7
|
|
#endif
|
|
#endif
|
|
|
|
/* Mapping data for the six terminfo colors that resolve to pairs of nethack
|
|
* colors. Black and white are handled specially.
|
|
*/
|
|
const struct {
|
|
int ti_color, nh_color, nh_bright_color;
|
|
} ti_map[6] = { { COLOR_RED, CLR_RED, CLR_ORANGE },
|
|
{ COLOR_GREEN, CLR_GREEN, CLR_BRIGHT_GREEN },
|
|
{ COLOR_YELLOW, CLR_BROWN, CLR_YELLOW },
|
|
{ COLOR_BLUE, CLR_BLUE, CLR_BRIGHT_BLUE },
|
|
{ COLOR_MAGENTA, CLR_MAGENTA, CLR_BRIGHT_MAGENTA },
|
|
{ COLOR_CYAN, CLR_CYAN, CLR_BRIGHT_CYAN } };
|
|
|
|
static char nilstring[] = "";
|
|
|
|
static void
|
|
init_hilite(void)
|
|
{
|
|
char *setf, *scratch;
|
|
int c, md_len;
|
|
int colors = tgetnum("Co");
|
|
|
|
if (colors < 8 || (MD == NULL) || (strlen(MD) == 0)
|
|
|| ((setf = tgetstr("AF", (char **) 0)) == (char *) 0
|
|
&& (setf = tgetstr("Sf", (char **) 0)) == (char *) 0)) {
|
|
/* Fallback when colors not available
|
|
* It's arbitrary to collapse all colors except gray
|
|
* together, but that's what the previous code did.
|
|
*/
|
|
hilites[CLR_BLACK] = nh_HI;
|
|
hilites[CLR_RED] = nh_HI;
|
|
hilites[CLR_GREEN] = nh_HI;
|
|
hilites[CLR_BROWN] = nh_HI;
|
|
hilites[CLR_BLUE] = nh_HI;
|
|
hilites[CLR_MAGENTA] = nh_HI;
|
|
hilites[CLR_CYAN] = nh_HI;
|
|
hilites[CLR_GRAY] = nilstring;
|
|
hilites[NO_COLOR] = nilstring;
|
|
hilites[CLR_ORANGE] = nh_HI;
|
|
hilites[CLR_BRIGHT_GREEN] = nh_HI;
|
|
hilites[CLR_YELLOW] = nh_HI;
|
|
hilites[CLR_BRIGHT_BLUE] = nh_HI;
|
|
hilites[CLR_BRIGHT_MAGENTA] = nh_HI;
|
|
hilites[CLR_BRIGHT_CYAN] = nh_HI;
|
|
hilites[CLR_WHITE] = nh_HI;
|
|
return;
|
|
}
|
|
|
|
if (colors >= 16) {
|
|
for (c = 0; c < SIZE(ti_map); c++) {
|
|
char *work;
|
|
|
|
/* system colors */
|
|
scratch = tparm(setf, ti_map[c].nh_color);
|
|
work = (char *) alloc(strlen(scratch) + 1);
|
|
Strcpy(work, scratch);
|
|
hilites[ti_map[c].nh_color] = work;
|
|
|
|
/* bright colors */
|
|
scratch = tparm(setf, ti_map[c].nh_bright_color);
|
|
work = (char *) alloc(strlen(scratch) + 1);
|
|
Strcpy(work, scratch);
|
|
hilites[ti_map[c].nh_bright_color] = work;
|
|
}
|
|
} else {
|
|
/* 8 system colors */
|
|
md_len = strlen(MD);
|
|
|
|
c = 6;
|
|
while (c--) {
|
|
char *work;
|
|
|
|
scratch = tparm(setf, ti_map[c].ti_color);
|
|
work = (char *) alloc(strlen(scratch) + md_len + 1);
|
|
Strcpy(work, MD);
|
|
hilites[ti_map[c].nh_bright_color] = work;
|
|
work += md_len;
|
|
Strcpy(work, scratch);
|
|
hilites[ti_map[c].nh_color] = work;
|
|
}
|
|
}
|
|
|
|
if (colors >= 16) {
|
|
scratch = tparm(setf, COLOR_WHITE|BRIGHT);
|
|
hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + 1);
|
|
Strcpy(hilites[CLR_WHITE], scratch);
|
|
} else {
|
|
scratch = tparm(setf, COLOR_WHITE);
|
|
hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1);
|
|
Strcpy(hilites[CLR_WHITE], MD);
|
|
Strcat(hilites[CLR_WHITE], scratch);
|
|
}
|
|
|
|
hilites[CLR_GRAY] = nilstring;
|
|
hilites[NO_COLOR] = nilstring;
|
|
|
|
if (iflags.wc2_darkgray) {
|
|
if (colors >= 16) {
|
|
scratch = tparm(setf, COLOR_BLACK|BRIGHT);
|
|
hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + 1);
|
|
Strcpy(hilites[CLR_BLACK], scratch);
|
|
} else {
|
|
/* On many terminals, esp. those using classic PC CGA/EGA/VGA
|
|
* textmode, specifying "hilight" and "black" simultaneously
|
|
* produces a dark shade of gray that is visible against a
|
|
* black background. We can use it to represent black objects.
|
|
*/
|
|
scratch = tparm(setf, COLOR_BLACK);
|
|
hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1);
|
|
Strcpy(hilites[CLR_BLACK], MD);
|
|
Strcat(hilites[CLR_BLACK], scratch);
|
|
}
|
|
} else {
|
|
/* But it's concievable that hilighted black-on-black could
|
|
* still be invisible on many others. We substitute blue for
|
|
* black.
|
|
*/
|
|
hilites[CLR_BLACK] = hilites[CLR_BLUE];
|
|
}
|
|
}
|
|
|
|
static void
|
|
kill_hilite(void)
|
|
{
|
|
int c;
|
|
|
|
/* if colors weren't available, no freeing needed */
|
|
if (hilites[CLR_BLACK] == nh_HI)
|
|
return;
|
|
|
|
if (hilites[CLR_BLACK]) {
|
|
if (hilites[CLR_BLACK] != hilites[CLR_BLUE])
|
|
free(hilites[CLR_BLACK]);
|
|
}
|
|
if (tgetnum("Co") >= 16) {
|
|
if (hilites[CLR_BLUE])
|
|
free(hilites[CLR_BLUE]);
|
|
if (hilites[CLR_GREEN])
|
|
free(hilites[CLR_GREEN]);
|
|
if (hilites[CLR_CYAN])
|
|
free(hilites[CLR_CYAN]);
|
|
if (hilites[CLR_MAGENTA])
|
|
free(hilites[CLR_MAGENTA]);
|
|
if (hilites[CLR_RED])
|
|
free(hilites[CLR_RED]);
|
|
if (hilites[CLR_BROWN])
|
|
free(hilites[CLR_BROWN]);
|
|
} else {
|
|
/* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */
|
|
/* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */
|
|
/* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */
|
|
/* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */
|
|
/* CLR_RED overlaps CLR_ORANGE, do not free */
|
|
/* CLR_BROWN overlaps CLR_YELLOW, do not free */
|
|
}
|
|
/* CLR_GRAY is static 'nilstring', do not free */
|
|
/* NO_COLOR is static 'nilstring', do not free */
|
|
if (hilites[CLR_BRIGHT_BLUE])
|
|
free(hilites[CLR_BRIGHT_BLUE]);
|
|
if (hilites[CLR_BRIGHT_GREEN])
|
|
free(hilites[CLR_BRIGHT_GREEN]);
|
|
if (hilites[CLR_BRIGHT_CYAN])
|
|
free(hilites[CLR_BRIGHT_CYAN]);
|
|
if (hilites[CLR_BRIGHT_MAGENTA])
|
|
free(hilites[CLR_BRIGHT_MAGENTA]);
|
|
if (hilites[CLR_ORANGE])
|
|
free(hilites[CLR_ORANGE]);
|
|
if (hilites[CLR_YELLOW])
|
|
free(hilites[CLR_YELLOW]);
|
|
if (hilites[CLR_WHITE])
|
|
free(hilites[CLR_WHITE]);
|
|
|
|
for (c = 0; c < CLR_MAX; c++)
|
|
hilites[c] = 0;
|
|
}
|
|
|
|
#else /* UNIX && TERMINFO */
|
|
|
|
#ifndef TOS
|
|
/* find the foreground and background colors set by nh_HI or nh_HE */
|
|
static void
|
|
analyze_seq(char *str, int *fg, int *bg)
|
|
{
|
|
register int c, code;
|
|
int len;
|
|
|
|
#ifdef MICRO
|
|
*fg = CLR_GRAY;
|
|
*bg = CLR_BLACK;
|
|
#else
|
|
*fg = *bg = NO_COLOR;
|
|
#endif
|
|
|
|
c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */
|
|
len = strlen(str) - 1; /* length excluding attrib suffix */
|
|
if ((c != 1 && (str[0] != '\033' || str[1] != '[')) || (len - c) < 1
|
|
|| str[len] != 'm')
|
|
return;
|
|
|
|
while (c < len) {
|
|
if ((code = atoi(&str[c])) == 0) { /* reset */
|
|
/* this also catches errors */
|
|
#ifdef MICRO
|
|
*fg = CLR_GRAY;
|
|
*bg = CLR_BLACK;
|
|
#else
|
|
*fg = *bg = NO_COLOR;
|
|
#endif
|
|
} else if (code == 1) { /* bold */
|
|
*fg |= BRIGHT;
|
|
#if 0
|
|
/* I doubt we'll ever resort to using blinking characters,
|
|
unless we want a pulsing glow for something. But, in case
|
|
we do... -3. */
|
|
} else if (code == 5) { /* blinking */
|
|
*fg |= BLINK;
|
|
} else if (code == 25) { /* stop blinking */
|
|
*fg &= ~BLINK;
|
|
#endif
|
|
} else if (code == 7 || code == 27) { /* reverse */
|
|
code = *fg & ~BRIGHT;
|
|
*fg = *bg | (*fg & BRIGHT);
|
|
*bg = code;
|
|
} else if (code >= 30 && code <= 37) { /* hi_foreground RGB */
|
|
*fg = code - 30;
|
|
} else if (code >= 40 && code <= 47) { /* hi_background RGB */
|
|
*bg = code - 40;
|
|
}
|
|
while (digit(str[++c]))
|
|
;
|
|
c++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Sets up highlighting sequences, using ANSI escape sequences (highlight code
|
|
* found in print.c). The nh_HI and nh_HE sequences (usually from SO) are
|
|
* scanned to find foreground and background colors.
|
|
*/
|
|
|
|
static void
|
|
init_hilite(void)
|
|
{
|
|
register int c;
|
|
#ifdef TOS
|
|
extern unsigned long tos_numcolors; /* in tos.c */
|
|
static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0";
|
|
|
|
if (tos_numcolors <= 2) {
|
|
return;
|
|
}
|
|
/* Under TOS, the "bright" and "dim" colors are reversed. Moreover,
|
|
* on the Falcon the dim colors are *really* dim; so we make most
|
|
* of the colors the bright versions, with a few exceptions where
|
|
* the dim ones look OK.
|
|
*/
|
|
hilites[0] = NOCOL;
|
|
for (c = 1; c < SIZE(hilites); c++) {
|
|
char *foo;
|
|
foo = (char *) alloc(sizeof("\033b0"));
|
|
if (tos_numcolors > 4)
|
|
Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0');
|
|
else
|
|
Strcpy(foo, "\033b0");
|
|
hilites[c] = foo;
|
|
}
|
|
|
|
if (tos_numcolors == 4) {
|
|
TI = nhStr("\033b0\033c3\033E\033e");
|
|
TE = nhStr("\033b3\033c0\033J");
|
|
nh_HE = COLHE;
|
|
hilites[CLR_GREEN] = hilites[CLR_GREEN | BRIGHT] = "\033b2";
|
|
hilites[CLR_RED] = hilites[CLR_RED | BRIGHT] = "\033b1";
|
|
} else {
|
|
Sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN ^ BRIGHT) + '0');
|
|
Sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN ^ BRIGHT) + '0');
|
|
|
|
TI = nhStr("\033b0\033c\017\033E\033e");
|
|
TE = nhStr("\033b\017\033c0\033J");
|
|
nh_HE = COLHE;
|
|
hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL;
|
|
hilites[NO_COLOR] = hilites[CLR_GRAY];
|
|
}
|
|
|
|
#else /* TOS */
|
|
|
|
int backg, foreg, hi_backg, hi_foreg;
|
|
|
|
for (c = 0; c < SIZE(hilites); c++)
|
|
hilites[c] = nh_HI;
|
|
hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *) 0;
|
|
|
|
analyze_seq(nh_HI, &hi_foreg, &hi_backg);
|
|
analyze_seq(nh_HE, &foreg, &backg);
|
|
|
|
for (c = 0; c < SIZE(hilites); c++)
|
|
/* avoid invisibility */
|
|
if ((backg & ~BRIGHT) != c) {
|
|
#ifdef MICRO
|
|
if (c == CLR_BLUE)
|
|
continue;
|
|
#endif
|
|
if (c == foreg)
|
|
hilites[c] = (char *) 0;
|
|
else if (c != hi_foreg || backg != hi_backg) {
|
|
hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm"));
|
|
Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT));
|
|
if ((c | BRIGHT) != (foreg | BRIGHT))
|
|
Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT);
|
|
if (backg != CLR_BLACK)
|
|
Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT);
|
|
Strcat(hilites[c], "m");
|
|
}
|
|
}
|
|
|
|
#ifdef MICRO
|
|
/* brighten low-visibility colors */
|
|
hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
|
|
#endif
|
|
#endif /* TOS */
|
|
}
|
|
|
|
static void
|
|
kill_hilite(void)
|
|
{
|
|
#ifndef TOS
|
|
register int c;
|
|
|
|
for (c = 0; c < CLR_MAX / 2; c++) {
|
|
if (hilites[c | BRIGHT] == hilites[c])
|
|
hilites[c | BRIGHT] = 0;
|
|
if (hilites[c] && hilites[c] != nh_HI)
|
|
free((genericptr_t) hilites[c]), hilites[c] = 0;
|
|
if (hilites[c | BRIGHT] && hilites[c | BRIGHT] != nh_HI)
|
|
free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
#endif /* UNIX && TERMINFO */
|
|
#endif /* TEXTCOLOR && TERMLIB */
|
|
|
|
#if defined(TEXTCOLOR) && !defined(TERMLIB) && defined(ANSI_DEFAULT)
|
|
static char adef_nilstring[] = "";
|
|
|
|
static void
|
|
init_hilite(void)
|
|
{
|
|
register int c;
|
|
|
|
if (!hilites[CLR_BLACK])
|
|
hilites[CLR_BLACK] = adef_nilstring;
|
|
if (!hilites[CLR_BLACK | BRIGHT])
|
|
hilites[CLR_BLACK | BRIGHT] = hilites[CLR_BLACK];
|
|
|
|
if (!hilites[CLR_GRAY])
|
|
hilites[CLR_GRAY] = adef_nilstring;
|
|
if (!hilites[NO_COLOR])
|
|
hilites[NO_COLOR] = hilites[CLR_GRAY];
|
|
|
|
for (c = 0; c < CLR_MAX / 2; c++) {
|
|
if (c == CLR_BLACK)
|
|
continue;
|
|
hilites[c | BRIGHT] = (char *) alloc(sizeof "\033[1;3%dm");
|
|
Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c);
|
|
if (c == CLR_GRAY)
|
|
continue;
|
|
#ifdef MICRO
|
|
if (c == CLR_BLUE) {
|
|
hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT];
|
|
} else
|
|
#endif
|
|
{
|
|
hilites[c] = (char *) alloc(sizeof "\033[0;3%dm");
|
|
Sprintf(hilites[c], "\033[0;3%dm", c);
|
|
}
|
|
}
|
|
|
|
/* See TEXTCOLOR && TERMLIB && UNIX && TERMINFO code above. */
|
|
if (iflags.wc2_darkgray) {
|
|
/* Bright black is dark gray. */
|
|
hilites[CLR_BLACK] = (char *) alloc(sizeof "\033[1;30m");
|
|
Sprintf(hilites[CLR_BLACK], "\033[1;30m");
|
|
} else {
|
|
/* Use blue for black. */
|
|
hilites[CLR_BLACK] = hilites[CLR_BLUE];
|
|
}
|
|
}
|
|
|
|
static void
|
|
kill_hilite(void)
|
|
{
|
|
register int c;
|
|
|
|
for (c = 0; c < CLR_MAX / 2; c++) {
|
|
if (c == CLR_GRAY || hilites[c] == adef_nilstring)
|
|
hilites[c] = 0;
|
|
if (hilites[c | BRIGHT] == adef_nilstring)
|
|
hilites[c] = 0;
|
|
if (c == CLR_BLACK)
|
|
continue;
|
|
if (hilites[c | BRIGHT] == hilites[c]) /* for blue */
|
|
hilites[c | BRIGHT] = 0;
|
|
if (hilites[c] && hilites[c] != nh_HI)
|
|
free((genericptr_t) hilites[c]), hilites[c] = 0;
|
|
if (hilites[c | BRIGHT] && hilites[c | BRIGHT] != nh_HI)
|
|
free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0;
|
|
}
|
|
|
|
if (hilites[CLR_BLACK]) {
|
|
if (hilites[CLR_BLACK] != hilites[CLR_BLUE])
|
|
free(hilites[CLR_BLACK]);
|
|
hilites[CLR_BLACK] = 0;
|
|
}
|
|
}
|
|
#endif /* TEXTCOLOR && !TERMLIB && ANSI_DEFAULT */
|
|
|
|
static char nulstr[] = "";
|
|
|
|
static char *
|
|
s_atr2str(int n)
|
|
{
|
|
switch (n) {
|
|
case ATR_BLINK:
|
|
case ATR_ULINE:
|
|
if (n == ATR_BLINK) {
|
|
if (MB && *MB)
|
|
return MB;
|
|
} else { /* Underline */
|
|
if (nh_US && *nh_US)
|
|
return nh_US;
|
|
}
|
|
/*FALLTHRU*/
|
|
case ATR_BOLD:
|
|
if (MD && *MD)
|
|
return MD;
|
|
if (nh_HI && *nh_HI)
|
|
return nh_HI;
|
|
break;
|
|
case ATR_INVERSE:
|
|
if (MR && *MR)
|
|
return MR;
|
|
break;
|
|
case ATR_DIM:
|
|
if (MH && *MH)
|
|
return MH;
|
|
break;
|
|
}
|
|
return nulstr;
|
|
}
|
|
|
|
static char *
|
|
e_atr2str(int n)
|
|
{
|
|
switch (n) {
|
|
case ATR_ULINE:
|
|
if (nh_UE && *nh_UE)
|
|
return nh_UE;
|
|
/*FALLTHRU*/
|
|
case ATR_BOLD:
|
|
case ATR_BLINK:
|
|
if (nh_HE && *nh_HE)
|
|
return nh_HE;
|
|
/*FALLTHRU*/
|
|
case ATR_DIM:
|
|
case ATR_INVERSE:
|
|
if (ME && *ME)
|
|
return ME;
|
|
break;
|
|
}
|
|
return nulstr;
|
|
}
|
|
|
|
/* suppress nonfunctional highlights so render_status() might be able to
|
|
optimize more; keep this in sync with s_atr2str() */
|
|
int
|
|
term_attr_fixup(int msk)
|
|
{
|
|
/* underline is converted to bold if its start sequence isn't available */
|
|
if ((msk & HL_ULINE) && (!nh_US || !*nh_US)) {
|
|
msk |= HL_BOLD;
|
|
msk &= ~HL_ULINE;
|
|
}
|
|
/* blink used to be converted to bold unconditionally; now depends on MB */
|
|
if ((msk & HL_BLINK) && (!MB || !*MB)) {
|
|
msk |= HL_BOLD;
|
|
msk &= ~HL_BLINK;
|
|
}
|
|
/* dim is ignored if its start sequence isn't available */
|
|
if ((msk & HL_DIM) && (!MH || !*MH)) {
|
|
msk &= ~HL_DIM;
|
|
}
|
|
return msk;
|
|
}
|
|
|
|
void
|
|
term_start_attr(int attr)
|
|
{
|
|
if (attr) {
|
|
const char *astr = s_atr2str(attr);
|
|
|
|
if (astr && *astr)
|
|
xputs(astr);
|
|
}
|
|
}
|
|
|
|
void
|
|
term_end_attr(int attr)
|
|
{
|
|
if (attr) {
|
|
const char *astr = e_atr2str(attr);
|
|
|
|
if (astr && *astr)
|
|
xputs(astr);
|
|
}
|
|
}
|
|
|
|
void
|
|
term_start_raw_bold(void)
|
|
{
|
|
xputs(nh_HI);
|
|
}
|
|
|
|
void
|
|
term_end_raw_bold(void)
|
|
{
|
|
xputs(nh_HE);
|
|
}
|
|
|
|
#ifdef TEXTCOLOR
|
|
|
|
void
|
|
term_end_color(void)
|
|
{
|
|
xputs(nh_HE);
|
|
}
|
|
|
|
void
|
|
term_start_color(int color)
|
|
{
|
|
if (color < CLR_MAX && hilites[color] && *hilites[color])
|
|
xputs(hilites[color]);
|
|
}
|
|
|
|
#endif /* TEXTCOLOR */
|
|
|
|
#endif /* TTY_GRAPHICS && !NO_TERMS */
|
|
|
|
/*termcap.c*/
|