/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ #include "jove.h" RCS("$Id: term.c,v 14.32.0.2 1993/07/14 23:40:12 tom Exp tom $") #include "io.h" #define Extern public /* to force definition of items in termcap.h. */ #include "termcap.h" DEF_STR( "term", TermName, 20, V_STRING|V_CONST ) ZERO; DEF_INT( "lines", LI, V_BASE10|V_CONST ); DEF_INT( "columns", CO, V_BASE10|V_CONST ); #ifdef TERMCAP #ifdef COLOR /* * The following non-standard termcap capabilities are used to implement * the color option of JOVE. * * "c0" - "c7" = set text color 0-7; (AIX scheme) * "d0" - "d7" = set background color 0-7; * or * "Sb", "Sf" = set background, text color #1; (SCO scheme) * "sp" = set color pair #1; * or, alternatively: * "Sc" = set color, takes 2 parameters (text color, background color); * * Color remap: * "Mb", "Mf" = background, text color map: * contains a series of offsets, separated by commas, to be indexed * by the color index before it is handed to "Sb", "Sf" or "Sc". * an empty offset implies the next higher integer. * * Default color: * "op" = original pair; set startup colors. (SCO scheme) * (if this exists it overrides exit-color). */ # include "screen.h" #endif #ifndef TINY # define MIN_TSPACE 512 #else # define MIN_TSPACE 256 #endif #if (TSPACE - 0) < MIN_TSPACE /* so we can set it from the Makefile */ # define TSPACE MIN_TSPACE /* at least this much */ #endif private char tspace[TSPACE]; #ifdef VARTERM /* * The following non-standard termcap capabilities are used to implement * the switchable screen size option of JOVE. * * "li" # standard screen height; "zl" = set term to `li' lines; * "LI" # alternate screen height; "zL" = set term to `LI' lines; * "co" # standard screen width; "zc" = set term to `co' columns; * "CO" # alternate screen width; "zC" = set term to `CO' columns; * * TODO: make it cooperate with arbitrary-sizeable terminal windows. */ /* indices for screen dimension array. */ # define NARROW 0 # define WIDE 1 # define INITIAL 2 # define WIDTH 0 # define HEIGHT 1 public short newdim[HEIGHT+1]; private short tdim[INITIAL+1][HEIGHT+1] ZERO; /* the dimensions */ private const char *TD[INITIAL+1][HEIGHT+1]; /* the switch commands */ private const char tdcap[HEIGHT+1][2] = { 'C','O', 'L','I' }; # define TC_VARTERM 'z','c', 'z','l', \ 'z','C', 'z','L', # define MEAS_VARTERM &TD[NARROW][WIDTH], &TD[NARROW][HEIGHT], \ &TD[WIDE][WIDTH], &TD[WIDE][HEIGHT], # define INIT_VARTERM() do { \ register int i = WIDE; \ do { \ tdim[i][WIDTH] = CO; \ tdim[i][HEIGHT] = LI; \ } while (--i >= 0); \ ttsize(); /* get ACTUAL size from the system */ \ tdim[INITIAL][WIDTH] = CO; \ tdim[INITIAL][HEIGHT] = LI; \ i = HEIGHT; \ do { \ register int n; \ if (TD[WIDE][i] && TD[NARROW][i] && \ (n = tgetnum(tdcap[i])) > 0) { \ if (n < tdim[NARROW][i]) { \ tdim[NARROW][i] = n; \ /* swap */ \ t = (char *) TD[WIDE][i]; \ TD[WIDE][i] = TD[NARROW][i]; \ TD[NARROW][i] = t; \ } \ else { \ tdim[WIDE][i] = n; \ } \ if (tdim[INITIAL][i] == tdim[NARROW][i])\ TD[INITIAL][i] = TD[NARROW][i]; \ else if (tdim[INITIAL][i] == tdim[WIDE][i])\ TD[INITIAL][i] = TD[WIDE][i]; \ /* else actual screen size differs from the sizes given in termcap. */ \ } \ /* Kludge to keep last size of window intact */ \ if (TD[INITIAL][i] == NULL) \ tdim[INITIAL][i] = 0; \ } while (--i >= 0); \ } while (0) /* change screen dimension `which' according to `how'. how < 0: NARROW, how > 0: WIDE; how == 0: Initial setup */ int set_tdim(how, which) register int how, which; { register int i = 0; if (how == 0) { if ((i = tdim[WIDE][HEIGHT] - tdim[NARROW][HEIGHT]) && (LI != (newdim[HEIGHT] = tdim[INITIAL][HEIGHT]))) putp(TD[INITIAL][HEIGHT]); which = WIDTH; how = INITIAL; } else if (how < 0) how = NARROW; else how = WIDE; if ((tdim[WIDE][which] != tdim[NARROW][which]) && (++i, (which == WIDTH ? CO : LI) != (newdim[which] = tdim[how][which]))) putp(TD[how][which]); return i; } DEF_CMD( "screen-wide", ScrDim, ARG(0) ); _IF(def VARTERM) DEF_CMD( "screen-narrow", ScrDim, ARG(0)|NEGATE ); _IF(def VARTERM) DEF_CMD( "screen-dense", ScrDim, ARG(1) ); _IF(def VARTERM) DEF_CMD( "screen-normal", ScrDim, ARG(1)|NEGATE ) _IF(def VARTERM) { if (!set_tdim(exp, ObjArg(LastCmd))) complain("[%f is not supported by terminal \"%s\"]", TermName); win_reshape(); } #else /* !VARTERM */ # define TC_VARTERM # define MEAS_VARTERM # define INIT_VARTERM() #endif /* VARTERM */ /* The ordering of `ts' and `meas' must agree !! */ private const char ts[] = { /* thank God (Jon?) for keyboard macros! */ 'b','c', 'b','l', 'c','e', 'c','l', 'c','m', 'k','e', 'k','s', 'm','m', 'm','o', 's','e', 's','o', 't','e', 't','i', 'v','b', 'v','e', 'v','i', 'v','s', #ifdef ANSICODES 's','p', #endif #ifdef CURSOPT 'h','o', 'l','l', #endif #ifndef FAST_IDLINE 'a','l', 'A','L', 'd','l', 'D','L', 's','f', 'S','F', 's','r', 'S','R', 'c','s', #endif #ifndef FAST_FLASH 'v','b', #endif #ifdef ID_CHAR 'i','c', 'I','C', 'd','c', 'D','C', 'i','m', 'e','i', 'i','p', #endif #ifdef LSRHS 'r','s', 'r','e', #endif #if (HIGHLIGHT) 'm','d', 'm','r', 'm','e', #endif #ifdef COLOR 'S','c', 'S','b', 'S','f', 's','p', 'M','b', 'M','f', 'o','p', #endif TC_VARTERM 'l','e', 'u','p', 'p','c', NIL }; private const char ** const meas[] = { &BC, &BL, &CE, &CL, &CM, &KE, &KS, &MM, &MO, &SE, &SO, &TE, &TI, &VB, &VE, &VI, &VS, #ifdef ANSICODES &SP, #endif #ifdef CURSOPT &HO, &LL, #endif #ifndef FAST_IDLINE &AL, &M_AL, &DL, &M_DL, &SF, &M_SF, &SR, &M_SR, &CS, #endif #ifndef FAST_FLASH &VB, #endif #ifdef ID_CHAR &IC, &M_IC, &DC, &M_DC, &IM, &EI, &IP, #endif #ifdef LSRHS &RS, &RE, #endif #if (HIGHLIGHT) &BO, &MR, &ME, #endif #ifdef COLOR &COlor, &CObg, &COfg, &COpair, &CObgmap, &COfgmap, &COorig, #endif MEAS_VARTERM &LE, &UP, &lPC }; /* Same trick for flags: The ordering of `tf' and `meaf' must agree !! */ private const char tf[] = { 'a','m', 'x','o', 'x','n', 'x','s', #ifdef DUMBTERMS 'u','l', 'h','z', #endif #ifdef ID_CHAR 'm','i', #endif NIL }; static int * const meaf[] = { &AM, &OKXonXoff, &XN, &XS, #ifdef DUMBTERMS &UL, &Hz, #endif #ifdef ID_CHAR &MI, #endif }; private void TermError __(( const char *_(mesg) )); private void TermError(mesg) const char *mesg; { printf("\rI cannot handle terminal \"%s\": %s.\n", TermName, mesg); flusho(); } private int etgetnum __(( const char *_(env), const char *_(cap) )); private int etgetnum(env, cap) const char *env, *cap; { register char *t; register int result; if ((t = getenv(env)) == NULL || (result = chr_to_int(t, 10, YES)) <= 0) if ((result = tgetnum(cap)) <= 0) TermError(env); return result; } public void getTERM() { register char *t; char *termp, tnamebuf[20], tbuff[2048]; /* Good grief! */ t = getenv("TERM"); while (TermName = t, tgetent(tbuff, t) < 1) { TermError("unknown type"); retry: putstr("Enter terminal name: "); flusho(); t = tnamebuf + 1; t[read(0, t, sizeof(tnamebuf)-1) - 1] = '\0'; if (!*t) _exit(0); /* do not be too persistent... */ } if ((CO = etgetnum("COLUMNS", "co")) <= 0 || (LI = etgetnum("LINES", "li")) <= 0) goto retry; if (CO > MAXCOLS) CO = MAXCOLS; if ((SG = tgetnum("sg")) < 0) SG = 0; /* Used for mode line only */ termp = tspace; /* Load string capabilities in one fell swoop. */ { register const char ** const *measp = meas; t = (char *) ts; do **measp++ = tgetstr(t, &termp); while (*(t += 2)); } /* Load flag capabilities in one fell swoop. */ { register int * const *meafp = meaf; t = (char *) tf; do **meafp++ = tgetflag(t); while (*(t += 2)); } #ifdef COLOR { /* * initialize color capabilities (according to AIX terminfo): * `c0'..`c7' foreground colors * `d0'..`d7' background colors */ extern char *Colors[2][NCOLORS]; if (!COlor && !COfg && !CObg && !COpair) { register char **col_p = &Colors[0][0]; char tinybuf[2]; t = tinybuf; t[0] = 'c', t[1] = '0'; do { *col_p++ = tgetstr(t, &termp); if (++t[1] == '0' + NCOLORS) { t[0]++; /* i.e. 'd' */ t[1] -= NCOLORS; /* i.e. '0' */ } } while (col_p < &Colors[2][0]); } } { /* * Set default color, if given in termcap (by `Cb#' and `Cf#', resp.) * else assume DEF_COLOR. */ register int bg_color, fg_color; if ((bg_color = tgetnum("Cb")) < 0) bg_color = BG_COLOR(DEF_COLOR); if ((fg_color = tgetnum("Cf")) < 0) fg_color = FG_COLOR(DEF_COLOR); if (fg_color == bg_color) if (bg_color == BG_COLOR(DEF_COLOR)) /* Cb undefined and Cf=BLACK implies Cb=WHITE */ bg_color ^= WHITE; else /* Cf undefined and Cb=WHITE implies Cf=BLACK. */ fg_color ^= WHITE; DefColor = MK_COLOR(fg_color, bg_color); } { /* Set color standout glitch. */ register int ncv_mask; if ((ncv_mask = tgetnum("NC")) >= 0) { /* (Now this is SCO black color-termcap magic:-) */ register int mask = 0; if (SO) mask = Bit(0); # if (HIGHLIGHT) if (ME) { if (MR) /* Reverse video replaces standout. */ mask = Bit(2); if (BO) mask |= Bit(5); } # endif if (ncv_mask & mask) { extern int ColorStandoutGlitch; ColorStandoutGlitch = YES; } } } # ifdef SCO_SYSV /* The following is valid only for SCO termcap, since JOVE assumes current background color erase as default: ``if (NOT back_color_erase AND any color defined)'' */ if (!tgetflag("be") && (tgetnum("Co") > 2 || tgetnum("pa") > 2)) { extern int ColorEraseGlitch; ColorEraseGlitch = YES; } # endif #endif /* COLOR */ INIT_VARTERM(); /* sanity check */ if (termp > &tspace[sizeof tspace]) { TermError("(recompile with larger tspace)"); _exit(1); /* this is serious! */ } #if 0 /* If your terminal really needs it, let it set BC properly! */ if (BC == NULL && (t = LE) && t[1] == '\0') BC = LE; #endif if (lPC) PC = *lPC; /* * handle XN glitch as if terminal were in no-automargin mode */ if (XN) AM = NO; #ifndef FAST_IDLINE /* * be sure not to use the scrolling region if we can't scroll. */ if (CS) if (SR == NULL) CS = SR = SF = NULL; else if (SF == NULL) SF = "\n"; #endif /* * [TRH] ignore cursor invisible if cursor visible not found, * and at lower baud rates */ if ((VS == NULL && (VS = VE) == NULL) || CharsPerSec < 480) VI = NULL; /* [TRH] use termcap to test presence of Meta key */ if (tgetflag("km")) MetaKey = ESC; OKXonXoff ^= 1; #ifndef DUMBTERMS if (CE == NULL) { TermError("(recompile with DUMBTERMS)"); goto retry; } #endif if (CL == NULL) { TermError("too dumb, sorry"); goto retry; } if (BL == NULL) /* set a reasonable default bell */ BL = "\7"; #ifdef LSRHS /* We, at the high school, are the only ones who do SO right in termcap, but unfortunately the right SO doesn't look as good with modelines. */ if (RS) SO = RS; if (RE) SE = RE; /* I only ever use SO for the modeline anyway. */ /* SO is really BOLDFACE! Why is LS always right and the rest of the world wrong? [sounds like Calimero to me...] */ #endif #if (HIGHLIGHT) /* Replace Standout with reverse video, if we have it. This is official termcap, unlike LSRHS above. */ if (MR && ME) SO = MR, SE = ME; #endif /* * [TRH] if we can't erase braindamaged standout, * just forget standout altogether */ if (XS && CE == NULL) #if (HIGHLIGHT) BO = ME = #endif SO = SE = NULL; #ifdef ID_CHAR if (IM && (*IM == '\0')) IM = NULL; disp_opt_init(); #endif #ifdef CURSOPT { register int it; /* Don't set phystab directly from "it", because it is missing from too many existing termcap entries; just assume the default. */ if ((it = tgetnum("it")) >= 0) phystab = it; } if (HO) HOlen = strlen(HO); if (LL) LLlen = strlen(LL); #endif if (UP) UPlen = strlen(UP); /* stow away termname to a safe place */ if ((t = TermName) == tnamebuf) TermName = copystr(t); #ifndef FAST_IDLINE if ((AL && DL) || CS) IDline_setup(t); #endif #ifdef FUNCKEYS FKeyInit(); #endif #ifdef COLOR COLOR_setup(t); #endif } #endif /* TERMCAP */ /* Deals with output to the terminal, setting up the amount of characters to be buffered depending on the output baud rate. */ #undef putch /* unhide the function */ void putch(c) { register File *f = stdout; putc(c, f); } #ifndef putpad /* could be #defined in termcap.h for systems that don't need padding. */ void putpad(str, lines) const char *str; { register const char *s; if (s = str) tputs(s, lines, (int (*)__((int))) putch); } #else # define tputs(s,l,f) putstr(s) #endif void putp(str) const char *str; { register const char *s; if (s = str) tputs(s, 1, (int (*)__((int))) putch); } /* * [TRH] output a capability num times, or alternatively output * its parameterized variant (with parameter num) */ #ifdef ID_CHAR /* this kludgery for dumb preprocessors (sigh) */ # undef FAST_IDLINE #endif #ifndef FAST_IDLINE /* !defined(FAST_IDLINE) || defined(ID_CHAR) */ void Nputpad(single, multi, num, n_affected) const char *single, *multi; register int num, n_affected; { if (multi && (num > 1)) putpad(tgoto(multi, 0, num), n_affected); else while (--num >= 0) putpad(single, n_affected); } #endif /* Determine the number of characters to buffer at each baud rate. The lower the number, the quicker the response when new input arrives. Of course the lower the number, the more prone the program is to stop in output. Decide what matters most to you. This initializes `stdout'. */ void settout(ttbuf) char *ttbuf; { #ifndef TERMCAP # define size (LI <= 25 ? TTBUFSIZ/2 : TTBUFSIZ) /* seems reasonable: about 1/5 of a screen */ #else static const int speeds[] = { /* /1 */ 960, /* /2 */ 720, /* /4 */ 360, /* /8 */ 240, /* /16 */ 180, /* /32 */ 120, /* /64 */ 60, /* /128 */ # if 0 30, /* /256 */ 20, /* /512 */ # endif -1 /* sentinel */ }; register const int *spp = speeds; register int size = TTBUFSIZ; while (CharsPerSec <= *spp++) size >>= 1; #endif stdout = fd_open(DevTty, F_WRITE|F_LOCKED|F_BINARY, 1, ttbuf, size); } #ifdef TGETSTR_BUG /* * Interactive 2.0.2 has an empty-headed implementation of * tgetstr() which advances the area pointer even when the * capability is not found, thus causing our keybuf to overflow * (sigh). */ char * tgetstr(cap, area) const char *cap; char **area; { register char *old_area = *area, *result; #undef tgetstr /* unmask "real" tgetstr */ if ((result = tgetstr(cap, area)) == NULL) *area = old_area; return result; } #endif /* TGETSTR_BUG */ /*====================================================================== * $Log: term.c,v $ * Revision 14.32.0.2 1993/07/14 23:40:12 tom * (getTERM): don't initialize `phystab' from "it" directly. * * Revision 14.32 1993/06/23 00:08:44 tom * COLOR: get op= (SCO default color), NC# (SCO) for ColorStandoutGlitch, * be (SCO only) for ColorEraseGlitch; * HIGHLIGHT: use mr= (reverse video) instead of so= if present. * * Revision 14.31 1993/02/13 23:20:18 tom * one random optimization. * * Revision 14.30 1993/01/27 01:33:22 tom * cleanup whitespace; parenthize || && expr to avoid compiler warnings. * * Revision 14.28 1992/10/02 15:38:58 tom * add color-remap support through (non-standard) termcapabilities Mb, Mf. * * Revision 14.27 1992/09/22 02:03:52 tom * some typecasts to suppress compiler warnings. * * Revision 14.26 1992/08/26 23:56:59 tom * add RCS directives. * */