|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 13995 (0x36ab)
Types: TextFile
Names: »te_subs.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/teco/te_subs.c«
/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */
/* This program and its components belong to GenRad Inc, Concord MA 01742 */
/* They may be copied if this copyright notice is included */
/* te_subs.c subroutines 11/8/85 */
#include "te_defs.h"
/* routines to copy a string of characters */
/* movenchars(from, to, n) */
/* from, to are the addresses of qps */
/* n is the number of characters to move */
/* moveuntil(from, to, c, &n, max) */
/* c is the match character that ends the move */
/* n is the returned number of chars moved */
/* max is the maximum number of chars to move */
movenchars(from, to, n)
struct qp *from, *to; /* address of buffer pointers */
register int n; /* number of characters */
{
register struct buffcell *fp, *tp; /* local qp ".p" pointers */
register int fc, tc; /* local qp ".c" subscripts */
if (n != 0)
{
fp = from->p; /* copy pointers to local registers */
fc = from->c;
tp = to->p;
tc = to->c;
for (; n > 0; n--)
{
tp->ch[tc++] = fp->ch[fc++]; /* move one char */
if (tc > CELLSIZE-1) /* check current cell done */
{
if (!tp->f) /* is there another following? */
{
tp->f = get_bcell(); /* no, add one */
tp->f->b = tp;
}
tp = tp->f;
tc = 0;
}
if (fc > CELLSIZE-1) /* check current cell done */
{
if (!fp->f) /* oops, run out of source */
{
if (n > 1) ERROR(E_UTC); /* error if not done */
}
else {
fp = fp->f; /* chain to next cell */
fc = 0;
}
}
}
from->p = fp; /* restore arguments */
to->p = tp;
from->c = fc;
to->c = tc;
}
}
\f
moveuntil(from, to, c, n, max, trace)
struct qp *from, *to; /* address of buffer pointers */
register char c; /* match char that ends move */
int *n; /* pointer to returned value */
int max; /* limit on chars to move */
int trace; /* echo characters if nonzero */
{
register struct buffcell *fp, *tp; /* local qpr ".p" pointers */
register int fc, tc; /* local qpr ".c" subscripts */
fp = from->p; /* copy pointers to local registers */
fc = from->c;
tp = to->p;
tc = to->c;
for (*n = 0; fp->ch[fc] != c; (*n)++) /* until terminating char... */
{
if (max-- <= 0) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
tp->ch[tc++] = fp->ch[fc++]; /* move one char */
if (trace) type_char(tp->ch[tc-1]); /* type it out if trace mode */
if (tc > CELLSIZE-1) /* check current cell done */
{
if (!tp->f) /* is there another following? */
{
tp->f = get_bcell(); /* no, add one */
tp->f->b = tp;
}
tp = tp->f;
tc = 0;
}
if (fc > CELLSIZE-1) /* check current cell done */
{
if (!fp->f) ERROR(E_UTC); /* oops, run out of source */
else {
fp = fp->f; /* chain to next cell */
fc = 0;
}
}
}
from->p = fp; /* restore arguments */
to->p = tp;
from->c = fc;
to->c = tc;
}
\f
/* routine to get numeric argument */
int get_value(d) /* get a value, default is argument */
int d;
{
int v;
v = (esp->flag1) ? esp->val1 :
(esp->op == OP_SUB) ? -d : d;
esp->flag1 = 0; /* consume argument */
esp->op = OP_START;
return(v);
}
/* routine to convert a line count */
/* returns number of chars between dot and nth line feed */
int lines(arg)
register int arg;
{
register int i, c;
register struct buffcell *p;
for (i = dot / CELLSIZE, p = buff.f; (i > 0) && (p->f); i--) p = p->f; /* find dot */
c = dot % CELLSIZE;
if (arg <= 0) /* scan backwards */
{
for (i = dot; (arg < 1) && (i > 0); ) /* repeat for each line */
{
--i; /* count characters */
if (--c < 0) /* back up the pointer */
{
if (!(p = p->b)) break;
c = CELLSIZE - 1;
}
if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) ++arg; /* if line sep found */
}
if (arg > 0) ++i; /* if terminated on a line separator, advance over the separator */
}
else /* scan forwards */
{
for (i = dot; (arg > 0) && (i < z); i++)
{
if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) --arg;
if (++c > CELLSIZE-1)
{
if (!(p = p->f)) break;
c = 0;
}
} /* this will incr over the separator anyway */
}
return(i - dot);
}
\f
/* routine to handle args for K, T, X, etc. */
/* if two args, 'char x' to 'char y' */
/* if just one arg, then n lines (default 1) */
/* sets a pointer to the beginning of the specd */
/* string, and a char count value */
int line_args(d, p)
int d; /* nonzero: leave dot at start */
struct qp *p;
{
int n;
if (esp->flag1 && esp->flag2) /* if two args */
{
if (esp->val1 <= esp->val2) /* in right order */
{
if (esp->val1 < 0) esp->val1 = 0;
if (esp->val2 > z) esp->val2 = z;
if (d) dot = esp->val1; /* update dot */
set_pointer(esp->val1, p); /* set the pointer */
esp->flag2 = esp->flag1 = 0; /* consume arguments */
esp->op = OP_START;
return(esp->val2 - esp->val1); /* and return the count */
}
else
{
if (esp->val2 < 0) esp->val2 = 0;
if (esp->val1 > z) esp->val1 = z;
if (d) dot = esp->val2; /* update dot */
set_pointer(esp->val2, p); /* args in reverse order */
esp->flag2 = esp->flag1 = 0; /* consume arguments */
esp->op = OP_START;
return(esp->val1 - esp->val2);
}
}
else
{
n = lines(get_value(1));
if (n < -dot) n = -dot;
else if (n > z-dot) n = z-dot;
if (n >= 0) set_pointer(dot, p);
else
{
n = -n;
set_pointer(dot - n, p);
if (d) dot -= n;
}
return(n);
}
}
\f
/* convert character c to a q-register spec */
int getqspec(fors, c) /* fors ("file or search") nonzero = allow _ or * */
int fors;
char c;
{
if (isdigit(c)) return(c - '0' + 1);
else if isalpha(c) return(mapch_l[c] - 'a' + 11);
else if (fors)
{
if (c == '_') return (SERBUF);
if (c == '*') return (FILBUF);
if (c == '%') return (SYSBUF);
if (c == '#') return (TIMBUF);
}
ERROR(E_IQN);
}
/* routines to do insert operations */
/* insert1() copies current cell up to dot into a new cell */
/* leaves bb pointing to end of that text */
/* insert2() copies rest of buffer */
struct buffcell *insert_p;
insert1()
{
int nchars; /* number of chars in cell */
set_pointer(dot, &aa); /* convert dot to a qp */
if (dot < buff_mod) buff_mod = dot; /* update earliest char loc touched */
insert_p = bb.p = get_bcell(); /* get a new cell */
bb.c = 0;
nchars = aa.c; /* save char position of dot in cell */
aa.c = 0;
/* now aa points to the beginning of the buffer cell that */
/* contains dot, bb points to the beginning of a new cell,*/
/* nchars is the number of chars before dot */
movenchars(&aa, &bb, nchars); /* copy cell up to dot */
}
insert2(count) /* count is the number of chars added */
int count;
{
aa.p->b->f = insert_p; /* put the new cell where the old one was */
insert_p->b = aa.p->b;
insert_p = NULL;
bb.p->f = aa.p; /* splice rest of buffer to end */
aa.p->b = bb.p;
movenchars(&aa, &bb, z-dot); /* squeeze buffer */
free_blist(bb.p->f); /* return unused cells */
bb.p->f = NULL; /* and end the buffer */
z += count; /* add # of chars inserted */
dot += count;
ctrl_s = -count; /* save string length */
}
\f
/* subroutine to delete n characters starting at dot */
/* argument is number of characters */
delete1(nchars)
int nchars;
{
if (!nchars) return; /* 0 chars is a nop */
if (nchars < 0) /* delete negative number of characters? */
{
nchars = -nchars; /* make ll positive */
if (nchars > dot) ERROR(E_POP); /* don't delete beyond beg of buffer */
dot -= nchars; /* put pointer before deleted text */
}
else if (dot + nchars > z) ERROR(E_POP); /* don't delete beyond end of buffer */
set_pointer(dot, &aa); /* pointer to beginning of area to delete */
set_pointer(dot+nchars, &bb); /* and to end */
if (dot < buff_mod) buff_mod = dot; /* update earliest char loc touched */
movenchars(&bb, &aa, z-(dot+nchars)); /* move text unless delete ends at z */
free_blist(aa.p->f); /* return any cells after end */
aa.p->f = NULL; /* end the buffer */
z -= nchars; /* adjust z */
}
\f
/* routine to process "O" command */
struct qh obuff; /* tag string buffer */
do_o()
{
int i, j; /* i used as start of tag, j as end */
int p, level; /* p is pointer to tag string, level is iteration lvl */
int epfound; /* flag for "second ! found" */
if (!build_string(&obuff)) return; /* no tag spec'd: continue */
if (obuff.z > CELLSIZE) ERROR(E_STL); /* string too long */
esp->op = OP_START; /* consume any argument */
if (esp->flag1) /* is there one? */
{
esp->flag1 = 0; /* consume it */
if (esp->val1 < 0) return; /* computed goto out of range - */
for (i = 0; (i < obuff.z) && (esp->val1 > 0); i++) /* scan to find right tag */
if (obuff.f->ch[i] == ',') esp->val1--; /* count commas */
if (esp->val1 > 0) return; /* computed goto out of range + */
/* now i is either at 0 or after the nth comma */
for (j = i; j < obuff.z; j++) /* find end of tag */
if (obuff.f->ch[j] == ',') break; /* stop at next comma */
if (j == i) return; /* two adjacent commas: zero length tag */
}
else
{
i = 0; /* not a computed goto: use whole tag buffer */
j = obuff.z;
}
/* start from beginning of iteration or macro, and look for tag */
if (cptr.flag & F_ITER) /* if in iteration */
{
cptr.p = cptr.il->p; /* restore */
cptr.c = cptr.il->c;
cptr.dot = cptr.il->dot;
}
else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b); /* find macro start */
\f
/* search for tag */
for (level = 0; ;) /* look through rest of command string */
{
switch (skipto(1)) /* look for interesting things, including ! */
{
case '<': /* start of iteration */
++level;
break;
case '>': /* end of iteration */
if ((level == 0) && (cptr.flag & F_ITER)) pop_iteration(1);
else --level;
break;
case '!': /* start of tag */
for (epfound = 0; ; epfound = 0) /* keep looking for tag */
{
for (p = i; p < j; p++)
{
if (getcmdc(0) == '!') epfound = 1; /* mark "trailing ! found */
if (mapch_l[cmdc] != mapch_l[obuff.f->ch[p]]) break; /* compare */
}
if (p >= j) /* if all comparison chars matched */
{
if (getcmdc(0) == '!') return; /* and tag ends with !, found it */
}
else if (!epfound) while (getcmdc(0) != '!'); /* else look for next ! and continue */
}
break;
} /* end of switch */
} /* end of scan loop */
} /* end of subroutine */
\f
/* routine to skip to next ", ', |, <, or > */
/* skips over these chars embedded in text strings */
/* stops in ! if argument is nonzero */
/* returns character found, and leaves it in skipc */
char skipto(arg)
int arg;
{
int atsw; /* "at" prefix */
char ta, term; /* temp attributes, terminator */
for (atsw = 0; ;) /* forever */
{
while (!(ta = spec_chars[skipc = getcmdc(0)] & (A_X | A_S | A_T | A_Q))); /* read until something interesting found */
again:
if (ta & A_Q) getcmdc(0); /* if command takes a Q spec, skip the spec */
if (ta & A_X) /* sought char found: quit */
{
if (skipc == '"') getcmdc(0); /* quote must skip next char */
return(skipc);
}
if (ta & A_S) /* other special char */
{
switch (skipc)
{
case '^': /* treat next char as CTL */
if (ta = spec_chars[skipc = getcmdc(0) & 0x1f]) goto again;
break;
case '@': /* use alternative text terminator */
atsw = 1;
break;
case CTL (^): /* ^^ is value of next char: skip that char */
getcmdc(0);
break;
case CTL (A): /* type text */
term = (atsw) ? getcmdc(0) : CTL (A);
atsw = 0;
while (getcmdc(0) != term); /* skip text */
break;
case '!': /* tag */
if (arg) return(skipc);
while (getcmdc(0) != '!'); /* skip until next ! */
break;
case 'e': /* first char of two-letter E or F command */
case 'f':
if (spec_chars[getcmdc(0)] & ((skipc == 'e') ? A_E : A_F)) /* if one with a text arg */
{
term = (atsw) ? getcmdc(0) : ESC;
atsw = 0;
while (getcmdc(0) != term); /* read past terminator */
}
break;
} /* end "switch" */
} /* end "if (ta & A_S)" */
\f
else if (ta & A_T) /* command with a text argument */
{
term = (atsw) ? getcmdc(0) : ESC;
atsw = 0;
while (getcmdc(0) != term); /* skip text */
}
} /* end "forever" */
} /* end "skipto()" */
\f
/* find number of characters to next matching (, [, or { (like '%' in vi) */
do_ctlp()
{
int i, l;
char c, c1;
set_pointer(dot, &aa); /* point to text buffer */
switch(c1 = aa.p->ch[aa.c])
{
case '(':
c = ')'; /* match char is ) */
i = 1; /* direction is positive */
break;
case ')':
c = '('; /* match char is ( */
i = -1; /* direction is negative */
break;
case '[':
c = ']';
i = 1;
break;
case ']':
c = '[';
i = -1;
break;
case '{':
c = '}';
i = 1;
break;
case '}':
c = '{';
i = -1;
break;
case '<':
c = '>';
i = 1;
break;
case '>':
c = '<';
i = -1;
break;
case '"':
c = '\'';
i = 1;
break;
\f
case '\'':
c = '"';
i = -1;
break;
default:
esp->val1 = i = 0; /* not on a matchable char, return 0 */
}
l = 1; /* start with one unmatched char */
if (i > 0) /* if searching forward */
{
for (i = dot, fwdc(&aa); (i < z) && (l); fwdc(&aa) )
{
++i;
if (aa.p->ch[aa.c] == c) --l;
else if (aa.p->ch[aa.c] == c1) ++l;
}
esp->val1 = (i < z) ? i - dot : 0;
}
else if (i < 0)
{
for (i = dot, backc(&aa); (i >= 0) && (l); backc(&aa) )
{
--i;
if (aa.p->ch[aa.c] == c) --l;
else if (aa.p->ch[aa.c] == c1) ++l;
}
esp->val1 = (i >= 0) ? i - dot : 0;
}
esp->flag1 = 1;
}