home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1707 / move1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  10.6 KB  |  655 lines

  1. /* m_1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains most movement functions */
  12.  
  13. #include "config.h"
  14. #include <ctype.h>
  15. #include "vi.h"
  16.  
  17. #ifndef isascii
  18. # define isascii(c)    !((c) & ~0x7f)
  19. #endif
  20.  
  21. /*ARGSUSED*/
  22. MARK    m_up(m, cnt)
  23.     MARK    m;    /* movement is relative to this mark */
  24.     long    cnt;    /* a numeric argument */
  25. {
  26.     DEFAULT(1);
  27.  
  28.     /* if at top already, don't move */
  29.     if (markline(m) - cnt < 1)
  30.     {
  31.         return MARK_UNSET;
  32.     }
  33.  
  34.     /* else move up one line */
  35.     m -= MARK_AT_LINE(cnt);
  36.  
  37.     return m;
  38. }
  39.  
  40. /*ARGSUSED*/
  41. MARK    m_down(m, cnt)
  42.     MARK    m;    /* movement is relative to this mark */
  43.     long    cnt;    /* a numeric argument */
  44. {
  45.     DEFAULT(1);
  46.  
  47.     /* if at bottom already, don't move */
  48.     if (markline(m) + cnt > nlines)
  49.     {
  50.         return MARK_UNSET;
  51.     }
  52.  
  53.     /* else move down one line */
  54.     m += MARK_AT_LINE(cnt);
  55.  
  56.     /* adjust column number */
  57.     if (markidx(m) >= plen)
  58.     {
  59.         m = (m & ~(BLKSIZE - 1));
  60.         if (plen > 0)
  61.         {
  62.             m += plen - 1;
  63.         }
  64.     }
  65.  
  66.     return m;
  67. }
  68.  
  69. /*ARGSUSED*/
  70. MARK    m_right(m, cnt)
  71.     MARK    m;    /* movement is relative to this mark */
  72.     long    cnt;    /* a numeric argument */
  73. {
  74.     int        idx;    /* index of the new cursor position */
  75.  
  76.     DEFAULT(1);
  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_toline(m, cnt)
  115.     MARK    m;    /* movement is relative to this mark */
  116.     long    cnt;    /* a numeric line number */
  117. {
  118.     /* if no number specified, assume last line */
  119.     DEFAULT(nlines);
  120.  
  121.     /* if invalid line number, don't move */
  122.     if (cnt > nlines)
  123.     {
  124.         msg("Line numbers range from 1 to %ld", nlines);
  125.         return MARK_UNSET;
  126.     }
  127.  
  128.     /* move to first character of the selected line */
  129.     m = MARK_AT_LINE(cnt);
  130.     return m;
  131. }
  132.  
  133. /*ARGSUSED*/
  134. MARK    m_tocol(m, cnt)
  135.     MARK    m;    /* movement is relative to this mark */
  136.     long    cnt;    /* a numeric argument */
  137. {
  138.     char    *text;    /* text of the line */
  139.     int    col;    /* column number */
  140.     int    idx;    /* index into the line */
  141.  
  142.     DEFAULT(1);
  143.  
  144.     /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  145.     cnt--;
  146.  
  147.     /* if 0, that's easy */
  148.     if (cnt == 0)
  149.     {
  150.         m &= ~(BLKSIZE - 1);
  151.         return m;
  152.     }
  153.  
  154.     /* find that column within the line */
  155.     pfetch(markline(m));
  156.     text = ptext;
  157.     for (col = idx = 0; col < cnt && *text; text++, idx++)
  158.     {
  159.         if (*text == '\t' && !*o_list)
  160.         {
  161.             col += *o_tabstop;
  162.             col -= col % *o_tabstop;
  163.         }
  164.         else if (UCHAR(*text) < ' ' || *text == '\177')
  165.         {
  166.             col += 2;
  167.         }
  168. #ifndef NO_CHARATTR
  169.         else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  170.         {
  171.             text += 2; /* plus one more as part of for loop */
  172.         }
  173. #endif
  174.         else
  175.         {
  176.             col++;
  177.         }
  178.     }
  179.     if (!*text)
  180.     {
  181.         return MARK_UNSET;
  182.     }
  183.     else
  184.     {
  185.         m = (m & ~(BLKSIZE - 1)) + idx;
  186.     }
  187.     return m;
  188. }
  189.  
  190. /*ARGSUSED*/
  191. MARK    m_front(m, cnt)
  192.     MARK    m;    /* movement is relative to this mark */
  193.     long    cnt;    /* a numeric argument (ignored) */
  194. {
  195.     char    *scan;
  196.  
  197.     /* move to the first non-whitespace character */
  198.     pfetch(markline(m));
  199.     scan = ptext;
  200.     m &= ~(BLKSIZE - 1);
  201.     while (*scan == ' ' || *scan == '\t')
  202.     {
  203.         scan++;
  204.         m++;
  205.     }
  206.  
  207.     return m;
  208. }
  209.  
  210. /*ARGSUSED*/
  211. MARK    m_rear(m, cnt)
  212.     MARK    m;    /* movement is relative to this mark */
  213.     long    cnt;    /* a numeric argument (ignored) */
  214. {
  215.     /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  216.      * that other code will convert this to a more reasonable MARK before
  217.      * anything tries to actually use it.  (See adjmove() in vi.c)
  218.      */
  219.     return m | (BLKSIZE - 1);
  220. }
  221.  
  222. #ifndef NO_SENTENCE
  223. /*ARGSUSED*/
  224. MARK    m_fsentence(m, cnt)
  225.     MARK    m;    /* movement is relative to this mark */
  226.     long    cnt;    /* a numeric argument */
  227. {
  228.     register char    *text;
  229.     register long    l;
  230.  
  231.     DEFAULT(1);
  232.  
  233.     /* get the current line */
  234.     l = markline(m);
  235.     pfetch(l);
  236.     text = ptext + markidx(m);
  237.  
  238.     /* for each requested sentence... */
  239.     while (cnt-- > 0)
  240.     {
  241.         /* search forward for one of [.?!] followed by spaces or EOL */
  242.         do
  243.         {
  244.             /* wrap at end of line */
  245.             if (!text[0])
  246.             {
  247.                 if (l >= nlines)
  248.                 {
  249.                     return MARK_UNSET;
  250.                 }
  251.                 l++;
  252.                 pfetch(l);
  253.                 text = ptext;
  254.             }
  255.             else
  256.             {
  257.                 text++;
  258.             }
  259.         } while (text[0] != '.' && text[0] != '?' && text[0] != '!'
  260.             || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
  261.     }
  262.  
  263.     /* construct a mark for this location */
  264.     m = buildmark(text);
  265.  
  266.     /* move forward to the first word of the next sentence */
  267.     m = m_fword(m, 1L);
  268.  
  269.     return m;
  270. }
  271.  
  272. /*ARGSUSED*/
  273. MARK    m_bsentence(m, cnt)
  274.     MARK    m;    /* movement is relative to this mark */
  275.     long    cnt;    /* a numeric argument */
  276. {
  277.     register char    *text;    /* used to scan thru text */
  278.     register long    l;    /* current line number */
  279.     int        flag;    /* have we passed at least one word? */
  280.  
  281.     DEFAULT(1);
  282.  
  283.     /* get the current line */
  284.     l = markline(m);
  285.     pfetch(l);
  286.     text = ptext + markidx(m);
  287.  
  288.     /* for each requested sentence... */
  289.     flag = TRUE;
  290.     while (cnt-- > 0)
  291.     {
  292.         /* search backward for one of [.?!] followed by spaces or EOL */
  293.         do
  294.         {
  295.             /* wrap at beginning of line */
  296.             if (text == ptext)
  297.             {
  298.                 do
  299.                 {
  300.                     if (l <= 1)
  301.                     {
  302.                         return MARK_UNSET;
  303.                     }
  304.                     l--;
  305.                     pfetch(l);
  306.                 } while (!*ptext);
  307.                 text = ptext + plen - 1;
  308.             }
  309.             else
  310.             {
  311.                 text--;
  312.             }
  313.  
  314.             /* are we moving past a "word"? */
  315.             if (text[0] >= '0')
  316.             {
  317.                 flag = FALSE;
  318.             }
  319.         } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!'
  320.             || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
  321.     }
  322.  
  323.     /* construct a mark for this location */
  324.     m = buildmark(text);
  325.  
  326.     /* move to the front of the following sentence */
  327.     m = m_fword(m, 1L);
  328.  
  329.     return m;
  330. }
  331. #endif
  332.  
  333. /*ARGSUSED*/
  334. MARK    m_fparagraph(m, cnt)
  335.     MARK    m;    /* movement is relative to this mark */
  336.     long    cnt;    /* a numeric argument */
  337. {
  338.     char    *text;
  339.     char    *pscn;    /* used to scan thru value of "paragraphs" option */
  340.     long    l;
  341.  
  342.     DEFAULT(1);
  343.  
  344.     for (l = markline(m); cnt > 0 && l++ < nlines; )
  345.     {
  346.         text = fetchline(l);
  347.         if (!*text)
  348.         {
  349.             cnt--;
  350.         }
  351. #ifndef NO_SENTENCE
  352.         else if (*text == '.')
  353.         {
  354.             for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
  355.             {
  356.                 if (pscn[0] == text[1] && pscn[1] == text[2])
  357.                 {
  358.                     cnt--;
  359.                     break;
  360.                 }
  361.             }
  362.         }
  363. #endif
  364.     }
  365.     if (l <= nlines)
  366.     {
  367.         m = MARK_AT_LINE(l);
  368.     }
  369.     else
  370.     {
  371.         m = MARK_LAST;
  372.     }
  373.     return m;
  374. }
  375.  
  376. /*ARGSUSED*/
  377. MARK    m_bparagraph(m, cnt)
  378.     MARK    m;    /* movement is relative to this mark */
  379.     long    cnt;    /* a numeric argument */
  380. {
  381.     char    *text;
  382.     char    *pscn;    /* used to scan thru value of "paragraph" option */
  383.     long    l;
  384.  
  385.     DEFAULT(1);
  386.  
  387.     for (l = markline(m); cnt > 0 && l-- > 1; )
  388.     {
  389.         text = fetchline(l);
  390.         if (!*text)
  391.         {
  392.             cnt--;
  393.         }
  394. #ifndef NO_SENTENCE
  395.         else if (*text == '.')
  396.         {
  397.             for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
  398.             {
  399.                 if (pscn[0] == text[1] && pscn[1] == text[2])
  400.                 {
  401.                     cnt--;
  402.                     break;
  403.                 }
  404.             }
  405.         }
  406. #endif
  407.     }
  408.     if (l >= 1)
  409.     {
  410.         m = MARK_AT_LINE(l);
  411.     }
  412.     else
  413.     {
  414.         m = MARK_FIRST;
  415.     }
  416.     return m;
  417. }
  418.  
  419. /*ARGSUSED*/
  420. MARK    m_fsection(m, cnt, key)
  421.     MARK    m;    /* movement is relative to this mark */
  422.     long    cnt;    /* (ignored) */
  423.     int    key;    /* second key stroke - must be ']' */
  424. {
  425.     char    *text;
  426.     char    *sscn;    /* used to scan thru value of "sections" option */
  427.     long    l;
  428.  
  429.     /* make sure second key was ']' */
  430.     if (key != ']')
  431.     {
  432.         return MARK_UNSET;
  433.     }
  434.  
  435.     for (l = markline(m); l++ < nlines; )
  436.     {
  437.         text = fetchline(l);
  438.         if (*text == '{')
  439.         {
  440.             break;
  441.         }
  442. #ifndef NO_SENTENCE
  443.         else if (*text == '.')
  444.         {
  445.             for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
  446.             {
  447.                 if (sscn[0] == text[1] && sscn[1] == text[2])
  448.                 {
  449.                     goto BreakBreak;
  450.                 }
  451.             }
  452.         }
  453. #endif
  454.     }
  455. BreakBreak:
  456.     if (l <= nlines)
  457.     {
  458.         m = MARK_AT_LINE(l);
  459.     }
  460.     else
  461.     {
  462.         m = MARK_LAST;
  463.     }
  464.     return m;
  465. }
  466.  
  467. /*ARGSUSED*/
  468. MARK    m_bsection(m, cnt, key)
  469.     MARK    m;    /* movement is relative to this mark */
  470.     long    cnt;    /* (ignored) */
  471.     int    key;    /* second key stroke - must be '[' */
  472. {
  473.     char    *text;
  474.     char    *sscn;    /* used to scan thru value of "sections" option */
  475.     long    l;
  476.  
  477.     /* make sure second key was '[' */
  478.     if (key != '[')
  479.     {
  480.         return MARK_UNSET;
  481.     }
  482.  
  483.     for (l = markline(m); l-- > 1; )
  484.     {
  485.         text = fetchline(l);
  486.         if (*text == '{')
  487.         {
  488.             break;
  489.         }
  490. #ifndef NO_SENTENCE
  491.         else if (*text == '.')
  492.         {
  493.             for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
  494.             {
  495.                 if (sscn[0] == text[1] && sscn[1] == text[2])
  496.                 {
  497.                     goto BreakBreak;
  498.                 }
  499.             }
  500.         }
  501. #endif
  502.     }
  503. BreakBreak:
  504.     if (l >= 1)
  505.     {
  506.         m = MARK_AT_LINE(l);
  507.     }
  508.     else
  509.     {
  510.         m = MARK_FIRST;
  511.     }
  512.     return m;
  513. }
  514.  
  515.  
  516. /*ARGSUSED*/
  517. MARK    m_match(m, cnt)
  518.     MARK    m;    /* movement is relative to this mark */
  519.     long    cnt;    /* a numeric argument */
  520. {
  521.     long    l;
  522.     register char    *text;
  523.     register char    match;
  524.     register char    nest;
  525.     register int    count;
  526.  
  527.     /* get the current line */
  528.     l = markline(m);
  529.     pfetch(l);
  530.     text = ptext + markidx(m);
  531.  
  532.     /* search forward within line for one of "[](){}" */
  533.     for (match = '\0'; !match && *text; text++)
  534.     {
  535.         /* tricky way to recognize 'em in ASCII */
  536.         nest = *text;
  537.         if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
  538.         {
  539.             match = nest ^ ('[' ^ ']');
  540.         }
  541.         else if ((nest & 0xfe) == '(')
  542.         {
  543.             match = nest ^ ('(' ^ ')');
  544.         }
  545.         else
  546.         {
  547.             match = 0;
  548.         }
  549.     }
  550.     if (!match)
  551.     {
  552.         return MARK_UNSET;
  553.     }
  554.     text--;
  555.  
  556.     /* search forward or backward for match */
  557.     if (match == '(' || match == '[' || match == '{')
  558.     {
  559.         /* search backward */
  560.         for (count = 1; count > 0; )
  561.         {
  562.             /* wrap at beginning of line */
  563.             if (text == ptext)
  564.             {
  565.                 do
  566.                 {
  567.                     if (l <= 1L)
  568.                     {
  569.                         return MARK_UNSET;
  570.                     }
  571.                     l--;
  572.                     pfetch(l);
  573.                 } while (!*ptext);
  574.                 text = ptext + plen - 1;
  575.             }
  576.             else
  577.             {
  578.                 text--;
  579.             }
  580.  
  581.             /* check the char */
  582.             if (*text == match)
  583.                 count--;
  584.             else if (*text == nest)
  585.                 count++;
  586.         }
  587.     }
  588.     else
  589.     {
  590.         /* search forward */
  591.         for (count = 1; count > 0; )
  592.         {
  593.             /* wrap at end of line */
  594.             if (!*text)
  595.             {
  596.                 if (l >= nlines)
  597.                 {
  598.                     return MARK_UNSET;
  599.                 }
  600.                 l++;
  601.                 pfetch(l);
  602.                 text = ptext;
  603.             }
  604.             else
  605.             {
  606.                 text++;
  607.             }
  608.  
  609.             /* check the char */
  610.             if (*text == match)
  611.                 count--;
  612.             else if (*text == nest)
  613.                 count++;
  614.         }
  615.     }
  616.  
  617.     /* construct a mark for this place */
  618.     m = buildmark(text);
  619.     return m;
  620. }
  621.  
  622. /*ARGSUSED*/
  623. MARK    m_tomark(m, cnt, key)
  624.     MARK    m;    /* movement is relative to this mark */
  625.     long    cnt;    /* (ignored) */
  626.     int    key;    /* keystroke - the mark to move to */
  627. {
  628.     /* mark '' is a special case */
  629.     if (key == '\'' || key == '`')
  630.     {
  631.         if (mark[26] == MARK_UNSET)
  632.         {
  633.             return MARK_FIRST;
  634.         }
  635.         else
  636.         {
  637.             return mark[26];
  638.         }
  639.     }
  640.  
  641.     /* if not a valid mark number, don't move */
  642.     if (key < 'a' || key > 'z')
  643.     {
  644.         return MARK_UNSET;
  645.     }
  646.  
  647.     /* return the selected mark -- may be MARK_UNSET */
  648.     if (!mark[key - 'a'])
  649.     {
  650.         msg("mark '%c is unset", key);
  651.     }
  652.     return mark[key - 'a'];
  653. }
  654.  
  655.