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