rsalz@uunet.uu.net (Rich Salz) (11/02/88)
Submitted-by: hoptoad!gnu (John Gilmore) Posting-number: Volume 16, Issue 51 Archive-name: psterm/part04 : psterm part 4 of 4 : To unbundle, sh this file echo tcap.cps cat >tcap.cps <<'@@@ Fin de tcap.cps' % % This file is a product of Sun Microsystems, Inc. and is provided for % unrestricted use provided that this legend is included on all tape % media and as a part of the software program in whole or part. % Users may copy, modify or distribute this file at will. % % THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE % WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR % PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. % % This file is provided with no support and without any obligation on the % part of Sun Microsystems, Inc. to assist in its use, correction, % modification or enhancement. % % SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE % INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE % OR ANY PART THEREOF. % % In no event will Sun Microsystems, Inc. be liable for any lost revenue % or profits or other special, indirect and consequential damages, even % if Sun has been advised of the possibility of such damages. % % Sun Microsystems, Inc. % 2550 Garcia Avenue % Mountain View, California 94043 % % Modifications to the original Sun Microsystems, Inc. source code % made by the Grasshopper Group are in the Public Domain. % % Extensions to this file by Eric Messick of the Grasshopper Group. % % Grasshopper Group % 212 Clayton St % San Francisco, CA 94117 % % % % "@(#)tcap.cps 9.5 88/01/19 SMI % "@(#)$Header: tcap.cps,v 2.2 88/10/04 05:59:57 gnu Release $ % % Copyright (c) 1985 by Sun Microsystems, Inc. %/ cdef PSDefs(reload) systemdict /LoadingPSTerm known { createevent dup begin /Name [/PSTimer /PSTermLoaded] def end expressinterest createevent dup begin /Name /PSTimer def /TimeStamp currenttime .5 add def end sendevent awaitevent pop } if pause systemdict /PSTermDict known not reload 0 ne or { systemdict /LoadingPSTerm true put systemdict /PSTermDict undef (psterm.ps) LoadFile pop } if pause cdef PSInitCode(string userinit) PSTermDict /UserCodeLoaded known not { (.pstermrc) LoadFile pop PSTermDict /UserCodeLoaded true put systemdict /LoadingPSTerm undef createevent dup begin /Name /PSTermLoaded def /TimeStamp currenttime def end sendevent } if pause userdict end PSTermDict begin begin % PSTermDict begin dictstackexch PSTermInit PSTermDict userinit known { userinit cvx exec } if cdef CreateWindow(x, y, fs, col, lines, string framelabel, string iconlabel, string initialfont, starticonic, iconx, icony) x y fs col lines framelabel iconlabel initialfont starticonic iconx icony createwindow cdef StartInput() startinput cdef ReInitialize() resetscale cdef CursorUp(x,y,cstring c) c x y CU cdef CursorDown(x,y,cstring c) c x y CD cdef PaintUnderRev(cstring s) s UR cdef PaintUnderNor(cstring s) s UN cdef PaintRev(cstring s) s PR cdef PaintNor(cstring s) s PN cdef MoveTo(x, y) x y MT cdef ClearToEndOfLine() CE cdef CopyLines(yfrom, yby, w, nl) yby w yfrom nl CL cdef BeginRepair() BRP cdef EndRepair() ERP cdef EndRefresh() EOR cdef SetFrameLabel(string str) str SL cdef SetSelContents(r, s, l, cstring str) str s l r setselcontents cdef RingBell() VB % no audible bell as yet cdef VisibleBell() VB cdef SetPageMode(onoff) onoff PM cdef SetAutoMargins(onoff) onoff AM cdef StartHiLighting(strokeit) strokeit [ cdef HiLightLine(length) length cdef EndHiLighting(endcol, startcol, startrow) endcol ] startcol startrow HL cdef ClearSelectionPath() clearselectionpath cdef RePaintHiLight() PaintHiLight cdef StrHiLightLine(cstring s) s cdef StrEndHiLighting(cstring ends, cstring starts, startrow) ends ] starts startrow HL cdef TakeDownOutline() takedownoutline cdef StartSavingSelection() startselset cdef SaveSelectionPiece(cstring s) s extsel cdef FinishSavingSelection() finishselset cdef HiLightRect(startcol, startrow, endcol, endrow, strokeit) strokeit startcol startrow endcol endrow HiLightRect cdef ToggleScrollBar(len) len TSB cdef SetScrollBarValue(len, pos) len pos SSBV cdef PopMsg(string str) gsave framebuffer setcanvas currentcursorlocation str popmsg grestore @@@ Fin de tcap.cps echo tcap_ops.c cat >tcap_ops.c <<'@@@ Fin de tcap_ops.c' /* * This file is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. * Users may copy, modify or distribute this file at will. * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * This file is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even * if Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 * * Modifications to the original Sun Microsystems, Inc. source code * made by the Grasshopper Group are in the Public Domain. * * Extensions to this file by Eric Messick of the Grasshopper Group. * * Grasshopper Group * 212 Clayton St * San Francisco, CA 94117 * */ #ifndef lint static char sccsid[] = "@(#)tcap_ops.c 9.6 88/01/19 Copyright 1985 Sun Micro"; static char RCSid[] = "@(#)$Header: tcap_ops.c,v 2.3 88/10/04 05:59:59 gnu Release $"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- tcap_ops.c tcap_ops.c, Mon Mar 24 11:52:31 1986 David Rosenthal, Sun Microsystems */ #include <stdio.h> #include <sys/types.h> #ifdef REF #include <ref/config.h> #endif #include "termcap.h" #include "tcap.h" /* * Termcap operations module. * * The external interface of this module is the array T[] and its * number of elements Ts, plus the initialization routine: * tc_init_ops() */ #include "screen.h" extern int CharsPerLine; extern int LinesPerScreen; extern struct pair Dot; extern struct tcap T[]; extern int Ts; extern char *malloc(); #ifndef bcopy extern void bcopy(); #endif #ifndef bzero extern void bzero(); #endif extern char *strncpy(); static struct tcap *tc_lookup(); static u_short TopLineOfScrollRegion, BottomLineOfScrollRegion; static struct pair SavedCursor; static u_short ScrollNLKludge = 0; struct tcap *CheckCR = 0; struct tcap *CheckNL = 0; struct tcap *CheckBS = 0; struct tcap *CheckTAB = 0; static unsigned int PermanentModes = 0, TemporaryModes = 0; static char *FrameLabel; static u_short FLindex; static int (*prevInput)(); struct tcap interruptedOp = { 0 }; struct line *lastInputLine; int PageFull = 0; static int PrevPageMode = -1; extern int PageMode; extern int userLinesPerScreen; extern int userCharsPerLine; static int al_op(), clear_body(), ce_op(), cm_in(), cs_op(); static int dc_op(), dl_op(), ic_op(), nl_op(), sf_op(); tc_init_ops() { struct tcap *me, *tc; if (userLinesPerScreen > 0) LinesPerScreen = userLinesPerScreen; if (userCharsPerLine > 0) CharsPerLine = userCharsPerLine; Dot.x = 0 ; Dot.y = LinesPerScreen - 1 ; TopLineOfScrollRegion = 0; BottomLineOfScrollRegion = LinesPerScreen - 1; FrameLabel = malloc((unsigned)CharsPerLine+1); /* * Beware of termcap entries that define ue and/or se identical * to me (turn off ALL attributes). Since we just pattern * match, it's likely we won't get me_op in normal operation, * so force the entries here. (known for vt100) */ me = tc_lookup("me"); if (me) { tc = tc_lookup("ue"); if (tc && tc->t_size == me->t_size && bcmp(me->t_text, tc->t_text, (int)tc->t_size) == 0) tc->t_op = me->t_op; tc = tc_lookup("se"); if (tc && tc->t_size == me->t_size && bcmp(me->t_text, tc->t_text, (int)tc->t_size) == 0) tc->t_op = me->t_op; } /* * Check for sf == \n, if so we must kludge things so that * sf_op will call nl_op as needed (exists on bitgraph). */ tc = tc_lookup("sf"); if (tc && tc->t_size == 1 && tc->t_text[0] == '\n') ScrollNLKludge = 1; /* * To minimize the number of times the regular text processing * is stopped to invoke the pattern matcher we check the most * strings CR, NL, BS, and TAB to see if they are \r, \n, \b,, * and \t, respectively. If any are, a quick check on the character * is made before the pattern matching machinery is invoked. */ tc = tc_lookup("cr"); if (tc && tc->t_size == 1 && tc->t_text[0] == '\r') CheckCR = tc; tc = tc_lookup("nl"); if (tc && tc->t_size == 1 && tc->t_text[0] == '\n') CheckNL = tc; tc = tc_lookup("bc"); if (tc && tc->t_size == 1 && tc->t_text[0] == '\b') CheckBS = tc; tc = tc_lookup("ta"); if (tc && tc->t_size == 1 && tc->t_text[0] == '\t') CheckTAB = tc; } tc_initmodemenu() { /* * Insure menu items properly reflect initial settings. */ SetPageMode(PageMode); SetAutoMargins(PermanentModes & AutoMarginMode); } static struct tcap * tc_lookup(key) char *key; { register struct tcap *tp; for (tp = T; *tp->t_key; tp++) if (strcmp(tp->t_key, key) == 0) return (tp); return ((struct tcap *)0); } /* * scrollreset is called whenever keyboard input is seen, in order to * do deferred scrolling and remember the last line on which the user * typed something. */ scrollreset(l) int l; { int n = PageFull; PageFull = 0; lastInputLine = (l == 1) ? screen[1] : 0; while (n-- > 0 && !PageFull) sf_op((struct tcap *) 0); if (lastInputLine == 0) lastInputLine = screen[Dot.y]; } toggleautomargins() { PermanentModes ^= (unsigned int) AutoMarginMode; SetAutoMargins(PermanentModes & AutoMarginMode); FlushPostScript(); } togglepagemode() { SetPageMode(PageMode = !PageMode); FlushPostScript(); } resetscreensize(row, col) int row, col; { struct tcap t; int dotx, doty; dotx = Dot.x ; if (dotx >= col) dotx = col - 1; doty = Dot.y - LinesPerScreen + row ; if (doty >= row) doty = row - 1; if (doty < 0) doty = 0 ; if (PageMode) { /* no scroll stop line */ lastInputLine = screen[doty - row + LinesPerScreen]; } CharsPerLine = col ; LinesPerScreen = row ; t.t_x = LinesPerScreen - 1 ; t.t_y = 0 ; cs_op(&t); /* change scrolling region to full screen */ /* if it wasn't full screen before, then it's the * program's responsibility to change it after * getting the sigwinch * note that this trashes Dot, so we save it. */ Dot.x = dotx ; Dot.y = doty ; } #ifdef notdef static trace(s, t) register char *s; register struct tcap *t; { register char *q = t->t_text; fprintf(stderr, "%s: ", s); fprintf(stderr, "[%s,", t->t_key); if (q == NULL) fprintf(stderr, "(nil)"); else while (*q) { if (*q < ' ') { fprintf(stderr, "^%c", *q + '@'); } else { fprintf(stderr, "%c", *q); } q++; } fprintf(stderr, ",%d,(%d,%d)]\n", t->t_index, t->t_x, t->t_y); } #endif #ifndef notdef #define trace(X, Y) (void)(X, Y) #endif #define ChangeScreen() #define MoveCursor() #ifdef notdef static PrintScreen() { register int y; for (y = 0; y < LinesPerScreen; y++) { register struct line *l = screen[y]; register int x; if (l == NULL) fprintf(stderr, "(nil)"); else for (x = 0; x < l->length; x++) { if (x == Dot.x && y == Dot.y) fprintf(stderr, "+"); else if (x == l->changeposition) fprintf(stderr, "|"); else fprintf(stderr, "%c", (l->body[x] == ' ' ? '.' : l->body[x])); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } #endif showc(t) struct tcap *t; { register char *cp = t->t_text; register struct line *l; register int dotx, c; register unsigned Modes = PermanentModes | TemporaryModes; int n = t->t_size; register char *bp; register u_char *pp; trace("==", t); TemporaryModes = 0; dotx = Dot.x; while (n > 0 && !PageFull) { l = screen[Dot.y]; if (l->changeposition > dotx) l->changeposition = dotx; if (l->length < dotx) l->length = dotx; bp = &l->body[dotx] ; pp = &l->prop[dotx] ; if (Modes & InsertMode && l->length > dotx) { n-- ; c = *cp++; if (c < ' ' || c >= 0177) continue; if (l->length < CharsPerLine) l->length++; bcopy((char *)pp, (char *)pp+1,(int)(l->length-dotx-1)); bcopy( bp, bp+1,(int)(l->length-dotx-1)); l->end_of_changes = CharsPerLine + 1 ; *bp = c; *pp = (Modes & Attributes); if (++dotx >= CharsPerLine) { if (Modes & AutoMarginMode) { trace("cr", t); l->end_of_changes = CharsPerLine + 1 ; l->flags |= LINE_WRAPPED ; if (l->length < dotx) l->length = dotx ; dotx = 0; MoveCursor(); nl_op(t); TemporaryModes |= WrapJustHappenedMode; } else dotx = CharsPerLine - 1; } } else { while (n-- > 0 && !PageFull) { c = *cp++; if (c < ' ' || c >= 0177) continue; *bp++ = c; *pp++ = (Modes & Attributes); if (++dotx >= CharsPerLine) { if (Modes & AutoMarginMode) { trace("cr", t); l->end_of_changes = CharsPerLine + 1 ; l->flags |= LINE_WRAPPED ; if (l->length < dotx) l->length = dotx ; dotx = 0; MoveCursor(); nl_op(t); TemporaryModes |= WrapJustHappenedMode; break; } else dotx = CharsPerLine - 1; } } } if (l->length < dotx) l->length = dotx ; if (l->end_of_changes < dotx) l->end_of_changes = dotx; } Dot.x = dotx; ChangeScreen(); /* * If we were interrupted by nl_op setting PageFull, set up * interruptedOp with a tcap that can be used to finish this later. */ if (PageFull && ++n > 0) { interruptedOp = *t; interruptedOp.t_text += (t->t_size - n); interruptedOp.t_size = n; } else interruptedOp.t_op = 0; } static int AL_op(t) /* add multiple blank lines */ struct tcap *t; { trace("AL", t); /* cheat for now */ while (t->t_y-- > 0) al_op(t); ChangeScreen(); } static int DC_op(t) struct tcap *t; { trace("DC", t); /* cheat for now */ while (t->t_y-- > 0) dc_op(t); ChangeScreen(); } static int DL_op(t) /* delete multiple lines */ struct tcap *t; { trace("DL", t); /* cheat for now */ while (t->t_y-- > 0) dl_op(t); ChangeScreen(); } static int DO_in(t) /* move cursor down n lines */ struct tcap *t; { trace("DO", t); return (cm_in(t)); /* Neat! It might even work */ } static int DO_op(t) /* move cursor down n lines */ register struct tcap *t; { trace("DO", t); if (t->t_y >= 0 && (Dot.y + t->t_y) < LinesPerScreen) Dot.y += t->t_y; MoveCursor(); } static int IC_op(t) struct tcap *t; { trace("IC", t); /* cheat for now */ while (t->t_y-- > 0) ic_op(t); ChangeScreen(); } static int LE_in(t) /* move cursor left n characters */ struct tcap *t; { trace("LE", t); return (cm_in(t)); /* Neat! It might even work */ } static int LE_op(t) /* move cursor left n characters */ register struct tcap *t; { trace("LE", t); if ((Dot.x - t->t_y) >= 0) Dot.x -= t->t_y; MoveCursor(); } static int RI_in(t) /* move cursor right n characters */ struct tcap *t; { trace("RI", t); return (cm_in(t)); /* Neat! It might even work */ } static int RI_op(t) /* move cursor right n characters */ register struct tcap *t; { trace("RI", t); if (t->t_y >= 0 && (Dot.x + t->t_y) <= CharsPerLine) Dot.x += t->t_y; MoveCursor(); } static int UP_in(t) /* move cursor up n lines */ struct tcap *t; { trace("UP", t); return (cm_in(t)); /* Neat! It might even work */ } static int UP_op(t) /* move cursor up n lines */ register struct tcap *t; { trace("UP", t); if ((Dot.y - t->t_y) >= 0) Dot.y -= t->t_y; MoveCursor(); } static int al_op(t) /* Add new blank line */ struct tcap *t; { register struct line **p, **current; register struct line *old; trace("al", t); current = &screen[Dot.y]; p = &screen[BottomLineOfScrollRegion]; old = *p; for (; p > current; p--) *p = *(p-1); *p = old; clear_body(old, 0); old->length = 0; old->changeposition = 0; old->end_of_changes = CharsPerLine; old->usedtobe = LinesPerScreen; ChangeScreen(); } static int am_in(t) /* Has auto-margins */ struct tcap *t; { trace("am", t); if (t->t_x) PermanentModes |= AutoMarginMode; return (0); } static int bc_op(t) /* back-character */ struct tcap *t; { trace("bc", t); if (Dot.x > 0) Dot.x--; MoveCursor(); } static int bl_op(t) /* Bell character */ struct tcap *t; { trace("bl", t); RingBell(); } /* * Clearing the whole line body for the clear ops may be excessive * but nothing short of it seems to work for programs which do a lot * of cursor manipulation, such as rogue or hack. */ static int clear_body(l, x) struct line *l; int x; { register int len = l->buffer_length - x; register char *cp; bzero((char *)&l->prop[x], len); l->flags = 0 ; for (cp = &l->body[x]; len-- > 0;) *cp++ = ' '; } static int cd_op(t) /* Clear to end of display */ struct tcap *t; { register struct line **p, **last; register struct line *l; trace("cd", t); ce_op(t); last = &screen[LinesPerScreen]; for (p = &screen[Dot.y+1]; p < last; p++) { (l = *p)->length = 0; l->changeposition = 0; l->end_of_changes = CharsPerLine ; clear_body(l, 0); } ChangeScreen(); } static int ce_op(t) /* Clear to end of line */ struct tcap *t; { register struct line *l = screen[Dot.y]; trace("ce", t); l->length = Dot.x; if (l->changeposition > Dot.x) l->changeposition = Dot.x; l->end_of_changes = CharsPerLine ; clear_body(l, (int)l->length); ChangeScreen(); } static int cl_op(t) /* Clear screen */ struct tcap *t; { register struct line **p, **last; register struct line *l; trace("cl", t); Dot.x = Dot.y = 0; last = &screen[LinesPerScreen]; for (p = &screen[0]; p < last; p++) { (l = *p)->length = 0; l->changeposition = 0; l->end_of_changes = CharsPerLine ; clear_body(l, 0); } ChangeScreen(); if (PageMode) lastInputLine = screen[Dot.y]; /* no scroll stop line */ } #ifdef HAVE_TERMCAP static int cm_in(t) /* Cursor motion */ register struct tcap *t; { register u_char c; char buf[128]; register char *cp = t->t_text, *bp = buf; trace("cm", t); if (cp == NULL) return(0); /* Pre-process out parts of the % escapes */ while ((c = *cp++) != '\0') { if (c == '%') { register u_char c2 = *cp++; switch (c2) { case '+': /* Subtract next then %. */ switch (t->t_2nd + t->t_pc_r) { case 0: case 2: t->t_yi = *cp++; break; case 1: t->t_xi = *cp++; break; } c2 = '.'; goto percent_dot; case '>': switch (t->t_2nd + t->t_pc_r) { case 1: t->t_xilim = *cp++; t->t_xi = *cp++; t->t_xilim += t->t_xi + 1; break; case 0: case 2: t->t_yilim = *cp++; t->t_yi = *cp++; t->t_yilim += t->t_yi + 1; break; } t->t_2nd = !t->t_2nd; break; case 'r': t->t_pc_r = 1; break; case 'i': t->t_xi++; t->t_yi++; break; case 'n': t->t_pc_n = 1; break; case 'B': t->t_pc_B = 1; break; case 'D': t->t_pc_D = 1; break; /* The following ones will be interpreted on the fly */ case 'd': /* series of decimal digits */ case '2': /* two decimal digits */ case '3': /* three decimal digits */ case '.': /* binary character */ percent_dot: case '%': *bp++ = c; *bp++ = c2; t->t_2nd = !t->t_2nd; break; default: /* Bad % escape */ return (1); } } else { *bp++ = c; } } *bp++ = '\0'; if (bp-buf > 1) { if ((t->t_text = malloc((unsigned)(bp-buf+1))) == NULL) return (2); strncpy(t->t_text, buf, bp-buf); t->t_size = bp-buf - 1; } else { t->t_text = NULL; } t->t_2nd = 0; return (0); } #else /* !HAVE_TERMCAP */ static int cm_in(t) /* Cursor motion */ register struct tcap *t; { register u_char c; char buf[128]; register char *cp = t->t_text, *bp = buf; trace("cm", t); if (cp == NULL) return(0); /* Pre-process out parts of the % escapes */ while ((c = *cp++) != '\0') { static int seen1 = 0; if (c == '%') { register u_char c2 = *cp++; switch (c2) { case 'p': switch (*cp++) { case '1': seen1++; t->t_2nd = 0; break; case '2': if (!seen1) t->t_pc_r = 1; t->t_2nd = 1; break; /* * This capability is not available in termcap so we will * assume that it is not present in terminfo either. This * means that terminal that send more than two pieces of * variable data with the "cm" directive will not work. * Currently for "cm" only two variables are defined. */ case '3': case '4': case '5': case '6': case '7': case '8': case '9': return(1); } break; case '\'': /* store constant for future operator */ switch (t->t_2nd + t->t_pc_r) { case 0: case 2: t->t_yi = *cp++; break; case 1: t->t_xi = *cp++; break; } if (*cp == '\'') cp++; /* blow past the trailing '\'' */ else return(1); break; case '{': /* store decimal constant for future operator */ switch (t->t_2nd + t->t_pc_r) { case 0: case 2: t->t_yi = ((*cp++) * 10) + (*cp++); break; case 1: t->t_xi = ((*cp++) * 10) + (*cp++); break; } if (*cp == '}') cp++; /* blow past trailing '}' */ else return(1); break; /* the following will not work do to the simplifications here */ case '?': /* if */ case 't': /* then */ case 'e': /* else */ return(1); /* lets not delude ourselves, the data * structures were set up to deal with termcap * not the complexities of terminfo. */ case 'i': t->t_xi++; t->t_yi++; break; case '+': if (*cp++ != '%') return(1); if (*cp++ != 'c') return(1); *bp++ = '%'; /* make it look like termcap */ *bp++ = '.'; break; /* use the simpified model of termcap so some of this * stuff is not valid */ case '\b': /* flags in format string */ case ':': /* needed for '-' and '+' flags */ case '#': /* flags in format string */ case '.': /* if only fract part of precision */ return(1); /* just leave a 'd' */ case '0': /* numeric part of precision */ case '1': /* numeric part of precision */ case '4': /* numeric part of precision */ case '5': /* numeric part of precision */ case '6': /* numeric part of precision */ case '7': /* numeric part of precision */ case '8': /* numeric part of precision */ case '9': /* numeric part of precision */ /* skip past the end of this definition, leave %d in its place*/ while (*cp != 'd' && *cp != 'o' && *cp != 'x' && *cp != 'X' && *cp != 's') cp++; /* don't support anything but 'd' */ if (*cp != 'd') return(1); *bp++ = c; /* '%' */ *bp++ = *cp++; /* 'd' */ /* The following ones will be interpreted on the fly. */ case '2': /* numeric part of precision */ case '3': /* numeric part of precision */ /* remove %[23]->[doxXs], put %[23] in bp */ *bp++ = c; *bp++ = c2; /* skip any factional part of the precision */ while (*cp != 'd' && *cp != 'o' && *cp != 'x' && *cp != 'X' && *cp != 's') cp++; /* don't support anything but 'd' */ if (*cp != 'd') return(1); *cp++; /* get rid of the 'd' */ break; /* not suported by termcap, so not supported here */ case 'o': /* octal: no other formating is present */ case 'x': /* hex: no other formating is present */ case 'X': /* HEX: no other formating is present */ case 's': /* String: no other formating is present */ case 'c': /* binary character */ case 'l': /* strlen() operator */ case '=': /* equal operator */ case '>': /* greater than operator */ case '<': /* less than operator */ case '-': /* subtract operator */ case '*': /* multiply operator */ case '/': /* divide operator */ case 'm': /* modula operator */ case '&': /* bitwise and operator */ case '|': /* bitwise or operator */ case '^': /* bitwise xor operator */ case '~': /* bitwise not operator */ case 'A': /* logical and operator */ case 'O': /* logical or operator */ case '!': /* logical not operator */ return(1); /* include the string "%A" where A = one of the following cases */ case 'd': /* decimal: no other formating is present */ case '%': *bp++ = c; *bp++ = c2; break; default: /* Bad % escape */ return (1); } } else { *bp++ = c; } } *bp++ = '\0'; if (bp-buf > 1) { if ((t->t_text = malloc(bp-buf+1)) == NULL) return (2); strncpy(t->t_text, buf, bp-buf); t->t_size = bp-buf - 1; } else { t->t_text = NULL; } t->t_2nd = 0; return (0); } #endif /* !HAVE_TERMCAP */ static int cm_op(t) /* Cursor motion */ register struct tcap *t; { trace("cm", t); lastInputLine = 0; /* no scroll stop line */ if (t->t_x >= 0 && t->t_x < CharsPerLine) Dot.x = t->t_x; if (t->t_y >= 0 && t->t_y < LinesPerScreen) Dot.y = t->t_y; MoveCursor(); } static int co_in(t) /* number of columns */ struct tcap *t; { trace("co", t); if (userCharsPerLine < 1) CharsPerLine = t->t_x; return (0); } static int cr_op(t) /* carriage return */ struct tcap *t; { trace("cr", t); Dot.x = 0; MoveCursor(); } static int cs_in(t) /* change scroll region */ struct tcap *t; { trace("cs", t); return (cm_in(t)); /* Neat! It might even work */ } static int cs_op(t) /* change scroll region */ register struct tcap *t; { trace("cs", t); if (t->t_y >= t->t_x || t->t_x >= LinesPerScreen) return; Dot.x = 0; Dot.y = t->t_y; TopLineOfScrollRegion = t->t_y; BottomLineOfScrollRegion = t->t_x; lastInputLine = 0; /* no scroll stop line */ MoveCursor(); } static int dc_op(t) /* delete character */ struct tcap *t; { register struct line *l = screen[Dot.y]; register int dotx = Dot.x; int len; trace("dc", t); if (l->changeposition > dotx) l->changeposition = dotx; if (dotx < l->length) { l->length--; len = l->length - dotx; bcopy((char *)&l->prop[dotx+1], (char *)&l->prop[dotx], len); l->prop[l->length] = 0 ; bcopy(&l->body[dotx+1], &l->body[dotx], len); l->body[l->length] = ' ' ; } l->end_of_changes = CharsPerLine ; ChangeScreen(); } static int dl_op(t) /* delete line */ struct tcap *t; { register struct line **p, **bottom; register struct line *old = screen[Dot.y]; trace("dl", t); lastInputLine = 0; /* no scroll stop line */ bottom = &screen[BottomLineOfScrollRegion]; for (p = &screen[Dot.y]; p < bottom; p++) *p = *(p+1); *p = old; clear_body(old, 0); old->length = 0; old->changeposition = 0; old->end_of_changes = CharsPerLine ; old->usedtobe = LinesPerScreen ; ChangeScreen(); } static int do_op(t) /* down one line */ struct tcap *t; { trace("do", t); if (PermanentModes & IgnoreNewlineAfterWrapMode) { if (TemporaryModes & WrapJustHappenedMode) { TemporaryModes &= ~WrapJustHappenedMode; return; } } if (Dot.y < LinesPerScreen - 1) Dot.y++; else { sf_op(t); } MoveCursor(); } static int ei_op(t) /* end insert mode */ struct tcap *t; { trace("ei", t); PermanentModes &= ~InsertMode; } static int el_op(t) /* end frame label definition mode */ struct tcap *t; { if (FrameLabel) { FrameLabel[FLindex] = '\0'; SetFrameLabel(FrameLabel); } t = T+Ts; t->t_op = prevInput; } static int ke_op(t) /* leave keyboard transmit mode */ struct tcap *t; { trace("ke", t); } static int ks_op(t) /* enter keyboard transmit mode */ struct tcap *t; { trace("ks", t); } static int ho_op(t) /* home cursor */ struct tcap *t; { trace("ho", t); lastInputLine = 0; /* no scroll stop line */ Dot.x = Dot.y = 0; MoveCursor(); } static int ic_op(t) /* insert character */ struct tcap *t; { trace("ic", t); TemporaryModes |= InsertMode; } static int im_op(t) /* enter insert mode */ struct tcap *t; { trace("im", t); PermanentModes |= InsertMode; } static int le_op(t) /* cursor left */ struct tcap *t; { trace("le", t); if (Dot.x > 0) Dot.x--; MoveCursor(); } static int li_in(t) /* number of lines */ struct tcap *t; { trace("li", t); if (userLinesPerScreen < 1) LinesPerScreen = t->t_x; return (0); } static int ll_op(t) /* last line first column */ struct tcap *t; { trace("ll", t); Dot.x = 0; Dot.y = LinesPerScreen - 1; MoveCursor(); } static int lm_op(t) /* label mode input */ register struct tcap *t; { trace("lm", t); if (FLindex + t->t_size >= CharsPerLine) t->t_size = CharsPerLine - FLindex; if (t->t_size > 0) { if (FrameLabel) strncpy(&FrameLabel[FLindex], t->t_text, (int)t->t_size); FLindex += t->t_size; } } static int mb_op(t) /* enable blink */ struct tcap *t; { trace("mb", t); PermanentModes |= BlinkMode; } static int md_op(t) /* enter bold mode */ struct tcap *t; { trace("md", t); PermanentModes |= BoldMode; } static int me_op(t) /* turn off attributes */ struct tcap *t; { trace("me", t); PermanentModes &= ~(Attributes); } static int mr_op(t) /* enter reverse video */ struct tcap *t; { trace("mr", t); PermanentModes |= ReverseVideoMode; } static int nd_op(t) /* cursor right */ struct tcap *t; { trace("nd", t); if (Dot.x < (CharsPerLine - 1)) Dot.x++; MoveCursor(); } static int nl_op(t) /* newline */ struct tcap *t; { trace("nl", t); if (PermanentModes & IgnoreNewlineAfterWrapMode) { if (TemporaryModes & WrapJustHappenedMode) { TemporaryModes &= ~WrapJustHappenedMode; return; } } if (Dot.y < LinesPerScreen - 1) Dot.y++; else { sf_op(t); } MoveCursor(); } static int rc_op(t) /* restore cursor */ struct tcap *t; { trace("rc", t); Dot = SavedCursor; MoveCursor(); } static int sc_op(t) /* save cursor */ struct tcap *t; { trace("sc", t); SavedCursor = Dot; MoveCursor(); } static int se_op(t) /* leave stand-out */ struct tcap *t; { trace("se", t); PermanentModes &= ~StandOutMode; } static int so_op(t) /* enter stand-out */ struct tcap *t; { trace("so", t); PermanentModes |= StandOutMode; } static int sf_op(t) /* scroll forwards */ struct tcap *t; { register struct line **p, **bottom; register struct line *old; static int SFrecur = 0; trace("sf", t); /* * When sf is "\n", nl_op won't be called, so we emulate * it's actions here (beware of recursion). */ if (ScrollNLKludge && !SFrecur) { SFrecur++; nl_op(t); SFrecur--; return (1); /* XXX */ } p = &screen[TopLineOfScrollRegion]; if (PageMode && *p == lastInputLine) { PageFull++; /* can't scroll this line */ return (0); } ScrollSaveLine(*p); bottom = &screen[BottomLineOfScrollRegion]; p = &screen[TopLineOfScrollRegion]; old = *p; for (; p < bottom; p++) *p = *(p+1); *p = old; clear_body(old, 0); old->length = 0; old->changeposition = 0; old->end_of_changes = CharsPerLine ; old->usedtobe = LinesPerScreen; ChangeScreen(); return (1); } static int sl_op(t) /* start defining new frame label */ register struct tcap *t; { trace("sl", t); FLindex = 0; t = T+Ts; prevInput = t->t_op; t->t_op = lm_op; } static int sr_op(t) /* scroll reverse */ struct tcap *t; { register struct line **p, **top; register struct line *old; trace("sr", t); lastInputLine = 0; /* no scroll stop line */ top = &screen[TopLineOfScrollRegion]; p = &screen[BottomLineOfScrollRegion]; old = *p; for (; p > top; p--) *p = *(p-1); *p = old; clear_body(old, 0); old->length = 0; old->changeposition = 0; old->end_of_changes = CharsPerLine ; old->usedtobe = LinesPerScreen; ChangeScreen(); } static int ta_op(t) /* tab */ struct tcap *t; { trace("ta", t); Dot.x = (Dot.x & ~07) + 010; if (Dot.x >= CharsPerLine - 1) Dot.x = CharsPerLine - 1; MoveCursor(); } static int te_op(t) /* end use of termcap */ struct tcap *t; { trace("te", t); if (PrevPageMode != -1) { PageMode = PrevPageMode; PrevPageMode = -1; } } static int ti_op(t) /* begin use of termcap */ { trace("ti", t); /* * Turn off page mode when using termcap. */ if (PrevPageMode == -1) { PrevPageMode = PageMode; PageMode = 0; } } static int ue_op(t) /* end underline */ struct tcap *t; { trace("ue", t); PermanentModes &= ~UnderlineMode; } static int up_op(t) /* cursor up */ struct tcap *t; { trace("up", t); if (Dot.y > 0) Dot.y--; else /* vi will never do this, but some ll caps may */ Dot.y = LinesPerScreen - 1; MoveCursor(); } static int us_op(t) /* start underline */ struct tcap *t; { trace("us", t); PermanentModes |= UnderlineMode; } static int vb_op(t) /* visibile bell */ struct tcap *t; { trace("bl", t); VisibleBell(); } static int xn_in(t) struct tcap *t; { trace("xn", t); if (t->t_x) PermanentModes |= IgnoreNewlineAfterWrapMode; return (0); } /* These capabilities are numeric or boolean - they dont have ops */ #define am_op NULL #define bs_op NULL #define co_op NULL #define li_op NULL #define pc_op NULL #define xn_op NULL /* These capabilities are strings that dont need initialization */ #define al_in NULL #define bc_in NULL #define bl_in NULL #define cd_in NULL #define ce_in NULL #define cl_in NULL #define cr_in NULL #define dc_in NULL #define dl_in NULL #define do_in NULL #define ei_in NULL #define ke_in NULL #define ks_in NULL #define ho_in NULL #define ic_in NULL #define im_in NULL #define le_in NULL #define ll_in NULL #define mb_in NULL #define md_in NULL #define me_in NULL #define mr_in NULL #define nd_in NULL #define nl_in NULL #define pc_in NULL #define rc_in NULL #define sc_in NULL #define se_in NULL #define sf_in NULL #define so_in NULL #define sr_in NULL #define ta_in NULL #define ue_in NULL #define up_in NULL #define us_in NULL #define s string #define n num #define b bool struct tcap T[] = { /* * key ty op in text deftx sz in tmp tf * x xi xl y yi yl r n B D 2 */ {"AL", s, AL_op, cs_in, NULL, NULL, 0, 0, NULL, 0}, {"DL", s, DL_op, cs_in, NULL, NULL, 0, 0, NULL, 0}, {"DC", s, DC_op, cs_in, NULL, NULL, 0, 0, NULL, 0}, {"DO", s, DO_op, DO_in, NULL, NULL, 0, 0, NULL, 0}, {"IC", s, IC_op, cs_in, NULL, NULL, 0, 0, NULL, 0}, {"LE", s, LE_op, LE_in, NULL, NULL, 0, 0, NULL, 0}, {"RI", s, RI_op, RI_in, NULL, NULL, 0, 0, NULL, 0}, {"UP", s, UP_op, UP_in, NULL, NULL, 0, 0, NULL, 0}, {"al", s, al_op, al_in, NULL, NULL, 0, 0, NULL, 0}, {"am", b, am_op, am_in, NULL, NULL, 0, 0, NULL, 0}, {"bc", s, bc_op, bc_in, NULL, "\10", 0, 0, NULL, 0}, {"bl", s, bl_op, bl_in, NULL, "\7", 0, 0, NULL, 0}, {"cd", s, cd_op, cd_in, NULL, NULL, 0, 0, NULL, 0}, {"ce", s, ce_op, ce_in, NULL, NULL, 0, 0, NULL, 0}, {"cl", s, cl_op, cl_in, NULL, NULL, 0, 0, NULL, 0}, {"cm", s, cm_op, cm_in, NULL, NULL, 0, 0, NULL, 0}, {"co", n, co_op, co_in, NULL, NULL, 0, 0, NULL, 0}, {"cr", s, cr_op, cr_in, NULL, "\015", 0, 0, NULL, 0}, {"cs", s, cs_op, cs_in, NULL, NULL, 0, 0, NULL, 0}, {"dc", s, dc_op, dc_in, NULL, NULL, 0, 0, NULL, 0}, {"dl", s, dl_op, dl_in, NULL, NULL, 0, 0, NULL, 0}, {"do", s, do_op, do_in, NULL, NULL, 0, 0, NULL, 0}, {"ei", s, ei_op, ei_in, NULL, NULL, 0, 0, NULL, 0}, {"el", s, el_op, NULL, NULL,"\033\\",0, 0, NULL, 0}, /* end label */ {"ke", s, ke_op, ke_in, NULL, NULL, 0, 0, NULL, 0}, {"ks", s, ks_op, ks_in, NULL, NULL, 0, 0, NULL, 0}, {"ho", s, ho_op, ho_in, NULL, NULL, 0, 0, NULL, 0}, {"ic", s, ic_op, ic_in, NULL, NULL, 0, 0, NULL, 0}, {"im", s, im_op, im_in, NULL, NULL, 0, 0, NULL, 0}, {"le", s, le_op, le_in, NULL, NULL, 0, 0, NULL, 0}, {"li", n, li_op, li_in, NULL, NULL, 0, 0, NULL, 0}, {"ll", s, ll_op, ll_in, NULL, NULL, 0, 0, NULL, 0}, {"lm", s, lm_op, NULL, NULL, NULL, 0, 0, NULL, 0}, /* label mode input */ {"mb", s, mb_op, mb_in, NULL, NULL, 0, 0, NULL, 0}, {"md", s, md_op, md_in, NULL, NULL, 0, 0, NULL, 0}, {"me", s, me_op, me_in, NULL, NULL, 0, 0, NULL, 0}, {"mr", s, mr_op, mr_in, NULL, NULL, 0, 0, NULL, 0}, {"nd", s, nd_op, nd_in, NULL, NULL, 0, 0, NULL, 0}, {"nl", s, nl_op, nl_in, NULL, "\012", 0, 0, NULL, 0}, {"pc", s, pc_op, pc_in, NULL, "\200", 0, 0, NULL, 0}, {"rc", s, rc_op, rc_in, NULL, NULL, 0, 0, NULL, 0}, {"sc", s, sc_op, sc_in, NULL, NULL, 0, 0, NULL, 0}, {"se", s, se_op, se_in, NULL, NULL, 0, 0, NULL, 0}, {"sf", s, sf_op, sf_in, NULL, NULL, 0, 0, NULL, 0}, {"sl", s, sl_op, NULL, NULL,"\033]l",0, 0, NULL, 0}, /* start label */ {"so", s, so_op, so_in, NULL, NULL, 0, 0, NULL, 0}, {"sr", s, sr_op, sr_in, NULL, NULL, 0, 0, NULL, 0}, {"ta", s, ta_op, ta_in, NULL, "\011", 0, 0, NULL, 0}, /* XXX */ {"te", s, te_op, NULL, NULL, NULL, 0, 0, NULL, 0}, {"ti", s, ti_op, NULL, NULL, NULL, 0, 0, NULL, 0}, {"ue", s, ue_op, ue_in, NULL, NULL, 0, 0, NULL, 0}, {"up", s, up_op, up_in, NULL, NULL, 0, 0, NULL, 0}, {"us", s, us_op, us_in, NULL, NULL, 0, 0, NULL, 0}, {"vb", s, vb_op, NULL, NULL, NULL, 0, 0, NULL, 0}, {"xn", b, xn_op, xn_in, NULL, NULL, 0, 0, NULL, 0}, {"", s, showc, NULL, NULL, NULL, 0, 0, NULL, 0}, }; /* T[Ts] is a special case - its the display-character operation */ int Ts = (sizeof T)/(sizeof T[0]) - 1; @@@ Fin de tcap_ops.c echo tcap_parse.c cat >tcap_parse.c <<'@@@ Fin de tcap_parse.c' /* * This file is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. * Users may copy, modify or distribute this file at will. * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * This file is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even * if Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 * * Modifications to the original Sun Microsystems, Inc. source code * made by the Grasshopper Group are in the Public Domain. * * Extensions to this file by Eric Messick of the Grasshopper Group. * * Grasshopper Group * 212 Clayton St * San Francisco, CA 94117 * */ #ifndef lint static char sccsid[] = "@(#)tcap_parse.c 9.5 88/01/19 Copyright 1985 Sun Micro"; static char RCSid[] = "@(#)$Header: tcap_parse.c,v 2.3 88/10/04 06:00:03 gnu Release $"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- tcap_parse.c: Parse termcap output based on termcap entry. tcap_parse.c, Mon Mar 24 11:25:44 1986 David Rosenthal, Sun Microsystems */ /* XXX - remember longest outstanding partial match? */ /* XXX - overlapping partial matches? */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #ifdef REF #include <ref/config.h> #endif #include "termcap.h" extern char *malloc(); #ifndef bcopy extern void bcopy(); #endif static int TerminalIsBraindamaged = 0; /* Import these from tcap_ops.c */ extern struct tcap T[]; extern int Ts; extern struct tcap *CheckCR; extern struct tcap *CheckNL; extern struct tcap *CheckTAB; extern struct tcap *CheckBS; extern int PageFull; extern int PageMode; static char *unpad(); static int tc_init_stacks(); /* * Initialize the display system from the TERMCAP entry. * We parse the entry and build the tcap structures * describing the operations supported by this type of * terminal. These descriptions are then used by tc_display() * in interpreting the data stream generated by the * application */ int tc_initialize(term) char *term; { #ifdef SUNTGETENT static void tc_fix_tcap_ent(); #endif static char tcapbuf[1024], tcaparea[1024]; char *areap = tcaparea; extern int tgetent(), tgetnum(), tgetflag(); extern char *tgetstr(); register struct tcap *tp; if (tgetent(tcapbuf, term) != 1) { /* unknown terminal type? */ fprintf(stderr, "tgetent failed\n"); return (1); } #ifdef SUNTGETENT tc_fix_tcap_ent(tcapbuf); #endif set_environment_var("TERMCAP", tcapbuf); for (tp = T; tp < T+Ts; tp++) { switch (tp->t_type) { case string: tp->t_text = unpad(tgetstr(tp->t_key, &areap)); if (tp->t_text == NULL) tp->t_text = tp->t_deftext; if (tp->t_text) { tp->t_size = strlen(tp->t_text); if (isprint(tp->t_text[0])) TerminalIsBraindamaged = 1; } else tp->t_size = 0; break; case num: tp->t_x = tgetnum(tp->t_key); break; case bool: tp->t_x = tgetflag(tp->t_key); break; } /* invoke any initialize routine */ if (tp->t_in && (*tp->t_in)(tp)) { fprintf(stderr, "termcap init failed for %s\n", tp->t_key); return (1); } } tc_init_ops(); return tc_init_stacks(); } #ifdef HAVE_TERMCAP static char * unpad(s) register char *s; { if (s) { register pad = 0; while (isdigit(*s)) pad++, s++; if (pad && *s == '*') s++; } return (s); } #else /* !HAVE_TERMCAP, ie next code is for TERMINFO */ /* * Remove the substring of the form "$<x^>" where x = number, and ^ = characters * in the set [* /]. This is the terminfo way of specifying delays or padding. */ static char * unpad(s) register char *s; { if (s) { register char *spt = s; register char *spt1, *spt2; char *strchr(); while (spt1 = strchr(spt, '$')) { if (*(spt1 + 1) == '<') { /* found the '$<' pair */ if (spt2 = strchr(spt1, '>')) { strcpy(spt1, ++spt2); /* found end '>' */ spt = spt1; /* copy tail of */ continue; /* string over */ /* '$<..', look */ /* for more */ } else break; /* no match for '$<' so quit */ } else { spt = spt1 + 1; /* found '$' but no '<', */ continue; /* look for more */ } } } return (s); } #endif /* !HAVE_TERMCAP */ #ifdef SUNTGETENT #define TCAPBUFSIZE 1024 #define SPECIALSIZE 2 static struct { char *last; char str[3]; } tcapSpecials[SPECIALSIZE] = { NULL, "co", NULL, "li" }; /* * Stomp on the first "co" and "li" entries in the termcap entry * to avoid braindamage in the Sun version of the termcap library. * Apparently the Sun version of tgetent() looks at the terminal * state and uses this to prepend extra line+column spec's that * reflect the terminal's current state. This is not what we want, * so our only recourse is to undo the this braindamage here. */ static void tc_fix_tcap_ent(buf) char *buf; { char *bp = buf; #ifndef SYSVREF char *index(); #else #define index(s, c) (char *)strchr(s, c) #endif int i; /* for each item in buf ... */ for (bp = index(bp, ':'); bp && *(bp+1); bp = index(bp, ':')) { ++bp; /* for each special tcap code ... */ for (i = 0; i < SPECIALSIZE; i++) { if (strncmp(tcapSpecials[i].str, bp, 2) == 0) { if (tcapSpecials[i].last) strncpy(tcapSpecials[i].last, "xx", 2); tcapSpecials[i].last = bp; break; } } } } #endif /* SUNTGETENT */ /* * Matching is performed with a push-down automata implemented * with dual stacks. An initial stack is loaded with all the * potential matches from the termcap structure. Matching then * takes place by popping each potential match off the ``current * stack'' and, if a successful match for the current character * occurs, pushing the match on the ``other stack''. When the * ``current stack'' is empty (all elements have been examined), * the stacks are swapped and the process restarted. This continues * until a completed match or the stack of potential matches has * been exhausted. */ static struct tcap **curstack, **cursp; /* ``potential match'' stack */ static struct tcap **otherstack, **othersp; /* ``match this pass'' stack */ static struct tcap **resetstack; /* prototype curstack */ static int stacksize; /* # of potential matches */ static int MatchInProgress; /* for fast check */ #define PushMatch(tp) (*--othersp = tp) #define PopMatch() (*cursp++) #define PopMatched() (*othersp++) #define SwapStacks() { \ struct tcap **t; \ t = curstack, curstack = otherstack, otherstack = t; \ cursp = othersp, othersp = otherstack + stacksize; \ MatchInProgress = 1; \ } #define ResetMatchStack() { \ bcopy((char *)resetstack, (char *)curstack, \ stacksize*sizeof (struct tcap *)); \ cursp = curstack; \ MatchInProgress = 0; \ } #define FlushStack(sp, stack) { \ while (sp < stack+stacksize) { \ tp = *sp++; \ tp->t_index = 0; \ tp->t_param = 0 ; \ tp->t_matched = 0; \ tp->t_2nd = 0; \ } \ } #define FlushMatchStack() FlushStack(cursp, curstack) #define FlushMatchedStack() FlushStack(othersp, otherstack); #define MatchStackEmpty() (cursp >= curstack+stacksize) #define MatchedStackEmpty() (othersp >= otherstack+stacksize) /* * Reset the pattern matching stack and load * it with all the potential matching entries. */ static int tc_init_stacks() { register struct tcap *tp; for (tp = T; tp < T+Ts; tp++) if (tp->t_text != NULL) stacksize++; curstack = (struct tcap **)malloc((unsigned) (3*sizeof(struct tcap *) * stacksize)); if (!curstack) return 1; otherstack = curstack+stacksize; resetstack = otherstack+stacksize; othersp = resetstack+stacksize; for (tp = T; tp < T+Ts; tp++) if (tp->t_text != NULL) PushMatch(tp); othersp = otherstack+stacksize; ResetMatchStack(); return 0; } extern struct tcap interruptedOp; /* * Interpret data from the application. We match data against * the ``escape sequences'' expected for this termcap description * and, if successful, invoke the routines used to emulate the * capabilities on the window. */ tc_display(cp, n) u_char *cp; register int n; { register int c, j; register struct tcap *tp; static char dbuf[256], *dp = dbuf; int restart, lim; /* * If we're blocked with a page full, indicate * nothing was sent to the screen. We should * never be called when already blocked, but * just in case, turn scrolling on again so we * don't lost any data. */ if (PageFull) { if (interruptedOp.t_key == 0) return (n); scrollreset(0); /* XXX */ } /* * If we have previous output, process it first. * Check on completion to see if we filled the screen. */ if (interruptedOp.t_key) { (*interruptedOp.t_op)(&interruptedOp); if (PageFull) return (n); interruptedOp.t_key = 0; } /* * For each input character, look for potential * matches in the tcap structure. For each possible * match, construct the resultant output buffer. * On first match process the operation (e.g. invoke * internal routine) and flush extraneous matches. * If input doesn't match any capability, send it to * the window. */ while (n > 0 && !PageFull) { /* * If we're not in the middle of a match, then * try and bypass the pattern matcher by performing * special checks on the most common input. */ if (!MatchInProgress) { while (n > 0 && !PageFull) { /* * If terminal has only non-printing escape sequences, * then process printable characters w/o matching against * the termcap strings. */ if (!TerminalIsBraindamaged) { for (dp = (char *)cp; n > 0 && isprint((int)*cp); n--) cp++; if ((char *)cp > dp) { tp = T+Ts; tp->t_text = dp; /* use original storage */ tp->t_size = (char *)cp - dp; (*tp->t_op)(tp); if (PageFull) return (n); continue; } } /* * Make quick checks for standard NL, CR, BS, and TAB * characters. This speeds up scrolling for most * terminal types. */ c = *cp; if (CheckNL && c == '\n') tp = CheckNL; else if (CheckCR && c == '\r') tp = CheckCR; else if (CheckTAB && c == '\t') tp = CheckTAB; else if (CheckBS && c == '\b') tp = CheckBS; else break; cp++, n--; (*tp->t_op)(tp); if (PageFull) return (n); } dp = dbuf; if (n == 0) break; } c = *dp++ = *cp++, n--; while (!MatchStackEmpty()) { tp = PopMatch(); again: j = tp->t_index; restart = 0; /* * Check match against numeric %[d23] specification. */ if (tp->t_text[j] == '%') { switch (tp->t_text[j+1]) { case 'd': /* series of decimal digits */ lim = 127; goto digit; case '2': /* two decimal digits */ lim = 2; goto digit; case '3': /* three decimal digits */ lim = 3; /* fall thru.. */ digit: if (isdigit(c) && tp->t_matched < lim) { tp->t_matched++; tp->t_param = tp->t_param*10 + (c-'0'); goto plainmatch; } else { if (tp->t_matched == 0) tp->t_param = 1 ; tp->t_matched = 0; restart = !isdigit(c); goto gotvalue; } /*NOTREACHED*/ break; case '.': /* binary character */ tp->t_param = c; gotvalue: switch (tp->t_2nd + tp->t_pc_r) { case 0: case 2: if ((tp->t_y = tp->t_param) >= tp->t_yilim) tp->t_y -= tp->t_yi; break; case 1: if ((tp->t_x = tp->t_param) >= tp->t_xilim) tp->t_x -= tp->t_xi; break; } tp->t_2nd = !tp->t_2nd; tp->t_index += 2; tp->t_param = 0 ; goto plainmatch; case '%': if ((c & 0177) == '%') { tp->t_index += 2; goto plainmatch; } else goto nomatch; default: abort(); /* XXX */ /* NOTREACHED */ } } else if ((c & 0177) == (tp->t_text[j] & 0177)) { tp->t_index++; plainmatch: /* plain match */ if (tp->t_index >= tp->t_size) {/* match completed */ if (tp->t_op) (*tp->t_op)(tp); dp = dbuf; tp->t_index = 0; tp->t_matched = 0; tp->t_param = 0 ; tp->t_2nd = 0; goto done; } /* * The end of a %d match is the only case where a * character must be pushed-back and re-parsed. */ if (restart) goto again; PushMatch(tp); /* push partial match */ } else { nomatch: /* failed match */ tp->t_index = 0; tp->t_param = 0 ; tp->t_matched = 0; tp->t_2nd = 0; } } if (!MatchedStackEmpty()) { SwapStacks(); continue; } done: /* * Come here either because no partial matches were * found in the table, or because a match completed. * In the first case we send the input data off * immediately. In the second case we reset the * state machines and go on to the next character. */ if (dp - dbuf) { /* flush output */ tp = T+Ts; tp->t_text = dbuf; tp->t_size = dp - dbuf; (*tp->t_op)(tp); dp = dbuf; } FlushMatchedStack(); /* reset partial matches */ FlushMatchStack(); /* reset unchecked partials */ ResetMatchStack(); /* re-init match stack */ } return (n); /* return number of chars processed */ } @@@ Fin de tcap_parse.c echo termcap.h cat >termcap.h <<'@@@ Fin de termcap.h' /* * This file is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. * Users may copy, modify or distribute this file at will. * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * This file is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even * if Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 * * Modifications to the original Sun Microsystems, Inc. source code * made by the Grasshopper Group are in the Public Domain. * * Extensions to this file by Eric Messick of the Grasshopper Group. * * Grasshopper Group * 212 Clayton St * San Francisco, CA 94117 * */ /* * "@(#)termcap.h 9.4 88/01/19 SMI * "@(#)$Header: termcap.h,v 2.0 88/09/16 00:19:39 eric Release $ * * Copyright (c) 1985 by Sun Microsystems, Inc. */ enum tct { string, num, bool}; struct tcap { char * t_key; /* Capability name */ enum tct t_type; /* Capability type */ int (*t_op)(/* struct tcap * */); int (*t_in)(/* struct tcap * */); char * t_text; /* Capability text */ char * t_deftext; /* Default text */ u_short t_size; /* Length of t_text */ u_short t_index; /* Posn. in t_text */ int t_param; /* parameter value for %match */ u_short t_matched; /* Length of matched string */ u_short t_x; /* Coordinate for cm= etc. */ u_short t_xi; /* Offset to subtract from t_x */ u_short t_xilim; /* If t_x >= t_xilim subtract t_xi */ u_short t_y; u_short t_yi; u_short t_yilim; unsigned t_pc_r : 1; /* %r present */ unsigned t_pc_n : 1; /* %n present */ unsigned t_pc_B : 1; /* %B present */ unsigned t_pc_D : 1; /* %D present */ unsigned t_2nd : 1; /* On second coord */ }; @@@ Fin de termcap.h exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.