xref: /vim-8.2.3635/src/buffer.c (revision b2a76ec0)
1 /* vi:set ts=8 sts=4 sw=4 noet:
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 #include "vim.h"
29 
30 #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
31 static char_u	*buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
32 # define HAVE_BUFLIST_MATCH
33 static char_u	*fname_match(regmatch_T *rmp, char_u *name, int ignore_case);
34 #endif
35 static void	buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options);
36 static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer);
37 #ifdef UNIX
38 static buf_T	*buflist_findname_stat(char_u *ffname, stat_T *st);
39 static int	otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp);
40 static int	buf_same_ino(buf_T *buf, stat_T *stp);
41 #else
42 static int	otherfile_buf(buf_T *buf, char_u *ffname);
43 #endif
44 #ifdef FEAT_TITLE
45 static int	ti_change(char_u *str, char_u **last);
46 #endif
47 static int	append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file);
48 static void	free_buffer(buf_T *);
49 static void	free_buffer_stuff(buf_T *buf, int free_options);
50 static void	clear_wininfo(buf_T *buf);
51 
52 #ifdef UNIX
53 # define dev_T dev_t
54 #else
55 # define dev_T unsigned
56 #endif
57 
58 #if defined(FEAT_SIGNS)
59 static void insert_sign(buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr);
60 #endif
61 
62 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
63 static char *msg_loclist = N_("[Location List]");
64 static char *msg_qflist = N_("[Quickfix List]");
65 #endif
66 #ifdef FEAT_AUTOCMD
67 static char *e_auabort = N_("E855: Autocommands caused command to abort");
68 #endif
69 
70 /* Number of times free_buffer() was called. */
71 static int	buf_free_count = 0;
72 
73 /* Read data from buffer for retrying. */
74     static int
75 read_buffer(
76     int		read_stdin,	    /* read file from stdin, otherwise fifo */
77     exarg_T	*eap,		    /* for forced 'ff' and 'fenc' or NULL */
78     int		flags)		    /* extra flags for readfile() */
79 {
80     int		retval = OK;
81     linenr_T	line_count;
82 
83     /*
84      * Read from the buffer which the text is already filled in and append at
85      * the end.  This makes it possible to retry when 'fileformat' or
86      * 'fileencoding' was guessed wrong.
87      */
88     line_count = curbuf->b_ml.ml_line_count;
89     retval = readfile(
90 	    read_stdin ? NULL : curbuf->b_ffname,
91 	    read_stdin ? NULL : curbuf->b_fname,
92 	    (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
93 	    flags | READ_BUFFER);
94     if (retval == OK)
95     {
96 	/* Delete the binary lines. */
97 	while (--line_count >= 0)
98 	    ml_delete((linenr_T)1, FALSE);
99     }
100     else
101     {
102 	/* Delete the converted lines. */
103 	while (curbuf->b_ml.ml_line_count > line_count)
104 	    ml_delete(line_count, FALSE);
105     }
106     /* Put the cursor on the first line. */
107     curwin->w_cursor.lnum = 1;
108     curwin->w_cursor.col = 0;
109 
110     if (read_stdin)
111     {
112 	/* Set or reset 'modified' before executing autocommands, so that
113 	 * it can be changed there. */
114 	if (!readonlymode && !BUFEMPTY())
115 	    changed();
116 	else if (retval == OK)
117 	    unchanged(curbuf, FALSE);
118 
119 #ifdef FEAT_AUTOCMD
120 	if (retval == OK)
121 	{
122 # ifdef FEAT_EVAL
123 	    apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
124 							curbuf, &retval);
125 # else
126 	    apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
127 # endif
128 	}
129 #endif
130     }
131     return retval;
132 }
133 
134 /*
135  * Open current buffer, that is: open the memfile and read the file into
136  * memory.
137  * Return FAIL for failure, OK otherwise.
138  */
139     int
140 open_buffer(
141     int		read_stdin,	    /* read file from stdin */
142     exarg_T	*eap,		    /* for forced 'ff' and 'fenc' or NULL */
143     int		flags)		    /* extra flags for readfile() */
144 {
145     int		retval = OK;
146 #ifdef FEAT_AUTOCMD
147     bufref_T	old_curbuf;
148 #endif
149 #ifdef FEAT_SYN_HL
150     long	old_tw = curbuf->b_p_tw;
151 #endif
152     int		read_fifo = FALSE;
153 
154     /*
155      * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
156      * When re-entering the same buffer, it should not change, because the
157      * user may have reset the flag by hand.
158      */
159     if (readonlymode && curbuf->b_ffname != NULL
160 					&& (curbuf->b_flags & BF_NEVERLOADED))
161 	curbuf->b_p_ro = TRUE;
162 
163     if (ml_open(curbuf) == FAIL)
164     {
165 	/*
166 	 * There MUST be a memfile, otherwise we can't do anything
167 	 * If we can't create one for the current buffer, take another buffer
168 	 */
169 	close_buffer(NULL, curbuf, 0, FALSE);
170 	FOR_ALL_BUFFERS(curbuf)
171 	    if (curbuf->b_ml.ml_mfp != NULL)
172 		break;
173 	/*
174 	 * if there is no memfile at all, exit
175 	 * This is OK, since there are no changes to lose.
176 	 */
177 	if (curbuf == NULL)
178 	{
179 	    EMSG(_("E82: Cannot allocate any buffer, exiting..."));
180 	    getout(2);
181 	}
182 	EMSG(_("E83: Cannot allocate buffer, using other one..."));
183 	enter_buffer(curbuf);
184 #ifdef FEAT_SYN_HL
185 	if (old_tw != curbuf->b_p_tw)
186 	    check_colorcolumn(curwin);
187 #endif
188 	return FAIL;
189     }
190 
191 #ifdef FEAT_AUTOCMD
192     /* The autocommands in readfile() may change the buffer, but only AFTER
193      * reading the file. */
194     set_bufref(&old_curbuf, curbuf);
195     modified_was_set = FALSE;
196 #endif
197 
198     /* mark cursor position as being invalid */
199     curwin->w_valid = 0;
200 
201     if (curbuf->b_ffname != NULL
202 #ifdef FEAT_NETBEANS_INTG
203 	    && netbeansReadFile
204 #endif
205        )
206     {
207 	int old_msg_silent = msg_silent;
208 #ifdef UNIX
209 	int save_bin = curbuf->b_p_bin;
210 	int perm;
211 #endif
212 #ifdef FEAT_NETBEANS_INTG
213 	int oldFire = netbeansFireChanges;
214 
215 	netbeansFireChanges = 0;
216 #endif
217 #ifdef UNIX
218 	perm = mch_getperm(curbuf->b_ffname);
219 	if (perm >= 0 && (0
220 # ifdef S_ISFIFO
221 		      || S_ISFIFO(perm)
222 # endif
223 # ifdef S_ISSOCK
224 		      || S_ISSOCK(perm)
225 # endif
226 # ifdef OPEN_CHR_FILES
227 		      || (S_ISCHR(perm) && is_dev_fd_file(curbuf->b_ffname))
228 # endif
229 		    ))
230 		read_fifo = TRUE;
231 	if (read_fifo)
232 	    curbuf->b_p_bin = TRUE;
233 #endif
234 	if (shortmess(SHM_FILEINFO))
235 	    msg_silent = 1;
236 	retval = readfile(curbuf->b_ffname, curbuf->b_fname,
237 		  (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
238 		  flags | READ_NEW | (read_fifo ? READ_FIFO : 0));
239 #ifdef UNIX
240 	if (read_fifo)
241 	{
242 	    curbuf->b_p_bin = save_bin;
243 	    if (retval == OK)
244 		retval = read_buffer(FALSE, eap, flags);
245 	}
246 #endif
247 	msg_silent = old_msg_silent;
248 #ifdef FEAT_NETBEANS_INTG
249 	netbeansFireChanges = oldFire;
250 #endif
251 	/* Help buffer is filtered. */
252 	if (curbuf->b_help)
253 	    fix_help_buffer();
254     }
255     else if (read_stdin)
256     {
257 	int	save_bin = curbuf->b_p_bin;
258 
259 	/*
260 	 * First read the text in binary mode into the buffer.
261 	 * Then read from that same buffer and append at the end.  This makes
262 	 * it possible to retry when 'fileformat' or 'fileencoding' was
263 	 * guessed wrong.
264 	 */
265 	curbuf->b_p_bin = TRUE;
266 	retval = readfile(NULL, NULL, (linenr_T)0,
267 		  (linenr_T)0, (linenr_T)MAXLNUM, NULL,
268 		  flags | (READ_NEW + READ_STDIN));
269 	curbuf->b_p_bin = save_bin;
270 	if (retval == OK)
271 	    retval = read_buffer(TRUE, eap, flags);
272     }
273 
274     /* if first time loading this buffer, init b_chartab[] */
275     if (curbuf->b_flags & BF_NEVERLOADED)
276     {
277 	(void)buf_init_chartab(curbuf, FALSE);
278 #ifdef FEAT_CINDENT
279 	parse_cino(curbuf);
280 #endif
281     }
282 
283     /*
284      * Set/reset the Changed flag first, autocmds may change the buffer.
285      * Apply the automatic commands, before processing the modelines.
286      * So the modelines have priority over auto commands.
287      */
288     /* When reading stdin, the buffer contents always needs writing, so set
289      * the changed flag.  Unless in readonly mode: "ls | gview -".
290      * When interrupted and 'cpoptions' contains 'i' set changed flag. */
291     if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
292 #ifdef FEAT_AUTOCMD
293 		|| modified_was_set	/* ":set modified" used in autocmd */
294 # ifdef FEAT_EVAL
295 		|| (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
296 # endif
297 #endif
298        )
299 	changed();
300     else if (retval == OK && !read_stdin && !read_fifo)
301 	unchanged(curbuf, FALSE);
302     save_file_ff(curbuf);		/* keep this fileformat */
303 
304     /* require "!" to overwrite the file, because it wasn't read completely */
305 #ifdef FEAT_EVAL
306     if (aborting())
307 #else
308     if (got_int)
309 #endif
310 	curbuf->b_flags |= BF_READERR;
311 
312 #ifdef FEAT_FOLDING
313     /* Need to update automatic folding.  Do this before the autocommands,
314      * they may use the fold info. */
315     foldUpdateAll(curwin);
316 #endif
317 
318 #ifdef FEAT_AUTOCMD
319     /* need to set w_topline, unless some autocommand already did that. */
320     if (!(curwin->w_valid & VALID_TOPLINE))
321     {
322 	curwin->w_topline = 1;
323 # ifdef FEAT_DIFF
324 	curwin->w_topfill = 0;
325 # endif
326     }
327 # ifdef FEAT_EVAL
328     apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);
329 # else
330     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
331 # endif
332 #endif
333 
334     if (retval == OK)
335     {
336 #ifdef FEAT_AUTOCMD
337 	/*
338 	 * The autocommands may have changed the current buffer.  Apply the
339 	 * modelines to the correct buffer, if it still exists and is loaded.
340 	 */
341 	if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL)
342 	{
343 	    aco_save_T	aco;
344 
345 	    /* Go to the buffer that was opened. */
346 	    aucmd_prepbuf(&aco, old_curbuf.br_buf);
347 #endif
348 	    do_modelines(0);
349 	    curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
350 
351 #ifdef FEAT_AUTOCMD
352 # ifdef FEAT_EVAL
353 	    apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
354 								    &retval);
355 # else
356 	    apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
357 # endif
358 
359 	    /* restore curwin/curbuf and a few other things */
360 	    aucmd_restbuf(&aco);
361 	}
362 #endif
363     }
364 
365     return retval;
366 }
367 
368 /*
369  * Store "buf" in "bufref" and set the free count.
370  */
371     void
372 set_bufref(bufref_T *bufref, buf_T *buf)
373 {
374     bufref->br_buf = buf;
375     bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum;
376     bufref->br_buf_free_count = buf_free_count;
377 }
378 
379 /*
380  * Return TRUE if "bufref->br_buf" points to the same buffer as when
381  * set_bufref() was called and it is a valid buffer.
382  * Only goes through the buffer list if buf_free_count changed.
383  * Also checks if b_fnum is still the same, a :bwipe followed by :new might get
384  * the same allocated memory, but it's a different buffer.
385  */
386     int
387 bufref_valid(bufref_T *bufref)
388 {
389     return bufref->br_buf_free_count == buf_free_count
390 	? TRUE : buf_valid(bufref->br_buf)
391 				  && bufref->br_fnum == bufref->br_buf->b_fnum;
392 }
393 
394 /*
395  * Return TRUE if "buf" points to a valid buffer (in the buffer list).
396  * This can be slow if there are many buffers, prefer using bufref_valid().
397  */
398     int
399 buf_valid(buf_T *buf)
400 {
401     buf_T	*bp;
402 
403     /* Assume that we more often have a recent buffer, start with the last
404      * one. */
405     for (bp = lastbuf; bp != NULL; bp = bp->b_prev)
406 	if (bp == buf)
407 	    return TRUE;
408     return FALSE;
409 }
410 
411 /*
412  * A hash table used to quickly lookup a buffer by its number.
413  */
414 static hashtab_T buf_hashtab;
415 
416     static void
417 buf_hashtab_add(buf_T *buf)
418 {
419     sprintf((char *)buf->b_key, "%x", buf->b_fnum);
420     if (hash_add(&buf_hashtab, buf->b_key) == FAIL)
421 	EMSG(_("E931: Buffer cannot be registered"));
422 }
423 
424     static void
425 buf_hashtab_remove(buf_T *buf)
426 {
427     hashitem_T *hi = hash_find(&buf_hashtab, buf->b_key);
428 
429     if (!HASHITEM_EMPTY(hi))
430 	hash_remove(&buf_hashtab, hi);
431 }
432 
433 /*
434  * Close the link to a buffer.
435  * "action" is used when there is no longer a window for the buffer.
436  * It can be:
437  * 0			buffer becomes hidden
438  * DOBUF_UNLOAD		buffer is unloaded
439  * DOBUF_DELETE		buffer is unloaded and removed from buffer list
440  * DOBUF_WIPE		buffer is unloaded and really deleted
441  * When doing all but the first one on the current buffer, the caller should
442  * get a new buffer very soon!
443  *
444  * The 'bufhidden' option can force freeing and deleting.
445  *
446  * When "abort_if_last" is TRUE then do not close the buffer if autocommands
447  * cause there to be only one window with this buffer.  e.g. when ":quit" is
448  * supposed to close the window but autocommands close all other windows.
449  */
450     void
451 close_buffer(
452     win_T	*win,		/* if not NULL, set b_last_cursor */
453     buf_T	*buf,
454     int		action,
455     int		abort_if_last UNUSED)
456 {
457 #ifdef FEAT_AUTOCMD
458     int		is_curbuf;
459     int		nwindows;
460     bufref_T	bufref;
461 # ifdef FEAT_WINDOWS
462     int		is_curwin = (curwin != NULL && curwin->w_buffer == buf);
463     win_T	*the_curwin = curwin;
464     tabpage_T	*the_curtab = curtab;
465 # endif
466 #endif
467     int		unload_buf = (action != 0);
468     int		del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
469     int		wipe_buf = (action == DOBUF_WIPE);
470 
471     /*
472      * Force unloading or deleting when 'bufhidden' says so.
473      * The caller must take care of NOT deleting/freeing when 'bufhidden' is
474      * "hide" (otherwise we could never free or delete a buffer).
475      */
476     if (buf->b_p_bh[0] == 'd')		/* 'bufhidden' == "delete" */
477     {
478 	del_buf = TRUE;
479 	unload_buf = TRUE;
480     }
481     else if (buf->b_p_bh[0] == 'w')	/* 'bufhidden' == "wipe" */
482     {
483 	del_buf = TRUE;
484 	unload_buf = TRUE;
485 	wipe_buf = TRUE;
486     }
487     else if (buf->b_p_bh[0] == 'u')	/* 'bufhidden' == "unload" */
488 	unload_buf = TRUE;
489 
490 #ifdef FEAT_AUTOCMD
491     /* Disallow deleting the buffer when it is locked (already being closed or
492      * halfway a command that relies on it). Unloading is allowed. */
493     if (buf->b_locked > 0 && (del_buf || wipe_buf))
494     {
495 	EMSG(_("E937: Attempt to delete a buffer that is in use"));
496 	return;
497     }
498 #endif
499 
500     if (win != NULL
501 #ifdef FEAT_WINDOWS
502 	&& win_valid_any_tab(win) /* in case autocommands closed the window */
503 #endif
504 	    )
505     {
506 	/* Set b_last_cursor when closing the last window for the buffer.
507 	 * Remember the last cursor position and window options of the buffer.
508 	 * This used to be only for the current window, but then options like
509 	 * 'foldmethod' may be lost with a ":only" command. */
510 	if (buf->b_nwindows == 1)
511 	    set_last_cursor(win);
512 	buflist_setfpos(buf, win,
513 		    win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
514 		    win->w_cursor.col, TRUE);
515     }
516 
517 #ifdef FEAT_AUTOCMD
518     set_bufref(&bufref, buf);
519 
520     /* When the buffer is no longer in a window, trigger BufWinLeave */
521     if (buf->b_nwindows == 1)
522     {
523 	++buf->b_locked;
524 	if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
525 								  FALSE, buf)
526 		&& !bufref_valid(&bufref))
527 	{
528 	    /* Autocommands deleted the buffer. */
529 aucmd_abort:
530 	    EMSG(_(e_auabort));
531 	    return;
532 	}
533 	--buf->b_locked;
534 	if (abort_if_last && one_window())
535 	    /* Autocommands made this the only window. */
536 	    goto aucmd_abort;
537 
538 	/* When the buffer becomes hidden, but is not unloaded, trigger
539 	 * BufHidden */
540 	if (!unload_buf)
541 	{
542 	    ++buf->b_locked;
543 	    if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
544 								  FALSE, buf)
545 		    && !bufref_valid(&bufref))
546 		/* Autocommands deleted the buffer. */
547 		goto aucmd_abort;
548 	    --buf->b_locked;
549 	    if (abort_if_last && one_window())
550 		/* Autocommands made this the only window. */
551 		goto aucmd_abort;
552 	}
553 # ifdef FEAT_EVAL
554 	if (aborting())	    /* autocmds may abort script processing */
555 	    return;
556 # endif
557     }
558 
559 # ifdef FEAT_WINDOWS
560     /* If the buffer was in curwin and the window has changed, go back to that
561      * window, if it still exists.  This avoids that ":edit x" triggering a
562      * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */
563     if (is_curwin && curwin != the_curwin &&  win_valid_any_tab(the_curwin))
564     {
565 	block_autocmds();
566 	goto_tabpage_win(the_curtab, the_curwin);
567 	unblock_autocmds();
568     }
569 # endif
570 
571     nwindows = buf->b_nwindows;
572 #endif
573 
574     /* decrease the link count from windows (unless not in any window) */
575     if (buf->b_nwindows > 0)
576 	--buf->b_nwindows;
577 
578     /* Return when a window is displaying the buffer or when it's not
579      * unloaded. */
580     if (buf->b_nwindows > 0 || !unload_buf)
581 	return;
582 
583     /* Always remove the buffer when there is no file name. */
584     if (buf->b_ffname == NULL)
585 	del_buf = TRUE;
586 
587     /* When closing the current buffer stop Visual mode before freeing
588      * anything. */
589     if (buf == curbuf && VIsual_active
590 #if defined(EXITFREE)
591 	    && !entered_free_all_mem
592 #endif
593 	    )
594 	end_visual_mode();
595 
596     /*
597      * Free all things allocated for this buffer.
598      * Also calls the "BufDelete" autocommands when del_buf is TRUE.
599      */
600 #ifdef FEAT_AUTOCMD
601     /* Remember if we are closing the current buffer.  Restore the number of
602      * windows, so that autocommands in buf_freeall() don't get confused. */
603     is_curbuf = (buf == curbuf);
604     buf->b_nwindows = nwindows;
605 #endif
606 
607     buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
608 
609 #ifdef FEAT_AUTOCMD
610     /* Autocommands may have deleted the buffer. */
611     if (!bufref_valid(&bufref))
612 	return;
613 # ifdef FEAT_EVAL
614     if (aborting())	    /* autocmds may abort script processing */
615 	return;
616 # endif
617 
618     /*
619      * It's possible that autocommands change curbuf to the one being deleted.
620      * This might cause the previous curbuf to be deleted unexpectedly.  But
621      * in some cases it's OK to delete the curbuf, because a new one is
622      * obtained anyway.  Therefore only return if curbuf changed to the
623      * deleted buffer.
624      */
625     if (buf == curbuf && !is_curbuf)
626 	return;
627 
628     if (
629 #ifdef FEAT_WINDOWS
630 	win_valid_any_tab(win) &&
631 #else
632 	win != NULL &&
633 #endif
634 			  win->w_buffer == buf)
635 	win->w_buffer = NULL;  /* make sure we don't use the buffer now */
636 
637     /* Autocommands may have opened or closed windows for this buffer.
638      * Decrement the count for the close we do here. */
639     if (buf->b_nwindows > 0)
640 	--buf->b_nwindows;
641 #endif
642 
643     /* Change directories when the 'acd' option is set. */
644     DO_AUTOCHDIR
645 
646     /*
647      * Remove the buffer from the list.
648      */
649     if (wipe_buf)
650     {
651 #ifdef FEAT_SUN_WORKSHOP
652 	if (usingSunWorkShop)
653 	    workshop_file_closed_lineno((char *)buf->b_ffname,
654 			(int)buf->b_last_cursor.lnum);
655 #endif
656 	vim_free(buf->b_ffname);
657 	vim_free(buf->b_sfname);
658 	if (buf->b_prev == NULL)
659 	    firstbuf = buf->b_next;
660 	else
661 	    buf->b_prev->b_next = buf->b_next;
662 	if (buf->b_next == NULL)
663 	    lastbuf = buf->b_prev;
664 	else
665 	    buf->b_next->b_prev = buf->b_prev;
666 	free_buffer(buf);
667     }
668     else
669     {
670 	if (del_buf)
671 	{
672 	    /* Free all internal variables and reset option values, to make
673 	     * ":bdel" compatible with Vim 5.7. */
674 	    free_buffer_stuff(buf, TRUE);
675 
676 	    /* Make it look like a new buffer. */
677 	    buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
678 
679 	    /* Init the options when loaded again. */
680 	    buf->b_p_initialized = FALSE;
681 	}
682 	buf_clear_file(buf);
683 	if (del_buf)
684 	    buf->b_p_bl = FALSE;
685     }
686 }
687 
688 /*
689  * Make buffer not contain a file.
690  */
691     void
692 buf_clear_file(buf_T *buf)
693 {
694     buf->b_ml.ml_line_count = 1;
695     unchanged(buf, TRUE);
696     buf->b_shortname = FALSE;
697     buf->b_p_eol = TRUE;
698     buf->b_start_eol = TRUE;
699 #ifdef FEAT_MBYTE
700     buf->b_p_bomb = FALSE;
701     buf->b_start_bomb = FALSE;
702 #endif
703     buf->b_ml.ml_mfp = NULL;
704     buf->b_ml.ml_flags = ML_EMPTY;		/* empty buffer */
705 #ifdef FEAT_NETBEANS_INTG
706     netbeans_deleted_all_lines(buf);
707 #endif
708 }
709 
710 /*
711  * buf_freeall() - free all things allocated for a buffer that are related to
712  * the file.  Careful: get here with "curwin" NULL when exiting.
713  * flags:
714  * BFA_DEL	  buffer is going to be deleted
715  * BFA_WIPE	  buffer is going to be wiped out
716  * BFA_KEEP_UNDO  do not free undo information
717  */
718     void
719 buf_freeall(buf_T *buf, int flags)
720 {
721 #ifdef FEAT_AUTOCMD
722     int		is_curbuf = (buf == curbuf);
723     bufref_T	bufref;
724 # ifdef FEAT_WINDOWS
725     int		is_curwin = (curwin != NULL && curwin->w_buffer == buf);
726     win_T	*the_curwin = curwin;
727     tabpage_T	*the_curtab = curtab;
728 # endif
729 
730     /* Make sure the buffer isn't closed by autocommands. */
731     ++buf->b_locked;
732     set_bufref(&bufref, buf);
733     if (buf->b_ml.ml_mfp != NULL)
734     {
735 	if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
736 								  FALSE, buf)
737 		&& !bufref_valid(&bufref))
738 	    /* autocommands deleted the buffer */
739 	    return;
740     }
741     if ((flags & BFA_DEL) && buf->b_p_bl)
742     {
743 	if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname,
744 								   FALSE, buf)
745 		&& !bufref_valid(&bufref))
746 	    /* autocommands deleted the buffer */
747 	    return;
748     }
749     if (flags & BFA_WIPE)
750     {
751 	if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
752 								  FALSE, buf)
753 		&& !bufref_valid(&bufref))
754 	    /* autocommands deleted the buffer */
755 	    return;
756     }
757     --buf->b_locked;
758 
759 # ifdef FEAT_WINDOWS
760     /* If the buffer was in curwin and the window has changed, go back to that
761      * window, if it still exists.  This avoids that ":edit x" triggering a
762      * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */
763     if (is_curwin && curwin != the_curwin &&  win_valid_any_tab(the_curwin))
764     {
765 	block_autocmds();
766 	goto_tabpage_win(the_curtab, the_curwin);
767 	unblock_autocmds();
768     }
769 # endif
770 
771 # ifdef FEAT_EVAL
772     if (aborting())	    /* autocmds may abort script processing */
773 	return;
774 # endif
775 
776     /*
777      * It's possible that autocommands change curbuf to the one being deleted.
778      * This might cause curbuf to be deleted unexpectedly.  But in some cases
779      * it's OK to delete the curbuf, because a new one is obtained anyway.
780      * Therefore only return if curbuf changed to the deleted buffer.
781      */
782     if (buf == curbuf && !is_curbuf)
783 	return;
784 #endif
785 #ifdef FEAT_DIFF
786     diff_buf_delete(buf);	    /* Can't use 'diff' for unloaded buffer. */
787 #endif
788 #ifdef FEAT_SYN_HL
789     /* Remove any ownsyntax, unless exiting. */
790     if (curwin != NULL && curwin->w_buffer == buf)
791 	reset_synblock(curwin);
792 #endif
793 
794 #ifdef FEAT_FOLDING
795     /* No folds in an empty buffer. */
796 # ifdef FEAT_WINDOWS
797     {
798 	win_T		*win;
799 	tabpage_T	*tp;
800 
801 	FOR_ALL_TAB_WINDOWS(tp, win)
802 	    if (win->w_buffer == buf)
803 		clearFolding(win);
804     }
805 # else
806     if (curwin != NULL && curwin->w_buffer == buf)
807 	clearFolding(curwin);
808 # endif
809 #endif
810 
811 #ifdef FEAT_TCL
812     tcl_buffer_free(buf);
813 #endif
814     ml_close(buf, TRUE);	    /* close and delete the memline/memfile */
815     buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
816     if ((flags & BFA_KEEP_UNDO) == 0)
817     {
818 	u_blockfree(buf);	    /* free the memory allocated for undo */
819 	u_clearall(buf);	    /* reset all undo information */
820     }
821 #ifdef FEAT_SYN_HL
822     syntax_clear(&buf->b_s);	    /* reset syntax info */
823 #endif
824     buf->b_flags &= ~BF_READERR;    /* a read error is no longer relevant */
825 }
826 
827 /*
828  * Free a buffer structure and the things it contains related to the buffer
829  * itself (not the file, that must have been done already).
830  */
831     static void
832 free_buffer(buf_T *buf)
833 {
834     ++buf_free_count;
835     free_buffer_stuff(buf, TRUE);
836 #ifdef FEAT_EVAL
837     unref_var_dict(buf->b_vars);
838 #endif
839 #ifdef FEAT_LUA
840     lua_buffer_free(buf);
841 #endif
842 #ifdef FEAT_MZSCHEME
843     mzscheme_buffer_free(buf);
844 #endif
845 #ifdef FEAT_PERL
846     perl_buf_free(buf);
847 #endif
848 #ifdef FEAT_PYTHON
849     python_buffer_free(buf);
850 #endif
851 #ifdef FEAT_PYTHON3
852     python3_buffer_free(buf);
853 #endif
854 #ifdef FEAT_RUBY
855     ruby_buffer_free(buf);
856 #endif
857 #ifdef FEAT_JOB_CHANNEL
858     channel_buffer_free(buf);
859 #endif
860 #ifdef FEAT_TERMINAL
861     free_terminal(buf->b_term);
862 #endif
863 
864     buf_hashtab_remove(buf);
865 
866 #ifdef FEAT_AUTOCMD
867     aubuflocal_remove(buf);
868 
869     if (autocmd_busy)
870     {
871 	/* Do not free the buffer structure while autocommands are executing,
872 	 * it's still needed. Free it when autocmd_busy is reset. */
873 	buf->b_next = au_pending_free_buf;
874 	au_pending_free_buf = buf;
875     }
876     else
877 #endif
878 	vim_free(buf);
879 }
880 
881 /*
882  * Initializes b:changedtick.
883  */
884     static void
885 init_changedtick(buf_T *buf)
886 {
887     dictitem_T *di = (dictitem_T *)&buf->b_ct_di;
888 
889     di->di_flags = DI_FLAGS_FIX | DI_FLAGS_RO;
890     di->di_tv.v_type = VAR_NUMBER;
891     di->di_tv.v_lock = VAR_FIXED;
892     di->di_tv.vval.v_number = 0;
893 
894 #ifdef FEAT_EVAL
895     STRCPY(buf->b_ct_di.di_key, "changedtick");
896     (void)dict_add(buf->b_vars, di);
897 #endif
898 }
899 
900 /*
901  * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
902  */
903     static void
904 free_buffer_stuff(
905     buf_T	*buf,
906     int		free_options)		/* free options as well */
907 {
908     if (free_options)
909     {
910 	clear_wininfo(buf);		/* including window-local options */
911 	free_buf_options(buf, TRUE);
912 #ifdef FEAT_SPELL
913 	ga_clear(&buf->b_s.b_langp);
914 #endif
915     }
916 #ifdef FEAT_EVAL
917     {
918 	varnumber_T tick = CHANGEDTICK(buf);
919 
920 	vars_clear(&buf->b_vars->dv_hashtab); /* free all buffer variables */
921 	hash_init(&buf->b_vars->dv_hashtab);
922 	init_changedtick(buf);
923 	CHANGEDTICK(buf) = tick;
924     }
925 #endif
926 #ifdef FEAT_USR_CMDS
927     uc_clear(&buf->b_ucmds);		/* clear local user commands */
928 #endif
929 #ifdef FEAT_SIGNS
930     buf_delete_signs(buf);		/* delete any signs */
931 #endif
932 #ifdef FEAT_NETBEANS_INTG
933     netbeans_file_killed(buf);
934 #endif
935 #ifdef FEAT_LOCALMAP
936     map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE);  /* clear local mappings */
937     map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE);   /* clear local abbrevs */
938 #endif
939 #ifdef FEAT_MBYTE
940     vim_free(buf->b_start_fenc);
941     buf->b_start_fenc = NULL;
942 #endif
943 }
944 
945 /*
946  * Free the b_wininfo list for buffer "buf".
947  */
948     static void
949 clear_wininfo(buf_T *buf)
950 {
951     wininfo_T	*wip;
952 
953     while (buf->b_wininfo != NULL)
954     {
955 	wip = buf->b_wininfo;
956 	buf->b_wininfo = wip->wi_next;
957 	if (wip->wi_optset)
958 	{
959 	    clear_winopt(&wip->wi_opt);
960 #ifdef FEAT_FOLDING
961 	    deleteFoldRecurse(&wip->wi_folds);
962 #endif
963 	}
964 	vim_free(wip);
965     }
966 }
967 
968 #if defined(FEAT_LISTCMDS) || defined(PROTO)
969 /*
970  * Go to another buffer.  Handles the result of the ATTENTION dialog.
971  */
972     void
973 goto_buffer(
974     exarg_T	*eap,
975     int		start,
976     int		dir,
977     int		count)
978 {
979 # if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
980     bufref_T	old_curbuf;
981 
982     set_bufref(&old_curbuf, curbuf);
983 
984     swap_exists_action = SEA_DIALOG;
985 # endif
986     (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
987 					     start, dir, count, eap->forceit);
988 # if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
989     if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
990     {
991 #  if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
992 	cleanup_T   cs;
993 
994 	/* Reset the error/interrupt/exception state here so that
995 	 * aborting() returns FALSE when closing a window. */
996 	enter_cleanup(&cs);
997 #  endif
998 
999 	/* Quitting means closing the split window, nothing else. */
1000 	win_close(curwin, TRUE);
1001 	swap_exists_action = SEA_NONE;
1002 	swap_exists_did_quit = TRUE;
1003 
1004 #  if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1005 	/* Restore the error/interrupt/exception state if not discarded by a
1006 	 * new aborting error, interrupt, or uncaught exception. */
1007 	leave_cleanup(&cs);
1008 #  endif
1009     }
1010     else
1011 	handle_swap_exists(&old_curbuf);
1012 # endif
1013 }
1014 #endif
1015 
1016 #if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO)
1017 /*
1018  * Handle the situation of swap_exists_action being set.
1019  * It is allowed for "old_curbuf" to be NULL or invalid.
1020  */
1021     void
1022 handle_swap_exists(bufref_T *old_curbuf)
1023 {
1024 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1025     cleanup_T	cs;
1026 # endif
1027 #ifdef FEAT_SYN_HL
1028     long	old_tw = curbuf->b_p_tw;
1029 #endif
1030     buf_T	*buf;
1031 
1032     if (swap_exists_action == SEA_QUIT)
1033     {
1034 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1035 	/* Reset the error/interrupt/exception state here so that
1036 	 * aborting() returns FALSE when closing a buffer. */
1037 	enter_cleanup(&cs);
1038 # endif
1039 
1040 	/* User selected Quit at ATTENTION prompt.  Go back to previous
1041 	 * buffer.  If that buffer is gone or the same as the current one,
1042 	 * open a new, empty buffer. */
1043 	swap_exists_action = SEA_NONE;	/* don't want it again */
1044 	swap_exists_did_quit = TRUE;
1045 	close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
1046 	if (old_curbuf == NULL || !bufref_valid(old_curbuf)
1047 					      || old_curbuf->br_buf == curbuf)
1048 	    buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
1049 	else
1050 	    buf = old_curbuf->br_buf;
1051 	if (buf != NULL)
1052 	{
1053 	    enter_buffer(buf);
1054 #ifdef FEAT_SYN_HL
1055 	    if (old_tw != curbuf->b_p_tw)
1056 		check_colorcolumn(curwin);
1057 #endif
1058 	}
1059 	/* If "old_curbuf" is NULL we are in big trouble here... */
1060 
1061 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1062 	/* Restore the error/interrupt/exception state if not discarded by a
1063 	 * new aborting error, interrupt, or uncaught exception. */
1064 	leave_cleanup(&cs);
1065 # endif
1066     }
1067     else if (swap_exists_action == SEA_RECOVER)
1068     {
1069 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1070 	/* Reset the error/interrupt/exception state here so that
1071 	 * aborting() returns FALSE when closing a buffer. */
1072 	enter_cleanup(&cs);
1073 # endif
1074 
1075 	/* User selected Recover at ATTENTION prompt. */
1076 	msg_scroll = TRUE;
1077 	ml_recover();
1078 	MSG_PUTS("\n");	/* don't overwrite the last message */
1079 	cmdline_row = msg_row;
1080 	do_modelines(0);
1081 
1082 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1083 	/* Restore the error/interrupt/exception state if not discarded by a
1084 	 * new aborting error, interrupt, or uncaught exception. */
1085 	leave_cleanup(&cs);
1086 # endif
1087     }
1088     swap_exists_action = SEA_NONE;
1089 }
1090 #endif
1091 
1092 #if defined(FEAT_LISTCMDS) || defined(PROTO)
1093 /*
1094  * do_bufdel() - delete or unload buffer(s)
1095  *
1096  * addr_count == 0: ":bdel" - delete current buffer
1097  * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
1098  *		    buffer "end_bnr", then any other arguments.
1099  * addr_count == 2: ":N,N bdel" - delete buffers in range
1100  *
1101  * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
1102  * DOBUF_DEL (":bdel")
1103  *
1104  * Returns error message or NULL
1105  */
1106     char_u *
1107 do_bufdel(
1108     int		command,
1109     char_u	*arg,		/* pointer to extra arguments */
1110     int		addr_count,
1111     int		start_bnr,	/* first buffer number in a range */
1112     int		end_bnr,	/* buffer nr or last buffer nr in a range */
1113     int		forceit)
1114 {
1115     int		do_current = 0;	/* delete current buffer? */
1116     int		deleted = 0;	/* number of buffers deleted */
1117     char_u	*errormsg = NULL; /* return value */
1118     int		bnr;		/* buffer number */
1119     char_u	*p;
1120 
1121     if (addr_count == 0)
1122     {
1123 	(void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
1124     }
1125     else
1126     {
1127 	if (addr_count == 2)
1128 	{
1129 	    if (*arg)		/* both range and argument is not allowed */
1130 		return (char_u *)_(e_trailing);
1131 	    bnr = start_bnr;
1132 	}
1133 	else	/* addr_count == 1 */
1134 	    bnr = end_bnr;
1135 
1136 	for ( ;!got_int; ui_breakcheck())
1137 	{
1138 	    /*
1139 	     * delete the current buffer last, otherwise when the
1140 	     * current buffer is deleted, the next buffer becomes
1141 	     * the current one and will be loaded, which may then
1142 	     * also be deleted, etc.
1143 	     */
1144 	    if (bnr == curbuf->b_fnum)
1145 		do_current = bnr;
1146 	    else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
1147 							       forceit) == OK)
1148 		++deleted;
1149 
1150 	    /*
1151 	     * find next buffer number to delete/unload
1152 	     */
1153 	    if (addr_count == 2)
1154 	    {
1155 		if (++bnr > end_bnr)
1156 		    break;
1157 	    }
1158 	    else    /* addr_count == 1 */
1159 	    {
1160 		arg = skipwhite(arg);
1161 		if (*arg == NUL)
1162 		    break;
1163 		if (!VIM_ISDIGIT(*arg))
1164 		{
1165 		    p = skiptowhite_esc(arg);
1166 		    bnr = buflist_findpat(arg, p, command == DOBUF_WIPE,
1167 								FALSE, FALSE);
1168 		    if (bnr < 0)	    /* failed */
1169 			break;
1170 		    arg = p;
1171 		}
1172 		else
1173 		    bnr = getdigits(&arg);
1174 	    }
1175 	}
1176 	if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
1177 					  FORWARD, do_current, forceit) == OK)
1178 	    ++deleted;
1179 
1180 	if (deleted == 0)
1181 	{
1182 	    if (command == DOBUF_UNLOAD)
1183 		STRCPY(IObuff, _("E515: No buffers were unloaded"));
1184 	    else if (command == DOBUF_DEL)
1185 		STRCPY(IObuff, _("E516: No buffers were deleted"));
1186 	    else
1187 		STRCPY(IObuff, _("E517: No buffers were wiped out"));
1188 	    errormsg = IObuff;
1189 	}
1190 	else if (deleted >= p_report)
1191 	{
1192 	    if (command == DOBUF_UNLOAD)
1193 	    {
1194 		if (deleted == 1)
1195 		    MSG(_("1 buffer unloaded"));
1196 		else
1197 		    smsg((char_u *)_("%d buffers unloaded"), deleted);
1198 	    }
1199 	    else if (command == DOBUF_DEL)
1200 	    {
1201 		if (deleted == 1)
1202 		    MSG(_("1 buffer deleted"));
1203 		else
1204 		    smsg((char_u *)_("%d buffers deleted"), deleted);
1205 	    }
1206 	    else
1207 	    {
1208 		if (deleted == 1)
1209 		    MSG(_("1 buffer wiped out"));
1210 		else
1211 		    smsg((char_u *)_("%d buffers wiped out"), deleted);
1212 	    }
1213 	}
1214     }
1215 
1216 
1217     return errormsg;
1218 }
1219 #endif /* FEAT_LISTCMDS */
1220 
1221 #if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \
1222 	|| defined(FEAT_PYTHON3) || defined(PROTO)
1223 
1224 static int	empty_curbuf(int close_others, int forceit, int action);
1225 
1226 /*
1227  * Make the current buffer empty.
1228  * Used when it is wiped out and it's the last buffer.
1229  */
1230     static int
1231 empty_curbuf(
1232     int close_others,
1233     int forceit,
1234     int action)
1235 {
1236     int	    retval;
1237     buf_T   *buf = curbuf;
1238     bufref_T bufref;
1239 
1240     if (action == DOBUF_UNLOAD)
1241     {
1242 	EMSG(_("E90: Cannot unload last buffer"));
1243 	return FAIL;
1244     }
1245 
1246     set_bufref(&bufref, buf);
1247 #ifdef FEAT_WINDOWS
1248     if (close_others)
1249 	/* Close any other windows on this buffer, then make it empty. */
1250 	close_windows(buf, TRUE);
1251 #endif
1252 
1253     setpcmark();
1254     retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
1255 					  forceit ? ECMD_FORCEIT : 0, curwin);
1256 
1257     /*
1258      * do_ecmd() may create a new buffer, then we have to delete
1259      * the old one.  But do_ecmd() may have done that already, check
1260      * if the buffer still exists.
1261      */
1262     if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
1263 	close_buffer(NULL, buf, action, FALSE);
1264     if (!close_others)
1265 	need_fileinfo = FALSE;
1266     return retval;
1267 }
1268 /*
1269  * Implementation of the commands for the buffer list.
1270  *
1271  * action == DOBUF_GOTO	    go to specified buffer
1272  * action == DOBUF_SPLIT    split window and go to specified buffer
1273  * action == DOBUF_UNLOAD   unload specified buffer(s)
1274  * action == DOBUF_DEL	    delete specified buffer(s) from buffer list
1275  * action == DOBUF_WIPE	    delete specified buffer(s) really
1276  *
1277  * start == DOBUF_CURRENT   go to "count" buffer from current buffer
1278  * start == DOBUF_FIRST	    go to "count" buffer from first buffer
1279  * start == DOBUF_LAST	    go to "count" buffer from last buffer
1280  * start == DOBUF_MOD	    go to "count" modified buffer from current buffer
1281  *
1282  * Return FAIL or OK.
1283  */
1284     int
1285 do_buffer(
1286     int		action,
1287     int		start,
1288     int		dir,		/* FORWARD or BACKWARD */
1289     int		count,		/* buffer number or number of buffers */
1290     int		forceit)	/* TRUE for :...! */
1291 {
1292     buf_T	*buf;
1293     buf_T	*bp;
1294     int		unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1295 						     || action == DOBUF_WIPE);
1296 
1297     switch (start)
1298     {
1299 	case DOBUF_FIRST:   buf = firstbuf; break;
1300 	case DOBUF_LAST:    buf = lastbuf;  break;
1301 	default:	    buf = curbuf;   break;
1302     }
1303     if (start == DOBUF_MOD)	    /* find next modified buffer */
1304     {
1305 	while (count-- > 0)
1306 	{
1307 	    do
1308 	    {
1309 		buf = buf->b_next;
1310 		if (buf == NULL)
1311 		    buf = firstbuf;
1312 	    }
1313 	    while (buf != curbuf && !bufIsChanged(buf));
1314 	}
1315 	if (!bufIsChanged(buf))
1316 	{
1317 	    EMSG(_("E84: No modified buffer found"));
1318 	    return FAIL;
1319 	}
1320     }
1321     else if (start == DOBUF_FIRST && count) /* find specified buffer number */
1322     {
1323 	while (buf != NULL && buf->b_fnum != count)
1324 	    buf = buf->b_next;
1325     }
1326     else
1327     {
1328 	bp = NULL;
1329 	while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
1330 	{
1331 	    /* remember the buffer where we start, we come back there when all
1332 	     * buffers are unlisted. */
1333 	    if (bp == NULL)
1334 		bp = buf;
1335 	    if (dir == FORWARD)
1336 	    {
1337 		buf = buf->b_next;
1338 		if (buf == NULL)
1339 		    buf = firstbuf;
1340 	    }
1341 	    else
1342 	    {
1343 		buf = buf->b_prev;
1344 		if (buf == NULL)
1345 		    buf = lastbuf;
1346 	    }
1347 	    /* don't count unlisted buffers */
1348 	    if (unload || buf->b_p_bl)
1349 	    {
1350 		 --count;
1351 		 bp = NULL;	/* use this buffer as new starting point */
1352 	    }
1353 	    if (bp == buf)
1354 	    {
1355 		/* back where we started, didn't find anything. */
1356 		EMSG(_("E85: There is no listed buffer"));
1357 		return FAIL;
1358 	    }
1359 	}
1360     }
1361 
1362     if (buf == NULL)	    /* could not find it */
1363     {
1364 	if (start == DOBUF_FIRST)
1365 	{
1366 	    /* don't warn when deleting */
1367 	    if (!unload)
1368 		EMSGN(_(e_nobufnr), count);
1369 	}
1370 	else if (dir == FORWARD)
1371 	    EMSG(_("E87: Cannot go beyond last buffer"));
1372 	else
1373 	    EMSG(_("E88: Cannot go before first buffer"));
1374 	return FAIL;
1375     }
1376 
1377 #ifdef FEAT_GUI
1378     need_mouse_correct = TRUE;
1379 #endif
1380 
1381 #ifdef FEAT_LISTCMDS
1382     /*
1383      * delete buffer buf from memory and/or the list
1384      */
1385     if (unload)
1386     {
1387 	int	forward;
1388 # if defined(FEAT_AUTOCMD) || defined(FEAT_WINDOWS)
1389 	bufref_T bufref;
1390 
1391 	set_bufref(&bufref, buf);
1392 # endif
1393 
1394 	/* When unloading or deleting a buffer that's already unloaded and
1395 	 * unlisted: fail silently. */
1396 	if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
1397 	    return FAIL;
1398 
1399 	if (!forceit && bufIsChanged(buf))
1400 	{
1401 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1402 	    if ((p_confirm || cmdmod.confirm) && p_write)
1403 	    {
1404 		dialog_changed(buf, FALSE);
1405 # ifdef FEAT_AUTOCMD
1406 		if (!bufref_valid(&bufref))
1407 		    /* Autocommand deleted buffer, oops!  It's not changed
1408 		     * now. */
1409 		    return FAIL;
1410 # endif
1411 		/* If it's still changed fail silently, the dialog already
1412 		 * mentioned why it fails. */
1413 		if (bufIsChanged(buf))
1414 		    return FAIL;
1415 	    }
1416 	    else
1417 #endif
1418 	    {
1419 		EMSGN(_("E89: No write since last change for buffer %ld (add ! to override)"),
1420 								 buf->b_fnum);
1421 		return FAIL;
1422 	    }
1423 	}
1424 
1425 	/* When closing the current buffer stop Visual mode. */
1426 	if (buf == curbuf && VIsual_active)
1427 	    end_visual_mode();
1428 
1429 	/*
1430 	 * If deleting the last (listed) buffer, make it empty.
1431 	 * The last (listed) buffer cannot be unloaded.
1432 	 */
1433 	FOR_ALL_BUFFERS(bp)
1434 	    if (bp->b_p_bl && bp != buf)
1435 		break;
1436 	if (bp == NULL && buf == curbuf)
1437 	    return empty_curbuf(TRUE, forceit, action);
1438 
1439 #ifdef FEAT_WINDOWS
1440 	/*
1441 	 * If the deleted buffer is the current one, close the current window
1442 	 * (unless it's the only window).  Repeat this so long as we end up in
1443 	 * a window with this buffer.
1444 	 */
1445 	while (buf == curbuf
1446 # ifdef FEAT_AUTOCMD
1447 		   && !(curwin->w_closing || curwin->w_buffer->b_locked > 0)
1448 # endif
1449 		   && (!ONE_WINDOW || first_tabpage->tp_next != NULL))
1450 	{
1451 	    if (win_close(curwin, FALSE) == FAIL)
1452 		break;
1453 	}
1454 #endif
1455 
1456 	/*
1457 	 * If the buffer to be deleted is not the current one, delete it here.
1458 	 */
1459 	if (buf != curbuf)
1460 	{
1461 #ifdef FEAT_WINDOWS
1462 	    close_windows(buf, FALSE);
1463 	    if (buf != curbuf && bufref_valid(&bufref))
1464 #endif
1465 		if (buf->b_nwindows <= 0)
1466 		    close_buffer(NULL, buf, action, FALSE);
1467 	    return OK;
1468 	}
1469 
1470 	/*
1471 	 * Deleting the current buffer: Need to find another buffer to go to.
1472 	 * There should be another, otherwise it would have been handled
1473 	 * above.  However, autocommands may have deleted all buffers.
1474 	 * First use au_new_curbuf.br_buf, if it is valid.
1475 	 * Then prefer the buffer we most recently visited.
1476 	 * Else try to find one that is loaded, after the current buffer,
1477 	 * then before the current buffer.
1478 	 * Finally use any buffer.
1479 	 */
1480 	buf = NULL;	/* selected buffer */
1481 	bp = NULL;	/* used when no loaded buffer found */
1482 #ifdef FEAT_AUTOCMD
1483 	if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf))
1484 	    buf = au_new_curbuf.br_buf;
1485 # ifdef FEAT_JUMPLIST
1486 	else
1487 # endif
1488 #endif
1489 #ifdef FEAT_JUMPLIST
1490 	    if (curwin->w_jumplistlen > 0)
1491 	{
1492 	    int     jumpidx;
1493 
1494 	    jumpidx = curwin->w_jumplistidx - 1;
1495 	    if (jumpidx < 0)
1496 		jumpidx = curwin->w_jumplistlen - 1;
1497 
1498 	    forward = jumpidx;
1499 	    while (jumpidx != curwin->w_jumplistidx)
1500 	    {
1501 		buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
1502 		if (buf != NULL)
1503 		{
1504 		    if (buf == curbuf || !buf->b_p_bl)
1505 			buf = NULL;	/* skip current and unlisted bufs */
1506 		    else if (buf->b_ml.ml_mfp == NULL)
1507 		    {
1508 			/* skip unloaded buf, but may keep it for later */
1509 			if (bp == NULL)
1510 			    bp = buf;
1511 			buf = NULL;
1512 		    }
1513 		}
1514 		if (buf != NULL)   /* found a valid buffer: stop searching */
1515 		    break;
1516 		/* advance to older entry in jump list */
1517 		if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
1518 		    break;
1519 		if (--jumpidx < 0)
1520 		    jumpidx = curwin->w_jumplistlen - 1;
1521 		if (jumpidx == forward)		/* List exhausted for sure */
1522 		    break;
1523 	    }
1524 	}
1525 #endif
1526 
1527 	if (buf == NULL)	/* No previous buffer, Try 2'nd approach */
1528 	{
1529 	    forward = TRUE;
1530 	    buf = curbuf->b_next;
1531 	    for (;;)
1532 	    {
1533 		if (buf == NULL)
1534 		{
1535 		    if (!forward)	/* tried both directions */
1536 			break;
1537 		    buf = curbuf->b_prev;
1538 		    forward = FALSE;
1539 		    continue;
1540 		}
1541 		/* in non-help buffer, try to skip help buffers, and vv */
1542 		if (buf->b_help == curbuf->b_help && buf->b_p_bl)
1543 		{
1544 		    if (buf->b_ml.ml_mfp != NULL)   /* found loaded buffer */
1545 			break;
1546 		    if (bp == NULL)	/* remember unloaded buf for later */
1547 			bp = buf;
1548 		}
1549 		if (forward)
1550 		    buf = buf->b_next;
1551 		else
1552 		    buf = buf->b_prev;
1553 	    }
1554 	}
1555 	if (buf == NULL)	/* No loaded buffer, use unloaded one */
1556 	    buf = bp;
1557 	if (buf == NULL)	/* No loaded buffer, find listed one */
1558 	{
1559 	    FOR_ALL_BUFFERS(buf)
1560 		if (buf->b_p_bl && buf != curbuf)
1561 		    break;
1562 	}
1563 	if (buf == NULL)	/* Still no buffer, just take one */
1564 	{
1565 	    if (curbuf->b_next != NULL)
1566 		buf = curbuf->b_next;
1567 	    else
1568 		buf = curbuf->b_prev;
1569 	}
1570     }
1571 
1572     if (buf == NULL)
1573     {
1574 	/* Autocommands must have wiped out all other buffers.  Only option
1575 	 * now is to make the current buffer empty. */
1576 	return empty_curbuf(FALSE, forceit, action);
1577     }
1578 
1579     /*
1580      * make buf current buffer
1581      */
1582     if (action == DOBUF_SPLIT)	    /* split window first */
1583     {
1584 # ifdef FEAT_WINDOWS
1585 	/* If 'switchbuf' contains "useopen": jump to first window containing
1586 	 * "buf" if one exists */
1587 	if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf))
1588 	    return OK;
1589 	/* If 'switchbuf' contains "usetab": jump to first window in any tab
1590 	 * page containing "buf" if one exists */
1591 	if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf))
1592 	    return OK;
1593 	if (win_split(0, 0) == FAIL)
1594 # endif
1595 	    return FAIL;
1596     }
1597 #endif
1598 
1599     /* go to current buffer - nothing to do */
1600     if (buf == curbuf)
1601 	return OK;
1602 
1603     /*
1604      * Check if the current buffer may be abandoned.
1605      */
1606     if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
1607     {
1608 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1609 	if ((p_confirm || cmdmod.confirm) && p_write)
1610 	{
1611 # ifdef FEAT_AUTOCMD
1612 	    bufref_T bufref;
1613 
1614 	    set_bufref(&bufref, buf);
1615 # endif
1616 	    dialog_changed(curbuf, FALSE);
1617 # ifdef FEAT_AUTOCMD
1618 	    if (!bufref_valid(&bufref))
1619 		/* Autocommand deleted buffer, oops! */
1620 		return FAIL;
1621 # endif
1622 	}
1623 	if (bufIsChanged(curbuf))
1624 #endif
1625 	{
1626 	    EMSG(_(e_nowrtmsg));
1627 	    return FAIL;
1628 	}
1629     }
1630 
1631     /* Go to the other buffer. */
1632     set_curbuf(buf, action);
1633 
1634 #if defined(FEAT_LISTCMDS) \
1635 	&& (defined(FEAT_SCROLLBIND) || defined(FEAT_CURSORBIND))
1636     if (action == DOBUF_SPLIT)
1637     {
1638 	RESET_BINDING(curwin);	/* reset 'scrollbind' and 'cursorbind' */
1639     }
1640 #endif
1641 
1642 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1643     if (aborting())	    /* autocmds may abort script processing */
1644 	return FAIL;
1645 #endif
1646 
1647     return OK;
1648 }
1649 #endif
1650 
1651 /*
1652  * Set current buffer to "buf".  Executes autocommands and closes current
1653  * buffer.  "action" tells how to close the current buffer:
1654  * DOBUF_GOTO	    free or hide it
1655  * DOBUF_SPLIT	    nothing
1656  * DOBUF_UNLOAD	    unload it
1657  * DOBUF_DEL	    delete it
1658  * DOBUF_WIPE	    wipe it out
1659  */
1660     void
1661 set_curbuf(buf_T *buf, int action)
1662 {
1663     buf_T	*prevbuf;
1664     int		unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1665 						     || action == DOBUF_WIPE);
1666 #ifdef FEAT_SYN_HL
1667     long	old_tw = curbuf->b_p_tw;
1668 #endif
1669     bufref_T	bufref;
1670 
1671     setpcmark();
1672     if (!cmdmod.keepalt)
1673 	curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
1674     buflist_altfpos(curwin);			 /* remember curpos */
1675 
1676     /* Don't restart Select mode after switching to another buffer. */
1677     VIsual_reselect = FALSE;
1678 
1679     /* close_windows() or apply_autocmds() may change curbuf */
1680     prevbuf = curbuf;
1681     set_bufref(&bufref, prevbuf);
1682 
1683 #ifdef FEAT_AUTOCMD
1684     if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
1685 # ifdef FEAT_EVAL
1686 	    || (bufref_valid(&bufref) && !aborting())
1687 # else
1688 	    || bufref_valid(&bufref)
1689 # endif
1690        )
1691 #endif
1692     {
1693 #ifdef FEAT_SYN_HL
1694 	if (prevbuf == curwin->w_buffer)
1695 	    reset_synblock(curwin);
1696 #endif
1697 #ifdef FEAT_WINDOWS
1698 	if (unload)
1699 	    close_windows(prevbuf, FALSE);
1700 #endif
1701 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1702 	if (bufref_valid(&bufref) && !aborting())
1703 #else
1704 	if (bufref_valid(&bufref))
1705 #endif
1706 	{
1707 #ifdef FEAT_WINDOWS
1708 	    win_T  *previouswin = curwin;
1709 #endif
1710 	    if (prevbuf == curbuf)
1711 		u_sync(FALSE);
1712 	    close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
1713 		    unload ? action : (action == DOBUF_GOTO
1714 			&& !P_HID(prevbuf)
1715 			&& !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
1716 #ifdef FEAT_WINDOWS
1717 	    if (curwin != previouswin && win_valid(previouswin))
1718 	      /* autocommands changed curwin, Grr! */
1719 	      curwin = previouswin;
1720 #endif
1721 	}
1722     }
1723 #ifdef FEAT_AUTOCMD
1724     /* An autocommand may have deleted "buf", already entered it (e.g., when
1725      * it did ":bunload") or aborted the script processing.
1726      * If curwin->w_buffer is null, enter_buffer() will make it valid again */
1727     if ((buf_valid(buf) && buf != curbuf
1728 # ifdef FEAT_EVAL
1729 	    && !aborting()
1730 # endif
1731 # ifdef FEAT_WINDOWS
1732 	 ) || curwin->w_buffer == NULL
1733 # endif
1734        )
1735 #endif
1736     {
1737 	enter_buffer(buf);
1738 #ifdef FEAT_SYN_HL
1739 	if (old_tw != curbuf->b_p_tw)
1740 	    check_colorcolumn(curwin);
1741 #endif
1742     }
1743 }
1744 
1745 /*
1746  * Enter a new current buffer.
1747  * Old curbuf must have been abandoned already!  This also means "curbuf" may
1748  * be pointing to freed memory.
1749  */
1750     void
1751 enter_buffer(buf_T *buf)
1752 {
1753     /* Copy buffer and window local option values.  Not for a help buffer. */
1754     buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
1755     if (!buf->b_help)
1756 	get_winopts(buf);
1757 #ifdef FEAT_FOLDING
1758     else
1759 	/* Remove all folds in the window. */
1760 	clearFolding(curwin);
1761     foldUpdateAll(curwin);	/* update folds (later). */
1762 #endif
1763 
1764     /* Get the buffer in the current window. */
1765     curwin->w_buffer = buf;
1766     curbuf = buf;
1767     ++curbuf->b_nwindows;
1768 
1769 #ifdef FEAT_DIFF
1770     if (curwin->w_p_diff)
1771 	diff_buf_add(curbuf);
1772 #endif
1773 
1774 #ifdef FEAT_SYN_HL
1775     curwin->w_s = &(curbuf->b_s);
1776 #endif
1777 
1778     /* Cursor on first line by default. */
1779     curwin->w_cursor.lnum = 1;
1780     curwin->w_cursor.col = 0;
1781 #ifdef FEAT_VIRTUALEDIT
1782     curwin->w_cursor.coladd = 0;
1783 #endif
1784     curwin->w_set_curswant = TRUE;
1785 #ifdef FEAT_AUTOCMD
1786     curwin->w_topline_was_set = FALSE;
1787 #endif
1788 
1789     /* mark cursor position as being invalid */
1790     curwin->w_valid = 0;
1791 
1792     /* Make sure the buffer is loaded. */
1793     if (curbuf->b_ml.ml_mfp == NULL)	/* need to load the file */
1794     {
1795 #ifdef FEAT_AUTOCMD
1796 	/* If there is no filetype, allow for detecting one.  Esp. useful for
1797 	 * ":ball" used in a autocommand.  If there already is a filetype we
1798 	 * might prefer to keep it. */
1799 	if (*curbuf->b_p_ft == NUL)
1800 	    did_filetype = FALSE;
1801 #endif
1802 
1803 	open_buffer(FALSE, NULL, 0);
1804     }
1805     else
1806     {
1807 	if (!msg_silent)
1808 	    need_fileinfo = TRUE;	/* display file info after redraw */
1809 	(void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
1810 #ifdef FEAT_AUTOCMD
1811 	curwin->w_topline = 1;
1812 # ifdef FEAT_DIFF
1813 	curwin->w_topfill = 0;
1814 # endif
1815 	apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
1816 	apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
1817 #endif
1818     }
1819 
1820     /* If autocommands did not change the cursor position, restore cursor lnum
1821      * and possibly cursor col. */
1822     if (curwin->w_cursor.lnum == 1 && inindent(0))
1823 	buflist_getfpos();
1824 
1825     check_arg_idx(curwin);		/* check for valid arg_idx */
1826 #ifdef FEAT_TITLE
1827     maketitle();
1828 #endif
1829 #ifdef FEAT_AUTOCMD
1830 	/* when autocmds didn't change it */
1831     if (curwin->w_topline == 1 && !curwin->w_topline_was_set)
1832 #endif
1833 	scroll_cursor_halfway(FALSE);	/* redisplay at correct position */
1834 
1835 #ifdef FEAT_NETBEANS_INTG
1836     /* Send fileOpened event because we've changed buffers. */
1837     netbeans_file_activated(curbuf);
1838 #endif
1839 
1840     /* Change directories when the 'acd' option is set. */
1841     DO_AUTOCHDIR
1842 
1843 #ifdef FEAT_KEYMAP
1844     if (curbuf->b_kmap_state & KEYMAP_INIT)
1845 	(void)keymap_init();
1846 #endif
1847 #ifdef FEAT_SPELL
1848     /* May need to set the spell language.  Can only do this after the buffer
1849      * has been properly setup. */
1850     if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
1851 	(void)did_set_spelllang(curwin);
1852 #endif
1853 #ifdef FEAT_VIMINFO
1854     curbuf->b_last_used = vim_time();
1855 #endif
1856 
1857     redraw_later(NOT_VALID);
1858 }
1859 
1860 #if defined(FEAT_AUTOCHDIR) || defined(PROTO)
1861 /*
1862  * Change to the directory of the current buffer.
1863  * Don't do this while still starting up.
1864  */
1865     void
1866 do_autochdir(void)
1867 {
1868     if ((starting == 0 || test_autochdir)
1869 	    && curbuf->b_ffname != NULL
1870 	    && vim_chdirfile(curbuf->b_ffname) == OK)
1871 	shorten_fnames(TRUE);
1872 }
1873 #endif
1874 
1875 /*
1876  * functions for dealing with the buffer list
1877  */
1878 
1879 static int  top_file_num = 1;		/* highest file number */
1880 
1881 /*
1882  * Add a file name to the buffer list.  Return a pointer to the buffer.
1883  * If the same file name already exists return a pointer to that buffer.
1884  * If it does not exist, or if fname == NULL, a new entry is created.
1885  * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
1886  * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
1887  * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
1888  * If (flags & BLN_NEW) is TRUE, don't use an existing buffer.
1889  * If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer
1890  *				    if the buffer already exists.
1891  * This is the ONLY way to create a new buffer.
1892  */
1893     buf_T *
1894 buflist_new(
1895     char_u	*ffname,	/* full path of fname or relative */
1896     char_u	*sfname,	/* short fname or NULL */
1897     linenr_T	lnum,		/* preferred cursor line */
1898     int		flags)		/* BLN_ defines */
1899 {
1900     buf_T	*buf;
1901 #ifdef UNIX
1902     stat_T	st;
1903 #endif
1904 
1905     if (top_file_num == 1)
1906 	hash_init(&buf_hashtab);
1907 
1908     fname_expand(curbuf, &ffname, &sfname);	/* will allocate ffname */
1909 
1910     /*
1911      * If file name already exists in the list, update the entry.
1912      */
1913 #ifdef UNIX
1914     /* On Unix we can use inode numbers when the file exists.  Works better
1915      * for hard links. */
1916     if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
1917 	st.st_dev = (dev_T)-1;
1918 #endif
1919     if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) && (buf =
1920 #ifdef UNIX
1921 		buflist_findname_stat(ffname, &st)
1922 #else
1923 		buflist_findname(ffname)
1924 #endif
1925 		) != NULL)
1926     {
1927 	vim_free(ffname);
1928 	if (lnum != 0)
1929 	    buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
1930 
1931 	if ((flags & BLN_NOOPT) == 0)
1932 	    /* copy the options now, if 'cpo' doesn't have 's' and not done
1933 	     * already */
1934 	    buf_copy_options(buf, 0);
1935 
1936 	if ((flags & BLN_LISTED) && !buf->b_p_bl)
1937 	{
1938 #ifdef FEAT_AUTOCMD
1939 	    bufref_T bufref;
1940 #endif
1941 	    buf->b_p_bl = TRUE;
1942 #ifdef FEAT_AUTOCMD
1943 	    set_bufref(&bufref, buf);
1944 	    if (!(flags & BLN_DUMMY))
1945 	    {
1946 		if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
1947 			&& !bufref_valid(&bufref))
1948 		    return NULL;
1949 	    }
1950 #endif
1951 	}
1952 	return buf;
1953     }
1954 
1955     /*
1956      * If the current buffer has no name and no contents, use the current
1957      * buffer.	Otherwise: Need to allocate a new buffer structure.
1958      *
1959      * This is the ONLY place where a new buffer structure is allocated!
1960      * (A spell file buffer is allocated in spell.c, but that's not a normal
1961      * buffer.)
1962      */
1963     buf = NULL;
1964     if ((flags & BLN_CURBUF)
1965 	    && curbuf != NULL
1966 	    && curbuf->b_ffname == NULL
1967 	    && curbuf->b_nwindows <= 1
1968 	    && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY()))
1969     {
1970 	buf = curbuf;
1971 #ifdef FEAT_AUTOCMD
1972 	/* It's like this buffer is deleted.  Watch out for autocommands that
1973 	 * change curbuf!  If that happens, allocate a new buffer anyway. */
1974 	if (curbuf->b_p_bl)
1975 	    apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
1976 	if (buf == curbuf)
1977 	    apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
1978 # ifdef FEAT_EVAL
1979 	if (aborting())		/* autocmds may abort script processing */
1980 	    return NULL;
1981 # endif
1982 #endif
1983 #ifdef FEAT_AUTOCMD
1984 	if (buf == curbuf)
1985 #endif
1986 	{
1987 	    /* Make sure 'bufhidden' and 'buftype' are empty */
1988 	    clear_string_option(&buf->b_p_bh);
1989 	    clear_string_option(&buf->b_p_bt);
1990 	}
1991     }
1992     if (buf != curbuf || curbuf == NULL)
1993     {
1994 	buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
1995 	if (buf == NULL)
1996 	{
1997 	    vim_free(ffname);
1998 	    return NULL;
1999 	}
2000 #ifdef FEAT_EVAL
2001 	/* init b: variables */
2002 	buf->b_vars = dict_alloc();
2003 	if (buf->b_vars == NULL)
2004 	{
2005 	    vim_free(ffname);
2006 	    vim_free(buf);
2007 	    return NULL;
2008 	}
2009 	init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
2010 #endif
2011 	init_changedtick(buf);
2012     }
2013 
2014     if (ffname != NULL)
2015     {
2016 	buf->b_ffname = ffname;
2017 	buf->b_sfname = vim_strsave(sfname);
2018     }
2019 
2020     clear_wininfo(buf);
2021     buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
2022 
2023     if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
2024 	    || buf->b_wininfo == NULL)
2025     {
2026 	vim_free(buf->b_ffname);
2027 	buf->b_ffname = NULL;
2028 	vim_free(buf->b_sfname);
2029 	buf->b_sfname = NULL;
2030 	if (buf != curbuf)
2031 	    free_buffer(buf);
2032 	return NULL;
2033     }
2034 
2035     if (buf == curbuf)
2036     {
2037 	/* free all things allocated for this buffer */
2038 	buf_freeall(buf, 0);
2039 	if (buf != curbuf)	 /* autocommands deleted the buffer! */
2040 	    return NULL;
2041 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
2042 	if (aborting())		/* autocmds may abort script processing */
2043 	    return NULL;
2044 #endif
2045 	free_buffer_stuff(buf, FALSE);	/* delete local variables et al. */
2046 
2047 	/* Init the options. */
2048 	buf->b_p_initialized = FALSE;
2049 	buf_copy_options(buf, BCO_ENTER);
2050 
2051 #ifdef FEAT_KEYMAP
2052 	/* need to reload lmaps and set b:keymap_name */
2053 	curbuf->b_kmap_state |= KEYMAP_INIT;
2054 #endif
2055     }
2056     else
2057     {
2058 	/*
2059 	 * put new buffer at the end of the buffer list
2060 	 */
2061 	buf->b_next = NULL;
2062 	if (firstbuf == NULL)		/* buffer list is empty */
2063 	{
2064 	    buf->b_prev = NULL;
2065 	    firstbuf = buf;
2066 	}
2067 	else				/* append new buffer at end of list */
2068 	{
2069 	    lastbuf->b_next = buf;
2070 	    buf->b_prev = lastbuf;
2071 	}
2072 	lastbuf = buf;
2073 
2074 	buf->b_fnum = top_file_num++;
2075 	if (top_file_num < 0)		/* wrap around (may cause duplicates) */
2076 	{
2077 	    EMSG(_("W14: Warning: List of file names overflow"));
2078 	    if (emsg_silent == 0)
2079 	    {
2080 		out_flush();
2081 		ui_delay(3000L, TRUE);	/* make sure it is noticed */
2082 	    }
2083 	    top_file_num = 1;
2084 	}
2085 	buf_hashtab_add(buf);
2086 
2087 	/*
2088 	 * Always copy the options from the current buffer.
2089 	 */
2090 	buf_copy_options(buf, BCO_ALWAYS);
2091     }
2092 
2093     buf->b_wininfo->wi_fpos.lnum = lnum;
2094     buf->b_wininfo->wi_win = curwin;
2095 
2096 #ifdef FEAT_SYN_HL
2097     hash_init(&buf->b_s.b_keywtab);
2098     hash_init(&buf->b_s.b_keywtab_ic);
2099 #endif
2100 
2101     buf->b_fname = buf->b_sfname;
2102 #ifdef UNIX
2103     if (st.st_dev == (dev_T)-1)
2104 	buf->b_dev_valid = FALSE;
2105     else
2106     {
2107 	buf->b_dev_valid = TRUE;
2108 	buf->b_dev = st.st_dev;
2109 	buf->b_ino = st.st_ino;
2110     }
2111 #endif
2112     buf->b_u_synced = TRUE;
2113     buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
2114     if (flags & BLN_DUMMY)
2115 	buf->b_flags |= BF_DUMMY;
2116     buf_clear_file(buf);
2117     clrallmarks(buf);			/* clear marks */
2118     fmarks_check_names(buf);		/* check file marks for this file */
2119     buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE;	/* init 'buflisted' */
2120 #ifdef FEAT_AUTOCMD
2121     if (!(flags & BLN_DUMMY))
2122     {
2123 	bufref_T bufref;
2124 
2125 	/* Tricky: these autocommands may change the buffer list.  They could
2126 	 * also split the window with re-using the one empty buffer. This may
2127 	 * result in unexpectedly losing the empty buffer. */
2128 	set_bufref(&bufref, buf);
2129 	if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
2130 		&& !bufref_valid(&bufref))
2131 	    return NULL;
2132 	if (flags & BLN_LISTED)
2133 	{
2134 	    if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
2135 		    && !bufref_valid(&bufref))
2136 		return NULL;
2137 	}
2138 # ifdef FEAT_EVAL
2139 	if (aborting())		/* autocmds may abort script processing */
2140 	    return NULL;
2141 # endif
2142     }
2143 #endif
2144 
2145     return buf;
2146 }
2147 
2148 /*
2149  * Free the memory for the options of a buffer.
2150  * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
2151  * 'fileencoding'.
2152  */
2153     void
2154 free_buf_options(
2155     buf_T	*buf,
2156     int		free_p_ff)
2157 {
2158     if (free_p_ff)
2159     {
2160 #ifdef FEAT_MBYTE
2161 	clear_string_option(&buf->b_p_fenc);
2162 #endif
2163 	clear_string_option(&buf->b_p_ff);
2164 	clear_string_option(&buf->b_p_bh);
2165 	clear_string_option(&buf->b_p_bt);
2166     }
2167 #ifdef FEAT_FIND_ID
2168     clear_string_option(&buf->b_p_def);
2169     clear_string_option(&buf->b_p_inc);
2170 # ifdef FEAT_EVAL
2171     clear_string_option(&buf->b_p_inex);
2172 # endif
2173 #endif
2174 #if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
2175     clear_string_option(&buf->b_p_inde);
2176     clear_string_option(&buf->b_p_indk);
2177 #endif
2178 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
2179     clear_string_option(&buf->b_p_bexpr);
2180 #endif
2181 #if defined(FEAT_CRYPT)
2182     clear_string_option(&buf->b_p_cm);
2183 #endif
2184     clear_string_option(&buf->b_p_fp);
2185 #if defined(FEAT_EVAL)
2186     clear_string_option(&buf->b_p_fex);
2187 #endif
2188 #ifdef FEAT_CRYPT
2189     clear_string_option(&buf->b_p_key);
2190 #endif
2191     clear_string_option(&buf->b_p_kp);
2192     clear_string_option(&buf->b_p_mps);
2193     clear_string_option(&buf->b_p_fo);
2194     clear_string_option(&buf->b_p_flp);
2195     clear_string_option(&buf->b_p_isk);
2196 #ifdef FEAT_KEYMAP
2197     clear_string_option(&buf->b_p_keymap);
2198     ga_clear(&buf->b_kmap_ga);
2199 #endif
2200 #ifdef FEAT_COMMENTS
2201     clear_string_option(&buf->b_p_com);
2202 #endif
2203 #ifdef FEAT_FOLDING
2204     clear_string_option(&buf->b_p_cms);
2205 #endif
2206     clear_string_option(&buf->b_p_nf);
2207 #ifdef FEAT_SYN_HL
2208     clear_string_option(&buf->b_p_syn);
2209     clear_string_option(&buf->b_s.b_syn_isk);
2210 #endif
2211 #ifdef FEAT_SPELL
2212     clear_string_option(&buf->b_s.b_p_spc);
2213     clear_string_option(&buf->b_s.b_p_spf);
2214     vim_regfree(buf->b_s.b_cap_prog);
2215     buf->b_s.b_cap_prog = NULL;
2216     clear_string_option(&buf->b_s.b_p_spl);
2217 #endif
2218 #ifdef FEAT_SEARCHPATH
2219     clear_string_option(&buf->b_p_sua);
2220 #endif
2221 #ifdef FEAT_AUTOCMD
2222     clear_string_option(&buf->b_p_ft);
2223 #endif
2224 #ifdef FEAT_CINDENT
2225     clear_string_option(&buf->b_p_cink);
2226     clear_string_option(&buf->b_p_cino);
2227 #endif
2228 #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
2229     clear_string_option(&buf->b_p_cinw);
2230 #endif
2231 #ifdef FEAT_INS_EXPAND
2232     clear_string_option(&buf->b_p_cpt);
2233 #endif
2234 #ifdef FEAT_COMPL_FUNC
2235     clear_string_option(&buf->b_p_cfu);
2236     clear_string_option(&buf->b_p_ofu);
2237 #endif
2238 #ifdef FEAT_QUICKFIX
2239     clear_string_option(&buf->b_p_gp);
2240     clear_string_option(&buf->b_p_mp);
2241     clear_string_option(&buf->b_p_efm);
2242 #endif
2243     clear_string_option(&buf->b_p_ep);
2244     clear_string_option(&buf->b_p_path);
2245     clear_string_option(&buf->b_p_tags);
2246     clear_string_option(&buf->b_p_tc);
2247 #ifdef FEAT_INS_EXPAND
2248     clear_string_option(&buf->b_p_dict);
2249     clear_string_option(&buf->b_p_tsr);
2250 #endif
2251 #ifdef FEAT_TEXTOBJ
2252     clear_string_option(&buf->b_p_qe);
2253 #endif
2254     buf->b_p_ar = -1;
2255     buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
2256 #ifdef FEAT_LISP
2257     clear_string_option(&buf->b_p_lw);
2258 #endif
2259     clear_string_option(&buf->b_p_bkc);
2260 #ifdef FEAT_MBYTE
2261     clear_string_option(&buf->b_p_menc);
2262 #endif
2263 }
2264 
2265 /*
2266  * Get alternate file "n".
2267  * Set linenr to "lnum" or altfpos.lnum if "lnum" == 0.
2268  *	Also set cursor column to altfpos.col if 'startofline' is not set.
2269  * if (options & GETF_SETMARK) call setpcmark()
2270  * if (options & GETF_ALT) we are jumping to an alternate file.
2271  * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
2272  *
2273  * Return FAIL for failure, OK for success.
2274  */
2275     int
2276 buflist_getfile(
2277     int		n,
2278     linenr_T	lnum,
2279     int		options,
2280     int		forceit)
2281 {
2282     buf_T	*buf;
2283 #ifdef FEAT_WINDOWS
2284     win_T	*wp = NULL;
2285 #endif
2286     pos_T	*fpos;
2287     colnr_T	col;
2288 
2289     buf = buflist_findnr(n);
2290     if (buf == NULL)
2291     {
2292 	if ((options & GETF_ALT) && n == 0)
2293 	    EMSG(_(e_noalt));
2294 	else
2295 	    EMSGN(_("E92: Buffer %ld not found"), n);
2296 	return FAIL;
2297     }
2298 
2299     /* if alternate file is the current buffer, nothing to do */
2300     if (buf == curbuf)
2301 	return OK;
2302 
2303     if (text_locked())
2304     {
2305 	text_locked_msg();
2306 	return FAIL;
2307     }
2308 #ifdef FEAT_AUTOCMD
2309     if (curbuf_locked())
2310 	return FAIL;
2311 #endif
2312 
2313     /* altfpos may be changed by getfile(), get it now */
2314     if (lnum == 0)
2315     {
2316 	fpos = buflist_findfpos(buf);
2317 	lnum = fpos->lnum;
2318 	col = fpos->col;
2319     }
2320     else
2321 	col = 0;
2322 
2323 #ifdef FEAT_WINDOWS
2324     if (options & GETF_SWITCH)
2325     {
2326 	/* If 'switchbuf' contains "useopen": jump to first window containing
2327 	 * "buf" if one exists */
2328 	if (swb_flags & SWB_USEOPEN)
2329 	    wp = buf_jump_open_win(buf);
2330 
2331 	/* If 'switchbuf' contains "usetab": jump to first window in any tab
2332 	 * page containing "buf" if one exists */
2333 	if (wp == NULL && (swb_flags & SWB_USETAB))
2334 	    wp = buf_jump_open_tab(buf);
2335 
2336 	/* If 'switchbuf' contains "split", "vsplit" or "newtab" and the
2337 	 * current buffer isn't empty: open new tab or window */
2338 	if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
2339 							       && !BUFEMPTY())
2340 	{
2341 	    if (swb_flags & SWB_NEWTAB)
2342 		tabpage_new();
2343 	    else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
2344 								      == FAIL)
2345 		return FAIL;
2346 	    RESET_BINDING(curwin);
2347 	}
2348     }
2349 #endif
2350 
2351     ++RedrawingDisabled;
2352     if (GETFILE_SUCCESS(getfile(buf->b_fnum, NULL, NULL,
2353 				     (options & GETF_SETMARK), lnum, forceit)))
2354     {
2355 	--RedrawingDisabled;
2356 
2357 	/* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
2358 	if (!p_sol && col != 0)
2359 	{
2360 	    curwin->w_cursor.col = col;
2361 	    check_cursor_col();
2362 #ifdef FEAT_VIRTUALEDIT
2363 	    curwin->w_cursor.coladd = 0;
2364 #endif
2365 	    curwin->w_set_curswant = TRUE;
2366 	}
2367 	return OK;
2368     }
2369     --RedrawingDisabled;
2370     return FAIL;
2371 }
2372 
2373 /*
2374  * go to the last know line number for the current buffer
2375  */
2376     void
2377 buflist_getfpos(void)
2378 {
2379     pos_T	*fpos;
2380 
2381     fpos = buflist_findfpos(curbuf);
2382 
2383     curwin->w_cursor.lnum = fpos->lnum;
2384     check_cursor_lnum();
2385 
2386     if (p_sol)
2387 	curwin->w_cursor.col = 0;
2388     else
2389     {
2390 	curwin->w_cursor.col = fpos->col;
2391 	check_cursor_col();
2392 #ifdef FEAT_VIRTUALEDIT
2393 	curwin->w_cursor.coladd = 0;
2394 #endif
2395 	curwin->w_set_curswant = TRUE;
2396     }
2397 }
2398 
2399 #if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO)
2400 /*
2401  * Find file in buffer list by name (it has to be for the current window).
2402  * Returns NULL if not found.
2403  */
2404     buf_T *
2405 buflist_findname_exp(char_u *fname)
2406 {
2407     char_u	*ffname;
2408     buf_T	*buf = NULL;
2409 
2410     /* First make the name into a full path name */
2411     ffname = FullName_save(fname,
2412 #ifdef UNIX
2413 	    TRUE	    /* force expansion, get rid of symbolic links */
2414 #else
2415 	    FALSE
2416 #endif
2417 	    );
2418     if (ffname != NULL)
2419     {
2420 	buf = buflist_findname(ffname);
2421 	vim_free(ffname);
2422     }
2423     return buf;
2424 }
2425 #endif
2426 
2427 /*
2428  * Find file in buffer list by name (it has to be for the current window).
2429  * "ffname" must have a full path.
2430  * Skips dummy buffers.
2431  * Returns NULL if not found.
2432  */
2433     buf_T *
2434 buflist_findname(char_u *ffname)
2435 {
2436 #ifdef UNIX
2437     stat_T	st;
2438 
2439     if (mch_stat((char *)ffname, &st) < 0)
2440 	st.st_dev = (dev_T)-1;
2441     return buflist_findname_stat(ffname, &st);
2442 }
2443 
2444 /*
2445  * Same as buflist_findname(), but pass the stat structure to avoid getting it
2446  * twice for the same file.
2447  * Returns NULL if not found.
2448  */
2449     static buf_T *
2450 buflist_findname_stat(
2451     char_u	*ffname,
2452     stat_T	*stp)
2453 {
2454 #endif
2455     buf_T	*buf;
2456 
2457     /* Start at the last buffer, expect to find a match sooner. */
2458     for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
2459 	if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname
2460 #ifdef UNIX
2461 		    , stp
2462 #endif
2463 		    ))
2464 	    return buf;
2465     return NULL;
2466 }
2467 
2468 #if defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) \
2469 	|| defined(PROTO)
2470 /*
2471  * Find file in buffer list by a regexp pattern.
2472  * Return fnum of the found buffer.
2473  * Return < 0 for error.
2474  */
2475     int
2476 buflist_findpat(
2477     char_u	*pattern,
2478     char_u	*pattern_end,	/* pointer to first char after pattern */
2479     int		unlisted,	/* find unlisted buffers */
2480     int		diffmode UNUSED, /* find diff-mode buffers only */
2481     int		curtab_only)	/* find buffers in current tab only */
2482 {
2483     buf_T	*buf;
2484     int		match = -1;
2485     int		find_listed;
2486     char_u	*pat;
2487     char_u	*patend;
2488     int		attempt;
2489     char_u	*p;
2490     int		toggledollar;
2491 
2492     if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
2493     {
2494 	if (*pattern == '%')
2495 	    match = curbuf->b_fnum;
2496 	else
2497 	    match = curwin->w_alt_fnum;
2498 #ifdef FEAT_DIFF
2499 	if (diffmode && !diff_mode_buf(buflist_findnr(match)))
2500 	    match = -1;
2501 #endif
2502     }
2503 
2504     /*
2505      * Try four ways of matching a listed buffer:
2506      * attempt == 0: without '^' or '$' (at any position)
2507      * attempt == 1: with '^' at start (only at position 0)
2508      * attempt == 2: with '$' at end (only match at end)
2509      * attempt == 3: with '^' at start and '$' at end (only full match)
2510      * Repeat this for finding an unlisted buffer if there was no matching
2511      * listed buffer.
2512      */
2513     else
2514     {
2515 	pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
2516 	if (pat == NULL)
2517 	    return -1;
2518 	patend = pat + STRLEN(pat) - 1;
2519 	toggledollar = (patend > pat && *patend == '$');
2520 
2521 	/* First try finding a listed buffer.  If not found and "unlisted"
2522 	 * is TRUE, try finding an unlisted buffer. */
2523 	find_listed = TRUE;
2524 	for (;;)
2525 	{
2526 	    for (attempt = 0; attempt <= 3; ++attempt)
2527 	    {
2528 		regmatch_T	regmatch;
2529 
2530 		/* may add '^' and '$' */
2531 		if (toggledollar)
2532 		    *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
2533 		p = pat;
2534 		if (*p == '^' && !(attempt & 1))	 /* add/remove '^' */
2535 		    ++p;
2536 		regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2537 		if (regmatch.regprog == NULL)
2538 		{
2539 		    vim_free(pat);
2540 		    return -1;
2541 		}
2542 
2543 		for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
2544 		    if (buf->b_p_bl == find_listed
2545 #ifdef FEAT_DIFF
2546 			    && (!diffmode || diff_mode_buf(buf))
2547 #endif
2548 			    && buflist_match(&regmatch, buf, FALSE) != NULL)
2549 		    {
2550 			if (curtab_only)
2551 			{
2552 			    /* Ignore the match if the buffer is not open in
2553 			     * the current tab. */
2554 #ifdef FEAT_WINDOWS
2555 			    win_T	*wp;
2556 
2557 			    FOR_ALL_WINDOWS(wp)
2558 				if (wp->w_buffer == buf)
2559 				    break;
2560 			    if (wp == NULL)
2561 				continue;
2562 #else
2563 			    if (curwin->w_buffer != buf)
2564 				continue;
2565 #endif
2566 			}
2567 			if (match >= 0)		/* already found a match */
2568 			{
2569 			    match = -2;
2570 			    break;
2571 			}
2572 			match = buf->b_fnum;	/* remember first match */
2573 		    }
2574 
2575 		vim_regfree(regmatch.regprog);
2576 		if (match >= 0)			/* found one match */
2577 		    break;
2578 	    }
2579 
2580 	    /* Only search for unlisted buffers if there was no match with
2581 	     * a listed buffer. */
2582 	    if (!unlisted || !find_listed || match != -1)
2583 		break;
2584 	    find_listed = FALSE;
2585 	}
2586 
2587 	vim_free(pat);
2588     }
2589 
2590     if (match == -2)
2591 	EMSG2(_("E93: More than one match for %s"), pattern);
2592     else if (match < 0)
2593 	EMSG2(_("E94: No matching buffer for %s"), pattern);
2594     return match;
2595 }
2596 #endif
2597 
2598 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2599 
2600 /*
2601  * Find all buffer names that match.
2602  * For command line expansion of ":buf" and ":sbuf".
2603  * Return OK if matches found, FAIL otherwise.
2604  */
2605     int
2606 ExpandBufnames(
2607     char_u	*pat,
2608     int		*num_file,
2609     char_u	***file,
2610     int		options)
2611 {
2612     int		count = 0;
2613     buf_T	*buf;
2614     int		round;
2615     char_u	*p;
2616     int		attempt;
2617     char_u	*patc;
2618 
2619     *num_file = 0;		    /* return values in case of FAIL */
2620     *file = NULL;
2621 
2622     /* Make a copy of "pat" and change "^" to "\(^\|[\/]\)". */
2623     if (*pat == '^')
2624     {
2625 	patc = alloc((unsigned)STRLEN(pat) + 11);
2626 	if (patc == NULL)
2627 	    return FAIL;
2628 	STRCPY(patc, "\\(^\\|[\\/]\\)");
2629 	STRCPY(patc + 11, pat + 1);
2630     }
2631     else
2632 	patc = pat;
2633 
2634     /*
2635      * attempt == 0: try match with    '\<', match at start of word
2636      * attempt == 1: try match without '\<', match anywhere
2637      */
2638     for (attempt = 0; attempt <= 1; ++attempt)
2639     {
2640 	regmatch_T	regmatch;
2641 
2642 	if (attempt > 0 && patc == pat)
2643 	    break;	/* there was no anchor, no need to try again */
2644 	regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
2645 	if (regmatch.regprog == NULL)
2646 	{
2647 	    if (patc != pat)
2648 		vim_free(patc);
2649 	    return FAIL;
2650 	}
2651 
2652 	/*
2653 	 * round == 1: Count the matches.
2654 	 * round == 2: Build the array to keep the matches.
2655 	 */
2656 	for (round = 1; round <= 2; ++round)
2657 	{
2658 	    count = 0;
2659 	    FOR_ALL_BUFFERS(buf)
2660 	    {
2661 		if (!buf->b_p_bl)	/* skip unlisted buffers */
2662 		    continue;
2663 		p = buflist_match(&regmatch, buf, p_wic);
2664 		if (p != NULL)
2665 		{
2666 		    if (round == 1)
2667 			++count;
2668 		    else
2669 		    {
2670 			if (options & WILD_HOME_REPLACE)
2671 			    p = home_replace_save(buf, p);
2672 			else
2673 			    p = vim_strsave(p);
2674 			(*file)[count++] = p;
2675 		    }
2676 		}
2677 	    }
2678 	    if (count == 0)	/* no match found, break here */
2679 		break;
2680 	    if (round == 1)
2681 	    {
2682 		*file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
2683 		if (*file == NULL)
2684 		{
2685 		    vim_regfree(regmatch.regprog);
2686 		    if (patc != pat)
2687 			vim_free(patc);
2688 		    return FAIL;
2689 		}
2690 	    }
2691 	}
2692 	vim_regfree(regmatch.regprog);
2693 	if (count)		/* match(es) found, break here */
2694 	    break;
2695     }
2696 
2697     if (patc != pat)
2698 	vim_free(patc);
2699 
2700     *num_file = count;
2701     return (count == 0 ? FAIL : OK);
2702 }
2703 
2704 #endif /* FEAT_CMDL_COMPL */
2705 
2706 #ifdef HAVE_BUFLIST_MATCH
2707 /*
2708  * Check for a match on the file name for buffer "buf" with regprog "prog".
2709  */
2710     static char_u *
2711 buflist_match(
2712     regmatch_T	*rmp,
2713     buf_T	*buf,
2714     int		ignore_case)  /* when TRUE ignore case, when FALSE use 'fic' */
2715 {
2716     char_u	*match;
2717 
2718     /* First try the short file name, then the long file name. */
2719     match = fname_match(rmp, buf->b_sfname, ignore_case);
2720     if (match == NULL)
2721 	match = fname_match(rmp, buf->b_ffname, ignore_case);
2722 
2723     return match;
2724 }
2725 
2726 /*
2727  * Try matching the regexp in "prog" with file name "name".
2728  * Return "name" when there is a match, NULL when not.
2729  */
2730     static char_u *
2731 fname_match(
2732     regmatch_T	*rmp,
2733     char_u	*name,
2734     int		ignore_case)  /* when TRUE ignore case, when FALSE use 'fic' */
2735 {
2736     char_u	*match = NULL;
2737     char_u	*p;
2738 
2739     if (name != NULL)
2740     {
2741 	/* Ignore case when 'fileignorecase' or the argument is set. */
2742 	rmp->rm_ic = p_fic || ignore_case;
2743 	if (vim_regexec(rmp, name, (colnr_T)0))
2744 	    match = name;
2745 	else
2746 	{
2747 	    /* Replace $(HOME) with '~' and try matching again. */
2748 	    p = home_replace_save(NULL, name);
2749 	    if (p != NULL && vim_regexec(rmp, p, (colnr_T)0))
2750 		match = name;
2751 	    vim_free(p);
2752 	}
2753     }
2754 
2755     return match;
2756 }
2757 #endif
2758 
2759 /*
2760  * Find a file in the buffer list by buffer number.
2761  */
2762     buf_T *
2763 buflist_findnr(int nr)
2764 {
2765     char_u	key[VIM_SIZEOF_INT * 2 + 1];
2766     hashitem_T	*hi;
2767 
2768     if (nr == 0)
2769 	nr = curwin->w_alt_fnum;
2770     sprintf((char *)key, "%x", nr);
2771     hi = hash_find(&buf_hashtab, key);
2772 
2773     if (!HASHITEM_EMPTY(hi))
2774 	return (buf_T *)(hi->hi_key
2775 			     - ((unsigned)(curbuf->b_key - (char_u *)curbuf)));
2776     return NULL;
2777 }
2778 
2779 /*
2780  * Get name of file 'n' in the buffer list.
2781  * When the file has no name an empty string is returned.
2782  * home_replace() is used to shorten the file name (used for marks).
2783  * Returns a pointer to allocated memory, of NULL when failed.
2784  */
2785     char_u *
2786 buflist_nr2name(
2787     int		n,
2788     int		fullname,
2789     int		helptail)	/* for help buffers return tail only */
2790 {
2791     buf_T	*buf;
2792 
2793     buf = buflist_findnr(n);
2794     if (buf == NULL)
2795 	return NULL;
2796     return home_replace_save(helptail ? buf : NULL,
2797 				     fullname ? buf->b_ffname : buf->b_fname);
2798 }
2799 
2800 /*
2801  * Set the "lnum" and "col" for the buffer "buf" and the current window.
2802  * When "copy_options" is TRUE save the local window option values.
2803  * When "lnum" is 0 only do the options.
2804  */
2805     static void
2806 buflist_setfpos(
2807     buf_T	*buf,
2808     win_T	*win,
2809     linenr_T	lnum,
2810     colnr_T	col,
2811     int		copy_options)
2812 {
2813     wininfo_T	*wip;
2814 
2815     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2816 	if (wip->wi_win == win)
2817 	    break;
2818     if (wip == NULL)
2819     {
2820 	/* allocate a new entry */
2821 	wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
2822 	if (wip == NULL)
2823 	    return;
2824 	wip->wi_win = win;
2825 	if (lnum == 0)		/* set lnum even when it's 0 */
2826 	    lnum = 1;
2827     }
2828     else
2829     {
2830 	/* remove the entry from the list */
2831 	if (wip->wi_prev)
2832 	    wip->wi_prev->wi_next = wip->wi_next;
2833 	else
2834 	    buf->b_wininfo = wip->wi_next;
2835 	if (wip->wi_next)
2836 	    wip->wi_next->wi_prev = wip->wi_prev;
2837 	if (copy_options && wip->wi_optset)
2838 	{
2839 	    clear_winopt(&wip->wi_opt);
2840 #ifdef FEAT_FOLDING
2841 	    deleteFoldRecurse(&wip->wi_folds);
2842 #endif
2843 	}
2844     }
2845     if (lnum != 0)
2846     {
2847 	wip->wi_fpos.lnum = lnum;
2848 	wip->wi_fpos.col = col;
2849     }
2850     if (copy_options)
2851     {
2852 	/* Save the window-specific option values. */
2853 	copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
2854 #ifdef FEAT_FOLDING
2855 	wip->wi_fold_manual = win->w_fold_manual;
2856 	cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
2857 #endif
2858 	wip->wi_optset = TRUE;
2859     }
2860 
2861     /* insert the entry in front of the list */
2862     wip->wi_next = buf->b_wininfo;
2863     buf->b_wininfo = wip;
2864     wip->wi_prev = NULL;
2865     if (wip->wi_next)
2866 	wip->wi_next->wi_prev = wip;
2867 
2868     return;
2869 }
2870 
2871 #ifdef FEAT_DIFF
2872 static int wininfo_other_tab_diff(wininfo_T *wip);
2873 
2874 /*
2875  * Return TRUE when "wip" has 'diff' set and the diff is only for another tab
2876  * page.  That's because a diff is local to a tab page.
2877  */
2878     static int
2879 wininfo_other_tab_diff(wininfo_T *wip)
2880 {
2881     win_T	*wp;
2882 
2883     if (wip->wi_opt.wo_diff)
2884     {
2885 	FOR_ALL_WINDOWS(wp)
2886 	    /* return FALSE when it's a window in the current tab page, thus
2887 	     * the buffer was in diff mode here */
2888 	    if (wip->wi_win == wp)
2889 		return FALSE;
2890 	return TRUE;
2891     }
2892     return FALSE;
2893 }
2894 #endif
2895 
2896 /*
2897  * Find info for the current window in buffer "buf".
2898  * If not found, return the info for the most recently used window.
2899  * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in
2900  * another tab page.
2901  * Returns NULL when there isn't any info.
2902  */
2903     static wininfo_T *
2904 find_wininfo(
2905     buf_T	*buf,
2906     int		skip_diff_buffer UNUSED)
2907 {
2908     wininfo_T	*wip;
2909 
2910     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2911 	if (wip->wi_win == curwin
2912 #ifdef FEAT_DIFF
2913 		&& (!skip_diff_buffer || !wininfo_other_tab_diff(wip))
2914 #endif
2915 	   )
2916 	    break;
2917 
2918     /* If no wininfo for curwin, use the first in the list (that doesn't have
2919      * 'diff' set and is in another tab page). */
2920     if (wip == NULL)
2921     {
2922 #ifdef FEAT_DIFF
2923 	if (skip_diff_buffer)
2924 	{
2925 	    for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2926 		if (!wininfo_other_tab_diff(wip))
2927 		    break;
2928 	}
2929 	else
2930 #endif
2931 	    wip = buf->b_wininfo;
2932     }
2933     return wip;
2934 }
2935 
2936 /*
2937  * Reset the local window options to the values last used in this window.
2938  * If the buffer wasn't used in this window before, use the values from
2939  * the most recently used window.  If the values were never set, use the
2940  * global values for the window.
2941  */
2942     void
2943 get_winopts(buf_T *buf)
2944 {
2945     wininfo_T	*wip;
2946 
2947     clear_winopt(&curwin->w_onebuf_opt);
2948 #ifdef FEAT_FOLDING
2949     clearFolding(curwin);
2950 #endif
2951 
2952     wip = find_wininfo(buf, TRUE);
2953     if (wip != NULL && wip->wi_optset)
2954     {
2955 	copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
2956 #ifdef FEAT_FOLDING
2957 	curwin->w_fold_manual = wip->wi_fold_manual;
2958 	curwin->w_foldinvalid = TRUE;
2959 	cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
2960 #endif
2961     }
2962     else
2963 	copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
2964 
2965 #ifdef FEAT_FOLDING
2966     /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
2967     if (p_fdls >= 0)
2968 	curwin->w_p_fdl = p_fdls;
2969 #endif
2970 #ifdef FEAT_SYN_HL
2971     check_colorcolumn(curwin);
2972 #endif
2973 }
2974 
2975 /*
2976  * Find the position (lnum and col) for the buffer 'buf' for the current
2977  * window.
2978  * Returns a pointer to no_position if no position is found.
2979  */
2980     pos_T *
2981 buflist_findfpos(buf_T *buf)
2982 {
2983     wininfo_T	*wip;
2984     static pos_T no_position = INIT_POS_T(1, 0, 0);
2985 
2986     wip = find_wininfo(buf, FALSE);
2987     if (wip != NULL)
2988 	return &(wip->wi_fpos);
2989     else
2990 	return &no_position;
2991 }
2992 
2993 /*
2994  * Find the lnum for the buffer 'buf' for the current window.
2995  */
2996     linenr_T
2997 buflist_findlnum(buf_T *buf)
2998 {
2999     return buflist_findfpos(buf)->lnum;
3000 }
3001 
3002 #if defined(FEAT_LISTCMDS) || defined(PROTO)
3003 /*
3004  * List all known file names (for :files and :buffers command).
3005  */
3006     void
3007 buflist_list(exarg_T *eap)
3008 {
3009     buf_T	*buf;
3010     int		len;
3011     int		i;
3012 
3013     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
3014     {
3015 	/* skip unlisted buffers, unless ! was used */
3016 	if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u'))
3017 		|| (vim_strchr(eap->arg, 'u') && buf->b_p_bl)
3018 		|| (vim_strchr(eap->arg, '+')
3019 			&& ((buf->b_flags & BF_READERR) || !bufIsChanged(buf)))
3020 		|| (vim_strchr(eap->arg, 'a')
3021 			 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0))
3022 		|| (vim_strchr(eap->arg, 'h')
3023 			 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0))
3024 		|| (vim_strchr(eap->arg, '-') && buf->b_p_ma)
3025 		|| (vim_strchr(eap->arg, '=') && !buf->b_p_ro)
3026 		|| (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR))
3027 		|| (vim_strchr(eap->arg, '%') && buf != curbuf)
3028 		|| (vim_strchr(eap->arg, '#')
3029 		      && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum)))
3030 	    continue;
3031 	if (buf_spname(buf) != NULL)
3032 	    vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
3033 	else
3034 	    home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
3035 	if (message_filtered(NameBuff))
3036 	    continue;
3037 
3038 	msg_putchar('\n');
3039 	len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
3040 		buf->b_fnum,
3041 		buf->b_p_bl ? ' ' : 'u',
3042 		buf == curbuf ? '%' :
3043 			(curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
3044 		buf->b_ml.ml_mfp == NULL ? ' ' :
3045 			(buf->b_nwindows == 0 ? 'h' : 'a'),
3046 		!buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '),
3047 		(buf->b_flags & BF_READERR) ? 'x'
3048 					    : (bufIsChanged(buf) ? '+' : ' '),
3049 		NameBuff);
3050 	if (len > IOSIZE - 20)
3051 	    len = IOSIZE - 20;
3052 
3053 	/* put "line 999" in column 40 or after the file name */
3054 	i = 40 - vim_strsize(IObuff);
3055 	do
3056 	{
3057 	    IObuff[len++] = ' ';
3058 	} while (--i > 0 && len < IOSIZE - 18);
3059 	vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
3060 		_("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
3061 					       : (long)buflist_findlnum(buf));
3062 	msg_outtrans(IObuff);
3063 	out_flush();	    /* output one line at a time */
3064 	ui_breakcheck();
3065     }
3066 }
3067 #endif
3068 
3069 /*
3070  * Get file name and line number for file 'fnum'.
3071  * Used by DoOneCmd() for translating '%' and '#'.
3072  * Used by insert_reg() and cmdline_paste() for '#' register.
3073  * Return FAIL if not found, OK for success.
3074  */
3075     int
3076 buflist_name_nr(
3077     int		fnum,
3078     char_u	**fname,
3079     linenr_T	*lnum)
3080 {
3081     buf_T	*buf;
3082 
3083     buf = buflist_findnr(fnum);
3084     if (buf == NULL || buf->b_fname == NULL)
3085 	return FAIL;
3086 
3087     *fname = buf->b_fname;
3088     *lnum = buflist_findlnum(buf);
3089 
3090     return OK;
3091 }
3092 
3093 /*
3094  * Set the file name for "buf"' to 'ffname', short file name to 'sfname'.
3095  * The file name with the full path is also remembered, for when :cd is used.
3096  * Returns FAIL for failure (file name already in use by other buffer)
3097  *	OK otherwise.
3098  */
3099     int
3100 setfname(
3101     buf_T	*buf,
3102     char_u	*ffname,
3103     char_u	*sfname,
3104     int		message)	/* give message when buffer already exists */
3105 {
3106     buf_T	*obuf = NULL;
3107 #ifdef UNIX
3108     stat_T	st;
3109 #endif
3110 
3111     if (ffname == NULL || *ffname == NUL)
3112     {
3113 	/* Removing the name. */
3114 	vim_free(buf->b_ffname);
3115 	vim_free(buf->b_sfname);
3116 	buf->b_ffname = NULL;
3117 	buf->b_sfname = NULL;
3118 #ifdef UNIX
3119 	st.st_dev = (dev_T)-1;
3120 #endif
3121     }
3122     else
3123     {
3124 	fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
3125 	if (ffname == NULL)		    /* out of memory */
3126 	    return FAIL;
3127 
3128 	/*
3129 	 * if the file name is already used in another buffer:
3130 	 * - if the buffer is loaded, fail
3131 	 * - if the buffer is not loaded, delete it from the list
3132 	 */
3133 #ifdef UNIX
3134 	if (mch_stat((char *)ffname, &st) < 0)
3135 	    st.st_dev = (dev_T)-1;
3136 #endif
3137 	if (!(buf->b_flags & BF_DUMMY))
3138 #ifdef UNIX
3139 	    obuf = buflist_findname_stat(ffname, &st);
3140 #else
3141 	    obuf = buflist_findname(ffname);
3142 #endif
3143 	if (obuf != NULL && obuf != buf)
3144 	{
3145 	    if (obuf->b_ml.ml_mfp != NULL)	/* it's loaded, fail */
3146 	    {
3147 		if (message)
3148 		    EMSG(_("E95: Buffer with this name already exists"));
3149 		vim_free(ffname);
3150 		return FAIL;
3151 	    }
3152 	    /* delete from the list */
3153 	    close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
3154 	}
3155 	sfname = vim_strsave(sfname);
3156 	if (ffname == NULL || sfname == NULL)
3157 	{
3158 	    vim_free(sfname);
3159 	    vim_free(ffname);
3160 	    return FAIL;
3161 	}
3162 #ifdef USE_FNAME_CASE
3163 # ifdef USE_LONG_FNAME
3164 	if (USE_LONG_FNAME)
3165 # endif
3166 	    fname_case(sfname, 0);    /* set correct case for short file name */
3167 #endif
3168 	vim_free(buf->b_ffname);
3169 	vim_free(buf->b_sfname);
3170 	buf->b_ffname = ffname;
3171 	buf->b_sfname = sfname;
3172     }
3173     buf->b_fname = buf->b_sfname;
3174 #ifdef UNIX
3175     if (st.st_dev == (dev_T)-1)
3176 	buf->b_dev_valid = FALSE;
3177     else
3178     {
3179 	buf->b_dev_valid = TRUE;
3180 	buf->b_dev = st.st_dev;
3181 	buf->b_ino = st.st_ino;
3182     }
3183 #endif
3184 
3185     buf->b_shortname = FALSE;
3186 
3187     buf_name_changed(buf);
3188     return OK;
3189 }
3190 
3191 /*
3192  * Crude way of changing the name of a buffer.  Use with care!
3193  * The name should be relative to the current directory.
3194  */
3195     void
3196 buf_set_name(int fnum, char_u *name)
3197 {
3198     buf_T	*buf;
3199 
3200     buf = buflist_findnr(fnum);
3201     if (buf != NULL)
3202     {
3203 	vim_free(buf->b_sfname);
3204 	vim_free(buf->b_ffname);
3205 	buf->b_ffname = vim_strsave(name);
3206 	buf->b_sfname = NULL;
3207 	/* Allocate ffname and expand into full path.  Also resolves .lnk
3208 	 * files on Win32. */
3209 	fname_expand(buf, &buf->b_ffname, &buf->b_sfname);
3210 	buf->b_fname = buf->b_sfname;
3211     }
3212 }
3213 
3214 /*
3215  * Take care of what needs to be done when the name of buffer "buf" has
3216  * changed.
3217  */
3218     void
3219 buf_name_changed(buf_T *buf)
3220 {
3221     /*
3222      * If the file name changed, also change the name of the swapfile
3223      */
3224     if (buf->b_ml.ml_mfp != NULL)
3225 	ml_setname(buf);
3226 
3227     if (curwin->w_buffer == buf)
3228 	check_arg_idx(curwin);	/* check file name for arg list */
3229 #ifdef FEAT_TITLE
3230     maketitle();		/* set window title */
3231 #endif
3232 #ifdef FEAT_WINDOWS
3233     status_redraw_all();	/* status lines need to be redrawn */
3234 #endif
3235     fmarks_check_names(buf);	/* check named file marks */
3236     ml_timestamp(buf);		/* reset timestamp */
3237 }
3238 
3239 /*
3240  * set alternate file name for current window
3241  *
3242  * Used by do_one_cmd(), do_write() and do_ecmd().
3243  * Return the buffer.
3244  */
3245     buf_T *
3246 setaltfname(
3247     char_u	*ffname,
3248     char_u	*sfname,
3249     linenr_T	lnum)
3250 {
3251     buf_T	*buf;
3252 
3253     /* Create a buffer.  'buflisted' is not set if it's a new buffer */
3254     buf = buflist_new(ffname, sfname, lnum, 0);
3255     if (buf != NULL && !cmdmod.keepalt)
3256 	curwin->w_alt_fnum = buf->b_fnum;
3257     return buf;
3258 }
3259 
3260 /*
3261  * Get alternate file name for current window.
3262  * Return NULL if there isn't any, and give error message if requested.
3263  */
3264     char_u  *
3265 getaltfname(
3266     int		errmsg)		/* give error message */
3267 {
3268     char_u	*fname;
3269     linenr_T	dummy;
3270 
3271     if (buflist_name_nr(0, &fname, &dummy) == FAIL)
3272     {
3273 	if (errmsg)
3274 	    EMSG(_(e_noalt));
3275 	return NULL;
3276     }
3277     return fname;
3278 }
3279 
3280 /*
3281  * Add a file name to the buflist and return its number.
3282  * Uses same flags as buflist_new(), except BLN_DUMMY.
3283  *
3284  * used by qf_init(), main() and doarglist()
3285  */
3286     int
3287 buflist_add(char_u *fname, int flags)
3288 {
3289     buf_T	*buf;
3290 
3291     buf = buflist_new(fname, NULL, (linenr_T)0, flags);
3292     if (buf != NULL)
3293 	return buf->b_fnum;
3294     return 0;
3295 }
3296 
3297 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3298 /*
3299  * Adjust slashes in file names.  Called after 'shellslash' was set.
3300  */
3301     void
3302 buflist_slash_adjust(void)
3303 {
3304     buf_T	*bp;
3305 
3306     FOR_ALL_BUFFERS(bp)
3307     {
3308 	if (bp->b_ffname != NULL)
3309 	    slash_adjust(bp->b_ffname);
3310 	if (bp->b_sfname != NULL)
3311 	    slash_adjust(bp->b_sfname);
3312     }
3313 }
3314 #endif
3315 
3316 /*
3317  * Set alternate cursor position for the current buffer and window "win".
3318  * Also save the local window option values.
3319  */
3320     void
3321 buflist_altfpos(win_T *win)
3322 {
3323     buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE);
3324 }
3325 
3326 /*
3327  * Return TRUE if 'ffname' is not the same file as current file.
3328  * Fname must have a full path (expanded by mch_FullName()).
3329  */
3330     int
3331 otherfile(char_u *ffname)
3332 {
3333     return otherfile_buf(curbuf, ffname
3334 #ifdef UNIX
3335 	    , NULL
3336 #endif
3337 	    );
3338 }
3339 
3340     static int
3341 otherfile_buf(
3342     buf_T		*buf,
3343     char_u		*ffname
3344 #ifdef UNIX
3345     , stat_T		*stp
3346 #endif
3347     )
3348 {
3349     /* no name is different */
3350     if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
3351 	return TRUE;
3352     if (fnamecmp(ffname, buf->b_ffname) == 0)
3353 	return FALSE;
3354 #ifdef UNIX
3355     {
3356 	stat_T	    st;
3357 
3358 	/* If no stat_T given, get it now */
3359 	if (stp == NULL)
3360 	{
3361 	    if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0)
3362 		st.st_dev = (dev_T)-1;
3363 	    stp = &st;
3364 	}
3365 	/* Use dev/ino to check if the files are the same, even when the names
3366 	 * are different (possible with links).  Still need to compare the
3367 	 * name above, for when the file doesn't exist yet.
3368 	 * Problem: The dev/ino changes when a file is deleted (and created
3369 	 * again) and remains the same when renamed/moved.  We don't want to
3370 	 * mch_stat() each buffer each time, that would be too slow.  Get the
3371 	 * dev/ino again when they appear to match, but not when they appear
3372 	 * to be different: Could skip a buffer when it's actually the same
3373 	 * file. */
3374 	if (buf_same_ino(buf, stp))
3375 	{
3376 	    buf_setino(buf);
3377 	    if (buf_same_ino(buf, stp))
3378 		return FALSE;
3379 	}
3380     }
3381 #endif
3382     return TRUE;
3383 }
3384 
3385 #if defined(UNIX) || defined(PROTO)
3386 /*
3387  * Set inode and device number for a buffer.
3388  * Must always be called when b_fname is changed!.
3389  */
3390     void
3391 buf_setino(buf_T *buf)
3392 {
3393     stat_T	st;
3394 
3395     if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
3396     {
3397 	buf->b_dev_valid = TRUE;
3398 	buf->b_dev = st.st_dev;
3399 	buf->b_ino = st.st_ino;
3400     }
3401     else
3402 	buf->b_dev_valid = FALSE;
3403 }
3404 
3405 /*
3406  * Return TRUE if dev/ino in buffer "buf" matches with "stp".
3407  */
3408     static int
3409 buf_same_ino(
3410     buf_T	*buf,
3411     stat_T	*stp)
3412 {
3413     return (buf->b_dev_valid
3414 	    && stp->st_dev == buf->b_dev
3415 	    && stp->st_ino == buf->b_ino);
3416 }
3417 #endif
3418 
3419 /*
3420  * Print info about the current buffer.
3421  */
3422     void
3423 fileinfo(
3424     int fullname,	    /* when non-zero print full path */
3425     int shorthelp,
3426     int	dont_truncate)
3427 {
3428     char_u	*name;
3429     int		n;
3430     char_u	*p;
3431     char_u	*buffer;
3432     size_t	len;
3433 
3434     buffer = alloc(IOSIZE);
3435     if (buffer == NULL)
3436 	return;
3437 
3438     if (fullname > 1)	    /* 2 CTRL-G: include buffer number */
3439     {
3440 	vim_snprintf((char *)buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
3441 	p = buffer + STRLEN(buffer);
3442     }
3443     else
3444 	p = buffer;
3445 
3446     *p++ = '"';
3447     if (buf_spname(curbuf) != NULL)
3448 	vim_strncpy(p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
3449     else
3450     {
3451 	if (!fullname && curbuf->b_fname != NULL)
3452 	    name = curbuf->b_fname;
3453 	else
3454 	    name = curbuf->b_ffname;
3455 	home_replace(shorthelp ? curbuf : NULL, name, p,
3456 					  (int)(IOSIZE - (p - buffer)), TRUE);
3457     }
3458 
3459     vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
3460 	    curbufIsChanged() ? (shortmess(SHM_MOD)
3461 					  ?  " [+]" : _(" [Modified]")) : " ",
3462 	    (curbuf->b_flags & BF_NOTEDITED)
3463 #ifdef FEAT_QUICKFIX
3464 		    && !bt_dontwrite(curbuf)
3465 #endif
3466 					? _("[Not edited]") : "",
3467 	    (curbuf->b_flags & BF_NEW)
3468 #ifdef FEAT_QUICKFIX
3469 		    && !bt_dontwrite(curbuf)
3470 #endif
3471 					? _("[New file]") : "",
3472 	    (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
3473 	    curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
3474 						      : _("[readonly]")) : "",
3475 	    (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
3476 							  || curbuf->b_p_ro) ?
3477 								    " " : "");
3478     /* With 32 bit longs and more than 21,474,836 lines multiplying by 100
3479      * causes an overflow, thus for large numbers divide instead. */
3480     if (curwin->w_cursor.lnum > 1000000L)
3481 	n = (int)(((long)curwin->w_cursor.lnum) /
3482 				   ((long)curbuf->b_ml.ml_line_count / 100L));
3483     else
3484 	n = (int)(((long)curwin->w_cursor.lnum * 100L) /
3485 					    (long)curbuf->b_ml.ml_line_count);
3486     if (curbuf->b_ml.ml_flags & ML_EMPTY)
3487     {
3488 	vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
3489     }
3490 #ifdef FEAT_CMDL_INFO
3491     else if (p_ru)
3492     {
3493 	/* Current line and column are already on the screen -- webb */
3494 	if (curbuf->b_ml.ml_line_count == 1)
3495 	    vim_snprintf_add((char *)buffer, IOSIZE, _("1 line --%d%%--"), n);
3496 	else
3497 	    vim_snprintf_add((char *)buffer, IOSIZE, _("%ld lines --%d%%--"),
3498 					 (long)curbuf->b_ml.ml_line_count, n);
3499     }
3500 #endif
3501     else
3502     {
3503 	vim_snprintf_add((char *)buffer, IOSIZE,
3504 		_("line %ld of %ld --%d%%-- col "),
3505 		(long)curwin->w_cursor.lnum,
3506 		(long)curbuf->b_ml.ml_line_count,
3507 		n);
3508 	validate_virtcol();
3509 	len = STRLEN(buffer);
3510 	col_print(buffer + len, IOSIZE - len,
3511 		   (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
3512     }
3513 
3514     (void)append_arg_number(curwin, buffer, IOSIZE, !shortmess(SHM_FILE));
3515 
3516     if (dont_truncate)
3517     {
3518 	/* Temporarily set msg_scroll to avoid the message being truncated.
3519 	 * First call msg_start() to get the message in the right place. */
3520 	msg_start();
3521 	n = msg_scroll;
3522 	msg_scroll = TRUE;
3523 	msg(buffer);
3524 	msg_scroll = n;
3525     }
3526     else
3527     {
3528 	p = msg_trunc_attr(buffer, FALSE, 0);
3529 	if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
3530 	    /* Need to repeat the message after redrawing when:
3531 	     * - When restart_edit is set (otherwise there will be a delay
3532 	     *   before redrawing).
3533 	     * - When the screen was scrolled but there is no wait-return
3534 	     *   prompt. */
3535 	    set_keep_msg(p, 0);
3536     }
3537 
3538     vim_free(buffer);
3539 }
3540 
3541     void
3542 col_print(
3543     char_u  *buf,
3544     size_t  buflen,
3545     int	    col,
3546     int	    vcol)
3547 {
3548     if (col == vcol)
3549 	vim_snprintf((char *)buf, buflen, "%d", col);
3550     else
3551 	vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol);
3552 }
3553 
3554 #if defined(FEAT_TITLE) || defined(PROTO)
3555 /*
3556  * put file name in title bar of window and in icon title
3557  */
3558 
3559 static char_u *lasttitle = NULL;
3560 static char_u *lasticon = NULL;
3561 
3562     void
3563 maketitle(void)
3564 {
3565     char_u	*p;
3566     char_u	*t_str = NULL;
3567     char_u	*i_name;
3568     char_u	*i_str = NULL;
3569     int		maxlen = 0;
3570     int		len;
3571     int		mustset;
3572     char_u	buf[IOSIZE];
3573     int		off;
3574 
3575     if (!redrawing())
3576     {
3577 	/* Postpone updating the title when 'lazyredraw' is set. */
3578 	need_maketitle = TRUE;
3579 	return;
3580     }
3581 
3582     need_maketitle = FALSE;
3583     if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL)
3584 	return;
3585 
3586     if (p_title)
3587     {
3588 	if (p_titlelen > 0)
3589 	{
3590 	    maxlen = p_titlelen * Columns / 100;
3591 	    if (maxlen < 10)
3592 		maxlen = 10;
3593 	}
3594 
3595 	t_str = buf;
3596 	if (*p_titlestring != NUL)
3597 	{
3598 #ifdef FEAT_STL_OPT
3599 	    if (stl_syntax & STL_IN_TITLE)
3600 	    {
3601 		int	use_sandbox = FALSE;
3602 		int	save_called_emsg = called_emsg;
3603 
3604 # ifdef FEAT_EVAL
3605 		use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
3606 # endif
3607 		called_emsg = FALSE;
3608 		build_stl_str_hl(curwin, t_str, sizeof(buf),
3609 					      p_titlestring, use_sandbox,
3610 					      0, maxlen, NULL, NULL);
3611 		if (called_emsg)
3612 		    set_string_option_direct((char_u *)"titlestring", -1,
3613 					   (char_u *)"", OPT_FREE, SID_ERROR);
3614 		called_emsg |= save_called_emsg;
3615 	    }
3616 	    else
3617 #endif
3618 		t_str = p_titlestring;
3619 	}
3620 	else
3621 	{
3622 	    /* format: "fname + (path) (1 of 2) - VIM" */
3623 
3624 #define SPACE_FOR_FNAME (IOSIZE - 100)
3625 #define SPACE_FOR_DIR   (IOSIZE - 20)
3626 #define SPACE_FOR_ARGNR (IOSIZE - 10)  /* at least room for " - VIM" */
3627 	    if (curbuf->b_fname == NULL)
3628 		vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
3629 #ifdef FEAT_TERMINAL
3630 	    else if (curbuf->b_term != NULL)
3631 	    {
3632 		vim_strncpy(buf, term_get_status_text(curbuf->b_term),
3633 							      SPACE_FOR_FNAME);
3634 	    }
3635 #endif
3636 	    else
3637 	    {
3638 		p = transstr(gettail(curbuf->b_fname));
3639 		vim_strncpy(buf, p, SPACE_FOR_FNAME);
3640 		vim_free(p);
3641 	    }
3642 
3643 #ifdef FEAT_TERMINAL
3644 	    if (curbuf->b_term == NULL)
3645 #endif
3646 		switch (bufIsChanged(curbuf)
3647 			+ (curbuf->b_p_ro * 2)
3648 			+ (!curbuf->b_p_ma * 4))
3649 		{
3650 		    case 1: STRCAT(buf, " +"); break;
3651 		    case 2: STRCAT(buf, " ="); break;
3652 		    case 3: STRCAT(buf, " =+"); break;
3653 		    case 4:
3654 		    case 6: STRCAT(buf, " -"); break;
3655 		    case 5:
3656 		    case 7: STRCAT(buf, " -+"); break;
3657 		}
3658 
3659 	    if (curbuf->b_fname != NULL
3660 #ifdef FEAT_TERMINAL
3661 		    && curbuf->b_term == NULL
3662 #endif
3663 		    )
3664 	    {
3665 		/* Get path of file, replace home dir with ~ */
3666 		off = (int)STRLEN(buf);
3667 		buf[off++] = ' ';
3668 		buf[off++] = '(';
3669 		home_replace(curbuf, curbuf->b_ffname,
3670 					buf + off, SPACE_FOR_DIR - off, TRUE);
3671 #ifdef BACKSLASH_IN_FILENAME
3672 		/* avoid "c:/name" to be reduced to "c" */
3673 		if (isalpha(buf[off]) && buf[off + 1] == ':')
3674 		    off += 2;
3675 #endif
3676 		/* remove the file name */
3677 		p = gettail_sep(buf + off);
3678 		if (p == buf + off)
3679 		{
3680 		    /* must be a help buffer */
3681 		    vim_strncpy(buf + off, (char_u *)_("help"),
3682 					   (size_t)(SPACE_FOR_DIR - off - 1));
3683 		}
3684 		else
3685 		    *p = NUL;
3686 
3687 		/* Translate unprintable chars and concatenate.  Keep some
3688 		 * room for the server name.  When there is no room (very long
3689 		 * file name) use (...). */
3690 		if (off < SPACE_FOR_DIR)
3691 		{
3692 		    p = transstr(buf + off);
3693 		    vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));
3694 		    vim_free(p);
3695 		}
3696 		else
3697 		{
3698 		    vim_strncpy(buf + off, (char_u *)"...",
3699 					     (size_t)(SPACE_FOR_ARGNR - off));
3700 		}
3701 		STRCAT(buf, ")");
3702 	    }
3703 
3704 	    append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
3705 
3706 #if defined(FEAT_CLIENTSERVER)
3707 	    if (serverName != NULL)
3708 	    {
3709 		STRCAT(buf, " - ");
3710 		vim_strcat(buf, serverName, IOSIZE);
3711 	    }
3712 	    else
3713 #endif
3714 		STRCAT(buf, " - VIM");
3715 
3716 	    if (maxlen > 0)
3717 	    {
3718 		/* make it shorter by removing a bit in the middle */
3719 		if (vim_strsize(buf) > maxlen)
3720 		    trunc_string(buf, buf, maxlen, IOSIZE);
3721 	    }
3722 	}
3723     }
3724     mustset = ti_change(t_str, &lasttitle);
3725 
3726     if (p_icon)
3727     {
3728 	i_str = buf;
3729 	if (*p_iconstring != NUL)
3730 	{
3731 #ifdef FEAT_STL_OPT
3732 	    if (stl_syntax & STL_IN_ICON)
3733 	    {
3734 		int	use_sandbox = FALSE;
3735 		int	save_called_emsg = called_emsg;
3736 
3737 # ifdef FEAT_EVAL
3738 		use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
3739 # endif
3740 		called_emsg = FALSE;
3741 		build_stl_str_hl(curwin, i_str, sizeof(buf),
3742 						    p_iconstring, use_sandbox,
3743 						    0, 0, NULL, NULL);
3744 		if (called_emsg)
3745 		    set_string_option_direct((char_u *)"iconstring", -1,
3746 					   (char_u *)"", OPT_FREE, SID_ERROR);
3747 		called_emsg |= save_called_emsg;
3748 	    }
3749 	    else
3750 #endif
3751 		i_str = p_iconstring;
3752 	}
3753 	else
3754 	{
3755 	    if (buf_spname(curbuf) != NULL)
3756 		i_name = buf_spname(curbuf);
3757 	    else		    /* use file name only in icon */
3758 		i_name = gettail(curbuf->b_ffname);
3759 	    *i_str = NUL;
3760 	    /* Truncate name at 100 bytes. */
3761 	    len = (int)STRLEN(i_name);
3762 	    if (len > 100)
3763 	    {
3764 		len -= 100;
3765 #ifdef FEAT_MBYTE
3766 		if (has_mbyte)
3767 		    len += (*mb_tail_off)(i_name, i_name + len) + 1;
3768 #endif
3769 		i_name += len;
3770 	    }
3771 	    STRCPY(i_str, i_name);
3772 	    trans_characters(i_str, IOSIZE);
3773 	}
3774     }
3775 
3776     mustset |= ti_change(i_str, &lasticon);
3777 
3778     if (mustset)
3779 	resettitle();
3780 }
3781 
3782 /*
3783  * Used for title and icon: Check if "str" differs from "*last".  Set "*last"
3784  * from "str" if it does.
3785  * Return TRUE when "*last" changed.
3786  */
3787     static int
3788 ti_change(char_u *str, char_u **last)
3789 {
3790     if ((str == NULL) != (*last == NULL)
3791 	    || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
3792     {
3793 	vim_free(*last);
3794 	if (str == NULL)
3795 	    *last = NULL;
3796 	else
3797 	    *last = vim_strsave(str);
3798 	return TRUE;
3799     }
3800     return FALSE;
3801 }
3802 
3803 /*
3804  * Put current window title back (used after calling a shell)
3805  */
3806     void
3807 resettitle(void)
3808 {
3809     mch_settitle(lasttitle, lasticon);
3810 }
3811 
3812 # if defined(EXITFREE) || defined(PROTO)
3813     void
3814 free_titles(void)
3815 {
3816     vim_free(lasttitle);
3817     vim_free(lasticon);
3818 }
3819 # endif
3820 
3821 #endif /* FEAT_TITLE */
3822 
3823 #if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO)
3824 /*
3825  * Build a string from the status line items in "fmt".
3826  * Return length of string in screen cells.
3827  *
3828  * Normally works for window "wp", except when working for 'tabline' then it
3829  * is "curwin".
3830  *
3831  * Items are drawn interspersed with the text that surrounds it
3832  * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
3833  * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
3834  *
3835  * If maxwidth is not zero, the string will be filled at any middle marker
3836  * or truncated if too long, fillchar is used for all whitespace.
3837  */
3838     int
3839 build_stl_str_hl(
3840     win_T	*wp,
3841     char_u	*out,		/* buffer to write into != NameBuff */
3842     size_t	outlen,		/* length of out[] */
3843     char_u	*fmt,
3844     int		use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */
3845     int		fillchar,
3846     int		maxwidth,
3847     struct stl_hlrec *hltab,	/* return: HL attributes (can be NULL) */
3848     struct stl_hlrec *tabtab)	/* return: tab page nrs (can be NULL) */
3849 {
3850     char_u	*p;
3851     char_u	*s;
3852     char_u	*t;
3853     int		byteval;
3854 #ifdef FEAT_EVAL
3855     win_T	*o_curwin;
3856     buf_T	*o_curbuf;
3857 #endif
3858     int		empty_line;
3859     colnr_T	virtcol;
3860     long	l;
3861     long	n;
3862     int		prevchar_isflag;
3863     int		prevchar_isitem;
3864     int		itemisflag;
3865     int		fillable;
3866     char_u	*str;
3867     long	num;
3868     int		width;
3869     int		itemcnt;
3870     int		curitem;
3871     int		groupitem[STL_MAX_ITEM];
3872     int		groupdepth;
3873     struct stl_item
3874     {
3875 	char_u		*start;
3876 	int		minwid;
3877 	int		maxwid;
3878 	enum
3879 	{
3880 	    Normal,
3881 	    Empty,
3882 	    Group,
3883 	    Middle,
3884 	    Highlight,
3885 	    TabPage,
3886 	    Trunc
3887 	}		type;
3888     }		item[STL_MAX_ITEM];
3889     int		minwid;
3890     int		maxwid;
3891     int		zeropad;
3892     char_u	base;
3893     char_u	opt;
3894 #define TMPLEN 70
3895     char_u	tmp[TMPLEN];
3896     char_u	*usefmt = fmt;
3897     struct stl_hlrec *sp;
3898 
3899 #ifdef FEAT_EVAL
3900     /*
3901      * When the format starts with "%!" then evaluate it as an expression and
3902      * use the result as the actual format string.
3903      */
3904     if (fmt[0] == '%' && fmt[1] == '!')
3905     {
3906 	usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
3907 	if (usefmt == NULL)
3908 	    usefmt = fmt;
3909     }
3910 #endif
3911 
3912     if (fillchar == 0)
3913 	fillchar = ' ';
3914 #ifdef FEAT_MBYTE
3915     /* Can't handle a multi-byte fill character yet. */
3916     else if (mb_char2len(fillchar) > 1)
3917 	fillchar = '-';
3918 #endif
3919 
3920     /* Get line & check if empty (cursorpos will show "0-1").  Note that
3921      * p will become invalid when getting another buffer line. */
3922     p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
3923     empty_line = (*p == NUL);
3924 
3925     /* Get the byte value now, in case we need it below. This is more
3926      * efficient than making a copy of the line. */
3927     if (wp->w_cursor.col > (colnr_T)STRLEN(p))
3928 	byteval = 0;
3929     else
3930 #ifdef FEAT_MBYTE
3931 	byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
3932 #else
3933 	byteval = p[wp->w_cursor.col];
3934 #endif
3935 
3936     groupdepth = 0;
3937     p = out;
3938     curitem = 0;
3939     prevchar_isflag = TRUE;
3940     prevchar_isitem = FALSE;
3941     for (s = usefmt; *s; )
3942     {
3943 	if (curitem == STL_MAX_ITEM)
3944 	{
3945 	    /* There are too many items.  Add the error code to the statusline
3946 	     * to give the user a hint about what went wrong. */
3947 	    if (p + 6 < out + outlen)
3948 	    {
3949 		mch_memmove(p, " E541", (size_t)5);
3950 		p += 5;
3951 	    }
3952 	    break;
3953 	}
3954 
3955 	if (*s != NUL && *s != '%')
3956 	    prevchar_isflag = prevchar_isitem = FALSE;
3957 
3958 	/*
3959 	 * Handle up to the next '%' or the end.
3960 	 */
3961 	while (*s != NUL && *s != '%' && p + 1 < out + outlen)
3962 	    *p++ = *s++;
3963 	if (*s == NUL || p + 1 >= out + outlen)
3964 	    break;
3965 
3966 	/*
3967 	 * Handle one '%' item.
3968 	 */
3969 	s++;
3970 	if (*s == NUL)  /* ignore trailing % */
3971 	    break;
3972 	if (*s == '%')
3973 	{
3974 	    if (p + 1 >= out + outlen)
3975 		break;
3976 	    *p++ = *s++;
3977 	    prevchar_isflag = prevchar_isitem = FALSE;
3978 	    continue;
3979 	}
3980 	if (*s == STL_MIDDLEMARK)
3981 	{
3982 	    s++;
3983 	    if (groupdepth > 0)
3984 		continue;
3985 	    item[curitem].type = Middle;
3986 	    item[curitem++].start = p;
3987 	    continue;
3988 	}
3989 	if (*s == STL_TRUNCMARK)
3990 	{
3991 	    s++;
3992 	    item[curitem].type = Trunc;
3993 	    item[curitem++].start = p;
3994 	    continue;
3995 	}
3996 	if (*s == ')')
3997 	{
3998 	    s++;
3999 	    if (groupdepth < 1)
4000 		continue;
4001 	    groupdepth--;
4002 
4003 	    t = item[groupitem[groupdepth]].start;
4004 	    *p = NUL;
4005 	    l = vim_strsize(t);
4006 	    if (curitem > groupitem[groupdepth] + 1
4007 		    && item[groupitem[groupdepth]].minwid == 0)
4008 	    {
4009 		/* remove group if all items are empty */
4010 		for (n = groupitem[groupdepth] + 1; n < curitem; n++)
4011 		    if (item[n].type == Normal || item[n].type == Highlight)
4012 			break;
4013 		if (n == curitem)
4014 		{
4015 		    p = t;
4016 		    l = 0;
4017 		}
4018 	    }
4019 	    if (l > item[groupitem[groupdepth]].maxwid)
4020 	    {
4021 		/* truncate, remove n bytes of text at the start */
4022 #ifdef FEAT_MBYTE
4023 		if (has_mbyte)
4024 		{
4025 		    /* Find the first character that should be included. */
4026 		    n = 0;
4027 		    while (l >= item[groupitem[groupdepth]].maxwid)
4028 		    {
4029 			l -= ptr2cells(t + n);
4030 			n += (*mb_ptr2len)(t + n);
4031 		    }
4032 		}
4033 		else
4034 #endif
4035 		    n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1;
4036 
4037 		*t = '<';
4038 		mch_memmove(t + 1, t + n, (size_t)(p - (t + n)));
4039 		p = p - n + 1;
4040 #ifdef FEAT_MBYTE
4041 		/* Fill up space left over by half a double-wide char. */
4042 		while (++l < item[groupitem[groupdepth]].minwid)
4043 		    *p++ = fillchar;
4044 #endif
4045 
4046 		/* correct the start of the items for the truncation */
4047 		for (l = groupitem[groupdepth] + 1; l < curitem; l++)
4048 		{
4049 		    item[l].start -= n;
4050 		    if (item[l].start < t)
4051 			item[l].start = t;
4052 		}
4053 	    }
4054 	    else if (abs(item[groupitem[groupdepth]].minwid) > l)
4055 	    {
4056 		/* fill */
4057 		n = item[groupitem[groupdepth]].minwid;
4058 		if (n < 0)
4059 		{
4060 		    /* fill by appending characters */
4061 		    n = 0 - n;
4062 		    while (l++ < n && p + 1 < out + outlen)
4063 			*p++ = fillchar;
4064 		}
4065 		else
4066 		{
4067 		    /* fill by inserting characters */
4068 		    mch_memmove(t + n - l, t, (size_t)(p - t));
4069 		    l = n - l;
4070 		    if (p + l >= out + outlen)
4071 			l = (long)((out + outlen) - p - 1);
4072 		    p += l;
4073 		    for (n = groupitem[groupdepth] + 1; n < curitem; n++)
4074 			item[n].start += l;
4075 		    for ( ; l > 0; l--)
4076 			*t++ = fillchar;
4077 		}
4078 	    }
4079 	    continue;
4080 	}
4081 	minwid = 0;
4082 	maxwid = 9999;
4083 	zeropad = FALSE;
4084 	l = 1;
4085 	if (*s == '0')
4086 	{
4087 	    s++;
4088 	    zeropad = TRUE;
4089 	}
4090 	if (*s == '-')
4091 	{
4092 	    s++;
4093 	    l = -1;
4094 	}
4095 	if (VIM_ISDIGIT(*s))
4096 	{
4097 	    minwid = (int)getdigits(&s);
4098 	    if (minwid < 0)	/* overflow */
4099 		minwid = 0;
4100 	}
4101 	if (*s == STL_USER_HL)
4102 	{
4103 	    item[curitem].type = Highlight;
4104 	    item[curitem].start = p;
4105 	    item[curitem].minwid = minwid > 9 ? 1 : minwid;
4106 	    s++;
4107 	    curitem++;
4108 	    continue;
4109 	}
4110 	if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR)
4111 	{
4112 	    if (*s == STL_TABCLOSENR)
4113 	    {
4114 		if (minwid == 0)
4115 		{
4116 		    /* %X ends the close label, go back to the previously
4117 		     * define tab label nr. */
4118 		    for (n = curitem - 1; n >= 0; --n)
4119 			if (item[n].type == TabPage && item[n].minwid >= 0)
4120 			{
4121 			    minwid = item[n].minwid;
4122 			    break;
4123 			}
4124 		}
4125 		else
4126 		    /* close nrs are stored as negative values */
4127 		    minwid = - minwid;
4128 	    }
4129 	    item[curitem].type = TabPage;
4130 	    item[curitem].start = p;
4131 	    item[curitem].minwid = minwid;
4132 	    s++;
4133 	    curitem++;
4134 	    continue;
4135 	}
4136 	if (*s == '.')
4137 	{
4138 	    s++;
4139 	    if (VIM_ISDIGIT(*s))
4140 	    {
4141 		maxwid = (int)getdigits(&s);
4142 		if (maxwid <= 0)	/* overflow */
4143 		    maxwid = 50;
4144 	    }
4145 	}
4146 	minwid = (minwid > 50 ? 50 : minwid) * l;
4147 	if (*s == '(')
4148 	{
4149 	    groupitem[groupdepth++] = curitem;
4150 	    item[curitem].type = Group;
4151 	    item[curitem].start = p;
4152 	    item[curitem].minwid = minwid;
4153 	    item[curitem].maxwid = maxwid;
4154 	    s++;
4155 	    curitem++;
4156 	    continue;
4157 	}
4158 	if (vim_strchr(STL_ALL, *s) == NULL)
4159 	{
4160 	    s++;
4161 	    continue;
4162 	}
4163 	opt = *s++;
4164 
4165 	/* OK - now for the real work */
4166 	base = 'D';
4167 	itemisflag = FALSE;
4168 	fillable = TRUE;
4169 	num = -1;
4170 	str = NULL;
4171 	switch (opt)
4172 	{
4173 	case STL_FILEPATH:
4174 	case STL_FULLPATH:
4175 	case STL_FILENAME:
4176 	    fillable = FALSE;	/* don't change ' ' to fillchar */
4177 	    if (buf_spname(wp->w_buffer) != NULL)
4178 		vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);
4179 	    else
4180 	    {
4181 		t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
4182 					  : wp->w_buffer->b_fname;
4183 		home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
4184 	    }
4185 	    trans_characters(NameBuff, MAXPATHL);
4186 	    if (opt != STL_FILENAME)
4187 		str = NameBuff;
4188 	    else
4189 		str = gettail(NameBuff);
4190 	    break;
4191 
4192 	case STL_VIM_EXPR: /* '{' */
4193 	    itemisflag = TRUE;
4194 	    t = p;
4195 	    while (*s != '}' && *s != NUL && p + 1 < out + outlen)
4196 		*p++ = *s++;
4197 	    if (*s != '}')	/* missing '}' or out of space */
4198 		break;
4199 	    s++;
4200 	    *p = 0;
4201 	    p = t;
4202 
4203 #ifdef FEAT_EVAL
4204 	    vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
4205 	    set_internal_string_var((char_u *)"actual_curbuf", tmp);
4206 
4207 	    o_curbuf = curbuf;
4208 	    o_curwin = curwin;
4209 	    curwin = wp;
4210 	    curbuf = wp->w_buffer;
4211 
4212 	    str = eval_to_string_safe(p, &t, use_sandbox);
4213 
4214 	    curwin = o_curwin;
4215 	    curbuf = o_curbuf;
4216 	    do_unlet((char_u *)"g:actual_curbuf", TRUE);
4217 
4218 	    if (str != NULL && *str != 0)
4219 	    {
4220 		if (*skipdigits(str) == NUL)
4221 		{
4222 		    num = atoi((char *)str);
4223 		    vim_free(str);
4224 		    str = NULL;
4225 		    itemisflag = FALSE;
4226 		}
4227 	    }
4228 #endif
4229 	    break;
4230 
4231 	case STL_LINE:
4232 	    num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
4233 		  ? 0L : (long)(wp->w_cursor.lnum);
4234 	    break;
4235 
4236 	case STL_NUMLINES:
4237 	    num = wp->w_buffer->b_ml.ml_line_count;
4238 	    break;
4239 
4240 	case STL_COLUMN:
4241 	    num = !(State & INSERT) && empty_line
4242 		  ? 0 : (int)wp->w_cursor.col + 1;
4243 	    break;
4244 
4245 	case STL_VIRTCOL:
4246 	case STL_VIRTCOL_ALT:
4247 	    /* In list mode virtcol needs to be recomputed */
4248 	    virtcol = wp->w_virtcol;
4249 	    if (wp->w_p_list && lcs_tab1 == NUL)
4250 	    {
4251 		wp->w_p_list = FALSE;
4252 		getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
4253 		wp->w_p_list = TRUE;
4254 	    }
4255 	    ++virtcol;
4256 	    /* Don't display %V if it's the same as %c. */
4257 	    if (opt == STL_VIRTCOL_ALT
4258 		    && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
4259 			    ? 0 : (int)wp->w_cursor.col + 1)))
4260 		break;
4261 	    num = (long)virtcol;
4262 	    break;
4263 
4264 	case STL_PERCENTAGE:
4265 	    num = (int)(((long)wp->w_cursor.lnum * 100L) /
4266 			(long)wp->w_buffer->b_ml.ml_line_count);
4267 	    break;
4268 
4269 	case STL_ALTPERCENT:
4270 	    str = tmp;
4271 	    get_rel_pos(wp, str, TMPLEN);
4272 	    break;
4273 
4274 	case STL_ARGLISTSTAT:
4275 	    fillable = FALSE;
4276 	    tmp[0] = 0;
4277 	    if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
4278 		str = tmp;
4279 	    break;
4280 
4281 	case STL_KEYMAP:
4282 	    fillable = FALSE;
4283 	    if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN))
4284 		str = tmp;
4285 	    break;
4286 	case STL_PAGENUM:
4287 #if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
4288 	    num = printer_page_num;
4289 #else
4290 	    num = 0;
4291 #endif
4292 	    break;
4293 
4294 	case STL_BUFNO:
4295 	    num = wp->w_buffer->b_fnum;
4296 	    break;
4297 
4298 	case STL_OFFSET_X:
4299 	    base = 'X';
4300 	case STL_OFFSET:
4301 #ifdef FEAT_BYTEOFF
4302 	    l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
4303 	    num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
4304 		  0L : l + 1 + (!(State & INSERT) && empty_line ?
4305 				0 : (int)wp->w_cursor.col);
4306 #endif
4307 	    break;
4308 
4309 	case STL_BYTEVAL_X:
4310 	    base = 'X';
4311 	case STL_BYTEVAL:
4312 	    num = byteval;
4313 	    if (num == NL)
4314 		num = 0;
4315 	    else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC)
4316 		num = NL;
4317 	    break;
4318 
4319 	case STL_ROFLAG:
4320 	case STL_ROFLAG_ALT:
4321 	    itemisflag = TRUE;
4322 	    if (wp->w_buffer->b_p_ro)
4323 		str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"));
4324 	    break;
4325 
4326 	case STL_HELPFLAG:
4327 	case STL_HELPFLAG_ALT:
4328 	    itemisflag = TRUE;
4329 	    if (wp->w_buffer->b_help)
4330 		str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
4331 							       : _("[Help]"));
4332 	    break;
4333 
4334 #ifdef FEAT_AUTOCMD
4335 	case STL_FILETYPE:
4336 	    if (*wp->w_buffer->b_p_ft != NUL
4337 		    && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
4338 	    {
4339 		vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
4340 							wp->w_buffer->b_p_ft);
4341 		str = tmp;
4342 	    }
4343 	    break;
4344 
4345 	case STL_FILETYPE_ALT:
4346 	    itemisflag = TRUE;
4347 	    if (*wp->w_buffer->b_p_ft != NUL
4348 		    && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
4349 	    {
4350 		vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
4351 							wp->w_buffer->b_p_ft);
4352 		for (t = tmp; *t != 0; t++)
4353 		    *t = TOUPPER_LOC(*t);
4354 		str = tmp;
4355 	    }
4356 	    break;
4357 #endif
4358 
4359 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
4360 	case STL_PREVIEWFLAG:
4361 	case STL_PREVIEWFLAG_ALT:
4362 	    itemisflag = TRUE;
4363 	    if (wp->w_p_pvw)
4364 		str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
4365 							    : _("[Preview]"));
4366 	    break;
4367 
4368 	case STL_QUICKFIX:
4369 	    if (bt_quickfix(wp->w_buffer))
4370 		str = (char_u *)(wp->w_llist_ref
4371 			    ? _(msg_loclist)
4372 			    : _(msg_qflist));
4373 	    break;
4374 #endif
4375 
4376 	case STL_MODIFIED:
4377 	case STL_MODIFIED_ALT:
4378 	    itemisflag = TRUE;
4379 	    switch ((opt == STL_MODIFIED_ALT)
4380 		    + bufIsChanged(wp->w_buffer) * 2
4381 		    + (!wp->w_buffer->b_p_ma) * 4)
4382 	    {
4383 		case 2: str = (char_u *)"[+]"; break;
4384 		case 3: str = (char_u *)",+"; break;
4385 		case 4: str = (char_u *)"[-]"; break;
4386 		case 5: str = (char_u *)",-"; break;
4387 		case 6: str = (char_u *)"[+-]"; break;
4388 		case 7: str = (char_u *)",+-"; break;
4389 	    }
4390 	    break;
4391 
4392 	case STL_HIGHLIGHT:
4393 	    t = s;
4394 	    while (*s != '#' && *s != NUL)
4395 		++s;
4396 	    if (*s == '#')
4397 	    {
4398 		item[curitem].type = Highlight;
4399 		item[curitem].start = p;
4400 		item[curitem].minwid = -syn_namen2id(t, (int)(s - t));
4401 		curitem++;
4402 	    }
4403 	    if (*s != NUL)
4404 		++s;
4405 	    continue;
4406 	}
4407 
4408 	item[curitem].start = p;
4409 	item[curitem].type = Normal;
4410 	if (str != NULL && *str)
4411 	{
4412 	    t = str;
4413 	    if (itemisflag)
4414 	    {
4415 		if ((t[0] && t[1])
4416 			&& ((!prevchar_isitem && *t == ',')
4417 			      || (prevchar_isflag && *t == ' ')))
4418 		    t++;
4419 		prevchar_isflag = TRUE;
4420 	    }
4421 	    l = vim_strsize(t);
4422 	    if (l > 0)
4423 		prevchar_isitem = TRUE;
4424 	    if (l > maxwid)
4425 	    {
4426 		while (l >= maxwid)
4427 #ifdef FEAT_MBYTE
4428 		    if (has_mbyte)
4429 		    {
4430 			l -= ptr2cells(t);
4431 			t += (*mb_ptr2len)(t);
4432 		    }
4433 		    else
4434 #endif
4435 			l -= byte2cells(*t++);
4436 		if (p + 1 >= out + outlen)
4437 		    break;
4438 		*p++ = '<';
4439 	    }
4440 	    if (minwid > 0)
4441 	    {
4442 		for (; l < minwid && p + 1 < out + outlen; l++)
4443 		{
4444 		    /* Don't put a "-" in front of a digit. */
4445 		    if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t))
4446 			*p++ = ' ';
4447 		    else
4448 			*p++ = fillchar;
4449 		}
4450 		minwid = 0;
4451 	    }
4452 	    else
4453 		minwid *= -1;
4454 	    while (*t && p + 1 < out + outlen)
4455 	    {
4456 		*p++ = *t++;
4457 		/* Change a space by fillchar, unless fillchar is '-' and a
4458 		 * digit follows. */
4459 		if (fillable && p[-1] == ' '
4460 				     && (!VIM_ISDIGIT(*t) || fillchar != '-'))
4461 		    p[-1] = fillchar;
4462 	    }
4463 	    for (; l < minwid && p + 1 < out + outlen; l++)
4464 		*p++ = fillchar;
4465 	}
4466 	else if (num >= 0)
4467 	{
4468 	    int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
4469 	    char_u nstr[20];
4470 
4471 	    if (p + 20 >= out + outlen)
4472 		break;		/* not sufficient space */
4473 	    prevchar_isitem = TRUE;
4474 	    t = nstr;
4475 	    if (opt == STL_VIRTCOL_ALT)
4476 	    {
4477 		*t++ = '-';
4478 		minwid--;
4479 	    }
4480 	    *t++ = '%';
4481 	    if (zeropad)
4482 		*t++ = '0';
4483 	    *t++ = '*';
4484 	    *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd');
4485 	    *t = 0;
4486 
4487 	    for (n = num, l = 1; n >= nbase; n /= nbase)
4488 		l++;
4489 	    if (opt == STL_VIRTCOL_ALT)
4490 		l++;
4491 	    if (l > maxwid)
4492 	    {
4493 		l += 2;
4494 		n = l - maxwid;
4495 		while (l-- > maxwid)
4496 		    num /= nbase;
4497 		*t++ = '>';
4498 		*t++ = '%';
4499 		*t = t[-3];
4500 		*++t = 0;
4501 		vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4502 								   0, num, n);
4503 	    }
4504 	    else
4505 		vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4506 								 minwid, num);
4507 	    p += STRLEN(p);
4508 	}
4509 	else
4510 	    item[curitem].type = Empty;
4511 
4512 	if (opt == STL_VIM_EXPR)
4513 	    vim_free(str);
4514 
4515 	if (num >= 0 || (!itemisflag && str && *str))
4516 	    prevchar_isflag = FALSE;	    /* Item not NULL, but not a flag */
4517 	curitem++;
4518     }
4519     *p = NUL;
4520     itemcnt = curitem;
4521 
4522 #ifdef FEAT_EVAL
4523     if (usefmt != fmt)
4524 	vim_free(usefmt);
4525 #endif
4526 
4527     width = vim_strsize(out);
4528     if (maxwidth > 0 && width > maxwidth)
4529     {
4530 	/* Result is too long, must truncate somewhere. */
4531 	l = 0;
4532 	if (itemcnt == 0)
4533 	    s = out;
4534 	else
4535 	{
4536 	    for ( ; l < itemcnt; l++)
4537 		if (item[l].type == Trunc)
4538 		{
4539 		    /* Truncate at %< item. */
4540 		    s = item[l].start;
4541 		    break;
4542 		}
4543 	    if (l == itemcnt)
4544 	    {
4545 		/* No %< item, truncate first item. */
4546 		s = item[0].start;
4547 		l = 0;
4548 	    }
4549 	}
4550 
4551 	if (width - vim_strsize(s) >= maxwidth)
4552 	{
4553 	    /* Truncation mark is beyond max length */
4554 #ifdef FEAT_MBYTE
4555 	    if (has_mbyte)
4556 	    {
4557 		s = out;
4558 		width = 0;
4559 		for (;;)
4560 		{
4561 		    width += ptr2cells(s);
4562 		    if (width >= maxwidth)
4563 			break;
4564 		    s += (*mb_ptr2len)(s);
4565 		}
4566 		/* Fill up for half a double-wide character. */
4567 		while (++width < maxwidth)
4568 		    *s++ = fillchar;
4569 	    }
4570 	    else
4571 #endif
4572 		s = out + maxwidth - 1;
4573 	    for (l = 0; l < itemcnt; l++)
4574 		if (item[l].start > s)
4575 		    break;
4576 	    itemcnt = l;
4577 	    *s++ = '>';
4578 	    *s = 0;
4579 	}
4580 	else
4581 	{
4582 #ifdef FEAT_MBYTE
4583 	    if (has_mbyte)
4584 	    {
4585 		n = 0;
4586 		while (width >= maxwidth)
4587 		{
4588 		    width -= ptr2cells(s + n);
4589 		    n += (*mb_ptr2len)(s + n);
4590 		}
4591 	    }
4592 	    else
4593 #endif
4594 		n = width - maxwidth + 1;
4595 	    p = s + n;
4596 	    STRMOVE(s + 1, p);
4597 	    *s = '<';
4598 
4599 	    /* Fill up for half a double-wide character. */
4600 	    while (++width < maxwidth)
4601 	    {
4602 		s = s + STRLEN(s);
4603 		*s++ = fillchar;
4604 		*s = NUL;
4605 	    }
4606 
4607 	    --n;	/* count the '<' */
4608 	    for (; l < itemcnt; l++)
4609 	    {
4610 		if (item[l].start - n >= s)
4611 		    item[l].start -= n;
4612 		else
4613 		    item[l].start = s;
4614 	    }
4615 	}
4616 	width = maxwidth;
4617     }
4618     else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
4619     {
4620 	/* Apply STL_MIDDLE if any */
4621 	for (l = 0; l < itemcnt; l++)
4622 	    if (item[l].type == Middle)
4623 		break;
4624 	if (l < itemcnt)
4625 	{
4626 	    p = item[l].start + maxwidth - width;
4627 	    STRMOVE(p, item[l].start);
4628 	    for (s = item[l].start; s < p; s++)
4629 		*s = fillchar;
4630 	    for (l++; l < itemcnt; l++)
4631 		item[l].start += maxwidth - width;
4632 	    width = maxwidth;
4633 	}
4634     }
4635 
4636     /* Store the info about highlighting. */
4637     if (hltab != NULL)
4638     {
4639 	sp = hltab;
4640 	for (l = 0; l < itemcnt; l++)
4641 	{
4642 	    if (item[l].type == Highlight)
4643 	    {
4644 		sp->start = item[l].start;
4645 		sp->userhl = item[l].minwid;
4646 		sp++;
4647 	    }
4648 	}
4649 	sp->start = NULL;
4650 	sp->userhl = 0;
4651     }
4652 
4653     /* Store the info about tab pages labels. */
4654     if (tabtab != NULL)
4655     {
4656 	sp = tabtab;
4657 	for (l = 0; l < itemcnt; l++)
4658 	{
4659 	    if (item[l].type == TabPage)
4660 	    {
4661 		sp->start = item[l].start;
4662 		sp->userhl = item[l].minwid;
4663 		sp++;
4664 	    }
4665 	}
4666 	sp->start = NULL;
4667 	sp->userhl = 0;
4668     }
4669 
4670     return width;
4671 }
4672 #endif /* FEAT_STL_OPT */
4673 
4674 #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \
4675 	    || defined(FEAT_GUI_TABLINE) || defined(PROTO)
4676 /*
4677  * Get relative cursor position in window into "buf[buflen]", in the form 99%,
4678  * using "Top", "Bot" or "All" when appropriate.
4679  */
4680     void
4681 get_rel_pos(
4682     win_T	*wp,
4683     char_u	*buf,
4684     int		buflen)
4685 {
4686     long	above; /* number of lines above window */
4687     long	below; /* number of lines below window */
4688 
4689     if (buflen < 3) /* need at least 3 chars for writing */
4690 	return;
4691     above = wp->w_topline - 1;
4692 #ifdef FEAT_DIFF
4693     above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
4694     if (wp->w_topline == 1 && wp->w_topfill >= 1)
4695 	above = 0;  /* All buffer lines are displayed and there is an
4696 		     * indication of filler lines, that can be considered
4697 		     * seeing all lines. */
4698 #endif
4699     below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
4700     if (below <= 0)
4701 	vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")),
4702 							(size_t)(buflen - 1));
4703     else if (above <= 0)
4704 	vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1));
4705     else
4706 	vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L
4707 				    ? (int)(above / ((above + below) / 100L))
4708 				    : (int)(above * 100L / (above + below)));
4709 }
4710 #endif
4711 
4712 /*
4713  * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
4714  * Return TRUE if it was appended.
4715  */
4716     static int
4717 append_arg_number(
4718     win_T	*wp,
4719     char_u	*buf,
4720     int		buflen,
4721     int		add_file)	/* Add "file" before the arg number */
4722 {
4723     char_u	*p;
4724 
4725     if (ARGCOUNT <= 1)		/* nothing to do */
4726 	return FALSE;
4727 
4728     p = buf + STRLEN(buf);	/* go to the end of the buffer */
4729     if (p - buf + 35 >= buflen)	/* getting too long */
4730 	return FALSE;
4731     *p++ = ' ';
4732     *p++ = '(';
4733     if (add_file)
4734     {
4735 	STRCPY(p, "file ");
4736 	p += 5;
4737     }
4738     vim_snprintf((char *)p, (size_t)(buflen - (p - buf)),
4739 		wp->w_arg_idx_invalid ? "(%d) of %d)"
4740 				  : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
4741     return TRUE;
4742 }
4743 
4744 /*
4745  * If fname is not a full path, make it a full path.
4746  * Returns pointer to allocated memory (NULL for failure).
4747  */
4748     char_u  *
4749 fix_fname(char_u  *fname)
4750 {
4751     /*
4752      * Force expanding the path always for Unix, because symbolic links may
4753      * mess up the full path name, even though it starts with a '/'.
4754      * Also expand when there is ".." in the file name, try to remove it,
4755      * because "c:/src/../README" is equal to "c:/README".
4756      * Similarly "c:/src//file" is equal to "c:/src/file".
4757      * For MS-Windows also expand names like "longna~1" to "longname".
4758      */
4759 #ifdef UNIX
4760     return FullName_save(fname, TRUE);
4761 #else
4762     if (!vim_isAbsName(fname)
4763 	    || strstr((char *)fname, "..") != NULL
4764 	    || strstr((char *)fname, "//") != NULL
4765 # ifdef BACKSLASH_IN_FILENAME
4766 	    || strstr((char *)fname, "\\\\") != NULL
4767 # endif
4768 # if defined(MSWIN)
4769 	    || vim_strchr(fname, '~') != NULL
4770 # endif
4771 	    )
4772 	return FullName_save(fname, FALSE);
4773 
4774     fname = vim_strsave(fname);
4775 
4776 # ifdef USE_FNAME_CASE
4777 #  ifdef USE_LONG_FNAME
4778     if (USE_LONG_FNAME)
4779 #  endif
4780     {
4781 	if (fname != NULL)
4782 	    fname_case(fname, 0);	/* set correct case for file name */
4783     }
4784 # endif
4785 
4786     return fname;
4787 #endif
4788 }
4789 
4790 /*
4791  * Make "ffname" a full file name, set "sfname" to "ffname" if not NULL.
4792  * "ffname" becomes a pointer to allocated memory (or NULL).
4793  */
4794     void
4795 fname_expand(
4796     buf_T	*buf UNUSED,
4797     char_u	**ffname,
4798     char_u	**sfname)
4799 {
4800     if (*ffname == NULL)	/* if no file name given, nothing to do */
4801 	return;
4802     if (*sfname == NULL)	/* if no short file name given, use ffname */
4803 	*sfname = *ffname;
4804     *ffname = fix_fname(*ffname);   /* expand to full path */
4805 
4806 #ifdef FEAT_SHORTCUT
4807     if (!buf->b_p_bin)
4808     {
4809 	char_u  *rfname;
4810 
4811 	/* If the file name is a shortcut file, use the file it links to. */
4812 	rfname = mch_resolve_shortcut(*ffname);
4813 	if (rfname != NULL)
4814 	{
4815 	    vim_free(*ffname);
4816 	    *ffname = rfname;
4817 	    *sfname = rfname;
4818 	}
4819     }
4820 #endif
4821 }
4822 
4823 /*
4824  * Get the file name for an argument list entry.
4825  */
4826     char_u *
4827 alist_name(aentry_T *aep)
4828 {
4829     buf_T	*bp;
4830 
4831     /* Use the name from the associated buffer if it exists. */
4832     bp = buflist_findnr(aep->ae_fnum);
4833     if (bp == NULL || bp->b_fname == NULL)
4834 	return aep->ae_fname;
4835     return bp->b_fname;
4836 }
4837 
4838 #if defined(FEAT_WINDOWS) || defined(PROTO)
4839 /*
4840  * do_arg_all(): Open up to 'count' windows, one for each argument.
4841  */
4842     void
4843 do_arg_all(
4844     int	count,
4845     int	forceit,		/* hide buffers in current windows */
4846     int keep_tabs)		/* keep current tabs, for ":tab drop file" */
4847 {
4848     int		i;
4849     win_T	*wp, *wpnext;
4850     char_u	*opened;	/* Array of weight for which args are open:
4851 				 *  0: not opened
4852 				 *  1: opened in other tab
4853 				 *  2: opened in curtab
4854 				 *  3: opened in curtab and curwin
4855 				 */
4856     int		opened_len;	/* length of opened[] */
4857     int		use_firstwin = FALSE;	/* use first window for arglist */
4858     int		split_ret = OK;
4859     int		p_ea_save;
4860     alist_T	*alist;		/* argument list to be used */
4861     buf_T	*buf;
4862     tabpage_T	*tpnext;
4863     int		had_tab = cmdmod.tab;
4864     win_T	*old_curwin, *last_curwin;
4865     tabpage_T	*old_curtab, *last_curtab;
4866     win_T	*new_curwin = NULL;
4867     tabpage_T	*new_curtab = NULL;
4868 
4869     if (ARGCOUNT <= 0)
4870     {
4871 	/* Don't give an error message.  We don't want it when the ":all"
4872 	 * command is in the .vimrc. */
4873 	return;
4874     }
4875     setpcmark();
4876 
4877     opened_len = ARGCOUNT;
4878     opened = alloc_clear((unsigned)opened_len);
4879     if (opened == NULL)
4880 	return;
4881 
4882     /* Autocommands may do anything to the argument list.  Make sure it's not
4883      * freed while we are working here by "locking" it.  We still have to
4884      * watch out for its size to be changed. */
4885     alist = curwin->w_alist;
4886     ++alist->al_refcount;
4887 
4888     old_curwin = curwin;
4889     old_curtab = curtab;
4890 
4891 # ifdef FEAT_GUI
4892     need_mouse_correct = TRUE;
4893 # endif
4894 
4895     /*
4896      * Try closing all windows that are not in the argument list.
4897      * Also close windows that are not full width;
4898      * When 'hidden' or "forceit" set the buffer becomes hidden.
4899      * Windows that have a changed buffer and can't be hidden won't be closed.
4900      * When the ":tab" modifier was used do this for all tab pages.
4901      */
4902     if (had_tab > 0)
4903 	goto_tabpage_tp(first_tabpage, TRUE, TRUE);
4904     for (;;)
4905     {
4906 	tpnext = curtab->tp_next;
4907 	for (wp = firstwin; wp != NULL; wp = wpnext)
4908 	{
4909 	    wpnext = wp->w_next;
4910 	    buf = wp->w_buffer;
4911 	    if (buf->b_ffname == NULL
4912 		    || (!keep_tabs && (buf->b_nwindows > 1
4913 			    || wp->w_width != Columns)))
4914 		i = opened_len;
4915 	    else
4916 	    {
4917 		/* check if the buffer in this window is in the arglist */
4918 		for (i = 0; i < opened_len; ++i)
4919 		{
4920 		    if (i < alist->al_ga.ga_len
4921 			    && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
4922 				|| fullpathcmp(alist_name(&AARGLIST(alist)[i]),
4923 					      buf->b_ffname, TRUE) & FPC_SAME))
4924 		    {
4925 			int weight = 1;
4926 
4927 			if (old_curtab == curtab)
4928 			{
4929 			    ++weight;
4930 			    if (old_curwin == wp)
4931 				++weight;
4932 			}
4933 
4934 			if (weight > (int)opened[i])
4935 			{
4936 			    opened[i] = (char_u)weight;
4937 			    if (i == 0)
4938 			    {
4939 				if (new_curwin != NULL)
4940 				    new_curwin->w_arg_idx = opened_len;
4941 				new_curwin = wp;
4942 				new_curtab = curtab;
4943 			    }
4944 			}
4945 			else if (keep_tabs)
4946 			    i = opened_len;
4947 
4948 			if (wp->w_alist != alist)
4949 			{
4950 			    /* Use the current argument list for all windows
4951 			     * containing a file from it. */
4952 			    alist_unlink(wp->w_alist);
4953 			    wp->w_alist = alist;
4954 			    ++wp->w_alist->al_refcount;
4955 			}
4956 			break;
4957 		    }
4958 		}
4959 	    }
4960 	    wp->w_arg_idx = i;
4961 
4962 	    if (i == opened_len && !keep_tabs)/* close this window */
4963 	    {
4964 		if (P_HID(buf) || forceit || buf->b_nwindows > 1
4965 							|| !bufIsChanged(buf))
4966 		{
4967 		    /* If the buffer was changed, and we would like to hide it,
4968 		     * try autowriting. */
4969 		    if (!P_HID(buf) && buf->b_nwindows <= 1
4970 							 && bufIsChanged(buf))
4971 		    {
4972 #ifdef FEAT_AUTOCMD
4973 			bufref_T    bufref;
4974 
4975 			set_bufref(&bufref, buf);
4976 #endif
4977 			(void)autowrite(buf, FALSE);
4978 #ifdef FEAT_AUTOCMD
4979 			/* check if autocommands removed the window */
4980 			if (!win_valid(wp) || !bufref_valid(&bufref))
4981 			{
4982 			    wpnext = firstwin;	/* start all over... */
4983 			    continue;
4984 			}
4985 #endif
4986 		    }
4987 #ifdef FEAT_WINDOWS
4988 		    /* don't close last window */
4989 		    if (ONE_WINDOW
4990 			    && (first_tabpage->tp_next == NULL || !had_tab))
4991 #endif
4992 			use_firstwin = TRUE;
4993 #ifdef FEAT_WINDOWS
4994 		    else
4995 		    {
4996 			win_close(wp, !P_HID(buf) && !bufIsChanged(buf));
4997 # ifdef FEAT_AUTOCMD
4998 			/* check if autocommands removed the next window */
4999 			if (!win_valid(wpnext))
5000 			    wpnext = firstwin;	/* start all over... */
5001 # endif
5002 		    }
5003 #endif
5004 		}
5005 	    }
5006 	}
5007 
5008 	/* Without the ":tab" modifier only do the current tab page. */
5009 	if (had_tab == 0 || tpnext == NULL)
5010 	    break;
5011 
5012 # ifdef FEAT_AUTOCMD
5013 	/* check if autocommands removed the next tab page */
5014 	if (!valid_tabpage(tpnext))
5015 	    tpnext = first_tabpage;	/* start all over...*/
5016 # endif
5017 	goto_tabpage_tp(tpnext, TRUE, TRUE);
5018     }
5019 
5020     /*
5021      * Open a window for files in the argument list that don't have one.
5022      * ARGCOUNT may change while doing this, because of autocommands.
5023      */
5024     if (count > opened_len || count <= 0)
5025 	count = opened_len;
5026 
5027 #ifdef FEAT_AUTOCMD
5028     /* Don't execute Win/Buf Enter/Leave autocommands here. */
5029     ++autocmd_no_enter;
5030     ++autocmd_no_leave;
5031 #endif
5032     last_curwin = curwin;
5033     last_curtab = curtab;
5034     win_enter(lastwin, FALSE);
5035 #ifdef FEAT_WINDOWS
5036     /* ":drop all" should re-use an empty window to avoid "--remote-tab"
5037      * leaving an empty tab page when executed locally. */
5038     if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
5039 			    && curbuf->b_ffname == NULL && !curbuf->b_changed)
5040 	use_firstwin = TRUE;
5041 #endif
5042 
5043     for (i = 0; i < count && i < opened_len && !got_int; ++i)
5044     {
5045 	if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
5046 	    arg_had_last = TRUE;
5047 	if (opened[i] > 0)
5048 	{
5049 	    /* Move the already present window to below the current window */
5050 	    if (curwin->w_arg_idx != i)
5051 	    {
5052 		for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
5053 		{
5054 		    if (wpnext->w_arg_idx == i)
5055 		    {
5056 			if (keep_tabs)
5057 			{
5058 			    new_curwin = wpnext;
5059 			    new_curtab = curtab;
5060 			}
5061 			else
5062 			    win_move_after(wpnext, curwin);
5063 			break;
5064 		    }
5065 		}
5066 	    }
5067 	}
5068 	else if (split_ret == OK)
5069 	{
5070 	    if (!use_firstwin)		/* split current window */
5071 	    {
5072 		p_ea_save = p_ea;
5073 		p_ea = TRUE;		/* use space from all windows */
5074 		split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
5075 		p_ea = p_ea_save;
5076 		if (split_ret == FAIL)
5077 		    continue;
5078 	    }
5079 #ifdef FEAT_AUTOCMD
5080 	    else    /* first window: do autocmd for leaving this buffer */
5081 		--autocmd_no_leave;
5082 #endif
5083 
5084 	    /*
5085 	     * edit file "i"
5086 	     */
5087 	    curwin->w_arg_idx = i;
5088 	    if (i == 0)
5089 	    {
5090 		new_curwin = curwin;
5091 		new_curtab = curtab;
5092 	    }
5093 	    (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
5094 		      ECMD_ONE,
5095 		      ((P_HID(curwin->w_buffer)
5096 			   || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
5097 						       + ECMD_OLDBUF, curwin);
5098 #ifdef FEAT_AUTOCMD
5099 	    if (use_firstwin)
5100 		++autocmd_no_leave;
5101 #endif
5102 	    use_firstwin = FALSE;
5103 	}
5104 	ui_breakcheck();
5105 
5106 	/* When ":tab" was used open a new tab for a new window repeatedly. */
5107 	if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
5108 	    cmdmod.tab = 9999;
5109     }
5110 
5111     /* Remove the "lock" on the argument list. */
5112     alist_unlink(alist);
5113 
5114 #ifdef FEAT_AUTOCMD
5115     --autocmd_no_enter;
5116 #endif
5117     /* restore last referenced tabpage's curwin */
5118     if (last_curtab != new_curtab)
5119     {
5120 	if (valid_tabpage(last_curtab))
5121 	    goto_tabpage_tp(last_curtab, TRUE, TRUE);
5122 	if (win_valid(last_curwin))
5123 	    win_enter(last_curwin, FALSE);
5124     }
5125     /* to window with first arg */
5126     if (valid_tabpage(new_curtab))
5127 	goto_tabpage_tp(new_curtab, TRUE, TRUE);
5128     if (win_valid(new_curwin))
5129 	win_enter(new_curwin, FALSE);
5130 
5131 #ifdef FEAT_AUTOCMD
5132     --autocmd_no_leave;
5133 #endif
5134     vim_free(opened);
5135 }
5136 
5137 # if defined(FEAT_LISTCMDS) || defined(PROTO)
5138 /*
5139  * Open a window for a number of buffers.
5140  */
5141     void
5142 ex_buffer_all(exarg_T *eap)
5143 {
5144     buf_T	*buf;
5145     win_T	*wp, *wpnext;
5146     int		split_ret = OK;
5147     int		p_ea_save;
5148     int		open_wins = 0;
5149     int		r;
5150     int		count;		/* Maximum number of windows to open. */
5151     int		all;		/* When TRUE also load inactive buffers. */
5152 #ifdef FEAT_WINDOWS
5153     int		had_tab = cmdmod.tab;
5154     tabpage_T	*tpnext;
5155 #endif
5156 
5157     if (eap->addr_count == 0)	/* make as many windows as possible */
5158 	count = 9999;
5159     else
5160 	count = eap->line2;	/* make as many windows as specified */
5161     if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
5162 	all = FALSE;
5163     else
5164 	all = TRUE;
5165 
5166     setpcmark();
5167 
5168 #ifdef FEAT_GUI
5169     need_mouse_correct = TRUE;
5170 #endif
5171 
5172     /*
5173      * Close superfluous windows (two windows for the same buffer).
5174      * Also close windows that are not full-width.
5175      */
5176 #ifdef FEAT_WINDOWS
5177     if (had_tab > 0)
5178 	goto_tabpage_tp(first_tabpage, TRUE, TRUE);
5179     for (;;)
5180     {
5181 #endif
5182 	tpnext = curtab->tp_next;
5183 	for (wp = firstwin; wp != NULL; wp = wpnext)
5184 	{
5185 	    wpnext = wp->w_next;
5186 	    if ((wp->w_buffer->b_nwindows > 1
5187 #ifdef FEAT_WINDOWS
5188 		    || ((cmdmod.split & WSP_VERT)
5189 			? wp->w_height + wp->w_status_height < Rows - p_ch
5190 							    - tabline_height()
5191 			: wp->w_width != Columns)
5192 		    || (had_tab > 0 && wp != firstwin)
5193 #endif
5194 		    ) && !ONE_WINDOW
5195 #ifdef FEAT_AUTOCMD
5196 		    && !(wp->w_closing || wp->w_buffer->b_locked > 0)
5197 #endif
5198 		    )
5199 	    {
5200 		win_close(wp, FALSE);
5201 #ifdef FEAT_AUTOCMD
5202 		wpnext = firstwin;	/* just in case an autocommand does
5203 					   something strange with windows */
5204 		tpnext = first_tabpage;	/* start all over...*/
5205 		open_wins = 0;
5206 #endif
5207 	    }
5208 	    else
5209 		++open_wins;
5210 	}
5211 
5212 #ifdef FEAT_WINDOWS
5213 	/* Without the ":tab" modifier only do the current tab page. */
5214 	if (had_tab == 0 || tpnext == NULL)
5215 	    break;
5216 	goto_tabpage_tp(tpnext, TRUE, TRUE);
5217     }
5218 #endif
5219 
5220     /*
5221      * Go through the buffer list.  When a buffer doesn't have a window yet,
5222      * open one.  Otherwise move the window to the right position.
5223      * Watch out for autocommands that delete buffers or windows!
5224      */
5225 #ifdef FEAT_AUTOCMD
5226     /* Don't execute Win/Buf Enter/Leave autocommands here. */
5227     ++autocmd_no_enter;
5228 #endif
5229     win_enter(lastwin, FALSE);
5230 #ifdef FEAT_AUTOCMD
5231     ++autocmd_no_leave;
5232 #endif
5233     for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
5234     {
5235 	/* Check if this buffer needs a window */
5236 	if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
5237 	    continue;
5238 
5239 #ifdef FEAT_WINDOWS
5240 	if (had_tab != 0)
5241 	{
5242 	    /* With the ":tab" modifier don't move the window. */
5243 	    if (buf->b_nwindows > 0)
5244 		wp = lastwin;	    /* buffer has a window, skip it */
5245 	    else
5246 		wp = NULL;
5247 	}
5248 	else
5249 #endif
5250 	{
5251 	    /* Check if this buffer already has a window */
5252 	    FOR_ALL_WINDOWS(wp)
5253 		if (wp->w_buffer == buf)
5254 		    break;
5255 	    /* If the buffer already has a window, move it */
5256 	    if (wp != NULL)
5257 		win_move_after(wp, curwin);
5258 	}
5259 
5260 	if (wp == NULL && split_ret == OK)
5261 	{
5262 #ifdef FEAT_AUTOCMD
5263 	    bufref_T	bufref;
5264 
5265 	    set_bufref(&bufref, buf);
5266 #endif
5267 	    /* Split the window and put the buffer in it */
5268 	    p_ea_save = p_ea;
5269 	    p_ea = TRUE;		/* use space from all windows */
5270 	    split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
5271 	    ++open_wins;
5272 	    p_ea = p_ea_save;
5273 	    if (split_ret == FAIL)
5274 		continue;
5275 
5276 	    /* Open the buffer in this window. */
5277 #if defined(HAS_SWAP_EXISTS_ACTION)
5278 	    swap_exists_action = SEA_DIALOG;
5279 #endif
5280 	    set_curbuf(buf, DOBUF_GOTO);
5281 #ifdef FEAT_AUTOCMD
5282 	    if (!bufref_valid(&bufref))
5283 	    {
5284 		/* autocommands deleted the buffer!!! */
5285 #if defined(HAS_SWAP_EXISTS_ACTION)
5286 		swap_exists_action = SEA_NONE;
5287 # endif
5288 		break;
5289 	    }
5290 #endif
5291 #if defined(HAS_SWAP_EXISTS_ACTION)
5292 	    if (swap_exists_action == SEA_QUIT)
5293 	    {
5294 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5295 		cleanup_T   cs;
5296 
5297 		/* Reset the error/interrupt/exception state here so that
5298 		 * aborting() returns FALSE when closing a window. */
5299 		enter_cleanup(&cs);
5300 # endif
5301 
5302 		/* User selected Quit at ATTENTION prompt; close this window. */
5303 		win_close(curwin, TRUE);
5304 		--open_wins;
5305 		swap_exists_action = SEA_NONE;
5306 		swap_exists_did_quit = TRUE;
5307 
5308 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5309 		/* Restore the error/interrupt/exception state if not
5310 		 * discarded by a new aborting error, interrupt, or uncaught
5311 		 * exception. */
5312 		leave_cleanup(&cs);
5313 # endif
5314 	    }
5315 	    else
5316 		handle_swap_exists(NULL);
5317 #endif
5318 	}
5319 
5320 	ui_breakcheck();
5321 	if (got_int)
5322 	{
5323 	    (void)vgetc();	/* only break the file loading, not the rest */
5324 	    break;
5325 	}
5326 #ifdef FEAT_EVAL
5327 	/* Autocommands deleted the buffer or aborted script processing!!! */
5328 	if (aborting())
5329 	    break;
5330 #endif
5331 #ifdef FEAT_WINDOWS
5332 	/* When ":tab" was used open a new tab for a new window repeatedly. */
5333 	if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
5334 	    cmdmod.tab = 9999;
5335 #endif
5336     }
5337 #ifdef FEAT_AUTOCMD
5338     --autocmd_no_enter;
5339 #endif
5340     win_enter(firstwin, FALSE);		/* back to first window */
5341 #ifdef FEAT_AUTOCMD
5342     --autocmd_no_leave;
5343 #endif
5344 
5345     /*
5346      * Close superfluous windows.
5347      */
5348     for (wp = lastwin; open_wins > count; )
5349     {
5350 	r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
5351 				     || autowrite(wp->w_buffer, FALSE) == OK);
5352 #ifdef FEAT_AUTOCMD
5353 	if (!win_valid(wp))
5354 	{
5355 	    /* BufWrite Autocommands made the window invalid, start over */
5356 	    wp = lastwin;
5357 	}
5358 	else
5359 #endif
5360 	    if (r)
5361 	{
5362 	    win_close(wp, !P_HID(wp->w_buffer));
5363 	    --open_wins;
5364 	    wp = lastwin;
5365 	}
5366 	else
5367 	{
5368 	    wp = wp->w_prev;
5369 	    if (wp == NULL)
5370 		break;
5371 	}
5372     }
5373 }
5374 # endif /* FEAT_LISTCMDS */
5375 
5376 #endif /* FEAT_WINDOWS */
5377 
5378 static int  chk_modeline(linenr_T, int);
5379 
5380 /*
5381  * do_modelines() - process mode lines for the current file
5382  *
5383  * "flags" can be:
5384  * OPT_WINONLY	    only set options local to window
5385  * OPT_NOWIN	    don't set options local to window
5386  *
5387  * Returns immediately if the "ml" option isn't set.
5388  */
5389     void
5390 do_modelines(int flags)
5391 {
5392     linenr_T	lnum;
5393     int		nmlines;
5394     static int	entered = 0;
5395 
5396     if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
5397 	return;
5398 
5399     /* Disallow recursive entry here.  Can happen when executing a modeline
5400      * triggers an autocommand, which reloads modelines with a ":do". */
5401     if (entered)
5402 	return;
5403 
5404     ++entered;
5405     for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
5406 								       ++lnum)
5407 	if (chk_modeline(lnum, flags) == FAIL)
5408 	    nmlines = 0;
5409 
5410     for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
5411 		       && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
5412 	if (chk_modeline(lnum, flags) == FAIL)
5413 	    nmlines = 0;
5414     --entered;
5415 }
5416 
5417 #include "version.h"		/* for version number */
5418 
5419 /*
5420  * chk_modeline() - check a single line for a mode string
5421  * Return FAIL if an error encountered.
5422  */
5423     static int
5424 chk_modeline(
5425     linenr_T	lnum,
5426     int		flags)		/* Same as for do_modelines(). */
5427 {
5428     char_u	*s;
5429     char_u	*e;
5430     char_u	*linecopy;		/* local copy of any modeline found */
5431     int		prev;
5432     int		vers;
5433     int		end;
5434     int		retval = OK;
5435     char_u	*save_sourcing_name;
5436     linenr_T	save_sourcing_lnum;
5437 #ifdef FEAT_EVAL
5438     scid_T	save_SID;
5439 #endif
5440 
5441     prev = -1;
5442     for (s = ml_get(lnum); *s != NUL; ++s)
5443     {
5444 	if (prev == -1 || vim_isspace(prev))
5445 	{
5446 	    if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
5447 		    || STRNCMP(s, "vi:", (size_t)3) == 0)
5448 		break;
5449 	    /* Accept both "vim" and "Vim". */
5450 	    if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm')
5451 	    {
5452 		if (s[3] == '<' || s[3] == '=' || s[3] == '>')
5453 		    e = s + 4;
5454 		else
5455 		    e = s + 3;
5456 		vers = getdigits(&e);
5457 		if (*e == ':'
5458 			&& (s[0] != 'V'
5459 				  || STRNCMP(skipwhite(e + 1), "set", 3) == 0)
5460 			&& (s[3] == ':'
5461 			    || (VIM_VERSION_100 >= vers && isdigit(s[3]))
5462 			    || (VIM_VERSION_100 < vers && s[3] == '<')
5463 			    || (VIM_VERSION_100 > vers && s[3] == '>')
5464 			    || (VIM_VERSION_100 == vers && s[3] == '=')))
5465 		    break;
5466 	    }
5467 	}
5468 	prev = *s;
5469     }
5470 
5471     if (*s)
5472     {
5473 	do				/* skip over "ex:", "vi:" or "vim:" */
5474 	    ++s;
5475 	while (s[-1] != ':');
5476 
5477 	s = linecopy = vim_strsave(s);	/* copy the line, it will change */
5478 	if (linecopy == NULL)
5479 	    return FAIL;
5480 
5481 	save_sourcing_lnum = sourcing_lnum;
5482 	save_sourcing_name = sourcing_name;
5483 	sourcing_lnum = lnum;		/* prepare for emsg() */
5484 	sourcing_name = (char_u *)"modelines";
5485 
5486 	end = FALSE;
5487 	while (end == FALSE)
5488 	{
5489 	    s = skipwhite(s);
5490 	    if (*s == NUL)
5491 		break;
5492 
5493 	    /*
5494 	     * Find end of set command: ':' or end of line.
5495 	     * Skip over "\:", replacing it with ":".
5496 	     */
5497 	    for (e = s; *e != ':' && *e != NUL; ++e)
5498 		if (e[0] == '\\' && e[1] == ':')
5499 		    STRMOVE(e, e + 1);
5500 	    if (*e == NUL)
5501 		end = TRUE;
5502 
5503 	    /*
5504 	     * If there is a "set" command, require a terminating ':' and
5505 	     * ignore the stuff after the ':'.
5506 	     * "vi:set opt opt opt: foo" -- foo not interpreted
5507 	     * "vi:opt opt opt: foo" -- foo interpreted
5508 	     * Accept "se" for compatibility with Elvis.
5509 	     */
5510 	    if (STRNCMP(s, "set ", (size_t)4) == 0
5511 		    || STRNCMP(s, "se ", (size_t)3) == 0)
5512 	    {
5513 		if (*e != ':')		/* no terminating ':'? */
5514 		    break;
5515 		end = TRUE;
5516 		s = vim_strchr(s, ' ') + 1;
5517 	    }
5518 	    *e = NUL;			/* truncate the set command */
5519 
5520 	    if (*s != NUL)		/* skip over an empty "::" */
5521 	    {
5522 #ifdef FEAT_EVAL
5523 		save_SID = current_SID;
5524 		current_SID = SID_MODELINE;
5525 #endif
5526 		retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
5527 #ifdef FEAT_EVAL
5528 		current_SID = save_SID;
5529 #endif
5530 		if (retval == FAIL)		/* stop if error found */
5531 		    break;
5532 	    }
5533 	    s = e + 1;			/* advance to next part */
5534 	}
5535 
5536 	sourcing_lnum = save_sourcing_lnum;
5537 	sourcing_name = save_sourcing_name;
5538 
5539 	vim_free(linecopy);
5540     }
5541     return retval;
5542 }
5543 
5544 #if defined(FEAT_VIMINFO) || defined(PROTO)
5545     int
5546 read_viminfo_bufferlist(
5547     vir_T	*virp,
5548     int		writing)
5549 {
5550     char_u	*tab;
5551     linenr_T	lnum;
5552     colnr_T	col;
5553     buf_T	*buf;
5554     char_u	*sfname;
5555     char_u	*xline;
5556 
5557     /* Handle long line and escaped characters. */
5558     xline = viminfo_readstring(virp, 1, FALSE);
5559 
5560     /* don't read in if there are files on the command-line or if writing: */
5561     if (xline != NULL && !writing && ARGCOUNT == 0
5562 				       && find_viminfo_parameter('%') != NULL)
5563     {
5564 	/* Format is: <fname> Tab <lnum> Tab <col>.
5565 	 * Watch out for a Tab in the file name, work from the end. */
5566 	lnum = 0;
5567 	col = 0;
5568 	tab = vim_strrchr(xline, '\t');
5569 	if (tab != NULL)
5570 	{
5571 	    *tab++ = '\0';
5572 	    col = (colnr_T)atoi((char *)tab);
5573 	    tab = vim_strrchr(xline, '\t');
5574 	    if (tab != NULL)
5575 	    {
5576 		*tab++ = '\0';
5577 		lnum = atol((char *)tab);
5578 	    }
5579 	}
5580 
5581 	/* Expand "~/" in the file name at "line + 1" to a full path.
5582 	 * Then try shortening it by comparing with the current directory */
5583 	expand_env(xline, NameBuff, MAXPATHL);
5584 	sfname = shorten_fname1(NameBuff);
5585 
5586 	buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
5587 	if (buf != NULL)	/* just in case... */
5588 	{
5589 	    buf->b_last_cursor.lnum = lnum;
5590 	    buf->b_last_cursor.col = col;
5591 	    buflist_setfpos(buf, curwin, lnum, col, FALSE);
5592 	}
5593     }
5594     vim_free(xline);
5595 
5596     return viminfo_readline(virp);
5597 }
5598 
5599     void
5600 write_viminfo_bufferlist(FILE *fp)
5601 {
5602     buf_T	*buf;
5603 #ifdef FEAT_WINDOWS
5604     win_T	*win;
5605     tabpage_T	*tp;
5606 #endif
5607     char_u	*line;
5608     int		max_buffers;
5609 
5610     if (find_viminfo_parameter('%') == NULL)
5611 	return;
5612 
5613     /* Without a number -1 is returned: do all buffers. */
5614     max_buffers = get_viminfo_parameter('%');
5615 
5616     /* Allocate room for the file name, lnum and col. */
5617 #define LINE_BUF_LEN (MAXPATHL + 40)
5618     line = alloc(LINE_BUF_LEN);
5619     if (line == NULL)
5620 	return;
5621 
5622 #ifdef FEAT_WINDOWS
5623     FOR_ALL_TAB_WINDOWS(tp, win)
5624 	set_last_cursor(win);
5625 #else
5626     set_last_cursor(curwin);
5627 #endif
5628 
5629     fputs(_("\n# Buffer list:\n"), fp);
5630     FOR_ALL_BUFFERS(buf)
5631     {
5632 	if (buf->b_fname == NULL
5633 		|| !buf->b_p_bl
5634 #ifdef FEAT_QUICKFIX
5635 		|| bt_quickfix(buf)
5636 #endif
5637 		|| removable(buf->b_ffname))
5638 	    continue;
5639 
5640 	if (max_buffers-- == 0)
5641 	    break;
5642 	putc('%', fp);
5643 	home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
5644 	vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
5645 			(long)buf->b_last_cursor.lnum,
5646 			buf->b_last_cursor.col);
5647 	viminfo_writestring(fp, line);
5648     }
5649     vim_free(line);
5650 }
5651 #endif
5652 
5653 
5654 /*
5655  * Return special buffer name.
5656  * Returns NULL when the buffer has a normal file name.
5657  */
5658     char_u *
5659 buf_spname(buf_T *buf)
5660 {
5661 #if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
5662     if (bt_quickfix(buf))
5663     {
5664 	win_T	    *win;
5665 	tabpage_T   *tp;
5666 
5667 	/*
5668 	 * For location list window, w_llist_ref points to the location list.
5669 	 * For quickfix window, w_llist_ref is NULL.
5670 	 */
5671 	if (find_win_for_buf(buf, &win, &tp) == OK && win->w_llist_ref != NULL)
5672 	    return (char_u *)_(msg_loclist);
5673 	else
5674 	    return (char_u *)_(msg_qflist);
5675     }
5676 #endif
5677 
5678     /* There is no _file_ when 'buftype' is "nofile", b_sfname
5679      * contains the name as specified by the user. */
5680     if (bt_nofile(buf))
5681     {
5682 #ifdef FEAT_TERMINAL
5683 	if (buf->b_term != NULL)
5684 	    return term_get_status_text(buf->b_term);
5685 #endif
5686 	if (buf->b_sfname != NULL)
5687 	    return buf->b_sfname;
5688 	return (char_u *)_("[Scratch]");
5689     }
5690 
5691     if (buf->b_fname == NULL)
5692 	return (char_u *)_("[No Name]");
5693     return NULL;
5694 }
5695 
5696 #if (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
5697 	|| defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
5698 	|| defined(PROTO)
5699 /*
5700  * Find a window for buffer "buf".
5701  * If found OK is returned and "wp" and "tp" are set to the window and tabpage.
5702  * If not found FAIL is returned.
5703  */
5704     int
5705 find_win_for_buf(
5706     buf_T     *buf,
5707     win_T     **wp,
5708     tabpage_T **tp)
5709 {
5710     FOR_ALL_TAB_WINDOWS(*tp, *wp)
5711 	if ((*wp)->w_buffer == buf)
5712 	    goto win_found;
5713     return FAIL;
5714 win_found:
5715     return OK;
5716 }
5717 #endif
5718 
5719 #if defined(FEAT_SIGNS) || defined(PROTO)
5720 /*
5721  * Insert the sign into the signlist.
5722  */
5723     static void
5724 insert_sign(
5725     buf_T	*buf,		/* buffer to store sign in */
5726     signlist_T	*prev,		/* previous sign entry */
5727     signlist_T	*next,		/* next sign entry */
5728     int		id,		/* sign ID */
5729     linenr_T	lnum,		/* line number which gets the mark */
5730     int		typenr)		/* typenr of sign we are adding */
5731 {
5732     signlist_T	*newsign;
5733 
5734     newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE);
5735     if (newsign != NULL)
5736     {
5737 	newsign->id = id;
5738 	newsign->lnum = lnum;
5739 	newsign->typenr = typenr;
5740 	newsign->next = next;
5741 #ifdef FEAT_NETBEANS_INTG
5742 	newsign->prev = prev;
5743 	if (next != NULL)
5744 	    next->prev = newsign;
5745 #endif
5746 
5747 	if (prev == NULL)
5748 	{
5749 	    /* When adding first sign need to redraw the windows to create the
5750 	     * column for signs. */
5751 	    if (buf->b_signlist == NULL)
5752 	    {
5753 		redraw_buf_later(buf, NOT_VALID);
5754 		changed_cline_bef_curs();
5755 	    }
5756 
5757 	    /* first sign in signlist */
5758 	    buf->b_signlist = newsign;
5759 #ifdef FEAT_NETBEANS_INTG
5760 	    if (netbeans_active())
5761 		buf->b_has_sign_column = TRUE;
5762 #endif
5763 	}
5764 	else
5765 	    prev->next = newsign;
5766     }
5767 }
5768 
5769 /*
5770  * Add the sign into the signlist. Find the right spot to do it though.
5771  */
5772     void
5773 buf_addsign(
5774     buf_T	*buf,		/* buffer to store sign in */
5775     int		id,		/* sign ID */
5776     linenr_T	lnum,		/* line number which gets the mark */
5777     int		typenr)		/* typenr of sign we are adding */
5778 {
5779     signlist_T	*sign;		/* a sign in the signlist */
5780     signlist_T	*prev;		/* the previous sign */
5781 
5782     prev = NULL;
5783     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5784     {
5785 	if (lnum == sign->lnum && id == sign->id)
5786 	{
5787 	    sign->typenr = typenr;
5788 	    return;
5789 	}
5790 	else if (
5791 #ifndef FEAT_NETBEANS_INTG  /* keep signs sorted by lnum */
5792 		   id < 0 &&
5793 #endif
5794 			     lnum < sign->lnum)
5795 	{
5796 #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5797 	    /* XXX - GRP: Is this because of sign slide problem? Or is it
5798 	     * really needed? Or is it because we allow multiple signs per
5799 	     * line? If so, should I add that feature to FEAT_SIGNS?
5800 	     */
5801 	    while (prev != NULL && prev->lnum == lnum)
5802 		prev = prev->prev;
5803 	    if (prev == NULL)
5804 		sign = buf->b_signlist;
5805 	    else
5806 		sign = prev->next;
5807 #endif
5808 	    insert_sign(buf, prev, sign, id, lnum, typenr);
5809 	    return;
5810 	}
5811 	prev = sign;
5812     }
5813 #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5814     /* XXX - GRP: See previous comment */
5815     while (prev != NULL && prev->lnum == lnum)
5816 	prev = prev->prev;
5817     if (prev == NULL)
5818 	sign = buf->b_signlist;
5819     else
5820 	sign = prev->next;
5821 #endif
5822     insert_sign(buf, prev, sign, id, lnum, typenr);
5823 
5824     return;
5825 }
5826 
5827 /*
5828  * For an existing, placed sign "markId" change the type to "typenr".
5829  * Returns the line number of the sign, or zero if the sign is not found.
5830  */
5831     linenr_T
5832 buf_change_sign_type(
5833     buf_T	*buf,		/* buffer to store sign in */
5834     int		markId,		/* sign ID */
5835     int		typenr)		/* typenr of sign we are adding */
5836 {
5837     signlist_T	*sign;		/* a sign in the signlist */
5838 
5839     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5840     {
5841 	if (sign->id == markId)
5842 	{
5843 	    sign->typenr = typenr;
5844 	    return sign->lnum;
5845 	}
5846     }
5847 
5848     return (linenr_T)0;
5849 }
5850 
5851     int
5852 buf_getsigntype(
5853     buf_T	*buf,
5854     linenr_T	lnum,
5855     int		type)	/* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
5856 {
5857     signlist_T	*sign;		/* a sign in a b_signlist */
5858 
5859     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5860 	if (sign->lnum == lnum
5861 		&& (type == SIGN_ANY
5862 # ifdef FEAT_SIGN_ICONS
5863 		    || (type == SIGN_ICON
5864 			&& sign_get_image(sign->typenr) != NULL)
5865 # endif
5866 		    || (type == SIGN_TEXT
5867 			&& sign_get_text(sign->typenr) != NULL)
5868 		    || (type == SIGN_LINEHL
5869 			&& sign_get_attr(sign->typenr, TRUE) != 0)))
5870 	    return sign->typenr;
5871     return 0;
5872 }
5873 
5874 
5875     linenr_T
5876 buf_delsign(
5877     buf_T	*buf,		/* buffer sign is stored in */
5878     int		id)		/* sign id */
5879 {
5880     signlist_T	**lastp;	/* pointer to pointer to current sign */
5881     signlist_T	*sign;		/* a sign in a b_signlist */
5882     signlist_T	*next;		/* the next sign in a b_signlist */
5883     linenr_T	lnum;		/* line number whose sign was deleted */
5884 
5885     lastp = &buf->b_signlist;
5886     lnum = 0;
5887     for (sign = buf->b_signlist; sign != NULL; sign = next)
5888     {
5889 	next = sign->next;
5890 	if (sign->id == id)
5891 	{
5892 	    *lastp = next;
5893 #ifdef FEAT_NETBEANS_INTG
5894 	    if (next != NULL)
5895 		next->prev = sign->prev;
5896 #endif
5897 	    lnum = sign->lnum;
5898 	    vim_free(sign);
5899 	    break;
5900 	}
5901 	else
5902 	    lastp = &sign->next;
5903     }
5904 
5905     /* When deleted the last sign need to redraw the windows to remove the
5906      * sign column. */
5907     if (buf->b_signlist == NULL)
5908     {
5909 	redraw_buf_later(buf, NOT_VALID);
5910 	changed_cline_bef_curs();
5911     }
5912 
5913     return lnum;
5914 }
5915 
5916 
5917 /*
5918  * Find the line number of the sign with the requested id. If the sign does
5919  * not exist, return 0 as the line number. This will still let the correct file
5920  * get loaded.
5921  */
5922     int
5923 buf_findsign(
5924     buf_T	*buf,		/* buffer to store sign in */
5925     int		id)		/* sign ID */
5926 {
5927     signlist_T	*sign;		/* a sign in the signlist */
5928 
5929     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5930 	if (sign->id == id)
5931 	    return sign->lnum;
5932 
5933     return 0;
5934 }
5935 
5936     int
5937 buf_findsign_id(
5938     buf_T	*buf,		/* buffer whose sign we are searching for */
5939     linenr_T	lnum)		/* line number of sign */
5940 {
5941     signlist_T	*sign;		/* a sign in the signlist */
5942 
5943     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5944 	if (sign->lnum == lnum)
5945 	    return sign->id;
5946 
5947     return 0;
5948 }
5949 
5950 
5951 # if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
5952 /* see if a given type of sign exists on a specific line */
5953     int
5954 buf_findsigntype_id(
5955     buf_T	*buf,		/* buffer whose sign we are searching for */
5956     linenr_T	lnum,		/* line number of sign */
5957     int		typenr)		/* sign type number */
5958 {
5959     signlist_T	*sign;		/* a sign in the signlist */
5960 
5961     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5962 	if (sign->lnum == lnum && sign->typenr == typenr)
5963 	    return sign->id;
5964 
5965     return 0;
5966 }
5967 
5968 
5969 #  if defined(FEAT_SIGN_ICONS) || defined(PROTO)
5970 /* return the number of icons on the given line */
5971     int
5972 buf_signcount(buf_T *buf, linenr_T lnum)
5973 {
5974     signlist_T	*sign;		/* a sign in the signlist */
5975     int		count = 0;
5976 
5977     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5978 	if (sign->lnum == lnum)
5979 	    if (sign_get_image(sign->typenr) != NULL)
5980 		count++;
5981 
5982     return count;
5983 }
5984 #  endif /* FEAT_SIGN_ICONS */
5985 # endif /* FEAT_NETBEANS_INTG */
5986 
5987 
5988 /*
5989  * Delete signs in buffer "buf".
5990  */
5991     void
5992 buf_delete_signs(buf_T *buf)
5993 {
5994     signlist_T	*next;
5995 
5996     /* When deleting the last sign need to redraw the windows to remove the
5997      * sign column. Not when curwin is NULL (this means we're exiting). */
5998     if (buf->b_signlist != NULL && curwin != NULL)
5999     {
6000 	redraw_buf_later(buf, NOT_VALID);
6001 	changed_cline_bef_curs();
6002     }
6003 
6004     while (buf->b_signlist != NULL)
6005     {
6006 	next = buf->b_signlist->next;
6007 	vim_free(buf->b_signlist);
6008 	buf->b_signlist = next;
6009     }
6010 }
6011 
6012 /*
6013  * Delete all signs in all buffers.
6014  */
6015     void
6016 buf_delete_all_signs(void)
6017 {
6018     buf_T	*buf;		/* buffer we are checking for signs */
6019 
6020     FOR_ALL_BUFFERS(buf)
6021 	if (buf->b_signlist != NULL)
6022 	    buf_delete_signs(buf);
6023 }
6024 
6025 /*
6026  * List placed signs for "rbuf".  If "rbuf" is NULL do it for all buffers.
6027  */
6028     void
6029 sign_list_placed(buf_T *rbuf)
6030 {
6031     buf_T	*buf;
6032     signlist_T	*p;
6033     char	lbuf[BUFSIZ];
6034 
6035     MSG_PUTS_TITLE(_("\n--- Signs ---"));
6036     msg_putchar('\n');
6037     if (rbuf == NULL)
6038 	buf = firstbuf;
6039     else
6040 	buf = rbuf;
6041     while (buf != NULL && !got_int)
6042     {
6043 	if (buf->b_signlist != NULL)
6044 	{
6045 	    vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
6046 	    MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D));
6047 	    msg_putchar('\n');
6048 	}
6049 	for (p = buf->b_signlist; p != NULL && !got_int; p = p->next)
6050 	{
6051 	    vim_snprintf(lbuf, BUFSIZ, _("    line=%ld  id=%d  name=%s"),
6052 			   (long)p->lnum, p->id, sign_typenr2name(p->typenr));
6053 	    MSG_PUTS(lbuf);
6054 	    msg_putchar('\n');
6055 	}
6056 	if (rbuf != NULL)
6057 	    break;
6058 	buf = buf->b_next;
6059     }
6060 }
6061 
6062 /*
6063  * Adjust a placed sign for inserted/deleted lines.
6064  */
6065     void
6066 sign_mark_adjust(
6067     linenr_T	line1,
6068     linenr_T	line2,
6069     long	amount,
6070     long	amount_after)
6071 {
6072     signlist_T	*sign;		/* a sign in a b_signlist */
6073 
6074     for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next)
6075     {
6076 	if (sign->lnum >= line1 && sign->lnum <= line2)
6077 	{
6078 	    if (amount == MAXLNUM)
6079 		sign->lnum = line1;
6080 	    else
6081 		sign->lnum += amount;
6082 	}
6083 	else if (sign->lnum > line2)
6084 	    sign->lnum += amount_after;
6085     }
6086 }
6087 #endif /* FEAT_SIGNS */
6088 
6089 /*
6090  * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
6091  */
6092     void
6093 set_buflisted(int on)
6094 {
6095     if (on != curbuf->b_p_bl)
6096     {
6097 	curbuf->b_p_bl = on;
6098 #ifdef FEAT_AUTOCMD
6099 	if (on)
6100 	    apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
6101 	else
6102 	    apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
6103 #endif
6104     }
6105 }
6106 
6107 /*
6108  * Read the file for "buf" again and check if the contents changed.
6109  * Return TRUE if it changed or this could not be checked.
6110  */
6111     int
6112 buf_contents_changed(buf_T *buf)
6113 {
6114     buf_T	*newbuf;
6115     int		differ = TRUE;
6116     linenr_T	lnum;
6117     aco_save_T	aco;
6118     exarg_T	ea;
6119 
6120     /* Allocate a buffer without putting it in the buffer list. */
6121     newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
6122     if (newbuf == NULL)
6123 	return TRUE;
6124 
6125     /* Force the 'fileencoding' and 'fileformat' to be equal. */
6126     if (prep_exarg(&ea, buf) == FAIL)
6127     {
6128 	wipe_buffer(newbuf, FALSE);
6129 	return TRUE;
6130     }
6131 
6132     /* set curwin/curbuf to buf and save a few things */
6133     aucmd_prepbuf(&aco, newbuf);
6134 
6135     if (ml_open(curbuf) == OK
6136 	    && readfile(buf->b_ffname, buf->b_fname,
6137 				  (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
6138 					    &ea, READ_NEW | READ_DUMMY) == OK)
6139     {
6140 	/* compare the two files line by line */
6141 	if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
6142 	{
6143 	    differ = FALSE;
6144 	    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
6145 		if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
6146 		{
6147 		    differ = TRUE;
6148 		    break;
6149 		}
6150 	}
6151     }
6152     vim_free(ea.cmd);
6153 
6154     /* restore curwin/curbuf and a few other things */
6155     aucmd_restbuf(&aco);
6156 
6157     if (curbuf != newbuf)	/* safety check */
6158 	wipe_buffer(newbuf, FALSE);
6159 
6160     return differ;
6161 }
6162 
6163 /*
6164  * Wipe out a buffer and decrement the last buffer number if it was used for
6165  * this buffer.  Call this to wipe out a temp buffer that does not contain any
6166  * marks.
6167  */
6168     void
6169 wipe_buffer(
6170     buf_T	*buf,
6171     int		aucmd UNUSED)	    /* When TRUE trigger autocommands. */
6172 {
6173     if (buf->b_fnum == top_file_num - 1)
6174 	--top_file_num;
6175 
6176 #ifdef FEAT_AUTOCMD
6177     if (!aucmd)		    /* Don't trigger BufDelete autocommands here. */
6178 	block_autocmds();
6179 #endif
6180     close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
6181 #ifdef FEAT_AUTOCMD
6182     if (!aucmd)
6183 	unblock_autocmds();
6184 #endif
6185 }
6186