home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / vi / v_paragraph.c < prev    next >
C/C++ Source or Header  |  1996-04-27  |  8KB  |  345 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)v_paragraph.c    10.7 (Berkeley) 3/6/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/time.h>
  19.  
  20. #include <bitstring.h>
  21. #include <errno.h>
  22. #include <limits.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #include "../common/common.h"
  28. #include "vi.h"
  29.  
  30. #define    INTEXT_CHECK {                            \
  31.     if (len == 0 || v_isempty(p, len)) {                \
  32.         if (!--cnt)                        \
  33.             goto found;                    \
  34.         pstate = P_INBLANK;                    \
  35.     }                                \
  36.     /*                                \
  37.      * !!!                                \
  38.      * Historic documentation (USD:15-11, 4.2) said that formfeed    \
  39.      * characters (^L) in the first column delimited paragraphs.    \
  40.      * The historic vi code mentions formfeed characters, but never    \
  41.      * implements them.  It seems reasonable, do it.        \
  42.      */                                \
  43.     if (p[0] == '\014') {                        \
  44.         if (!--cnt)                        \
  45.             goto found;                    \
  46.         continue;                        \
  47.     }                                \
  48.     if (p[0] != '.' || len < 2)                    \
  49.         continue;                        \
  50.     for (lp = VIP(sp)->ps; *lp != '\0'; lp += 2)            \
  51.         if (lp[0] == p[1] &&                    \
  52.             (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&    \
  53.             !--cnt)                        \
  54.             goto found;                    \
  55. }
  56.  
  57. /*
  58.  * v_paragraphf -- [count]}
  59.  *    Move forward count paragraphs.
  60.  *
  61.  * Paragraphs are empty lines after text, formfeed characters, or values
  62.  * from the paragraph or section options.
  63.  *
  64.  * PUBLIC: int v_paragraphf __P((SCR *, VICMD *));
  65.  */
  66. int
  67. v_paragraphf(sp, vp)
  68.     SCR *sp;
  69.     VICMD *vp;
  70. {
  71.     enum { P_INTEXT, P_INBLANK } pstate;
  72.     size_t lastlen, len;
  73.     recno_t cnt, lastlno, lno;
  74.     int isempty;
  75.     char *p, *lp;
  76.  
  77.     /*
  78.      * !!!
  79.      * If the starting cursor position is at or before any non-blank
  80.      * characters in the line, i.e. the movement is cutting all of the
  81.      * line's text, the buffer is in line mode.  It's a lot easier to
  82.      * check here, because we know that the end is going to be the start
  83.      * or end of a line.
  84.      *
  85.      * This was historical practice in vi, with a single exception.  If
  86.      * the paragraph movement was from the start of the last line to EOF,
  87.      * then all the characters were deleted from the last line, but the
  88.      * line itself remained.  If somebody complains, don't pause, don't
  89.      * hesitate, just hit them.
  90.      */
  91.     if (ISMOTION(vp))
  92.         if (vp->m_start.cno == 0)
  93.             F_SET(vp, VM_LMODE);
  94.         else {
  95.             vp->m_stop = vp->m_start;
  96.             vp->m_stop.cno = 0;
  97.             if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
  98.                 return (1);
  99.             if (vp->m_start.cno <= vp->m_stop.cno)
  100.                 F_SET(vp, VM_LMODE);
  101.         }
  102.  
  103.     /* Figure out what state we're currently in. */
  104.     lno = vp->m_start.lno;
  105.     if (db_get(sp, lno, 0, &p, &len))
  106.         goto eof;
  107.  
  108.     /*
  109.      * If we start in text, we want to switch states
  110.      * (2 * N - 1) times, in non-text, (2 * N) times.
  111.      */
  112.     cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
  113.     cnt *= 2;
  114.     if (len == 0 || v_isempty(p, len))
  115.         pstate = P_INBLANK;
  116.     else {
  117.         --cnt;
  118.         pstate = P_INTEXT;
  119.     }
  120.  
  121.     for (;;) {
  122.         lastlno = lno;
  123.         lastlen = len;
  124.         if (db_get(sp, ++lno, 0, &p, &len))
  125.             goto eof;
  126.         switch (pstate) {
  127.         case P_INTEXT:
  128.             INTEXT_CHECK;
  129.             break;
  130.         case P_INBLANK:
  131.             if (len == 0 || v_isempty(p, len))
  132.                 break;
  133.             if (--cnt) {
  134.                 pstate = P_INTEXT;
  135.                 break;
  136.             }
  137.             /*
  138.              * !!!
  139.              * Non-motion commands move to the end of the range,
  140.              * delete and yank stay at the start.  Ignore others.
  141.              * Adjust the end of the range for motion commands;
  142.              * historically, a motion component was to the end of
  143.              * the previous line, whereas the movement command was
  144.              * to the start of the new "paragraph".
  145.              */
  146. found:            if (ISMOTION(vp)) {
  147.                 vp->m_stop.lno = lastlno;
  148.                 vp->m_stop.cno = lastlen ? lastlen - 1 : 0;
  149.                 vp->m_final = vp->m_start;
  150.             } else {
  151.                 vp->m_stop.lno = lno;
  152.                 vp->m_stop.cno = 0;
  153.                 vp->m_final = vp->m_stop;
  154.             }
  155.             return (0);
  156.         default:
  157.             abort();
  158.         }
  159.     }
  160.  
  161.     /*
  162.      * !!!
  163.      * Adjust end of the range for motion commands; EOF is a movement
  164.      * sink.  The } command historically moved to the end of the last
  165.      * line, not the beginning, from any position before the end of the
  166.      * last line.  It also historically worked on empty files, so we
  167.      * have to make it okay.
  168.      */
  169. eof:    if (vp->m_start.lno == lno || vp->m_start.lno == lno - 1) {
  170.         if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
  171.             if (!isempty)
  172.                 return (1);
  173.             vp->m_start.cno = 0;
  174.             return (0);
  175.         }
  176.         if (vp->m_start.cno == (len ? len - 1 : 0)) {
  177.             v_eof(sp, NULL);
  178.             return (1);
  179.         }
  180.     }
  181.     /*
  182.      * !!!
  183.      * Non-motion commands move to the end of the range, delete
  184.      * and yank stay at the start.  Ignore others.
  185.      *
  186.      * If deleting the line (which happens if deleting to EOF), then
  187.      * cursor movement is to the first nonblank.
  188.      */
  189.     if (ISMOTION(vp) && ISCMD(vp->rkp, 'd')) {
  190.         F_CLR(vp, VM_RCM_MASK);
  191.         F_SET(vp, VM_RCM_SETFNB);
  192.     }
  193.     vp->m_stop.lno = lno - 1;
  194.     vp->m_stop.cno = len ? len - 1 : 0;
  195.     vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
  196.     return (0);
  197. }
  198.  
  199. /*
  200.  * v_paragraphb -- [count]{
  201.  *    Move backward count paragraphs.
  202.  *
  203.  * PUBLIC: int v_paragraphb __P((SCR *, VICMD *));
  204.  */
  205. int
  206. v_paragraphb(sp, vp)
  207.     SCR *sp;
  208.     VICMD *vp;
  209. {
  210.     enum { P_INTEXT, P_INBLANK } pstate;
  211.     size_t len;
  212.     recno_t cnt, lno;
  213.     char *p, *lp;
  214.  
  215.     /*
  216.      * !!!
  217.      * Check for SOF.  The historic vi didn't complain if users hit SOF
  218.      * repeatedly, unless it was part of a motion command.  There is no
  219.      * question but that Emerson's editor of choice was vi.
  220.      *
  221.      * The { command historically moved to the beginning of the first
  222.      * line if invoked on the first line.
  223.      *
  224.      * !!!
  225.      * If the starting cursor position is in the first column (backward
  226.      * paragraph movements did NOT historically pay attention to non-blank
  227.      * characters) i.e. the movement is cutting the entire line, the buffer
  228.      * is in line mode.  Cuts from the beginning of the line also did not
  229.      * cut the current line, but started at the previous EOL.
  230.      *
  231.      * Correct for a left motion component while we're thinking about it.
  232.      */
  233.     lno = vp->m_start.lno;
  234.  
  235.     if (ISMOTION(vp))
  236.         if (vp->m_start.cno == 0) {
  237.             if (vp->m_start.lno == 1) {
  238.                 v_sof(sp, &vp->m_start);
  239.                 return (1);
  240.             } else
  241.                 --vp->m_start.lno;
  242.             F_SET(vp, VM_LMODE);
  243.         } else
  244.             --vp->m_start.cno;
  245.  
  246.     if (vp->m_start.lno <= 1)
  247.         goto sof;
  248.  
  249.     /* Figure out what state we're currently in. */
  250.     if (db_get(sp, lno, 0, &p, &len))
  251.         goto sof;
  252.  
  253.     /*
  254.      * If we start in text, we want to switch states
  255.      * (2 * N - 1) times, in non-text, (2 * N) times.
  256.      */
  257.     cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
  258.     cnt *= 2;
  259.     if (len == 0 || v_isempty(p, len))
  260.         pstate = P_INBLANK;
  261.     else {
  262.         --cnt;
  263.         pstate = P_INTEXT;
  264.  
  265.         /*
  266.          * !!!
  267.          * If the starting cursor is past the first column,
  268.          * the current line is checked for a paragraph.
  269.          */
  270.         if (vp->m_start.cno > 0)
  271.             ++lno;
  272.     }
  273.  
  274.     for (;;) {
  275.         if (db_get(sp, --lno, 0, &p, &len))
  276.             goto sof;
  277.         switch (pstate) {
  278.         case P_INTEXT:
  279.             INTEXT_CHECK;
  280.             break;
  281.         case P_INBLANK:
  282.             if (len != 0 && !v_isempty(p, len)) {
  283.                 if (!--cnt)
  284.                     goto found;
  285.                 pstate = P_INTEXT;
  286.             }
  287.             break;
  288.         default:
  289.             abort();
  290.         }
  291.     }
  292.  
  293.     /* SOF is a movement sink. */
  294. sof:    lno = 1;
  295.  
  296. found:    vp->m_stop.lno = lno;
  297.     vp->m_stop.cno = 0;
  298.  
  299.     /*
  300.      * All commands move to the end of the range.  (We already
  301.      * adjusted the start of the range for motion commands).
  302.      */
  303.     vp->m_final = vp->m_stop;
  304.     return (0);
  305. }
  306.  
  307. /*
  308.  * v_buildps --
  309.  *    Build the paragraph command search pattern.
  310.  *
  311.  * PUBLIC: int v_buildps __P((SCR *, char *, char *));
  312.  */
  313. int
  314. v_buildps(sp, p_p, s_p)
  315.     SCR *sp;
  316.     char *p_p, *s_p;
  317. {
  318.     VI_PRIVATE *vip;
  319.     size_t p_len, s_len;
  320.     char *p;
  321.  
  322.     /*
  323.      * The vi paragraph command searches for either a paragraph or
  324.      * section option macro.
  325.      */
  326.     p_len = p_p == NULL ? 0 : strlen(p_p);
  327.     s_len = s_p == NULL ? 0 : strlen(s_p);
  328.  
  329.     if (p_len == 0 && s_len == 0)
  330.         return (0);
  331.  
  332.     MALLOC_RET(sp, p, char *, p_len + s_len + 1);
  333.  
  334.     vip = VIP(sp);
  335.     if (vip->ps != NULL)
  336.         free(vip->ps);
  337.  
  338.     if (p_p != NULL)
  339.         memmove(p, p_p, p_len + 1);
  340.     if (s_p != NULL)
  341.         memmove(p + p_len, s_p, s_len + 1);
  342.     vip->ps = p;
  343.     return (0);
  344. }
  345.