home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / text_ed / elv16b2 / st / move1.c < prev    next >
C/C++ Source or Header  |  1992-05-12  |  10KB  |  593 lines

  1. /* move1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains most movement functions */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #include "ctype.h"
  16.  
  17. MARK    m_updnto(m, cnt, cmd)
  18.     MARK    m;    /* movement is relative to this mark */
  19.     long    cnt;    /* a numeric argument */
  20.     int    cmd;    /* the command character */
  21. {
  22.     DEFAULT(cmd == 'G' ? nlines : 1L);
  23.  
  24.     /* move up or down 'cnt' lines */
  25.     switch (cmd)
  26.     {
  27.       case ctrl('P'):
  28.       case '-':
  29.       case 'k':
  30.         m -= MARK_AT_LINE(cnt);
  31.         break;
  32.  
  33.       case 'G':
  34.         if (cnt < 1L || cnt > nlines)
  35.         {
  36.             msg("Only %ld lines", nlines);
  37.             return MARK_UNSET;
  38.         }
  39.         m = MARK_AT_LINE(cnt);
  40.         break;
  41.  
  42.       case '_':
  43.         cnt--;
  44.         /* fall through... */
  45.  
  46.       default:
  47.         m += MARK_AT_LINE(cnt);
  48.     }
  49.  
  50.     /* if that left us screwed up, then fail */
  51.     if (m < MARK_FIRST || markline(m) > nlines)
  52.     {
  53.         return MARK_UNSET;
  54.     }
  55.  
  56.     return m;
  57. }
  58.  
  59. /*ARGSUSED*/
  60. MARK    m_right(m, cnt, key, prevkey)
  61.     MARK    m;    /* movement is relative to this mark */
  62.     long    cnt;    /* a numeric argument */
  63.     int    key;    /* movement keystroke */
  64.     int    prevkey;/* operator keystroke, or 0 if none */
  65. {
  66.     int        idx;    /* index of the new cursor position */
  67.  
  68.     DEFAULT(1);
  69.  
  70.     /* If used with an operator, then move 1 less character, since the 'l'
  71.      * command includes the character that it moves onto.
  72.      */
  73.     if (prevkey != '\0')
  74.     {
  75.         cnt--;
  76.     }
  77.  
  78.     /* move to right, if that's OK */
  79.     pfetch(markline(m));
  80.     idx = markidx(m) + cnt;
  81.     if (idx < plen)
  82.     {
  83.         m += cnt;
  84.     }
  85.     else
  86.     {
  87.         return MARK_UNSET;
  88.     }
  89.  
  90.     return m;
  91. }
  92.  
  93. /*ARGSUSED*/
  94. MARK    m_left(m, cnt)
  95.     MARK    m;    /* movement is relative to this mark */
  96.     long    cnt;    /* a numeric argument */
  97. {
  98.     DEFAULT(1);
  99.  
  100.     /* move to the left, if that's OK */
  101.     if (markidx(m) >= cnt)
  102.     {
  103.         m -= cnt;
  104.     }
  105.     else
  106.     {
  107.         return MARK_UNSET;
  108.     }
  109.  
  110.     return m;
  111. }
  112.  
  113. /*ARGSUSED*/
  114. MARK    m_tocol(m, cnt, cmd)
  115.     MARK    m;    /* movement is relative to this mark */
  116.     long    cnt;    /* a numeric argument */
  117.     int    cmd;    /* either ctrl('X') or '|' */
  118. {
  119.     char    *text;    /* text of the line */
  120.     int    col;    /* column number */
  121.     int    idx;    /* index into the line */
  122.  
  123.  
  124.     /* if doing ^X, then adjust for sideways scrolling */
  125.     if (cmd == ctrl('X'))
  126.     {
  127.         DEFAULT(*o_columns & 0xff);
  128.         cnt += leftcol;
  129.     }
  130.     else
  131.     {
  132.         DEFAULT(1);
  133.     }
  134.  
  135.     /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  136.     cnt--;
  137.  
  138.     /* if 0, that's easy */
  139.     if (cnt == 0)
  140.     {
  141.         m &= ~(BLKSIZE - 1);
  142.         return m;
  143.     }
  144.  
  145.     /* find that column within the line */
  146.     pfetch(markline(m));
  147.     text = ptext;
  148.     for (col = idx = 0; col < cnt && *text; text++, idx++)
  149.     {
  150.         if (*text == '\t' && !*o_list)
  151.         {
  152.             col += *o_tabstop;
  153.             col -= col % *o_tabstop;
  154.         }
  155.         else if (UCHAR(*text) < ' ' || *text == '\177')
  156.         {
  157.             col += 2;
  158.         }
  159. #ifndef NO_CHARATTR
  160.         else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  161.         {
  162.             text += 2; /* plus one more as part of for loop */
  163.         }
  164. #endif
  165.         else
  166.         {
  167.             col++;
  168.         }
  169.     }
  170.     if (!*text)
  171.     {
  172.         /* the desired column was past the end of the line, so
  173.          * act like the user pressed "$" instead.
  174.          */
  175.         return m | (BLKSIZE - 1);
  176.     }
  177.     else
  178.     {
  179.         m = (m & ~(BLKSIZE - 1)) + idx;
  180.     }
  181.     return m;
  182. }
  183.  
  184. /*ARGSUSED*/
  185. MARK    m_front(m, cnt)
  186.     MARK    m;    /* movement is relative to this mark */
  187.     long    cnt;    /* a numeric argument (ignored) */
  188. {
  189.     char    *scan;
  190.  
  191.     /* move to the first non-whitespace character */
  192.     pfetch(markline(m));
  193.     scan = ptext;
  194.     m &= ~(BLKSIZE - 1);
  195.     while (*scan == ' ' || *scan == '\t')
  196.     {
  197.         scan++;
  198.         m++;
  199.     }
  200.  
  201.     return m;
  202. }
  203.  
  204. /*ARGSUSED*/
  205. MARK    m_rear(m, cnt)
  206.     MARK    m;    /* movement is relative to this mark */
  207.     long    cnt;    /* a numeric argument (ignored) */
  208. {
  209.     /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  210.      * that other code will convert this to a more reasonable MARK before
  211.      * anything tries to actually use it.  (See adjmove() in vi.c)
  212.      */
  213.     return m | (BLKSIZE - 1);
  214. }
  215.  
  216. #ifndef NO_SENTENCE
  217. static int isperiod(ptr)
  218.     char    *ptr;    /* pointer to possible sentence-ender */
  219. {
  220.     /* if not '.', '?', or '!', then it isn't a sentence ender */
  221.     if (*ptr != '.' && *ptr != '?' && *ptr != '!')
  222.     {
  223.         return FALSE;
  224.     }
  225.  
  226.     /* skip any intervening ')', ']', or '"' characters */
  227.     do
  228.     {
  229.         ptr++;
  230.     } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
  231.  
  232.     /* do we have two spaces or EOL? */
  233.     if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
  234.     {
  235.         return TRUE;
  236.     }
  237.     return FALSE;
  238. }
  239.  
  240. /*ARGSUSED*/
  241. MARK    m_sentence(m, cnt, cmd)
  242.     MARK    m;    /* movement is relative to this mark */
  243.     long    cnt;    /* a numeric argument */
  244.     int    cmd;    /* either '(' or ')' */
  245. {
  246.     REG char    *text;
  247.     REG long    l;
  248.  
  249.     DEFAULT(1);
  250.  
  251.     /* If '(' command, then move back one word, so that if we hit '(' at
  252.      * the start of a sentence we don't simply stop at the end of the
  253.      * previous sentence and bounce back to the start of this one again.
  254.      */
  255.     if (cmd == '(')
  256.     {
  257.         m = m_bword(m, 1L, 'b');
  258.         if (!m)
  259.         {
  260.             return m;
  261.         }
  262.     }
  263.  
  264.     /* get the current line */
  265.     l = markline(m);
  266.     pfetch(l);
  267.     text = ptext + markidx(m);
  268.  
  269.     /* for each requested sentence... */
  270.     while (cnt-- > 0)
  271.     {
  272.         /* search forward for one of [.?!] followed by spaces or EOL */
  273.         do
  274.         {
  275.             if (cmd == ')')
  276.             {
  277.                 /* move forward, wrap at end of line */
  278.                 if (!text[0])
  279.                 {
  280.                     l++;
  281.                     if (l > nlines)
  282.                     {
  283.                         return MARK_EOF;
  284.                     }
  285.                     pfetch(l);
  286.                     text = ptext;
  287.                 }
  288.                 else
  289.                 {
  290.                     text++;
  291.                 }
  292.             }
  293.             else
  294.             {
  295.                 /* move backward, wrap at beginning of line */
  296.                 if (text == ptext)
  297.                 {
  298.                     do
  299.                     {
  300.                         if (l <= 1)
  301.                         {
  302.                             return MARK_FIRST;
  303.                         }
  304.                         l--;
  305.                         pfetch(l);
  306.                     } while (!*ptext);
  307.                     text = ptext + plen - 1;
  308.                 }
  309.                 else
  310.                 {
  311.                     text--;
  312.                 }
  313.             }
  314.         } while (!isperiod(text));
  315.     }
  316.  
  317.     /* construct a mark for this location */
  318.     m = buildmark(text);
  319.  
  320.     /* move forward to the first word of the next sentence */
  321.     m = m_fword(m, 1L, 'w', '\0');
  322.     if (m == MARK_UNSET)
  323.     {
  324.         m = MARK_EOF;
  325.     }
  326.  
  327.     return m;
  328. }
  329. #endif
  330.  
  331. MARK    m_paragraph(m, cnt, cmd)
  332.     MARK    m;    /* movement is relative to this mark */
  333.     long    cnt;    /* a numeric argument */
  334.     int    cmd;    /* either '{' or '}' */
  335. {
  336.     char    *text;    /* text of the current line */
  337.     char    *pscn;    /* used to scan thru value of "paragraphs" option */
  338.     long    l, ol;    /* current line number, original line number */
  339.     int    dir;    /* -1 if we're moving up, or 1 if down */
  340.     char    col0;    /* character to expect in column 0 */
  341. #ifndef NO_SENTENCE
  342. # define SENTENCE(x)    (x)
  343.     char    *list;    /* either o_sections or o_paragraph */
  344. #else
  345. # define SENTENCE(x)
  346. #endif
  347.  
  348.     DEFAULT(1);
  349.  
  350.     /* set the direction, based on the command */
  351.     switch (cmd)
  352.     {
  353.       case '{':
  354.         dir = -1;
  355.         col0 = '\0';
  356.         SENTENCE(list = o_paragraphs); 
  357.         break;
  358.  
  359.       case '}':
  360.         dir = 1;
  361.         col0 = '\0';
  362.         SENTENCE(list = o_paragraphs); 
  363.         break;
  364.  
  365.       case '[':
  366.         if (getkey(0) != '[')
  367.         {
  368.             return MARK_UNSET;
  369.         }
  370.         dir = -1;
  371.         col0 = '{';
  372.         SENTENCE(list = o_sections); 
  373.         break;
  374.  
  375.       case ']':
  376.         if (getkey(0) != ']')
  377.         {
  378.             return MARK_UNSET;
  379.         }
  380.         dir = 1;
  381.         col0 = '{';
  382.         SENTENCE(list = o_sections); 
  383.         break;
  384.     }
  385.     ol = l = markline(m);
  386.  
  387.     /* for each paragraph that we want to travel through... */
  388.     while (l > 0 && l <= nlines && cnt-- > 0)
  389.     {
  390.         /* skip blank lines between paragraphs */
  391.         while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
  392.         {
  393.             l += dir;
  394.         }
  395.  
  396.         /* skip non-blank lines that aren't paragraph separators
  397.          */
  398.         do
  399.         {
  400. #ifndef NO_SENTENCE
  401.             if (*text == '.' && l != ol)
  402.             {
  403.                 for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
  404.                 {
  405.                     if (pscn[0] == text[1] && pscn[1] == text[2])
  406.                     {
  407.                         pscn = (char *)0;
  408.                         goto BreakBreak;
  409.                     }
  410.                 }
  411.             }
  412. #endif
  413.             l += dir;
  414.         } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
  415. BreakBreak:    ;
  416.     }
  417.  
  418.     if (l > nlines)
  419.     {
  420.         m = MARK_EOF;
  421.     }
  422.     else if (l <= 0)
  423.     {
  424.         m = MARK_FIRST;
  425.     }
  426.     else
  427.     {
  428.         m = MARK_AT_LINE(l);
  429.     }
  430. #ifdef DEBUG2
  431.     debout("m_paragraph() returning %ld.%d\n", markline(m), markidx(m));
  432. #endif
  433.     return m;
  434. }
  435.  
  436.  
  437. /*ARGSUSED*/
  438. MARK    m_match(m, cnt)
  439.     MARK    m;    /* movement is relative to this mark */
  440.     long    cnt;    /* a numeric argument (normally 0) */
  441. {
  442.     long    l;
  443.     REG char    *text;
  444.     REG char    match;
  445.     REG char    nest;
  446.     REG int        count;
  447.  
  448. #ifndef NO_EXTENSIONS
  449.     /* if we're given a number, then treat it as a percentage of the file */
  450.     if (cnt > 0)
  451.     {
  452.         /* make sure it is a reasonable number */
  453.         if (cnt > 100)
  454.         {
  455.             msg("can only be from 1%% to 100%%");
  456.             return MARK_UNSET;
  457.         }
  458.  
  459.         /* return the appropriate line number */
  460.         l = (nlines - 1L) * cnt / 100L + 1L;
  461.         return MARK_AT_LINE(l);
  462.     }
  463. #endif /* undef NO_EXTENSIONS */
  464.  
  465.     /* get the current line */
  466.     l = markline(m);
  467.     pfetch(l);
  468.     text = ptext + markidx(m);
  469.  
  470.     /* search forward within line for one of "[](){}" */
  471.     for (match = '\0'; !match && *text; text++)
  472.     {
  473.         /* tricky way to recognize 'em in ASCII */
  474.         nest = *text;
  475.         if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
  476.         {
  477.             match = nest ^ ('[' ^ ']');
  478.         }
  479.         else if ((nest & 0xfe) == '(')
  480.         {
  481.             match = nest ^ ('(' ^ ')');
  482.         }
  483.         else
  484.         {
  485.             match = 0;
  486.         }
  487.     }
  488.     if (!match)
  489.     {
  490.         return MARK_UNSET;
  491.     }
  492.     text--;
  493.  
  494.     /* search forward or backward for match */
  495.     if (match == '(' || match == '[' || match == '{')
  496.     {
  497.         /* search backward */
  498.         for (count = 1; count > 0; )
  499.         {
  500.             /* wrap at beginning of line */
  501.             if (text == ptext)
  502.             {
  503.                 do
  504.                 {
  505.                     if (l <= 1L)
  506.                     {
  507.                         return MARK_UNSET;
  508.                     }
  509.                     l--;
  510.                     pfetch(l);
  511.                 } while (!*ptext);
  512.                 text = ptext + plen - 1;
  513.             }
  514.             else
  515.             {
  516.                 text--;
  517.             }
  518.  
  519.             /* check the char */
  520.             if (*text == match)
  521.                 count--;
  522.             else if (*text == nest)
  523.                 count++;
  524.         }
  525.     }
  526.     else
  527.     {
  528.         /* search forward */
  529.         for (count = 1; count > 0; )
  530.         {
  531.             /* wrap at end of line */
  532.             if (!*text)
  533.             {
  534.                 if (l >= nlines)
  535.                 {
  536.                     return MARK_UNSET;
  537.                 }
  538.                 l++;
  539.                 pfetch(l);
  540.                 text = ptext;
  541.             }
  542.             else
  543.             {
  544.                 text++;
  545.             }
  546.  
  547.             /* check the char */
  548.             if (*text == match)
  549.                 count--;
  550.             else if (*text == nest)
  551.                 count++;
  552.         }
  553.     }
  554.  
  555.     /* construct a mark for this place */
  556.     m = buildmark(text);
  557.     return m;
  558. }
  559.  
  560. /*ARGSUSED*/
  561. MARK    m_tomark(m, cnt, key)
  562.     MARK    m;    /* movement is relative to this mark */
  563.     long    cnt;    /* (ignored) */
  564.     int    key;    /* keystroke - the mark to move to */
  565. {
  566.     /* mark '' is a special case */
  567.     if (key == '\'' || key == '`')
  568.     {
  569.         if (mark[26] == MARK_UNSET)
  570.         {
  571.             return MARK_FIRST;
  572.         }
  573.         else
  574.         {
  575.             return mark[26];
  576.         }
  577.     }
  578.  
  579.     /* if not a valid mark number, don't move */
  580.     if (key < 'a' || key > 'z')
  581.     {
  582.         return MARK_UNSET;
  583.     }
  584.  
  585.     /* return the selected mark -- may be MARK_UNSET */
  586.     if (!mark[key - 'a'])
  587.     {
  588.         msg("mark '%c is unset", key);
  589.     }
  590.     return mark[key - 'a'];
  591. }
  592.  
  593.