This is ansi.c in view mode; [Download] [Up]
/* Copyright (c) 1991 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) * Copyright (c) 1987 Oliver Laumann * All rights reserved. Not derived from licensed software. * * Permission is granted to freely use, copy, modify, and redistribute * this software, provided that no attempt is made to gain profit from it, * the authors are not construed to be liable for any results of using the * software, alterations are clearly marked as such, and this notice is * not modified. * * Noteworthy contributors to screen's design and implementation: * Wayne Davison (davison@borland.com) * Patrick Wolfe (pat@kai.com, kailand!pat) * Bart Schaefer (schaefer@cse.ogi.edu) * Nathan Glasser (nathan@brokaw.lcs.mit.edu) * Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu) * Howard Chu (hyc@hanauma.jpl.nasa.gov) * Tim MacKenzie (tym@dibbler.cs.monash.edu.au) * Markku Jarvinen (mta@{cc,cs,ee}.tut.fi) * Marc Boucher (marc@CAM.ORG) * **************************************************************** */ #ifndef lint static char rcs_id[] = "$Id: ansi.c,v 1.2 92/02/03 02:27:30 jnweiger Exp $ FAU"; #endif #include <stdio.h> #include <sys/types.h> #ifdef BSDI #include <sys/signal.h> #endif /* BSDI */ #include <fcntl.h> #include "config.h" #include "screen.h" #include "ansi.h" #include "extern.h" #ifndef sun /* we want to know about TIOCGWINSZ. jw. */ # include <sys/ioctl.h> #endif extern char *getenv(), *tgetstr(), *tgoto(); #ifndef __STDC__ extern char *malloc(); #endif extern struct win *fore; extern int ForeNum; extern force_vt, assume_LP; extern int BellDisplayed; extern int MsgMinWait; extern int all_norefresh; int TermcapROWS, TermcapCOLS; /* defaults that we learned from termcap */ int default_width, default_height; /* width/height a new window will get */ int maxwidth; int Z0width, Z1width; /* widths for Z0/Z1 switching */ char display_tty[MAXPATH]; int screenwidth, screenheight; /* width/height of the screen */ int screentop, screenbot; /* scrollregion start/end */ int screenx, screeny; /* cursor position */ char GlobalAttr; /* current attributes */ char GlobalCharset; /* current font */ int insert; /* insert mode */ int keypad; /* application keypad */ int flow = 1; /* flow control */ int status; /* status is displayed */ static int status_lastx, status_lasty; static int rows, cols; /* window size of the curr window */ int default_flow = -1, wrap = 1, default_monitor = 0; int visual_bell = 0, termcapHS, use_hardstatus = 1; char *Termcap, *extra_incap, *extra_outcap; static int Termcaplen; char *blank, *null, *LastMsg; char Term[MAXSTR+5]; /* +5: "TERM=" */ char screenterm[20] = "screen"; char *Z0, *Z1; int ISO2022, HS; time_t TimeDisplayed, time(); /* * the termcap routines need this to work */ short ospeed; char *BC; char *UP; static void AddCap __P((char *)); static void MakeString __P((char *, char *, int, char *)); static int Special __P((int)); static void DoESC __P((int, int )); static void DoCSI __P((int, int )); static void CPutStr __P((char *, int)); static void SetChar __P(()); static void StartString __P((enum string_t)); static void AddChar __P((int )); static void PrintChar __P((int )); static void PrintFlush __P((void)); static void KeypadMode __P((int)); static void DesignateCharset __P((int, int )); static void MapCharset __P((int)); static void SaveCursor __P((void)); static void RestoreCursor __P((void)); static void CountChars __P((int)); static int CalcCost __P((char *)); static int Rewrite __P((int, int, int, int)); static void BackSpace __P((void)); static void Return __P((void)); static void LineFeed __P((int)); static void ReverseLineFeed __P((void)); static void InsertAChar __P((int)); static void InsertChar __P((int)); static void DeleteChar __P((int)); static void DeleteLine __P((int)); static void InsertLine __P((int)); static void ScrollUpMap __P((int)); static void ScrollDownMap __P((int)); static void Scroll __P((char *, int, int, char *)); static void ForwardTab __P((void)); static void BackwardTab __P((void)); static void ClearScreen __P((void)); static void ClearFromBOS __P((void)); static void ClearToEOS __P((void)); static void ClearLine __P((void)); static void ClearToEOL __P((void)); static void ClearFromBOL __P((void)); static void ClearInLine __P((int, int, int, int )); static void CursorRight __P(()); static void CursorUp __P(()); static void CursorDown __P(()); static void CursorLeft __P(()); static void ASetMode __P((int)); static void SelectRendition __P((void)); static void FillWithEs __P((void)); static void RedisplayLine __P((char *, char *, char *, int, int, int )); static void FindAKA __P((void)); static void SetCurr __P((struct win *)); static void inpRedisplayLine __P((int, int, int, int)); static void process_inp_input __P((char **, int *)); static void AbortInp __P((void)); static void AKAfin __P((char *, int)); static void Colonfin __P((char *, int)); static void RAW_PUTCHAR __P((int)); static char *e_tgetstr __P((char *, char **)); static int e_tgetflag __P((char *)); static int e_tgetnum __P((char *)); static char *tbuf, *tentry, *termname; static char *tp; static char *TI, *TE, *BL, *VB, *CR, *NL, *CL, *IS; char *WS; /* used in ResizeScreen() */ char *CE; /* used in help.c */ static char *CM, *US, *UE, *SO, *SE, *CD, *DO, *SR, *SF, *AL; static char *CS, *DL, *DC, *IC, *IM, *EI, *ND, *KS, *KE; static char *MB, *MD, *MH, *MR, *ME, *PO, *PF, *HO; static char *TS, *FS, *DS, *VI, *VE, *VS; static char *CDC, *CDL, *CAL, *CUP, *CDO, *CLE, *CRI, *CIC; static char *attrtab[NATTR]; static AM, MS, COP; int LP; /* * Do not confuse S0 (es-zero), E0 (e-zero) with SO (es-oh), PO (pe-oh), * Z0 (z-zero), DO (de-oh)... :-) */ static char *C0, *S0, *E0; static char c0_tab[256]; /* */ static screencap = 0; char *OldImage, *OldAttr, *OldFont; static struct win *curr; static display = 1; static StrCost; static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost, NLcost; static tcLineLen; static StatLen; static lp_missing = 0; int in_ovl; int ovl_blockfore; void (*ovl_process)(); void (*ovl_RedisplayLine)(); int (*ovl_Rewrite)(); static char *KeyCaps[] = { "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9", "kb", "kd", "kh", "kl", "ko", "kr", "ku", "K1", "K2", "K3", "K4", "K5", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "l8", "l9" }; #define NKEYCAPS ((int)(sizeof(KeyCaps)/sizeof(*KeyCaps))) static char *KeyCapsArr[NKEYCAPS]; static char TermcapConst[] = "\\\n\ \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\ \t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\ \t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\ \t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:xv:"; void InitTermcap() { register char *s; int i; screencap = 0; if ((s = getenv("SCREENCAP")) != 0) { if ((Termcap = malloc(strlen(s) + 10)) != 0) { sprintf(Termcap, "TERMCAP=%s", s); screencap = 1; } } else Termcap = malloc((unsigned) 1024); Termcaplen = 0; tbuf = malloc((unsigned) 1024); tentry = tp = malloc((unsigned) 1024); if (!(Termcap && tbuf && tentry)) Msg_nomem; bzero(tbuf, 1024); if ((termname = getenv("TERM")) == 0) Msg(0, "No TERM in environment."); debug1("InitTermcap: looking for tgetent('%s');\n", termname); if (tgetent(tbuf, termname) != 1) Msg(0, "Cannot find termcap entry for %s.", termname); debug1("got it:\n%s\n",tbuf); #ifdef DEBUG if (extra_incap) debug1("Extra incap: %s\n", extra_incap); if (extra_outcap) debug1("Extra outcap: %s\n", extra_outcap); #endif TermcapCOLS = TermcapROWS = 0; if (s = getenv("COLUMNS")) TermcapCOLS = atoi(s); if (TermcapCOLS <= 0) TermcapCOLS = e_tgetnum("co"); if (TermcapCOLS <= 0) TermcapCOLS = 80; if (s = getenv("LINES")) TermcapROWS = atoi(s); if (TermcapROWS <= 0) TermcapROWS = e_tgetnum("li"); if (TermcapROWS <= 0) TermcapROWS = 24; if (e_tgetflag("hc")) Msg(0, "You can't run screen on a hardcopy terminal."); if (e_tgetflag("os")) Msg(0, "You can't run screen on a terminal that overstrikes."); if (e_tgetflag("ns")) Msg(0, "Terminal must support scrolling."); if (!(CL = e_tgetstr("cl", &tp))) Msg(0, "Clear screen capability required."); if (!(CM = e_tgetstr("cm", &tp))) Msg(0, "Addressable cursor capability required."); if (default_flow < 0) default_flow = e_tgetflag("NF") ? FLOW_NOW * 0 : e_tgetflag("xo") ? FLOW_NOW * 1 : FLOW_AUTOFLAG; AM = e_tgetflag("am"); LP = assume_LP || (!extra_incap && !strncmp(termname, "vt", 2)) || !AM || e_tgetflag("LP") || e_tgetflag("xv"); COP = e_tgetflag("OP"); HO = e_tgetstr("ho", &tp); TI = e_tgetstr("ti", &tp); TE = e_tgetstr("te", &tp); if (!(BL = e_tgetstr("bl", &tp))) BL = "\007"; VB = e_tgetstr("vb", &tp); if (!(BC = e_tgetstr("bc", &tp))) { if (e_tgetflag("bs")) BC = "\b"; else BC = e_tgetstr("le", &tp); } if (!(CR = e_tgetstr("cr", &tp))) CR = "\r"; if (!(NL = e_tgetstr("nl", &tp))) NL = "\n"; IS = e_tgetstr("is", &tp); MS = 1; if (e_tgetnum("sg") <= 0 && e_tgetnum("ug") <= 0) { MS = e_tgetflag("ms"); attrtab[ATTR_DI] = MH = e_tgetstr("mh", &tp); /* Dim */ attrtab[ATTR_US] = US = e_tgetstr("us", &tp); /* Underline */ attrtab[ATTR_BD] = MD = e_tgetstr("md", &tp); /* Bold */ attrtab[ATTR_RV] = MR = e_tgetstr("mr", &tp); /* Reverse */ attrtab[ATTR_SO] = SO = e_tgetstr("so", &tp); /* Standout */ attrtab[ATTR_BL] = MB = e_tgetstr("mb", &tp); /* Blinking */ ME = e_tgetstr("me", &tp); SE = e_tgetstr("se", &tp); UE = e_tgetstr("ue", &tp); /* * Does ME also reverse the effect of SO and/or US? This is not * clearly specified by the termcap manual. Anyway, we should at * least look whether ME and SE/UE are equal: */ if (UE && ((SE && strcmp(SE, UE) == 0) || (ME && strcmp(ME, UE) == 0))) UE = 0; if (SE && (ME && strcmp(ME, SE) == 0)) SE = 0; /* Set up missing entries */ s = 0; for (i = NATTR-1; i >= 0; i--) if (attrtab[i]) s = attrtab[i]; for (i = 0; i < NATTR; i++) { if (attrtab[i] == 0) attrtab[i] = s; else s = attrtab[i]; } } else { US = UE = SO = SE = MB = MD = MH = MR = ME = 0; for (i = 0; i < NATTR; i++) attrtab[i] = 0; } CE = e_tgetstr("ce", &tp); CD = e_tgetstr("cd", &tp); if (!(DO = e_tgetstr("do", &tp))) DO = NL; UP = e_tgetstr("up", &tp); ND = e_tgetstr("nd", &tp); SR = e_tgetstr("sr", &tp); if (!(SF = e_tgetstr("sf", &tp))) SF = NL; AL = e_tgetstr("al", &tp); DL = e_tgetstr("dl", &tp); CS = e_tgetstr("cs", &tp); DC = e_tgetstr("dc", &tp); IC = e_tgetstr("ic", &tp); CIC = e_tgetstr("IC", &tp); CDC = e_tgetstr("DC", &tp); CDL = e_tgetstr("DL", &tp); CAL = e_tgetstr("AL", &tp); CUP = e_tgetstr("UP", &tp); CDO = e_tgetstr("DO", &tp); CLE = e_tgetstr("LE", &tp); CRI = e_tgetstr("RI", &tp); IM = e_tgetstr("im", &tp); EI = e_tgetstr("ei", &tp); if (e_tgetflag("in")) IC = IM = 0; if (IC && IC[0] == '\0') IC = 0; if (CIC && CIC[0] == '\0') CIC = 0; if (IM && IM[0] == '\0') IM = 0; if (EI && EI[0] == '\0') EI = 0; if (EI == 0) IM = 0; if (IC && IM && strcmp(IC, IM) == 0) IC = 0; KS = e_tgetstr("ks", &tp); KE = e_tgetstr("ke", &tp); if (KE == 0) KS = 0; ISO2022 = e_tgetflag("G0"); if (ISO2022) { if ((S0 = e_tgetstr("S0", &tp)) == NULL) #ifdef TERMINFO S0 = "\033(%p1%c"; #else S0 = "\033(%."; #endif if ((E0 = e_tgetstr("E0", &tp)) == NULL) E0 = "\033(B"; C0 = e_tgetstr("C0", &tp); } else if ((S0 = e_tgetstr("as", &tp)) != NULL && (E0 = e_tgetstr("ae", &tp)) != NULL) { ISO2022 = 1; C0 = e_tgetstr("ac", &tp); } else { S0 = E0 = ""; C0 = "g.h.i'j-k-l-m-n+o~p\"q-r-s_t+u+v+w+x|y<z>"; } for (i = 0; i < 256; i++) c0_tab[i] = i; if (C0) for (i = strlen(C0)&~1; i >= 0; i-=2) c0_tab[C0[i]] = C0[i+1]; debug1("ISO2022 = %d\n", ISO2022); /* WS changes the window size */ WS = e_tgetstr("WS", &tp); VI = e_tgetstr("vi", &tp); VE = e_tgetstr("ve", &tp); VS = e_tgetstr("vs", &tp); PO = e_tgetstr("po", &tp); if (!(PF = e_tgetstr("pf", &tp))) PO = 0; debug2("terminal size is %d, %d (says TERMCAP)\n", TermcapCOLS, TermcapROWS); /* Termcap fields Z0 & Z1 contain width-changing sequences. */ if ((Z0 = e_tgetstr("Z0", &tp)) != NULL && (Z1 = e_tgetstr("Z1", &tp)) == NULL) Z0 = NULL; Z0width = 132; Z1width = 80; CheckScreenSize(0); if ((HS = e_tgetflag("hs")) != 0) { debug("oy! we have a hardware status line, says termcap\n"); TS = e_tgetstr("ts", &tp); FS = e_tgetstr("fs", &tp); DS = e_tgetstr("ds", &tp); if ((HS = e_tgetnum("ws")) <= 0) HS = screenwidth; if (!TS || !FS || !DS) HS = 0; } termcapHS = HS; if (!use_hardstatus) HS = 0; UPcost = CalcCost(UP); DOcost = CalcCost(DO); NLcost = CalcCost(NL); LEcost = CalcCost(BC); NDcost = CalcCost(ND); CRcost = CalcCost(CR); IMcost = CalcCost(IM); EIcost = CalcCost(EI); for (i = 0; i < NKEYCAPS; i++) KeyCapsArr[i] = e_tgetstr(KeyCaps[i], &tp); MakeTermcap(0); } /* * if the adaptflag is on, we keep the size of this display, else * we may try to restore our old window sizes. */ void InitTerm(adapt) int adapt; { display = 1; screentop = screenbot = -1; PutStr(IS); PutStr(TI); if (IM && strcmp(IM, EI)) PutStr(EI); insert = 0; if (KS && strcmp(KS, KE)) PutStr(KE); keypad = 0; PutStr(E0); GlobalCharset = ASCII; ResizeScreen((struct win *)0); ChangeScrollRegion(0, screenheight-1); PutStr(CL); screenx = screeny = 0; fflush(stdout); debug1("we %swant to adapt all our windows to the display\n", (adapt) ? "" : "don't "); /* In case the size was changed by a init sequence */ CheckScreenSize((adapt) ? 2 : 0); } void FinitTerm() { display = 1; InsertMode(0); KeypadMode(0); ResizeScreen((struct win *)0); ChangeScrollRegion(0, screenheight - 1); SaveSetAttr(0, ASCII); screenx = screeny = -1; GotoPos(0, screenheight - 1); PutStr(TE); fflush(stdout); if (Termcap) { Free(Termcap); debug("FinitTerm: old termcap freed\n"); } if (tbuf) { Free(tbuf); debug("FinitTerm: old tbuf freed\n"); } if (tentry) { Free(tentry); debug("FinitTerm: old tentry freed\n"); } } static void AddCap(s) char *s; { register int n; if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < 1024-4) { strcpy(Termcap + Termcaplen, "\\\n\t:"); Termcaplen += 4; tcLineLen = 0; } if (Termcaplen + n < 1024) { strcpy(Termcap + Termcaplen, s); Termcaplen += n; tcLineLen += n; } else Msg(0, "TERMCAP overflow - sorry."); } char *MakeTermcap(aflag) int aflag; { char buf[1024]; register char *p, *cp, ch; int i; if (screencap) { sprintf(Term, "TERM=screen"); return Termcap; } if (screenterm == 0 || *screenterm == '\0') { debug("MakeTermcap sets screenterm=screen\n"); strcpy(screenterm, "screen"); } for (;;) { sprintf(Term, "TERM="); p = Term + 5; if (!aflag && strlen(screenterm) + strlen(termname) < MAXSTR-1) { sprintf(p, "%s.%s", screenterm, termname); if (tgetent(buf, p) == 1) break; } if (screenwidth >= 132) { sprintf(p, "%s-w", screenterm); if (tgetent(buf, p) == 1) break; } sprintf(p, "%s", screenterm); if (tgetent(buf, p) == 1) break; sprintf(p, "vt100"); break; } tcLineLen = 100; /* Force NL */ sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal|", p); Termcaplen = strlen(Termcap); if (extra_outcap && *extra_outcap) { for (cp = extra_outcap; p = index(cp, ':'); cp = p) { ch = *++p; *p = '\0'; AddCap(cp); *p = ch; } tcLineLen = 100; /* Force NL */ } if (Termcaplen + strlen(TermcapConst) < 1024) { strcpy(Termcap + Termcaplen, TermcapConst); Termcaplen += strlen(TermcapConst); } sprintf(buf, "li#%d:co#%d:", screenheight, screenwidth); AddCap(buf); if ((force_vt && !COP) || LP || !AM) AddCap("LP:"); else AddCap("am:"); if (VB) AddCap("vb=\\E[?5h\\E[?5l:"); if (US) { AddCap("us=\\E[4m:"); AddCap("ue=\\E[24m:"); } if (SO) { AddCap("so=\\E[3m:"); AddCap("se=\\E[23m:"); } if (MB) AddCap("mb=\\E[5m:"); if (MD) AddCap("md=\\E[1m:"); if (MH) AddCap("mh=\\E[2m:"); if (MR) AddCap("mr=\\E[7m:"); if (MB || MD || MH || MR) AddCap("me=\\E[m:ms:"); if ((CS && SR) || AL || CAL || aflag) { AddCap("sr=\\EM:"); AddCap("al=\\E[L:"); AddCap("AL=\\E[%dL:"); } else if (SR) AddCap("sr=\\EM:"); if (CS || DL || CDL || aflag) { AddCap("dl=\\E[M:"); AddCap("DL=\\E[%dM:"); } if (CS) AddCap("cs=\\E[%i%d;%dr:"); if (DC || CDC || aflag) { AddCap("dc=\\E[P:"); AddCap("DC=\\E[%dP:"); } if (CIC || IC || IM || aflag) { AddCap("im=\\E[4h:"); AddCap("ei=\\E[4l:"); AddCap("mi:"); AddCap("ic=\\E[@:"); AddCap("IC=\\E[%d@:"); } if (KS) AddCap("ks=\\E=:"); if (KE) AddCap("ke=\\E>:"); if (ISO2022) AddCap("G0:"); if (PO) { AddCap("po=\\E[5i:"); AddCap("pf=\\E[4i:"); } if (Z0) { AddCap("Z0=\\E[?3h:"); AddCap("Z1=\\E[?3l:"); } if (WS) AddCap("WS=\\E[8;%d;%dt:"); for (i = 0; i < NKEYCAPS; i++) { if (KeyCapsArr[i] == 0) continue; MakeString(KeyCaps[i], buf, sizeof(buf), KeyCapsArr[i]); AddCap(buf); } return Termcap; } static void MakeString(cap, buf, buflen, s) char *cap, *buf; int buflen; char *s; { register char *p, *pmax; register unsigned int c; p = buf; pmax = p + buflen - (3+4+2); *p++ = *cap++; *p++ = *cap; *p++ = '='; while ((c = *s++) && (p < pmax)) { switch (c) { case '\033': *p++ = '\\'; *p++ = 'E'; break; case ':': sprintf(p, "\\072"); p += 4; break; case '^': case '\\': *p++ = '\\'; *p++ = c; break; default: if (c >= 200) { sprintf(p, "\\%03o", c & 0377); p += 4; } else if (c < ' ') { *p++ = '^'; *p++ = c + '@'; } else *p++ = c; } } *p++ = ':'; *p = '\0'; } void Activate(norefresh) int norefresh; { debug1("Activate(%d)\n", norefresh); if (display) RemoveStatus(); display = fore->active = 1; ResizeScreen(fore); SetCurr(fore); debug3("Fore (%d) has size %dx%d", ForeNum, curr->width, curr->height); debug1("(%d)\n", curr->histheight); ChangeScrollRegion(curr->top, curr->bot); KeypadMode(curr->keypad); SetFlow(curr->flow & FLOW_NOW); if (curr->monitor != MON_OFF) curr->monitor = MON_ON; curr->bell = BELL_OFF; Redisplay(norefresh || all_norefresh); } void ResetScreen(p) register struct win *p; { register int i; p->wrap = wrap; p->origin = 0; p->insert = 0; p->vbwait = 0; p->keypad = 0; p->top = 0; p->bot = p->height - 1; p->saved = 0; p->LocalAttr = 0; p->x = p->y = 0; p->state = LIT; p->StringType = NONE; p->ss = 0; p->LocalCharset = G0; bzero(p->tabs, p->width); for (i = 8; i < p->width; i += 8) p->tabs[i] = 1; for (i = G0; i <= G3; i++) p->charsets[i] = ASCII; } void WriteString(wp, buf, len) struct win *wp; char *buf; int len; { register int c, intermediate = 0; if (!len) return; if (wp->logfp != NULL) if ((int)fwrite(buf, len, 1, wp->logfp) < 1) { extern int errno; Msg(errno, "Error writing logfile"); fclose(wp->logfp); wp->logfp = NULL; } /* * SetCurr() here may prevent output, as it may set display = 0 */ SetCurr(wp); if (display) { if (!HS) RemoveStatus(); } else if (curr->monitor == MON_ON) curr->monitor = MON_FOUND; do { c = (unsigned char)*buf++; if (c == '\0' || c == '\177') continue; NextChar: switch (curr->state) { case PRIN: switch (c) { case '\033': curr->state = PRINESC; break; default: PrintChar(c); } break; case PRINESC: switch (c) { case '[': curr->state = PRINCSI; break; default: PrintChar('\033'); PrintChar(c); curr->state = PRIN; } break; case PRINCSI: switch (c) { case '4': curr->state = PRIN4; break; default: PrintChar('\033'); PrintChar('['); PrintChar(c); curr->state = PRIN; } break; case PRIN4: switch (c) { case 'i': curr->state = LIT; PrintFlush(); break; default: PrintChar('\033'); PrintChar('['); PrintChar('4'); PrintChar(c); curr->state = PRIN; } break; case STRESC: switch (c) { case '\\': curr->state = LIT; *(curr->stringp) = '\0'; switch (curr->StringType) { case PM: if (!display) break; MakeStatus(curr->string); if (!HS && status && len > 1) { curr->outlen = len - 1; bcopy(buf, curr->outbuf, curr->outlen); return; } break; case DCS: if (display) printf("%s", curr->string); break; case AKA: if (curr->akapos == 0 && !*curr->string) break; strncpy(curr->cmd + curr->akapos, curr->string, 20); if (!*curr->string) curr->autoaka = curr->y + 1; break; default: break; } break; default: curr->state = ASTR; AddChar('\033'); AddChar(c); } break; case ASTR: switch (c) { case '\0': break; case '\033': curr->state = STRESC; break; default: AddChar(c); } break; case ESC: switch (c) { case '[': curr->NumArgs = 0; intermediate = 0; bzero((char *) curr->args, MAXARGS * sizeof(int)); curr->state = CSI; break; case ']': StartString(OSC); break; case '_': StartString(APC); break; case 'P': StartString(DCS); break; case '^': StartString(PM); break; case '"': case 'k': StartString(AKA); break; default: if (Special(c)) break; if (c >= ' ' && c <= '/') intermediate = intermediate ? -1 : c; else if (c >= '0' && c <= '~') { DoESC(c, intermediate); curr->state = LIT; } else { curr->state = LIT; goto NextChar; } } break; case CSI: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (curr->NumArgs < MAXARGS) { curr->args[curr->NumArgs] = 10 * curr->args[curr->NumArgs] + c - '0'; } break; case ';': case ':': curr->NumArgs++; break; default: if (Special(c)) break; if (c >= '@' && c <= '~') { curr->NumArgs++; DoCSI(c, intermediate); if (curr->state != PRIN) curr->state = LIT; } else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?')) intermediate = intermediate ? -1 : c; else { curr->state = LIT; goto NextChar; } } break; case LIT: default: if (!Special(c)) { if (c == '\033') { intermediate = 0; curr->state = ESC; if (display && lp_missing && (CIC || IC || IM)) { RedisplayLine(blank, null, null, screenbot, cols - 2, cols - 1); GotoPos(curr->x, curr->y); } if (curr->autoaka < 0) curr->autoaka = 0; } else if (c < ' ') break; else { NewRendition(curr->LocalAttr); NewCharset(curr->charsets[(curr->ss) ? curr->ss : curr->LocalCharset]); if (curr->x < cols - 1) { if (curr->insert) InsertAChar(c); else { if (display) PUTCHAR(c); SetChar(c); } curr->x++; } else if (curr->x == cols - 1) { if (curr->wrap && (LP || !force_vt || COP)) { if (display) RAW_PUTCHAR(c); SetChar(c); if (AM && !LP) { curr->x = 0; /* terminal auto-wrapped */ LineFeed(0); } else curr->x++; } else { if (display) { if (LP || curr->y != screenbot) { RAW_PUTCHAR(c); GotoPos(curr->x, curr->y); } else CheckLP(c); } SetChar(c); if (curr->wrap) curr->x++; } } else { LineFeed(2); /* cr+lf, handle LP */ if (curr->insert) InsertAChar(c); else { if (display) PUTCHAR(c); SetChar(c); } curr->x = 1; } if (curr->ss) { NewCharset(curr->charsets[curr->LocalCharset]); curr->ss = 0; } } } } } while (--len); curr->outlen = 0; if (curr->state == PRIN) PrintFlush(); } static int Special(c) register int c; { switch (c) { case '\b': BackSpace(); return 1; case '\r': Return(); return 1; case '\n': if (curr->autoaka) FindAKA(); LineFeed(1); return 1; case '\007': if (!visual_bell) PutStr(BL); else { if (!VB) curr->bell = BELL_VISUAL; else PutStr(VB); } if (!display) curr->bell = BELL_ON; return 1; case '\t': ForwardTab(); return 1; case '\017': /* SI */ MapCharset(G0); return 1; case '\016': /* SO */ MapCharset(G1); return 1; } return 0; } static void DoESC(c, intermediate) int c, intermediate; { switch (intermediate) { case 0: switch (c) { case 'E': LineFeed(2); break; case 'D': LineFeed(1); break; case 'M': ReverseLineFeed(); break; case 'H': curr->tabs[curr->x] = 1; break; case 'Z': /* jph: Identify as VT100 */ Report(curr, "\033[?%d;%dc", 1, 2); break; case '7': SaveCursor(); break; case '8': RestoreCursor(); break; case 'c': ClearScreen(); ResetScreen(curr); NewRendition(0); NewCharset(ASCII); InsertMode(0); KeypadMode(0); ChangeScrollRegion(0, rows-1); break; case '=': KeypadMode(curr->keypad = 1); #if !defined(TIOCPKT) || defined(sgi) NewAutoFlow(curr, 0); #endif /* !TIOCPKT || sgi */ break; case '>': KeypadMode(curr->keypad = 0); #if !defined(TIOCPKT) || defined(sgi) NewAutoFlow(curr, 1); #endif /* !TIOCPKT || sgi */ break; case 'n': /* LS2 */ MapCharset(G2); break; case 'o': /* LS3 */ MapCharset(G3); break; case 'N': /* SS2 */ if (curr->charsets[curr->LocalCharset] != curr->charsets[G2]) curr->ss = G2; else curr->ss = 0; break; case 'O': /* SS3 */ if (curr->charsets[curr->LocalCharset] != curr->charsets[G3]) curr->ss = G3; else curr->ss = 0; break; } break; case '#': switch (c) { case '8': FillWithEs(); break; } break; case '(': DesignateCharset(c, G0); break; case ')': DesignateCharset(c, G1); break; case '*': DesignateCharset(c, G2); break; case '+': DesignateCharset(c, G3); break; } } static void DoCSI(c, intermediate) int c, intermediate; { register int i, a1 = curr->args[0], a2 = curr->args[1]; if (curr->NumArgs > MAXARGS) curr->NumArgs = MAXARGS; switch (intermediate) { case 0: switch (c) { case 'H': case 'f': if (a1 < 1) a1 = 1; if (curr->origin) a1 += curr->top; if (a1 > rows) a1 = rows; if (a2 < 1) a2 = 1; if (a2 > cols) a2 = cols; GotoPos(--a2, --a1); curr->x = a2; curr->y = a1; if (curr->autoaka) curr->autoaka = a1 + 1; break; case 'J': if (a1 < 0 || a1 > 2) a1 = 0; switch (a1) { case 0: ClearToEOS(); break; case 1: ClearFromBOS(); break; case 2: ClearScreen(); GotoPos(curr->x, curr->y); break; } break; case 'K': if (a1 < 0 || a1 > 2) a1 %= 3; switch (a1) { case 0: ClearToEOL(); break; case 1: ClearFromBOL(); break; case 2: ClearLine(); break; } break; case 'A': CursorUp(a1 ? a1 : 1); break; case 'B': CursorDown(a1 ? a1 : 1); break; case 'C': CursorRight(a1 ? a1 : 1); break; case 'D': CursorLeft(a1 ? a1 : 1); break; case 'm': SelectRendition(); break; case 'g': if (a1 == 0) curr->tabs[curr->x] = 0; else if (a1 == 3) bzero(curr->tabs, cols); break; case 'r': if (!a1) a1 = 1; if (!a2) a2 = rows; if (a1 < 1 || a2 > rows || a1 >= a2) break; curr->top = a1 - 1; curr->bot = a2 - 1; ChangeScrollRegion(curr->top, curr->bot); if (curr->origin) { GotoPos(0, curr->top); curr->y = curr->top; curr->x = 0; } else { GotoPos(0, 0); curr->y = curr->x = 0; } break; case 's': SaveCursor(); break; case 't': if (a1 != 8) break; a1 = curr->args[2]; if (a1 < 1) a1 = curr->width; if (a2 < 1) a2 = curr->height; if (WS == NULL) { a2 = curr->height; if (Z0 == NULL || (a1 != Z0width && a1 != Z1width)) a1 = curr->width; } if (a1 == curr->width && a2 == curr->height) break; ChangeWindowSize(curr, a1, a2); SetCurr(curr); if (display) Activate(0); break; case 'u': RestoreCursor(); break; case 'I': if (!a1) a1 = 1; while (a1--) ForwardTab(); break; case 'Z': if (!a1) a1 = 1; while (a1--) BackwardTab(); break; case 'L': InsertLine(a1 ? a1 : 1); break; case 'M': DeleteLine(a1 ? a1 : 1); break; case 'P': DeleteChar(a1 ? a1 : 1); break; case '@': InsertChar(a1 ? a1 : 1); break; case 'h': ASetMode(1); break; case 'l': ASetMode(0); break; case 'i': if (PO && a1 == 5) { curr->stringp = curr->string; curr->state = PRIN; } break; case 'n': if (a1 == 6) /* Report cursor position */ Report(curr, "\033[%d;%dR", curr->y + 1, curr->x + 1); break; case 'c': /* Identify as VT100 */ Report(curr, "\033[?%d;%dc", 1, 2); break; } break; case '?': debug2("\\E[?%d%c\n",a1,c); if (c != 'h' && c != 'l') break; i = (c == 'h'); switch (a1) { case 3: i = (i ? Z0width : Z1width); if ((Z0 || WS) && curr->width != i) { ChangeWindowSize(curr, i, curr->height); SetCurr(curr); if (display) Activate(0); } break; case 5: if (i) curr->vbwait = 1; else { if (curr->vbwait) PutStr(VB); curr->vbwait = 0; } break; case 6: if ((curr->origin = i) != 0) { GotoPos(0, curr->top); curr->y = curr->top; curr->x = 0; } else { GotoPos(0, 0); curr->y = curr->x = 0; } break; case 7: curr->wrap = i; break; case 35: debug1("Cursor %svisible\n", i?"in":""); curr->cursor_invisible = i; break; } break; } } void INSERTCHAR(c) int c; { if (!insert && (IC || CIC)) { if (IC) PutStr(IC); else CPutStr(CIC, 1); RAW_PUTCHAR(c); return; } InsertMode(1); if (insert) RAW_PUTCHAR(c); else RefreshLine(screeny, screenx, screenwidth-1); } void PUTCHAR(c) int c; { if (insert) InsertMode(0); RAW_PUTCHAR(c); } /* * RAW_PUTCHAR() is for all text that will be displayed. * NOTE, that charset Nr. 0 has a conversion table, but c1, c2, ... don't. */ static void RAW_PUTCHAR(c) int c; { if (GlobalCharset == '0') putchar(c0_tab[c]); else putchar(c); if (screenx < screenwidth - 1) screenx++; else { screenx++; if ((AM && !LP) || screenx > screenwidth) { screenx -= screenwidth; if (screeny < screenheight-1 && screeny != screenbot) screeny++; } } } void PutChar(c) int c; { /* this PutChar for ESC-sequences only */ putchar(c); } void PutStr(s) char *s; { if (display && s) tputs(s, 1, PutChar); } static void CPutStr(s, c) char *s; int c; { if (display && s) tputs(tgoto(s, 0, c), 1, PutChar); } static void SetChar(c) register int c; { register struct win *p = curr; p->image[p->y][p->x] = c; p->attr[p->y][p->x] = p->LocalAttr; p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset]; } static void StartString(type) enum string_t type; { curr->StringType = type; curr->stringp = curr->string; curr->state = ASTR; } static void AddChar(c) int c; { if (curr->stringp >= curr->string + MAXSTR - 1) curr->state = LIT; else *(curr->stringp)++ = c; } static void PrintChar(c) int c; { if (curr->stringp >= curr->string + MAXSTR - 1) PrintFlush(); *(curr->stringp)++ = c; } static void PrintFlush() { if (curr->stringp > curr->string) { tputs(PO, 1, PutChar); (void) fflush(stdout); (void) write(1, curr->string, curr->stringp - curr->string); tputs(PF, 1, PutChar); (void) fflush(stdout); curr->stringp = curr->string; } } /* Insert mode is a toggle on some terminals, so we need this hack: */ void InsertMode(on) int on; { if (display && on != insert && IM) { insert = on; if (insert) PutStr(IM); else PutStr(EI); } } /* ...and maybe keypad application mode is a toggle, too: */ static void KeypadMode(on) int on; { if (display && keypad != on && KS) { keypad = on; if (keypad) PutStr(KS); else PutStr(KE); } } void NewAutoFlow(win, on) struct win *win; int on; { debug1("NewAutoFlow: %d\n", on); SetCurr(win); if (win->flow & FLOW_AUTOFLAG) win->flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on; else win->flow = (win->flow & ~FLOW_AUTO) | FLOW_AUTO * on; if (display) SetFlow(win->flow & FLOW_NOW); } static void DesignateCharset(c, n) int c, n; { curr->ss = 0; if (c == 'B') c = ASCII; if (curr->charsets[n] != c) { curr->charsets[n] = c; if (curr->LocalCharset == n) NewCharset(c); } } static void MapCharset(n) int n; { curr->ss = 0; if (curr->LocalCharset != n) { curr->LocalCharset = n; NewCharset(curr->charsets[n]); } } void NewCharset(new) int new; { if (!display || GlobalCharset == new) return; GlobalCharset = new; if (new == ASCII) PutStr(E0); else CPutStr(S0, new); } static void SaveCursor() { curr->saved = 1; curr->Saved_x = curr->x; curr->Saved_y = curr->y; curr->SavedLocalAttr = curr->LocalAttr; curr->SavedLocalCharset = curr->LocalCharset; bcopy((char *) curr->charsets, (char *) curr->SavedCharsets, 4 * sizeof(int)); } static void RestoreCursor() { if (curr->saved) { GotoPos(curr->Saved_x, curr->Saved_y); curr->x = curr->Saved_x; curr->y = curr->Saved_y; curr->LocalAttr = curr->SavedLocalAttr; NewRendition(curr->LocalAttr); bcopy((char *) curr->SavedCharsets, (char *) curr->charsets, 4 * sizeof(int)); curr->LocalCharset = curr->SavedLocalCharset; NewCharset(curr->charsets[curr->LocalCharset]); } } /*ARGSUSED*/ static void CountChars(c) int c; { StrCost++; } static int CalcCost(s) register char *s; { if (s) { StrCost = 0; tputs(s, 1, CountChars); return StrCost; } else return EXPENSIVE; } void GotoPos(x2, y2) int x2, y2; { register int dy, dx, x1, y1; register int costx, costy; register int m; register char *s; int CMcost; enum move_t xm = M_NONE, ym = M_NONE; if (!display) return; x1 = screenx; y1 = screeny; if (x1 == screenwidth) if (LP && AM) x1 = -1; /* don't know how the terminal treats this */ else x1--; if (x2 == screenwidth) x2--; dx = x2 - x1; dy = y2 - y1; if (dy == 0 && dx == 0) { return; } if (!MS && GlobalAttr) /* Safe to move in SO mode ? */ NewRendition(0); if (y1 < 0 /* don't know the y position */ || (y2 > screenbot && y1 <= screenbot) /* have to cross border */ || (y2 < screentop && y1 >= screentop)) /* of scrollregion ? */ { DoCM: if (HO && !x2 && !y2) PutStr(HO); else PutStr(tgoto(CM, x2, y2)); screenx = x2; screeny = y2; return; } /* Calculate CMcost */ if (HO && !x2 && !y2) s = HO; else s = tgoto(CM, x2, y2); CMcost = CalcCost(s); /* Calculate the cost to move the cursor to the right x position */ costx = EXPENSIVE; if (x1 >= 0) /* relativ x positioning only if we know where we are */ { if (dx > 0) { if (CRI && (dx > 1 || !ND)) { costx = CalcCost(tgoto(CRI, 0, dx)); xm = M_CRI; } if ((m = NDcost * dx) < costx) { costx = m; xm = M_RI; } /* Speedup: dx <= Rewrite() */ if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx) { costx = m; xm = M_RW; } } else if (dx < 0) { if (CLE && (dx < -1 || !BC)) { costx = CalcCost(tgoto(CLE, 0, -dx)); xm = M_CLE; } if ((m = -dx * LEcost) < costx) { costx = m; xm = M_LE; } } else costx = 0; } /* Speedup: Rewrite() >= x2 */ if (x2 + CRcost < costx && (m = Rewrite(y1, 0, x2, 0) + CRcost) < costx) { costx = m; xm = M_CR; } /* Check if it is already cheaper to do CM */ if (costx >= CMcost) goto DoCM; /* Calculate the cost to move the cursor to the right y position */ costy = EXPENSIVE; if (dy > 0) { if (CDO && dy > 1) /* DO & NL are always != 0 */ { costy = CalcCost(tgoto(CDO, 0, dy)); ym = M_CDO; } if ((m = dy * ((x2 == 0) ? NLcost : DOcost)) < costy) { costy = m; ym = M_DO; } } else if (dy < 0) { if (CUP && (dy < -1 || !UP)) { costy = CalcCost(tgoto(CUP, 0, -dy)); ym = M_CUP; } if ((m = -dy * UPcost) < costy) { costy = m; ym = M_UP; } } else costy = 0; /* Finally check if it is cheaper to do CM */ if (costx + costy >= CMcost) goto DoCM; switch (xm) { case M_LE: while (dx++ < 0) PutStr(BC); break; case M_CLE: CPutStr(CLE, -dx); break; case M_RI: while (dx-- > 0) PutStr(ND); break; case M_CRI: CPutStr(CRI, dx); break; case M_CR: PutStr(CR); screenx = 0; x1 = 0; /* FALLTHROUGH */ case M_RW: if (x1 < x2) (void) Rewrite(y1, x1, x2, 1); break; default: break; } switch (ym) { case M_UP: while (dy++ < 0) PutStr(UP); break; case M_CUP: CPutStr(CUP, -dy); break; case M_DO: s = (x2 == 0) ? NL : DO; while (dy-- > 0) PutStr(s); break; case M_CDO: CPutStr(CDO, dy); break; default: break; } screenx = x2; screeny = y2; } static int Rewrite(y, x1, x2, doit) int y, x1, x2, doit; { register int cost, dx; register char *p, *f, *i; if (x1 == x2) return(0); if (in_ovl) { if (ovl_Rewrite == 0) return EXPENSIVE; else return ((*ovl_Rewrite)(y, x1, x2, doit)); } dx = x2 - x1; if (doit) { i = curr->image[y] + x1; while (dx-- > 0) PUTCHAR(*i++); return(0); } p = curr->attr[y] + x1; f = curr->font[y] + x1; cost = dx = x2 - x1; if (insert) cost += EIcost + IMcost; while(dx-- > 0) { if (*p++ != GlobalAttr || *f++ != GlobalCharset) return EXPENSIVE; } return cost; } static void BackSpace() { if (curr->x > 0) { curr->x--; } else if (curr->wrap && curr->y > 0) { curr->x = cols - 1; curr->y--; } if (display) GotoPos(curr->x, curr->y); } static void Return() { if (curr->x > 0) { curr->x = 0; if (display) GotoPos(curr->x, curr->y); } } static void LineFeed(out_mode) int out_mode; { /* out_mode: 0=no-output lf, 1=lf, 2=cr+lf */ if (out_mode == 2) curr->x = 0; if (curr->y != curr->bot) /* Don't scroll */ { if (curr->y < rows-1) curr->y++; if (out_mode && display) GotoPos(curr->x, curr->y); return; } ScrollUpMap(1); if (curr->autoaka > 1) curr->autoaka--; if (out_mode && display) { ScrollRegion(curr->top, curr->bot, 1); GotoPos(curr->x, curr->y); } } static void ReverseLineFeed() { if (curr->y == curr->top) { ScrollDownMap(1); if (!display) return; ScrollRegion(curr->top, curr->bot, -1); GotoPos(curr->x, curr->y); } else if (curr->y > 0) CursorUp(1); } static void InsertAChar(c) int c; { register int y = curr->y, x = curr->x; if (x == cols) x--; bcopy(curr->image[y], OldImage, cols); bcopy(curr->attr[y], OldAttr, cols); bcopy(curr->font[y], OldFont, cols); bcopy(curr->image[y] + x, curr->image[y] + x + 1, cols - x - 1); bcopy(curr->attr[y] + x, curr->attr[y] + x + 1, cols - x - 1); bcopy(curr->font[y] + x, curr->font[y] + x + 1, cols - x - 1); SetChar(c); if (!display) return; if (CIC || IC || IM) { InsertMode(curr->insert); INSERTCHAR(c); if (y == screenbot) lp_missing = 0; } else { RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1); GotoPos(++x, y); } } static void InsertChar(n) int n; { register int i, y = curr->y, x = curr->x; if (n <= 0) return; /* * The termcap manual states that only one of IM and IC is * to be defined unless the terminal needs both sequences. * We don't like this because we think that there may be cases * where it is preferable to send IC instead of IM/EI. * The hack is to ignore the IC sequence if we are already * in insert mode, so that programs which follow the termcap * guidelines still work. (I don't believe that there are * terminals which need IC in the insert mode. Why switch to * insert mode if you must send IC before every character ?) */ if (curr->insert) return; if (x == cols) --x; bcopy(curr->image[y], OldImage, cols); bcopy(curr->attr[y], OldAttr, cols); bcopy(curr->font[y], OldFont, cols); if (n > cols - x) n = cols - x; bcopy(curr->image[y] + x, curr->image[y] + x + n, cols - x - n); bcopy(curr->attr[y] + x, curr->attr[y] + x + n, cols - x - n); bcopy(curr->font[y] + x, curr->font[y] + x + n, cols - x - n); ClearInLine(0, y, x, x + n - 1); if (!display) return; if (IC || CIC || IM) { if (y == screenbot) lp_missing = 0; if (!insert) { if (n == 1 && IC) { PutStr(IC); return; } if (CIC) { CPutStr(CIC, n); return; } } InsertMode(1); for (i = n; i--; ) INSERTCHAR(' '); GotoPos(x, y); } else { RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1); GotoPos(x, y); } } static void DeleteChar(n) int n; { register int i, y = curr->y, x = curr->x; if (x == cols) --x; bcopy(curr->image[y], OldImage, cols); bcopy(curr->attr[y], OldAttr, cols); bcopy(curr->font[y], OldFont, cols); if (n > cols - x) n = cols - x; bcopy(curr->image[y] + x + n, curr->image[y] + x, cols - x - n); bcopy(curr->attr[y] + x + n, curr->attr[y] + x, cols - x - n); bcopy(curr->font[y] + x + n, curr->font[y] + x, cols - x - n); ClearInLine(0, y, cols - n, cols - 1); if (!display) return; if (CDC && !(n == 1 && DC)) { CPutStr(CDC, n); if (lp_missing && y == screenbot) { FixLP(cols - 1 - n, y); GotoPos(x, y); } } else if (DC) { for (i = n; i; i--) PutStr(DC); if (lp_missing && y == screenbot) { FixLP(cols - 1 - n, y); GotoPos(x, y); } } else { RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1); GotoPos(x, y); } } static void DeleteLine(n) int n; { register int old = curr->top; if (curr->y < curr->top || curr->y > curr->bot) return; if (n > curr->bot - curr->y + 1) n = curr->bot - curr->y + 1; curr->top = curr->y; ScrollUpMap(n); curr->top = old; if (!display) return; ScrollRegion(curr->y, curr->bot, n); GotoPos(curr->x, curr->y); } static void InsertLine(n) int n; { register int old = curr->top; if (curr->y < curr->top || curr->y > curr->bot) return; if (n > curr->bot - curr->y + 1) n = curr->bot - curr->y + 1; curr->top = curr->y; ScrollDownMap(n); curr->top = old; if (!display) return; ScrollRegion(curr->y, curr->bot, -n); GotoPos(curr->x, curr->y); } void ScrollRegion(ys, ye, n) int ys, ye, n; { int i; int up; int oldtop, oldbot; int alok, dlok, aldlfaster; int missy = 0; if (n == 0) return; if (ys == 0 && ye == screenheight-1 && (n >= screenheight || -n >= screenheight)) { PutStr(CL); screeny = screenx = 0; lp_missing = 0; return; } if (lp_missing) { if (screenbot>ye || screenbot<ys) missy = screenbot; else { missy = screenbot - n; if (missy>ye || missy<ys) lp_missing = 0; } } up = 1; if (n < 0) { up = 0; n = -n; } if (n >= ye-ys+1) n = ye-ys+1; oldtop = screentop; oldbot = screenbot; if (screenbot != ye) ChangeScrollRegion(ys, ye); alok = (AL || CAL || (ye == screenbot && up)); dlok = (DL || CDL || (ye == screenbot && !up)); if (screentop != ys && !(alok && dlok)) ChangeScrollRegion(ys, ye); if (lp_missing && (oldbot != screenbot || (oldbot == screenbot && up && screentop == ys && screenbot == ye))) { /* Can't use FixLP */ GotoPos(screenwidth-1, oldbot); SaveSetAttr(curr->attr[missy][screenwidth-1], curr->font[missy][screenwidth-1]); PUTCHAR(curr->image[missy][screenwidth-1]); RestoreAttr(); lp_missing = 0; if (oldbot == screenbot) /* have scrolled */ { if (--n == 0) { ChangeScrollRegion(oldtop, oldbot); return; } } } aldlfaster = (n > 1 && ye == screenbot && ((up && CDL) || (!up && CAL))); if ((up || SR) && screentop == ys && screenbot == ye && !aldlfaster) { if (up) { GotoPos(0, ye); while (n-- > 0) PutStr(NL); /* was SF, I think NL is faster */ } else { GotoPos(0, ys); while (n-- > 0) PutStr(SR); } } else if (alok && dlok) { if (up || ye != screenbot) { GotoPos(0, up ? ys : ye+1-n); if (CDL && !(n == 1 && DL)) CPutStr(CDL, n); else for(i=n; i--; ) PutStr(DL); } if (!up || ye != screenbot) { GotoPos(0, up ? ye+1-n : ys); if (CAL && !(n == 1 && AL)) CPutStr(CAL, n); else for(i=n; i--; ) PutStr(AL); } } else { Redisplay(0); return; } if (lp_missing && missy != screenbot) FixLP(screenwidth-1, missy); ChangeScrollRegion(oldtop, oldbot); if (lp_missing && missy != screenbot) FixLP(screenwidth-1, missy); } static void ScrollUpMap(n) int n; { char tmp[256 * sizeof(char *)]; register int ii, i, cnt1, cnt2; register char **ppi, **ppa, **ppf; i = curr->top + n; cnt1 = n * sizeof(char *); cnt2 = (curr->bot - i + 1) * sizeof(char *); ppi = curr->image + i; ppa = curr->attr + i; ppf = curr->font + i; for(ii = curr->top; ii < i; ii++) AddLineToHist(curr, &curr->image[ii], &curr->attr[ii], &curr->font[ii]); for (i = n; i; --i) { bclear(*--ppi, cols); bzero(*--ppa, cols); bzero(*--ppf, cols); } Scroll((char *) ppi, cnt1, cnt2, tmp); Scroll((char *) ppa, cnt1, cnt2, tmp); Scroll((char *) ppf, cnt1, cnt2, tmp); } static void ScrollDownMap(n) int n; { char tmp[256 * sizeof(char *)]; register int i, cnt1, cnt2; register char **ppi, **ppa, **ppf; i = curr->top; cnt1 = (curr->bot - i - n + 1) * sizeof(char *); cnt2 = n * sizeof(char *); Scroll((char *) (ppi = curr->image + i), cnt1, cnt2, tmp); Scroll((char *) (ppa = curr->attr + i), cnt1, cnt2, tmp); Scroll((char *) (ppf = curr->font + i), cnt1, cnt2, tmp); for (i = n; i; --i) { bclear(*ppi++, cols); bzero(*ppa++, cols); bzero(*ppf++, cols); } } static void Scroll(cp, cnt1, cnt2, tmp) char *cp, *tmp; int cnt1, cnt2; { if (!cnt1 || !cnt2) return; if (cnt1 <= cnt2) { bcopy(cp, tmp, cnt1); bcopy(cp + cnt1, cp, cnt2); bcopy(tmp, cp + cnt2, cnt1); } else { bcopy(cp + cnt1, tmp, cnt2); bcopy(cp, cp + cnt2, cnt1); bcopy(tmp, cp, cnt2); } } static void ForwardTab() { register int x = curr->x; if (x == cols) { LineFeed(2); x = 0; } if (curr->tabs[x] && x < cols - 1) x++; while (x < cols - 1 && !curr->tabs[x]) x++; GotoPos(x, curr->y); curr->x = x; } static void BackwardTab() { register int x = curr->x; if (curr->tabs[x] && x > 0) x--; while (x > 0 && !curr->tabs[x]) x--; GotoPos(x, curr->y); curr->x = x; } static void ClearScreen() { register int i; register char **ppi = curr->image, **ppa = curr->attr, **ppf = curr->font; for (i = 0; i < rows; ++i) { AddLineToHist(curr, ppi, ppa, ppf); bclear(*ppi++, cols); bzero(*ppa++, cols); bzero(*ppf++, cols); } if (display) { PutStr(CL); screenx = screeny = 0; lp_missing = 0; } } static void ClearFromBOS() { register int n, y = curr->y, x = curr->x; for (n = 0; n < y; ++n) ClearInLine(1, n, 0, cols - 1); ClearInLine(1, y, 0, x); GotoPos(x, y); RestoreAttr(); } static void ClearToEOS() { register int n, y = curr->y, x = curr->x; if (!y && !x) { ClearScreen(); return; } if (display && CD) { PutStr(CD); lp_missing = 0; } ClearInLine(!CD, y, x, cols - 1); for (n = y + 1; n < rows; n++) ClearInLine(!CD, n, 0, cols - 1); GotoPos(x, y); RestoreAttr(); } static void ClearLine() { register int y = curr->y, x = curr->x; ClearInLine(1, y, 0, cols - 1); GotoPos(x, y); RestoreAttr(); } static void ClearToEOL() { register int y = curr->y, x = curr->x; ClearInLine(1, y, x, cols - 1); GotoPos(x, y); RestoreAttr(); } static void ClearFromBOL() { register int y = curr->y, x = curr->x; ClearInLine(1, y, 0, x); GotoPos(x, y); RestoreAttr(); } static void ClearInLine(displ, y, x1, x2) int displ, y, x1, x2; { register int n; if (x1 == cols) x1--; if (x2 == cols) x2--; if ((n = x2 - x1 + 1) != 0) { if (displ && display) { if (x2 == cols - 1 && CE) { GotoPos(x1, y); PutStr(CE); if (y == screenbot) lp_missing = 0; } else DisplayLine(curr->image[y], curr->attr[y], curr->font[y], blank, null, null, y, x1, x2); } if (curr) { bclear(curr->image[y] + x1, n); bzero(curr->attr[y] + x1, n); bzero(curr->font[y] + x1, n); } } } static void CursorRight(n) register int n; { register int x = curr->x; if (x == cols) { LineFeed(2); x = 0; } if ((curr->x += n) >= cols) curr->x = cols - 1; GotoPos(curr->x, curr->y); } static void CursorUp(n) register int n; { if (curr->y < curr->top) /* if above scrolling rgn, */ { if ((curr->y -= n) < 0) /* ignore its limits */ curr->y = 0; } else if ((curr->y -= n) < curr->top) curr->y = curr->top; GotoPos(curr->x, curr->y); } static void CursorDown(n) register int n; { if (curr->y > curr->bot) /* if below scrolling rgn, */ { if ((curr->y += n) > rows - 1) /* ignore its limits */ curr->y = rows - 1; } else if ((curr->y += n) > curr->bot) curr->y = curr->bot; GotoPos(curr->x, curr->y); } static void CursorLeft(n) register int n; { if ((curr->x -= n) < 0) curr->x = 0; GotoPos(curr->x, curr->y); } static void ASetMode(on) int on; { register int i; for (i = 0; i < curr->NumArgs; ++i) { switch (curr->args[i]) { case 4: curr->insert = on; InsertMode(on); break; } } } static void SelectRendition() { register int i = 0, a = curr->LocalAttr; do { switch (curr->args[i]) { case 0: a = 0; break; case 1: a |= A_BD; break; case 2: a |= A_DI; break; case 3: a |= A_SO; break; case 4: a |= A_US; break; case 5: a |= A_BL; break; case 7: a |= A_RV; break; case 22: a &= ~(A_BD | A_SO | A_DI); break; case 23: a &= ~A_SO; break; case 24: a &= ~A_US; break; case 25: a &= ~A_BL; break; case 27: a &= ~A_RV; break; } } while (++i < curr->NumArgs); NewRendition(curr->LocalAttr = a); } void NewRendition(new) register int new; { register int i, old = GlobalAttr; if (!display || old == new) return; GlobalAttr = new; for (i = 1; i <= A_MAX; i <<= 1) { if ((old & i) && !(new & i)) { PutStr(UE); PutStr(SE); PutStr(ME); if (new & A_DI) PutStr(attrtab[ATTR_DI]); if (new & A_US) PutStr(attrtab[ATTR_US]); if (new & A_BD) PutStr(attrtab[ATTR_BD]); if (new & A_RV) PutStr(attrtab[ATTR_RV]); if (new & A_SO) PutStr(attrtab[ATTR_SO]); if (new & A_BL) PutStr(attrtab[ATTR_BL]); return; } } if ((new & A_DI) && !(old & A_DI)) PutStr(attrtab[ATTR_DI]); if ((new & A_US) && !(old & A_US)) PutStr(attrtab[ATTR_US]); if ((new & A_BD) && !(old & A_BD)) PutStr(attrtab[ATTR_BD]); if ((new & A_RV) && !(old & A_RV)) PutStr(attrtab[ATTR_RV]); if ((new & A_SO) && !(old & A_SO)) PutStr(attrtab[ATTR_SO]); if ((new & A_BL) && !(old & A_BL)) PutStr(attrtab[ATTR_BL]); } void SaveSetAttr(newattr, newcharset) int newattr, newcharset; { NewRendition(newattr); NewCharset(newcharset); } void RestoreAttr() { NewRendition(curr->LocalAttr); NewCharset(curr->charsets[curr->LocalCharset]); } static void FillWithEs() { register int i; register char *p, *ep; curr->y = curr->x = 0; for (i = 0; i < rows; ++i) { bzero(curr->attr[i], cols); bzero(curr->font[i], cols); p = curr->image[i]; ep = p + cols; while (p < ep) *p++ = 'E'; } if (display) Redisplay(0); } /* * if cur_only, we only redisplay current line, as a full refresh is * too expensive. */ void Redisplay(cur_only) int cur_only; { register int i, stop; PutStr(CL); screenx = screeny = 0; lp_missing = 0; stop = rows; i = 0; if (cur_only) { i = stop = curr->y; stop++; } for (; i < stop; ++i) { if (in_ovl) (*ovl_RedisplayLine)(i, 0, cols - 1, 1); else DisplayLine(blank, null, null, curr->image[i], curr->attr[i], curr->font[i], i, 0, cols - 1); } if (!in_ovl) { GotoPos(curr->x, curr->y); NewRendition(curr->LocalAttr); NewCharset(curr->charsets[curr->LocalCharset]); } } void DisplayLine(os, oa, of, s, as, fs, y, from, to) int from, to, y; register char *os, *oa, *of, *s, *as, *fs; { register int x; int last2flag = 0, delete_lp = 0; if (!LP && y == screenbot && to == cols - 1) if (lp_missing || s[to] != os[to] || as[to] != oa[to] || of[to] != fs[to]) { if ((IC || IM) && (from < to || !in_ovl)) { if ((to -= 2) < from - 1) from--; last2flag = 1; lp_missing = 0; } else { to--; delete_lp = (CE || DC || CDC); lp_missing = (s[to] != ' ' || as[to] || fs[to]); } } else to--; for (x = from; x <= to; ++x) { if (s[x] == os[x] && as[x] == oa[x] && of[x] == fs[x]) continue; GotoPos(x, y); NewRendition(as[x]); NewCharset(fs[x]); PUTCHAR(s[x]); } if (last2flag) { GotoPos(x, y); NewRendition(as[x + 1]); NewCharset(fs[x + 1]); PUTCHAR(s[x + 1]); GotoPos(x, y); NewRendition(as[x]); NewCharset(fs[x]); INSERTCHAR(s[x]); } else if (delete_lp) { if (DC) PutStr(DC); else if (CDC) CPutStr(CDC, 1); else if (CE) PutStr(CE); } } void RefreshLine(y, from, to) int y, from, to; { char *oi = null; if (CE && to == screenwidth-1) { GotoPos(from, y); PutStr(CE); oi = blank; } if (in_ovl) (*ovl_RedisplayLine)(y, from, to, (oi == blank)); else DisplayLine(oi, null, null, curr->image[y], curr->attr[y], curr->font[y], y, from, to); } static void RedisplayLine(os, oa, of, y, from, to) int from, to, y; char *os, *oa, *of; { DisplayLine(os, oa, of, curr->image[y], curr->attr[y], curr->font[y], y, from, to); NewRendition(curr->LocalAttr); NewCharset(curr->charsets[curr->LocalCharset]); } void FixLP(x2, y2) register int x2, y2; { register struct win *p = curr; GotoPos(x2, y2); SaveSetAttr(p->attr[y2][x2], p->font[y2][x2]); PUTCHAR(p->image[y2][x2]); RestoreAttr(); lp_missing = 0; } void CheckLP(n_ch) char n_ch; { register int y = screenbot, x = cols - 1; register char n_at, n_fo, o_ch, o_at, o_fo; o_ch = curr->image[y][x]; o_at = curr->attr[y][x]; o_fo = curr->font[y][x]; n_at = curr->LocalAttr; n_fo = curr->charsets[curr->LocalCharset]; lp_missing = 0; if (n_ch == o_ch && n_at == o_at && n_fo == o_fo) { return; } if (n_ch != ' ' || n_at || n_fo) lp_missing = 1; if (o_ch != ' ' || o_at || o_fo) { if (DC) PutStr(DC); else if (CDC) CPutStr(CDC, 1); else if (CE) PutStr(CE); else lp_missing = 1; } } static void FindAKA() { register char *cp, *line, ch; register struct win *wp = curr; register int len = strlen(wp->cmd); int y; y = (wp->autoaka > 0 && wp->autoaka <= wp->height) ? wp->autoaka - 1 : wp->y; cols = wp->width; try_line: cp = line = wp->image[y]; if (wp->autoaka > 0 && (ch = *wp->cmd) != '\0') { for (;;) { if ((cp = index(cp, ch)) != NULL && !strncmp(cp, wp->cmd, len)) break; if (!cp || ++cp - line >= cols - len) { if (++y == wp->autoaka && y < rows) goto try_line; return; } } cp += len; } for (len = cols - (cp - line); len && *cp == ' '; len--, cp++) ; if (len) { if (wp->autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^')) wp->autoaka = -1; else wp->autoaka = 0; line = wp->cmd + wp->akapos; while (len && *cp != ' ') { if ((*line++ = *cp++) == '/') line = wp->cmd + wp->akapos; len--; } *line = '\0'; } else wp->autoaka = 0; } /* We dont use HS status line with Input. * If we would use it, then we should check e_tgetflag("es") if * we are allowed to use esc sequences there. * For now, we hope that Goto(,,STATLINE,0) brings us in the bottom * line. jw. */ static char inpbuf[101]; static int inplen; static int inpmaxlen; static char *inpstring; static int inpstringlen; static void (*inpfinfunc)(); void Input(istr, len, finfunc) char *istr; int len; void (*finfunc)(); { int maxlen; inpstring = istr; inpstringlen = strlen(istr); if (len > 100) len = 100; maxlen = screenwidth - inpstringlen; if (!LP && STATLINE == screenbot) maxlen--; if (len > maxlen) len = maxlen; if (len < 2) { Msg(0, "Width too small"); return; } inpmaxlen = len; inpfinfunc = finfunc; InitOverlayPage(process_inp_input, inpRedisplayLine, (int (*)())0, 1); inplen = 0; GotoPos(0, STATLINE); if (CE) PutStr(CE); else { DisplayLine(curr->image[screeny], curr->attr[screeny], curr->font[screeny], blank, null, null, screeny, 0, cols - 1); } inpRedisplayLine(STATLINE, 0, inpstringlen - 1, 0); GotoPos(inpstringlen, STATLINE); } static void process_inp_input(ppbuf, plen) char **ppbuf; int *plen; { int len, x; char *pbuf; char ch; if (ppbuf == 0) { AbortInp(); return; } x = inpstringlen+inplen; len = *plen; pbuf = *ppbuf; while (len) { ch = *pbuf++; len--; if (ch >= ' ' && ch <= '~' && inplen < inpmaxlen) { inpbuf[inplen++] = ch; GotoPos(x, STATLINE); SaveSetAttr(A_SO, ASCII); PUTCHAR(ch); x++; } else if ((ch == '\b' || ch == 0177) && inplen > 0) { inplen--; x--; GotoPos(x, STATLINE); SaveSetAttr(0, ASCII); PUTCHAR(' '); GotoPos(x, STATLINE); } else if (ch == '\004' || ch == '\003' || ch == '\000' || ch == '\n' || ch == '\r') { if (ch != '\n' && ch != '\r') inplen = 0; inpbuf[inplen] = 0; AbortInp(); /* redisplays... */ (*inpfinfunc)(inpbuf, inplen); break; } } *ppbuf = pbuf; *plen = len; } static void AbortInp() { in_ovl = 0; /* So we can use RefreshLine() */ RefreshLine(STATLINE, 0, screenwidth-1); ExitOverlayPage(); } static void inpRedisplayLine(y, xs, xe, isblank) int y, xs, xe, isblank; { int q, r, s, l, v; if (y != STATLINE) return; inpbuf[inplen] = 0; GotoPos(xs,y); q = xs; v = xe - xs + 1; s = 0; r = inpstringlen; if (v > 0 && q < r) { SaveSetAttr(A_SO, ASCII); l = v; if (l > r-q) l = r-q; printf("%-*.*s", l, l, inpstring + q - s); q += l; v -= l; } s = r; r += inplen; if (v > 0 && q < r) { SaveSetAttr(A_SO, ASCII); l = v; if (l > r-q) l = r-q; printf("%-*.*s", l, l, inpbuf + q - s); q += l; v -= l; } s = r; r = screenwidth; if (!isblank && v > 0 && q < r) { SaveSetAttr(0, ASCII); l = v; if (l > r-q) l = r-q; printf("%-*.*s", l, l, ""); q += l; } SetLastPos(q, y); } static void AKAfin(buf, len) char *buf; int len; { if (len) { strcpy(curr->cmd + curr->akapos, buf); } } void InputAKA() { void Input(), AKAfin(); Input("Set window's a.k.a. to: ", 20, AKAfin); } static void Colonfin(buf, len) char *buf; int len; { if (len) RcLine(buf); } void InputColon() { void Input(), Colonfin(); Input(":", 100, Colonfin); } void MakeBlankLine(p, n) register char *p; register int n; { while (n--) *p++ = ' '; } void MakeStatus(msg) char *msg; { register char *s, *t; register int max, ti; SetCurr(fore); display = 1; if (!(max = HS)) { max = !LP ? cols - 1 : cols; } if (status) { if (!BellDisplayed) { ti = time((time_t *) 0) - TimeDisplayed; if (ti < MsgMinWait) sleep(MsgMinWait - ti); } RemoveStatus(); } for (s = t = msg; *s && t - msg < max; ++s) if (*s == BELL) PutStr(BL); else if (*s >= ' ' && *s <= '~') *t++ = *s; *t = '\0'; if (t > msg) { strncpy(LastMsg, msg, maxwidth); status = 1; status_lastx = screenx; status_lasty = screeny; StatLen = t - msg; if (!HS) { GotoPos(0, STATLINE); SaveSetAttr(A_SO, ASCII); InsertMode(0); printf("%s", msg); screenx = -1; } else { debug("HS:"); SaveSetAttr(0, ASCII); InsertMode(0); CPutStr(TS, 0); printf("%s", msg); PutStr(FS); } (void) fflush(stdout); (void) time(&TimeDisplayed); } } void RemoveStatus() { if (!status) return; status = 0; BellDisplayed = 0; SetCurr(fore); display = 1; if (!HS) { GotoPos(0, STATLINE); if (in_ovl) (*ovl_RedisplayLine)(STATLINE, 0, StatLen - 1, 0); else RedisplayLine(null, null, null, STATLINE, 0, StatLen - 1); GotoPos(status_lastx, status_lasty); } else { SaveSetAttr(0, ASCII); PutStr(DS); } } void ClearDisplay() { PutStr(CL); screeny = screenx = 0; fflush(stdout); } static void SetCurr(wp) struct win *wp; { curr = wp; cols = curr->width; rows = curr->height; display = curr->active; } void InitOverlayPage(pro, red, rewrite, blockfore) void (*pro)(); void (*red)(); int (*rewrite)(); int blockfore; { RemoveStatus(); SetOvlCurr(); ChangeScrollRegion(0, screenheight - 1); SetFlow(1); ovl_process = pro; ovl_RedisplayLine = red; ovl_Rewrite = rewrite; ovl_blockfore = blockfore; curr->active = 0; in_ovl = 1; } void ExitOverlayPage() { ChangeScrollRegion(curr->top, curr->bot); GotoPos(curr->x, curr->y); RestoreAttr(); SetFlow(curr->flow & FLOW_NOW); curr->active = 1; in_ovl = 0; } void SetOvlCurr() { SetCurr(fore); SaveSetAttr(0, ASCII); InsertMode(0); display = 1; } void SetLastPos(x,y) int x,y; { screenx = x; screeny = y; } void WSresize(width, height) int width, height; { debug2("(display=%d:WSresize says:'%s'\n", display, tgoto(WS, width, height)); PutStr(tgoto(WS, width, height)); } void ChangeScrollRegion(top, bot) int top, bot; { if (display == 0) return; if (CS == 0) { screentop = 0; screenbot = screenheight - 1; return; } if (top == screentop && bot == screenbot) return; debug2("ChangeScrollRegion: (%d - %d)\n", top, bot); PutStr(tgoto(CS, bot, top)); screentop = top; screenbot = bot; screeny = screenx = -1; /* Just in case... */ } void AddLineToHist(wp, pi, pa, pf) struct win *wp; char **pi, **pa, **pf; { register char *q; if (wp->histheight == 0) return; q = *pi; *pi = wp->ihist[wp->histidx]; wp->ihist[wp->histidx] = q; q = *pa; *pa = wp->ahist[wp->histidx]; wp->ahist[wp->histidx] = q; q = *pf; *pf = wp->fhist[wp->histidx]; wp->fhist[wp->histidx] = q; if (++wp->histidx >= wp->histheight) wp->histidx = 0; } /* * * Termcap routines that use our extra_incap * */ /* findcap: * cap = capability we are looking for * tepp = pointer to bufferpointer * n = size of buffer (0 = infinity) */ char * findcap(cap, tepp, n) char *cap; char **tepp; int n; { char *tep; char c, *p, *cp; int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */ int num = 0, capl; if (!extra_incap) return (0); tep = *tepp; capl = strlen(cap); cp = 0; mode = 0; for (p = extra_incap; *p; ) { if (strncmp(p, cap, capl) == 0) { p+=capl; c = *p; if (c && c != ':' && c != '@') p++; if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#') cp = tep; } while (c = *p) { p++; if (mode == 0) { if (c == ':') break; if (c == '^') mode = 1; if (c == '\\') mode = 2; } else if (mode == 1) { c = c & 0x1f; mode = 0; } else if (mode == 2) { switch(c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': mode = 3; num = 0; break; case 'E': c = 27; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; } if (mode == 2) mode = 0; } if (mode > 2) { num = num * 8 + (c - '0'); if (mode++ == 5 || (*p < '0' || *p > '9')) { c = num; mode = 0; } } if (mode) continue; if (cp && n != 1) { *cp++ = c; n--; } } if (cp) { *cp++ = 0; *tepp = cp; debug2("'%s' found in extra_incap -> %s\n", cap, tep); return(tep); } } return(0); } static char * e_tgetstr(cap, tepp) char *cap; char **tepp; { char *tep; if (tep = findcap(cap, tepp, 0)) return((*tep == '@') ? 0 : tep); return (tgetstr(cap, tepp)); } static int e_tgetflag(cap) char *cap; { char buf[2], *bufp; char *tep; bufp = buf; if (tep = findcap(cap, &bufp, 2)) return((*tep == '@') ? 0 : 1); return (tgetflag(cap)); } static int e_tgetnum(cap) char *cap; { char buf[20], *bufp; char *tep, c; int res, base = 10; bufp = buf; if (tep = findcap(cap, &bufp, 20)) { c = *tep; if (c == '@') return(-1); if (c == '0') base = 8; res = 0; while ((c = *tep++) >= '0' && c <= '9') res = res * base + (c - '0'); return(res); } return (tgetnum(cap)); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.