/* This file contains the functions & variables needed for a tiny subset of
* curses. The principle advantage of this version of curses is its
* extreme speed. Disadvantages are potentially larger code, few supported
* functions, limited compatibility with full curses, and only stdscr.
# include <sys/stream.h> /* winsize struct defined in one of these? */
# undef TIOCGWINSZ /* we can't handle it correctly yet */
extern int VMS_read_raw
; /* Set in initscr() */
/* variables, publicly available & used in the macros */
char *termtype
; /* name of terminal entry */
short ospeed
; /* speed of the tty, eg B2400 */
char *BC
; /* backspace character string */
WINDOW
*stdscr
; /* pointer into kbuf[] */
WINDOW kbuf
[KBSIZ
]; /* a very large output buffer */
int LINES
; /* :li#: number of rows */
int COLS
; /* :co#: number of columns */
int AM
; /* :am: boolean: auto margins? */
int PT
; /* :pt: boolean: physical tabs? */
char *VB
; /* :vb=: visible bell */
char *UP
; /* :up=: move cursor up */
char *SO
= ""; /* :so=: standout start */
char *SE
= ""; /* :se=: standout end */
char *US
= ""; /* :us=: underline start */
char *UE
= ""; /* :ue=: underline end */
char *MD
= ""; /* :md=: bold start */
char *ME
= ""; /* :me=: bold end */
char *AS
= ""; /* :as=: alternate (italic) start */
char *AE
= ""; /* :ae=: alternate (italic) end */
char *MV
; /* :mv=: "visible" selection start */
char *CM
; /* :cm=: cursor movement */
char *CE
; /* :ce=: clear to end of line */
char *CD
; /* :cd=: clear to end of screen */
char *AL
; /* :al=: add a line */
char *DL
; /* :dl=: delete a line */
char *SR_
; /* :sr=: scroll reverse */
char *SR
; /* :sr=: scroll reverse */
char *KS
= ""; /* :ks=: switch keypad to application mode */
char *KE
= ""; /* :ke=: switch keypad to system mode */
char *KU
; /* :ku=: key sequence sent by up arrow */
char *KD
; /* :kd=: key sequence sent by down arrow */
char *KL
; /* :kl=: key sequence sent by left arrow */
char *KR
; /* :kr=: key sequence sent by right arrow */
char *HM
; /* :HM=: key sequence sent by the <Home> key */
char *EN
; /* :EN=: key sequence sent by the <End> key */
char *PU
; /* :PU=: key sequence sent by the <PgUp> key */
char *PD
; /* :PD=: key sequence sent by the <PgDn> key */
char *KI
; /* :kI=: key sequence sent by the <Insert> key */
char *FKEY
[NFKEYS
]; /* :k0=: ... :k9=: sequences sent by function keys */
char *IM
= ""; /* :im=: insert mode start */
char *IC
= ""; /* :ic=: insert the following character */
char *EI
= ""; /* :ei=: insert mode end */
char *DC
; /* :dc=: delete a character */
char *TI
= ""; /* :ti=: terminal init */ /* GB */
char *TE
= ""; /* :te=: terminal exit */ /* GB */
char *CQ
= (char *)0;/* :cQ=: normal cursor */
char *CX
= (char *)1;/* :cX=: cursor used for EX command/entry */
char *CV
= (char *)2;/* :cV=: cursor used for VI command mode */
char *CI
= (char *)3;/* :cI=: cursor used for VI input mode */
char *CR
= (char *)4;/* :cR=: cursor used for VI replace mode */
char *CQ
= ""; /* :cQ=: normal cursor */
char *CX
= ""; /* :cX=: cursor used for EX command/entry */
char *CV
= ""; /* :cV=: cursor used for VI command mode */
char *CI
= ""; /* :cI=: cursor used for VI input mode */
char *CR
= ""; /* :cR=: cursor used for VI replace mode */
char *aend
= ""; /* end an attribute -- either UE or ME */
char ERASEKEY
; /* backspace key taken from ioctl structure */
static struct termios oldtermio
; /* original tty mode */
static struct termios newtermio
; /* cbreak/noecho tty mode */
static struct termio oldtermio
; /* original tty mode */
static struct termio newtermio
; /* cbreak/noecho tty mode */
static struct sgttyb oldsgttyb
; /* original tty mode */
static struct sgttyb newsgttyb
; /* cbreak/nl/noecho tty mode */
static int oldint
; /* ^C or DEL, the "intr" character */
static int oldswitch
; /* ^Z, the "suspend" character */
static int olddswitch
; /* ^Y, the "delayed suspend" char */
static int oldquote
; /* ^V, the "quote next char" char */
static struct sgbuf oldsgttyb
; /* orginal tty mode */
static struct sgbuf newsgttyb
; /* noecho tty mode */
static char *capbuf
; /* capability string buffer */
/* Initialize the Curses package. */
/* make sure TERM variable is set */
termtype
= getenv("TERM");
/* VMS getenv() handles TERM as a environment setting. Foreign
* terminal support can be implemented by setting the ELVIS_TERM
* logical or symbol to match a tinytcap entry.
if (!strcmp(termtype
,"unknown"))
termtype
= getenv("ELVIS_TERM");
/* For MS-DOS, if TERM is unset we can default to "pcbios", or
if (*(unsigned char far
*)(0xffff000eL
) == 6 /* Rainbow 100a */
|| *(unsigned char far
*)(0xffff000eL
) == 148)/* Rainbow 100b */
if (!strcmp(termtype
, "pcbios"))
write(2, "Environment variable TERM must be set\n", (unsigned)38);
writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
write(2, "UNKNOWN terminal: define ELVIS_TERM\n", (unsigned)36);
/* start termcap stuff */
/* create stdscr and curscr */
/* change the terminal mode to cbreak/noecho */
tcgetattr(2, &oldtermio
);
ioctl(2, TCGETA
, &oldtermio
);
ioctl(2, TIOCGETP
, &oldsgttyb
);
VMS_read_raw
= 1; /* cbreak/noecho */
/* Shut down the Curses package. */
/* change the terminal mode back the way it was */
static int curses_active
= FALSE
;
/* Send any required termination strings. Turn off "raw" mode. */
#if ANY_UNIX && !(UNIXV || COH_386)
/* change the terminal mode back the way it was */
tcsetattr(2, TCSADRAIN
, &oldtermio
);
ioctl(2, TCSETAW
, &oldtermio
);
ioctl(2, TIOCSETP
, &oldsgttyb
);
ioctl(2, TIOCGETC
, (struct sgttyb
*) &tbuf
);
ioctl(2, TIOCSETC
, (struct sgttyb
*) &tbuf
);
ioctl(2, TIOCGLTC
, <buf
);
ltbuf
.t_suspc
= oldswitch
;
ltbuf
.t_dsuspc
= olddswitch
;
ltbuf
.t_lnextc
= oldquote
;
ioctl(2, TIOCSLTC
, <buf
);
/* put the terminal in RAW mode. If "quietly" is FALSE, then ask the user
* to hit a key, and wait for keystroke before returning.
void resume_curses(quietly
)
/* change the terminal mode to cbreak/noecho */
ospeed
= (oldtermio
.c_cflag
& CBAUD
);
ERASEKEY
= oldtermio
.c_cc
[VERASE
];
newtermio
.c_iflag
&= (IXON
|IXOFF
|IXANY
|ISTRIP
|IGNBRK
);
newtermio
.c_oflag
&= ~OPOST
;
newtermio
.c_lflag
&= ISIG
;
newtermio
.c_cc
[VINTR
] = ctrl('C'); /* always use ^C for interrupts */
newtermio
.c_cc
[VMIN
] = 1;
newtermio
.c_cc
[VTIME
] = 0;
newtermio
.c_cc
[VSWTCH
] = 0;
newtermio
.c_cc
[VSUSP
] = 0;
tcsetattr(2, TCSADRAIN
, &newtermio
);
ioctl(2, TCSETAW
, &newtermio
);
# else /* BSD, V7, Coherent-286, or Minix */
ospeed
= oldsgttyb
.sg_ospeed
;
ERASEKEY
= oldsgttyb
.sg_erase
;
newsgttyb
.sg_flags
|= CBREAK
;
newsgttyb
.sg_flags
&= ~(CRMOD
|ECHO
|XTABS
);
ioctl(2, TIOCSETP
, &newsgttyb
);
ioctl(2, TIOCGETC
, (struct sgttyb
*) &tbuf
);
tbuf
.t_intrc
= ctrl('C'); /* always use ^C for interrupts */
ioctl(2, TIOCSETC
, (struct sgttyb
*) &tbuf
);
ioctl(2, TIOCGLTC
, <buf
);
oldswitch
= ltbuf
.t_suspc
;
ltbuf
.t_suspc
= 0; /* disable ^Z for elvis */
olddswitch
= ltbuf
.t_dsuspc
;
ltbuf
.t_dsuspc
= 0; /* disable ^Y for elvis */
oldquote
= ltbuf
.t_lnextc
;
ltbuf
.t_lnextc
= 0; /* disable ^V for elvis */
ioctl(2, TIOCSLTC
, <buf
);
newsgttyb
.sg_kbich
= ctrl('C');
ospeed
= oldsgttyb
.sg_baud
;
ERASEKEY
= oldsgttyb
.sg_bspch
;
/* turn on window resize and RAW */
read(0,&c
,0); /* Flush the tty buffer. */
ERASEKEY
= '\177'; /* Accept <DEL> as <^H> for VMS */
/* If we're supposed to quit quietly, then we're done */
qaddstr("\n[Press <RETURN> to continue]");
qaddstr("[Press <RETURN> to continue]");
ttyread(kbuf
, 20, 0); /* in RAW mode, so <20 is very likely */
redraw(MARK_UNSET
, FALSE
);
/* This function fetches an optional string from termcap */
static void mayhave(T
, s
)
char **T
; /* where to store the returned pointer */
char *s
; /* name of the capability */
val
= tgetstr(s
, &capbuf
);
/* This function fetches a required string from termcap */
static void musthave(T
, s
)
char **T
; /* where to store the returned pointer */
char *s
; /* name of the capability */
write(2, "This termcap entry lacks the :", (unsigned)30);
write(2, s
, (unsigned)2);
write(2, "=: capability\n", (unsigned)14);
/* This function fetches a pair of strings from termcap. If one of them is
* missing, then the other one is ignored.
static void pair(T
, U
, sT
, sU
)
char **T
; /* where to store the first pointer */
char **U
; /* where to store the second pointer */
char *sT
; /* name of the first capability */
char *sU
; /* name of the second capability */
/* Read everything from termcap */
static void starttcap(term
)
/* allocate memory for capbuf */
/* get the termcap entry */
switch (tgetent(kbuf
, term
))
write(2, "Can't read /etc/termcap\n", (unsigned)24);
write(2, "Unrecognized TERM type\n", (unsigned)23);
pair(&SO
, &SE
, "so", "se");
pair(&US
, &UE
, "us", "ue");
pair(&MD
, &ME
, "md", "me");
/* get italics, or have it default to underline */
pair(&AS
, &AE
, "as", "ae");
MV
= SO
; /* by default */
pair(&IM
, &EI
, "im", "ei");
/* other termcap stuff */
AM
= (tgetflag("am") && !tgetflag("xn"));
amiopenwin(termtype
); /* Must run this before ttysetup(); */
ttysetup(); /* Must run this before getsize(0); */
pair(&KS
, &KE
, "ks", "ke"); /* keypad enable/disable */
mayhave(&KU
, "ku"); /* up */
mayhave(&KD
, "kd"); /* down */
mayhave(&KR
, "kr"); /* right */
mayhave(&KL
, "kl"); /* left */
if (KL
&& KL
[0]=='\b' && !KL
[1])
/* never use '\b' as a left arrow! */
mayhave(&PU
, "kP"); /* PgUp */
mayhave(&PD
, "kN"); /* PgDn */
mayhave(&HM
, "kh"); /* Home */
mayhave(&EN
, "kH"); /* End */
mayhave(&KI
, "kI"); /* Insert */
if (!PU
) mayhave(&PU
, "K2"); /* "3x3 pad" names for PgUp, etc. */
if (!PD
) mayhave(&PD
, "K5");
if (!HM
) mayhave(&HM
, "K1");
if (!EN
) mayhave(&EN
, "K4");
mayhave(&PU
, "PU"); /* old XENIX names for PgUp, etc. */
mayhave(&PD
, "PD"); /* (overrides others, if used.) */
mayhave(&FKEY
[0], "k0"); /* function key codes */
mayhave(&FKEY
[10], "s0"); /* shift function key codes */
mayhave(&FKEY
[11], "s1");
mayhave(&FKEY
[12], "s2");
mayhave(&FKEY
[13], "s3");
mayhave(&FKEY
[14], "s4");
mayhave(&FKEY
[15], "s5");
mayhave(&FKEY
[16], "s6");
mayhave(&FKEY
[17], "s7");
mayhave(&FKEY
[18], "s8");
mayhave(&FKEY
[19], "s9");
mayhave(&FKEY
[20], "c0"); /* control function key codes */
mayhave(&FKEY
[21], "c1");
mayhave(&FKEY
[22], "c2");
mayhave(&FKEY
[23], "c3");
mayhave(&FKEY
[24], "c4");
mayhave(&FKEY
[25], "c5");
mayhave(&FKEY
[26], "c6");
mayhave(&FKEY
[27], "c7");
mayhave(&FKEY
[28], "c8");
mayhave(&FKEY
[29], "c9");
mayhave(&FKEY
[30], "a0"); /* alt function key codes */
mayhave(&FKEY
[31], "a1");
mayhave(&FKEY
[32], "a2");
mayhave(&FKEY
[33], "a3");
mayhave(&FKEY
[34], "a4");
mayhave(&FKEY
[35], "a5");
mayhave(&FKEY
[36], "a6");
mayhave(&FKEY
[37], "a7");
mayhave(&FKEY
[38], "a8");
mayhave(&FKEY
[39], "a9");
CQ
= tgetstr("cQ", &capbuf
);
CX
= tgetstr("cX", &capbuf
);
CV
= tgetstr("cV", &capbuf
);
CI
= tgetstr("cI", &capbuf
);
CR
= tgetstr("cR", &capbuf
);
pair(&CQ
, &CV
, "ve", "vs");
#endif /* !NO_CURSORSHAPE */
strcpy(VISIBLEcolor
, MV
);
/* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
* your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
* This function is called once during initialization, and thereafter it is
* called whenever the SIGWINCH signal is sent to this process.
/* reset the signal vector */
signal(SIGWINCH
, (void *)getsize
);
/* get the window size, one way or another. */
if (ioctl(2, TIOCGWINSZ
, &size
) >= 0)
/* Amiga gets window size by asking the console.device */
if (!strcmp(TERMTYPE
, termtype
))
Write(Output(), "\2330 q", 4); /* Ask the console.device */
len
= Read(Input(), buf
, 29);
sscanf(&buf
[5], "%d;%d", &lines
, &cols
);
if ((lines
== 0 || cols
== 0) && signo
== 0)
if (!strcmp(termtype
, "rainbow"))
/* Determine whether Rainbow is in 80-column or 132-column mode */
cols
= *(unsigned char far
*)0xee000f57L
;
if (lines
>= 2 && cols
>= 30)
/* Make sure we got values that we can live with */
if (LINES
< 2 || COLS
< 30)
write(2, "Screen too small\n", (unsigned)17);
if (*o_lines
!= LINES
|| *o_columns
!= COLS
)
/* This is a function version of addch() -- it is used by tputs() */
/* This function quickly adds a string to the output queue. It does *NOT*
* convert \n into <CR><LF>.
for (s_
=(str
), d_
=stdscr
; *d_
++ = *s_
++; )
/* Output the ESC sequence needed to go into any video mode, if supported */
else if (a
== A_UNDERLINE
)
else if (a
== A_ALTCHARSET
)
/* Insert a single character into the display */
VOIDBIOS(;,ttywrite(kbuf
, (unsigned)(stdscr
- kbuf
)));
if (stdscr
- kbuf
> 2000)
ttywrite(kbuf
, (unsigned)(stdscr
- kbuf
));
/* This function is called during termination. It resets color modes */
/* if ANSI terminal & colors were set, then reset the colors */
if (!strcmp(UP
, "\033[A") && strcmp(SOcolor
, SO
))
tputs("\033[37;40m\033[m", 1, faddch
);
/* This sets the color strings that work for ANSI terminals. If the TERMCAP
* doesn't look like an ANSI terminal, then it returns FALSE. If the colors
* aren't understood, it also returns FALSE. If all goes well, it returns TRUE
int ansicolor(cmode
, attrbyte
)
int cmode
; /* mode to set, e.g. A_NORMAL */
int attrbyte
; /* IBM PC attribute byte */
char temp
[24]; /* hold the new mode string */
/* if not ANSI-ish, then fail */
if (strcmp(UP
, "\033[A") && strcmp(UP
, "\033OA"))
/* Only give an error message if we're editing a file.
* (I.e., if we're *NOT* currently doing a ".exrc")
msg("Don't know how to set colors for this terminal");
/* construct the color string */
#ifdef MWC /* either Coherent-286 ("COHERENT"), or Coherent-386 ("M_SYSV") */
sprintf(temp
, "\033[m\033[3%cm\033[4%cm%s%s",
"04261537"[attrbyte
& 0x07],
"04261537"[(attrbyte
>> 4) & 0x07],
(attrbyte
& 0x08) ? "\033[1m" : "",
(attrbyte
& 0x80) ? "\033[5m" : "");
sprintf(temp
, "\033[m\033[3%c;4%c%s%sm",
"04261537"[attrbyte
& 0x07],
"04261537"[(attrbyte
>> 4) & 0x07],
(attrbyte
& 0x08) ? ";1" : "",
(attrbyte
& 0x80) ? ";5" : "");
/* stick it in the right place */
if (!strcmp(MEcolor
, normalcolor
))
if (!strcmp(UEcolor
, normalcolor
))
if (!strcmp(AEcolor
, normalcolor
))
if (!strcmp(SEcolor
, normalcolor
))
strcpy(normalcolor
, temp
);
tputs(normalcolor
, 1, faddch
);
strcpy(MEcolor
, normalcolor
);
strcpy(UEcolor
, normalcolor
);
strcpy(AEcolor
, normalcolor
);
strcpy(SEcolor
, normalcolor
);
strcpy(POPUPcolor
, temp
);
strcpy(VISIBLEcolor
, temp
);
/* This function outputs the ESC sequence needed to switch the screen back
* to "normal" mode. On color terminals which haven't had their color set
* yet, this is one of the termcap strings; for color terminals that really
* have had colors defined, we just the "normal color" escape sequence.
tputs(MEcolor
, 1, faddch
);
tputs(UEcolor
, 1, faddch
);
tputs(AEcolor
, 1, faddch
);
tputs(SEcolor
, 1, faddch
);