[mod.sources] v09i030: A TECO text editor, Part03/04

sources-request@mirror.UUCP (03/13/87)

Submitted by: genrad!mlf
Mod.sources: Volume 9, Issue 30
Archive-name: teco/Part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
#		"End of archive 3 (of 4)."
# Contents:  te_exec1.c te_exec2.c
# Wrapped by rs@mirror on Thu Mar 12 19:54:32 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"te_exec1.c\" \(21012 characters\)
if test -f te_exec1.c ; then 
  echo shar: Will not over-write existing file \"te_exec1.c\"
else
sed "s/^X//" >te_exec1.c <<'END_OF_te_exec1.c'
X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum						*/
X/* This program and its components belong to GenRad Inc, Concord MA 01742	*/
X/* They may be copied if this copyright notice is included					*/
X
X/* te_exec1.c   continue executing commands   1/8/87 */
X#include "te_defs.h"
X
Xexec_cmds1()
X	{
X	char command;					/* command character */
X	int cond;						/* conditional in progress */
X
X	switch (command = mapch_l[cmdc])
X		{
X/* operators */
X
X		case '+':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_ADD;
X			break;
X
X		case '-':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_SUB;
X			break;
X
X		case '*':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_MULT;
X			break;
X
X		case '/':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_DIV;
X			break;
X
X		case '&':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_AND;
X			break;
X
X		case '#':
X			esp->exp = (esp->flag1) ? esp->val1 : 0;
X			esp->flag1 = 0;
X			esp->op = OP_OR;
X			break;
X
X		case ')':
X			if ((!esp->flag1) || (esp <= &estack[0])) ERROR(E_NAP);
X			--esp;
X			esp->val1 = (esp+1)->val1;	/* carry value from inside () */
X			esp->flag1 = 1;
X			break;
X		case ',':
X			if (!esp->flag1) ERROR(E_NAC);
X			else esp->val2 = esp->val1;
X			esp->flag2 = 1;
X			esp->flag1 = 0;
X			break;
X
X		case CTL (_):
X			if (!esp->flag1) ERROR(E_NAB);
X			else esp->val1 = ~esp->val1;
X			break;
X
X/* radix control */
X
X		case CTL (D):
X			ctrl_r = 10;
X			esp->flag1 = 0;
X			esp->op = OP_START;
X			break;
X
X		case CTL (O):
X			ctrl_r = 8;
X			esp->flag1 = 0;
X			esp->op = OP_START;
X			break;
X
X		case CTL (R):
X			if (!esp->flag1)	/* fetch it */
X				{
X				esp->val1 = ctrl_r;
X				esp->flag1 = 1;
X				}
X			else
X				{
X				if ((esp->val1 != 8) && (esp->val1 != 10) && (esp->val1 != 16)) ERROR(E_IRA);
X				ctrl_r = esp->val1;
X				esp->flag1 = 0;
X				esp->op = OP_START;
X				}
X			break;
X
X/* other commands */
X
X		case CTL (C):			/* 1 ^C stops macro execution, 2 exit */
X			if (peekcmdc(CTL (C))) exitflag = -1;		/* 2 ^C: stop execution and exit */
X			else if (msp <= &mstack[0]) exitflag = 1;	/* 1 ^C: in command string: stop execution */
X			else --msp;									/*		 in a macro - pop it */
X			break;
X
X		case CTL (X):			/* search mode flag */
X			set_var(&ctrl_x);
X			break;
X
X		case 'e':
X			do_e();
X			break;
X
X		case 'f':
X			do_f();
X			break;
X/* macro call, iteration, conditional */
X
X		case 'm':				/* macro call */
X			mm = getqspec(0, getcmdc(trace_sw));	/* read the macro name */
X			if (msp > &mstack[MSTACKSIZE-1]) ERROR(E_PDO);	/* check room for another level */
X			++msp;					/* push stack */
X			cptr.p = qreg[mm].f;	/* to stack entry, put q-reg text start */
X			cptr.flag = cptr.c = cptr.dot = 0;	/* initial char position, iteration flag */
X			cptr.z = qreg[mm].z;	/* number of chars in macro */
X			break;
X
X		case '<':				/* begin iteration */
X			if ((esp->flag1) && (esp->val1 <= 0))		/* if this is not to be executed */
X				find_enditer();							/* just skip the intervening stuff */
X			else
X				{
X				if (!cptr.il)		/* does this macro have an iteration list? */
X					{
X					cptr.il = (struct is *) get_dcell();	/* no, make one for it */
X					cptr.il->b = NULL;						/* with NULL reverse pointer */
X					}
X				else if (cptr.flag & F_ITER)		/* is there an iteration in process? */
X					{
X					if (!cptr.il->f)				/* yes, if it has no forward pointer */
X						{
X						cptr.il->f = (struct is *) get_dcell();		/* append a cell to the iteration list */
X						cptr.il->f->b = cptr.il;					/* and link it in */
X						}
X					cptr.il = cptr.il->f;						/* and advance the iteration list pointer to it */
X					}
X				cptr.flag |= F_ITER;				/* set iteration flag */
X				cptr.il->p = cptr.p;				/* save start of iteration */
X				cptr.il->c = cptr.c;
X				cptr.il->dot = cptr.dot;
X				if (cptr.il->dflag = esp->flag1)	/* if there is an argument, set the "def iter" flag */
X					{
X					cptr.il->count = esp->val1;		/* save the count */
X					esp->flag1 = 0;					/* and consume the arg */
X					}
X				}
X			break;
X
X		case '>':				/* end iteration */
X			if (!(cptr.flag & F_ITER)) ERROR(E_BNI);		/* error if > not in iteration */
X			pop_iteration(0);		/* decrement count and pop conditionally */
X			esp->flag1 = esp->flag2 = 0;	/* consume arguments */
X			esp->op = OP_START;
X			break;
X
X		case ';':				/* semicolon iteration exit */
X			if (!(cptr.flag &F_ITER)) ERROR(E_SNI);		/* error if ; not in iteration */
X			if ( ( ((esp->flag1) ? esp->val1 : srch_result) >= 0) ? (!colonflag) : colonflag)	/* if exit */
X				{
X				find_enditer();			/* get to end of iteration */
X				pop_iteration(1);		/* and pop unconditionally */
X				}
X			esp->flag1 = colonflag = 0;		/* consume arg and colon */
X			esp->op = OP_START;
X			break;
X/* conditionals */
X
X		case '"':
X			if (!esp->flag1) ERROR(E_NAQ);		/* must be an argument */
X			esp->flag1 = 0;					/* consume argument */
X			esp->op = OP_START;
X			switch (mapch_l[getcmdc(trace_sw)])
X				{
X				case 'a':
X					cond = isalpha(esp->val1);
X					break;
X
X				case 'c':
X					cond = isalpha(esp->val1) | (esp->val1 == '$') | (esp->val1 == '.');
X					break;
X
X				case 'd':
X					cond = isdigit(esp->val1);
X					break;
X
X				case 'e':
X				case 'f':
X				case 'u':
X				case '=':
X					cond = !(esp->val1);
X					break;
X
X				case 'g':
X				case '>':
X					cond = (esp->val1 > 0);
X					break;
X
X				case 'l':
X				case 's':
X				case 't':
X				case '<':
X					cond = (esp->val1 < 0);
X					break;
X
X				case 'n':
X					cond = esp->val1;
X					break;
X
X				case 'r':
X					cond = isalnum(esp->val1);
X					break;
X
X				case 'v':
X					cond = islower(esp->val1);
X					break;
X
X				case 'w':
X					cond = isupper(esp->val1);
X					break;
X
X				default:
X					ERROR(E_IQC);
X				}
X			if (!cond)			/* if this conditional isn't satisfied */
X				{
X				for (ll = 1; ll > 0;)		/* read to matching | or ' */
X					{
X					while ((skipto(0) != '"') && (skipc != '|') && (skipc != '\''));	/* skip chars */
X					if (skipc == '"')	   ++ll;	/* start another level */
X					else if (skipc == '\'') --ll;	/* end a level */
X					else if (ll == 1) break;		/* "else" (|): if on this level, start executing */
X					}
X				}
X			break;
X
X		case '\'':				/* end of conditional */
X			break;				/* ignore it if executing */
X
X		case '|':				/* "else" clause */
X			for (ll = 1; ll > 0;)			/* skip to matching ' */
X				{
X				while ((skipto(0) != '"') && (skipc != '\''));	/* skip chars */
X				if (skipc == '"') ++ll;			/* start another level */
X				else			 --ll;			/* end a level */
X				}
X			break;
X/* q-register numeric operations */
X
X		case 'u':
X			if (!esp->flag1) ERROR(E_NAU);	/* error if no arg */
X			else qreg[getqspec(0, getcmdc(trace_sw))].v = esp->val1;
X			esp->flag1 = esp->flag2;		/* command's "value" is 2nd arg */
X			esp->val1 = esp->val2;
X			esp->flag2 = 0;					/* clear 2nd arg */
X			esp->op = OP_START;
X			break;
X
X		case 'q':		/* Qn is numeric val, :Qn is # of chars, mQn is mth char */
X			mm = getqspec((colonflag || esp->flag1), getcmdc(trace_sw));		/* read register name */
X			if (!(esp->flag1))
X				{
X				esp->val1 = (colonflag) ? qreg[mm].z : qreg[mm].v;
X				esp->flag1 = 1;
X				}
X			else		/* esp->flag1 is already set */
X				{
X				if ((esp->val1 >= 0) && (esp->val1 < qreg[mm].z))	/* char subscript within range? */
X					{
X					for (ll = 0, aa.p = qreg[mm].f; ll < (esp->val1 / CELLSIZE); ll++) aa.p = aa.p->f;
X					esp->val1 = (int) aa.p->ch[esp->val1 % CELLSIZE];
X					}
X				else esp->val1 = -1;	/* char position out of range */
X				esp->op = OP_START;		/* consume argument */
X				}
X			colonflag = 0;
X			break;
X
X		case '%':
X			esp->val1 = (qreg[getqspec(0, getcmdc(trace_sw))].v += get_value(1));	/* add to q reg */
X			esp->flag1 = 1;
X			break;
X/* move pointer */
X
X		case 'c':
X			if (((tdot = dot + get_value(1)) < 0) || (tdot > z))
X				ERROR(E_POP);	/* add arg to dot, default 1 */
X			else dot = tdot;
X			esp->flag2 = 0;
X			break;
X
X		case 'r':
X			if (((tdot = dot - get_value(1)) < 0) || (tdot > z))
X				ERROR(E_POP);	/* add arg to dot, default 1 */
X			else dot = tdot;
X			esp->flag2 = 0;
X			break;
X
X		case 'j':
X			if (((tdot = get_value(0)) < 0) || (tdot > z))
X				ERROR(E_POP);	/* add arg to dot, default 1 */
X			else dot = tdot;
X			esp->flag2 = 0;
X			break;
X
X		case 'l':
X			dot += lines(get_value(1));
X			break;
X
X/* number of chars until nth line feed */
X
X		case CTL (Q):
X			esp->val1 = lines(get_value(1));
X			esp->flag1 = 1;
X			break;
X
X/* print numeric value */
X
X		case '=':
X			if (!esp->flag1) ERROR(E_NAE);	/* error if no arg */
X			else
X				{
X				if (peekcmdc('='))		/* at least one more '=' */
X					{
X					getcmdc(trace_sw);		/* read past it */
X					if (peekcmdc('='))		/* another? */
X						{
X						getcmdc(trace_sw);			/* yes, read it too */
X						printf("%x", esp->val1);	/* print in hex */
X						}
X					else printf("%o", esp->val1);	/* print in octal */
X					}
X				else printf("%d", esp->val1);
X				if (!colonflag) crlf();
X				esp->flag1 = esp->flag2 =  colonflag = 0;
X				esp->op = OP_START;
X				if (!WN_scroll) window(WIN_REDRAW);			/* if not in scroll mode, force full redraw on next refresh */
X				}
X			break;
X/* insert text */
X
X		case TAB:					/* insert tab, then text */
X			if (ez_val & EZ_NOTABI) break;		/* tab disabled */
X			if (esp->flag1) ERROR(E_IIA);		/* can't have arg */
X
X		case 'i':					/* insert text at pointer */
X			term_char = (atflag) ? getcmdc(trace_sw) : ESC;		/* set terminator */
X			if (esp->flag1)		/* if a nI$ command */
X				{
X				if (!peekcmdc(term_char)) ERROR(E_IIA);	/* next char must be term */
X				insert1();			/* first part of insert */
X				bb.p->ch[bb.c] = esp->val1 & 0177;		/* insert character */
X				fwdcx(&bb);			/* advance pointer and extend buffer if necessary */
X				ins_count = 1;		/* save string length */
X				esp->op = OP_START;	/* consume argument */
X				}
X			else					/* not a nI command: insert text */
X				{
X				insert1();			/* initial insert operations */
X
X				if (command == TAB)			/* TAB insert puts in a tab first */
X					{
X					bb.p->ch[bb.c] = TAB;	/* insert a tab */
X					fwdcx(&bb);				/* advance pointer and maybe extend buffer */
X					}
X				moveuntil(&cptr, &bb, term_char, &ins_count, cptr.z - cptr.dot, trace_sw);	/* copy cmd str -> buffer */
X				if (command == TAB) ++ins_count;	/* add 1 if a tab inserted */
X				cptr.dot += ins_count;	/* indicate advance over that many chars */
X				}
X			insert2(ins_count);		/* finish insert */
X			getcmdc(trace_sw);		/* flush terminating char */
X			colonflag = atflag = esp->flag1 = esp->flag2 = 0;	/* clear args */
X			break;
X
X/* type text from text buffer */
X	
X		case 't':
X			for (ll = line_args(0, &aa); ll > 0; ll--)	/* while there are chars to type */
X				{
X				type_char(aa.p->ch[aa.c]);
X				fwdc(&aa);
X				}
X			if (!WN_scroll) window(WIN_REDRAW);			/* if not in scroll mode, force full redraw on next refresh */
X			break;
X
X		case 'v':
X			if ((ll = get_value(1)) > 0)		/* arg must be positive */
X				{
X				mm = lines(1 - ll);					/* find start */
X				nn = lines(ll) - mm;				/* and number of chars */
X				set_pointer(dot + mm, &aa);			/* pointer to start of text */
X				for (; nn > 0; nn--)				/* as above */
X					{
X					type_char(aa.p->ch[aa.c]);
X					fwdc(&aa);
X					}
X				}
X			if (!WN_scroll) window(WIN_REDRAW);			/* if not in scroll mode, force full redraw on next refresh */
X			break;
X/* type text from command string */
X
X		case CTL (A):
X			term_char = (atflag) ? getcmdc(trace_sw) : CTL(A);		/* set terminator */
X			while (getcmdc(0) != term_char) type_char(cmdc);	/* output chars */
X			atflag = colonflag = esp->flag2 = esp->flag1 = 0;
X			esp->op = OP_START;
X			if (!WN_scroll) window(WIN_REDRAW);			/* if not in scroll mode, force full redraw on next refresh */
X			break;
X
X	/* delete text */
X
X		case 'd':
X			if (!esp->flag2)				/* if only one argument */
X				{
X				delete1(get_value(1));			/* delete chars (default is 1) */
X				break;
X				}				/* if two args, fall through to treat m,nD as m,nK */
X
X		case 'k':					/* delete lines or chars */
X			ll = line_args(1, &aa);	/* aa points to start, ll chars, leave dot at beginning */
X			delete1(ll);			/* delete ll chars */
X			break;
X
X/* q-register text loading commands */
X
X		case CTL (U):
X			mm = getqspec(0, getcmdc(trace_sw));
X			if (!colonflag)			/* X, ^U commands destroy previous contents */
X				{
X				dly_free_blist(qreg[mm].f);
X				qreg[mm].f = NULL;
X				qreg[mm].z = 0;
X				}
X			term_char = (atflag) ? getcmdc(trace_sw) : ESC;		/* set terminator */
X			atflag = 0;			/* clear flag */
X
X			if ((esp->flag1) || (!peekcmdc(term_char)))		/* if an arg or a nonzero insert, find register */
X				{
X				make_buffer(&qreg[mm]);			/* attach a text buffer to the q register */
X				for (bb.p = qreg[mm].f; bb.p->f != NULL; bb.p = bb.p->f);	/* find end of reg */
X				bb.c = (colonflag) ? qreg[mm].z % CELLSIZE : 0;
X				}
X			if (!(esp->flag1))
X				{
X				moveuntil(&cptr, &bb, term_char, &ll, cptr.z - cptr.dot, trace_sw);
X				cptr.dot += ll;			/* indicate advance over that many chars */
X				qreg[mm].z += ll;		/* update q-reg char count */
X				getcmdc(trace_sw);		/* skip terminator */
X				}
X			else
X				{
X				if (getcmdc(trace_sw) != term_char) ERROR(E_IIA);	/* must be zero length string */
X				bb.p->ch[bb.c] = esp->val1;				/* store char */
X				fwdcx(&bb);				/* extend the register */
X				++qreg[mm].z;
X				esp->flag1 = 0;			/* consume argument */
X				}
X			colonflag = 0;
X			break;
X		case 'x':
X			mm = getqspec(0, getcmdc(trace_sw));
X			if (!colonflag)			/* X, ^U commands destroy previous contents */
X				{
X				dly_free_blist(qreg[mm].f);		/* return, but delayed (in case executing now) */
X				qreg[mm].f = NULL;
X				qreg[mm].z = 0;
X				}
X
X			if (ll = line_args(0, &aa))		/* read args and move chars, if any */
X				{
X				make_buffer(&qreg[mm]);			/* attach a text buffer to the q register */
X				for (bb.p = qreg[mm].f; bb.p->f != NULL; bb.p = bb.p->f);	/* find end of reg */
X				bb.c = (colonflag) ? qreg[mm].z % CELLSIZE : 0;
X
X				movenchars(&aa, &bb, ll);
X				qreg[mm].z += ll;		/* update q-reg char count */
X				}
X			colonflag = 0;
X			break;
X
X		case 'g':				/* get q register */
X			if (qreg[mm = getqspec(1, getcmdc(trace_sw))].z)	/* if any chars in it */
X				{
X				cc.p = qreg[mm].f;		/* point cc to start of reg */
X				cc.c = 0;
X				if (colonflag)		/* :Gx types q-reg */
X					{
X					for (ll = qreg[mm].z; ll > 0; ll--)
X						{
X						type_char(cc.p->ch[cc.c]);	/* type char */
X						fwdc(&cc);
X						}
X					}
X				else
X					{
X					insert1();				/* set up for insert */
X					movenchars(&cc, &bb, qreg[mm].z);	/* copy q reg text */
X					insert2(qreg[mm].z);	/* finish insert */
X					}
X				}
X			colonflag = 0;
X			break;
X/* q-register push and pop */
X
X		case '[':
X			if (qsp > &qstack[QSTACKSIZE-1]) ERROR(E_PDO);		/* stack full */
X			else
X				{
X				make_buffer(++qsp);		/* increment stack ptr and put a text buffer there */
X				mm = getqspec(1, getcmdc(trace_sw));		/* get the q reg name */
X
X				aa.p = qreg[mm].f;			/* point to the q register */
X				aa.c = 0;
X				bb.p = qsp->f;				/* point to the new list */
X				bb.c = 0;
X				movenchars(&aa, &bb, qreg[mm].z);	/* copy the text */
X				qsp->z = qreg[mm].z;		/* and the length */
X				qsp->v = qreg[mm].v;		/* and the value */
X				}
X			break;
X
X		case ']':
X			mm = getqspec(1, getcmdc(trace_sw));		/* get reg name */
X			if (qsp < &qstack[0])				/* if stack empty */
X				{
X				if (colonflag)					/* :] returns 0 */
X					{
X					esp->flag1 = 1;
X					esp->val1 = 0;
X					colonflag = 0;
X					}
X				else ERROR(E_CPQ);				/* ] makes an error */
X				}
X			else									/* stack not empty */
X				{
X				free_blist(qreg[mm].f);			/* return orig contents of reg */
X				qreg[mm].f = qsp->f;			/* substitute stack entry */
X				qsp->f->b = (struct buffcell *) &qreg[mm];
X				qsp->f = NULL;					/* null out stack entry */
X				qreg[mm].z = qsp->z;
X				qreg[mm].v = qsp->v;
X				if (colonflag)
X					{
X					esp->flag1 = 1;				/* :] returns -1 */
X					esp->val1 = -1;
X					colonflag = 0;
X					}
X				--qsp;
X				}
X			break;
X		case '\\':
X			if (!(esp->flag1))		/* no argument; read number */
X				{
X				ll = esp->val1 = 0;			/* sign flag and initial value */
X				for (ctrl_s = 0; dot <= z; dot++, ctrl_s--)		/* count digits; don't read beyond buffer */
X					{
X					set_pointer(dot, &aa);	/* point to dot */
X					if ((aa.p->ch[aa.c] == '+') || (aa.p->ch[aa.c] == '-'))
X						{
X						if (ll) break;		/* second sign: quit */
X						else ll = aa.p->ch[aa.c];	/* first sign: save it */
X						}
X					else
X						{
X						if (ctrl_r != 16)	/* octal or decimal */
X							{					/* stop if not a valid digit */
X							if ((!isdigit(aa.p->ch[aa.c])) || (aa.p->ch[aa.c] - '0' >= ctrl_r)) break;
X							esp->val1 = esp->val1 * ctrl_r + (aa.p->ch[aa.c] - '0');
X							}
X						else
X							{
X							if (!isxdigit(aa.p->ch[aa.c])) break;
X							esp->val1 = esp->val1 * 16 + ( (isdigit(aa.p->ch[aa.c])) ?
X												aa.p->ch[aa.c] - '0' : mapch_l[aa.p->ch[aa.c]] - 'a' + 10);
X							}		/* end of hex */
X						}		/* end of digit processing */
X					}		/* end of "for each char" */
X				if (ll == '-') esp->val1 = -(esp->val1);	/* if minus sign */
X				esp->flag1 = 1;				/* always returns a value */
X				}
X
X			else					/* argument: insert it as a digit string */
X				{
X				if (ctrl_r == 8)		sprintf(t_bcell.ch, "%o", esp->val1);	/* print as digits */
X				else if (ctrl_r == 10)	sprintf(t_bcell.ch, "%d", esp->val1);
X				else					sprintf(t_bcell.ch, "%x", esp->val1);
X				insert1();			/* start insert */
X				cc.p = &t_bcell;	/* point cc to the temp cell */
X				cc.c = 0;
X				moveuntil(&cc, &bb, '\0', &ins_count, CELLSIZE-1, 0);	/* copy the char string */
X				insert2(ins_count);	/* finish the insert */
X				esp->flag1 = 0;		/* consume argument */
X				esp->op = OP_START;
X				}
X			break;
X		case CTL (T):			/* type or input character */
X			if (esp->flag1)		/* type */
X				{
X				type_char(esp->val1);
X				esp->flag1 = 0;
X				if (!WN_scroll) window(WIN_REDRAW);			/* if not in scroll mode, force full redraw on next refresh */
X				}
X			else
X				{
X				esp->val1 = (et_val & ET_NOWAIT) ? gettty_nowait() : gettty();
X				if (!(et_val & ET_NOECHO) && (esp->val1 > 0) && !inp_noterm) type_char(esp->val1);		/* echo */
X				esp->flag1 = 1;
X				}
X			break;
X
X/* search commands */
X
X		case 's':					/* search within buffer */
X			build_string(&sbuf);	/* read the search string */
X			end_search (  do_search( setup_search() )  );		/* search */
X			break;
X
X		case 'n':					/* search through rest of file */
X		case '_':
X			do_nsearch(command);	/* call routine for N, _, E_ */
X			break;
X
X		case 'o':					/* branch to tag */
X			do_o();
X			break;
X/* file I/O commands */
X
X		case 'p':					/* write a page, get next (ignore args for now) */
X			if (esp->flag1 && esp->flag2)	/* if two args */
X				write_file(&aa, line_args(0, &aa), 0);		/* write spec'd buffer with no FF */
X			else							/* one arg */
X				{
X				for (ll = get_value(1);	ll > 0; ll--)	/* get count and loop */
X					{
X					set_pointer(0, &aa);
X					if (peekcmdc('w')) write_file(&aa, z, 1);	/* PW writes buffer, then FF */
X					else
X						{
X						write_file(&aa, z, ctrl_e);		/* P writes buffer, FF if read in, then gets next page */
X						dot = z = 0;			/* empty the buffer */
X						set_pointer(0, &aa);	/* set a pointer to the beginning of the buffer */
X						buff_mod = 0;			/* mark where new buffer starts */
X						esp->val1 = read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );	/* read a page */
X						esp->flag1 = colonflag;
X						}
X					}
X				}
X			if (peekcmdc('w')) getcmdc(trace_sw);		/* if a PW command, consume the W */
X			colonflag = 0;
X			break;
X
X		case 'y':					/* get a page into buffer */
X			if (esp->flag1) ERROR(E_NYA);
X			if ((z) && (!(ed_val & ED_YPROT))) ERROR(E_YCA);	/* don't lose text */
X			dot = z = 0;			/* clear buffer */
X			set_pointer(0, &aa);	/* set a pointer to the beginning of the buffer */
X			buff_mod = 0;			/* mark where new buffer starts */
X			read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );		/* read a page */
X			esp->flag1 = colonflag;
X			esp->op = OP_START;
X			colonflag = 0;
X			break;
X		case 'a':					/* append, or ascii value */
X			if (esp->flag1 && !colonflag)		/* ascii value */
X				{
X				ll = dot + esp->val1;		/* set a pointer before addr'd char */
X				if ((ll >= 0) && (ll < z))	/* if character lies within buffer */
X					{
X					set_pointer(ll, &aa);
X					esp->val1 = (int) aa.p->ch[aa.c];	/* get char (flag already set) */
X					}
X				else esp->val1 = -1;		/* otherwise return -1 */
X				}
X			else
X				{
X				set_pointer(z, &aa);				/* set pointer to end of buffer */
X				if (z < buff_mod) buff_mod = z;			/* mark where new buffer starts */
X				if (esp->flag1 && (esp->val1 <= 0)) ERROR(E_IAA);		/* neg or 0 arg to :A */
X				read_file(&aa, &z, (esp->flag1 ? esp->val1 : 0) );		/* read a page */
X				esp->flag1 = colonflag;
X				colonflag = 0;
X				}
X			esp->op = OP_START;
X			break;
X
X/* window commands */
X
X		case 'w':
X			do_window(0);					/* this stuff is with the window driver */
X			break;
X
X		case CTL (W):
X			do_window(1);					/* this is, too */
X			break;
X
X		default:
X			ERROR(E_ILL);					/* invalid command */
X
X		}		/* end of "switch" */
X	return;		/* normal exit */
X	}			/* end of exec_cmds1 */
X
END_OF_te_exec1.c
if test 21012 -ne `wc -c <te_exec1.c`; then
    echo shar: \"te_exec1.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"te_exec2.c\" \(29256 characters\)
if test -f te_exec2.c ; then 
  echo shar: Will not over-write existing file \"te_exec2.c\"
else
sed "s/^X//" >te_exec2.c <<'END_OF_te_exec2.c'
X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum						*/
X/* This program and its components belong to GenRad Inc, Concord MA 01742	*/
X/* They may be copied if this copyright notice is included					*/
X
X/* te_exec2.c   process "E" and "F" commands   2/26/87 */
X#include "te_defs.h"
X#include <sys/wait.h>
X
Xstruct qh oldcstring;						/* hold command string during ei */
X
X/* file stuff for input/output files */
X
Xstruct infiledata pi_file = { NULL, -1 };	/* input files */
Xstruct infiledata si_file = { NULL, -1 };
Xstruct infiledata *infile = &pi_file;		/* pointer to currently active input file structure */
Xstruct outfiledata po_file, so_file;		/* output files */
Xstruct outfiledata *outfile = &po_file;		/* pointer to currently active output file structure */
XFILE *eisw;									/* indirect command file pointer */
X
X/* process E commands */
X
Xdo_e()
X	{
X	char c;							/* temps */
X	int old_var;
X	FILE *t_eisw;
X
X	switch (mapch_l[getcmdc(trace_sw)])		/* read next character and dispatch */
X		{	
X
X/* numeric values */
X
X		case 'd':				/* ED */
X			set_var(&ed_val);
X			break;
X
X		case 's':				/* ES */
X			set_var(&es_val);
X			break;
X
X		case 't':				/* ET */
X			old_var = et_val;
X			set_var(&et_val);
X			et_val = (et_val & 0100651) | 001006;	/* force read_only bits */
X			if ((et_val ^ old_var) & ET_TRUNC) window(WIN_REDRAW);		/* redraw if ET & 256 changes */
X			break;
X
X		case 'u':				/* EU */
X			set_var(&eu_val);
X			break;
X
X		case 'v':				/* EV */
X			set_var(&ev_val);
X			break;
X
X		case 'z':				/* EZ */
X			old_var = ez_val;
X			set_var(&ez_val);
X			tabmask = (ez_val & EZ_TAB4) ? 3 : 7;		/* set tab mask */
X			if ((ez_val ^ old_var) & EZ_TAB4) window(WIN_REDRAW);		/* force window redisplay if EZ_TAB4 changes */
X			break;
X/* E_ search */
X
X		case '_':
X			do_nsearch('e');
X			break;
X
X/* file I/O commands */
X
X		case 'a':				/* set secondary output */
X			outfile = &so_file;
X			break;
X
X		case 'b':				/* open read/write with backup */
X			if (!read_filename(1, 'r')) ERROR(E_NFI);	/* read the name */
X			if (infile->fd) fclose(infile->fd);			/* close previously-open file */
X			if (!(infile->fd = fopen(fbuf.f->ch, "r")))
X				{
X				if (!colonflag) ERROR(E_FNF);
X				}
X			else
X				{
X				if (outfile->fd) ERROR(E_OFO);		/* output file already open */
X				for (ll = 0; ll < CELLSIZE; ll++)		/* save file string */
X					if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
X				outfile->name_size = ll;
X				outfile->t_name[ll++] = '.';
X				outfile->t_name[ll++] = 't';
X				outfile->t_name[ll++] = 'm';
X				outfile->t_name[ll++] = 'p';
X				outfile->t_name[ll] = '\0';
X				if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
X				outfile->bak = 1;	/* set backup mode */
X				}
X			infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			break;
X
X		case 'x':				/* finish edit and exit */
X			exitflag = -1;
X
X			/* --- fall through to "EC" --- */
X
X		case 'c':				/* finish edit */
X			set_pointer(0, &aa);				/* set a pointer to start of text buffer */
X			write_file(&aa, z, ctrl_e);			/* write the current buffer */
X			dot = z = 0;						/* empty the buffer */
X			window(WIN_REDRAW);					/* force window redraw */
X			if ((outfile->fd) && (infile->fd) && !(infile->eofsw))	/* if any input remaining, copy it to output */
X				while ((c = getc(infile->fd)) != EOF) putc(c, outfile->fd);
X
X			/* --- fall through to "EF" --- */
X		case 'f':				/* close output file */
X			if (outfile->fd)	/* only if one is open */
X				{
X				fclose(outfile->fd);
X				if (outfile->bak & 1)		/* if this is "backup" mode */
X					{
X					outfile->f_name[outfile->name_size] = '.';
X					outfile->f_name[outfile->name_size+1] = 'b';
X					outfile->f_name[outfile->name_size+2] = 'a';
X					outfile->f_name[outfile->name_size+3] = 'k';
X					outfile->f_name[outfile->name_size+4] = '\0';
X					outfile->t_name[outfile->name_size] = '\0';
X					rename(outfile->t_name, outfile->f_name);	/* rename orig file */
X					}
X
X				if (!(outfile->bak & 8))		/* if output file had ".tmp" extension */
X					{								/* remove it */
X					outfile->t_name[outfile->name_size] = '.';
X					outfile->f_name[outfile->name_size] = '\0';
X					rename(outfile->t_name, outfile->f_name);	/* rename output */
X					}
X				}
X			outfile->fd = NULL;			/* mark "no output file open" */
X			break;
X
X		case 'i':				/* indirect file execution */
X			if (!read_filename(1, 'i'))		/* if no filename specified, reset command input */
X				{
X				if (eisw)		/* if ending a file execute, restore the previous "old command string" */
X					{
X					fclose(eisw);				/* return the file descriptor */
X					dly_free_blist(cbuf.f);		/* return the command string used by the file (after execution done) */
X					cbuf.f = oldcstring.f;
X					cbuf.z = oldcstring.z;
X					}
X				t_eisw = 0;
X				}
X			else if (!(t_eisw = fopen(fbuf.f->ch, "r")))
X				{
X				if (!colonflag) ERROR(E_FNF);
X				}
X			else if (!eisw)			/* if this "ei" came from the command string */
X				{
X				oldcstring.f = cbuf.f;		/* save current command string */
X				oldcstring.z = cbuf.z;
X				cbuf.f = NULL;				/* and make it inaccessible to "rdcmd" */
X				}
X			if (eisw) fclose(eisw);			/* if a command file had been open, close it */
X			esp->val1 = (eisw = t_eisw) ? -1 : 0;
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			esp->op = OP_START;
X			break;
X		case 'k':				/* kill output file */
X			kill_output(outfile);
X			break;
X
X		case 'p':				/* switch to secondary input */
X			infile = &si_file;
X			break;
X
X		case 'r':				/* specify input file, or switch to primary input */
X			if (!read_filename(0, 'r')) infile = &pi_file;		/* no name, switch to primary input */
X			else
X				{
X				if (infile->fd) fclose(infile->fd);				/* close previously-open file */
X				if (!(infile->fd = fopen(fbuf.f->ch, "r")))
X					{
X					if (!colonflag) ERROR(E_FNF);
X					}
X				}
X			infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			esp->op = OP_START;
X			break;
X
X		case 'w':				/* specify output file, or switch to primary output */
X			if(!read_filename(0, 'w')) outfile = &po_file;
X			else
X				{
X				if (outfile->fd) ERROR(E_OFO);		/* output file already open */
X				for (ll = 0; ll < CELLSIZE; ll++)			/* save file string */
X					if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
X				outfile->name_size = ll;
X				if (!(ez_val & EZ_NOTMPFIL))			/* if not using literal output name */
X					{
X					outfile->t_name[ll++] = '.';		/* use provisional suffix ".tmp" */
X					outfile->t_name[ll++] = 't';
X					outfile->t_name[ll++] = 'm';
X					outfile->t_name[ll++] = 'p';
X					outfile->t_name[ll] = '\0';
X					}
X				if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
X				outfile->bak = ez_val & EZ_NOTMPFIL;			/* save "temp suffix" status */
X				}
X			break;
X
X		case 'y':				/* EY is Y without protection */
X			if (esp->flag1) ERROR(E_NYA);
X			dot = z = 0;			/* clear buffer */
X			set_pointer(0, &aa);
X			read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			esp->op = OP_START;
X			break;
X		case 'n':				/* wildcard filespec */
X			esp->val1 = do_en();
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			esp->op = OP_START;
X			break;
X
X		case 'q':				/* system command */
X			esp->val1 = do_eq();			/* do this as a separate routine */
X			esp->flag1 = colonflag;
X			colonflag = 0;
X			esp->op = OP_START;
X			break;
X
X		default:
X			ERROR(E_IEC);
X		}
X	}
X/* routine to execute a system command			*/
X/* this is done by forking off another process	*/
X/* to execute a shell via 'execl'				*/
X/* routine returns -1 if success, 0 if error in fork */
X
Xint do_eq()
X	{
X	int t;
X	union wait status;
X	char *pname;				/* pointer to name of shell */
X	extern char *getenv();
X
X	build_string(&sysbuf);
X	if (sysbuf.z > CELLSIZE-2) ERROR(E_STL);	/* command must fit within one cell */
X	sysbuf.f->ch[sysbuf.z] = '\0';				/* store terminating null */
X	if (!(pname = getenv("SHELL"))) ERROR(E_SYS);	/* read shell name */
X
X	if (!esp->flag1)			/* if not m,nEQ command */
X		{
X		if (win_data[7]) window(WIN_SUSP);			/* restore full screen */
X		crlf();										/* force characters out */
X		setup_tty(TTY_SUSP);						/* restore terminal to normal mode */
X
X		t = vfork();							/* fork a new process */
X		if (t == 0)								/* if this is the child */
X			{
X			execl(pname, pname, "-c", &sysbuf.f->ch[0], 0);		/* call the named Unix routine */
X			printf("Error in 'execl'\n");		/* normally shouldn't get here */
X			exit(1);
X			}
X
X		while (wait(&status) != t);				/* if parent, wait for child to finish */
X		if (status.w_retcode) t = -1;			/* keep failure indication from child */
X		
X		setup_tty(TTY_RESUME);						/* restore terminal to teco mode */
X		if (win_data[7])					/* if window was enabled */
X			{
X			vt(VT_SETSPEC1);				/* set reverse video */
X			fputs("Type RETURN to continue", stdout);		/* require CR before continuing */
X			vt(VT_CLRSPEC);					/* reverse video off */
X			while (gettty() != LF);
X			putchar(CR);					/* back to beginning of line */
X			vt(VT_EEOL);					/* and erase the message */
X			window(WIN_RESUME);				/* re-enable window */
X			window(WIN_REDRAW);				/* and make it redraw afterwards */
X			}
X		}
X
X	else t = do_eq1(pname);					/* m,nEQ command */
X
X	return( (t == -1) ? 0 : -1);			/* return failure if fork failed or proc status nonzero */
X	}
X/* Execute m,nEQtext$ command.  Run "text" as a Unix command that	*/
X/* receives its std input from chars m through n of teco's buffer.	*/
X/* Output from the command is placed in Q#.							*/
X
Xint do_eq1(shell)
X	char *shell;			/* arg is pointer to shell name */
X	{
X	int ff, pipe_in[2], pipe_out[2];	/* fork result and two pipes */
X	FILE *xx_in, *xx_out;				/* std in and out for called process */
X	FILE *fdopen();
X	union wait status;
X
X	ll = line_args(1, &aa);		/* set aa to start of text, ll to number of chars */
X	dot += ll;					/* set pointer at end of text */
X	ctrl_s = -ll;				/* set ^S to - # of chars */
X
X	if (pipe(pipe_out)) ERROR(E_SYS);	/* make input pipe; failure if can't */
X
X	if (win_data[7]) window(WIN_SUSP);	/* disable split screen */
X	setup_tty(TTY_SUSP);				/* put console back to original state */
X	if ((ff = fork()) == -1)			/* fork first child: if error, quit */
X		{
X		close(pipe_out[0]);
X		close(pipe_out[1]);
X		setup_tty(TTY_RESUME);
X		if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
X		ERROR(E_SYS);
X		}
X
X	if (ff)							/* if this is the parent, the task is to read into q# */
X		{
X		make_buffer(&timbuf);		/* initialize the q# header */
X		bb.p = timbuf.f;			/* init bb to point to q# */
X		timbuf.z = 	bb.c = 0;
X
X		close(pipe_out[1]);			/* parent won't write to this pipe */
X
X		if ((xx_out = fdopen(pipe_out[0], "r")) == 0)	/* open the "std out" pipe for reading */
X			{
X			close(pipe_out[0]);		/* if can't open output pipe */
X			setup_tty(TTY_RESUME);
X			if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
X			ERROR(E_SYS);			/* "open" failure */
X			}
X		read_stream(xx_out, 0, &bb, &timbuf.z, 0, 0, 1);		/* read from pipe to q# */
X		close(pipe_out[0]);
X
X		while (wait(&status) != ff);		/* wait for children to finish */
X		setup_tty(TTY_RESUME);
X		if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
X		return(status.w_retcode ? -1 : 0);
X		}
X/* This is the child.  It in turn forks into two processes, of which the "parent"	*/
X/* (original child) writes the specified part of the buffer to the pipe, and the	*/
X/* new child (grandchild to the original teco) execl's the Unix command.			*/
X
X	else							/* this is the child */
X		{
X		close(pipe_out[0]);				/* won't read from "output" pipe */
X		if (pipe(pipe_in)) exit(1);		/* make the "std in" pipe for the process, quit if can't */
X
X		if ((ff = fork()) == -1) exit(1);	/* fork to two processes (total 3), exit if error */
X
X		if (ff)							/* parent - will send chars */
X			{
X			close(pipe_in[0]);			/* won't read from this pipe */
X
X		/* open pipe for writing; exit if open fails */
X
X			if ((xx_in = fdopen(pipe_in[1], "w")) == 0) exit(1);
X
X			write_stream(xx_in, &aa, ll, 0);		/* write to stream, CRLF becomes LF */
X			fclose(xx_in);
X
X			while (wait(&status) != ff);	/* wait for child */
X			exit(status.w_retcode);			/* exit with child's status */
X			}
X
X		else							/* this process is the grandchild */
X			{
X			close(pipe_in[1]);			/* close "input" for writing */
X			dup2(pipe_in[0], fileno(stdin));		/* substitute pipe_in for stdin */
X			dup2(pipe_out[1], fileno(stdout));		/* and pipe_out for stdout	*/
X			close(pipe_in[0]);			/* close original descriptors */
X			close(pipe_out[1]);
X
X			execl(shell, shell, "-c", &sysbuf.f->ch[0], 0);		/* execute specified routine */
X			fputs("execl failed\n", stderr);
X			exit(1);
X			}
X		}
X	}
X/* Routines to handle EN wild-card file specification	*/
X/* ENfilespec$ defines file class, leaving 'filespec'	*/
X/* in filespec buffer and reading expanded list of		*/
X/* files into local buffer.  EN$ gets next filespec		*/
X/* into filespec buffer.								*/
X
Xstruct qh en_buf;				/* header for storage for file list */
Xstruct qp en_ptr;				/* pointer to load/read file list	*/
Xstatic char glob_cmd0[] = { 'g', 'l', 'o', 'b', ' ' } ;
X
Xint do_en()
X	{
X	int t;
X
X	if (build_string(&fbuf))					/* if a file string is specified */
X		{
X		if (fbuf.z > CELLSIZE-2) ERROR(E_STL);		/* upper limit on string length */
X		fbuf.f->ch[fbuf.z] = '\0';				/* terminating null */
X		t = do_glob(&en_buf);					/* glob the result */
X		en_ptr.p = en_buf.f;					/* set the buffer pointer to the beginning of the buffer */
X		en_ptr.dot = en_ptr.c = 0;
X		}
X	else										/* if no string, get next filename */
X		{
X		do_en_next();
X		t = (fbuf.z) ? -1 : 0;					/* t zero if no more filespecs */
X		if (!t && !colonflag) ERROR(E_NFI);		/* if no colon, end of spec is an error */
X		}
X	return (t);
X	}
X
X/* routine to expand the string in the filespec buffer */
X/* argument is the address of a qh that gets the expanded string */
X/* argument->v gets set to the number of file specs found */
X
Xint do_glob(buff)
X	struct qh *buff;
X	{
X	char glob_cmd[CELLSIZE+5];			/* "glob filespec" command string */
X	int t;
X	char c;
X	int glob_pipe[2];					/* pipe to forked shell for expanding filenames */
X	struct qp glob_ptr;					/* pointer for loading result buffer */
X	FILE *xx_out;						/* stream for reading chars from pipe */
X	FILE *fdopen();
X	union wait status;
X
X	make_buffer(buff);					/* initialize expanded file buffer */
X	glob_ptr.p = buff->f;				/* initialize pointer to buffer */
X	glob_ptr.c = glob_ptr.dot = buff->z = buff->v = 0;
X	for (t = 0; t < 5; t++) glob_cmd[t] = glob_cmd0[t];		/* set up "glob filespec" command */
X	for (t = 0; t < fbuf.z +1; t++) glob_cmd[t+5] = fbuf.f->ch[t];
X
X	if (pipe(glob_pipe)) ERROR(E_SYS);		/* make a pipe */
X	setup_tty(TTY_SUSP);					/* put console back to normal */
X	if ((t = fork()) == -1)					/* spawn a child... if failure */
X		{
X		close(glob_pipe[0]);				/* undo the pipe */
X		close(glob_pipe[1]);
X		setup_tty(TTY_RESUME);
X		ERROR(E_SYS);						/* and exit with failure */
X		}
X
X	if (t)									/* if this is the parent */
X		{
X		close(glob_pipe[1]);				/* parent won't write */
X		if ((xx_out = fdopen(glob_pipe[0], "r")) == 0)	/* open pipe for read */
X			{
X			close(glob_pipe[0]);						/* failure to open */
X			setup_tty(TTY_RESUME);
X			ERROR(E_SYS);
X			}
X
X		while ((c = getc(xx_out)) != EOF)		/* read characters from pipe */
X			{
X			if (c == '\0') ++buff->v;			/* count null chars that separate file specs */
X			glob_ptr.p->ch[glob_ptr.c] = c;		/* store them in buffer */
X			fwdcx(&glob_ptr);
X			}
X
X		fclose(xx_out);							/* through with stream */
X		buff->z = glob_ptr.dot;					/* save character count */
X		while (wait(&status) != t);				/* wait for child to finish */
X		setup_tty(TTY_RESUME);
X		return(status.w_retcode ? 0 : -1);		/* return success unless child exited nonzero */
X		}
X	else										/* this is the child */
X		{
X		close(glob_pipe[0]);					/* child won't read */
X		dup2(glob_pipe[1], fileno(stdout));		/* substitute pipe for standard out */
X		close(glob_pipe[1]);					/* don't need that anymore */
X		execl("/bin/csh", "csh", "-fc", glob_cmd, 0);		/* execute the "glob" */
X		fputs("execl failed\n", stderr);
X		exit(1);
X		}
X	}
X
X/* routine to get next file spec from "EN" list into filespec buffer */
X
Xdo_en_next()
X	{
X	char c;
X
X	make_buffer(&fbuf);							/* initialize the filespec buffer */
X	fbuf.z = 0;
X
X	while(en_ptr.dot < en_buf.z)				/* stop at end of string */
X		{
X		c = en_ptr.p->ch[en_ptr.c];
X		fwdc(&en_ptr);
X		if (!c) break;							/* null is terminator between file specs */
X		fbuf.f->ch[fbuf.z++] = c;				/* store char */
X		if (fbuf.z >= CELLSIZE-1) ERROR(E_STL);		/* limit on filespec size */
X		}
X
X	fbuf.f->ch[fbuf.z] = '\0';					/* filespec ends with NULL */
X	}
X
X/* routine to read a file name				*/
X/* reads it into fbuf text area				*/
X/* returns nonzero if a name, 0 if none		*/
X/* flag nonzero => empty name clears filespec buffer */
X/* func is 'r' for ER or EB cmds, 'i' for EI, 'w' for EW */
X
Xint read_filename(flag, func)
X	int flag;
X	char func;
X	{
X	int i, t, expand;
X	char c;
X	struct qh temp_buff;						/* temp buffer for globbing filespec */
X
X	if (!(t = build_string(&fbuf)))				/* if no name spec'd */
X		{
X		if (flag) fbuf.z = 0;					/* if no name spec'd, set length to 0 */
X		}
X	else
X		{
X		if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
X		fbuf.f->ch[fbuf.z] = '\0';				/* store terminating NULL */
X
X/* check for characters to be expanded by the shell */
X
X		for (i = 0; i < fbuf.z; i++)
X			if ((c = fbuf.f->ch[i]) == '*' || c == '?' || c == '[' || c == 0173) break;
X		if ( (expand = (i < fbuf.z)) || fbuf.f->ch[0] == '~')	/* one of these was found, or first char is ~ */
X			{
X			temp_buff.f = NULL;					/* make a temp buffer to glob filename into */
X			make_buffer(temp_buff);
X			do_glob(&temp_buff);				/* expand the file name */
X			if (temp_buff.z == 0)				/* no match */
X				{
X				free_blist(temp_buff.f);		/* return the storage */
X				ERROR(func == 'w' ? E_COF : E_FNF);	/* "can't open" or "file not found" */
X				}
X			else if (temp_buff.v == 0)			/* if exactly one file name */
X				{
X				free_blist(fbuf.f);				/* return the old file spec */
X				fbuf.f = temp_buff.f;			/* put the temp buffer there instead */
X				fbuf.z = temp_buff.z;
X				if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
X				fbuf.f->ch[fbuf.z] = '\0';
X
X				if (func == 'w' && expand)		/* if this is EW and 'twas from a wildcard expansion */
X					{
X					vt(VT_SETSPEC1);			/* "file XXXX already exists: overwrite? [yn]" */
X					fputs("File ", stdout);
X					fputs(fbuf.f->ch, stdout);
X					fputs(" already exists: overwrite? [ny] ", stdout);
X					vt(VT_CLRSPEC);
X					c = gettty();				/* read user's response */
X					putchar(CR);
X					vt(VT_EEOL);				/* clean up the screen */
X					if (c != 'y') ERROR(E_COF);	/* abort here */
X					}
X				}
X
X			else								/* multiple file specs */
X				{
X				if (func != 'r' || !(ez_val & EZ_MULT))				/* if multiple file specs here aren't allowed */
X					{
X					free_blist(temp_buff.f);			/* return the storage */
X					ERROR(E_AMB);
X					}
X				free_blist(en_buf.f);					/* substitute the expansion for the "EN" list */
X				en_ptr.p = en_buf.f = temp_buff.f;		/* and initialize the "EN" list pointer */
X				en_buf.z = temp_buff.z;
X				en_ptr.dot = en_ptr.c = 0;
X				do_en_next();					/* get the first file */
X				}
X			}
X		}
X	return(t);
X	}
X
X
X
X/* fetch or set variable */
X
Xset_var(arg)
X	int *arg;			/* argument is pointer to variable */
X	{
X	if (esp->flag1)		/* if an argument, then set the variable */
X		{
X		if (esp->flag2)					/* if two arguments, then <clr>, <set> */
X			*arg = (*arg & ~esp->val2) | esp->val1;
X		else *arg = esp->val1;			/* one arg is new value */
X		esp->flag2 = esp->flag1 = 0;	/* consume argument */
X		}
X	else				/* otherwise fetch the variable's value */
X		{
X		esp->val1 = *arg;
X		esp->flag1 = 1;
X		}
X	}
X
X
X
X/* read from selected input file stream into specified buffer	*/
X/* terminate on end-of-file or form feed						*/
X/* if endsw > 0 terminates after that many lines				*/
X/* if endsw < 0 stops if z > BUFF_LIMIT							*/
X/* returns -1 if read EOF, 0 otherwise							*/
X
Xint read_file(buff, nchars, endsw)
X	struct qp *buff;
X	int *nchars, endsw;
X	{
X	if (!infile->fd) infile->eofsw = -1, ctrl_e = 0;	/* return if no input file open */
X	else infile->eofsw = read_stream(infile->fd, &ctrl_e, buff, nchars, endsw, ez_val & EZ_CRLF, ez_val & EZ_READFF);
X	return(esp->val1 = infile->eofsw);
X	}
X/* read from an I/O stream into specified buffer							*/
X/* this is used by read_file and by "eq" pipe from other Unix processes		*/
X/* args buff, nchars, endsw as above; file is stream pointer, ff_found is	*/
X/* address of a switch to set if read ended with a FF, crlf_sw is lf->crlf	*/
X/* conversion, ff_sw indicates whether to stop on a form feed.				*/
X
Xint read_stream(file, ff_found, buff, nchars, endsw, crlf_sw, ff_sw)
X	FILE *file;
X	struct qp *buff;
X	int *ff_found, *nchars, endsw, crlf_sw, ff_sw;
X	{
X	char chr;
X	int crflag;
X	register struct buffcell *p;
X	register int c;
X
X	p = (*buff).p;		/* copy pointer locally */
X	c = (*buff).c;
X	crflag = 0;			/* "last char wasn't CR" */
X	while (((chr = getc(file)) != EOF) && ((chr != FF) || ff_sw))
X		{
X		if ((chr == LF) && !crflag && !crlf_sw)		/* automatic cr before lf */
X			{
X			p->ch[c] = CR;		/* store a cr */
X			++(*nchars);		/* increment buffer count */
X			if (++c > CELLSIZE-1)	/* next cell? */
X				{
X				if (!p->f)			/* need a new cell? */
X					{
X					p->f = get_bcell();
X					p->f->b = p;
X					}
X				p = p->f;
X				c = 0;
X				}
X			}
X		p->ch[c] = chr;			/* store char */
X		++(*nchars);			/* increment character count */
X		if (++c > CELLSIZE-1)	/* next cell? */
X			{
X			if (!p->f)			/* need a new cell? */
X				{
X				p->f = get_bcell();
X				p->f->b = p;
X				}
X			p = p->f;
X			c = 0;
X			}
X		crflag = (chr == CR);	/* flag set if last char was CR */
X		if ((chr == LF) && ((endsw < 0 && z > BUFF_LIMIT) || (endsw > 0 && --endsw == 0))) break;	/* term after N lines */
X		}
X	(*buff).p = p;			/* update pointer */
X	(*buff).c = c;
X	if (ff_found) *ff_found = (chr == FF) ? -1 : 0;		/* set flag to indicate whether FF found */
X	return( (chr == EOF) ? -1 : 0);					/* and return "eof found" value */
X	}
X/* routine to write text buffer out to selected output file	*/
X/* arguments are qp to start of text, number of characters,	*/
X/* and an "append FF" switch								*/
X
Xwrite_file(buff, nchars, ffsw)
X	struct qp *buff;
X	int nchars, ffsw;
X	{
X	if (!outfile->fd && (nchars)) ERROR(E_NFO);
X	else write_stream(outfile->fd, buff, nchars, ez_val & EZ_CRLF);
X	if (outfile->fd && ffsw) putc(FF, outfile->fd);
X	}
X
X
X/* routine to write text buffer to I/O stream.  Used by	*/
X/* write_file, above, and by "eq" write to pipe to other	*/
X/* Unix processes.  Arguments buff, nchars as above; file	*/
X/* is stream pointer, crlf_sw zero converts CRLF to LF		*/
X
Xwrite_stream(file, buff, nchars, crlf_sw)
X	FILE *file;
X	struct qp *buff;
X	int nchars, crlf_sw;
X	{
X	char c;
X	int crflag;
X
X	crflag = 0;
X	for (; nchars > 0; nchars--)
X		{
X		if ((c = (*buff).p->ch[(*buff).c]) == CR) crflag = 1;	/* set flag if a c.r. */
X		else
X			{
X			if ((crflag) && ((c != LF) || crlf_sw))			/* if c.r. not before lf, or if not in */
X				putc(CR, file);								/* "no cr" mode, output the c.r. */
X			crflag = 0;
X			putc(c, file);
X			}
X		if (++(*buff).c > CELLSIZE-1)
X			{
X			(*buff).p = (*buff).p->f;
X			(*buff).c = 0;
X			}
X		}
X	}
X
X
X/* routine to kill output file: argument is pointer to an output file structure */
X
Xkill_output(outptr)
X	struct outfiledata *outptr;
X	{
X	if (outptr->fd)
X		{
X		fclose(outptr->fd);
X		unlink(outptr->t_name);
X		outptr->fd = NULL;
X		}
X	}
X/* "panic" routine called when "hangup" signal occurs */
X/* this routine saves the text buffer and closes the output files */
X
Xchar panic_name[] = "TECO_SAVED.tmp";			/* name of file created to save buffer */
X
Xpanic()
X	{
X	if (!outfile->fd && z) outfile->fd = fopen(panic_name, "w");	/* if buffer nonempty and no file open, make one */
X
X	set_pointer(0, &aa);								/* set a pointer to start of text buffer */
X	if (outfile->fd && z) write_file(&aa, z, 0);		/* and write out buffer unless "open" failed */
X
X	if (po_file.fd) fclose(po_file.fd), po_file.fd = NULL;		/* close any open output files */
X	if (so_file.fd) fclose(so_file.fd), so_file.fd = NULL;
X	}
X/* do "F" commands */
X
Xdo_f()
X	{
X	struct buffcell *delete_p;
X
X	switch (mapch_l[getcmdc(trace_sw)])		 /* read next character and dispatch */
X		{
X		case '<':			/* back to beginning of current iteration */
X			if (cptr.flag & F_ITER)		/* if in iteration */
X				{
X				cptr.p = cptr.il->p;	/* restore */
X				cptr.c = cptr.il->c;
X				cptr.dot = cptr.il->dot;
X				}
X			else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b);	/* else, restart current macro */
X			break;
X
X		case '>':			/* to end of current iteration */
X			find_enditer();	/* find it */
X			if ( ( ((esp->flag1) ? esp->val1 : srch_result) >= 0) ? (~colonflag) : colonflag)	/* if exit */
X			pop_iteration(0);	/* and exit if appropriate */
X			break;
X
X		case '\'':					/* to end of conditional */
X		case '|':					/* to "else," or end */
X			find_endcond(cmdc);
X			break;
X
X/* "F" search commands */
X
X		case 'b':						/* bounded search, alternative args */
X			do_fb();
X			break;
X
X		case 'c':						/* bounded search, alternative args, then "FR" */
X			if (do_fb()) goto do_fr;
X			while (getcmdc(trace_sw) != term_char);		/* otherwise skip insert string */
X			break;
X
X		case 'n':						/* do "N" and then "FR" */
X			if (do_nsearch('n')) goto do_fr;
X			while (getcmdc(trace_sw) != term_char);		/* otherwise skip insert string */
X			break;
X
X		case '_':						/* do "_" and then "FR" */
X			if (do_nsearch('_')) goto do_fr;
X			while (getcmdc(trace_sw) != term_char);		/* otherwise skip insert string */
X			break;
X
X		case 's':						/* search and replace: search, then do "FR" */
X			build_string(&sbuf);		/* read search string and terminator */
X			if (end_search(  do_search( setup_search() )  )) goto do_fr;	/* if search passed, do "FR" */
X			while (getcmdc(trace_sw) != term_char);		/* otherwise skip insert string */
X			break;
X		case 'r':						/* replace last insert, search, etc. */
X			if (esp->flag1) ERROR(E_NFR);	/* shouldn't have argument */
X			term_char = (atflag) ? getcmdc(trace_sw) : ESC;		/* set terminator */
X			atflag = 0;
X		  do_fr:					/* entry from FN, F_, and FC */
X			set_pointer(dot, &cc);		/* save a pointer to the current spot */
X			dot += ctrl_s;				/* back dot up over the string */
X			set_pointer(dot, &aa);		/* code from "insert1": convert dot to a qp */
X			delete_p = aa.p;			/* save beginning of original cell */
X			if (dot < buff_mod) buff_mod = dot;		/* update earliest char loc touched */
X			insert_p = bb.p = get_bcell();			/* get a new cell */
X			bb.c = 0;
X			ins_count = aa.c;		/* save char position of dot in cell */
X			aa.c = 0;
X
X			movenchars(&aa, &bb, ins_count);	/* copy cell up to dot */
X			moveuntil(&cptr, &bb, term_char, &ins_count, cptr.z-cptr.dot, trace_sw);	/* insert */
X			cptr.dot += ins_count;		/* advance command-string pointer */
X			getcmdc(trace_sw);			/* skip terminator */
X
X			z += ctrl_s;				/* subtract delete length from buffer count */
X			delete_p->b->f = insert_p;	/* put the new cell where the old one was */
X			insert_p->b = delete_p->b;	/* code borrowed from "insert2" */
X			insert_p = NULL;
X
X			if (bb.c == cc.c)			/* if replacement text was same length, we can save time */
X				{
X				for (; bb.c < CELLSIZE; bb.c++) bb.p->ch[bb.c] = cc.p->ch[bb.c];	/* copy rest of cell */
X				bb.p->f = cc.p->f;		/* replace orig cell's place in chain with end of new list */
X				if (bb.p->f) bb.p->f->b = bb.p;
X				cc.p->f = NULL;			/* terminate the part snipped out */
X				free_blist(delete_p);	/* return the old part */
X				}
X
X			else						/* different positions: shift the remainder of the buffer */
X				{
X				bb.p->f = delete_p;		/* splice rest of buffer to end */
X				delete_p->b = bb.p;
X				movenchars(&cc, &bb, z-dot);	/* squeeze buffer */
X				free_blist(bb.p->f);		/* return unused cells */
X				bb.p->f = NULL;				/* and end the buffer */
X				}
X
X			z += ins_count;				/* add # of chars inserted */
X			dot += ins_count;
X			ctrl_s = -ins_count;		/* save string length */
X			esp->flag1 = esp->flag2 = 0;	/* and consume arguments */
X			esp->op = OP_START;
X			break;
X
X		default:
X			ERROR(E_IFC);
X		}
X	}
X/* routines for macro iteration */
X/* pop iteration: if arg nonzero, exit unconditionally */
X/* else check exit conditions and exit or reiterate */
X
Xpop_iteration(arg)
X	int arg;
X	{
X	if (!arg && (!cptr.il->dflag || (--(cptr.il->count) > 0)) )		/* if reiteration */
X		{
X		cptr.p = cptr.il->p;		/* restore */
X		cptr.c = cptr.il->c;
X		cptr.dot = cptr.il->dot;
X		}
X	else
X		{
X		if (cptr.il->b) cptr.il = cptr.il->b;	/* if not last thing on stack, back up */
X		else cptr.flag &= ~F_ITER;				/* else clear "iteration" flag */
X		}
X	}
X
X
X/* find end of iteration - read over arbitrary <> and one > */
X
Xfind_enditer()
X	{
X	register int icnt;
X
X	for (icnt = 1; icnt > 0;)		/* scan for matching > */
X		{
X		while ((skipto(0) != '<') && (skipc != '>'));	/* scan for next < or > */
X		if (skipc == '<') ++icnt;		/* and keep track of macro level */
X		else --icnt;
X		}
X	}
X
X
X
X/* find end of conditional */
Xchar find_endcond(arg)
X	char arg;
X	{
X	register int icnt;
X
X	for (icnt = 1; icnt > 0;)
X		{
X		while ((skipto(0) != '"') && (skipc != '\'') && (skipc != '|'));
X		if (skipc == '"') ++icnt;
X		else if (skipc == '\'') -- icnt;
X		else if ((icnt == 1) && (arg == '|')) break;
X		}
X	}
X
END_OF_te_exec2.c
if test 29256 -ne `wc -c <te_exec2.c`; then
    echo shar: \"te_exec2.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
DONE=true
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	echo shar: You still need to run archive ${I}.
	DONE=false
    fi
done
if test "$DONE" = "true" ; then
	echo You have unpacked all 4 archives.
	echo "See the *.doc files"
	rm -f ark[1-9]isdone
fi
##  End of shell archive.
exit 0