|
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; }