blob: e7d1c75b4980e5d54fb16c55b9987410fc2e83bb [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* 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 * fileio.c: read from and write to a file
12 */
13
14#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000015# include "vimio.h" /* for lseek(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#if defined __EMX__
Bram Moolenaar362e1a32006-03-06 23:29:24 +000019# include "vimio.h" /* for mktemp(), CJW 1997-12-03 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000020#endif
21
22#include "vim.h"
23
Bram Moolenaar071d4272004-06-13 20:20:40 +000024#ifdef __TANDEM
25# include <limits.h> /* for SSIZE_MAX */
26#endif
27
28#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
29# include <utime.h> /* for struct utimbuf */
30#endif
31
32#define BUFSIZE 8192 /* size of normal write buffer */
33#define SMBUFSIZE 256 /* size of emergency write buffer */
34
35#ifdef FEAT_CRYPT
36# define CRYPT_MAGIC "VimCrypt~01!" /* "01" is the version nr */
37# define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */
38#endif
39
40/* Is there any system that doesn't have access()? */
Bram Moolenaar9372a112005-12-06 19:59:18 +000041#define USE_MCH_ACCESS
Bram Moolenaar071d4272004-06-13 20:20:40 +000042
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +000043#if defined(sun) && defined(S_ISCHR)
44# define OPEN_CHR_FILES
45static int is_dev_fd_file(char_u *fname);
46#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000047#ifdef FEAT_MBYTE
48static char_u *next_fenc __ARGS((char_u **pp));
49# ifdef FEAT_EVAL
50static char_u *readfile_charconvert __ARGS((char_u *fname, char_u *fenc, int *fdp));
51# endif
52#endif
53#ifdef FEAT_VIMINFO
54static void check_marks_read __ARGS((void));
55#endif
56#ifdef FEAT_CRYPT
57static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, long *filesizep, int newfile));
58#endif
59#ifdef UNIX
60static void set_file_time __ARGS((char_u *fname, time_t atime, time_t mtime));
61#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +000062static int set_rw_fname __ARGS((char_u *fname, char_u *sfname));
Bram Moolenaar071d4272004-06-13 20:20:40 +000063static int msg_add_fileformat __ARGS((int eol_type));
Bram Moolenaar071d4272004-06-13 20:20:40 +000064static void msg_add_eol __ARGS((void));
65static int check_mtime __ARGS((buf_T *buf, struct stat *s));
66static int time_differs __ARGS((long t1, long t2));
67#ifdef FEAT_AUTOCMD
Bram Moolenaar754b5602006-02-09 23:53:20 +000068static int apply_autocmds_exarg __ARGS((event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap));
Bram Moolenaar70836c82006-02-20 21:28:49 +000069static int au_find_group __ARGS((char_u *name));
70
71# define AUGROUP_DEFAULT -1 /* default autocmd group */
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +000072# define AUGROUP_ERROR -2 /* erroneous autocmd group */
Bram Moolenaar70836c82006-02-20 21:28:49 +000073# define AUGROUP_ALL -3 /* all autocmd groups */
Bram Moolenaar071d4272004-06-13 20:20:40 +000074#endif
75
76#if defined(FEAT_CRYPT) || defined(FEAT_MBYTE)
77# define HAS_BW_FLAGS
78# define FIO_LATIN1 0x01 /* convert Latin1 */
79# define FIO_UTF8 0x02 /* convert UTF-8 */
80# define FIO_UCS2 0x04 /* convert UCS-2 */
81# define FIO_UCS4 0x08 /* convert UCS-4 */
82# define FIO_UTF16 0x10 /* convert UTF-16 */
83# ifdef WIN3264
84# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
85# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
86# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
87# endif
88# ifdef MACOS_X
89# define FIO_MACROMAN 0x20 /* convert MacRoman */
90# endif
91# define FIO_ENDIAN_L 0x80 /* little endian */
92# define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
93# define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
94# define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
95# define FIO_ALL -1 /* allow all formats */
96#endif
97
98/* When converting, a read() or write() may leave some bytes to be converted
99 * for the next call. The value is guessed... */
100#define CONV_RESTLEN 30
101
102/* We have to guess how much a sequence of bytes may expand when converting
103 * with iconv() to be able to allocate a buffer. */
104#define ICONV_MULT 8
105
106/*
107 * Structure to pass arguments from buf_write() to buf_write_bytes().
108 */
109struct bw_info
110{
111 int bw_fd; /* file descriptor */
112 char_u *bw_buf; /* buffer with data to be written */
Bram Moolenaard089d9b2007-09-30 12:02:55 +0000113 int bw_len; /* length of data */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114#ifdef HAS_BW_FLAGS
115 int bw_flags; /* FIO_ flags */
116#endif
117#ifdef FEAT_MBYTE
118 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
119 int bw_restlen; /* nr of bytes in bw_rest[] */
120 int bw_first; /* first write call */
121 char_u *bw_conv_buf; /* buffer for writing converted chars */
122 int bw_conv_buflen; /* size of bw_conv_buf */
123 int bw_conv_error; /* set for conversion error */
Bram Moolenaar32b485f2009-07-29 16:06:27 +0000124 linenr_T bw_conv_error_lnum; /* first line with error or zero */
125 linenr_T bw_start_lnum; /* line number at start of buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126# ifdef USE_ICONV
127 iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
128# endif
129#endif
130};
131
132static int buf_write_bytes __ARGS((struct bw_info *ip));
133
134#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000135static linenr_T readfile_linenr __ARGS((linenr_T linecnt, char_u *p, char_u *endp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136static int ucs2bytes __ARGS((unsigned c, char_u **pp, int flags));
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +0000137static int need_conversion __ARGS((char_u *fenc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138static int get_fio_flags __ARGS((char_u *ptr));
139static char_u *check_for_bom __ARGS((char_u *p, long size, int *lenp, int flags));
140static int make_bom __ARGS((char_u *buf, char_u *name));
141# ifdef WIN3264
142static int get_win_fio_flags __ARGS((char_u *ptr));
143# endif
144# ifdef MACOS_X
145static int get_mac_fio_flags __ARGS((char_u *ptr));
146# endif
147#endif
148static int move_lines __ARGS((buf_T *frombuf, buf_T *tobuf));
Bram Moolenaareaf03392009-11-17 11:08:52 +0000149static void vim_settempdir __ARGS((char_u *tempdir));
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000150#ifdef FEAT_AUTOCMD
151static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
152#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000153
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 void
155filemess(buf, name, s, attr)
156 buf_T *buf;
157 char_u *name;
158 char_u *s;
159 int attr;
160{
161 int msg_scroll_save;
162
163 if (msg_silent != 0)
164 return;
165 msg_add_fname(buf, name); /* put file name in IObuff with quotes */
166 /* If it's extremely long, truncate it. */
167 if (STRLEN(IObuff) > IOSIZE - 80)
168 IObuff[IOSIZE - 80] = NUL;
169 STRCAT(IObuff, s);
170 /*
171 * For the first message may have to start a new line.
172 * For further ones overwrite the previous one, reset msg_scroll before
173 * calling filemess().
174 */
175 msg_scroll_save = msg_scroll;
176 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
177 msg_scroll = FALSE;
178 if (!msg_scroll) /* wait a bit when overwriting an error msg */
179 check_for_delay(FALSE);
180 msg_start();
181 msg_scroll = msg_scroll_save;
182 msg_scrolled_ign = TRUE;
183 /* may truncate the message to avoid a hit-return prompt */
184 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
185 msg_clr_eos();
186 out_flush();
187 msg_scrolled_ign = FALSE;
188}
189
190/*
191 * Read lines from file "fname" into the buffer after line "from".
192 *
193 * 1. We allocate blocks with lalloc, as big as possible.
194 * 2. Each block is filled with characters from the file with a single read().
195 * 3. The lines are inserted in the buffer with ml_append().
196 *
197 * (caller must check that fname != NULL, unless READ_STDIN is used)
198 *
199 * "lines_to_skip" is the number of lines that must be skipped
200 * "lines_to_read" is the number of lines that are appended
201 * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
202 *
203 * flags:
204 * READ_NEW starting to edit a new buffer
205 * READ_FILTER reading filter output
206 * READ_STDIN read from stdin instead of a file
207 * READ_BUFFER read from curbuf instead of a file (converting after reading
208 * stdin)
209 * READ_DUMMY read into a dummy buffer (to check if file contents changed)
210 *
211 * return FAIL for failure, OK otherwise
212 */
213 int
214readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
215 char_u *fname;
216 char_u *sfname;
217 linenr_T from;
218 linenr_T lines_to_skip;
219 linenr_T lines_to_read;
220 exarg_T *eap; /* can be NULL! */
221 int flags;
222{
223 int fd = 0;
224 int newfile = (flags & READ_NEW);
225 int check_readonly;
226 int filtering = (flags & READ_FILTER);
227 int read_stdin = (flags & READ_STDIN);
228 int read_buffer = (flags & READ_BUFFER);
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000229 int set_options = newfile || read_buffer
230 || (eap != NULL && eap->read_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
232 colnr_T read_buf_col = 0; /* next char to read from this line */
233 char_u c;
234 linenr_T lnum = from;
235 char_u *ptr = NULL; /* pointer into read buffer */
236 char_u *buffer = NULL; /* read buffer */
237 char_u *new_buffer = NULL; /* init to shut up gcc */
238 char_u *line_start = NULL; /* init to shut up gcc */
239 int wasempty; /* buffer was empty before reading */
240 colnr_T len;
241 long size = 0;
242 char_u *p;
243 long filesize = 0;
244 int skip_read = FALSE;
245#ifdef FEAT_CRYPT
246 char_u *cryptkey = NULL;
247#endif
248 int split = 0; /* number of split lines */
249#define UNKNOWN 0x0fffffff /* file size is unknown */
250 linenr_T linecnt;
251 int error = FALSE; /* errors encountered */
252 int ff_error = EOL_UNKNOWN; /* file format with errors */
253 long linerest = 0; /* remaining chars in line */
254#ifdef UNIX
255 int perm = 0;
256 int swap_mode = -1; /* protection bits for swap file */
257#else
258 int perm;
259#endif
260 int fileformat = 0; /* end-of-line format */
261 int keep_fileformat = FALSE;
262 struct stat st;
263 int file_readonly;
264 linenr_T skip_count = 0;
265 linenr_T read_count = 0;
266 int msg_save = msg_scroll;
267 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
268 * last read was missing the eol */
269 int try_mac = (vim_strchr(p_ffs, 'm') != NULL);
270 int try_dos = (vim_strchr(p_ffs, 'd') != NULL);
271 int try_unix = (vim_strchr(p_ffs, 'x') != NULL);
272 int file_rewind = FALSE;
273#ifdef FEAT_MBYTE
274 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000275 linenr_T conv_error = 0; /* line nr with conversion error */
276 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
278 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000279 int bad_char_behavior = BAD_REPLACE;
280 /* BAD_KEEP, BAD_DROP or character to
281 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282 char_u *tmpname = NULL; /* name of 'charconvert' output file */
283 int fio_flags = 0;
284 char_u *fenc; /* fileencoding to use */
285 int fenc_alloced; /* fenc_next is in allocated memory */
286 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
287 int advance_fenc = FALSE;
288 long real_size = 0;
289# ifdef USE_ICONV
290 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
291# ifdef FEAT_EVAL
292 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
293 'charconvert' next */
294# endif
295# endif
296 int converted = FALSE; /* TRUE if conversion done */
297 int notconverted = FALSE; /* TRUE if conversion wanted but it
298 wasn't possible */
299 char_u conv_rest[CONV_RESTLEN];
300 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
301#endif
302
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000303#ifdef FEAT_AUTOCMD
304 /* Remember the initial values of curbuf, curbuf->b_ffname and
305 * curbuf->b_fname to detect whether they are altered as a result of
306 * executing nasty autocommands. Also check if "fname" and "sfname"
307 * point to one of these values. */
308 buf_T *old_curbuf = curbuf;
309 char_u *old_b_ffname = curbuf->b_ffname;
310 char_u *old_b_fname = curbuf->b_fname;
311 int using_b_ffname = (fname == curbuf->b_ffname)
312 || (sfname == curbuf->b_ffname);
313 int using_b_fname = (fname == curbuf->b_fname)
314 || (sfname == curbuf->b_fname);
315#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316 write_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317
318 /*
319 * If there is no file name yet, use the one for the read file.
320 * BF_NOTEDITED is set to reflect this.
321 * Don't do this for a read from a filter.
322 * Only do this when 'cpoptions' contains the 'f' flag.
323 */
324 if (curbuf->b_ffname == NULL
325 && !filtering
326 && fname != NULL
327 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
328 && !(flags & READ_DUMMY))
329 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000330 if (set_rw_fname(fname, sfname) == FAIL)
331 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332 }
333
Bram Moolenaardf177f62005-02-22 08:39:57 +0000334 /* After reading a file the cursor line changes but we don't want to
335 * display the line. */
336 ex_no_reprint = TRUE;
337
Bram Moolenaar55b7cf82006-09-09 12:52:42 +0000338 /* don't display the file info for another buffer now */
339 need_fileinfo = FALSE;
340
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341 /*
342 * For Unix: Use the short file name whenever possible.
343 * Avoids problems with networks and when directory names are changed.
344 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
345 * another directory, which we don't detect.
346 */
347 if (sfname == NULL)
348 sfname = fname;
349#if defined(UNIX) || defined(__EMX__)
350 fname = sfname;
351#endif
352
353#ifdef FEAT_AUTOCMD
354 /*
355 * The BufReadCmd and FileReadCmd events intercept the reading process by
356 * executing the associated commands instead.
357 */
358 if (!filtering && !read_stdin && !read_buffer)
359 {
360 pos_T pos;
361
362 pos = curbuf->b_op_start;
363
364 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
365 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
366 curbuf->b_op_start.col = 0;
367
368 if (newfile)
369 {
370 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
371 FALSE, curbuf, eap))
372#ifdef FEAT_EVAL
373 return aborting() ? FAIL : OK;
374#else
375 return OK;
376#endif
377 }
378 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
379 FALSE, NULL, eap))
380#ifdef FEAT_EVAL
381 return aborting() ? FAIL : OK;
382#else
383 return OK;
384#endif
385
386 curbuf->b_op_start = pos;
387 }
388#endif
389
390 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
391 msg_scroll = FALSE; /* overwrite previous file message */
392 else
393 msg_scroll = TRUE; /* don't overwrite previous file message */
394
395 /*
396 * If the name ends in a path separator, we can't open it. Check here,
397 * because reading the file may actually work, but then creating the swap
398 * file may destroy it! Reported on MS-DOS and Win 95.
399 * If the name is too long we might crash further on, quit here.
400 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000401 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000403 p = fname + STRLEN(fname);
404 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000405 {
406 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
407 msg_end();
408 msg_scroll = msg_save;
409 return FAIL;
410 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 }
412
413#ifdef UNIX
414 /*
415 * On Unix it is possible to read a directory, so we have to
416 * check for it before the mch_open().
417 */
418 if (!read_stdin && !read_buffer)
419 {
420 perm = mch_getperm(fname);
421 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
422# ifdef S_ISFIFO
423 && !S_ISFIFO(perm) /* ... or fifo */
424# endif
425# ifdef S_ISSOCK
426 && !S_ISSOCK(perm) /* ... or socket */
427# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +0000428# ifdef OPEN_CHR_FILES
429 && !(S_ISCHR(perm) && is_dev_fd_file(fname))
430 /* ... or a character special file named /dev/fd/<n> */
431# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 )
433 {
434 if (S_ISDIR(perm))
435 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
436 else
437 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
438 msg_end();
439 msg_scroll = msg_save;
440 return FAIL;
441 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000443# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
444 /*
445 * MS-Windows allows opening a device, but we will probably get stuck
446 * trying to read it.
447 */
448 if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
449 {
Bram Moolenaar5386a122007-06-28 20:02:32 +0000450 filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000451 msg_end();
452 msg_scroll = msg_save;
453 return FAIL;
454 }
455# endif
Bram Moolenaar043545e2006-10-10 16:44:07 +0000456 }
457#endif
458
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 /* set default 'fileformat' */
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000460 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461 {
462 if (eap != NULL && eap->force_ff != 0)
463 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
464 else if (*p_ffs != NUL)
465 set_fileformat(default_fileformat(), OPT_LOCAL);
466 }
467
468 /* set or reset 'binary' */
469 if (eap != NULL && eap->force_bin != 0)
470 {
471 int oldval = curbuf->b_p_bin;
472
473 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
474 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
475 }
476
477 /*
478 * When opening a new file we take the readonly flag from the file.
479 * Default is r/w, can be set to r/o below.
480 * Don't reset it when in readonly mode
481 * Only set/reset b_p_ro when BF_CHECK_RO is set.
482 */
483 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000484 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485 curbuf->b_p_ro = FALSE;
486
487 if (newfile && !read_stdin && !read_buffer)
488 {
489 /* Remember time of file.
490 * For RISCOS, also remember the filetype.
491 */
492 if (mch_stat((char *)fname, &st) >= 0)
493 {
494 buf_store_time(curbuf, &st, fname);
495 curbuf->b_mtime_read = curbuf->b_mtime;
496
497#if defined(RISCOS) && defined(FEAT_OSFILETYPE)
498 /* Read the filetype into the buffer local filetype option. */
499 mch_read_filetype(fname);
500#endif
501#ifdef UNIX
502 /*
503 * Use the protection bits of the original file for the swap file.
504 * This makes it possible for others to read the name of the
505 * edited file from the swapfile, but only if they can read the
506 * edited file.
507 * Remove the "write" and "execute" bits for group and others
508 * (they must not write the swapfile).
509 * Add the "read" and "write" bits for the user, otherwise we may
510 * not be able to write to the file ourselves.
511 * Setting the bits is done below, after creating the swap file.
512 */
513 swap_mode = (st.st_mode & 0644) | 0600;
514#endif
515#ifdef FEAT_CW_EDITOR
516 /* Get the FSSpec on MacOS
517 * TODO: Update it properly when the buffer name changes
518 */
519 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
520#endif
521#ifdef VMS
522 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000523 curbuf->b_fab_rat = st.st_fab_rat;
524 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525#endif
526 }
527 else
528 {
529 curbuf->b_mtime = 0;
530 curbuf->b_mtime_read = 0;
531 curbuf->b_orig_size = 0;
532 curbuf->b_orig_mode = 0;
533 }
534
535 /* Reset the "new file" flag. It will be set again below when the
536 * file doesn't exist. */
537 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
538 }
539
540/*
541 * for UNIX: check readonly with perm and mch_access()
542 * for RISCOS: same as Unix, otherwise file gets re-datestamped!
543 * for MSDOS and Amiga: check readonly by trying to open the file for writing
544 */
545 file_readonly = FALSE;
546 if (read_stdin)
547 {
548#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
549 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
550 setmode(0, O_BINARY);
551#endif
552 }
553 else if (!read_buffer)
554 {
555#ifdef USE_MCH_ACCESS
556 if (
557# ifdef UNIX
558 !(perm & 0222) ||
559# endif
560 mch_access((char *)fname, W_OK))
561 file_readonly = TRUE;
562 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
563#else
564 if (!newfile
565 || readonlymode
566 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
567 {
568 file_readonly = TRUE;
569 /* try to open ro */
570 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
571 }
572#endif
573 }
574
575 if (fd < 0) /* cannot open at all */
576 {
577#ifndef UNIX
578 int isdir_f;
579#endif
580 msg_scroll = msg_save;
581#ifndef UNIX
582 /*
583 * On MSDOS and Amiga we can't open a directory, check here.
584 */
585 isdir_f = (mch_isdir(fname));
586 perm = mch_getperm(fname); /* check if the file exists */
587 if (isdir_f)
588 {
589 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
590 curbuf->b_p_ro = TRUE; /* must use "w!" now */
591 }
592 else
593#endif
594 if (newfile)
595 {
596 if (perm < 0)
597 {
598 /*
599 * Set the 'new-file' flag, so that when the file has
600 * been created by someone else, a ":w" will complain.
601 */
602 curbuf->b_flags |= BF_NEW;
603
604 /* Create a swap file now, so that other Vims are warned
605 * that we are editing this file. Don't do this for a
606 * "nofile" or "nowrite" buffer type. */
607#ifdef FEAT_QUICKFIX
608 if (!bt_dontwrite(curbuf))
609#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000610 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000612#ifdef FEAT_AUTOCMD
613 /* SwapExists autocommand may mess things up */
614 if (curbuf != old_curbuf
615 || (using_b_ffname
616 && (old_b_ffname != curbuf->b_ffname))
617 || (using_b_fname
618 && (old_b_fname != curbuf->b_fname)))
619 {
620 EMSG(_(e_auchangedbuf));
621 return FAIL;
622 }
623#endif
624 }
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000625 if (dir_of_file_exists(fname))
626 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
627 else
628 filemess(curbuf, sfname,
629 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630#ifdef FEAT_VIMINFO
631 /* Even though this is a new file, it might have been
632 * edited before and deleted. Get the old marks. */
633 check_marks_read();
634#endif
635#ifdef FEAT_MBYTE
636 if (eap != NULL && eap->force_enc != 0)
637 {
638 /* set forced 'fileencoding' */
639 fenc = enc_canonize(eap->cmd + eap->force_enc);
640 if (fenc != NULL)
641 set_string_option_direct((char_u *)"fenc", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000642 fenc, OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 vim_free(fenc);
644 }
645#endif
646#ifdef FEAT_AUTOCMD
647 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
648 FALSE, curbuf, eap);
649#endif
650 /* remember the current fileformat */
651 save_file_ff(curbuf);
652
653#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
654 if (aborting()) /* autocmds may abort script processing */
655 return FAIL;
656#endif
657 return OK; /* a new file is not an error */
658 }
659 else
660 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000661 filemess(curbuf, sfname, (char_u *)(
662# ifdef EFBIG
663 (errno == EFBIG) ? _("[File too big]") :
664# endif
665 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 curbuf->b_p_ro = TRUE; /* must use "w!" now */
667 }
668 }
669
670 return FAIL;
671 }
672
673 /*
674 * Only set the 'ro' flag for readonly files the first time they are
675 * loaded. Help files always get readonly mode
676 */
677 if ((check_readonly && file_readonly) || curbuf->b_help)
678 curbuf->b_p_ro = TRUE;
679
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000680 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 {
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000682 /* Don't change 'eol' if reading from buffer as it will already be
683 * correctly set when reading stdin. */
684 if (!read_buffer)
685 {
686 curbuf->b_p_eol = TRUE;
687 curbuf->b_start_eol = TRUE;
688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689#ifdef FEAT_MBYTE
690 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000691 curbuf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692#endif
693 }
694
695 /* Create a swap file now, so that other Vims are warned that we are
696 * editing this file.
697 * Don't do this for a "nofile" or "nowrite" buffer type. */
698#ifdef FEAT_QUICKFIX
699 if (!bt_dontwrite(curbuf))
700#endif
701 {
702 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000703#ifdef FEAT_AUTOCMD
704 if (!read_stdin && (curbuf != old_curbuf
705 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
706 || (using_b_fname && (old_b_fname != curbuf->b_fname))))
707 {
708 EMSG(_(e_auchangedbuf));
709 if (!read_buffer)
710 close(fd);
711 return FAIL;
712 }
713#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714#ifdef UNIX
715 /* Set swap file protection bits after creating it. */
Bram Moolenaarf061e0b2009-06-24 15:32:01 +0000716 if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
717 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
719#endif
720 }
721
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000722#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723 /* If "Quit" selected at ATTENTION dialog, don't load the file */
724 if (swap_exists_action == SEA_QUIT)
725 {
726 if (!read_buffer && !read_stdin)
727 close(fd);
728 return FAIL;
729 }
730#endif
731
732 ++no_wait_return; /* don't wait for return yet */
733
734 /*
735 * Set '[ mark to the line above where the lines go (line 1 if zero).
736 */
737 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
738 curbuf->b_op_start.col = 0;
739
740#ifdef FEAT_AUTOCMD
741 if (!read_buffer)
742 {
743 int m = msg_scroll;
744 int n = msg_scrolled;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745
746 /*
747 * The file must be closed again, the autocommands may want to change
748 * the file before reading it.
749 */
750 if (!read_stdin)
751 close(fd); /* ignore errors */
752
753 /*
754 * The output from the autocommands should not overwrite anything and
755 * should not be overwritten: Set msg_scroll, restore its value if no
756 * output was done.
757 */
758 msg_scroll = TRUE;
759 if (filtering)
760 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
761 FALSE, curbuf, eap);
762 else if (read_stdin)
763 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
764 FALSE, curbuf, eap);
765 else if (newfile)
766 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
767 FALSE, curbuf, eap);
768 else
769 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
770 FALSE, NULL, eap);
771 if (msg_scrolled == n)
772 msg_scroll = m;
773
774#ifdef FEAT_EVAL
775 if (aborting()) /* autocmds may abort script processing */
776 {
777 --no_wait_return;
778 msg_scroll = msg_save;
779 curbuf->b_p_ro = TRUE; /* must use "w!" now */
780 return FAIL;
781 }
782#endif
783 /*
784 * Don't allow the autocommands to change the current buffer.
785 * Try to re-open the file.
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000786 *
787 * Don't allow the autocommands to change the buffer name either
788 * (cd for example) if it invalidates fname or sfname.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 */
790 if (!read_stdin && (curbuf != old_curbuf
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000791 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
792 || (using_b_fname && (old_b_fname != curbuf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
794 {
795 --no_wait_return;
796 msg_scroll = msg_save;
797 if (fd < 0)
798 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
799 else
800 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
801 curbuf->b_p_ro = TRUE; /* must use "w!" now */
802 return FAIL;
803 }
804 }
805#endif /* FEAT_AUTOCMD */
806
807 /* Autocommands may add lines to the file, need to check if it is empty */
808 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
809
810 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
811 {
812 /*
813 * Show the user that we are busy reading the input. Sometimes this
814 * may take a while. When reading from stdin another program may
815 * still be running, don't move the cursor to the last line, unless
816 * always using the GUI.
817 */
818 if (read_stdin)
819 {
820#ifndef ALWAYS_USE_GUI
821 mch_msg(_("Vim: Reading from stdin...\n"));
822#endif
823#ifdef FEAT_GUI
824 /* Also write a message in the GUI window, if there is one. */
825 if (gui.in_use && !gui.dying && !gui.starting)
826 {
827 p = (char_u *)_("Reading from stdin...");
828 gui_write(p, (int)STRLEN(p));
829 }
830#endif
831 }
832 else if (!read_buffer)
833 filemess(curbuf, sfname, (char_u *)"", 0);
834 }
835
836 msg_scroll = FALSE; /* overwrite the file message */
837
838 /*
839 * Set linecnt now, before the "retry" caused by a wrong guess for
840 * fileformat, and after the autocommands, which may change them.
841 */
842 linecnt = curbuf->b_ml.ml_line_count;
843
844#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000845 /* "++bad=" argument. */
846 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000847 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000848 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000849 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000850 curbuf->b_bad_char = eap->bad_char;
851 }
852 else
853 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000854
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000856 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857 */
858 if (eap != NULL && eap->force_enc != 0)
859 {
860 fenc = enc_canonize(eap->cmd + eap->force_enc);
861 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000862 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 }
864 else if (curbuf->b_p_bin)
865 {
866 fenc = (char_u *)""; /* binary: don't convert */
867 fenc_alloced = FALSE;
868 }
869 else if (curbuf->b_help)
870 {
871 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000872 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873
874 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
875 * fails it must be latin1.
876 * Always do this when 'encoding' is "utf-8". Otherwise only do
877 * this when needed to avoid [converted] remarks all the time.
878 * It is needed when the first line contains non-ASCII characters.
879 * That is only in *.??x files. */
880 fenc = (char_u *)"latin1";
881 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000882 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000884 fc = fname[STRLEN(fname) - 1];
885 if (TOLOWER_ASC(fc) == 'x')
886 {
887 /* Read the first line (and a bit more). Immediately rewind to
888 * the start of the file. If the read() fails "len" is -1. */
889 len = vim_read(fd, firstline, 80);
890 lseek(fd, (off_t)0L, SEEK_SET);
891 for (p = firstline; p < firstline + len; ++p)
892 if (*p >= 0x80)
893 {
894 c = TRUE;
895 break;
896 }
897 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 }
899
900 if (c)
901 {
902 fenc_next = fenc;
903 fenc = (char_u *)"utf-8";
904
905 /* When the file is utf-8 but a character doesn't fit in
906 * 'encoding' don't retry. In help text editing utf-8 bytes
907 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000908 if (!enc_utf8)
909 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910 }
911 fenc_alloced = FALSE;
912 }
913 else if (*p_fencs == NUL)
914 {
915 fenc = curbuf->b_p_fenc; /* use format from buffer */
916 fenc_alloced = FALSE;
917 }
918 else
919 {
920 fenc_next = p_fencs; /* try items in 'fileencodings' */
921 fenc = next_fenc(&fenc_next);
922 fenc_alloced = TRUE;
923 }
924#endif
925
926 /*
927 * Jump back here to retry reading the file in different ways.
928 * Reasons to retry:
929 * - encoding conversion failed: try another one from "fenc_next"
930 * - BOM detected and fenc was set, need to setup conversion
931 * - "fileformat" check failed: try another
932 *
933 * Variables set for special retry actions:
934 * "file_rewind" Rewind the file to start reading it again.
935 * "advance_fenc" Advance "fenc" using "fenc_next".
936 * "skip_read" Re-use already read bytes (BOM detected).
937 * "did_iconv" iconv() conversion failed, try 'charconvert'.
938 * "keep_fileformat" Don't reset "fileformat".
939 *
940 * Other status indicators:
941 * "tmpname" When != NULL did conversion with 'charconvert'.
942 * Output file has to be deleted afterwards.
943 * "iconv_fd" When != -1 did conversion with iconv().
944 */
945retry:
946
947 if (file_rewind)
948 {
949 if (read_buffer)
950 {
951 read_buf_lnum = 1;
952 read_buf_col = 0;
953 }
954 else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0)
955 {
956 /* Can't rewind the file, give up. */
957 error = TRUE;
958 goto failed;
959 }
960 /* Delete the previously read lines. */
961 while (lnum > from)
962 ml_delete(lnum--, FALSE);
963 file_rewind = FALSE;
964#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000965 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000966 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000968 curbuf->b_start_bomb = FALSE;
969 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000970 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971#endif
972 }
973
974 /*
975 * When retrying with another "fenc" and the first time "fileformat"
976 * will be reset.
977 */
978 if (keep_fileformat)
979 keep_fileformat = FALSE;
980 else
981 {
982 if (eap != NULL && eap->force_ff != 0)
Bram Moolenaar1c860362008-11-12 15:05:21 +0000983 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984 fileformat = get_fileformat_force(curbuf, eap);
Bram Moolenaar1c860362008-11-12 15:05:21 +0000985 try_unix = try_dos = try_mac = FALSE;
986 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 else if (curbuf->b_p_bin)
988 fileformat = EOL_UNIX; /* binary: use Unix format */
989 else if (*p_ffs == NUL)
990 fileformat = get_fileformat(curbuf);/* use format from buffer */
991 else
992 fileformat = EOL_UNKNOWN; /* detect from file */
993 }
994
995#ifdef FEAT_MBYTE
996# ifdef USE_ICONV
997 if (iconv_fd != (iconv_t)-1)
998 {
999 /* aborted conversion with iconv(), close the descriptor */
1000 iconv_close(iconv_fd);
1001 iconv_fd = (iconv_t)-1;
1002 }
1003# endif
1004
1005 if (advance_fenc)
1006 {
1007 /*
1008 * Try the next entry in 'fileencodings'.
1009 */
1010 advance_fenc = FALSE;
1011
1012 if (eap != NULL && eap->force_enc != 0)
1013 {
1014 /* Conversion given with "++cc=" wasn't possible, read
1015 * without conversion. */
1016 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001017 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 if (fenc_alloced)
1019 vim_free(fenc);
1020 fenc = (char_u *)"";
1021 fenc_alloced = FALSE;
1022 }
1023 else
1024 {
1025 if (fenc_alloced)
1026 vim_free(fenc);
1027 if (fenc_next != NULL)
1028 {
1029 fenc = next_fenc(&fenc_next);
1030 fenc_alloced = (fenc_next != NULL);
1031 }
1032 else
1033 {
1034 fenc = (char_u *)"";
1035 fenc_alloced = FALSE;
1036 }
1037 }
1038 if (tmpname != NULL)
1039 {
1040 mch_remove(tmpname); /* delete converted file */
1041 vim_free(tmpname);
1042 tmpname = NULL;
1043 }
1044 }
1045
1046 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001047 * Conversion may be required when the encoding of the file is different
1048 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 */
1050 fio_flags = 0;
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001051 converted = need_conversion(fenc);
1052 if (converted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 {
1054
1055 /* "ucs-bom" means we need to check the first bytes of the file
1056 * for a BOM. */
1057 if (STRCMP(fenc, ENC_UCSBOM) == 0)
1058 fio_flags = FIO_UCSBOM;
1059
1060 /*
1061 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
1062 * done. This is handled below after read(). Prepare the
1063 * fio_flags to avoid having to parse the string each time.
1064 * Also check for Unicode to Latin1 conversion, because iconv()
1065 * appears not to handle this correctly. This works just like
1066 * conversion to UTF-8 except how the resulting character is put in
1067 * the buffer.
1068 */
1069 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
1070 fio_flags = get_fio_flags(fenc);
1071
1072# ifdef WIN3264
1073 /*
1074 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
1075 * is handled with MultiByteToWideChar().
1076 */
1077 if (fio_flags == 0)
1078 fio_flags = get_win_fio_flags(fenc);
1079# endif
1080
1081# ifdef MACOS_X
1082 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1083 if (fio_flags == 0)
1084 fio_flags = get_mac_fio_flags(fenc);
1085# endif
1086
1087# ifdef USE_ICONV
1088 /*
1089 * Try using iconv() if we can't convert internally.
1090 */
1091 if (fio_flags == 0
1092# ifdef FEAT_EVAL
1093 && !did_iconv
1094# endif
1095 )
1096 iconv_fd = (iconv_t)my_iconv_open(
1097 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
1098# endif
1099
1100# ifdef FEAT_EVAL
1101 /*
1102 * Use the 'charconvert' expression when conversion is required
1103 * and we can't do it internally or with iconv().
1104 */
1105 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
1106# ifdef USE_ICONV
1107 && iconv_fd == (iconv_t)-1
1108# endif
1109 )
1110 {
1111# ifdef USE_ICONV
1112 did_iconv = FALSE;
1113# endif
1114 /* Skip conversion when it's already done (retry for wrong
1115 * "fileformat"). */
1116 if (tmpname == NULL)
1117 {
1118 tmpname = readfile_charconvert(fname, fenc, &fd);
1119 if (tmpname == NULL)
1120 {
1121 /* Conversion failed. Try another one. */
1122 advance_fenc = TRUE;
1123 if (fd < 0)
1124 {
1125 /* Re-opening the original file failed! */
1126 EMSG(_("E202: Conversion made file unreadable!"));
1127 error = TRUE;
1128 goto failed;
1129 }
1130 goto retry;
1131 }
1132 }
1133 }
1134 else
1135# endif
1136 {
1137 if (fio_flags == 0
1138# ifdef USE_ICONV
1139 && iconv_fd == (iconv_t)-1
1140# endif
1141 )
1142 {
1143 /* Conversion wanted but we can't.
1144 * Try the next conversion in 'fileencodings' */
1145 advance_fenc = TRUE;
1146 goto retry;
1147 }
1148 }
1149 }
1150
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001151 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001153 * stdin or fixed at a specific encoding. */
1154 can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155#endif
1156
1157 if (!skip_read)
1158 {
1159 linerest = 0;
1160 filesize = 0;
1161 skip_count = lines_to_skip;
1162 read_count = lines_to_read;
1163#ifdef FEAT_MBYTE
1164 conv_restlen = 0;
1165#endif
1166 }
1167
1168 while (!error && !got_int)
1169 {
1170 /*
1171 * We allocate as much space for the file as we can get, plus
1172 * space for the old line plus room for one terminating NUL.
1173 * The amount is limited by the fact that read() only can read
1174 * upto max_unsigned characters (and other things).
1175 */
1176#if SIZEOF_INT <= 2
1177 if (linerest >= 0x7ff0)
1178 {
1179 ++split;
1180 *ptr = NL; /* split line by inserting a NL */
1181 size = 1;
1182 }
1183 else
1184#endif
1185 {
1186 if (!skip_read)
1187 {
1188#if SIZEOF_INT > 2
Bram Moolenaar311d9822007-02-27 15:48:28 +00001189# if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190 size = SSIZE_MAX; /* use max I/O size, 52K */
1191# else
1192 size = 0x10000L; /* use buffer >= 64K */
1193# endif
1194#else
1195 size = 0x7ff0L - linerest; /* limit buffer to 32K */
1196#endif
1197
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001198 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001199 {
1200 if ((new_buffer = lalloc((long_u)(size + linerest + 1),
1201 FALSE)) != NULL)
1202 break;
1203 }
1204 if (new_buffer == NULL)
1205 {
1206 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1207 error = TRUE;
1208 break;
1209 }
1210 if (linerest) /* copy characters from the previous buffer */
1211 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1212 vim_free(buffer);
1213 buffer = new_buffer;
1214 ptr = buffer + linerest;
1215 line_start = buffer;
1216
1217#ifdef FEAT_MBYTE
1218 /* May need room to translate into.
1219 * For iconv() we don't really know the required space, use a
1220 * factor ICONV_MULT.
1221 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1222 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1223 * become up to 4 bytes, size must be multiple of 2
1224 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1225 * multiple of 2
1226 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1227 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001228 real_size = (int)size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229# ifdef USE_ICONV
1230 if (iconv_fd != (iconv_t)-1)
1231 size = size / ICONV_MULT;
1232 else
1233# endif
1234 if (fio_flags & FIO_LATIN1)
1235 size = size / 2;
1236 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1237 size = (size * 2 / 3) & ~1;
1238 else if (fio_flags & FIO_UCS4)
1239 size = (size * 2 / 3) & ~3;
1240 else if (fio_flags == FIO_UCSBOM)
1241 size = size / ICONV_MULT; /* worst case */
1242# ifdef WIN3264
1243 else if (fio_flags & FIO_CODEPAGE)
1244 size = size / ICONV_MULT; /* also worst case */
1245# endif
1246# ifdef MACOS_X
1247 else if (fio_flags & FIO_MACROMAN)
1248 size = size / ICONV_MULT; /* also worst case */
1249# endif
1250#endif
1251
1252#ifdef FEAT_MBYTE
1253 if (conv_restlen > 0)
1254 {
1255 /* Insert unconverted bytes from previous line. */
1256 mch_memmove(ptr, conv_rest, conv_restlen);
1257 ptr += conv_restlen;
1258 size -= conv_restlen;
1259 }
1260#endif
1261
1262 if (read_buffer)
1263 {
1264 /*
1265 * Read bytes from curbuf. Used for converting text read
1266 * from stdin.
1267 */
1268 if (read_buf_lnum > from)
1269 size = 0;
1270 else
1271 {
1272 int n, ni;
1273 long tlen;
1274
1275 tlen = 0;
1276 for (;;)
1277 {
1278 p = ml_get(read_buf_lnum) + read_buf_col;
1279 n = (int)STRLEN(p);
1280 if ((int)tlen + n + 1 > size)
1281 {
1282 /* Filled up to "size", append partial line.
1283 * Change NL to NUL to reverse the effect done
1284 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001285 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 for (ni = 0; ni < n; ++ni)
1287 {
1288 if (p[ni] == NL)
1289 ptr[tlen++] = NUL;
1290 else
1291 ptr[tlen++] = p[ni];
1292 }
1293 read_buf_col += n;
1294 break;
1295 }
1296 else
1297 {
1298 /* Append whole line and new-line. Change NL
1299 * to NUL to reverse the effect done below. */
1300 for (ni = 0; ni < n; ++ni)
1301 {
1302 if (p[ni] == NL)
1303 ptr[tlen++] = NUL;
1304 else
1305 ptr[tlen++] = p[ni];
1306 }
1307 ptr[tlen++] = NL;
1308 read_buf_col = 0;
1309 if (++read_buf_lnum > from)
1310 {
1311 /* When the last line didn't have an
1312 * end-of-line don't add it now either. */
1313 if (!curbuf->b_p_eol)
1314 --tlen;
1315 size = tlen;
1316 break;
1317 }
1318 }
1319 }
1320 }
1321 }
1322 else
1323 {
1324 /*
1325 * Read bytes from the file.
1326 */
1327 size = vim_read(fd, ptr, size);
1328 }
1329
1330 if (size <= 0)
1331 {
1332 if (size < 0) /* read error */
1333 error = TRUE;
1334#ifdef FEAT_MBYTE
1335 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001336 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001337 /*
1338 * Reached end-of-file but some trailing bytes could
1339 * not be converted. Truncated file?
1340 */
1341
1342 /* When we did a conversion report an error. */
1343 if (fio_flags != 0
1344# ifdef USE_ICONV
1345 || iconv_fd != (iconv_t)-1
1346# endif
1347 )
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001348 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001349 if (conv_error == 0)
1350 conv_error = curbuf->b_ml.ml_line_count
1351 - linecnt + 1;
1352 }
1353 /* Remember the first linenr with an illegal byte */
1354 else if (illegal_byte == 0)
1355 illegal_byte = curbuf->b_ml.ml_line_count
1356 - linecnt + 1;
1357 if (bad_char_behavior == BAD_DROP)
1358 {
1359 *(ptr - conv_restlen) = NUL;
1360 conv_restlen = 0;
1361 }
1362 else
1363 {
1364 /* Replace the trailing bytes with the replacement
1365 * character if we were converting; if we weren't,
1366 * leave the UTF8 checking code to do it, as it
1367 * works slightly differently. */
1368 if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
1369# ifdef USE_ICONV
1370 || iconv_fd != (iconv_t)-1
1371# endif
1372 ))
1373 {
1374 while (conv_restlen > 0)
1375 {
1376 *(--ptr) = bad_char_behavior;
1377 --conv_restlen;
1378 }
1379 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001380 fio_flags = 0; /* don't convert this */
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001381# ifdef USE_ICONV
1382 if (iconv_fd != (iconv_t)-1)
1383 {
1384 iconv_close(iconv_fd);
1385 iconv_fd = (iconv_t)-1;
1386 }
1387# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001388 }
1389 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390#endif
1391 }
1392
1393#ifdef FEAT_CRYPT
1394 /*
1395 * At start of file: Check for magic number of encryption.
1396 */
1397 if (filesize == 0)
1398 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1399 &filesize, newfile);
1400 /*
1401 * Decrypt the read bytes.
1402 */
1403 if (cryptkey != NULL && size > 0)
1404 for (p = ptr; p < ptr + size; ++p)
1405 ZDECODE(*p);
1406#endif
1407 }
1408 skip_read = FALSE;
1409
1410#ifdef FEAT_MBYTE
1411 /*
1412 * At start of file (or after crypt magic number): Check for BOM.
1413 * Also check for a BOM for other Unicode encodings, but not after
1414 * converting with 'charconvert' or when a BOM has already been
1415 * found.
1416 */
1417 if ((filesize == 0
1418# ifdef FEAT_CRYPT
1419 || (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
1420# endif
1421 )
1422 && (fio_flags == FIO_UCSBOM
1423 || (!curbuf->b_p_bomb
1424 && tmpname == NULL
1425 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1426 {
1427 char_u *ccname;
1428 int blen;
1429
1430 /* no BOM detection in a short file or in binary mode */
1431 if (size < 2 || curbuf->b_p_bin)
1432 ccname = NULL;
1433 else
1434 ccname = check_for_bom(ptr, size, &blen,
1435 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1436 if (ccname != NULL)
1437 {
1438 /* Remove BOM from the text */
1439 filesize += blen;
1440 size -= blen;
1441 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001442 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001443 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001444 curbuf->b_p_bomb = TRUE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001445 curbuf->b_start_bomb = TRUE;
1446 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001447 }
1448
1449 if (fio_flags == FIO_UCSBOM)
1450 {
1451 if (ccname == NULL)
1452 {
1453 /* No BOM detected: retry with next encoding. */
1454 advance_fenc = TRUE;
1455 }
1456 else
1457 {
1458 /* BOM detected: set "fenc" and jump back */
1459 if (fenc_alloced)
1460 vim_free(fenc);
1461 fenc = ccname;
1462 fenc_alloced = FALSE;
1463 }
1464 /* retry reading without getting new bytes or rewinding */
1465 skip_read = TRUE;
1466 goto retry;
1467 }
1468 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001469
1470 /* Include not converted bytes. */
1471 ptr -= conv_restlen;
1472 size += conv_restlen;
1473 conv_restlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001474#endif
1475 /*
1476 * Break here for a read error or end-of-file.
1477 */
1478 if (size <= 0)
1479 break;
1480
1481#ifdef FEAT_MBYTE
1482
Bram Moolenaar071d4272004-06-13 20:20:40 +00001483# ifdef USE_ICONV
1484 if (iconv_fd != (iconv_t)-1)
1485 {
1486 /*
1487 * Attempt conversion of the read bytes to 'encoding' using
1488 * iconv().
1489 */
1490 const char *fromp;
1491 char *top;
1492 size_t from_size;
1493 size_t to_size;
1494
1495 fromp = (char *)ptr;
1496 from_size = size;
1497 ptr += size;
1498 top = (char *)ptr;
1499 to_size = real_size - size;
1500
1501 /*
1502 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001503 * another conversion. Except for when there is no
1504 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001506 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1507 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1509 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001510 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001511 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001512 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001513 if (conv_error == 0)
1514 conv_error = readfile_linenr(linecnt,
1515 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001516
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001517 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001518 ++fromp;
1519 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001520 if (bad_char_behavior == BAD_KEEP)
1521 {
1522 *top++ = *(fromp - 1);
1523 --to_size;
1524 }
1525 else if (bad_char_behavior != BAD_DROP)
1526 {
1527 *top++ = bad_char_behavior;
1528 --to_size;
1529 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001530 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001531
1532 if (from_size > 0)
1533 {
1534 /* Some remaining characters, keep them for the next
1535 * round. */
1536 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1537 conv_restlen = (int)from_size;
1538 }
1539
1540 /* move the linerest to before the converted characters */
1541 line_start = ptr - linerest;
1542 mch_memmove(line_start, buffer, (size_t)linerest);
1543 size = (long)((char_u *)top - ptr);
1544 }
1545# endif
1546
1547# ifdef WIN3264
1548 if (fio_flags & FIO_CODEPAGE)
1549 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001550 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001551 WCHAR ucs2buf[3];
1552 int ucs2len;
1553 int codepage = FIO_GET_CP(fio_flags);
1554 int bytelen;
1555 int found_bad;
1556 char replstr[2];
1557
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 /*
1559 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001560 * a codepage, using standard MS-Windows functions. This
1561 * requires two steps:
1562 * 1. convert from 'fileencoding' to ucs-2
1563 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001564 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001565 * Because there may be illegal bytes AND an incomplete byte
1566 * sequence at the end, we may have to do the conversion one
1567 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001570 /* Replacement string for WideCharToMultiByte(). */
1571 if (bad_char_behavior > 0)
1572 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001574 replstr[0] = '?';
1575 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576
1577 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001578 * Move the bytes to the end of the buffer, so that we have
1579 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001581 src = ptr + real_size - size;
1582 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001584 /*
1585 * Do the conversion.
1586 */
1587 dst = ptr;
1588 size = size;
1589 while (size > 0)
1590 {
1591 found_bad = FALSE;
1592
1593# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1594 if (codepage == CP_UTF8)
1595 {
1596 /* Handle CP_UTF8 input ourselves to be able to handle
1597 * trailing bytes properly.
1598 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001599 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001600 if (bytelen > size)
1601 {
1602 /* Only got some bytes of a character. Normally
1603 * it's put in "conv_rest", but if it's too long
1604 * deal with it as if they were illegal bytes. */
1605 if (bytelen <= CONV_RESTLEN)
1606 break;
1607
1608 /* weird overlong byte sequence */
1609 bytelen = size;
1610 found_bad = TRUE;
1611 }
1612 else
1613 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001614 int u8c = utf_ptr2char(src);
1615
Bram Moolenaar86e01082005-12-29 22:45:34 +00001616 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001617 found_bad = TRUE;
1618 ucs2buf[0] = u8c;
1619 ucs2len = 1;
1620 }
1621 }
1622 else
1623# endif
1624 {
1625 /* We don't know how long the byte sequence is, try
1626 * from one to three bytes. */
1627 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1628 ++bytelen)
1629 {
1630 ucs2len = MultiByteToWideChar(codepage,
1631 MB_ERR_INVALID_CHARS,
1632 (LPCSTR)src, bytelen,
1633 ucs2buf, 3);
1634 if (ucs2len > 0)
1635 break;
1636 }
1637 if (ucs2len == 0)
1638 {
1639 /* If we have only one byte then it's probably an
1640 * incomplete byte sequence. Otherwise discard
1641 * one byte as a bad character. */
1642 if (size == 1)
1643 break;
1644 found_bad = TRUE;
1645 bytelen = 1;
1646 }
1647 }
1648
1649 if (!found_bad)
1650 {
1651 int i;
1652
1653 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1654 if (enc_utf8)
1655 {
1656 /* From UCS-2 to UTF-8. Cannot fail. */
1657 for (i = 0; i < ucs2len; ++i)
1658 dst += utf_char2bytes(ucs2buf[i], dst);
1659 }
1660 else
1661 {
1662 BOOL bad = FALSE;
1663 int dstlen;
1664
1665 /* From UCS-2 to "enc_codepage". If the
1666 * conversion uses the default character "?",
1667 * the data doesn't fit in this encoding. */
1668 dstlen = WideCharToMultiByte(enc_codepage, 0,
1669 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001670 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001671 replstr, &bad);
1672 if (bad)
1673 found_bad = TRUE;
1674 else
1675 dst += dstlen;
1676 }
1677 }
1678
1679 if (found_bad)
1680 {
1681 /* Deal with bytes we can't convert. */
1682 if (can_retry)
1683 goto rewind_retry;
1684 if (conv_error == 0)
1685 conv_error = readfile_linenr(linecnt, ptr, dst);
1686 if (bad_char_behavior != BAD_DROP)
1687 {
1688 if (bad_char_behavior == BAD_KEEP)
1689 {
1690 mch_memmove(dst, src, bytelen);
1691 dst += bytelen;
1692 }
1693 else
1694 *dst++ = bad_char_behavior;
1695 }
1696 }
1697
1698 src += bytelen;
1699 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001701
1702 if (size > 0)
1703 {
1704 /* An incomplete byte sequence remaining. */
1705 mch_memmove(conv_rest, src, size);
1706 conv_restlen = size;
1707 }
1708
1709 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001710 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 }
1712 else
1713# endif
Bram Moolenaar56718732006-03-15 22:53:57 +00001714# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 if (fio_flags & FIO_MACROMAN)
1716 {
1717 /*
1718 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001719 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001721 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723 }
1724 else
1725# endif
1726 if (fio_flags != 0)
1727 {
1728 int u8c;
1729 char_u *dest;
1730 char_u *tail = NULL;
1731
1732 /*
1733 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1734 * "enc_utf8" not set: Convert Unicode to Latin1.
1735 * Go from end to start through the buffer, because the number
1736 * of bytes may increase.
1737 * "dest" points to after where the UTF-8 bytes go, "p" points
1738 * to after the next character to convert.
1739 */
1740 dest = ptr + real_size;
1741 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1742 {
1743 p = ptr + size;
1744 if (fio_flags == FIO_UTF8)
1745 {
1746 /* Check for a trailing incomplete UTF-8 sequence */
1747 tail = ptr + size - 1;
1748 while (tail > ptr && (*tail & 0xc0) == 0x80)
1749 --tail;
1750 if (tail + utf_byte2len(*tail) <= ptr + size)
1751 tail = NULL;
1752 else
1753 p = tail;
1754 }
1755 }
1756 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1757 {
1758 /* Check for a trailing byte */
1759 p = ptr + (size & ~1);
1760 if (size & 1)
1761 tail = p;
1762 if ((fio_flags & FIO_UTF16) && p > ptr)
1763 {
1764 /* Check for a trailing leading word */
1765 if (fio_flags & FIO_ENDIAN_L)
1766 {
1767 u8c = (*--p << 8);
1768 u8c += *--p;
1769 }
1770 else
1771 {
1772 u8c = *--p;
1773 u8c += (*--p << 8);
1774 }
1775 if (u8c >= 0xd800 && u8c <= 0xdbff)
1776 tail = p;
1777 else
1778 p += 2;
1779 }
1780 }
1781 else /* FIO_UCS4 */
1782 {
1783 /* Check for trailing 1, 2 or 3 bytes */
1784 p = ptr + (size & ~3);
1785 if (size & 3)
1786 tail = p;
1787 }
1788
1789 /* If there is a trailing incomplete sequence move it to
1790 * conv_rest[]. */
1791 if (tail != NULL)
1792 {
1793 conv_restlen = (int)((ptr + size) - tail);
1794 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1795 size -= conv_restlen;
1796 }
1797
1798
1799 while (p > ptr)
1800 {
1801 if (fio_flags & FIO_LATIN1)
1802 u8c = *--p;
1803 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1804 {
1805 if (fio_flags & FIO_ENDIAN_L)
1806 {
1807 u8c = (*--p << 8);
1808 u8c += *--p;
1809 }
1810 else
1811 {
1812 u8c = *--p;
1813 u8c += (*--p << 8);
1814 }
1815 if ((fio_flags & FIO_UTF16)
1816 && u8c >= 0xdc00 && u8c <= 0xdfff)
1817 {
1818 int u16c;
1819
1820 if (p == ptr)
1821 {
1822 /* Missing leading word. */
1823 if (can_retry)
1824 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001825 if (conv_error == 0)
1826 conv_error = readfile_linenr(linecnt,
1827 ptr, p);
1828 if (bad_char_behavior == BAD_DROP)
1829 continue;
1830 if (bad_char_behavior != BAD_KEEP)
1831 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 }
1833
1834 /* found second word of double-word, get the first
1835 * word and compute the resulting character */
1836 if (fio_flags & FIO_ENDIAN_L)
1837 {
1838 u16c = (*--p << 8);
1839 u16c += *--p;
1840 }
1841 else
1842 {
1843 u16c = *--p;
1844 u16c += (*--p << 8);
1845 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001846 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1847 + (u8c & 0x3ff);
1848
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 /* Check if the word is indeed a leading word. */
1850 if (u16c < 0xd800 || u16c > 0xdbff)
1851 {
1852 if (can_retry)
1853 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001854 if (conv_error == 0)
1855 conv_error = readfile_linenr(linecnt,
1856 ptr, p);
1857 if (bad_char_behavior == BAD_DROP)
1858 continue;
1859 if (bad_char_behavior != BAD_KEEP)
1860 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862 }
1863 }
1864 else if (fio_flags & FIO_UCS4)
1865 {
1866 if (fio_flags & FIO_ENDIAN_L)
1867 {
1868 u8c = (*--p << 24);
1869 u8c += (*--p << 16);
1870 u8c += (*--p << 8);
1871 u8c += *--p;
1872 }
1873 else /* big endian */
1874 {
1875 u8c = *--p;
1876 u8c += (*--p << 8);
1877 u8c += (*--p << 16);
1878 u8c += (*--p << 24);
1879 }
1880 }
1881 else /* UTF-8 */
1882 {
1883 if (*--p < 0x80)
1884 u8c = *p;
1885 else
1886 {
1887 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001888 p -= len;
1889 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 if (len == 0)
1891 {
1892 /* Not a valid UTF-8 character, retry with
1893 * another fenc when possible, otherwise just
1894 * report the error. */
1895 if (can_retry)
1896 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001897 if (conv_error == 0)
1898 conv_error = readfile_linenr(linecnt,
1899 ptr, p);
1900 if (bad_char_behavior == BAD_DROP)
1901 continue;
1902 if (bad_char_behavior != BAD_KEEP)
1903 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 }
1906 }
1907 if (enc_utf8) /* produce UTF-8 */
1908 {
1909 dest -= utf_char2len(u8c);
1910 (void)utf_char2bytes(u8c, dest);
1911 }
1912 else /* produce Latin1 */
1913 {
1914 --dest;
1915 if (u8c >= 0x100)
1916 {
1917 /* character doesn't fit in latin1, retry with
1918 * another fenc when possible, otherwise just
1919 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001920 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001922 if (conv_error == 0)
1923 conv_error = readfile_linenr(linecnt, ptr, p);
1924 if (bad_char_behavior == BAD_DROP)
1925 ++dest;
1926 else if (bad_char_behavior == BAD_KEEP)
1927 *dest = u8c;
1928 else if (eap != NULL && eap->bad_char != 0)
1929 *dest = bad_char_behavior;
1930 else
1931 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 else
1934 *dest = u8c;
1935 }
1936 }
1937
1938 /* move the linerest to before the converted characters */
1939 line_start = dest - linerest;
1940 mch_memmove(line_start, buffer, (size_t)linerest);
1941 size = (long)((ptr + real_size) - dest);
1942 ptr = dest;
1943 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001944 else if (enc_utf8 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001946 int incomplete_tail = FALSE;
1947
1948 /* Reading UTF-8: Check if the bytes are valid UTF-8. */
1949 for (p = ptr; ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001951 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001952 int l;
1953
1954 if (todo <= 0)
1955 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 if (*p >= 0x80)
1957 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 /* A length of 1 means it's an illegal byte. Accept
1959 * an incomplete character at the end though, the next
1960 * read() will get the next bytes, we'll check it
1961 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001962 l = utf_ptr2len_len(p, todo);
Bram Moolenaarf453d352008-06-04 17:37:34 +00001963 if (l > todo && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001965 /* Avoid retrying with a different encoding when
1966 * a truncated file is more likely, or attempting
1967 * to read the rest of an incomplete sequence when
1968 * we have already done so. */
1969 if (p > ptr || filesize > 0)
1970 incomplete_tail = TRUE;
1971 /* Incomplete byte sequence, move it to conv_rest[]
1972 * and try to read the rest of it, unless we've
1973 * already done so. */
1974 if (p > ptr)
1975 {
1976 conv_restlen = todo;
1977 mch_memmove(conv_rest, p, conv_restlen);
1978 size -= conv_restlen;
1979 break;
1980 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001981 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001982 if (l == 1 || l > todo)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001983 {
1984 /* Illegal byte. If we can try another encoding
Bram Moolenaarf453d352008-06-04 17:37:34 +00001985 * do that, unless at EOF where a truncated
1986 * file is more likely than a conversion error. */
1987 if (can_retry && !incomplete_tail)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001988 break;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001989# ifdef USE_ICONV
1990 /* When we did a conversion report an error. */
1991 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
1992 conv_error = readfile_linenr(linecnt, ptr, p);
1993# endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00001994 /* Remember the first linenr with an illegal byte */
1995 if (conv_error == 0 && illegal_byte == 0)
1996 illegal_byte = readfile_linenr(linecnt, ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001997
1998 /* Drop, keep or replace the bad byte. */
1999 if (bad_char_behavior == BAD_DROP)
2000 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002001 mch_memmove(p, p + 1, todo - 1);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002002 --p;
2003 --size;
2004 }
2005 else if (bad_char_behavior != BAD_KEEP)
2006 *p = bad_char_behavior;
2007 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002008 else
2009 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002010 }
2011 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002012 if (p < ptr + size && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013 {
2014 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002015rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002016 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002018 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
2019 /* iconv() failed, try 'charconvert' */
2020 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021 else
2022# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002023 /* use next item from 'fileencodings' */
2024 advance_fenc = TRUE;
2025 file_rewind = TRUE;
2026 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 }
2028 }
2029#endif
2030
2031 /* count the number of characters (after conversion!) */
2032 filesize += size;
2033
2034 /*
2035 * when reading the first part of a file: guess EOL type
2036 */
2037 if (fileformat == EOL_UNKNOWN)
2038 {
2039 /* First try finding a NL, for Dos and Unix */
2040 if (try_dos || try_unix)
2041 {
2042 for (p = ptr; p < ptr + size; ++p)
2043 {
2044 if (*p == NL)
2045 {
2046 if (!try_unix
2047 || (try_dos && p > ptr && p[-1] == CAR))
2048 fileformat = EOL_DOS;
2049 else
2050 fileformat = EOL_UNIX;
2051 break;
2052 }
2053 }
2054
2055 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
2056 if (fileformat == EOL_UNIX && try_mac)
2057 {
2058 /* Need to reset the counters when retrying fenc. */
2059 try_mac = 1;
2060 try_unix = 1;
2061 for (; p >= ptr && *p != CAR; p--)
2062 ;
2063 if (p >= ptr)
2064 {
2065 for (p = ptr; p < ptr + size; ++p)
2066 {
2067 if (*p == NL)
2068 try_unix++;
2069 else if (*p == CAR)
2070 try_mac++;
2071 }
2072 if (try_mac > try_unix)
2073 fileformat = EOL_MAC;
2074 }
2075 }
2076 }
2077
2078 /* No NL found: may use Mac format */
2079 if (fileformat == EOL_UNKNOWN && try_mac)
2080 fileformat = EOL_MAC;
2081
2082 /* Still nothing found? Use first format in 'ffs' */
2083 if (fileformat == EOL_UNKNOWN)
2084 fileformat = default_fileformat();
2085
2086 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002087 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 set_fileformat(fileformat, OPT_LOCAL);
2089 }
2090 }
2091
2092 /*
2093 * This loop is executed once for every character read.
2094 * Keep it fast!
2095 */
2096 if (fileformat == EOL_MAC)
2097 {
2098 --ptr;
2099 while (++ptr, --size >= 0)
2100 {
2101 /* catch most common case first */
2102 if ((c = *ptr) != NUL && c != CAR && c != NL)
2103 continue;
2104 if (c == NUL)
2105 *ptr = NL; /* NULs are replaced by newlines! */
2106 else if (c == NL)
2107 *ptr = CAR; /* NLs are replaced by CRs! */
2108 else
2109 {
2110 if (skip_count == 0)
2111 {
2112 *ptr = NUL; /* end of line */
2113 len = (colnr_T) (ptr - line_start + 1);
2114 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2115 {
2116 error = TRUE;
2117 break;
2118 }
2119 ++lnum;
2120 if (--read_count == 0)
2121 {
2122 error = TRUE; /* break loop */
2123 line_start = ptr; /* nothing left to write */
2124 break;
2125 }
2126 }
2127 else
2128 --skip_count;
2129 line_start = ptr + 1;
2130 }
2131 }
2132 }
2133 else
2134 {
2135 --ptr;
2136 while (++ptr, --size >= 0)
2137 {
2138 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2139 continue;
2140 if (c == NUL)
2141 *ptr = NL; /* NULs are replaced by newlines! */
2142 else
2143 {
2144 if (skip_count == 0)
2145 {
2146 *ptr = NUL; /* end of line */
2147 len = (colnr_T)(ptr - line_start + 1);
2148 if (fileformat == EOL_DOS)
2149 {
2150 if (ptr[-1] == CAR) /* remove CR */
2151 {
2152 ptr[-1] = NUL;
2153 --len;
2154 }
2155 /*
2156 * Reading in Dos format, but no CR-LF found!
2157 * When 'fileformats' includes "unix", delete all
2158 * the lines read so far and start all over again.
2159 * Otherwise give an error message later.
2160 */
2161 else if (ff_error != EOL_DOS)
2162 {
2163 if ( try_unix
2164 && !read_stdin
2165 && (read_buffer
2166 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2167 {
2168 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002169 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 set_fileformat(EOL_UNIX, OPT_LOCAL);
2171 file_rewind = TRUE;
2172 keep_fileformat = TRUE;
2173 goto retry;
2174 }
2175 ff_error = EOL_DOS;
2176 }
2177 }
2178 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2179 {
2180 error = TRUE;
2181 break;
2182 }
2183 ++lnum;
2184 if (--read_count == 0)
2185 {
2186 error = TRUE; /* break loop */
2187 line_start = ptr; /* nothing left to write */
2188 break;
2189 }
2190 }
2191 else
2192 --skip_count;
2193 line_start = ptr + 1;
2194 }
2195 }
2196 }
2197 linerest = (long)(ptr - line_start);
2198 ui_breakcheck();
2199 }
2200
2201failed:
2202 /* not an error, max. number of lines reached */
2203 if (error && read_count == 0)
2204 error = FALSE;
2205
2206 /*
2207 * If we get EOF in the middle of a line, note the fact and
2208 * complete the line ourselves.
2209 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2210 */
2211 if (!error
2212 && !got_int
2213 && linerest != 0
2214 && !(!curbuf->b_p_bin
2215 && fileformat == EOL_DOS
2216 && *line_start == Ctrl_Z
2217 && ptr == line_start + 1))
2218 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002219 /* remember for when writing */
2220 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 curbuf->b_p_eol = FALSE;
2222 *ptr = NUL;
2223 if (ml_append(lnum, line_start,
2224 (colnr_T)(ptr - line_start + 1), newfile) == FAIL)
2225 error = TRUE;
2226 else
2227 read_no_eol_lnum = ++lnum;
2228 }
2229
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002230 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 save_file_ff(curbuf); /* remember the current file format */
2232
2233#ifdef FEAT_CRYPT
2234 if (cryptkey != curbuf->b_p_key)
2235 vim_free(cryptkey);
2236#endif
2237
2238#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002239 /* If editing a new file: set 'fenc' for the current buffer.
2240 * Also for ":read ++edit file". */
2241 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002243 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 if (fenc_alloced)
2245 vim_free(fenc);
2246# ifdef USE_ICONV
2247 if (iconv_fd != (iconv_t)-1)
2248 {
2249 iconv_close(iconv_fd);
2250 iconv_fd = (iconv_t)-1;
2251 }
2252# endif
2253#endif
2254
2255 if (!read_buffer && !read_stdin)
2256 close(fd); /* errors are ignored */
2257 vim_free(buffer);
2258
2259#ifdef HAVE_DUP
2260 if (read_stdin)
2261 {
2262 /* Use stderr for stdin, makes shell commands work. */
2263 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002264 ignored = dup(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 }
2266#endif
2267
2268#ifdef FEAT_MBYTE
2269 if (tmpname != NULL)
2270 {
2271 mch_remove(tmpname); /* delete converted file */
2272 vim_free(tmpname);
2273 }
2274#endif
2275 --no_wait_return; /* may wait for return now */
2276
2277 /*
2278 * In recovery mode everything but autocommands is skipped.
2279 */
2280 if (!recoverymode)
2281 {
2282 /* need to delete the last line, which comes from the empty buffer */
2283 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2284 {
2285#ifdef FEAT_NETBEANS_INTG
2286 netbeansFireChanges = 0;
2287#endif
2288 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2289#ifdef FEAT_NETBEANS_INTG
2290 netbeansFireChanges = 1;
2291#endif
2292 --linecnt;
2293 }
2294 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2295 if (filesize == 0)
2296 linecnt = 0;
2297 if (newfile || read_buffer)
Bram Moolenaar7263a772007-05-10 17:35:54 +00002298 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 redraw_curbuf_later(NOT_VALID);
Bram Moolenaar7263a772007-05-10 17:35:54 +00002300#ifdef FEAT_DIFF
2301 /* After reading the text into the buffer the diff info needs to
2302 * be updated. */
2303 diff_invalidate(curbuf);
2304#endif
2305#ifdef FEAT_FOLDING
2306 /* All folds in the window are invalid now. Mark them for update
2307 * before triggering autocommands. */
2308 foldUpdateAll(curwin);
2309#endif
2310 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 else if (linecnt) /* appended at least one line */
2312 appended_lines_mark(from, linecnt);
2313
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314#ifndef ALWAYS_USE_GUI
2315 /*
2316 * If we were reading from the same terminal as where messages go,
2317 * the screen will have been messed up.
2318 * Switch on raw mode now and clear the screen.
2319 */
2320 if (read_stdin)
2321 {
2322 settmode(TMODE_RAW); /* set to raw mode */
2323 starttermcap();
2324 screenclear();
2325 }
2326#endif
2327
2328 if (got_int)
2329 {
2330 if (!(flags & READ_DUMMY))
2331 {
2332 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2333 if (newfile)
2334 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2335 }
2336 msg_scroll = msg_save;
2337#ifdef FEAT_VIMINFO
2338 check_marks_read();
2339#endif
2340 return OK; /* an interrupt isn't really an error */
2341 }
2342
2343 if (!filtering && !(flags & READ_DUMMY))
2344 {
2345 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2346 c = FALSE;
2347
2348#ifdef UNIX
2349# ifdef S_ISFIFO
2350 if (S_ISFIFO(perm)) /* fifo or socket */
2351 {
2352 STRCAT(IObuff, _("[fifo/socket]"));
2353 c = TRUE;
2354 }
2355# else
2356# ifdef S_IFIFO
2357 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2358 {
2359 STRCAT(IObuff, _("[fifo]"));
2360 c = TRUE;
2361 }
2362# endif
2363# ifdef S_IFSOCK
2364 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2365 {
2366 STRCAT(IObuff, _("[socket]"));
2367 c = TRUE;
2368 }
2369# endif
2370# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002371# ifdef OPEN_CHR_FILES
2372 if (S_ISCHR(perm)) /* or character special */
2373 {
2374 STRCAT(IObuff, _("[character special]"));
2375 c = TRUE;
2376 }
2377# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378#endif
2379 if (curbuf->b_p_ro)
2380 {
2381 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2382 c = TRUE;
2383 }
2384 if (read_no_eol_lnum)
2385 {
2386 msg_add_eol();
2387 c = TRUE;
2388 }
2389 if (ff_error == EOL_DOS)
2390 {
2391 STRCAT(IObuff, _("[CR missing]"));
2392 c = TRUE;
2393 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 if (split)
2395 {
2396 STRCAT(IObuff, _("[long lines split]"));
2397 c = TRUE;
2398 }
2399#ifdef FEAT_MBYTE
2400 if (notconverted)
2401 {
2402 STRCAT(IObuff, _("[NOT converted]"));
2403 c = TRUE;
2404 }
2405 else if (converted)
2406 {
2407 STRCAT(IObuff, _("[converted]"));
2408 c = TRUE;
2409 }
2410#endif
2411#ifdef FEAT_CRYPT
2412 if (cryptkey != NULL)
2413 {
2414 STRCAT(IObuff, _("[crypted]"));
2415 c = TRUE;
2416 }
2417#endif
2418#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002419 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002421 sprintf((char *)IObuff + STRLEN(IObuff),
2422 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423 c = TRUE;
2424 }
2425 else if (illegal_byte > 0)
2426 {
2427 sprintf((char *)IObuff + STRLEN(IObuff),
2428 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2429 c = TRUE;
2430 }
2431 else
2432#endif
2433 if (error)
2434 {
2435 STRCAT(IObuff, _("[READ ERRORS]"));
2436 c = TRUE;
2437 }
2438 if (msg_add_fileformat(fileformat))
2439 c = TRUE;
2440#ifdef FEAT_CRYPT
2441 if (cryptkey != NULL)
2442 msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
2443 else
2444#endif
2445 msg_add_lines(c, (long)linecnt, filesize);
2446
2447 vim_free(keep_msg);
2448 keep_msg = NULL;
2449 msg_scrolled_ign = TRUE;
2450#ifdef ALWAYS_USE_GUI
2451 /* Don't show the message when reading stdin, it would end up in a
2452 * message box (which might be shown when exiting!) */
2453 if (read_stdin || read_buffer)
2454 p = msg_may_trunc(FALSE, IObuff);
2455 else
2456#endif
2457 p = msg_trunc_attr(IObuff, FALSE, 0);
2458 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002459 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 /* Need to repeat the message after redrawing when:
2461 * - When reading from stdin (the screen will be cleared next).
2462 * - When restart_edit is set (otherwise there will be a delay
2463 * before redrawing).
2464 * - When the screen was scrolled but there is no wait-return
2465 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002466 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 msg_scrolled_ign = FALSE;
2468 }
2469
2470 /* with errors writing the file requires ":w!" */
2471 if (newfile && (error
2472#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002473 || conv_error != 0
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002474 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475#endif
2476 ))
2477 curbuf->b_p_ro = TRUE;
2478
2479 u_clearline(); /* cannot use "U" command after adding lines */
2480
2481 /*
2482 * In Ex mode: cursor at last new line.
2483 * Otherwise: cursor at first new line.
2484 */
2485 if (exmode_active)
2486 curwin->w_cursor.lnum = from + linecnt;
2487 else
2488 curwin->w_cursor.lnum = from + 1;
2489 check_cursor_lnum();
2490 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2491
2492 /*
2493 * Set '[ and '] marks to the newly read lines.
2494 */
2495 curbuf->b_op_start.lnum = from + 1;
2496 curbuf->b_op_start.col = 0;
2497 curbuf->b_op_end.lnum = from + linecnt;
2498 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002499
2500#ifdef WIN32
2501 /*
2502 * Work around a weird problem: When a file has two links (only
2503 * possible on NTFS) and we write through one link, then stat() it
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00002504 * through the other link, the timestamp information may be wrong.
Bram Moolenaar03f48552006-02-28 23:52:23 +00002505 * It's correct again after reading the file, thus reset the timestamp
2506 * here.
2507 */
2508 if (newfile && !read_stdin && !read_buffer
2509 && mch_stat((char *)fname, &st) >= 0)
2510 {
2511 buf_store_time(curbuf, &st, fname);
2512 curbuf->b_mtime_read = curbuf->b_mtime;
2513 }
2514#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 }
2516 msg_scroll = msg_save;
2517
2518#ifdef FEAT_VIMINFO
2519 /*
2520 * Get the marks before executing autocommands, so they can be used there.
2521 */
2522 check_marks_read();
2523#endif
2524
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 /*
2526 * Trick: We remember if the last line of the read didn't have
2527 * an eol for when writing it again. This is required for
2528 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2529 */
2530 write_no_eol_lnum = read_no_eol_lnum;
2531
Bram Moolenaardf177f62005-02-22 08:39:57 +00002532#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 if (!read_stdin && !read_buffer)
2534 {
2535 int m = msg_scroll;
2536 int n = msg_scrolled;
2537
2538 /* Save the fileformat now, otherwise the buffer will be considered
2539 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002540 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 save_file_ff(curbuf);
2542
2543 /*
2544 * The output from the autocommands should not overwrite anything and
2545 * should not be overwritten: Set msg_scroll, restore its value if no
2546 * output was done.
2547 */
2548 msg_scroll = TRUE;
2549 if (filtering)
2550 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2551 FALSE, curbuf, eap);
2552 else if (newfile)
2553 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2554 FALSE, curbuf, eap);
2555 else
2556 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2557 FALSE, NULL, eap);
2558 if (msg_scrolled == n)
2559 msg_scroll = m;
2560#ifdef FEAT_EVAL
2561 if (aborting()) /* autocmds may abort script processing */
2562 return FAIL;
2563#endif
2564 }
2565#endif
2566
2567 if (recoverymode && error)
2568 return FAIL;
2569 return OK;
2570}
2571
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002572#ifdef OPEN_CHR_FILES
2573/*
2574 * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
2575 * which is the name of files used for process substitution output by
2576 * some shells on some operating systems, e.g., bash on SunOS.
2577 * Do not accept "/dev/fd/[012]", opening these may hang Vim.
2578 */
2579 static int
2580is_dev_fd_file(fname)
2581 char_u *fname;
2582{
2583 return (STRNCMP(fname, "/dev/fd/", 8) == 0
2584 && VIM_ISDIGIT(fname[8])
2585 && *skipdigits(fname + 9) == NUL
2586 && (fname[9] != NUL
2587 || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
2588}
2589#endif
2590
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002591#ifdef FEAT_MBYTE
2592
2593/*
2594 * From the current line count and characters read after that, estimate the
2595 * line number where we are now.
2596 * Used for error messages that include a line number.
2597 */
2598 static linenr_T
2599readfile_linenr(linecnt, p, endp)
2600 linenr_T linecnt; /* line count before reading more bytes */
2601 char_u *p; /* start of more bytes read */
2602 char_u *endp; /* end of more bytes read */
2603{
2604 char_u *s;
2605 linenr_T lnum;
2606
2607 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2608 for (s = p; s < endp; ++s)
2609 if (*s == '\n')
2610 ++lnum;
2611 return lnum;
2612}
2613#endif
2614
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002616 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2617 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 * Returns OK or FAIL.
2619 */
2620 int
2621prep_exarg(eap, buf)
2622 exarg_T *eap;
2623 buf_T *buf;
2624{
2625 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2626#ifdef FEAT_MBYTE
2627 + STRLEN(buf->b_p_fenc)
2628#endif
2629 + 15));
2630 if (eap->cmd == NULL)
2631 return FAIL;
2632
2633#ifdef FEAT_MBYTE
2634 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2635 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002636 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637#else
2638 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2639#endif
2640 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002641
2642 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002643 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002644 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 return OK;
2646}
2647
2648#ifdef FEAT_MBYTE
2649/*
2650 * Find next fileencoding to use from 'fileencodings'.
2651 * "pp" points to fenc_next. It's advanced to the next item.
2652 * When there are no more items, an empty string is returned and *pp is set to
2653 * NULL.
2654 * When *pp is not set to NULL, the result is in allocated memory.
2655 */
2656 static char_u *
2657next_fenc(pp)
2658 char_u **pp;
2659{
2660 char_u *p;
2661 char_u *r;
2662
2663 if (**pp == NUL)
2664 {
2665 *pp = NULL;
2666 return (char_u *)"";
2667 }
2668 p = vim_strchr(*pp, ',');
2669 if (p == NULL)
2670 {
2671 r = enc_canonize(*pp);
2672 *pp += STRLEN(*pp);
2673 }
2674 else
2675 {
2676 r = vim_strnsave(*pp, (int)(p - *pp));
2677 *pp = p + 1;
2678 if (r != NULL)
2679 {
2680 p = enc_canonize(r);
2681 vim_free(r);
2682 r = p;
2683 }
2684 }
2685 if (r == NULL) /* out of memory */
2686 {
2687 r = (char_u *)"";
2688 *pp = NULL;
2689 }
2690 return r;
2691}
2692
2693# ifdef FEAT_EVAL
2694/*
2695 * Convert a file with the 'charconvert' expression.
2696 * This closes the file which is to be read, converts it and opens the
2697 * resulting file for reading.
2698 * Returns name of the resulting converted file (the caller should delete it
2699 * after reading it).
2700 * Returns NULL if the conversion failed ("*fdp" is not set) .
2701 */
2702 static char_u *
2703readfile_charconvert(fname, fenc, fdp)
2704 char_u *fname; /* name of input file */
2705 char_u *fenc; /* converted from */
2706 int *fdp; /* in/out: file descriptor of file */
2707{
2708 char_u *tmpname;
2709 char_u *errmsg = NULL;
2710
2711 tmpname = vim_tempname('r');
2712 if (tmpname == NULL)
2713 errmsg = (char_u *)_("Can't find temp file for conversion");
2714 else
2715 {
2716 close(*fdp); /* close the input file, ignore errors */
2717 *fdp = -1;
2718 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2719 fname, tmpname) == FAIL)
2720 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2721 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2722 O_RDONLY | O_EXTRA, 0)) < 0)
2723 errmsg = (char_u *)_("can't read output of 'charconvert'");
2724 }
2725
2726 if (errmsg != NULL)
2727 {
2728 /* Don't use emsg(), it breaks mappings, the retry with
2729 * another type of conversion might still work. */
2730 MSG(errmsg);
2731 if (tmpname != NULL)
2732 {
2733 mch_remove(tmpname); /* delete converted file */
2734 vim_free(tmpname);
2735 tmpname = NULL;
2736 }
2737 }
2738
2739 /* If the input file is closed, open it (caller should check for error). */
2740 if (*fdp < 0)
2741 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2742
2743 return tmpname;
2744}
2745# endif
2746
2747#endif
2748
2749#ifdef FEAT_VIMINFO
2750/*
2751 * Read marks for the current buffer from the viminfo file, when we support
2752 * buffer marks and the buffer has a name.
2753 */
2754 static void
2755check_marks_read()
2756{
2757 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2758 && curbuf->b_ffname != NULL)
Bram Moolenaard812df62008-11-09 12:46:09 +00002759 read_viminfo(NULL, VIF_WANT_MARKS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760
2761 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2762 * the ' parameter after opening a buffer. */
2763 curbuf->b_marks_read = TRUE;
2764}
2765#endif
2766
2767#ifdef FEAT_CRYPT
2768/*
2769 * Check for magic number used for encryption.
2770 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2771 * *filesizep are updated.
2772 * Return the (new) encryption key, NULL for no encryption.
2773 */
2774 static char_u *
2775check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile)
2776 char_u *cryptkey; /* previous encryption key or NULL */
2777 char_u *ptr; /* pointer to read bytes */
2778 long *sizep; /* length of read bytes */
2779 long *filesizep; /* nr of bytes used from file */
2780 int newfile; /* editing a new buffer */
2781{
2782 if (*sizep >= CRYPT_MAGIC_LEN
2783 && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
2784 {
2785 if (cryptkey == NULL)
2786 {
2787 if (*curbuf->b_p_key)
2788 cryptkey = curbuf->b_p_key;
2789 else
2790 {
2791 /* When newfile is TRUE, store the typed key
2792 * in the 'key' option and don't free it. */
2793 cryptkey = get_crypt_key(newfile, FALSE);
2794 /* check if empty key entered */
2795 if (cryptkey != NULL && *cryptkey == NUL)
2796 {
2797 if (cryptkey != curbuf->b_p_key)
2798 vim_free(cryptkey);
2799 cryptkey = NULL;
2800 }
2801 }
2802 }
2803
2804 if (cryptkey != NULL)
2805 {
2806 crypt_init_keys(cryptkey);
2807
2808 /* Remove magic number from the text */
2809 *filesizep += CRYPT_MAGIC_LEN;
2810 *sizep -= CRYPT_MAGIC_LEN;
2811 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
2812 }
2813 }
2814 /* When starting to edit a new file which does not have
2815 * encryption, clear the 'key' option, except when
2816 * starting up (called with -x argument) */
2817 else if (newfile && *curbuf->b_p_key && !starting)
2818 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2819
2820 return cryptkey;
2821}
2822#endif
2823
2824#ifdef UNIX
2825 static void
2826set_file_time(fname, atime, mtime)
2827 char_u *fname;
2828 time_t atime; /* access time */
2829 time_t mtime; /* modification time */
2830{
2831# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2832 struct utimbuf buf;
2833
2834 buf.actime = atime;
2835 buf.modtime = mtime;
2836 (void)utime((char *)fname, &buf);
2837# else
2838# if defined(HAVE_UTIMES)
2839 struct timeval tvp[2];
2840
2841 tvp[0].tv_sec = atime;
2842 tvp[0].tv_usec = 0;
2843 tvp[1].tv_sec = mtime;
2844 tvp[1].tv_usec = 0;
2845# ifdef NeXT
2846 (void)utimes((char *)fname, tvp);
2847# else
2848 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2849# endif
2850# endif
2851# endif
2852}
2853#endif /* UNIX */
2854
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002855#if defined(VMS) && !defined(MIN)
2856/* Older DECC compiler for VAX doesn't define MIN() */
2857# define MIN(a, b) ((a) < (b) ? (a) : (b))
2858#endif
2859
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00002861 * Return TRUE if a file appears to be read-only from the file permissions.
2862 */
2863 int
2864check_file_readonly(fname, perm)
2865 char_u *fname; /* full path to file */
2866 int perm; /* known permissions on file */
2867{
2868#ifndef USE_MCH_ACCESS
2869 int fd = 0;
2870#endif
2871
2872 return (
2873#ifdef USE_MCH_ACCESS
2874# ifdef UNIX
2875 (perm & 0222) == 0 ||
2876# endif
2877 mch_access((char *)fname, W_OK)
2878#else
2879 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
2880 ? TRUE : (close(fd), FALSE)
2881#endif
2882 );
2883}
2884
2885
2886/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00002887 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 *
2889 * We do our own buffering here because fwrite() is so slow.
2890 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00002891 * If "forceit" is true, we don't care for errors when attempting backups.
2892 * In case of an error everything possible is done to restore the original
Bram Moolenaare37d50a2008-08-06 17:06:04 +00002893 * file. But when "forceit" is TRUE, we risk losing it.
Bram Moolenaar292ad192005-12-11 21:29:51 +00002894 *
2895 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
2896 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 *
2898 * This function must NOT use NameBuff (because it's called by autowrite()).
2899 *
2900 * return FAIL for failure, OK otherwise
2901 */
2902 int
2903buf_write(buf, fname, sfname, start, end, eap, append, forceit,
2904 reset_changed, filtering)
2905 buf_T *buf;
2906 char_u *fname;
2907 char_u *sfname;
2908 linenr_T start, end;
2909 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
2910 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00002911 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 int forceit;
2913 int reset_changed;
2914 int filtering;
2915{
2916 int fd;
2917 char_u *backup = NULL;
2918 int backup_copy = FALSE; /* copy the original file? */
2919 int dobackup;
2920 char_u *ffname;
2921 char_u *wfname = NULL; /* name of file to write to */
2922 char_u *s;
2923 char_u *ptr;
2924 char_u c;
2925 int len;
2926 linenr_T lnum;
2927 long nchars;
2928 char_u *errmsg = NULL;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00002929 int errmsg_allocated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930 char_u *errnum = NULL;
2931 char_u *buffer;
2932 char_u smallbuf[SMBUFSIZE];
2933 char_u *backup_ext;
2934 int bufsize;
2935 long perm; /* file permissions */
2936 int retval = OK;
2937 int newfile = FALSE; /* TRUE if file doesn't exist yet */
2938 int msg_save = msg_scroll;
2939 int overwriting; /* TRUE if writing over original */
2940 int no_eol = FALSE; /* no end-of-line written */
2941 int device = FALSE; /* writing to a device */
2942 struct stat st_old;
2943 int prev_got_int = got_int;
2944 int file_readonly = FALSE; /* overwritten file is read-only */
2945 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
2946#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
2947 int made_writable = FALSE; /* 'w' bit has been set */
2948#endif
2949 /* writing everything */
2950 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
2951#ifdef FEAT_AUTOCMD
2952 linenr_T old_line_count = buf->b_ml.ml_line_count;
2953#endif
2954 int attr;
2955 int fileformat;
2956 int write_bin;
2957 struct bw_info write_info; /* info for buf_write_bytes() */
2958#ifdef FEAT_MBYTE
2959 int converted = FALSE;
2960 int notconverted = FALSE;
2961 char_u *fenc; /* effective 'fileencoding' */
2962 char_u *fenc_tofree = NULL; /* allocated "fenc" */
2963#endif
2964#ifdef HAS_BW_FLAGS
2965 int wb_flags = 0;
2966#endif
2967#ifdef HAVE_ACL
2968 vim_acl_T acl = NULL; /* ACL copied from original file to
2969 backup or new file */
2970#endif
2971
2972 if (fname == NULL || *fname == NUL) /* safety check */
2973 return FAIL;
2974
2975 /*
2976 * Disallow writing from .exrc and .vimrc in current directory for
2977 * security reasons.
2978 */
2979 if (check_secure())
2980 return FAIL;
2981
2982 /* Avoid a crash for a long name. */
2983 if (STRLEN(fname) >= MAXPATHL)
2984 {
2985 EMSG(_(e_longname));
2986 return FAIL;
2987 }
2988
2989#ifdef FEAT_MBYTE
2990 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
2991 write_info.bw_conv_buf = NULL;
2992 write_info.bw_conv_error = FALSE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00002993 write_info.bw_conv_error_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994 write_info.bw_restlen = 0;
2995# ifdef USE_ICONV
2996 write_info.bw_iconv_fd = (iconv_t)-1;
2997# endif
2998#endif
2999
Bram Moolenaardf177f62005-02-22 08:39:57 +00003000 /* After writing a file changedtick changes but we don't want to display
3001 * the line. */
3002 ex_no_reprint = TRUE;
3003
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 /*
3005 * If there is no file name yet, use the one for the written file.
3006 * BF_NOTEDITED is set to reflect this (in case the write fails).
3007 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003008 * Don't do this when appending.
3009 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003011 if (buf->b_ffname == NULL
3012 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 && whole
3014 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003015#ifdef FEAT_QUICKFIX
3016 && !bt_nofile(buf)
3017#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00003019 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
3021 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003022 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003024 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 }
3026
3027 if (sfname == NULL)
3028 sfname = fname;
3029 /*
3030 * For Unix: Use the short file name whenever possible.
3031 * Avoids problems with networks and when directory names are changed.
3032 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
3033 * another directory, which we don't detect
3034 */
3035 ffname = fname; /* remember full fname */
3036#ifdef UNIX
3037 fname = sfname;
3038#endif
3039
3040 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
3041 overwriting = TRUE;
3042 else
3043 overwriting = FALSE;
3044
3045 if (exiting)
3046 settmode(TMODE_COOK); /* when exiting allow typahead now */
3047
3048 ++no_wait_return; /* don't wait for return yet */
3049
3050 /*
3051 * Set '[ and '] marks to the lines to be written.
3052 */
3053 buf->b_op_start.lnum = start;
3054 buf->b_op_start.col = 0;
3055 buf->b_op_end.lnum = end;
3056 buf->b_op_end.col = 0;
3057
3058#ifdef FEAT_AUTOCMD
3059 {
3060 aco_save_T aco;
3061 int buf_ffname = FALSE;
3062 int buf_sfname = FALSE;
3063 int buf_fname_f = FALSE;
3064 int buf_fname_s = FALSE;
3065 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003066 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003067 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068
3069 /*
3070 * Apply PRE aucocommands.
3071 * Set curbuf to the buffer to be written.
3072 * Careful: The autocommands may call buf_write() recursively!
3073 */
3074 if (ffname == buf->b_ffname)
3075 buf_ffname = TRUE;
3076 if (sfname == buf->b_sfname)
3077 buf_sfname = TRUE;
3078 if (fname == buf->b_ffname)
3079 buf_fname_f = TRUE;
3080 if (fname == buf->b_sfname)
3081 buf_fname_s = TRUE;
3082
3083 /* set curwin/curbuf to buf and save a few things */
3084 aucmd_prepbuf(&aco, buf);
3085
3086 if (append)
3087 {
3088 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
3089 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003090 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003091#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00003092 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003093 nofile_err = TRUE;
3094 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003095#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003096 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003098 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 }
3100 else if (filtering)
3101 {
3102 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
3103 NULL, sfname, FALSE, curbuf, eap);
3104 }
3105 else if (reset_changed && whole)
3106 {
3107 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
3108 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003109 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003110#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003111 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003112 nofile_err = TRUE;
3113 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003114#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003115 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003117 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118 }
3119 else
3120 {
3121 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
3122 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003123 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003124#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003125 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003126 nofile_err = TRUE;
3127 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003128#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003129 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003131 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 }
3133
3134 /* restore curwin/curbuf and a few other things */
3135 aucmd_restbuf(&aco);
3136
3137 /*
3138 * In three situations we return here and don't write the file:
3139 * 1. the autocommands deleted or unloaded the buffer.
3140 * 2. The autocommands abort script processing.
3141 * 3. If one of the "Cmd" autocommands was executed.
3142 */
3143 if (!buf_valid(buf))
3144 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003145 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00003146 || did_cmd || nofile_err
3147#ifdef FEAT_EVAL
3148 || aborting()
3149#endif
3150 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151 {
3152 --no_wait_return;
3153 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003154 if (nofile_err)
3155 EMSG(_("E676: No matching autocommands for acwrite buffer"));
3156
Bram Moolenaar1e015462005-09-25 22:16:38 +00003157 if (nofile_err
3158#ifdef FEAT_EVAL
3159 || aborting()
3160#endif
3161 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162 /* An aborting error, interrupt or exception in the
3163 * autocommands. */
3164 return FAIL;
3165 if (did_cmd)
3166 {
3167 if (buf == NULL)
3168 /* The buffer was deleted. We assume it was written
3169 * (can't retry anyway). */
3170 return OK;
3171 if (overwriting)
3172 {
3173 /* Assume the buffer was written, update the timestamp. */
3174 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003175 if (append)
3176 buf->b_flags &= ~BF_NEW;
3177 else
3178 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003180 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003181 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 /* Buffer still changed, the autocommands didn't work
3183 * properly. */
3184 return FAIL;
3185 return OK;
3186 }
3187#ifdef FEAT_EVAL
3188 if (!aborting())
3189#endif
3190 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
3191 return FAIL;
3192 }
3193
3194 /*
3195 * The autocommands may have changed the number of lines in the file.
3196 * When writing the whole file, adjust the end.
3197 * When writing part of the file, assume that the autocommands only
3198 * changed the number of lines that are to be written (tricky!).
3199 */
3200 if (buf->b_ml.ml_line_count != old_line_count)
3201 {
3202 if (whole) /* write all */
3203 end = buf->b_ml.ml_line_count;
3204 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3205 end += buf->b_ml.ml_line_count - old_line_count;
3206 else /* less lines */
3207 {
3208 end -= old_line_count - buf->b_ml.ml_line_count;
3209 if (end < start)
3210 {
3211 --no_wait_return;
3212 msg_scroll = msg_save;
3213 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3214 return FAIL;
3215 }
3216 }
3217 }
3218
3219 /*
3220 * The autocommands may have changed the name of the buffer, which may
3221 * be kept in fname, ffname and sfname.
3222 */
3223 if (buf_ffname)
3224 ffname = buf->b_ffname;
3225 if (buf_sfname)
3226 sfname = buf->b_sfname;
3227 if (buf_fname_f)
3228 fname = buf->b_ffname;
3229 if (buf_fname_s)
3230 fname = buf->b_sfname;
3231 }
3232#endif
3233
3234#ifdef FEAT_NETBEANS_INTG
3235 if (usingNetbeans && isNetbeansBuffer(buf))
3236 {
3237 if (whole)
3238 {
3239 /*
3240 * b_changed can be 0 after an undo, but we still need to write
3241 * the buffer to NetBeans.
3242 */
3243 if (buf->b_changed || isNetbeansModified(buf))
3244 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003245 --no_wait_return; /* may wait for return now */
3246 msg_scroll = msg_save;
3247 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248 return retval;
3249 }
3250 else
3251 {
3252 errnum = (char_u *)"E656: ";
Bram Moolenaared0e7452008-06-27 19:17:34 +00003253 errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 buffer = NULL;
3255 goto fail;
3256 }
3257 }
3258 else
3259 {
3260 errnum = (char_u *)"E657: ";
3261 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3262 buffer = NULL;
3263 goto fail;
3264 }
3265 }
3266#endif
3267
3268 if (shortmess(SHM_OVER) && !exiting)
3269 msg_scroll = FALSE; /* overwrite previous file message */
3270 else
3271 msg_scroll = TRUE; /* don't overwrite previous file message */
3272 if (!filtering)
3273 filemess(buf,
3274#ifndef UNIX
3275 sfname,
3276#else
3277 fname,
3278#endif
3279 (char_u *)"", 0); /* show that we are busy */
3280 msg_scroll = FALSE; /* always overwrite the file message now */
3281
3282 buffer = alloc(BUFSIZE);
3283 if (buffer == NULL) /* can't allocate big buffer, use small
3284 * one (to be able to write when out of
3285 * memory) */
3286 {
3287 buffer = smallbuf;
3288 bufsize = SMBUFSIZE;
3289 }
3290 else
3291 bufsize = BUFSIZE;
3292
3293 /*
3294 * Get information about original file (if there is one).
3295 */
3296#if defined(UNIX) && !defined(ARCHIE)
Bram Moolenaar6f192452007-11-08 19:49:02 +00003297 st_old.st_dev = 0;
3298 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 perm = -1;
3300 if (mch_stat((char *)fname, &st_old) < 0)
3301 newfile = TRUE;
3302 else
3303 {
3304 perm = st_old.st_mode;
3305 if (!S_ISREG(st_old.st_mode)) /* not a file */
3306 {
3307 if (S_ISDIR(st_old.st_mode))
3308 {
3309 errnum = (char_u *)"E502: ";
3310 errmsg = (char_u *)_("is a directory");
3311 goto fail;
3312 }
3313 if (mch_nodetype(fname) != NODE_WRITABLE)
3314 {
3315 errnum = (char_u *)"E503: ";
3316 errmsg = (char_u *)_("is not a file or writable device");
3317 goto fail;
3318 }
3319 /* It's a device of some kind (or a fifo) which we can write to
3320 * but for which we can't make a backup. */
3321 device = TRUE;
3322 newfile = TRUE;
3323 perm = -1;
3324 }
3325 }
3326#else /* !UNIX */
3327 /*
3328 * Check for a writable device name.
3329 */
3330 c = mch_nodetype(fname);
3331 if (c == NODE_OTHER)
3332 {
3333 errnum = (char_u *)"E503: ";
3334 errmsg = (char_u *)_("is not a file or writable device");
3335 goto fail;
3336 }
3337 if (c == NODE_WRITABLE)
3338 {
Bram Moolenaar043545e2006-10-10 16:44:07 +00003339# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
3340 /* MS-Windows allows opening a device, but we will probably get stuck
3341 * trying to write to it. */
3342 if (!p_odev)
3343 {
3344 errnum = (char_u *)"E796: ";
3345 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
3346 goto fail;
3347 }
3348# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 device = TRUE;
3350 newfile = TRUE;
3351 perm = -1;
3352 }
3353 else
3354 {
3355 perm = mch_getperm(fname);
3356 if (perm < 0)
3357 newfile = TRUE;
3358 else if (mch_isdir(fname))
3359 {
3360 errnum = (char_u *)"E502: ";
3361 errmsg = (char_u *)_("is a directory");
3362 goto fail;
3363 }
3364 if (overwriting)
3365 (void)mch_stat((char *)fname, &st_old);
3366 }
3367#endif /* !UNIX */
3368
3369 if (!device && !newfile)
3370 {
3371 /*
3372 * Check if the file is really writable (when renaming the file to
3373 * make a backup we won't discover it later).
3374 */
Bram Moolenaar5386a122007-06-28 20:02:32 +00003375 file_readonly = check_file_readonly(fname, (int)perm);
3376
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 if (!forceit && file_readonly)
3378 {
3379 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3380 {
3381 errnum = (char_u *)"E504: ";
3382 errmsg = (char_u *)_(err_readonly);
3383 }
3384 else
3385 {
3386 errnum = (char_u *)"E505: ";
3387 errmsg = (char_u *)_("is read-only (add ! to override)");
3388 }
3389 goto fail;
3390 }
3391
3392 /*
3393 * Check if the timestamp hasn't changed since reading the file.
3394 */
3395 if (overwriting)
3396 {
3397 retval = check_mtime(buf, &st_old);
3398 if (retval == FAIL)
3399 goto fail;
3400 }
3401 }
3402
3403#ifdef HAVE_ACL
3404 /*
3405 * For systems that support ACL: get the ACL from the original file.
3406 */
3407 if (!newfile)
3408 acl = mch_get_acl(fname);
3409#endif
3410
3411 /*
3412 * If 'backupskip' is not empty, don't make a backup for some files.
3413 */
3414 dobackup = (p_wb || p_bk || *p_pm != NUL);
3415#ifdef FEAT_WILDIGN
3416 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3417 dobackup = FALSE;
3418#endif
3419
3420 /*
3421 * Save the value of got_int and reset it. We don't want a previous
3422 * interruption cancel writing, only hitting CTRL-C while writing should
3423 * abort it.
3424 */
3425 prev_got_int = got_int;
3426 got_int = FALSE;
3427
3428 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3429 buf->b_saving = TRUE;
3430
3431 /*
3432 * If we are not appending or filtering, the file exists, and the
3433 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3434 * When 'patchmode' is set also make a backup when appending.
3435 *
3436 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3437 * off. This helps when editing large files on almost-full disks.
3438 */
3439 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3440 {
3441#if defined(UNIX) || defined(WIN32)
3442 struct stat st;
3443#endif
3444
3445 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3446 backup_copy = TRUE;
3447#if defined(UNIX) || defined(WIN32)
3448 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3449 {
3450 int i;
3451
3452# ifdef UNIX
3453 /*
3454 * Don't rename the file when:
3455 * - it's a hard link
3456 * - it's a symbolic link
3457 * - we don't have write permission in the directory
3458 * - we can't set the owner/group of the new file
3459 */
3460 if (st_old.st_nlink > 1
3461 || mch_lstat((char *)fname, &st) < 0
3462 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003463 || st.st_ino != st_old.st_ino
3464# ifndef HAVE_FCHOWN
3465 || st.st_uid != st_old.st_uid
3466 || st.st_gid != st_old.st_gid
3467# endif
3468 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 backup_copy = TRUE;
3470 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003471# else
3472# ifdef WIN32
3473 /* On NTFS file systems hard links are possible. */
3474 if (mch_is_linked(fname))
3475 backup_copy = TRUE;
3476 else
3477# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478# endif
3479 {
3480 /*
3481 * Check if we can create a file and set the owner/group to
3482 * the ones from the original file.
3483 * First find a file name that doesn't exist yet (use some
3484 * arbitrary numbers).
3485 */
3486 STRCPY(IObuff, fname);
3487 for (i = 4913; ; i += 123)
3488 {
3489 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003490 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 break;
3492 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003493 fd = mch_open((char *)IObuff,
3494 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 if (fd < 0) /* can't write in directory */
3496 backup_copy = TRUE;
3497 else
3498 {
3499# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003500# ifdef HAVE_FCHOWN
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00003501 ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003502# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 if (mch_stat((char *)IObuff, &st) < 0
3504 || st.st_uid != st_old.st_uid
3505 || st.st_gid != st_old.st_gid
Bram Moolenaar78a15312009-05-15 19:33:18 +00003506 || (long)st.st_mode != perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507 backup_copy = TRUE;
3508# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003509 /* Close the file before removing it, on MS-Windows we
3510 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003511 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003512 mch_remove(IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513 }
3514 }
3515 }
3516
3517# ifdef UNIX
3518 /*
3519 * Break symlinks and/or hardlinks if we've been asked to.
3520 */
3521 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3522 {
3523 int lstat_res;
3524
3525 lstat_res = mch_lstat((char *)fname, &st);
3526
3527 /* Symlinks. */
3528 if ((bkc_flags & BKC_BREAKSYMLINK)
3529 && lstat_res == 0
3530 && st.st_ino != st_old.st_ino)
3531 backup_copy = FALSE;
3532
3533 /* Hardlinks. */
3534 if ((bkc_flags & BKC_BREAKHARDLINK)
3535 && st_old.st_nlink > 1
3536 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3537 backup_copy = FALSE;
3538 }
3539#endif
3540
3541#endif
3542
3543 /* make sure we have a valid backup extension to use */
3544 if (*p_bex == NUL)
3545 {
3546#ifdef RISCOS
3547 backup_ext = (char_u *)"/bak";
3548#else
3549 backup_ext = (char_u *)".bak";
3550#endif
3551 }
3552 else
3553 backup_ext = p_bex;
3554
3555 if (backup_copy
3556 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3557 {
3558 int bfd;
3559 char_u *copybuf, *wp;
3560 int some_error = FALSE;
3561 struct stat st_new;
3562 char_u *dirp;
3563 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003564#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 int did_set_shortname;
3566#endif
3567
3568 copybuf = alloc(BUFSIZE + 1);
3569 if (copybuf == NULL)
3570 {
3571 some_error = TRUE; /* out of memory */
3572 goto nobackup;
3573 }
3574
3575 /*
3576 * Try to make the backup in each directory in the 'bdir' option.
3577 *
3578 * Unix semantics has it, that we may have a writable file,
3579 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3580 * - the directory is not writable,
3581 * - the file may be a symbolic link,
3582 * - the file may belong to another user/group, etc.
3583 *
3584 * For these reasons, the existing writable file must be truncated
3585 * and reused. Creation of a backup COPY will be attempted.
3586 */
3587 dirp = p_bdir;
3588 while (*dirp)
3589 {
3590#ifdef UNIX
3591 st_new.st_ino = 0;
3592 st_new.st_dev = 0;
3593 st_new.st_gid = 0;
3594#endif
3595
3596 /*
3597 * Isolate one directory name, using an entry in 'bdir'.
3598 */
3599 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3600 rootname = get_file_in_dir(fname, copybuf);
3601 if (rootname == NULL)
3602 {
3603 some_error = TRUE; /* out of memory */
3604 goto nobackup;
3605 }
3606
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003607#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 did_set_shortname = FALSE;
3609#endif
3610
3611 /*
3612 * May try twice if 'shortname' not set.
3613 */
3614 for (;;)
3615 {
3616 /*
3617 * Make backup file name.
3618 */
3619 backup = buf_modname(
3620#ifdef SHORT_FNAME
3621 TRUE,
3622#else
3623 (buf->b_p_sn || buf->b_shortname),
3624#endif
3625 rootname, backup_ext, FALSE);
3626 if (backup == NULL)
3627 {
3628 vim_free(rootname);
3629 some_error = TRUE; /* out of memory */
3630 goto nobackup;
3631 }
3632
3633 /*
3634 * Check if backup file already exists.
3635 */
3636 if (mch_stat((char *)backup, &st_new) >= 0)
3637 {
3638#ifdef UNIX
3639 /*
3640 * Check if backup file is same as original file.
3641 * May happen when modname() gave the same file back.
3642 * E.g. silly link, or file name-length reached.
3643 * If we don't check here, we either ruin the file
3644 * when copying or erase it after writing. jw.
3645 */
3646 if (st_new.st_dev == st_old.st_dev
3647 && st_new.st_ino == st_old.st_ino)
3648 {
3649 vim_free(backup);
3650 backup = NULL; /* no backup file to delete */
3651# ifndef SHORT_FNAME
3652 /*
3653 * may try again with 'shortname' set
3654 */
3655 if (!(buf->b_shortname || buf->b_p_sn))
3656 {
3657 buf->b_shortname = TRUE;
3658 did_set_shortname = TRUE;
3659 continue;
3660 }
3661 /* setting shortname didn't help */
3662 if (did_set_shortname)
3663 buf->b_shortname = FALSE;
3664# endif
3665 break;
3666 }
3667#endif
3668
3669 /*
3670 * If we are not going to keep the backup file, don't
3671 * delete an existing one, try to use another name.
3672 * Change one character, just before the extension.
3673 */
3674 if (!p_bk)
3675 {
3676 wp = backup + STRLEN(backup) - 1
3677 - STRLEN(backup_ext);
3678 if (wp < backup) /* empty file name ??? */
3679 wp = backup;
3680 *wp = 'z';
3681 while (*wp > 'a'
3682 && mch_stat((char *)backup, &st_new) >= 0)
3683 --*wp;
3684 /* They all exist??? Must be something wrong. */
3685 if (*wp == 'a')
3686 {
3687 vim_free(backup);
3688 backup = NULL;
3689 }
3690 }
3691 }
3692 break;
3693 }
3694 vim_free(rootname);
3695
3696 /*
3697 * Try to create the backup file
3698 */
3699 if (backup != NULL)
3700 {
3701 /* remove old backup, if present */
3702 mch_remove(backup);
3703 /* Open with O_EXCL to avoid the file being created while
3704 * we were sleeping (symlink hacker attack?) */
3705 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003706 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3707 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 if (bfd < 0)
3709 {
3710 vim_free(backup);
3711 backup = NULL;
3712 }
3713 else
3714 {
3715 /* set file protection same as original file, but
3716 * strip s-bit */
3717 (void)mch_setperm(backup, perm & 0777);
3718
3719#ifdef UNIX
3720 /*
3721 * Try to set the group of the backup same as the
3722 * original file. If this fails, set the protection
3723 * bits for the group same as the protection bits for
3724 * others.
3725 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003726 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003728 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729# endif
3730 )
3731 mch_setperm(backup,
3732 (perm & 0707) | ((perm & 07) << 3));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003733# ifdef HAVE_SELINUX
3734 mch_copy_sec(fname, backup);
3735# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736#endif
3737
3738 /*
3739 * copy the file.
3740 */
3741 write_info.bw_fd = bfd;
3742 write_info.bw_buf = copybuf;
3743#ifdef HAS_BW_FLAGS
3744 write_info.bw_flags = FIO_NOCONVERT;
3745#endif
3746 while ((write_info.bw_len = vim_read(fd, copybuf,
3747 BUFSIZE)) > 0)
3748 {
3749 if (buf_write_bytes(&write_info) == FAIL)
3750 {
3751 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3752 break;
3753 }
3754 ui_breakcheck();
3755 if (got_int)
3756 {
3757 errmsg = (char_u *)_(e_interr);
3758 break;
3759 }
3760 }
3761
3762 if (close(bfd) < 0 && errmsg == NULL)
3763 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3764 if (write_info.bw_len < 0)
3765 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3766#ifdef UNIX
3767 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3768#endif
3769#ifdef HAVE_ACL
3770 mch_set_acl(backup, acl);
3771#endif
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003772#ifdef HAVE_SELINUX
3773 mch_copy_sec(fname, backup);
3774#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 break;
3776 }
3777 }
3778 }
3779 nobackup:
3780 close(fd); /* ignore errors for closing read file */
3781 vim_free(copybuf);
3782
3783 if (backup == NULL && errmsg == NULL)
3784 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3785 /* ignore errors when forceit is TRUE */
3786 if ((some_error || errmsg != NULL) && !forceit)
3787 {
3788 retval = FAIL;
3789 goto fail;
3790 }
3791 errmsg = NULL;
3792 }
3793 else
3794 {
3795 char_u *dirp;
3796 char_u *p;
3797 char_u *rootname;
3798
3799 /*
3800 * Make a backup by renaming the original file.
3801 */
3802 /*
3803 * If 'cpoptions' includes the "W" flag, we don't want to
3804 * overwrite a read-only file. But rename may be possible
3805 * anyway, thus we need an extra check here.
3806 */
3807 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3808 {
3809 errnum = (char_u *)"E504: ";
3810 errmsg = (char_u *)_(err_readonly);
3811 goto fail;
3812 }
3813
3814 /*
3815 *
3816 * Form the backup file name - change path/fo.o.h to
3817 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3818 * that works is used.
3819 */
3820 dirp = p_bdir;
3821 while (*dirp)
3822 {
3823 /*
3824 * Isolate one directory name and make the backup file name.
3825 */
3826 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
3827 rootname = get_file_in_dir(fname, IObuff);
3828 if (rootname == NULL)
3829 backup = NULL;
3830 else
3831 {
3832 backup = buf_modname(
3833#ifdef SHORT_FNAME
3834 TRUE,
3835#else
3836 (buf->b_p_sn || buf->b_shortname),
3837#endif
3838 rootname, backup_ext, FALSE);
3839 vim_free(rootname);
3840 }
3841
3842 if (backup != NULL)
3843 {
3844 /*
3845 * If we are not going to keep the backup file, don't
3846 * delete an existing one, try to use another name.
3847 * Change one character, just before the extension.
3848 */
3849 if (!p_bk && mch_getperm(backup) >= 0)
3850 {
3851 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
3852 if (p < backup) /* empty file name ??? */
3853 p = backup;
3854 *p = 'z';
3855 while (*p > 'a' && mch_getperm(backup) >= 0)
3856 --*p;
3857 /* They all exist??? Must be something wrong! */
3858 if (*p == 'a')
3859 {
3860 vim_free(backup);
3861 backup = NULL;
3862 }
3863 }
3864 }
3865 if (backup != NULL)
3866 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003868 * Delete any existing backup and move the current version
3869 * to the backup. For safety, we don't remove the backup
3870 * until the write has finished successfully. And if the
3871 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 */
3873 /*
3874 * If the renaming of the original file to the backup file
3875 * works, quit here.
3876 */
3877 if (vim_rename(fname, backup) == 0)
3878 break;
3879
3880 vim_free(backup); /* don't do the rename below */
3881 backup = NULL;
3882 }
3883 }
3884 if (backup == NULL && !forceit)
3885 {
3886 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
3887 goto fail;
3888 }
3889 }
3890 }
3891
3892#if defined(UNIX) && !defined(ARCHIE)
3893 /* When using ":w!" and the file was read-only: make it writable */
3894 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
3895 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
3896 {
3897 perm |= 0200;
3898 (void)mch_setperm(fname, perm);
3899 made_writable = TRUE;
3900 }
3901#endif
3902
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003903 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003904 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
3905 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 {
3907 buf->b_p_ro = FALSE;
3908#ifdef FEAT_TITLE
3909 need_maketitle = TRUE; /* set window title later */
3910#endif
3911#ifdef FEAT_WINDOWS
3912 status_redraw_all(); /* redraw status lines later */
3913#endif
3914 }
3915
3916 if (end > buf->b_ml.ml_line_count)
3917 end = buf->b_ml.ml_line_count;
3918 if (buf->b_ml.ml_flags & ML_EMPTY)
3919 start = end + 1;
3920
3921 /*
3922 * If the original file is being overwritten, there is a small chance that
3923 * we crash in the middle of writing. Therefore the file is preserved now.
3924 * This makes all block numbers positive so that recovery does not need
3925 * the original file.
3926 * Don't do this if there is a backup file and we are exiting.
3927 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003928 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 && !(exiting && backup != NULL))
3930 {
3931 ml_preserve(buf, FALSE);
3932 if (got_int)
3933 {
3934 errmsg = (char_u *)_(e_interr);
3935 goto restore_backup;
3936 }
3937 }
3938
3939#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
3940 /*
3941 * Before risking to lose the original file verify if there's
3942 * a resource fork to preserve, and if cannot be done warn
3943 * the users. This happens when overwriting without backups.
3944 */
3945 if (backup == NULL && overwriting && !append)
3946 if (mch_has_resource_fork(fname))
3947 {
3948 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
3949 goto restore_backup;
3950 }
3951#endif
3952
3953#ifdef VMS
3954 vms_remove_version(fname); /* remove version */
3955#endif
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00003956 /* Default: write the file directly. May write to a temp file for
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957 * multi-byte conversion. */
3958 wfname = fname;
3959
3960#ifdef FEAT_MBYTE
3961 /* Check for forced 'fileencoding' from "++opt=val" argument. */
3962 if (eap != NULL && eap->force_enc != 0)
3963 {
3964 fenc = eap->cmd + eap->force_enc;
3965 fenc = enc_canonize(fenc);
3966 fenc_tofree = fenc;
3967 }
3968 else
3969 fenc = buf->b_p_fenc;
3970
3971 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00003972 * Check if the file needs to be converted.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003973 */
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00003974 converted = need_conversion(fenc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975
3976 /*
3977 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
3978 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
3979 * Prepare the flags for it and allocate bw_conv_buf when needed.
3980 */
3981 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
3982 {
3983 wb_flags = get_fio_flags(fenc);
3984 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
3985 {
3986 /* Need to allocate a buffer to translate into. */
3987 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
3988 write_info.bw_conv_buflen = bufsize * 2;
3989 else /* FIO_UCS4 */
3990 write_info.bw_conv_buflen = bufsize * 4;
3991 write_info.bw_conv_buf
3992 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3993 if (write_info.bw_conv_buf == NULL)
3994 end = 0;
3995 }
3996 }
3997
3998# ifdef WIN3264
3999 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
4000 {
4001 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
4002 write_info.bw_conv_buflen = bufsize * 4;
4003 write_info.bw_conv_buf
4004 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4005 if (write_info.bw_conv_buf == NULL)
4006 end = 0;
4007 }
4008# endif
4009
4010# ifdef MACOS_X
4011 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
4012 {
4013 write_info.bw_conv_buflen = bufsize * 3;
4014 write_info.bw_conv_buf
4015 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4016 if (write_info.bw_conv_buf == NULL)
4017 end = 0;
4018 }
4019# endif
4020
4021# if defined(FEAT_EVAL) || defined(USE_ICONV)
4022 if (converted && wb_flags == 0)
4023 {
4024# ifdef USE_ICONV
4025 /*
4026 * Use iconv() conversion when conversion is needed and it's not done
4027 * internally.
4028 */
4029 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
4030 enc_utf8 ? (char_u *)"utf-8" : p_enc);
4031 if (write_info.bw_iconv_fd != (iconv_t)-1)
4032 {
4033 /* We're going to use iconv(), allocate a buffer to convert in. */
4034 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
4035 write_info.bw_conv_buf
4036 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4037 if (write_info.bw_conv_buf == NULL)
4038 end = 0;
4039 write_info.bw_first = TRUE;
4040 }
4041# ifdef FEAT_EVAL
4042 else
4043# endif
4044# endif
4045
4046# ifdef FEAT_EVAL
4047 /*
4048 * When the file needs to be converted with 'charconvert' after
4049 * writing, write to a temp file instead and let the conversion
4050 * overwrite the original file.
4051 */
4052 if (*p_ccv != NUL)
4053 {
4054 wfname = vim_tempname('w');
4055 if (wfname == NULL) /* Can't write without a tempfile! */
4056 {
4057 errmsg = (char_u *)_("E214: Can't find temp file for writing");
4058 goto restore_backup;
4059 }
4060 }
4061# endif
4062 }
4063# endif
4064 if (converted && wb_flags == 0
4065# ifdef USE_ICONV
4066 && write_info.bw_iconv_fd == (iconv_t)-1
4067# endif
4068# ifdef FEAT_EVAL
4069 && wfname == fname
4070# endif
4071 )
4072 {
4073 if (!forceit)
4074 {
4075 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
4076 goto restore_backup;
4077 }
4078 notconverted = TRUE;
4079 }
4080#endif
4081
4082 /*
4083 * Open the file "wfname" for writing.
4084 * We may try to open the file twice: If we can't write to the
4085 * file and forceit is TRUE we delete the existing file and try to create
4086 * a new one. If this still fails we may have lost the original file!
4087 * (this may happen when the user reached his quotum for number of files).
4088 * Appending will fail if the file does not exist and forceit is FALSE.
4089 */
4090 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
4091 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
4092 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004093 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 {
4095 /*
4096 * A forced write will try to create a new file if the old one is
4097 * still readonly. This may also happen when the directory is
4098 * read-only. In that case the mch_remove() will fail.
4099 */
4100 if (errmsg == NULL)
4101 {
4102#ifdef UNIX
4103 struct stat st;
4104
4105 /* Don't delete the file when it's a hard or symbolic link. */
4106 if ((!newfile && st_old.st_nlink > 1)
4107 || (mch_lstat((char *)fname, &st) == 0
4108 && (st.st_dev != st_old.st_dev
4109 || st.st_ino != st_old.st_ino)))
4110 errmsg = (char_u *)_("E166: Can't open linked file for writing");
4111 else
4112#endif
4113 {
4114 errmsg = (char_u *)_("E212: Can't open file for writing");
4115 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
4116 && perm >= 0)
4117 {
4118#ifdef UNIX
4119 /* we write to the file, thus it should be marked
4120 writable after all */
4121 if (!(perm & 0200))
4122 made_writable = TRUE;
4123 perm |= 0200;
4124 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
4125 perm &= 0777;
4126#endif
4127 if (!append) /* don't remove when appending */
4128 mch_remove(wfname);
4129 continue;
4130 }
4131 }
4132 }
4133
4134restore_backup:
4135 {
4136 struct stat st;
4137
4138 /*
4139 * If we failed to open the file, we don't need a backup. Throw it
4140 * away. If we moved or removed the original file try to put the
4141 * backup in its place.
4142 */
4143 if (backup != NULL && wfname == fname)
4144 {
4145 if (backup_copy)
4146 {
4147 /*
4148 * There is a small chance that we removed the original,
4149 * try to move the copy in its place.
4150 * This may not work if the vim_rename() fails.
4151 * In that case we leave the copy around.
4152 */
4153 /* If file does not exist, put the copy in its place */
4154 if (mch_stat((char *)fname, &st) < 0)
4155 vim_rename(backup, fname);
4156 /* if original file does exist throw away the copy */
4157 if (mch_stat((char *)fname, &st) >= 0)
4158 mch_remove(backup);
4159 }
4160 else
4161 {
4162 /* try to put the original file back */
4163 vim_rename(backup, fname);
4164 }
4165 }
4166
4167 /* if original file no longer exists give an extra warning */
4168 if (!newfile && mch_stat((char *)fname, &st) < 0)
4169 end = 0;
4170 }
4171
4172#ifdef FEAT_MBYTE
4173 if (wfname != fname)
4174 vim_free(wfname);
4175#endif
4176 goto fail;
4177 }
4178 errmsg = NULL;
4179
4180#if defined(MACOS_CLASSIC) || defined(WIN3264)
4181 /* TODO: Is it need for MACOS_X? (Dany) */
4182 /*
4183 * On macintosh copy the original files attributes (i.e. the backup)
Bram Moolenaar7263a772007-05-10 17:35:54 +00004184 * This is done in order to preserve the resource fork and the
4185 * Finder attribute (label, comments, custom icons, file creator)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 */
4187 if (backup != NULL && overwriting && !append)
4188 {
4189 if (backup_copy)
4190 (void)mch_copy_file_attribute(wfname, backup);
4191 else
4192 (void)mch_copy_file_attribute(backup, wfname);
4193 }
4194
4195 if (!overwriting && !append)
4196 {
4197 if (buf->b_ffname != NULL)
4198 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
Bram Moolenaar7263a772007-05-10 17:35:54 +00004199 /* Should copy resource fork */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 }
4201#endif
4202
4203 write_info.bw_fd = fd;
4204
4205#ifdef FEAT_CRYPT
4206 if (*buf->b_p_key && !filtering)
4207 {
4208 crypt_init_keys(buf->b_p_key);
4209 /* Write magic number, so that Vim knows that this file is encrypted
4210 * when reading it again. This also undergoes utf-8 to ucs-2/4
4211 * conversion when needed. */
4212 write_info.bw_buf = (char_u *)CRYPT_MAGIC;
4213 write_info.bw_len = CRYPT_MAGIC_LEN;
4214 write_info.bw_flags = FIO_NOCONVERT;
4215 if (buf_write_bytes(&write_info) == FAIL)
4216 end = 0;
4217 wb_flags |= FIO_ENCRYPTED;
4218 }
4219#endif
4220
4221 write_info.bw_buf = buffer;
4222 nchars = 0;
4223
4224 /* use "++bin", "++nobin" or 'binary' */
4225 if (eap != NULL && eap->force_bin != 0)
4226 write_bin = (eap->force_bin == FORCE_BIN);
4227 else
4228 write_bin = buf->b_p_bin;
4229
4230#ifdef FEAT_MBYTE
4231 /*
4232 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004233 * Skip it when appending and the file already existed, the BOM only makes
4234 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004236 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 {
4238 write_info.bw_len = make_bom(buffer, fenc);
4239 if (write_info.bw_len > 0)
4240 {
4241 /* don't convert, do encryption */
4242 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4243 if (buf_write_bytes(&write_info) == FAIL)
4244 end = 0;
4245 else
4246 nchars += write_info.bw_len;
4247 }
4248 }
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004249 write_info.bw_start_lnum = start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250#endif
4251
4252 write_info.bw_len = bufsize;
4253#ifdef HAS_BW_FLAGS
4254 write_info.bw_flags = wb_flags;
4255#endif
4256 fileformat = get_fileformat_force(buf, eap);
4257 s = buffer;
4258 len = 0;
4259 for (lnum = start; lnum <= end; ++lnum)
4260 {
4261 /*
4262 * The next while loop is done once for each character written.
4263 * Keep it fast!
4264 */
4265 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4266 while ((c = *++ptr) != NUL)
4267 {
4268 if (c == NL)
4269 *s = NUL; /* replace newlines with NULs */
4270 else if (c == CAR && fileformat == EOL_MAC)
4271 *s = NL; /* Mac: replace CRs with NLs */
4272 else
4273 *s = c;
4274 ++s;
4275 if (++len != bufsize)
4276 continue;
4277 if (buf_write_bytes(&write_info) == FAIL)
4278 {
4279 end = 0; /* write error: break loop */
4280 break;
4281 }
4282 nchars += bufsize;
4283 s = buffer;
4284 len = 0;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004285#ifdef FEAT_MBYTE
4286 write_info.bw_start_lnum = lnum;
4287#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 }
4289 /* write failed or last line has no EOL: stop here */
4290 if (end == 0
4291 || (lnum == end
4292 && write_bin
4293 && (lnum == write_no_eol_lnum
4294 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4295 {
4296 ++lnum; /* written the line, count it */
4297 no_eol = TRUE;
4298 break;
4299 }
4300 if (fileformat == EOL_UNIX)
4301 *s++ = NL;
4302 else
4303 {
4304 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4305 if (fileformat == EOL_DOS) /* write CR-NL */
4306 {
4307 if (++len == bufsize)
4308 {
4309 if (buf_write_bytes(&write_info) == FAIL)
4310 {
4311 end = 0; /* write error: break loop */
4312 break;
4313 }
4314 nchars += bufsize;
4315 s = buffer;
4316 len = 0;
4317 }
4318 *s++ = NL;
4319 }
4320 }
4321 if (++len == bufsize && end)
4322 {
4323 if (buf_write_bytes(&write_info) == FAIL)
4324 {
4325 end = 0; /* write error: break loop */
4326 break;
4327 }
4328 nchars += bufsize;
4329 s = buffer;
4330 len = 0;
4331
4332 ui_breakcheck();
4333 if (got_int)
4334 {
4335 end = 0; /* Interrupted, break loop */
4336 break;
4337 }
4338 }
4339#ifdef VMS
4340 /*
4341 * On VMS there is a problem: newlines get added when writing blocks
4342 * at a time. Fix it by writing a line at a time.
4343 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004344 * Explanation: VAX/DECC RTL insists that records in some RMS
4345 * structures end with a newline (carriage return) character, and if
4346 * they don't it adds one.
4347 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 */
Bram Moolenaarb52e2602007-10-29 21:38:54 +00004349 if (buf->b_fab_rfm == FAB$C_VFC
4350 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004352 int b2write;
4353
4354 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4355 ? MIN(4096, bufsize)
4356 : MIN(buf->b_fab_mrs, bufsize));
4357
4358 b2write = len;
4359 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004361 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4362 if (buf_write_bytes(&write_info) == FAIL)
4363 {
4364 end = 0;
4365 break;
4366 }
4367 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368 }
4369 write_info.bw_len = bufsize;
4370 nchars += len;
4371 s = buffer;
4372 len = 0;
4373 }
4374#endif
4375 }
4376 if (len > 0 && end > 0)
4377 {
4378 write_info.bw_len = len;
4379 if (buf_write_bytes(&write_info) == FAIL)
4380 end = 0; /* write error */
4381 nchars += len;
4382 }
4383
4384#if defined(UNIX) && defined(HAVE_FSYNC)
4385 /* On many journalling file systems there is a bug that causes both the
4386 * original and the backup file to be lost when halting the system right
4387 * after writing the file. That's because only the meta-data is
4388 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004389 * been written to disk and we don't lose it.
4390 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004391 * (could be a pipe).
4392 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4393 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 {
4395 errmsg = (char_u *)_("E667: Fsync failed");
4396 end = 0;
4397 }
4398#endif
4399
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004400#ifdef HAVE_SELINUX
4401 /* Probably need to set the security context. */
4402 if (!backup_copy)
4403 mch_copy_sec(backup, wfname);
4404#endif
4405
Bram Moolenaara5792f52005-11-23 21:25:05 +00004406#ifdef UNIX
4407 /* When creating a new file, set its owner/group to that of the original
4408 * file. Get the new device and inode number. */
4409 if (backup != NULL && !backup_copy)
4410 {
4411# ifdef HAVE_FCHOWN
4412 struct stat st;
4413
4414 /* don't change the owner when it's already OK, some systems remove
4415 * permission or ACL stuff */
4416 if (mch_stat((char *)wfname, &st) < 0
4417 || st.st_uid != st_old.st_uid
4418 || st.st_gid != st_old.st_gid)
4419 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004420 ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004421 if (perm >= 0) /* set permission again, may have changed */
4422 (void)mch_setperm(wfname, perm);
4423 }
4424# endif
4425 buf_setino(buf);
4426 }
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00004427 else if (!buf->b_dev_valid)
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004428 /* Set the inode when creating a new file. */
4429 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004430#endif
4431
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 if (close(fd) != 0)
4433 {
4434 errmsg = (char_u *)_("E512: Close failed");
4435 end = 0;
4436 }
4437
4438#ifdef UNIX
4439 if (made_writable)
4440 perm &= ~0200; /* reset 'w' bit for security reasons */
4441#endif
4442 if (perm >= 0) /* set perm. of new file same as old file */
4443 (void)mch_setperm(wfname, perm);
4444#ifdef RISCOS
4445 if (!append && !filtering)
4446 /* Set the filetype after writing the file. */
4447 mch_set_filetype(wfname, buf->b_p_oft);
4448#endif
4449#ifdef HAVE_ACL
4450 /* Probably need to set the ACL before changing the user (can't set the
4451 * ACL on a file the user doesn't own). */
4452 if (!backup_copy)
4453 mch_set_acl(wfname, acl);
4454#endif
4455
Bram Moolenaar071d4272004-06-13 20:20:40 +00004456
4457#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4458 if (wfname != fname)
4459 {
4460 /*
4461 * The file was written to a temp file, now it needs to be converted
4462 * with 'charconvert' to (overwrite) the output file.
4463 */
4464 if (end != 0)
4465 {
4466 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4467 wfname, fname) == FAIL)
4468 {
4469 write_info.bw_conv_error = TRUE;
4470 end = 0;
4471 }
4472 }
4473 mch_remove(wfname);
4474 vim_free(wfname);
4475 }
4476#endif
4477
4478 if (end == 0)
4479 {
4480 if (errmsg == NULL)
4481 {
4482#ifdef FEAT_MBYTE
4483 if (write_info.bw_conv_error)
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004484 {
4485 if (write_info.bw_conv_error_lnum == 0)
4486 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
4487 else
4488 {
4489 errmsg_allocated = TRUE;
4490 errmsg = alloc(300);
4491 vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"),
4492 (long)write_info.bw_conv_error_lnum);
4493 }
4494 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 else
4496#endif
4497 if (got_int)
4498 errmsg = (char_u *)_(e_interr);
4499 else
4500 errmsg = (char_u *)_("E514: write error (file system full?)");
4501 }
4502
4503 /*
4504 * If we have a backup file, try to put it in place of the new file,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004505 * because the new file is probably corrupt. This avoids losing the
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 * original file when trying to make a backup when writing the file a
4507 * second time.
4508 * When "backup_copy" is set we need to copy the backup over the new
4509 * file. Otherwise rename the backup file.
4510 * If this is OK, don't give the extra warning message.
4511 */
4512 if (backup != NULL)
4513 {
4514 if (backup_copy)
4515 {
4516 /* This may take a while, if we were interrupted let the user
4517 * know we got the message. */
4518 if (got_int)
4519 {
4520 MSG(_(e_interr));
4521 out_flush();
4522 }
4523 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4524 {
4525 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004526 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4527 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 {
4529 /* copy the file. */
4530 write_info.bw_buf = smallbuf;
4531#ifdef HAS_BW_FLAGS
4532 write_info.bw_flags = FIO_NOCONVERT;
4533#endif
4534 while ((write_info.bw_len = vim_read(fd, smallbuf,
4535 SMBUFSIZE)) > 0)
4536 if (buf_write_bytes(&write_info) == FAIL)
4537 break;
4538
4539 if (close(write_info.bw_fd) >= 0
4540 && write_info.bw_len == 0)
4541 end = 1; /* success */
4542 }
4543 close(fd); /* ignore errors for closing read file */
4544 }
4545 }
4546 else
4547 {
4548 if (vim_rename(backup, fname) == 0)
4549 end = 1;
4550 }
4551 }
4552 goto fail;
4553 }
4554
4555 lnum -= start; /* compute number of written lines */
4556 --no_wait_return; /* may wait for return now */
4557
4558#if !(defined(UNIX) || defined(VMS))
4559 fname = sfname; /* use shortname now, for the messages */
4560#endif
4561 if (!filtering)
4562 {
4563 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4564 c = FALSE;
4565#ifdef FEAT_MBYTE
4566 if (write_info.bw_conv_error)
4567 {
4568 STRCAT(IObuff, _(" CONVERSION ERROR"));
4569 c = TRUE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004570 if (write_info.bw_conv_error_lnum != 0)
4571 {
Bram Moolenaarc0662022009-09-11 13:04:24 +00004572 size_t l = STRLEN(IObuff);
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004573 vim_snprintf((char *)IObuff + l, IOSIZE - l, _(" in line %ld;"),
4574 (long)write_info.bw_conv_error_lnum);
4575 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004576 }
4577 else if (notconverted)
4578 {
4579 STRCAT(IObuff, _("[NOT converted]"));
4580 c = TRUE;
4581 }
4582 else if (converted)
4583 {
4584 STRCAT(IObuff, _("[converted]"));
4585 c = TRUE;
4586 }
4587#endif
4588 if (device)
4589 {
4590 STRCAT(IObuff, _("[Device]"));
4591 c = TRUE;
4592 }
4593 else if (newfile)
4594 {
4595 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4596 c = TRUE;
4597 }
4598 if (no_eol)
4599 {
4600 msg_add_eol();
4601 c = TRUE;
4602 }
4603 /* may add [unix/dos/mac] */
4604 if (msg_add_fileformat(fileformat))
4605 c = TRUE;
4606#ifdef FEAT_CRYPT
4607 if (wb_flags & FIO_ENCRYPTED)
4608 {
4609 STRCAT(IObuff, _("[crypted]"));
4610 c = TRUE;
4611 }
4612#endif
4613 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4614 if (!shortmess(SHM_WRITE))
4615 {
4616 if (append)
4617 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4618 else
4619 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4620 }
4621
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00004622 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 }
4624
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004625 /* When written everything correctly: reset 'modified'. Unless not
4626 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004627 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628#ifdef FEAT_MBYTE
4629 && !write_info.bw_conv_error
4630#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004631 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4632 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633 {
4634 unchanged(buf, TRUE);
4635 u_unchanged(buf);
4636 }
4637
4638 /*
4639 * If written to the current file, update the timestamp of the swap file
4640 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4641 */
4642 if (overwriting)
4643 {
4644 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004645 if (append)
4646 buf->b_flags &= ~BF_NEW;
4647 else
4648 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 }
4650
4651 /*
4652 * If we kept a backup until now, and we are in patch mode, then we make
4653 * the backup file our 'original' file.
4654 */
4655 if (*p_pm && dobackup)
4656 {
4657 char *org = (char *)buf_modname(
4658#ifdef SHORT_FNAME
4659 TRUE,
4660#else
4661 (buf->b_p_sn || buf->b_shortname),
4662#endif
4663 fname, p_pm, FALSE);
4664
4665 if (backup != NULL)
4666 {
4667 struct stat st;
4668
4669 /*
4670 * If the original file does not exist yet
4671 * the current backup file becomes the original file
4672 */
4673 if (org == NULL)
4674 EMSG(_("E205: Patchmode: can't save original file"));
4675 else if (mch_stat(org, &st) < 0)
4676 {
4677 vim_rename(backup, (char_u *)org);
4678 vim_free(backup); /* don't delete the file */
4679 backup = NULL;
4680#ifdef UNIX
4681 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4682#endif
4683 }
4684 }
4685 /*
4686 * If there is no backup file, remember that a (new) file was
4687 * created.
4688 */
4689 else
4690 {
4691 int empty_fd;
4692
4693 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004694 || (empty_fd = mch_open(org,
4695 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004696 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 EMSG(_("E206: patchmode: can't touch empty original file"));
4698 else
4699 close(empty_fd);
4700 }
4701 if (org != NULL)
4702 {
4703 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4704 vim_free(org);
4705 }
4706 }
4707
4708 /*
4709 * Remove the backup unless 'backup' option is set
4710 */
4711 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4712 EMSG(_("E207: Can't delete backup file"));
4713
4714#ifdef FEAT_SUN_WORKSHOP
4715 if (usingSunWorkShop)
4716 workshop_file_saved((char *) ffname);
4717#endif
4718
4719 goto nofail;
4720
4721 /*
4722 * Finish up. We get here either after failure or success.
4723 */
4724fail:
4725 --no_wait_return; /* may wait for return now */
4726nofail:
4727
4728 /* Done saving, we accept changed buffer warnings again */
4729 buf->b_saving = FALSE;
4730
4731 vim_free(backup);
4732 if (buffer != smallbuf)
4733 vim_free(buffer);
4734#ifdef FEAT_MBYTE
4735 vim_free(fenc_tofree);
4736 vim_free(write_info.bw_conv_buf);
4737# ifdef USE_ICONV
4738 if (write_info.bw_iconv_fd != (iconv_t)-1)
4739 {
4740 iconv_close(write_info.bw_iconv_fd);
4741 write_info.bw_iconv_fd = (iconv_t)-1;
4742 }
4743# endif
4744#endif
4745#ifdef HAVE_ACL
4746 mch_free_acl(acl);
4747#endif
4748
4749 if (errmsg != NULL)
4750 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004751 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752
4753 attr = hl_attr(HLF_E); /* set highlight for error messages */
4754 msg_add_fname(buf,
4755#ifndef UNIX
4756 sfname
4757#else
4758 fname
4759#endif
4760 ); /* put file name in IObuff with quotes */
4761 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4762 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4763 /* If the error message has the form "is ...", put the error number in
4764 * front of the file name. */
4765 if (errnum != NULL)
4766 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00004767 STRMOVE(IObuff + numlen, IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 mch_memmove(IObuff, errnum, (size_t)numlen);
4769 }
4770 STRCAT(IObuff, errmsg);
4771 emsg(IObuff);
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004772 if (errmsg_allocated)
4773 vim_free(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774
4775 retval = FAIL;
4776 if (end == 0)
4777 {
4778 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4779 attr | MSG_HIST);
4780 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4781 attr | MSG_HIST);
4782
4783 /* Update the timestamp to avoid an "overwrite changed file"
4784 * prompt when writing again. */
4785 if (mch_stat((char *)fname, &st_old) >= 0)
4786 {
4787 buf_store_time(buf, &st_old, fname);
4788 buf->b_mtime_read = buf->b_mtime;
4789 }
4790 }
4791 }
4792 msg_scroll = msg_save;
4793
4794#ifdef FEAT_AUTOCMD
4795#ifdef FEAT_EVAL
4796 if (!should_abort(retval))
4797#else
4798 if (!got_int)
4799#endif
4800 {
4801 aco_save_T aco;
4802
4803 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4804
4805 /*
4806 * Apply POST autocommands.
4807 * Careful: The autocommands may call buf_write() recursively!
4808 */
4809 aucmd_prepbuf(&aco, buf);
4810
4811 if (append)
4812 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4813 FALSE, curbuf, eap);
4814 else if (filtering)
4815 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4816 FALSE, curbuf, eap);
4817 else if (reset_changed && whole)
4818 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4819 FALSE, curbuf, eap);
4820 else
4821 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4822 FALSE, curbuf, eap);
4823
4824 /* restore curwin/curbuf and a few other things */
4825 aucmd_restbuf(&aco);
4826
4827#ifdef FEAT_EVAL
4828 if (aborting()) /* autocmds may abort script processing */
4829 retval = FALSE;
4830#endif
4831 }
4832#endif
4833
4834 got_int |= prev_got_int;
4835
4836#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4837 /* Update machine specific information. */
4838 mch_post_buffer_write(buf);
4839#endif
4840 return retval;
4841}
4842
4843/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004844 * Set the name of the current buffer. Use when the buffer doesn't have a
4845 * name and a ":r" or ":w" command with a file name is used.
4846 */
4847 static int
4848set_rw_fname(fname, sfname)
4849 char_u *fname;
4850 char_u *sfname;
4851{
4852#ifdef FEAT_AUTOCMD
Bram Moolenaar8b38e242009-06-16 13:35:20 +00004853 buf_T *buf = curbuf;
4854
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004855 /* It's like the unnamed buffer is deleted.... */
4856 if (curbuf->b_p_bl)
4857 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
4858 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
4859# ifdef FEAT_EVAL
4860 if (aborting()) /* autocmds may abort script processing */
4861 return FAIL;
4862# endif
Bram Moolenaar8b38e242009-06-16 13:35:20 +00004863 if (curbuf != buf)
4864 {
4865 /* We are in another buffer now, don't do the renaming. */
4866 EMSG(_(e_auchangedbuf));
4867 return FAIL;
4868 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004869#endif
4870
4871 if (setfname(curbuf, fname, sfname, FALSE) == OK)
4872 curbuf->b_flags |= BF_NOTEDITED;
4873
4874#ifdef FEAT_AUTOCMD
4875 /* ....and a new named one is created */
4876 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
4877 if (curbuf->b_p_bl)
4878 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
4879# ifdef FEAT_EVAL
4880 if (aborting()) /* autocmds may abort script processing */
4881 return FAIL;
4882# endif
4883
4884 /* Do filetype detection now if 'filetype' is empty. */
4885 if (*curbuf->b_p_ft == NUL)
4886 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004887 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar70836c82006-02-20 21:28:49 +00004888 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00004889 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004890 }
4891#endif
4892
4893 return OK;
4894}
4895
4896/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 * Put file name into IObuff with quotes.
4898 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004899 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900msg_add_fname(buf, fname)
4901 buf_T *buf;
4902 char_u *fname;
4903{
4904 if (fname == NULL)
4905 fname = (char_u *)"-stdin-";
4906 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4907 IObuff[0] = '"';
4908 STRCAT(IObuff, "\" ");
4909}
4910
4911/*
4912 * Append message for text mode to IObuff.
4913 * Return TRUE if something appended.
4914 */
4915 static int
4916msg_add_fileformat(eol_type)
4917 int eol_type;
4918{
4919#ifndef USE_CRNL
4920 if (eol_type == EOL_DOS)
4921 {
4922 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4923 return TRUE;
4924 }
4925#endif
4926#ifndef USE_CR
4927 if (eol_type == EOL_MAC)
4928 {
4929 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4930 return TRUE;
4931 }
4932#endif
4933#if defined(USE_CRNL) || defined(USE_CR)
4934 if (eol_type == EOL_UNIX)
4935 {
4936 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4937 return TRUE;
4938 }
4939#endif
4940 return FALSE;
4941}
4942
4943/*
4944 * Append line and character count to IObuff.
4945 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004946 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947msg_add_lines(insert_space, lnum, nchars)
4948 int insert_space;
4949 long lnum;
4950 long nchars;
4951{
4952 char_u *p;
4953
4954 p = IObuff + STRLEN(IObuff);
4955
4956 if (insert_space)
4957 *p++ = ' ';
4958 if (shortmess(SHM_LINES))
4959 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4960 else
4961 {
4962 if (lnum == 1)
4963 STRCPY(p, _("1 line, "));
4964 else
4965 sprintf((char *)p, _("%ld lines, "), lnum);
4966 p += STRLEN(p);
4967 if (nchars == 1)
4968 STRCPY(p, _("1 character"));
4969 else
4970 sprintf((char *)p, _("%ld characters"), nchars);
4971 }
4972}
4973
4974/*
4975 * Append message for missing line separator to IObuff.
4976 */
4977 static void
4978msg_add_eol()
4979{
4980 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4981}
4982
4983/*
4984 * Check modification time of file, before writing to it.
4985 * The size isn't checked, because using a tool like "gzip" takes care of
4986 * using the same timestamp but can't set the size.
4987 */
4988 static int
4989check_mtime(buf, st)
4990 buf_T *buf;
4991 struct stat *st;
4992{
4993 if (buf->b_mtime_read != 0
4994 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4995 {
4996 msg_scroll = TRUE; /* don't overwrite messages here */
4997 msg_silent = 0; /* must give this prompt */
4998 /* don't use emsg() here, don't want to flush the buffers */
4999 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
5000 hl_attr(HLF_E));
5001 if (ask_yesno((char_u *)_("Do you really want to write to it"),
5002 TRUE) == 'n')
5003 return FAIL;
5004 msg_scroll = FALSE; /* always overwrite the file message now */
5005 }
5006 return OK;
5007}
5008
5009 static int
5010time_differs(t1, t2)
5011 long t1, t2;
5012{
5013#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
5014 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
5015 * the seconds. Since the roundoff is done when flushing the inode, the
5016 * time may change unexpectedly by one second!!! */
5017 return (t1 - t2 > 1 || t2 - t1 > 1);
5018#else
5019 return (t1 != t2);
5020#endif
5021}
5022
5023/*
5024 * Call write() to write a number of bytes to the file.
5025 * Also handles encryption and 'encoding' conversion.
5026 *
5027 * Return FAIL for failure, OK otherwise.
5028 */
5029 static int
5030buf_write_bytes(ip)
5031 struct bw_info *ip;
5032{
5033 int wlen;
5034 char_u *buf = ip->bw_buf; /* data to write */
5035 int len = ip->bw_len; /* length of data */
5036#ifdef HAS_BW_FLAGS
5037 int flags = ip->bw_flags; /* extra flags */
5038#endif
5039
5040#ifdef FEAT_MBYTE
5041 /*
5042 * Skip conversion when writing the crypt magic number or the BOM.
5043 */
5044 if (!(flags & FIO_NOCONVERT))
5045 {
5046 char_u *p;
5047 unsigned c;
5048 int n;
5049
5050 if (flags & FIO_UTF8)
5051 {
5052 /*
5053 * Convert latin1 in the buffer to UTF-8 in the file.
5054 */
5055 p = ip->bw_conv_buf; /* translate to buffer */
5056 for (wlen = 0; wlen < len; ++wlen)
5057 p += utf_char2bytes(buf[wlen], p);
5058 buf = ip->bw_conv_buf;
5059 len = (int)(p - ip->bw_conv_buf);
5060 }
5061 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
5062 {
5063 /*
5064 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
5065 * Latin1 chars in the file.
5066 */
5067 if (flags & FIO_LATIN1)
5068 p = buf; /* translate in-place (can only get shorter) */
5069 else
5070 p = ip->bw_conv_buf; /* translate to buffer */
5071 for (wlen = 0; wlen < len; wlen += n)
5072 {
5073 if (wlen == 0 && ip->bw_restlen != 0)
5074 {
5075 int l;
5076
5077 /* Use remainder of previous call. Append the start of
5078 * buf[] to get a full sequence. Might still be too
5079 * short! */
5080 l = CONV_RESTLEN - ip->bw_restlen;
5081 if (l > len)
5082 l = len;
5083 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005084 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085 if (n > ip->bw_restlen + len)
5086 {
5087 /* We have an incomplete byte sequence at the end to
5088 * be written. We can't convert it without the
5089 * remaining bytes. Keep them for the next call. */
5090 if (ip->bw_restlen + len > CONV_RESTLEN)
5091 return FAIL;
5092 ip->bw_restlen += len;
5093 break;
5094 }
5095 if (n > 1)
5096 c = utf_ptr2char(ip->bw_rest);
5097 else
5098 c = ip->bw_rest[0];
5099 if (n >= ip->bw_restlen)
5100 {
5101 n -= ip->bw_restlen;
5102 ip->bw_restlen = 0;
5103 }
5104 else
5105 {
5106 ip->bw_restlen -= n;
5107 mch_memmove(ip->bw_rest, ip->bw_rest + n,
5108 (size_t)ip->bw_restlen);
5109 n = 0;
5110 }
5111 }
5112 else
5113 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005114 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115 if (n > len - wlen)
5116 {
5117 /* We have an incomplete byte sequence at the end to
5118 * be written. We can't convert it without the
5119 * remaining bytes. Keep them for the next call. */
5120 if (len - wlen > CONV_RESTLEN)
5121 return FAIL;
5122 ip->bw_restlen = len - wlen;
5123 mch_memmove(ip->bw_rest, buf + wlen,
5124 (size_t)ip->bw_restlen);
5125 break;
5126 }
5127 if (n > 1)
5128 c = utf_ptr2char(buf + wlen);
5129 else
5130 c = buf[wlen];
5131 }
5132
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005133 if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error)
5134 {
5135 ip->bw_conv_error = TRUE;
5136 ip->bw_conv_error_lnum = ip->bw_start_lnum;
5137 }
5138 if (c == NL)
5139 ++ip->bw_start_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005140 }
5141 if (flags & FIO_LATIN1)
5142 len = (int)(p - buf);
5143 else
5144 {
5145 buf = ip->bw_conv_buf;
5146 len = (int)(p - ip->bw_conv_buf);
5147 }
5148 }
5149
5150# ifdef WIN3264
5151 else if (flags & FIO_CODEPAGE)
5152 {
5153 /*
5154 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
5155 * codepage.
5156 */
5157 char_u *from;
5158 size_t fromlen;
5159 char_u *to;
5160 int u8c;
5161 BOOL bad = FALSE;
5162 int needed;
5163
5164 if (ip->bw_restlen > 0)
5165 {
5166 /* Need to concatenate the remainder of the previous call and
5167 * the bytes of the current call. Use the end of the
5168 * conversion buffer for this. */
5169 fromlen = len + ip->bw_restlen;
5170 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5171 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5172 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5173 }
5174 else
5175 {
5176 from = buf;
5177 fromlen = len;
5178 }
5179
5180 to = ip->bw_conv_buf;
5181 if (enc_utf8)
5182 {
5183 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
5184 * The buffer has been allocated to be big enough. */
5185 while (fromlen > 0)
5186 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005187 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188 if (n > (int)fromlen) /* incomplete byte sequence */
5189 break;
5190 u8c = utf_ptr2char(from);
5191 *to++ = (u8c & 0xff);
5192 *to++ = (u8c >> 8);
5193 fromlen -= n;
5194 from += n;
5195 }
5196
5197 /* Copy remainder to ip->bw_rest[] to be used for the next
5198 * call. */
5199 if (fromlen > CONV_RESTLEN)
5200 {
5201 /* weird overlong sequence */
5202 ip->bw_conv_error = TRUE;
5203 return FAIL;
5204 }
5205 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005206 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005207 }
5208 else
5209 {
5210 /* Convert from enc_codepage to UCS-2, to the start of the
5211 * buffer. The buffer has been allocated to be big enough. */
5212 ip->bw_restlen = 0;
5213 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005214 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005215 NULL, 0);
5216 if (needed == 0)
5217 {
5218 /* When conversion fails there may be a trailing byte. */
5219 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005220 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 NULL, 0);
5222 if (needed == 0)
5223 {
5224 /* Conversion doesn't work. */
5225 ip->bw_conv_error = TRUE;
5226 return FAIL;
5227 }
5228 /* Save the trailing byte for the next call. */
5229 ip->bw_rest[0] = from[fromlen - 1];
5230 ip->bw_restlen = 1;
5231 }
5232 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005233 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234 (LPWSTR)to, needed);
5235 if (needed == 0)
5236 {
5237 /* Safety check: Conversion doesn't work. */
5238 ip->bw_conv_error = TRUE;
5239 return FAIL;
5240 }
5241 to += needed * 2;
5242 }
5243
5244 fromlen = to - ip->bw_conv_buf;
5245 buf = to;
5246# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5247 if (FIO_GET_CP(flags) == CP_UTF8)
5248 {
5249 /* Convert from UCS-2 to UTF-8, using the remainder of the
5250 * conversion buffer. Fails when out of space. */
5251 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5252 {
5253 u8c = *from++;
5254 u8c += (*from++ << 8);
5255 to += utf_char2bytes(u8c, to);
5256 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5257 {
5258 ip->bw_conv_error = TRUE;
5259 return FAIL;
5260 }
5261 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005262 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263 }
5264 else
5265#endif
5266 {
5267 /* Convert from UCS-2 to the codepage, using the remainder of
5268 * the conversion buffer. If the conversion uses the default
5269 * character "0", the data doesn't fit in this encoding, so
5270 * fail. */
5271 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5272 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005273 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
5274 &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275 if (bad)
5276 {
5277 ip->bw_conv_error = TRUE;
5278 return FAIL;
5279 }
5280 }
5281 }
5282# endif
5283
Bram Moolenaar56718732006-03-15 22:53:57 +00005284# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285 else if (flags & FIO_MACROMAN)
5286 {
5287 /*
5288 * Convert UTF-8 or latin1 to Apple MacRoman.
5289 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290 char_u *from;
5291 size_t fromlen;
5292
5293 if (ip->bw_restlen > 0)
5294 {
5295 /* Need to concatenate the remainder of the previous call and
5296 * the bytes of the current call. Use the end of the
5297 * conversion buffer for this. */
5298 fromlen = len + ip->bw_restlen;
5299 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5300 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5301 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5302 }
5303 else
5304 {
5305 from = buf;
5306 fromlen = len;
5307 }
5308
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005309 if (enc2macroman(from, fromlen,
5310 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5311 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005312 {
5313 ip->bw_conv_error = TRUE;
5314 return FAIL;
5315 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005316 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317 }
5318# endif
5319
5320# ifdef USE_ICONV
5321 if (ip->bw_iconv_fd != (iconv_t)-1)
5322 {
5323 const char *from;
5324 size_t fromlen;
5325 char *to;
5326 size_t tolen;
5327
5328 /* Convert with iconv(). */
5329 if (ip->bw_restlen > 0)
5330 {
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005331 char *fp;
5332
Bram Moolenaar071d4272004-06-13 20:20:40 +00005333 /* Need to concatenate the remainder of the previous call and
5334 * the bytes of the current call. Use the end of the
5335 * conversion buffer for this. */
5336 fromlen = len + ip->bw_restlen;
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005337 fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5338 mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
5339 mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
5340 from = fp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005341 tolen = ip->bw_conv_buflen - fromlen;
5342 }
5343 else
5344 {
5345 from = (const char *)buf;
5346 fromlen = len;
5347 tolen = ip->bw_conv_buflen;
5348 }
5349 to = (char *)ip->bw_conv_buf;
5350
5351 if (ip->bw_first)
5352 {
5353 size_t save_len = tolen;
5354
5355 /* output the initial shift state sequence */
5356 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5357
5358 /* There is a bug in iconv() on Linux (which appears to be
5359 * wide-spread) which sets "to" to NULL and messes up "tolen".
5360 */
5361 if (to == NULL)
5362 {
5363 to = (char *)ip->bw_conv_buf;
5364 tolen = save_len;
5365 }
5366 ip->bw_first = FALSE;
5367 }
5368
5369 /*
5370 * If iconv() has an error or there is not enough room, fail.
5371 */
5372 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5373 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5374 || fromlen > CONV_RESTLEN)
5375 {
5376 ip->bw_conv_error = TRUE;
5377 return FAIL;
5378 }
5379
5380 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5381 if (fromlen > 0)
5382 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5383 ip->bw_restlen = (int)fromlen;
5384
5385 buf = ip->bw_conv_buf;
5386 len = (int)((char_u *)to - ip->bw_conv_buf);
5387 }
5388# endif
5389 }
5390#endif /* FEAT_MBYTE */
5391
5392#ifdef FEAT_CRYPT
5393 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5394 {
5395 int ztemp, t, i;
5396
5397 for (i = 0; i < len; i++)
5398 {
5399 ztemp = buf[i];
5400 buf[i] = ZENCODE(ztemp, t);
5401 }
5402 }
5403#endif
5404
5405 /* Repeat the write(), it may be interrupted by a signal. */
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005406 while (len > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 {
5408 wlen = vim_write(ip->bw_fd, buf, len);
5409 if (wlen <= 0) /* error! */
5410 return FAIL;
5411 len -= wlen;
5412 buf += wlen;
5413 }
5414 return OK;
5415}
5416
5417#ifdef FEAT_MBYTE
5418/*
5419 * Convert a Unicode character to bytes.
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005420 * Return TRUE for an error, FALSE when it's OK.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005421 */
5422 static int
5423ucs2bytes(c, pp, flags)
5424 unsigned c; /* in: character */
5425 char_u **pp; /* in/out: pointer to result */
5426 int flags; /* FIO_ flags */
5427{
5428 char_u *p = *pp;
5429 int error = FALSE;
5430 int cc;
5431
5432
5433 if (flags & FIO_UCS4)
5434 {
5435 if (flags & FIO_ENDIAN_L)
5436 {
5437 *p++ = c;
5438 *p++ = (c >> 8);
5439 *p++ = (c >> 16);
5440 *p++ = (c >> 24);
5441 }
5442 else
5443 {
5444 *p++ = (c >> 24);
5445 *p++ = (c >> 16);
5446 *p++ = (c >> 8);
5447 *p++ = c;
5448 }
5449 }
5450 else if (flags & (FIO_UCS2 | FIO_UTF16))
5451 {
5452 if (c >= 0x10000)
5453 {
5454 if (flags & FIO_UTF16)
5455 {
5456 /* Make two words, ten bits of the character in each. First
5457 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5458 c -= 0x10000;
5459 if (c >= 0x100000)
5460 error = TRUE;
5461 cc = ((c >> 10) & 0x3ff) + 0xd800;
5462 if (flags & FIO_ENDIAN_L)
5463 {
5464 *p++ = cc;
5465 *p++ = ((unsigned)cc >> 8);
5466 }
5467 else
5468 {
5469 *p++ = ((unsigned)cc >> 8);
5470 *p++ = cc;
5471 }
5472 c = (c & 0x3ff) + 0xdc00;
5473 }
5474 else
5475 error = TRUE;
5476 }
5477 if (flags & FIO_ENDIAN_L)
5478 {
5479 *p++ = c;
5480 *p++ = (c >> 8);
5481 }
5482 else
5483 {
5484 *p++ = (c >> 8);
5485 *p++ = c;
5486 }
5487 }
5488 else /* Latin1 */
5489 {
5490 if (c >= 0x100)
5491 {
5492 error = TRUE;
5493 *p++ = 0xBF;
5494 }
5495 else
5496 *p++ = c;
5497 }
5498
5499 *pp = p;
5500 return error;
5501}
5502
5503/*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005504 * Return TRUE if file encoding "fenc" requires conversion from or to
5505 * 'encoding'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005506 */
5507 static int
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005508need_conversion(fenc)
5509 char_u *fenc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510{
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005511 int same_encoding;
5512 int enc_flags;
5513 int fenc_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005514
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005515 if (*fenc == NUL || STRCMP(p_enc, fenc) == 0)
5516 same_encoding = TRUE;
5517 else
5518 {
5519 /* Ignore difference between "ansi" and "latin1", "ucs-4" and
5520 * "ucs-4be", etc. */
5521 enc_flags = get_fio_flags(p_enc);
5522 fenc_flags = get_fio_flags(fenc);
5523 same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
5524 }
5525 if (same_encoding)
5526 {
5527 /* Specified encoding matches with 'encoding'. This requires
5528 * conversion when 'encoding' is Unicode but not UTF-8. */
5529 return enc_unicode != 0;
5530 }
5531
5532 /* Encodings differ. However, conversion is not needed when 'enc' is any
5533 * Unicode encoding and the file is UTF-8. */
5534 return !(enc_utf8 && fenc_flags == FIO_UTF8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005535}
5536
5537/*
5538 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5539 * internal conversion.
5540 * if "ptr" is an empty string, use 'encoding'.
5541 */
5542 static int
5543get_fio_flags(ptr)
5544 char_u *ptr;
5545{
5546 int prop;
5547
5548 if (*ptr == NUL)
5549 ptr = p_enc;
5550
5551 prop = enc_canon_props(ptr);
5552 if (prop & ENC_UNICODE)
5553 {
5554 if (prop & ENC_2BYTE)
5555 {
5556 if (prop & ENC_ENDIAN_L)
5557 return FIO_UCS2 | FIO_ENDIAN_L;
5558 return FIO_UCS2;
5559 }
5560 if (prop & ENC_4BYTE)
5561 {
5562 if (prop & ENC_ENDIAN_L)
5563 return FIO_UCS4 | FIO_ENDIAN_L;
5564 return FIO_UCS4;
5565 }
5566 if (prop & ENC_2WORD)
5567 {
5568 if (prop & ENC_ENDIAN_L)
5569 return FIO_UTF16 | FIO_ENDIAN_L;
5570 return FIO_UTF16;
5571 }
5572 return FIO_UTF8;
5573 }
5574 if (prop & ENC_LATIN1)
5575 return FIO_LATIN1;
5576 /* must be ENC_DBCS, requires iconv() */
5577 return 0;
5578}
5579
5580#ifdef WIN3264
5581/*
5582 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5583 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5584 * Used for conversion between 'encoding' and 'fileencoding'.
5585 */
5586 static int
5587get_win_fio_flags(ptr)
5588 char_u *ptr;
5589{
5590 int cp;
5591
5592 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5593 if (!enc_utf8 && enc_codepage <= 0)
5594 return 0;
5595
5596 cp = encname2codepage(ptr);
5597 if (cp == 0)
5598 {
5599# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5600 if (STRCMP(ptr, "utf-8") == 0)
5601 cp = CP_UTF8;
5602 else
5603# endif
5604 return 0;
5605 }
5606 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5607}
5608#endif
5609
5610#ifdef MACOS_X
5611/*
5612 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5613 * needed for the internal conversion to/from utf-8 or latin1.
5614 */
5615 static int
5616get_mac_fio_flags(ptr)
5617 char_u *ptr;
5618{
5619 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5620 && (enc_canon_props(ptr) & ENC_MACROMAN))
5621 return FIO_MACROMAN;
5622 return 0;
5623}
5624#endif
5625
5626/*
5627 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5628 * "size" must be at least 2.
5629 * Return the name of the encoding and set "*lenp" to the length.
5630 * Returns NULL when no BOM found.
5631 */
5632 static char_u *
5633check_for_bom(p, size, lenp, flags)
5634 char_u *p;
5635 long size;
5636 int *lenp;
5637 int flags;
5638{
5639 char *name = NULL;
5640 int len = 2;
5641
5642 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
Bram Moolenaaree0f5a62008-07-24 20:09:16 +00005643 && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644 {
5645 name = "utf-8"; /* EF BB BF */
5646 len = 3;
5647 }
5648 else if (p[0] == 0xff && p[1] == 0xfe)
5649 {
5650 if (size >= 4 && p[2] == 0 && p[3] == 0
5651 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5652 {
5653 name = "ucs-4le"; /* FF FE 00 00 */
5654 len = 4;
5655 }
Bram Moolenaar223a1892008-11-11 20:57:11 +00005656 else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657 name = "ucs-2le"; /* FF FE */
Bram Moolenaar223a1892008-11-11 20:57:11 +00005658 else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
5659 /* utf-16le is preferred, it also works for ucs-2le text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 name = "utf-16le"; /* FF FE */
5661 }
5662 else if (p[0] == 0xfe && p[1] == 0xff
5663 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5664 {
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005665 /* Default to utf-16, it works also for ucs-2 text. */
5666 if (flags == FIO_UCS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667 name = "ucs-2"; /* FE FF */
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005668 else
5669 name = "utf-16"; /* FE FF */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 }
5671 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5672 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5673 {
5674 name = "ucs-4"; /* 00 00 FE FF */
5675 len = 4;
5676 }
5677
5678 *lenp = len;
5679 return (char_u *)name;
5680}
5681
5682/*
5683 * Generate a BOM in "buf[4]" for encoding "name".
5684 * Return the length of the BOM (zero when no BOM).
5685 */
5686 static int
5687make_bom(buf, name)
5688 char_u *buf;
5689 char_u *name;
5690{
5691 int flags;
5692 char_u *p;
5693
5694 flags = get_fio_flags(name);
5695
5696 /* Can't put a BOM in a non-Unicode file. */
5697 if (flags == FIO_LATIN1 || flags == 0)
5698 return 0;
5699
5700 if (flags == FIO_UTF8) /* UTF-8 */
5701 {
5702 buf[0] = 0xef;
5703 buf[1] = 0xbb;
5704 buf[2] = 0xbf;
5705 return 3;
5706 }
5707 p = buf;
5708 (void)ucs2bytes(0xfeff, &p, flags);
5709 return (int)(p - buf);
5710}
5711#endif
5712
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00005713#if defined(FEAT_VIMINFO) || defined(FEAT_BROWSE) || \
Bram Moolenaara0174af2008-01-02 20:08:25 +00005714 defined(FEAT_QUICKFIX) || defined(FEAT_AUTOCMD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005715/*
5716 * Try to find a shortname by comparing the fullname with the current
5717 * directory.
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005718 * Returns "full_path" or pointer into "full_path" if shortened.
5719 */
5720 char_u *
5721shorten_fname1(full_path)
5722 char_u *full_path;
5723{
5724 char_u dirname[MAXPATHL];
5725 char_u *p = full_path;
5726
5727 if (mch_dirname(dirname, MAXPATHL) == OK)
5728 {
5729 p = shorten_fname(full_path, dirname);
5730 if (p == NULL || *p == NUL)
5731 p = full_path;
5732 }
5733 return p;
5734}
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00005735#endif
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005736
5737/*
5738 * Try to find a shortname by comparing the fullname with the current
5739 * directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740 * Returns NULL if not shorter name possible, pointer into "full_path"
5741 * otherwise.
5742 */
5743 char_u *
5744shorten_fname(full_path, dir_name)
5745 char_u *full_path;
5746 char_u *dir_name;
5747{
5748 int len;
5749 char_u *p;
5750
5751 if (full_path == NULL)
5752 return NULL;
5753 len = (int)STRLEN(dir_name);
5754 if (fnamencmp(dir_name, full_path, len) == 0)
5755 {
5756 p = full_path + len;
5757#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5758 /*
5759 * MSDOS: when a file is in the root directory, dir_name will end in a
5760 * slash, since C: by itself does not define a specific dir. In this
5761 * case p may already be correct. <negri>
5762 */
5763 if (!((len > 2) && (*(p - 2) == ':')))
5764#endif
5765 {
5766 if (vim_ispathsep(*p))
5767 ++p;
5768#ifndef VMS /* the path separator is always part of the path */
5769 else
5770 p = NULL;
5771#endif
5772 }
5773 }
5774#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5775 /*
5776 * When using a file in the current drive, remove the drive name:
5777 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5778 * a floppy from "A:\dir" to "B:\dir".
5779 */
5780 else if (len > 3
5781 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5782 && full_path[1] == ':'
5783 && vim_ispathsep(full_path[2]))
5784 p = full_path + 2;
5785#endif
5786 else
5787 p = NULL;
5788 return p;
5789}
5790
5791/*
5792 * Shorten filenames for all buffers.
5793 * When "force" is TRUE: Use full path from now on for files currently being
5794 * edited, both for file name and swap file name. Try to shorten the file
5795 * names a bit, if safe to do so.
5796 * When "force" is FALSE: Only try to shorten absolute file names.
5797 * For buffers that have buftype "nofile" or "scratch": never change the file
5798 * name.
5799 */
5800 void
5801shorten_fnames(force)
5802 int force;
5803{
5804 char_u dirname[MAXPATHL];
5805 buf_T *buf;
5806 char_u *p;
5807
5808 mch_dirname(dirname, MAXPATHL);
5809 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5810 {
5811 if (buf->b_fname != NULL
5812#ifdef FEAT_QUICKFIX
5813 && !bt_nofile(buf)
5814#endif
5815 && !path_with_url(buf->b_fname)
5816 && (force
5817 || buf->b_sfname == NULL
5818 || mch_isFullName(buf->b_sfname)))
5819 {
5820 vim_free(buf->b_sfname);
5821 buf->b_sfname = NULL;
5822 p = shorten_fname(buf->b_ffname, dirname);
5823 if (p != NULL)
5824 {
5825 buf->b_sfname = vim_strsave(p);
5826 buf->b_fname = buf->b_sfname;
5827 }
5828 if (p == NULL || buf->b_fname == NULL)
5829 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005830 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005831
5832 /* Always make the swap file name a full path, a "nofile" buffer may
5833 * also have a swap file. */
5834 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835 }
5836#ifdef FEAT_WINDOWS
5837 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005838 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839#endif
5840}
5841
5842#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5843 || defined(FEAT_GUI_MSWIN) \
5844 || defined(FEAT_GUI_MAC) \
5845 || defined(PROTO)
5846/*
5847 * Shorten all filenames in "fnames[count]" by current directory.
5848 */
5849 void
5850shorten_filenames(fnames, count)
5851 char_u **fnames;
5852 int count;
5853{
5854 int i;
5855 char_u dirname[MAXPATHL];
5856 char_u *p;
5857
5858 if (fnames == NULL || count < 1)
5859 return;
5860 mch_dirname(dirname, sizeof(dirname));
5861 for (i = 0; i < count; ++i)
5862 {
5863 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5864 {
5865 /* shorten_fname() returns pointer in given "fnames[i]". If free
5866 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5867 * "p" first then free fnames[i]. */
5868 p = vim_strsave(p);
5869 vim_free(fnames[i]);
5870 fnames[i] = p;
5871 }
5872 }
5873}
5874#endif
5875
5876/*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00005877 * add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878 * fo_o_h.ext for MSDOS or when shortname option set.
5879 *
5880 * Assumed that fname is a valid name found in the filesystem we assure that
5881 * the return value is a different name and ends in 'ext'.
5882 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5883 * characters otherwise.
5884 * Space for the returned name is allocated, must be freed later.
5885 * Returns NULL when out of memory.
5886 */
5887 char_u *
5888modname(fname, ext, prepend_dot)
5889 char_u *fname, *ext;
5890 int prepend_dot; /* may prepend a '.' to file name */
5891{
5892 return buf_modname(
5893#ifdef SHORT_FNAME
5894 TRUE,
5895#else
5896 (curbuf->b_p_sn || curbuf->b_shortname),
5897#endif
5898 fname, ext, prepend_dot);
5899}
5900
5901 char_u *
5902buf_modname(shortname, fname, ext, prepend_dot)
5903 int shortname; /* use 8.3 file name */
5904 char_u *fname, *ext;
5905 int prepend_dot; /* may prepend a '.' to file name */
5906{
5907 char_u *retval;
5908 char_u *s;
5909 char_u *e;
5910 char_u *ptr;
5911 int fnamelen, extlen;
5912
5913 extlen = (int)STRLEN(ext);
5914
5915 /*
5916 * If there is no file name we must get the name of the current directory
5917 * (we need the full path in case :cd is used).
5918 */
5919 if (fname == NULL || *fname == NUL)
5920 {
5921 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5922 if (retval == NULL)
5923 return NULL;
5924 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5925 (fnamelen = (int)STRLEN(retval)) == 0)
5926 {
5927 vim_free(retval);
5928 return NULL;
5929 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005930 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005931 {
5932 retval[fnamelen++] = PATHSEP;
5933 retval[fnamelen] = NUL;
5934 }
5935#ifndef SHORT_FNAME
5936 prepend_dot = FALSE; /* nothing to prepend a dot to */
5937#endif
5938 }
5939 else
5940 {
5941 fnamelen = (int)STRLEN(fname);
5942 retval = alloc((unsigned)(fnamelen + extlen + 3));
5943 if (retval == NULL)
5944 return NULL;
5945 STRCPY(retval, fname);
5946#ifdef VMS
5947 vms_remove_version(retval); /* we do not need versions here */
5948#endif
5949 }
5950
5951 /*
5952 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5953 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5954 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5955 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5956 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005957 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005958 {
5959#ifndef RISCOS
5960 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005961# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005963# else
5964# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005966# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005967# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005968 )
5969 if (*ptr == '.') /* replace '.' by '_' */
5970 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005971#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005972 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005973 {
5974 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005975 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005976 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005977 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978
5979 /* the file name has at most BASENAMELEN characters. */
5980#ifndef SHORT_FNAME
5981 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5982 ptr[BASENAMELEN] = '\0';
5983#endif
5984
5985 s = ptr + STRLEN(ptr);
5986
5987 /*
5988 * For 8.3 file names we may have to reduce the length.
5989 */
5990#ifdef USE_LONG_FNAME
5991 if (!USE_LONG_FNAME || shortname)
5992#else
5993# ifndef SHORT_FNAME
5994 if (shortname)
5995# endif
5996#endif
5997 {
5998 /*
5999 * If there is no file name, or the file name ends in '/', and the
6000 * extension starts with '.', put a '_' before the dot, because just
6001 * ".ext" is invalid.
6002 */
6003 if (fname == NULL || *fname == NUL
6004 || vim_ispathsep(fname[STRLEN(fname) - 1]))
6005 {
6006#ifdef RISCOS
6007 if (*ext == '/')
6008#else
6009 if (*ext == '.')
6010#endif
6011 *s++ = '_';
6012 }
6013 /*
6014 * If the extension starts with '.', truncate the base name at 8
6015 * characters
6016 */
6017#ifdef RISCOS
6018 /* We normally use '/', but swap files are '_' */
6019 else if (*ext == '/' || *ext == '_')
6020#else
6021 else if (*ext == '.')
6022#endif
6023 {
Bram Moolenaar78a15312009-05-15 19:33:18 +00006024 if ((size_t)(s - ptr) > (size_t)8)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025 {
6026 s = ptr + 8;
6027 *s = '\0';
6028 }
6029 }
6030 /*
6031 * If the extension doesn't start with '.', and the file name
6032 * doesn't have an extension yet, append a '.'
6033 */
6034#ifdef RISCOS
6035 else if ((e = vim_strchr(ptr, '/')) == NULL)
6036 *s++ = '/';
6037#else
6038 else if ((e = vim_strchr(ptr, '.')) == NULL)
6039 *s++ = '.';
6040#endif
6041 /*
6042 * If the extension doesn't start with '.', and there already is an
Bram Moolenaar7263a772007-05-10 17:35:54 +00006043 * extension, it may need to be truncated
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 */
6045 else if ((int)STRLEN(e) + extlen > 4)
6046 s = e + 4 - extlen;
6047 }
6048#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
6049 /*
6050 * If there is no file name, and the extension starts with '.', put a
6051 * '_' before the dot, because just ".ext" may be invalid if it's on a
6052 * FAT partition, and on HPFS it doesn't matter.
6053 */
6054 else if ((fname == NULL || *fname == NUL) && *ext == '.')
6055 *s++ = '_';
6056#endif
6057
6058 /*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006059 * Append the extension.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060 * ext can start with '.' and cannot exceed 3 more characters.
6061 */
6062 STRCPY(s, ext);
6063
6064#ifndef SHORT_FNAME
6065 /*
6066 * Prepend the dot.
6067 */
6068 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
6069#ifdef RISCOS
6070 '/'
6071#else
6072 '.'
6073#endif
6074#ifdef USE_LONG_FNAME
6075 && USE_LONG_FNAME
6076#endif
6077 )
6078 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006079 STRMOVE(e + 1, e);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006080#ifdef RISCOS
6081 *e = '/';
6082#else
6083 *e = '.';
6084#endif
6085 }
6086#endif
6087
6088 /*
6089 * Check that, after appending the extension, the file name is really
6090 * different.
6091 */
6092 if (fname != NULL && STRCMP(fname, retval) == 0)
6093 {
6094 /* we search for a character that can be replaced by '_' */
6095 while (--s >= ptr)
6096 {
6097 if (*s != '_')
6098 {
6099 *s = '_';
6100 break;
6101 }
6102 }
6103 if (s < ptr) /* fname was "________.<ext>", how tricky! */
6104 *ptr = 'v';
6105 }
6106 return retval;
6107}
6108
6109/*
6110 * Like fgets(), but if the file line is too long, it is truncated and the
6111 * rest of the line is thrown away. Returns TRUE for end-of-file.
6112 */
6113 int
6114vim_fgets(buf, size, fp)
6115 char_u *buf;
6116 int size;
6117 FILE *fp;
6118{
6119 char *eof;
6120#define FGETS_SIZE 200
6121 char tbuf[FGETS_SIZE];
6122
6123 buf[size - 2] = NUL;
6124#ifdef USE_CR
6125 eof = fgets_cr((char *)buf, size, fp);
6126#else
6127 eof = fgets((char *)buf, size, fp);
6128#endif
6129 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
6130 {
6131 buf[size - 1] = NUL; /* Truncate the line */
6132
6133 /* Now throw away the rest of the line: */
6134 do
6135 {
6136 tbuf[FGETS_SIZE - 2] = NUL;
6137#ifdef USE_CR
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00006138 ignoredp = fgets_cr((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139#else
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00006140 ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141#endif
6142 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
6143 }
6144 return (eof == NULL);
6145}
6146
6147#if defined(USE_CR) || defined(PROTO)
6148/*
6149 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
6150 * Returns TRUE for end-of-file.
6151 * Only used for the Mac, because it's much slower than vim_fgets().
6152 */
6153 int
6154tag_fgets(buf, size, fp)
6155 char_u *buf;
6156 int size;
6157 FILE *fp;
6158{
6159 int i = 0;
6160 int c;
6161 int eof = FALSE;
6162
6163 for (;;)
6164 {
6165 c = fgetc(fp);
6166 if (c == EOF)
6167 {
6168 eof = TRUE;
6169 break;
6170 }
6171 if (c == '\r')
6172 {
6173 /* Always store a NL for end-of-line. */
6174 if (i < size - 1)
6175 buf[i++] = '\n';
6176 c = fgetc(fp);
6177 if (c != '\n') /* Macintosh format: single CR. */
6178 ungetc(c, fp);
6179 break;
6180 }
6181 if (i < size - 1)
6182 buf[i++] = c;
6183 if (c == '\n')
6184 break;
6185 }
6186 buf[i] = NUL;
6187 return eof;
6188}
6189#endif
6190
6191/*
6192 * rename() only works if both files are on the same file system, this
6193 * function will (attempts to?) copy the file across if rename fails -- webb
6194 * Return -1 for failure, 0 for success.
6195 */
6196 int
6197vim_rename(from, to)
6198 char_u *from;
6199 char_u *to;
6200{
6201 int fd_in;
6202 int fd_out;
6203 int n;
6204 char *errmsg = NULL;
6205 char *buffer;
6206#ifdef AMIGA
6207 BPTR flock;
6208#endif
6209 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006210 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006211#ifdef HAVE_ACL
6212 vim_acl_T acl; /* ACL from original file */
6213#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006214#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
6215 int use_tmp_file = FALSE;
6216#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006217
6218 /*
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006219 * When the names are identical, there is nothing to do. When they refer
6220 * to the same file (ignoring case and slash/backslash differences) but
6221 * the file name differs we need to go through a temp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006222 */
6223 if (fnamecmp(from, to) == 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006224 {
6225#ifdef CASE_INSENSITIVE_FILENAME
6226 if (STRCMP(gettail(from), gettail(to)) != 0)
6227 use_tmp_file = TRUE;
6228 else
6229#endif
6230 return 0;
6231 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006232
6233 /*
6234 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
6235 */
6236 if (mch_stat((char *)from, &st) < 0)
6237 return -1;
6238
Bram Moolenaar3576da72008-12-30 15:15:57 +00006239#ifdef UNIX
6240 {
6241 struct stat st_to;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006242
6243 /* It's possible for the source and destination to be the same file.
6244 * This happens when "from" and "to" differ in case and are on a FAT32
6245 * filesystem. In that case go through a temp file name. */
6246 if (mch_stat((char *)to, &st_to) >= 0
6247 && st.st_dev == st_to.st_dev
6248 && st.st_ino == st_to.st_ino)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006249 use_tmp_file = TRUE;
6250 }
6251#endif
6252
6253#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
6254 if (use_tmp_file)
6255 {
6256 char tempname[MAXPATHL + 1];
6257
6258 /*
6259 * Find a name that doesn't exist and is in the same directory.
6260 * Rename "from" to "tempname" and then rename "tempname" to "to".
6261 */
6262 if (STRLEN(from) >= MAXPATHL - 5)
6263 return -1;
6264 STRCPY(tempname, from);
6265 for (n = 123; n < 99999; ++n)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006266 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006267 sprintf((char *)gettail((char_u *)tempname), "%d", n);
6268 if (mch_stat(tempname, &st) < 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006269 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006270 if (mch_rename((char *)from, tempname) == 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006271 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006272 if (mch_rename(tempname, (char *)to) == 0)
6273 return 0;
6274 /* Strange, the second step failed. Try moving the
6275 * file back and return failure. */
6276 mch_rename(tempname, (char *)from);
Bram Moolenaar3576da72008-12-30 15:15:57 +00006277 return -1;
6278 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006279 /* If it fails for one temp name it will most likely fail
6280 * for any temp name, give up. */
6281 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006282 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006283 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006284 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006285 }
6286#endif
6287
Bram Moolenaar071d4272004-06-13 20:20:40 +00006288 /*
6289 * Delete the "to" file, this is required on some systems to make the
6290 * mch_rename() work, on other systems it makes sure that we don't have
6291 * two files when the mch_rename() fails.
6292 */
6293
6294#ifdef AMIGA
6295 /*
6296 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
6297 * that the name of the "to" file is the same as the "from" file, even
Bram Moolenaar7263a772007-05-10 17:35:54 +00006298 * though the names are different. To avoid the chance of accidentally
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 * deleting the "from" file (horror!) we lock it during the remove.
6300 *
6301 * When used for making a backup before writing the file: This should not
6302 * happen with ":w", because startscript() should detect this problem and
6303 * set buf->b_shortname, causing modname() to return a correct ".bak" file
6304 * name. This problem does exist with ":w filename", but then the
6305 * original file will be somewhere else so the backup isn't really
6306 * important. If autoscripting is off the rename may fail.
6307 */
6308 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
6309#endif
6310 mch_remove(to);
6311#ifdef AMIGA
6312 if (flock)
6313 UnLock(flock);
6314#endif
6315
6316 /*
6317 * First try a normal rename, return if it works.
6318 */
6319 if (mch_rename((char *)from, (char *)to) == 0)
6320 return 0;
6321
6322 /*
6323 * Rename() failed, try copying the file.
6324 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006325 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006326#ifdef HAVE_ACL
6327 /* For systems that support ACL: get the ACL from the original file. */
6328 acl = mch_get_acl(from);
6329#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006330 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6331 if (fd_in == -1)
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006332 {
6333#ifdef HAVE_ACL
6334 mch_free_acl(acl);
6335#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006336 return -1;
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006337 }
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006338
6339 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006340 fd_out = mch_open((char *)to,
6341 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006342 if (fd_out == -1)
6343 {
6344 close(fd_in);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006345#ifdef HAVE_ACL
6346 mch_free_acl(acl);
6347#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006348 return -1;
6349 }
6350
6351 buffer = (char *)alloc(BUFSIZE);
6352 if (buffer == NULL)
6353 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006354 close(fd_out);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006355 close(fd_in);
6356#ifdef HAVE_ACL
6357 mch_free_acl(acl);
6358#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006359 return -1;
6360 }
6361
6362 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
6363 if (vim_write(fd_out, buffer, n) != n)
6364 {
6365 errmsg = _("E208: Error writing to \"%s\"");
6366 break;
6367 }
6368
6369 vim_free(buffer);
6370 close(fd_in);
6371 if (close(fd_out) < 0)
6372 errmsg = _("E209: Error closing \"%s\"");
6373 if (n < 0)
6374 {
6375 errmsg = _("E210: Error reading \"%s\"");
6376 to = from;
6377 }
Bram Moolenaar7263a772007-05-10 17:35:54 +00006378#ifndef UNIX /* for Unix mch_open() already set the permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006379 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006380#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006381#ifdef HAVE_ACL
6382 mch_set_acl(to, acl);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006383 mch_free_acl(acl);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006384#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006385 if (errmsg != NULL)
6386 {
6387 EMSG2(errmsg, to);
6388 return -1;
6389 }
6390 mch_remove(from);
6391 return 0;
6392}
6393
6394static int already_warned = FALSE;
6395
6396/*
6397 * Check if any not hidden buffer has been changed.
6398 * Postpone the check if there are characters in the stuff buffer, a global
6399 * command is being executed, a mapping is being executed or an autocommand is
6400 * busy.
6401 * Returns TRUE if some message was written (screen should be redrawn and
6402 * cursor positioned).
6403 */
6404 int
6405check_timestamps(focus)
6406 int focus; /* called for GUI focus event */
6407{
6408 buf_T *buf;
6409 int didit = 0;
6410 int n;
6411
6412 /* Don't check timestamps while system() or another low-level function may
6413 * cause us to lose and gain focus. */
6414 if (no_check_timestamps > 0)
6415 return FALSE;
6416
6417 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6418 * event and we would keep on checking if the file is steadily growing.
6419 * Do check again after typing something. */
6420 if (focus && did_check_timestamps)
6421 {
6422 need_check_timestamps = TRUE;
6423 return FALSE;
6424 }
6425
6426 if (!stuff_empty() || global_busy || !typebuf_typed()
6427#ifdef FEAT_AUTOCMD
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006428 || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006429#endif
6430 )
6431 need_check_timestamps = TRUE; /* check later */
6432 else
6433 {
6434 ++no_wait_return;
6435 did_check_timestamps = TRUE;
6436 already_warned = FALSE;
6437 for (buf = firstbuf; buf != NULL; )
6438 {
6439 /* Only check buffers in a window. */
6440 if (buf->b_nwindows > 0)
6441 {
6442 n = buf_check_timestamp(buf, focus);
6443 if (didit < n)
6444 didit = n;
6445 if (n > 0 && !buf_valid(buf))
6446 {
6447 /* Autocommands have removed the buffer, start at the
6448 * first one again. */
6449 buf = firstbuf;
6450 continue;
6451 }
6452 }
6453 buf = buf->b_next;
6454 }
6455 --no_wait_return;
6456 need_check_timestamps = FALSE;
6457 if (need_wait_return && didit == 2)
6458 {
6459 /* make sure msg isn't overwritten */
6460 msg_puts((char_u *)"\n");
6461 out_flush();
6462 }
6463 }
6464 return didit;
6465}
6466
6467/*
6468 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6469 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6470 * empty.
6471 */
6472 static int
6473move_lines(frombuf, tobuf)
6474 buf_T *frombuf;
6475 buf_T *tobuf;
6476{
6477 buf_T *tbuf = curbuf;
6478 int retval = OK;
6479 linenr_T lnum;
6480 char_u *p;
6481
6482 /* Copy the lines in "frombuf" to "tobuf". */
6483 curbuf = tobuf;
6484 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6485 {
6486 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6487 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6488 {
6489 vim_free(p);
6490 retval = FAIL;
6491 break;
6492 }
6493 vim_free(p);
6494 }
6495
6496 /* Delete all the lines in "frombuf". */
6497 if (retval != FAIL)
6498 {
6499 curbuf = frombuf;
Bram Moolenaar9460b9d2007-01-09 14:37:01 +00006500 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
6501 if (ml_delete(lnum, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502 {
6503 /* Oops! We could try putting back the saved lines, but that
6504 * might fail again... */
6505 retval = FAIL;
6506 break;
6507 }
6508 }
6509
6510 curbuf = tbuf;
6511 return retval;
6512}
6513
6514/*
6515 * Check if buffer "buf" has been changed.
6516 * Also check if the file for a new buffer unexpectedly appeared.
6517 * return 1 if a changed buffer was found.
6518 * return 2 if a message has been displayed.
6519 * return 0 otherwise.
6520 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006521 int
6522buf_check_timestamp(buf, focus)
6523 buf_T *buf;
Bram Moolenaar78a15312009-05-15 19:33:18 +00006524 int focus UNUSED; /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525{
6526 struct stat st;
6527 int stat_res;
6528 int retval = 0;
6529 char_u *path;
6530 char_u *tbuf;
6531 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006532 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 int helpmesg = FALSE;
6534 int reload = FALSE;
6535#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6536 int can_reload = FALSE;
6537#endif
6538 size_t orig_size = buf->b_orig_size;
6539 int orig_mode = buf->b_orig_mode;
6540#ifdef FEAT_GUI
6541 int save_mouse_correct = need_mouse_correct;
6542#endif
6543#ifdef FEAT_AUTOCMD
6544 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006545 int n;
6546 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006547#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006548 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006549
6550 /* If there is no file name, the buffer is not loaded, 'buftype' is
6551 * set, we are in the middle of a save or being called recursively: ignore
6552 * this buffer. */
6553 if (buf->b_ffname == NULL
6554 || buf->b_ml.ml_mfp == NULL
6555#if defined(FEAT_QUICKFIX)
6556 || *buf->b_p_bt != NUL
6557#endif
6558 || buf->b_saving
6559#ifdef FEAT_AUTOCMD
6560 || busy
6561#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006562#ifdef FEAT_NETBEANS_INTG
6563 || isNetbeansBuffer(buf)
6564#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565 )
6566 return 0;
6567
6568 if ( !(buf->b_flags & BF_NOTEDITED)
6569 && buf->b_mtime != 0
6570 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6571 || time_differs((long)st.st_mtime, buf->b_mtime)
6572#ifdef HAVE_ST_MODE
6573 || (int)st.st_mode != buf->b_orig_mode
6574#else
6575 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6576#endif
6577 ))
6578 {
6579 retval = 1;
6580
Bram Moolenaar316059c2006-01-14 21:18:42 +00006581 /* set b_mtime to stop further warnings (e.g., when executing
6582 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006583 if (stat_res < 0)
6584 {
6585 buf->b_mtime = 0;
6586 buf->b_orig_size = 0;
6587 buf->b_orig_mode = 0;
6588 }
6589 else
6590 buf_store_time(buf, &st, buf->b_ffname);
6591
6592 /* Don't do anything for a directory. Might contain the file
6593 * explorer. */
6594 if (mch_isdir(buf->b_fname))
6595 ;
6596
6597 /*
6598 * If 'autoread' is set, the buffer has no changes and the file still
6599 * exists, reload the buffer. Use the buffer-local option value if it
6600 * was set, the global option value otherwise.
6601 */
6602 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6603 && !bufIsChanged(buf) && stat_res >= 0)
6604 reload = TRUE;
6605 else
6606 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006607 if (stat_res < 0)
6608 reason = "deleted";
6609 else if (bufIsChanged(buf))
6610 reason = "conflict";
6611 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6612 reason = "changed";
6613 else if (orig_mode != buf->b_orig_mode)
6614 reason = "mode";
6615 else
6616 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006617
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006618#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006619 /*
6620 * Only give the warning if there are no FileChangedShell
6621 * autocommands.
6622 * Avoid being called recursively by setting "busy".
6623 */
6624 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006625# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006626 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6627 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006628# endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006629 ++allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006630 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6631 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006632 --allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006633 busy = FALSE;
6634 if (n)
6635 {
6636 if (!buf_valid(buf))
6637 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006638# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006639 s = get_vim_var_str(VV_FCS_CHOICE);
6640 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6641 reload = TRUE;
6642 else if (STRCMP(s, "ask") == 0)
6643 n = FALSE;
6644 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006645# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006646 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006648 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649#endif
6650 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006651 if (*reason == 'd')
6652 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006653 else
6654 {
6655 helpmesg = TRUE;
6656#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6657 can_reload = TRUE;
6658#endif
6659 /*
6660 * Check if the file contents really changed to avoid
6661 * giving a warning when only the timestamp was set (e.g.,
6662 * checked out of CVS). Always warn when the buffer was
6663 * changed.
6664 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006665 if (reason[2] == 'n')
6666 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006667 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006668 mesg2 = _("See \":help W12\" for more info.");
6669 }
6670 else if (reason[1] == 'h')
6671 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006672 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006673 mesg2 = _("See \":help W11\" for more info.");
6674 }
6675 else if (*reason == 'm')
6676 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006677 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006678 mesg2 = _("See \":help W16\" for more info.");
6679 }
Bram Moolenaar85388b52009-06-24 09:58:32 +00006680 else
6681 /* Only timestamp changed, store it to avoid a warning
6682 * in check_mtime() later. */
6683 buf->b_mtime_read = buf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006684 }
6685 }
6686 }
6687
6688 }
6689 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6690 && vim_fexists(buf->b_ffname))
6691 {
6692 retval = 1;
6693 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6694 buf->b_flags |= BF_NEW_W;
6695#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6696 can_reload = TRUE;
6697#endif
6698 }
6699
6700 if (mesg != NULL)
6701 {
6702 path = home_replace_save(buf, buf->b_fname);
6703 if (path != NULL)
6704 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006705 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006706 mesg2 = "";
6707 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6708 + STRLEN(mesg2) + 2));
6709 sprintf((char *)tbuf, mesg, path);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006710#ifdef FEAT_EVAL
6711 /* Set warningmsg here, before the unimportant and output-specific
6712 * mesg2 has been appended. */
6713 set_vim_var_string(VV_WARNINGMSG, tbuf, -1);
6714#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006715#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6716 if (can_reload)
6717 {
6718 if (*mesg2 != NUL)
6719 {
6720 STRCAT(tbuf, "\n");
6721 STRCAT(tbuf, mesg2);
6722 }
6723 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6724 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6725 reload = TRUE;
6726 }
6727 else
6728#endif
6729 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6730 {
6731 if (*mesg2 != NUL)
6732 {
6733 STRCAT(tbuf, "; ");
6734 STRCAT(tbuf, mesg2);
6735 }
6736 EMSG(tbuf);
6737 retval = 2;
6738 }
6739 else
6740 {
Bram Moolenaared203462004-06-16 11:19:22 +00006741# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006742 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006743# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744 {
6745 msg_start();
6746 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6747 if (*mesg2 != NUL)
6748 msg_puts_attr((char_u *)mesg2,
6749 hl_attr(HLF_W) + MSG_HIST);
6750 msg_clr_eos();
6751 (void)msg_end();
6752 if (emsg_silent == 0)
6753 {
6754 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006755# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006756 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006757# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006758 /* give the user some time to think about it */
6759 ui_delay(1000L, TRUE);
6760
6761 /* don't redraw and erase the message */
6762 redraw_cmdline = FALSE;
6763 }
6764 }
6765 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766 }
6767
6768 vim_free(path);
6769 vim_free(tbuf);
6770 }
6771 }
6772
6773 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006774 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006775 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006776
Bram Moolenaar56718732006-03-15 22:53:57 +00006777#ifdef FEAT_AUTOCMD
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006778 /* Trigger FileChangedShell when the file was changed in any way. */
6779 if (buf_valid(buf) && retval != 0)
Bram Moolenaar56718732006-03-15 22:53:57 +00006780 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6781 buf->b_fname, buf->b_fname, FALSE, buf);
6782#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006783#ifdef FEAT_GUI
6784 /* restore this in case an autocommand has set it; it would break
6785 * 'mousefocus' */
6786 need_mouse_correct = save_mouse_correct;
6787#endif
6788
6789 return retval;
6790}
6791
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006792/*
6793 * Reload a buffer that is already loaded.
6794 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006795 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6796 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006797 */
6798 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006799buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006800 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006801 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006802{
6803 exarg_T ea;
6804 pos_T old_cursor;
6805 linenr_T old_topline;
6806 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006807 buf_T *savebuf;
6808 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006809 aco_save_T aco;
6810
6811 /* set curwin/curbuf for "buf" and save some things */
6812 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006813
6814 /* We only want to read the text from the file, not reset the syntax
6815 * highlighting, clear marks, diff status, etc. Force the fileformat
6816 * and encoding to be the same. */
6817 if (prep_exarg(&ea, buf) == OK)
6818 {
6819 old_cursor = curwin->w_cursor;
6820 old_topline = curwin->w_topline;
6821
6822 /*
6823 * To behave like when a new file is edited (matters for
6824 * BufReadPost autocommands) we first need to delete the current
6825 * buffer contents. But if reading the file fails we should keep
6826 * the old contents. Can't use memory only, the file might be
6827 * too big. Use a hidden buffer to move the buffer contents to.
6828 */
6829 if (bufempty())
6830 savebuf = NULL;
6831 else
6832 {
6833 /* Allocate a buffer without putting it in the buffer list. */
6834 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006835 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006836 {
6837 /* Open the memline. */
6838 curbuf = savebuf;
6839 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006840 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006841 curbuf = buf;
6842 curwin->w_buffer = buf;
6843 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006844 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006845 || move_lines(buf, savebuf) == FAIL)
6846 {
6847 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6848 buf->b_fname);
6849 saved = FAIL;
6850 }
6851 }
6852
6853 if (saved == OK)
6854 {
6855 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6856#ifdef FEAT_AUTOCMD
6857 keep_filetype = TRUE; /* don't detect 'filetype' */
6858#endif
6859 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6860 (linenr_T)0,
6861 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6862 {
6863#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6864 if (!aborting())
6865#endif
6866 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006867 if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006868 {
6869 /* Put the text back from the save buffer. First
6870 * delete any lines that readfile() added. */
6871 while (!bufempty())
Bram Moolenaar8424a622006-04-19 21:23:36 +00006872 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006873 break;
6874 (void)move_lines(savebuf, buf);
6875 }
6876 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006877 else if (buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006878 {
6879 /* Mark the buffer as unmodified and free undo info. */
6880 unchanged(buf, TRUE);
6881 u_blockfree(buf);
6882 u_clearall(buf);
6883 }
6884 }
6885 vim_free(ea.cmd);
6886
Bram Moolenaar8424a622006-04-19 21:23:36 +00006887 if (savebuf != NULL && buf_valid(savebuf))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006888 wipe_buffer(savebuf, FALSE);
6889
6890#ifdef FEAT_DIFF
6891 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00006892 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006893#endif
6894
6895 /* Restore the topline and cursor position and check it (lines may
6896 * have been removed). */
6897 if (old_topline > curbuf->b_ml.ml_line_count)
6898 curwin->w_topline = curbuf->b_ml.ml_line_count;
6899 else
6900 curwin->w_topline = old_topline;
6901 curwin->w_cursor = old_cursor;
6902 check_cursor();
6903 update_topline();
6904#ifdef FEAT_AUTOCMD
6905 keep_filetype = FALSE;
6906#endif
6907#ifdef FEAT_FOLDING
6908 {
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00006909 win_T *wp;
6910 tabpage_T *tp;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006911
6912 /* Update folds unless they are defined manually. */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00006913 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006914 if (wp->w_buffer == curwin->w_buffer
6915 && !foldmethodIsManual(wp))
6916 foldUpdateAll(wp);
6917 }
6918#endif
6919 /* If the mode didn't change and 'readonly' was set, keep the old
6920 * value; the user probably used the ":view" command. But don't
6921 * reset it, might have had a read error. */
6922 if (orig_mode == curbuf->b_orig_mode)
6923 curbuf->b_p_ro |= old_ro;
6924 }
6925
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006926 /* restore curwin/curbuf and a few other things */
6927 aucmd_restbuf(&aco);
6928 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006929}
6930
Bram Moolenaar071d4272004-06-13 20:20:40 +00006931 void
6932buf_store_time(buf, st, fname)
6933 buf_T *buf;
6934 struct stat *st;
Bram Moolenaar78a15312009-05-15 19:33:18 +00006935 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006936{
6937 buf->b_mtime = (long)st->st_mtime;
6938 buf->b_orig_size = (size_t)st->st_size;
6939#ifdef HAVE_ST_MODE
6940 buf->b_orig_mode = (int)st->st_mode;
6941#else
6942 buf->b_orig_mode = mch_getperm(fname);
6943#endif
6944}
6945
6946/*
6947 * Adjust the line with missing eol, used for the next write.
6948 * Used for do_filter(), when the input lines for the filter are deleted.
6949 */
6950 void
6951write_lnum_adjust(offset)
6952 linenr_T offset;
6953{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006954 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006955 write_no_eol_lnum += offset;
6956}
6957
6958#if defined(TEMPDIRNAMES) || defined(PROTO)
6959static long temp_count = 0; /* Temp filename counter. */
6960
6961/*
6962 * Delete the temp directory and all files it contains.
6963 */
6964 void
6965vim_deltempdir()
6966{
6967 char_u **files;
6968 int file_count;
6969 int i;
6970
6971 if (vim_tempdir != NULL)
6972 {
6973 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6974 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6975 EW_DIR|EW_FILE|EW_SILENT) == OK)
6976 {
6977 for (i = 0; i < file_count; ++i)
6978 mch_remove(files[i]);
6979 FreeWild(file_count, files);
6980 }
6981 gettail(NameBuff)[-1] = NUL;
6982 (void)mch_rmdir(NameBuff);
6983
6984 vim_free(vim_tempdir);
6985 vim_tempdir = NULL;
6986 }
6987}
6988#endif
6989
6990/*
Bram Moolenaareaf03392009-11-17 11:08:52 +00006991 * Directory "tempdir" was created. Expand this name to a full path and put
6992 * it in "vim_tempdir". This avoids that using ":cd" would confuse us.
6993 * "tempdir" must be no longer than MAXPATHL.
6994 */
6995 static void
6996vim_settempdir(tempdir)
6997 char_u *tempdir;
6998{
6999 char_u *buf;
7000
7001 buf = alloc((unsigned)MAXPATHL + 2);
7002 if (buf != NULL)
7003 {
7004 if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
7005 STRCPY(buf, tempdir);
7006# ifdef __EMX__
7007 if (vim_strchr(buf, '/') != NULL)
7008 STRCAT(buf, "/");
7009 else
7010# endif
7011 add_pathsep(buf);
7012 vim_tempdir = vim_strsave(buf);
7013 vim_free(buf);
7014 }
7015}
7016
7017/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007018 * vim_tempname(): Return a unique name that can be used for a temp file.
7019 *
7020 * The temp file is NOT created.
7021 *
7022 * The returned pointer is to allocated memory.
7023 * The returned pointer is NULL if no valid name was found.
7024 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007025 char_u *
7026vim_tempname(extra_char)
Bram Moolenaar78a15312009-05-15 19:33:18 +00007027 int extra_char UNUSED; /* char to use in the name instead of '?' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007028{
7029#ifdef USE_TMPNAM
7030 char_u itmp[L_tmpnam]; /* use tmpnam() */
7031#else
7032 char_u itmp[TEMPNAMELEN];
7033#endif
7034
7035#ifdef TEMPDIRNAMES
7036 static char *(tempdirs[]) = {TEMPDIRNAMES};
7037 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038# ifndef EEXIST
7039 struct stat st;
7040# endif
7041
7042 /*
7043 * This will create a directory for private use by this instance of Vim.
7044 * This is done once, and the same directory is used for all temp files.
7045 * This method avoids security problems because of symlink attacks et al.
7046 * It's also a bit faster, because we only need to check for an existing
7047 * file when creating the directory and not for each temp file.
7048 */
7049 if (vim_tempdir == NULL)
7050 {
7051 /*
7052 * Try the entries in TEMPDIRNAMES to create the temp directory.
7053 */
Bram Moolenaar78a15312009-05-15 19:33:18 +00007054 for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007056 size_t itmplen;
7057# ifndef HAVE_MKDTEMP
7058 long nr;
7059 long off;
7060# endif
7061
Bram Moolenaar071d4272004-06-13 20:20:40 +00007062 /* expand $TMP, leave room for "/v1100000/999999999" */
7063 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
7064 if (mch_isdir(itmp)) /* directory exists */
7065 {
7066# ifdef __EMX__
7067 /* If $TMP contains a forward slash (perhaps using bash or
7068 * tcsh), don't add a backslash, use a forward slash!
7069 * Adding 2 backslashes didn't work. */
7070 if (vim_strchr(itmp, '/') != NULL)
7071 STRCAT(itmp, "/");
7072 else
7073# endif
7074 add_pathsep(itmp);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007075 itmplen = STRLEN(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076
Bram Moolenaareaf03392009-11-17 11:08:52 +00007077# ifdef HAVE_MKDTEMP
7078 /* Leave room for filename */
7079 STRCAT(itmp, "vXXXXXX");
7080 if (mkdtemp((char *)itmp) != NULL)
7081 vim_settempdir(itmp);
7082# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007083 /* Get an arbitrary number of up to 6 digits. When it's
7084 * unlikely that it already exists it will be faster,
7085 * otherwise it doesn't matter. The use of mkdir() avoids any
7086 * security problems because of the predictable number. */
7087 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
7088
7089 /* Try up to 10000 different values until we find a name that
7090 * doesn't exist. */
7091 for (off = 0; off < 10000L; ++off)
7092 {
7093 int r;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007094# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095 mode_t umask_save;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007096# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007097
Bram Moolenaareaf03392009-11-17 11:08:52 +00007098 sprintf((char *)itmp + itmplen, "v%ld", nr + off);
7099# ifndef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007100 /* If mkdir() does not set errno to EEXIST, check for
7101 * existing file here. There is a race condition then,
7102 * although it's fail-safe. */
7103 if (mch_stat((char *)itmp, &st) >= 0)
7104 continue;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007105# endif
7106# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007107 /* Make sure the umask doesn't remove the executable bit.
7108 * "repl" has been reported to use "177". */
7109 umask_save = umask(077);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007110# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007111 r = vim_mkdir(itmp, 0700);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007112# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007113 (void)umask(umask_save);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007114# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007115 if (r == 0)
7116 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007117 vim_settempdir(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007118 break;
7119 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007120# ifdef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121 /* If the mkdir() didn't fail because the file/dir exists,
7122 * we probably can't create any dir here, try another
7123 * place. */
7124 if (errno != EEXIST)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007125# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 break;
7127 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007128# endif /* HAVE_MKDTEMP */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007129 if (vim_tempdir != NULL)
7130 break;
7131 }
7132 }
7133 }
7134
7135 if (vim_tempdir != NULL)
7136 {
7137 /* There is no need to check if the file exists, because we own the
7138 * directory and nobody else creates a file in it. */
7139 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
7140 return vim_strsave(itmp);
7141 }
7142
7143 return NULL;
7144
7145#else /* TEMPDIRNAMES */
7146
7147# ifdef WIN3264
7148 char szTempFile[_MAX_PATH + 1];
7149 char buf4[4];
7150 char_u *retval;
7151 char_u *p;
7152
7153 STRCPY(itmp, "");
7154 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
7155 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
7156 strcpy(buf4, "VIM");
7157 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
7158 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
7159 return NULL;
7160 /* GetTempFileName() will create the file, we don't want that */
7161 (void)DeleteFile(itmp);
7162
7163 /* Backslashes in a temp file name cause problems when filtering with
7164 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
7165 * didn't set 'shellslash'. */
7166 retval = vim_strsave(itmp);
7167 if (*p_shcf == '-' || p_ssl)
7168 for (p = retval; *p; ++p)
7169 if (*p == '\\')
7170 *p = '/';
7171 return retval;
7172
7173# else /* WIN3264 */
7174
7175# ifdef USE_TMPNAM
7176 /* tmpnam() will make its own name */
7177 if (*tmpnam((char *)itmp) == NUL)
7178 return NULL;
7179# else
7180 char_u *p;
7181
7182# ifdef VMS_TEMPNAM
7183 /* mktemp() is not working on VMS. It seems to be
7184 * a do-nothing function. Therefore we use tempnam().
7185 */
7186 sprintf((char *)itmp, "VIM%c", extra_char);
7187 p = (char_u *)tempnam("tmp:", (char *)itmp);
7188 if (p != NULL)
7189 {
7190 /* VMS will use '.LOG' if we don't explicitly specify an extension,
7191 * and VIM will then be unable to find the file later */
7192 STRCPY(itmp, p);
7193 STRCAT(itmp, ".txt");
7194 free(p);
7195 }
7196 else
7197 return NULL;
7198# else
7199 STRCPY(itmp, TEMPNAME);
7200 if ((p = vim_strchr(itmp, '?')) != NULL)
7201 *p = extra_char;
7202 if (mktemp((char *)itmp) == NULL)
7203 return NULL;
7204# endif
7205# endif
7206
7207 return vim_strsave(itmp);
7208# endif /* WIN3264 */
7209#endif /* TEMPDIRNAMES */
7210}
7211
7212#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
7213/*
7214 * Convert all backslashes in fname to forward slashes in-place.
7215 */
7216 void
7217forward_slash(fname)
7218 char_u *fname;
7219{
7220 char_u *p;
7221
7222 for (p = fname; *p != NUL; ++p)
7223# ifdef FEAT_MBYTE
7224 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007225 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007226 ++p;
7227 else
7228# endif
7229 if (*p == '\\')
7230 *p = '/';
7231}
7232#endif
7233
7234
7235/*
7236 * Code for automatic commands.
7237 *
7238 * Only included when "FEAT_AUTOCMD" has been defined.
7239 */
7240
7241#if defined(FEAT_AUTOCMD) || defined(PROTO)
7242
7243/*
7244 * The autocommands are stored in a list for each event.
7245 * Autocommands for the same pattern, that are consecutive, are joined
7246 * together, to avoid having to match the pattern too often.
7247 * The result is an array of Autopat lists, which point to AutoCmd lists:
7248 *
7249 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
7250 * Autopat.cmds Autopat.cmds
7251 * | |
7252 * V V
7253 * AutoCmd.next AutoCmd.next
7254 * | |
7255 * V V
7256 * AutoCmd.next NULL
7257 * |
7258 * V
7259 * NULL
7260 *
7261 * first_autopat[1] --> Autopat.next --> NULL
7262 * Autopat.cmds
7263 * |
7264 * V
7265 * AutoCmd.next
7266 * |
7267 * V
7268 * NULL
7269 * etc.
7270 *
7271 * The order of AutoCmds is important, this is the order in which they were
7272 * defined and will have to be executed.
7273 */
7274typedef struct AutoCmd
7275{
7276 char_u *cmd; /* The command to be executed (NULL
7277 when command has been removed) */
7278 char nested; /* If autocommands nest here */
7279 char last; /* last command in list */
7280#ifdef FEAT_EVAL
7281 scid_T scriptID; /* script ID where defined */
7282#endif
7283 struct AutoCmd *next; /* Next AutoCmd in list */
7284} AutoCmd;
7285
7286typedef struct AutoPat
7287{
7288 int group; /* group ID */
7289 char_u *pat; /* pattern as typed (NULL when pattern
7290 has been removed) */
7291 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00007292 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007293 char allow_dirs; /* Pattern may match whole path */
7294 char last; /* last pattern for apply_autocmds() */
7295 AutoCmd *cmds; /* list of commands to do */
7296 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007297 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007298} AutoPat;
7299
7300static struct event_name
7301{
7302 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007303 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007304} event_names[] =
7305{
7306 {"BufAdd", EVENT_BUFADD},
7307 {"BufCreate", EVENT_BUFADD},
7308 {"BufDelete", EVENT_BUFDELETE},
7309 {"BufEnter", EVENT_BUFENTER},
7310 {"BufFilePost", EVENT_BUFFILEPOST},
7311 {"BufFilePre", EVENT_BUFFILEPRE},
7312 {"BufHidden", EVENT_BUFHIDDEN},
7313 {"BufLeave", EVENT_BUFLEAVE},
7314 {"BufNew", EVENT_BUFNEW},
7315 {"BufNewFile", EVENT_BUFNEWFILE},
7316 {"BufRead", EVENT_BUFREADPOST},
7317 {"BufReadCmd", EVENT_BUFREADCMD},
7318 {"BufReadPost", EVENT_BUFREADPOST},
7319 {"BufReadPre", EVENT_BUFREADPRE},
7320 {"BufUnload", EVENT_BUFUNLOAD},
7321 {"BufWinEnter", EVENT_BUFWINENTER},
7322 {"BufWinLeave", EVENT_BUFWINLEAVE},
7323 {"BufWipeout", EVENT_BUFWIPEOUT},
7324 {"BufWrite", EVENT_BUFWRITEPRE},
7325 {"BufWritePost", EVENT_BUFWRITEPOST},
7326 {"BufWritePre", EVENT_BUFWRITEPRE},
7327 {"BufWriteCmd", EVENT_BUFWRITECMD},
7328 {"CmdwinEnter", EVENT_CMDWINENTER},
7329 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007330 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007331 {"CursorHold", EVENT_CURSORHOLD},
7332 {"CursorHoldI", EVENT_CURSORHOLDI},
7333 {"CursorMoved", EVENT_CURSORMOVED},
7334 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007335 {"EncodingChanged", EVENT_ENCODINGCHANGED},
7336 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007337 {"FileAppendPost", EVENT_FILEAPPENDPOST},
7338 {"FileAppendPre", EVENT_FILEAPPENDPRE},
7339 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
7340 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
Bram Moolenaar56718732006-03-15 22:53:57 +00007341 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007342 {"FileChangedRO", EVENT_FILECHANGEDRO},
7343 {"FileReadPost", EVENT_FILEREADPOST},
7344 {"FileReadPre", EVENT_FILEREADPRE},
7345 {"FileReadCmd", EVENT_FILEREADCMD},
7346 {"FileType", EVENT_FILETYPE},
7347 {"FileWritePost", EVENT_FILEWRITEPOST},
7348 {"FileWritePre", EVENT_FILEWRITEPRE},
7349 {"FileWriteCmd", EVENT_FILEWRITECMD},
7350 {"FilterReadPost", EVENT_FILTERREADPOST},
7351 {"FilterReadPre", EVENT_FILTERREADPRE},
7352 {"FilterWritePost", EVENT_FILTERWRITEPOST},
7353 {"FilterWritePre", EVENT_FILTERWRITEPRE},
7354 {"FocusGained", EVENT_FOCUSGAINED},
7355 {"FocusLost", EVENT_FOCUSLOST},
7356 {"FuncUndefined", EVENT_FUNCUNDEFINED},
7357 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar265e5072006-08-29 16:13:22 +00007358 {"GUIFailed", EVENT_GUIFAILED},
Bram Moolenaar843ee412004-06-30 16:16:41 +00007359 {"InsertChange", EVENT_INSERTCHANGE},
7360 {"InsertEnter", EVENT_INSERTENTER},
7361 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00007362 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00007363 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
7364 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00007366 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar5c4bab02006-03-10 21:37:46 +00007367 {"ShellCmdPost", EVENT_SHELLCMDPOST},
7368 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaara2031822006-03-07 22:29:51 +00007369 {"SourcePre", EVENT_SOURCEPRE},
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00007370 {"SourceCmd", EVENT_SOURCECMD},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00007371 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007372 {"StdinReadPost", EVENT_STDINREADPOST},
7373 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00007374 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00007375 {"Syntax", EVENT_SYNTAX},
Bram Moolenaar70836c82006-02-20 21:28:49 +00007376 {"TabEnter", EVENT_TABENTER},
7377 {"TabLeave", EVENT_TABLEAVE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007378 {"TermChanged", EVENT_TERMCHANGED},
7379 {"TermResponse", EVENT_TERMRESPONSE},
7380 {"User", EVENT_USER},
7381 {"VimEnter", EVENT_VIMENTER},
7382 {"VimLeave", EVENT_VIMLEAVE},
7383 {"VimLeavePre", EVENT_VIMLEAVEPRE},
7384 {"WinEnter", EVENT_WINENTER},
7385 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar56718732006-03-15 22:53:57 +00007386 {"VimResized", EVENT_VIMRESIZED},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007387 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007388};
7389
7390static AutoPat *first_autopat[NUM_EVENTS] =
7391{
7392 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7393 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7394 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7395 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007396 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7397 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007398};
7399
7400/*
7401 * struct used to keep status while executing autocommands for an event.
7402 */
7403typedef struct AutoPatCmd
7404{
7405 AutoPat *curpat; /* next AutoPat to examine */
7406 AutoCmd *nextcmd; /* next AutoCmd to execute */
7407 int group; /* group being used */
7408 char_u *fname; /* fname to match with */
7409 char_u *sfname; /* sfname to match with */
7410 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007411 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007412 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7413 buf is deleted */
7414 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007415} AutoPatCmd;
7416
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007417static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007418
Bram Moolenaar071d4272004-06-13 20:20:40 +00007419/*
7420 * augroups stores a list of autocmd group names.
7421 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007422static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7424
7425/*
7426 * The ID of the current group. Group 0 is the default one.
7427 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007428static int current_augroup = AUGROUP_DEFAULT;
7429
7430static int au_need_clean = FALSE; /* need to delete marked patterns */
7431
Bram Moolenaar754b5602006-02-09 23:53:20 +00007432static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007433static void au_remove_pat __ARGS((AutoPat *ap));
7434static void au_remove_cmds __ARGS((AutoPat *ap));
7435static void au_cleanup __ARGS((void));
7436static int au_new_group __ARGS((char_u *name));
7437static void au_del_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007438static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7439static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007440static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007441static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007442static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007443static int do_autocmd_event __ARGS((event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007444static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007445static int apply_autocmds_group __ARGS((event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007446static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7447
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007448
Bram Moolenaar754b5602006-02-09 23:53:20 +00007449static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007450static int last_group;
Bram Moolenaar78ab3312007-09-29 12:16:41 +00007451static int autocmd_blocked = 0; /* block all autocmds */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007452
7453/*
7454 * Show the autocommands for one AutoPat.
7455 */
7456 static void
7457show_autocmd(ap, event)
7458 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007459 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007460{
7461 AutoCmd *ac;
7462
7463 /* Check for "got_int" (here and at various places below), which is set
7464 * when "q" has been hit for the "--more--" prompt */
7465 if (got_int)
7466 return;
7467 if (ap->pat == NULL) /* pattern has been removed */
7468 return;
7469
7470 msg_putchar('\n');
7471 if (got_int)
7472 return;
7473 if (event != last_event || ap->group != last_group)
7474 {
7475 if (ap->group != AUGROUP_DEFAULT)
7476 {
7477 if (AUGROUP_NAME(ap->group) == NULL)
7478 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7479 else
7480 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7481 msg_puts((char_u *)" ");
7482 }
7483 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7484 last_event = event;
7485 last_group = ap->group;
7486 msg_putchar('\n');
7487 if (got_int)
7488 return;
7489 }
7490 msg_col = 4;
7491 msg_outtrans(ap->pat);
7492
7493 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7494 {
7495 if (ac->cmd != NULL) /* skip removed commands */
7496 {
7497 if (msg_col >= 14)
7498 msg_putchar('\n');
7499 msg_col = 14;
7500 if (got_int)
7501 return;
7502 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007503#ifdef FEAT_EVAL
7504 if (p_verbose > 0)
7505 last_set_msg(ac->scriptID);
7506#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007507 if (got_int)
7508 return;
7509 if (ac->next != NULL)
7510 {
7511 msg_putchar('\n');
7512 if (got_int)
7513 return;
7514 }
7515 }
7516 }
7517}
7518
7519/*
7520 * Mark an autocommand pattern for deletion.
7521 */
7522 static void
7523au_remove_pat(ap)
7524 AutoPat *ap;
7525{
7526 vim_free(ap->pat);
7527 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007528 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007529 au_need_clean = TRUE;
7530}
7531
7532/*
7533 * Mark all commands for a pattern for deletion.
7534 */
7535 static void
7536au_remove_cmds(ap)
7537 AutoPat *ap;
7538{
7539 AutoCmd *ac;
7540
7541 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7542 {
7543 vim_free(ac->cmd);
7544 ac->cmd = NULL;
7545 }
7546 au_need_clean = TRUE;
7547}
7548
7549/*
7550 * Cleanup autocommands and patterns that have been deleted.
7551 * This is only done when not executing autocommands.
7552 */
7553 static void
7554au_cleanup()
7555{
7556 AutoPat *ap, **prev_ap;
7557 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007558 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007559
7560 if (autocmd_busy || !au_need_clean)
7561 return;
7562
7563 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007564 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7565 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007566 {
7567 /* loop over all autocommand patterns */
7568 prev_ap = &(first_autopat[(int)event]);
7569 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7570 {
7571 /* loop over all commands for this pattern */
7572 prev_ac = &(ap->cmds);
7573 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7574 {
7575 /* remove the command if the pattern is to be deleted or when
7576 * the command has been marked for deletion */
7577 if (ap->pat == NULL || ac->cmd == NULL)
7578 {
7579 *prev_ac = ac->next;
7580 vim_free(ac->cmd);
7581 vim_free(ac);
7582 }
7583 else
7584 prev_ac = &(ac->next);
7585 }
7586
7587 /* remove the pattern if it has been marked for deletion */
7588 if (ap->pat == NULL)
7589 {
7590 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007591 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007592 vim_free(ap);
7593 }
7594 else
7595 prev_ap = &(ap->next);
7596 }
7597 }
7598
7599 au_need_clean = FALSE;
7600}
7601
7602/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007603 * Called when buffer is freed, to remove/invalidate related buffer-local
7604 * autocmds.
7605 */
7606 void
7607aubuflocal_remove(buf)
7608 buf_T *buf;
7609{
7610 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007611 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007612 AutoPatCmd *apc;
7613
7614 /* invalidate currently executing autocommands */
7615 for (apc = active_apc_list; apc; apc = apc->next)
7616 if (buf->b_fnum == apc->arg_bufnr)
7617 apc->arg_bufnr = 0;
7618
7619 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007620 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7621 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007622 /* loop over all autocommand patterns */
7623 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7624 if (ap->buflocal_nr == buf->b_fnum)
7625 {
7626 au_remove_pat(ap);
7627 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007628 {
7629 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007630 smsg((char_u *)
7631 _("auto-removing autocommand: %s <buffer=%d>"),
7632 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007633 verbose_leave();
7634 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007635 }
7636 au_cleanup();
7637}
7638
7639/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640 * Add an autocmd group name.
7641 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7642 */
7643 static int
7644au_new_group(name)
7645 char_u *name;
7646{
7647 int i;
7648
7649 i = au_find_group(name);
7650 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7651 {
7652 /* First try using a free entry. */
7653 for (i = 0; i < augroups.ga_len; ++i)
7654 if (AUGROUP_NAME(i) == NULL)
7655 break;
7656 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7657 return AUGROUP_ERROR;
7658
7659 AUGROUP_NAME(i) = vim_strsave(name);
7660 if (AUGROUP_NAME(i) == NULL)
7661 return AUGROUP_ERROR;
7662 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007663 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007664 }
7665
7666 return i;
7667}
7668
7669 static void
7670au_del_group(name)
7671 char_u *name;
7672{
7673 int i;
7674
7675 i = au_find_group(name);
7676 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7677 EMSG2(_("E367: No such group: \"%s\""), name);
7678 else
7679 {
7680 vim_free(AUGROUP_NAME(i));
7681 AUGROUP_NAME(i) = NULL;
7682 }
7683}
7684
7685/*
7686 * Find the ID of an autocmd group name.
7687 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7688 */
7689 static int
7690au_find_group(name)
7691 char_u *name;
7692{
7693 int i;
7694
7695 for (i = 0; i < augroups.ga_len; ++i)
7696 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7697 return i;
7698 return AUGROUP_ERROR;
7699}
7700
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007701/*
7702 * Return TRUE if augroup "name" exists.
7703 */
7704 int
7705au_has_group(name)
7706 char_u *name;
7707{
7708 return au_find_group(name) != AUGROUP_ERROR;
7709}
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007710
Bram Moolenaar071d4272004-06-13 20:20:40 +00007711/*
7712 * ":augroup {name}".
7713 */
7714 void
7715do_augroup(arg, del_group)
7716 char_u *arg;
7717 int del_group;
7718{
7719 int i;
7720
7721 if (del_group)
7722 {
7723 if (*arg == NUL)
7724 EMSG(_(e_argreq));
7725 else
7726 au_del_group(arg);
7727 }
7728 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7729 current_augroup = AUGROUP_DEFAULT;
7730 else if (*arg) /* ":aug xxx": switch to group xxx */
7731 {
7732 i = au_new_group(arg);
7733 if (i != AUGROUP_ERROR)
7734 current_augroup = i;
7735 }
7736 else /* ":aug": list the group names */
7737 {
7738 msg_start();
7739 for (i = 0; i < augroups.ga_len; ++i)
7740 {
7741 if (AUGROUP_NAME(i) != NULL)
7742 {
7743 msg_puts(AUGROUP_NAME(i));
7744 msg_puts((char_u *)" ");
7745 }
7746 }
7747 msg_clr_eos();
7748 msg_end();
7749 }
7750}
7751
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007752#if defined(EXITFREE) || defined(PROTO)
7753 void
7754free_all_autocmds()
7755{
7756 for (current_augroup = -1; current_augroup < augroups.ga_len;
7757 ++current_augroup)
7758 do_autocmd((char_u *)"", TRUE);
7759 ga_clear_strings(&augroups);
7760}
7761#endif
7762
Bram Moolenaar071d4272004-06-13 20:20:40 +00007763/*
7764 * Return the event number for event name "start".
7765 * Return NUM_EVENTS if the event name was not found.
7766 * Return a pointer to the next event name in "end".
7767 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007768 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007769event_name2nr(start, end)
7770 char_u *start;
7771 char_u **end;
7772{
7773 char_u *p;
7774 int i;
7775 int len;
7776
7777 /* the event name ends with end of line, a blank or a comma */
7778 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7779 ;
7780 for (i = 0; event_names[i].name != NULL; ++i)
7781 {
7782 len = (int)STRLEN(event_names[i].name);
7783 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7784 break;
7785 }
7786 if (*p == ',')
7787 ++p;
7788 *end = p;
7789 if (event_names[i].name == NULL)
7790 return NUM_EVENTS;
7791 return event_names[i].event;
7792}
7793
7794/*
7795 * Return the name for event "event".
7796 */
7797 static char_u *
7798event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007799 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007800{
7801 int i;
7802
7803 for (i = 0; event_names[i].name != NULL; ++i)
7804 if (event_names[i].event == event)
7805 return (char_u *)event_names[i].name;
7806 return (char_u *)"Unknown";
7807}
7808
7809/*
7810 * Scan over the events. "*" stands for all events.
7811 */
7812 static char_u *
7813find_end_event(arg, have_group)
7814 char_u *arg;
7815 int have_group; /* TRUE when group name was found */
7816{
7817 char_u *pat;
7818 char_u *p;
7819
7820 if (*arg == '*')
7821 {
7822 if (arg[1] && !vim_iswhite(arg[1]))
7823 {
7824 EMSG2(_("E215: Illegal character after *: %s"), arg);
7825 return NULL;
7826 }
7827 pat = arg + 1;
7828 }
7829 else
7830 {
7831 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7832 {
7833 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7834 {
7835 if (have_group)
7836 EMSG2(_("E216: No such event: %s"), pat);
7837 else
7838 EMSG2(_("E216: No such group or event: %s"), pat);
7839 return NULL;
7840 }
7841 }
7842 }
7843 return pat;
7844}
7845
7846/*
7847 * Return TRUE if "event" is included in 'eventignore'.
7848 */
7849 static int
7850event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007851 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007852{
7853 char_u *p = p_ei;
7854
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007855 while (*p != NUL)
7856 {
7857 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7858 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007859 if (event_name2nr(p, &p) == event)
7860 return TRUE;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007861 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007862
7863 return FALSE;
7864}
7865
7866/*
7867 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7868 */
7869 int
7870check_ei()
7871{
7872 char_u *p = p_ei;
7873
Bram Moolenaar071d4272004-06-13 20:20:40 +00007874 while (*p)
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007875 {
7876 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7877 {
7878 p += 3;
7879 if (*p == ',')
7880 ++p;
7881 }
7882 else if (event_name2nr(p, &p) == NUM_EVENTS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007883 return FAIL;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007884 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007885
7886 return OK;
7887}
7888
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007889# if defined(FEAT_SYN_HL) || defined(PROTO)
7890
7891/*
7892 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7893 * buffer loaded into the window. "what" must start with a comma.
7894 * Returns the old value of 'eventignore' in allocated memory.
7895 */
7896 char_u *
7897au_event_disable(what)
7898 char *what;
7899{
7900 char_u *new_ei;
7901 char_u *save_ei;
7902
7903 save_ei = vim_strsave(p_ei);
7904 if (save_ei != NULL)
7905 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007906 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007907 if (new_ei != NULL)
7908 {
7909 STRCAT(new_ei, what);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007910 set_string_option_direct((char_u *)"ei", -1, new_ei,
7911 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007912 vim_free(new_ei);
7913 }
7914 }
7915 return save_ei;
7916}
7917
7918 void
7919au_event_restore(old_ei)
7920 char_u *old_ei;
7921{
7922 if (old_ei != NULL)
7923 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007924 set_string_option_direct((char_u *)"ei", -1, old_ei,
7925 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007926 vim_free(old_ei);
7927 }
7928}
7929# endif /* FEAT_SYN_HL */
7930
Bram Moolenaar071d4272004-06-13 20:20:40 +00007931/*
7932 * do_autocmd() -- implements the :autocmd command. Can be used in the
7933 * following ways:
7934 *
7935 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7936 * will be automatically executed for <event>
7937 * when editing a file matching <pat>, in
7938 * the current group.
7939 * :autocmd <event> <pat> Show the auto-commands associated with
7940 * <event> and <pat>.
7941 * :autocmd <event> Show the auto-commands associated with
7942 * <event>.
7943 * :autocmd Show all auto-commands.
7944 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7945 * <event> and <pat>, and add the command
7946 * <cmd>, for the current group.
7947 * :autocmd! <event> <pat> Remove all auto-commands associated with
7948 * <event> and <pat> for the current group.
7949 * :autocmd! <event> Remove all auto-commands associated with
7950 * <event> for the current group.
7951 * :autocmd! Remove ALL auto-commands for the current
7952 * group.
7953 *
7954 * Multiple events and patterns may be given separated by commas. Here are
7955 * some examples:
7956 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7957 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7958 *
7959 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007960 *
7961 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007962 */
7963 void
7964do_autocmd(arg, forceit)
7965 char_u *arg;
7966 int forceit;
7967{
7968 char_u *pat;
7969 char_u *envpat = NULL;
7970 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007971 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007972 int need_free = FALSE;
7973 int nested = FALSE;
7974 int group;
7975
7976 /*
7977 * Check for a legal group name. If not, use AUGROUP_ALL.
7978 */
7979 group = au_get_grouparg(&arg);
7980 if (arg == NULL) /* out of memory */
7981 return;
7982
7983 /*
7984 * Scan over the events.
7985 * If we find an illegal name, return here, don't do anything.
7986 */
7987 pat = find_end_event(arg, group != AUGROUP_ALL);
7988 if (pat == NULL)
7989 return;
7990
7991 /*
7992 * Scan over the pattern. Put a NUL at the end.
7993 */
7994 pat = skipwhite(pat);
7995 cmd = pat;
7996 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7997 cmd++;
7998 if (*cmd)
7999 *cmd++ = NUL;
8000
8001 /* Expand environment variables in the pattern. Set 'shellslash', we want
8002 * forward slashes here. */
8003 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
8004 {
8005#ifdef BACKSLASH_IN_FILENAME
8006 int p_ssl_save = p_ssl;
8007
8008 p_ssl = TRUE;
8009#endif
8010 envpat = expand_env_save(pat);
8011#ifdef BACKSLASH_IN_FILENAME
8012 p_ssl = p_ssl_save;
8013#endif
8014 if (envpat != NULL)
8015 pat = envpat;
8016 }
8017
8018 /*
8019 * Check for "nested" flag.
8020 */
8021 cmd = skipwhite(cmd);
8022 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
8023 {
8024 nested = TRUE;
8025 cmd = skipwhite(cmd + 6);
8026 }
8027
8028 /*
8029 * Find the start of the commands.
8030 * Expand <sfile> in it.
8031 */
8032 if (*cmd != NUL)
8033 {
8034 cmd = expand_sfile(cmd);
8035 if (cmd == NULL) /* some error */
8036 return;
8037 need_free = TRUE;
8038 }
8039
8040 /*
8041 * Print header when showing autocommands.
8042 */
8043 if (!forceit && *cmd == NUL)
8044 {
8045 /* Highlight title */
8046 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
8047 }
8048
8049 /*
8050 * Loop over the events.
8051 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00008052 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008053 last_group = AUGROUP_ERROR; /* for listing the group name */
8054 if (*arg == '*' || *arg == NUL)
8055 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00008056 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
8057 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008058 if (do_autocmd_event(event, pat,
8059 nested, cmd, forceit, group) == FAIL)
8060 break;
8061 }
8062 else
8063 {
8064 while (*arg && !vim_iswhite(*arg))
8065 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
8066 nested, cmd, forceit, group) == FAIL)
8067 break;
8068 }
8069
8070 if (need_free)
8071 vim_free(cmd);
8072 vim_free(envpat);
8073}
8074
8075/*
8076 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
8077 * The "argp" argument is advanced to the following argument.
8078 *
8079 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
8080 */
8081 static int
8082au_get_grouparg(argp)
8083 char_u **argp;
8084{
8085 char_u *group_name;
8086 char_u *p;
8087 char_u *arg = *argp;
8088 int group = AUGROUP_ALL;
8089
8090 p = skiptowhite(arg);
8091 if (p > arg)
8092 {
8093 group_name = vim_strnsave(arg, (int)(p - arg));
8094 if (group_name == NULL) /* out of memory */
8095 return AUGROUP_ERROR;
8096 group = au_find_group(group_name);
8097 if (group == AUGROUP_ERROR)
8098 group = AUGROUP_ALL; /* no match, use all groups */
8099 else
8100 *argp = skipwhite(p); /* match, skip over group name */
8101 vim_free(group_name);
8102 }
8103 return group;
8104}
8105
8106/*
8107 * do_autocmd() for one event.
8108 * If *pat == NUL do for all patterns.
8109 * If *cmd == NUL show entries.
8110 * If forceit == TRUE delete entries.
8111 * If group is not AUGROUP_ALL, only use this group.
8112 */
8113 static int
8114do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008115 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008116 char_u *pat;
8117 int nested;
8118 char_u *cmd;
8119 int forceit;
8120 int group;
8121{
8122 AutoPat *ap;
8123 AutoPat **prev_ap;
8124 AutoCmd *ac;
8125 AutoCmd **prev_ac;
8126 int brace_level;
8127 char_u *endpat;
8128 int findgroup;
8129 int allgroups;
8130 int patlen;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00008131 int is_buflocal;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008132 int buflocal_nr;
8133 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008134
8135 if (group == AUGROUP_ALL)
8136 findgroup = current_augroup;
8137 else
8138 findgroup = group;
8139 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
8140
8141 /*
8142 * Show or delete all patterns for an event.
8143 */
8144 if (*pat == NUL)
8145 {
8146 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8147 {
8148 if (forceit) /* delete the AutoPat, if it's in the current group */
8149 {
8150 if (ap->group == findgroup)
8151 au_remove_pat(ap);
8152 }
8153 else if (group == AUGROUP_ALL || ap->group == group)
8154 show_autocmd(ap, event);
8155 }
8156 }
8157
8158 /*
8159 * Loop through all the specified patterns.
8160 */
8161 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
8162 {
8163 /*
8164 * Find end of the pattern.
8165 * Watch out for a comma in braces, like "*.\{obj,o\}".
8166 */
8167 brace_level = 0;
8168 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
8169 || endpat[-1] == '\\'); ++endpat)
8170 {
8171 if (*endpat == '{')
8172 brace_level++;
8173 else if (*endpat == '}')
8174 brace_level--;
8175 }
8176 if (pat == endpat) /* ignore single comma */
8177 continue;
8178 patlen = (int)(endpat - pat);
8179
8180 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008181 * detect special <buflocal[=X]> buffer-local patterns
8182 */
8183 is_buflocal = FALSE;
8184 buflocal_nr = 0;
8185
8186 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
8187 && pat[patlen - 1] == '>')
8188 {
8189 /* Error will be printed only for addition. printing and removing
8190 * will proceed silently. */
8191 is_buflocal = TRUE;
8192 if (patlen == 8)
8193 buflocal_nr = curbuf->b_fnum;
8194 else if (patlen > 9 && pat[7] == '=')
8195 {
8196 /* <buffer=abuf> */
8197 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
8198 buflocal_nr = autocmd_bufnr;
8199 /* <buffer=123> */
8200 else if (skipdigits(pat + 8) == pat + patlen - 1)
8201 buflocal_nr = atoi((char *)pat + 8);
8202 }
8203 }
8204
8205 if (is_buflocal)
8206 {
8207 /* normalize pat into standard "<buffer>#N" form */
8208 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
8209 pat = buflocal_pat; /* can modify pat and patlen */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00008210 patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008211 }
8212
8213 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008214 * Find AutoPat entries with this pattern.
8215 */
8216 prev_ap = &first_autopat[(int)event];
8217 while ((ap = *prev_ap) != NULL)
8218 {
8219 if (ap->pat != NULL)
8220 {
8221 /* Accept a pattern when:
8222 * - a group was specified and it's that group, or a group was
8223 * not specified and it's the current group, or a group was
8224 * not specified and we are listing
8225 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008226 * - the pattern matches.
8227 * For <buffer[=X]>, this condition works because we normalize
8228 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008229 */
8230 if ((allgroups || ap->group == findgroup)
8231 && ap->patlen == patlen
8232 && STRNCMP(pat, ap->pat, patlen) == 0)
8233 {
8234 /*
8235 * Remove existing autocommands.
8236 * If adding any new autocmd's for this AutoPat, don't
8237 * delete the pattern from the autopat list, append to
8238 * this list.
8239 */
8240 if (forceit)
8241 {
8242 if (*cmd != NUL && ap->next == NULL)
8243 {
8244 au_remove_cmds(ap);
8245 break;
8246 }
8247 au_remove_pat(ap);
8248 }
8249
8250 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008251 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00008252 */
8253 else if (*cmd == NUL)
8254 show_autocmd(ap, event);
8255
8256 /*
8257 * Add autocmd to this autopat, if it's the last one.
8258 */
8259 else if (ap->next == NULL)
8260 break;
8261 }
8262 }
8263 prev_ap = &ap->next;
8264 }
8265
8266 /*
8267 * Add a new command.
8268 */
8269 if (*cmd != NUL)
8270 {
8271 /*
8272 * If the pattern we want to add a command to does appear at the
8273 * end of the list (or not is not in the list at all), add the
8274 * pattern at the end of the list.
8275 */
8276 if (ap == NULL)
8277 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008278 /* refuse to add buffer-local ap if buffer number is invalid */
8279 if (is_buflocal && (buflocal_nr == 0
8280 || buflist_findnr(buflocal_nr) == NULL))
8281 {
8282 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
8283 buflocal_nr);
8284 return FAIL;
8285 }
8286
Bram Moolenaar071d4272004-06-13 20:20:40 +00008287 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
8288 if (ap == NULL)
8289 return FAIL;
8290 ap->pat = vim_strnsave(pat, patlen);
8291 ap->patlen = patlen;
8292 if (ap->pat == NULL)
8293 {
8294 vim_free(ap);
8295 return FAIL;
8296 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008297
8298 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008299 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008300 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008301 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008302 }
8303 else
8304 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00008305 char_u *reg_pat;
8306
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008307 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008308 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008309 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008310 if (reg_pat != NULL)
8311 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00008312 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008313 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008314 {
8315 vim_free(ap->pat);
8316 vim_free(ap);
8317 return FAIL;
8318 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008319 }
8320 ap->cmds = NULL;
8321 *prev_ap = ap;
8322 ap->next = NULL;
8323 if (group == AUGROUP_ALL)
8324 ap->group = current_augroup;
8325 else
8326 ap->group = group;
8327 }
8328
8329 /*
8330 * Add the autocmd at the end of the AutoCmd list.
8331 */
8332 prev_ac = &(ap->cmds);
8333 while ((ac = *prev_ac) != NULL)
8334 prev_ac = &ac->next;
8335 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
8336 if (ac == NULL)
8337 return FAIL;
8338 ac->cmd = vim_strsave(cmd);
8339#ifdef FEAT_EVAL
8340 ac->scriptID = current_SID;
8341#endif
8342 if (ac->cmd == NULL)
8343 {
8344 vim_free(ac);
8345 return FAIL;
8346 }
8347 ac->next = NULL;
8348 *prev_ac = ac;
8349 ac->nested = nested;
8350 }
8351 }
8352
8353 au_cleanup(); /* may really delete removed patterns/commands now */
8354 return OK;
8355}
8356
8357/*
8358 * Implementation of ":doautocmd [group] event [fname]".
8359 * Return OK for success, FAIL for failure;
8360 */
8361 int
8362do_doautocmd(arg, do_msg)
8363 char_u *arg;
8364 int do_msg; /* give message for no matching autocmds? */
8365{
8366 char_u *fname;
8367 int nothing_done = TRUE;
8368 int group;
8369
8370 /*
8371 * Check for a legal group name. If not, use AUGROUP_ALL.
8372 */
8373 group = au_get_grouparg(&arg);
8374 if (arg == NULL) /* out of memory */
8375 return FAIL;
8376
8377 if (*arg == '*')
8378 {
8379 EMSG(_("E217: Can't execute autocommands for ALL events"));
8380 return FAIL;
8381 }
8382
8383 /*
8384 * Scan over the events.
8385 * If we find an illegal name, return here, don't do anything.
8386 */
8387 fname = find_end_event(arg, group != AUGROUP_ALL);
8388 if (fname == NULL)
8389 return FAIL;
8390
8391 fname = skipwhite(fname);
8392
8393 /*
8394 * Loop over the events.
8395 */
8396 while (*arg && !vim_iswhite(*arg))
8397 if (apply_autocmds_group(event_name2nr(arg, &arg),
8398 fname, NULL, TRUE, group, curbuf, NULL))
8399 nothing_done = FALSE;
8400
8401 if (nothing_done && do_msg)
8402 MSG(_("No matching autocommands"));
8403
8404#ifdef FEAT_EVAL
8405 return aborting() ? FAIL : OK;
8406#else
8407 return OK;
8408#endif
8409}
8410
8411/*
8412 * ":doautoall": execute autocommands for each loaded buffer.
8413 */
8414 void
8415ex_doautoall(eap)
8416 exarg_T *eap;
8417{
8418 int retval;
8419 aco_save_T aco;
8420 buf_T *buf;
8421
8422 /*
8423 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8424 * equal to curbuf, but for some buffers there may not be a window.
8425 * So we change the buffer for the current window for a moment. This
8426 * gives problems when the autocommands make changes to the list of
8427 * buffers or windows...
8428 */
8429 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8430 {
Bram Moolenaar3a847972008-07-08 09:36:58 +00008431 if (buf->b_ml.ml_mfp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008432 {
8433 /* find a window for this buffer and save some values */
8434 aucmd_prepbuf(&aco, buf);
8435
8436 /* execute the autocommands for this buffer */
8437 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaareeefcc72007-05-01 21:21:21 +00008438
8439 /* Execute the modeline settings, but don't set window-local
8440 * options if we are using the current window for another buffer. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008441 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008442
8443 /* restore the current window */
8444 aucmd_restbuf(&aco);
8445
8446 /* stop if there is some error or buffer was deleted */
8447 if (retval == FAIL || !buf_valid(buf))
8448 break;
8449 }
8450 }
8451
8452 check_cursor(); /* just in case lines got deleted */
8453}
8454
8455/*
8456 * Prepare for executing autocommands for (hidden) buffer "buf".
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008457 * Search for a visible window containing the current buffer. If there isn't
8458 * one then use "aucmd_win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00008459 * Set "curbuf" and "curwin" to match "buf".
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008460 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008461 */
8462 void
8463aucmd_prepbuf(aco, buf)
8464 aco_save_T *aco; /* structure to save values in */
8465 buf_T *buf; /* new curbuf */
8466{
8467 win_T *win;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008468#ifdef FEAT_WINDOWS
8469 int save_ea;
8470#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008471
8472 /* Find a window that is for the new buffer */
8473 if (buf == curbuf) /* be quick when buf is curbuf */
8474 win = curwin;
8475 else
8476#ifdef FEAT_WINDOWS
8477 for (win = firstwin; win != NULL; win = win->w_next)
8478 if (win->w_buffer == buf)
8479 break;
8480#else
8481 win = NULL;
8482#endif
8483
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008484 /* Allocate "aucmd_win" when needed. If this fails (out of memory) fall
8485 * back to using the current window. */
8486 if (win == NULL && aucmd_win == NULL)
8487 {
8488 win_alloc_aucmd_win();
8489 if (aucmd_win == NULL)
8490 win = curwin;
8491 }
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008492 if (win == NULL && aucmd_win_used)
8493 /* Strange recursive autocommand, fall back to using the current
8494 * window. Expect a few side effects... */
8495 win = curwin;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008496
8497 aco->save_curwin = curwin;
8498 aco->save_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008499 if (win != NULL)
8500 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008501 /* There is a window for "buf" in the current tab page, make it the
8502 * curwin. This is preferred, it has the least side effects (esp. if
8503 * "buf" is curbuf). */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008504 aco->use_aucmd_win = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008505 curwin = win;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008506 }
8507 else
8508 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008509 /* There is no window for "buf", use "aucmd_win". To minimize the side
8510 * effects, insert it in a the current tab page.
8511 * Anything related to a window (e.g., setting folds) may have
8512 * unexpected results. */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008513 aco->use_aucmd_win = TRUE;
8514 aucmd_win_used = TRUE;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008515 aucmd_win->w_buffer = buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008516 ++buf->b_nwindows;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008517 win_init_empty(aucmd_win); /* set cursor and topline to safe values */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008518 vim_free(aucmd_win->w_localdir);
8519 aucmd_win->w_localdir = NULL;
8520
8521 /* Make sure w_localdir and globaldir are NULL to avoid a chdir() in
8522 * win_enter_ext(). */
8523 aucmd_win->w_localdir = NULL;
8524 aco->globaldir = globaldir;
8525 globaldir = NULL;
8526
Bram Moolenaar071d4272004-06-13 20:20:40 +00008527
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008528#ifdef FEAT_WINDOWS
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008529 /* Split the current window, put the aucmd_win in the upper half.
8530 * We don't want the BufEnter or WinEnter autocommands. */
8531 block_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008532 make_snapshot(SNAP_AUCMD_IDX);
8533 save_ea = p_ea;
8534 p_ea = FALSE;
8535 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
8536 (void)win_comp_pos(); /* recompute window positions */
8537 p_ea = save_ea;
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008538 unblock_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008539#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008540 curwin = aucmd_win;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008541 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008542 curbuf = buf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008543 aco->new_curwin = curwin;
8544 aco->new_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008545}
8546
8547/*
8548 * Cleanup after executing autocommands for a (hidden) buffer.
8549 * Restore the window as it was (if possible).
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008550 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008551 */
8552 void
8553aucmd_restbuf(aco)
8554 aco_save_T *aco; /* structure holding saved values */
8555{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008556#ifdef FEAT_WINDOWS
8557 int dummy;
8558#endif
8559
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008560 if (aco->use_aucmd_win)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008561 {
8562 --curbuf->b_nwindows;
8563#ifdef FEAT_WINDOWS
8564 /* Find "aucmd_win", it can't be closed, but it may be in another tab
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008565 * page. Do not trigger autocommands here. */
8566 block_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008567 if (curwin != aucmd_win)
8568 {
8569 tabpage_T *tp;
8570 win_T *wp;
8571
8572 FOR_ALL_TAB_WINDOWS(tp, wp)
8573 {
8574 if (wp == aucmd_win)
8575 {
8576 if (tp != curtab)
8577 goto_tabpage_tp(tp);
8578 win_goto(aucmd_win);
8579 break;
8580 }
8581 }
8582 }
8583
8584 /* Remove the window and frame from the tree of frames. */
8585 (void)winframe_remove(curwin, &dummy, NULL);
8586 win_remove(curwin, NULL);
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008587 aucmd_win_used = FALSE;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008588 last_status(FALSE); /* may need to remove last status line */
8589 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
8590 (void)win_comp_pos(); /* recompute window positions */
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008591 unblock_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008592
8593 if (win_valid(aco->save_curwin))
8594 curwin = aco->save_curwin;
8595 else
8596 /* Hmm, original window disappeared. Just use the first one. */
8597 curwin = firstwin;
8598# ifdef FEAT_EVAL
8599 vars_clear(&aucmd_win->w_vars.dv_hashtab); /* free all w: variables */
8600# endif
8601#else
8602 curwin = aco->save_curwin;
8603#endif
8604 curbuf = curwin->w_buffer;
8605
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008606 vim_free(globaldir);
8607 globaldir = aco->globaldir;
8608
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008609 /* the buffer contents may have changed */
8610 check_cursor();
8611 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
8612 {
8613 curwin->w_topline = curbuf->b_ml.ml_line_count;
8614#ifdef FEAT_DIFF
8615 curwin->w_topfill = 0;
8616#endif
8617 }
8618#if defined(FEAT_GUI)
8619 /* Hide the scrollbars from the aucmd_win and update. */
8620 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
8621 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
8622 gui_may_update_scrollbars();
8623#endif
8624 }
8625 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008626 {
8627 /* restore curwin */
8628#ifdef FEAT_WINDOWS
8629 if (win_valid(aco->save_curwin))
8630#endif
8631 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008632 /* Restore the buffer which was previously edited by curwin, if
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008633 * it was changed, we are still the same window and the buffer is
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008634 * valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008635 if (curwin == aco->new_curwin
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008636 && curbuf != aco->new_curbuf
8637 && buf_valid(aco->new_curbuf)
8638 && aco->new_curbuf->b_ml.ml_mfp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008639 {
8640 --curbuf->b_nwindows;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008641 curbuf = aco->new_curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008642 curwin->w_buffer = curbuf;
8643 ++curbuf->b_nwindows;
8644 }
8645
8646 curwin = aco->save_curwin;
8647 curbuf = curwin->w_buffer;
8648 }
8649 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008650}
8651
8652static int autocmd_nested = FALSE;
8653
8654/*
8655 * Execute autocommands for "event" and file name "fname".
8656 * Return TRUE if some commands were executed.
8657 */
8658 int
8659apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008660 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008661 char_u *fname; /* NULL or empty means use actual file name */
8662 char_u *fname_io; /* fname to use for <afile> on cmdline */
8663 int force; /* when TRUE, ignore autocmd_busy */
8664 buf_T *buf; /* buffer for <abuf> */
8665{
8666 return apply_autocmds_group(event, fname, fname_io, force,
8667 AUGROUP_ALL, buf, NULL);
8668}
8669
8670/*
8671 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8672 * setting v:filearg.
8673 */
8674 static int
8675apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008676 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008677 char_u *fname;
8678 char_u *fname_io;
8679 int force;
8680 buf_T *buf;
8681 exarg_T *eap;
8682{
8683 return apply_autocmds_group(event, fname, fname_io, force,
8684 AUGROUP_ALL, buf, eap);
8685}
8686
8687/*
8688 * Like apply_autocmds(), but handles the caller's retval. If the script
8689 * processing is being aborted or if retval is FAIL when inside a try
8690 * conditional, no autocommands are executed. If otherwise the autocommands
8691 * cause the script to be aborted, retval is set to FAIL.
8692 */
8693 int
8694apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008695 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008696 char_u *fname; /* NULL or empty means use actual file name */
8697 char_u *fname_io; /* fname to use for <afile> on cmdline */
8698 int force; /* when TRUE, ignore autocmd_busy */
8699 buf_T *buf; /* buffer for <abuf> */
8700 int *retval; /* pointer to caller's retval */
8701{
8702 int did_cmd;
8703
Bram Moolenaar1e015462005-09-25 22:16:38 +00008704#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008705 if (should_abort(*retval))
8706 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008707#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008708
8709 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8710 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008711 if (did_cmd
8712#ifdef FEAT_EVAL
8713 && aborting()
8714#endif
8715 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008716 *retval = FAIL;
8717 return did_cmd;
8718}
8719
Bram Moolenaard35f9712005-12-18 22:02:33 +00008720/*
8721 * Return TRUE when there is a CursorHold autocommand defined.
8722 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008723 int
8724has_cursorhold()
8725{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008726 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8727 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008728}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008729
8730/*
8731 * Return TRUE if the CursorHold event can be triggered.
8732 */
8733 int
8734trigger_cursorhold()
8735{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008736 int state;
8737
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00008738 if (!did_cursorhold && has_cursorhold() && !Recording
8739#ifdef FEAT_INS_EXPAND
8740 && !ins_compl_active()
8741#endif
8742 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00008743 {
8744 state = get_real_state();
8745 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8746 return TRUE;
8747 }
8748 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008749}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008750
8751/*
8752 * Return TRUE when there is a CursorMoved autocommand defined.
8753 */
8754 int
8755has_cursormoved()
8756{
8757 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8758}
8759
8760/*
8761 * Return TRUE when there is a CursorMovedI autocommand defined.
8762 */
8763 int
8764has_cursormovedI()
8765{
8766 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8767}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008768
8769 static int
8770apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008771 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008772 char_u *fname; /* NULL or empty means use actual file name */
8773 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8774 use fname */
8775 int force; /* when TRUE, ignore autocmd_busy */
8776 int group; /* group ID, or AUGROUP_ALL */
8777 buf_T *buf; /* buffer for <abuf> */
8778 exarg_T *eap; /* command arguments */
8779{
8780 char_u *sfname = NULL; /* short file name */
8781 char_u *tail;
8782 int save_changed;
8783 buf_T *old_curbuf;
8784 int retval = FALSE;
8785 char_u *save_sourcing_name;
8786 linenr_T save_sourcing_lnum;
8787 char_u *save_autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00008788 int save_autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008789 int save_autocmd_bufnr;
8790 char_u *save_autocmd_match;
8791 int save_autocmd_busy;
8792 int save_autocmd_nested;
8793 static int nesting = 0;
8794 AutoPatCmd patcmd;
8795 AutoPat *ap;
8796#ifdef FEAT_EVAL
8797 scid_T save_current_SID;
8798 void *save_funccalp;
8799 char_u *save_cmdarg;
8800 long save_cmdbang;
8801#endif
8802 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008803#ifdef FEAT_PROFILE
8804 proftime_T wait_time;
8805#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008806
8807 /*
8808 * Quickly return if there are no autocommands for this event or
8809 * autocommands are blocked.
8810 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00008811 if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008812 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008813
8814 /*
8815 * When autocommands are busy, new autocommands are only executed when
8816 * explicitly enabled with the "nested" flag.
8817 */
8818 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008819 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008820
8821#ifdef FEAT_EVAL
8822 /*
Bram Moolenaar7263a772007-05-10 17:35:54 +00008823 * Quickly return when immediately aborting on error, or when an interrupt
Bram Moolenaar071d4272004-06-13 20:20:40 +00008824 * occurred or an exception was thrown but not caught.
8825 */
8826 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008827 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008828#endif
8829
8830 /*
8831 * FileChangedShell never nests, because it can create an endless loop.
8832 */
Bram Moolenaar56718732006-03-15 22:53:57 +00008833 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
8834 || event == EVENT_FILECHANGEDSHELLPOST))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008835 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008836
8837 /*
8838 * Ignore events in 'eventignore'.
8839 */
8840 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008841 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008842
8843 /*
8844 * Allow nesting of autocommands, but restrict the depth, because it's
8845 * possible to create an endless loop.
8846 */
8847 if (nesting == 10)
8848 {
8849 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008850 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008851 }
8852
8853 /*
8854 * Check if these autocommands are disabled. Used when doing ":all" or
8855 * ":ball".
8856 */
8857 if ( (autocmd_no_enter
8858 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8859 || (autocmd_no_leave
8860 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008861 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008862
8863 /*
8864 * Save the autocmd_* variables and info about the current buffer.
8865 */
8866 save_autocmd_fname = autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00008867 save_autocmd_fname_full = autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008868 save_autocmd_bufnr = autocmd_bufnr;
8869 save_autocmd_match = autocmd_match;
8870 save_autocmd_busy = autocmd_busy;
8871 save_autocmd_nested = autocmd_nested;
8872 save_changed = curbuf->b_changed;
8873 old_curbuf = curbuf;
8874
8875 /*
8876 * Set the file name to be used for <afile>.
Bram Moolenaara0174af2008-01-02 20:08:25 +00008877 * Make a copy to avoid that changing a buffer name or directory makes it
8878 * invalid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008879 */
8880 if (fname_io == NULL)
8881 {
8882 if (fname != NULL && *fname != NUL)
8883 autocmd_fname = fname;
8884 else if (buf != NULL)
Bram Moolenaarf6dad432008-09-18 19:29:58 +00008885 autocmd_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008886 else
8887 autocmd_fname = NULL;
8888 }
8889 else
8890 autocmd_fname = fname_io;
Bram Moolenaara0174af2008-01-02 20:08:25 +00008891 if (autocmd_fname != NULL)
Bram Moolenaarf6dad432008-09-18 19:29:58 +00008892 autocmd_fname = vim_strsave(autocmd_fname);
8893 autocmd_fname_full = FALSE; /* call FullName_save() later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008894
8895 /*
8896 * Set the buffer number to be used for <abuf>.
8897 */
8898 if (buf == NULL)
8899 autocmd_bufnr = 0;
8900 else
8901 autocmd_bufnr = buf->b_fnum;
8902
8903 /*
8904 * When the file name is NULL or empty, use the file name of buffer "buf".
8905 * Always use the full path of the file name to match with, in case
8906 * "allow_dirs" is set.
8907 */
8908 if (fname == NULL || *fname == NUL)
8909 {
8910 if (buf == NULL)
8911 fname = NULL;
8912 else
8913 {
8914#ifdef FEAT_SYN_HL
8915 if (event == EVENT_SYNTAX)
8916 fname = buf->b_p_syn;
8917 else
8918#endif
8919 if (event == EVENT_FILETYPE)
8920 fname = buf->b_p_ft;
8921 else
8922 {
8923 if (buf->b_sfname != NULL)
8924 sfname = vim_strsave(buf->b_sfname);
8925 fname = buf->b_ffname;
8926 }
8927 }
8928 if (fname == NULL)
8929 fname = (char_u *)"";
8930 fname = vim_strsave(fname); /* make a copy, so we can change it */
8931 }
8932 else
8933 {
8934 sfname = vim_strsave(fname);
Bram Moolenaar5135d462009-04-29 16:03:38 +00008935 /* Don't try expanding FileType, Syntax, FuncUndefined, WindowID or
8936 * QuickFixCmd* */
Bram Moolenaar7c626922005-02-07 22:01:03 +00008937 if (event == EVENT_FILETYPE
8938 || event == EVENT_SYNTAX
Bram Moolenaar5135d462009-04-29 16:03:38 +00008939 || event == EVENT_FUNCUNDEFINED
Bram Moolenaar7c626922005-02-07 22:01:03 +00008940 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008941 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008942 || event == EVENT_QUICKFIXCMDPRE
8943 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008944 fname = vim_strsave(fname);
8945 else
8946 fname = FullName_save(fname, FALSE);
8947 }
8948 if (fname == NULL) /* out of memory */
8949 {
8950 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008951 retval = FALSE;
8952 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008953 }
8954
8955#ifdef BACKSLASH_IN_FILENAME
8956 /*
8957 * Replace all backslashes with forward slashes. This makes the
8958 * autocommand patterns portable between Unix and MS-DOS.
8959 */
8960 if (sfname != NULL)
8961 forward_slash(sfname);
8962 forward_slash(fname);
8963#endif
8964
8965#ifdef VMS
8966 /* remove version for correct match */
8967 if (sfname != NULL)
8968 vms_remove_version(sfname);
8969 vms_remove_version(fname);
8970#endif
8971
8972 /*
8973 * Set the name to be used for <amatch>.
8974 */
8975 autocmd_match = fname;
8976
8977
8978 /* Don't redraw while doing auto commands. */
8979 ++RedrawingDisabled;
8980 save_sourcing_name = sourcing_name;
8981 sourcing_name = NULL; /* don't free this one */
8982 save_sourcing_lnum = sourcing_lnum;
8983 sourcing_lnum = 0; /* no line number here */
8984
8985#ifdef FEAT_EVAL
8986 save_current_SID = current_SID;
8987
Bram Moolenaar05159a02005-02-26 23:04:13 +00008988# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008989 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008990 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8991# endif
8992
Bram Moolenaar071d4272004-06-13 20:20:40 +00008993 /* Don't use local function variables, if called from a function */
8994 save_funccalp = save_funccal();
8995#endif
8996
8997 /*
8998 * When starting to execute autocommands, save the search patterns.
8999 */
9000 if (!autocmd_busy)
9001 {
9002 save_search_patterns();
9003 saveRedobuff();
9004 did_filetype = keep_filetype;
9005 }
9006
9007 /*
9008 * Note that we are applying autocmds. Some commands need to know.
9009 */
9010 autocmd_busy = TRUE;
9011 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
9012 ++nesting; /* see matching decrement below */
9013
9014 /* Remember that FileType was triggered. Used for did_filetype(). */
9015 if (event == EVENT_FILETYPE)
9016 did_filetype = TRUE;
9017
9018 tail = gettail(fname);
9019
9020 /* Find first autocommand that matches */
9021 patcmd.curpat = first_autopat[(int)event];
9022 patcmd.nextcmd = NULL;
9023 patcmd.group = group;
9024 patcmd.fname = fname;
9025 patcmd.sfname = sfname;
9026 patcmd.tail = tail;
9027 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009028 patcmd.arg_bufnr = autocmd_bufnr;
9029 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009030 auto_next_pat(&patcmd, FALSE);
9031
9032 /* found one, start executing the autocommands */
9033 if (patcmd.curpat != NULL)
9034 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009035 /* add to active_apc_list */
9036 patcmd.next = active_apc_list;
9037 active_apc_list = &patcmd;
9038
Bram Moolenaar071d4272004-06-13 20:20:40 +00009039#ifdef FEAT_EVAL
9040 /* set v:cmdarg (only when there is a matching pattern) */
9041 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
9042 if (eap != NULL)
9043 {
9044 save_cmdarg = set_cmdarg(eap, NULL);
9045 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
9046 }
9047 else
9048 save_cmdarg = NULL; /* avoid gcc warning */
9049#endif
9050 retval = TRUE;
9051 /* mark the last pattern, to avoid an endless loop when more patterns
9052 * are added when executing autocommands */
9053 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
9054 ap->last = FALSE;
9055 ap->last = TRUE;
9056 check_lnums(TRUE); /* make sure cursor and topline are valid */
9057 do_cmdline(NULL, getnextac, (void *)&patcmd,
9058 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
9059#ifdef FEAT_EVAL
9060 if (eap != NULL)
9061 {
9062 (void)set_cmdarg(NULL, save_cmdarg);
9063 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
9064 }
9065#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009066 /* delete from active_apc_list */
9067 if (active_apc_list == &patcmd) /* just in case */
9068 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009069 }
9070
9071 --RedrawingDisabled;
9072 autocmd_busy = save_autocmd_busy;
9073 filechangeshell_busy = FALSE;
9074 autocmd_nested = save_autocmd_nested;
9075 vim_free(sourcing_name);
9076 sourcing_name = save_sourcing_name;
9077 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaara0174af2008-01-02 20:08:25 +00009078 vim_free(autocmd_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009079 autocmd_fname = save_autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009080 autocmd_fname_full = save_autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009081 autocmd_bufnr = save_autocmd_bufnr;
9082 autocmd_match = save_autocmd_match;
9083#ifdef FEAT_EVAL
9084 current_SID = save_current_SID;
9085 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00009086# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00009087 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00009088 prof_child_exit(&wait_time);
9089# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009090#endif
9091 vim_free(fname);
9092 vim_free(sfname);
9093 --nesting; /* see matching increment above */
9094
9095 /*
9096 * When stopping to execute autocommands, restore the search patterns and
9097 * the redo buffer.
9098 */
9099 if (!autocmd_busy)
9100 {
9101 restore_search_patterns();
9102 restoreRedobuff();
9103 did_filetype = FALSE;
9104 }
9105
9106 /*
9107 * Some events don't set or reset the Changed flag.
9108 * Check if still in the same buffer!
9109 */
9110 if (curbuf == old_curbuf
9111 && (event == EVENT_BUFREADPOST
9112 || event == EVENT_BUFWRITEPOST
9113 || event == EVENT_FILEAPPENDPOST
9114 || event == EVENT_VIMLEAVE
9115 || event == EVENT_VIMLEAVEPRE))
9116 {
9117#ifdef FEAT_TITLE
9118 if (curbuf->b_changed != save_changed)
9119 need_maketitle = TRUE;
9120#endif
9121 curbuf->b_changed = save_changed;
9122 }
9123
9124 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009125
9126BYPASS_AU:
9127 /* When wiping out a buffer make sure all its buffer-local autocommands
9128 * are deleted. */
9129 if (event == EVENT_BUFWIPEOUT && buf != NULL)
9130 aubuflocal_remove(buf);
9131
Bram Moolenaar071d4272004-06-13 20:20:40 +00009132 return retval;
9133}
9134
Bram Moolenaar78ab3312007-09-29 12:16:41 +00009135# ifdef FEAT_EVAL
9136static char_u *old_termresponse = NULL;
9137# endif
9138
9139/*
9140 * Block triggering autocommands until unblock_autocmd() is called.
9141 * Can be used recursively, so long as it's symmetric.
9142 */
9143 void
9144block_autocmds()
9145{
9146# ifdef FEAT_EVAL
9147 /* Remember the value of v:termresponse. */
9148 if (autocmd_blocked == 0)
9149 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
9150# endif
9151 ++autocmd_blocked;
9152}
9153
9154 void
9155unblock_autocmds()
9156{
9157 --autocmd_blocked;
9158
9159# ifdef FEAT_EVAL
9160 /* When v:termresponse was set while autocommands were blocked, trigger
9161 * the autocommands now. Esp. useful when executing a shell command
9162 * during startup (vimdiff). */
9163 if (autocmd_blocked == 0
9164 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
9165 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
9166# endif
9167}
9168
Bram Moolenaar071d4272004-06-13 20:20:40 +00009169/*
9170 * Find next autocommand pattern that matches.
9171 */
9172 static void
9173auto_next_pat(apc, stop_at_last)
9174 AutoPatCmd *apc;
9175 int stop_at_last; /* stop when 'last' flag is set */
9176{
9177 AutoPat *ap;
9178 AutoCmd *cp;
9179 char_u *name;
9180 char *s;
9181
9182 vim_free(sourcing_name);
9183 sourcing_name = NULL;
9184
9185 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
9186 {
9187 apc->curpat = NULL;
9188
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009189 /* Only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009190 * the group matches. For buffer-local autocommands only check the
9191 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009192 if (ap->pat != NULL && ap->cmds != NULL
9193 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
9194 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009195 /* execution-condition */
9196 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00009197 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
9198 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009199 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009200 {
9201 name = event_nr2name(apc->event);
9202 s = _("%s Auto commands for \"%s\"");
9203 sourcing_name = alloc((unsigned)(STRLEN(s)
9204 + STRLEN(name) + ap->patlen + 1));
9205 if (sourcing_name != NULL)
9206 {
9207 sprintf((char *)sourcing_name, s,
9208 (char *)name, (char *)ap->pat);
9209 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009210 {
9211 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00009212 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009213 verbose_leave();
9214 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009215 }
9216
9217 apc->curpat = ap;
9218 apc->nextcmd = ap->cmds;
9219 /* mark last command */
9220 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
9221 cp->last = FALSE;
9222 cp->last = TRUE;
9223 }
9224 line_breakcheck();
9225 if (apc->curpat != NULL) /* found a match */
9226 break;
9227 }
9228 if (stop_at_last && ap->last)
9229 break;
9230 }
9231}
9232
9233/*
9234 * Get next autocommand command.
9235 * Called by do_cmdline() to get the next line for ":if".
9236 * Returns allocated string, or NULL for end of autocommands.
9237 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009238 static char_u *
9239getnextac(c, cookie, indent)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009240 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009241 void *cookie;
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009242 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009243{
9244 AutoPatCmd *acp = (AutoPatCmd *)cookie;
9245 char_u *retval;
9246 AutoCmd *ac;
9247
9248 /* Can be called again after returning the last line. */
9249 if (acp->curpat == NULL)
9250 return NULL;
9251
9252 /* repeat until we find an autocommand to execute */
9253 for (;;)
9254 {
9255 /* skip removed commands */
9256 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
9257 if (acp->nextcmd->last)
9258 acp->nextcmd = NULL;
9259 else
9260 acp->nextcmd = acp->nextcmd->next;
9261
9262 if (acp->nextcmd != NULL)
9263 break;
9264
9265 /* at end of commands, find next pattern that matches */
9266 if (acp->curpat->last)
9267 acp->curpat = NULL;
9268 else
9269 acp->curpat = acp->curpat->next;
9270 if (acp->curpat != NULL)
9271 auto_next_pat(acp, TRUE);
9272 if (acp->curpat == NULL)
9273 return NULL;
9274 }
9275
9276 ac = acp->nextcmd;
9277
9278 if (p_verbose >= 9)
9279 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009280 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00009281 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009282 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009283 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00009284 }
9285 retval = vim_strsave(ac->cmd);
9286 autocmd_nested = ac->nested;
9287#ifdef FEAT_EVAL
9288 current_SID = ac->scriptID;
9289#endif
9290 if (ac->last)
9291 acp->nextcmd = NULL;
9292 else
9293 acp->nextcmd = ac->next;
9294 return retval;
9295}
9296
9297/*
9298 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009299 * To account for buffer-local autocommands, function needs to know
9300 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009301 */
9302 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009303has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00009304 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009305 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009306 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009307{
9308 AutoPat *ap;
9309 char_u *fname;
9310 char_u *tail = gettail(sfname);
9311 int retval = FALSE;
9312
9313 fname = FullName_save(sfname, FALSE);
9314 if (fname == NULL)
9315 return FALSE;
9316
9317#ifdef BACKSLASH_IN_FILENAME
9318 /*
9319 * Replace all backslashes with forward slashes. This makes the
9320 * autocommand patterns portable between Unix and MS-DOS.
9321 */
9322 sfname = vim_strsave(sfname);
9323 if (sfname != NULL)
9324 forward_slash(sfname);
9325 forward_slash(fname);
9326#endif
9327
9328 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
9329 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009330 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00009331 ? match_file_pat(NULL, ap->reg_prog,
9332 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009333 : buf != NULL && ap->buflocal_nr == buf->b_fnum
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009334 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009335 {
9336 retval = TRUE;
9337 break;
9338 }
9339
9340 vim_free(fname);
9341#ifdef BACKSLASH_IN_FILENAME
9342 vim_free(sfname);
9343#endif
9344
9345 return retval;
9346}
9347
9348#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
9349/*
9350 * Function given to ExpandGeneric() to obtain the list of autocommand group
9351 * names.
9352 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009353 char_u *
9354get_augroup_name(xp, idx)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009355 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009356 int idx;
9357{
9358 if (idx == augroups.ga_len) /* add "END" add the end */
9359 return (char_u *)"END";
9360 if (idx >= augroups.ga_len) /* end of list */
9361 return NULL;
9362 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
9363 return (char_u *)"";
9364 return AUGROUP_NAME(idx); /* return a name */
9365}
9366
9367static int include_groups = FALSE;
9368
9369 char_u *
9370set_context_in_autocmd(xp, arg, doautocmd)
9371 expand_T *xp;
9372 char_u *arg;
Bram Moolenaard812df62008-11-09 12:46:09 +00009373 int doautocmd; /* TRUE for :doauto*, FALSE for :autocmd */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009374{
9375 char_u *p;
9376 int group;
9377
9378 /* check for a group name, skip it if present */
9379 include_groups = FALSE;
9380 p = arg;
9381 group = au_get_grouparg(&arg);
9382 if (group == AUGROUP_ERROR)
9383 return NULL;
9384 /* If there only is a group name that's what we expand. */
9385 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
9386 {
9387 arg = p;
9388 group = AUGROUP_ALL;
9389 }
9390
9391 /* skip over event name */
9392 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
9393 if (*p == ',')
9394 arg = p + 1;
9395 if (*p == NUL)
9396 {
9397 if (group == AUGROUP_ALL)
9398 include_groups = TRUE;
9399 xp->xp_context = EXPAND_EVENTS; /* expand event name */
9400 xp->xp_pattern = arg;
9401 return NULL;
9402 }
9403
9404 /* skip over pattern */
9405 arg = skipwhite(p);
9406 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
9407 arg++;
9408 if (*arg)
9409 return arg; /* expand (next) command */
9410
9411 if (doautocmd)
9412 xp->xp_context = EXPAND_FILES; /* expand file names */
9413 else
9414 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
9415 return NULL;
9416}
9417
9418/*
9419 * Function given to ExpandGeneric() to obtain the list of event names.
9420 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009421 char_u *
9422get_event_name(xp, idx)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009423 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009424 int idx;
9425{
9426 if (idx < augroups.ga_len) /* First list group names, if wanted */
9427 {
9428 if (!include_groups || AUGROUP_NAME(idx) == NULL)
9429 return (char_u *)""; /* skip deleted entries */
9430 return AUGROUP_NAME(idx); /* return a name */
9431 }
9432 return (char_u *)event_names[idx - augroups.ga_len].name;
9433}
9434
9435#endif /* FEAT_CMDL_COMPL */
9436
9437/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009438 * Return TRUE if autocmd is supported.
9439 */
9440 int
9441autocmd_supported(name)
9442 char_u *name;
9443{
9444 char_u *p;
9445
9446 return (event_name2nr(name, &p) != NUM_EVENTS);
9447}
9448
9449/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00009450 * Return TRUE if an autocommand is defined for a group, event and
9451 * pattern: The group can be omitted to accept any group. "event" and "pattern"
9452 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
9453 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
9454 * Used for:
9455 * exists("#Group") or
9456 * exists("#Group#Event") or
9457 * exists("#Group#Event#pat") or
9458 * exists("#Event") or
9459 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00009460 */
9461 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00009462au_exists(arg)
9463 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009464{
Bram Moolenaar195d6352005-12-19 22:08:24 +00009465 char_u *arg_save;
9466 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009467 char_u *event_name;
9468 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00009469 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009470 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009471 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00009472 int group;
9473 int retval = FALSE;
9474
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009475 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009476 arg_save = vim_strsave(arg);
9477 if (arg_save == NULL)
9478 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009479 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00009480 if (p != NULL)
9481 *p++ = NUL;
9482
9483 /* First, look for an autocmd group name */
9484 group = au_find_group(arg_save);
9485 if (group == AUGROUP_ERROR)
9486 {
9487 /* Didn't match a group name, assume the first argument is an event. */
9488 group = AUGROUP_ALL;
9489 event_name = arg_save;
9490 }
9491 else
9492 {
9493 if (p == NULL)
9494 {
9495 /* "Group": group name is present and it's recognized */
9496 retval = TRUE;
9497 goto theend;
9498 }
9499
9500 /* Must be "Group#Event" or "Group#Event#pat". */
9501 event_name = p;
9502 p = vim_strchr(event_name, '#');
9503 if (p != NULL)
9504 *p++ = NUL; /* "Group#Event#pat" */
9505 }
9506
9507 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009508
9509 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009510 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009511
9512 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009513 if (event == NUM_EVENTS)
9514 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009515
9516 /* Find the first autocommand for this event.
9517 * If there isn't any, return FALSE;
9518 * If there is one and no pattern given, return TRUE; */
9519 ap = first_autopat[(int)event];
9520 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009521 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009522
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009523 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
9524 /* for pattern "<buffer=N>, fnamecmp() will work fine */
Bram Moolenaar5b7880d2009-09-11 15:24:31 +00009525 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009526 buflocal_buf = curbuf;
9527
Bram Moolenaar071d4272004-06-13 20:20:40 +00009528 /* Check if there is an autocommand with the given pattern. */
9529 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009530 /* only use a pattern when it has not been removed and has commands. */
9531 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009532 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009533 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaar5b7880d2009-09-11 15:24:31 +00009534 && (pattern == NULL
9535 || (buflocal_buf == NULL
9536 ? fnamecmp(ap->pat, pattern) == 0
9537 : ap->buflocal_nr == buflocal_buf->b_fnum)))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009538 {
9539 retval = TRUE;
9540 break;
9541 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009542
Bram Moolenaar195d6352005-12-19 22:08:24 +00009543theend:
9544 vim_free(arg_save);
9545 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009546}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009547
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009548#else /* FEAT_AUTOCMD */
9549
9550/*
9551 * Prepare for executing commands for (hidden) buffer "buf".
9552 * This is the non-autocommand version, it simply saves "curbuf" and sets
9553 * "curbuf" and "curwin" to match "buf".
9554 */
9555 void
9556aucmd_prepbuf(aco, buf)
9557 aco_save_T *aco; /* structure to save values in */
9558 buf_T *buf; /* new curbuf */
9559{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009560 aco->save_curbuf = curbuf;
9561 --curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009562 curbuf = buf;
9563 curwin->w_buffer = buf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009564 ++curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009565}
9566
9567/*
9568 * Restore after executing commands for a (hidden) buffer.
9569 * This is the non-autocommand version.
9570 */
9571 void
9572aucmd_restbuf(aco)
9573 aco_save_T *aco; /* structure holding saved values */
9574{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009575 --curbuf->b_nwindows;
9576 curbuf = aco->save_curbuf;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009577 curwin->w_buffer = curbuf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009578 ++curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009579}
9580
Bram Moolenaar071d4272004-06-13 20:20:40 +00009581#endif /* FEAT_AUTOCMD */
9582
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009583
Bram Moolenaar071d4272004-06-13 20:20:40 +00009584#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9585/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009586 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9587 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9588 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009589 * Used for autocommands and 'wildignore'.
9590 * Returns TRUE if there is a match, FALSE otherwise.
9591 */
9592 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009593match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009594 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009595 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009596 char_u *fname; /* full path of file name */
9597 char_u *sfname; /* short file name or NULL */
9598 char_u *tail; /* tail of path */
9599 int allow_dirs; /* allow matching with dir */
9600{
9601 regmatch_T regmatch;
9602 int result = FALSE;
9603#ifdef FEAT_OSFILETYPE
9604 int no_pattern = FALSE; /* TRUE if check is filetype only */
9605 char_u *type_start;
9606 char_u c;
9607 int match = FALSE;
9608#endif
9609
9610#ifdef CASE_INSENSITIVE_FILENAME
9611 regmatch.rm_ic = TRUE; /* Always ignore case */
9612#else
9613 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9614#endif
9615#ifdef FEAT_OSFILETYPE
9616 if (*pattern == '<')
9617 {
9618 /* There is a filetype condition specified with this pattern.
9619 * Check the filetype matches first. If not, don't bother with the
9620 * pattern (set regprog to NULL).
9621 * Always use magic for the regexp.
9622 */
9623
9624 for (type_start = pattern + 1; (c = *pattern); pattern++)
9625 {
9626 if ((c == ';' || c == '>') && match == FALSE)
9627 {
9628 *pattern = NUL; /* Terminate the string */
9629 match = mch_check_filetype(fname, type_start);
9630 *pattern = c; /* Restore the terminator */
9631 type_start = pattern + 1;
9632 }
9633 if (c == '>')
9634 break;
9635 }
9636
9637 /* (c should never be NUL, but check anyway) */
9638 if (match == FALSE || c == NUL)
9639 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9640 else if (*pattern == NUL)
9641 {
9642 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9643 no_pattern = TRUE; /* Always matches - don't check pat. */
9644 }
9645 else
9646 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9647 }
9648 else
9649#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009650 {
9651 if (prog != NULL)
9652 regmatch.regprog = prog;
9653 else
9654 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9655 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009656
9657 /*
9658 * Try for a match with the pattern with:
9659 * 1. the full file name, when the pattern has a '/'.
9660 * 2. the short file name, when the pattern has a '/'.
9661 * 3. the tail of the file name, when the pattern has no '/'.
9662 */
9663 if (
9664#ifdef FEAT_OSFILETYPE
9665 /* If the check is for a filetype only and we don't care
9666 * about the path then skip all the regexp stuff.
9667 */
9668 no_pattern ||
9669#endif
9670 (regmatch.regprog != NULL
9671 && ((allow_dirs
9672 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9673 || (sfname != NULL
9674 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9675 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9676 result = TRUE;
9677
Bram Moolenaar748bf032005-02-02 23:04:36 +00009678 if (prog == NULL)
9679 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009680 return result;
9681}
9682#endif
9683
9684#if defined(FEAT_WILDIGN) || defined(PROTO)
9685/*
9686 * Return TRUE if a file matches with a pattern in "list".
9687 * "list" is a comma-separated list of patterns, like 'wildignore'.
9688 * "sfname" is the short file name or NULL, "ffname" the long file name.
9689 */
9690 int
9691match_file_list(list, sfname, ffname)
9692 char_u *list;
9693 char_u *sfname;
9694 char_u *ffname;
9695{
9696 char_u buf[100];
9697 char_u *tail;
9698 char_u *regpat;
9699 char allow_dirs;
9700 int match;
9701 char_u *p;
9702
9703 tail = gettail(sfname);
9704
9705 /* try all patterns in 'wildignore' */
9706 p = list;
9707 while (*p)
9708 {
9709 copy_option_part(&p, buf, 100, ",");
9710 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9711 if (regpat == NULL)
9712 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009713 match = match_file_pat(regpat, NULL, ffname, sfname,
9714 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009715 vim_free(regpat);
9716 if (match)
9717 return TRUE;
9718 }
9719 return FALSE;
9720}
9721#endif
9722
9723/*
9724 * Convert the given pattern "pat" which has shell style wildcards in it, into
9725 * a regular expression, and return the result in allocated memory. If there
9726 * is a directory path separator to be matched, then TRUE is put in
9727 * allow_dirs, otherwise FALSE is put there -- webb.
9728 * Handle backslashes before special characters, like "\*" and "\ ".
9729 *
9730 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9731 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9732 *
9733 * Returns NULL when out of memory.
9734 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009735 char_u *
9736file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9737 char_u *pat;
9738 char_u *pat_end; /* first char after pattern or NULL */
9739 char *allow_dirs; /* Result passed back out in here */
Bram Moolenaar78a15312009-05-15 19:33:18 +00009740 int no_bslash UNUSED; /* Don't use a backward slash as pathsep */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009741{
9742 int size;
9743 char_u *endp;
9744 char_u *reg_pat;
9745 char_u *p;
9746 int i;
9747 int nested = 0;
9748 int add_dollar = TRUE;
9749#ifdef FEAT_OSFILETYPE
9750 int check_length = 0;
9751#endif
9752
9753 if (allow_dirs != NULL)
9754 *allow_dirs = FALSE;
9755 if (pat_end == NULL)
9756 pat_end = pat + STRLEN(pat);
9757
9758#ifdef FEAT_OSFILETYPE
9759 /* Find out how much of the string is the filetype check */
9760 if (*pat == '<')
9761 {
9762 /* Count chars until the next '>' */
9763 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9764 ;
9765 if (p < pat_end)
9766 {
9767 /* Pattern is of the form <.*>.* */
9768 check_length = p - pat + 1;
9769 if (p + 1 >= pat_end)
9770 {
9771 /* The 'pattern' is a filetype check ONLY */
9772 reg_pat = (char_u *)alloc(check_length + 1);
9773 if (reg_pat != NULL)
9774 {
9775 mch_memmove(reg_pat, pat, (size_t)check_length);
9776 reg_pat[check_length] = NUL;
9777 }
9778 return reg_pat;
9779 }
9780 }
9781 /* else: there was no closing '>' - assume it was a normal pattern */
9782
9783 }
9784 pat += check_length;
9785 size = 2 + check_length;
9786#else
9787 size = 2; /* '^' at start, '$' at end */
9788#endif
9789
9790 for (p = pat; p < pat_end; p++)
9791 {
9792 switch (*p)
9793 {
9794 case '*':
9795 case '.':
9796 case ',':
9797 case '{':
9798 case '}':
9799 case '~':
9800 size += 2; /* extra backslash */
9801 break;
9802#ifdef BACKSLASH_IN_FILENAME
9803 case '\\':
9804 case '/':
9805 size += 4; /* could become "[\/]" */
9806 break;
9807#endif
9808 default:
9809 size++;
9810# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009811 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009812 {
9813 ++p;
9814 ++size;
9815 }
9816# endif
9817 break;
9818 }
9819 }
9820 reg_pat = alloc(size + 1);
9821 if (reg_pat == NULL)
9822 return NULL;
9823
9824#ifdef FEAT_OSFILETYPE
9825 /* Copy the type check in to the start. */
9826 if (check_length)
9827 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9828 i = check_length;
9829#else
9830 i = 0;
9831#endif
9832
9833 if (pat[0] == '*')
9834 while (pat[0] == '*' && pat < pat_end - 1)
9835 pat++;
9836 else
9837 reg_pat[i++] = '^';
9838 endp = pat_end - 1;
9839 if (*endp == '*')
9840 {
9841 while (endp - pat > 0 && *endp == '*')
9842 endp--;
9843 add_dollar = FALSE;
9844 }
9845 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9846 {
9847 switch (*p)
9848 {
9849 case '*':
9850 reg_pat[i++] = '.';
9851 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009852 while (p[1] == '*') /* "**" matches like "*" */
9853 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009854 break;
9855 case '.':
9856#ifdef RISCOS
9857 if (allow_dirs != NULL)
9858 *allow_dirs = TRUE;
9859 /* FALLTHROUGH */
9860#endif
9861 case '~':
9862 reg_pat[i++] = '\\';
9863 reg_pat[i++] = *p;
9864 break;
9865 case '?':
9866#ifdef RISCOS
9867 case '#':
9868#endif
9869 reg_pat[i++] = '.';
9870 break;
9871 case '\\':
9872 if (p[1] == NUL)
9873 break;
9874#ifdef BACKSLASH_IN_FILENAME
9875 if (!no_bslash)
9876 {
9877 /* translate:
9878 * "\x" to "\\x" e.g., "dir\file"
9879 * "\*" to "\\.*" e.g., "dir\*.c"
9880 * "\?" to "\\." e.g., "dir\??.c"
9881 * "\+" to "\+" e.g., "fileX\+.c"
9882 */
9883 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9884 && p[1] != '+')
9885 {
9886 reg_pat[i++] = '[';
9887 reg_pat[i++] = '\\';
9888 reg_pat[i++] = '/';
9889 reg_pat[i++] = ']';
9890 if (allow_dirs != NULL)
9891 *allow_dirs = TRUE;
9892 break;
9893 }
9894 }
9895#endif
9896 if (*++p == '?'
9897#ifdef BACKSLASH_IN_FILENAME
9898 && no_bslash
9899#endif
9900 )
9901 reg_pat[i++] = '?';
9902 else
9903 if (*p == ',')
9904 reg_pat[i++] = ',';
9905 else
9906 {
9907 if (allow_dirs != NULL && vim_ispathsep(*p)
9908#ifdef BACKSLASH_IN_FILENAME
9909 && (!no_bslash || *p != '\\')
9910#endif
9911 )
9912 *allow_dirs = TRUE;
9913 reg_pat[i++] = '\\';
9914 reg_pat[i++] = *p;
9915 }
9916 break;
9917#ifdef BACKSLASH_IN_FILENAME
9918 case '/':
9919 reg_pat[i++] = '[';
9920 reg_pat[i++] = '\\';
9921 reg_pat[i++] = '/';
9922 reg_pat[i++] = ']';
9923 if (allow_dirs != NULL)
9924 *allow_dirs = TRUE;
9925 break;
9926#endif
9927 case '{':
9928 reg_pat[i++] = '\\';
9929 reg_pat[i++] = '(';
9930 nested++;
9931 break;
9932 case '}':
9933 reg_pat[i++] = '\\';
9934 reg_pat[i++] = ')';
9935 --nested;
9936 break;
9937 case ',':
9938 if (nested)
9939 {
9940 reg_pat[i++] = '\\';
9941 reg_pat[i++] = '|';
9942 }
9943 else
9944 reg_pat[i++] = ',';
9945 break;
9946 default:
9947# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009948 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009949 reg_pat[i++] = *p++;
9950 else
9951# endif
9952 if (allow_dirs != NULL && vim_ispathsep(*p))
9953 *allow_dirs = TRUE;
9954 reg_pat[i++] = *p;
9955 break;
9956 }
9957 }
9958 if (add_dollar)
9959 reg_pat[i++] = '$';
9960 reg_pat[i] = NUL;
9961 if (nested != 0)
9962 {
9963 if (nested < 0)
9964 EMSG(_("E219: Missing {."));
9965 else
9966 EMSG(_("E220: Missing }."));
9967 vim_free(reg_pat);
9968 reg_pat = NULL;
9969 }
9970 return reg_pat;
9971}