home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume9 / teco / part02 / te_subs.c < prev   
Encoding:
C/C++ Source or Header  |  1987-03-11  |  13.7 KB  |  543 lines

  1. /* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum                        */
  2. /* This program and its components belong to GenRad Inc, Concord MA 01742    */
  3. /* They may be copied if this copyright notice is included                    */
  4.  
  5. /* te_subs.c subroutines  11/8/85 */
  6. #include "te_defs.h"
  7.  
  8. /* routines to copy a string of characters        */
  9. /* movenchars(from, to, n)                        */
  10. /*      from, to are the addresses of qps        */
  11. /*    n is the number of characters to move        */
  12. /* moveuntil(from, to, c, &n, max)                */
  13. /*      c is the match character that ends the move */
  14. /*    n is the returned number of chars moved    */
  15. /* max is the maximum number of chars to move    */
  16.  
  17. movenchars(from, to, n)
  18.     struct qp *from, *to;        /* address of buffer pointers */
  19.     register int n;                /* number of characters */
  20.     {
  21.     register struct buffcell *fp, *tp;    /* local qp ".p" pointers    */
  22.     register int fc, tc;                /* local qp ".c" subscripts */
  23.  
  24.     if (n != 0)
  25.         {
  26.         fp = from->p;                /* copy pointers to local registers */
  27.         fc = from->c;
  28.         tp = to->p;
  29.         tc = to->c;
  30.  
  31.         for (; n > 0; n--)
  32.             {
  33.             tp->ch[tc++] = fp->ch[fc++];    /* move one char */
  34.  
  35.             if (tc > CELLSIZE-1)    /* check current cell done */
  36.                 {
  37.                 if (!tp->f)        /* is there another following? */
  38.                     {
  39.                     tp->f = get_bcell();    /* no, add one */
  40.                     tp->f->b = tp;
  41.                     }
  42.                 tp = tp->f;
  43.                 tc = 0;
  44.                 }
  45.  
  46.             if (fc > CELLSIZE-1)    /* check current cell done */
  47.                 {
  48.                 if (!fp->f)        /* oops, run out of source */
  49.                     {
  50.                     if (n > 1) ERROR(E_UTC);    /* error if not done */
  51.                     }
  52.                 else {
  53.                     fp = fp->f;        /* chain to next cell */
  54.                     fc = 0;
  55.                     }
  56.                 }
  57.             }
  58.         from->p = fp;        /* restore arguments */
  59.         to->p = tp;
  60.         from->c = fc;
  61.         to->c = tc;
  62.         }
  63.     }
  64. moveuntil(from, to, c, n, max, trace)
  65.     struct qp *from, *to;        /* address of buffer pointers    */
  66.     register char c;            /* match char that ends move    */
  67.     int *n;                        /* pointer to returned value    */
  68.     int max;                    /* limit on chars to move        */
  69.     int trace;                    /* echo characters if nonzero    */
  70.     {
  71.     register struct buffcell *fp, *tp;    /* local qpr ".p" pointers    */
  72.     register int fc, tc;                /* local qpr ".c" subscripts */
  73.  
  74.     fp = from->p;                /* copy pointers to local registers */
  75.     fc = from->c;
  76.     tp = to->p;
  77.     tc = to->c;
  78.  
  79.     for (*n = 0; fp->ch[fc] != c; (*n)++)    /* until terminating char... */
  80.         {
  81.         if (max-- <= 0) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  82.         tp->ch[tc++] = fp->ch[fc++];    /* move one char */
  83.         if (trace) type_char(tp->ch[tc-1]);        /* type it out if trace mode */
  84.  
  85.         if (tc > CELLSIZE-1)    /* check current cell done */
  86.             {
  87.             if (!tp->f)        /* is there another following? */
  88.                 {
  89.                 tp->f = get_bcell();    /* no, add one */
  90.                 tp->f->b = tp;
  91.                 }
  92.             tp = tp->f;
  93.             tc = 0;
  94.             }
  95.  
  96.         if (fc > CELLSIZE-1)    /* check current cell done */
  97.             {
  98.             if (!fp->f) ERROR(E_UTC);     /* oops, run out of source */
  99.             else {
  100.                 fp = fp->f;        /* chain to next cell */
  101.                 fc = 0;
  102.                 }
  103.             }
  104.         }
  105.  
  106.     from->p = fp;        /* restore arguments */
  107.     to->p = tp;
  108.     from->c = fc;
  109.     to->c = tc;
  110.     }
  111.  
  112. /* routine to get numeric argument */
  113. int get_value(d)        /* get a value, default is argument */
  114.     int d;
  115.     {
  116.     int v;
  117.  
  118.     v = (esp->flag1) ? esp->val1 : 
  119.             (esp->op == OP_SUB) ? -d : d;
  120.     esp->flag1 = 0;        /* consume argument */
  121.     esp->op = OP_START;
  122.     return(v);
  123.     }
  124.  
  125.  
  126.  
  127.  
  128. /* routine to convert a line count */
  129. /* returns number of chars between dot and nth line feed */
  130.  
  131. int lines(arg)
  132.     register int arg;
  133.     {
  134.     register int i, c;
  135.     register struct buffcell *p;
  136.  
  137.     for (i = dot / CELLSIZE, p = buff.f; (i > 0) && (p->f); i--) p = p->f;    /* find dot */
  138.     c = dot % CELLSIZE;
  139.     if (arg <= 0)                /* scan backwards */
  140.         {
  141.         for (i = dot; (arg < 1) && (i > 0); )        /* repeat for each line */
  142.             {
  143.             --i;                /* count characters */
  144.             if (--c < 0)    /* back up the pointer */
  145.                 {
  146.                 if (!(p = p->b)) break;
  147.                 c = CELLSIZE - 1;
  148.                 }
  149.             if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) ++arg;    /* if line sep found */
  150.             }
  151.         if (arg > 0) ++i;                /* if terminated on a line separator, advance over the separator */
  152.         }
  153.  
  154.     else                        /* scan forwards */
  155.         {
  156.         for (i = dot; (arg > 0) && (i < z); i++)
  157.             {
  158.             if ( (ez_val & EZ_NOVTFF) ? (p->ch[c] == LF) : (spec_chars[p->ch[c]] & A_L) ) --arg;
  159.             if (++c > CELLSIZE-1)
  160.                 {
  161.                 if (!(p = p->f)) break;
  162.                 c = 0;
  163.                 }
  164.             }            /* this will incr over the separator anyway */
  165.         }
  166.     return(i - dot);
  167.     }
  168.  
  169. /* routine to handle args for K, T, X, etc.        */
  170. /* if two args, 'char x' to 'char y'            */
  171. /* if just one arg, then n lines (default 1)    */
  172. /* sets a pointer to the beginning of the specd    */
  173. /* string, and a char count value                */
  174.  
  175. int line_args(d, p)
  176.     int d;                    /* nonzero: leave dot at start */
  177.     struct qp *p;
  178.     {
  179.     int n;
  180.  
  181.     if (esp->flag1 && esp->flag2)        /* if two args */
  182.         {
  183.         if (esp->val1 <= esp->val2)        /* in right order */
  184.             {
  185.             if (esp->val1 < 0) esp->val1 = 0;
  186.             if (esp->val2 > z) esp->val2 = z;
  187.             if (d) dot = esp->val1;        /* update dot */
  188.             set_pointer(esp->val1, p);    /* set the pointer */
  189.             esp->flag2 = esp->flag1 = 0;    /* consume arguments */
  190.             esp->op = OP_START;
  191.             return(esp->val2 - esp->val1);    /* and return the count */
  192.             }
  193.         else
  194.             {
  195.             if (esp->val2 < 0) esp->val2 = 0;
  196.             if (esp->val1 > z) esp->val1 = z;
  197.             if (d) dot = esp->val2;        /* update dot */
  198.             set_pointer(esp->val2, p);    /* args in reverse order */
  199.             esp->flag2 = esp->flag1 = 0;    /* consume arguments */
  200.             esp->op = OP_START;
  201.             return(esp->val1 - esp->val2);
  202.             }
  203.         }
  204.     else
  205.         {
  206.         n = lines(get_value(1));
  207.         if (n < -dot) n = -dot;
  208.         else if (n > z-dot) n = z-dot;
  209.         if (n >= 0) set_pointer(dot, p);
  210.         else
  211.             {
  212.             n = -n;
  213.             set_pointer(dot - n, p);
  214.             if (d) dot -= n;
  215.             }
  216.         return(n);
  217.         }
  218.     }
  219.  
  220. /* convert character c to a q-register spec */
  221. int getqspec(fors, c)    /* fors ("file or search") nonzero = allow _ or * */
  222.     int fors;
  223.     char c;
  224.     {
  225.     if (isdigit(c)) return(c - '0' + 1);
  226.     else if isalpha(c) return(mapch_l[c] - 'a' + 11);
  227.     else if (fors)
  228.         {
  229.         if (c == '_') return (SERBUF);
  230.         if (c == '*') return (FILBUF);
  231.         if (c == '%') return (SYSBUF);
  232.         if (c == '#') return (TIMBUF);
  233.         }
  234.     ERROR(E_IQN);
  235.     }
  236.  
  237.  
  238.  
  239. /* routines to do insert operations */
  240. /* insert1() copies current cell up to dot into a new cell */
  241. /* leaves bb pointing to end of that text */
  242. /* insert2() copies rest of buffer */
  243.  
  244. struct buffcell *insert_p;
  245.  
  246. insert1()
  247.     {
  248.     int nchars;                /* number of chars in cell */
  249.  
  250.     set_pointer(dot, &aa);    /* convert dot to a qp */
  251.     if (dot < buff_mod) buff_mod = dot;        /* update earliest char loc touched */
  252.     insert_p = bb.p = get_bcell();        /* get a new cell */
  253.     bb.c = 0;
  254.     nchars = aa.c;            /* save char position of dot in cell */
  255.     aa.c = 0;
  256.  
  257. /* now aa points to the beginning of the buffer cell that */
  258. /* contains dot, bb points to the beginning of a new cell,*/
  259. /* nchars is the number of chars before dot */
  260.  
  261.     movenchars(&aa, &bb, nchars);    /* copy cell up to dot */
  262.     }
  263.  
  264.  
  265.  
  266. insert2(count)                /* count is the number of chars added */
  267.     int count;
  268.     {
  269.     aa.p->b->f = insert_p;        /* put the new cell where the old one was */
  270.     insert_p->b = aa.p->b;
  271.     insert_p = NULL;
  272.  
  273.     bb.p->f = aa.p;            /* splice rest of buffer to end */
  274.     aa.p->b = bb.p;
  275.     movenchars(&aa, &bb, z-dot);    /* squeeze buffer */
  276.     free_blist(bb.p->f);    /* return unused cells */
  277.     bb.p->f = NULL;            /* and end the buffer */
  278.     z += count;                /* add # of chars inserted */
  279.     dot += count;
  280.     ctrl_s = -count;        /* save string length */
  281.     }
  282.  
  283. /* subroutine to delete n characters starting at dot    */
  284. /* argument is number of characters                        */
  285.  
  286. delete1(nchars)
  287.     int nchars;
  288.     {
  289.     if (!nchars) return;        /* 0 chars is a nop */
  290.     if (nchars < 0)        /* delete negative number of characters? */
  291.         {
  292.         nchars = -nchars;            /* make ll positive */
  293.         if (nchars > dot) ERROR(E_POP);        /* don't delete beyond beg of buffer */
  294.         dot -= nchars;                /* put pointer before deleted text */
  295.         }
  296.     else if (dot + nchars > z) ERROR(E_POP);    /* don't delete beyond end of buffer */
  297.  
  298.     set_pointer(dot, &aa);            /* pointer to beginning of area to delete */
  299.     set_pointer(dot+nchars, &bb);    /* and to end */
  300.     if (dot < buff_mod) buff_mod = dot;        /* update earliest char loc touched */
  301.     movenchars(&bb, &aa, z-(dot+nchars));    /* move text unless delete ends at z */
  302.     free_blist(aa.p->f);            /* return any cells after end */
  303.     aa.p->f = NULL;                    /* end the buffer */
  304.     z -= nchars;                    /* adjust z */
  305.     }
  306.  
  307. /* routine to process "O" command */
  308.  
  309. struct qh obuff;        /* tag string buffer */
  310.  
  311. do_o()
  312.     {
  313.     int i, j;            /* i used as start of tag, j as end */
  314.     int p, level;        /* p is pointer to tag string, level is iteration lvl */
  315.     int epfound;        /* flag for "second ! found"        */
  316.  
  317.     if (!build_string(&obuff)) return;        /* no tag spec'd: continue */
  318.     if (obuff.z > CELLSIZE) ERROR(E_STL);    /* string too long */
  319.     esp->op = OP_START;                        /* consume any argument */
  320.     if (esp->flag1)                            /* is there one? */
  321.         {
  322.         esp->flag1 = 0;                        /* consume it */
  323.         if (esp->val1 < 0) return;            /* computed goto out of range - */
  324.         for (i = 0; (i < obuff.z) && (esp->val1 > 0); i++)        /* scan to find right tag */
  325.             if (obuff.f->ch[i] == ',') esp->val1--;                /* count commas */
  326.         if (esp->val1 > 0) return;            /* computed goto out of range + */
  327.  
  328. /* now i is either at 0 or after the nth comma */
  329.  
  330.         for (j = i; j < obuff.z; j++)    /* find end of tag */
  331.             if (obuff.f->ch[j] == ',') break;        /* stop at next comma */
  332.         if (j == i) return;                /* two adjacent commas: zero length tag */
  333.         }
  334.  
  335.     else
  336.         {
  337.         i = 0;                /* not a computed goto: use whole tag buffer */
  338.         j = obuff.z;
  339.         }
  340.  
  341. /* start from beginning of iteration or macro, and look for tag */
  342.  
  343.     if (cptr.flag & F_ITER)            /* if in iteration */
  344.         {
  345.         cptr.p = cptr.il->p;        /* restore */
  346.         cptr.c = cptr.il->c;
  347.         cptr.dot = cptr.il->dot;
  348.         }
  349.     else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b);    /* find macro start */
  350.  
  351. /* search for tag */
  352.  
  353.     for (level = 0; ;)            /* look through rest of command string */
  354.         {
  355.         switch (skipto(1))        /* look for interesting things, including ! */
  356.             {
  357.             case '<':            /* start of iteration */
  358.                 ++level;
  359.                 break;
  360.  
  361.             case '>':            /* end of iteration */
  362.                 if ((level == 0) && (cptr.flag & F_ITER)) pop_iteration(1);
  363.                 else --level;
  364.                 break;
  365.  
  366.             case '!':                /* start of tag */
  367.                 for (epfound = 0; ; epfound = 0)        /* keep looking for tag */
  368.                     {
  369.                     for (p = i; p < j; p++)
  370.                         {
  371.                         if (getcmdc(0) == '!') epfound = 1;        /* mark "trailing ! found */
  372.                         if (mapch_l[cmdc] != mapch_l[obuff.f->ch[p]]) break;    /* compare */
  373.                         }
  374.                     if (p >= j)            /* if all comparison chars matched */
  375.                         {
  376.                         if (getcmdc(0) == '!') return;    /* and tag ends with !, found it */
  377.                         }
  378.                     else if (!epfound) while (getcmdc(0) != '!');        /* else look for next ! and continue */
  379.                     }
  380.                 break;
  381.             }            /* end of switch */
  382.         }            /* end of scan loop */
  383.     }            /* end of subroutine */
  384.  
  385. /* routine to skip to next ", ', |, <, or >            */
  386. /* skips over these chars embedded in text strings    */
  387. /* stops in ! if argument is nonzero                */
  388. /* returns character found, and leaves it in skipc    */
  389.  
  390. char skipto(arg)
  391.     int arg;
  392.     {
  393.     int atsw;                /* "at" prefix */
  394.     char ta, term;            /* temp attributes, terminator */
  395.  
  396.     for (atsw = 0; ;)        /* forever        */
  397.         {
  398.         while (!(ta = spec_chars[skipc = getcmdc(0)] & (A_X | A_S | A_T | A_Q)));    /* read until something interesting found */
  399.  
  400.     again:
  401.         if (ta & A_Q) getcmdc(0);        /* if command takes a Q spec, skip the spec */
  402.         if (ta & A_X)                    /* sought char found: quit */
  403.             {
  404.             if (skipc == '"') getcmdc(0);    /* quote must skip next char */
  405.             return(skipc);
  406.             }
  407.         if (ta & A_S)                                /* other special char */
  408.             {
  409.             switch (skipc)
  410.                 {
  411.                 case '^':                            /* treat next char as CTL */
  412.                     if (ta = spec_chars[skipc = getcmdc(0) & 0x1f]) goto again;
  413.                     break;
  414.  
  415.                 case '@':                            /* use alternative text terminator */
  416.                     atsw = 1;
  417.                     break;
  418.  
  419.                 case CTL (^):                        /* ^^ is value of next char: skip that char */
  420.                     getcmdc(0);
  421.                     break;
  422.  
  423.                 case CTL (A):                        /* type text */
  424.                     term = (atsw) ? getcmdc(0) : CTL (A);
  425.                     atsw = 0;
  426.                     while (getcmdc(0) != term);        /* skip text */
  427.                     break;
  428.  
  429.                 case '!':                            /* tag */
  430.                     if (arg) return(skipc);
  431.                     while (getcmdc(0) != '!');        /* skip until next ! */
  432.                     break;
  433.  
  434.                 case 'e':                            /* first char of two-letter E or F command */
  435.                 case 'f':
  436.                     if (spec_chars[getcmdc(0)] & ((skipc == 'e') ? A_E : A_F))         /* if one with a text arg */
  437.                         {
  438.                         term = (atsw) ? getcmdc(0) : ESC;
  439.                         atsw = 0;
  440.                         while (getcmdc(0) != term);        /* read past terminator */
  441.                         }
  442.                     break;
  443.                 }                /* end "switch" */
  444.             }                /* end "if (ta & A_S)" */
  445.  
  446.         else if (ta & A_T)                        /* command with a text argument */
  447.             {
  448.             term = (atsw) ? getcmdc(0) : ESC;
  449.             atsw = 0;
  450.             while (getcmdc(0) != term);            /* skip text */
  451.             }
  452.         }                /* end "forever" */
  453.     }                /* end "skipto()" */
  454.  
  455. /* find number of characters to next matching (, [, or {  (like '%' in vi) */
  456.  
  457. do_ctlp()
  458.     {
  459.     int i, l;
  460.     char c, c1;
  461.  
  462.     set_pointer(dot, &aa);            /* point to text buffer */
  463.     switch(c1 = aa.p->ch[aa.c])
  464.         {
  465.         case '(':
  466.             c = ')';            /* match char is ) */
  467.             i = 1;                /* direction is positive */
  468.             break;
  469.  
  470.         case ')':
  471.             c = '(';            /* match char is ( */
  472.             i = -1;                /* direction is negative */
  473.             break;
  474.  
  475.         case '[':
  476.             c = ']';
  477.             i = 1;
  478.             break;
  479.  
  480.         case ']':
  481.             c = '[';
  482.             i = -1;
  483.             break;
  484.  
  485.         case '{':
  486.             c = '}';
  487.             i = 1;
  488.             break;
  489.  
  490.         case '}':
  491.             c = '{';
  492.             i = -1;
  493.             break;
  494.  
  495.         case '<':
  496.             c = '>';
  497.             i = 1;
  498.             break;
  499.  
  500.         case '>':
  501.             c = '<';
  502.             i = -1;
  503.             break;
  504.  
  505.         case '"':
  506.             c = '\'';
  507.             i = 1;
  508.             break;
  509.  
  510.         case '\'':
  511.             c = '"';
  512.             i = -1;
  513.             break;
  514.  
  515.         default:
  516.             esp->val1 = i = 0;        /* not on a matchable char, return 0 */
  517.         }
  518.  
  519.     l = 1;            /* start with one unmatched char */
  520.     if (i > 0)        /* if searching forward */
  521.         {
  522.         for (i = dot, fwdc(&aa); (i < z) && (l); fwdc(&aa) )
  523.             {
  524.             ++i;
  525.             if (aa.p->ch[aa.c] == c) --l;
  526.             else if (aa.p->ch[aa.c] == c1) ++l;
  527.             }
  528.         esp->val1 = (i < z) ? i - dot : 0;
  529.         }
  530.     else if (i < 0)
  531.         {
  532.         for (i = dot, backc(&aa); (i >= 0) && (l); backc(&aa) )
  533.             {
  534.             --i;
  535.             if (aa.p->ch[aa.c] == c) --l;
  536.             else if (aa.p->ch[aa.c] == c1) ++l;
  537.             }
  538.         esp->val1 = (i >= 0) ? i - dot : 0;
  539.         }
  540.     esp->flag1 = 1;
  541.     }
  542.  
  543.