home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / buffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-26  |  116.1 KB  |  4,996 lines

  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.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * buffer.c: functions for dealing with the buffer structure
  12.  */
  13.  
  14. /*
  15.  * The buffer list is a double linked list of all buffers.
  16.  * Each buffer can be in one of these states:
  17.  * never loaded: BF_NEVERLOADED is set, only the file name is valid
  18.  *   not loaded: b_ml.ml_mfp == NULL, no memfile allocated
  19.  *     hidden: b_nwindows == 0, loaded but not displayed in a window
  20.  *     normal: loaded and displayed in a window
  21.  *
  22.  * Instead of storing file names all over the place, each file name is
  23.  * stored in the buffer list. It can be referenced by a number.
  24.  *
  25.  * The current implementation remembers all file names ever used.
  26.  */
  27.  
  28.  
  29. #include "vim.h"
  30.  
  31. #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
  32. static char_u    *buflist_match __ARGS((regprog_T *prog, buf_T *buf));
  33. # define HAVE_BUFLIST_MATCH
  34. static char_u    *fname_match __ARGS((regprog_T *prog, char_u *name));
  35. #endif
  36. static void    buflist_setfpos __ARGS((buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options));
  37. static wininfo_T *find_wininfo __ARGS((buf_T *buf));
  38. #ifdef UNIX
  39. static buf_T    *buflist_findname_stat __ARGS((char_u *ffname, struct stat *st));
  40. static int    otherfile_buf __ARGS((buf_T *buf, char_u *ffname, struct stat *stp));
  41. static int    buf_same_ino __ARGS((buf_T *buf, struct stat *stp));
  42. #else
  43. static int    otherfile_buf __ARGS((buf_T *buf, char_u *ffname));
  44. #endif
  45. #ifdef FEAT_TITLE
  46. static int    ti_change __ARGS((char_u *str, char_u **last));
  47. #endif
  48. static void    free_buffer __ARGS((buf_T *));
  49. static void    free_buffer_stuff __ARGS((buf_T *buf, int free_options));
  50. static void    clear_wininfo __ARGS((buf_T *buf));
  51.  
  52. #ifdef UNIX
  53. # define dev_T dev_t
  54. #else
  55. # define dev_T unsigned
  56. #endif
  57.  
  58. /*
  59.  * Open current buffer, that is: open the memfile and read the file into memory
  60.  * return FAIL for failure, OK otherwise
  61.  */
  62.     int
  63. open_buffer(read_stdin, eap)
  64.     int        read_stdin;        /* read file from stdin */
  65.     exarg_T    *eap;            /* for forced 'ff' and 'fenc' or NULL */
  66. {
  67.     int        retval = OK;
  68. #ifdef FEAT_AUTOCMD
  69.     buf_T    *old_curbuf;
  70. #endif
  71.  
  72.     /*
  73.      * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
  74.      * When re-entering the same buffer, it should not change, because the
  75.      * user may have reset the flag by hand.
  76.      */
  77.     if (readonlymode && curbuf->b_ffname != NULL
  78.                     && (curbuf->b_flags & BF_NEVERLOADED))
  79.     curbuf->b_p_ro = TRUE;
  80.  
  81.     if (ml_open() == FAIL)
  82.     {
  83.     /*
  84.      * There MUST be a memfile, otherwise we can't do anything
  85.      * If we can't create one for the current buffer, take another buffer
  86.      */
  87.     close_buffer(NULL, curbuf, 0);
  88.     for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
  89.         if (curbuf->b_ml.ml_mfp != NULL)
  90.         break;
  91.     /*
  92.      * if there is no memfile at all, exit
  93.      * This is OK, since there are no changes to loose.
  94.      */
  95.     if (curbuf == NULL)
  96.     {
  97.         EMSG(_("E82: Cannot allocate any buffer, exiting..."));
  98.         getout(2);
  99.     }
  100.     EMSG(_("E83: Cannot allocate buffer, using other one..."));
  101.     enter_buffer(curbuf);
  102.     return FAIL;
  103.     }
  104.  
  105. #ifdef FEAT_AUTOCMD
  106.     /* The autocommands in readfile() may change the buffer, but only AFTER
  107.      * reading the file. */
  108.     old_curbuf = curbuf;
  109.     modified_was_set = FALSE;
  110. #endif
  111.  
  112.     /* mark cursor position as being invalid */
  113.     changed_line_abv_curs();
  114.  
  115.     if (curbuf->b_ffname != NULL
  116. #ifdef FEAT_NETBEANS_INTG
  117.         && netbeansReadFile
  118. #endif
  119.        )
  120.     {
  121. #ifdef FEAT_NETBEANS_INTG
  122.     int oldFire = netbeansFireChanges;
  123.  
  124.     netbeansFireChanges = 0;
  125. #endif
  126.     retval = readfile(curbuf->b_ffname, curbuf->b_fname,
  127.           (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW);
  128. #ifdef FEAT_NETBEANS_INTG
  129.     netbeansFireChanges = oldFire;
  130. #endif
  131.     /* Help buffer is filtered. */
  132.     if (curbuf->b_help)
  133.         fix_help_buffer();
  134.     }
  135.     else if (read_stdin)
  136.     {
  137.     int        save_bin = curbuf->b_p_bin;
  138.     linenr_T    line_count;
  139.  
  140.     /*
  141.      * First read the text in binary mode into the buffer.
  142.      * Then read from that same buffer and append at the end.  This makes
  143.      * it possible to retry when 'fileformat' or 'fileencoding' was
  144.      * guessed wrong.
  145.      */
  146.     curbuf->b_p_bin = TRUE;
  147.     retval = readfile(NULL, NULL, (linenr_T)0,
  148.           (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW + READ_STDIN);
  149.     curbuf->b_p_bin = save_bin;
  150.     if (retval == OK)
  151.     {
  152.         line_count = curbuf->b_ml.ml_line_count;
  153.         retval = readfile(NULL, NULL, (linenr_T)line_count,
  154.                 (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_BUFFER);
  155.         if (retval == OK)
  156.         {
  157.         /* Delete the binary lines. */
  158.         while (--line_count >= 0)
  159.             ml_delete((linenr_T)1, FALSE);
  160.         }
  161.         else
  162.         {
  163.         /* Delete the converted lines. */
  164.         while (curbuf->b_ml.ml_line_count > line_count)
  165.             ml_delete(line_count, FALSE);
  166.         }
  167.         /* Put the cursor on the first line. */
  168.         curwin->w_cursor.lnum = 1;
  169.         curwin->w_cursor.col = 0;
  170. #ifdef FEAT_AUTOCMD
  171. # ifdef FEAT_EVAL
  172.         apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
  173.                             curbuf, &retval);
  174. # else
  175.         apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
  176. # endif
  177. #endif
  178.     }
  179.     }
  180.  
  181.     /* if first time loading this buffer, init b_chartab[] */
  182.     if (curbuf->b_flags & BF_NEVERLOADED)
  183.     (void)buf_init_chartab(curbuf, FALSE);
  184.  
  185.     /*
  186.      * Set/reset the Changed flag first, autocmds may change the buffer.
  187.      * Apply the automatic commands, before processing the modelines.
  188.      * So the modelines have priority over auto commands.
  189.      */
  190.     /* When reading stdin, the buffer contents always needs writing, so set
  191.      * the changed flag.  Unless in readonly mode: "ls | gview -".
  192.      * When interrupted and 'cpoptions' contains 'i' set changed flag. */
  193.     if ((read_stdin && !readonlymode && !bufempty())
  194. #ifdef FEAT_AUTOCMD
  195.         || modified_was_set    /* ":set modified" used in autocmd */
  196. # ifdef FEAT_EVAL
  197.         || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
  198. # endif
  199. #endif
  200.         || (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL))
  201.     changed();
  202.     else if (retval != FAIL)
  203.     unchanged(curbuf, FALSE);
  204.     save_file_ff(curbuf);        /* keep this fileformat */
  205.  
  206.     /* require "!" to overwrite the file, because it wasn't read completely */
  207. #ifdef FEAT_EVAL
  208.     if (aborting())
  209. #else
  210.     if (got_int)
  211. #endif
  212.     curbuf->b_flags |= BF_READERR;
  213.  
  214. #ifdef FEAT_AUTOCMD
  215.     /* need to set w_topline, unless some autocommand already did that. */
  216.     if (!(curwin->w_valid & VALID_TOPLINE))
  217.     {
  218.     curwin->w_topline = 1;
  219. # ifdef FEAT_DIFF
  220.     curwin->w_topfill = 0;
  221. # endif
  222.     }
  223. # ifdef FEAT_EVAL
  224.     apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);
  225. # else
  226.     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  227. # endif
  228. #endif
  229.  
  230.     if (retval != FAIL)
  231.     {
  232. #ifdef FEAT_AUTOCMD
  233.     /*
  234.      * The autocommands may have changed the current buffer.  Apply the
  235.      * modelines to the correct buffer, if it still exists and is loaded.
  236.      */
  237.     if (buf_valid(old_curbuf) && old_curbuf->b_ml.ml_mfp != NULL)
  238.     {
  239.         aco_save_T    aco;
  240.  
  241.         /* Go to the buffer that was opened. */
  242.         aucmd_prepbuf(&aco, old_curbuf);
  243. #endif
  244.         do_modelines();
  245.         curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
  246.  
  247. #ifdef FEAT_AUTOCMD
  248. # ifdef FEAT_EVAL
  249.         apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
  250.                                     &retval);
  251. # else
  252.         apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
  253. # endif
  254.  
  255.         /* restore curwin/curbuf and a few other things */
  256.         aucmd_restbuf(&aco);
  257.     }
  258. #endif
  259.     }
  260.  
  261. #ifdef FEAT_FOLDING
  262.     /* Need to update automatic folding. */
  263.     foldUpdateAll(curwin);
  264. #endif
  265.  
  266.     return retval;
  267. }
  268.  
  269. /*
  270.  * Return TRUE if "buf" points to a valid buffer (in the buffer list).
  271.  */
  272.     int
  273. buf_valid(buf)
  274.     buf_T    *buf;
  275. {
  276.     buf_T    *bp;
  277.  
  278.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  279.     if (bp == buf)
  280.         return TRUE;
  281.     return FALSE;
  282. }
  283.  
  284. /*
  285.  * Close the link to a buffer.
  286.  * "action" is used when there is no longer a window for the buffer.
  287.  * It can be:
  288.  * 0            buffer becomes hidden
  289.  * DOBUF_UNLOAD        buffer is unloaded
  290.  * DOBUF_DELETE        buffer is unloaded and removed from buffer list
  291.  * DOBUF_WIPE        buffer is unloaded and really deleted
  292.  * When doing all but the first one on the current buffer, the caller should
  293.  * get a new buffer very soon!
  294.  *
  295.  * The 'bufhidden' option can force freeing and deleting.
  296.  */
  297.     void
  298. close_buffer(win, buf, action)
  299.     win_T    *win;        /* if not NULL, set b_last_cursor */
  300.     buf_T    *buf;
  301.     int        action;
  302. {
  303. #ifdef FEAT_AUTOCMD
  304.     int        is_curbuf;
  305.     int        nwindows = buf->b_nwindows;
  306. #endif
  307.     int        unload_buf = (action != 0);
  308.     int        del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
  309.     int        wipe_buf = (action == DOBUF_WIPE);
  310.  
  311. #ifdef FEAT_QUICKFIX
  312.     /*
  313.      * Force unloading or deleting when 'bufhidden' says so.
  314.      * The caller must take care of NOT deleting/freeing when 'bufhidden' is
  315.      * "hide" (otherwise we could never free or delete a buffer).
  316.      */
  317.     if (buf->b_p_bh[0] == 'd')        /* 'bufhidden' == "delete" */
  318.     {
  319.     del_buf = TRUE;
  320.     unload_buf = TRUE;
  321.     }
  322.     else if (buf->b_p_bh[0] == 'w')    /* 'bufhidden' == "wipe" */
  323.     {
  324.     del_buf = TRUE;
  325.     unload_buf = TRUE;
  326.     wipe_buf = TRUE;
  327.     }
  328.     else if (buf->b_p_bh[0] == 'u')    /* 'bufhidden' == "unload" */
  329.     unload_buf = TRUE;
  330. #endif
  331.  
  332.     if (win != NULL)
  333.     {
  334.     /* Set b_last_cursor when closing the last window for the buffer.
  335.      * Remember the last cursor position and window options of the buffer.
  336.      * This used to be only for the current window, but then options like
  337.      * 'foldmethod' may be lost with a ":only" command. */
  338.     if (buf->b_nwindows == 1)
  339.         set_last_cursor(win);
  340.     buflist_setfpos(buf, win,
  341.             win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
  342.             win->w_cursor.col, TRUE);
  343.     }
  344.  
  345. #ifdef FEAT_AUTOCMD
  346.     /* When the buffer is no longer in a window, trigger BufWinLeave */
  347.     if (buf->b_nwindows == 1)
  348.     {
  349.     apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
  350.                                   FALSE, buf);
  351.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  352.         return;
  353.  
  354.     /* When the buffer becomes hidden, but is not unloaded, trigger
  355.      * BufHidden */
  356.     if (!unload_buf)
  357.     {
  358.         apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
  359.                                   FALSE, buf);
  360.         if (!buf_valid(buf))    /* autocmds may delete the buffer */
  361.         return;
  362.     }
  363. # ifdef FEAT_EVAL
  364.     if (aborting())        /* autocmds may abort script processing */
  365.         return;
  366. # endif
  367.     }
  368.     nwindows = buf->b_nwindows;
  369. #endif
  370.  
  371.     /* decrease the link count from windows (unless not in any window) */
  372.     if (buf->b_nwindows > 0)
  373.     --buf->b_nwindows;
  374.  
  375.     /* Return when a window is displaying the buffer or when it's not
  376.      * unloaded. */
  377.     if (buf->b_nwindows > 0 || !unload_buf)
  378.     {
  379.     if (buf == curbuf)
  380.         u_sync();        /* sync undo before going to another buffer */
  381.     return;
  382.     }
  383.  
  384.     /* Always remove the buffer when there is no file name. */
  385.     if (buf->b_ffname == NULL)
  386.     del_buf = TRUE;
  387.  
  388.     /*
  389.      * Free all things allocated for this buffer.
  390.      * Also calls the "BufDelete" autocommands when del_buf is TRUE.
  391.      */
  392. #ifdef FEAT_AUTOCMD
  393.     /* Remember if we are closing the current buffer.  Restore the number of
  394.      * windows, so that autocommands in buf_freeall() don't get confused. */
  395.     is_curbuf = (buf == curbuf);
  396.     buf->b_nwindows = nwindows;
  397. #endif
  398.  
  399.     buf_freeall(buf, del_buf, wipe_buf);
  400.  
  401. #ifdef FEAT_AUTOCMD
  402.     /* Autocommands may have deleted the buffer. */
  403.     if (!buf_valid(buf))
  404.     return;
  405. # ifdef FEAT_EVAL
  406.     /* Autocommands may abort script processing. */
  407.     if (aborting())
  408.     return;
  409. # endif
  410.  
  411.     /* Autocommands may have opened or closed windows for this buffer.
  412.      * Decrement the count for the close we do here. */
  413.     if (buf->b_nwindows > 0)
  414.     --buf->b_nwindows;
  415.  
  416.     /*
  417.      * It's possible that autocommands change curbuf to the one being deleted.
  418.      * This might cause the previous curbuf to be deleted unexpectedly.  But
  419.      * in some cases it's OK to delete the curbuf, because a new one is
  420.      * obtained anyway.  Therefore only return if curbuf changed to the
  421.      * deleted buffer.
  422.      */
  423.     if (buf == curbuf && !is_curbuf)
  424.     return;
  425. #endif
  426.  
  427. #ifdef FEAT_NETBEANS_INTG
  428.     if (usingNetbeans)
  429.     netbeans_file_closed(buf);
  430. #endif
  431. #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_SUN_WORKSHOP)
  432.     /* Change directories when the acd option is set on. */
  433.     if (p_acd && curbuf->b_ffname != NULL
  434.                      && vim_chdirfile(curbuf->b_ffname) == OK)
  435.     shorten_fnames(TRUE);
  436. #endif
  437.  
  438.     /*
  439.      * Remove the buffer from the list.
  440.      */
  441.     if (wipe_buf)
  442.     {
  443. #ifdef FEAT_SUN_WORKSHOP
  444.     if (usingSunWorkShop)
  445.         workshop_file_closed_lineno((char *)buf->b_ffname,
  446.             (int)buf->b_last_cursor.lnum);
  447. #endif
  448.     vim_free(buf->b_ffname);
  449.     vim_free(buf->b_sfname);
  450.     if (buf->b_prev == NULL)
  451.         firstbuf = buf->b_next;
  452.     else
  453.         buf->b_prev->b_next = buf->b_next;
  454.     if (buf->b_next == NULL)
  455.         lastbuf = buf->b_prev;
  456.     else
  457.         buf->b_next->b_prev = buf->b_prev;
  458.     free_buffer(buf);
  459.     }
  460.     else
  461.     {
  462.     if (del_buf)
  463.     {
  464.         /* Free all internal variables and reset option values, to make
  465.          * ":bdel" compatible with Vim 5.7. */
  466.         free_buffer_stuff(buf, TRUE);
  467.  
  468.         /* Make it look like a new buffer. */
  469.         buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
  470.  
  471.         /* Init the options when loaded again. */
  472.         buf->b_p_initialized = FALSE;
  473.     }
  474.     buf_clear_file(buf);
  475.     if (del_buf)
  476.         buf->b_p_bl = FALSE;
  477.     }
  478. }
  479.  
  480. /*
  481.  * Make buffer not contain a file.
  482.  */
  483.     void
  484. buf_clear_file(buf)
  485.     buf_T    *buf;
  486. {
  487.     buf->b_ml.ml_line_count = 1;
  488.     unchanged(buf, TRUE);
  489. #ifndef SHORT_FNAME
  490.     buf->b_shortname = FALSE;
  491. #endif
  492.     buf->b_p_eol = TRUE;
  493.     buf->b_start_eol = TRUE;
  494. #ifdef FEAT_MBYTE
  495.     buf->b_p_bomb = FALSE;
  496. #endif
  497.     buf->b_ml.ml_mfp = NULL;
  498.     buf->b_ml.ml_flags = ML_EMPTY;        /* empty buffer */
  499. #ifdef FEAT_NETBEANS_INTG
  500.     netbeans_deleted_all_lines(buf);
  501.     netbeansOpenFile = 0;  /* reset in netbeans_file_opened() */
  502. #endif
  503. }
  504.  
  505. /*
  506.  * buf_freeall() - free all things allocated for a buffer that are related to
  507.  * the file.
  508.  */
  509. /*ARGSUSED*/
  510.     void
  511. buf_freeall(buf, del_buf, wipe_buf)
  512.     buf_T    *buf;
  513.     int        del_buf;    /* buffer is going to be deleted */
  514.     int        wipe_buf;    /* buffer is going to be wiped out */
  515. {
  516. #ifdef FEAT_AUTOCMD
  517.     int        is_curbuf = (buf == curbuf);
  518.  
  519.     apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf);
  520.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  521.     return;
  522.     if (del_buf && buf->b_p_bl)
  523.     {
  524.     apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, FALSE, buf);
  525.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  526.         return;
  527.     }
  528.     if (wipe_buf)
  529.     {
  530.     apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
  531.                                   FALSE, buf);
  532.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  533.         return;
  534.     }
  535. # ifdef FEAT_EVAL
  536.     if (aborting())        /* autocmds may abort script processing */
  537.     return;
  538. # endif
  539.  
  540.     /*
  541.      * It's possible that autocommands change curbuf to the one being deleted.
  542.      * This might cause curbuf to be deleted unexpectedly.  But in some cases
  543.      * it's OK to delete the curbuf, because a new one is obtained anyway.
  544.      * Therefore only return if curbuf changed to the deleted buffer.
  545.      */
  546.     if (buf == curbuf && !is_curbuf)
  547.     return;
  548. #endif
  549. #ifdef FEAT_DIFF
  550.     diff_buf_delete(buf);        /* Can't use 'diff' for unloaded buffer. */
  551. #endif
  552. #ifdef FEAT_TCL
  553.     tcl_buffer_free(buf);
  554. #endif
  555.     u_blockfree(buf);            /* free the memory allocated for undo */
  556.     ml_close(buf, TRUE);        /* close and delete the memline/memfile */
  557.     buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
  558.     u_clearall(buf);            /* reset all undo information */
  559. #ifdef FEAT_SYN_HL
  560.     syntax_clear(buf);            /* reset syntax info */
  561. #endif
  562. }
  563.  
  564. /*
  565.  * Free a buffer structure and the things it contains related to the buffer
  566.  * itself (not the file, that must have been done already).
  567.  */
  568.     static void
  569. free_buffer(buf)
  570.     buf_T    *buf;
  571. {
  572.     free_buffer_stuff(buf, TRUE);
  573. #ifdef FEAT_PERL
  574.     perl_buf_free(buf);
  575. #endif
  576. #ifdef FEAT_PYTHON
  577.     python_buffer_free(buf);
  578. #endif
  579. #ifdef FEAT_RUBY
  580.     ruby_buffer_free(buf);
  581. #endif
  582.     vim_free(buf);
  583. }
  584.  
  585. /*
  586.  * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
  587.  */
  588.     static void
  589. free_buffer_stuff(buf, free_options)
  590.     buf_T    *buf;
  591.     int        free_options;        /* free options as well */
  592. {
  593.     if (free_options)
  594.     {
  595.     clear_wininfo(buf);        /* including window-local options */
  596.     free_buf_options(buf, TRUE);
  597.     }
  598. #ifdef FEAT_EVAL
  599.     var_clear(&buf->b_vars);        /* free all internal variables */
  600. #endif
  601. #ifdef FEAT_USR_CMDS
  602.     uc_clear(&buf->b_ucmds);        /* clear local user commands */
  603. #endif
  604. #ifdef FEAT_LOCALMAP
  605.     map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE);  /* clear local mappings */
  606.     map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE);   /* clear local abbrevs */
  607. #endif
  608. #ifdef FEAT_MBYTE
  609.     vim_free(buf->b_start_fenc);
  610.     buf->b_start_fenc = NULL;
  611. #endif
  612. }
  613.  
  614. /*
  615.  * Free the b_wininfo list for buffer "buf".
  616.  */
  617.     static void
  618. clear_wininfo(buf)
  619.     buf_T    *buf;
  620. {
  621.     wininfo_T    *wip;
  622.  
  623.     while (buf->b_wininfo != NULL)
  624.     {
  625.     wip = buf->b_wininfo;
  626.     buf->b_wininfo = wip->wi_next;
  627.     if (wip->wi_optset)
  628.     {
  629.         clear_winopt(&wip->wi_opt);
  630. #ifdef FEAT_FOLDING
  631.         deleteFoldRecurse(&wip->wi_folds);
  632. #endif
  633.     }
  634.     vim_free(wip);
  635.     }
  636. }
  637.  
  638. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  639. /*
  640.  * Go to another buffer.  Handles the result of the ATTENTION dialog.
  641.  */
  642.     void
  643. goto_buffer(eap, start, dir, count)
  644.     exarg_T    *eap;
  645.     int        start;
  646.     int        dir;
  647.     int        count;
  648. {
  649. # if defined(FEAT_WINDOWS) \
  650.         && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  651.     buf_T    *old_curbuf = curbuf;
  652.  
  653.     swap_exists_action = SEA_DIALOG;
  654. # endif
  655.     (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
  656.                          start, dir, count, eap->forceit);
  657. # if defined(FEAT_WINDOWS) \
  658.         && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  659.     if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
  660.     {
  661.     /* Quitting means closing the split window, nothing else. */
  662.     win_close(curwin, TRUE);
  663.     swap_exists_action = SEA_NONE;
  664.     }
  665.     else
  666.     handle_swap_exists(old_curbuf);
  667. # endif
  668. }
  669. #endif
  670.  
  671. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
  672. /*
  673.  * Handle the situation of swap_exists_action being set.
  674.  * It is allowed for "old_curbuf" to be NULL or invalid.
  675.  */
  676.     void
  677. handle_swap_exists(old_curbuf)
  678.     buf_T    *old_curbuf;
  679. {
  680.     if (swap_exists_action == SEA_QUIT)
  681.     {
  682.     /* User selected Quit at ATTENTION prompt.  Go back to previous
  683.      * buffer.  If that buffer is gone or the same as the current one,
  684.      * open a new, empty buffer. */
  685.     swap_exists_action = SEA_NONE;    /* don't want it again */
  686.     close_buffer(curwin, curbuf, DOBUF_UNLOAD);
  687.     if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
  688.         old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
  689.     enter_buffer(old_curbuf);
  690.     }
  691.     else if (swap_exists_action == SEA_RECOVER)
  692.     {
  693.     /* User selected Recover at ATTENTION prompt. */
  694.     msg_scroll = TRUE;
  695.     ml_recover();
  696.     MSG_PUTS("\n");    /* don't overwrite the last message */
  697.     cmdline_row = msg_row;
  698.     do_modelines();
  699.     }
  700.     swap_exists_action = SEA_NONE;
  701. }
  702. #endif
  703.  
  704. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  705. /*
  706.  * do_bufdel() - delete or unload buffer(s)
  707.  *
  708.  * addr_count == 0: ":bdel" - delete current buffer
  709.  * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
  710.  *            buffer "end_bnr", then any other arguments.
  711.  * addr_count == 2: ":N,N bdel" - delete buffers in range
  712.  *
  713.  * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
  714.  * DOBUF_DEL (":bdel")
  715.  *
  716.  * Returns error message or NULL
  717.  */
  718.     char_u *
  719. do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
  720.     int        command;
  721.     char_u    *arg;        /* pointer to extra arguments */
  722.     int        addr_count;
  723.     int        start_bnr;    /* first buffer number in a range */
  724.     int        end_bnr;    /* buffer nr or last buffer nr in a range */
  725.     int        forceit;
  726. {
  727.     int        do_current = 0;    /* delete current buffer? */
  728.     int        deleted = 0;    /* number of buffers deleted */
  729.     char_u    *errormsg = NULL; /* return value */
  730.     int        bnr;        /* buffer number */
  731.     char_u    *p;
  732.  
  733. #ifdef FEAT_NETBEANS_INTG
  734.     netbeansCloseFile = 1;
  735. #endif
  736.     if (addr_count == 0)
  737.     {
  738.     (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
  739.     }
  740.     else
  741.     {
  742.     if (addr_count == 2)
  743.     {
  744.         if (*arg)        /* both range and argument is not allowed */
  745.         return (char_u *)_(e_trailing);
  746.         bnr = start_bnr;
  747.     }
  748.     else    /* addr_count == 1 */
  749.         bnr = end_bnr;
  750.  
  751.     for ( ;!got_int; ui_breakcheck())
  752.     {
  753.         /*
  754.          * delete the current buffer last, otherwise when the
  755.          * current buffer is deleted, the next buffer becomes
  756.          * the current one and will be loaded, which may then
  757.          * also be deleted, etc.
  758.          */
  759.         if (bnr == curbuf->b_fnum)
  760.         do_current = bnr;
  761.         else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
  762.                                    forceit) == OK)
  763.         ++deleted;
  764.  
  765.         /*
  766.          * find next buffer number to delete/unload
  767.          */
  768.         if (addr_count == 2)
  769.         {
  770.         if (++bnr > end_bnr)
  771.             break;
  772.         }
  773.         else    /* addr_count == 1 */
  774.         {
  775.         arg = skipwhite(arg);
  776.         if (*arg == NUL)
  777.             break;
  778.         if (!isdigit(*arg))
  779.         {
  780.             p = skiptowhite_esc(arg);
  781.             bnr = buflist_findpat(arg, p, command == DOBUF_WIPE, FALSE);
  782.             if (bnr < 0)        /* failed */
  783.             break;
  784.             arg = p;
  785.         }
  786.         else
  787.             bnr = getdigits(&arg);
  788.         }
  789.     }
  790.     if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
  791.                       FORWARD, do_current, forceit) == OK)
  792.         ++deleted;
  793.  
  794.     if (deleted == 0)
  795.     {
  796.         if (command == DOBUF_UNLOAD)
  797.         sprintf((char *)IObuff, _("E515: No buffers were unloaded"));
  798.         else if (command == DOBUF_DEL)
  799.         sprintf((char *)IObuff, _("E516: No buffers were deleted"));
  800.         else
  801.         sprintf((char *)IObuff, _("E517: No buffers were wiped out"));
  802.         errormsg = IObuff;
  803.     }
  804.     else if (deleted >= p_report)
  805.     {
  806.         if (command == DOBUF_UNLOAD)
  807.         {
  808.         if (deleted == 1)
  809.             MSG(_("1 buffer unloaded"));
  810.         else
  811.             smsg((char_u *)_("%d buffers unloaded"), deleted);
  812.         }
  813.         else if (command == DOBUF_DEL)
  814.         {
  815.         if (deleted == 1)
  816.             MSG(_("1 buffer deleted"));
  817.         else
  818.             smsg((char_u *)_("%d buffers deleted"), deleted);
  819.         }
  820.         else
  821.         {
  822.         if (deleted == 1)
  823.             MSG(_("1 buffer wiped out"));
  824.         else
  825.             smsg((char_u *)_("%d buffers wiped out"), deleted);
  826.         }
  827.     }
  828.     }
  829.  
  830. #ifdef FEAT_NETBEANS_INTG
  831.     netbeansCloseFile = 0;
  832. #endif
  833.  
  834.     return errormsg;
  835. }
  836.  
  837. /*
  838.  * Implementation of the commands for the buffer list.
  839.  *
  840.  * action == DOBUF_GOTO        go to specified buffer
  841.  * action == DOBUF_SPLIT    split window and go to specified buffer
  842.  * action == DOBUF_UNLOAD   unload specified buffer(s)
  843.  * action == DOBUF_DEL        delete specified buffer(s) from buffer list
  844.  * action == DOBUF_WIPE        delete specified buffer(s) really
  845.  *
  846.  * start == DOBUF_CURRENT   go to "count" buffer from current buffer
  847.  * start == DOBUF_FIRST        go to "count" buffer from first buffer
  848.  * start == DOBUF_LAST        go to "count" buffer from last buffer
  849.  * start == DOBUF_MOD        go to "count" modified buffer from current buffer
  850.  *
  851.  * Return FAIL or OK.
  852.  */
  853.     int
  854. do_buffer(action, start, dir, count, forceit)
  855.     int        action;
  856.     int        start;
  857.     int        dir;        /* FORWARD or BACKWARD */
  858.     int        count;        /* buffer number or number of buffers */
  859.     int        forceit;    /* TRUE for :...! */
  860. {
  861.     buf_T    *buf;
  862.     buf_T    *bp;
  863.     int        unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
  864.                              || action == DOBUF_WIPE);
  865.  
  866.     switch (start)
  867.     {
  868.     case DOBUF_FIRST:   buf = firstbuf; break;
  869.     case DOBUF_LAST:    buf = lastbuf;  break;
  870.     default:        buf = curbuf;   break;
  871.     }
  872.     if (start == DOBUF_MOD)        /* find next modified buffer */
  873.     {
  874.     while (count-- > 0)
  875.     {
  876.         do
  877.         {
  878.         buf = buf->b_next;
  879.         if (buf == NULL)
  880.             buf = firstbuf;
  881.         }
  882.         while (buf != curbuf && !bufIsChanged(buf));
  883.     }
  884.     if (!bufIsChanged(buf))
  885.     {
  886.         EMSG(_("E84: No modified buffer found"));
  887.         return FAIL;
  888.     }
  889.     }
  890.     else if (start == DOBUF_FIRST && count) /* find specified buffer number */
  891.     {
  892.     while (buf != NULL && buf->b_fnum != count)
  893.         buf = buf->b_next;
  894.     }
  895.     else
  896.     {
  897.     bp = NULL;
  898.     while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
  899.     {
  900.         /* remember the buffer where we start, we come back there when all
  901.          * buffers are unlisted. */
  902.         if (bp == NULL)
  903.         bp = buf;
  904.         if (dir == FORWARD)
  905.         {
  906.         buf = buf->b_next;
  907.         if (buf == NULL)
  908.             buf = firstbuf;
  909.         }
  910.         else
  911.         {
  912.         buf = buf->b_prev;
  913.         if (buf == NULL)
  914.             buf = lastbuf;
  915.         }
  916.         /* don't count unlisted buffers */
  917.         if (unload || buf->b_p_bl)
  918.         {
  919.          --count;
  920.          bp = NULL;    /* use this buffer as new starting point */
  921.         }
  922.         if (bp == buf)
  923.         {
  924.         /* back where we started, didn't find anything. */
  925.         EMSG(_("E85: There is no listed buffer"));
  926.         return FAIL;
  927.         }
  928.     }
  929.     }
  930.  
  931.     if (buf == NULL)        /* could not find it */
  932.     {
  933.     if (start == DOBUF_FIRST)
  934.     {
  935.         /* don't warn when deleting */
  936.         if (!unload)
  937.         EMSGN(_("E86: Cannot go to buffer %ld"), count);
  938.     }
  939.     else if (dir == FORWARD)
  940.         EMSG(_("E87: Cannot go beyond last buffer"));
  941.     else
  942.         EMSG(_("E88: Cannot go before first buffer"));
  943.     return FAIL;
  944.     }
  945.  
  946. #ifdef FEAT_GUI
  947.     need_mouse_correct = TRUE;
  948. #endif
  949.  
  950. #ifdef FEAT_LISTCMDS
  951.     /*
  952.      * delete buffer buf from memory and/or the list
  953.      */
  954.     if (unload)
  955.     {
  956.     int    forward;
  957.     int    retval;
  958.  
  959.     /* When unloading or deleting a buffer that's already unloaded and
  960.      * unlisted: fail silently. */
  961.     if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
  962.         return FAIL;
  963.  
  964.     if (!forceit && bufIsChanged(buf))
  965.     {
  966.         EMSGN(_("E89: No write since last change for buffer %ld (add ! to override)"),
  967.             buf->b_fnum);
  968.         return FAIL;
  969.     }
  970.  
  971.     /*
  972.      * If deleting the last (listed) buffer, make it empty.
  973.      * The last (listed) buffer cannot be unloaded.
  974.      */
  975.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  976.         if (bp->b_p_bl && bp != buf)
  977.         break;
  978.     if (bp == NULL && buf == curbuf)
  979.     {
  980.         if (action == DOBUF_UNLOAD)
  981.         {
  982.         EMSG(_("E90: Cannot unload last buffer"));
  983.         return FAIL;
  984.         }
  985.  
  986.         /* Close any other windows on this buffer, then make it empty. */
  987. #ifdef FEAT_WINDOWS
  988.         {
  989.         win_T    *wp, *nextwp;
  990.  
  991.         for (wp = firstwin; wp != NULL; wp = nextwp)
  992.         {
  993.             nextwp = wp->w_next;
  994.             if (wp != curwin && wp->w_buffer == buf)
  995.             {
  996.             /* Start all over, autocommands may change the window
  997.              * layout. */
  998.             nextwp = firstwin;
  999.             win_close(wp, FALSE);
  1000.             }
  1001.         }
  1002.         }
  1003. #endif
  1004.         setpcmark();
  1005.         retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
  1006.                           forceit ? ECMD_FORCEIT : 0);
  1007.  
  1008.         /*
  1009.          * do_ecmd() may create a new buffer, then we have to delete
  1010.          * the old one.  But do_ecmd() may have done that already, check
  1011.          * if the buffer still exists.
  1012.          */
  1013.         if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
  1014.         close_buffer(NULL, buf, action);
  1015.         return retval;
  1016.     }
  1017.  
  1018. #ifdef FEAT_WINDOWS
  1019.     /*
  1020.      * If the deleted buffer is the current one, close the current window
  1021.      * (unless it's the only window).
  1022.      */
  1023.     while (buf == curbuf && firstwin != lastwin)
  1024.         win_close(curwin, FALSE);
  1025. #endif
  1026.  
  1027.     /*
  1028.      * If the buffer to be deleted is not the current one, delete it here.
  1029.      */
  1030.     if (buf != curbuf)
  1031.     {
  1032. #ifdef FEAT_WINDOWS
  1033.         close_windows(buf);
  1034. #endif
  1035.         if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
  1036.         close_buffer(NULL, buf, action);
  1037.         return OK;
  1038.     }
  1039.  
  1040.     /*
  1041.      * Deleting the current buffer: Need to find another buffer to go to.
  1042.      * There must be another, otherwise it would have been handled above.
  1043.      * First use au_new_curbuf, if it is valid.
  1044.      * Then prefer the buffer we most recently visited.
  1045.      * Else try to find one that is loaded, after the current buffer,
  1046.      * then before the current buffer.
  1047.      * Finally use any buffer.
  1048.      */
  1049.     buf = NULL;    /* selected buffer */
  1050.     bp = NULL;    /* used when no loaded buffer found */
  1051. #ifdef FEAT_AUTOCMD
  1052.     if (au_new_curbuf != NULL && buf_valid(au_new_curbuf))
  1053.         buf = au_new_curbuf;
  1054. # ifdef FEAT_JUMPLIST
  1055.     else
  1056. # endif
  1057. #endif
  1058. #ifdef FEAT_JUMPLIST
  1059.         if (curwin->w_jumplistlen > 0)
  1060.     {
  1061.         int     jumpidx;
  1062.  
  1063.         jumpidx = curwin->w_jumplistidx - 1;
  1064.         if (jumpidx < 0)
  1065.         jumpidx = curwin->w_jumplistlen - 1;
  1066.  
  1067.         forward = jumpidx;
  1068.         while (jumpidx != curwin->w_jumplistidx)
  1069.         {
  1070.         buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
  1071.         if (buf != NULL)
  1072.         {
  1073.             if (buf == curbuf || !buf->b_p_bl)
  1074.             buf = NULL;    /* skip current and unlisted bufs */
  1075.             else if (buf->b_ml.ml_mfp == NULL)
  1076.             {
  1077.             /* skip unloaded buf, but may keep it for later */
  1078.             if (bp == NULL)
  1079.                 bp = buf;
  1080.             buf = NULL;
  1081.             }
  1082.         }
  1083.         if (buf != NULL)   /* found a valid buffer: stop searching */
  1084.             break;
  1085.         /* advance to older entry in jump list */
  1086.         if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
  1087.             break;
  1088.         if (--jumpidx < 0)
  1089.             jumpidx = curwin->w_jumplistlen - 1;
  1090.         if (jumpidx == forward)        /* List exhausted for sure */
  1091.             break;
  1092.         }
  1093.     }
  1094. #endif
  1095.  
  1096.     if (buf == NULL)    /* No previous buffer, Try 2'nd approach */
  1097.     {
  1098.         forward = TRUE;
  1099.         buf = curbuf->b_next;
  1100.         for (;;)
  1101.         {
  1102.         if (buf == NULL)
  1103.         {
  1104.             if (!forward)    /* tried both directions */
  1105.             break;
  1106.             buf = curbuf->b_prev;
  1107.             forward = FALSE;
  1108.             continue;
  1109.         }
  1110.         /* in non-help buffer, try to skip help buffers, and vv */
  1111.         if (buf->b_help == curbuf->b_help && buf->b_p_bl)
  1112.         {
  1113.             if (buf->b_ml.ml_mfp != NULL)   /* found loaded buffer */
  1114.             break;
  1115.             if (bp == NULL)    /* remember unloaded buf for later */
  1116.             bp = buf;
  1117.         }
  1118.         if (forward)
  1119.             buf = buf->b_next;
  1120.         else
  1121.             buf = buf->b_prev;
  1122.         }
  1123.     }
  1124.     if (buf == NULL)    /* No loaded buffer, use unloaded one */
  1125.         buf = bp;
  1126.     if (buf == NULL)    /* No loaded buffer, find listed one */
  1127.     {
  1128.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1129.         if (buf->b_p_bl && buf != curbuf)
  1130.             break;
  1131.     }
  1132.     if (buf == NULL)    /* Still no buffer, just take one */
  1133.     {
  1134.         if (curbuf->b_next != NULL)
  1135.         buf = curbuf->b_next;
  1136.         else
  1137.         buf = curbuf->b_prev;
  1138.     }
  1139.     }
  1140.  
  1141.     /*
  1142.      * make buf current buffer
  1143.      */
  1144.     if (action == DOBUF_SPLIT)        /* split window first */
  1145.     {
  1146. # ifdef FEAT_WINDOWS
  1147.     /* jump to first window containing buf if one exists ("useopen") */
  1148.     if (vim_strchr(p_swb, 'u') && buf_jump_open_win(buf))
  1149.         return OK;
  1150.     if (win_split(0, 0) == FAIL)
  1151. # endif
  1152.         return FAIL;
  1153.     }
  1154. #endif
  1155.  
  1156.     /* go to current buffer - nothing to do */
  1157.     if (buf == curbuf)
  1158.     return OK;
  1159.  
  1160.     /*
  1161.      * Check if the current buffer may be abandoned.
  1162.      */
  1163.     if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
  1164.     {
  1165.     EMSG(_(e_nowrtmsg));
  1166.     return FAIL;
  1167.     }
  1168.  
  1169.     /* Go to the other buffer. */
  1170.     set_curbuf(buf, action);
  1171.  
  1172. #if defined(FEAT_LISTCMDS) && defined(FEAT_SCROLLBIND)
  1173.     if (action == DOBUF_SPLIT)
  1174.     curwin->w_p_scb = FALSE;    /* reset 'scrollbind' */
  1175. #endif
  1176.  
  1177. #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
  1178.     if (aborting())        /* autocmds may abort script processing */
  1179.     return FAIL;
  1180. #endif
  1181.  
  1182.     return OK;
  1183. }
  1184.  
  1185. #endif /* FEAT_LISTCMDS */
  1186.  
  1187. /*
  1188.  * Set current buffer to "buf".  Executes autocommands and closes current
  1189.  * buffer.  "action" tells how to close the current buffer:
  1190.  * DOBUF_GOTO        free or hide it
  1191.  * DOBUF_SPLIT        nothing
  1192.  * DOBUF_UNLOAD        unload it
  1193.  * DOBUF_DEL        delete it
  1194.  * DOBUF_WIPE        wipe it out
  1195.  */
  1196.     void
  1197. set_curbuf(buf, action)
  1198.     buf_T    *buf;
  1199.     int        action;
  1200. {
  1201.     buf_T    *prevbuf;
  1202.     int        unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
  1203.                              || action == DOBUF_WIPE);
  1204.  
  1205.     setpcmark();
  1206.     curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
  1207.     buflist_altfpos();             /* remember curpos */
  1208.  
  1209. #ifdef FEAT_VISUAL
  1210.     /* Don't restart Select mode after switching to another buffer. */
  1211.     VIsual_reselect = FALSE;
  1212. #endif
  1213.  
  1214.     /* close_windows() or apply_autocmds() may change curbuf */
  1215.     prevbuf = curbuf;
  1216.  
  1217. #ifdef FEAT_AUTOCMD
  1218.     apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
  1219. # ifdef FEAT_EVAL
  1220.     if (buf_valid(prevbuf) && !aborting())
  1221. # else
  1222.     if (buf_valid(prevbuf))
  1223. # endif
  1224. #endif
  1225.     {
  1226. #ifdef FEAT_WINDOWS
  1227.     if (unload)
  1228.         close_windows(prevbuf);
  1229. #endif
  1230. #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
  1231.     if (buf_valid(prevbuf) && !aborting())
  1232. #else
  1233.     if (buf_valid(prevbuf))
  1234. #endif
  1235.         close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
  1236.             unload ? action : (action == DOBUF_GOTO
  1237.             && !P_HID(prevbuf)
  1238.             && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0);
  1239.     }
  1240. #ifdef FEAT_AUTOCMD
  1241. # ifdef FEAT_EVAL
  1242.     /* An autocommand may have deleted buf or aborted the script processing! */
  1243.     if (buf_valid(buf) && !aborting())
  1244. # else
  1245.     if (buf_valid(buf))        /* an autocommand may have deleted buf! */
  1246. # endif
  1247. #endif
  1248.     enter_buffer(buf);
  1249. }
  1250.  
  1251. /*
  1252.  * Enter a new current buffer.
  1253.  * Old curbuf must have been abandoned already!
  1254.  */
  1255.     void
  1256. enter_buffer(buf)
  1257.     buf_T    *buf;
  1258. {
  1259.     /* Copy buffer and window local option values.  Not for a help buffer. */
  1260.     buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
  1261.     if (!buf->b_help)
  1262.     get_winopts(buf);
  1263. #ifdef FEAT_FOLDING
  1264.     else
  1265.     /* Remove all folds in the window. */
  1266.     clearFolding(curwin);
  1267.     foldUpdateAll(curwin);    /* update folds (later). */
  1268. #endif
  1269.  
  1270.     /* Get the buffer in the current window. */
  1271.     curwin->w_buffer = buf;
  1272.     curbuf = buf;
  1273.     ++curbuf->b_nwindows;
  1274.  
  1275. #ifdef FEAT_DIFF
  1276.     diff_new_buffer();
  1277. #endif
  1278.  
  1279.     /* Cursor on first line by default. */
  1280.     curwin->w_cursor.lnum = 1;
  1281.     curwin->w_cursor.col = 0;
  1282. #ifdef FEAT_VIRTUALEDIT
  1283.     curwin->w_cursor.coladd = 0;
  1284. #endif
  1285.     curwin->w_set_curswant = TRUE;
  1286.  
  1287.     /* Make sure the buffer is loaded. */
  1288.     if (curbuf->b_ml.ml_mfp == NULL)    /* need to load the file */
  1289.     open_buffer(FALSE, NULL);
  1290.     else
  1291.     {
  1292.     need_fileinfo = TRUE;        /* display file info after redraw */
  1293.     (void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
  1294. #ifdef FEAT_AUTOCMD
  1295.     curwin->w_topline = 1;
  1296. # ifdef FEAT_DIFF
  1297.     curwin->w_topfill = 0;
  1298. # endif
  1299.     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  1300.     apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
  1301. #endif
  1302.     }
  1303.  
  1304.     /* If autocommands did not change the cursor position, restore cursor lnum
  1305.      * and possibly cursor col. */
  1306.     if (curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
  1307.     buflist_getfpos();
  1308.  
  1309.     check_arg_idx(curwin);        /* check for valid arg_idx */
  1310. #ifdef FEAT_TITLE
  1311.     maketitle();
  1312. #endif
  1313. #ifdef FEAT_AUTOCMD
  1314.     if (curwin->w_topline == 1)        /* when autocmds didn't change it */
  1315. #endif
  1316.     scroll_cursor_halfway(FALSE);    /* redisplay at correct position */
  1317.  
  1318. #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_SUN_WORKSHOP)
  1319.     /* Change directories when the acd option is set on. */
  1320.     if (p_acd && vim_chdirfile(buf->b_ffname) == OK)
  1321.     shorten_fnames(TRUE);
  1322. #endif
  1323.  
  1324. #ifdef FEAT_KEYMAP
  1325.     if (curbuf->b_kmap_state & KEYMAP_INIT)
  1326.     keymap_init();
  1327. #endif
  1328.     redraw_later(NOT_VALID);
  1329. }
  1330.  
  1331. /*
  1332.  * functions for dealing with the buffer list
  1333.  */
  1334.  
  1335. /*
  1336.  * Add a file name to the buffer list.  Return a pointer to the buffer.
  1337.  * If the same file name already exists return a pointer to that buffer.
  1338.  * If it does not exist, or if fname == NULL, a new entry is created.
  1339.  * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
  1340.  * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
  1341.  * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
  1342.  * This is the ONLY way to create a new buffer.
  1343.  */
  1344. static int  top_file_num = 1;        /* highest file number */
  1345.  
  1346.     buf_T *
  1347. buflist_new(ffname, sfname, lnum, flags)
  1348.     char_u    *ffname;    /* full path of fname or relative */
  1349.     char_u    *sfname;    /* short fname or NULL */
  1350.     linenr_T    lnum;        /* preferred cursor line */
  1351.     int        flags;        /* BLN_ defines */
  1352. {
  1353.     buf_T    *buf;
  1354. #ifdef UNIX
  1355.     struct stat    st;
  1356. #endif
  1357.  
  1358.     fname_expand(&ffname, &sfname);    /* will allocate ffname */
  1359.  
  1360.     /*
  1361.      * If file name already exists in the list, update the entry.
  1362.      */
  1363. #ifdef UNIX
  1364.     /* On Unix we can use inode numbers when the file exists.  Works better
  1365.      * for hard links. */
  1366.     if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
  1367.     st.st_dev = (dev_T)-1;
  1368. #endif
  1369.     if (ffname != NULL && !(flags & BLN_DUMMY) && (buf =
  1370. #ifdef UNIX
  1371.         buflist_findname_stat(ffname, &st)
  1372. #else
  1373.         buflist_findname(ffname)
  1374. #endif
  1375.         ) != NULL)
  1376.     {
  1377.     vim_free(ffname);
  1378.     if (lnum != 0)
  1379.         buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
  1380.     /* copy the options now, if 'cpo' doesn't have 's' and not done
  1381.      * already */
  1382.     buf_copy_options(buf, 0);
  1383.     if ((flags & BLN_LISTED) && !buf->b_p_bl)
  1384.     {
  1385.         buf->b_p_bl = TRUE;
  1386. #ifdef FEAT_AUTOCMD
  1387.         if (!(flags & BLN_DUMMY))
  1388.         apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
  1389. #endif
  1390.     }
  1391.     return buf;
  1392.     }
  1393.  
  1394.     /*
  1395.      * If the current buffer has no name and no contents, use the current
  1396.      * buffer.    Otherwise: Need to allocate a new buffer structure.
  1397.      *
  1398.      * This is the ONLY place where a new buffer structure is allocated!
  1399.      */
  1400.     buf = NULL;
  1401.     if ((flags & BLN_CURBUF)
  1402.         && curbuf != NULL
  1403.         && curbuf->b_ffname == NULL
  1404.         && curbuf->b_nwindows <= 1
  1405.         && (curbuf->b_ml.ml_mfp == NULL || bufempty()))
  1406.     {
  1407.     buf = curbuf;
  1408. #ifdef FEAT_AUTOCMD
  1409.     /* It's like this buffer is deleted.  Watch out for autocommands that
  1410.      * change curbuf!  If that happens, allocate a new buffer anyway. */
  1411.     if (curbuf->b_p_bl)
  1412.         apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
  1413.     if (buf == curbuf)
  1414.         apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
  1415. # ifdef FEAT_EVAL
  1416.     if (aborting())        /* autocmds may abort script processing */
  1417.         return NULL;
  1418. # endif
  1419. #endif
  1420. #ifdef FEAT_QUICKFIX
  1421. # ifdef FEAT_AUTOCMD
  1422.     if (buf == curbuf)
  1423. # endif
  1424.     {
  1425.         /* Make sure 'bufhidden' and 'buftype' are empty */
  1426.         clear_string_option(&buf->b_p_bh);
  1427.         clear_string_option(&buf->b_p_bt);
  1428.     }
  1429. #endif
  1430.     }
  1431.     if (buf != curbuf || curbuf == NULL)
  1432.     {
  1433.     buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
  1434.     if (buf == NULL)
  1435.     {
  1436.         vim_free(ffname);
  1437.         return NULL;
  1438.     }
  1439.     }
  1440.  
  1441.     if (ffname != NULL)
  1442.     {
  1443.     buf->b_ffname = ffname;
  1444.     buf->b_sfname = vim_strsave(sfname);
  1445.     }
  1446.  
  1447.     clear_wininfo(buf);
  1448.     buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
  1449.  
  1450.     if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
  1451.         || buf->b_wininfo == NULL)
  1452.     {
  1453.     vim_free(buf->b_ffname);
  1454.     buf->b_ffname = NULL;
  1455.     vim_free(buf->b_sfname);
  1456.     buf->b_sfname = NULL;
  1457.     if (buf != curbuf)
  1458.         free_buffer(buf);
  1459.     return NULL;
  1460.     }
  1461.  
  1462.     if (buf == curbuf)
  1463.     {
  1464.     /* free all things allocated for this buffer */
  1465.     buf_freeall(buf, FALSE, FALSE);
  1466.     if (buf != curbuf)     /* autocommands deleted the buffer! */
  1467.         return NULL;
  1468. #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
  1469.     if (aborting())        /* autocmds may abort script processing */
  1470.         return NULL;
  1471. #endif
  1472.     /* buf->b_nwindows = 0; why was this here? */
  1473.     free_buffer_stuff(buf, FALSE);    /* delete local variables et al. */
  1474. #ifdef FEAT_KEYMAP
  1475.     /* need to reload lmaps and set b:keymap_name */
  1476.     curbuf->b_kmap_state |= KEYMAP_INIT;
  1477. #endif
  1478.     }
  1479.     else
  1480.     {
  1481.     /*
  1482.      * put new buffer at the end of the buffer list
  1483.      */
  1484.     buf->b_next = NULL;
  1485.     if (firstbuf == NULL)        /* buffer list is empty */
  1486.     {
  1487.         buf->b_prev = NULL;
  1488.         firstbuf = buf;
  1489.     }
  1490.     else                /* append new buffer at end of list */
  1491.     {
  1492.         lastbuf->b_next = buf;
  1493.         buf->b_prev = lastbuf;
  1494.     }
  1495.     lastbuf = buf;
  1496.  
  1497.     buf->b_fnum = top_file_num++;
  1498.     if (top_file_num < 0)        /* wrap around (may cause duplicates) */
  1499.     {
  1500.         EMSG(_("W14: Warning: List of file names overflow"));
  1501.         if (emsg_silent == 0)
  1502.         {
  1503.         out_flush();
  1504.         ui_delay(3000L, TRUE);    /* make sure it is noticed */
  1505.         }
  1506.         top_file_num = 1;
  1507.     }
  1508.  
  1509.     /*
  1510.      * Always copy the options from the current buffer.
  1511.      */
  1512.     buf_copy_options(buf, BCO_ALWAYS);
  1513.     }
  1514.  
  1515.     buf->b_wininfo->wi_fpos.lnum = lnum;
  1516.     buf->b_wininfo->wi_win = curwin;
  1517.  
  1518. #ifdef FEAT_EVAL
  1519.     var_init(&buf->b_vars);        /* init internal variables */
  1520. #endif
  1521.  
  1522.     buf->b_fname = buf->b_sfname;
  1523. #ifdef UNIX
  1524.     if (st.st_dev == (dev_T)-1)
  1525.     buf->b_dev = -1;
  1526.     else
  1527.     {
  1528.     buf->b_dev = st.st_dev;
  1529.     buf->b_ino = st.st_ino;
  1530.     }
  1531. #endif
  1532.     buf->b_u_synced = TRUE;
  1533.     buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
  1534.     buf_clear_file(buf);
  1535.     clrallmarks(buf);            /* clear marks */
  1536.     fmarks_check_names(buf);        /* check file marks for this file */
  1537.     buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE;    /* init 'buflisted' */
  1538. #ifdef FEAT_AUTOCMD
  1539.     if (!(flags & BLN_DUMMY))
  1540.     {
  1541.     apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf);
  1542.     if (flags & BLN_LISTED)
  1543.         apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
  1544. # ifdef FEAT_EVAL
  1545.     if (aborting())        /* autocmds may abort script processing */
  1546.         return NULL;
  1547. # endif
  1548.     }
  1549. #endif
  1550.  
  1551.     return buf;
  1552. }
  1553.  
  1554. /*
  1555.  * Free the memory for the options of a buffer.
  1556.  * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
  1557.  * 'fileencoding'.
  1558.  */
  1559.     void
  1560. free_buf_options(buf, free_p_ff)
  1561.     buf_T    *buf;
  1562.     int        free_p_ff;
  1563. {
  1564.     if (free_p_ff)
  1565.     {
  1566. #ifdef FEAT_MBYTE
  1567.     clear_string_option(&buf->b_p_fenc);
  1568. #endif
  1569.     clear_string_option(&buf->b_p_ff);
  1570. #ifdef FEAT_QUICKFIX
  1571.     clear_string_option(&buf->b_p_bh);
  1572.     clear_string_option(&buf->b_p_bt);
  1573. #endif
  1574.     }
  1575. #ifdef FEAT_FIND_ID
  1576.     clear_string_option(&buf->b_p_def);
  1577.     clear_string_option(&buf->b_p_inc);
  1578. # ifdef FEAT_EVAL
  1579.     clear_string_option(&buf->b_p_inex);
  1580. # endif
  1581. #endif
  1582. #if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
  1583.     clear_string_option(&buf->b_p_inde);
  1584.     clear_string_option(&buf->b_p_indk);
  1585. #endif
  1586. #ifdef FEAT_CRYPT
  1587.     clear_string_option(&buf->b_p_key);
  1588. #endif
  1589.     clear_string_option(&buf->b_p_kp);
  1590.     clear_string_option(&buf->b_p_mps);
  1591.     clear_string_option(&buf->b_p_fo);
  1592.     clear_string_option(&buf->b_p_isk);
  1593. #ifdef FEAT_KEYMAP
  1594.     clear_string_option(&buf->b_p_keymap);
  1595.     ga_clear(&buf->b_kmap_ga);
  1596. #endif
  1597. #ifdef FEAT_COMMENTS
  1598.     clear_string_option(&buf->b_p_com);
  1599. #endif
  1600. #ifdef FEAT_FOLDING
  1601.     clear_string_option(&buf->b_p_cms);
  1602. #endif
  1603.     clear_string_option(&buf->b_p_nf);
  1604. #ifdef FEAT_SYN_HL
  1605.     clear_string_option(&buf->b_p_syn);
  1606. #endif
  1607. #ifdef FEAT_SEARCHPATH
  1608.     clear_string_option(&buf->b_p_sua);
  1609. #endif
  1610. #ifdef FEAT_AUTOCMD
  1611.     clear_string_option(&buf->b_p_ft);
  1612. #endif
  1613. #ifdef FEAT_OSFILETYPE
  1614.     clear_string_option(&buf->b_p_oft);
  1615. #endif
  1616. #ifdef FEAT_CINDENT
  1617.     clear_string_option(&buf->b_p_cink);
  1618.     clear_string_option(&buf->b_p_cino);
  1619. #endif
  1620. #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
  1621.     clear_string_option(&buf->b_p_cinw);
  1622. #endif
  1623. #ifdef FEAT_INS_EXPAND
  1624.     clear_string_option(&buf->b_p_cpt);
  1625. #endif
  1626. #ifdef FEAT_QUICKFIX
  1627.     clear_string_option(&buf->b_p_gp);
  1628.     clear_string_option(&buf->b_p_mp);
  1629.     clear_string_option(&buf->b_p_efm);
  1630. #endif
  1631.     clear_string_option(&buf->b_p_ep);
  1632.     clear_string_option(&buf->b_p_path);
  1633.     clear_string_option(&buf->b_p_tags);
  1634. #ifdef FEAT_INS_EXPAND
  1635.     clear_string_option(&buf->b_p_dict);
  1636.     clear_string_option(&buf->b_p_tsr);
  1637. #endif
  1638.     buf->b_p_ar = -1;
  1639. }
  1640.  
  1641. /*
  1642.  * get alternate file n
  1643.  * set linenr to lnum or altfpos.lnum if lnum == 0
  1644.  *    also set cursor column to altfpos.col if 'startofline' is not set.
  1645.  * if (options & GETF_SETMARK) call setpcmark()
  1646.  * if (options & GETF_ALT) we are jumping to an alternate file.
  1647.  * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
  1648.  *
  1649.  * return FAIL for failure, OK for success
  1650.  */
  1651.     int
  1652. buflist_getfile(n, lnum, options, forceit)
  1653.     int        n;
  1654.     linenr_T    lnum;
  1655.     int        options;
  1656.     int        forceit;
  1657. {
  1658.     buf_T    *buf;
  1659. #ifdef FEAT_WINDOWS
  1660.     win_T    *wp = NULL;
  1661. #endif
  1662.     pos_T    *fpos;
  1663.     colnr_T    col;
  1664.  
  1665.     buf = buflist_findnr(n);
  1666.     if (buf == NULL)
  1667.     {
  1668.     if ((options & GETF_ALT) && n == 0)
  1669.         EMSG(_(e_noalt));
  1670.     else
  1671.         EMSGN(_("E92: Buffer %ld not found"), n);
  1672.     return FAIL;
  1673.     }
  1674.  
  1675.     /* if alternate file is the current buffer, nothing to do */
  1676.     if (buf == curbuf)
  1677.     return OK;
  1678.  
  1679. #ifdef FEAT_CMDWIN
  1680.     if (cmdwin_type != 0)
  1681.     return FAIL;
  1682. #endif
  1683.  
  1684.     /* altfpos may be changed by getfile(), get it now */
  1685.     if (lnum == 0)
  1686.     {
  1687.     fpos = buflist_findfpos(buf);
  1688.     lnum = fpos->lnum;
  1689.     col = fpos->col;
  1690.     }
  1691.     else
  1692.     col = 0;
  1693.  
  1694. #ifdef FEAT_WINDOWS
  1695.     if (options & GETF_SWITCH)
  1696.     {
  1697.     /* use existing open window for buffer if wanted */
  1698.     if (vim_strchr(p_swb, 'u'))     /* useopen */
  1699.         wp = buf_jump_open_win(buf);
  1700.     /* split window if wanted ("split") */
  1701.     if (wp == NULL && vim_strchr(p_swb, 't') && !bufempty())
  1702.     {
  1703.         if (win_split(0, 0) == FAIL)
  1704.         return FAIL;
  1705. # ifdef FEAT_SCROLLBIND
  1706.         curwin->w_p_scb = FALSE;
  1707. # endif
  1708.     }
  1709.     }
  1710. #endif
  1711.  
  1712.     ++RedrawingDisabled;
  1713.     if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
  1714.                               lnum, forceit) <= 0)
  1715.     {
  1716.     --RedrawingDisabled;
  1717.  
  1718.     /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
  1719.     if (!p_sol && col != 0)
  1720.     {
  1721.         curwin->w_cursor.col = col;
  1722.         check_cursor_col();
  1723. #ifdef FEAT_VIRTUALEDIT
  1724.         curwin->w_cursor.coladd = 0;
  1725. #endif
  1726.         curwin->w_set_curswant = TRUE;
  1727.     }
  1728.     return OK;
  1729.     }
  1730.     --RedrawingDisabled;
  1731.     return FAIL;
  1732. }
  1733.  
  1734. /*
  1735.  * go to the last know line number for the current buffer
  1736.  */
  1737.     void
  1738. buflist_getfpos()
  1739. {
  1740.     pos_T    *fpos;
  1741.  
  1742.     fpos = buflist_findfpos(curbuf);
  1743.  
  1744.     curwin->w_cursor.lnum = fpos->lnum;
  1745.     check_cursor_lnum();
  1746.  
  1747.     if (p_sol)
  1748.     curwin->w_cursor.col = 0;
  1749.     else
  1750.     {
  1751.     curwin->w_cursor.col = fpos->col;
  1752.     check_cursor_col();
  1753. #ifdef FEAT_VIRTUALEDIT
  1754.     curwin->w_cursor.coladd = 0;
  1755. #endif
  1756.     curwin->w_set_curswant = TRUE;
  1757.     }
  1758. }
  1759.  
  1760. /*
  1761.  * find file in buffer list by name (it has to be for the current window)
  1762.  * 'ffname' must have a full path.
  1763.  */
  1764.     buf_T *
  1765. buflist_findname(ffname)
  1766.     char_u    *ffname;
  1767. {
  1768. #ifdef UNIX
  1769.     struct stat st;
  1770.  
  1771.     if (mch_stat((char *)ffname, &st) < 0)
  1772.     st.st_dev = (dev_T)-1;
  1773.     return buflist_findname_stat(ffname, &st);
  1774. }
  1775.  
  1776. /*
  1777.  * Same as buflist_findname(), but pass the stat structure to avoid getting it
  1778.  * twice for the same file.
  1779.  */
  1780.     static buf_T *
  1781. buflist_findname_stat(ffname, stp)
  1782.     char_u    *ffname;
  1783.     struct stat    *stp;
  1784. {
  1785. #endif
  1786.     buf_T    *buf;
  1787.  
  1788.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1789.     if (!otherfile_buf(buf, ffname
  1790. #ifdef UNIX
  1791.             , stp
  1792. #endif
  1793.             ))
  1794.         return buf;
  1795.     return NULL;
  1796. }
  1797.  
  1798. #if defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) || defined(PROTO)
  1799. /*
  1800.  * Find file in buffer list by a regexp pattern.
  1801.  * Return fnum of the found buffer.
  1802.  * Return < 0 for error.
  1803.  */
  1804. /*ARGSUSED*/
  1805.     int
  1806. buflist_findpat(pattern, pattern_end, unlisted, diffmode)
  1807.     char_u    *pattern;
  1808.     char_u    *pattern_end;    /* pointer to first char after pattern */
  1809.     int        unlisted;    /* find unlisted buffers */
  1810.     int        diffmode;    /* find diff-mode buffers only */
  1811. {
  1812.     buf_T    *buf;
  1813.     regprog_T    *prog;
  1814.     int        match = -1;
  1815.     int        find_listed;
  1816.     char_u    *pat;
  1817.     char_u    *patend;
  1818.     int        attempt;
  1819.     char_u    *p;
  1820.     int        toggledollar;
  1821.  
  1822.     if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
  1823.     {
  1824.     if (*pattern == '%')
  1825.         match = curbuf->b_fnum;
  1826.     else
  1827.         match = curwin->w_alt_fnum;
  1828. #ifdef FEAT_DIFF
  1829.     if (diffmode && !diff_mode_buf(buflist_findnr(match)))
  1830.         match = -1;
  1831. #endif
  1832.     }
  1833.  
  1834.     /*
  1835.      * Try four ways of matching a listed buffer:
  1836.      * attempt == 0: without '^' or '$' (at any position)
  1837.      * attempt == 1: with '^' at start (only at postion 0)
  1838.      * attempt == 2: with '$' at end (only match at end)
  1839.      * attempt == 3: with '^' at start and '$' at end (only full match)
  1840.      * Repeat this for finding an unlisted buffer if there was no matching
  1841.      * listed buffer.
  1842.      */
  1843.     else
  1844.     {
  1845.     pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
  1846.     if (pat == NULL)
  1847.         return -1;
  1848.     patend = pat + STRLEN(pat) - 1;
  1849.     toggledollar = (patend > pat && *patend == '$');
  1850.  
  1851.     /* First try finding a listed buffer.  If not found and "unlisted"
  1852.      * is TRUE, try finding an unlisted buffer. */
  1853.     find_listed = TRUE;
  1854.     for (;;)
  1855.     {
  1856.         for (attempt = 0; attempt <= 3; ++attempt)
  1857.         {
  1858.         /* may add '^' and '$' */
  1859.         if (toggledollar)
  1860.             *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
  1861.         p = pat;
  1862.         if (*p == '^' && !(attempt & 1))     /* add/remove '^' */
  1863.             ++p;
  1864.         prog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
  1865.         if (prog == NULL)
  1866.         {
  1867.             vim_free(pat);
  1868.             return -1;
  1869.         }
  1870.  
  1871.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1872.             if (buf->b_p_bl == find_listed
  1873. #ifdef FEAT_DIFF
  1874.                 && (!diffmode || diff_mode_buf(buf))
  1875. #endif
  1876.                 && buflist_match(prog, buf) != NULL)
  1877.             {
  1878.             if (match >= 0)        /* already found a match */
  1879.             {
  1880.                 match = -2;
  1881.                 break;
  1882.             }
  1883.             match = buf->b_fnum;    /* remember first match */
  1884.             }
  1885.  
  1886.         vim_free(prog);
  1887.         if (match >= 0)            /* found one match */
  1888.             break;
  1889.         }
  1890.  
  1891.         /* Only search for unlisted buffers if there was no match with
  1892.          * a listed buffer. */
  1893.         if (!unlisted || !find_listed || match != -1)
  1894.         break;
  1895.         find_listed = FALSE;
  1896.     }
  1897.  
  1898.     vim_free(pat);
  1899.     }
  1900.  
  1901.     if (match == -2)
  1902.     EMSG2(_("E93: More than one match for %s"), pattern);
  1903.     else if (match < 0)
  1904.     EMSG2(_("E94: No matching buffer for %s"), pattern);
  1905.     return match;
  1906. }
  1907. #endif
  1908.  
  1909. #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
  1910.  
  1911. /*
  1912.  * Find all buffer names that match.
  1913.  * For command line expansion of ":buf" and ":sbuf".
  1914.  * Return OK if matches found, FAIL otherwise.
  1915.  */
  1916.     int
  1917. ExpandBufnames(pat, num_file, file, options)
  1918.     char_u    *pat;
  1919.     int        *num_file;
  1920.     char_u    ***file;
  1921.     int        options;
  1922. {
  1923.     int        count = 0;
  1924.     buf_T    *buf;
  1925.     int        round;
  1926.     char_u    *p;
  1927.     int        attempt;
  1928.     regprog_T    *prog;
  1929.  
  1930.     *num_file = 0;            /* return values in case of FAIL */
  1931.     *file = NULL;
  1932.  
  1933.     /*
  1934.      * attempt == 1: try match with    '^', match at start
  1935.      * attempt == 2: try match without '^', match anywhere
  1936.      */
  1937.     for (attempt = 1; attempt <= 2; ++attempt)
  1938.     {
  1939.     if (attempt == 2)
  1940.     {
  1941.         if (*pat != '^')        /* there's no '^', no need to try again */
  1942.         break;
  1943.         ++pat;            /* skip the '^' */
  1944.     }
  1945.     prog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
  1946.     if (prog == NULL)
  1947.         return FAIL;
  1948.  
  1949.     /*
  1950.      * round == 1: Count the matches.
  1951.      * round == 2: Build the array to keep the matches.
  1952.      */
  1953.     for (round = 1; round <= 2; ++round)
  1954.     {
  1955.         count = 0;
  1956.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1957.         {
  1958.         if (!buf->b_p_bl)    /* skip unlisted buffers */
  1959.             continue;
  1960.         p = buflist_match(prog, buf);
  1961.         if (p != NULL)
  1962.         {
  1963.             if (round == 1)
  1964.             ++count;
  1965.             else
  1966.             {
  1967.             if (options & WILD_HOME_REPLACE)
  1968.                 p = home_replace_save(buf, p);
  1969.             else
  1970.                 p = vim_strsave(p);
  1971.             (*file)[count++] = p;
  1972.             }
  1973.         }
  1974.         }
  1975.         if (count == 0)    /* no match found, break here */
  1976.         break;
  1977.         if (round == 1)
  1978.         {
  1979.         *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
  1980.         if (*file == NULL)
  1981.         {
  1982.             vim_free(prog);
  1983.             return FAIL;
  1984.         }
  1985.         }
  1986.     }
  1987.     vim_free(prog);
  1988.     if (count)        /* match(es) found, break here */
  1989.         break;
  1990.     }
  1991.  
  1992.     *num_file = count;
  1993.     return (count == 0 ? FAIL : OK);
  1994. }
  1995.  
  1996. #endif /* FEAT_CMDL_COMPL */
  1997.  
  1998. #ifdef HAVE_BUFLIST_MATCH
  1999. /*
  2000.  * Check for a match on the file name for buffer "buf" with regprog "prog".
  2001.  */
  2002.     static char_u *
  2003. buflist_match(prog, buf)
  2004.     regprog_T    *prog;
  2005.     buf_T    *buf;
  2006. {
  2007.     char_u    *match;
  2008.  
  2009.     /* First try the short file name, then the long file name. */
  2010.     match = fname_match(prog, buf->b_sfname);
  2011.     if (match == NULL)
  2012.     match = fname_match(prog, buf->b_ffname);
  2013.  
  2014.     return match;
  2015. }
  2016.  
  2017. /*
  2018.  * Try matching the regexp in "prog" with file name "name".
  2019.  * Return "name" when there is a match, NULL when not.
  2020.  */
  2021.     static char_u *
  2022. fname_match(prog, name)
  2023.     regprog_T    *prog;
  2024.     char_u    *name;
  2025. {
  2026.     char_u    *match = NULL;
  2027.     char_u    *p;
  2028.     regmatch_T    regmatch;
  2029.  
  2030.     if (name != NULL)
  2031.     {
  2032.     regmatch.regprog = prog;
  2033. #ifdef CASE_INSENSITIVE_FILENAME
  2034.     regmatch.rm_ic = TRUE;        /* Always ignore case */
  2035. #else
  2036.     regmatch.rm_ic = FALSE;        /* Never ignore case */
  2037. #endif
  2038.  
  2039.     if (vim_regexec(®match, name, (colnr_T)0))
  2040.         match = name;
  2041.     else
  2042.     {
  2043.         /* Replace $(HOME) with '~' and try matching again. */
  2044.         p = home_replace_save(NULL, name);
  2045.         if (p != NULL && vim_regexec(®match, p, (colnr_T)0))
  2046.         match = name;
  2047.         vim_free(p);
  2048.     }
  2049.     }
  2050.  
  2051.     return match;
  2052. }
  2053. #endif
  2054.  
  2055. /*
  2056.  * find file in buffer list by number
  2057.  */
  2058.     buf_T *
  2059. buflist_findnr(nr)
  2060.     int        nr;
  2061. {
  2062.     buf_T    *buf;
  2063.  
  2064.     if (nr == 0)
  2065.     nr = curwin->w_alt_fnum;
  2066.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  2067.     if (buf->b_fnum == nr)
  2068.         return (buf);
  2069.     return NULL;
  2070. }
  2071.  
  2072. /*
  2073.  * Get name of file 'n' in the buffer list.
  2074.  * When the file has no name an empty string is returned.
  2075.  * home_replace() is used to shorten the file name (used for marks).
  2076.  * Returns a pointer to allocated memory, of NULL when failed.
  2077.  */
  2078.     char_u *
  2079. buflist_nr2name(n, fullname, helptail)
  2080.     int        n;
  2081.     int        fullname;
  2082.     int        helptail;    /* for help buffers return tail only */
  2083. {
  2084.     buf_T    *buf;
  2085.  
  2086.     buf = buflist_findnr(n);
  2087.     if (buf == NULL)
  2088.     return NULL;
  2089.     return home_replace_save(helptail ? buf : NULL,
  2090.                      fullname ? buf->b_ffname : buf->b_fname);
  2091. }
  2092.  
  2093. /*
  2094.  * Set the "lnum" and "col" for the buffer "buf" and the current window.
  2095.  * When "copy_options" is TRUE save the local window option values.
  2096.  * When "lnum" is 0 only do the options.
  2097.  */
  2098.     static void
  2099. buflist_setfpos(buf, win, lnum, col, copy_options)
  2100.     buf_T    *buf;
  2101.     win_T    *win;
  2102.     linenr_T    lnum;
  2103.     colnr_T    col;
  2104.     int        copy_options;
  2105. {
  2106.     wininfo_T    *wip;
  2107.  
  2108.     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
  2109.     if (wip->wi_win == win)
  2110.         break;
  2111.     if (wip == NULL)
  2112.     {
  2113.     /* allocate a new entry */
  2114.     wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
  2115.     if (wip == NULL)
  2116.         return;
  2117.     wip->wi_win = win;
  2118.     if (lnum == 0)        /* set lnum even when it's 0 */
  2119.         lnum = 1;
  2120.     }
  2121.     else
  2122.     {
  2123.     /* remove the entry from the list */
  2124.     if (wip->wi_prev)
  2125.         wip->wi_prev->wi_next = wip->wi_next;
  2126.     else
  2127.         buf->b_wininfo = wip->wi_next;
  2128.     if (wip->wi_next)
  2129.         wip->wi_next->wi_prev = wip->wi_prev;
  2130.     if (copy_options && wip->wi_optset)
  2131.     {
  2132.         clear_winopt(&wip->wi_opt);
  2133. #ifdef FEAT_FOLDING
  2134.         deleteFoldRecurse(&wip->wi_folds);
  2135. #endif
  2136.     }
  2137.     }
  2138.     if (lnum != 0)
  2139.     {
  2140.     wip->wi_fpos.lnum = lnum;
  2141.     wip->wi_fpos.col = col;
  2142.     }
  2143.     if (copy_options)
  2144.     {
  2145.     /* Save the window-specific option values. */
  2146.     copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
  2147. #ifdef FEAT_FOLDING
  2148.     wip->wi_fold_manual = win->w_fold_manual;
  2149.     cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
  2150. #endif
  2151.     wip->wi_optset = TRUE;
  2152.     }
  2153.  
  2154.     /* insert the entry in front of the list */
  2155.     wip->wi_next = buf->b_wininfo;
  2156.     buf->b_wininfo = wip;
  2157.     wip->wi_prev = NULL;
  2158.     if (wip->wi_next)
  2159.     wip->wi_next->wi_prev = wip;
  2160.  
  2161.     return;
  2162. }
  2163.  
  2164. /*
  2165.  * Find info for the current window in buffer "buf".
  2166.  * If not found, return the info for the most recently used window.
  2167.  * Returns NULL when there isn't any info.
  2168.  */
  2169.     static wininfo_T *
  2170. find_wininfo(buf)
  2171.     buf_T    *buf;
  2172. {
  2173.     wininfo_T    *wip;
  2174.  
  2175.     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
  2176.     if (wip->wi_win == curwin)
  2177.         break;
  2178.     if (wip == NULL)    /* if no fpos for curwin, use the first in the list */
  2179.     wip = buf->b_wininfo;
  2180.     return wip;
  2181. }
  2182.  
  2183. /*
  2184.  * Reset the local window options to the values last used in this window.
  2185.  * If the buffer wasn't used in this window before, use the values from
  2186.  * the most recently used window.  If the values were never set, use the
  2187.  * global values for the window.
  2188.  */
  2189.     void
  2190. get_winopts(buf)
  2191.     buf_T    *buf;
  2192. {
  2193.     wininfo_T    *wip;
  2194.  
  2195.     clear_winopt(&curwin->w_onebuf_opt);
  2196. #ifdef FEAT_FOLDING
  2197.     clearFolding(curwin);
  2198. #endif
  2199.  
  2200.     wip = find_wininfo(buf);
  2201.     if (wip != NULL && wip->wi_optset)
  2202.     {
  2203.     copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
  2204. #ifdef FEAT_FOLDING
  2205.     curwin->w_fold_manual = wip->wi_fold_manual;
  2206.     curwin->w_foldinvalid = TRUE;
  2207.     cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
  2208. #endif
  2209.     }
  2210.     else
  2211.     copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
  2212.  
  2213. #ifdef FEAT_FOLDING
  2214.     /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
  2215.     if (p_fdls >= 0)
  2216.     curwin->w_p_fdl = p_fdls;
  2217. #endif
  2218. }
  2219.  
  2220. /*
  2221.  * Find the position (lnum and col) for the buffer 'buf' for the current
  2222.  * window.
  2223.  * Returns a pointer to no_position if no position is found.
  2224.  */
  2225.     pos_T *
  2226. buflist_findfpos(buf)
  2227.     buf_T    *buf;
  2228. {
  2229.     wininfo_T    *wip;
  2230.     static pos_T no_position = {1, 0};
  2231.  
  2232.     wip = find_wininfo(buf);
  2233.     if (wip != NULL)
  2234.     return &(wip->wi_fpos);
  2235.     else
  2236.     return &no_position;
  2237. }
  2238.  
  2239. /*
  2240.  * Find the lnum for the buffer 'buf' for the current window.
  2241.  */
  2242.     linenr_T
  2243. buflist_findlnum(buf)
  2244.     buf_T    *buf;
  2245. {
  2246.     return buflist_findfpos(buf)->lnum;
  2247. }
  2248.  
  2249. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  2250. /*
  2251.  * List all know file names (for :files and :buffers command).
  2252.  */
  2253. /*ARGSUSED*/
  2254.     void
  2255. buflist_list(eap)
  2256.     exarg_T    *eap;
  2257. {
  2258.     buf_T    *buf;
  2259.     int        len;
  2260.     int        i;
  2261.  
  2262.     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
  2263.     {
  2264.     /* skip unlisted buffers, unless ! was used */
  2265.     if (!buf->b_p_bl && !eap->forceit)
  2266.         continue;
  2267.     msg_putchar('\n');
  2268.     if (buf_spname(buf) != NULL)
  2269.         STRCPY(NameBuff, buf_spname(buf));
  2270.     else
  2271.         home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
  2272.  
  2273.     sprintf((char *)IObuff, "%3d%c%c%c%c%c \"",
  2274.         buf->b_fnum,
  2275.         buf->b_p_bl ? ' ' : 'u',
  2276.         buf == curbuf ? '%' :
  2277.             (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
  2278.         buf->b_ml.ml_mfp == NULL ? ' ' :
  2279.             (buf->b_nwindows == 0 ? 'h' : 'a'),
  2280.         !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '),
  2281.         (buf->b_flags & BF_READERR) ? 'x'
  2282.                         : (bufIsChanged(buf) ? '+' : ' ')
  2283.         );
  2284.  
  2285.     len = (int)STRLEN(IObuff);
  2286.     STRNCPY(IObuff + len, NameBuff, IOSIZE - 20 - len);
  2287.     IObuff[IOSIZE - 20 - len] = NUL;    /* make sure it's terminated */
  2288.  
  2289.     len = (int)STRLEN(IObuff);
  2290.     IObuff[len++] = '"';
  2291.  
  2292.     /* put "line 999" in column 40 or after the file name */
  2293.     IObuff[len] = NUL;
  2294.     i = 40 - vim_strsize(IObuff);
  2295.     do
  2296.     {
  2297.         IObuff[len++] = ' ';
  2298.     } while (--i > 0 && len < IOSIZE - 18);
  2299.     sprintf((char *)IObuff + len, _("line %ld"),
  2300.         buf == curbuf ? curwin->w_cursor.lnum :
  2301.                 (long)buflist_findlnum(buf));
  2302.     msg_outtrans(IObuff);
  2303.     out_flush();        /* output one line at a time */
  2304.     ui_breakcheck();
  2305.     }
  2306. }
  2307. #endif
  2308.  
  2309. /*
  2310.  * Get file name and line number for file 'fnum'.
  2311.  * Used by DoOneCmd() for translating '%' and '#'.
  2312.  * Used by insert_reg() and cmdline_paste() for '#' register.
  2313.  * Return FAIL if not found, OK for success.
  2314.  */
  2315.     int
  2316. buflist_name_nr(fnum, fname, lnum)
  2317.     int        fnum;
  2318.     char_u    **fname;
  2319.     linenr_T    *lnum;
  2320. {
  2321.     buf_T    *buf;
  2322.  
  2323.     buf = buflist_findnr(fnum);
  2324.     if (buf == NULL || buf->b_fname == NULL)
  2325.     return FAIL;
  2326.  
  2327.     *fname = buf->b_fname;
  2328.     *lnum = buflist_findlnum(buf);
  2329.  
  2330.     return OK;
  2331. }
  2332.  
  2333. /*
  2334.  * Set the current file name to 'ffname', short file name to 'sfname'.
  2335.  * The file name with the full path is also remembered, for when :cd is used.
  2336.  * Returns FAIL for failure (file name already in use by other buffer)
  2337.  *    OK otherwise.
  2338.  */
  2339.     int
  2340. setfname(ffname, sfname, message)
  2341.     char_u *ffname, *sfname;
  2342.     int        message;
  2343. {
  2344.     buf_T    *buf;
  2345. #ifdef UNIX
  2346.     struct stat st;
  2347. #endif
  2348.  
  2349.     if (ffname == NULL || *ffname == NUL)
  2350.     {
  2351.     vim_free(curbuf->b_ffname);
  2352.     vim_free(curbuf->b_sfname);
  2353.     curbuf->b_ffname = NULL;
  2354.     curbuf->b_sfname = NULL;
  2355. #ifdef UNIX
  2356.     st.st_dev = (dev_T)-1;
  2357. #endif
  2358.     }
  2359.     else
  2360.     {
  2361.     fname_expand(&ffname, &sfname);        /* will allocate ffname */
  2362.     if (ffname == NULL)            /* out of memory */
  2363.         return FAIL;
  2364.  
  2365.     /*
  2366.      * if the file name is already used in another buffer:
  2367.      * - if the buffer is loaded, fail
  2368.      * - if the buffer is not loaded, delete it from the list
  2369.      */
  2370. #ifdef UNIX
  2371.     if (mch_stat((char *)ffname, &st) < 0)
  2372.         st.st_dev = (dev_T)-1;
  2373.     buf = buflist_findname_stat(ffname, &st);
  2374. #else
  2375.     buf = buflist_findname(ffname);
  2376. #endif
  2377.     if (buf != NULL && buf != curbuf)
  2378.     {
  2379.         if (buf->b_ml.ml_mfp != NULL)    /* it's loaded, fail */
  2380.         {
  2381.         if (message)
  2382.             EMSG(_("E95: Buffer with this name already exists"));
  2383.         vim_free(ffname);
  2384.         return FAIL;
  2385.         }
  2386.         close_buffer(NULL, buf, DOBUF_WIPE); /* delete from the list */
  2387.     }
  2388.     sfname = vim_strsave(sfname);
  2389.     if (ffname == NULL || sfname == NULL)
  2390.     {
  2391.         vim_free(sfname);
  2392.         vim_free(ffname);
  2393.         return FAIL;
  2394.     }
  2395. #ifdef USE_FNAME_CASE
  2396. # ifdef USE_LONG_FNAME
  2397.     if (USE_LONG_FNAME)
  2398. # endif
  2399.         fname_case(sfname, 0);    /* set correct case for short file name */
  2400. #endif
  2401.     vim_free(curbuf->b_ffname);
  2402.     vim_free(curbuf->b_sfname);
  2403.     curbuf->b_ffname = ffname;
  2404.     curbuf->b_sfname = sfname;
  2405.     }
  2406.     curbuf->b_fname = curbuf->b_sfname;
  2407. #ifdef UNIX
  2408.     if (st.st_dev == (dev_T)-1)
  2409.     curbuf->b_dev = -1;
  2410.     else
  2411.     {
  2412.     curbuf->b_dev = st.st_dev;
  2413.     curbuf->b_ino = st.st_ino;
  2414.     }
  2415. #endif
  2416.  
  2417. #ifndef SHORT_FNAME
  2418.     curbuf->b_shortname = FALSE;
  2419. #endif
  2420.  
  2421.     buf_name_changed();
  2422.     return OK;
  2423. }
  2424.  
  2425. /*
  2426.  * Take care of what needs to be done when the name of the current buffer has
  2427.  * changed.
  2428.  */
  2429.     void
  2430. buf_name_changed()
  2431. {
  2432.     /*
  2433.      * If the file name changed, also change the name of the swapfile
  2434.      */
  2435.     if (curbuf->b_ml.ml_mfp != NULL)
  2436.     ml_setname();
  2437.  
  2438.     check_arg_idx(curwin);    /* check file name for arg list */
  2439. #ifdef FEAT_TITLE
  2440.     maketitle();        /* set window title */
  2441. #endif
  2442. #ifdef FEAT_WINDOWS
  2443.     status_redraw_all();    /* status lines need to be redrawn */
  2444. #endif
  2445.     fmarks_check_names(curbuf);    /* check named file marks */
  2446.     ml_timestamp(curbuf);    /* reset timestamp */
  2447. }
  2448.  
  2449. /*
  2450.  * set alternate file name for current window
  2451.  *
  2452.  * Used by do_one_cmd(), do_write() and do_ecmd().
  2453.  * Return the buffer.
  2454.  */
  2455.     buf_T *
  2456. setaltfname(ffname, sfname, lnum)
  2457.     char_u    *ffname;
  2458.     char_u    *sfname;
  2459.     linenr_T    lnum;
  2460. {
  2461.     buf_T    *buf;
  2462.  
  2463.     /* Create a buffer.  'buflisted' is not set if it's a new buffer */
  2464.     buf = buflist_new(ffname, sfname, lnum, 0);
  2465.     if (buf != NULL)
  2466.     curwin->w_alt_fnum = buf->b_fnum;
  2467.     return buf;
  2468. }
  2469.  
  2470. /*
  2471.  * Get alternate file name for current window.
  2472.  * Return NULL if there isn't any, and give error message if requested.
  2473.  */
  2474.     char_u  *
  2475. getaltfname(errmsg)
  2476.     int        errmsg;        /* give error message */
  2477. {
  2478.     char_u    *fname;
  2479.     linenr_T    dummy;
  2480.  
  2481.     if (buflist_name_nr(0, &fname, &dummy) == FAIL)
  2482.     {
  2483.     if (errmsg)
  2484.         EMSG(_(e_noalt));
  2485.     return NULL;
  2486.     }
  2487.     return fname;
  2488. }
  2489.  
  2490. /*
  2491.  * Add a file name to the buflist and return its number.
  2492.  * Uses same flags as buflist_new(), except BLN_DUMMY.
  2493.  *
  2494.  * used by qf_init(), main() and doarglist()
  2495.  */
  2496.     int
  2497. buflist_add(fname, flags)
  2498.     char_u    *fname;
  2499.     int        flags;
  2500. {
  2501.     buf_T    *buf;
  2502.  
  2503.     buf = buflist_new(fname, NULL, (linenr_T)0, flags);
  2504.     if (buf != NULL)
  2505.     return buf->b_fnum;
  2506.     return 0;
  2507. }
  2508.  
  2509. #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
  2510. /*
  2511.  * Adjust slashes in file names.  Called after 'shellslash' was set.
  2512.  */
  2513.     void
  2514. buflist_slash_adjust()
  2515. {
  2516.     buf_T    *bp;
  2517.  
  2518.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  2519.     {
  2520.     if (bp->b_ffname != NULL)
  2521.         slash_adjust(bp->b_ffname);
  2522.     if (bp->b_sfname != NULL)
  2523.         slash_adjust(bp->b_sfname);
  2524.     }
  2525. }
  2526. #endif
  2527.  
  2528. /*
  2529.  * Set alternate cursor position for current window.
  2530.  * Also save the local window option values.
  2531.  */
  2532.     void
  2533. buflist_altfpos()
  2534. {
  2535.     buflist_setfpos(curbuf, curwin, curwin->w_cursor.lnum,
  2536.                           curwin->w_cursor.col, TRUE);
  2537. }
  2538.  
  2539. /*
  2540.  * Return TRUE if 'ffname' is not the same file as current file.
  2541.  * Fname must have a full path (expanded by mch_FullName()).
  2542.  */
  2543.     int
  2544. otherfile(ffname)
  2545.     char_u    *ffname;
  2546. {
  2547.     return otherfile_buf(curbuf, ffname
  2548. #ifdef UNIX
  2549.         , NULL
  2550. #endif
  2551.         );
  2552. }
  2553.  
  2554.     static int
  2555. otherfile_buf(buf, ffname
  2556. #ifdef UNIX
  2557.     , stp
  2558. #endif
  2559.     )
  2560.     buf_T    *buf;
  2561.     char_u    *ffname;
  2562. #ifdef UNIX
  2563.     struct stat    *stp;
  2564. #endif
  2565. {
  2566.     /* no name is different */
  2567.     if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
  2568.     return TRUE;
  2569.     if (fnamecmp(ffname, buf->b_ffname) == 0)
  2570.     return FALSE;
  2571. #ifdef UNIX
  2572.     {
  2573.     struct stat    st;
  2574.  
  2575.     /* If no struct stat given, get it now */
  2576.     if (stp == NULL)
  2577.     {
  2578.         if (buf->b_dev < 0 || mch_stat((char *)ffname, &st) < 0)
  2579.         st.st_dev = (dev_T)-1;
  2580.         stp = &st;
  2581.     }
  2582.     /* Use dev/ino to check if the files are the same, even when the names
  2583.      * are different (possible with links).  Still need to compare the
  2584.      * name above, for when the file doesn't exist yet.
  2585.      * Problem: The dev/ino changes when a file is deleted (and created
  2586.      * again) and remains the same when renamed/moved.  We don't want to
  2587.      * mch_stat() each buffer each time, that would be too slow.  Get the
  2588.      * dev/ino again when they appear to match, but not when they appear
  2589.      * to be different: Could skip a buffer when it's actually the same
  2590.      * file. */
  2591.     if (buf_same_ino(buf, stp))
  2592.     {
  2593.         buf_setino(buf);
  2594.         if (buf_same_ino(buf, stp))
  2595.         return FALSE;
  2596.     }
  2597.     }
  2598. #endif
  2599.     return TRUE;
  2600. }
  2601.  
  2602. #if defined(UNIX) || defined(PROTO)
  2603. /*
  2604.  * Set inode and device number for a buffer.
  2605.  * Must always be called when b_fname is changed!.
  2606.  */
  2607.     void
  2608. buf_setino(buf)
  2609.     buf_T    *buf;
  2610. {
  2611.     struct stat    st;
  2612.  
  2613.     if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
  2614.     {
  2615.     buf->b_dev = st.st_dev;
  2616.     buf->b_ino = st.st_ino;
  2617.     }
  2618.     else
  2619.     buf->b_dev = -1;
  2620. }
  2621.  
  2622. /*
  2623.  * Return TRUE if dev/ino in buffer "buf" matches with "stp".
  2624.  */
  2625.     static int
  2626. buf_same_ino(buf, stp)
  2627.     buf_T    *buf;
  2628.     struct stat *stp;
  2629. {
  2630.     return (buf->b_dev >= 0
  2631.         && stp->st_dev == buf->b_dev
  2632.         && stp->st_ino == buf->b_ino);
  2633. }
  2634. #endif
  2635.  
  2636.     void
  2637. fileinfo(fullname, shorthelp, dont_truncate)
  2638.     int fullname;
  2639.     int shorthelp;
  2640.     int    dont_truncate;
  2641. {
  2642.     char_u    *name;
  2643.     int        n;
  2644.     char_u    *p;
  2645.     char_u    *buffer;
  2646.  
  2647.     buffer = alloc(IOSIZE);
  2648.     if (buffer == NULL)
  2649.     return;
  2650.  
  2651.     if (fullname > 1)        /* 2 CTRL-G: include buffer number */
  2652.     {
  2653.     sprintf((char *)buffer, "buf %d: ", curbuf->b_fnum);
  2654.     p = buffer + STRLEN(buffer);
  2655.     }
  2656.     else
  2657.     p = buffer;
  2658.  
  2659.     *p++ = '"';
  2660.     if (buf_spname(curbuf) != NULL)
  2661.     STRCPY(p, buf_spname(curbuf));
  2662.     else
  2663.     {
  2664.     if (!fullname && curbuf->b_fname != NULL)
  2665.         name = curbuf->b_fname;
  2666.     else
  2667.         name = curbuf->b_ffname;
  2668.     home_replace(shorthelp ? curbuf : NULL, name, p,
  2669.                       (int)(IOSIZE - (p - buffer)), TRUE);
  2670.     }
  2671.  
  2672.     sprintf((char *)buffer + STRLEN(buffer),
  2673.         "\"%s%s%s%s%s%s",
  2674.         curbufIsChanged() ? (shortmess(SHM_MOD)
  2675.                       ?  " [+]" : _(" [Modified]")) : " ",
  2676.         (curbuf->b_flags & BF_NOTEDITED)
  2677. #ifdef FEAT_QUICKFIX
  2678.             && !bt_dontwrite(curbuf)
  2679. #endif
  2680.                     ? _("[Not edited]") : "",
  2681.         (curbuf->b_flags & BF_NEW)
  2682. #ifdef FEAT_QUICKFIX
  2683.             && !bt_dontwrite(curbuf)
  2684. #endif
  2685.                     ? _("[New file]") : "",
  2686.         (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
  2687.         curbuf->b_p_ro ? (shortmess(SHM_RO) ? "[RO]"
  2688.                               : _("[readonly]")) : "",
  2689.         (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
  2690.                               || curbuf->b_p_ro) ?
  2691.                                     " " : "");
  2692.     n = (int)(((long)curwin->w_cursor.lnum * 100L) /
  2693.                         (long)curbuf->b_ml.ml_line_count);
  2694.     if (curbuf->b_ml.ml_flags & ML_EMPTY)
  2695.     {
  2696.     STRCPY(buffer + STRLEN(buffer), _(no_lines_msg));
  2697.     }
  2698. #ifdef FEAT_CMDL_INFO
  2699.     else if (p_ru)
  2700.     {
  2701.     /* Current line and column are already on the screen -- webb */
  2702.     if (curbuf->b_ml.ml_line_count == 1)
  2703.         sprintf((char *)buffer + STRLEN(buffer), _("1 line --%d%%--"), n);
  2704.     else
  2705.         sprintf((char *)buffer + STRLEN(buffer), _("%ld lines --%d%%--"),
  2706.                      (long)curbuf->b_ml.ml_line_count, n);
  2707.     }
  2708. #endif
  2709.     else
  2710.     {
  2711.     sprintf((char *)buffer + STRLEN(buffer),
  2712.         _("line %ld of %ld --%d%%-- col "),
  2713.         (long)curwin->w_cursor.lnum,
  2714.         (long)curbuf->b_ml.ml_line_count,
  2715.         n);
  2716.     validate_virtcol();
  2717.     col_print(buffer + STRLEN(buffer),
  2718.            (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
  2719.     }
  2720.  
  2721.     (void)append_arg_number(curwin, buffer, !shortmess(SHM_FILE), IOSIZE);
  2722.  
  2723.     if (dont_truncate)
  2724.     {
  2725.     /* Temporarily set msg_scroll to avoid the message being truncated.
  2726.      * First call msg_start() to get the message in the right place. */
  2727.     msg_start();
  2728.     n = msg_scroll;
  2729.     msg_scroll = TRUE;
  2730.     msg(buffer);
  2731.     msg_scroll = n;
  2732.     }
  2733.     else
  2734.     {
  2735.     p = msg_trunc_attr(buffer, FALSE, 0);
  2736.     if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
  2737.     {
  2738.         /* Need to repeat the message after redrawing when:
  2739.          * - When restart_edit is set (otherwise there will be a delay
  2740.          *   before redrawing).
  2741.          * - When the screen was scrolled but there is no wait-return
  2742.          *   prompt. */
  2743.         set_keep_msg(p);
  2744.         keep_msg_attr = 0;
  2745.     }
  2746.     }
  2747.  
  2748.     vim_free(buffer);
  2749. }
  2750.  
  2751.     void
  2752. col_print(buf, col, vcol)
  2753.     char_u  *buf;
  2754.     int        col;
  2755.     int        vcol;
  2756. {
  2757.     if (col == vcol)
  2758.     sprintf((char *)buf, "%d", col);
  2759.     else
  2760.     sprintf((char *)buf, "%d-%d", col, vcol);
  2761. }
  2762.  
  2763. #if defined(FEAT_TITLE) || defined(PROTO)
  2764. /*
  2765.  * put file name in title bar of window and in icon title
  2766.  */
  2767.  
  2768. static char_u *lasttitle = NULL;
  2769. static char_u *lasticon = NULL;
  2770.  
  2771.     void
  2772. maketitle()
  2773. {
  2774.     char_u    *p;
  2775.     char_u    *t_str = NULL;
  2776.     char_u    *i_name;
  2777.     char_u    *i_str = NULL;
  2778.     int        maxlen = 0;
  2779.     int        len;
  2780.     int        mustset;
  2781.     char_u    buf[IOSIZE];
  2782.     int        off;
  2783.  
  2784.     need_maketitle = FALSE;
  2785.     if (!p_title && !p_icon)
  2786.     return;
  2787.  
  2788.     if (p_title)
  2789.     {
  2790.     if (p_titlelen > 0)
  2791.     {
  2792.         maxlen = p_titlelen * Columns / 100;
  2793.         if (maxlen < 10)
  2794.         maxlen = 10;
  2795.     }
  2796.  
  2797.     t_str = buf;
  2798.     if (*p_titlestring != NUL)
  2799.     {
  2800. #ifdef FEAT_STL_OPT
  2801.         if (stl_syntax & STL_IN_TITLE)
  2802.         build_stl_str_hl(curwin, t_str, sizeof(buf),
  2803.                           p_titlestring, 0, maxlen, NULL);
  2804.         else
  2805. #endif
  2806.         t_str = p_titlestring;
  2807.     }
  2808.     else
  2809.     {
  2810.         /* format: "fname + (path) (1 of 2) - VIM" */
  2811.  
  2812.         if (curbuf->b_fname == NULL)
  2813.         STRCPY(buf, _("[No file]"));
  2814.         else
  2815.         {
  2816.         p = transstr(gettail(curbuf->b_fname));
  2817.         STRNCPY(buf, p, IOSIZE - 100);
  2818.         vim_free(p);
  2819.         buf[IOSIZE - 100] = NUL; /* in case it was too long */
  2820.         }
  2821.  
  2822.         switch (bufIsChanged(curbuf)
  2823.             + (curbuf->b_p_ro * 2)
  2824.             + (!curbuf->b_p_ma * 4))
  2825.         {
  2826.         case 1: STRCAT(buf, " +"); break;
  2827.         case 2: STRCAT(buf, " ="); break;
  2828.         case 3: STRCAT(buf, " =+"); break;
  2829.         case 4:
  2830.         case 6: STRCAT(buf, " -"); break;
  2831.         case 5:
  2832.         case 7: STRCAT(buf, " -+"); break;
  2833.         }
  2834.  
  2835.         if (curbuf->b_fname != NULL)
  2836.         {
  2837.         /* Get path of file, replace home dir with ~ */
  2838.         off = (int)STRLEN(buf);
  2839.         buf[off++] = ' ';
  2840.         buf[off++] = '(';
  2841.         home_replace(curbuf, curbuf->b_ffname,
  2842.                            buf + off, IOSIZE - off, TRUE);
  2843. #ifdef BACKSLASH_IN_FILENAME
  2844.         /* avoid "c:/name" to be reduced to "c" */
  2845.         if (isalpha(buf[off]) && buf[off + 1] == ':')
  2846.             off += 2;
  2847. #endif
  2848.         /* remove the file name */
  2849.         p = gettail(buf + off);
  2850.         if (p == buf + off)
  2851.         {
  2852.             /* must be a help buffer */
  2853.             STRCPY(buf + off, _("help"));
  2854.         }
  2855.         else
  2856.         {
  2857.             while (p > buf + off + 1 && vim_ispathsep(p[-1]))
  2858.             --p;
  2859. #ifdef VMS
  2860.             /* path separator is part of the path */
  2861.             ++p;
  2862. #endif
  2863.             *p = NUL;
  2864.         }
  2865.         /* translate unprintable chars */
  2866.         p = transstr(buf + off);
  2867.         STRNCPY(buf + off, p, IOSIZE - off);
  2868.         vim_free(p);
  2869.         buf[IOSIZE - 1] = NUL;  /* in case it was too long */
  2870.         STRCAT(buf, ")");
  2871.         }
  2872.  
  2873.         append_arg_number(curwin, buf, FALSE, IOSIZE);
  2874.  
  2875. #if defined(FEAT_CLIENTSERVER)
  2876.         if (serverName != NULL)
  2877.         {
  2878.         STRCAT(buf, " - ");
  2879.         STRCAT(buf, serverName);
  2880.         }
  2881.         else
  2882. #endif
  2883.         STRCAT(buf, " - VIM");
  2884.  
  2885.         if (maxlen > 0)
  2886.         {
  2887.         /* make it shorter by removing a bit in the middle */
  2888.         len = vim_strsize(buf);
  2889.         if (len > maxlen)
  2890.             trunc_string(buf, buf, maxlen);
  2891.         }
  2892.     }
  2893.     }
  2894.     mustset = ti_change(t_str, &lasttitle);
  2895.  
  2896.     if (p_icon)
  2897.     {
  2898.     i_str = buf;
  2899.     if (*p_iconstring != NUL)
  2900.     {
  2901. #ifdef FEAT_STL_OPT
  2902.         if (stl_syntax & STL_IN_ICON)
  2903.         build_stl_str_hl(curwin, i_str, sizeof(buf),
  2904.                             p_iconstring, 0, 0, NULL);
  2905.         else
  2906. #endif
  2907.         i_str = p_iconstring;
  2908.     }
  2909.     else
  2910.     {
  2911.         if (buf_spname(curbuf) != NULL)
  2912.         i_name = (char_u *)buf_spname(curbuf);
  2913.         else            /* use file name only in icon */
  2914.         i_name = gettail(curbuf->b_ffname);
  2915.         *i_str = NUL;
  2916.         /* Truncate name at 100 bytes. */
  2917.         len = STRLEN(i_name);
  2918.         if (len > 100)
  2919.         {
  2920.         len -= 100;
  2921. #ifdef FEAT_MBYTE
  2922.         if (has_mbyte)
  2923.             len += (*mb_tail_off)(i_name, i_name + len) + 1;
  2924. #endif
  2925.         i_name += len;
  2926.         }
  2927.         STRCPY(i_str, i_name);
  2928.         trans_characters(i_str, IOSIZE);
  2929.     }
  2930.     }
  2931.  
  2932.     mustset |= ti_change(i_str, &lasticon);
  2933.  
  2934.     if (mustset)
  2935.     resettitle();
  2936. }
  2937.  
  2938. /*
  2939.  * Used for title and icon: Check if "str" differs from "*last".  Set "*last"
  2940.  * from "str" if it does.
  2941.  * Return TRUE when "*last" changed.
  2942.  */
  2943.     static int
  2944. ti_change(str, last)
  2945.     char_u    *str;
  2946.     char_u    **last;
  2947. {
  2948.     if ((str == NULL) != (*last == NULL)
  2949.         || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
  2950.     {
  2951.     vim_free(*last);
  2952.     if (str == NULL)
  2953.         *last = NULL;
  2954.     else
  2955.         *last = vim_strsave(str);
  2956.     return TRUE;
  2957.     }
  2958.     return FALSE;
  2959. }
  2960.  
  2961. /*
  2962.  * Put current window title back (used after calling a shell)
  2963.  */
  2964.     void
  2965. resettitle()
  2966. {
  2967.     mch_settitle(lasttitle, lasticon);
  2968. }
  2969. #endif /* FEAT_TITLE */
  2970.  
  2971. #if defined(FEAT_STL_OPT) || defined(PROTO)
  2972. /*
  2973.  * Build a string from the status line items in fmt.
  2974.  * Return length of string in screen cells.
  2975.  *
  2976.  * Items are drawn interspersed with the text that surrounds it
  2977.  * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
  2978.  * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
  2979.  *
  2980.  * If maxwidth is not zero, the string will be filled at any middle marker
  2981.  * or truncated if too long, fillchar is used for all whitespace.
  2982.  */
  2983.     int
  2984. build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl)
  2985.     win_T    *wp;
  2986.     char_u    *out;        /* buffer to write into */
  2987.     size_t    outlen;        /* length of out[] */
  2988.     char_u    *fmt;
  2989.     int        fillchar;
  2990.     int        maxwidth;
  2991.     struct stl_hlrec *hl;
  2992. {
  2993.     char_u    *p;
  2994.     char_u    *s;
  2995.     char_u    *t;
  2996.     char_u    *linecont;
  2997. #ifdef FEAT_EVAL
  2998.     win_T    *o_curwin;
  2999.     buf_T    *o_curbuf;
  3000. #endif
  3001.     int        empty_line;
  3002.     colnr_T    virtcol;
  3003.     long    l;
  3004.     long    n;
  3005.     int        prevchar_isflag;
  3006.     int        prevchar_isitem;
  3007.     int        itemisflag;
  3008.     int        fillable;
  3009.     char_u    *str;
  3010.     long    num;
  3011.     int        width;
  3012.     int        itemcnt;
  3013.     int        curitem;
  3014.     int        groupitem[STL_MAX_ITEM];
  3015.     int        groupdepth;
  3016.     struct stl_item
  3017.     {
  3018.     char_u        *start;
  3019.     int        minwid;
  3020.     int        maxwid;
  3021.     enum
  3022.     {
  3023.         Normal,
  3024.         Empty,
  3025.         Group,
  3026.         Middle,
  3027.         Highlight,
  3028.         Trunc
  3029.     }        type;
  3030.     }        item[STL_MAX_ITEM];
  3031.     int        minwid;
  3032.     int        maxwid;
  3033.     int        zeropad;
  3034.     char_u    base;
  3035.     char_u    opt;
  3036. #define TMPLEN 70
  3037.     char_u    tmp[TMPLEN];
  3038.  
  3039.     if (fillchar == 0)
  3040.     fillchar = ' ';
  3041.     /*
  3042.      * Get line & check if empty (cursorpos will show "0-1").
  3043.      * If inversion is possible we use it. Else '=' characters are used.
  3044.      */
  3045.     linecont = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
  3046.     empty_line = (*linecont == NUL);
  3047.  
  3048.     groupdepth = 0;
  3049.     p = out;
  3050.     curitem = 0;
  3051.     prevchar_isflag = TRUE;
  3052.     prevchar_isitem = FALSE;
  3053.     for (s = fmt; *s;)
  3054.     {
  3055.     if (*s != NUL && *s != '%')
  3056.         prevchar_isflag = prevchar_isitem = FALSE;
  3057.  
  3058.     /*
  3059.      * Handle up to the next '%' or the end.
  3060.      */
  3061.     while (*s != NUL && *s != '%' && p + 1 < out + outlen)
  3062.         *p++ = *s++;
  3063.     if (*s == NUL || p + 1 >= out + outlen)
  3064.         break;
  3065.  
  3066.     /*
  3067.      * Handle one '%' item.
  3068.      */
  3069.     s++;
  3070.     if (*s == '%')
  3071.     {
  3072.         if (p + 1 >= out + outlen)
  3073.         break;
  3074.         *p++ = *s++;
  3075.         prevchar_isflag = prevchar_isitem = FALSE;
  3076.         continue;
  3077.     }
  3078.     if (*s == STL_MIDDLEMARK)
  3079.     {
  3080.         s++;
  3081.         if (groupdepth > 0)
  3082.         continue;
  3083.         item[curitem].type = Middle;
  3084.         item[curitem++].start = p;
  3085.         continue;
  3086.     }
  3087.     if (*s == STL_TRUNCMARK)
  3088.     {
  3089.         s++;
  3090.         item[curitem].type = Trunc;
  3091.         item[curitem++].start = p;
  3092.         continue;
  3093.     }
  3094.     if (*s == ')')
  3095.     {
  3096.         s++;
  3097.         if (groupdepth < 1)
  3098.         continue;
  3099.         groupdepth--;
  3100.  
  3101.         t = item[groupitem[groupdepth]].start;
  3102.         *p = NUL;
  3103.         l = vim_strsize(t);
  3104.         if (curitem > groupitem[groupdepth] + 1
  3105.             && item[groupitem[groupdepth]].minwid == 0)
  3106.         {
  3107.         /* remove group if all items are empty */
  3108.         for (n = groupitem[groupdepth] + 1; n < curitem; n++)
  3109.             if (item[n].type == Normal)
  3110.             break;
  3111.         if (n == curitem)
  3112.         {
  3113.             p = t;
  3114.             l = 0;
  3115.         }
  3116.         }
  3117.         if (l > item[groupitem[groupdepth]].maxwid)
  3118.         {
  3119.         /* truncate, remove n bytes of text at the start */
  3120. #ifdef FEAT_MBYTE
  3121.         if (has_mbyte)
  3122.         {
  3123.             /* Find the first character that should be included. */
  3124.             n = 0;
  3125.             while (l >= item[groupitem[groupdepth]].maxwid)
  3126.             {
  3127.             l -= ptr2cells(t + n);
  3128.             n += (*mb_ptr2len_check)(t + n);
  3129.             }
  3130.         }
  3131.         else
  3132. #endif
  3133.             n = (p - t) - item[groupitem[groupdepth]].maxwid + 1;
  3134.  
  3135.         *t = '<';
  3136.         mch_memmove(t + 1, t + n, p - (t + n));
  3137.         p = p - n + 1;
  3138. #ifdef FEAT_MBYTE
  3139.         /* Fill up space left over by half a double-wide char. */
  3140.         while (++l < item[groupitem[groupdepth]].minwid)
  3141.             *p++ = fillchar;
  3142. #endif
  3143.  
  3144.         /* correct the start of the items for the truncation */
  3145.         for (l = groupitem[groupdepth] + 1; l < curitem; l++)
  3146.         {
  3147.             item[l].start -= n;
  3148.             if (item[l].start < t)
  3149.             item[l].start = t;
  3150.         }
  3151.         }
  3152.         else if (abs(item[groupitem[groupdepth]].minwid) > l)
  3153.         {
  3154.         /* fill */
  3155.         n = item[groupitem[groupdepth]].minwid;
  3156.         if (n < 0)
  3157.         {
  3158.             /* fill by appending characters */
  3159.             n = 0 - n;
  3160.             while (l++ < n && p + 1 < out + outlen)
  3161.             *p++ = fillchar;
  3162.         }
  3163.         else
  3164.         {
  3165.             /* fill by inserting characters */
  3166.             mch_memmove(t + n - l, t, p - t);
  3167.             l = n - l;
  3168.             if (p + l >= out + outlen)
  3169.             l = (out + outlen) - p - 1;
  3170.             p += l;
  3171.             for (n = groupitem[groupdepth] + 1; n < curitem; n++)
  3172.             item[n].start += l;
  3173.             for ( ; l > 0; l--)
  3174.             *t++ = fillchar;
  3175.         }
  3176.         }
  3177.         continue;
  3178.     }
  3179.     minwid = 0;
  3180.     maxwid = 9999;
  3181.     zeropad = FALSE;
  3182.     l = 1;
  3183.     if (*s == '0')
  3184.     {
  3185.         s++;
  3186.         zeropad = TRUE;
  3187.     }
  3188.     if (*s == '-')
  3189.     {
  3190.         s++;
  3191.         l = -1;
  3192.     }
  3193.     if (isdigit(*s))
  3194.     {
  3195.         minwid = (int)getdigits(&s);
  3196.         if (minwid < 0)    /* overflow */
  3197.         minwid = 0;
  3198.     }
  3199.     if (*s == STL_HIGHLIGHT)
  3200.     {
  3201.         item[curitem].type = Highlight;
  3202.         item[curitem].start = p;
  3203.         item[curitem].minwid = minwid > 9 ? 1 : minwid;
  3204.         s++;
  3205.         curitem++;
  3206.         continue;
  3207.     }
  3208.     if (*s == '.')
  3209.     {
  3210.         s++;
  3211.         if (isdigit(*s))
  3212.         {
  3213.         maxwid = (int)getdigits(&s);
  3214.         if (maxwid <= 0)    /* overflow */
  3215.             maxwid = 50;
  3216.         }
  3217.     }
  3218.     minwid = (minwid > 50 ? 50 : minwid) * l;
  3219.     if (*s == '(')
  3220.     {
  3221.         groupitem[groupdepth++] = curitem;
  3222.         item[curitem].type = Group;
  3223.         item[curitem].start = p;
  3224.         item[curitem].minwid = minwid;
  3225.         item[curitem].maxwid = maxwid;
  3226.         s++;
  3227.         curitem++;
  3228.         continue;
  3229.     }
  3230.     if (vim_strchr(STL_ALL, *s) == NULL)
  3231.     {
  3232.         s++;
  3233.         continue;
  3234.     }
  3235.     opt = *s++;
  3236.  
  3237.     /* OK - now for the real work */
  3238.     base = 'D';
  3239.     itemisflag = FALSE;
  3240.     fillable = TRUE;
  3241.     num = -1;
  3242.     str = NULL;
  3243.     switch (opt)
  3244.     {
  3245.     case STL_FILEPATH:
  3246.     case STL_FULLPATH:
  3247.     case STL_FILENAME:
  3248.         fillable = FALSE;    /* don't change ' ' to fillchar */
  3249.         if (buf_spname(wp->w_buffer) != NULL)
  3250.         STRCPY(NameBuff, buf_spname(wp->w_buffer));
  3251.         else
  3252.         {
  3253.         t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
  3254.                     : wp->w_buffer->b_fname;
  3255.         home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
  3256.         }
  3257.         trans_characters(NameBuff, MAXPATHL);
  3258.         if (opt != STL_FILENAME)
  3259.         str = NameBuff;
  3260.         else
  3261.         str = gettail(NameBuff);
  3262.         break;
  3263.  
  3264.     case STL_VIM_EXPR: /* '{' */
  3265.         itemisflag = TRUE;
  3266.         t = p;
  3267.         while (*s != '}' && *s != NUL && p + 1 < out + outlen)
  3268.         *p++ = *s++;
  3269.         if (*s != '}')    /* missing '}' or out of space */
  3270.         break;
  3271.         s++;
  3272.         *p = 0;
  3273.         p = t;
  3274.  
  3275. #ifdef FEAT_EVAL
  3276.         sprintf((char *)tmp, "%d", curbuf->b_fnum);
  3277.         set_internal_string_var((char_u *)"actual_curbuf", tmp);
  3278.  
  3279.         o_curbuf = curbuf;
  3280.         o_curwin = curwin;
  3281.         curwin = wp;
  3282.         curbuf = wp->w_buffer;
  3283.  
  3284.         str = eval_to_string_safe(p, &t);
  3285.  
  3286.         curwin = o_curwin;
  3287.         curbuf = o_curbuf;
  3288.         do_unlet((char_u *)"g:actual_curbuf");
  3289.  
  3290.         if (str != NULL && *str != 0)
  3291.         {
  3292.         if (*skipdigits(str) == NUL)
  3293.         {
  3294.             num = atoi((char *)str);
  3295.             vim_free(str);
  3296.             str = NULL;
  3297.             itemisflag = FALSE;
  3298.         }
  3299.         }
  3300. #endif
  3301.         break;
  3302.  
  3303.     case STL_LINE:
  3304.         num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  3305.           ? 0L : (long)(wp->w_cursor.lnum);
  3306.         break;
  3307.  
  3308.     case STL_NUMLINES:
  3309.         num = wp->w_buffer->b_ml.ml_line_count;
  3310.         break;
  3311.  
  3312.     case STL_COLUMN:
  3313.         num = !(State & INSERT) && empty_line
  3314.           ? 0 : (int)wp->w_cursor.col + 1;
  3315.         break;
  3316.  
  3317.     case STL_VIRTCOL:
  3318.     case STL_VIRTCOL_ALT:
  3319.         /* In list mode virtcol needs to be recomputed */
  3320.         virtcol = wp->w_virtcol;
  3321.         if (wp->w_p_list && lcs_tab1 == NUL)
  3322.         {
  3323.         wp->w_p_list = FALSE;
  3324.         getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
  3325.         wp->w_p_list = TRUE;
  3326.         }
  3327.         ++virtcol;
  3328.         /* Don't display %V if it's the same as %c. */
  3329.         if (opt == STL_VIRTCOL_ALT
  3330.             && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
  3331.                 ? 0 : (int)wp->w_cursor.col + 1)))
  3332.         break;
  3333.         num = (long)virtcol;
  3334.         break;
  3335.  
  3336.     case STL_PERCENTAGE:
  3337.         num = (int)(((long)wp->w_cursor.lnum * 100L) /
  3338.             (long)wp->w_buffer->b_ml.ml_line_count);
  3339.         break;
  3340.  
  3341.     case STL_ALTPERCENT:
  3342.         str = tmp;
  3343.         get_rel_pos(wp, str);
  3344.         break;
  3345.  
  3346.     case STL_ARGLISTSTAT:
  3347.         fillable = FALSE;
  3348.         tmp[0] = 0;
  3349.         if (append_arg_number(wp, tmp, FALSE, (int)sizeof(tmp)))
  3350.         str = tmp;
  3351.         break;
  3352.  
  3353.     case STL_KEYMAP:
  3354.         fillable = FALSE;
  3355.         if (get_keymap_str(wp, tmp, TMPLEN))
  3356.         str = tmp;
  3357.         break;
  3358.     case STL_PAGENUM:
  3359. #ifdef FEAT_PRINTER
  3360.         num = get_printer_page_num();
  3361. #else
  3362.         num = 0;
  3363. #endif
  3364.         break;
  3365.  
  3366.     case STL_BUFNO:
  3367.         num = wp->w_buffer->b_fnum;
  3368.         break;
  3369.  
  3370.     case STL_OFFSET_X:
  3371.         base = 'X';
  3372.     case STL_OFFSET:
  3373. #ifdef FEAT_BYTEOFF
  3374.         l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
  3375.         num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
  3376.           0L : l + 1 + (!(State & INSERT) && empty_line ?
  3377.                 0 : (int)wp->w_cursor.col);
  3378. #endif
  3379.         break;
  3380.  
  3381.     case STL_BYTEVAL_X:
  3382.         base = 'X';
  3383.     case STL_BYTEVAL:
  3384.         if (((State & INSERT) && wp == curwin) || empty_line)
  3385.         num = 0;
  3386.         else
  3387.         {
  3388. #ifdef FEAT_MBYTE
  3389.         num = (*mb_ptr2char)(linecont + wp->w_cursor.col);
  3390. #else
  3391.         num = linecont[wp->w_cursor.col];
  3392. #endif
  3393.         }
  3394.         if (num == NL)
  3395.         num = 0;
  3396.         else if (num == CR && get_fileformat(wp->w_buffer) == EOL_MAC)
  3397.         num = NL;
  3398.         break;
  3399.  
  3400.     case STL_ROFLAG:
  3401.     case STL_ROFLAG_ALT:
  3402.         itemisflag = TRUE;
  3403.         if (wp->w_buffer->b_p_ro)
  3404.         str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : "[RO]");
  3405.         break;
  3406.  
  3407.     case STL_HELPFLAG:
  3408.     case STL_HELPFLAG_ALT:
  3409.         itemisflag = TRUE;
  3410.         if (wp->w_buffer->b_help)
  3411.         str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
  3412.                                    : _("[help]"));
  3413.         break;
  3414.  
  3415. #ifdef FEAT_AUTOCMD
  3416.     case STL_FILETYPE:
  3417.         if (*wp->w_buffer->b_p_ft != NUL
  3418.             && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
  3419.         {
  3420.         sprintf((char *)tmp, "[%s]", wp->w_buffer->b_p_ft);
  3421.         str = tmp;
  3422.         }
  3423.         break;
  3424.  
  3425.     case STL_FILETYPE_ALT:
  3426.         itemisflag = TRUE;
  3427.         if (*wp->w_buffer->b_p_ft != NUL
  3428.             && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
  3429.         {
  3430.         sprintf((char *)tmp, ",%s", wp->w_buffer->b_p_ft);
  3431.         for (t = tmp; *t != 0; t++)
  3432.             *t = TOUPPER_LOC(*t);
  3433.         str = tmp;
  3434.         }
  3435.         break;
  3436. #endif
  3437.  
  3438. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  3439.     case STL_PREVIEWFLAG:
  3440.     case STL_PREVIEWFLAG_ALT:
  3441.         itemisflag = TRUE;
  3442.         if (wp->w_p_pvw)
  3443.         str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
  3444.                                 : _("[Preview]"));
  3445.         break;
  3446. #endif
  3447.  
  3448.     case STL_MODIFIED:
  3449.     case STL_MODIFIED_ALT:
  3450.         itemisflag = TRUE;
  3451.         switch ((opt == STL_MODIFIED_ALT)
  3452.             + bufIsChanged(wp->w_buffer) * 2
  3453.             + (!wp->w_buffer->b_p_ma) * 4)
  3454.         {
  3455.         case 2: str = (char_u *)"[+]"; break;
  3456.         case 3: str = (char_u *)",+"; break;
  3457.         case 4: str = (char_u *)"[-]"; break;
  3458.         case 5: str = (char_u *)",-"; break;
  3459.         case 6: str = (char_u *)"[+-]"; break;
  3460.         case 7: str = (char_u *)",+-"; break;
  3461.         }
  3462.         break;
  3463.     }
  3464.  
  3465.     item[curitem].start = p;
  3466.     item[curitem].type = Normal;
  3467.     if (str != NULL && *str)
  3468.     {
  3469.         t = str;
  3470.         if (itemisflag)
  3471.         {
  3472.         if ((t[0] && t[1])
  3473.             && ((!prevchar_isitem && *t == ',')
  3474.                   || (prevchar_isflag && *t == ' ')))
  3475.             t++;
  3476.         prevchar_isflag = TRUE;
  3477.         }
  3478.         l = vim_strsize(t);
  3479.         if (l > 0)
  3480.         prevchar_isitem = TRUE;
  3481.         if (l > maxwid)
  3482.         {
  3483.         while (l >= maxwid)
  3484. #ifdef FEAT_MBYTE
  3485.             if (has_mbyte)
  3486.             {
  3487.             l -= ptr2cells(s);
  3488.             t += (*mb_ptr2len_check)(t);
  3489.             }
  3490.             else
  3491. #endif
  3492.             l -= byte2cells(*t++);
  3493.         if (p + 1 >= out + outlen)
  3494.             break;
  3495.         *p++ = '<';
  3496.         }
  3497.         if (minwid > 0)
  3498.         {
  3499.         for (; l < minwid && p + 1 < out + outlen; l++)
  3500.         {
  3501.             /* Don't put a "-" in front of a digit. */
  3502.             if (l + 1 == minwid && fillchar == '-' && isdigit(*t))
  3503.             *p++ = ' ';
  3504.             else
  3505.             *p++ = fillchar;
  3506.         }
  3507.         minwid = 0;
  3508.         }
  3509.         else
  3510.         minwid *= -1;
  3511.         while (*t && p + 1 < out + outlen)
  3512.         {
  3513.         *p++ = *t++;
  3514.         /* Change a space by fillchar, unless fillchar is '-' and a
  3515.          * digit follows. */
  3516.         if (fillable && p[-1] == ' '
  3517.                      && (!isdigit(*t) || fillchar != '-'))
  3518.             p[-1] = fillchar;
  3519.         }
  3520.         for (; l < minwid && p + 1 < out + outlen; l++)
  3521.         *p++ = fillchar;
  3522.     }
  3523.     else if (num >= 0)
  3524.     {
  3525.         int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
  3526.         char_u nstr[20];
  3527.  
  3528.         if (p + 20 >= out + outlen)
  3529.         break;        /* not sufficient space */
  3530.         prevchar_isitem = TRUE;
  3531.         t = nstr;
  3532.         if (opt == STL_VIRTCOL_ALT)
  3533.         {
  3534.         *t++ = '-';
  3535.         minwid--;
  3536.         }
  3537.         *t++ = '%';
  3538.         if (zeropad)
  3539.         *t++ = '0';
  3540.         *t++ = '*';
  3541.         *t++ = nbase == 16 ? base : (nbase == 8 ? 'o' : 'd');
  3542.         *t = 0;
  3543.  
  3544.         for (n = num, l = 1; n >= nbase; n /= nbase)
  3545.         l++;
  3546.         if (opt == STL_VIRTCOL_ALT)
  3547.         l++;
  3548.         if (l > maxwid)
  3549.         {
  3550.         l += 2;
  3551.         n = l - maxwid;
  3552.         while (l-- > maxwid)
  3553.             num /= nbase;
  3554.         *t++ = '>';
  3555.         *t++ = '%';
  3556.         *t = t[-3];
  3557.         *++t = 0;
  3558.         sprintf((char *)p, (char *)nstr, 0, num, n);
  3559.         }
  3560.         else
  3561.         sprintf((char *)p, (char *)nstr, minwid, num);
  3562.         p += STRLEN(p);
  3563.     }
  3564.     else
  3565.         item[curitem].type = Empty;
  3566.  
  3567.     if (opt == STL_VIM_EXPR)
  3568.         vim_free(str);
  3569.  
  3570.     if (num >= 0 || (!itemisflag && str && *str))
  3571.         prevchar_isflag = FALSE;        /* Item not NULL, but not a flag */
  3572.     curitem++;
  3573.     }
  3574.     *p = NUL;
  3575.     itemcnt = curitem;
  3576.  
  3577.     width = vim_strsize(out);
  3578.     if (maxwidth > 0 && width > maxwidth)
  3579.     {
  3580.     /* Result is too long, must trunctate somewhere. */
  3581.     l = 0;
  3582.     if (itemcnt == 0)
  3583.         s = out;
  3584.     else
  3585.     {
  3586.         for ( ; l < itemcnt; l++)
  3587.         if (item[l].type == Trunc)
  3588.         {
  3589.             /* Truncate at %< item. */
  3590.             s = item[l].start;
  3591.             break;
  3592.         }
  3593.         if (l == itemcnt)
  3594.         {
  3595.         /* No %< item, truncate first item. */
  3596.         s = item[0].start;
  3597.         l = 0;
  3598.         }
  3599.     }
  3600.  
  3601.     if (width - vim_strsize(s) >= maxwidth)
  3602.     {
  3603.         /* Truncation mark is beyond max length */
  3604. #ifdef FEAT_MBYTE
  3605.         if (has_mbyte)
  3606.         {
  3607.         s = out;
  3608.         width = 0;
  3609.         for (;;)
  3610.         {
  3611.             width += ptr2cells(s);
  3612.             if (width >= maxwidth)
  3613.             break;
  3614.             s += (*mb_ptr2len_check)(s);
  3615.         }
  3616.         /* Fill up for half a double-wide character. */
  3617.         while (++width < maxwidth)
  3618.             *s++ = fillchar;
  3619.         }
  3620.         else
  3621. #endif
  3622.         s = out + maxwidth - 1;
  3623.         for (l = 0; l < itemcnt; l++)
  3624.         if (item[l].start > s)
  3625.             break;
  3626.         itemcnt = l;
  3627.         *s++ = '>';
  3628.         *s = 0;
  3629.     }
  3630.     else
  3631.     {
  3632. #ifdef FEAT_MBYTE
  3633.         if (has_mbyte)
  3634.         {
  3635.         n = 0;
  3636.         while (width >= maxwidth)
  3637.         {
  3638.             width -= ptr2cells(s + n);
  3639.             n += (*mb_ptr2len_check)(s + n);
  3640.         }
  3641.         }
  3642.         else
  3643. #endif
  3644.         n = width - maxwidth + 1;
  3645.         p = s + n;
  3646.         mch_memmove(s + 1, p, STRLEN(p) + 1);
  3647.         *s = '<';
  3648.  
  3649.         /* Fill up for half a double-wide character. */
  3650.         while (++width < maxwidth)
  3651.         {
  3652.         s = s + STRLEN(s);
  3653.         *s++ = fillchar;
  3654.         *s = NUL;
  3655.         }
  3656.  
  3657.         --n;    /* count the '<' */
  3658.         for (; l < itemcnt; l++)
  3659.         {
  3660.         if (item[l].start - n >= s)
  3661.             item[l].start -= n;
  3662.         else
  3663.             item[l].start = s;
  3664.         }
  3665.     }
  3666.     width = maxwidth;
  3667.     }
  3668.     else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
  3669.     {
  3670.     /* Apply STL_MIDDLE if any */
  3671.     for (l = 0; l < itemcnt; l++)
  3672.         if (item[l].type == Middle)
  3673.         break;
  3674.     if (l < itemcnt)
  3675.     {
  3676.         p = item[l].start + maxwidth - width;
  3677.         mch_memmove(p, item[l].start, STRLEN(item[l].start) + 1);
  3678.         for (s = item[l].start; s < p; s++)
  3679.         *s = fillchar;
  3680.         for (l++; l < itemcnt; l++)
  3681.         item[l].start += maxwidth - width;
  3682.         width = maxwidth;
  3683.     }
  3684.     }
  3685.  
  3686.     if (hl != NULL)
  3687.     {
  3688.     for (l = 0; l < itemcnt; l++)
  3689.     {
  3690.         if (item[l].type == Highlight)
  3691.         {
  3692.         hl->start = item[l].start;
  3693.         hl->userhl = item[l].minwid;
  3694.         hl++;
  3695.         }
  3696.     }
  3697.     hl->start = NULL;
  3698.     hl->userhl = 0;
  3699.     }
  3700.  
  3701.     return width;
  3702. }
  3703. #endif /* FEAT_STL_OPT */
  3704.  
  3705. #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) || defined(PROTO)
  3706. /*
  3707.  * Get relative cursor position in window, in the form 99%, using "Top", "Bot"
  3708.  * or "All" when appropriate.
  3709.  */
  3710.     void
  3711. get_rel_pos(wp, str)
  3712.     win_T    *wp;
  3713.     char_u    *str;
  3714. {
  3715.     long    above; /* number of lines above window */
  3716.     long    below; /* number of lines below window */
  3717.  
  3718.     above = wp->w_topline - 1;
  3719. #ifdef FEAT_DIFF
  3720.     above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
  3721. #endif
  3722.     below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
  3723.     if (below <= 0)
  3724.     STRCPY(str, above == 0 ? _("All") : _("Bot"));
  3725.     else if (above <= 0)
  3726.     STRCPY(str, _("Top"));
  3727.     else
  3728.     sprintf((char *)str, "%2d%%",
  3729.         (int)(above * 100 / (above + below)));
  3730. }
  3731. #endif
  3732.  
  3733. /*
  3734.  * Append (file 2 of 8) to 'buf', if editing more than one file.
  3735.  * Return TRUE if it was appended.
  3736.  */
  3737.     int
  3738. append_arg_number(wp, buf, add_file, maxlen)
  3739.     win_T    *wp;
  3740.     char_u    *buf;
  3741.     int        add_file;    /* Add "file" before the arg number */
  3742.     int        maxlen;        /* maximum nr of chars in buf or zero*/
  3743. {
  3744.     char_u    *p;
  3745.  
  3746.     if (ARGCOUNT <= 1)        /* nothing to do */
  3747.     return FALSE;
  3748.  
  3749.     p = buf + STRLEN(buf);        /* go to the end of the buffer */
  3750.     if (maxlen && p - buf + 35 >= maxlen) /* getting too long */
  3751.     return FALSE;
  3752.     *p++ = ' ';
  3753.     *p++ = '(';
  3754.     if (add_file)
  3755.     {
  3756.     STRCPY(p, "file ");
  3757.     p += 5;
  3758.     }
  3759.     sprintf((char *)p, wp->w_arg_idx_invalid ? "(%d) of %d)"
  3760.                   : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
  3761.     return TRUE;
  3762. }
  3763.  
  3764. /*
  3765.  * If fname is not a full path, make it a full path.
  3766.  * Returns pointer to allocated memory (NULL for failure).
  3767.  */
  3768.     char_u  *
  3769. fix_fname(fname)
  3770.     char_u  *fname;
  3771. {
  3772.     /*
  3773.      * Force expanding the path always for Unix, because symbolic links may
  3774.      * mess up the full path name, even though it starts with a '/'.
  3775.      * Also expand when there is ".." in the file name, try to remove it,
  3776.      * because "c:/src/../README" is equal to "c:/README".
  3777.      * For MS-Windows also expand names like "longna~1" to "longname".
  3778.      */
  3779. #ifdef UNIX
  3780.     return FullName_save(fname, TRUE);
  3781. #else
  3782.     if (!vim_isAbsName(fname) || strstr((char *)fname, "..") != NULL
  3783. #if defined(MSWIN) || defined(DJGPP)
  3784.         || vim_strchr(fname, '~') != NULL
  3785. #endif
  3786.         )
  3787.     return FullName_save(fname, FALSE);
  3788.  
  3789.     fname = vim_strsave(fname);
  3790.  
  3791. #ifdef USE_FNAME_CASE
  3792. # ifdef USE_LONG_FNAME
  3793.     if (USE_LONG_FNAME)
  3794. # endif
  3795.     {
  3796.     if (fname != NULL)
  3797.         fname_case(fname, 0);    /* set correct case for file name */
  3798.     }
  3799. #endif
  3800.  
  3801.     return fname;
  3802. #endif
  3803. }
  3804.  
  3805. /*
  3806.  * make ffname a full file name, set sfname to ffname if not NULL
  3807.  * ffname becomes a pointer to allocated memory (or NULL).
  3808.  */
  3809.     void
  3810. fname_expand(ffname, sfname)
  3811.     char_u    **ffname;
  3812.     char_u    **sfname;
  3813. {
  3814.     if (*ffname == NULL)    /* if no file name given, nothing to do */
  3815.     return;
  3816.     if (*sfname == NULL)    /* if no short file name given, use ffname */
  3817.     *sfname = *ffname;
  3818.     *ffname = fix_fname(*ffname);   /* expand to full path */
  3819.  
  3820. #ifdef FEAT_SHORTCUT
  3821.     if (!curbuf->b_p_bin)
  3822.     {
  3823.     char_u  *rfname = NULL;
  3824.  
  3825.     /* If the file name is a shortcut file, use the file it links to. */
  3826.     rfname = mch_resolve_shortcut(*ffname);
  3827.     if (rfname)
  3828.     {
  3829.         vim_free(*ffname);
  3830.         *ffname = rfname;
  3831.         *sfname = rfname;
  3832.     }
  3833.     }
  3834. #endif
  3835. }
  3836.  
  3837. /*
  3838.  * Get the file name for an argument list entry.
  3839.  */
  3840.     char_u *
  3841. alist_name(aep)
  3842.     aentry_T    *aep;
  3843. {
  3844.     buf_T    *bp;
  3845.  
  3846.     /* Use the name from the associated buffer if it exists. */
  3847.     bp = buflist_findnr(aep->ae_fnum);
  3848.     if (bp == NULL)
  3849.     return aep->ae_fname;
  3850.     return bp->b_fname;
  3851. }
  3852.  
  3853. #if defined(FEAT_WINDOWS) || defined(PROTO)
  3854. /*
  3855.  * do_arg_all(): Open up to 'count' windows, one for each argument.
  3856.  */
  3857.     void
  3858. do_arg_all(count, forceit)
  3859.     int    count;
  3860.     int    forceit;        /* hide buffers in current windows */
  3861. {
  3862.     int        i;
  3863.     win_T    *wp, *wpnext;
  3864.     char_u    *opened;    /* array of flags for which args are open */
  3865.     int        opened_len;    /* lenght of opened[] */
  3866.     int        use_firstwin = FALSE;    /* use first window for arglist */
  3867.     int        split_ret = OK;
  3868.     int        p_ea_save;
  3869.     alist_T    *alist;        /* argument list to be used */
  3870.     buf_T    *buf;
  3871.  
  3872.     if (ARGCOUNT <= 0)
  3873.     {
  3874.     /* Don't give an error message.  We don't want it when the ":all"
  3875.      * command is in the .vimrc. */
  3876.     return;
  3877.     }
  3878.     setpcmark();
  3879.  
  3880.     opened_len = ARGCOUNT;
  3881.     opened = alloc_clear((unsigned)opened_len);
  3882.     if (opened == NULL)
  3883.     return;
  3884.  
  3885. #ifdef FEAT_GUI
  3886.     need_mouse_correct = TRUE;
  3887. #endif
  3888.  
  3889.     /*
  3890.      * Try closing all windows that are not in the argument list.
  3891.      * Also close windows that are not full width;
  3892.      * When 'hidden' or "forceit" set the buffer becomes hidden.
  3893.      * Windows that have a changed buffer and can't be hidden won't be closed.
  3894.      */
  3895.     for (wp = firstwin; wp != NULL; wp = wpnext)
  3896.     {
  3897.     wpnext = wp->w_next;
  3898.     buf = wp->w_buffer;
  3899.     if (buf->b_ffname == NULL
  3900.         || buf->b_nwindows > 1
  3901. #ifdef FEAT_VERTSPLIT
  3902.         || wp->w_width != Columns
  3903. #endif
  3904.         )
  3905.         i = ARGCOUNT;
  3906.     else
  3907.     {
  3908.         /* check if the buffer in this window is in the arglist */
  3909.         for (i = 0; i < ARGCOUNT; ++i)
  3910.         {
  3911.         if (ARGLIST[i].ae_fnum == buf->b_fnum
  3912.             || fullpathcmp(alist_name(&ARGLIST[i]),
  3913.                           buf->b_ffname, TRUE) & FPC_SAME)
  3914.         {
  3915.             if (i < opened_len)
  3916.             opened[i] = TRUE;
  3917.             if (wp->w_alist != curwin->w_alist)
  3918.             {
  3919.             /* Use the current argument list for all windows
  3920.              * containing a file from it. */
  3921.             alist_unlink(wp->w_alist);
  3922.             wp->w_alist = curwin->w_alist;
  3923.             ++wp->w_alist->al_refcount;
  3924.             }
  3925.             break;
  3926.         }
  3927.         }
  3928.     }
  3929.     wp->w_arg_idx = i;
  3930.  
  3931.     if (i == ARGCOUNT)        /* close this window */
  3932.     {
  3933.         if (P_HID(buf) || forceit || buf->b_nwindows > 1
  3934.                             || !bufIsChanged(buf))
  3935.         {
  3936.         /* If the buffer was changed, and we would like to hide it,
  3937.          * try autowriting. */
  3938.         if (!P_HID(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf))
  3939.         {
  3940.             (void)autowrite(buf, FALSE);
  3941. #ifdef FEAT_AUTOCMD
  3942.             /* check if autocommands removed the window */
  3943.             if (!win_valid(wp) || !buf_valid(buf))
  3944.             {
  3945.             wpnext = firstwin;    /* start all over... */
  3946.             continue;
  3947.             }
  3948. #endif
  3949.         }
  3950. #ifdef FEAT_WINDOWS
  3951.         if (firstwin == lastwin)    /* can't close last window */
  3952. #endif
  3953.             use_firstwin = TRUE;
  3954. #ifdef FEAT_WINDOWS
  3955.         else
  3956.         {
  3957.             win_close(wp, !P_HID(buf) && !bufIsChanged(buf));
  3958. # ifdef FEAT_AUTOCMD
  3959.             /* check if autocommands removed the next window */
  3960.             if (!win_valid(wpnext))
  3961.             wpnext = firstwin;    /* start all over... */
  3962. # endif
  3963.         }
  3964. #endif
  3965.         }
  3966.     }
  3967.     }
  3968.  
  3969.     /*
  3970.      * Open a window for files in the argument list that don't have one.
  3971.      * ARGCOUNT may change while doing this, because of autocommands.
  3972.      */
  3973.     if (count > ARGCOUNT || count <= 0)
  3974.     count = ARGCOUNT;
  3975.  
  3976.     /* Autocommands may do anything to the argument list.  Make sure it's not
  3977.      * freed while we are working here by "locking" it.  We still have to
  3978.      * watch out for its size to be changed. */
  3979.     alist = curwin->w_alist;
  3980.     ++alist->al_refcount;
  3981.  
  3982. #ifdef FEAT_AUTOCMD
  3983.     /* Don't execute Win/Buf Enter/Leave autocommands here. */
  3984.     ++autocmd_no_enter;
  3985.     ++autocmd_no_leave;
  3986. #endif
  3987.     win_enter(lastwin, FALSE);
  3988.     for (i = 0; i < count && i < alist->al_ga.ga_len && !got_int; ++i)
  3989.     {
  3990.     if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
  3991.         arg_had_last = TRUE;
  3992.     if (i < opened_len && opened[i])
  3993.     {
  3994.         /* Move the already present window to below the current window */
  3995.         if (curwin->w_arg_idx != i)
  3996.         {
  3997.         for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
  3998.         {
  3999.             if (wpnext->w_arg_idx == i)
  4000.             {
  4001.             win_move_after(wpnext, curwin);
  4002.             break;
  4003.             }
  4004.         }
  4005.         }
  4006.     }
  4007.     else if (split_ret == OK)
  4008.     {
  4009.         if (!use_firstwin)        /* split current window */
  4010.         {
  4011.         p_ea_save = p_ea;
  4012.         p_ea = TRUE;        /* use space from all windows */
  4013.         split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
  4014.         p_ea = p_ea_save;
  4015.         if (split_ret == FAIL)
  4016.             continue;
  4017.         }
  4018. #ifdef FEAT_AUTOCMD
  4019.         else    /* first window: do autocmd for leaving this buffer */
  4020.         --autocmd_no_leave;
  4021. #endif
  4022.  
  4023.         /*
  4024.          * edit file i
  4025.          */
  4026.         curwin->w_arg_idx = i;
  4027.         (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
  4028.               ECMD_ONE,
  4029.               ((P_HID(curwin->w_buffer)
  4030.                || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
  4031.                                    + ECMD_OLDBUF);
  4032. #ifdef FEAT_AUTOCMD
  4033.         if (use_firstwin)
  4034.         ++autocmd_no_leave;
  4035. #endif
  4036.         use_firstwin = FALSE;
  4037.     }
  4038.     ui_breakcheck();
  4039.     }
  4040.  
  4041.     /* Remove the "lock" on the argument list. */
  4042.     alist_unlink(alist);
  4043.  
  4044. #ifdef FEAT_AUTOCMD
  4045.     --autocmd_no_enter;
  4046. #endif
  4047.     win_enter(firstwin, FALSE);            /* back to first window */
  4048. #ifdef FEAT_AUTOCMD
  4049.     --autocmd_no_leave;
  4050. #endif
  4051. }
  4052.  
  4053. # if defined(FEAT_LISTCMDS) || defined(PROTO)
  4054. /*
  4055.  * Open a window for a number of buffers.
  4056.  */
  4057.     void
  4058. ex_buffer_all(eap)
  4059.     exarg_T    *eap;
  4060. {
  4061.     buf_T    *buf;
  4062.     win_T    *wp, *wpnext;
  4063.     int        split_ret = OK;
  4064.     int        p_ea_save;
  4065.     int        open_wins = 0;
  4066.     int        r;
  4067.     int        count;        /* Maximum number of windows to open. */
  4068.     int        all;        /* When TRUE also load inactive buffers. */
  4069.  
  4070.     if (eap->addr_count == 0)    /* make as many windows as possible */
  4071.     count = 9999;
  4072.     else
  4073.     count = eap->line2;    /* make as many windows as specified */
  4074.     if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
  4075.     all = FALSE;
  4076.     else
  4077.     all = TRUE;
  4078.  
  4079.     setpcmark();
  4080.  
  4081. #ifdef FEAT_GUI
  4082.     need_mouse_correct = TRUE;
  4083. #endif
  4084.  
  4085.     /*
  4086.      * Close superfluous windows (two windows for the same buffer).
  4087.      * Also close windows that are not full-width.
  4088.      */
  4089.     for (wp = firstwin; wp != NULL; wp = wpnext)
  4090.     {
  4091.     wpnext = wp->w_next;
  4092.     if (wp->w_buffer->b_nwindows > 1
  4093. #ifdef FEAT_VERTSPLIT
  4094.         || ((cmdmod.split & WSP_VERT)
  4095.               ? wp->w_height + wp->w_status_height < Rows - p_ch
  4096.               : wp->w_width != Columns)
  4097. #endif
  4098.         )
  4099.     {
  4100.         win_close(wp, FALSE);
  4101. #ifdef FEAT_AUTOCMD
  4102.         wpnext = firstwin;    /* just in case an autocommand does something
  4103.                    strange with windows */
  4104.         open_wins = 0;
  4105. #endif
  4106.     }
  4107.     else
  4108.         ++open_wins;
  4109.     }
  4110.  
  4111.     /*
  4112.      * Go through the buffer list.  When a buffer doesn't have a window yet,
  4113.      * open one.  Otherwise move the window to the right position.
  4114.      * Watch out for autocommands that delete buffers or windows!
  4115.      */
  4116. #ifdef FEAT_AUTOCMD
  4117.     /* Don't execute Win/Buf Enter/Leave autocommands here. */
  4118.     ++autocmd_no_enter;
  4119. #endif
  4120.     win_enter(lastwin, FALSE);
  4121. #ifdef FEAT_AUTOCMD
  4122.     ++autocmd_no_leave;
  4123. #endif
  4124.     for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
  4125.     {
  4126.     /* Check if this buffer needs a window */
  4127.     if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
  4128.         continue;
  4129.  
  4130.     /* Check if this buffer already has a window */
  4131.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  4132.         if (wp->w_buffer == buf)
  4133.         break;
  4134.     /* If the buffer already has a window, move it */
  4135.     if (wp != NULL)
  4136.         win_move_after(wp, curwin);
  4137.     else if (split_ret == OK)
  4138.     {
  4139.         /* Split the window and put the buffer in it */
  4140.         p_ea_save = p_ea;
  4141.         p_ea = TRUE;        /* use space from all windows */
  4142.         split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
  4143.         ++open_wins;
  4144.         p_ea = p_ea_save;
  4145.         if (split_ret == FAIL)
  4146.         continue;
  4147.  
  4148.         /* Open the buffer in this window. */
  4149. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  4150.         swap_exists_action = SEA_DIALOG;
  4151. #endif
  4152.         set_curbuf(buf, DOBUF_GOTO);
  4153. #ifdef FEAT_AUTOCMD
  4154. # ifdef FEAT_EVAL
  4155.         /* Autocommands deleted the buffer or aborted script
  4156.          * processing!!! */
  4157.         if (!buf_valid(buf) || aborting())
  4158. # else
  4159.         if (!buf_valid(buf))    /* autocommands deleted the buffer!!! */
  4160. # endif
  4161.         {
  4162. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  4163.         swap_exists_action = SEA_NONE;
  4164. #endif
  4165.         break;
  4166.         }
  4167. #endif
  4168. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  4169.         if (swap_exists_action == SEA_QUIT)
  4170.         {
  4171.         /* User selected Quit at ATTENTION prompt; close this window. */
  4172.         win_close(curwin, TRUE);
  4173.         --open_wins;
  4174.         swap_exists_action = SEA_NONE;
  4175.         }
  4176.         else
  4177.         handle_swap_exists(NULL);
  4178. #endif
  4179.     }
  4180.  
  4181.     ui_breakcheck();
  4182.     if (got_int)
  4183.     {
  4184.         (void)vgetc();    /* only break the file loading, not the rest */
  4185.         break;
  4186.     }
  4187.     }
  4188. #ifdef FEAT_AUTOCMD
  4189.     --autocmd_no_enter;
  4190. #endif
  4191.     win_enter(firstwin, FALSE);        /* back to first window */
  4192. #ifdef FEAT_AUTOCMD
  4193.     --autocmd_no_leave;
  4194. #endif
  4195.  
  4196.     /*
  4197.      * Close superfluous windows.
  4198.      */
  4199.     for (wp = lastwin; open_wins > count; )
  4200.     {
  4201.     r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
  4202.                      || autowrite(wp->w_buffer, FALSE) == OK);
  4203. #ifdef FEAT_AUTOCMD
  4204.     if (!win_valid(wp))
  4205.     {
  4206.         /* BufWrite Autocommands made the window invalid, start over */
  4207.         wp = lastwin;
  4208.     }
  4209.     else
  4210. #endif
  4211.         if (r)
  4212.     {
  4213.         win_close(wp, !P_HID(wp->w_buffer));
  4214.         --open_wins;
  4215.         wp = lastwin;
  4216.     }
  4217.     else
  4218.     {
  4219.         wp = wp->w_prev;
  4220.         if (wp == NULL)
  4221.         break;
  4222.     }
  4223.     }
  4224. }
  4225. # endif /* FEAT_LISTCMDS */
  4226.  
  4227. #endif /* FEAT_WINDOWS */
  4228.  
  4229. /*
  4230.  * do_modelines() - process mode lines for the current file
  4231.  *
  4232.  * Returns immediately if the "ml" option isn't set.
  4233.  */
  4234. static int  chk_modeline __ARGS((linenr_T));
  4235.  
  4236.     void
  4237. do_modelines()
  4238. {
  4239.     linenr_T        lnum;
  4240.     int            nmlines;
  4241.     static int        entered = 0;
  4242.  
  4243.     if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
  4244.     return;
  4245.  
  4246.     /* Disallow recursive entry here.  Can happen when executing a modeline
  4247.      * triggers an autocommand, which reloads modelines with a ":do". */
  4248.     if (entered)
  4249.     return;
  4250.  
  4251.     ++entered;
  4252.     for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
  4253.                                        ++lnum)
  4254.     if (chk_modeline(lnum) == FAIL)
  4255.         nmlines = 0;
  4256.  
  4257.     for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
  4258.                && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
  4259.     if (chk_modeline(lnum) == FAIL)
  4260.         nmlines = 0;
  4261.     --entered;
  4262. }
  4263.  
  4264. #include "version.h"        /* for version number */
  4265.  
  4266. /*
  4267.  * chk_modeline() - check a single line for a mode string
  4268.  * Return FAIL if an error encountered.
  4269.  */
  4270.     static int
  4271. chk_modeline(lnum)
  4272.     linenr_T    lnum;
  4273. {
  4274.     char_u    *s;
  4275.     char_u    *e;
  4276.     char_u    *linecopy;        /* local copy of any modeline found */
  4277.     int        prev;
  4278.     int        vers;
  4279.     int        end;
  4280.     int        retval = OK;
  4281.     char_u    *save_sourcing_name;
  4282.     linenr_T    save_sourcing_lnum;
  4283. #ifdef FEAT_EVAL
  4284.     scid_T    save_SID;
  4285. #endif
  4286.  
  4287.     prev = -1;
  4288.     for (s = ml_get(lnum); *s != NUL; ++s)
  4289.     {
  4290.     if (prev == -1 || vim_isspace(prev))
  4291.     {
  4292.         if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
  4293.             || STRNCMP(s, "vi:", (size_t)3) == 0)
  4294.         break;
  4295.         if (STRNCMP(s, "vim", 3) == 0)
  4296.         {
  4297.         if (s[3] == '<' || s[3] == '=' || s[3] == '>')
  4298.             e = s + 4;
  4299.         else
  4300.             e = s + 3;
  4301.         vers = getdigits(&e);
  4302.         if (*e == ':'
  4303.             && (s[3] == ':'
  4304.                 || (VIM_VERSION_100 >= vers && isdigit(s[3]))
  4305.                 || (VIM_VERSION_100 < vers && s[3] == '<')
  4306.                 || (VIM_VERSION_100 > vers && s[3] == '>')
  4307.                 || (VIM_VERSION_100 == vers && s[3] == '=')))
  4308.             break;
  4309.         }
  4310.     }
  4311.     prev = *s;
  4312.     }
  4313.  
  4314.     if (*s)
  4315.     {
  4316.     do                /* skip over "ex:", "vi:" or "vim:" */
  4317.         ++s;
  4318.     while (s[-1] != ':');
  4319.  
  4320.     s = linecopy = vim_strsave(s);    /* copy the line, it will change */
  4321.     if (linecopy == NULL)
  4322.         return FAIL;
  4323.  
  4324.     save_sourcing_lnum = sourcing_lnum;
  4325.     save_sourcing_name = sourcing_name;
  4326.     sourcing_lnum = lnum;        /* prepare for emsg() */
  4327.     sourcing_name = (char_u *)"modelines";
  4328.  
  4329.     end = FALSE;
  4330.     while (end == FALSE)
  4331.     {
  4332.         s = skipwhite(s);
  4333.         if (*s == NUL)
  4334.         break;
  4335.  
  4336.         /*
  4337.          * Find end of set command: ':' or end of line.
  4338.          * Skip over "\:", replacing it with ":".
  4339.          */
  4340.         for (e = s; *e != ':' && *e != NUL; ++e)
  4341.         if (e[0] == '\\' && e[1] == ':')
  4342.             STRCPY(e, e + 1);
  4343.         if (*e == NUL)
  4344.         end = TRUE;
  4345.  
  4346.         /*
  4347.          * If there is a "set" command, require a terminating ':' and
  4348.          * ignore the stuff after the ':'.
  4349.          * "vi:set opt opt opt: foo" -- foo not interpreted
  4350.          * "vi:opt opt opt: foo" -- foo interpreted
  4351.          * Accept "se" for compatibility with Elvis.
  4352.          */
  4353.         if (STRNCMP(s, "set ", (size_t)4) == 0
  4354.             || STRNCMP(s, "se ", (size_t)3) == 0)
  4355.         {
  4356.         if (*e != ':')        /* no terminating ':'? */
  4357.             break;
  4358.         end = TRUE;
  4359.         s = vim_strchr(s, ' ') + 1;
  4360.         }
  4361.         *e = NUL;            /* truncate the set command */
  4362.  
  4363.         if (*s != NUL)        /* skip over an empty "::" */
  4364.         {
  4365. #ifdef FEAT_EVAL
  4366.         save_SID = current_SID;
  4367.         current_SID = SID_MODELINE;
  4368. #endif
  4369.         retval = do_set(s, OPT_MODELINE | OPT_LOCAL);
  4370. #ifdef FEAT_EVAL
  4371.         current_SID = save_SID;
  4372. #endif
  4373.         if (retval == FAIL)        /* stop if error found */
  4374.             break;
  4375.         }
  4376.         s = e + 1;            /* advance to next part */
  4377.     }
  4378.  
  4379.     sourcing_lnum = save_sourcing_lnum;
  4380.     sourcing_name = save_sourcing_name;
  4381.  
  4382.     vim_free(linecopy);
  4383.     }
  4384.     return retval;
  4385. }
  4386.  
  4387. #ifdef FEAT_VIMINFO
  4388.     int
  4389. read_viminfo_bufferlist(virp, writing)
  4390.     vir_T    *virp;
  4391.     int        writing;
  4392. {
  4393.     char_u    *tab;
  4394.     linenr_T    lnum;
  4395.     colnr_T    col;
  4396.     buf_T    *buf;
  4397.     char_u    *sfname;
  4398.     char_u    *xline;
  4399.  
  4400.     /* Handle long line and escaped characters. */
  4401.     xline = viminfo_readstring(virp, 1, FALSE);
  4402.  
  4403.     /* don't read in if there are files on the command-line or if writing: */
  4404.     if (xline != NULL && !writing && ARGCOUNT == 0
  4405.                        && find_viminfo_parameter('%') != NULL)
  4406.     {
  4407.     /* Format is: <fname> Tab <lnum> Tab <col>.
  4408.      * Watch out for a Tab in the file name, work from the end. */
  4409.     lnum = 0;
  4410.     col = 0;
  4411.     tab = vim_strrchr(xline, '\t');
  4412.     if (tab != NULL)
  4413.     {
  4414.         *tab++ = '\0';
  4415.         col = atoi((char *)tab);
  4416.         tab = vim_strrchr(xline, '\t');
  4417.         if (tab != NULL)
  4418.         {
  4419.         *tab++ = '\0';
  4420.         lnum = atol((char *)tab);
  4421.         }
  4422.     }
  4423.  
  4424.     /* Expand "~/" in the file name at "line + 1" to a full path.
  4425.      * Then try shortening it by comparing with the current directory */
  4426.     expand_env(xline, NameBuff, MAXPATHL);
  4427.     mch_dirname(IObuff, IOSIZE);
  4428.     sfname = shorten_fname(NameBuff, IObuff);
  4429.     if (sfname == NULL)
  4430.         sfname = NameBuff;
  4431.  
  4432.     buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
  4433.     if (buf != NULL)    /* just in case... */
  4434.     {
  4435.         buf->b_last_cursor.lnum = lnum;
  4436.         buf->b_last_cursor.col = col;
  4437.         buflist_setfpos(buf, curwin, lnum, col, FALSE);
  4438.     }
  4439.     }
  4440.     vim_free(xline);
  4441.  
  4442.     return viminfo_readline(virp);
  4443. }
  4444.  
  4445.     void
  4446. write_viminfo_bufferlist(fp)
  4447.     FILE    *fp;
  4448. {
  4449.     buf_T    *buf;
  4450. #ifdef FEAT_WINDOWS
  4451.     win_T    *win;
  4452. #endif
  4453.     char_u    *line;
  4454.  
  4455.     if (find_viminfo_parameter('%') == NULL)
  4456.     return;
  4457.  
  4458.     /* Allocate room for the file name, lnum and col. */
  4459.     line = alloc(MAXPATHL + 30);
  4460.     if (line == NULL)
  4461.     return;
  4462.  
  4463. #ifdef FEAT_WINDOWS
  4464.     for (win = firstwin; win != NULL; win = win->w_next)
  4465.     set_last_cursor(win);
  4466. #else
  4467.     set_last_cursor(curwin);
  4468. #endif
  4469.  
  4470.     fprintf(fp, _("\n# Buffer list:\n"));
  4471.     for (buf = firstbuf; buf != NULL ; buf = buf->b_next)
  4472.     {
  4473.     if (buf->b_fname == NULL
  4474.         || !buf->b_p_bl
  4475. #ifdef FEAT_QUICKFIX
  4476.         || bt_quickfix(buf)
  4477. #endif
  4478.         || removable(buf->b_ffname))
  4479.         continue;
  4480.  
  4481.     putc('%', fp);
  4482.     home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
  4483.     sprintf((char *)line + STRLEN(line), "\t%ld\t%d",
  4484.             (long)buf->b_last_cursor.lnum,
  4485.             buf->b_last_cursor.col);
  4486.     viminfo_writestring(fp, line);
  4487.     }
  4488.     vim_free(line);
  4489. }
  4490. #endif
  4491.  
  4492.  
  4493. /*
  4494.  * Return special buffer name.
  4495.  * Returns NULL when the buffer has a normal file name.
  4496.  */
  4497.     char *
  4498. buf_spname(buf)
  4499.     buf_T    *buf;
  4500. {
  4501. #if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
  4502.     if (bt_quickfix(buf))
  4503.     return _("[Error List]");
  4504. #endif
  4505. #ifdef FEAT_QUICKFIX
  4506.     /* There is no _file_ when 'buftype' is "nofile", b_sfname
  4507.      * contains the name as specified by the user */
  4508.     if (bt_nofile(buf))
  4509.     {
  4510.     if (buf->b_sfname != NULL)
  4511.         return (char *)buf->b_sfname;
  4512.     return "[Scratch]";
  4513.     }
  4514. #endif
  4515.     if (buf->b_fname == NULL)
  4516.     return _("[No File]");
  4517.     return NULL;
  4518. }
  4519.  
  4520.  
  4521. #if defined(FEAT_SIGNS) || defined(PROTO)
  4522.  
  4523. static void insert_sign __ARGS((buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr));
  4524.  
  4525. /*
  4526.  * Insert the sign into the signlist.
  4527.  */
  4528.     static void
  4529. insert_sign(buf, prev, next, id, lnum, typenr)
  4530.     buf_T    *buf;        /* buffer to store sign in */
  4531.     signlist_T    *prev;        /* previous sign entry */
  4532.     signlist_T    *next;        /* next sign entry */
  4533.     int        id;        /* sign ID */
  4534.     linenr_T    lnum;        /* line number which gets the mark */
  4535.     int        typenr;        /* typenr of sign we are adding */
  4536. {
  4537.     signlist_T    *newsign;
  4538.  
  4539.     newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE);
  4540.     if (newsign != NULL)
  4541.     {
  4542.     newsign->id = id;
  4543.     newsign->lnum = lnum;
  4544.     newsign->typenr = typenr;
  4545.     newsign->next = next;
  4546. #ifdef FEAT_NETBEANS_INTG
  4547.     newsign->prev = prev;
  4548.     if (next != NULL)
  4549.         next->prev = newsign;
  4550. #endif
  4551.  
  4552.     if (prev == NULL)
  4553.     {
  4554.         /* When adding first sign need to redraw the windows to create the
  4555.          * column for signs. */
  4556.         if (buf->b_signlist == NULL)
  4557.         {
  4558.         redraw_buf_later(buf, NOT_VALID);
  4559.         changed_cline_bef_curs();
  4560.         }
  4561.  
  4562.         /* first sign in signlist */
  4563.         buf->b_signlist = newsign;
  4564.     }
  4565.     else
  4566.         prev->next = newsign;
  4567.     }
  4568. }
  4569.  
  4570. /*
  4571.  * Add the sign into the signlist. Find the right spot to do it though.
  4572.  */
  4573.     void
  4574. buf_addsign(buf, id, lnum, typenr)
  4575.     buf_T    *buf;        /* buffer to store sign in */
  4576.     int        id;        /* sign ID */
  4577.     linenr_T    lnum;        /* line number which gets the mark */
  4578.     int        typenr;        /* typenr of sign we are adding */
  4579. {
  4580.     signlist_T    *sign;        /* a sign in the signlist */
  4581.     signlist_T    *prev;        /* the previous sign */
  4582.  
  4583.     prev = NULL;
  4584.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4585.     {
  4586.     if (lnum == sign->lnum && id == sign->id)
  4587.     {
  4588.         sign->typenr = typenr;
  4589.         return;
  4590.     }
  4591.     else if (
  4592. #ifndef FEAT_NETBEANS_INTG  /* keep signs sorted by lnum */
  4593.            id < 0 &&
  4594. #endif
  4595.                  lnum < sign->lnum)
  4596.     {
  4597. #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
  4598.         /* XXX - GRP: Is this because of sign slide problem? Or is it
  4599.          * really needed? Or is it because we allow multiple signs per
  4600.          * line? If so, should I add that feature to FEAT_SIGNS?
  4601.          */
  4602.         while (prev != NULL && prev->lnum == lnum)
  4603.         prev = prev->prev;
  4604.         if (prev == NULL)
  4605.         sign = buf->b_signlist;
  4606.         else
  4607.         sign = prev->next;
  4608. #endif
  4609.         insert_sign(buf, prev, sign, id, lnum, typenr);
  4610.         return;
  4611.     }
  4612.     prev = sign;
  4613.     }
  4614. #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
  4615.     /* XXX - GRP: See previous comment */
  4616.     while (prev != NULL && prev->lnum == lnum)
  4617.     prev = prev->prev;
  4618.     if (prev == NULL)
  4619.     sign = buf->b_signlist;
  4620.     else
  4621.     sign = prev->next;
  4622. #endif
  4623.     insert_sign(buf, prev, sign, id, lnum, typenr);
  4624.  
  4625.     return;
  4626. }
  4627.  
  4628.     int
  4629. buf_change_sign_type(buf, markId, typenr)
  4630.     buf_T    *buf;        /* buffer to store sign in */
  4631.     int        markId;        /* sign ID */
  4632.     int        typenr;        /* typenr of sign we are adding */
  4633. {
  4634.     signlist_T    *sign;        /* a sign in the signlist */
  4635.  
  4636.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4637.     {
  4638.     if (sign->id == markId)
  4639.     {
  4640.         sign->typenr = typenr;
  4641.         return sign->lnum;
  4642.     }
  4643.     }
  4644.  
  4645.     return 0;
  4646. }
  4647.  
  4648.     int_u
  4649. buf_getsigntype(buf, lnum, type)
  4650.     buf_T    *buf;
  4651.     linenr_T    lnum;
  4652.     int        type;    /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
  4653. {
  4654.     signlist_T    *sign;        /* a sign in a b_signlist */
  4655.  
  4656.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4657.     if (sign->lnum == lnum
  4658.         && (type == SIGN_ANY
  4659. # ifdef FEAT_SIGN_ICONS
  4660.             || (type == SIGN_ICON
  4661.             && sign_get_image(sign->typenr) != NULL)
  4662. # endif
  4663.             || (type == SIGN_TEXT
  4664.             && sign_get_text(sign->typenr) != NULL)
  4665.             || (type == SIGN_LINEHL
  4666.             && sign_get_attr(sign->typenr, TRUE) != 0)))
  4667.         return sign->typenr;
  4668.     return 0;
  4669. }
  4670.  
  4671.  
  4672.     linenr_T
  4673. buf_delsign(buf, id)
  4674.     buf_T    *buf;        /* buffer sign is stored in */
  4675.     int        id;        /* sign id */
  4676. {
  4677.     signlist_T    **lastp;    /* pointer to pointer to current sign */
  4678.     signlist_T    *sign;        /* a sign in a b_signlist */
  4679.     signlist_T    *next;        /* the next sign in a b_signlist */
  4680.     linenr_T    lnum;        /* line number whose sign was deleted */
  4681.  
  4682.     lastp = &buf->b_signlist;
  4683.     lnum = 0;
  4684.     for (sign = buf->b_signlist; sign != NULL; sign = next)
  4685.     {
  4686.     next = sign->next;
  4687.     if (sign->id == id)
  4688.     {
  4689.         *lastp = next;
  4690. #ifdef FEAT_NETBEANS_INTG
  4691.         if (next != NULL)
  4692.         next->prev = sign->prev;
  4693. #endif
  4694.         lnum = sign->lnum;
  4695.         vim_free(sign);
  4696.         break;
  4697.     }
  4698.     else
  4699.         lastp = &sign->next;
  4700.     }
  4701.  
  4702.     /* When deleted the last sign need to redraw the windows to remove the
  4703.      * sign column. */
  4704.     if (buf->b_signlist == NULL)
  4705.     {
  4706.     redraw_buf_later(buf, NOT_VALID);
  4707.     changed_cline_bef_curs();
  4708.     }
  4709.  
  4710.     return lnum;
  4711. }
  4712.  
  4713.  
  4714. /*
  4715.  * Find the line number of the sign with the requested id. If the sign does
  4716.  * not exist, return 0 as the line number. This will still let the correct file
  4717.  * get loaded.
  4718.  */
  4719.     int
  4720. buf_findsign(buf, id)
  4721.     buf_T    *buf;        /* buffer to store sign in */
  4722.     int        id;        /* sign ID */
  4723. {
  4724.     signlist_T    *sign;        /* a sign in the signlist */
  4725.  
  4726.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4727.     if (sign->id == id)
  4728.         return sign->lnum;
  4729.  
  4730.     return 0;
  4731. }
  4732.  
  4733.     int
  4734. buf_findsign_id(buf, lnum)
  4735.     buf_T    *buf;        /* buffer whose sign we are searching for */
  4736.     linenr_T    lnum;        /* line number of sign */
  4737. {
  4738.     signlist_T    *sign;        /* a sign in the signlist */
  4739.  
  4740.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4741.     if (sign->lnum == lnum)
  4742.         return sign->id;
  4743.  
  4744.     return 0;
  4745. }
  4746.  
  4747.  
  4748. # if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
  4749. /* see if a given type of sign exists on a specific line */
  4750.     int
  4751. buf_findsigntype_id(buf, lnum, typenr)
  4752.     buf_T    *buf;        /* buffer whose sign we are searching for */
  4753.     linenr_T    lnum;        /* line number of sign */
  4754.     int        typenr;        /* sign type number */
  4755. {
  4756.     signlist_T    *sign;        /* a sign in the signlist */
  4757.  
  4758.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4759.     if (sign->lnum == lnum && sign->typenr == typenr)
  4760.         return sign->id;
  4761.  
  4762.     return 0;
  4763. }
  4764.  
  4765.  
  4766. #  if defined(FEAT_SIGN_ICONS) || defined(PROTO)
  4767. /* return the number of icons on the given line */
  4768.     int
  4769. buf_signcount(buf, lnum)
  4770.     buf_T    *buf;
  4771.     linenr_T    lnum;
  4772. {
  4773.     signlist_T    *sign;        /* a sign in the signlist */
  4774.     int        count = 0;
  4775.  
  4776.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4777.     if (sign->lnum == lnum)
  4778.         if (sign_get_image(sign->typenr) != NULL)
  4779.         count++;
  4780.  
  4781.     return count;
  4782. }
  4783. #  endif /* FEAT_SIGN_ICONS */
  4784. # endif /* FEAT_NETBEANS_INTG */
  4785.  
  4786.  
  4787.     void
  4788. buf_delete_all_signs()
  4789. {
  4790.     buf_T    *buf;        /* buffer we are checking for signs */
  4791.     signlist_T    *sign;        /* a sign in a b_signlist */
  4792.     signlist_T    *next;        /* the next sign in a b_signlist */
  4793.  
  4794.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  4795.     if (buf->b_signlist != NULL)
  4796.     {
  4797.         /* Need to redraw the windows to remove the sign column. */
  4798.         redraw_buf_later(buf, NOT_VALID);
  4799.         for (sign = buf->b_signlist; sign != NULL; sign = next)
  4800.         {
  4801.         next = sign->next;
  4802.         vim_free(sign);
  4803.         }
  4804.         buf->b_signlist = NULL;
  4805.     }
  4806. }
  4807.  
  4808. /*
  4809.  * List placed signs for "rbuf".  If "rbuf" is NULL do it for all buffers.
  4810.  */
  4811.     void
  4812. sign_list_placed(rbuf)
  4813.     buf_T    *rbuf;
  4814. {
  4815.     buf_T    *buf;
  4816.     signlist_T    *p;
  4817.     char    lbuf[BUFSIZ];
  4818.  
  4819.     MSG_PUTS_TITLE(_("\n--- Signs ---"));
  4820.     msg_putchar('\n');
  4821.     if (rbuf == NULL)
  4822.     buf = firstbuf;
  4823.     else
  4824.     buf = rbuf;
  4825.     while (buf != NULL)
  4826.     {
  4827.     if (buf->b_signlist != NULL)
  4828.     {
  4829. #ifdef HAVE_SNPRINTF
  4830.         snprintf
  4831. #else
  4832.         sprintf
  4833. #endif
  4834.         (lbuf,
  4835. #ifdef HAVE_SNPRINTF
  4836.          BUFSIZ,
  4837. #endif
  4838.             _("Signs for %s:"), buf->b_fname);
  4839.         MSG_PUTS_ATTR(lbuf, hl_attr(HLF_D));
  4840.         msg_putchar('\n');
  4841.     }
  4842.     for (p = buf->b_signlist; p != NULL; p = p->next)
  4843.     {
  4844.         sprintf(lbuf, _("    line=%ld  id=%d  name=%s"),
  4845.                (long)p->lnum, p->id, sign_typenr2name(p->typenr));
  4846.         MSG_PUTS(lbuf);
  4847.         msg_putchar('\n');
  4848.     }
  4849.     if (rbuf != NULL)
  4850.         break;
  4851.     buf = buf->b_next;
  4852.     }
  4853. }
  4854.  
  4855. /*
  4856.  * Adjust a placed sign for inserted/deleted lines.
  4857.  */
  4858.     void
  4859. sign_mark_adjust(line1, line2, amount, amount_after)
  4860.     linenr_T    line1;
  4861.     linenr_T    line2;
  4862.     long    amount;
  4863.     long    amount_after;
  4864. {
  4865.     signlist_T    *sign;        /* a sign in a b_signlist */
  4866.  
  4867.     for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next)
  4868.     {
  4869.     if (sign->lnum >= line1 && sign->lnum <= line2)
  4870.     {
  4871.         if (amount == MAXLNUM)
  4872.         sign->lnum = line1;
  4873.         else
  4874.         sign->lnum += amount;
  4875.     }
  4876.     else if (sign->lnum > line2)
  4877.         sign->lnum += amount_after;
  4878.     }
  4879. }
  4880. #endif /* FEAT_SIGNS */
  4881.  
  4882. /*
  4883.  * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
  4884.  */
  4885.     void
  4886. set_buflisted(on)
  4887.     int        on;
  4888. {
  4889.     if (on != curbuf->b_p_bl)
  4890.     {
  4891.     curbuf->b_p_bl = on;
  4892. #ifdef FEAT_AUTOCMD
  4893.     if (on)
  4894.         apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
  4895.     else
  4896.         apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
  4897. #endif
  4898.     }
  4899. }
  4900.  
  4901. /*
  4902.  * Read the file for "buf" again and check if the contents changed.
  4903.  * Return TRUE if it changed or this could not be checked.
  4904.  */
  4905.     int
  4906. buf_contents_changed(buf)
  4907.     buf_T    *buf;
  4908. {
  4909.     buf_T    *newbuf;
  4910.     int        differ = TRUE;
  4911.     linenr_T    lnum;
  4912. #ifdef FEAT_AUTOCMD
  4913.     aco_save_T    aco;
  4914. #else
  4915.     buf_T    *old_curbuf = curbuf;
  4916. #endif
  4917.     exarg_T    ea;
  4918.  
  4919.     /* Allocate a buffer without putting it in the buffer list. */
  4920.     newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
  4921.     if (newbuf == NULL)
  4922.     return TRUE;
  4923.  
  4924.     /* Force the 'fileencoding' and 'fileformat' to be equal. */
  4925.     if (prep_exarg(&ea, buf) == FAIL)
  4926.     {
  4927.     wipe_buffer(newbuf, FALSE);
  4928.     return TRUE;
  4929.     }
  4930.  
  4931. #ifdef FEAT_AUTOCMD
  4932.     /* set curwin/curbuf to buf and save a few things */
  4933.     aucmd_prepbuf(&aco, newbuf);
  4934. #else
  4935.     curbuf = newbuf;
  4936.     curwin->w_buffer = newbuf;
  4937. #endif
  4938.  
  4939.     if (ml_open() == OK
  4940.         && readfile(buf->b_ffname, buf->b_fname,
  4941.                   (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
  4942.                         &ea, READ_NEW | READ_DUMMY) == OK)
  4943.     {
  4944.     /* compare the two files line by line */
  4945.     if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
  4946.     {
  4947.         differ = FALSE;
  4948.         for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
  4949.         if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
  4950.         {
  4951.             differ = TRUE;
  4952.             break;
  4953.         }
  4954.     }
  4955.     }
  4956.     vim_free(ea.cmd);
  4957.  
  4958. #ifdef FEAT_AUTOCMD
  4959.     /* restore curwin/curbuf and a few other things */
  4960.     aucmd_restbuf(&aco);
  4961. #else
  4962.     curbuf = old_curbuf;
  4963.     curwin->w_buffer = old_curbuf;
  4964. #endif
  4965.  
  4966.     if (curbuf != newbuf)    /* safety check */
  4967.     wipe_buffer(newbuf, FALSE);
  4968.  
  4969.     return differ;
  4970. }
  4971.  
  4972. /*
  4973.  * Wipe out a buffer and decrement the last buffer number if it was used for
  4974.  * this buffer.  Call this to wipe out a temp buffer that does not contain any
  4975.  * marks.
  4976.  */
  4977. /*ARGSUSED*/
  4978.     void
  4979. wipe_buffer(buf, aucmd)
  4980.     buf_T    *buf;
  4981.     int        aucmd;        /* When TRUE trigger autocommands. */
  4982. {
  4983.     if (buf->b_fnum == top_file_num - 1)
  4984.     --top_file_num;
  4985.  
  4986. #ifdef FEAT_AUTOCMD
  4987.     if (!aucmd)            /* Don't trigger BufDelete autocommands here. */
  4988.     ++autocmd_block;
  4989. #endif
  4990.     close_buffer(NULL, buf, DOBUF_WIPE);
  4991. #ifdef FEAT_AUTOCMD
  4992.     if (!aucmd)
  4993.     --autocmd_block;
  4994. #endif
  4995. }
  4996.