home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / amiga / vim46src.lha / vim-4.6 / src / misccmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-04  |  86.9 KB  |  4,000 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * misccmds.c: functions that didn't seem to fit elsewhere
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17. #ifdef HAVE_FCNTL_H
  18. # include <fcntl.h>            /* for chdir() */
  19. #endif
  20.  
  21. static int get_indent_str __ARGS((char_u *ptr));
  22. static void check_status __ARGS((BUF *));
  23.  
  24. /*
  25.  * count the size of the indent in the current line
  26.  */
  27.     int
  28. get_indent()
  29. {
  30.     return get_indent_str(ml_get_curline());
  31. }
  32.  
  33. /*
  34.  * count the size of the indent in line "lnum"
  35.  */
  36.     int
  37. get_indent_lnum(lnum)
  38.     linenr_t    lnum;
  39. {
  40.     return get_indent_str(ml_get(lnum));
  41. }
  42.  
  43. /*
  44.  * count the size of the indent in line "ptr"
  45.  */
  46.     static int
  47. get_indent_str(ptr)
  48.     register char_u *ptr;
  49. {
  50.     register int count = 0;
  51.  
  52.     for ( ; *ptr; ++ptr)
  53.     {
  54.         if (*ptr == TAB)    /* count a tab for what it is worth */
  55.             count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
  56.         else if (*ptr == ' ')
  57.             ++count;            /* count a space for one */
  58.         else
  59.             break;
  60.     }
  61.     return (count);
  62. }
  63.  
  64. /*
  65.  * set the indent of the current line
  66.  * leaves the cursor on the first non-blank in the line
  67.  */
  68.     void
  69. set_indent(size, del_first)
  70.     register int    size;
  71.     int             del_first;
  72. {
  73.     int                oldstate = State;
  74.     register int    c;
  75.  
  76.     State = INSERT;                    /* don't want REPLACE for State */
  77.     curwin->w_cursor.col = 0;
  78.     if (del_first)                    /* delete old indent */
  79.     {
  80.                                     /* vim_iswhite() is a define! */
  81.         while ((c = gchar_cursor()), vim_iswhite(c))
  82.             (void)delchar(FALSE);
  83.     }
  84.     if (!curbuf->b_p_et)            /* if 'expandtab' is set, don't use TABs */
  85.         while (size >= (int)curbuf->b_p_ts)
  86.         {
  87.             ins_char(TAB);
  88.             size -= (int)curbuf->b_p_ts;
  89.         }
  90.     while (size)
  91.     {
  92.         ins_char(' ');
  93.         --size;
  94.     }
  95.     State = oldstate;
  96. }
  97.  
  98. #if defined(CINDENT) || defined(SMARTINDENT)
  99.  
  100. static int is_cinword __ARGS((char_u *line));
  101.  
  102. /*
  103.  * Return TRUE if the string "line" starts with a word from 'cinwords'.
  104.  */
  105.     static int
  106. is_cinword(line)
  107.     char_u        *line;
  108. {
  109.     char_u    *cinw;
  110.     char_u    *cinw_buf;
  111.     int        cinw_len;
  112.     int        retval = FALSE;
  113.     int        len;
  114.  
  115.     cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
  116.     cinw_buf = alloc((unsigned)cinw_len);
  117.     if (cinw_buf != NULL)
  118.     {
  119.         line = skipwhite(line);
  120.         for (cinw = curbuf->b_p_cinw; *cinw; )
  121.         {
  122.             len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
  123.             if (STRNCMP(line, cinw_buf, len) == 0 &&
  124.                        (!iswordchar(line[len]) || !iswordchar(line[len - 1])))
  125.             {
  126.                 retval = TRUE;
  127.                 break;
  128.             }
  129.         }
  130.         vim_free(cinw_buf);
  131.     }
  132.     return retval;
  133. }
  134. #endif
  135.  
  136. /*
  137.  * Opencmd
  138.  *
  139.  * Add a new line below or above the current line.
  140.  * Caller must take care of undo.
  141.  *
  142.  * Return TRUE for success, FALSE for failure
  143.  */
  144.  
  145.     int
  146. Opencmd(dir, redraw, del_spaces)
  147.     int         dir;            /* FORWARD or BACKWARD */
  148.     int            redraw;            /* redraw afterwards */
  149.     int            del_spaces;        /* delete spaces after cursor */
  150. {
  151.     char_u  *saved_line;        /* copy of the original line */
  152.     char_u    *p_extra = NULL;    /* what goes to next line */
  153.     int        extra_len = 0;        /* length of p_extra string */
  154.     FPOS    old_cursor;         /* old cursor position */
  155.     int        newcol = 0;            /* new cursor column */
  156.     int     newindent = 0;        /* auto-indent of the new line */
  157.     int        n;
  158.     int        trunc_line = FALSE;    /* truncate current line afterwards */
  159.     int        retval = FALSE;        /* return value, default is FAIL */
  160.     int        lead_len;            /* length of comment leader */
  161.     char_u    *lead_flags;        /* position in 'comments' for comment leader */
  162.     char_u    *leader = NULL;        /* copy of comment leader */
  163.     char_u    *allocated = NULL;    /* allocated memory */
  164.     char_u    *p;
  165.     int        saved_char = NUL;    /* init for GCC */
  166.     FPOS    *pos;
  167.     int        old_plines = 0;        /* init for GCC */
  168.     int        new_plines = 0;        /* init for GCC */
  169. #ifdef SMARTINDENT
  170.     int        no_si = FALSE;        /* reset did_si afterwards */
  171.     int        first_char = NUL;    /* init for GCC */
  172. #endif
  173.  
  174.     /*
  175.      * make a copy of the current line so we can mess with it
  176.      */
  177.     saved_line = strsave(ml_get_curline());
  178.     if (saved_line == NULL)            /* out of memory! */
  179.         return FALSE;
  180.  
  181.     if (State == INSERT || State == REPLACE)
  182.     {
  183.         p_extra = saved_line + curwin->w_cursor.col;
  184. #ifdef SMARTINDENT
  185.         if (curbuf->b_p_si)            /* need first char after new line break */
  186.         {
  187.             p = skipwhite(p_extra);
  188.             first_char = *p;
  189.         }
  190. #endif
  191.         extra_len = STRLEN(p_extra);
  192.         saved_char = *p_extra;
  193.         *p_extra = NUL;
  194.     }
  195.  
  196.     u_clearline();                /* cannot do "U" command when adding lines */
  197. #ifdef SMARTINDENT
  198.     did_si = FALSE;
  199. #endif
  200.  
  201.     /*
  202.      * If 'autoindent' and/or 'smartindent' is set, try to figure out what
  203.      * indent to use for the new line.
  204.      */
  205.     if (curbuf->b_p_ai
  206. #ifdef SMARTINDENT
  207.                         || curbuf->b_p_si
  208. #endif
  209.                                             )
  210.     {
  211.         /*
  212.          * count white space on current line
  213.          */
  214.         newindent = get_indent();
  215.         if (newindent == 0)
  216.             newindent = old_indent;        /* for ^^D command in insert mode */
  217.         old_indent = 0;
  218.  
  219.         /*
  220.          * If we just did an auto-indent, then we didn't type anything on
  221.          * the prior line, and it should be truncated.
  222.          */
  223.         if (dir == FORWARD && did_ai)
  224.             trunc_line = TRUE;
  225.  
  226. #ifdef SMARTINDENT
  227.         /*
  228.          * Do smart indenting.
  229.          * In insert/replace mode (only when dir == FORWARD)
  230.          * we may move some text to the next line. If it starts with '{'
  231.          * don't add an indent. Fixes inserting a NL before '{' in line
  232.          *         "if (condition) {"
  233.          */
  234.         else if (curbuf->b_p_si && *saved_line != NUL &&
  235.                                        (p_extra == NULL || first_char != '{'))
  236.         {
  237.             char_u    *ptr;
  238.             char_u    last_char;
  239.  
  240.             old_cursor = curwin->w_cursor;
  241.             ptr = saved_line;
  242.             lead_len = get_leader_len(ptr, NULL);
  243.             if (dir == FORWARD)
  244.             {
  245.                 /*
  246.                  * Skip preprocessor directives, unless they are
  247.                  * recognised as comments.
  248.                  */
  249.                 if (lead_len == 0 && ptr[0] == '#')
  250.                 {
  251.                     while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
  252.                         ptr = ml_get(--curwin->w_cursor.lnum);
  253.                     newindent = get_indent();
  254.                 }
  255.                 lead_len = get_leader_len(ptr, NULL);
  256.                 if (lead_len > 0)
  257.                 {
  258.                     /*
  259.                      * This case gets the following right:
  260.                      *        \*
  261.                      *         * A comment (read "\" as "/").
  262.                      *         *\
  263.                      * #define IN_THE_WAY
  264.                      *        This should line up here;
  265.                      */
  266.                     p = skipwhite(ptr);
  267.                     if (p[0] == '/' && p[1] == '*')
  268.                         p++;
  269.                     if (p[0] == '*')
  270.                     {
  271.                         for (p++; *p; p++)
  272.                         {
  273.                             if (p[0] == '/' && p[-1] == '*')
  274.                             {
  275.                                 /*
  276.                                  * End of C comment, indent should line up
  277.                                  * with the line containing the start of
  278.                                  * the comment
  279.                                  */
  280.                                 curwin->w_cursor.col = p - ptr;
  281.                                 if ((pos = findmatch(NUL)) != NULL)
  282.                                 {
  283.                                     curwin->w_cursor.lnum = pos->lnum;
  284.                                     newindent = get_indent();
  285.                                 }
  286.                             }
  287.                         }
  288.                     }
  289.                 }
  290.                 else    /* Not a comment line */
  291.                 {
  292.                     /* Find last non-blank in line */
  293.                     p = ptr + STRLEN(ptr) - 1;
  294.                     while (p > ptr && vim_iswhite(*p))
  295.                         --p;
  296.                     last_char = *p;
  297.  
  298.                     /*
  299.                      * find the character just before the '{' or ';'
  300.                      */
  301.                     if (last_char == '{' || last_char == ';')
  302.                     {
  303.                         if (p > ptr)
  304.                             --p;
  305.                         while (p > ptr && vim_iswhite(*p))
  306.                             --p;
  307.                     }
  308.                     /*
  309.                      * Try to catch lines that are split over multiple
  310.                      * lines.  eg:
  311.                      *        if (condition &&
  312.                      *                    condition) {
  313.                      *            Should line up here!
  314.                      *        }
  315.                      */
  316.                     if (*p == ')')
  317.                     {
  318.                         curwin->w_cursor.col = p - ptr;
  319.                         if ((pos = findmatch('(')) != NULL)
  320.                         {
  321.                             curwin->w_cursor.lnum = pos->lnum;
  322.                             newindent = get_indent();
  323.                             ptr = ml_get_curline();
  324.                         }
  325.                     }
  326.                     /*
  327.                      * If last character is '{' do indent, without
  328.                      * checking for "if" and the like.
  329.                      */
  330.                     if (last_char == '{')
  331.                     {
  332.                         did_si = TRUE;    /* do indent */
  333.                         no_si = TRUE;    /* don't delete it when '{' typed */
  334.                     }
  335.                     /*
  336.                      * Look for "if" and the like, use 'cinwords'.
  337.                      * Don't do this if the previous line ended in ';' or
  338.                      * '}'.
  339.                      */
  340.                     else if (last_char != ';' && last_char != '}' &&
  341.                                                             is_cinword(ptr))
  342.                         did_si = TRUE;
  343.                 }
  344.             }
  345.             else /* dir == BACKWARD */
  346.             {
  347.                 /*
  348.                  * Skip preprocessor directives, unless they are
  349.                  * recognised as comments.
  350.                  */
  351.                 if (lead_len == 0 && ptr[0] == '#')
  352.                 {
  353.                     int was_backslashed = FALSE;
  354.  
  355.                     while ((ptr[0] == '#' || was_backslashed) &&
  356.                          curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  357.                     {
  358.                         if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
  359.                             was_backslashed = TRUE;
  360.                         else
  361.                             was_backslashed = FALSE;
  362.                         ptr = ml_get(++curwin->w_cursor.lnum);
  363.                     }
  364.                     if (was_backslashed)
  365.                         newindent = 0;        /* Got to end of file */
  366.                     else
  367.                         newindent = get_indent();
  368.                 }
  369.                 p = skipwhite(ptr);
  370.                 if (*p == '}')        /* if line starts with '}': do indent */
  371.                     did_si = TRUE;
  372.                 else                /* can delete indent when '{' typed */
  373.                     can_si_back = TRUE;
  374.             }
  375.             curwin->w_cursor = old_cursor;
  376.         }
  377.         if (curbuf->b_p_si)
  378.             can_si = TRUE;
  379. #endif /* SMARTINDENT */
  380.  
  381.         did_ai = TRUE;
  382.     }
  383.     
  384.     /*
  385.      * Find out if the current line starts with a comment leader.
  386.      * This may then be inserted in front of the new line.
  387.      */
  388.     lead_len = get_leader_len(saved_line, &lead_flags);
  389.     if (lead_len > 0)
  390.     {
  391.         char_u    *lead_repl = NULL;            /* replaces comment leader */
  392.         int        lead_repl_len = 0;            /* length of *lead_repl */
  393.         char_u    lead_middle[COM_MAX_LEN];    /* middle-comment string */
  394.         char_u    lead_end[COM_MAX_LEN];        /* end-comment string */
  395.         char_u    *comment_end = NULL;        /* where lead_end has been found */
  396.         int        extra_space = FALSE;        /* append extra space */
  397.         int        current_flag;
  398.  
  399.         /*
  400.          * If the comment leader has the start, middle or end flag, it may not
  401.          * be used or may be replaced with the middle leader.
  402.          */
  403.         for (p = lead_flags; *p && *p != ':'; ++p)
  404.         {
  405.             if (*p == COM_START || *p == COM_MIDDLE)
  406.             {
  407.                 current_flag = *p;
  408.                 if (*p == COM_START)
  409.                 {
  410.                     /*
  411.                      * Doing "O" on a start of comment does not insert leader.
  412.                      */
  413.                     if (dir == BACKWARD)
  414.                     {
  415.                         lead_len = 0;
  416.                         break;
  417.                     }
  418.  
  419.                    /* find start of middle part */
  420.                     (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  421.                 }
  422.  
  423.                 /*
  424.                  * Isolate the strings of the middle and end leader.
  425.                  */
  426.                 while (*p && p[-1] != ':')        /* find end of middle flags */
  427.                     ++p;
  428.                 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  429.                 while (*p && p[-1] != ':')        /* find end of end flags */
  430.                     ++p;
  431.                 (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
  432.  
  433.                 /*
  434.                  * If the end of the comment is in the same line, don't use
  435.                  * the comment leader.
  436.                  */
  437.                 if (dir == FORWARD)
  438.                 {
  439.                     n = STRLEN(lead_end);
  440.                     for (p = saved_line + lead_len; *p; ++p)
  441.                         if (STRNCMP(p, lead_end, n) == 0)
  442.                         {
  443.                             comment_end = p;
  444.                             lead_len = 0;
  445.                             break;
  446.                         }
  447.                 }
  448.  
  449.                 /*
  450.                  * Doing "o" on a start of comment inserts the middle leader.
  451.                  */
  452.                 if (lead_len)
  453.                 {
  454.                     if (current_flag == COM_START)
  455.                     {
  456.                         lead_repl = lead_middle;
  457.                         lead_repl_len = STRLEN(lead_middle);
  458.                     }
  459.  
  460.                     /*
  461.                      * If we have hit RETURN immediately after the start
  462.                      * comment leader, then put a space after the middle
  463.                      * comment leader on the next line.
  464.                      */
  465.                     if (!vim_iswhite(saved_line[lead_len - 1]) &&
  466.                             ((p_extra != NULL &&
  467.                                      (int)curwin->w_cursor.col == lead_len) ||
  468.                              (p_extra == NULL && saved_line[lead_len] == NUL)))
  469.                         extra_space = TRUE;
  470.                 }
  471.                 break;
  472.             }
  473.             if (*p == COM_END)
  474.             {
  475.                 /*
  476.                  * Doing "o" on the end of a comment does not insert leader.
  477.                  * Remember where the end is, might want to use it to find the
  478.                  * start (for C-comments).
  479.                  */
  480.                 if (dir == FORWARD)
  481.                 {
  482.                     comment_end = skipwhite(saved_line);
  483.                     lead_len = 0;
  484.                     break;
  485.                 }
  486.  
  487.                 /*
  488.                  * Doing "O" on the end of a comment inserts the middle leader.
  489.                  * Find the string for the middle leader, searching backwards.
  490.                  */
  491.                 while (p > curbuf->b_p_com && *p != ',')
  492.                     --p;
  493.                 for (lead_repl = p; lead_repl > curbuf->b_p_com &&
  494.                                             lead_repl[-1] != ':'; --lead_repl)
  495.                     ;
  496.                 lead_repl_len = p - lead_repl;
  497.                 break;
  498.             }
  499.             if (*p == COM_FIRST)
  500.             {
  501.                 /*
  502.                  * Comment leader for first line only:  Don't repeat leader
  503.                  * when using "O", blank out leader when using "o".
  504.                  */
  505.                 if (dir == BACKWARD)
  506.                     lead_len = 0;
  507.                 else
  508.                 {
  509.                     lead_repl = (char_u *)"";
  510.                     lead_repl_len = 0;
  511.                 }
  512.                 break;
  513.             }
  514.         }
  515.         if (lead_len)
  516.         {
  517.             /* allocate buffer (may concatenate p_exta later) */
  518.             leader = alloc(lead_len + lead_repl_len + extra_space +
  519.                                                               extra_len + 1);
  520.             allocated = leader;                /* remember to free it later */
  521.  
  522.             if (leader == NULL)
  523.                 lead_len = 0;
  524.             else
  525.             {
  526.                 STRNCPY(leader, saved_line, lead_len);
  527.                 leader[lead_len] = NUL;
  528.  
  529.                 /*
  530.                  * Replace leader with lead_repl, right or left adjusted
  531.                  */
  532.                 if (lead_repl != NULL)
  533.                 {
  534.                     for (p = lead_flags; *p && *p != ':'; ++p)
  535.                         if (*p == COM_RIGHT || *p == COM_LEFT)
  536.                             break;
  537.                     if (*p == COM_RIGHT)    /* right adjusted leader */
  538.                     {
  539.                         /* find last non-white in the leader to line up with */
  540.                         for (p = leader + lead_len - 1; p > leader &&
  541.                                                          vim_iswhite(*p); --p)
  542.                             ;
  543.  
  544.                         ++p;
  545.                         if (p < leader + lead_repl_len)
  546.                             p = leader;
  547.                         else
  548.                             p -= lead_repl_len;
  549.                         vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  550.                         if (p + lead_repl_len > leader + lead_len)
  551.                             p[lead_repl_len] = NUL;
  552.  
  553.                         /* blank-out any other chars from the old leader. */
  554.                         while (--p >= leader)
  555.                             if (!vim_iswhite(*p))
  556.                                 *p = ' ';
  557.                     }
  558.                     else                     /* left adjusted leader */
  559.                     {
  560.                         p = skipwhite(leader);
  561.                         vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  562.  
  563.                         /* blank-out any other chars from the old leader. */
  564.                         for (p += lead_repl_len; p < leader + lead_len; ++p)
  565.                             if (!vim_iswhite(*p))
  566.                                 *p = ' ';
  567.                         *p = NUL;
  568.                     }
  569.  
  570.                     /* Recompute the indent, it may have changed. */
  571.                     if (curbuf->b_p_ai
  572. #ifdef SMARTINDENT
  573.                                         || curbuf->b_p_si
  574. #endif
  575.                                                            )
  576.                         newindent = get_indent_str(leader);
  577.                 }
  578.  
  579.                 lead_len = STRLEN(leader);
  580.                 if (extra_space)
  581.                 {
  582.                     leader[lead_len++] = ' ';
  583.                     leader[lead_len] = NUL;
  584.                 }
  585.  
  586.                 newcol = lead_len;
  587.  
  588.                 /*
  589.                  * if a new indent will be set below, remove the indent that
  590.                  * is in the comment leader
  591.                  */
  592.                 if (newindent
  593. #ifdef SMARTINDENT
  594.                                 || did_si
  595. #endif
  596.                                            )
  597.                 {
  598.                     while (lead_len && vim_iswhite(*leader))
  599.                     {
  600.                         --lead_len;
  601.                         --newcol;
  602.                         ++leader;
  603.                     }
  604.                 }
  605.  
  606.             }
  607. #ifdef SMARTINDENT
  608.             did_si = can_si = FALSE;
  609. #endif
  610.         }
  611.         else if (comment_end != NULL)
  612.         {
  613.             /*
  614.              * We have finished a comment, so we don't use the leader.
  615.              * If this was a C-comment and 'ai' or 'si' is set do a normal
  616.              * indent to align with the line containing the start of the
  617.              * comment.
  618.              */
  619.             if (comment_end[0] == '*' && comment_end[1] == '/' &&
  620.                         (curbuf->b_p_ai
  621. #ifdef SMARTINDENT
  622.                                         || curbuf->b_p_si
  623. #endif
  624.                                                            ))
  625.             {
  626.                 old_cursor = curwin->w_cursor;
  627.                 curwin->w_cursor.col = comment_end - saved_line;
  628.                 if ((pos = findmatch(NUL)) != NULL)
  629.                 {
  630.                     curwin->w_cursor.lnum = pos->lnum;
  631.                     newindent = get_indent();
  632.                 }
  633.                 curwin->w_cursor = old_cursor;
  634.             }
  635.         }
  636.     }
  637.  
  638.     /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
  639.     if (p_extra != NULL)
  640.     {
  641.         *p_extra = saved_char;            /* restore char that NUL replaced */
  642.  
  643.         /*
  644.          * When 'ai' set or "del_spaces" TRUE, skip to the first non-blank.
  645.          *
  646.          * When in REPLACE mode, put the deleted blanks on the replace
  647.          * stack, followed by a NUL, so they can be put back when
  648.          * a BS is entered.
  649.          */
  650.         if (State == REPLACE)
  651.             replace_push(NUL);        /* end of extra blanks */
  652.         if (curbuf->b_p_ai || del_spaces)
  653.         {
  654.             while (*p_extra == ' ' || *p_extra == '\t')
  655.             {
  656.                 if (State == REPLACE)
  657.                     replace_push(*p_extra);
  658.                 ++p_extra;
  659.             }
  660.         }
  661.         if (*p_extra != NUL)
  662.             did_ai = FALSE;         /* append some text, don't trucate now */
  663.     }
  664.  
  665.     if (p_extra == NULL)
  666.         p_extra = (char_u *)"";                /* append empty line */
  667.  
  668.     /* concatenate leader and p_extra, if there is a leader */
  669.     if (lead_len)
  670.     {
  671.         STRCAT(leader, p_extra);
  672.         p_extra = leader;
  673.     }
  674.  
  675.     old_cursor = curwin->w_cursor;
  676.     if (dir == BACKWARD)
  677.         --curwin->w_cursor.lnum;
  678.     if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
  679.         goto theend;
  680.     mark_adjust(curwin->w_cursor.lnum + 1, MAXLNUM, 1L, 0L);
  681.     if (newindent
  682. #ifdef SMARTINDENT
  683.                     || did_si
  684. #endif
  685.                                 )
  686.     {
  687.         ++curwin->w_cursor.lnum;
  688. #ifdef SMARTINDENT
  689.         if (did_si)
  690.         {
  691.             if (p_sr)
  692.                 newindent -= newindent % (int)curbuf->b_p_sw;
  693.             newindent += (int)curbuf->b_p_sw;
  694.         }
  695. #endif
  696.         set_indent(newindent, FALSE);
  697.         /*
  698.          * In REPLACE mode the new indent must be put on
  699.          * the replace stack for when it is deleted with BS
  700.          */
  701.         if (State == REPLACE)
  702.             for (n = 0; n < (int)curwin->w_cursor.col; ++n)
  703.                 replace_push(NUL);
  704.         newcol += curwin->w_cursor.col;
  705. #ifdef SMARTINDENT
  706.         if (no_si)
  707.             did_si = FALSE;
  708. #endif
  709.     }
  710.     /*
  711.      * In REPLACE mode the extra leader must be put on the replace stack for
  712.      * when it is deleted with BS.
  713.      */
  714.     if (State == REPLACE)
  715.         while (lead_len-- > 0)
  716.             replace_push(NUL);
  717.  
  718.     curwin->w_cursor = old_cursor;
  719.  
  720.     if (dir == FORWARD)
  721.     {
  722.         if (redraw)        /* want to know the old number of screen lines */
  723.         {
  724.             old_plines = plines(curwin->w_cursor.lnum);
  725.             new_plines = old_plines;
  726.         }
  727.         if (trunc_line || State == INSERT || State == REPLACE)
  728.         {
  729.             if (trunc_line)
  730.             {
  731.                     /* find start of trailing white space */
  732.                 for (n = STRLEN(saved_line); n > 0 &&
  733.                                           vim_iswhite(saved_line[n - 1]); --n)
  734.                     ;
  735.                 saved_line[n] = NUL;
  736.             }
  737.             else                    /* truncate current line at cursor */
  738.                 *(saved_line + curwin->w_cursor.col) = NUL;
  739.             ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
  740.             saved_line = NULL;
  741.             new_plines = plines(curwin->w_cursor.lnum);
  742.         }
  743.  
  744.         /*
  745.          * Get the cursor to the start of the line, so that 'curwin->w_row'
  746.          * gets set to the right physical line number for the stuff that
  747.          * follows...
  748.          */
  749.         curwin->w_cursor.col = 0;
  750.  
  751.         if (redraw)
  752.         {
  753.             /*
  754.              * Call cursupdate() to compute w_row.
  755.              * But we don't want it to update the srceen.
  756.              */
  757.             ++RedrawingDisabled;
  758.             cursupdate();
  759.             --RedrawingDisabled;
  760.  
  761.             /*
  762.              * If we're doing an open on the last logical line, then go ahead
  763.              * and scroll the screen up. Otherwise, just insert a blank line
  764.              * at the right place if the number of screen lines changed.
  765.              * We use calls to plines() in case the cursor is resting on a
  766.              * long line, we want to know the row below the line.
  767.              */
  768.             n = curwin->w_row + new_plines;
  769.             if (n == curwin->w_winpos + curwin->w_height)
  770.                 scrollup(1L);
  771.             else
  772.                 win_ins_lines(curwin, n,
  773.                   plines(curwin->w_cursor.lnum + 1) + new_plines - old_plines,
  774.                                                                   TRUE, TRUE);
  775.         }
  776.  
  777.         /*
  778.          * Put the cursor on the new line.  Careful: the cursupdate() and
  779.          * scrollup() above may have moved w_cursor, we must use old_cursor.
  780.          */
  781.         curwin->w_cursor.lnum = old_cursor.lnum + 1;
  782.     }
  783.     else if (redraw)             /* insert physical line above current line */
  784.         win_ins_lines(curwin, curwin->w_row, 1, TRUE, TRUE);
  785.  
  786.     curwin->w_cursor.col = newcol;
  787.  
  788. #ifdef LISPINDENT
  789.     /*
  790.      * May do lisp indenting.
  791.      */
  792.     if (leader == NULL && curbuf->b_p_lisp && curbuf->b_p_ai)
  793.         fixthisline(get_lisp_indent);
  794. #endif
  795. #ifdef CINDENT
  796.     /*
  797.      * May do indenting after opening a new line.
  798.      */
  799.     if (leader == NULL && curbuf->b_p_cin &&
  800.             in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW :
  801.                         KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
  802.         fixthisline(get_c_indent);
  803. #endif
  804.  
  805.     if (redraw)
  806.     {
  807.         updateScreen(VALID_TO_CURSCHAR);
  808.         cursupdate();            /* update curwin->w_row */
  809.     }
  810.     CHANGED;
  811.  
  812.     retval = TRUE;                /* success! */
  813. theend:
  814.     vim_free(saved_line);
  815.     vim_free(allocated);
  816.     return retval;
  817. }
  818.  
  819. /*
  820.  * get_leader_len() returns the length of the prefix of the given string
  821.  * which introduces a comment.  If this string is not a comment then 0 is
  822.  * returned.
  823.  * When "flags" is non-zero, it is set to point to the flags of the recognized
  824.  * comment leader.
  825.  */
  826.     int
  827. get_leader_len(line, flags)
  828.     char_u    *line;
  829.     char_u    **flags;
  830. {
  831.     int        i, j;
  832.     int        got_com = FALSE;
  833.     int        found_one;
  834.     char_u    part_buf[COM_MAX_LEN];    /* buffer for one option part */
  835.     char_u    *string;                /* pointer to comment string */
  836.     char_u    *list;
  837.  
  838.     if (!fo_do_comments)            /* don't format comments at all */
  839.         return 0;
  840.  
  841.     i = 0;
  842.     while (vim_iswhite(line[i]))    /* leading white space is ignored */
  843.         ++i;
  844.  
  845.     /*
  846.      * Repeat to match several nested comment strings.
  847.      */
  848.     while (line[i])
  849.     {
  850.         /*
  851.          * scan through the 'comments' option for a match
  852.          */
  853.         found_one = FALSE;
  854.         for (list = curbuf->b_p_com; *list; )
  855.         {
  856.             /*
  857.              * Get one option part into part_buf[].  Advance list to next one.
  858.              * put string at start of string.
  859.              */
  860.             if (!got_com && flags != NULL)    /* remember where flags started */
  861.                 *flags = list;
  862.             (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
  863.             string = vim_strchr(part_buf, ':');
  864.             if (string == NULL)        /* missing ':', ignore this part */
  865.                 continue;
  866.             *string++ = NUL;        /* isolate flags from string */
  867.  
  868.             /*
  869.              * When already found a nested comment, only accept further
  870.              * nested comments.
  871.              */
  872.             if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
  873.                 continue;
  874.  
  875.             /*
  876.              * Line contents and string must match.
  877.              */
  878.             for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
  879.                 ;
  880.             if (string[j] != NUL)
  881.                 continue;
  882.  
  883.             /*
  884.              * When 'b' flag used, there must be white space or an
  885.              * end-of-line after the string in the line.
  886.              */
  887.             if (vim_strchr(part_buf, COM_BLANK) != NULL &&
  888.                               !vim_iswhite(line[i + j]) && line[i + j] != NUL)
  889.                 continue;
  890.  
  891.             /*
  892.              * We have found a match, stop searching.
  893.              */
  894.             i += j;
  895.             got_com = TRUE;
  896.             found_one = TRUE;
  897.             break;
  898.         }
  899.  
  900.         /*
  901.          * No match found, stop scanning.
  902.          */
  903.         if (!found_one)
  904.             break;
  905.  
  906.         /*
  907.          * Include any trailing white space.
  908.          */
  909.         while (vim_iswhite(line[i]))
  910.             ++i;
  911.  
  912.         /*
  913.          * If this comment doesn't nest, stop here.
  914.          */
  915.         if (vim_strchr(part_buf, COM_NEST) == NULL)
  916.             break;
  917.     }
  918.     return (got_com ? i : 0);
  919. }
  920.  
  921. /*
  922.  * plines(p) - return the number of physical screen lines taken by line 'p'
  923.  */
  924.     int
  925. plines(p)
  926.     linenr_t    p;
  927. {
  928.     return plines_win(curwin, p);
  929. }
  930.     
  931.     int
  932. plines_win(wp, p)
  933.     WIN            *wp;
  934.     linenr_t    p;
  935. {
  936.     register long        col;
  937.     register char_u        *s;
  938.     register int        lines;
  939.  
  940.     if (!wp->w_p_wrap)
  941.         return 1;
  942.  
  943.     s = ml_get_buf(wp->w_buffer, p, FALSE);
  944.     if (*s == NUL)                /* empty line */
  945.         return 1;
  946.  
  947.     col = win_linetabsize(wp, s);
  948.  
  949.     /*
  950.      * If list mode is on, then the '$' at the end of the line takes up one
  951.      * extra column.
  952.      */
  953.     if (wp->w_p_list)
  954.         col += 1;
  955.  
  956.     /*
  957.      * If 'number' mode is on, add another 8.
  958.      */
  959.     if (wp->w_p_nu)
  960.         col += 8;
  961.  
  962.     lines = (col + (Columns - 1)) / Columns;
  963.     if (lines <= wp->w_height)
  964.         return lines;
  965.     return (int)(wp->w_height);        /* maximum length */
  966. }
  967.  
  968. /*
  969.  * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  970.  */
  971.     int
  972. plines_m(first, last)
  973.     linenr_t        first, last;
  974. {
  975.     return plines_m_win(curwin, first, last);
  976. }
  977.  
  978.     int
  979. plines_m_win(wp, first, last)
  980.     WIN                *wp;
  981.     linenr_t        first, last;
  982. {
  983.     int count = 0;
  984.  
  985.     while (first <= last)
  986.         count += plines_win(wp, first++);
  987.     return (count);
  988. }
  989.  
  990. /*
  991.  * Insert or replace a single character at the cursor position.
  992.  * When in REPLACE mode, replace any existing character.
  993.  */
  994.     void
  995. ins_char(c)
  996.     int            c;
  997. {
  998.     register char_u  *p;
  999.     char_u            *newp;
  1000.     char_u            *oldp;
  1001.     int                oldlen;
  1002.     int                extra;
  1003.     colnr_t            col = curwin->w_cursor.col;
  1004.     linenr_t        lnum = curwin->w_cursor.lnum;
  1005.  
  1006.     oldp = ml_get(lnum);
  1007.     oldlen = STRLEN(oldp) + 1;
  1008.  
  1009.     if (State != REPLACE || *(oldp + col) == NUL)
  1010.         extra = 1;
  1011.     else
  1012.         extra = 0;
  1013.  
  1014.     /*
  1015.      * a character has to be put on the replace stack if there is a
  1016.      * character that is replaced, so it can be put back when BS is used.
  1017.      * Otherwise a 0 is put on the stack, indicating that a new character
  1018.      * was inserted, which can be deleted when BS is used.
  1019.      */
  1020.     if (State == REPLACE)
  1021.         replace_push(!extra ? *(oldp + col) : 0);
  1022.     newp = alloc_check((unsigned)(oldlen + extra));
  1023.     if (newp == NULL)
  1024.         return;
  1025.     vim_memmove(newp, oldp, (size_t)col);
  1026.     p = newp + col;
  1027.     vim_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
  1028.     *p = c;
  1029.     ml_replace(lnum, newp, FALSE);
  1030.  
  1031.     /*
  1032.      * If we're in insert or replace mode and 'showmatch' is set, then check for
  1033.      * right parens and braces. If there isn't a match, then beep. If there
  1034.      * is a match AND it's on the screen, then flash to it briefly. If it
  1035.      * isn't on the screen, don't do anything.
  1036.      */
  1037. #ifdef RIGHTLEFT
  1038.     if (p_sm && (State & INSERT) && 
  1039.             ((!curwin->w_p_rl && (c == ')' || c == '}' || c == ']')) ||
  1040.              (curwin->w_p_rl && (c == '(' || c == '{' || c == '['))))
  1041. #else
  1042.      if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
  1043. #endif
  1044.         showmatch();
  1045.  
  1046. #ifdef RIGHTLEFT
  1047.     if (!p_ri || State == REPLACE)        /* normal insert: cursor right */
  1048. #endif
  1049.         ++curwin->w_cursor.col;
  1050.     CHANGED;
  1051. }
  1052.  
  1053. /*
  1054.  * Insert a string at the cursor position.
  1055.  * Note: Nothing special for replace mode.
  1056.  */
  1057.     void
  1058. ins_str(s)
  1059.     char_u  *s;
  1060. {
  1061.     register char_u        *oldp, *newp;
  1062.     register int        newlen = STRLEN(s);
  1063.     int                    oldlen;
  1064.     colnr_t                col = curwin->w_cursor.col;
  1065.     linenr_t            lnum = curwin->w_cursor.lnum;
  1066.  
  1067.     oldp = ml_get(lnum);
  1068.     oldlen = STRLEN(oldp);
  1069.  
  1070.     newp = alloc_check((unsigned)(oldlen + newlen + 1));
  1071.     if (newp == NULL)
  1072.         return;
  1073.     vim_memmove(newp, oldp, (size_t)col);
  1074.     vim_memmove(newp + col, s, (size_t)newlen);
  1075.     vim_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
  1076.     ml_replace(lnum, newp, FALSE);
  1077.     curwin->w_cursor.col += newlen;
  1078.     CHANGED;
  1079. }
  1080.  
  1081. /*
  1082.  * delete one character under the cursor
  1083.  *
  1084.  * return FAIL for failure, OK otherwise
  1085.  */
  1086.     int
  1087. delchar(fixpos)
  1088.     int            fixpos;     /* if TRUE fix the cursor position when done */
  1089. {
  1090.     char_u        *oldp, *newp;
  1091.     colnr_t        oldlen;
  1092.     linenr_t    lnum = curwin->w_cursor.lnum;
  1093.     colnr_t        col = curwin->w_cursor.col;
  1094.     int            was_alloced;
  1095.  
  1096.     oldp = ml_get(lnum);
  1097.     oldlen = STRLEN(oldp);
  1098.  
  1099.     if (col >= oldlen)    /* can't do anything (happens with replace mode) */
  1100.         return FAIL;
  1101.  
  1102. /*
  1103.  * If the old line has been allocated the deletion can be done in the
  1104.  * existing line. Otherwise a new line has to be allocated
  1105.  */
  1106.     was_alloced = ml_line_alloced();        /* check if oldp was allocated */
  1107.     if (was_alloced)
  1108.         newp = oldp;                            /* use same allocated memory */
  1109.     else
  1110.     {
  1111.         newp = alloc((unsigned)oldlen);        /* need to allocated a new line */
  1112.         if (newp == NULL)
  1113.             return FAIL;
  1114.         vim_memmove(newp, oldp, (size_t)col);
  1115.     }
  1116.     vim_memmove(newp + col, oldp + col + 1, (size_t)(oldlen - col));
  1117.     if (!was_alloced)
  1118.         ml_replace(lnum, newp, FALSE);
  1119.  
  1120.     /*
  1121.      * If we just took off the last character of a non-blank line, we don't
  1122.      * want to end up positioned at the NUL.
  1123.      */
  1124.     if (fixpos && curwin->w_cursor.col > 0 && col == oldlen - 1)
  1125.         --curwin->w_cursor.col;
  1126.  
  1127.     CHANGED;
  1128.     return OK;
  1129. }
  1130.  
  1131. /*
  1132.  * Delete from cursor to end of line.
  1133.  *
  1134.  * return FAIL for failure, OK otherwise
  1135.  */
  1136.     int
  1137. truncate_line(fixpos)
  1138.     int            fixpos;     /* if TRUE fix the cursor position when done */
  1139. {
  1140.     char_u        *newp;
  1141.     linenr_t    lnum = curwin->w_cursor.lnum;
  1142.     colnr_t        col = curwin->w_cursor.col;
  1143.  
  1144.     if (col == 0)
  1145.         newp = strsave((char_u *)"");
  1146.     else
  1147.         newp = strnsave(ml_get(lnum), col);
  1148.  
  1149.     if (newp == NULL)
  1150.         return FAIL;
  1151.  
  1152.     ml_replace(lnum, newp, FALSE);
  1153.  
  1154.     /*
  1155.      * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
  1156.      */
  1157.     if (fixpos && curwin->w_cursor.col > 0)
  1158.         --curwin->w_cursor.col;
  1159.  
  1160.     CHANGED;
  1161.     return OK;
  1162. }
  1163.  
  1164.     void
  1165. dellines(nlines, dowindow, undo)
  1166.     long             nlines;            /* number of lines to delete */
  1167.     int             dowindow;        /* if true, update the window */
  1168.     int                undo;            /* if true, prepare for undo */
  1169. {
  1170.     int             num_plines = 0;
  1171.  
  1172.     if (nlines <= 0)
  1173.         return;
  1174.     /*
  1175.      * There's no point in keeping the window updated if redrawing is disabled
  1176.      * or we're deleting more than a window's worth of lines.
  1177.      */
  1178.     if (RedrawingDisabled)
  1179.         dowindow = FALSE;
  1180.     else if (nlines > (curwin->w_height - curwin->w_row) && dowindow)
  1181.     {
  1182.         dowindow = FALSE;
  1183.         /* flaky way to clear rest of window */
  1184.         win_del_lines(curwin, curwin->w_row, curwin->w_height, TRUE, TRUE);
  1185.     }
  1186.     /* save the deleted lines for undo */
  1187.     if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
  1188.         return;
  1189.  
  1190.     /* adjust marks for deleted lines and lines that follow */
  1191.     mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
  1192.                                                             MAXLNUM, -nlines);
  1193.  
  1194.     while (nlines-- > 0)
  1195.     {
  1196.         if (curbuf->b_ml.ml_flags & ML_EMPTY)         /* nothing to delete */
  1197.             break;
  1198.  
  1199.         /*
  1200.          * Set up to delete the correct number of physical lines on the
  1201.          * window
  1202.          */
  1203.         if (dowindow)
  1204.             num_plines += plines(curwin->w_cursor.lnum);
  1205.  
  1206.         ml_delete(curwin->w_cursor.lnum, TRUE);
  1207.  
  1208.         CHANGED;
  1209.  
  1210.         /* If we delete the last line in the file, stop */
  1211.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1212.         {
  1213.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1214.             break;
  1215.         }
  1216.     }
  1217.     curwin->w_cursor.col = 0;
  1218.     /*
  1219.      * Delete the correct number of physical lines on the window
  1220.      */
  1221.     if (dowindow && num_plines > 0)
  1222.         win_del_lines(curwin, curwin->w_row, num_plines, TRUE, TRUE);
  1223. }
  1224.  
  1225.     int
  1226. gchar(pos)
  1227.     FPOS *pos;
  1228. {
  1229.     return (int)(*(ml_get_pos(pos)));
  1230. }
  1231.  
  1232.     int
  1233. gchar_cursor()
  1234. {
  1235.     return (int)(*(ml_get_cursor()));
  1236. }
  1237.  
  1238. /*
  1239.  * Write a character at the current cursor position.
  1240.  * It is directly written into the block.
  1241.  */
  1242.     void
  1243. pchar_cursor(c)
  1244.     int c;
  1245. {
  1246.     *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
  1247.                                                     curwin->w_cursor.col) = c;
  1248. }
  1249.  
  1250. /*
  1251.  * Put *pos at end of current buffer
  1252.  */
  1253.     void
  1254. goto_endofbuf(pos)
  1255.     FPOS    *pos;
  1256. {
  1257.     char_u    *p;
  1258.  
  1259.     pos->lnum = curbuf->b_ml.ml_line_count;
  1260.     pos->col = 0;
  1261.     p = ml_get(pos->lnum);
  1262.     while (*p++)
  1263.         ++pos->col;
  1264. }
  1265.  
  1266. /*
  1267.  * When extra == 0: Return TRUE if the cursor is before or on the first
  1268.  *                    non-blank in the line.
  1269.  * When extra == 1: Return TRUE if the cursor is before the first non-blank in
  1270.  *                    the line.
  1271.  */
  1272.     int
  1273. inindent(extra)
  1274.     int        extra;
  1275. {
  1276.     register char_u *ptr;
  1277.     register colnr_t col;
  1278.  
  1279.     for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
  1280.         ++ptr;
  1281.     if (col >= curwin->w_cursor.col + extra)
  1282.         return TRUE;
  1283.     else
  1284.         return FALSE;
  1285. }
  1286.  
  1287. /*
  1288.  * skipwhite: skip over ' ' and '\t'.
  1289.  */
  1290.     char_u *
  1291. skipwhite(p)
  1292.     register char_u *p;
  1293. {
  1294.     while (vim_iswhite(*p))    /* skip to next non-white */
  1295.         ++p;
  1296.     return p;
  1297. }
  1298.  
  1299. /*
  1300.  * skipdigits: skip over digits;
  1301.  */
  1302.     char_u *
  1303. skipdigits(p)
  1304.     register char_u *p;
  1305. {
  1306.     while (isdigit(*p))    /* skip to next non-digit */
  1307.         ++p;
  1308.     return p;
  1309. }
  1310.  
  1311. /*
  1312.  * skiptowhite: skip over text until ' ' or '\t' or NUL.
  1313.  */
  1314.     char_u *
  1315. skiptowhite(p)
  1316.     register char_u *p;
  1317. {
  1318.     while (*p != ' ' && *p != '\t' && *p != NUL)
  1319.         ++p;
  1320.     return p;
  1321. }
  1322.  
  1323. /*
  1324.  * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
  1325.  */
  1326.     char_u *
  1327. skiptowhite_esc(p)
  1328.     register char_u *p;
  1329. {
  1330.     while (*p != ' ' && *p != '\t' && *p != NUL)
  1331.     {
  1332.         if ((*p == '\\' || *p == Ctrl('V')) && *(p + 1) != NUL)
  1333.             ++p;
  1334.         ++p;
  1335.     }
  1336.     return p;
  1337. }
  1338.  
  1339. /*
  1340.  * getdigits: get a number from a string and skip over it
  1341.  *
  1342.  * note: you must give a pointer to a char_u pointer!
  1343.  */
  1344.  
  1345.     long
  1346. getdigits(pp)
  1347.     char_u **pp;
  1348. {
  1349.     register char_u *p;
  1350.     long retval;
  1351.     
  1352.     p = *pp;
  1353.     retval = atol((char *)p);
  1354.     p = skipdigits(p);        /* skip to next non-digit */
  1355.     *pp = p;
  1356.     return retval;
  1357. }
  1358.  
  1359. /*
  1360.  * Skip to next part of an option argument: Skip space and comma.
  1361.  */
  1362.     char_u *
  1363. skip_to_option_part(p)
  1364.     char_u    *p;
  1365. {
  1366.     if (*p == ',')
  1367.         ++p;
  1368.     while (*p == ' ')
  1369.         ++p;
  1370.     return p;
  1371. }
  1372.  
  1373.     char *
  1374. plural(n)
  1375.     long n;
  1376. {
  1377.     static char buf[2] = "s";
  1378.  
  1379.     if (n == 1)
  1380.         return &(buf[1]);
  1381.     return &(buf[0]);
  1382. }
  1383.  
  1384. /*
  1385.  * set_Changed is called when something in the current buffer is changed
  1386.  */
  1387.     void
  1388. set_Changed()
  1389. {
  1390.     if (!curbuf->b_changed)
  1391.     {
  1392.         change_warning(0);
  1393.         curbuf->b_changed = TRUE;
  1394.         check_status(curbuf);
  1395.     }
  1396.     modified = TRUE;                /* used for redrawing */
  1397.     tag_modified = TRUE;            /* used for tag searching check */
  1398. }
  1399.  
  1400. /*
  1401.  * unset_Changed is called when the changed flag must be reset for buffer 'buf'
  1402.  */
  1403.     void
  1404. unset_Changed(buf)
  1405.     BUF        *buf;
  1406. {
  1407.     if (buf->b_changed)
  1408.     {
  1409.         buf->b_changed = 0;
  1410.         check_status(buf);
  1411.     }
  1412. }
  1413.  
  1414. /*
  1415.  * check_status: called when the status bars for the buffer 'buf'
  1416.  *                 need to be updated
  1417.  */
  1418.     static void
  1419. check_status(buf)
  1420.     BUF        *buf;
  1421. {
  1422.     WIN        *wp;
  1423.     int        i;
  1424.  
  1425.     i = 0;
  1426.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  1427.         if (wp->w_buffer == buf && wp->w_status_height)
  1428.         {
  1429.             wp->w_redr_status = TRUE;
  1430.             ++i;
  1431.         }
  1432.     if (i)
  1433.         redraw_later(NOT_VALID);
  1434. }
  1435.  
  1436. /*
  1437.  * If the file is readonly, give a warning message with the first change.
  1438.  * Don't do this for autocommands.
  1439.  * Don't use emsg(), because it flushes the macro buffer.
  1440.  * If we have undone all changes b_changed will be FALSE, but b_did_warn
  1441.  * will be TRUE.
  1442.  */
  1443.     void
  1444. change_warning(col)
  1445.     int        col;                /* column for message; non-zero when in insert
  1446.                                    mode and 'showmode' is on */
  1447. {
  1448.     if (curbuf->b_did_warn == FALSE && curbuf->b_changed == 0 &&
  1449. #ifdef AUTOCMD
  1450.                                               !autocmd_busy &&
  1451. #endif
  1452.                                               curbuf->b_p_ro)
  1453.     {
  1454.         /*
  1455.          * Do what msg() does, but with a column offset.
  1456.          */
  1457.         msg_start();
  1458.         msg_col = col;
  1459.         MSG_OUTSTR("Warning: Changing a readonly file");
  1460.         msg_clr_eos();
  1461.         (void)msg_end();
  1462.         mch_delay(1000L, TRUE);    /* give him some time to think about it */
  1463.         curbuf->b_did_warn = TRUE;
  1464.     }
  1465. }
  1466.  
  1467. /*
  1468.  * Ask for a reply from the user, a 'y' or a 'n'.
  1469.  * No other characters are accepted, the message is repeated until a valid
  1470.  * reply is entered or CTRL-C is hit.
  1471.  * If direct is TRUE, don't use vgetc but mch_inchar, don't get characters from
  1472.  * any buffers but directly from the user.
  1473.  *
  1474.  * return the 'y' or 'n'
  1475.  */
  1476.     int
  1477. ask_yesno(str, direct)
  1478.     char_u    *str;
  1479.     int        direct;
  1480. {
  1481.     int        r = ' ';
  1482.     char_u    buf[20];
  1483.     int        len = 0;
  1484.     int        idx = 0;
  1485.  
  1486.     if (exiting)                /* put terminal in raw mode for this question */
  1487.         settmode(1);
  1488.     while (r != 'y' && r != 'n')
  1489.     {
  1490.         (void)set_highlight('r');    /* same highlighting as for wait_return */
  1491.         msg_highlight = TRUE;
  1492.         smsg((char_u *)"%s (y/n)?", str);
  1493.         if (direct)
  1494.         {
  1495.             flushbuf();
  1496.             if (idx >= len)
  1497.             {
  1498.                 len = mch_inchar(buf, 20, -1L);
  1499.                 idx = 0;
  1500.             }
  1501.             r = buf[idx++];
  1502.         }
  1503.         else
  1504.             r = vgetc();
  1505.         if (r == Ctrl('C') || r == ESC)
  1506.             r = 'n';
  1507.         msg_outchar(r);        /* show what you typed */
  1508.         flushbuf();
  1509.     }
  1510.     return r;
  1511. }
  1512.  
  1513. /*
  1514.  * get a number from the user
  1515.  */
  1516.     int
  1517. get_number()
  1518. {
  1519.     int        n = 0;
  1520.     int        c;
  1521.  
  1522.     for (;;)
  1523.     {
  1524.         windgoto(msg_row, msg_col);
  1525.         c = vgetc();
  1526.         if (isdigit(c))
  1527.         {
  1528.             n = n * 10 + c - '0';
  1529.             msg_outchar(c);
  1530.         }
  1531.         else if (c == K_DEL || c == K_BS || c == Ctrl('H'))
  1532.         {
  1533.             n /= 10;
  1534.             MSG_OUTSTR("\b \b");
  1535.         }
  1536.         else if (c == CR || c == NL || c == Ctrl('C'))
  1537.             break;
  1538.     }
  1539.     return n;
  1540. }
  1541.  
  1542.     void
  1543. msgmore(n)
  1544.     long n;
  1545. {
  1546.     long pn;
  1547.  
  1548.     if (global_busy ||        /* no messages now, wait until global is finished */
  1549.             keep_msg)        /* there is a message already, skip this one */
  1550.         return;
  1551.  
  1552.     if (n > 0)
  1553.         pn = n;
  1554.     else
  1555.         pn = -n;
  1556.  
  1557.     if (pn > p_report)
  1558.     {
  1559.         sprintf((char *)msg_buf, "%ld %s line%s %s",
  1560.                 pn, n > 0 ? "more" : "fewer", plural(pn),
  1561.                 got_int ? "(Interrupted)" : "");
  1562.         if (msg(msg_buf))
  1563.             keep_msg = msg_buf;
  1564.     }
  1565. }
  1566.  
  1567. /*
  1568.  * flush map and typeahead buffers and give a warning for an error
  1569.  */
  1570.     void
  1571. beep_flush()
  1572. {
  1573.     flush_buffers(FALSE);
  1574.     vim_beep();
  1575. }
  1576.  
  1577. /*
  1578.  * give a warning for an error
  1579.  */
  1580.     void
  1581. vim_beep()
  1582. {
  1583.     if (p_vb)
  1584.     {
  1585.         outstr(T_VB);
  1586.     }
  1587.     else
  1588.     {
  1589. #if defined MSDOS  ||  defined WIN32 /* ? gvr */
  1590.         /*
  1591.          * The number of beeps outputted is reduced to avoid having to wait
  1592.          * for all the beeps to finish. This is only a problem on systems
  1593.          * where the beeps don't overlap.
  1594.          */
  1595.         if (beep_count == 0 || beep_count == 10)
  1596.         {
  1597.             outchar('\007');
  1598.             beep_count = 1;
  1599.         }
  1600.         else
  1601.             ++beep_count;
  1602. #else
  1603.         outchar('\007');
  1604. #endif
  1605.     }
  1606. }
  1607.  
  1608. /*
  1609.  * To get the "real" home directory:
  1610.  * - get value of $HOME
  1611.  * For Unix:
  1612.  *    - go to that directory
  1613.  *    - do mch_dirname() to get the real name of that directory.
  1614.  *    This also works with mounts and links.
  1615.  *    Don't do this for MS-DOS, it will change the "current dir" for a drive.
  1616.  */
  1617. static char_u    *homedir = NULL;
  1618.  
  1619.     void
  1620. init_homedir()
  1621. {
  1622.     char_u    *var;
  1623.  
  1624.     var = vim_getenv((char_u *)"HOME");
  1625. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1626.     /*
  1627.      * Default home dir is C:/
  1628.      * Best assumption we can make in such a situation.
  1629.      */
  1630.     if (var == NULL)
  1631.         var = "C:/";
  1632. #endif
  1633.     if (var != NULL)
  1634.     {
  1635. #ifdef UNIX
  1636.         if (mch_dirname(NameBuff, MAXPATHL) == OK)
  1637.         {
  1638.             if (!vim_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
  1639.                 var = IObuff;
  1640.             vim_chdir((char *)NameBuff);
  1641.         }
  1642. #endif
  1643.         homedir = strsave(var);
  1644.     }
  1645. }
  1646.  
  1647. /* 
  1648.  * Expand environment variable with path name.
  1649.  * For Unix and OS/2 "~/" is also expanded, like $HOME.
  1650.  * If anything fails no expansion is done and dst equals src.
  1651.  * Note that IObuff must NOT be used as either src or dst!  This is because
  1652.  * vim_getenv() may use IObuff to do its expansion.
  1653.  */
  1654.     void
  1655. expand_env(src, dst, dstlen)
  1656.     char_u    *src;            /* input string e.g. "$HOME/vim.hlp" */
  1657.     char_u    *dst;            /* where to put the result */
  1658.     int        dstlen;            /* maximum length of the result */
  1659. {
  1660.     char_u    *tail;
  1661.     int        c;
  1662.     char_u    *var;
  1663.     int        copy_char;
  1664. #if defined(UNIX) || defined(OS2)
  1665.     int        mustfree;
  1666.     int        at_start = TRUE;
  1667. #endif
  1668.  
  1669.     src = skipwhite(src);
  1670.     --dstlen;                /* leave one char space for "\," */
  1671.     while (*src && dstlen > 0)
  1672.     {
  1673.         copy_char = TRUE;
  1674.         if (*src == '$'
  1675. #if defined(UNIX) || defined(OS2)
  1676.                         || (*src == '~' && at_start)
  1677. #endif
  1678.                                                     )
  1679.         {
  1680. #if defined(UNIX) || defined(OS2)
  1681.             mustfree = FALSE;
  1682.  
  1683.             /*
  1684.              * The variable name is copied into dst temporarily, because it may
  1685.              * be a string in read-only memory and a NUL needs to be inserted.
  1686.              */
  1687.             if (*src == '$')                            /* environment var */
  1688.             {
  1689. #endif
  1690.                 tail = src + 1;
  1691.                 var = dst;
  1692.                 c = dstlen - 1;
  1693.  
  1694. #ifdef UNIX
  1695.                 /* Unix has ${var-name} type environment vars */
  1696.                 if (*tail == '{' && !isidchar('{'))
  1697.                 {
  1698.                     tail++;        /* ignore '{' */
  1699.                     while (c-- > 0 && *tail && *tail != '}')
  1700.                         *var++ = *tail++;
  1701.                     tail++;        /* ignore '}' */
  1702.                 }
  1703.                 else
  1704. #endif
  1705.                 {
  1706.                     while (c-- > 0 && *tail && isidchar(*tail))
  1707. #ifdef OS2
  1708.                     {    /* env vars only in uppercase */
  1709.                         *var++ = toupper(*tail);
  1710.                         tail++;        /* toupper() may be a macro! */
  1711.                     }
  1712. #else
  1713.                         *var++ = *tail++;
  1714. #endif
  1715.                 }
  1716.                 *var = NUL;
  1717. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1718.                 /* use "C:/" when $HOME is not set */
  1719.                 if (STRCMP(dst, "HOME") == 0)
  1720.                     var = homedir;
  1721.                 else
  1722. #endif
  1723.                     var = vim_getenv(dst);
  1724. #if defined(UNIX) || defined(OS2)
  1725.             }
  1726.                                                         /* home directory */
  1727.             else if (src[1] == NUL ||
  1728.                               vim_strchr((char_u *)"/ ,\t\n", src[1]) != NULL)
  1729.             {
  1730.                 var = homedir;
  1731.                 tail = src + 1;
  1732.             }
  1733.             else                                        /* user directory */
  1734. # ifdef OS2
  1735.             {
  1736.                 /* cannot expand user's home directory, so don't try */
  1737.                 var = NULL;
  1738.                 tail = "";    /* shut gcc up about "may be used uninitialized" */
  1739.             }
  1740. # else
  1741.             {
  1742.                 /*
  1743.                  * Copy ~user to dst[], so we can put a NUL after it.
  1744.                  */
  1745.                 tail = src;
  1746.                 var = dst;
  1747.                 c = dstlen - 1;
  1748.                 while (c-- > 0 && *tail &&
  1749.                                        isfilechar(*tail) && !ispathsep(*tail))
  1750.                     *var++ = *tail++;
  1751.                 *var = NUL;
  1752.  
  1753.                 /*
  1754.                  * If the system supports getpwnam(), use it.
  1755.                  * Otherwise, or if getpwnam() fails, the shell is used to
  1756.                  * expand ~user.  This is slower and may fail if the shell
  1757.                  * does not support ~user (old versions of /bin/sh).
  1758.                  */
  1759. #  if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
  1760.                 {
  1761.                     struct passwd *pw;
  1762.  
  1763.                     pw = getpwnam((char *)dst + 1);
  1764.                     if (pw != NULL)
  1765.                         var = (char_u *)pw->pw_dir;
  1766.                     else
  1767.                         var = NULL;
  1768.                 }
  1769.                 if (var == NULL)
  1770. #  endif
  1771.                 {
  1772.                     var = ExpandOne(dst, NULL, 0, WILD_EXPAND_FREE);
  1773.                     mustfree = TRUE;
  1774.                 }
  1775.             }
  1776. # endif /* OS2 */
  1777. #endif /* UNIX || OS2 */
  1778.             if (var != NULL && *var != NUL &&
  1779.                           (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
  1780.             {
  1781.                 STRCPY(dst, var);
  1782.                 dstlen -= STRLEN(var);
  1783.                 dst += STRLEN(var);
  1784.                     /* if var[] ends in a path separator and tail[] starts
  1785.                      * with it, skip a character */
  1786.                 if (*var && ispathsep(*(dst-1)) && ispathsep(*tail))
  1787.                     ++tail;
  1788.                 src = tail;
  1789.                 copy_char = FALSE;
  1790.             }
  1791. #if defined(UNIX) || defined(OS2)
  1792.             if (mustfree)
  1793.                 vim_free(var);
  1794. #endif
  1795.         }
  1796.  
  1797.         if (copy_char)        /* copy at least one char */
  1798.         {
  1799. #if defined(UNIX) || defined(OS2)
  1800.             /*
  1801.              * Recogize the start of a new name, for '~'.
  1802.              */
  1803.             at_start = FALSE;
  1804. #endif
  1805.             if (src[0] == '\\')
  1806.             {
  1807.                 *dst++ = *src++;
  1808.                 --dstlen;
  1809.             }
  1810. #if defined(UNIX) || defined(OS2)
  1811.             else if (src[0] == ' ' || src[0] == ',')
  1812.                 at_start = TRUE;
  1813. #endif
  1814.             *dst++ = *src++;
  1815.             --dstlen;
  1816.         }
  1817.     }
  1818.     *dst = NUL;
  1819. }
  1820.  
  1821. /* 
  1822.  * Replace home directory by "~" in each space or comma separated filename in
  1823.  * 'src'.  If anything fails (except when out of space) dst equals src.
  1824.  */
  1825.     void
  1826. home_replace(buf, src, dst, dstlen)
  1827.     BUF        *buf;            /* when not NULL, check for help files */
  1828.     char_u    *src;            /* input file name */
  1829.     char_u    *dst;            /* where to put the result */
  1830.     int        dstlen;            /* maximum length of the result */
  1831. {
  1832.     size_t    dirlen = 0, envlen = 0;
  1833.     size_t    len;
  1834.     char_u    *homedir_env;
  1835.     char_u    *p;
  1836.  
  1837.     if (src == NULL)
  1838.     {
  1839.         *dst = NUL;
  1840.         return;
  1841.     }
  1842.  
  1843.     /*
  1844.      * If the file is a help file, remove the path completely.
  1845.      */
  1846.     if (buf != NULL && buf->b_help)
  1847.     {
  1848.         STRCPY(dst, gettail(src));
  1849.         return;
  1850.     }
  1851.  
  1852.     /*
  1853.      * We check both the value of the $HOME environment variable and the
  1854.      * "real" home directory.
  1855.      */
  1856.     if (homedir != NULL)
  1857.         dirlen = STRLEN(homedir);
  1858.     homedir_env = vim_getenv((char_u *)"HOME");
  1859.     if (homedir_env != NULL)
  1860.         envlen = STRLEN(homedir_env);
  1861.  
  1862.     src = skipwhite(src);
  1863.     while (*src && dstlen > 0)
  1864.     {
  1865.         /*
  1866.          * Here we are at the beginning of a filename.
  1867.          * First, check to see if the beginning of the filename matches
  1868.          * $HOME or the "real" home directory. Check that there is a '/'
  1869.          * after the match (so that if e.g. the file is "/home/pieter/bla",
  1870.          * and the home directory is "/home/piet", the file does not end up
  1871.          * as "~er/bla" (which would seem to indicate the file "bla" in user
  1872.          * er's home directory)).
  1873.          */
  1874.         p = homedir;
  1875.         len = dirlen;
  1876.         for (;;)
  1877.         {
  1878.             if (len && fnamencmp(src, p, len) == 0 && (ispathsep(src[len]) ||
  1879.                        src[len] == ',' || src[len] == ' ' || src[len] == NUL))
  1880.             {
  1881.                 src += len;
  1882.                 if (--dstlen > 0)
  1883.                     *dst++ = '~';
  1884.  
  1885.                 /*
  1886.                  * If it's just the home directory, add  "/".
  1887.                  */
  1888.                 if (!ispathsep(src[0]) && --dstlen > 0)
  1889.                     *dst++ = '/';
  1890.             }
  1891.             if (p == homedir_env)
  1892.                 break;
  1893.             p = homedir_env;
  1894.             len = envlen;
  1895.         }
  1896.  
  1897.         /* skip to separator: space or comma */
  1898.         while (*src && *src != ',' && *src != ' ' && --dstlen > 0)
  1899.             *dst++ = *src++;
  1900.         /* skip separator */
  1901.         while ((*src == ' ' || *src == ',') && --dstlen > 0)
  1902.             *dst++ = *src++;
  1903.     }
  1904.     /* if (dstlen == 0) out of space, what to do??? */
  1905.  
  1906.     *dst = NUL;
  1907. }
  1908.  
  1909. /*
  1910.  * Like home_replace, store the replaced string in allocated memory.
  1911.  * When something fails, NULL is returned.
  1912.  */
  1913.     char_u    *
  1914. home_replace_save(buf, src)
  1915.     BUF        *buf;            /* when not NULL, check for help files */
  1916.     char_u    *src;            /* input file name */
  1917. {
  1918.     char_u        *dst;
  1919.     unsigned    len;
  1920.  
  1921.     len = 3;                    /* space for "~/" and trailing NUL */
  1922.     if (src != NULL)            /* just in case */
  1923.         len += STRLEN(src);
  1924.     dst = alloc(len);
  1925.     if (dst != NULL)
  1926.         home_replace(buf, src, dst, len);
  1927.     return dst;
  1928. }
  1929.  
  1930. /*
  1931.  * Compare two file names and return:
  1932.  * FPC_SAME   if they both exist and are the same file.
  1933.  * FPC_DIFF   if they both exist and are different files.
  1934.  * FPC_NOTX   if they both don't exist.
  1935.  * FPC_DIFFX  if one of them doesn't exist.
  1936.  * For the first name environment variables are expanded
  1937.  */
  1938.     int
  1939. fullpathcmp(s1, s2)
  1940.     char_u *s1, *s2;
  1941. {
  1942. #ifdef UNIX
  1943.     char_u            buf1[MAXPATHL];
  1944.     struct stat        st1, st2;
  1945.     int                r1, r2;
  1946.  
  1947.     expand_env(s1, buf1, MAXPATHL);
  1948.     r1 = stat((char *)buf1, &st1);
  1949.     r2 = stat((char *)s2, &st2);
  1950.     if (r1 != 0 && r2 != 0)
  1951.         return FPC_NOTX;
  1952.     if (r1 != 0 || r2 != 0)
  1953.         return FPC_DIFFX;
  1954.     if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
  1955.         return FPC_SAME;
  1956.     return FPC_DIFF;
  1957. #else
  1958.     char_u    *buf1 = NULL;
  1959.     char_u    *buf2 = NULL;
  1960.     int        retval = FPC_DIFF;
  1961.     int        r1, r2;
  1962.     
  1963.     if ((buf1 = alloc(MAXPATHL)) != NULL && (buf2 = alloc(MAXPATHL)) != NULL)
  1964.     {
  1965.         expand_env(s1, buf2, MAXPATHL);
  1966.         /*
  1967.          * If FullName() failed, the file probably doesn't exist.
  1968.          */
  1969.         r1 = FullName(buf2, buf1, MAXPATHL, FALSE);
  1970.         r2 = FullName(s2, buf2, MAXPATHL, FALSE);
  1971.         if (r1 != OK && r2 != OK)
  1972.             retval = FPC_NOTX;
  1973.         else if (r1 != OK || r2 != OK)
  1974.             retval = FPC_DIFFX;
  1975.         else if (fnamecmp(buf1, buf2))
  1976.             retval = FPC_DIFF;
  1977.         else
  1978.             retval = FPC_SAME;
  1979.     }
  1980.     vim_free(buf1);
  1981.     vim_free(buf2);
  1982.     return retval;
  1983. #endif
  1984. }
  1985.  
  1986. /*
  1987.  * get the tail of a path: the file name.
  1988.  */
  1989.     char_u *
  1990. gettail(fname)
  1991.     char_u *fname;
  1992. {
  1993.     register char_u *p1, *p2;
  1994.  
  1995.     if (fname == NULL)
  1996.         return (char_u *)"";
  1997.     for (p1 = p2 = fname; *p2; ++p2)    /* find last part of path */
  1998.     {
  1999.         if (ispathsep(*p2))
  2000.             p1 = p2 + 1;
  2001.     }
  2002.     return p1;
  2003. }
  2004.  
  2005. /*
  2006.  * Get a pointer to one character past the head of a path name.
  2007.  * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/".
  2008.  * If there is no head, path is returned.
  2009.  */
  2010.     char_u *
  2011. get_past_head(path)
  2012.     char_u    *path;
  2013. {
  2014.     char_u    *retval;
  2015.  
  2016. #if defined(MSDOS) || defined(WIN32) || defined(OS2)
  2017.     /* may skip "c:" */
  2018.     if (isalpha(path[0]) && path[1] == ':')
  2019.         retval = path + 2;
  2020.     else
  2021.         retval = path;
  2022. #else
  2023. # if defined(AMIGA)
  2024.     /* may skip "label:" */
  2025.     retval = vim_strchr(path, ':');
  2026.     if (retval == NULL)
  2027.         retval = path;
  2028. # else    /* Unix */
  2029.     retval = path;
  2030. # endif
  2031. #endif
  2032.  
  2033.     while (ispathsep(*retval))
  2034.         ++retval;
  2035.  
  2036.     return retval;
  2037. }
  2038.  
  2039. /*
  2040.  * return TRUE if 'c' is a path separator.
  2041.  */
  2042.     int
  2043. ispathsep(c)
  2044.     int c;
  2045. {
  2046. #ifdef UNIX
  2047.     return (c == '/');        /* UNIX has ':' inside file names */
  2048. #else
  2049. # ifdef BACKSLASH_IN_FILENAME
  2050.     return (c == ':' || c == '/' || c == '\\');
  2051. # else    /* Amiga */
  2052.     return (c == ':' || c == '/');
  2053. # endif
  2054. #endif
  2055. }
  2056.  
  2057. /*
  2058.  * Concatenate filenames fname1 and fname2 into allocated memory.
  2059.  * Only add a '/' or '\\' when 'sep' is TRUE and it is neccesary.
  2060.  */
  2061.     char_u    *
  2062. concat_fnames(fname1, fname2, sep)
  2063.     char_u    *fname1;
  2064.     char_u    *fname2;
  2065.     int        sep;
  2066. {
  2067.     char_u    *dest;
  2068.  
  2069.     dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 2));
  2070.     if (dest != NULL)
  2071.     {
  2072.         STRCPY(dest, fname1);
  2073.         if (sep && *dest && !ispathsep(*(dest + STRLEN(dest) - 1)))
  2074.             STRCAT(dest, PATHSEPSTR);
  2075.         STRCAT(dest, fname2);
  2076.     }
  2077.     return dest;
  2078. }
  2079.  
  2080. /*
  2081.  * FullName_save - Make an allocated copy of a full file name.
  2082.  * Returns NULL when failed.
  2083.  */
  2084.     char_u     *
  2085. FullName_save(fname)
  2086.     char_u        *fname;
  2087. {
  2088.     char_u        *buf;
  2089.     char_u        *new_fname = NULL;
  2090.  
  2091.     buf = alloc((unsigned)MAXPATHL);
  2092.     if (buf != NULL)
  2093.     {
  2094.         if (FullName(fname, buf, MAXPATHL, FALSE) != FAIL)
  2095.             new_fname = strsave(buf);
  2096.         vim_free(buf);
  2097.     }
  2098.     return new_fname;
  2099. }
  2100.  
  2101. #ifdef CINDENT
  2102.  
  2103. /*
  2104.  * Functions for C-indenting.
  2105.  * Most of this originally comes from Eric Fischer.
  2106.  */
  2107. /*
  2108.  * Below "XXX" means that this function may unlock the current line.
  2109.  */
  2110.  
  2111. static int        isdefault __ARGS((char_u *));
  2112. static char_u    *after_label __ARGS((char_u *l));
  2113. static int        get_indent_nolabel __ARGS((linenr_t lnum));
  2114. static int        skip_label __ARGS((linenr_t, char_u **pp, int ind_maxcomment));
  2115. static int        ispreproc __ARGS((char_u *));
  2116. static int        iscomment __ARGS((char_u *));
  2117. static int        commentorempty __ARGS((char_u *));
  2118. static int        isterminated __ARGS((char_u *));
  2119. static int        isfuncdecl __ARGS((char_u *));
  2120. static char_u    *skip_string __ARGS((char_u *p));
  2121. static int        isif __ARGS((char_u *));
  2122. static int        iselse __ARGS((char_u *));
  2123. static int        isdo __ARGS((char_u *));
  2124. static int        iswhileofdo __ARGS((char_u *, linenr_t, int));
  2125. static FPOS        *find_start_comment __ARGS((int ind_maxcomment));
  2126. static FPOS        *find_start_brace __ARGS((int));
  2127. static FPOS        *find_match_paren __ARGS((int, int));
  2128. static int        find_last_paren __ARGS((char_u *l));
  2129. static int        find_match __ARGS((int lookfor, linenr_t ourscope,
  2130.                         int ind_maxparen, int ind_maxcomment));
  2131.  
  2132. /*
  2133.  * Recognize a label: "label:".
  2134.  * Note: curwin->w_cursor must be where we are looking for the label.
  2135.  */
  2136.     int
  2137. islabel(ind_maxcomment)            /* XXX */
  2138.     int            ind_maxcomment;
  2139. {
  2140.     char_u        *s;
  2141.  
  2142.     s = skipwhite(ml_get_curline());
  2143.  
  2144.     /*
  2145.      * Exclude "default" from labels, since it should be indented
  2146.      * like a switch label.
  2147.      */
  2148.  
  2149.     if (isdefault(s))
  2150.         return FALSE;
  2151.  
  2152.     if (!isidchar(*s))        /* need at least one ID character */
  2153.         return FALSE;
  2154.  
  2155.     while (isidchar(*s))
  2156.         s++;
  2157.  
  2158.     s = skipwhite(s);
  2159.  
  2160.     /* "::" is not a label, it's C++ */
  2161.     if (*s == ':' && s[1] != ':')
  2162.     {
  2163.         /*
  2164.          * Only accept a label if the previous line is terminated or is a case
  2165.          * label.
  2166.          */
  2167.         FPOS    cursor_save;
  2168.         FPOS    *trypos;
  2169.         char_u    *line;
  2170.  
  2171.         cursor_save = curwin->w_cursor;
  2172.         while (curwin->w_cursor.lnum > 1)
  2173.         {
  2174.             --curwin->w_cursor.lnum;
  2175.  
  2176.             /*
  2177.              * If we're in a comment now, skip to the start of the comment.
  2178.              */
  2179.             curwin->w_cursor.col = 0;
  2180.             if ((trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  2181.                 curwin->w_cursor = *trypos;
  2182.  
  2183.             line = ml_get_curline();
  2184.             if (ispreproc(line))        /* ignore #defines, #if, etc. */
  2185.                 continue;
  2186.             if (commentorempty(line))
  2187.                 continue;
  2188.  
  2189.             curwin->w_cursor = cursor_save;
  2190.             if (isterminated(line) || iscase(line))
  2191.                 return TRUE;
  2192.             return FALSE;
  2193.         }
  2194.         curwin->w_cursor = cursor_save;
  2195.         return TRUE;            /* label at start of file??? */
  2196.     }
  2197.     return FALSE;
  2198. }
  2199.  
  2200. /*
  2201.  * Recognize a switch label: "case .*:" or "default:".
  2202.  */
  2203.      int
  2204. iscase(s)
  2205.     char_u *s;
  2206. {
  2207.     s = skipwhite(s);
  2208.     if (STRNCMP(s, "case", 4) == 0 && !isidchar(s[4]))
  2209.     {
  2210.         for (s += 4; *s; ++s)
  2211.             if (*s == ':')
  2212.             {
  2213.                 if (s[1] == ':')        /* skip over "::" for C++ */
  2214.                     ++s;
  2215.                 else
  2216.                     return TRUE;
  2217.             }
  2218.         return FALSE;
  2219.     }
  2220.  
  2221.     if (isdefault(s))
  2222.         return TRUE;
  2223.     return FALSE;
  2224. }
  2225.  
  2226. /*
  2227.  * Recognize a "default" switch label.
  2228.  */
  2229.     static int
  2230. isdefault(s)
  2231.     char_u    *s;
  2232. {
  2233.     return (STRNCMP(s, "default", 7) == 0 &&
  2234.             *(s = skipwhite(s + 7)) == ':' &&
  2235.             s[1] != ':');
  2236. }
  2237.  
  2238. /*
  2239.  * Return a pointer to the first non-empty non-comment character after a ':'.
  2240.  * Return NULL if not found.
  2241.  *        case 234:    a = b;
  2242.  *                     ^
  2243.  */
  2244.     static char_u *
  2245. after_label(l)
  2246.     char_u    *l;
  2247. {
  2248.     for ( ; *l; ++l)
  2249.         if (*l == ':')
  2250.         {
  2251.             if (l[1] == ':')        /* skip over "::" for C++ */
  2252.                 ++l;
  2253.             else
  2254.                 break;
  2255.         }
  2256.     if (*l == NUL)
  2257.         return NULL;
  2258.     l = skipwhite(l + 1);
  2259.     if (commentorempty(l))
  2260.         return NULL;
  2261.     return l;
  2262. }
  2263.  
  2264. /*
  2265.  * Get indent of line "lnum", skipping a label.
  2266.  * Return 0 if there is nothing after the label.
  2267.  */
  2268.     static int
  2269. get_indent_nolabel(lnum)                /* XXX */
  2270.     linenr_t    lnum;
  2271. {
  2272.     char_u        *l;
  2273.     FPOS        fp;
  2274.     colnr_t        col;
  2275.     char_u        *p;
  2276.  
  2277.     l = ml_get(lnum);
  2278.     p = after_label(l);
  2279.     if (p == NULL)
  2280.         return 0;
  2281.  
  2282.     fp.col = p - l;
  2283.     fp.lnum = lnum;
  2284.     getvcol(curwin, &fp, &col, NULL, NULL);
  2285.     return (int)col;
  2286. }
  2287.  
  2288. /*
  2289.  * Find indent for line "lnum", ignoring any case or jump label.
  2290.  * Also return a pointer to the text (after the label).
  2291.  *   label:        if (asdf && asdfasdf)
  2292.  *              ^
  2293.  */
  2294.     static int
  2295. skip_label(lnum, pp, ind_maxcomment)
  2296.     linenr_t    lnum;
  2297.     char_u        **pp;
  2298.     int            ind_maxcomment;
  2299. {
  2300.     char_u        *l;
  2301.     int            amount;
  2302.     FPOS        cursor_save;
  2303.  
  2304.     cursor_save = curwin->w_cursor;
  2305.     curwin->w_cursor.lnum = lnum;
  2306.     l = ml_get_curline();
  2307.     if (iscase(l) || islabel(ind_maxcomment)) /* XXX */
  2308.     {
  2309.         amount = get_indent_nolabel(lnum);
  2310.         l = after_label(ml_get_curline());
  2311.         if (l == NULL)            /* just in case */
  2312.             l = ml_get_curline();
  2313.     }
  2314.     else
  2315.     {
  2316.         amount = get_indent();
  2317.         l = ml_get_curline();
  2318.     }
  2319.     *pp = l;
  2320.  
  2321.     curwin->w_cursor = cursor_save;
  2322.     return amount;
  2323. }
  2324.  
  2325. /*
  2326.  * Recognize a preprocessor statement: Any line that starts with '#'.
  2327.  */
  2328.     static int
  2329. ispreproc(s)
  2330.     char_u *s;
  2331. {
  2332.     s = skipwhite(s);
  2333.     if (*s == '#')
  2334.         return TRUE;
  2335.     return 0;
  2336. }
  2337.  
  2338. /*
  2339.  * Recognize the start of a C or C++ comment.
  2340.  */
  2341.     static int
  2342. iscomment(p)
  2343.     char_u    *p;
  2344. {
  2345.     return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
  2346. }
  2347.  
  2348. /*
  2349.  * Recognize an empty or comment line.
  2350.  */
  2351.     static int
  2352. commentorempty(s)
  2353.     char_u *s;
  2354. {
  2355.     s = skipwhite(s);
  2356.     if (*s == NUL || iscomment(s))
  2357.         return TRUE;
  2358.     return FALSE;
  2359. }
  2360.  
  2361. /*
  2362.  * Recognize a line that starts with '{' or '}', or ends with ';' or '}'.
  2363.  * Don't consider "} else" a terminated line.
  2364.  * Also consider a line terminated if it ends in ','.  This is not 100%
  2365.  * correct, but this mostly means we are in initializations and then it's OK.
  2366.  */
  2367.     static int
  2368. isterminated(s)
  2369.     char_u *s;
  2370. {
  2371.     s = skipwhite(s);
  2372.  
  2373.     if (*s == '{' || (*s == '}' && !iselse(s)))
  2374.         return TRUE;
  2375.  
  2376.     while (*s)
  2377.     {
  2378.         if (iscomment(s))        /* at start of comment ignore rest of line */
  2379.             return FALSE;
  2380.         s = skip_string(s);
  2381.         if ((*s == ';' || *s == '{' || *s == ',') && commentorempty(s + 1))
  2382.             return TRUE;
  2383.         s++;
  2384.     }
  2385.     return FALSE;
  2386. }
  2387.  
  2388. /*
  2389.  * Recognize the basic picture of a function declaration -- it needs to
  2390.  * have an open paren somewhere and a close paren at the end of the line and
  2391.  * no semicolons anywhere.
  2392.  */
  2393.     static int
  2394. isfuncdecl(s)
  2395.     char_u *s;
  2396. {
  2397.     while (*s && *s != '(' && *s != ';')
  2398.         if (iscomment(s++))
  2399.             return FALSE;            /* comment before () ??? */
  2400.     if (*s != '(')
  2401.         return FALSE;                /* ';' before any () or no '(' */
  2402.  
  2403.     while (*s && *s != ';')
  2404.     {
  2405.         if (*s == ')' && commentorempty(s + 1))
  2406.             return TRUE;
  2407.         if (iscomment(s++))
  2408.             return FALSE;            /* comment between ( and ) ??? */
  2409.     }
  2410.     return FALSE;
  2411. }
  2412.  
  2413. /*
  2414.  * Skip over a "string" and a 'c' character.
  2415.  */
  2416.     static char_u *
  2417. skip_string(p)
  2418.     char_u    *p;
  2419. {
  2420.     int        i;
  2421.  
  2422.     /*
  2423.      * We loop, because strings may be concatenated: "date""time".
  2424.      */
  2425.     for ( ; ; ++p)
  2426.     {
  2427.         if (p[0] == '\'')                    /* 'c' or '\n' or '\000' */
  2428.         {
  2429.             if (!p[1])                        /* ' at end of line */
  2430.                 break;
  2431.             i = 2;
  2432.             if (p[1] == '\\')                /* '\n' or '\000' */
  2433.             {
  2434.                 ++i;
  2435.                 while (isdigit(p[i - 1]))    /* '\000' */
  2436.                     ++i;
  2437.             }
  2438.             if (p[i] == '\'')                /* check for trailing ' */
  2439.             {
  2440.                 p += i;
  2441.                 continue;
  2442.             }
  2443.         }
  2444.         else if (p[0] == '"')                /* start of string */
  2445.         {
  2446.             for (++p; p[0]; ++p)
  2447.             {
  2448.                 if (p[0] == '\\' && p[1])
  2449.                     ++p;
  2450.                 else if (p[0] == '"')        /* end of string */
  2451.                     break;
  2452.             }
  2453.             continue;
  2454.         }
  2455.         break;                                /* no string found */
  2456.     }
  2457.     if (!*p)
  2458.         --p;                                /* backup from NUL */
  2459.     return p;
  2460. }
  2461.  
  2462.     static int
  2463. isif(p)
  2464.     char_u    *p;
  2465. {
  2466.     return (STRNCMP(p, "if", 2) == 0 && !isidchar(p[2]));
  2467. }
  2468.  
  2469.     static int
  2470. iselse(p)
  2471.     char_u    *p;
  2472. {
  2473.     if (*p == '}')            /* accept "} else" */
  2474.         p = skipwhite(p + 1);
  2475.     return (STRNCMP(p, "else", 4) == 0 && !isidchar(p[4]));
  2476. }
  2477.  
  2478.     static int
  2479. isdo(p)
  2480.     char_u    *p;
  2481. {
  2482.     return (STRNCMP(p, "do", 2) == 0 && !isidchar(p[2]));
  2483. }
  2484.  
  2485. /*
  2486.  * Check if this is a "while" that should have a matching "do".
  2487.  * We only accept a "while (condition) ;", with only white space between the
  2488.  * ')' and ';'. The condition may be spread over several lines.
  2489.  */
  2490.     static int
  2491. iswhileofdo(p, lnum, ind_maxparen)            /* XXX */
  2492.     char_u        *p;
  2493.     linenr_t    lnum;
  2494.     int            ind_maxparen;
  2495. {
  2496.     FPOS        cursor_save;
  2497.     FPOS        *trypos;
  2498.     int            retval = FALSE;
  2499.  
  2500.     p = skipwhite(p);
  2501.     if (*p == '}')                /* accept "} while (cond);" */
  2502.         p = skipwhite(p + 1);
  2503.     if (STRNCMP(p, "while", 5) == 0 && !isidchar(p[5]))
  2504.     {
  2505.         cursor_save = curwin->w_cursor;
  2506.         curwin->w_cursor.lnum = lnum;
  2507.         curwin->w_cursor.col = 0;
  2508.         p = ml_get_curline();
  2509.         while (*p && *p != 'w')    /* skip any '}', until the 'w' of the "while" */
  2510.         {
  2511.             ++p;
  2512.             ++curwin->w_cursor.col;
  2513.         }
  2514.         if ((trypos = findmatchlimit(0, 0, ind_maxparen)) != NULL)
  2515.         {
  2516.             p = ml_get_pos(trypos) + 1;
  2517.             p = skipwhite(p);
  2518.             if (*p == ';')
  2519.                 retval = TRUE;
  2520.         }
  2521.         curwin->w_cursor = cursor_save;
  2522.     }
  2523.     return retval;
  2524. }
  2525.  
  2526. /*
  2527.  * Find the start of a comment, not knowing if we are in a comment right now.
  2528.  * Search starts at w_cursor.lnum and goes backwards.
  2529.  */
  2530.     static FPOS *
  2531. find_start_comment(ind_maxcomment)            /* XXX */
  2532.     int            ind_maxcomment;
  2533. {
  2534.     FPOS        *pos;
  2535.     char_u        *line;
  2536.     char_u        *p;
  2537.  
  2538.     if ((pos = findmatchlimit('*', FM_BACKWARD, ind_maxcomment)) == NULL)
  2539.         return NULL;
  2540.  
  2541.     /*
  2542.      * Check if the comment start we found is inside a string.
  2543.      */
  2544.     line = ml_get(pos->lnum);
  2545.     for (p = line; *p && (unsigned)(p - line) < pos->col; ++p)
  2546.         p = skip_string(p);
  2547.     if ((unsigned)(p - line) > pos->col)
  2548.         return NULL;
  2549.     return pos;
  2550. }
  2551.  
  2552. /*
  2553.  * Find the '{' at the start of the block we are in.
  2554.  * Return NULL of no match found.
  2555.  * Ignore a '{' that is in a comment, makes indenting the next three lines
  2556.  * work. */
  2557. /* foo()    */
  2558. /* {        */
  2559. /* }        */
  2560.  
  2561.     static FPOS *
  2562. find_start_brace(ind_maxcomment)            /* XXX */
  2563.     int            ind_maxcomment;
  2564. {
  2565.     FPOS        cursor_save;
  2566.     FPOS        *trypos;
  2567.     FPOS        *pos;
  2568.     static FPOS    pos_copy;
  2569.  
  2570.     cursor_save = curwin->w_cursor;
  2571.     while ((trypos = findmatchlimit('{', FM_BLOCKSTOP, 0)) != NULL)
  2572.     {
  2573.         pos_copy = *trypos;        /* copy FPOS, next findmatch will change it */
  2574.         trypos = &pos_copy;
  2575.         curwin->w_cursor = *trypos;
  2576.         pos = NULL;
  2577.         if (!iscomment(skipwhite(ml_get(trypos->lnum))) &&
  2578.                  (pos = find_start_comment(ind_maxcomment)) == NULL) /* XXX */
  2579.             break;
  2580.         if (pos != NULL)
  2581.             curwin->w_cursor.lnum = pos->lnum;
  2582.     }
  2583.     curwin->w_cursor = cursor_save;
  2584.     return trypos;
  2585. }
  2586.  
  2587. /*
  2588.  * Find the matching '(', failing if it is in a comment.
  2589.  * Return NULL of no match found.
  2590.  */
  2591.     static FPOS *
  2592. find_match_paren(ind_maxparen, ind_maxcomment)        /* XXX */
  2593.     int            ind_maxparen;
  2594.     int            ind_maxcomment;
  2595. {
  2596.     FPOS        cursor_save;
  2597.     FPOS        *trypos;
  2598.     static FPOS    pos_copy;
  2599.  
  2600.     cursor_save = curwin->w_cursor;
  2601.     if ((trypos = findmatchlimit('(', 0, ind_maxparen)) != NULL)
  2602.     {
  2603.         if (iscomment(skipwhite(ml_get(trypos->lnum))))
  2604.             trypos = NULL;
  2605.         else
  2606.         {
  2607.             pos_copy = *trypos;        /* copy trypos, findmatch will change it */
  2608.             trypos = &pos_copy;
  2609.             curwin->w_cursor = *trypos;
  2610.             if (find_start_comment(ind_maxcomment) != NULL)    /* XXX */
  2611.                 trypos = NULL;
  2612.         }
  2613.     }
  2614.     curwin->w_cursor = cursor_save;
  2615.     return trypos;
  2616. }
  2617.  
  2618. /*
  2619.  * Set w_cursor.col to the column number of the last ')' in line "l".
  2620.  */
  2621.     static int
  2622. find_last_paren(l)
  2623.     char_u *l;
  2624. {
  2625.     int        i;
  2626.     int        retval = FALSE;
  2627.  
  2628.     curwin->w_cursor.col = 0;                /* default is start of line */
  2629.  
  2630.     for (i = 0; l[i]; i++)
  2631.     {
  2632.         i = skip_string(l + i) - l;            /* ignore parens in quotes */
  2633.         if (l[i] == ')')
  2634.         {
  2635.             curwin->w_cursor.col = i;
  2636.             retval = TRUE;
  2637.         }
  2638.     }
  2639.     return retval;
  2640. }
  2641.  
  2642.     int
  2643. get_c_indent()
  2644. {
  2645.     /*
  2646.      * spaces from a block's opening brace the prevailing indent for that
  2647.      * block should be
  2648.      */
  2649.     int ind_level = curbuf->b_p_sw;
  2650.  
  2651.     /*
  2652.      * spaces from the edge of the line an open brace that's at the end of a
  2653.      * line is imagined to be.
  2654.      */
  2655.     int ind_open_imag = 0;
  2656.  
  2657.     /*
  2658.      * spaces from the prevailing indent for a line that is not precededof by
  2659.      * an opening brace.
  2660.      */
  2661.     int ind_no_brace = 0;
  2662.  
  2663.     /*
  2664.      * column where the first { of a function should be located
  2665.      */
  2666.     int ind_first_open = 0;
  2667.  
  2668.     /*
  2669.      * spaces from the prevailing indent a leftmost open brace should be
  2670.      * located
  2671.      */
  2672.     int ind_open_extra = 0;
  2673.  
  2674.     /*
  2675.      * spaces from the matching open brace (real location for one at the left
  2676.      * edge; imaginary location from one that ends a line) the matching close
  2677.      * brace should be located
  2678.      */
  2679.     int ind_close_extra = 0;
  2680.  
  2681.     /*
  2682.      * spaces from the edge of the line an open brace sitting in the leftmost
  2683.      * column is imagined to be
  2684.      */
  2685.     int ind_open_left_imag = 0;
  2686.  
  2687.     /*
  2688.      * spaces from the switch() indent a "case xx" label should be located
  2689.      */
  2690.     int ind_case = curbuf->b_p_sw;
  2691.  
  2692.     /*
  2693.      * spaces from the "case xx:" code after a switch() should be located
  2694.      */
  2695.     int ind_case_code = curbuf->b_p_sw;
  2696.  
  2697.     /*
  2698.      * amount K&R-style parameters should be indented
  2699.      */
  2700.     int ind_param = curbuf->b_p_sw;
  2701.  
  2702.     /*
  2703.      * amount a function type spec should be indented
  2704.      */
  2705.     int ind_func_type = curbuf->b_p_sw;
  2706.  
  2707.     /*
  2708.      * additional spaces beyond the prevailing indent a continuation line
  2709.      * should be located
  2710.      */
  2711.     int ind_continuation = curbuf->b_p_sw;
  2712.  
  2713.     /*
  2714.      * spaces from the indent of the line with an unclosed parentheses
  2715.      */
  2716.     int ind_unclosed = curbuf->b_p_sw * 2;
  2717.  
  2718.     /*
  2719.      * spaces from the comment opener when there is nothing after it.
  2720.      */
  2721.     int ind_in_comment = 3;
  2722.  
  2723.     /*
  2724.      * max lines to search for an open paren
  2725.      */
  2726.     int ind_maxparen = 20;
  2727.  
  2728.     /*
  2729.      * max lines to search for an open comment
  2730.      */
  2731.     int ind_maxcomment = 30;
  2732.  
  2733.     FPOS        cur_curpos;
  2734.     int            amount;
  2735.     int            scope_amount;
  2736.     int            cur_amount;
  2737.     colnr_t        col;
  2738.     char_u        *theline;
  2739.     char_u        *linecopy;
  2740.     FPOS        *trypos;
  2741.     FPOS        our_paren_pos;
  2742.     char_u        *start;
  2743.     int            start_brace;
  2744. #define BRACE_IN_COL0    1            /* '{' is in comumn 0 */
  2745. #define BRACE_AT_START    2            /* '{' is at start of line */
  2746. #define BRACE_AT_END    3            /* '{' is at end of line */
  2747.     linenr_t    ourscope;
  2748.     char_u        *l;
  2749.     char_u        *look;
  2750.     int            lookfor;
  2751. #define LOOKFOR_IF        1
  2752. #define LOOKFOR_DO        2
  2753. #define LOOKFOR_CASE    3
  2754. #define LOOKFOR_ANY        4
  2755. #define LOOKFOR_TERM    5
  2756. #define LOOKFOR_UNTERM    6
  2757.     int            whilelevel;
  2758.     linenr_t    lnum;
  2759.     char_u        *options;
  2760.     int            fraction = 0;        /* init for GCC */
  2761.     int            divider;
  2762.     int            n;
  2763.  
  2764.     for (options = curbuf->b_p_cino; *options; )
  2765.     {
  2766.         l = options++;
  2767.         if (*options == '-')
  2768.             ++options;
  2769.         n = getdigits(&options);
  2770.         divider = 0;
  2771.         if (*options == '.')        /* ".5s" means a fraction */
  2772.         {
  2773.             fraction = atol((char *)++options);
  2774.             while (isdigit(*options))
  2775.             {
  2776.                 ++options;
  2777.                 if (divider)
  2778.                     divider *= 10;
  2779.                 else
  2780.                     divider = 10;
  2781.             }
  2782.         }
  2783.         if (*options == 's')        /* "2s" means two times 'shiftwidth' */
  2784.         {
  2785.             if (n == 0 && fraction == 0)
  2786.                 n = curbuf->b_p_sw;        /* just "s" is one 'shiftwidth' */
  2787.             else
  2788.             {
  2789.                 n *= curbuf->b_p_sw;
  2790.                 if (divider)
  2791.                     n += (curbuf->b_p_sw * fraction + divider / 2) / divider;
  2792.             }
  2793.             ++options;
  2794.         }
  2795.         if (l[1] == '-')
  2796.             n = -n;
  2797.         switch (*l)
  2798.         {
  2799.             case '>': ind_level = n; break;
  2800.             case 'e': ind_open_imag = n; break;
  2801.             case 'n': ind_no_brace = n; break;
  2802.             case 'f': ind_first_open = n; break;
  2803.             case '{': ind_open_extra = n; break;
  2804.             case '}': ind_close_extra = n; break;
  2805.             case '^': ind_open_left_imag = n; break;
  2806.             case ':': ind_case = n; break;
  2807.             case '=': ind_case_code = n; break;
  2808.             case 'p': ind_param = n; break;
  2809.             case 't': ind_func_type = n; break;
  2810.             case 'c': ind_in_comment = n; break;
  2811.             case '+': ind_continuation = n; break;
  2812.             case '(': ind_unclosed = n; break;
  2813.             case ')': ind_maxparen = n; break;
  2814.             case '*': ind_maxcomment = n; break;
  2815.         }
  2816.     }
  2817.  
  2818.     /* remember where the cursor was when we started */
  2819.  
  2820.     cur_curpos = curwin->w_cursor;
  2821.  
  2822.     /* get the current contents of the line.
  2823.      * This is required, because onle the most recent line obtained with
  2824.      * ml_get is valid! */
  2825.  
  2826.     linecopy = strsave(ml_get(cur_curpos.lnum));
  2827.     if (linecopy == NULL)
  2828.         return 0;
  2829.  
  2830.     /*
  2831.      * In insert mode and the cursor is on a ')' trunctate the line at the
  2832.      * cursor position.  We don't want to line up with the matching '(' when
  2833.      * inserting new stuff.
  2834.      */
  2835.     if ((State & INSERT) && linecopy[curwin->w_cursor.col] == ')')
  2836.         linecopy[curwin->w_cursor.col] = NUL;
  2837.  
  2838.     theline = skipwhite(linecopy);
  2839.  
  2840.     /* move the cursor to the start of the line */
  2841.  
  2842.     curwin->w_cursor.col = 0;
  2843.  
  2844.     /*
  2845.      * #defines and so on always go at the left when included in 'cinkeys'.
  2846.      */
  2847.     if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
  2848.     {
  2849.         amount = 0;
  2850.     }
  2851.  
  2852.     /* 
  2853.      * Is it a non-case label?  Then that goes at the left margin too.
  2854.        */
  2855.     else if (islabel(ind_maxcomment))        /* XXX */
  2856.     {
  2857.         amount = 0;
  2858.     }
  2859.  
  2860.     /* 
  2861.      * If we're inside a comment and not looking at the start of the
  2862.      * comment...
  2863.      */
  2864.     else if (!iscomment(theline) &&
  2865.               (trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  2866.     {
  2867.  
  2868.         /* find how indented the line beginning the comment is */
  2869.         getvcol(curwin, trypos, &col, NULL, NULL);
  2870.         amount = col;
  2871.  
  2872.         /* if our line starts with an asterisk, line up with the
  2873.          * asterisk in the comment opener; otherwise, line up
  2874.          * with the first character of the comment text.
  2875.          */
  2876.         if (theline[0] == '*')
  2877.         {
  2878.             amount += 1;
  2879.         }
  2880.         else
  2881.         {
  2882.             /*
  2883.              * If we are more than one line away from the comment opener, take
  2884.              * the indent of the previous non-empty line.
  2885.              * If we are just below the comment opener and there are any
  2886.              * white characters after it line up with the text after it.
  2887.              * up with them; otherwise, just use a single space.
  2888.              */
  2889.             amount = -1;
  2890.             for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
  2891.             {
  2892.                 if (linewhite(lnum))                /* skip blank lines */
  2893.                     continue;
  2894.                 amount = get_indent_lnum(lnum);        /* XXX */
  2895.                 break;
  2896.             }
  2897.             if (amount == -1)                        /* use the comment opener */
  2898.             {
  2899.                 start = ml_get(trypos->lnum);
  2900.                 look = start + trypos->col + 2;      /* skip / and * */
  2901.                 if (*look)                            /* if something after it */
  2902.                     trypos->col = skipwhite(look) - start;
  2903.                 getvcol(curwin, trypos, &col, NULL, NULL);
  2904.                 amount = col;
  2905.                 if (!*look)
  2906.                     amount += ind_in_comment;
  2907.             }
  2908.         }
  2909.     }
  2910.  
  2911.     /*
  2912.      * Are we inside parentheses?
  2913.      */                                                /* XXX */
  2914.     else if ((trypos = find_match_paren(ind_maxparen, ind_maxcomment)) != NULL)
  2915.     {
  2916.         /*
  2917.          * If the matching paren is more than one line away, use the indent of
  2918.          * a previous non-empty line that matches the same paren.
  2919.          */
  2920.         amount = -1;
  2921.         our_paren_pos = *trypos;
  2922.         if (theline[0] != ')')
  2923.         {
  2924.             for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
  2925.             {
  2926.                 l = skipwhite(ml_get(lnum));
  2927.                 if (commentorempty(l))        /* skip comment lines */
  2928.                     continue;
  2929.                 if (ispreproc(l))            /* ignore #defines, #if, etc. */
  2930.                     continue;
  2931.                 curwin->w_cursor.lnum = lnum;
  2932.  
  2933.                 /* Skip a comment. XXX */
  2934.                 if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  2935.                 {
  2936.                     lnum = trypos->lnum + 1;
  2937.                     continue;
  2938.                 }
  2939.  
  2940.                 /* XXX */
  2941.                 if ((trypos = find_match_paren(ind_maxparen,
  2942.                                                    ind_maxcomment)) != NULL &&
  2943.                                          trypos->lnum == our_paren_pos.lnum &&
  2944.                                              trypos->col == our_paren_pos.col)
  2945.                 {
  2946.                     amount = get_indent_lnum(lnum);        /* XXX */
  2947.                     break;
  2948.                 }
  2949.             }
  2950.         }
  2951.  
  2952.         /*
  2953.          * Line up with line where the matching paren is.
  2954.          * If the line starts with a '(' or the indent for unclosed
  2955.          * parentheses is zero, line up with the unclosed parentheses.
  2956.          */
  2957.         if (amount == -1)
  2958.         {
  2959.             amount = skip_label(our_paren_pos.lnum, &look, ind_maxcomment);
  2960.             if (theline[0] == ')' || ind_unclosed == 0 ||
  2961.                                                       *skipwhite(look) == '(')
  2962.             {
  2963.  
  2964.                 /* 
  2965.                  * If we're looking at a close paren, line up right there;
  2966.                  * otherwise, line up with the next non-white character.
  2967.                  */
  2968.                 if (theline[0] != ')')
  2969.                 {
  2970.                     col = our_paren_pos.col + 1;
  2971.                     look = ml_get(our_paren_pos.lnum);
  2972.                     while (vim_iswhite(look[col]))
  2973.                         col++;
  2974.                     if (look[col] != NUL)        /* In case of trailing space */
  2975.                         our_paren_pos.col = col;
  2976.                     else
  2977.                         our_paren_pos.col++;
  2978.                 }
  2979.  
  2980.                 /*
  2981.                  * Find how indented the paren is, or the character after it if
  2982.                  * we did the above "if".
  2983.                  */
  2984.                 getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
  2985.                 amount = col;
  2986.             }
  2987.             else
  2988.                 amount += ind_unclosed;
  2989.         }
  2990.     }
  2991.  
  2992.     /*
  2993.      * Are we at least inside braces, then?
  2994.      */
  2995.     else if ((trypos = find_start_brace(ind_maxcomment)) != NULL) /* XXX */
  2996.     {
  2997.         ourscope = trypos->lnum;
  2998.         start = ml_get(ourscope);
  2999.  
  3000.         /* 
  3001.          * Now figure out how indented the line is in general.
  3002.          * If the brace was at the start of the line, we use that;
  3003.          * otherwise, check out the indentation of the line as
  3004.          * a whole and then add the "imaginary indent" to that.
  3005.          */
  3006.         look = skipwhite(start);
  3007.         if (*look == '{')
  3008.         {
  3009.             getvcol(curwin, trypos, &col, NULL, NULL);
  3010.             amount = col;
  3011.             if (*start == '{')
  3012.                 start_brace = BRACE_IN_COL0;
  3013.             else
  3014.                 start_brace = BRACE_AT_START;
  3015.         }
  3016.         else
  3017.         {
  3018.             /* 
  3019.              * that opening brace might have been on a continuation
  3020.              * line.  if so, find the start of the line.
  3021.              */
  3022.             curwin->w_cursor.lnum = ourscope;
  3023.  
  3024.             /* 
  3025.              * position the cursor over the rightmost paren, so that
  3026.              * matching it will take us back to the start of the line.
  3027.              */
  3028.             lnum = ourscope;
  3029.             if (find_last_paren(start) &&
  3030.                     (trypos = find_match_paren(ind_maxparen,
  3031.                                                      ind_maxcomment)) != NULL)
  3032.                 lnum = trypos->lnum;
  3033.  
  3034.             /*
  3035.              * It could have been something like
  3036.              *     case 1: if (asdf &&
  3037.              *                     ldfd) {
  3038.              *                 }
  3039.              */
  3040.             amount = skip_label(lnum, &l, ind_maxcomment);
  3041.  
  3042.             start_brace = BRACE_AT_END;
  3043.         }
  3044.  
  3045.         /* 
  3046.          * if we're looking at a closing brace, that's where
  3047.          * we want to be.  otherwise, add the amount of room
  3048.          * that an indent is supposed to be.
  3049.          */
  3050.         if (theline[0] == '}')
  3051.         {
  3052.             /* 
  3053.              * they may want closing braces to line up with something
  3054.              * other than the open brace.  indulge them, if so. 
  3055.              */
  3056.             amount += ind_close_extra;
  3057.         }
  3058.         else
  3059.         {
  3060.             /* 
  3061.              * If we're looking at an "else", try to find an "if"
  3062.              * to match it with.
  3063.              * If we're looking at a "while", try to find a "do"
  3064.              * to match it with.
  3065.              */
  3066.             lookfor = 0;
  3067.             if (iselse(theline))
  3068.                 lookfor = LOOKFOR_IF;
  3069.             else if (iswhileofdo(theline, cur_curpos.lnum, ind_maxparen))
  3070.                                                                     /* XXX */
  3071.                 lookfor = LOOKFOR_DO;
  3072.             if (lookfor)
  3073.             {
  3074.                 curwin->w_cursor.lnum = cur_curpos.lnum;
  3075.                 if (find_match(lookfor, ourscope, ind_maxparen,
  3076.                                                         ind_maxcomment) == OK)
  3077.                 {
  3078.                     amount = get_indent();        /* XXX */
  3079.                     goto theend;
  3080.                 }
  3081.             }
  3082.  
  3083.             /* 
  3084.              * We get here if we are not on an "while-of-do" or "else" (or
  3085.              * failed to find a matching "if").
  3086.              * Search backwards for something to line up with.
  3087.              * First set amount for when we don't find anything.
  3088.              */
  3089.  
  3090.             /* 
  3091.              * if the '{' is  _really_ at the left margin, use the imaginary
  3092.              * location of a left-margin brace.  Otherwise, correct the
  3093.              * location for ind_open_extra.
  3094.              */
  3095.  
  3096.             if (start_brace == BRACE_IN_COL0)        /* '{' is in column 0 */
  3097.             {
  3098.                 amount = ind_open_left_imag;
  3099.             }
  3100.             else 
  3101.             {
  3102.                 if (start_brace == BRACE_AT_END)    /* '{' is at end of line */
  3103.                     amount += ind_open_imag;
  3104.                 else
  3105.                 {
  3106.                     amount -= ind_open_extra;
  3107.                     if (amount < 0)
  3108.                         amount = 0;
  3109.                 }
  3110.             }
  3111.  
  3112.             if (iscase(theline))        /* it's a switch() label */
  3113.             {
  3114.                 lookfor = LOOKFOR_CASE;    /* find a previous switch() label */
  3115.                 amount += ind_case;
  3116.             }
  3117.             else
  3118.             {
  3119.                 lookfor = LOOKFOR_ANY;
  3120.                 amount += ind_level;    /* ind_level from start of block */
  3121.             }
  3122.             scope_amount = amount;
  3123.             whilelevel = 0;
  3124.  
  3125.             /*
  3126.              * Search backwards.  If we find something we recognize, line up
  3127.              * with that.
  3128.              *
  3129.              * if we're looking at an open brace, indent
  3130.              * the usual amount relative to the conditional
  3131.              * that opens the block.
  3132.              */
  3133.             curwin->w_cursor = cur_curpos;
  3134.             for (;;)
  3135.             {
  3136.                 curwin->w_cursor.lnum--;
  3137.                 curwin->w_cursor.col = 0;
  3138.  
  3139.                 /*
  3140.                  * If we went all the way back to the start of our scope, line
  3141.                  * up with it.
  3142.                  */
  3143.                 if (curwin->w_cursor.lnum <= ourscope)
  3144.                 {
  3145.                     if (lookfor == LOOKFOR_UNTERM)
  3146.                         amount += ind_continuation;
  3147.                     else if (lookfor != LOOKFOR_TERM)
  3148.                         amount = scope_amount;
  3149.                     break;
  3150.                 }
  3151.  
  3152.                 /*
  3153.                  * If we're in a comment now, skip to the start of the comment.
  3154.                  */                                            /* XXX */
  3155.                 if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3156.                 {
  3157.                     curwin->w_cursor.lnum = trypos->lnum + 1;
  3158.                     continue;
  3159.                 }
  3160.  
  3161.                 l = ml_get_curline();
  3162.  
  3163.                 /*
  3164.                  * If this is a switch() label, may line up relative to that.
  3165.                  */
  3166.                 if (iscase(l))
  3167.                 {
  3168.                     /*
  3169.                      *  case xx:
  3170.                      *         c = 99 +        <- this indent plus continuation
  3171.                      *->           here;
  3172.                      */
  3173.                     if (lookfor == LOOKFOR_UNTERM)
  3174.                     {
  3175.                         amount += ind_continuation;
  3176.                         break;
  3177.                     }
  3178.  
  3179.                     /*
  3180.                      *  case xx:        <- line up with this case
  3181.                      *      x = 333;
  3182.                      *  case yy:
  3183.                      */
  3184.                     if (lookfor == LOOKFOR_CASE)
  3185.                     {
  3186.                         /*
  3187.                          * Check that this case label is not for another
  3188.                          * switch()
  3189.                          */                                    /* XXX */
  3190.                         if ((trypos = find_start_brace(ind_maxcomment)) ==
  3191.                                              NULL || trypos->lnum == ourscope)
  3192.                         {
  3193.                             amount = get_indent();        /* XXX */
  3194.                             break;
  3195.                         }
  3196.                         continue;
  3197.                     }
  3198.  
  3199.                     n = get_indent_nolabel(curwin->w_cursor.lnum);  /* XXX */
  3200.  
  3201.                     /*
  3202.                      *   case xx: if (cond)            <- line up with this if
  3203.                      *                y = y + 1;
  3204.                      * ->         s = 99;
  3205.                      *
  3206.                      *   case xx:
  3207.                      *       if (cond)            <- line up with this line
  3208.                      *           y = y + 1;
  3209.                      * ->    s = 99;
  3210.                      */
  3211.                     if (lookfor == LOOKFOR_TERM)
  3212.                     {
  3213.                         if (n)
  3214.                             amount = n;
  3215.                         break;
  3216.                     }
  3217.  
  3218.                     /*
  3219.                      *   case xx: x = x + 1;        <- line up with this x
  3220.                      * ->         y = y + 1;
  3221.                      *
  3222.                      *   case xx: if (cond)            <- line up with this if
  3223.                      * ->              y = y + 1;
  3224.                      */
  3225.                     if (n)
  3226.                     {
  3227.                         amount = n;
  3228.                         l = after_label(ml_get_curline());
  3229.                         if (l != NULL && is_cinword(l))
  3230.                             amount += ind_level + ind_no_brace;
  3231.                         break;
  3232.                     }
  3233.  
  3234.                     /*
  3235.                      *   Try to get the indent of a statement before the
  3236.                      *   switch label.  If nothing is found, line up relative
  3237.                      *   to the switch label.
  3238.                      *       break;                <- may line up with this line
  3239.                      *   case xx:
  3240.                      * ->   y = 1;
  3241.                      */
  3242.                     scope_amount = get_indent() + ind_case_code;    /* XXX */
  3243.                     lookfor = LOOKFOR_ANY;
  3244.                     continue;
  3245.                 }
  3246.  
  3247.                 /*
  3248.                  * Looking for a switch() label, ignore other lines.
  3249.                  */
  3250.                 if (lookfor == LOOKFOR_CASE)
  3251.                     continue;
  3252.  
  3253.                 /*
  3254.                  * Ignore jump labels with nothing after them.
  3255.                  */
  3256.                 if (islabel(ind_maxcomment))
  3257.                 {
  3258.                     l = after_label(ml_get_curline());
  3259.                     if (l == NULL || commentorempty(l))
  3260.                         continue;
  3261.                 }
  3262.  
  3263.                 /*
  3264.                  * Ignore #defines, #if, etc.
  3265.                  * Ignore comment and empty lines.
  3266.                  * (need to get the line again, islabel() may have unlocked it)
  3267.                  */
  3268.                 l = ml_get_curline();
  3269.                 if (ispreproc(l) || commentorempty(l))
  3270.                     continue;
  3271.  
  3272.                 /*
  3273.                  * What happens next depends on the line being terminated.
  3274.                  */
  3275.                 if (!isterminated(l))
  3276.                 {
  3277.                     /* 
  3278.                      * if we're in the middle of a paren thing,
  3279.                      * go back to the line that starts it so
  3280.                      * we can get the right prevailing indent
  3281.                      *     if ( foo &&
  3282.                      *                 bar )
  3283.                      */
  3284.                     /* 
  3285.                      * position the cursor over the rightmost paren, so that
  3286.                      * matching it will take us back to the start of the line.
  3287.                      */
  3288.                     (void)find_last_paren(l);
  3289.                     if ((trypos = find_match_paren(ind_maxparen,
  3290.                                                      ind_maxcomment)) != NULL)
  3291.                     {
  3292.                         /*
  3293.                          * Check if we are on a case label now.  This is
  3294.                          * handled above.
  3295.                          *     case xx:  if ( asdf &&
  3296.                          *                      asdf)
  3297.                          */
  3298.                         curwin->w_cursor.lnum = trypos->lnum;
  3299.                         l = ml_get_curline();
  3300.                         if (iscase(l))
  3301.                         {
  3302.                             ++curwin->w_cursor.lnum;
  3303.                             continue;
  3304.                         }
  3305.                     }
  3306.  
  3307.                     /*
  3308.                      * Get indent and pointer to text for current line,
  3309.                      * ignoring any jump label.        XXX
  3310.                      */
  3311.                     cur_amount = skip_label(curwin->w_cursor.lnum,
  3312.                                                           &l, ind_maxcomment);
  3313.  
  3314.                     /*
  3315.                      * If this is just above the line we are indenting, and it
  3316.                      * starts with a '{', line it up with this line.
  3317.                      *             while (not)
  3318.                      * ->        {
  3319.                      *             }
  3320.                      */
  3321.                     if (lookfor != LOOKFOR_TERM && theline[0] == '{')
  3322.                     {
  3323.                         amount = cur_amount + ind_open_extra;
  3324.                         break;
  3325.                     }
  3326.  
  3327.                     /*
  3328.                      * Check if we are after an "if", "while", etc.
  3329.                      * Also allow "} else".
  3330.                      */
  3331.                     if (is_cinword(l) || iselse(l))
  3332.                     {
  3333.                         /*
  3334.                          * Found an unterminated line after an if (), line up
  3335.                          * with the last one.
  3336.                          *     if (cond)
  3337.                          *            100 +
  3338.                          * ->            here;
  3339.                          */
  3340.                         if (lookfor == LOOKFOR_UNTERM)
  3341.                         {
  3342.                             amount += ind_continuation;
  3343.                             break;
  3344.                         }
  3345.  
  3346.                         /*
  3347.                          * If this is just above the line we are indenting, we
  3348.                          * are finished.
  3349.                          *             while (not)
  3350.                          * ->            here;
  3351.                          * Otherwise this indent can be used when the line
  3352.                          * before this is terminated.
  3353.                          *         yyy;
  3354.                          *         if (stat)
  3355.                          *             while (not)
  3356.                          *                 xxx;
  3357.                          * ->    here;
  3358.                          */
  3359.                         amount = cur_amount;
  3360.                         if (lookfor != LOOKFOR_TERM)
  3361.                         {
  3362.                             amount += ind_level + ind_no_brace;
  3363.                             break;
  3364.                         }
  3365.  
  3366.                         /*
  3367.                          * Special trick: when expecting the while () after a
  3368.                          * do, line up with the while()
  3369.                          *     do
  3370.                          *          x = 1;
  3371.                          * ->  here
  3372.                          */
  3373.                         l = skipwhite(ml_get_curline());
  3374.                         if (isdo(l))
  3375.                         {
  3376.                             if (whilelevel == 0)
  3377.                                 break;
  3378.                             --whilelevel;
  3379.                         }
  3380.  
  3381.                         /*
  3382.                          * When searching for a terminated line, don't use the
  3383.                          * one between the "if" and the "else".
  3384.                          * Need to use the scope of this "else".  XXX 
  3385.                          */
  3386.                         if (iselse(l) &&
  3387.                                 ((trypos = find_start_brace(ind_maxcomment))
  3388.                                                                     == NULL ||
  3389.                                 find_match(LOOKFOR_IF, trypos->lnum,
  3390.                                         ind_maxparen, ind_maxcomment) == FAIL))
  3391.                             break;
  3392.                     }
  3393.  
  3394.                     /* 
  3395.                      * If we're below an unterminated line that is not an
  3396.                      * "if" or something, we may line up with this line or
  3397.                      * add someting for a continuation line, depending on
  3398.                      * the line before this one.
  3399.                      */
  3400.                     else
  3401.                     {
  3402.                         /*
  3403.                          * Found two unterminated lines on a row, line up with
  3404.                          * the last one.
  3405.                          *     c = 99 +
  3406.                          *            100 +
  3407.                          * ->        here;
  3408.                          */
  3409.                         if (lookfor == LOOKFOR_UNTERM)
  3410.                             break;
  3411.  
  3412.                         /*
  3413.                          * Found first unterminated line on a row, may line up
  3414.                          * with this line, remember its indent
  3415.                          *            100 +
  3416.                          * ->        here;
  3417.                          */
  3418.                         amount = cur_amount;
  3419.                         if (lookfor != LOOKFOR_TERM)
  3420.                             lookfor = LOOKFOR_UNTERM;
  3421.                     }
  3422.                 }
  3423.  
  3424.                 /*
  3425.                  * Check if we are after a while (cond);
  3426.                  * If so: Ignore until the matching "do".
  3427.                  */
  3428.                                                         /* XXX */
  3429.                 else if (iswhileofdo(l, curwin->w_cursor.lnum, ind_maxparen))
  3430.                 {
  3431.                     /*
  3432.                      * Found an unterminated line after a while ();, line up
  3433.                      * with the last one.
  3434.                      *        while (cond);
  3435.                      *        100 +                <- line up with this one
  3436.                      * ->            here;
  3437.                      */
  3438.                     if (lookfor == LOOKFOR_UNTERM)
  3439.                     {
  3440.                         amount += ind_continuation;
  3441.                         break;
  3442.                     }
  3443.  
  3444.                     if (whilelevel == 0)
  3445.                     {
  3446.                         lookfor = LOOKFOR_TERM;
  3447.                         amount = get_indent();        /* XXX */
  3448.                         if (theline[0] == '{')
  3449.                             amount += ind_open_extra;
  3450.                     }
  3451.                     ++whilelevel;
  3452.                 }
  3453.  
  3454.                 /*
  3455.                  * We are after a "normal" statement.
  3456.                  * If we had another statement we can stop now and use the
  3457.                  * indent of that other statement.
  3458.                  * Otherwise the indent of the current statement may be used,
  3459.                  * search backwards for the next "normal" statement.
  3460.                  */
  3461.                 else
  3462.                 {
  3463.                     /*
  3464.                      * Handle "do {" line.
  3465.                      */
  3466.                     if (whilelevel > 0)
  3467.                     {
  3468.                         l = skipwhite(ml_get_curline());
  3469.                         if (isdo(l))
  3470.                         {
  3471.                             amount = get_indent();        /* XXX */
  3472.                             --whilelevel;
  3473.                             continue;
  3474.                         }
  3475.                     }
  3476.  
  3477.                     /*
  3478.                      * Found a terminated line above an unterminated line. Add
  3479.                      * the amount for a continuation line.
  3480.                      *   x = 1;
  3481.                      *   y = foo +
  3482.                      * ->        here;
  3483.                      */
  3484.                     if (lookfor == LOOKFOR_UNTERM)
  3485.                     {
  3486.                         amount += ind_continuation;
  3487.                         break;
  3488.                     }
  3489.  
  3490.                     /*
  3491.                      * Found a terminated line above a terminated line or "if"
  3492.                      * etc. line. Use the amount of the line below us.
  3493.                      *   x = 1;                            x = 1;
  3494.                      *   if (asdf)                    y = 2;
  3495.                      *         while (asdf)         ->here;
  3496.                      *             here;
  3497.                      * ->foo;
  3498.                      */
  3499.                     if (lookfor == LOOKFOR_TERM)
  3500.                     {
  3501.                         if (whilelevel == 0)
  3502.                             break;
  3503.                     }
  3504.  
  3505.                     /*
  3506.                      * First line above the one we're indenting is terminated.
  3507.                      * To know what needs to be done look further backward for
  3508.                      * a terminated line.
  3509.                      */
  3510.                     else
  3511.                     {
  3512.                         /* 
  3513.                          * position the cursor over the rightmost paren, so
  3514.                          * that matching it will take us back to the start of
  3515.                          * the line.  Helps for:
  3516.                          *     func(asdr,
  3517.                          *            asdfasdf);
  3518.                          *     here;
  3519.                          */
  3520. term_again:
  3521.                         l = ml_get_curline();
  3522.                         if (find_last_paren(l) &&
  3523.                                 (trypos = find_match_paren(ind_maxparen,
  3524.                                                      ind_maxcomment)) != NULL)
  3525.                         {
  3526.                             /*
  3527.                              * Check if we are on a case label now.  This is
  3528.                              * handled above.
  3529.                              *     case xx:  if ( asdf &&
  3530.                              *                      asdf)
  3531.                              */
  3532.                             curwin->w_cursor.lnum = trypos->lnum;
  3533.                             l = ml_get_curline();
  3534.                             if (iscase(l))
  3535.                             {
  3536.                                 ++curwin->w_cursor.lnum;
  3537.                                 continue;
  3538.                             }
  3539.                         }
  3540.  
  3541.                         /*
  3542.                          * Get indent and pointer to text for current line,
  3543.                          * ignoring any jump label.
  3544.                          */
  3545.                         amount = skip_label(curwin->w_cursor.lnum,
  3546.                                                           &l, ind_maxcomment);
  3547.  
  3548.                         if (theline[0] == '{')
  3549.                             amount += ind_open_extra;
  3550.                         lookfor = LOOKFOR_TERM;
  3551.  
  3552.                         /*
  3553.                          * If we're at the end of a block, skip to the start of
  3554.                          * that block.
  3555.                          */
  3556.                         curwin->w_cursor.col = 0;
  3557.                         if (*skipwhite(l) == '}' &&
  3558.                                    (trypos = find_start_brace(ind_maxcomment))
  3559.                                                             != NULL) /* XXX */
  3560.                         {
  3561.                             curwin->w_cursor.lnum = trypos->lnum;
  3562.                             goto term_again;
  3563.                         }
  3564.                     }
  3565.                 }
  3566.             }
  3567.         }
  3568.     }
  3569.  
  3570.     /* 
  3571.      * ok -- we're not inside any sort of structure at all!
  3572.      *
  3573.      * this means we're at the top level, and everything should
  3574.      * basically just match where the previous line is, except
  3575.      * for the lines immediately following a function declaration,
  3576.      * which are K&R-style parameters and need to be indented.
  3577.      */
  3578.     else
  3579.     {
  3580.         /* 
  3581.          * if our line starts with an open brace, forget about any 
  3582.          * prevailing indent and make sure it looks like the start 
  3583.          * of a function
  3584.          */
  3585.  
  3586.         if (theline[0] == '{')
  3587.         {
  3588.             amount = ind_first_open;
  3589.         }
  3590.  
  3591.         /* 
  3592.          * If the NEXT line is a function declaration, the current
  3593.          * line needs to be indented as a function type spec.
  3594.          * Don't do this if the current line looks like a comment.
  3595.          */
  3596.         else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count &&
  3597.                                                    !commentorempty(theline) &&
  3598.                                       isfuncdecl(ml_get(cur_curpos.lnum + 1)))
  3599.         {
  3600.             amount = ind_func_type;
  3601.         }
  3602.         else
  3603.         {
  3604.             amount = 0;
  3605.             curwin->w_cursor = cur_curpos;
  3606.  
  3607.             /* search backwards until we find something we recognize */
  3608.  
  3609.             while (curwin->w_cursor.lnum > 1)
  3610.             {
  3611.                 curwin->w_cursor.lnum--;
  3612.                 curwin->w_cursor.col = 0;
  3613.  
  3614.                 l = ml_get_curline();
  3615.  
  3616.                 /*
  3617.                  * If we're in a comment now, skip to the start of the comment.
  3618.                  */                                                /* XXX */
  3619.                 if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3620.                 {
  3621.                     curwin->w_cursor.lnum = trypos->lnum + 1;
  3622.                     continue;
  3623.                 }
  3624.  
  3625.                 /*
  3626.                  * If the line looks like a function declaration, and we're
  3627.                  * not in a comment, put it the left margin.
  3628.                  */
  3629.                 if (isfuncdecl(theline))
  3630.                     break;
  3631.  
  3632.                 /* 
  3633.                  * Skip preprocessor directives and blank lines.
  3634.                  */
  3635.                 if (ispreproc(l))
  3636.                     continue;
  3637.  
  3638.                 if (commentorempty(l))
  3639.                     continue;
  3640.  
  3641.                 /* 
  3642.                  * If the PREVIOUS line is a function declaration, the current
  3643.                  * line (and the ones that follow) needs to be indented as
  3644.                  * parameters.
  3645.                  */
  3646.                 if (isfuncdecl(l))
  3647.                 {
  3648.                     amount = ind_param;
  3649.                     break;
  3650.                 }
  3651.  
  3652.                 /* 
  3653.                  * Doesn't look like anything interesting -- so just
  3654.                  * use the indent of this line.
  3655.                  * 
  3656.                  * Position the cursor over the rightmost paren, so that
  3657.                  * matching it will take us back to the start of the line.
  3658.                  */
  3659.                 find_last_paren(l);
  3660.  
  3661.                 if ((trypos = find_match_paren(ind_maxparen,
  3662.                                                      ind_maxcomment)) != NULL)
  3663.                     curwin->w_cursor.lnum = trypos->lnum;
  3664.                 amount = get_indent();        /* XXX */
  3665.                 break;
  3666.             }
  3667.         }
  3668.     }
  3669.  
  3670. theend:
  3671.     /* put the cursor back where it belongs */
  3672.     curwin->w_cursor = cur_curpos;
  3673.  
  3674.     vim_free(linecopy);
  3675.  
  3676.     if (amount < 0)
  3677.         return 0;
  3678.     return amount;
  3679. }
  3680.  
  3681.     static int
  3682. find_match(lookfor, ourscope, ind_maxparen, ind_maxcomment)
  3683.     int            lookfor;
  3684.     linenr_t    ourscope;
  3685.     int            ind_maxparen;
  3686.     int            ind_maxcomment;
  3687. {
  3688.     char_u        *look;
  3689.     FPOS        *theirscope;
  3690.     char_u        *mightbeif;
  3691.     int            elselevel;
  3692.     int            whilelevel;
  3693.  
  3694.     if (lookfor == LOOKFOR_IF)
  3695.     {
  3696.         elselevel = 1;
  3697.         whilelevel = 0;
  3698.     }
  3699.     else
  3700.     {
  3701.         elselevel = 0;
  3702.         whilelevel = 1;
  3703.     }
  3704.  
  3705.     curwin->w_cursor.col = 0;
  3706.  
  3707.     while (curwin->w_cursor.lnum > ourscope + 1)
  3708.     {
  3709.         curwin->w_cursor.lnum--;
  3710.         curwin->w_cursor.col = 0;
  3711.  
  3712.         look = skipwhite(ml_get_curline());
  3713.         if (iselse(look) || isif(look) || isdo(look) ||
  3714.              iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))  /* XXX */
  3715.         {
  3716.             /* 
  3717.              * if we've gone outside the braces entirely,
  3718.              * we must be out of scope...
  3719.              */
  3720.             theirscope = find_start_brace(ind_maxcomment);    /* XXX */
  3721.             if (theirscope == NULL)
  3722.                 break;
  3723.  
  3724.             /* 
  3725.              * and if the brace enclosing this is further
  3726.              * back than the one enclosing the else, we're
  3727.              * out of luck too.
  3728.              */
  3729.             if (theirscope->lnum < ourscope)
  3730.                 break;
  3731.  
  3732.             /* 
  3733.              * and if they're enclosed in a *deeper* brace,
  3734.              * then we can ignore it because it's in a
  3735.              * different scope...
  3736.              */
  3737.             if (theirscope->lnum > ourscope)
  3738.                 continue;
  3739.  
  3740.             /* 
  3741.              * if it was an "else" (that's not an "else if")
  3742.              * then we need to go back to another if, so 
  3743.              * increment elselevel
  3744.              */
  3745.             look = skipwhite(ml_get_curline());
  3746.             if (iselse(look))
  3747.             {
  3748.                 mightbeif = skipwhite(look + 4);
  3749.                 if (!isif(mightbeif))
  3750.                     ++elselevel;
  3751.                 continue;
  3752.             }
  3753.  
  3754.             /* 
  3755.              * if it was a "while" then we need to go back to
  3756.              * another "do", so increment whilelevel.
  3757.              */
  3758.             if (iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))/* XXX */
  3759.             {
  3760.                 ++whilelevel;
  3761.                 continue;
  3762.             }
  3763.  
  3764.             /* If it's an "if" decrement elselevel */
  3765.             look = skipwhite(ml_get_curline());
  3766.             if (isif(look))
  3767.             {
  3768.                 elselevel--;
  3769.                 /*
  3770.                  * When looking for an "if" ignore "while"s that
  3771.                  * get in the way.
  3772.                  */
  3773.                 if (elselevel == 0 && lookfor == LOOKFOR_IF)
  3774.                     whilelevel = 0;
  3775.             }
  3776.  
  3777.             /* If it's a "do" decrement whilelevel */
  3778.             if (isdo(look))
  3779.                 whilelevel--;
  3780.  
  3781.             /* 
  3782.              * if we've used up all the elses, then
  3783.              * this must be the if that we want!
  3784.              * match the indent level of that if.
  3785.              */
  3786.             if (elselevel <= 0 && whilelevel <= 0)
  3787.             {
  3788.                 return OK;
  3789.             }
  3790.         }
  3791.     }
  3792.     return FAIL;
  3793. }
  3794.  
  3795. #endif /* CINDENT */
  3796.  
  3797. #ifdef LISPINDENT
  3798.     int
  3799. get_lisp_indent()
  3800. {
  3801.     FPOS        *pos, realpos;
  3802.     long        amount = 0;
  3803.     char_u        *that;
  3804.     colnr_t        col;
  3805.     colnr_t        maybe;
  3806.     colnr_t        firsttry;
  3807.  
  3808.  
  3809.     realpos = curwin->w_cursor;
  3810.     curwin->w_cursor.col = 0;
  3811.  
  3812.     if ((pos = findmatch('(')) != NULL)
  3813.     {
  3814.         curwin->w_cursor.lnum = pos->lnum;
  3815.         curwin->w_cursor.col = pos->col;
  3816.         col = pos->col;
  3817.  
  3818.         that = ml_get_curline();
  3819.         maybe = get_indent();        /* XXX */
  3820.  
  3821.         if (maybe == 0)
  3822.             amount = 2;
  3823.         else
  3824.         {
  3825.             while (*that && col)
  3826.             {
  3827.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3828.                 col--;
  3829.                 that++;
  3830.             }
  3831.  
  3832.              that++;
  3833.             amount++;
  3834.             firsttry = amount;
  3835.  
  3836.             /*
  3837.              * Go to the start of the second word.
  3838.              * If there is no second word, go back to firsttry.
  3839.              * Also stop at a '('.
  3840.              */
  3841.  
  3842.             while (vim_iswhite(*that))
  3843.             {
  3844.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3845.                 that++;
  3846.             }
  3847.             while (*that && !vim_iswhite(*that) && *that != '(')
  3848.             {
  3849.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3850.                 that++;
  3851.             }
  3852.             while (vim_iswhite(*that))
  3853.             {
  3854.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3855.                 that++;
  3856.             }
  3857.             if (! *that)
  3858.                 amount = firsttry;
  3859.         }
  3860.     }
  3861.     else    /* no matching '(' found, use indent of previous non-empty line */
  3862.     {
  3863.         while (curwin->w_cursor.lnum > 1)
  3864.         {
  3865.             --curwin->w_cursor.lnum;
  3866.             if (!linewhite(curwin->w_cursor.lnum))
  3867.                 break;
  3868.         }
  3869.         amount = get_indent();        /* XXX */
  3870.     }
  3871.  
  3872.     curwin->w_cursor = realpos;
  3873.  
  3874.     if (amount < 0)
  3875.         amount = 0;
  3876.     return (int)amount;
  3877. }
  3878. #endif /* LISPINDENT */
  3879.  
  3880. #if defined(UNIX) || defined(WIN32) || defined(__EMX__)
  3881. /*
  3882.  * Preserve files and exit.
  3883.  * When called IObuff must contain a message.
  3884.  */
  3885.     void
  3886. preserve_exit()
  3887. {
  3888.     BUF        *buf;
  3889.  
  3890. #ifdef USE_GUI
  3891.     if (gui.in_use)
  3892.     {
  3893.         gui.dying = TRUE;
  3894.         trash_output_buf();        /* trash any pending output */
  3895.     }
  3896.     else
  3897. #endif
  3898.     {
  3899.         windgoto((int)Rows - 1, 0);
  3900.  
  3901.         /*
  3902.          * Switch terminal mode back now, so these messages end up on the
  3903.          * "normal" screen (if there are two screens).
  3904.          */
  3905.         settmode(0);
  3906. #ifdef WIN32
  3907.         if (can_end_termcap_mode(FALSE) == TRUE)
  3908. #endif
  3909.             stoptermcap();
  3910.         flushbuf();
  3911.     }
  3912.  
  3913.     outstr(IObuff);
  3914.     screen_start();                    /* don't know where cursor is now */
  3915.     flushbuf();
  3916.  
  3917.     ml_close_notmod();                /* close all not-modified buffers */
  3918.  
  3919.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  3920.     {
  3921.         if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
  3922.         {
  3923.             OUTSTR("Vim: preserving files...\n");
  3924.             screen_start();            /* don't know where cursor is now */
  3925.             flushbuf();
  3926.             ml_sync_all(FALSE, FALSE);    /* preserve all swap files */
  3927.             break;
  3928.         }
  3929.     }
  3930.  
  3931.     ml_close_all(FALSE);            /* close all memfiles, without deleting */
  3932.  
  3933.     OUTSTR("Vim: Finished.\n");
  3934.  
  3935.     getout(1);
  3936. }
  3937. #endif /* defined(UNIX) || defined(WIN32) || defined(__EMX__) */
  3938.  
  3939. /*
  3940.  * return TRUE if "fname" exists.
  3941.  */
  3942.     int
  3943. vim_fexists(fname)
  3944.     char_u    *fname;
  3945. {
  3946.     struct stat st;
  3947.  
  3948.     if (stat((char *)fname, &st))
  3949.         return FALSE;
  3950.     return TRUE;
  3951. }
  3952.  
  3953. /*
  3954.  * Check for CTRL-C pressed, but only once in a while.
  3955.  * Should be used instead of mch_breakcheck() for functions that check for
  3956.  * each line in the file.  Calling mch_breakcheck() each time takes too much
  3957.  * time, because it can be a system call.
  3958.  */
  3959.  
  3960. #ifndef BREAKCHECK_SKIP
  3961. # define BREAKCHECK_SKIP 32
  3962. #endif
  3963.  
  3964.     void
  3965. line_breakcheck()
  3966. {
  3967.     static int    count = 0;
  3968.  
  3969.     if (++count == BREAKCHECK_SKIP)
  3970.     {
  3971.         count = 0;
  3972.         mch_breakcheck();
  3973.     }
  3974. }
  3975.  
  3976. /*
  3977.  * Free the list of files returned by ExpandWildCards() or other expansion
  3978.  * functions.
  3979.  */
  3980.     void
  3981. FreeWild(num, file)
  3982.     int        num;
  3983.     char_u    **file;
  3984. {
  3985.     if (file == NULL || num == 0)
  3986.         return;
  3987. #if defined(__EMX__) && defined(__ALWAYS_HAS_TRAILING_NULL_POINTER) /* XXX */
  3988.     /*
  3989.      * Is this still OK for when other functions than ExpandWildCards() have
  3990.      * been used???
  3991.      */
  3992.     _fnexplodefree((char **)file);
  3993. #else
  3994.     while (num--)
  3995.         vim_free(file[num]);
  3996.     vim_free(file);
  3997. #endif
  3998. }
  3999.  
  4000.