build system. Anyone who wants to do a build from sys/unix and doesn't want to figure this out just needs to do: sh setup.sh hints/unix instead of: sh setup.sh and then continue on as usual. New files: sys/unix/NewInstall.unx - the new directions sys/unix/hints/* - the hints files. There will be more later. sys/unix/mkmkfile.sh - helper for setup.sh Summary of changes: see NewInstall.unx for info on the new build system introduction of various preprocessor symbols to turn options off that are defaulted on historically comment out nethackrc (and similar) entries that still use the old symbol syntax. commenting out of Makefile.* lines that now come from hints/unix GAMEDIR is replaced with HACKDIR so the Makefiles and the C source agree. Note that I have NOT changed the docs and/or Makefiles for be, msdos, os2, vms, or winnt. If port maintainers don't then I will, but I can't test those ports. nethack.sh now handles the font path automatically
1152 lines
26 KiB
C
1152 lines
26 KiB
C
/* SCCS Id: @(#)termcap.c 3.5 2007/12/12 */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* 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"
|
|
|
|
|
|
#ifdef MICROPORT_286_BUG
|
|
#define Tgetstr(key) (tgetstr(key,tbuf))
|
|
#else
|
|
#define Tgetstr(key) (tgetstr(key,&tbufptr))
|
|
#endif /* MICROPORT_286_BUG **/
|
|
|
|
static char * FDECL(s_atr2str, (int));
|
|
static char * FDECL(e_atr2str, (int));
|
|
|
|
void FDECL(cmov, (int, int));
|
|
void FDECL(nocmov, (int, int));
|
|
#if defined(TEXTCOLOR) && defined(TERMLIB)
|
|
# if !defined(UNIX) || !defined(TERMINFO)
|
|
# ifndef TOS
|
|
static void FDECL(analyze_seq, (char *, int *, int *));
|
|
# endif
|
|
# endif
|
|
static void NDECL(init_hilite);
|
|
static void NDECL(kill_hilite);
|
|
#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_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE;
|
|
STATIC_VAR char *VS, *VE;
|
|
STATIC_VAR char *ME;
|
|
STATIC_VAR char *MR;
|
|
#if 0
|
|
STATIC_VAR char *MB, *MH;
|
|
STATIC_VAR char *MD; /* may already be in use below */
|
|
#endif
|
|
|
|
#ifdef TERMLIB
|
|
# ifdef TEXTCOLOR
|
|
STATIC_VAR char *MD;
|
|
# endif
|
|
STATIC_VAR int SG;
|
|
STATIC_OVL char PC = '\0';
|
|
STATIC_VAR 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_VAR 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(wid, hgt)
|
|
int *wid, *hgt;
|
|
{
|
|
register int i;
|
|
#ifdef TERMLIB
|
|
register const char *term;
|
|
register char *tptr;
|
|
char *tbufptr, *pc;
|
|
|
|
# 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
|
|
#ifndef ANSI_DEFAULT
|
|
error("Can't get TERM.");
|
|
#else
|
|
# ifdef TOS
|
|
{
|
|
CO = 80; LI = 25;
|
|
TI = VS = VE = TE = nullstr;
|
|
HO = "\033H";
|
|
CE = "\033K"; /* the VT52 termcap */
|
|
UP = "\033A";
|
|
nh_CM = "\033Y%c%c"; /* used with function tgoto() */
|
|
nh_ND = "\033C";
|
|
XD = "\033B";
|
|
BC = "\033D";
|
|
SO = "\033p";
|
|
SE = "\033q";
|
|
/* HI and HE will be updated in init_hilite if we're using color */
|
|
nh_HI = "\033p";
|
|
nh_HE = "\033q";
|
|
*wid = CO;
|
|
*hgt = LI;
|
|
CL = "\033E"; /* last thing set */
|
|
return;
|
|
}
|
|
# else /* TOS */
|
|
{
|
|
# ifdef MICRO
|
|
get_scr_size();
|
|
# ifdef CLIPPING
|
|
if(CO < COLNO || LI < ROWNO+3)
|
|
setclipped();
|
|
# endif
|
|
# endif
|
|
HO = "\033[H";
|
|
/* nh_CD = "\033[J"; */
|
|
CE = "\033[K"; /* the ANSI termcap */
|
|
# ifndef TERMLIB
|
|
nh_CM = "\033[%d;%dH";
|
|
# else
|
|
nh_CM = "\033[%i%d;%dH";
|
|
# endif
|
|
UP = "\033[A";
|
|
nh_ND = "\033[C";
|
|
XD = "\033[B";
|
|
# ifdef MICRO /* backspaces are non-destructive */
|
|
BC = "\b";
|
|
# else
|
|
BC = "\033[D";
|
|
# endif
|
|
nh_HI = SO = "\033[1m";
|
|
nh_US = "\033[4m";
|
|
MR = "\033[7m";
|
|
TI = nh_HE = ME = SE = nh_UE = "\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 = "\016";
|
|
AE = "\017";
|
|
# endif
|
|
TE = VS = VE = nullstr;
|
|
# ifdef TEXTCOLOR
|
|
for (i = 0; i < CLR_MAX / 2; i++)
|
|
if (i != CLR_BLACK) {
|
|
hilites[i|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm"));
|
|
Sprintf(hilites[i|BRIGHT], "\033[1;3%dm", i);
|
|
if (i != CLR_GRAY)
|
|
# ifdef MICRO
|
|
if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT];
|
|
else
|
|
# endif
|
|
{
|
|
hilites[i] = (char *) alloc(sizeof("\033[0;3%dm"));
|
|
Sprintf(hilites[i], "\033[0;3%dm", i);
|
|
}
|
|
}
|
|
# endif
|
|
*wid = CO;
|
|
*hgt = LI;
|
|
CL = "\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();
|
|
# if defined(TOS) && defined(__GNUC__)
|
|
}
|
|
# endif
|
|
# endif
|
|
# 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 */
|
|
# if 0
|
|
MB = Tgetstr("mb"); /* blink */
|
|
MD = Tgetstr("md"); /* boldface */
|
|
MH = Tgetstr("mh"); /* dim */
|
|
# endif
|
|
ME = Tgetstr("me"); /* turn off all attributes */
|
|
if (!ME || (SE == nullstr)) ME = SE; /* 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
|
|
*/
|
|
nh_HI = (char *) alloc((unsigned)(strlen(SO)+1));
|
|
nh_HE = (char *) alloc((unsigned)(strlen(ME)+1));
|
|
i = 0;
|
|
while (digit(SO[i])) i++;
|
|
Strcpy(nh_HI, &SO[i]);
|
|
i = 0;
|
|
while (digit(ME[i])) i++;
|
|
Strcpy(nh_HE, &ME[i]);
|
|
AS = Tgetstr("as");
|
|
AE = Tgetstr("ae");
|
|
nh_CD = Tgetstr("cd");
|
|
# ifdef TEXTCOLOR
|
|
MD = Tgetstr("md");
|
|
# endif
|
|
# 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()
|
|
{
|
|
#if defined(TEXTCOLOR) && defined(TERMLIB)
|
|
kill_hilite();
|
|
#endif
|
|
/* we don't attempt to clean up individual termcap variables [yet?] */
|
|
return;
|
|
}
|
|
|
|
void
|
|
tty_number_pad(state)
|
|
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 NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */
|
|
static void NDECL(tty_decgraphics_termcap_fixup);
|
|
|
|
/*
|
|
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()
|
|
{
|
|
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 NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */
|
|
#endif
|
|
|
|
#ifdef PC9800
|
|
extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */
|
|
static void NDECL(tty_ascgraphics_hilite_fixup);
|
|
|
|
static void
|
|
tty_ascgraphics_hilite_fixup()
|
|
{
|
|
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()
|
|
{
|
|
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 (Cmd.num_pad) tty_number_pad(1); /* make keypad send digits */
|
|
}
|
|
|
|
void
|
|
tty_end_screen()
|
|
{
|
|
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(x, y)
|
|
int x,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) {
|
|
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(x, y)
|
|
register int x, y;
|
|
{
|
|
xputs(tgoto(nh_CM, x, y));
|
|
ttyDisplay->cury = y;
|
|
ttyDisplay->curx = x;
|
|
}
|
|
|
|
/* See note above. xputc() is a special function. */
|
|
void
|
|
xputc(c)
|
|
#if defined(apollo)
|
|
int c;
|
|
#else
|
|
char c;
|
|
#endif
|
|
{
|
|
(void) putchar(c);
|
|
}
|
|
|
|
void
|
|
xputs(s)
|
|
const char *s;
|
|
{
|
|
# ifndef TERMLIB
|
|
(void) fputs(s, stdout);
|
|
# else
|
|
# if defined(NHSTDC) || defined(ULTRIX_PROTO)
|
|
tputs(s, 1, (int (*)())xputc);
|
|
# else
|
|
tputs(s, 1, xputc);
|
|
# endif
|
|
# endif
|
|
}
|
|
|
|
void
|
|
cl_end()
|
|
{
|
|
if(CE)
|
|
xputs(CE);
|
|
else { /* no-CE fix - free after Harold Rynes */
|
|
/* this looks terrible, especially on a slow terminal
|
|
but is better than nothing */
|
|
register int cx = ttyDisplay->curx+1;
|
|
|
|
while(cx < CO) {
|
|
xputc(' ');
|
|
cx++;
|
|
}
|
|
tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
|
|
(int)ttyDisplay->cury);
|
|
}
|
|
}
|
|
|
|
void
|
|
clear_screen()
|
|
{
|
|
/* 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()
|
|
{
|
|
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()
|
|
{
|
|
if(SO) xputs(SO);
|
|
}
|
|
|
|
void
|
|
standoutend()
|
|
{
|
|
if(SE) xputs(SE);
|
|
}
|
|
|
|
#if 0 /* if you need one of these, uncomment it (here and in extern.h) */
|
|
void
|
|
revbeg()
|
|
{
|
|
if(MR) xputs(MR);
|
|
}
|
|
|
|
void
|
|
boldbeg()
|
|
{
|
|
if(MD) xputs(MD);
|
|
}
|
|
|
|
void
|
|
blinkbeg()
|
|
{
|
|
if(MB) xputs(MB);
|
|
}
|
|
|
|
void
|
|
dimbeg()
|
|
/* not in most termcap entries */
|
|
{
|
|
if(MH) xputs(MH);
|
|
}
|
|
|
|
void
|
|
m_end()
|
|
{
|
|
if(ME) xputs(ME);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
backsp()
|
|
{
|
|
xputs(BC);
|
|
}
|
|
|
|
void
|
|
tty_nhbell()
|
|
{
|
|
if (flags.silent) return;
|
|
(void) putchar('\007'); /* curx does not change */
|
|
(void) fflush(stdout);
|
|
}
|
|
|
|
#ifdef ASCIIGRAPH
|
|
void
|
|
graph_on() {
|
|
if (AS) xputs(AS);
|
|
}
|
|
|
|
void
|
|
graph_off() {
|
|
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()
|
|
{
|
|
#if defined(MICRO)
|
|
register int i;
|
|
#endif
|
|
#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)
|
|
# ifdef TERMINFO
|
|
/* cbosgd!cbcephus!pds for SYS V R2 */
|
|
# ifdef NHSTDC
|
|
tputs("$<50>", 1, (int (*)())xputc);
|
|
# else
|
|
tputs("$<50>", 1, xputc);
|
|
# endif
|
|
# else
|
|
# if defined(NHSTDC) || defined(ULTRIX_PROTO)
|
|
tputs("50", 1, (int (*)())xputc);
|
|
# else
|
|
tputs("50", 1, xputc);
|
|
# endif
|
|
# endif
|
|
|
|
else if(ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) {
|
|
/* delay by sending cm(here) an appropriate number of times */
|
|
register int cmlen = 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 */
|
|
}
|
|
|
|
void
|
|
cl_eos() /* free after Robert Viduya */
|
|
{ /* must only be called with curx = 1 */
|
|
|
|
if(nh_CD)
|
|
xputs(nh_CD);
|
|
else {
|
|
register int cy = ttyDisplay->cury+1;
|
|
while(cy <= LI-2) {
|
|
cl_end();
|
|
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
|
|
|
|
# ifdef COLOR_BLACK /* trust include file */
|
|
#undef COLOR_BLACK
|
|
# else
|
|
# ifndef _M_UNIX /* guess BGR */
|
|
#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_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
|
|
#define COLOR_BLACK COLOR_BLUE
|
|
|
|
const int ti_map[8] = {
|
|
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
|
|
COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
|
|
|
|
static void
|
|
init_hilite()
|
|
{
|
|
register int c;
|
|
char *setf, *scratch;
|
|
|
|
for (c = 0; c < SIZE(hilites); c++)
|
|
hilites[c] = nh_HI;
|
|
hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0;
|
|
|
|
if (tgetnum("Co") < 8
|
|
|| ((setf = tgetstr("AF", (char **)0)) == (char *)0
|
|
&& (setf = tgetstr("Sf", (char **)0)) == (char *)0))
|
|
return;
|
|
|
|
for (c = 0; c < CLR_MAX / 2; c++) {
|
|
scratch = tparm(setf, ti_map[c]);
|
|
if (c != CLR_GRAY) {
|
|
hilites[c] = (char *) alloc(strlen(scratch) + 1);
|
|
Strcpy(hilites[c], scratch);
|
|
}
|
|
if (c != CLR_BLACK) {
|
|
hilites[c|BRIGHT] = (char*) alloc(strlen(scratch)+strlen(MD)+1);
|
|
Strcpy(hilites[c|BRIGHT], MD);
|
|
Strcat(hilites[c|BRIGHT], scratch);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
# else /* UNIX && TERMINFO */
|
|
|
|
# ifndef TOS
|
|
/* find the foreground and background colors set by nh_HI or nh_HE */
|
|
static void
|
|
analyze_seq (str, fg, bg)
|
|
char *str;
|
|
int *fg, *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()
|
|
{
|
|
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 = "\033b0\033c3\033E\033e";
|
|
TE = "\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 = "\033b0\033c\017\033E\033e";
|
|
TE = "\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 */
|
|
}
|
|
# endif /* UNIX */
|
|
|
|
static void
|
|
kill_hilite()
|
|
{
|
|
# 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 /* TEXTCOLOR */
|
|
|
|
|
|
static char nulstr[] = "";
|
|
|
|
static char *
|
|
s_atr2str(n)
|
|
int n;
|
|
{
|
|
switch (n) {
|
|
case ATR_ULINE:
|
|
if(nh_US) return nh_US;
|
|
case ATR_BOLD:
|
|
case ATR_BLINK:
|
|
#if defined(TERMLIB) && defined(TEXTCOLOR)
|
|
if (MD) return MD;
|
|
#endif
|
|
return nh_HI;
|
|
case ATR_INVERSE:
|
|
return MR;
|
|
}
|
|
return nulstr;
|
|
}
|
|
|
|
static char *
|
|
e_atr2str(n)
|
|
int n;
|
|
{
|
|
switch (n) {
|
|
case ATR_ULINE:
|
|
if(nh_UE) return nh_UE;
|
|
case ATR_BOLD:
|
|
case ATR_BLINK:
|
|
return nh_HE;
|
|
case ATR_INVERSE:
|
|
return ME;
|
|
}
|
|
return nulstr;
|
|
}
|
|
|
|
|
|
void
|
|
term_start_attr(attr)
|
|
int attr;
|
|
{
|
|
if (attr) {
|
|
xputs(s_atr2str(attr));
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
term_end_attr(attr)
|
|
int attr;
|
|
{
|
|
if(attr) {
|
|
xputs(e_atr2str(attr));
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
term_start_raw_bold()
|
|
{
|
|
xputs(nh_HI);
|
|
}
|
|
|
|
|
|
void
|
|
term_end_raw_bold()
|
|
{
|
|
xputs(nh_HE);
|
|
}
|
|
|
|
|
|
#ifdef TEXTCOLOR
|
|
|
|
void
|
|
term_end_color()
|
|
{
|
|
xputs(nh_HE);
|
|
}
|
|
|
|
|
|
void
|
|
term_start_color(color)
|
|
int color;
|
|
{
|
|
xputs(hilites[color]);
|
|
}
|
|
|
|
|
|
int
|
|
has_color(color)
|
|
int color;
|
|
{
|
|
#ifdef X11_GRAPHICS
|
|
/* XXX has_color() should be added to windowprocs */
|
|
if (windowprocs.name != NULL &&
|
|
!strcmpi(windowprocs.name, "X11")) return TRUE;
|
|
#endif
|
|
#ifdef GEM_GRAPHICS
|
|
/* XXX has_color() should be added to windowprocs */
|
|
if (windowprocs.name != NULL &&
|
|
!strcmpi(windowprocs.name, "Gem")) return TRUE;
|
|
#endif
|
|
#ifdef QT_GRAPHICS
|
|
/* XXX has_color() should be added to windowprocs */
|
|
if (windowprocs.name != NULL &&
|
|
!strcmpi(windowprocs.name, "Qt")) return TRUE;
|
|
#endif
|
|
#ifdef AMII_GRAPHICS
|
|
/* hilites[] not used */
|
|
return iflags.use_color;
|
|
#endif
|
|
return hilites[color] != (char *)0;
|
|
}
|
|
|
|
#endif /* TEXTCOLOR */
|
|
|
|
#endif /* TTY_GRAPHICS */
|
|
|
|
/*termcap.c*/
|