misc1.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:112k
源码类别:

编辑器/阅读器

开发平台:

DOS

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