home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / ex / ex_vops3.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  9KB  |  522 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #include "ex.h"
  3. #include "ex_tty.h"
  4. #include "ex_vis.h"
  5.  
  6. /*
  7.  * Routines to handle structure.
  8.  * Operations supported are:
  9.  *    ( ) { } [ ]
  10.  *
  11.  * These cover:        LISP        TEXT
  12.  *    ( )        s-exprs        sentences
  13.  *    { }        list at same    paragraphs
  14.  *    [ ]        defuns        sections
  15.  *
  16.  * { and } for C used to attempt to do something with matching {}'s, but
  17.  * I couldn't find definitions which worked intuitively very well, so I
  18.  * scrapped this.
  19.  *
  20.  * The code here is very hard to understand.
  21.  */
  22. line    *llimit;
  23. int    (*lf)();
  24.  
  25. #ifdef LISP
  26. int    lindent();
  27. #endif
  28.  
  29. bool    wasend;
  30.  
  31. /*
  32.  * Find over structure, repeated count times.
  33.  * Don't go past line limit.  F is the operation to
  34.  * be performed eventually.  If pastatom then the user said {}
  35.  * rather than (), implying past atoms in a list (or a paragraph
  36.  * rather than a sentence.
  37.  */
  38. lfind(pastatom, cnt, f, limit)
  39.     bool pastatom;
  40.     int cnt, (*f)();
  41.     line *limit;
  42. {
  43.     register int c;
  44.     register int rc = 0;
  45.     char save[LBSIZE];
  46.  
  47.     /*
  48.      * Initialize, saving the current line buffer state
  49.      * and computing the limit; a 0 argument means
  50.      * directional end of file.
  51.      */
  52.     wasend = 0;
  53.     lf = f;
  54.     strcpy(save, linebuf);
  55.     if (limit == 0)
  56.         limit = dir < 0 ? one : dol;
  57.     llimit = limit;
  58.     wdot = dot;
  59.     wcursor = cursor;
  60.  
  61. #ifdef LISP
  62.     if (!value(LISP)) {
  63. #endif
  64.         char *icurs;
  65.         line *idot;
  66.  
  67.         if (linebuf[0] == 0) {
  68.             do
  69.                 if (!lnext())
  70.                     goto ret;
  71.             while (linebuf[0] == 0);
  72.             if (dir > 0) {
  73.                 wdot--;
  74.                 linebuf[0] = 0;
  75.                 wcursor = linebuf;
  76.                 /*
  77.                  * If looking for sentence, next line
  78.                  * starts one.
  79.                  */
  80.                 if (!pastatom) {
  81.                     icurs = wcursor;
  82.                     idot = wdot;
  83.                     goto begin;
  84.                 }
  85.             }
  86.         }
  87.         icurs = wcursor;
  88.         idot = wdot;
  89.  
  90.         /*
  91.          * Advance so as to not find same thing again.
  92.          */
  93.         if (dir > 0) {
  94.             if (!lnext()) {
  95.                 rc = -1;
  96.                 goto ret;
  97.             }
  98.         } else
  99.             ignore(lskipa1(""));
  100.  
  101.         /*
  102.          * Count times find end of sentence/paragraph.
  103.          */
  104. begin:
  105.         for (;;) {
  106.             while (!endsent(pastatom))
  107.                 if (!lnext())
  108.                     goto ret;
  109.             if (!pastatom || wcursor == linebuf && endPS())
  110.                 if (--cnt <= 0)
  111.                     break;
  112.             if (linebuf[0] == 0) {
  113.                 do
  114.                     if (!lnext())
  115.                         goto ret;
  116.                 while (linebuf[0] == 0);
  117.             } else
  118.                 if (!lnext())
  119.                     goto ret;
  120.         }
  121.  
  122.         /*
  123.          * If going backwards, and didn't hit the end of the buffer,
  124.          * then reverse direction.
  125.          */
  126.         if (dir < 0 && (wdot != llimit || wcursor != linebuf)) {
  127.             dir = 1;
  128.             llimit = dot;
  129.             /*
  130.              * Empty line needs special treatement.
  131.              * If moved to it from other than begining of next line,
  132.              * then a sentence starts on next line.
  133.              */
  134.             if (linebuf[0] == 0 && !pastatom && 
  135.                (wdot != dot - 1 || cursor != linebuf)) {
  136.                 lnext();
  137.                 goto ret;
  138.             }
  139.         }
  140.  
  141.         /*
  142.          * If we are not at a section/paragraph division,
  143.          * advance to next.
  144.          */
  145.         if (wcursor == icurs && wdot == idot || wcursor != linebuf || !endPS())
  146.             ignore(lskipa1(""));
  147. #ifdef LISP
  148.     } else {
  149.         c = *wcursor;
  150.         /*
  151.          * Startup by skipping if at a ( going left or a ) going
  152.          * right to keep from getting stuck immediately.
  153.          */
  154.         if (dir < 0 && c == '(' || dir > 0 && c == ')') {
  155.             if (!lnext()) {
  156.                 rc = -1;
  157.                 goto ret;
  158.             }
  159.         }
  160.         /*
  161.          * Now chew up repitition count.  Each time around
  162.          * if at the beginning of an s-exp (going forwards)
  163.          * or the end of an s-exp (going backwards)
  164.          * skip the s-exp.  If not at beg/end resp, then stop
  165.          * if we hit a higher level paren, else skip an atom,
  166.          * counting it unless pastatom.
  167.          */
  168.         while (cnt > 0) {
  169.             c = *wcursor;
  170.             if (dir < 0 && c == ')' || dir > 0 && c == '(') {
  171.                 if (!lskipbal("()"))
  172.                     goto ret;
  173.                 /*
  174.                   * Unless this is the last time going
  175.                  * backwards, skip past the matching paren
  176.                  * so we don't think it is a higher level paren.
  177.                  */
  178.                 if (dir < 0 && cnt == 1)
  179.                     goto ret;
  180.                 if (!lnext() || !ltosolid())
  181.                     goto ret;
  182.                 --cnt;
  183.             } else if (dir < 0 && c == '(' || dir > 0 && c == ')')
  184.                 /* Found a higher level paren */
  185.                 goto ret;
  186.             else {
  187.                 if (!lskipatom())
  188.                     goto ret;
  189.                 if (!pastatom)
  190.                     --cnt;
  191.             }
  192.         }
  193.     }
  194. #endif
  195. ret:
  196.     strcLIN(save);
  197.     return (rc);
  198. }
  199.  
  200. /*
  201.  * Is this the end of a sentence?
  202.  */
  203. endsent(pastatom)
  204.     bool pastatom;
  205. {
  206.     register char *cp = wcursor;
  207.     register int c, d;
  208.  
  209.     /*
  210.      * If this is the beginning of a line, then
  211.      * check for the end of a paragraph or section.
  212.      */
  213.     if (cp == linebuf)
  214.         return (endPS());
  215.  
  216.     /*
  217.      * Sentences end with . ! ? not at the beginning
  218.      * of the line, and must be either at the end of the line,
  219.      * or followed by 2 spaces.  Any number of intervening ) ] ' "
  220.      * characters are allowed.
  221.      */
  222.     if (!any(c = *cp, ".!?"))
  223.         goto tryps;
  224.     do
  225.         if ((d = *++cp) == 0)
  226.             return (1);
  227.     while (any(d, ")]'"));
  228.     if (*cp == 0 || *cp++ == ' ' && *cp == ' ')
  229.         return (1);
  230. tryps:
  231.     if (cp[1] == 0)
  232.         return (endPS());
  233.     return (0);
  234. }
  235.  
  236. /*
  237.  * End of paragraphs/sections are respective
  238.  * macros as well as blank lines and form feeds.
  239.  */
  240. endPS()
  241. {
  242.  
  243.     return (linebuf[0] == 0 ||
  244.         isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
  245.         
  246. }
  247.  
  248. #ifdef LISP
  249. lindent(addr)
  250.     line *addr;
  251. {
  252.     register int i;
  253.     char *swcurs = wcursor;
  254.     line *swdot = wdot;
  255.  
  256. again:
  257.     if (addr > one) {
  258.         register char *cp;
  259.         register int cnt = 0;
  260.  
  261.         addr--;
  262.         getline(*addr);
  263.         for (cp = linebuf; *cp; cp++)
  264.             if (*cp == '(')
  265.                 cnt++;
  266.             else if (*cp == ')')
  267.                 cnt--;
  268.         cp = vpastwh(linebuf);
  269.         if (*cp == 0)
  270.             goto again;
  271.         if (cnt == 0)
  272.             return (whitecnt(linebuf));
  273.         addr++;
  274.     }
  275.     wcursor = linebuf;
  276.     linebuf[0] = 0;
  277.     wdot = addr;
  278.     dir = -1;
  279.     llimit = one;
  280.     lf = lindent;
  281.     if (!lskipbal("()"))
  282.         i = 0;
  283.     else if (wcursor == linebuf)
  284.         i = 2;
  285.     else {
  286.         register char *wp = wcursor;
  287.  
  288.         dir = 1;
  289.         llimit = wdot;
  290.         if (!lnext() || !ltosolid() || !lskipatom()) {
  291.             wcursor = wp;
  292.             i = 1;
  293.         } else
  294.             i = 0;
  295.         i += column(wcursor) - 1;
  296.         if (!inopen)
  297.             i--;
  298.     }
  299.     wdot = swdot;
  300.     wcursor = swcurs;
  301.     return (i);
  302. }
  303. #endif
  304.  
  305. lmatchp(addr)
  306.     line *addr;
  307. {
  308.     register int i;
  309.     register char *parens, *cp;
  310.  
  311.     for (cp = cursor; !any(*cp, "({)}");)
  312.         if (*cp++ == 0)
  313.             return (0);
  314.     lf = 0;
  315.     parens = any(*cp, "()") ? "()" : "{}";
  316.     if (*cp == parens[1]) {
  317.         dir = -1;
  318.         llimit = one;
  319.     } else {
  320.         dir = 1;
  321.         llimit = dol;
  322.     }
  323.     if (addr)
  324.         llimit = addr;
  325.     if (splitw)
  326.         llimit = dot;
  327.     wcursor = cp;
  328.     wdot = dot;
  329.     i = lskipbal(parens);
  330.     return (i);
  331. }
  332.  
  333. lsmatch(cp)
  334.     char *cp;
  335. {
  336.     char save[LBSIZE];
  337.     register char *sp = save;
  338.     register char *scurs = cursor;
  339.  
  340.     wcursor = cp;
  341.     strcpy(sp, linebuf);
  342.     *wcursor = 0;
  343.     strcpy(cursor, genbuf);
  344.     cursor = strend(linebuf) - 1;
  345.     if (lmatchp(dot - vcline)) {
  346.         register int i = insmode;
  347.         register int c = outcol;
  348.         register int l = outline;
  349.  
  350.         if (!MI)
  351.             endim();
  352.         vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1);
  353.         flush();
  354.         sleep(1);
  355.         vgoto(l, c);
  356.         if (i)
  357.             goim();
  358.     }
  359.     strcLIN(sp);
  360.     wdot = 0;
  361.     wcursor = 0;
  362.     cursor = scurs;
  363. }
  364.  
  365. ltosolid()
  366. {
  367.  
  368.     return (ltosol1("()"));
  369. }
  370.  
  371. ltosol1(parens)
  372.     register char *parens;
  373. {
  374.     register char *cp;
  375.  
  376.     if (*parens && !*wcursor && !lnext())
  377.         return (0);
  378.     while (isspace(*wcursor) || (*wcursor == 0 && *parens))
  379.         if (!lnext())
  380.             return (0);
  381.     if (any(*wcursor, parens) || dir > 0)
  382.         return (1);
  383.     for (cp = wcursor; cp > linebuf; cp--)
  384.         if (isspace(cp[-1]) || any(cp[-1], parens))
  385.             break;
  386.     wcursor = cp;
  387.     return (1);
  388. }
  389.  
  390. lskipbal(parens)
  391.     register char *parens;
  392. {
  393.     register int level = dir;
  394.     register int c;
  395.  
  396.     do {
  397.         if (!lnext())
  398.             return (0);
  399.         c = *wcursor;
  400.         if (c == parens[1])
  401.             level--;
  402.         else if (c == parens[0])
  403.             level++;
  404.     } while (level);
  405.     return (1);
  406. }
  407.  
  408. lskipatom()
  409. {
  410.  
  411.     return (lskipa1("()"));
  412. }
  413.  
  414. lskipa1(parens)
  415.     register char *parens;
  416. {
  417.     register int c;
  418.  
  419.     for (;;) {
  420.         if (dir < 0 && wcursor == linebuf) {
  421.             if (!lnext())
  422.                 return (0);
  423.             break;
  424.         }
  425.         c = *wcursor;
  426.         if (c && (isspace(c) || any(c, parens)))
  427.             break;
  428.         if (!lnext())
  429.             return (0);
  430.         if (dir > 0 && wcursor == linebuf)
  431.             break;
  432.     }
  433.     return (ltosol1(parens));
  434. }
  435.  
  436. lnext()
  437. {
  438.  
  439.     if (dir > 0) {
  440.         if (*wcursor)
  441.             wcursor++;
  442.         if (*wcursor)
  443.             return (1);
  444.         if (wdot >= llimit) {
  445.             if (wcursor > linebuf)
  446.                 wcursor--;
  447.             return (0);
  448.         }
  449.         wdot++;
  450.         getline(*wdot);
  451.         wcursor = linebuf;
  452.         return (1);
  453.     } else {
  454.         --wcursor;
  455.         if (wcursor >= linebuf)
  456.             return (1);
  457. #ifdef LISP
  458.         if (lf == lindent && linebuf[0] == '(')
  459.             llimit = wdot;
  460. #endif
  461.         if (wdot <= llimit) {
  462.             wcursor = linebuf;
  463.             return (0);
  464.         }
  465.         wdot--;
  466.         getline(*wdot);
  467.         wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1;
  468.         return (1);
  469.     }
  470. }
  471.  
  472. lbrack(c, f)
  473.     register int c;
  474.     int (*f)();
  475. {
  476.     register line *addr;
  477.  
  478.     addr = dot;
  479.     for (;;) {
  480.         addr += dir;
  481.         if (addr < one || addr > dol) {
  482.             addr -= dir;
  483.             break;
  484.         }
  485.         getline(*addr);
  486.         if (linebuf[0] == '{' ||
  487. #ifdef LISP
  488.             value(LISP) && linebuf[0] == '(' ||
  489. #endif
  490.             isa(svalue(SECTIONS))) {
  491.             if (c == ']' && f != vmove) {
  492.                 addr--;
  493.                 getline(*addr);
  494.             }
  495.             break;
  496.         }
  497.         if (c == ']' && f != vmove && linebuf[0] == '}')
  498.             break;
  499.     }
  500.     if (addr == dot)
  501.         return (0);
  502.     if (f != vmove)
  503.         wcursor = c == ']' ? strend(linebuf) : linebuf;
  504.     else
  505.         wcursor = 0;
  506.     wdot = addr;
  507.     vmoving = 0;
  508.     return (1);
  509. }
  510.  
  511. isa(cp)
  512.     register char *cp;
  513. {
  514.  
  515.     if (linebuf[0] != '.')
  516.         return (0);
  517.     for (; cp[0] && cp[1]; cp += 2)
  518.         if (linebuf[1] == cp[0] && linebuf[2] == cp[1])
  519.             return (1);
  520.     return (0);
  521. }
  522.