[comp.sources.unix] v16i051: Terminal emulator for NeWS window system, Part04/04

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.