blob: b4fbdfbac979ceb040216eb1a4146a35c938fa37 [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
15
Bram Moolenaarf4888d02009-12-02 12:31:27 +000016#if defined(__TANDEM) || defined(__MINT__)
Bram Moolenaar071d4272004-06-13 20:20:40 +000017# include <limits.h> /* for SSIZE_MAX */
18#endif
19
20#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
21# include <utime.h> /* for struct utimbuf */
22#endif
23
24#define BUFSIZE 8192 /* size of normal write buffer */
25#define SMBUFSIZE 256 /* size of emergency write buffer */
26
27#ifdef FEAT_CRYPT
Bram Moolenaar40e6a712010-05-16 22:32:54 +020028/* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */
Bram Moolenaarf50a2532010-05-21 15:36:08 +020029static char *crypt_magic[] = {"VimCrypt~01!", "VimCrypt~02!"};
30static char crypt_magic_head[] = "VimCrypt~";
31# define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */
Bram Moolenaar80794b12010-06-13 05:20:42 +020032
33/* For blowfish, after the magic header, we store 8 bytes of salt and then 8
34 * bytes of seed (initialisation vector). */
35static int crypt_salt_len[] = {0, 8};
Bram Moolenaarf50a2532010-05-21 15:36:08 +020036static int crypt_seed_len[] = {0, 8};
Bram Moolenaar80794b12010-06-13 05:20:42 +020037#define CRYPT_SALT_LEN_MAX 8
Bram Moolenaar40e6a712010-05-16 22:32:54 +020038#define CRYPT_SEED_LEN_MAX 8
Bram Moolenaar071d4272004-06-13 20:20:40 +000039#endif
40
41/* Is there any system that doesn't have access()? */
Bram Moolenaar9372a112005-12-06 19:59:18 +000042#define USE_MCH_ACCESS
Bram Moolenaar071d4272004-06-13 20:20:40 +000043
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +000044#if defined(sun) && defined(S_ISCHR)
45# define OPEN_CHR_FILES
46static int is_dev_fd_file(char_u *fname);
47#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000048#ifdef FEAT_MBYTE
49static char_u *next_fenc __ARGS((char_u **pp));
50# ifdef FEAT_EVAL
51static char_u *readfile_charconvert __ARGS((char_u *fname, char_u *fenc, int *fdp));
52# endif
53#endif
54#ifdef FEAT_VIMINFO
55static void check_marks_read __ARGS((void));
56#endif
57#ifdef FEAT_CRYPT
Bram Moolenaar49771f42010-07-20 17:32:38 +020058static int crypt_method_from_magic __ARGS((char *ptr, int len));
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +020059static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, off_t *filesizep, int newfile, char_u *fname, int *did_ask));
Bram Moolenaar071d4272004-06-13 20:20:40 +000060#endif
61#ifdef UNIX
62static void set_file_time __ARGS((char_u *fname, time_t atime, time_t mtime));
63#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +000064static int set_rw_fname __ARGS((char_u *fname, char_u *sfname));
Bram Moolenaar071d4272004-06-13 20:20:40 +000065static int msg_add_fileformat __ARGS((int eol_type));
Bram Moolenaar071d4272004-06-13 20:20:40 +000066static void msg_add_eol __ARGS((void));
67static int check_mtime __ARGS((buf_T *buf, struct stat *s));
68static int time_differs __ARGS((long t1, long t2));
69#ifdef FEAT_AUTOCMD
Bram Moolenaar754b5602006-02-09 23:53:20 +000070static 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 +000071static int au_find_group __ARGS((char_u *name));
72
73# define AUGROUP_DEFAULT -1 /* default autocmd group */
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +000074# define AUGROUP_ERROR -2 /* erroneous autocmd group */
Bram Moolenaar70836c82006-02-20 21:28:49 +000075# define AUGROUP_ALL -3 /* all autocmd groups */
Bram Moolenaar071d4272004-06-13 20:20:40 +000076#endif
77
78#if defined(FEAT_CRYPT) || defined(FEAT_MBYTE)
79# define HAS_BW_FLAGS
80# define FIO_LATIN1 0x01 /* convert Latin1 */
81# define FIO_UTF8 0x02 /* convert UTF-8 */
82# define FIO_UCS2 0x04 /* convert UCS-2 */
83# define FIO_UCS4 0x08 /* convert UCS-4 */
84# define FIO_UTF16 0x10 /* convert UTF-16 */
85# ifdef WIN3264
86# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
87# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
88# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
89# endif
90# ifdef MACOS_X
91# define FIO_MACROMAN 0x20 /* convert MacRoman */
92# endif
93# define FIO_ENDIAN_L 0x80 /* little endian */
94# define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
95# define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
96# define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
97# define FIO_ALL -1 /* allow all formats */
98#endif
99
100/* When converting, a read() or write() may leave some bytes to be converted
101 * for the next call. The value is guessed... */
102#define CONV_RESTLEN 30
103
104/* We have to guess how much a sequence of bytes may expand when converting
105 * with iconv() to be able to allocate a buffer. */
106#define ICONV_MULT 8
107
108/*
109 * Structure to pass arguments from buf_write() to buf_write_bytes().
110 */
111struct bw_info
112{
113 int bw_fd; /* file descriptor */
114 char_u *bw_buf; /* buffer with data to be written */
Bram Moolenaard089d9b2007-09-30 12:02:55 +0000115 int bw_len; /* length of data */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116#ifdef HAS_BW_FLAGS
117 int bw_flags; /* FIO_ flags */
118#endif
119#ifdef FEAT_MBYTE
120 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
121 int bw_restlen; /* nr of bytes in bw_rest[] */
122 int bw_first; /* first write call */
123 char_u *bw_conv_buf; /* buffer for writing converted chars */
124 int bw_conv_buflen; /* size of bw_conv_buf */
125 int bw_conv_error; /* set for conversion error */
Bram Moolenaar32b485f2009-07-29 16:06:27 +0000126 linenr_T bw_conv_error_lnum; /* first line with error or zero */
127 linenr_T bw_start_lnum; /* line number at start of buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000128# ifdef USE_ICONV
129 iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
130# endif
131#endif
132};
133
134static int buf_write_bytes __ARGS((struct bw_info *ip));
135
136#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000137static linenr_T readfile_linenr __ARGS((linenr_T linecnt, char_u *p, char_u *endp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138static int ucs2bytes __ARGS((unsigned c, char_u **pp, int flags));
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +0000139static int need_conversion __ARGS((char_u *fenc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140static int get_fio_flags __ARGS((char_u *ptr));
141static char_u *check_for_bom __ARGS((char_u *p, long size, int *lenp, int flags));
142static int make_bom __ARGS((char_u *buf, char_u *name));
143# ifdef WIN3264
144static int get_win_fio_flags __ARGS((char_u *ptr));
145# endif
146# ifdef MACOS_X
147static int get_mac_fio_flags __ARGS((char_u *ptr));
148# endif
149#endif
150static int move_lines __ARGS((buf_T *frombuf, buf_T *tobuf));
Bram Moolenaar4592dee2009-11-18 19:11:58 +0000151#ifdef TEMPDIRNAMES
Bram Moolenaareaf03392009-11-17 11:08:52 +0000152static void vim_settempdir __ARGS((char_u *tempdir));
Bram Moolenaar4592dee2009-11-18 19:11:58 +0000153#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000154#ifdef FEAT_AUTOCMD
155static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
156#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000157
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158 void
159filemess(buf, name, s, attr)
160 buf_T *buf;
161 char_u *name;
162 char_u *s;
163 int attr;
164{
165 int msg_scroll_save;
166
167 if (msg_silent != 0)
168 return;
169 msg_add_fname(buf, name); /* put file name in IObuff with quotes */
170 /* If it's extremely long, truncate it. */
171 if (STRLEN(IObuff) > IOSIZE - 80)
172 IObuff[IOSIZE - 80] = NUL;
173 STRCAT(IObuff, s);
174 /*
175 * For the first message may have to start a new line.
176 * For further ones overwrite the previous one, reset msg_scroll before
177 * calling filemess().
178 */
179 msg_scroll_save = msg_scroll;
180 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
181 msg_scroll = FALSE;
182 if (!msg_scroll) /* wait a bit when overwriting an error msg */
183 check_for_delay(FALSE);
184 msg_start();
185 msg_scroll = msg_scroll_save;
186 msg_scrolled_ign = TRUE;
187 /* may truncate the message to avoid a hit-return prompt */
188 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
189 msg_clr_eos();
190 out_flush();
191 msg_scrolled_ign = FALSE;
192}
193
194/*
195 * Read lines from file "fname" into the buffer after line "from".
196 *
197 * 1. We allocate blocks with lalloc, as big as possible.
198 * 2. Each block is filled with characters from the file with a single read().
199 * 3. The lines are inserted in the buffer with ml_append().
200 *
201 * (caller must check that fname != NULL, unless READ_STDIN is used)
202 *
203 * "lines_to_skip" is the number of lines that must be skipped
204 * "lines_to_read" is the number of lines that are appended
205 * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
206 *
207 * flags:
208 * READ_NEW starting to edit a new buffer
209 * READ_FILTER reading filter output
210 * READ_STDIN read from stdin instead of a file
211 * READ_BUFFER read from curbuf instead of a file (converting after reading
212 * stdin)
213 * READ_DUMMY read into a dummy buffer (to check if file contents changed)
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200214 * READ_KEEP_UNDO don't clear undo info or read it from a file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215 *
216 * return FAIL for failure, OK otherwise
217 */
218 int
219readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
220 char_u *fname;
221 char_u *sfname;
222 linenr_T from;
223 linenr_T lines_to_skip;
224 linenr_T lines_to_read;
225 exarg_T *eap; /* can be NULL! */
226 int flags;
227{
228 int fd = 0;
229 int newfile = (flags & READ_NEW);
230 int check_readonly;
231 int filtering = (flags & READ_FILTER);
232 int read_stdin = (flags & READ_STDIN);
233 int read_buffer = (flags & READ_BUFFER);
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000234 int set_options = newfile || read_buffer
235 || (eap != NULL && eap->read_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
237 colnr_T read_buf_col = 0; /* next char to read from this line */
238 char_u c;
239 linenr_T lnum = from;
240 char_u *ptr = NULL; /* pointer into read buffer */
241 char_u *buffer = NULL; /* read buffer */
242 char_u *new_buffer = NULL; /* init to shut up gcc */
243 char_u *line_start = NULL; /* init to shut up gcc */
244 int wasempty; /* buffer was empty before reading */
245 colnr_T len;
246 long size = 0;
247 char_u *p;
Bram Moolenaar914703b2010-05-31 21:59:46 +0200248 off_t filesize = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249 int skip_read = FALSE;
250#ifdef FEAT_CRYPT
251 char_u *cryptkey = NULL;
Bram Moolenaarf50a2532010-05-21 15:36:08 +0200252 int did_ask_for_key = FALSE;
Bram Moolenaar4cf35c22011-02-25 16:52:17 +0100253 int crypt_method_used;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200255#ifdef FEAT_PERSISTENT_UNDO
256 context_sha256_T sha_ctx;
257 int read_undo_file = FALSE;
258#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 int split = 0; /* number of split lines */
260#define UNKNOWN 0x0fffffff /* file size is unknown */
261 linenr_T linecnt;
262 int error = FALSE; /* errors encountered */
263 int ff_error = EOL_UNKNOWN; /* file format with errors */
264 long linerest = 0; /* remaining chars in line */
265#ifdef UNIX
266 int perm = 0;
267 int swap_mode = -1; /* protection bits for swap file */
268#else
269 int perm;
270#endif
271 int fileformat = 0; /* end-of-line format */
272 int keep_fileformat = FALSE;
273 struct stat st;
274 int file_readonly;
275 linenr_T skip_count = 0;
276 linenr_T read_count = 0;
277 int msg_save = msg_scroll;
278 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
279 * last read was missing the eol */
280 int try_mac = (vim_strchr(p_ffs, 'm') != NULL);
281 int try_dos = (vim_strchr(p_ffs, 'd') != NULL);
282 int try_unix = (vim_strchr(p_ffs, 'x') != NULL);
283 int file_rewind = FALSE;
284#ifdef FEAT_MBYTE
285 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000286 linenr_T conv_error = 0; /* line nr with conversion error */
287 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
289 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000290 int bad_char_behavior = BAD_REPLACE;
291 /* BAD_KEEP, BAD_DROP or character to
292 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293 char_u *tmpname = NULL; /* name of 'charconvert' output file */
294 int fio_flags = 0;
295 char_u *fenc; /* fileencoding to use */
296 int fenc_alloced; /* fenc_next is in allocated memory */
297 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
298 int advance_fenc = FALSE;
299 long real_size = 0;
300# ifdef USE_ICONV
301 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
302# ifdef FEAT_EVAL
303 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
304 'charconvert' next */
305# endif
306# endif
307 int converted = FALSE; /* TRUE if conversion done */
308 int notconverted = FALSE; /* TRUE if conversion wanted but it
309 wasn't possible */
310 char_u conv_rest[CONV_RESTLEN];
311 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
312#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000313#ifdef FEAT_AUTOCMD
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200314 buf_T *old_curbuf;
315 char_u *old_b_ffname;
316 char_u *old_b_fname;
317 int using_b_ffname;
318 int using_b_fname;
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000319#endif
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200320
Bram Moolenaarcab35ad2011-02-15 17:39:22 +0100321 curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322
323 /*
324 * If there is no file name yet, use the one for the read file.
325 * BF_NOTEDITED is set to reflect this.
326 * Don't do this for a read from a filter.
327 * Only do this when 'cpoptions' contains the 'f' flag.
328 */
329 if (curbuf->b_ffname == NULL
330 && !filtering
331 && fname != NULL
332 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
333 && !(flags & READ_DUMMY))
334 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000335 if (set_rw_fname(fname, sfname) == FAIL)
336 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337 }
338
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200339#ifdef FEAT_AUTOCMD
340 /* Remember the initial values of curbuf, curbuf->b_ffname and
341 * curbuf->b_fname to detect whether they are altered as a result of
342 * executing nasty autocommands. Also check if "fname" and "sfname"
343 * point to one of these values. */
344 old_curbuf = curbuf;
345 old_b_ffname = curbuf->b_ffname;
346 old_b_fname = curbuf->b_fname;
347 using_b_ffname = (fname == curbuf->b_ffname)
348 || (sfname == curbuf->b_ffname);
349 using_b_fname = (fname == curbuf->b_fname) || (sfname == curbuf->b_fname);
350#endif
351
Bram Moolenaardf177f62005-02-22 08:39:57 +0000352 /* After reading a file the cursor line changes but we don't want to
353 * display the line. */
354 ex_no_reprint = TRUE;
355
Bram Moolenaar55b7cf82006-09-09 12:52:42 +0000356 /* don't display the file info for another buffer now */
357 need_fileinfo = FALSE;
358
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 /*
360 * For Unix: Use the short file name whenever possible.
361 * Avoids problems with networks and when directory names are changed.
362 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
363 * another directory, which we don't detect.
364 */
365 if (sfname == NULL)
366 sfname = fname;
367#if defined(UNIX) || defined(__EMX__)
368 fname = sfname;
369#endif
370
371#ifdef FEAT_AUTOCMD
372 /*
373 * The BufReadCmd and FileReadCmd events intercept the reading process by
374 * executing the associated commands instead.
375 */
376 if (!filtering && !read_stdin && !read_buffer)
377 {
378 pos_T pos;
379
380 pos = curbuf->b_op_start;
381
382 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
383 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
384 curbuf->b_op_start.col = 0;
385
386 if (newfile)
387 {
388 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
389 FALSE, curbuf, eap))
390#ifdef FEAT_EVAL
391 return aborting() ? FAIL : OK;
392#else
393 return OK;
394#endif
395 }
396 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
397 FALSE, NULL, eap))
398#ifdef FEAT_EVAL
399 return aborting() ? FAIL : OK;
400#else
401 return OK;
402#endif
403
404 curbuf->b_op_start = pos;
405 }
406#endif
407
408 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
409 msg_scroll = FALSE; /* overwrite previous file message */
410 else
411 msg_scroll = TRUE; /* don't overwrite previous file message */
412
413 /*
414 * If the name ends in a path separator, we can't open it. Check here,
415 * because reading the file may actually work, but then creating the swap
416 * file may destroy it! Reported on MS-DOS and Win 95.
417 * If the name is too long we might crash further on, quit here.
418 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000419 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000421 p = fname + STRLEN(fname);
422 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000423 {
424 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
425 msg_end();
426 msg_scroll = msg_save;
427 return FAIL;
428 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 }
430
431#ifdef UNIX
432 /*
433 * On Unix it is possible to read a directory, so we have to
434 * check for it before the mch_open().
435 */
436 if (!read_stdin && !read_buffer)
437 {
438 perm = mch_getperm(fname);
439 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
440# ifdef S_ISFIFO
441 && !S_ISFIFO(perm) /* ... or fifo */
442# endif
443# ifdef S_ISSOCK
444 && !S_ISSOCK(perm) /* ... or socket */
445# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +0000446# ifdef OPEN_CHR_FILES
447 && !(S_ISCHR(perm) && is_dev_fd_file(fname))
448 /* ... or a character special file named /dev/fd/<n> */
449# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450 )
451 {
452 if (S_ISDIR(perm))
453 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
454 else
455 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
456 msg_end();
457 msg_scroll = msg_save;
458 return FAIL;
459 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000461# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
462 /*
463 * MS-Windows allows opening a device, but we will probably get stuck
464 * trying to read it.
465 */
466 if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
467 {
Bram Moolenaar5386a122007-06-28 20:02:32 +0000468 filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000469 msg_end();
470 msg_scroll = msg_save;
471 return FAIL;
472 }
473# endif
Bram Moolenaar043545e2006-10-10 16:44:07 +0000474 }
475#endif
476
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 /* set default 'fileformat' */
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000478 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 {
480 if (eap != NULL && eap->force_ff != 0)
481 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
482 else if (*p_ffs != NUL)
483 set_fileformat(default_fileformat(), OPT_LOCAL);
484 }
485
486 /* set or reset 'binary' */
487 if (eap != NULL && eap->force_bin != 0)
488 {
489 int oldval = curbuf->b_p_bin;
490
491 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
492 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
493 }
494
495 /*
496 * When opening a new file we take the readonly flag from the file.
497 * Default is r/w, can be set to r/o below.
498 * Don't reset it when in readonly mode
499 * Only set/reset b_p_ro when BF_CHECK_RO is set.
500 */
501 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000502 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 curbuf->b_p_ro = FALSE;
504
505 if (newfile && !read_stdin && !read_buffer)
506 {
Bram Moolenaare60acc12011-05-10 16:41:25 +0200507 /* Remember time of file. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 if (mch_stat((char *)fname, &st) >= 0)
509 {
510 buf_store_time(curbuf, &st, fname);
511 curbuf->b_mtime_read = curbuf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512#ifdef UNIX
513 /*
514 * Use the protection bits of the original file for the swap file.
515 * This makes it possible for others to read the name of the
516 * edited file from the swapfile, but only if they can read the
517 * edited file.
518 * Remove the "write" and "execute" bits for group and others
519 * (they must not write the swapfile).
520 * Add the "read" and "write" bits for the user, otherwise we may
521 * not be able to write to the file ourselves.
522 * Setting the bits is done below, after creating the swap file.
523 */
524 swap_mode = (st.st_mode & 0644) | 0600;
525#endif
526#ifdef FEAT_CW_EDITOR
527 /* Get the FSSpec on MacOS
528 * TODO: Update it properly when the buffer name changes
529 */
530 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
531#endif
532#ifdef VMS
533 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000534 curbuf->b_fab_rat = st.st_fab_rat;
535 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536#endif
537 }
538 else
539 {
540 curbuf->b_mtime = 0;
541 curbuf->b_mtime_read = 0;
542 curbuf->b_orig_size = 0;
543 curbuf->b_orig_mode = 0;
544 }
545
546 /* Reset the "new file" flag. It will be set again below when the
547 * file doesn't exist. */
548 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
549 }
550
551/*
552 * for UNIX: check readonly with perm and mch_access()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 * for MSDOS and Amiga: check readonly by trying to open the file for writing
554 */
555 file_readonly = FALSE;
556 if (read_stdin)
557 {
558#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
559 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
560 setmode(0, O_BINARY);
561#endif
562 }
563 else if (!read_buffer)
564 {
565#ifdef USE_MCH_ACCESS
566 if (
567# ifdef UNIX
568 !(perm & 0222) ||
569# endif
570 mch_access((char *)fname, W_OK))
571 file_readonly = TRUE;
572 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
573#else
574 if (!newfile
575 || readonlymode
576 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
577 {
578 file_readonly = TRUE;
579 /* try to open ro */
580 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
581 }
582#endif
583 }
584
585 if (fd < 0) /* cannot open at all */
586 {
587#ifndef UNIX
588 int isdir_f;
589#endif
590 msg_scroll = msg_save;
591#ifndef UNIX
592 /*
593 * On MSDOS and Amiga we can't open a directory, check here.
594 */
595 isdir_f = (mch_isdir(fname));
596 perm = mch_getperm(fname); /* check if the file exists */
597 if (isdir_f)
598 {
599 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
600 curbuf->b_p_ro = TRUE; /* must use "w!" now */
601 }
602 else
603#endif
604 if (newfile)
605 {
Bram Moolenaar2efbc662010-05-14 18:56:38 +0200606 if (perm < 0
607#ifdef ENOENT
608 && errno == ENOENT
609#endif
610 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
612 /*
613 * Set the 'new-file' flag, so that when the file has
614 * been created by someone else, a ":w" will complain.
615 */
616 curbuf->b_flags |= BF_NEW;
617
618 /* Create a swap file now, so that other Vims are warned
619 * that we are editing this file. Don't do this for a
620 * "nofile" or "nowrite" buffer type. */
621#ifdef FEAT_QUICKFIX
622 if (!bt_dontwrite(curbuf))
623#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000624 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000626#ifdef FEAT_AUTOCMD
627 /* SwapExists autocommand may mess things up */
628 if (curbuf != old_curbuf
629 || (using_b_ffname
630 && (old_b_ffname != curbuf->b_ffname))
631 || (using_b_fname
632 && (old_b_fname != curbuf->b_fname)))
633 {
634 EMSG(_(e_auchangedbuf));
635 return FAIL;
636 }
637#endif
638 }
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000639 if (dir_of_file_exists(fname))
640 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
641 else
642 filemess(curbuf, sfname,
643 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644#ifdef FEAT_VIMINFO
645 /* Even though this is a new file, it might have been
646 * edited before and deleted. Get the old marks. */
647 check_marks_read();
648#endif
649#ifdef FEAT_MBYTE
650 if (eap != NULL && eap->force_enc != 0)
651 {
652 /* set forced 'fileencoding' */
653 fenc = enc_canonize(eap->cmd + eap->force_enc);
654 if (fenc != NULL)
655 set_string_option_direct((char_u *)"fenc", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000656 fenc, OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657 vim_free(fenc);
658 }
659#endif
660#ifdef FEAT_AUTOCMD
661 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
662 FALSE, curbuf, eap);
663#endif
664 /* remember the current fileformat */
665 save_file_ff(curbuf);
666
667#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
668 if (aborting()) /* autocmds may abort script processing */
669 return FAIL;
670#endif
671 return OK; /* a new file is not an error */
672 }
673 else
674 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000675 filemess(curbuf, sfname, (char_u *)(
676# ifdef EFBIG
677 (errno == EFBIG) ? _("[File too big]") :
678# endif
Bram Moolenaar2efbc662010-05-14 18:56:38 +0200679# ifdef EOVERFLOW
680 (errno == EOVERFLOW) ? _("[File too big]") :
681# endif
Bram Moolenaar202795b2005-10-11 20:29:39 +0000682 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 curbuf->b_p_ro = TRUE; /* must use "w!" now */
684 }
685 }
686
687 return FAIL;
688 }
689
690 /*
691 * Only set the 'ro' flag for readonly files the first time they are
692 * loaded. Help files always get readonly mode
693 */
694 if ((check_readonly && file_readonly) || curbuf->b_help)
695 curbuf->b_p_ro = TRUE;
696
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000697 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698 {
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000699 /* Don't change 'eol' if reading from buffer as it will already be
700 * correctly set when reading stdin. */
701 if (!read_buffer)
702 {
703 curbuf->b_p_eol = TRUE;
704 curbuf->b_start_eol = TRUE;
705 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706#ifdef FEAT_MBYTE
707 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000708 curbuf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709#endif
710 }
711
712 /* Create a swap file now, so that other Vims are warned that we are
713 * editing this file.
714 * Don't do this for a "nofile" or "nowrite" buffer type. */
715#ifdef FEAT_QUICKFIX
716 if (!bt_dontwrite(curbuf))
717#endif
718 {
719 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000720#ifdef FEAT_AUTOCMD
721 if (!read_stdin && (curbuf != old_curbuf
722 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
723 || (using_b_fname && (old_b_fname != curbuf->b_fname))))
724 {
725 EMSG(_(e_auchangedbuf));
726 if (!read_buffer)
727 close(fd);
728 return FAIL;
729 }
730#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731#ifdef UNIX
732 /* Set swap file protection bits after creating it. */
Bram Moolenaarf061e0b2009-06-24 15:32:01 +0000733 if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
734 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
736#endif
737 }
738
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000739#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 /* If "Quit" selected at ATTENTION dialog, don't load the file */
741 if (swap_exists_action == SEA_QUIT)
742 {
743 if (!read_buffer && !read_stdin)
744 close(fd);
745 return FAIL;
746 }
747#endif
748
749 ++no_wait_return; /* don't wait for return yet */
750
751 /*
752 * Set '[ mark to the line above where the lines go (line 1 if zero).
753 */
754 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
755 curbuf->b_op_start.col = 0;
756
757#ifdef FEAT_AUTOCMD
758 if (!read_buffer)
759 {
760 int m = msg_scroll;
761 int n = msg_scrolled;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762
763 /*
764 * The file must be closed again, the autocommands may want to change
765 * the file before reading it.
766 */
767 if (!read_stdin)
768 close(fd); /* ignore errors */
769
770 /*
771 * The output from the autocommands should not overwrite anything and
772 * should not be overwritten: Set msg_scroll, restore its value if no
773 * output was done.
774 */
775 msg_scroll = TRUE;
776 if (filtering)
777 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
778 FALSE, curbuf, eap);
779 else if (read_stdin)
780 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
781 FALSE, curbuf, eap);
782 else if (newfile)
783 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
784 FALSE, curbuf, eap);
785 else
786 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
787 FALSE, NULL, eap);
788 if (msg_scrolled == n)
789 msg_scroll = m;
790
791#ifdef FEAT_EVAL
792 if (aborting()) /* autocmds may abort script processing */
793 {
794 --no_wait_return;
795 msg_scroll = msg_save;
796 curbuf->b_p_ro = TRUE; /* must use "w!" now */
797 return FAIL;
798 }
799#endif
800 /*
801 * Don't allow the autocommands to change the current buffer.
802 * Try to re-open the file.
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000803 *
804 * Don't allow the autocommands to change the buffer name either
805 * (cd for example) if it invalidates fname or sfname.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 */
807 if (!read_stdin && (curbuf != old_curbuf
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000808 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
809 || (using_b_fname && (old_b_fname != curbuf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
811 {
812 --no_wait_return;
813 msg_scroll = msg_save;
814 if (fd < 0)
815 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
816 else
817 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
818 curbuf->b_p_ro = TRUE; /* must use "w!" now */
819 return FAIL;
820 }
821 }
822#endif /* FEAT_AUTOCMD */
823
824 /* Autocommands may add lines to the file, need to check if it is empty */
825 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
826
827 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
828 {
829 /*
830 * Show the user that we are busy reading the input. Sometimes this
831 * may take a while. When reading from stdin another program may
832 * still be running, don't move the cursor to the last line, unless
833 * always using the GUI.
834 */
835 if (read_stdin)
836 {
837#ifndef ALWAYS_USE_GUI
838 mch_msg(_("Vim: Reading from stdin...\n"));
839#endif
840#ifdef FEAT_GUI
841 /* Also write a message in the GUI window, if there is one. */
842 if (gui.in_use && !gui.dying && !gui.starting)
843 {
844 p = (char_u *)_("Reading from stdin...");
845 gui_write(p, (int)STRLEN(p));
846 }
847#endif
848 }
849 else if (!read_buffer)
850 filemess(curbuf, sfname, (char_u *)"", 0);
851 }
852
853 msg_scroll = FALSE; /* overwrite the file message */
854
855 /*
856 * Set linecnt now, before the "retry" caused by a wrong guess for
857 * fileformat, and after the autocommands, which may change them.
858 */
859 linecnt = curbuf->b_ml.ml_line_count;
860
861#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000862 /* "++bad=" argument. */
863 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000864 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000865 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000866 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000867 curbuf->b_bad_char = eap->bad_char;
868 }
869 else
870 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000873 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 */
875 if (eap != NULL && eap->force_enc != 0)
876 {
877 fenc = enc_canonize(eap->cmd + eap->force_enc);
878 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000879 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 }
881 else if (curbuf->b_p_bin)
882 {
883 fenc = (char_u *)""; /* binary: don't convert */
884 fenc_alloced = FALSE;
885 }
886 else if (curbuf->b_help)
887 {
888 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000889 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890
891 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
892 * fails it must be latin1.
893 * Always do this when 'encoding' is "utf-8". Otherwise only do
894 * this when needed to avoid [converted] remarks all the time.
895 * It is needed when the first line contains non-ASCII characters.
896 * That is only in *.??x files. */
897 fenc = (char_u *)"latin1";
898 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000899 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000901 fc = fname[STRLEN(fname) - 1];
902 if (TOLOWER_ASC(fc) == 'x')
903 {
904 /* Read the first line (and a bit more). Immediately rewind to
905 * the start of the file. If the read() fails "len" is -1. */
Bram Moolenaar540fc6f2010-12-17 16:27:16 +0100906 len = read_eintr(fd, firstline, 80);
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000907 lseek(fd, (off_t)0L, SEEK_SET);
908 for (p = firstline; p < firstline + len; ++p)
909 if (*p >= 0x80)
910 {
911 c = TRUE;
912 break;
913 }
914 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 }
916
917 if (c)
918 {
919 fenc_next = fenc;
920 fenc = (char_u *)"utf-8";
921
922 /* When the file is utf-8 but a character doesn't fit in
923 * 'encoding' don't retry. In help text editing utf-8 bytes
924 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000925 if (!enc_utf8)
926 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927 }
928 fenc_alloced = FALSE;
929 }
930 else if (*p_fencs == NUL)
931 {
932 fenc = curbuf->b_p_fenc; /* use format from buffer */
933 fenc_alloced = FALSE;
934 }
935 else
936 {
937 fenc_next = p_fencs; /* try items in 'fileencodings' */
938 fenc = next_fenc(&fenc_next);
939 fenc_alloced = TRUE;
940 }
941#endif
942
943 /*
944 * Jump back here to retry reading the file in different ways.
945 * Reasons to retry:
946 * - encoding conversion failed: try another one from "fenc_next"
947 * - BOM detected and fenc was set, need to setup conversion
948 * - "fileformat" check failed: try another
949 *
950 * Variables set for special retry actions:
951 * "file_rewind" Rewind the file to start reading it again.
952 * "advance_fenc" Advance "fenc" using "fenc_next".
953 * "skip_read" Re-use already read bytes (BOM detected).
954 * "did_iconv" iconv() conversion failed, try 'charconvert'.
955 * "keep_fileformat" Don't reset "fileformat".
956 *
957 * Other status indicators:
958 * "tmpname" When != NULL did conversion with 'charconvert'.
959 * Output file has to be deleted afterwards.
960 * "iconv_fd" When != -1 did conversion with iconv().
961 */
962retry:
963
964 if (file_rewind)
965 {
966 if (read_buffer)
967 {
968 read_buf_lnum = 1;
969 read_buf_col = 0;
970 }
971 else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0)
972 {
973 /* Can't rewind the file, give up. */
974 error = TRUE;
975 goto failed;
976 }
977 /* Delete the previously read lines. */
978 while (lnum > from)
979 ml_delete(lnum--, FALSE);
980 file_rewind = FALSE;
981#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000982 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000983 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000985 curbuf->b_start_bomb = FALSE;
986 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000987 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988#endif
989 }
990
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200991#ifdef FEAT_CRYPT
992 if (cryptkey != NULL)
993 /* Need to reset the state, but keep the key, don't want to ask for it
994 * again. */
995 crypt_pop_state();
996#endif
997
Bram Moolenaar071d4272004-06-13 20:20:40 +0000998 /*
999 * When retrying with another "fenc" and the first time "fileformat"
1000 * will be reset.
1001 */
1002 if (keep_fileformat)
1003 keep_fileformat = FALSE;
1004 else
1005 {
1006 if (eap != NULL && eap->force_ff != 0)
Bram Moolenaar1c860362008-11-12 15:05:21 +00001007 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 fileformat = get_fileformat_force(curbuf, eap);
Bram Moolenaar1c860362008-11-12 15:05:21 +00001009 try_unix = try_dos = try_mac = FALSE;
1010 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 else if (curbuf->b_p_bin)
1012 fileformat = EOL_UNIX; /* binary: use Unix format */
1013 else if (*p_ffs == NUL)
1014 fileformat = get_fileformat(curbuf);/* use format from buffer */
1015 else
1016 fileformat = EOL_UNKNOWN; /* detect from file */
1017 }
1018
1019#ifdef FEAT_MBYTE
1020# ifdef USE_ICONV
1021 if (iconv_fd != (iconv_t)-1)
1022 {
1023 /* aborted conversion with iconv(), close the descriptor */
1024 iconv_close(iconv_fd);
1025 iconv_fd = (iconv_t)-1;
1026 }
1027# endif
1028
1029 if (advance_fenc)
1030 {
1031 /*
1032 * Try the next entry in 'fileencodings'.
1033 */
1034 advance_fenc = FALSE;
1035
1036 if (eap != NULL && eap->force_enc != 0)
1037 {
1038 /* Conversion given with "++cc=" wasn't possible, read
1039 * without conversion. */
1040 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001041 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 if (fenc_alloced)
1043 vim_free(fenc);
1044 fenc = (char_u *)"";
1045 fenc_alloced = FALSE;
1046 }
1047 else
1048 {
1049 if (fenc_alloced)
1050 vim_free(fenc);
1051 if (fenc_next != NULL)
1052 {
1053 fenc = next_fenc(&fenc_next);
1054 fenc_alloced = (fenc_next != NULL);
1055 }
1056 else
1057 {
1058 fenc = (char_u *)"";
1059 fenc_alloced = FALSE;
1060 }
1061 }
1062 if (tmpname != NULL)
1063 {
1064 mch_remove(tmpname); /* delete converted file */
1065 vim_free(tmpname);
1066 tmpname = NULL;
1067 }
1068 }
1069
1070 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001071 * Conversion may be required when the encoding of the file is different
1072 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073 */
1074 fio_flags = 0;
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001075 converted = need_conversion(fenc);
1076 if (converted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 {
1078
1079 /* "ucs-bom" means we need to check the first bytes of the file
1080 * for a BOM. */
1081 if (STRCMP(fenc, ENC_UCSBOM) == 0)
1082 fio_flags = FIO_UCSBOM;
1083
1084 /*
1085 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
1086 * done. This is handled below after read(). Prepare the
1087 * fio_flags to avoid having to parse the string each time.
1088 * Also check for Unicode to Latin1 conversion, because iconv()
1089 * appears not to handle this correctly. This works just like
1090 * conversion to UTF-8 except how the resulting character is put in
1091 * the buffer.
1092 */
1093 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
1094 fio_flags = get_fio_flags(fenc);
1095
1096# ifdef WIN3264
1097 /*
1098 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
1099 * is handled with MultiByteToWideChar().
1100 */
1101 if (fio_flags == 0)
1102 fio_flags = get_win_fio_flags(fenc);
1103# endif
1104
1105# ifdef MACOS_X
1106 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1107 if (fio_flags == 0)
1108 fio_flags = get_mac_fio_flags(fenc);
1109# endif
1110
1111# ifdef USE_ICONV
1112 /*
1113 * Try using iconv() if we can't convert internally.
1114 */
1115 if (fio_flags == 0
1116# ifdef FEAT_EVAL
1117 && !did_iconv
1118# endif
1119 )
1120 iconv_fd = (iconv_t)my_iconv_open(
1121 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
1122# endif
1123
1124# ifdef FEAT_EVAL
1125 /*
1126 * Use the 'charconvert' expression when conversion is required
1127 * and we can't do it internally or with iconv().
1128 */
1129 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
1130# ifdef USE_ICONV
1131 && iconv_fd == (iconv_t)-1
1132# endif
1133 )
1134 {
1135# ifdef USE_ICONV
1136 did_iconv = FALSE;
1137# endif
1138 /* Skip conversion when it's already done (retry for wrong
1139 * "fileformat"). */
1140 if (tmpname == NULL)
1141 {
1142 tmpname = readfile_charconvert(fname, fenc, &fd);
1143 if (tmpname == NULL)
1144 {
1145 /* Conversion failed. Try another one. */
1146 advance_fenc = TRUE;
1147 if (fd < 0)
1148 {
1149 /* Re-opening the original file failed! */
1150 EMSG(_("E202: Conversion made file unreadable!"));
1151 error = TRUE;
1152 goto failed;
1153 }
1154 goto retry;
1155 }
1156 }
1157 }
1158 else
1159# endif
1160 {
1161 if (fio_flags == 0
1162# ifdef USE_ICONV
1163 && iconv_fd == (iconv_t)-1
1164# endif
1165 )
1166 {
1167 /* Conversion wanted but we can't.
1168 * Try the next conversion in 'fileencodings' */
1169 advance_fenc = TRUE;
1170 goto retry;
1171 }
1172 }
1173 }
1174
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001175 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001177 * stdin or fixed at a specific encoding. */
1178 can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179#endif
1180
1181 if (!skip_read)
1182 {
1183 linerest = 0;
1184 filesize = 0;
1185 skip_count = lines_to_skip;
1186 read_count = lines_to_read;
1187#ifdef FEAT_MBYTE
1188 conv_restlen = 0;
1189#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001190#ifdef FEAT_PERSISTENT_UNDO
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001191 read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0
1192 && curbuf->b_ffname != NULL
1193 && curbuf->b_p_udf
1194 && !filtering
1195 && !read_stdin
1196 && !read_buffer);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001197 if (read_undo_file)
1198 sha256_start(&sha_ctx);
1199#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 }
1201
1202 while (!error && !got_int)
1203 {
1204 /*
1205 * We allocate as much space for the file as we can get, plus
1206 * space for the old line plus room for one terminating NUL.
1207 * The amount is limited by the fact that read() only can read
1208 * upto max_unsigned characters (and other things).
1209 */
1210#if SIZEOF_INT <= 2
1211 if (linerest >= 0x7ff0)
1212 {
1213 ++split;
1214 *ptr = NL; /* split line by inserting a NL */
1215 size = 1;
1216 }
1217 else
1218#endif
1219 {
1220 if (!skip_read)
1221 {
1222#if SIZEOF_INT > 2
Bram Moolenaar311d9822007-02-27 15:48:28 +00001223# if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224 size = SSIZE_MAX; /* use max I/O size, 52K */
1225# else
1226 size = 0x10000L; /* use buffer >= 64K */
1227# endif
1228#else
1229 size = 0x7ff0L - linerest; /* limit buffer to 32K */
1230#endif
1231
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001232 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 {
1234 if ((new_buffer = lalloc((long_u)(size + linerest + 1),
1235 FALSE)) != NULL)
1236 break;
1237 }
1238 if (new_buffer == NULL)
1239 {
1240 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1241 error = TRUE;
1242 break;
1243 }
1244 if (linerest) /* copy characters from the previous buffer */
1245 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1246 vim_free(buffer);
1247 buffer = new_buffer;
1248 ptr = buffer + linerest;
1249 line_start = buffer;
1250
1251#ifdef FEAT_MBYTE
1252 /* May need room to translate into.
1253 * For iconv() we don't really know the required space, use a
1254 * factor ICONV_MULT.
1255 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1256 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1257 * become up to 4 bytes, size must be multiple of 2
1258 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1259 * multiple of 2
1260 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1261 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001262 real_size = (int)size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001263# ifdef USE_ICONV
1264 if (iconv_fd != (iconv_t)-1)
1265 size = size / ICONV_MULT;
1266 else
1267# endif
1268 if (fio_flags & FIO_LATIN1)
1269 size = size / 2;
1270 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1271 size = (size * 2 / 3) & ~1;
1272 else if (fio_flags & FIO_UCS4)
1273 size = (size * 2 / 3) & ~3;
1274 else if (fio_flags == FIO_UCSBOM)
1275 size = size / ICONV_MULT; /* worst case */
1276# ifdef WIN3264
1277 else if (fio_flags & FIO_CODEPAGE)
1278 size = size / ICONV_MULT; /* also worst case */
1279# endif
1280# ifdef MACOS_X
1281 else if (fio_flags & FIO_MACROMAN)
1282 size = size / ICONV_MULT; /* also worst case */
1283# endif
1284#endif
1285
1286#ifdef FEAT_MBYTE
1287 if (conv_restlen > 0)
1288 {
1289 /* Insert unconverted bytes from previous line. */
1290 mch_memmove(ptr, conv_rest, conv_restlen);
1291 ptr += conv_restlen;
1292 size -= conv_restlen;
1293 }
1294#endif
1295
1296 if (read_buffer)
1297 {
1298 /*
1299 * Read bytes from curbuf. Used for converting text read
1300 * from stdin.
1301 */
1302 if (read_buf_lnum > from)
1303 size = 0;
1304 else
1305 {
1306 int n, ni;
1307 long tlen;
1308
1309 tlen = 0;
1310 for (;;)
1311 {
1312 p = ml_get(read_buf_lnum) + read_buf_col;
1313 n = (int)STRLEN(p);
1314 if ((int)tlen + n + 1 > size)
1315 {
1316 /* Filled up to "size", append partial line.
1317 * Change NL to NUL to reverse the effect done
1318 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001319 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001320 for (ni = 0; ni < n; ++ni)
1321 {
1322 if (p[ni] == NL)
1323 ptr[tlen++] = NUL;
1324 else
1325 ptr[tlen++] = p[ni];
1326 }
1327 read_buf_col += n;
1328 break;
1329 }
1330 else
1331 {
1332 /* Append whole line and new-line. Change NL
1333 * to NUL to reverse the effect done below. */
1334 for (ni = 0; ni < n; ++ni)
1335 {
1336 if (p[ni] == NL)
1337 ptr[tlen++] = NUL;
1338 else
1339 ptr[tlen++] = p[ni];
1340 }
1341 ptr[tlen++] = NL;
1342 read_buf_col = 0;
1343 if (++read_buf_lnum > from)
1344 {
1345 /* When the last line didn't have an
1346 * end-of-line don't add it now either. */
1347 if (!curbuf->b_p_eol)
1348 --tlen;
1349 size = tlen;
1350 break;
1351 }
1352 }
1353 }
1354 }
1355 }
1356 else
1357 {
1358 /*
1359 * Read bytes from the file.
1360 */
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01001361 size = read_eintr(fd, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362 }
1363
1364 if (size <= 0)
1365 {
1366 if (size < 0) /* read error */
1367 error = TRUE;
1368#ifdef FEAT_MBYTE
1369 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001370 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001371 /*
1372 * Reached end-of-file but some trailing bytes could
1373 * not be converted. Truncated file?
1374 */
1375
1376 /* When we did a conversion report an error. */
1377 if (fio_flags != 0
1378# ifdef USE_ICONV
1379 || iconv_fd != (iconv_t)-1
1380# endif
1381 )
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001382 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001383 if (conv_error == 0)
1384 conv_error = curbuf->b_ml.ml_line_count
1385 - linecnt + 1;
1386 }
1387 /* Remember the first linenr with an illegal byte */
1388 else if (illegal_byte == 0)
1389 illegal_byte = curbuf->b_ml.ml_line_count
1390 - linecnt + 1;
1391 if (bad_char_behavior == BAD_DROP)
1392 {
1393 *(ptr - conv_restlen) = NUL;
1394 conv_restlen = 0;
1395 }
1396 else
1397 {
1398 /* Replace the trailing bytes with the replacement
1399 * character if we were converting; if we weren't,
1400 * leave the UTF8 checking code to do it, as it
1401 * works slightly differently. */
1402 if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
1403# ifdef USE_ICONV
1404 || iconv_fd != (iconv_t)-1
1405# endif
1406 ))
1407 {
1408 while (conv_restlen > 0)
1409 {
1410 *(--ptr) = bad_char_behavior;
1411 --conv_restlen;
1412 }
1413 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001414 fio_flags = 0; /* don't convert this */
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001415# ifdef USE_ICONV
1416 if (iconv_fd != (iconv_t)-1)
1417 {
1418 iconv_close(iconv_fd);
1419 iconv_fd = (iconv_t)-1;
1420 }
1421# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001422 }
1423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424#endif
1425 }
1426
1427#ifdef FEAT_CRYPT
1428 /*
1429 * At start of file: Check for magic number of encryption.
1430 */
1431 if (filesize == 0)
1432 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001433 &filesize, newfile, sfname,
1434 &did_ask_for_key);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001435 /*
1436 * Decrypt the read bytes.
1437 */
1438 if (cryptkey != NULL && size > 0)
Bram Moolenaar04c9baf2010-06-01 23:37:39 +02001439 crypt_decode(ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001440#endif
1441 }
1442 skip_read = FALSE;
1443
1444#ifdef FEAT_MBYTE
1445 /*
1446 * At start of file (or after crypt magic number): Check for BOM.
1447 * Also check for a BOM for other Unicode encodings, but not after
1448 * converting with 'charconvert' or when a BOM has already been
1449 * found.
1450 */
1451 if ((filesize == 0
1452# ifdef FEAT_CRYPT
Bram Moolenaar40e6a712010-05-16 22:32:54 +02001453 || (filesize == (CRYPT_MAGIC_LEN
Bram Moolenaar80794b12010-06-13 05:20:42 +02001454 + crypt_salt_len[use_crypt_method]
Bram Moolenaar40e6a712010-05-16 22:32:54 +02001455 + crypt_seed_len[use_crypt_method])
1456 && cryptkey != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457# endif
1458 )
1459 && (fio_flags == FIO_UCSBOM
1460 || (!curbuf->b_p_bomb
1461 && tmpname == NULL
1462 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1463 {
1464 char_u *ccname;
1465 int blen;
1466
1467 /* no BOM detection in a short file or in binary mode */
1468 if (size < 2 || curbuf->b_p_bin)
1469 ccname = NULL;
1470 else
1471 ccname = check_for_bom(ptr, size, &blen,
1472 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1473 if (ccname != NULL)
1474 {
1475 /* Remove BOM from the text */
1476 filesize += blen;
1477 size -= blen;
1478 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001479 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001480 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481 curbuf->b_p_bomb = TRUE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001482 curbuf->b_start_bomb = TRUE;
1483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484 }
1485
1486 if (fio_flags == FIO_UCSBOM)
1487 {
1488 if (ccname == NULL)
1489 {
1490 /* No BOM detected: retry with next encoding. */
1491 advance_fenc = TRUE;
1492 }
1493 else
1494 {
1495 /* BOM detected: set "fenc" and jump back */
1496 if (fenc_alloced)
1497 vim_free(fenc);
1498 fenc = ccname;
1499 fenc_alloced = FALSE;
1500 }
1501 /* retry reading without getting new bytes or rewinding */
1502 skip_read = TRUE;
1503 goto retry;
1504 }
1505 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001506
1507 /* Include not converted bytes. */
1508 ptr -= conv_restlen;
1509 size += conv_restlen;
1510 conv_restlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511#endif
1512 /*
1513 * Break here for a read error or end-of-file.
1514 */
1515 if (size <= 0)
1516 break;
1517
1518#ifdef FEAT_MBYTE
1519
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520# ifdef USE_ICONV
1521 if (iconv_fd != (iconv_t)-1)
1522 {
1523 /*
1524 * Attempt conversion of the read bytes to 'encoding' using
1525 * iconv().
1526 */
1527 const char *fromp;
1528 char *top;
1529 size_t from_size;
1530 size_t to_size;
1531
1532 fromp = (char *)ptr;
1533 from_size = size;
1534 ptr += size;
1535 top = (char *)ptr;
1536 to_size = real_size - size;
1537
1538 /*
1539 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001540 * another conversion. Except for when there is no
1541 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001543 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1544 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1546 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001547 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001548 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001549 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001550 if (conv_error == 0)
1551 conv_error = readfile_linenr(linecnt,
1552 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001553
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001554 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001555 ++fromp;
1556 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001557 if (bad_char_behavior == BAD_KEEP)
1558 {
1559 *top++ = *(fromp - 1);
1560 --to_size;
1561 }
1562 else if (bad_char_behavior != BAD_DROP)
1563 {
1564 *top++ = bad_char_behavior;
1565 --to_size;
1566 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001567 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568
1569 if (from_size > 0)
1570 {
1571 /* Some remaining characters, keep them for the next
1572 * round. */
1573 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1574 conv_restlen = (int)from_size;
1575 }
1576
1577 /* move the linerest to before the converted characters */
1578 line_start = ptr - linerest;
1579 mch_memmove(line_start, buffer, (size_t)linerest);
1580 size = (long)((char_u *)top - ptr);
1581 }
1582# endif
1583
1584# ifdef WIN3264
1585 if (fio_flags & FIO_CODEPAGE)
1586 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001587 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001588 WCHAR ucs2buf[3];
1589 int ucs2len;
1590 int codepage = FIO_GET_CP(fio_flags);
1591 int bytelen;
1592 int found_bad;
1593 char replstr[2];
1594
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595 /*
1596 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001597 * a codepage, using standard MS-Windows functions. This
1598 * requires two steps:
1599 * 1. convert from 'fileencoding' to ucs-2
1600 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001602 * Because there may be illegal bytes AND an incomplete byte
1603 * sequence at the end, we may have to do the conversion one
1604 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001607 /* Replacement string for WideCharToMultiByte(). */
1608 if (bad_char_behavior > 0)
1609 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001611 replstr[0] = '?';
1612 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613
1614 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001615 * Move the bytes to the end of the buffer, so that we have
1616 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001618 src = ptr + real_size - size;
1619 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001621 /*
1622 * Do the conversion.
1623 */
1624 dst = ptr;
1625 size = size;
1626 while (size > 0)
1627 {
1628 found_bad = FALSE;
1629
1630# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1631 if (codepage == CP_UTF8)
1632 {
1633 /* Handle CP_UTF8 input ourselves to be able to handle
1634 * trailing bytes properly.
1635 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001636 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001637 if (bytelen > size)
1638 {
1639 /* Only got some bytes of a character. Normally
1640 * it's put in "conv_rest", but if it's too long
1641 * deal with it as if they were illegal bytes. */
1642 if (bytelen <= CONV_RESTLEN)
1643 break;
1644
1645 /* weird overlong byte sequence */
1646 bytelen = size;
1647 found_bad = TRUE;
1648 }
1649 else
1650 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001651 int u8c = utf_ptr2char(src);
1652
Bram Moolenaar86e01082005-12-29 22:45:34 +00001653 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001654 found_bad = TRUE;
1655 ucs2buf[0] = u8c;
1656 ucs2len = 1;
1657 }
1658 }
1659 else
1660# endif
1661 {
1662 /* We don't know how long the byte sequence is, try
1663 * from one to three bytes. */
1664 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1665 ++bytelen)
1666 {
1667 ucs2len = MultiByteToWideChar(codepage,
1668 MB_ERR_INVALID_CHARS,
1669 (LPCSTR)src, bytelen,
1670 ucs2buf, 3);
1671 if (ucs2len > 0)
1672 break;
1673 }
1674 if (ucs2len == 0)
1675 {
1676 /* If we have only one byte then it's probably an
1677 * incomplete byte sequence. Otherwise discard
1678 * one byte as a bad character. */
1679 if (size == 1)
1680 break;
1681 found_bad = TRUE;
1682 bytelen = 1;
1683 }
1684 }
1685
1686 if (!found_bad)
1687 {
1688 int i;
1689
1690 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1691 if (enc_utf8)
1692 {
1693 /* From UCS-2 to UTF-8. Cannot fail. */
1694 for (i = 0; i < ucs2len; ++i)
1695 dst += utf_char2bytes(ucs2buf[i], dst);
1696 }
1697 else
1698 {
1699 BOOL bad = FALSE;
1700 int dstlen;
1701
1702 /* From UCS-2 to "enc_codepage". If the
1703 * conversion uses the default character "?",
1704 * the data doesn't fit in this encoding. */
1705 dstlen = WideCharToMultiByte(enc_codepage, 0,
1706 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001707 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001708 replstr, &bad);
1709 if (bad)
1710 found_bad = TRUE;
1711 else
1712 dst += dstlen;
1713 }
1714 }
1715
1716 if (found_bad)
1717 {
1718 /* Deal with bytes we can't convert. */
1719 if (can_retry)
1720 goto rewind_retry;
1721 if (conv_error == 0)
1722 conv_error = readfile_linenr(linecnt, ptr, dst);
1723 if (bad_char_behavior != BAD_DROP)
1724 {
1725 if (bad_char_behavior == BAD_KEEP)
1726 {
1727 mch_memmove(dst, src, bytelen);
1728 dst += bytelen;
1729 }
1730 else
1731 *dst++ = bad_char_behavior;
1732 }
1733 }
1734
1735 src += bytelen;
1736 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001738
1739 if (size > 0)
1740 {
1741 /* An incomplete byte sequence remaining. */
1742 mch_memmove(conv_rest, src, size);
1743 conv_restlen = size;
1744 }
1745
1746 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001747 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748 }
1749 else
1750# endif
Bram Moolenaar56718732006-03-15 22:53:57 +00001751# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 if (fio_flags & FIO_MACROMAN)
1753 {
1754 /*
1755 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001756 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001758 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 }
1761 else
1762# endif
1763 if (fio_flags != 0)
1764 {
1765 int u8c;
1766 char_u *dest;
1767 char_u *tail = NULL;
1768
1769 /*
1770 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1771 * "enc_utf8" not set: Convert Unicode to Latin1.
1772 * Go from end to start through the buffer, because the number
1773 * of bytes may increase.
1774 * "dest" points to after where the UTF-8 bytes go, "p" points
1775 * to after the next character to convert.
1776 */
1777 dest = ptr + real_size;
1778 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1779 {
1780 p = ptr + size;
1781 if (fio_flags == FIO_UTF8)
1782 {
1783 /* Check for a trailing incomplete UTF-8 sequence */
1784 tail = ptr + size - 1;
1785 while (tail > ptr && (*tail & 0xc0) == 0x80)
1786 --tail;
1787 if (tail + utf_byte2len(*tail) <= ptr + size)
1788 tail = NULL;
1789 else
1790 p = tail;
1791 }
1792 }
1793 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1794 {
1795 /* Check for a trailing byte */
1796 p = ptr + (size & ~1);
1797 if (size & 1)
1798 tail = p;
1799 if ((fio_flags & FIO_UTF16) && p > ptr)
1800 {
1801 /* Check for a trailing leading word */
1802 if (fio_flags & FIO_ENDIAN_L)
1803 {
1804 u8c = (*--p << 8);
1805 u8c += *--p;
1806 }
1807 else
1808 {
1809 u8c = *--p;
1810 u8c += (*--p << 8);
1811 }
1812 if (u8c >= 0xd800 && u8c <= 0xdbff)
1813 tail = p;
1814 else
1815 p += 2;
1816 }
1817 }
1818 else /* FIO_UCS4 */
1819 {
1820 /* Check for trailing 1, 2 or 3 bytes */
1821 p = ptr + (size & ~3);
1822 if (size & 3)
1823 tail = p;
1824 }
1825
1826 /* If there is a trailing incomplete sequence move it to
1827 * conv_rest[]. */
1828 if (tail != NULL)
1829 {
1830 conv_restlen = (int)((ptr + size) - tail);
1831 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1832 size -= conv_restlen;
1833 }
1834
1835
1836 while (p > ptr)
1837 {
1838 if (fio_flags & FIO_LATIN1)
1839 u8c = *--p;
1840 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1841 {
1842 if (fio_flags & FIO_ENDIAN_L)
1843 {
1844 u8c = (*--p << 8);
1845 u8c += *--p;
1846 }
1847 else
1848 {
1849 u8c = *--p;
1850 u8c += (*--p << 8);
1851 }
1852 if ((fio_flags & FIO_UTF16)
1853 && u8c >= 0xdc00 && u8c <= 0xdfff)
1854 {
1855 int u16c;
1856
1857 if (p == ptr)
1858 {
1859 /* Missing leading word. */
1860 if (can_retry)
1861 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001862 if (conv_error == 0)
1863 conv_error = readfile_linenr(linecnt,
1864 ptr, p);
1865 if (bad_char_behavior == BAD_DROP)
1866 continue;
1867 if (bad_char_behavior != BAD_KEEP)
1868 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 }
1870
1871 /* found second word of double-word, get the first
1872 * word and compute the resulting character */
1873 if (fio_flags & FIO_ENDIAN_L)
1874 {
1875 u16c = (*--p << 8);
1876 u16c += *--p;
1877 }
1878 else
1879 {
1880 u16c = *--p;
1881 u16c += (*--p << 8);
1882 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001883 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1884 + (u8c & 0x3ff);
1885
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 /* Check if the word is indeed a leading word. */
1887 if (u16c < 0xd800 || u16c > 0xdbff)
1888 {
1889 if (can_retry)
1890 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001891 if (conv_error == 0)
1892 conv_error = readfile_linenr(linecnt,
1893 ptr, p);
1894 if (bad_char_behavior == BAD_DROP)
1895 continue;
1896 if (bad_char_behavior != BAD_KEEP)
1897 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 }
1900 }
1901 else if (fio_flags & FIO_UCS4)
1902 {
1903 if (fio_flags & FIO_ENDIAN_L)
1904 {
1905 u8c = (*--p << 24);
1906 u8c += (*--p << 16);
1907 u8c += (*--p << 8);
1908 u8c += *--p;
1909 }
1910 else /* big endian */
1911 {
1912 u8c = *--p;
1913 u8c += (*--p << 8);
1914 u8c += (*--p << 16);
1915 u8c += (*--p << 24);
1916 }
1917 }
1918 else /* UTF-8 */
1919 {
1920 if (*--p < 0x80)
1921 u8c = *p;
1922 else
1923 {
1924 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001925 p -= len;
1926 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927 if (len == 0)
1928 {
1929 /* Not a valid UTF-8 character, retry with
1930 * another fenc when possible, otherwise just
1931 * report the error. */
1932 if (can_retry)
1933 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001934 if (conv_error == 0)
1935 conv_error = readfile_linenr(linecnt,
1936 ptr, p);
1937 if (bad_char_behavior == BAD_DROP)
1938 continue;
1939 if (bad_char_behavior != BAD_KEEP)
1940 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 }
1943 }
1944 if (enc_utf8) /* produce UTF-8 */
1945 {
1946 dest -= utf_char2len(u8c);
1947 (void)utf_char2bytes(u8c, dest);
1948 }
1949 else /* produce Latin1 */
1950 {
1951 --dest;
1952 if (u8c >= 0x100)
1953 {
1954 /* character doesn't fit in latin1, retry with
1955 * another fenc when possible, otherwise just
1956 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001957 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001959 if (conv_error == 0)
1960 conv_error = readfile_linenr(linecnt, ptr, p);
1961 if (bad_char_behavior == BAD_DROP)
1962 ++dest;
1963 else if (bad_char_behavior == BAD_KEEP)
1964 *dest = u8c;
1965 else if (eap != NULL && eap->bad_char != 0)
1966 *dest = bad_char_behavior;
1967 else
1968 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 }
1970 else
1971 *dest = u8c;
1972 }
1973 }
1974
1975 /* move the linerest to before the converted characters */
1976 line_start = dest - linerest;
1977 mch_memmove(line_start, buffer, (size_t)linerest);
1978 size = (long)((ptr + real_size) - dest);
1979 ptr = dest;
1980 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001981 else if (enc_utf8 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001983 int incomplete_tail = FALSE;
1984
1985 /* Reading UTF-8: Check if the bytes are valid UTF-8. */
1986 for (p = ptr; ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001988 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001989 int l;
1990
1991 if (todo <= 0)
1992 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 if (*p >= 0x80)
1994 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 /* A length of 1 means it's an illegal byte. Accept
1996 * an incomplete character at the end though, the next
1997 * read() will get the next bytes, we'll check it
1998 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001999 l = utf_ptr2len_len(p, todo);
Bram Moolenaarf453d352008-06-04 17:37:34 +00002000 if (l > todo && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002002 /* Avoid retrying with a different encoding when
2003 * a truncated file is more likely, or attempting
2004 * to read the rest of an incomplete sequence when
2005 * we have already done so. */
2006 if (p > ptr || filesize > 0)
2007 incomplete_tail = TRUE;
2008 /* Incomplete byte sequence, move it to conv_rest[]
2009 * and try to read the rest of it, unless we've
2010 * already done so. */
2011 if (p > ptr)
2012 {
2013 conv_restlen = todo;
2014 mch_memmove(conv_rest, p, conv_restlen);
2015 size -= conv_restlen;
2016 break;
2017 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002019 if (l == 1 || l > todo)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002020 {
2021 /* Illegal byte. If we can try another encoding
Bram Moolenaarf453d352008-06-04 17:37:34 +00002022 * do that, unless at EOF where a truncated
2023 * file is more likely than a conversion error. */
2024 if (can_retry && !incomplete_tail)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002025 break;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002026# ifdef USE_ICONV
2027 /* When we did a conversion report an error. */
2028 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
2029 conv_error = readfile_linenr(linecnt, ptr, p);
2030# endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00002031 /* Remember the first linenr with an illegal byte */
2032 if (conv_error == 0 && illegal_byte == 0)
2033 illegal_byte = readfile_linenr(linecnt, ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002034
2035 /* Drop, keep or replace the bad byte. */
2036 if (bad_char_behavior == BAD_DROP)
2037 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002038 mch_memmove(p, p + 1, todo - 1);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002039 --p;
2040 --size;
2041 }
2042 else if (bad_char_behavior != BAD_KEEP)
2043 *p = bad_char_behavior;
2044 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002045 else
2046 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 }
2048 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002049 if (p < ptr + size && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 {
2051 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002053 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002055 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
2056 /* iconv() failed, try 'charconvert' */
2057 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058 else
2059# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002060 /* use next item from 'fileencodings' */
2061 advance_fenc = TRUE;
2062 file_rewind = TRUE;
2063 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 }
2065 }
2066#endif
2067
2068 /* count the number of characters (after conversion!) */
2069 filesize += size;
2070
2071 /*
2072 * when reading the first part of a file: guess EOL type
2073 */
2074 if (fileformat == EOL_UNKNOWN)
2075 {
2076 /* First try finding a NL, for Dos and Unix */
2077 if (try_dos || try_unix)
2078 {
2079 for (p = ptr; p < ptr + size; ++p)
2080 {
2081 if (*p == NL)
2082 {
2083 if (!try_unix
2084 || (try_dos && p > ptr && p[-1] == CAR))
2085 fileformat = EOL_DOS;
2086 else
2087 fileformat = EOL_UNIX;
2088 break;
2089 }
2090 }
2091
2092 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
2093 if (fileformat == EOL_UNIX && try_mac)
2094 {
2095 /* Need to reset the counters when retrying fenc. */
2096 try_mac = 1;
2097 try_unix = 1;
2098 for (; p >= ptr && *p != CAR; p--)
2099 ;
2100 if (p >= ptr)
2101 {
2102 for (p = ptr; p < ptr + size; ++p)
2103 {
2104 if (*p == NL)
2105 try_unix++;
2106 else if (*p == CAR)
2107 try_mac++;
2108 }
2109 if (try_mac > try_unix)
2110 fileformat = EOL_MAC;
2111 }
2112 }
2113 }
2114
2115 /* No NL found: may use Mac format */
2116 if (fileformat == EOL_UNKNOWN && try_mac)
2117 fileformat = EOL_MAC;
2118
2119 /* Still nothing found? Use first format in 'ffs' */
2120 if (fileformat == EOL_UNKNOWN)
2121 fileformat = default_fileformat();
2122
2123 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002124 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125 set_fileformat(fileformat, OPT_LOCAL);
2126 }
2127 }
2128
2129 /*
2130 * This loop is executed once for every character read.
2131 * Keep it fast!
2132 */
2133 if (fileformat == EOL_MAC)
2134 {
2135 --ptr;
2136 while (++ptr, --size >= 0)
2137 {
2138 /* catch most common case first */
2139 if ((c = *ptr) != NUL && c != CAR && c != NL)
2140 continue;
2141 if (c == NUL)
2142 *ptr = NL; /* NULs are replaced by newlines! */
2143 else if (c == NL)
2144 *ptr = CAR; /* NLs are replaced by CRs! */
2145 else
2146 {
2147 if (skip_count == 0)
2148 {
2149 *ptr = NUL; /* end of line */
2150 len = (colnr_T) (ptr - line_start + 1);
2151 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2152 {
2153 error = TRUE;
2154 break;
2155 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002156#ifdef FEAT_PERSISTENT_UNDO
2157 if (read_undo_file)
2158 sha256_update(&sha_ctx, line_start, len);
2159#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 ++lnum;
2161 if (--read_count == 0)
2162 {
2163 error = TRUE; /* break loop */
2164 line_start = ptr; /* nothing left to write */
2165 break;
2166 }
2167 }
2168 else
2169 --skip_count;
2170 line_start = ptr + 1;
2171 }
2172 }
2173 }
2174 else
2175 {
2176 --ptr;
2177 while (++ptr, --size >= 0)
2178 {
2179 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2180 continue;
2181 if (c == NUL)
2182 *ptr = NL; /* NULs are replaced by newlines! */
2183 else
2184 {
2185 if (skip_count == 0)
2186 {
2187 *ptr = NUL; /* end of line */
2188 len = (colnr_T)(ptr - line_start + 1);
2189 if (fileformat == EOL_DOS)
2190 {
2191 if (ptr[-1] == CAR) /* remove CR */
2192 {
2193 ptr[-1] = NUL;
2194 --len;
2195 }
2196 /*
2197 * Reading in Dos format, but no CR-LF found!
2198 * When 'fileformats' includes "unix", delete all
2199 * the lines read so far and start all over again.
2200 * Otherwise give an error message later.
2201 */
2202 else if (ff_error != EOL_DOS)
2203 {
2204 if ( try_unix
2205 && !read_stdin
2206 && (read_buffer
2207 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2208 {
2209 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002210 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 set_fileformat(EOL_UNIX, OPT_LOCAL);
2212 file_rewind = TRUE;
2213 keep_fileformat = TRUE;
2214 goto retry;
2215 }
2216 ff_error = EOL_DOS;
2217 }
2218 }
2219 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2220 {
2221 error = TRUE;
2222 break;
2223 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002224#ifdef FEAT_PERSISTENT_UNDO
2225 if (read_undo_file)
2226 sha256_update(&sha_ctx, line_start, len);
2227#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 ++lnum;
2229 if (--read_count == 0)
2230 {
2231 error = TRUE; /* break loop */
2232 line_start = ptr; /* nothing left to write */
2233 break;
2234 }
2235 }
2236 else
2237 --skip_count;
2238 line_start = ptr + 1;
2239 }
2240 }
2241 }
2242 linerest = (long)(ptr - line_start);
2243 ui_breakcheck();
2244 }
2245
2246failed:
2247 /* not an error, max. number of lines reached */
2248 if (error && read_count == 0)
2249 error = FALSE;
2250
2251 /*
2252 * If we get EOF in the middle of a line, note the fact and
2253 * complete the line ourselves.
2254 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2255 */
2256 if (!error
2257 && !got_int
2258 && linerest != 0
2259 && !(!curbuf->b_p_bin
2260 && fileformat == EOL_DOS
2261 && *line_start == Ctrl_Z
2262 && ptr == line_start + 1))
2263 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002264 /* remember for when writing */
2265 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 curbuf->b_p_eol = FALSE;
2267 *ptr = NUL;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002268 len = (colnr_T)(ptr - line_start + 1);
2269 if (ml_append(lnum, line_start, len, newfile) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 error = TRUE;
2271 else
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002272 {
2273#ifdef FEAT_PERSISTENT_UNDO
2274 if (read_undo_file)
2275 sha256_update(&sha_ctx, line_start, len);
2276#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277 read_no_eol_lnum = ++lnum;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 }
2280
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002281 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 save_file_ff(curbuf); /* remember the current file format */
2283
2284#ifdef FEAT_CRYPT
Bram Moolenaar4cf35c22011-02-25 16:52:17 +01002285 crypt_method_used = use_crypt_method;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002286 if (cryptkey != NULL)
2287 {
2288 crypt_pop_state();
2289 if (cryptkey != curbuf->b_p_key)
2290 free_crypt_key(cryptkey);
2291 /* don't set cryptkey to NULL, it's used below as a flag that
2292 * encryption was used */
2293 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294#endif
2295
2296#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002297 /* If editing a new file: set 'fenc' for the current buffer.
2298 * Also for ":read ++edit file". */
2299 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002301 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302 if (fenc_alloced)
2303 vim_free(fenc);
2304# ifdef USE_ICONV
2305 if (iconv_fd != (iconv_t)-1)
2306 {
2307 iconv_close(iconv_fd);
2308 iconv_fd = (iconv_t)-1;
2309 }
2310# endif
2311#endif
2312
2313 if (!read_buffer && !read_stdin)
2314 close(fd); /* errors are ignored */
Bram Moolenaarf05da212009-11-17 16:13:15 +00002315#ifdef HAVE_FD_CLOEXEC
2316 else
2317 {
2318 int fdflags = fcntl(fd, F_GETFD);
2319 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2320 fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
2321 }
2322#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 vim_free(buffer);
2324
2325#ifdef HAVE_DUP
2326 if (read_stdin)
2327 {
2328 /* Use stderr for stdin, makes shell commands work. */
2329 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002330 ignored = dup(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 }
2332#endif
2333
2334#ifdef FEAT_MBYTE
2335 if (tmpname != NULL)
2336 {
2337 mch_remove(tmpname); /* delete converted file */
2338 vim_free(tmpname);
2339 }
2340#endif
2341 --no_wait_return; /* may wait for return now */
2342
2343 /*
2344 * In recovery mode everything but autocommands is skipped.
2345 */
2346 if (!recoverymode)
2347 {
2348 /* need to delete the last line, which comes from the empty buffer */
2349 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2350 {
2351#ifdef FEAT_NETBEANS_INTG
2352 netbeansFireChanges = 0;
2353#endif
2354 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2355#ifdef FEAT_NETBEANS_INTG
2356 netbeansFireChanges = 1;
2357#endif
2358 --linecnt;
2359 }
2360 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2361 if (filesize == 0)
2362 linecnt = 0;
2363 if (newfile || read_buffer)
Bram Moolenaar7263a772007-05-10 17:35:54 +00002364 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 redraw_curbuf_later(NOT_VALID);
Bram Moolenaar7263a772007-05-10 17:35:54 +00002366#ifdef FEAT_DIFF
2367 /* After reading the text into the buffer the diff info needs to
2368 * be updated. */
2369 diff_invalidate(curbuf);
2370#endif
2371#ifdef FEAT_FOLDING
2372 /* All folds in the window are invalid now. Mark them for update
2373 * before triggering autocommands. */
2374 foldUpdateAll(curwin);
2375#endif
2376 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 else if (linecnt) /* appended at least one line */
2378 appended_lines_mark(from, linecnt);
2379
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380#ifndef ALWAYS_USE_GUI
2381 /*
2382 * If we were reading from the same terminal as where messages go,
2383 * the screen will have been messed up.
2384 * Switch on raw mode now and clear the screen.
2385 */
2386 if (read_stdin)
2387 {
2388 settmode(TMODE_RAW); /* set to raw mode */
2389 starttermcap();
2390 screenclear();
2391 }
2392#endif
2393
2394 if (got_int)
2395 {
2396 if (!(flags & READ_DUMMY))
2397 {
2398 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2399 if (newfile)
2400 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2401 }
2402 msg_scroll = msg_save;
2403#ifdef FEAT_VIMINFO
2404 check_marks_read();
2405#endif
2406 return OK; /* an interrupt isn't really an error */
2407 }
2408
2409 if (!filtering && !(flags & READ_DUMMY))
2410 {
2411 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2412 c = FALSE;
2413
2414#ifdef UNIX
2415# ifdef S_ISFIFO
2416 if (S_ISFIFO(perm)) /* fifo or socket */
2417 {
2418 STRCAT(IObuff, _("[fifo/socket]"));
2419 c = TRUE;
2420 }
2421# else
2422# ifdef S_IFIFO
2423 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2424 {
2425 STRCAT(IObuff, _("[fifo]"));
2426 c = TRUE;
2427 }
2428# endif
2429# ifdef S_IFSOCK
2430 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2431 {
2432 STRCAT(IObuff, _("[socket]"));
2433 c = TRUE;
2434 }
2435# endif
2436# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002437# ifdef OPEN_CHR_FILES
2438 if (S_ISCHR(perm)) /* or character special */
2439 {
2440 STRCAT(IObuff, _("[character special]"));
2441 c = TRUE;
2442 }
2443# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444#endif
2445 if (curbuf->b_p_ro)
2446 {
2447 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2448 c = TRUE;
2449 }
2450 if (read_no_eol_lnum)
2451 {
2452 msg_add_eol();
2453 c = TRUE;
2454 }
2455 if (ff_error == EOL_DOS)
2456 {
2457 STRCAT(IObuff, _("[CR missing]"));
2458 c = TRUE;
2459 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 if (split)
2461 {
2462 STRCAT(IObuff, _("[long lines split]"));
2463 c = TRUE;
2464 }
2465#ifdef FEAT_MBYTE
2466 if (notconverted)
2467 {
2468 STRCAT(IObuff, _("[NOT converted]"));
2469 c = TRUE;
2470 }
2471 else if (converted)
2472 {
2473 STRCAT(IObuff, _("[converted]"));
2474 c = TRUE;
2475 }
2476#endif
2477#ifdef FEAT_CRYPT
2478 if (cryptkey != NULL)
2479 {
Bram Moolenaar4cf35c22011-02-25 16:52:17 +01002480 if (crypt_method_used == 1)
2481 STRCAT(IObuff, _("[blowfish]"));
2482 else
2483 STRCAT(IObuff, _("[crypted]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484 c = TRUE;
2485 }
2486#endif
2487#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002488 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002490 sprintf((char *)IObuff + STRLEN(IObuff),
2491 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 c = TRUE;
2493 }
2494 else if (illegal_byte > 0)
2495 {
2496 sprintf((char *)IObuff + STRLEN(IObuff),
2497 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2498 c = TRUE;
2499 }
2500 else
2501#endif
2502 if (error)
2503 {
2504 STRCAT(IObuff, _("[READ ERRORS]"));
2505 c = TRUE;
2506 }
2507 if (msg_add_fileformat(fileformat))
2508 c = TRUE;
2509#ifdef FEAT_CRYPT
2510 if (cryptkey != NULL)
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002511 msg_add_lines(c, (long)linecnt, filesize
Bram Moolenaar80794b12010-06-13 05:20:42 +02002512 - CRYPT_MAGIC_LEN
2513 - crypt_salt_len[use_crypt_method]
2514 - crypt_seed_len[use_crypt_method]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 else
2516#endif
2517 msg_add_lines(c, (long)linecnt, filesize);
2518
2519 vim_free(keep_msg);
2520 keep_msg = NULL;
2521 msg_scrolled_ign = TRUE;
2522#ifdef ALWAYS_USE_GUI
2523 /* Don't show the message when reading stdin, it would end up in a
2524 * message box (which might be shown when exiting!) */
2525 if (read_stdin || read_buffer)
2526 p = msg_may_trunc(FALSE, IObuff);
2527 else
2528#endif
2529 p = msg_trunc_attr(IObuff, FALSE, 0);
2530 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002531 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 /* Need to repeat the message after redrawing when:
2533 * - When reading from stdin (the screen will be cleared next).
2534 * - When restart_edit is set (otherwise there will be a delay
2535 * before redrawing).
2536 * - When the screen was scrolled but there is no wait-return
2537 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002538 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 msg_scrolled_ign = FALSE;
2540 }
2541
2542 /* with errors writing the file requires ":w!" */
2543 if (newfile && (error
2544#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002545 || conv_error != 0
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002546 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547#endif
2548 ))
2549 curbuf->b_p_ro = TRUE;
2550
2551 u_clearline(); /* cannot use "U" command after adding lines */
2552
2553 /*
2554 * In Ex mode: cursor at last new line.
2555 * Otherwise: cursor at first new line.
2556 */
2557 if (exmode_active)
2558 curwin->w_cursor.lnum = from + linecnt;
2559 else
2560 curwin->w_cursor.lnum = from + 1;
2561 check_cursor_lnum();
2562 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2563
2564 /*
2565 * Set '[ and '] marks to the newly read lines.
2566 */
2567 curbuf->b_op_start.lnum = from + 1;
2568 curbuf->b_op_start.col = 0;
2569 curbuf->b_op_end.lnum = from + linecnt;
2570 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002571
2572#ifdef WIN32
2573 /*
2574 * Work around a weird problem: When a file has two links (only
2575 * possible on NTFS) and we write through one link, then stat() it
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00002576 * through the other link, the timestamp information may be wrong.
Bram Moolenaar03f48552006-02-28 23:52:23 +00002577 * It's correct again after reading the file, thus reset the timestamp
2578 * here.
2579 */
2580 if (newfile && !read_stdin && !read_buffer
2581 && mch_stat((char *)fname, &st) >= 0)
2582 {
2583 buf_store_time(curbuf, &st, fname);
2584 curbuf->b_mtime_read = curbuf->b_mtime;
2585 }
2586#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 }
2588 msg_scroll = msg_save;
2589
2590#ifdef FEAT_VIMINFO
2591 /*
2592 * Get the marks before executing autocommands, so they can be used there.
2593 */
2594 check_marks_read();
2595#endif
2596
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 /*
2598 * Trick: We remember if the last line of the read didn't have
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002599 * an eol even when 'binary' is off, for when writing it again with
2600 * 'binary' on. This is required for
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2602 */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002603 curbuf->b_no_eol_lnum = read_no_eol_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02002605 /* When reloading a buffer put the cursor at the first line that is
2606 * different. */
2607 if (flags & READ_KEEP_UNDO)
2608 u_find_first_changed();
2609
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002610#ifdef FEAT_PERSISTENT_UNDO
2611 /*
2612 * When opening a new file locate undo info and read it.
2613 */
2614 if (read_undo_file)
2615 {
2616 char_u hash[UNDO_HASH_SIZE];
2617
2618 sha256_finish(&sha_ctx, hash);
Bram Moolenaar6ed8ed82010-05-30 20:40:11 +02002619 u_read_undo(NULL, hash, fname);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002620 }
2621#endif
2622
Bram Moolenaardf177f62005-02-22 08:39:57 +00002623#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 if (!read_stdin && !read_buffer)
2625 {
2626 int m = msg_scroll;
2627 int n = msg_scrolled;
2628
2629 /* Save the fileformat now, otherwise the buffer will be considered
2630 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002631 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 save_file_ff(curbuf);
2633
2634 /*
2635 * The output from the autocommands should not overwrite anything and
2636 * should not be overwritten: Set msg_scroll, restore its value if no
2637 * output was done.
2638 */
2639 msg_scroll = TRUE;
2640 if (filtering)
2641 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2642 FALSE, curbuf, eap);
2643 else if (newfile)
2644 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2645 FALSE, curbuf, eap);
2646 else
2647 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2648 FALSE, NULL, eap);
2649 if (msg_scrolled == n)
2650 msg_scroll = m;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002651# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 if (aborting()) /* autocmds may abort script processing */
2653 return FAIL;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002654# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 }
2656#endif
2657
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002658 /* Reset now, following writes should not omit the EOL. Also, the line
2659 * number will become invalid because of edits. */
2660 curbuf->b_no_eol_lnum = 0;
2661
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662 if (recoverymode && error)
2663 return FAIL;
2664 return OK;
2665}
2666
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002667#ifdef OPEN_CHR_FILES
2668/*
2669 * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
2670 * which is the name of files used for process substitution output by
2671 * some shells on some operating systems, e.g., bash on SunOS.
2672 * Do not accept "/dev/fd/[012]", opening these may hang Vim.
2673 */
2674 static int
2675is_dev_fd_file(fname)
2676 char_u *fname;
2677{
2678 return (STRNCMP(fname, "/dev/fd/", 8) == 0
2679 && VIM_ISDIGIT(fname[8])
2680 && *skipdigits(fname + 9) == NUL
2681 && (fname[9] != NUL
2682 || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
2683}
2684#endif
2685
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002686#ifdef FEAT_MBYTE
2687
2688/*
2689 * From the current line count and characters read after that, estimate the
2690 * line number where we are now.
2691 * Used for error messages that include a line number.
2692 */
2693 static linenr_T
2694readfile_linenr(linecnt, p, endp)
2695 linenr_T linecnt; /* line count before reading more bytes */
2696 char_u *p; /* start of more bytes read */
2697 char_u *endp; /* end of more bytes read */
2698{
2699 char_u *s;
2700 linenr_T lnum;
2701
2702 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2703 for (s = p; s < endp; ++s)
2704 if (*s == '\n')
2705 ++lnum;
2706 return lnum;
2707}
2708#endif
2709
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002711 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2712 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 * Returns OK or FAIL.
2714 */
2715 int
2716prep_exarg(eap, buf)
2717 exarg_T *eap;
2718 buf_T *buf;
2719{
2720 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2721#ifdef FEAT_MBYTE
2722 + STRLEN(buf->b_p_fenc)
2723#endif
2724 + 15));
2725 if (eap->cmd == NULL)
2726 return FAIL;
2727
2728#ifdef FEAT_MBYTE
2729 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2730 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002731 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732#else
2733 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2734#endif
2735 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002736
2737 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002738 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002739 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 return OK;
2741}
2742
2743#ifdef FEAT_MBYTE
2744/*
2745 * Find next fileencoding to use from 'fileencodings'.
2746 * "pp" points to fenc_next. It's advanced to the next item.
2747 * When there are no more items, an empty string is returned and *pp is set to
2748 * NULL.
2749 * When *pp is not set to NULL, the result is in allocated memory.
2750 */
2751 static char_u *
2752next_fenc(pp)
2753 char_u **pp;
2754{
2755 char_u *p;
2756 char_u *r;
2757
2758 if (**pp == NUL)
2759 {
2760 *pp = NULL;
2761 return (char_u *)"";
2762 }
2763 p = vim_strchr(*pp, ',');
2764 if (p == NULL)
2765 {
2766 r = enc_canonize(*pp);
2767 *pp += STRLEN(*pp);
2768 }
2769 else
2770 {
2771 r = vim_strnsave(*pp, (int)(p - *pp));
2772 *pp = p + 1;
2773 if (r != NULL)
2774 {
2775 p = enc_canonize(r);
2776 vim_free(r);
2777 r = p;
2778 }
2779 }
2780 if (r == NULL) /* out of memory */
2781 {
2782 r = (char_u *)"";
2783 *pp = NULL;
2784 }
2785 return r;
2786}
2787
2788# ifdef FEAT_EVAL
2789/*
2790 * Convert a file with the 'charconvert' expression.
2791 * This closes the file which is to be read, converts it and opens the
2792 * resulting file for reading.
2793 * Returns name of the resulting converted file (the caller should delete it
2794 * after reading it).
2795 * Returns NULL if the conversion failed ("*fdp" is not set) .
2796 */
2797 static char_u *
2798readfile_charconvert(fname, fenc, fdp)
2799 char_u *fname; /* name of input file */
2800 char_u *fenc; /* converted from */
2801 int *fdp; /* in/out: file descriptor of file */
2802{
2803 char_u *tmpname;
2804 char_u *errmsg = NULL;
2805
2806 tmpname = vim_tempname('r');
2807 if (tmpname == NULL)
2808 errmsg = (char_u *)_("Can't find temp file for conversion");
2809 else
2810 {
2811 close(*fdp); /* close the input file, ignore errors */
2812 *fdp = -1;
2813 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2814 fname, tmpname) == FAIL)
2815 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2816 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2817 O_RDONLY | O_EXTRA, 0)) < 0)
2818 errmsg = (char_u *)_("can't read output of 'charconvert'");
2819 }
2820
2821 if (errmsg != NULL)
2822 {
2823 /* Don't use emsg(), it breaks mappings, the retry with
2824 * another type of conversion might still work. */
2825 MSG(errmsg);
2826 if (tmpname != NULL)
2827 {
2828 mch_remove(tmpname); /* delete converted file */
2829 vim_free(tmpname);
2830 tmpname = NULL;
2831 }
2832 }
2833
2834 /* If the input file is closed, open it (caller should check for error). */
2835 if (*fdp < 0)
2836 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2837
2838 return tmpname;
2839}
2840# endif
2841
2842#endif
2843
2844#ifdef FEAT_VIMINFO
2845/*
2846 * Read marks for the current buffer from the viminfo file, when we support
2847 * buffer marks and the buffer has a name.
2848 */
2849 static void
2850check_marks_read()
2851{
2852 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2853 && curbuf->b_ffname != NULL)
Bram Moolenaard812df62008-11-09 12:46:09 +00002854 read_viminfo(NULL, VIF_WANT_MARKS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855
2856 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2857 * the ' parameter after opening a buffer. */
2858 curbuf->b_marks_read = TRUE;
2859}
2860#endif
2861
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002862#if defined(FEAT_CRYPT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863/*
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002864 * Get the crypt method used for a file from "ptr[len]", the magic text at the
2865 * start of the file.
2866 * Returns -1 when no encryption used.
2867 */
2868 static int
Bram Moolenaar49771f42010-07-20 17:32:38 +02002869crypt_method_from_magic(ptr, len)
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002870 char *ptr;
2871 int len;
2872{
2873 int i;
2874
2875 for (i = 0; i < (int)(sizeof(crypt_magic) / sizeof(crypt_magic[0])); i++)
2876 {
Bram Moolenaar80794b12010-06-13 05:20:42 +02002877 if (len < (CRYPT_MAGIC_LEN + crypt_salt_len[i] + crypt_seed_len[i]))
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002878 continue;
2879 if (memcmp(ptr, crypt_magic[i], CRYPT_MAGIC_LEN) == 0)
2880 return i;
2881 }
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002882
Bram Moolenaar442b4222010-05-24 21:34:22 +02002883 i = (int)STRLEN(crypt_magic_head);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002884 if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
2885 EMSG(_("E821: File is encrypted with unknown method"));
2886
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002887 return -1;
2888}
2889
2890/*
2891 * Check for magic number used for encryption. Applies to the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2893 * *filesizep are updated.
2894 * Return the (new) encryption key, NULL for no encryption.
2895 */
2896 static char_u *
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002897check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898 char_u *cryptkey; /* previous encryption key or NULL */
2899 char_u *ptr; /* pointer to read bytes */
2900 long *sizep; /* length of read bytes */
Bram Moolenaar914703b2010-05-31 21:59:46 +02002901 off_t *filesizep; /* nr of bytes used from file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 int newfile; /* editing a new buffer */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002903 char_u *fname; /* file name to display */
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002904 int *did_ask; /* flag: whether already asked for key */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905{
Bram Moolenaar49771f42010-07-20 17:32:38 +02002906 int method = crypt_method_from_magic((char *)ptr, *sizep);
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002907
2908 if (method >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909 {
Bram Moolenaar49771f42010-07-20 17:32:38 +02002910 set_crypt_method(curbuf, method);
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002911 if (method > 0)
2912 (void)blowfish_self_test();
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002913 if (cryptkey == NULL && !*did_ask)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914 {
2915 if (*curbuf->b_p_key)
2916 cryptkey = curbuf->b_p_key;
2917 else
2918 {
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002919 /* When newfile is TRUE, store the typed key in the 'key'
2920 * option and don't free it. bf needs hash of the key saved.
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002921 * Don't ask for the key again when first time Enter was hit.
2922 * Happens when retrying to detect encoding. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002923 smsg((char_u *)_(need_key_msg), fname);
2924 msg_scroll = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 cryptkey = get_crypt_key(newfile, FALSE);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002926 *did_ask = TRUE;
2927
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 /* check if empty key entered */
2929 if (cryptkey != NULL && *cryptkey == NUL)
2930 {
2931 if (cryptkey != curbuf->b_p_key)
2932 vim_free(cryptkey);
2933 cryptkey = NULL;
2934 }
2935 }
2936 }
2937
2938 if (cryptkey != NULL)
2939 {
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002940 int seed_len = crypt_seed_len[method];
Bram Moolenaar80794b12010-06-13 05:20:42 +02002941 int salt_len = crypt_salt_len[method];
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002942
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002943 crypt_push_state();
2944 use_crypt_method = method;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002945 if (method == 0)
2946 crypt_init_keys(cryptkey);
2947 else
2948 {
Bram Moolenaar80794b12010-06-13 05:20:42 +02002949 bf_key_init(cryptkey, ptr + CRYPT_MAGIC_LEN, salt_len);
2950 bf_ofb_init(ptr + CRYPT_MAGIC_LEN + salt_len, seed_len);
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002951 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952
2953 /* Remove magic number from the text */
Bram Moolenaar80794b12010-06-13 05:20:42 +02002954 *filesizep += CRYPT_MAGIC_LEN + salt_len + seed_len;
2955 *sizep -= CRYPT_MAGIC_LEN + salt_len + seed_len;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002956 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len,
2957 (size_t)*sizep);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 }
2959 }
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002960 /* When starting to edit a new file which does not have encryption, clear
2961 * the 'key' option, except when starting up (called with -x argument) */
Bram Moolenaarfa0ff9a2010-07-25 16:05:19 +02002962 else if (newfile && *curbuf->b_p_key != NUL && !starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2964
2965 return cryptkey;
2966}
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002967
2968/*
2969 * Check for magic number used for encryption. Applies to the current buffer.
2970 * If found and decryption is possible returns OK;
2971 */
2972 int
2973prepare_crypt_read(fp)
2974 FILE *fp;
2975{
2976 int method;
Bram Moolenaar80794b12010-06-13 05:20:42 +02002977 char_u buffer[CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
2978 + CRYPT_SEED_LEN_MAX + 2];
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002979
2980 if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
2981 return FAIL;
Bram Moolenaar49771f42010-07-20 17:32:38 +02002982 method = crypt_method_from_magic((char *)buffer,
Bram Moolenaar80794b12010-06-13 05:20:42 +02002983 CRYPT_MAGIC_LEN +
Bram Moolenaarcc448b32010-07-14 16:52:17 +02002984 CRYPT_SEED_LEN_MAX +
2985 CRYPT_SALT_LEN_MAX);
Bram Moolenaar49771f42010-07-20 17:32:38 +02002986 if (method < 0 || method != get_crypt_method(curbuf))
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002987 return FAIL;
2988
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002989 crypt_push_state();
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002990 if (method == 0)
2991 crypt_init_keys(curbuf->b_p_key);
2992 else
2993 {
Bram Moolenaar80794b12010-06-13 05:20:42 +02002994 int salt_len = crypt_salt_len[method];
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002995 int seed_len = crypt_seed_len[method];
2996
Bram Moolenaar80794b12010-06-13 05:20:42 +02002997 if (fread(buffer, salt_len + seed_len, 1, fp) != 1)
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002998 return FAIL;
Bram Moolenaar80794b12010-06-13 05:20:42 +02002999 bf_key_init(curbuf->b_p_key, buffer, salt_len);
3000 bf_ofb_init(buffer + salt_len, seed_len);
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003001 }
3002 return OK;
3003}
3004
3005/*
3006 * Prepare for writing encrypted bytes for buffer "buf".
3007 * Returns a pointer to an allocated header of length "*lenp".
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003008 * When out of memory returns NULL.
3009 * Otherwise calls crypt_push_state(), call crypt_pop_state() later.
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003010 */
3011 char_u *
3012prepare_crypt_write(buf, lenp)
3013 buf_T *buf;
3014 int *lenp;
3015{
3016 char_u *header;
Bram Moolenaar49771f42010-07-20 17:32:38 +02003017 int seed_len = crypt_seed_len[get_crypt_method(buf)];
3018 int salt_len = crypt_salt_len[get_crypt_method(buf)];
Bram Moolenaar80794b12010-06-13 05:20:42 +02003019 char_u *salt;
3020 char_u *seed;
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003021
Bram Moolenaar80794b12010-06-13 05:20:42 +02003022 header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
3023 + CRYPT_SEED_LEN_MAX + 2);
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003024 if (header != NULL)
3025 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003026 crypt_push_state();
Bram Moolenaar49771f42010-07-20 17:32:38 +02003027 use_crypt_method = get_crypt_method(buf); /* select zip or blowfish */
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003028 vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
3029 CRYPT_MAGIC_LEN);
Bram Moolenaar49771f42010-07-20 17:32:38 +02003030 if (use_crypt_method == 0)
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003031 crypt_init_keys(buf->b_p_key);
3032 else
3033 {
Bram Moolenaar80794b12010-06-13 05:20:42 +02003034 /* Using blowfish, add salt and seed. */
3035 salt = header + CRYPT_MAGIC_LEN;
3036 seed = salt + salt_len;
3037 sha2_seed(salt, salt_len, seed, seed_len);
3038 bf_key_init(buf->b_p_key, salt, salt_len);
3039 bf_ofb_init(seed, seed_len);
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003040 }
3041 }
Bram Moolenaar80794b12010-06-13 05:20:42 +02003042 *lenp = CRYPT_MAGIC_LEN + salt_len + seed_len;
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02003043 return header;
3044}
3045
Bram Moolenaar80794b12010-06-13 05:20:42 +02003046#endif /* FEAT_CRYPT */
3047
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048#ifdef UNIX
3049 static void
3050set_file_time(fname, atime, mtime)
3051 char_u *fname;
3052 time_t atime; /* access time */
3053 time_t mtime; /* modification time */
3054{
3055# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
3056 struct utimbuf buf;
3057
3058 buf.actime = atime;
3059 buf.modtime = mtime;
3060 (void)utime((char *)fname, &buf);
3061# else
3062# if defined(HAVE_UTIMES)
3063 struct timeval tvp[2];
3064
3065 tvp[0].tv_sec = atime;
3066 tvp[0].tv_usec = 0;
3067 tvp[1].tv_sec = mtime;
3068 tvp[1].tv_usec = 0;
3069# ifdef NeXT
3070 (void)utimes((char *)fname, tvp);
3071# else
3072 (void)utimes((char *)fname, (const struct timeval *)&tvp);
3073# endif
3074# endif
3075# endif
3076}
3077#endif /* UNIX */
3078
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003079#if defined(VMS) && !defined(MIN)
3080/* Older DECC compiler for VAX doesn't define MIN() */
3081# define MIN(a, b) ((a) < (b) ? (a) : (b))
3082#endif
3083
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00003085 * Return TRUE if a file appears to be read-only from the file permissions.
3086 */
3087 int
3088check_file_readonly(fname, perm)
3089 char_u *fname; /* full path to file */
3090 int perm; /* known permissions on file */
3091{
3092#ifndef USE_MCH_ACCESS
3093 int fd = 0;
3094#endif
3095
3096 return (
3097#ifdef USE_MCH_ACCESS
3098# ifdef UNIX
3099 (perm & 0222) == 0 ||
3100# endif
3101 mch_access((char *)fname, W_OK)
3102#else
3103 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
3104 ? TRUE : (close(fd), FALSE)
3105#endif
3106 );
3107}
3108
3109
3110/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00003111 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112 *
3113 * We do our own buffering here because fwrite() is so slow.
3114 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00003115 * If "forceit" is true, we don't care for errors when attempting backups.
3116 * In case of an error everything possible is done to restore the original
Bram Moolenaare37d50a2008-08-06 17:06:04 +00003117 * file. But when "forceit" is TRUE, we risk losing it.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003118 *
3119 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
3120 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121 *
3122 * This function must NOT use NameBuff (because it's called by autowrite()).
3123 *
3124 * return FAIL for failure, OK otherwise
3125 */
3126 int
3127buf_write(buf, fname, sfname, start, end, eap, append, forceit,
3128 reset_changed, filtering)
3129 buf_T *buf;
3130 char_u *fname;
3131 char_u *sfname;
3132 linenr_T start, end;
3133 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
3134 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00003135 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 int forceit;
3137 int reset_changed;
3138 int filtering;
3139{
3140 int fd;
3141 char_u *backup = NULL;
3142 int backup_copy = FALSE; /* copy the original file? */
3143 int dobackup;
3144 char_u *ffname;
3145 char_u *wfname = NULL; /* name of file to write to */
3146 char_u *s;
3147 char_u *ptr;
3148 char_u c;
3149 int len;
3150 linenr_T lnum;
3151 long nchars;
3152 char_u *errmsg = NULL;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003153 int errmsg_allocated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154 char_u *errnum = NULL;
3155 char_u *buffer;
3156 char_u smallbuf[SMBUFSIZE];
3157 char_u *backup_ext;
3158 int bufsize;
3159 long perm; /* file permissions */
3160 int retval = OK;
3161 int newfile = FALSE; /* TRUE if file doesn't exist yet */
3162 int msg_save = msg_scroll;
3163 int overwriting; /* TRUE if writing over original */
3164 int no_eol = FALSE; /* no end-of-line written */
3165 int device = FALSE; /* writing to a device */
3166 struct stat st_old;
3167 int prev_got_int = got_int;
3168 int file_readonly = FALSE; /* overwritten file is read-only */
3169 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
3170#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
3171 int made_writable = FALSE; /* 'w' bit has been set */
3172#endif
3173 /* writing everything */
3174 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
3175#ifdef FEAT_AUTOCMD
3176 linenr_T old_line_count = buf->b_ml.ml_line_count;
3177#endif
3178 int attr;
3179 int fileformat;
3180 int write_bin;
3181 struct bw_info write_info; /* info for buf_write_bytes() */
3182#ifdef FEAT_MBYTE
3183 int converted = FALSE;
3184 int notconverted = FALSE;
3185 char_u *fenc; /* effective 'fileencoding' */
3186 char_u *fenc_tofree = NULL; /* allocated "fenc" */
3187#endif
3188#ifdef HAS_BW_FLAGS
3189 int wb_flags = 0;
3190#endif
3191#ifdef HAVE_ACL
3192 vim_acl_T acl = NULL; /* ACL copied from original file to
3193 backup or new file */
3194#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003195#ifdef FEAT_PERSISTENT_UNDO
3196 int write_undo_file = FALSE;
3197 context_sha256_T sha_ctx;
3198#endif
Bram Moolenaar4cf35c22011-02-25 16:52:17 +01003199#ifdef FEAT_CRYPT
3200 int crypt_method_used;
3201#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202
3203 if (fname == NULL || *fname == NUL) /* safety check */
3204 return FAIL;
Bram Moolenaar70d60e92009-12-31 13:53:33 +00003205 if (buf->b_ml.ml_mfp == NULL)
3206 {
3207 /* This can happen during startup when there is a stray "w" in the
3208 * vimrc file. */
3209 EMSG(_(e_emptybuf));
3210 return FAIL;
3211 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212
3213 /*
3214 * Disallow writing from .exrc and .vimrc in current directory for
3215 * security reasons.
3216 */
3217 if (check_secure())
3218 return FAIL;
3219
3220 /* Avoid a crash for a long name. */
3221 if (STRLEN(fname) >= MAXPATHL)
3222 {
3223 EMSG(_(e_longname));
3224 return FAIL;
3225 }
3226
3227#ifdef FEAT_MBYTE
3228 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
3229 write_info.bw_conv_buf = NULL;
3230 write_info.bw_conv_error = FALSE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003231 write_info.bw_conv_error_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 write_info.bw_restlen = 0;
3233# ifdef USE_ICONV
3234 write_info.bw_iconv_fd = (iconv_t)-1;
3235# endif
3236#endif
3237
Bram Moolenaardf177f62005-02-22 08:39:57 +00003238 /* After writing a file changedtick changes but we don't want to display
3239 * the line. */
3240 ex_no_reprint = TRUE;
3241
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 /*
3243 * If there is no file name yet, use the one for the written file.
3244 * BF_NOTEDITED is set to reflect this (in case the write fails).
3245 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003246 * Don't do this when appending.
3247 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003249 if (buf->b_ffname == NULL
3250 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251 && whole
3252 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003253#ifdef FEAT_QUICKFIX
3254 && !bt_nofile(buf)
3255#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00003257 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
3259 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003260 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003262 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 }
3264
3265 if (sfname == NULL)
3266 sfname = fname;
3267 /*
3268 * For Unix: Use the short file name whenever possible.
3269 * Avoids problems with networks and when directory names are changed.
3270 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
3271 * another directory, which we don't detect
3272 */
3273 ffname = fname; /* remember full fname */
3274#ifdef UNIX
3275 fname = sfname;
3276#endif
3277
3278 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
3279 overwriting = TRUE;
3280 else
3281 overwriting = FALSE;
3282
3283 if (exiting)
3284 settmode(TMODE_COOK); /* when exiting allow typahead now */
3285
3286 ++no_wait_return; /* don't wait for return yet */
3287
3288 /*
3289 * Set '[ and '] marks to the lines to be written.
3290 */
3291 buf->b_op_start.lnum = start;
3292 buf->b_op_start.col = 0;
3293 buf->b_op_end.lnum = end;
3294 buf->b_op_end.col = 0;
3295
3296#ifdef FEAT_AUTOCMD
3297 {
3298 aco_save_T aco;
3299 int buf_ffname = FALSE;
3300 int buf_sfname = FALSE;
3301 int buf_fname_f = FALSE;
3302 int buf_fname_s = FALSE;
3303 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003304 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003305 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306
3307 /*
3308 * Apply PRE aucocommands.
3309 * Set curbuf to the buffer to be written.
3310 * Careful: The autocommands may call buf_write() recursively!
3311 */
3312 if (ffname == buf->b_ffname)
3313 buf_ffname = TRUE;
3314 if (sfname == buf->b_sfname)
3315 buf_sfname = TRUE;
3316 if (fname == buf->b_ffname)
3317 buf_fname_f = TRUE;
3318 if (fname == buf->b_sfname)
3319 buf_fname_s = TRUE;
3320
3321 /* set curwin/curbuf to buf and save a few things */
3322 aucmd_prepbuf(&aco, buf);
3323
3324 if (append)
3325 {
3326 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
3327 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003328 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003329#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00003330 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003331 nofile_err = TRUE;
3332 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003333#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003334 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003336 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 }
3338 else if (filtering)
3339 {
3340 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
3341 NULL, sfname, FALSE, curbuf, eap);
3342 }
3343 else if (reset_changed && whole)
3344 {
3345 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
3346 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003347 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003348#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003349 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003350 nofile_err = TRUE;
3351 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003352#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003353 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003355 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 }
3357 else
3358 {
3359 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
3360 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003361 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003362#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003363 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003364 nofile_err = TRUE;
3365 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003366#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003367 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 }
3371
3372 /* restore curwin/curbuf and a few other things */
3373 aucmd_restbuf(&aco);
3374
3375 /*
3376 * In three situations we return here and don't write the file:
3377 * 1. the autocommands deleted or unloaded the buffer.
3378 * 2. The autocommands abort script processing.
3379 * 3. If one of the "Cmd" autocommands was executed.
3380 */
3381 if (!buf_valid(buf))
3382 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003383 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00003384 || did_cmd || nofile_err
3385#ifdef FEAT_EVAL
3386 || aborting()
3387#endif
3388 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389 {
3390 --no_wait_return;
3391 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003392 if (nofile_err)
3393 EMSG(_("E676: No matching autocommands for acwrite buffer"));
3394
Bram Moolenaar1e015462005-09-25 22:16:38 +00003395 if (nofile_err
3396#ifdef FEAT_EVAL
3397 || aborting()
3398#endif
3399 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 /* An aborting error, interrupt or exception in the
3401 * autocommands. */
3402 return FAIL;
3403 if (did_cmd)
3404 {
3405 if (buf == NULL)
3406 /* The buffer was deleted. We assume it was written
3407 * (can't retry anyway). */
3408 return OK;
3409 if (overwriting)
3410 {
3411 /* Assume the buffer was written, update the timestamp. */
3412 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003413 if (append)
3414 buf->b_flags &= ~BF_NEW;
3415 else
3416 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003418 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003419 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 /* Buffer still changed, the autocommands didn't work
3421 * properly. */
3422 return FAIL;
3423 return OK;
3424 }
3425#ifdef FEAT_EVAL
3426 if (!aborting())
3427#endif
3428 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
3429 return FAIL;
3430 }
3431
3432 /*
3433 * The autocommands may have changed the number of lines in the file.
3434 * When writing the whole file, adjust the end.
3435 * When writing part of the file, assume that the autocommands only
3436 * changed the number of lines that are to be written (tricky!).
3437 */
3438 if (buf->b_ml.ml_line_count != old_line_count)
3439 {
3440 if (whole) /* write all */
3441 end = buf->b_ml.ml_line_count;
3442 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3443 end += buf->b_ml.ml_line_count - old_line_count;
3444 else /* less lines */
3445 {
3446 end -= old_line_count - buf->b_ml.ml_line_count;
3447 if (end < start)
3448 {
3449 --no_wait_return;
3450 msg_scroll = msg_save;
3451 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3452 return FAIL;
3453 }
3454 }
3455 }
3456
3457 /*
3458 * The autocommands may have changed the name of the buffer, which may
3459 * be kept in fname, ffname and sfname.
3460 */
3461 if (buf_ffname)
3462 ffname = buf->b_ffname;
3463 if (buf_sfname)
3464 sfname = buf->b_sfname;
3465 if (buf_fname_f)
3466 fname = buf->b_ffname;
3467 if (buf_fname_s)
3468 fname = buf->b_sfname;
3469 }
3470#endif
3471
3472#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003473 if (netbeans_active() && isNetbeansBuffer(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 {
3475 if (whole)
3476 {
3477 /*
3478 * b_changed can be 0 after an undo, but we still need to write
3479 * the buffer to NetBeans.
3480 */
3481 if (buf->b_changed || isNetbeansModified(buf))
3482 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003483 --no_wait_return; /* may wait for return now */
3484 msg_scroll = msg_save;
3485 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486 return retval;
3487 }
3488 else
3489 {
3490 errnum = (char_u *)"E656: ";
Bram Moolenaared0e7452008-06-27 19:17:34 +00003491 errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 buffer = NULL;
3493 goto fail;
3494 }
3495 }
3496 else
3497 {
3498 errnum = (char_u *)"E657: ";
3499 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3500 buffer = NULL;
3501 goto fail;
3502 }
3503 }
3504#endif
3505
3506 if (shortmess(SHM_OVER) && !exiting)
3507 msg_scroll = FALSE; /* overwrite previous file message */
3508 else
3509 msg_scroll = TRUE; /* don't overwrite previous file message */
3510 if (!filtering)
3511 filemess(buf,
3512#ifndef UNIX
3513 sfname,
3514#else
3515 fname,
3516#endif
3517 (char_u *)"", 0); /* show that we are busy */
3518 msg_scroll = FALSE; /* always overwrite the file message now */
3519
3520 buffer = alloc(BUFSIZE);
3521 if (buffer == NULL) /* can't allocate big buffer, use small
3522 * one (to be able to write when out of
3523 * memory) */
3524 {
3525 buffer = smallbuf;
3526 bufsize = SMBUFSIZE;
3527 }
3528 else
3529 bufsize = BUFSIZE;
3530
3531 /*
3532 * Get information about original file (if there is one).
3533 */
3534#if defined(UNIX) && !defined(ARCHIE)
Bram Moolenaar6f192452007-11-08 19:49:02 +00003535 st_old.st_dev = 0;
3536 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 perm = -1;
3538 if (mch_stat((char *)fname, &st_old) < 0)
3539 newfile = TRUE;
3540 else
3541 {
3542 perm = st_old.st_mode;
3543 if (!S_ISREG(st_old.st_mode)) /* not a file */
3544 {
3545 if (S_ISDIR(st_old.st_mode))
3546 {
3547 errnum = (char_u *)"E502: ";
3548 errmsg = (char_u *)_("is a directory");
3549 goto fail;
3550 }
3551 if (mch_nodetype(fname) != NODE_WRITABLE)
3552 {
3553 errnum = (char_u *)"E503: ";
3554 errmsg = (char_u *)_("is not a file or writable device");
3555 goto fail;
3556 }
3557 /* It's a device of some kind (or a fifo) which we can write to
3558 * but for which we can't make a backup. */
3559 device = TRUE;
3560 newfile = TRUE;
3561 perm = -1;
3562 }
3563 }
3564#else /* !UNIX */
3565 /*
3566 * Check for a writable device name.
3567 */
3568 c = mch_nodetype(fname);
3569 if (c == NODE_OTHER)
3570 {
3571 errnum = (char_u *)"E503: ";
3572 errmsg = (char_u *)_("is not a file or writable device");
3573 goto fail;
3574 }
3575 if (c == NODE_WRITABLE)
3576 {
Bram Moolenaar043545e2006-10-10 16:44:07 +00003577# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
3578 /* MS-Windows allows opening a device, but we will probably get stuck
3579 * trying to write to it. */
3580 if (!p_odev)
3581 {
3582 errnum = (char_u *)"E796: ";
3583 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
3584 goto fail;
3585 }
3586# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 device = TRUE;
3588 newfile = TRUE;
3589 perm = -1;
3590 }
3591 else
3592 {
3593 perm = mch_getperm(fname);
3594 if (perm < 0)
3595 newfile = TRUE;
3596 else if (mch_isdir(fname))
3597 {
3598 errnum = (char_u *)"E502: ";
3599 errmsg = (char_u *)_("is a directory");
3600 goto fail;
3601 }
3602 if (overwriting)
3603 (void)mch_stat((char *)fname, &st_old);
3604 }
3605#endif /* !UNIX */
3606
3607 if (!device && !newfile)
3608 {
3609 /*
3610 * Check if the file is really writable (when renaming the file to
3611 * make a backup we won't discover it later).
3612 */
Bram Moolenaar5386a122007-06-28 20:02:32 +00003613 file_readonly = check_file_readonly(fname, (int)perm);
3614
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 if (!forceit && file_readonly)
3616 {
3617 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3618 {
3619 errnum = (char_u *)"E504: ";
3620 errmsg = (char_u *)_(err_readonly);
3621 }
3622 else
3623 {
3624 errnum = (char_u *)"E505: ";
3625 errmsg = (char_u *)_("is read-only (add ! to override)");
3626 }
3627 goto fail;
3628 }
3629
3630 /*
3631 * Check if the timestamp hasn't changed since reading the file.
3632 */
3633 if (overwriting)
3634 {
3635 retval = check_mtime(buf, &st_old);
3636 if (retval == FAIL)
3637 goto fail;
3638 }
3639 }
3640
3641#ifdef HAVE_ACL
3642 /*
3643 * For systems that support ACL: get the ACL from the original file.
3644 */
3645 if (!newfile)
3646 acl = mch_get_acl(fname);
3647#endif
3648
3649 /*
3650 * If 'backupskip' is not empty, don't make a backup for some files.
3651 */
3652 dobackup = (p_wb || p_bk || *p_pm != NUL);
3653#ifdef FEAT_WILDIGN
3654 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3655 dobackup = FALSE;
3656#endif
3657
3658 /*
3659 * Save the value of got_int and reset it. We don't want a previous
3660 * interruption cancel writing, only hitting CTRL-C while writing should
3661 * abort it.
3662 */
3663 prev_got_int = got_int;
3664 got_int = FALSE;
3665
3666 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3667 buf->b_saving = TRUE;
3668
3669 /*
3670 * If we are not appending or filtering, the file exists, and the
3671 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3672 * When 'patchmode' is set also make a backup when appending.
3673 *
3674 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3675 * off. This helps when editing large files on almost-full disks.
3676 */
3677 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3678 {
3679#if defined(UNIX) || defined(WIN32)
3680 struct stat st;
3681#endif
3682
3683 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3684 backup_copy = TRUE;
3685#if defined(UNIX) || defined(WIN32)
3686 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3687 {
3688 int i;
3689
3690# ifdef UNIX
3691 /*
3692 * Don't rename the file when:
3693 * - it's a hard link
3694 * - it's a symbolic link
3695 * - we don't have write permission in the directory
3696 * - we can't set the owner/group of the new file
3697 */
3698 if (st_old.st_nlink > 1
3699 || mch_lstat((char *)fname, &st) < 0
3700 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003701 || st.st_ino != st_old.st_ino
3702# ifndef HAVE_FCHOWN
3703 || st.st_uid != st_old.st_uid
3704 || st.st_gid != st_old.st_gid
3705# endif
3706 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 backup_copy = TRUE;
3708 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003709# else
3710# ifdef WIN32
3711 /* On NTFS file systems hard links are possible. */
3712 if (mch_is_linked(fname))
3713 backup_copy = TRUE;
3714 else
3715# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716# endif
3717 {
3718 /*
3719 * Check if we can create a file and set the owner/group to
3720 * the ones from the original file.
3721 * First find a file name that doesn't exist yet (use some
3722 * arbitrary numbers).
3723 */
3724 STRCPY(IObuff, fname);
3725 for (i = 4913; ; i += 123)
3726 {
3727 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003728 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 break;
3730 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003731 fd = mch_open((char *)IObuff,
3732 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 if (fd < 0) /* can't write in directory */
3734 backup_copy = TRUE;
3735 else
3736 {
3737# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003738# ifdef HAVE_FCHOWN
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00003739 ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003740# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 if (mch_stat((char *)IObuff, &st) < 0
3742 || st.st_uid != st_old.st_uid
3743 || st.st_gid != st_old.st_gid
Bram Moolenaar78a15312009-05-15 19:33:18 +00003744 || (long)st.st_mode != perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 backup_copy = TRUE;
3746# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003747 /* Close the file before removing it, on MS-Windows we
3748 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003749 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003750 mch_remove(IObuff);
Bram Moolenaar3479c5d2010-08-08 18:46:06 +02003751# ifdef MSWIN
3752 /* MS-Windows may trigger a virus scanner to open the
3753 * file, we can't delete it then. Keep trying for half a
3754 * second. */
3755 {
3756 int try;
3757
3758 for (try = 0; try < 10; ++try)
3759 {
3760 if (mch_lstat((char *)IObuff, &st) < 0)
3761 break;
3762 ui_delay(50L, TRUE); /* wait 50 msec */
3763 mch_remove(IObuff);
3764 }
3765 }
3766# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767 }
3768 }
3769 }
3770
3771# ifdef UNIX
3772 /*
3773 * Break symlinks and/or hardlinks if we've been asked to.
3774 */
3775 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3776 {
3777 int lstat_res;
3778
3779 lstat_res = mch_lstat((char *)fname, &st);
3780
3781 /* Symlinks. */
3782 if ((bkc_flags & BKC_BREAKSYMLINK)
3783 && lstat_res == 0
3784 && st.st_ino != st_old.st_ino)
3785 backup_copy = FALSE;
3786
3787 /* Hardlinks. */
3788 if ((bkc_flags & BKC_BREAKHARDLINK)
3789 && st_old.st_nlink > 1
3790 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3791 backup_copy = FALSE;
3792 }
3793#endif
3794
3795#endif
3796
3797 /* make sure we have a valid backup extension to use */
3798 if (*p_bex == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 backup_ext = (char_u *)".bak";
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 else
3801 backup_ext = p_bex;
3802
3803 if (backup_copy
3804 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3805 {
3806 int bfd;
3807 char_u *copybuf, *wp;
3808 int some_error = FALSE;
3809 struct stat st_new;
3810 char_u *dirp;
3811 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003812#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 int did_set_shortname;
3814#endif
3815
3816 copybuf = alloc(BUFSIZE + 1);
3817 if (copybuf == NULL)
3818 {
3819 some_error = TRUE; /* out of memory */
3820 goto nobackup;
3821 }
3822
3823 /*
3824 * Try to make the backup in each directory in the 'bdir' option.
3825 *
3826 * Unix semantics has it, that we may have a writable file,
3827 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3828 * - the directory is not writable,
3829 * - the file may be a symbolic link,
3830 * - the file may belong to another user/group, etc.
3831 *
3832 * For these reasons, the existing writable file must be truncated
3833 * and reused. Creation of a backup COPY will be attempted.
3834 */
3835 dirp = p_bdir;
3836 while (*dirp)
3837 {
3838#ifdef UNIX
3839 st_new.st_ino = 0;
3840 st_new.st_dev = 0;
3841 st_new.st_gid = 0;
3842#endif
3843
3844 /*
3845 * Isolate one directory name, using an entry in 'bdir'.
3846 */
3847 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3848 rootname = get_file_in_dir(fname, copybuf);
3849 if (rootname == NULL)
3850 {
3851 some_error = TRUE; /* out of memory */
3852 goto nobackup;
3853 }
3854
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003855#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 did_set_shortname = FALSE;
3857#endif
3858
3859 /*
3860 * May try twice if 'shortname' not set.
3861 */
3862 for (;;)
3863 {
3864 /*
3865 * Make backup file name.
3866 */
3867 backup = buf_modname(
3868#ifdef SHORT_FNAME
3869 TRUE,
3870#else
3871 (buf->b_p_sn || buf->b_shortname),
3872#endif
3873 rootname, backup_ext, FALSE);
3874 if (backup == NULL)
3875 {
3876 vim_free(rootname);
3877 some_error = TRUE; /* out of memory */
3878 goto nobackup;
3879 }
3880
3881 /*
3882 * Check if backup file already exists.
3883 */
3884 if (mch_stat((char *)backup, &st_new) >= 0)
3885 {
3886#ifdef UNIX
3887 /*
3888 * Check if backup file is same as original file.
3889 * May happen when modname() gave the same file back.
3890 * E.g. silly link, or file name-length reached.
3891 * If we don't check here, we either ruin the file
3892 * when copying or erase it after writing. jw.
3893 */
3894 if (st_new.st_dev == st_old.st_dev
3895 && st_new.st_ino == st_old.st_ino)
3896 {
3897 vim_free(backup);
3898 backup = NULL; /* no backup file to delete */
3899# ifndef SHORT_FNAME
3900 /*
3901 * may try again with 'shortname' set
3902 */
3903 if (!(buf->b_shortname || buf->b_p_sn))
3904 {
3905 buf->b_shortname = TRUE;
3906 did_set_shortname = TRUE;
3907 continue;
3908 }
3909 /* setting shortname didn't help */
3910 if (did_set_shortname)
3911 buf->b_shortname = FALSE;
3912# endif
3913 break;
3914 }
3915#endif
3916
3917 /*
3918 * If we are not going to keep the backup file, don't
3919 * delete an existing one, try to use another name.
3920 * Change one character, just before the extension.
3921 */
3922 if (!p_bk)
3923 {
3924 wp = backup + STRLEN(backup) - 1
3925 - STRLEN(backup_ext);
3926 if (wp < backup) /* empty file name ??? */
3927 wp = backup;
3928 *wp = 'z';
3929 while (*wp > 'a'
3930 && mch_stat((char *)backup, &st_new) >= 0)
3931 --*wp;
3932 /* They all exist??? Must be something wrong. */
3933 if (*wp == 'a')
3934 {
3935 vim_free(backup);
3936 backup = NULL;
3937 }
3938 }
3939 }
3940 break;
3941 }
3942 vim_free(rootname);
3943
3944 /*
3945 * Try to create the backup file
3946 */
3947 if (backup != NULL)
3948 {
3949 /* remove old backup, if present */
3950 mch_remove(backup);
3951 /* Open with O_EXCL to avoid the file being created while
3952 * we were sleeping (symlink hacker attack?) */
3953 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003954 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3955 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003956 if (bfd < 0)
3957 {
3958 vim_free(backup);
3959 backup = NULL;
3960 }
3961 else
3962 {
3963 /* set file protection same as original file, but
3964 * strip s-bit */
3965 (void)mch_setperm(backup, perm & 0777);
3966
3967#ifdef UNIX
3968 /*
3969 * Try to set the group of the backup same as the
3970 * original file. If this fails, set the protection
3971 * bits for the group same as the protection bits for
3972 * others.
3973 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003974 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003976 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977# endif
3978 )
3979 mch_setperm(backup,
3980 (perm & 0707) | ((perm & 07) << 3));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003981# ifdef HAVE_SELINUX
3982 mch_copy_sec(fname, backup);
3983# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984#endif
3985
3986 /*
3987 * copy the file.
3988 */
3989 write_info.bw_fd = bfd;
3990 write_info.bw_buf = copybuf;
3991#ifdef HAS_BW_FLAGS
3992 write_info.bw_flags = FIO_NOCONVERT;
3993#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01003994 while ((write_info.bw_len = read_eintr(fd, copybuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 BUFSIZE)) > 0)
3996 {
3997 if (buf_write_bytes(&write_info) == FAIL)
3998 {
3999 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
4000 break;
4001 }
4002 ui_breakcheck();
4003 if (got_int)
4004 {
4005 errmsg = (char_u *)_(e_interr);
4006 break;
4007 }
4008 }
4009
4010 if (close(bfd) < 0 && errmsg == NULL)
4011 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
4012 if (write_info.bw_len < 0)
4013 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
4014#ifdef UNIX
4015 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
4016#endif
4017#ifdef HAVE_ACL
4018 mch_set_acl(backup, acl);
4019#endif
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004020#ifdef HAVE_SELINUX
4021 mch_copy_sec(fname, backup);
4022#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 break;
4024 }
4025 }
4026 }
4027 nobackup:
4028 close(fd); /* ignore errors for closing read file */
4029 vim_free(copybuf);
4030
4031 if (backup == NULL && errmsg == NULL)
4032 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
4033 /* ignore errors when forceit is TRUE */
4034 if ((some_error || errmsg != NULL) && !forceit)
4035 {
4036 retval = FAIL;
4037 goto fail;
4038 }
4039 errmsg = NULL;
4040 }
4041 else
4042 {
4043 char_u *dirp;
4044 char_u *p;
4045 char_u *rootname;
4046
4047 /*
4048 * Make a backup by renaming the original file.
4049 */
4050 /*
4051 * If 'cpoptions' includes the "W" flag, we don't want to
4052 * overwrite a read-only file. But rename may be possible
4053 * anyway, thus we need an extra check here.
4054 */
4055 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
4056 {
4057 errnum = (char_u *)"E504: ";
4058 errmsg = (char_u *)_(err_readonly);
4059 goto fail;
4060 }
4061
4062 /*
4063 *
4064 * Form the backup file name - change path/fo.o.h to
4065 * path/fo.o.h.bak Try all directories in 'backupdir', first one
4066 * that works is used.
4067 */
4068 dirp = p_bdir;
4069 while (*dirp)
4070 {
4071 /*
4072 * Isolate one directory name and make the backup file name.
4073 */
4074 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
4075 rootname = get_file_in_dir(fname, IObuff);
4076 if (rootname == NULL)
4077 backup = NULL;
4078 else
4079 {
4080 backup = buf_modname(
4081#ifdef SHORT_FNAME
4082 TRUE,
4083#else
4084 (buf->b_p_sn || buf->b_shortname),
4085#endif
4086 rootname, backup_ext, FALSE);
4087 vim_free(rootname);
4088 }
4089
4090 if (backup != NULL)
4091 {
4092 /*
4093 * If we are not going to keep the backup file, don't
4094 * delete an existing one, try to use another name.
4095 * Change one character, just before the extension.
4096 */
4097 if (!p_bk && mch_getperm(backup) >= 0)
4098 {
4099 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
4100 if (p < backup) /* empty file name ??? */
4101 p = backup;
4102 *p = 'z';
4103 while (*p > 'a' && mch_getperm(backup) >= 0)
4104 --*p;
4105 /* They all exist??? Must be something wrong! */
4106 if (*p == 'a')
4107 {
4108 vim_free(backup);
4109 backup = NULL;
4110 }
4111 }
4112 }
4113 if (backup != NULL)
4114 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00004116 * Delete any existing backup and move the current version
4117 * to the backup. For safety, we don't remove the backup
4118 * until the write has finished successfully. And if the
4119 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 */
4121 /*
4122 * If the renaming of the original file to the backup file
4123 * works, quit here.
4124 */
4125 if (vim_rename(fname, backup) == 0)
4126 break;
4127
4128 vim_free(backup); /* don't do the rename below */
4129 backup = NULL;
4130 }
4131 }
4132 if (backup == NULL && !forceit)
4133 {
4134 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
4135 goto fail;
4136 }
4137 }
4138 }
4139
4140#if defined(UNIX) && !defined(ARCHIE)
4141 /* When using ":w!" and the file was read-only: make it writable */
4142 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
4143 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
4144 {
4145 perm |= 0200;
4146 (void)mch_setperm(fname, perm);
4147 made_writable = TRUE;
4148 }
4149#endif
4150
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004151 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004152 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
4153 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
4155 buf->b_p_ro = FALSE;
4156#ifdef FEAT_TITLE
4157 need_maketitle = TRUE; /* set window title later */
4158#endif
4159#ifdef FEAT_WINDOWS
4160 status_redraw_all(); /* redraw status lines later */
4161#endif
4162 }
4163
4164 if (end > buf->b_ml.ml_line_count)
4165 end = buf->b_ml.ml_line_count;
4166 if (buf->b_ml.ml_flags & ML_EMPTY)
4167 start = end + 1;
4168
4169 /*
4170 * If the original file is being overwritten, there is a small chance that
4171 * we crash in the middle of writing. Therefore the file is preserved now.
4172 * This makes all block numbers positive so that recovery does not need
4173 * the original file.
4174 * Don't do this if there is a backup file and we are exiting.
4175 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004176 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 && !(exiting && backup != NULL))
4178 {
4179 ml_preserve(buf, FALSE);
4180 if (got_int)
4181 {
4182 errmsg = (char_u *)_(e_interr);
4183 goto restore_backup;
4184 }
4185 }
4186
4187#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4188 /*
4189 * Before risking to lose the original file verify if there's
4190 * a resource fork to preserve, and if cannot be done warn
4191 * the users. This happens when overwriting without backups.
4192 */
4193 if (backup == NULL && overwriting && !append)
4194 if (mch_has_resource_fork(fname))
4195 {
4196 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
4197 goto restore_backup;
4198 }
4199#endif
4200
4201#ifdef VMS
4202 vms_remove_version(fname); /* remove version */
4203#endif
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00004204 /* Default: write the file directly. May write to a temp file for
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 * multi-byte conversion. */
4206 wfname = fname;
4207
4208#ifdef FEAT_MBYTE
4209 /* Check for forced 'fileencoding' from "++opt=val" argument. */
4210 if (eap != NULL && eap->force_enc != 0)
4211 {
4212 fenc = eap->cmd + eap->force_enc;
4213 fenc = enc_canonize(fenc);
4214 fenc_tofree = fenc;
4215 }
4216 else
4217 fenc = buf->b_p_fenc;
4218
4219 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004220 * Check if the file needs to be converted.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 */
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004222 converted = need_conversion(fenc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223
4224 /*
4225 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
4226 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
4227 * Prepare the flags for it and allocate bw_conv_buf when needed.
4228 */
4229 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
4230 {
4231 wb_flags = get_fio_flags(fenc);
4232 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
4233 {
4234 /* Need to allocate a buffer to translate into. */
4235 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
4236 write_info.bw_conv_buflen = bufsize * 2;
4237 else /* FIO_UCS4 */
4238 write_info.bw_conv_buflen = bufsize * 4;
4239 write_info.bw_conv_buf
4240 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4241 if (write_info.bw_conv_buf == NULL)
4242 end = 0;
4243 }
4244 }
4245
4246# ifdef WIN3264
4247 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
4248 {
4249 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
4250 write_info.bw_conv_buflen = bufsize * 4;
4251 write_info.bw_conv_buf
4252 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4253 if (write_info.bw_conv_buf == NULL)
4254 end = 0;
4255 }
4256# endif
4257
4258# ifdef MACOS_X
4259 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
4260 {
4261 write_info.bw_conv_buflen = bufsize * 3;
4262 write_info.bw_conv_buf
4263 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4264 if (write_info.bw_conv_buf == NULL)
4265 end = 0;
4266 }
4267# endif
4268
4269# if defined(FEAT_EVAL) || defined(USE_ICONV)
4270 if (converted && wb_flags == 0)
4271 {
4272# ifdef USE_ICONV
4273 /*
4274 * Use iconv() conversion when conversion is needed and it's not done
4275 * internally.
4276 */
4277 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
4278 enc_utf8 ? (char_u *)"utf-8" : p_enc);
4279 if (write_info.bw_iconv_fd != (iconv_t)-1)
4280 {
4281 /* We're going to use iconv(), allocate a buffer to convert in. */
4282 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
4283 write_info.bw_conv_buf
4284 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
4285 if (write_info.bw_conv_buf == NULL)
4286 end = 0;
4287 write_info.bw_first = TRUE;
4288 }
4289# ifdef FEAT_EVAL
4290 else
4291# endif
4292# endif
4293
4294# ifdef FEAT_EVAL
4295 /*
4296 * When the file needs to be converted with 'charconvert' after
4297 * writing, write to a temp file instead and let the conversion
4298 * overwrite the original file.
4299 */
4300 if (*p_ccv != NUL)
4301 {
4302 wfname = vim_tempname('w');
4303 if (wfname == NULL) /* Can't write without a tempfile! */
4304 {
4305 errmsg = (char_u *)_("E214: Can't find temp file for writing");
4306 goto restore_backup;
4307 }
4308 }
4309# endif
4310 }
4311# endif
4312 if (converted && wb_flags == 0
4313# ifdef USE_ICONV
4314 && write_info.bw_iconv_fd == (iconv_t)-1
4315# endif
4316# ifdef FEAT_EVAL
4317 && wfname == fname
4318# endif
4319 )
4320 {
4321 if (!forceit)
4322 {
4323 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
4324 goto restore_backup;
4325 }
4326 notconverted = TRUE;
4327 }
4328#endif
4329
4330 /*
4331 * Open the file "wfname" for writing.
4332 * We may try to open the file twice: If we can't write to the
4333 * file and forceit is TRUE we delete the existing file and try to create
4334 * a new one. If this still fails we may have lost the original file!
4335 * (this may happen when the user reached his quotum for number of files).
4336 * Appending will fail if the file does not exist and forceit is FALSE.
4337 */
4338 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
4339 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
4340 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004341 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 {
4343 /*
4344 * A forced write will try to create a new file if the old one is
4345 * still readonly. This may also happen when the directory is
4346 * read-only. In that case the mch_remove() will fail.
4347 */
4348 if (errmsg == NULL)
4349 {
4350#ifdef UNIX
4351 struct stat st;
4352
4353 /* Don't delete the file when it's a hard or symbolic link. */
4354 if ((!newfile && st_old.st_nlink > 1)
4355 || (mch_lstat((char *)fname, &st) == 0
4356 && (st.st_dev != st_old.st_dev
4357 || st.st_ino != st_old.st_ino)))
4358 errmsg = (char_u *)_("E166: Can't open linked file for writing");
4359 else
4360#endif
4361 {
4362 errmsg = (char_u *)_("E212: Can't open file for writing");
4363 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
4364 && perm >= 0)
4365 {
4366#ifdef UNIX
4367 /* we write to the file, thus it should be marked
4368 writable after all */
4369 if (!(perm & 0200))
4370 made_writable = TRUE;
4371 perm |= 0200;
4372 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
4373 perm &= 0777;
4374#endif
4375 if (!append) /* don't remove when appending */
4376 mch_remove(wfname);
4377 continue;
4378 }
4379 }
4380 }
4381
4382restore_backup:
4383 {
4384 struct stat st;
4385
4386 /*
4387 * If we failed to open the file, we don't need a backup. Throw it
4388 * away. If we moved or removed the original file try to put the
4389 * backup in its place.
4390 */
4391 if (backup != NULL && wfname == fname)
4392 {
4393 if (backup_copy)
4394 {
4395 /*
4396 * There is a small chance that we removed the original,
4397 * try to move the copy in its place.
4398 * This may not work if the vim_rename() fails.
4399 * In that case we leave the copy around.
4400 */
4401 /* If file does not exist, put the copy in its place */
4402 if (mch_stat((char *)fname, &st) < 0)
4403 vim_rename(backup, fname);
4404 /* if original file does exist throw away the copy */
4405 if (mch_stat((char *)fname, &st) >= 0)
4406 mch_remove(backup);
4407 }
4408 else
4409 {
4410 /* try to put the original file back */
4411 vim_rename(backup, fname);
4412 }
4413 }
4414
4415 /* if original file no longer exists give an extra warning */
4416 if (!newfile && mch_stat((char *)fname, &st) < 0)
4417 end = 0;
4418 }
4419
4420#ifdef FEAT_MBYTE
4421 if (wfname != fname)
4422 vim_free(wfname);
4423#endif
4424 goto fail;
4425 }
4426 errmsg = NULL;
4427
4428#if defined(MACOS_CLASSIC) || defined(WIN3264)
4429 /* TODO: Is it need for MACOS_X? (Dany) */
4430 /*
4431 * On macintosh copy the original files attributes (i.e. the backup)
Bram Moolenaar7263a772007-05-10 17:35:54 +00004432 * This is done in order to preserve the resource fork and the
4433 * Finder attribute (label, comments, custom icons, file creator)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 */
4435 if (backup != NULL && overwriting && !append)
4436 {
4437 if (backup_copy)
4438 (void)mch_copy_file_attribute(wfname, backup);
4439 else
4440 (void)mch_copy_file_attribute(backup, wfname);
4441 }
4442
4443 if (!overwriting && !append)
4444 {
4445 if (buf->b_ffname != NULL)
4446 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
Bram Moolenaar7263a772007-05-10 17:35:54 +00004447 /* Should copy resource fork */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448 }
4449#endif
4450
4451 write_info.bw_fd = fd;
4452
4453#ifdef FEAT_CRYPT
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004454 if (*buf->b_p_key != NUL && !filtering)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 {
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02004456 char_u *header;
4457 int header_len;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02004458
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02004459 header = prepare_crypt_write(buf, &header_len);
4460 if (header == NULL)
4461 end = 0;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02004462 else
4463 {
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02004464 /* Write magic number, so that Vim knows that this file is
4465 * encrypted when reading it again. This also undergoes utf-8 to
4466 * ucs-2/4 conversion when needed. */
4467 write_info.bw_buf = header;
4468 write_info.bw_len = header_len;
4469 write_info.bw_flags = FIO_NOCONVERT;
4470 if (buf_write_bytes(&write_info) == FAIL)
4471 end = 0;
4472 wb_flags |= FIO_ENCRYPTED;
4473 vim_free(header);
Bram Moolenaar40e6a712010-05-16 22:32:54 +02004474 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 }
4476#endif
4477
4478 write_info.bw_buf = buffer;
4479 nchars = 0;
4480
4481 /* use "++bin", "++nobin" or 'binary' */
4482 if (eap != NULL && eap->force_bin != 0)
4483 write_bin = (eap->force_bin == FORCE_BIN);
4484 else
4485 write_bin = buf->b_p_bin;
4486
4487#ifdef FEAT_MBYTE
4488 /*
4489 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004490 * Skip it when appending and the file already existed, the BOM only makes
4491 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004492 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004493 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 {
4495 write_info.bw_len = make_bom(buffer, fenc);
4496 if (write_info.bw_len > 0)
4497 {
4498 /* don't convert, do encryption */
4499 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4500 if (buf_write_bytes(&write_info) == FAIL)
4501 end = 0;
4502 else
4503 nchars += write_info.bw_len;
4504 }
4505 }
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004506 write_info.bw_start_lnum = start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507#endif
4508
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004509#ifdef FEAT_PERSISTENT_UNDO
4510 write_undo_file = (buf->b_p_udf && overwriting && !append
4511 && !filtering && reset_changed);
4512 if (write_undo_file)
4513 /* Prepare for computing the hash value of the text. */
4514 sha256_start(&sha_ctx);
4515#endif
4516
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 write_info.bw_len = bufsize;
4518#ifdef HAS_BW_FLAGS
4519 write_info.bw_flags = wb_flags;
4520#endif
4521 fileformat = get_fileformat_force(buf, eap);
4522 s = buffer;
4523 len = 0;
4524 for (lnum = start; lnum <= end; ++lnum)
4525 {
4526 /*
4527 * The next while loop is done once for each character written.
4528 * Keep it fast!
4529 */
4530 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004531#ifdef FEAT_PERSISTENT_UNDO
4532 if (write_undo_file)
Bram Moolenaar442b4222010-05-24 21:34:22 +02004533 sha256_update(&sha_ctx, ptr + 1, (UINT32_T)(STRLEN(ptr + 1) + 1));
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004534#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535 while ((c = *++ptr) != NUL)
4536 {
4537 if (c == NL)
4538 *s = NUL; /* replace newlines with NULs */
4539 else if (c == CAR && fileformat == EOL_MAC)
4540 *s = NL; /* Mac: replace CRs with NLs */
4541 else
4542 *s = c;
4543 ++s;
4544 if (++len != bufsize)
4545 continue;
4546 if (buf_write_bytes(&write_info) == FAIL)
4547 {
4548 end = 0; /* write error: break loop */
4549 break;
4550 }
4551 nchars += bufsize;
4552 s = buffer;
4553 len = 0;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004554#ifdef FEAT_MBYTE
4555 write_info.bw_start_lnum = lnum;
4556#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 }
4558 /* write failed or last line has no EOL: stop here */
4559 if (end == 0
4560 || (lnum == end
4561 && write_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004562 && (lnum == buf->b_no_eol_lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4564 {
4565 ++lnum; /* written the line, count it */
4566 no_eol = TRUE;
4567 break;
4568 }
4569 if (fileformat == EOL_UNIX)
4570 *s++ = NL;
4571 else
4572 {
4573 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4574 if (fileformat == EOL_DOS) /* write CR-NL */
4575 {
4576 if (++len == bufsize)
4577 {
4578 if (buf_write_bytes(&write_info) == FAIL)
4579 {
4580 end = 0; /* write error: break loop */
4581 break;
4582 }
4583 nchars += bufsize;
4584 s = buffer;
4585 len = 0;
4586 }
4587 *s++ = NL;
4588 }
4589 }
4590 if (++len == bufsize && end)
4591 {
4592 if (buf_write_bytes(&write_info) == FAIL)
4593 {
4594 end = 0; /* write error: break loop */
4595 break;
4596 }
4597 nchars += bufsize;
4598 s = buffer;
4599 len = 0;
4600
4601 ui_breakcheck();
4602 if (got_int)
4603 {
4604 end = 0; /* Interrupted, break loop */
4605 break;
4606 }
4607 }
4608#ifdef VMS
4609 /*
4610 * On VMS there is a problem: newlines get added when writing blocks
4611 * at a time. Fix it by writing a line at a time.
4612 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004613 * Explanation: VAX/DECC RTL insists that records in some RMS
4614 * structures end with a newline (carriage return) character, and if
4615 * they don't it adds one.
4616 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 */
Bram Moolenaarb52e2602007-10-29 21:38:54 +00004618 if (buf->b_fab_rfm == FAB$C_VFC
4619 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004621 int b2write;
4622
4623 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4624 ? MIN(4096, bufsize)
4625 : MIN(buf->b_fab_mrs, bufsize));
4626
4627 b2write = len;
4628 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004630 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4631 if (buf_write_bytes(&write_info) == FAIL)
4632 {
4633 end = 0;
4634 break;
4635 }
4636 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 }
4638 write_info.bw_len = bufsize;
4639 nchars += len;
4640 s = buffer;
4641 len = 0;
4642 }
4643#endif
4644 }
4645 if (len > 0 && end > 0)
4646 {
4647 write_info.bw_len = len;
4648 if (buf_write_bytes(&write_info) == FAIL)
4649 end = 0; /* write error */
4650 nchars += len;
4651 }
4652
4653#if defined(UNIX) && defined(HAVE_FSYNC)
4654 /* On many journalling file systems there is a bug that causes both the
4655 * original and the backup file to be lost when halting the system right
4656 * after writing the file. That's because only the meta-data is
4657 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004658 * been written to disk and we don't lose it.
4659 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004660 * (could be a pipe).
4661 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4662 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663 {
4664 errmsg = (char_u *)_("E667: Fsync failed");
4665 end = 0;
4666 }
4667#endif
4668
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004669#ifdef HAVE_SELINUX
4670 /* Probably need to set the security context. */
4671 if (!backup_copy)
4672 mch_copy_sec(backup, wfname);
4673#endif
4674
Bram Moolenaara5792f52005-11-23 21:25:05 +00004675#ifdef UNIX
4676 /* When creating a new file, set its owner/group to that of the original
4677 * file. Get the new device and inode number. */
4678 if (backup != NULL && !backup_copy)
4679 {
4680# ifdef HAVE_FCHOWN
4681 struct stat st;
4682
4683 /* don't change the owner when it's already OK, some systems remove
4684 * permission or ACL stuff */
4685 if (mch_stat((char *)wfname, &st) < 0
4686 || st.st_uid != st_old.st_uid
4687 || st.st_gid != st_old.st_gid)
4688 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004689 ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004690 if (perm >= 0) /* set permission again, may have changed */
4691 (void)mch_setperm(wfname, perm);
4692 }
4693# endif
4694 buf_setino(buf);
4695 }
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00004696 else if (!buf->b_dev_valid)
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004697 /* Set the inode when creating a new file. */
4698 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004699#endif
4700
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 if (close(fd) != 0)
4702 {
4703 errmsg = (char_u *)_("E512: Close failed");
4704 end = 0;
4705 }
4706
4707#ifdef UNIX
4708 if (made_writable)
4709 perm &= ~0200; /* reset 'w' bit for security reasons */
4710#endif
4711 if (perm >= 0) /* set perm. of new file same as old file */
4712 (void)mch_setperm(wfname, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713#ifdef HAVE_ACL
4714 /* Probably need to set the ACL before changing the user (can't set the
4715 * ACL on a file the user doesn't own). */
4716 if (!backup_copy)
4717 mch_set_acl(wfname, acl);
4718#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004719#ifdef FEAT_CRYPT
Bram Moolenaar4cf35c22011-02-25 16:52:17 +01004720 crypt_method_used = use_crypt_method;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004721 if (wb_flags & FIO_ENCRYPTED)
4722 crypt_pop_state();
4723#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725
4726#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4727 if (wfname != fname)
4728 {
4729 /*
4730 * The file was written to a temp file, now it needs to be converted
4731 * with 'charconvert' to (overwrite) the output file.
4732 */
4733 if (end != 0)
4734 {
4735 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4736 wfname, fname) == FAIL)
4737 {
4738 write_info.bw_conv_error = TRUE;
4739 end = 0;
4740 }
4741 }
4742 mch_remove(wfname);
4743 vim_free(wfname);
4744 }
4745#endif
4746
4747 if (end == 0)
4748 {
4749 if (errmsg == NULL)
4750 {
4751#ifdef FEAT_MBYTE
4752 if (write_info.bw_conv_error)
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004753 {
4754 if (write_info.bw_conv_error_lnum == 0)
4755 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
4756 else
4757 {
4758 errmsg_allocated = TRUE;
4759 errmsg = alloc(300);
4760 vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"),
4761 (long)write_info.bw_conv_error_lnum);
4762 }
4763 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 else
4765#endif
4766 if (got_int)
4767 errmsg = (char_u *)_(e_interr);
4768 else
4769 errmsg = (char_u *)_("E514: write error (file system full?)");
4770 }
4771
4772 /*
4773 * If we have a backup file, try to put it in place of the new file,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004774 * because the new file is probably corrupt. This avoids losing the
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775 * original file when trying to make a backup when writing the file a
4776 * second time.
4777 * When "backup_copy" is set we need to copy the backup over the new
4778 * file. Otherwise rename the backup file.
4779 * If this is OK, don't give the extra warning message.
4780 */
4781 if (backup != NULL)
4782 {
4783 if (backup_copy)
4784 {
4785 /* This may take a while, if we were interrupted let the user
4786 * know we got the message. */
4787 if (got_int)
4788 {
4789 MSG(_(e_interr));
4790 out_flush();
4791 }
4792 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4793 {
4794 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004795 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4796 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 {
4798 /* copy the file. */
4799 write_info.bw_buf = smallbuf;
4800#ifdef HAS_BW_FLAGS
4801 write_info.bw_flags = FIO_NOCONVERT;
4802#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004803 while ((write_info.bw_len = read_eintr(fd, smallbuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804 SMBUFSIZE)) > 0)
4805 if (buf_write_bytes(&write_info) == FAIL)
4806 break;
4807
4808 if (close(write_info.bw_fd) >= 0
4809 && write_info.bw_len == 0)
4810 end = 1; /* success */
4811 }
4812 close(fd); /* ignore errors for closing read file */
4813 }
4814 }
4815 else
4816 {
4817 if (vim_rename(backup, fname) == 0)
4818 end = 1;
4819 }
4820 }
4821 goto fail;
4822 }
4823
4824 lnum -= start; /* compute number of written lines */
4825 --no_wait_return; /* may wait for return now */
4826
4827#if !(defined(UNIX) || defined(VMS))
4828 fname = sfname; /* use shortname now, for the messages */
4829#endif
4830 if (!filtering)
4831 {
4832 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4833 c = FALSE;
4834#ifdef FEAT_MBYTE
4835 if (write_info.bw_conv_error)
4836 {
4837 STRCAT(IObuff, _(" CONVERSION ERROR"));
4838 c = TRUE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004839 if (write_info.bw_conv_error_lnum != 0)
Bram Moolenaara800b422010-06-27 01:15:55 +02004840 vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"),
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004841 (long)write_info.bw_conv_error_lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 }
4843 else if (notconverted)
4844 {
4845 STRCAT(IObuff, _("[NOT converted]"));
4846 c = TRUE;
4847 }
4848 else if (converted)
4849 {
4850 STRCAT(IObuff, _("[converted]"));
4851 c = TRUE;
4852 }
4853#endif
4854 if (device)
4855 {
4856 STRCAT(IObuff, _("[Device]"));
4857 c = TRUE;
4858 }
4859 else if (newfile)
4860 {
4861 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4862 c = TRUE;
4863 }
4864 if (no_eol)
4865 {
4866 msg_add_eol();
4867 c = TRUE;
4868 }
4869 /* may add [unix/dos/mac] */
4870 if (msg_add_fileformat(fileformat))
4871 c = TRUE;
4872#ifdef FEAT_CRYPT
4873 if (wb_flags & FIO_ENCRYPTED)
4874 {
Bram Moolenaar4cf35c22011-02-25 16:52:17 +01004875 if (crypt_method_used == 1)
4876 STRCAT(IObuff, _("[blowfish]"));
4877 else
4878 STRCAT(IObuff, _("[crypted]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879 c = TRUE;
4880 }
4881#endif
4882 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4883 if (!shortmess(SHM_WRITE))
4884 {
4885 if (append)
4886 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4887 else
4888 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4889 }
4890
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00004891 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892 }
4893
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004894 /* When written everything correctly: reset 'modified'. Unless not
4895 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004896 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897#ifdef FEAT_MBYTE
4898 && !write_info.bw_conv_error
4899#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004900 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4901 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004902 {
4903 unchanged(buf, TRUE);
4904 u_unchanged(buf);
Bram Moolenaar730cde92010-06-27 05:18:54 +02004905 u_update_save_nr(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906 }
4907
4908 /*
4909 * If written to the current file, update the timestamp of the swap file
4910 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4911 */
4912 if (overwriting)
4913 {
4914 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004915 if (append)
4916 buf->b_flags &= ~BF_NEW;
4917 else
4918 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919 }
4920
4921 /*
4922 * If we kept a backup until now, and we are in patch mode, then we make
4923 * the backup file our 'original' file.
4924 */
4925 if (*p_pm && dobackup)
4926 {
4927 char *org = (char *)buf_modname(
4928#ifdef SHORT_FNAME
4929 TRUE,
4930#else
4931 (buf->b_p_sn || buf->b_shortname),
4932#endif
4933 fname, p_pm, FALSE);
4934
4935 if (backup != NULL)
4936 {
4937 struct stat st;
4938
4939 /*
4940 * If the original file does not exist yet
4941 * the current backup file becomes the original file
4942 */
4943 if (org == NULL)
4944 EMSG(_("E205: Patchmode: can't save original file"));
4945 else if (mch_stat(org, &st) < 0)
4946 {
4947 vim_rename(backup, (char_u *)org);
4948 vim_free(backup); /* don't delete the file */
4949 backup = NULL;
4950#ifdef UNIX
4951 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4952#endif
4953 }
4954 }
4955 /*
4956 * If there is no backup file, remember that a (new) file was
4957 * created.
4958 */
4959 else
4960 {
4961 int empty_fd;
4962
4963 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004964 || (empty_fd = mch_open(org,
4965 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004966 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 EMSG(_("E206: patchmode: can't touch empty original file"));
4968 else
4969 close(empty_fd);
4970 }
4971 if (org != NULL)
4972 {
4973 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4974 vim_free(org);
4975 }
4976 }
4977
4978 /*
4979 * Remove the backup unless 'backup' option is set
4980 */
4981 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4982 EMSG(_("E207: Can't delete backup file"));
4983
4984#ifdef FEAT_SUN_WORKSHOP
4985 if (usingSunWorkShop)
4986 workshop_file_saved((char *) ffname);
4987#endif
4988
4989 goto nofail;
4990
4991 /*
4992 * Finish up. We get here either after failure or success.
4993 */
4994fail:
4995 --no_wait_return; /* may wait for return now */
4996nofail:
4997
4998 /* Done saving, we accept changed buffer warnings again */
4999 buf->b_saving = FALSE;
5000
5001 vim_free(backup);
5002 if (buffer != smallbuf)
5003 vim_free(buffer);
5004#ifdef FEAT_MBYTE
5005 vim_free(fenc_tofree);
5006 vim_free(write_info.bw_conv_buf);
5007# ifdef USE_ICONV
5008 if (write_info.bw_iconv_fd != (iconv_t)-1)
5009 {
5010 iconv_close(write_info.bw_iconv_fd);
5011 write_info.bw_iconv_fd = (iconv_t)-1;
5012 }
5013# endif
5014#endif
5015#ifdef HAVE_ACL
5016 mch_free_acl(acl);
5017#endif
5018
5019 if (errmsg != NULL)
5020 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005021 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005022
5023 attr = hl_attr(HLF_E); /* set highlight for error messages */
5024 msg_add_fname(buf,
5025#ifndef UNIX
5026 sfname
5027#else
5028 fname
5029#endif
5030 ); /* put file name in IObuff with quotes */
5031 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
5032 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
5033 /* If the error message has the form "is ...", put the error number in
5034 * front of the file name. */
5035 if (errnum != NULL)
5036 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005037 STRMOVE(IObuff + numlen, IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038 mch_memmove(IObuff, errnum, (size_t)numlen);
5039 }
5040 STRCAT(IObuff, errmsg);
5041 emsg(IObuff);
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005042 if (errmsg_allocated)
5043 vim_free(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044
5045 retval = FAIL;
5046 if (end == 0)
5047 {
5048 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
5049 attr | MSG_HIST);
5050 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
5051 attr | MSG_HIST);
5052
5053 /* Update the timestamp to avoid an "overwrite changed file"
5054 * prompt when writing again. */
5055 if (mch_stat((char *)fname, &st_old) >= 0)
5056 {
5057 buf_store_time(buf, &st_old, fname);
5058 buf->b_mtime_read = buf->b_mtime;
5059 }
5060 }
5061 }
5062 msg_scroll = msg_save;
5063
Bram Moolenaar55debbe2010-05-23 23:34:36 +02005064#ifdef FEAT_PERSISTENT_UNDO
5065 /*
5066 * When writing the whole file and 'undofile' is set, also write the undo
5067 * file.
5068 */
5069 if (retval == OK && write_undo_file)
5070 {
5071 char_u hash[UNDO_HASH_SIZE];
5072
5073 sha256_finish(&sha_ctx, hash);
5074 u_write_undo(NULL, FALSE, buf, hash);
5075 }
5076#endif
5077
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078#ifdef FEAT_AUTOCMD
5079#ifdef FEAT_EVAL
5080 if (!should_abort(retval))
5081#else
5082 if (!got_int)
5083#endif
5084 {
5085 aco_save_T aco;
5086
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 /*
5088 * Apply POST autocommands.
5089 * Careful: The autocommands may call buf_write() recursively!
5090 */
5091 aucmd_prepbuf(&aco, buf);
5092
5093 if (append)
5094 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
5095 FALSE, curbuf, eap);
5096 else if (filtering)
5097 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
5098 FALSE, curbuf, eap);
5099 else if (reset_changed && whole)
5100 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
5101 FALSE, curbuf, eap);
5102 else
5103 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
5104 FALSE, curbuf, eap);
5105
5106 /* restore curwin/curbuf and a few other things */
5107 aucmd_restbuf(&aco);
5108
5109#ifdef FEAT_EVAL
5110 if (aborting()) /* autocmds may abort script processing */
5111 retval = FALSE;
5112#endif
5113 }
5114#endif
5115
5116 got_int |= prev_got_int;
5117
5118#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
5119 /* Update machine specific information. */
5120 mch_post_buffer_write(buf);
5121#endif
5122 return retval;
5123}
5124
5125/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005126 * Set the name of the current buffer. Use when the buffer doesn't have a
5127 * name and a ":r" or ":w" command with a file name is used.
5128 */
5129 static int
5130set_rw_fname(fname, sfname)
5131 char_u *fname;
5132 char_u *sfname;
5133{
5134#ifdef FEAT_AUTOCMD
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005135 buf_T *buf = curbuf;
5136
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005137 /* It's like the unnamed buffer is deleted.... */
5138 if (curbuf->b_p_bl)
5139 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
5140 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
5141# ifdef FEAT_EVAL
5142 if (aborting()) /* autocmds may abort script processing */
5143 return FAIL;
5144# endif
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005145 if (curbuf != buf)
5146 {
5147 /* We are in another buffer now, don't do the renaming. */
5148 EMSG(_(e_auchangedbuf));
5149 return FAIL;
5150 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005151#endif
5152
5153 if (setfname(curbuf, fname, sfname, FALSE) == OK)
5154 curbuf->b_flags |= BF_NOTEDITED;
5155
5156#ifdef FEAT_AUTOCMD
5157 /* ....and a new named one is created */
5158 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
5159 if (curbuf->b_p_bl)
5160 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
5161# ifdef FEAT_EVAL
5162 if (aborting()) /* autocmds may abort script processing */
5163 return FAIL;
5164# endif
5165
5166 /* Do filetype detection now if 'filetype' is empty. */
5167 if (*curbuf->b_p_ft == NUL)
5168 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005169 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar70836c82006-02-20 21:28:49 +00005170 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00005171 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005172 }
5173#endif
5174
5175 return OK;
5176}
5177
5178/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 * Put file name into IObuff with quotes.
5180 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005181 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182msg_add_fname(buf, fname)
5183 buf_T *buf;
5184 char_u *fname;
5185{
5186 if (fname == NULL)
5187 fname = (char_u *)"-stdin-";
5188 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
5189 IObuff[0] = '"';
5190 STRCAT(IObuff, "\" ");
5191}
5192
5193/*
5194 * Append message for text mode to IObuff.
5195 * Return TRUE if something appended.
5196 */
5197 static int
5198msg_add_fileformat(eol_type)
5199 int eol_type;
5200{
5201#ifndef USE_CRNL
5202 if (eol_type == EOL_DOS)
5203 {
5204 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
5205 return TRUE;
5206 }
5207#endif
5208#ifndef USE_CR
5209 if (eol_type == EOL_MAC)
5210 {
5211 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
5212 return TRUE;
5213 }
5214#endif
5215#if defined(USE_CRNL) || defined(USE_CR)
5216 if (eol_type == EOL_UNIX)
5217 {
5218 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
5219 return TRUE;
5220 }
5221#endif
5222 return FALSE;
5223}
5224
5225/*
5226 * Append line and character count to IObuff.
5227 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005228 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229msg_add_lines(insert_space, lnum, nchars)
5230 int insert_space;
5231 long lnum;
Bram Moolenaar914703b2010-05-31 21:59:46 +02005232 off_t nchars;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233{
5234 char_u *p;
5235
5236 p = IObuff + STRLEN(IObuff);
5237
5238 if (insert_space)
5239 *p++ = ' ';
5240 if (shortmess(SHM_LINES))
Bram Moolenaar914703b2010-05-31 21:59:46 +02005241 sprintf((char *)p,
5242#ifdef LONG_LONG_OFF_T
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005243 "%ldL, %lldC", lnum, nchars
Bram Moolenaar914703b2010-05-31 21:59:46 +02005244#else
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005245 /* Explicit typecast avoids warning on Mac OS X 10.6 */
5246 "%ldL, %ldC", lnum, (long)nchars
Bram Moolenaar914703b2010-05-31 21:59:46 +02005247#endif
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005248 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249 else
5250 {
5251 if (lnum == 1)
5252 STRCPY(p, _("1 line, "));
5253 else
5254 sprintf((char *)p, _("%ld lines, "), lnum);
5255 p += STRLEN(p);
5256 if (nchars == 1)
5257 STRCPY(p, _("1 character"));
5258 else
Bram Moolenaar914703b2010-05-31 21:59:46 +02005259 sprintf((char *)p,
5260#ifdef LONG_LONG_OFF_T
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005261 _("%lld characters"), nchars
Bram Moolenaar914703b2010-05-31 21:59:46 +02005262#else
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005263 /* Explicit typecast avoids warning on Mac OS X 10.6 */
5264 _("%ld characters"), (long)nchars
Bram Moolenaar914703b2010-05-31 21:59:46 +02005265#endif
Bram Moolenaarf9b01292010-06-12 06:45:20 +02005266 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267 }
5268}
5269
5270/*
5271 * Append message for missing line separator to IObuff.
5272 */
5273 static void
5274msg_add_eol()
5275{
5276 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
5277}
5278
5279/*
5280 * Check modification time of file, before writing to it.
5281 * The size isn't checked, because using a tool like "gzip" takes care of
5282 * using the same timestamp but can't set the size.
5283 */
5284 static int
5285check_mtime(buf, st)
5286 buf_T *buf;
5287 struct stat *st;
5288{
5289 if (buf->b_mtime_read != 0
5290 && time_differs((long)st->st_mtime, buf->b_mtime_read))
5291 {
5292 msg_scroll = TRUE; /* don't overwrite messages here */
5293 msg_silent = 0; /* must give this prompt */
5294 /* don't use emsg() here, don't want to flush the buffers */
5295 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
5296 hl_attr(HLF_E));
5297 if (ask_yesno((char_u *)_("Do you really want to write to it"),
5298 TRUE) == 'n')
5299 return FAIL;
5300 msg_scroll = FALSE; /* always overwrite the file message now */
5301 }
5302 return OK;
5303}
5304
5305 static int
5306time_differs(t1, t2)
5307 long t1, t2;
5308{
5309#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
5310 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
5311 * the seconds. Since the roundoff is done when flushing the inode, the
5312 * time may change unexpectedly by one second!!! */
5313 return (t1 - t2 > 1 || t2 - t1 > 1);
5314#else
5315 return (t1 != t2);
5316#endif
5317}
5318
5319/*
5320 * Call write() to write a number of bytes to the file.
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005321 * Handles encryption and 'encoding' conversion.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005322 *
5323 * Return FAIL for failure, OK otherwise.
5324 */
5325 static int
5326buf_write_bytes(ip)
5327 struct bw_info *ip;
5328{
5329 int wlen;
5330 char_u *buf = ip->bw_buf; /* data to write */
5331 int len = ip->bw_len; /* length of data */
5332#ifdef HAS_BW_FLAGS
5333 int flags = ip->bw_flags; /* extra flags */
5334#endif
5335
5336#ifdef FEAT_MBYTE
5337 /*
5338 * Skip conversion when writing the crypt magic number or the BOM.
5339 */
5340 if (!(flags & FIO_NOCONVERT))
5341 {
5342 char_u *p;
5343 unsigned c;
5344 int n;
5345
5346 if (flags & FIO_UTF8)
5347 {
5348 /*
5349 * Convert latin1 in the buffer to UTF-8 in the file.
5350 */
5351 p = ip->bw_conv_buf; /* translate to buffer */
5352 for (wlen = 0; wlen < len; ++wlen)
5353 p += utf_char2bytes(buf[wlen], p);
5354 buf = ip->bw_conv_buf;
5355 len = (int)(p - ip->bw_conv_buf);
5356 }
5357 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
5358 {
5359 /*
5360 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
5361 * Latin1 chars in the file.
5362 */
5363 if (flags & FIO_LATIN1)
5364 p = buf; /* translate in-place (can only get shorter) */
5365 else
5366 p = ip->bw_conv_buf; /* translate to buffer */
5367 for (wlen = 0; wlen < len; wlen += n)
5368 {
5369 if (wlen == 0 && ip->bw_restlen != 0)
5370 {
5371 int l;
5372
5373 /* Use remainder of previous call. Append the start of
5374 * buf[] to get a full sequence. Might still be too
5375 * short! */
5376 l = CONV_RESTLEN - ip->bw_restlen;
5377 if (l > len)
5378 l = len;
5379 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005380 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381 if (n > ip->bw_restlen + len)
5382 {
5383 /* We have an incomplete byte sequence at the end to
5384 * be written. We can't convert it without the
5385 * remaining bytes. Keep them for the next call. */
5386 if (ip->bw_restlen + len > CONV_RESTLEN)
5387 return FAIL;
5388 ip->bw_restlen += len;
5389 break;
5390 }
5391 if (n > 1)
5392 c = utf_ptr2char(ip->bw_rest);
5393 else
5394 c = ip->bw_rest[0];
5395 if (n >= ip->bw_restlen)
5396 {
5397 n -= ip->bw_restlen;
5398 ip->bw_restlen = 0;
5399 }
5400 else
5401 {
5402 ip->bw_restlen -= n;
5403 mch_memmove(ip->bw_rest, ip->bw_rest + n,
5404 (size_t)ip->bw_restlen);
5405 n = 0;
5406 }
5407 }
5408 else
5409 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005410 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005411 if (n > len - wlen)
5412 {
5413 /* We have an incomplete byte sequence at the end to
5414 * be written. We can't convert it without the
5415 * remaining bytes. Keep them for the next call. */
5416 if (len - wlen > CONV_RESTLEN)
5417 return FAIL;
5418 ip->bw_restlen = len - wlen;
5419 mch_memmove(ip->bw_rest, buf + wlen,
5420 (size_t)ip->bw_restlen);
5421 break;
5422 }
5423 if (n > 1)
5424 c = utf_ptr2char(buf + wlen);
5425 else
5426 c = buf[wlen];
5427 }
5428
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005429 if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error)
5430 {
5431 ip->bw_conv_error = TRUE;
5432 ip->bw_conv_error_lnum = ip->bw_start_lnum;
5433 }
5434 if (c == NL)
5435 ++ip->bw_start_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005436 }
5437 if (flags & FIO_LATIN1)
5438 len = (int)(p - buf);
5439 else
5440 {
5441 buf = ip->bw_conv_buf;
5442 len = (int)(p - ip->bw_conv_buf);
5443 }
5444 }
5445
5446# ifdef WIN3264
5447 else if (flags & FIO_CODEPAGE)
5448 {
5449 /*
5450 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
5451 * codepage.
5452 */
5453 char_u *from;
5454 size_t fromlen;
5455 char_u *to;
5456 int u8c;
5457 BOOL bad = FALSE;
5458 int needed;
5459
5460 if (ip->bw_restlen > 0)
5461 {
5462 /* Need to concatenate the remainder of the previous call and
5463 * the bytes of the current call. Use the end of the
5464 * conversion buffer for this. */
5465 fromlen = len + ip->bw_restlen;
5466 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5467 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5468 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5469 }
5470 else
5471 {
5472 from = buf;
5473 fromlen = len;
5474 }
5475
5476 to = ip->bw_conv_buf;
5477 if (enc_utf8)
5478 {
5479 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
5480 * The buffer has been allocated to be big enough. */
5481 while (fromlen > 0)
5482 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005483 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484 if (n > (int)fromlen) /* incomplete byte sequence */
5485 break;
5486 u8c = utf_ptr2char(from);
5487 *to++ = (u8c & 0xff);
5488 *to++ = (u8c >> 8);
5489 fromlen -= n;
5490 from += n;
5491 }
5492
5493 /* Copy remainder to ip->bw_rest[] to be used for the next
5494 * call. */
5495 if (fromlen > CONV_RESTLEN)
5496 {
5497 /* weird overlong sequence */
5498 ip->bw_conv_error = TRUE;
5499 return FAIL;
5500 }
5501 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005502 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503 }
5504 else
5505 {
5506 /* Convert from enc_codepage to UCS-2, to the start of the
5507 * buffer. The buffer has been allocated to be big enough. */
5508 ip->bw_restlen = 0;
5509 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005510 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511 NULL, 0);
5512 if (needed == 0)
5513 {
5514 /* When conversion fails there may be a trailing byte. */
5515 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005516 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005517 NULL, 0);
5518 if (needed == 0)
5519 {
5520 /* Conversion doesn't work. */
5521 ip->bw_conv_error = TRUE;
5522 return FAIL;
5523 }
5524 /* Save the trailing byte for the next call. */
5525 ip->bw_rest[0] = from[fromlen - 1];
5526 ip->bw_restlen = 1;
5527 }
5528 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005529 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005530 (LPWSTR)to, needed);
5531 if (needed == 0)
5532 {
5533 /* Safety check: Conversion doesn't work. */
5534 ip->bw_conv_error = TRUE;
5535 return FAIL;
5536 }
5537 to += needed * 2;
5538 }
5539
5540 fromlen = to - ip->bw_conv_buf;
5541 buf = to;
5542# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5543 if (FIO_GET_CP(flags) == CP_UTF8)
5544 {
5545 /* Convert from UCS-2 to UTF-8, using the remainder of the
5546 * conversion buffer. Fails when out of space. */
5547 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5548 {
5549 u8c = *from++;
5550 u8c += (*from++ << 8);
5551 to += utf_char2bytes(u8c, to);
5552 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5553 {
5554 ip->bw_conv_error = TRUE;
5555 return FAIL;
5556 }
5557 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005558 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005559 }
5560 else
5561#endif
5562 {
5563 /* Convert from UCS-2 to the codepage, using the remainder of
5564 * the conversion buffer. If the conversion uses the default
5565 * character "0", the data doesn't fit in this encoding, so
5566 * fail. */
5567 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5568 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005569 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
5570 &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571 if (bad)
5572 {
5573 ip->bw_conv_error = TRUE;
5574 return FAIL;
5575 }
5576 }
5577 }
5578# endif
5579
Bram Moolenaar56718732006-03-15 22:53:57 +00005580# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005581 else if (flags & FIO_MACROMAN)
5582 {
5583 /*
5584 * Convert UTF-8 or latin1 to Apple MacRoman.
5585 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005586 char_u *from;
5587 size_t fromlen;
5588
5589 if (ip->bw_restlen > 0)
5590 {
5591 /* Need to concatenate the remainder of the previous call and
5592 * the bytes of the current call. Use the end of the
5593 * conversion buffer for this. */
5594 fromlen = len + ip->bw_restlen;
5595 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5596 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5597 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5598 }
5599 else
5600 {
5601 from = buf;
5602 fromlen = len;
5603 }
5604
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005605 if (enc2macroman(from, fromlen,
5606 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5607 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608 {
5609 ip->bw_conv_error = TRUE;
5610 return FAIL;
5611 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613 }
5614# endif
5615
5616# ifdef USE_ICONV
5617 if (ip->bw_iconv_fd != (iconv_t)-1)
5618 {
5619 const char *from;
5620 size_t fromlen;
5621 char *to;
5622 size_t tolen;
5623
5624 /* Convert with iconv(). */
5625 if (ip->bw_restlen > 0)
5626 {
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005627 char *fp;
5628
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629 /* Need to concatenate the remainder of the previous call and
5630 * the bytes of the current call. Use the end of the
5631 * conversion buffer for this. */
5632 fromlen = len + ip->bw_restlen;
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005633 fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5634 mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
5635 mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
5636 from = fp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 tolen = ip->bw_conv_buflen - fromlen;
5638 }
5639 else
5640 {
5641 from = (const char *)buf;
5642 fromlen = len;
5643 tolen = ip->bw_conv_buflen;
5644 }
5645 to = (char *)ip->bw_conv_buf;
5646
5647 if (ip->bw_first)
5648 {
5649 size_t save_len = tolen;
5650
5651 /* output the initial shift state sequence */
5652 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5653
5654 /* There is a bug in iconv() on Linux (which appears to be
5655 * wide-spread) which sets "to" to NULL and messes up "tolen".
5656 */
5657 if (to == NULL)
5658 {
5659 to = (char *)ip->bw_conv_buf;
5660 tolen = save_len;
5661 }
5662 ip->bw_first = FALSE;
5663 }
5664
5665 /*
5666 * If iconv() has an error or there is not enough room, fail.
5667 */
5668 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5669 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5670 || fromlen > CONV_RESTLEN)
5671 {
5672 ip->bw_conv_error = TRUE;
5673 return FAIL;
5674 }
5675
5676 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5677 if (fromlen > 0)
5678 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5679 ip->bw_restlen = (int)fromlen;
5680
5681 buf = ip->bw_conv_buf;
5682 len = (int)((char_u *)to - ip->bw_conv_buf);
5683 }
5684# endif
5685 }
5686#endif /* FEAT_MBYTE */
5687
5688#ifdef FEAT_CRYPT
5689 if (flags & FIO_ENCRYPTED) /* encrypt the data */
Bram Moolenaar04c9baf2010-06-01 23:37:39 +02005690 crypt_encode(buf, len, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691#endif
5692
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005693 wlen = write_eintr(ip->bw_fd, buf, len);
5694 return (wlen < len) ? FAIL : OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695}
5696
5697#ifdef FEAT_MBYTE
5698/*
5699 * Convert a Unicode character to bytes.
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005700 * Return TRUE for an error, FALSE when it's OK.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701 */
5702 static int
5703ucs2bytes(c, pp, flags)
5704 unsigned c; /* in: character */
5705 char_u **pp; /* in/out: pointer to result */
5706 int flags; /* FIO_ flags */
5707{
5708 char_u *p = *pp;
5709 int error = FALSE;
5710 int cc;
5711
5712
5713 if (flags & FIO_UCS4)
5714 {
5715 if (flags & FIO_ENDIAN_L)
5716 {
5717 *p++ = c;
5718 *p++ = (c >> 8);
5719 *p++ = (c >> 16);
5720 *p++ = (c >> 24);
5721 }
5722 else
5723 {
5724 *p++ = (c >> 24);
5725 *p++ = (c >> 16);
5726 *p++ = (c >> 8);
5727 *p++ = c;
5728 }
5729 }
5730 else if (flags & (FIO_UCS2 | FIO_UTF16))
5731 {
5732 if (c >= 0x10000)
5733 {
5734 if (flags & FIO_UTF16)
5735 {
5736 /* Make two words, ten bits of the character in each. First
5737 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5738 c -= 0x10000;
5739 if (c >= 0x100000)
5740 error = TRUE;
5741 cc = ((c >> 10) & 0x3ff) + 0xd800;
5742 if (flags & FIO_ENDIAN_L)
5743 {
5744 *p++ = cc;
5745 *p++ = ((unsigned)cc >> 8);
5746 }
5747 else
5748 {
5749 *p++ = ((unsigned)cc >> 8);
5750 *p++ = cc;
5751 }
5752 c = (c & 0x3ff) + 0xdc00;
5753 }
5754 else
5755 error = TRUE;
5756 }
5757 if (flags & FIO_ENDIAN_L)
5758 {
5759 *p++ = c;
5760 *p++ = (c >> 8);
5761 }
5762 else
5763 {
5764 *p++ = (c >> 8);
5765 *p++ = c;
5766 }
5767 }
5768 else /* Latin1 */
5769 {
5770 if (c >= 0x100)
5771 {
5772 error = TRUE;
5773 *p++ = 0xBF;
5774 }
5775 else
5776 *p++ = c;
5777 }
5778
5779 *pp = p;
5780 return error;
5781}
5782
5783/*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005784 * Return TRUE if file encoding "fenc" requires conversion from or to
5785 * 'encoding'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786 */
5787 static int
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005788need_conversion(fenc)
5789 char_u *fenc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005790{
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005791 int same_encoding;
5792 int enc_flags;
5793 int fenc_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005795 if (*fenc == NUL || STRCMP(p_enc, fenc) == 0)
Bram Moolenaar442b4222010-05-24 21:34:22 +02005796 {
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005797 same_encoding = TRUE;
Bram Moolenaar442b4222010-05-24 21:34:22 +02005798 fenc_flags = 0;
5799 }
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005800 else
5801 {
5802 /* Ignore difference between "ansi" and "latin1", "ucs-4" and
5803 * "ucs-4be", etc. */
5804 enc_flags = get_fio_flags(p_enc);
5805 fenc_flags = get_fio_flags(fenc);
5806 same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
5807 }
5808 if (same_encoding)
5809 {
5810 /* Specified encoding matches with 'encoding'. This requires
5811 * conversion when 'encoding' is Unicode but not UTF-8. */
5812 return enc_unicode != 0;
5813 }
5814
5815 /* Encodings differ. However, conversion is not needed when 'enc' is any
5816 * Unicode encoding and the file is UTF-8. */
5817 return !(enc_utf8 && fenc_flags == FIO_UTF8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005818}
5819
5820/*
5821 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5822 * internal conversion.
5823 * if "ptr" is an empty string, use 'encoding'.
5824 */
5825 static int
5826get_fio_flags(ptr)
5827 char_u *ptr;
5828{
5829 int prop;
5830
5831 if (*ptr == NUL)
5832 ptr = p_enc;
5833
5834 prop = enc_canon_props(ptr);
5835 if (prop & ENC_UNICODE)
5836 {
5837 if (prop & ENC_2BYTE)
5838 {
5839 if (prop & ENC_ENDIAN_L)
5840 return FIO_UCS2 | FIO_ENDIAN_L;
5841 return FIO_UCS2;
5842 }
5843 if (prop & ENC_4BYTE)
5844 {
5845 if (prop & ENC_ENDIAN_L)
5846 return FIO_UCS4 | FIO_ENDIAN_L;
5847 return FIO_UCS4;
5848 }
5849 if (prop & ENC_2WORD)
5850 {
5851 if (prop & ENC_ENDIAN_L)
5852 return FIO_UTF16 | FIO_ENDIAN_L;
5853 return FIO_UTF16;
5854 }
5855 return FIO_UTF8;
5856 }
5857 if (prop & ENC_LATIN1)
5858 return FIO_LATIN1;
5859 /* must be ENC_DBCS, requires iconv() */
5860 return 0;
5861}
5862
5863#ifdef WIN3264
5864/*
5865 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5866 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5867 * Used for conversion between 'encoding' and 'fileencoding'.
5868 */
5869 static int
5870get_win_fio_flags(ptr)
5871 char_u *ptr;
5872{
5873 int cp;
5874
5875 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5876 if (!enc_utf8 && enc_codepage <= 0)
5877 return 0;
5878
5879 cp = encname2codepage(ptr);
5880 if (cp == 0)
5881 {
5882# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5883 if (STRCMP(ptr, "utf-8") == 0)
5884 cp = CP_UTF8;
5885 else
5886# endif
5887 return 0;
5888 }
5889 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5890}
5891#endif
5892
5893#ifdef MACOS_X
5894/*
5895 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5896 * needed for the internal conversion to/from utf-8 or latin1.
5897 */
5898 static int
5899get_mac_fio_flags(ptr)
5900 char_u *ptr;
5901{
5902 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5903 && (enc_canon_props(ptr) & ENC_MACROMAN))
5904 return FIO_MACROMAN;
5905 return 0;
5906}
5907#endif
5908
5909/*
5910 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5911 * "size" must be at least 2.
5912 * Return the name of the encoding and set "*lenp" to the length.
5913 * Returns NULL when no BOM found.
5914 */
5915 static char_u *
5916check_for_bom(p, size, lenp, flags)
5917 char_u *p;
5918 long size;
5919 int *lenp;
5920 int flags;
5921{
5922 char *name = NULL;
5923 int len = 2;
5924
5925 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
Bram Moolenaaree0f5a62008-07-24 20:09:16 +00005926 && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005927 {
5928 name = "utf-8"; /* EF BB BF */
5929 len = 3;
5930 }
5931 else if (p[0] == 0xff && p[1] == 0xfe)
5932 {
5933 if (size >= 4 && p[2] == 0 && p[3] == 0
5934 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5935 {
5936 name = "ucs-4le"; /* FF FE 00 00 */
5937 len = 4;
5938 }
Bram Moolenaar223a1892008-11-11 20:57:11 +00005939 else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005940 name = "ucs-2le"; /* FF FE */
Bram Moolenaar223a1892008-11-11 20:57:11 +00005941 else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
5942 /* utf-16le is preferred, it also works for ucs-2le text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943 name = "utf-16le"; /* FF FE */
5944 }
5945 else if (p[0] == 0xfe && p[1] == 0xff
5946 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5947 {
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005948 /* Default to utf-16, it works also for ucs-2 text. */
5949 if (flags == FIO_UCS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950 name = "ucs-2"; /* FE FF */
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005951 else
5952 name = "utf-16"; /* FE FF */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953 }
5954 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5955 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5956 {
5957 name = "ucs-4"; /* 00 00 FE FF */
5958 len = 4;
5959 }
5960
5961 *lenp = len;
5962 return (char_u *)name;
5963}
5964
5965/*
5966 * Generate a BOM in "buf[4]" for encoding "name".
5967 * Return the length of the BOM (zero when no BOM).
5968 */
5969 static int
5970make_bom(buf, name)
5971 char_u *buf;
5972 char_u *name;
5973{
5974 int flags;
5975 char_u *p;
5976
5977 flags = get_fio_flags(name);
5978
5979 /* Can't put a BOM in a non-Unicode file. */
5980 if (flags == FIO_LATIN1 || flags == 0)
5981 return 0;
5982
5983 if (flags == FIO_UTF8) /* UTF-8 */
5984 {
5985 buf[0] = 0xef;
5986 buf[1] = 0xbb;
5987 buf[2] = 0xbf;
5988 return 3;
5989 }
5990 p = buf;
5991 (void)ucs2bytes(0xfeff, &p, flags);
5992 return (int)(p - buf);
5993}
5994#endif
5995
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00005996#if defined(FEAT_VIMINFO) || defined(FEAT_BROWSE) || \
Bram Moolenaara0174af2008-01-02 20:08:25 +00005997 defined(FEAT_QUICKFIX) || defined(FEAT_AUTOCMD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005998/*
5999 * Try to find a shortname by comparing the fullname with the current
6000 * directory.
Bram Moolenaard089d9b2007-09-30 12:02:55 +00006001 * Returns "full_path" or pointer into "full_path" if shortened.
6002 */
6003 char_u *
6004shorten_fname1(full_path)
6005 char_u *full_path;
6006{
Bram Moolenaard9462e32011-04-11 21:35:11 +02006007 char_u *dirname;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00006008 char_u *p = full_path;
6009
Bram Moolenaard9462e32011-04-11 21:35:11 +02006010 dirname = alloc(MAXPATHL);
6011 if (dirname == NULL)
6012 return full_path;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00006013 if (mch_dirname(dirname, MAXPATHL) == OK)
6014 {
6015 p = shorten_fname(full_path, dirname);
6016 if (p == NULL || *p == NUL)
6017 p = full_path;
6018 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02006019 vim_free(dirname);
Bram Moolenaard089d9b2007-09-30 12:02:55 +00006020 return p;
6021}
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00006022#endif
Bram Moolenaard089d9b2007-09-30 12:02:55 +00006023
6024/*
6025 * Try to find a shortname by comparing the fullname with the current
6026 * directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006027 * Returns NULL if not shorter name possible, pointer into "full_path"
6028 * otherwise.
6029 */
6030 char_u *
6031shorten_fname(full_path, dir_name)
6032 char_u *full_path;
6033 char_u *dir_name;
6034{
6035 int len;
6036 char_u *p;
6037
6038 if (full_path == NULL)
6039 return NULL;
6040 len = (int)STRLEN(dir_name);
6041 if (fnamencmp(dir_name, full_path, len) == 0)
6042 {
6043 p = full_path + len;
6044#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
6045 /*
6046 * MSDOS: when a file is in the root directory, dir_name will end in a
6047 * slash, since C: by itself does not define a specific dir. In this
6048 * case p may already be correct. <negri>
6049 */
6050 if (!((len > 2) && (*(p - 2) == ':')))
6051#endif
6052 {
6053 if (vim_ispathsep(*p))
6054 ++p;
6055#ifndef VMS /* the path separator is always part of the path */
6056 else
6057 p = NULL;
6058#endif
6059 }
6060 }
6061#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
6062 /*
6063 * When using a file in the current drive, remove the drive name:
6064 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
6065 * a floppy from "A:\dir" to "B:\dir".
6066 */
6067 else if (len > 3
6068 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
6069 && full_path[1] == ':'
6070 && vim_ispathsep(full_path[2]))
6071 p = full_path + 2;
6072#endif
6073 else
6074 p = NULL;
6075 return p;
6076}
6077
6078/*
6079 * Shorten filenames for all buffers.
6080 * When "force" is TRUE: Use full path from now on for files currently being
6081 * edited, both for file name and swap file name. Try to shorten the file
6082 * names a bit, if safe to do so.
6083 * When "force" is FALSE: Only try to shorten absolute file names.
6084 * For buffers that have buftype "nofile" or "scratch": never change the file
6085 * name.
6086 */
6087 void
6088shorten_fnames(force)
6089 int force;
6090{
6091 char_u dirname[MAXPATHL];
6092 buf_T *buf;
6093 char_u *p;
6094
6095 mch_dirname(dirname, MAXPATHL);
6096 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
6097 {
6098 if (buf->b_fname != NULL
6099#ifdef FEAT_QUICKFIX
6100 && !bt_nofile(buf)
6101#endif
6102 && !path_with_url(buf->b_fname)
6103 && (force
6104 || buf->b_sfname == NULL
6105 || mch_isFullName(buf->b_sfname)))
6106 {
6107 vim_free(buf->b_sfname);
6108 buf->b_sfname = NULL;
6109 p = shorten_fname(buf->b_ffname, dirname);
6110 if (p != NULL)
6111 {
6112 buf->b_sfname = vim_strsave(p);
6113 buf->b_fname = buf->b_sfname;
6114 }
6115 if (p == NULL || buf->b_fname == NULL)
6116 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006117 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006118
6119 /* Always make the swap file name a full path, a "nofile" buffer may
6120 * also have a swap file. */
6121 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122 }
6123#ifdef FEAT_WINDOWS
6124 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006125 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006126#endif
6127}
6128
6129#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
6130 || defined(FEAT_GUI_MSWIN) \
6131 || defined(FEAT_GUI_MAC) \
6132 || defined(PROTO)
6133/*
6134 * Shorten all filenames in "fnames[count]" by current directory.
6135 */
6136 void
6137shorten_filenames(fnames, count)
6138 char_u **fnames;
6139 int count;
6140{
6141 int i;
6142 char_u dirname[MAXPATHL];
6143 char_u *p;
6144
6145 if (fnames == NULL || count < 1)
6146 return;
6147 mch_dirname(dirname, sizeof(dirname));
6148 for (i = 0; i < count; ++i)
6149 {
6150 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
6151 {
6152 /* shorten_fname() returns pointer in given "fnames[i]". If free
6153 * "fnames[i]" first, "p" becomes invalid. So we need to copy
6154 * "p" first then free fnames[i]. */
6155 p = vim_strsave(p);
6156 vim_free(fnames[i]);
6157 fnames[i] = p;
6158 }
6159 }
6160}
6161#endif
6162
6163/*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006164 * add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165 * fo_o_h.ext for MSDOS or when shortname option set.
6166 *
6167 * Assumed that fname is a valid name found in the filesystem we assure that
6168 * the return value is a different name and ends in 'ext'.
6169 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
6170 * characters otherwise.
6171 * Space for the returned name is allocated, must be freed later.
6172 * Returns NULL when out of memory.
6173 */
6174 char_u *
6175modname(fname, ext, prepend_dot)
6176 char_u *fname, *ext;
6177 int prepend_dot; /* may prepend a '.' to file name */
6178{
6179 return buf_modname(
6180#ifdef SHORT_FNAME
6181 TRUE,
6182#else
6183 (curbuf->b_p_sn || curbuf->b_shortname),
6184#endif
6185 fname, ext, prepend_dot);
6186}
6187
6188 char_u *
6189buf_modname(shortname, fname, ext, prepend_dot)
6190 int shortname; /* use 8.3 file name */
6191 char_u *fname, *ext;
6192 int prepend_dot; /* may prepend a '.' to file name */
6193{
6194 char_u *retval;
6195 char_u *s;
6196 char_u *e;
6197 char_u *ptr;
6198 int fnamelen, extlen;
6199
6200 extlen = (int)STRLEN(ext);
6201
6202 /*
6203 * If there is no file name we must get the name of the current directory
6204 * (we need the full path in case :cd is used).
6205 */
6206 if (fname == NULL || *fname == NUL)
6207 {
6208 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
6209 if (retval == NULL)
6210 return NULL;
6211 if (mch_dirname(retval, MAXPATHL) == FAIL ||
6212 (fnamelen = (int)STRLEN(retval)) == 0)
6213 {
6214 vim_free(retval);
6215 return NULL;
6216 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006217 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006218 {
6219 retval[fnamelen++] = PATHSEP;
6220 retval[fnamelen] = NUL;
6221 }
6222#ifndef SHORT_FNAME
6223 prepend_dot = FALSE; /* nothing to prepend a dot to */
6224#endif
6225 }
6226 else
6227 {
6228 fnamelen = (int)STRLEN(fname);
6229 retval = alloc((unsigned)(fnamelen + extlen + 3));
6230 if (retval == NULL)
6231 return NULL;
6232 STRCPY(retval, fname);
6233#ifdef VMS
6234 vms_remove_version(retval); /* we do not need versions here */
6235#endif
6236 }
6237
6238 /*
6239 * search backwards until we hit a '/', '\' or ':' replacing all '.'
6240 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
6241 * Then truncate what is after the '/', '\' or ':' to 8 characters for
6242 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
6243 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006244 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 if (*ext == '.'
Bram Moolenaare60acc12011-05-10 16:41:25 +02006247#ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248 && (!USE_LONG_FNAME || shortname)
Bram Moolenaare60acc12011-05-10 16:41:25 +02006249#else
6250# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251 && shortname
6252# endif
Bram Moolenaare60acc12011-05-10 16:41:25 +02006253#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254 )
6255 if (*ptr == '.') /* replace '.' by '_' */
6256 *ptr = '_';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006257 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006258 {
6259 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006260 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006261 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006262 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006263
6264 /* the file name has at most BASENAMELEN characters. */
6265#ifndef SHORT_FNAME
6266 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
6267 ptr[BASENAMELEN] = '\0';
6268#endif
6269
6270 s = ptr + STRLEN(ptr);
6271
6272 /*
6273 * For 8.3 file names we may have to reduce the length.
6274 */
6275#ifdef USE_LONG_FNAME
6276 if (!USE_LONG_FNAME || shortname)
6277#else
6278# ifndef SHORT_FNAME
6279 if (shortname)
6280# endif
6281#endif
6282 {
6283 /*
6284 * If there is no file name, or the file name ends in '/', and the
6285 * extension starts with '.', put a '_' before the dot, because just
6286 * ".ext" is invalid.
6287 */
6288 if (fname == NULL || *fname == NUL
6289 || vim_ispathsep(fname[STRLEN(fname) - 1]))
6290 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 *s++ = '_';
6293 }
6294 /*
6295 * If the extension starts with '.', truncate the base name at 8
6296 * characters
6297 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298 else if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 {
Bram Moolenaar78a15312009-05-15 19:33:18 +00006300 if ((size_t)(s - ptr) > (size_t)8)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006301 {
6302 s = ptr + 8;
6303 *s = '\0';
6304 }
6305 }
6306 /*
6307 * If the extension doesn't start with '.', and the file name
6308 * doesn't have an extension yet, append a '.'
6309 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006310 else if ((e = vim_strchr(ptr, '.')) == NULL)
6311 *s++ = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006312 /*
6313 * If the extension doesn't start with '.', and there already is an
Bram Moolenaar7263a772007-05-10 17:35:54 +00006314 * extension, it may need to be truncated
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315 */
6316 else if ((int)STRLEN(e) + extlen > 4)
6317 s = e + 4 - extlen;
6318 }
6319#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
6320 /*
6321 * If there is no file name, and the extension starts with '.', put a
6322 * '_' before the dot, because just ".ext" may be invalid if it's on a
6323 * FAT partition, and on HPFS it doesn't matter.
6324 */
6325 else if ((fname == NULL || *fname == NUL) && *ext == '.')
6326 *s++ = '_';
6327#endif
6328
6329 /*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006330 * Append the extension.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006331 * ext can start with '.' and cannot exceed 3 more characters.
6332 */
6333 STRCPY(s, ext);
6334
6335#ifndef SHORT_FNAME
6336 /*
6337 * Prepend the dot.
6338 */
Bram Moolenaare60acc12011-05-10 16:41:25 +02006339 if (prepend_dot && !shortname && *(e = gettail(retval)) != '.'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006340#ifdef USE_LONG_FNAME
6341 && USE_LONG_FNAME
6342#endif
6343 )
6344 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006345 STRMOVE(e + 1, e);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346 *e = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006347 }
6348#endif
6349
6350 /*
6351 * Check that, after appending the extension, the file name is really
6352 * different.
6353 */
6354 if (fname != NULL && STRCMP(fname, retval) == 0)
6355 {
6356 /* we search for a character that can be replaced by '_' */
6357 while (--s >= ptr)
6358 {
6359 if (*s != '_')
6360 {
6361 *s = '_';
6362 break;
6363 }
6364 }
6365 if (s < ptr) /* fname was "________.<ext>", how tricky! */
6366 *ptr = 'v';
6367 }
6368 return retval;
6369}
6370
6371/*
6372 * Like fgets(), but if the file line is too long, it is truncated and the
6373 * rest of the line is thrown away. Returns TRUE for end-of-file.
6374 */
6375 int
6376vim_fgets(buf, size, fp)
6377 char_u *buf;
6378 int size;
6379 FILE *fp;
6380{
6381 char *eof;
6382#define FGETS_SIZE 200
6383 char tbuf[FGETS_SIZE];
6384
6385 buf[size - 2] = NUL;
6386#ifdef USE_CR
6387 eof = fgets_cr((char *)buf, size, fp);
6388#else
6389 eof = fgets((char *)buf, size, fp);
6390#endif
6391 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
6392 {
6393 buf[size - 1] = NUL; /* Truncate the line */
6394
6395 /* Now throw away the rest of the line: */
6396 do
6397 {
6398 tbuf[FGETS_SIZE - 2] = NUL;
6399#ifdef USE_CR
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00006400 ignoredp = fgets_cr((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006401#else
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00006402 ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006403#endif
6404 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
6405 }
6406 return (eof == NULL);
6407}
6408
6409#if defined(USE_CR) || defined(PROTO)
6410/*
6411 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
6412 * Returns TRUE for end-of-file.
6413 * Only used for the Mac, because it's much slower than vim_fgets().
6414 */
6415 int
6416tag_fgets(buf, size, fp)
6417 char_u *buf;
6418 int size;
6419 FILE *fp;
6420{
6421 int i = 0;
6422 int c;
6423 int eof = FALSE;
6424
6425 for (;;)
6426 {
6427 c = fgetc(fp);
6428 if (c == EOF)
6429 {
6430 eof = TRUE;
6431 break;
6432 }
6433 if (c == '\r')
6434 {
6435 /* Always store a NL for end-of-line. */
6436 if (i < size - 1)
6437 buf[i++] = '\n';
6438 c = fgetc(fp);
6439 if (c != '\n') /* Macintosh format: single CR. */
6440 ungetc(c, fp);
6441 break;
6442 }
6443 if (i < size - 1)
6444 buf[i++] = c;
6445 if (c == '\n')
6446 break;
6447 }
6448 buf[i] = NUL;
6449 return eof;
6450}
6451#endif
6452
6453/*
6454 * rename() only works if both files are on the same file system, this
6455 * function will (attempts to?) copy the file across if rename fails -- webb
6456 * Return -1 for failure, 0 for success.
6457 */
6458 int
6459vim_rename(from, to)
6460 char_u *from;
6461 char_u *to;
6462{
6463 int fd_in;
6464 int fd_out;
6465 int n;
6466 char *errmsg = NULL;
6467 char *buffer;
6468#ifdef AMIGA
6469 BPTR flock;
6470#endif
6471 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006472 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006473#ifdef HAVE_ACL
6474 vim_acl_T acl; /* ACL from original file */
6475#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006476#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
6477 int use_tmp_file = FALSE;
6478#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006479
6480 /*
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006481 * When the names are identical, there is nothing to do. When they refer
6482 * to the same file (ignoring case and slash/backslash differences) but
6483 * the file name differs we need to go through a temp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006484 */
6485 if (fnamecmp(from, to) == 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006486 {
6487#ifdef CASE_INSENSITIVE_FILENAME
6488 if (STRCMP(gettail(from), gettail(to)) != 0)
6489 use_tmp_file = TRUE;
6490 else
6491#endif
6492 return 0;
6493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006494
6495 /*
6496 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
6497 */
6498 if (mch_stat((char *)from, &st) < 0)
6499 return -1;
6500
Bram Moolenaar3576da72008-12-30 15:15:57 +00006501#ifdef UNIX
6502 {
6503 struct stat st_to;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006504
6505 /* It's possible for the source and destination to be the same file.
6506 * This happens when "from" and "to" differ in case and are on a FAT32
6507 * filesystem. In that case go through a temp file name. */
6508 if (mch_stat((char *)to, &st_to) >= 0
6509 && st.st_dev == st_to.st_dev
6510 && st.st_ino == st_to.st_ino)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006511 use_tmp_file = TRUE;
6512 }
6513#endif
Bram Moolenaar1c32dff2011-05-05 16:41:24 +02006514#ifdef WIN3264
6515 {
6516 BY_HANDLE_FILE_INFORMATION info1, info2;
6517
6518 /* It's possible for the source and destination to be the same file.
6519 * In that case go through a temp file name. This makes rename("foo",
6520 * "./foo") a no-op (in a complicated way). */
6521 if (win32_fileinfo(from, &info1) == FILEINFO_OK
6522 && win32_fileinfo(to, &info2) == FILEINFO_OK
6523 && info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
6524 && info1.nFileIndexHigh == info2.nFileIndexHigh
6525 && info1.nFileIndexLow == info2.nFileIndexLow)
6526 use_tmp_file = TRUE;
6527 }
6528#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006529
6530#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
6531 if (use_tmp_file)
6532 {
6533 char tempname[MAXPATHL + 1];
6534
6535 /*
6536 * Find a name that doesn't exist and is in the same directory.
6537 * Rename "from" to "tempname" and then rename "tempname" to "to".
6538 */
6539 if (STRLEN(from) >= MAXPATHL - 5)
6540 return -1;
6541 STRCPY(tempname, from);
6542 for (n = 123; n < 99999; ++n)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006543 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006544 sprintf((char *)gettail((char_u *)tempname), "%d", n);
6545 if (mch_stat(tempname, &st) < 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006546 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006547 if (mch_rename((char *)from, tempname) == 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006548 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006549 if (mch_rename(tempname, (char *)to) == 0)
6550 return 0;
6551 /* Strange, the second step failed. Try moving the
6552 * file back and return failure. */
6553 mch_rename(tempname, (char *)from);
Bram Moolenaar3576da72008-12-30 15:15:57 +00006554 return -1;
6555 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006556 /* If it fails for one temp name it will most likely fail
6557 * for any temp name, give up. */
6558 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006559 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006560 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006561 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006562 }
6563#endif
6564
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565 /*
6566 * Delete the "to" file, this is required on some systems to make the
6567 * mch_rename() work, on other systems it makes sure that we don't have
6568 * two files when the mch_rename() fails.
6569 */
6570
6571#ifdef AMIGA
6572 /*
6573 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
6574 * that the name of the "to" file is the same as the "from" file, even
Bram Moolenaar7263a772007-05-10 17:35:54 +00006575 * though the names are different. To avoid the chance of accidentally
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576 * deleting the "from" file (horror!) we lock it during the remove.
6577 *
6578 * When used for making a backup before writing the file: This should not
6579 * happen with ":w", because startscript() should detect this problem and
6580 * set buf->b_shortname, causing modname() to return a correct ".bak" file
6581 * name. This problem does exist with ":w filename", but then the
6582 * original file will be somewhere else so the backup isn't really
6583 * important. If autoscripting is off the rename may fail.
6584 */
6585 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
6586#endif
6587 mch_remove(to);
6588#ifdef AMIGA
6589 if (flock)
6590 UnLock(flock);
6591#endif
6592
6593 /*
6594 * First try a normal rename, return if it works.
6595 */
6596 if (mch_rename((char *)from, (char *)to) == 0)
6597 return 0;
6598
6599 /*
6600 * Rename() failed, try copying the file.
6601 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006602 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006603#ifdef HAVE_ACL
6604 /* For systems that support ACL: get the ACL from the original file. */
6605 acl = mch_get_acl(from);
6606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006607 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6608 if (fd_in == -1)
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006609 {
6610#ifdef HAVE_ACL
6611 mch_free_acl(acl);
6612#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006613 return -1;
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006614 }
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006615
6616 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006617 fd_out = mch_open((char *)to,
6618 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006619 if (fd_out == -1)
6620 {
6621 close(fd_in);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006622#ifdef HAVE_ACL
6623 mch_free_acl(acl);
6624#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006625 return -1;
6626 }
6627
6628 buffer = (char *)alloc(BUFSIZE);
6629 if (buffer == NULL)
6630 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006631 close(fd_out);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006632 close(fd_in);
6633#ifdef HAVE_ACL
6634 mch_free_acl(acl);
6635#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006636 return -1;
6637 }
6638
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01006639 while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0)
6640 if (write_eintr(fd_out, buffer, n) != n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006641 {
6642 errmsg = _("E208: Error writing to \"%s\"");
6643 break;
6644 }
6645
6646 vim_free(buffer);
6647 close(fd_in);
6648 if (close(fd_out) < 0)
6649 errmsg = _("E209: Error closing \"%s\"");
6650 if (n < 0)
6651 {
6652 errmsg = _("E210: Error reading \"%s\"");
6653 to = from;
6654 }
Bram Moolenaar7263a772007-05-10 17:35:54 +00006655#ifndef UNIX /* for Unix mch_open() already set the permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006656 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006657#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006658#ifdef HAVE_ACL
6659 mch_set_acl(to, acl);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006660 mch_free_acl(acl);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006661#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662 if (errmsg != NULL)
6663 {
6664 EMSG2(errmsg, to);
6665 return -1;
6666 }
6667 mch_remove(from);
6668 return 0;
6669}
6670
6671static int already_warned = FALSE;
6672
6673/*
6674 * Check if any not hidden buffer has been changed.
6675 * Postpone the check if there are characters in the stuff buffer, a global
6676 * command is being executed, a mapping is being executed or an autocommand is
6677 * busy.
6678 * Returns TRUE if some message was written (screen should be redrawn and
6679 * cursor positioned).
6680 */
6681 int
6682check_timestamps(focus)
6683 int focus; /* called for GUI focus event */
6684{
6685 buf_T *buf;
6686 int didit = 0;
6687 int n;
6688
6689 /* Don't check timestamps while system() or another low-level function may
6690 * cause us to lose and gain focus. */
6691 if (no_check_timestamps > 0)
6692 return FALSE;
6693
6694 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6695 * event and we would keep on checking if the file is steadily growing.
6696 * Do check again after typing something. */
6697 if (focus && did_check_timestamps)
6698 {
6699 need_check_timestamps = TRUE;
6700 return FALSE;
6701 }
6702
6703 if (!stuff_empty() || global_busy || !typebuf_typed()
6704#ifdef FEAT_AUTOCMD
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006705 || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006706#endif
6707 )
6708 need_check_timestamps = TRUE; /* check later */
6709 else
6710 {
6711 ++no_wait_return;
6712 did_check_timestamps = TRUE;
6713 already_warned = FALSE;
6714 for (buf = firstbuf; buf != NULL; )
6715 {
6716 /* Only check buffers in a window. */
6717 if (buf->b_nwindows > 0)
6718 {
6719 n = buf_check_timestamp(buf, focus);
6720 if (didit < n)
6721 didit = n;
6722 if (n > 0 && !buf_valid(buf))
6723 {
6724 /* Autocommands have removed the buffer, start at the
6725 * first one again. */
6726 buf = firstbuf;
6727 continue;
6728 }
6729 }
6730 buf = buf->b_next;
6731 }
6732 --no_wait_return;
6733 need_check_timestamps = FALSE;
6734 if (need_wait_return && didit == 2)
6735 {
6736 /* make sure msg isn't overwritten */
6737 msg_puts((char_u *)"\n");
6738 out_flush();
6739 }
6740 }
6741 return didit;
6742}
6743
6744/*
6745 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6746 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6747 * empty.
6748 */
6749 static int
6750move_lines(frombuf, tobuf)
6751 buf_T *frombuf;
6752 buf_T *tobuf;
6753{
6754 buf_T *tbuf = curbuf;
6755 int retval = OK;
6756 linenr_T lnum;
6757 char_u *p;
6758
6759 /* Copy the lines in "frombuf" to "tobuf". */
6760 curbuf = tobuf;
6761 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6762 {
6763 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6764 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6765 {
6766 vim_free(p);
6767 retval = FAIL;
6768 break;
6769 }
6770 vim_free(p);
6771 }
6772
6773 /* Delete all the lines in "frombuf". */
6774 if (retval != FAIL)
6775 {
6776 curbuf = frombuf;
Bram Moolenaar9460b9d2007-01-09 14:37:01 +00006777 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
6778 if (ml_delete(lnum, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006779 {
6780 /* Oops! We could try putting back the saved lines, but that
6781 * might fail again... */
6782 retval = FAIL;
6783 break;
6784 }
6785 }
6786
6787 curbuf = tbuf;
6788 return retval;
6789}
6790
6791/*
6792 * Check if buffer "buf" has been changed.
6793 * Also check if the file for a new buffer unexpectedly appeared.
6794 * return 1 if a changed buffer was found.
6795 * return 2 if a message has been displayed.
6796 * return 0 otherwise.
6797 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006798 int
6799buf_check_timestamp(buf, focus)
6800 buf_T *buf;
Bram Moolenaar78a15312009-05-15 19:33:18 +00006801 int focus UNUSED; /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006802{
6803 struct stat st;
6804 int stat_res;
6805 int retval = 0;
6806 char_u *path;
6807 char_u *tbuf;
6808 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006809 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006810 int helpmesg = FALSE;
6811 int reload = FALSE;
6812#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6813 int can_reload = FALSE;
6814#endif
Bram Moolenaar914703b2010-05-31 21:59:46 +02006815 off_t orig_size = buf->b_orig_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006816 int orig_mode = buf->b_orig_mode;
6817#ifdef FEAT_GUI
6818 int save_mouse_correct = need_mouse_correct;
6819#endif
6820#ifdef FEAT_AUTOCMD
6821 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006822 int n;
6823 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006824#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006825 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826
6827 /* If there is no file name, the buffer is not loaded, 'buftype' is
6828 * set, we are in the middle of a save or being called recursively: ignore
6829 * this buffer. */
6830 if (buf->b_ffname == NULL
6831 || buf->b_ml.ml_mfp == NULL
6832#if defined(FEAT_QUICKFIX)
6833 || *buf->b_p_bt != NUL
6834#endif
6835 || buf->b_saving
6836#ifdef FEAT_AUTOCMD
6837 || busy
6838#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006839#ifdef FEAT_NETBEANS_INTG
6840 || isNetbeansBuffer(buf)
6841#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006842 )
6843 return 0;
6844
6845 if ( !(buf->b_flags & BF_NOTEDITED)
6846 && buf->b_mtime != 0
6847 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6848 || time_differs((long)st.st_mtime, buf->b_mtime)
6849#ifdef HAVE_ST_MODE
6850 || (int)st.st_mode != buf->b_orig_mode
6851#else
6852 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6853#endif
6854 ))
6855 {
6856 retval = 1;
6857
Bram Moolenaar316059c2006-01-14 21:18:42 +00006858 /* set b_mtime to stop further warnings (e.g., when executing
6859 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 if (stat_res < 0)
6861 {
6862 buf->b_mtime = 0;
6863 buf->b_orig_size = 0;
6864 buf->b_orig_mode = 0;
6865 }
6866 else
6867 buf_store_time(buf, &st, buf->b_ffname);
6868
6869 /* Don't do anything for a directory. Might contain the file
6870 * explorer. */
6871 if (mch_isdir(buf->b_fname))
6872 ;
6873
6874 /*
6875 * If 'autoread' is set, the buffer has no changes and the file still
6876 * exists, reload the buffer. Use the buffer-local option value if it
6877 * was set, the global option value otherwise.
6878 */
6879 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6880 && !bufIsChanged(buf) && stat_res >= 0)
6881 reload = TRUE;
6882 else
6883 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006884 if (stat_res < 0)
6885 reason = "deleted";
6886 else if (bufIsChanged(buf))
6887 reason = "conflict";
6888 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6889 reason = "changed";
6890 else if (orig_mode != buf->b_orig_mode)
6891 reason = "mode";
6892 else
6893 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006894
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006895#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006896 /*
6897 * Only give the warning if there are no FileChangedShell
6898 * autocommands.
6899 * Avoid being called recursively by setting "busy".
6900 */
6901 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006902# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006903 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6904 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006905# endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006906 ++allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6908 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006909 --allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 busy = FALSE;
6911 if (n)
6912 {
6913 if (!buf_valid(buf))
6914 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006915# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006916 s = get_vim_var_str(VV_FCS_CHOICE);
6917 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6918 reload = TRUE;
6919 else if (STRCMP(s, "ask") == 0)
6920 n = FALSE;
6921 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006922# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006923 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006925 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926#endif
6927 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006928 if (*reason == 'd')
6929 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 else
6931 {
6932 helpmesg = TRUE;
6933#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6934 can_reload = TRUE;
6935#endif
6936 /*
6937 * Check if the file contents really changed to avoid
6938 * giving a warning when only the timestamp was set (e.g.,
6939 * checked out of CVS). Always warn when the buffer was
6940 * changed.
6941 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006942 if (reason[2] == 'n')
6943 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006944 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006945 mesg2 = _("See \":help W12\" for more info.");
6946 }
6947 else if (reason[1] == 'h')
6948 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006949 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006950 mesg2 = _("See \":help W11\" for more info.");
6951 }
6952 else if (*reason == 'm')
6953 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006954 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006955 mesg2 = _("See \":help W16\" for more info.");
6956 }
Bram Moolenaar85388b52009-06-24 09:58:32 +00006957 else
6958 /* Only timestamp changed, store it to avoid a warning
6959 * in check_mtime() later. */
6960 buf->b_mtime_read = buf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 }
6962 }
6963 }
6964
6965 }
6966 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6967 && vim_fexists(buf->b_ffname))
6968 {
6969 retval = 1;
6970 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6971 buf->b_flags |= BF_NEW_W;
6972#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6973 can_reload = TRUE;
6974#endif
6975 }
6976
6977 if (mesg != NULL)
6978 {
6979 path = home_replace_save(buf, buf->b_fname);
6980 if (path != NULL)
6981 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006982 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006983 mesg2 = "";
6984 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6985 + STRLEN(mesg2) + 2));
6986 sprintf((char *)tbuf, mesg, path);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006987#ifdef FEAT_EVAL
6988 /* Set warningmsg here, before the unimportant and output-specific
6989 * mesg2 has been appended. */
6990 set_vim_var_string(VV_WARNINGMSG, tbuf, -1);
6991#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006992#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6993 if (can_reload)
6994 {
6995 if (*mesg2 != NUL)
6996 {
6997 STRCAT(tbuf, "\n");
6998 STRCAT(tbuf, mesg2);
6999 }
7000 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01007001 (char_u *)_("&OK\n&Load File"), 1, NULL, TRUE) == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007002 reload = TRUE;
7003 }
7004 else
7005#endif
7006 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
7007 {
7008 if (*mesg2 != NUL)
7009 {
7010 STRCAT(tbuf, "; ");
7011 STRCAT(tbuf, mesg2);
7012 }
7013 EMSG(tbuf);
7014 retval = 2;
7015 }
7016 else
7017 {
Bram Moolenaared203462004-06-16 11:19:22 +00007018# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00007019 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00007020# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007021 {
7022 msg_start();
7023 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
7024 if (*mesg2 != NUL)
7025 msg_puts_attr((char_u *)mesg2,
7026 hl_attr(HLF_W) + MSG_HIST);
7027 msg_clr_eos();
7028 (void)msg_end();
7029 if (emsg_silent == 0)
7030 {
7031 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00007032# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00007034# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007035 /* give the user some time to think about it */
7036 ui_delay(1000L, TRUE);
7037
7038 /* don't redraw and erase the message */
7039 redraw_cmdline = FALSE;
7040 }
7041 }
7042 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007043 }
7044
7045 vim_free(path);
7046 vim_free(tbuf);
7047 }
7048 }
7049
7050 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007051 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00007052 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053
Bram Moolenaar56718732006-03-15 22:53:57 +00007054#ifdef FEAT_AUTOCMD
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007055 /* Trigger FileChangedShell when the file was changed in any way. */
7056 if (buf_valid(buf) && retval != 0)
Bram Moolenaar56718732006-03-15 22:53:57 +00007057 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
7058 buf->b_fname, buf->b_fname, FALSE, buf);
7059#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007060#ifdef FEAT_GUI
7061 /* restore this in case an autocommand has set it; it would break
7062 * 'mousefocus' */
7063 need_mouse_correct = save_mouse_correct;
7064#endif
7065
7066 return retval;
7067}
7068
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007069/*
7070 * Reload a buffer that is already loaded.
7071 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00007072 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
7073 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007074 */
7075 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00007076buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007077 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00007078 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007079{
7080 exarg_T ea;
7081 pos_T old_cursor;
7082 linenr_T old_topline;
7083 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007084 buf_T *savebuf;
7085 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007086 aco_save_T aco;
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007087 int flags = READ_NEW;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007088
7089 /* set curwin/curbuf for "buf" and save some things */
7090 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007091
7092 /* We only want to read the text from the file, not reset the syntax
7093 * highlighting, clear marks, diff status, etc. Force the fileformat
7094 * and encoding to be the same. */
7095 if (prep_exarg(&ea, buf) == OK)
7096 {
7097 old_cursor = curwin->w_cursor;
7098 old_topline = curwin->w_topline;
7099
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007100 if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007101 {
7102 /* Save all the text, so that the reload can be undone.
7103 * Sync first so that this is a separate undo-able action. */
7104 u_sync(FALSE);
7105 saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
7106 flags |= READ_KEEP_UNDO;
7107 }
7108
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007109 /*
7110 * To behave like when a new file is edited (matters for
7111 * BufReadPost autocommands) we first need to delete the current
7112 * buffer contents. But if reading the file fails we should keep
7113 * the old contents. Can't use memory only, the file might be
7114 * too big. Use a hidden buffer to move the buffer contents to.
7115 */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007116 if (bufempty() || saved == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007117 savebuf = NULL;
7118 else
7119 {
7120 /* Allocate a buffer without putting it in the buffer list. */
7121 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar8424a622006-04-19 21:23:36 +00007122 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007123 {
7124 /* Open the memline. */
7125 curbuf = savebuf;
7126 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00007127 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007128 curbuf = buf;
7129 curwin->w_buffer = buf;
7130 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00007131 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007132 || move_lines(buf, savebuf) == FAIL)
7133 {
7134 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
7135 buf->b_fname);
7136 saved = FAIL;
7137 }
7138 }
7139
7140 if (saved == OK)
7141 {
7142 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
7143#ifdef FEAT_AUTOCMD
7144 keep_filetype = TRUE; /* don't detect 'filetype' */
7145#endif
7146 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
7147 (linenr_T)0,
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007148 (linenr_T)MAXLNUM, &ea, flags) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007149 {
7150#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
7151 if (!aborting())
7152#endif
7153 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar8424a622006-04-19 21:23:36 +00007154 if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007155 {
7156 /* Put the text back from the save buffer. First
7157 * delete any lines that readfile() added. */
7158 while (!bufempty())
Bram Moolenaar8424a622006-04-19 21:23:36 +00007159 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007160 break;
7161 (void)move_lines(savebuf, buf);
7162 }
7163 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007164 else if (buf == curbuf) /* "buf" still valid */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007165 {
7166 /* Mark the buffer as unmodified and free undo info. */
7167 unchanged(buf, TRUE);
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007168 if ((flags & READ_KEEP_UNDO) == 0)
7169 {
7170 u_blockfree(buf);
7171 u_clearall(buf);
7172 }
7173 else
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007174 {
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007175 /* Mark all undo states as changed. */
7176 u_unchanged(curbuf);
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007177 }
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007178 }
7179 }
7180 vim_free(ea.cmd);
7181
Bram Moolenaar8424a622006-04-19 21:23:36 +00007182 if (savebuf != NULL && buf_valid(savebuf))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007183 wipe_buffer(savebuf, FALSE);
7184
7185#ifdef FEAT_DIFF
7186 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00007187 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007188#endif
7189
7190 /* Restore the topline and cursor position and check it (lines may
7191 * have been removed). */
7192 if (old_topline > curbuf->b_ml.ml_line_count)
7193 curwin->w_topline = curbuf->b_ml.ml_line_count;
7194 else
7195 curwin->w_topline = old_topline;
7196 curwin->w_cursor = old_cursor;
7197 check_cursor();
7198 update_topline();
7199#ifdef FEAT_AUTOCMD
7200 keep_filetype = FALSE;
7201#endif
7202#ifdef FEAT_FOLDING
7203 {
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007204 win_T *wp;
7205 tabpage_T *tp;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007206
7207 /* Update folds unless they are defined manually. */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007208 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007209 if (wp->w_buffer == curwin->w_buffer
7210 && !foldmethodIsManual(wp))
7211 foldUpdateAll(wp);
7212 }
7213#endif
7214 /* If the mode didn't change and 'readonly' was set, keep the old
7215 * value; the user probably used the ":view" command. But don't
7216 * reset it, might have had a read error. */
7217 if (orig_mode == curbuf->b_orig_mode)
7218 curbuf->b_p_ro |= old_ro;
7219 }
7220
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007221 /* restore curwin/curbuf and a few other things */
7222 aucmd_restbuf(&aco);
7223 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007224}
7225
Bram Moolenaar071d4272004-06-13 20:20:40 +00007226 void
7227buf_store_time(buf, st, fname)
7228 buf_T *buf;
7229 struct stat *st;
Bram Moolenaar78a15312009-05-15 19:33:18 +00007230 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007231{
7232 buf->b_mtime = (long)st->st_mtime;
Bram Moolenaar914703b2010-05-31 21:59:46 +02007233 buf->b_orig_size = st->st_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234#ifdef HAVE_ST_MODE
7235 buf->b_orig_mode = (int)st->st_mode;
7236#else
7237 buf->b_orig_mode = mch_getperm(fname);
7238#endif
7239}
7240
7241/*
7242 * Adjust the line with missing eol, used for the next write.
7243 * Used for do_filter(), when the input lines for the filter are deleted.
7244 */
7245 void
7246write_lnum_adjust(offset)
7247 linenr_T offset;
7248{
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01007249 if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */
7250 curbuf->b_no_eol_lnum += offset;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007251}
7252
7253#if defined(TEMPDIRNAMES) || defined(PROTO)
7254static long temp_count = 0; /* Temp filename counter. */
7255
7256/*
7257 * Delete the temp directory and all files it contains.
7258 */
7259 void
7260vim_deltempdir()
7261{
7262 char_u **files;
7263 int file_count;
7264 int i;
7265
7266 if (vim_tempdir != NULL)
7267 {
7268 sprintf((char *)NameBuff, "%s*", vim_tempdir);
7269 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
7270 EW_DIR|EW_FILE|EW_SILENT) == OK)
7271 {
7272 for (i = 0; i < file_count; ++i)
7273 mch_remove(files[i]);
7274 FreeWild(file_count, files);
7275 }
7276 gettail(NameBuff)[-1] = NUL;
7277 (void)mch_rmdir(NameBuff);
7278
7279 vim_free(vim_tempdir);
7280 vim_tempdir = NULL;
7281 }
7282}
7283#endif
7284
Bram Moolenaar4592dee2009-11-18 19:11:58 +00007285#ifdef TEMPDIRNAMES
Bram Moolenaar071d4272004-06-13 20:20:40 +00007286/*
Bram Moolenaareaf03392009-11-17 11:08:52 +00007287 * Directory "tempdir" was created. Expand this name to a full path and put
7288 * it in "vim_tempdir". This avoids that using ":cd" would confuse us.
7289 * "tempdir" must be no longer than MAXPATHL.
7290 */
7291 static void
7292vim_settempdir(tempdir)
7293 char_u *tempdir;
7294{
7295 char_u *buf;
7296
7297 buf = alloc((unsigned)MAXPATHL + 2);
7298 if (buf != NULL)
7299 {
7300 if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
7301 STRCPY(buf, tempdir);
7302# ifdef __EMX__
7303 if (vim_strchr(buf, '/') != NULL)
7304 STRCAT(buf, "/");
7305 else
7306# endif
7307 add_pathsep(buf);
7308 vim_tempdir = vim_strsave(buf);
7309 vim_free(buf);
7310 }
7311}
Bram Moolenaar4592dee2009-11-18 19:11:58 +00007312#endif
Bram Moolenaareaf03392009-11-17 11:08:52 +00007313
7314/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007315 * vim_tempname(): Return a unique name that can be used for a temp file.
7316 *
7317 * The temp file is NOT created.
7318 *
7319 * The returned pointer is to allocated memory.
7320 * The returned pointer is NULL if no valid name was found.
7321 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007322 char_u *
7323vim_tempname(extra_char)
Bram Moolenaar78a15312009-05-15 19:33:18 +00007324 int extra_char UNUSED; /* char to use in the name instead of '?' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007325{
7326#ifdef USE_TMPNAM
7327 char_u itmp[L_tmpnam]; /* use tmpnam() */
7328#else
7329 char_u itmp[TEMPNAMELEN];
7330#endif
7331
7332#ifdef TEMPDIRNAMES
7333 static char *(tempdirs[]) = {TEMPDIRNAMES};
7334 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007335# ifndef EEXIST
7336 struct stat st;
7337# endif
7338
7339 /*
7340 * This will create a directory for private use by this instance of Vim.
7341 * This is done once, and the same directory is used for all temp files.
7342 * This method avoids security problems because of symlink attacks et al.
7343 * It's also a bit faster, because we only need to check for an existing
7344 * file when creating the directory and not for each temp file.
7345 */
7346 if (vim_tempdir == NULL)
7347 {
7348 /*
7349 * Try the entries in TEMPDIRNAMES to create the temp directory.
7350 */
Bram Moolenaar78a15312009-05-15 19:33:18 +00007351 for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007352 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007353# ifndef HAVE_MKDTEMP
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007354 size_t itmplen;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007355 long nr;
7356 long off;
7357# endif
7358
Bram Moolenaar071d4272004-06-13 20:20:40 +00007359 /* expand $TMP, leave room for "/v1100000/999999999" */
7360 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
7361 if (mch_isdir(itmp)) /* directory exists */
7362 {
7363# ifdef __EMX__
7364 /* If $TMP contains a forward slash (perhaps using bash or
7365 * tcsh), don't add a backslash, use a forward slash!
7366 * Adding 2 backslashes didn't work. */
7367 if (vim_strchr(itmp, '/') != NULL)
7368 STRCAT(itmp, "/");
7369 else
7370# endif
7371 add_pathsep(itmp);
7372
Bram Moolenaareaf03392009-11-17 11:08:52 +00007373# ifdef HAVE_MKDTEMP
7374 /* Leave room for filename */
7375 STRCAT(itmp, "vXXXXXX");
7376 if (mkdtemp((char *)itmp) != NULL)
7377 vim_settempdir(itmp);
7378# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007379 /* Get an arbitrary number of up to 6 digits. When it's
7380 * unlikely that it already exists it will be faster,
7381 * otherwise it doesn't matter. The use of mkdir() avoids any
7382 * security problems because of the predictable number. */
7383 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007384 itmplen = STRLEN(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007385
7386 /* Try up to 10000 different values until we find a name that
7387 * doesn't exist. */
7388 for (off = 0; off < 10000L; ++off)
7389 {
7390 int r;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007391# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007392 mode_t umask_save;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007393# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007394
Bram Moolenaareaf03392009-11-17 11:08:52 +00007395 sprintf((char *)itmp + itmplen, "v%ld", nr + off);
7396# ifndef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397 /* If mkdir() does not set errno to EEXIST, check for
7398 * existing file here. There is a race condition then,
7399 * although it's fail-safe. */
7400 if (mch_stat((char *)itmp, &st) >= 0)
7401 continue;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007402# endif
7403# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007404 /* Make sure the umask doesn't remove the executable bit.
7405 * "repl" has been reported to use "177". */
7406 umask_save = umask(077);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007407# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007408 r = vim_mkdir(itmp, 0700);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007409# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007410 (void)umask(umask_save);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007411# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007412 if (r == 0)
7413 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007414 vim_settempdir(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007415 break;
7416 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007417# ifdef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007418 /* If the mkdir() didn't fail because the file/dir exists,
7419 * we probably can't create any dir here, try another
7420 * place. */
7421 if (errno != EEXIST)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007422# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007423 break;
7424 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007425# endif /* HAVE_MKDTEMP */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007426 if (vim_tempdir != NULL)
7427 break;
7428 }
7429 }
7430 }
7431
7432 if (vim_tempdir != NULL)
7433 {
7434 /* There is no need to check if the file exists, because we own the
7435 * directory and nobody else creates a file in it. */
7436 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
7437 return vim_strsave(itmp);
7438 }
7439
7440 return NULL;
7441
7442#else /* TEMPDIRNAMES */
7443
7444# ifdef WIN3264
7445 char szTempFile[_MAX_PATH + 1];
7446 char buf4[4];
7447 char_u *retval;
7448 char_u *p;
7449
7450 STRCPY(itmp, "");
7451 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
Bram Moolenaarb1891912011-02-09 14:47:03 +01007452 {
7453 szTempFile[0] = '.'; /* GetTempPath() failed, use current dir */
7454 szTempFile[1] = NUL;
7455 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007456 strcpy(buf4, "VIM");
7457 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
7458 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
7459 return NULL;
7460 /* GetTempFileName() will create the file, we don't want that */
7461 (void)DeleteFile(itmp);
7462
7463 /* Backslashes in a temp file name cause problems when filtering with
7464 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
7465 * didn't set 'shellslash'. */
7466 retval = vim_strsave(itmp);
7467 if (*p_shcf == '-' || p_ssl)
7468 for (p = retval; *p; ++p)
7469 if (*p == '\\')
7470 *p = '/';
7471 return retval;
7472
7473# else /* WIN3264 */
7474
7475# ifdef USE_TMPNAM
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007476 char_u *p;
7477
Bram Moolenaar071d4272004-06-13 20:20:40 +00007478 /* tmpnam() will make its own name */
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007479 p = tmpnam((char *)itmp);
7480 if (p == NULL || *p == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007481 return NULL;
7482# else
7483 char_u *p;
7484
7485# ifdef VMS_TEMPNAM
7486 /* mktemp() is not working on VMS. It seems to be
7487 * a do-nothing function. Therefore we use tempnam().
7488 */
7489 sprintf((char *)itmp, "VIM%c", extra_char);
7490 p = (char_u *)tempnam("tmp:", (char *)itmp);
7491 if (p != NULL)
7492 {
7493 /* VMS will use '.LOG' if we don't explicitly specify an extension,
7494 * and VIM will then be unable to find the file later */
7495 STRCPY(itmp, p);
7496 STRCAT(itmp, ".txt");
7497 free(p);
7498 }
7499 else
7500 return NULL;
7501# else
7502 STRCPY(itmp, TEMPNAME);
7503 if ((p = vim_strchr(itmp, '?')) != NULL)
7504 *p = extra_char;
7505 if (mktemp((char *)itmp) == NULL)
7506 return NULL;
7507# endif
7508# endif
7509
7510 return vim_strsave(itmp);
7511# endif /* WIN3264 */
7512#endif /* TEMPDIRNAMES */
7513}
7514
7515#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
7516/*
7517 * Convert all backslashes in fname to forward slashes in-place.
7518 */
7519 void
7520forward_slash(fname)
7521 char_u *fname;
7522{
7523 char_u *p;
7524
7525 for (p = fname; *p != NUL; ++p)
7526# ifdef FEAT_MBYTE
7527 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007528 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007529 ++p;
7530 else
7531# endif
7532 if (*p == '\\')
7533 *p = '/';
7534}
7535#endif
7536
7537
7538/*
7539 * Code for automatic commands.
7540 *
7541 * Only included when "FEAT_AUTOCMD" has been defined.
7542 */
7543
7544#if defined(FEAT_AUTOCMD) || defined(PROTO)
7545
7546/*
7547 * The autocommands are stored in a list for each event.
7548 * Autocommands for the same pattern, that are consecutive, are joined
7549 * together, to avoid having to match the pattern too often.
7550 * The result is an array of Autopat lists, which point to AutoCmd lists:
7551 *
7552 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
7553 * Autopat.cmds Autopat.cmds
7554 * | |
7555 * V V
7556 * AutoCmd.next AutoCmd.next
7557 * | |
7558 * V V
7559 * AutoCmd.next NULL
7560 * |
7561 * V
7562 * NULL
7563 *
7564 * first_autopat[1] --> Autopat.next --> NULL
7565 * Autopat.cmds
7566 * |
7567 * V
7568 * AutoCmd.next
7569 * |
7570 * V
7571 * NULL
7572 * etc.
7573 *
7574 * The order of AutoCmds is important, this is the order in which they were
7575 * defined and will have to be executed.
7576 */
7577typedef struct AutoCmd
7578{
7579 char_u *cmd; /* The command to be executed (NULL
7580 when command has been removed) */
7581 char nested; /* If autocommands nest here */
7582 char last; /* last command in list */
7583#ifdef FEAT_EVAL
7584 scid_T scriptID; /* script ID where defined */
7585#endif
7586 struct AutoCmd *next; /* Next AutoCmd in list */
7587} AutoCmd;
7588
7589typedef struct AutoPat
7590{
7591 int group; /* group ID */
7592 char_u *pat; /* pattern as typed (NULL when pattern
7593 has been removed) */
7594 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00007595 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007596 char allow_dirs; /* Pattern may match whole path */
7597 char last; /* last pattern for apply_autocmds() */
7598 AutoCmd *cmds; /* list of commands to do */
7599 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007600 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007601} AutoPat;
7602
7603static struct event_name
7604{
7605 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007606 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007607} event_names[] =
7608{
7609 {"BufAdd", EVENT_BUFADD},
7610 {"BufCreate", EVENT_BUFADD},
7611 {"BufDelete", EVENT_BUFDELETE},
7612 {"BufEnter", EVENT_BUFENTER},
7613 {"BufFilePost", EVENT_BUFFILEPOST},
7614 {"BufFilePre", EVENT_BUFFILEPRE},
7615 {"BufHidden", EVENT_BUFHIDDEN},
7616 {"BufLeave", EVENT_BUFLEAVE},
7617 {"BufNew", EVENT_BUFNEW},
7618 {"BufNewFile", EVENT_BUFNEWFILE},
7619 {"BufRead", EVENT_BUFREADPOST},
7620 {"BufReadCmd", EVENT_BUFREADCMD},
7621 {"BufReadPost", EVENT_BUFREADPOST},
7622 {"BufReadPre", EVENT_BUFREADPRE},
7623 {"BufUnload", EVENT_BUFUNLOAD},
7624 {"BufWinEnter", EVENT_BUFWINENTER},
7625 {"BufWinLeave", EVENT_BUFWINLEAVE},
7626 {"BufWipeout", EVENT_BUFWIPEOUT},
7627 {"BufWrite", EVENT_BUFWRITEPRE},
7628 {"BufWritePost", EVENT_BUFWRITEPOST},
7629 {"BufWritePre", EVENT_BUFWRITEPRE},
7630 {"BufWriteCmd", EVENT_BUFWRITECMD},
7631 {"CmdwinEnter", EVENT_CMDWINENTER},
7632 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007633 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007634 {"CursorHold", EVENT_CURSORHOLD},
7635 {"CursorHoldI", EVENT_CURSORHOLDI},
7636 {"CursorMoved", EVENT_CURSORMOVED},
7637 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007638 {"EncodingChanged", EVENT_ENCODINGCHANGED},
7639 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640 {"FileAppendPost", EVENT_FILEAPPENDPOST},
7641 {"FileAppendPre", EVENT_FILEAPPENDPRE},
7642 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
7643 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
Bram Moolenaar56718732006-03-15 22:53:57 +00007644 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007645 {"FileChangedRO", EVENT_FILECHANGEDRO},
7646 {"FileReadPost", EVENT_FILEREADPOST},
7647 {"FileReadPre", EVENT_FILEREADPRE},
7648 {"FileReadCmd", EVENT_FILEREADCMD},
7649 {"FileType", EVENT_FILETYPE},
7650 {"FileWritePost", EVENT_FILEWRITEPOST},
7651 {"FileWritePre", EVENT_FILEWRITEPRE},
7652 {"FileWriteCmd", EVENT_FILEWRITECMD},
7653 {"FilterReadPost", EVENT_FILTERREADPOST},
7654 {"FilterReadPre", EVENT_FILTERREADPRE},
7655 {"FilterWritePost", EVENT_FILTERWRITEPOST},
7656 {"FilterWritePre", EVENT_FILTERWRITEPRE},
7657 {"FocusGained", EVENT_FOCUSGAINED},
7658 {"FocusLost", EVENT_FOCUSLOST},
7659 {"FuncUndefined", EVENT_FUNCUNDEFINED},
7660 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar265e5072006-08-29 16:13:22 +00007661 {"GUIFailed", EVENT_GUIFAILED},
Bram Moolenaar843ee412004-06-30 16:16:41 +00007662 {"InsertChange", EVENT_INSERTCHANGE},
7663 {"InsertEnter", EVENT_INSERTENTER},
7664 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00007665 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00007666 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
7667 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007668 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00007669 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar5c4bab02006-03-10 21:37:46 +00007670 {"ShellCmdPost", EVENT_SHELLCMDPOST},
7671 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaara2031822006-03-07 22:29:51 +00007672 {"SourcePre", EVENT_SOURCEPRE},
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00007673 {"SourceCmd", EVENT_SOURCECMD},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00007674 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007675 {"StdinReadPost", EVENT_STDINREADPOST},
7676 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00007677 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00007678 {"Syntax", EVENT_SYNTAX},
Bram Moolenaar70836c82006-02-20 21:28:49 +00007679 {"TabEnter", EVENT_TABENTER},
7680 {"TabLeave", EVENT_TABLEAVE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007681 {"TermChanged", EVENT_TERMCHANGED},
7682 {"TermResponse", EVENT_TERMRESPONSE},
7683 {"User", EVENT_USER},
7684 {"VimEnter", EVENT_VIMENTER},
7685 {"VimLeave", EVENT_VIMLEAVE},
7686 {"VimLeavePre", EVENT_VIMLEAVEPRE},
7687 {"WinEnter", EVENT_WINENTER},
7688 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar56718732006-03-15 22:53:57 +00007689 {"VimResized", EVENT_VIMRESIZED},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007690 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007691};
7692
7693static AutoPat *first_autopat[NUM_EVENTS] =
7694{
7695 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7696 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7697 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7698 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007699 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7700 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007701};
7702
7703/*
7704 * struct used to keep status while executing autocommands for an event.
7705 */
7706typedef struct AutoPatCmd
7707{
7708 AutoPat *curpat; /* next AutoPat to examine */
7709 AutoCmd *nextcmd; /* next AutoCmd to execute */
7710 int group; /* group being used */
7711 char_u *fname; /* fname to match with */
7712 char_u *sfname; /* sfname to match with */
7713 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007714 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007715 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7716 buf is deleted */
7717 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007718} AutoPatCmd;
7719
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007720static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007721
Bram Moolenaar071d4272004-06-13 20:20:40 +00007722/*
7723 * augroups stores a list of autocmd group names.
7724 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007725static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007726#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7727
7728/*
7729 * The ID of the current group. Group 0 is the default one.
7730 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007731static int current_augroup = AUGROUP_DEFAULT;
7732
7733static int au_need_clean = FALSE; /* need to delete marked patterns */
7734
Bram Moolenaar754b5602006-02-09 23:53:20 +00007735static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007736static void au_remove_pat __ARGS((AutoPat *ap));
7737static void au_remove_cmds __ARGS((AutoPat *ap));
7738static void au_cleanup __ARGS((void));
7739static int au_new_group __ARGS((char_u *name));
7740static void au_del_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007741static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7742static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007743static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007744static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007745static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007746static 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 +00007747static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007748static 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 +00007749static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7750
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007751
Bram Moolenaar754b5602006-02-09 23:53:20 +00007752static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007753static int last_group;
Bram Moolenaar78ab3312007-09-29 12:16:41 +00007754static int autocmd_blocked = 0; /* block all autocmds */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007755
7756/*
7757 * Show the autocommands for one AutoPat.
7758 */
7759 static void
7760show_autocmd(ap, event)
7761 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007762 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007763{
7764 AutoCmd *ac;
7765
7766 /* Check for "got_int" (here and at various places below), which is set
7767 * when "q" has been hit for the "--more--" prompt */
7768 if (got_int)
7769 return;
7770 if (ap->pat == NULL) /* pattern has been removed */
7771 return;
7772
7773 msg_putchar('\n');
7774 if (got_int)
7775 return;
7776 if (event != last_event || ap->group != last_group)
7777 {
7778 if (ap->group != AUGROUP_DEFAULT)
7779 {
7780 if (AUGROUP_NAME(ap->group) == NULL)
7781 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7782 else
7783 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7784 msg_puts((char_u *)" ");
7785 }
7786 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7787 last_event = event;
7788 last_group = ap->group;
7789 msg_putchar('\n');
7790 if (got_int)
7791 return;
7792 }
7793 msg_col = 4;
7794 msg_outtrans(ap->pat);
7795
7796 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7797 {
7798 if (ac->cmd != NULL) /* skip removed commands */
7799 {
7800 if (msg_col >= 14)
7801 msg_putchar('\n');
7802 msg_col = 14;
7803 if (got_int)
7804 return;
7805 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007806#ifdef FEAT_EVAL
7807 if (p_verbose > 0)
7808 last_set_msg(ac->scriptID);
7809#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007810 if (got_int)
7811 return;
7812 if (ac->next != NULL)
7813 {
7814 msg_putchar('\n');
7815 if (got_int)
7816 return;
7817 }
7818 }
7819 }
7820}
7821
7822/*
7823 * Mark an autocommand pattern for deletion.
7824 */
7825 static void
7826au_remove_pat(ap)
7827 AutoPat *ap;
7828{
7829 vim_free(ap->pat);
7830 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007831 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007832 au_need_clean = TRUE;
7833}
7834
7835/*
7836 * Mark all commands for a pattern for deletion.
7837 */
7838 static void
7839au_remove_cmds(ap)
7840 AutoPat *ap;
7841{
7842 AutoCmd *ac;
7843
7844 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7845 {
7846 vim_free(ac->cmd);
7847 ac->cmd = NULL;
7848 }
7849 au_need_clean = TRUE;
7850}
7851
7852/*
7853 * Cleanup autocommands and patterns that have been deleted.
7854 * This is only done when not executing autocommands.
7855 */
7856 static void
7857au_cleanup()
7858{
7859 AutoPat *ap, **prev_ap;
7860 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007861 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007862
7863 if (autocmd_busy || !au_need_clean)
7864 return;
7865
7866 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007867 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7868 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007869 {
7870 /* loop over all autocommand patterns */
7871 prev_ap = &(first_autopat[(int)event]);
7872 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7873 {
7874 /* loop over all commands for this pattern */
7875 prev_ac = &(ap->cmds);
7876 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7877 {
7878 /* remove the command if the pattern is to be deleted or when
7879 * the command has been marked for deletion */
7880 if (ap->pat == NULL || ac->cmd == NULL)
7881 {
7882 *prev_ac = ac->next;
7883 vim_free(ac->cmd);
7884 vim_free(ac);
7885 }
7886 else
7887 prev_ac = &(ac->next);
7888 }
7889
7890 /* remove the pattern if it has been marked for deletion */
7891 if (ap->pat == NULL)
7892 {
7893 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007894 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007895 vim_free(ap);
7896 }
7897 else
7898 prev_ap = &(ap->next);
7899 }
7900 }
7901
7902 au_need_clean = FALSE;
7903}
7904
7905/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007906 * Called when buffer is freed, to remove/invalidate related buffer-local
7907 * autocmds.
7908 */
7909 void
7910aubuflocal_remove(buf)
7911 buf_T *buf;
7912{
7913 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007914 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007915 AutoPatCmd *apc;
7916
7917 /* invalidate currently executing autocommands */
7918 for (apc = active_apc_list; apc; apc = apc->next)
7919 if (buf->b_fnum == apc->arg_bufnr)
7920 apc->arg_bufnr = 0;
7921
7922 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007923 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7924 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007925 /* loop over all autocommand patterns */
7926 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7927 if (ap->buflocal_nr == buf->b_fnum)
7928 {
7929 au_remove_pat(ap);
7930 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007931 {
7932 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007933 smsg((char_u *)
7934 _("auto-removing autocommand: %s <buffer=%d>"),
7935 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007936 verbose_leave();
7937 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007938 }
7939 au_cleanup();
7940}
7941
7942/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007943 * Add an autocmd group name.
7944 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7945 */
7946 static int
7947au_new_group(name)
7948 char_u *name;
7949{
7950 int i;
7951
7952 i = au_find_group(name);
7953 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7954 {
7955 /* First try using a free entry. */
7956 for (i = 0; i < augroups.ga_len; ++i)
7957 if (AUGROUP_NAME(i) == NULL)
7958 break;
7959 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7960 return AUGROUP_ERROR;
7961
7962 AUGROUP_NAME(i) = vim_strsave(name);
7963 if (AUGROUP_NAME(i) == NULL)
7964 return AUGROUP_ERROR;
7965 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007966 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007967 }
7968
7969 return i;
7970}
7971
7972 static void
7973au_del_group(name)
7974 char_u *name;
7975{
7976 int i;
7977
7978 i = au_find_group(name);
7979 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7980 EMSG2(_("E367: No such group: \"%s\""), name);
7981 else
7982 {
7983 vim_free(AUGROUP_NAME(i));
7984 AUGROUP_NAME(i) = NULL;
7985 }
7986}
7987
7988/*
7989 * Find the ID of an autocmd group name.
7990 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7991 */
7992 static int
7993au_find_group(name)
7994 char_u *name;
7995{
7996 int i;
7997
7998 for (i = 0; i < augroups.ga_len; ++i)
7999 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
8000 return i;
8001 return AUGROUP_ERROR;
8002}
8003
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00008004/*
8005 * Return TRUE if augroup "name" exists.
8006 */
8007 int
8008au_has_group(name)
8009 char_u *name;
8010{
8011 return au_find_group(name) != AUGROUP_ERROR;
8012}
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00008013
Bram Moolenaar071d4272004-06-13 20:20:40 +00008014/*
8015 * ":augroup {name}".
8016 */
8017 void
8018do_augroup(arg, del_group)
8019 char_u *arg;
8020 int del_group;
8021{
8022 int i;
8023
8024 if (del_group)
8025 {
8026 if (*arg == NUL)
8027 EMSG(_(e_argreq));
8028 else
8029 au_del_group(arg);
8030 }
8031 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
8032 current_augroup = AUGROUP_DEFAULT;
8033 else if (*arg) /* ":aug xxx": switch to group xxx */
8034 {
8035 i = au_new_group(arg);
8036 if (i != AUGROUP_ERROR)
8037 current_augroup = i;
8038 }
8039 else /* ":aug": list the group names */
8040 {
8041 msg_start();
8042 for (i = 0; i < augroups.ga_len; ++i)
8043 {
8044 if (AUGROUP_NAME(i) != NULL)
8045 {
8046 msg_puts(AUGROUP_NAME(i));
8047 msg_puts((char_u *)" ");
8048 }
8049 }
8050 msg_clr_eos();
8051 msg_end();
8052 }
8053}
8054
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00008055#if defined(EXITFREE) || defined(PROTO)
8056 void
8057free_all_autocmds()
8058{
8059 for (current_augroup = -1; current_augroup < augroups.ga_len;
8060 ++current_augroup)
8061 do_autocmd((char_u *)"", TRUE);
8062 ga_clear_strings(&augroups);
8063}
8064#endif
8065
Bram Moolenaar071d4272004-06-13 20:20:40 +00008066/*
8067 * Return the event number for event name "start".
8068 * Return NUM_EVENTS if the event name was not found.
8069 * Return a pointer to the next event name in "end".
8070 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00008071 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00008072event_name2nr(start, end)
8073 char_u *start;
8074 char_u **end;
8075{
8076 char_u *p;
8077 int i;
8078 int len;
8079
8080 /* the event name ends with end of line, a blank or a comma */
8081 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
8082 ;
8083 for (i = 0; event_names[i].name != NULL; ++i)
8084 {
8085 len = (int)STRLEN(event_names[i].name);
8086 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
8087 break;
8088 }
8089 if (*p == ',')
8090 ++p;
8091 *end = p;
8092 if (event_names[i].name == NULL)
8093 return NUM_EVENTS;
8094 return event_names[i].event;
8095}
8096
8097/*
8098 * Return the name for event "event".
8099 */
8100 static char_u *
8101event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008102 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008103{
8104 int i;
8105
8106 for (i = 0; event_names[i].name != NULL; ++i)
8107 if (event_names[i].event == event)
8108 return (char_u *)event_names[i].name;
8109 return (char_u *)"Unknown";
8110}
8111
8112/*
8113 * Scan over the events. "*" stands for all events.
8114 */
8115 static char_u *
8116find_end_event(arg, have_group)
8117 char_u *arg;
8118 int have_group; /* TRUE when group name was found */
8119{
8120 char_u *pat;
8121 char_u *p;
8122
8123 if (*arg == '*')
8124 {
8125 if (arg[1] && !vim_iswhite(arg[1]))
8126 {
8127 EMSG2(_("E215: Illegal character after *: %s"), arg);
8128 return NULL;
8129 }
8130 pat = arg + 1;
8131 }
8132 else
8133 {
8134 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
8135 {
8136 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
8137 {
8138 if (have_group)
8139 EMSG2(_("E216: No such event: %s"), pat);
8140 else
8141 EMSG2(_("E216: No such group or event: %s"), pat);
8142 return NULL;
8143 }
8144 }
8145 }
8146 return pat;
8147}
8148
8149/*
8150 * Return TRUE if "event" is included in 'eventignore'.
8151 */
8152 static int
8153event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008154 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008155{
8156 char_u *p = p_ei;
8157
Bram Moolenaarf193fff2006-04-27 00:02:13 +00008158 while (*p != NUL)
8159 {
8160 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
8161 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008162 if (event_name2nr(p, &p) == event)
8163 return TRUE;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00008164 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008165
8166 return FALSE;
8167}
8168
8169/*
8170 * Return OK when the contents of p_ei is valid, FAIL otherwise.
8171 */
8172 int
8173check_ei()
8174{
8175 char_u *p = p_ei;
8176
Bram Moolenaar071d4272004-06-13 20:20:40 +00008177 while (*p)
Bram Moolenaarf193fff2006-04-27 00:02:13 +00008178 {
8179 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
8180 {
8181 p += 3;
8182 if (*p == ',')
8183 ++p;
8184 }
8185 else if (event_name2nr(p, &p) == NUM_EVENTS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008186 return FAIL;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00008187 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008188
8189 return OK;
8190}
8191
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00008192# if defined(FEAT_SYN_HL) || defined(PROTO)
8193
8194/*
8195 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
8196 * buffer loaded into the window. "what" must start with a comma.
8197 * Returns the old value of 'eventignore' in allocated memory.
8198 */
8199 char_u *
8200au_event_disable(what)
8201 char *what;
8202{
8203 char_u *new_ei;
8204 char_u *save_ei;
8205
8206 save_ei = vim_strsave(p_ei);
8207 if (save_ei != NULL)
8208 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00008209 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00008210 if (new_ei != NULL)
8211 {
Bram Moolenaar8cac9fd2010-03-02 12:48:05 +01008212 if (*what == ',' && *p_ei == NUL)
8213 STRCPY(new_ei, what + 1);
8214 else
8215 STRCAT(new_ei, what);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00008216 set_string_option_direct((char_u *)"ei", -1, new_ei,
8217 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00008218 vim_free(new_ei);
8219 }
8220 }
8221 return save_ei;
8222}
8223
8224 void
8225au_event_restore(old_ei)
8226 char_u *old_ei;
8227{
8228 if (old_ei != NULL)
8229 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00008230 set_string_option_direct((char_u *)"ei", -1, old_ei,
8231 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00008232 vim_free(old_ei);
8233 }
8234}
8235# endif /* FEAT_SYN_HL */
8236
Bram Moolenaar071d4272004-06-13 20:20:40 +00008237/*
8238 * do_autocmd() -- implements the :autocmd command. Can be used in the
8239 * following ways:
8240 *
8241 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
8242 * will be automatically executed for <event>
8243 * when editing a file matching <pat>, in
8244 * the current group.
8245 * :autocmd <event> <pat> Show the auto-commands associated with
8246 * <event> and <pat>.
8247 * :autocmd <event> Show the auto-commands associated with
8248 * <event>.
8249 * :autocmd Show all auto-commands.
8250 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
8251 * <event> and <pat>, and add the command
8252 * <cmd>, for the current group.
8253 * :autocmd! <event> <pat> Remove all auto-commands associated with
8254 * <event> and <pat> for the current group.
8255 * :autocmd! <event> Remove all auto-commands associated with
8256 * <event> for the current group.
8257 * :autocmd! Remove ALL auto-commands for the current
8258 * group.
8259 *
8260 * Multiple events and patterns may be given separated by commas. Here are
8261 * some examples:
8262 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
8263 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
8264 *
8265 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00008266 *
8267 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008268 */
8269 void
8270do_autocmd(arg, forceit)
8271 char_u *arg;
8272 int forceit;
8273{
8274 char_u *pat;
8275 char_u *envpat = NULL;
8276 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00008277 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008278 int need_free = FALSE;
8279 int nested = FALSE;
8280 int group;
8281
8282 /*
8283 * Check for a legal group name. If not, use AUGROUP_ALL.
8284 */
8285 group = au_get_grouparg(&arg);
8286 if (arg == NULL) /* out of memory */
8287 return;
8288
8289 /*
8290 * Scan over the events.
8291 * If we find an illegal name, return here, don't do anything.
8292 */
8293 pat = find_end_event(arg, group != AUGROUP_ALL);
8294 if (pat == NULL)
8295 return;
8296
8297 /*
8298 * Scan over the pattern. Put a NUL at the end.
8299 */
8300 pat = skipwhite(pat);
8301 cmd = pat;
8302 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
8303 cmd++;
8304 if (*cmd)
8305 *cmd++ = NUL;
8306
8307 /* Expand environment variables in the pattern. Set 'shellslash', we want
8308 * forward slashes here. */
8309 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
8310 {
8311#ifdef BACKSLASH_IN_FILENAME
8312 int p_ssl_save = p_ssl;
8313
8314 p_ssl = TRUE;
8315#endif
8316 envpat = expand_env_save(pat);
8317#ifdef BACKSLASH_IN_FILENAME
8318 p_ssl = p_ssl_save;
8319#endif
8320 if (envpat != NULL)
8321 pat = envpat;
8322 }
8323
8324 /*
8325 * Check for "nested" flag.
8326 */
8327 cmd = skipwhite(cmd);
8328 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
8329 {
8330 nested = TRUE;
8331 cmd = skipwhite(cmd + 6);
8332 }
8333
8334 /*
8335 * Find the start of the commands.
8336 * Expand <sfile> in it.
8337 */
8338 if (*cmd != NUL)
8339 {
8340 cmd = expand_sfile(cmd);
8341 if (cmd == NULL) /* some error */
8342 return;
8343 need_free = TRUE;
8344 }
8345
8346 /*
8347 * Print header when showing autocommands.
8348 */
8349 if (!forceit && *cmd == NUL)
8350 {
8351 /* Highlight title */
8352 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
8353 }
8354
8355 /*
8356 * Loop over the events.
8357 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00008358 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008359 last_group = AUGROUP_ERROR; /* for listing the group name */
8360 if (*arg == '*' || *arg == NUL)
8361 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00008362 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
8363 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008364 if (do_autocmd_event(event, pat,
8365 nested, cmd, forceit, group) == FAIL)
8366 break;
8367 }
8368 else
8369 {
8370 while (*arg && !vim_iswhite(*arg))
8371 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
8372 nested, cmd, forceit, group) == FAIL)
8373 break;
8374 }
8375
8376 if (need_free)
8377 vim_free(cmd);
8378 vim_free(envpat);
8379}
8380
8381/*
8382 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
8383 * The "argp" argument is advanced to the following argument.
8384 *
8385 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
8386 */
8387 static int
8388au_get_grouparg(argp)
8389 char_u **argp;
8390{
8391 char_u *group_name;
8392 char_u *p;
8393 char_u *arg = *argp;
8394 int group = AUGROUP_ALL;
8395
8396 p = skiptowhite(arg);
8397 if (p > arg)
8398 {
8399 group_name = vim_strnsave(arg, (int)(p - arg));
8400 if (group_name == NULL) /* out of memory */
8401 return AUGROUP_ERROR;
8402 group = au_find_group(group_name);
8403 if (group == AUGROUP_ERROR)
8404 group = AUGROUP_ALL; /* no match, use all groups */
8405 else
8406 *argp = skipwhite(p); /* match, skip over group name */
8407 vim_free(group_name);
8408 }
8409 return group;
8410}
8411
8412/*
8413 * do_autocmd() for one event.
8414 * If *pat == NUL do for all patterns.
8415 * If *cmd == NUL show entries.
8416 * If forceit == TRUE delete entries.
8417 * If group is not AUGROUP_ALL, only use this group.
8418 */
8419 static int
8420do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008421 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008422 char_u *pat;
8423 int nested;
8424 char_u *cmd;
8425 int forceit;
8426 int group;
8427{
8428 AutoPat *ap;
8429 AutoPat **prev_ap;
8430 AutoCmd *ac;
8431 AutoCmd **prev_ac;
8432 int brace_level;
8433 char_u *endpat;
8434 int findgroup;
8435 int allgroups;
8436 int patlen;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00008437 int is_buflocal;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008438 int buflocal_nr;
8439 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008440
8441 if (group == AUGROUP_ALL)
8442 findgroup = current_augroup;
8443 else
8444 findgroup = group;
8445 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
8446
8447 /*
8448 * Show or delete all patterns for an event.
8449 */
8450 if (*pat == NUL)
8451 {
8452 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8453 {
8454 if (forceit) /* delete the AutoPat, if it's in the current group */
8455 {
8456 if (ap->group == findgroup)
8457 au_remove_pat(ap);
8458 }
8459 else if (group == AUGROUP_ALL || ap->group == group)
8460 show_autocmd(ap, event);
8461 }
8462 }
8463
8464 /*
8465 * Loop through all the specified patterns.
8466 */
8467 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
8468 {
8469 /*
8470 * Find end of the pattern.
8471 * Watch out for a comma in braces, like "*.\{obj,o\}".
8472 */
8473 brace_level = 0;
8474 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
8475 || endpat[-1] == '\\'); ++endpat)
8476 {
8477 if (*endpat == '{')
8478 brace_level++;
8479 else if (*endpat == '}')
8480 brace_level--;
8481 }
8482 if (pat == endpat) /* ignore single comma */
8483 continue;
8484 patlen = (int)(endpat - pat);
8485
8486 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008487 * detect special <buflocal[=X]> buffer-local patterns
8488 */
8489 is_buflocal = FALSE;
8490 buflocal_nr = 0;
8491
8492 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
8493 && pat[patlen - 1] == '>')
8494 {
8495 /* Error will be printed only for addition. printing and removing
8496 * will proceed silently. */
8497 is_buflocal = TRUE;
8498 if (patlen == 8)
8499 buflocal_nr = curbuf->b_fnum;
8500 else if (patlen > 9 && pat[7] == '=')
8501 {
8502 /* <buffer=abuf> */
8503 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
8504 buflocal_nr = autocmd_bufnr;
8505 /* <buffer=123> */
8506 else if (skipdigits(pat + 8) == pat + patlen - 1)
8507 buflocal_nr = atoi((char *)pat + 8);
8508 }
8509 }
8510
8511 if (is_buflocal)
8512 {
8513 /* normalize pat into standard "<buffer>#N" form */
8514 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
8515 pat = buflocal_pat; /* can modify pat and patlen */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00008516 patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008517 }
8518
8519 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008520 * Find AutoPat entries with this pattern.
8521 */
8522 prev_ap = &first_autopat[(int)event];
8523 while ((ap = *prev_ap) != NULL)
8524 {
8525 if (ap->pat != NULL)
8526 {
8527 /* Accept a pattern when:
8528 * - a group was specified and it's that group, or a group was
8529 * not specified and it's the current group, or a group was
8530 * not specified and we are listing
8531 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008532 * - the pattern matches.
8533 * For <buffer[=X]>, this condition works because we normalize
8534 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008535 */
8536 if ((allgroups || ap->group == findgroup)
8537 && ap->patlen == patlen
8538 && STRNCMP(pat, ap->pat, patlen) == 0)
8539 {
8540 /*
8541 * Remove existing autocommands.
8542 * If adding any new autocmd's for this AutoPat, don't
8543 * delete the pattern from the autopat list, append to
8544 * this list.
8545 */
8546 if (forceit)
8547 {
8548 if (*cmd != NUL && ap->next == NULL)
8549 {
8550 au_remove_cmds(ap);
8551 break;
8552 }
8553 au_remove_pat(ap);
8554 }
8555
8556 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008557 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00008558 */
8559 else if (*cmd == NUL)
8560 show_autocmd(ap, event);
8561
8562 /*
8563 * Add autocmd to this autopat, if it's the last one.
8564 */
8565 else if (ap->next == NULL)
8566 break;
8567 }
8568 }
8569 prev_ap = &ap->next;
8570 }
8571
8572 /*
8573 * Add a new command.
8574 */
8575 if (*cmd != NUL)
8576 {
8577 /*
8578 * If the pattern we want to add a command to does appear at the
8579 * end of the list (or not is not in the list at all), add the
8580 * pattern at the end of the list.
8581 */
8582 if (ap == NULL)
8583 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008584 /* refuse to add buffer-local ap if buffer number is invalid */
8585 if (is_buflocal && (buflocal_nr == 0
8586 || buflist_findnr(buflocal_nr) == NULL))
8587 {
8588 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
8589 buflocal_nr);
8590 return FAIL;
8591 }
8592
Bram Moolenaar071d4272004-06-13 20:20:40 +00008593 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
8594 if (ap == NULL)
8595 return FAIL;
8596 ap->pat = vim_strnsave(pat, patlen);
8597 ap->patlen = patlen;
8598 if (ap->pat == NULL)
8599 {
8600 vim_free(ap);
8601 return FAIL;
8602 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008603
8604 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008605 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008606 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008607 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008608 }
8609 else
8610 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00008611 char_u *reg_pat;
8612
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008613 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008614 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008615 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008616 if (reg_pat != NULL)
8617 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00008618 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008619 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008620 {
8621 vim_free(ap->pat);
8622 vim_free(ap);
8623 return FAIL;
8624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008625 }
8626 ap->cmds = NULL;
8627 *prev_ap = ap;
8628 ap->next = NULL;
8629 if (group == AUGROUP_ALL)
8630 ap->group = current_augroup;
8631 else
8632 ap->group = group;
8633 }
8634
8635 /*
8636 * Add the autocmd at the end of the AutoCmd list.
8637 */
8638 prev_ac = &(ap->cmds);
8639 while ((ac = *prev_ac) != NULL)
8640 prev_ac = &ac->next;
8641 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
8642 if (ac == NULL)
8643 return FAIL;
8644 ac->cmd = vim_strsave(cmd);
8645#ifdef FEAT_EVAL
8646 ac->scriptID = current_SID;
8647#endif
8648 if (ac->cmd == NULL)
8649 {
8650 vim_free(ac);
8651 return FAIL;
8652 }
8653 ac->next = NULL;
8654 *prev_ac = ac;
8655 ac->nested = nested;
8656 }
8657 }
8658
8659 au_cleanup(); /* may really delete removed patterns/commands now */
8660 return OK;
8661}
8662
8663/*
8664 * Implementation of ":doautocmd [group] event [fname]".
8665 * Return OK for success, FAIL for failure;
8666 */
8667 int
8668do_doautocmd(arg, do_msg)
8669 char_u *arg;
8670 int do_msg; /* give message for no matching autocmds? */
8671{
8672 char_u *fname;
8673 int nothing_done = TRUE;
8674 int group;
8675
8676 /*
8677 * Check for a legal group name. If not, use AUGROUP_ALL.
8678 */
8679 group = au_get_grouparg(&arg);
8680 if (arg == NULL) /* out of memory */
8681 return FAIL;
8682
8683 if (*arg == '*')
8684 {
8685 EMSG(_("E217: Can't execute autocommands for ALL events"));
8686 return FAIL;
8687 }
8688
8689 /*
8690 * Scan over the events.
8691 * If we find an illegal name, return here, don't do anything.
8692 */
8693 fname = find_end_event(arg, group != AUGROUP_ALL);
8694 if (fname == NULL)
8695 return FAIL;
8696
8697 fname = skipwhite(fname);
8698
8699 /*
8700 * Loop over the events.
8701 */
8702 while (*arg && !vim_iswhite(*arg))
8703 if (apply_autocmds_group(event_name2nr(arg, &arg),
8704 fname, NULL, TRUE, group, curbuf, NULL))
8705 nothing_done = FALSE;
8706
8707 if (nothing_done && do_msg)
8708 MSG(_("No matching autocommands"));
8709
8710#ifdef FEAT_EVAL
8711 return aborting() ? FAIL : OK;
8712#else
8713 return OK;
8714#endif
8715}
8716
8717/*
8718 * ":doautoall": execute autocommands for each loaded buffer.
8719 */
8720 void
8721ex_doautoall(eap)
8722 exarg_T *eap;
8723{
8724 int retval;
8725 aco_save_T aco;
8726 buf_T *buf;
8727
8728 /*
8729 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8730 * equal to curbuf, but for some buffers there may not be a window.
8731 * So we change the buffer for the current window for a moment. This
8732 * gives problems when the autocommands make changes to the list of
8733 * buffers or windows...
8734 */
8735 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8736 {
Bram Moolenaar3a847972008-07-08 09:36:58 +00008737 if (buf->b_ml.ml_mfp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008738 {
8739 /* find a window for this buffer and save some values */
8740 aucmd_prepbuf(&aco, buf);
8741
8742 /* execute the autocommands for this buffer */
8743 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaareeefcc72007-05-01 21:21:21 +00008744
8745 /* Execute the modeline settings, but don't set window-local
8746 * options if we are using the current window for another buffer. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008747 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008748
8749 /* restore the current window */
8750 aucmd_restbuf(&aco);
8751
8752 /* stop if there is some error or buffer was deleted */
8753 if (retval == FAIL || !buf_valid(buf))
8754 break;
8755 }
8756 }
8757
8758 check_cursor(); /* just in case lines got deleted */
8759}
8760
8761/*
8762 * Prepare for executing autocommands for (hidden) buffer "buf".
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008763 * Search for a visible window containing the current buffer. If there isn't
8764 * one then use "aucmd_win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00008765 * Set "curbuf" and "curwin" to match "buf".
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008766 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008767 */
8768 void
8769aucmd_prepbuf(aco, buf)
8770 aco_save_T *aco; /* structure to save values in */
8771 buf_T *buf; /* new curbuf */
8772{
8773 win_T *win;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008774#ifdef FEAT_WINDOWS
8775 int save_ea;
8776#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008777
8778 /* Find a window that is for the new buffer */
8779 if (buf == curbuf) /* be quick when buf is curbuf */
8780 win = curwin;
8781 else
8782#ifdef FEAT_WINDOWS
8783 for (win = firstwin; win != NULL; win = win->w_next)
8784 if (win->w_buffer == buf)
8785 break;
8786#else
8787 win = NULL;
8788#endif
8789
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008790 /* Allocate "aucmd_win" when needed. If this fails (out of memory) fall
8791 * back to using the current window. */
8792 if (win == NULL && aucmd_win == NULL)
8793 {
8794 win_alloc_aucmd_win();
8795 if (aucmd_win == NULL)
8796 win = curwin;
8797 }
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008798 if (win == NULL && aucmd_win_used)
8799 /* Strange recursive autocommand, fall back to using the current
8800 * window. Expect a few side effects... */
8801 win = curwin;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008802
8803 aco->save_curwin = curwin;
8804 aco->save_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008805 if (win != NULL)
8806 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008807 /* There is a window for "buf" in the current tab page, make it the
8808 * curwin. This is preferred, it has the least side effects (esp. if
8809 * "buf" is curbuf). */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008810 aco->use_aucmd_win = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008811 curwin = win;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008812 }
8813 else
8814 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008815 /* There is no window for "buf", use "aucmd_win". To minimize the side
8816 * effects, insert it in a the current tab page.
8817 * Anything related to a window (e.g., setting folds) may have
8818 * unexpected results. */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008819 aco->use_aucmd_win = TRUE;
8820 aucmd_win_used = TRUE;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008821 aucmd_win->w_buffer = buf;
Bram Moolenaarcdddaa42010-06-07 23:07:44 +02008822 aucmd_win->w_s = &buf->b_s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008823 ++buf->b_nwindows;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008824 win_init_empty(aucmd_win); /* set cursor and topline to safe values */
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008825 vim_free(aucmd_win->w_localdir);
8826 aucmd_win->w_localdir = NULL;
8827
8828 /* Make sure w_localdir and globaldir are NULL to avoid a chdir() in
8829 * win_enter_ext(). */
8830 aucmd_win->w_localdir = NULL;
8831 aco->globaldir = globaldir;
8832 globaldir = NULL;
8833
Bram Moolenaar071d4272004-06-13 20:20:40 +00008834
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008835#ifdef FEAT_WINDOWS
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008836 /* Split the current window, put the aucmd_win in the upper half.
8837 * We don't want the BufEnter or WinEnter autocommands. */
8838 block_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008839 make_snapshot(SNAP_AUCMD_IDX);
8840 save_ea = p_ea;
8841 p_ea = FALSE;
8842 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
8843 (void)win_comp_pos(); /* recompute window positions */
8844 p_ea = save_ea;
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008845 unblock_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008846#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00008847 curwin = aucmd_win;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008848 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008849 curbuf = buf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008850 aco->new_curwin = curwin;
8851 aco->new_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008852}
8853
8854/*
8855 * Cleanup after executing autocommands for a (hidden) buffer.
8856 * Restore the window as it was (if possible).
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008857 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008858 */
8859 void
8860aucmd_restbuf(aco)
8861 aco_save_T *aco; /* structure holding saved values */
8862{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008863#ifdef FEAT_WINDOWS
8864 int dummy;
8865#endif
8866
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008867 if (aco->use_aucmd_win)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008868 {
8869 --curbuf->b_nwindows;
8870#ifdef FEAT_WINDOWS
8871 /* Find "aucmd_win", it can't be closed, but it may be in another tab
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008872 * page. Do not trigger autocommands here. */
8873 block_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008874 if (curwin != aucmd_win)
8875 {
8876 tabpage_T *tp;
8877 win_T *wp;
8878
8879 FOR_ALL_TAB_WINDOWS(tp, wp)
8880 {
8881 if (wp == aucmd_win)
8882 {
8883 if (tp != curtab)
8884 goto_tabpage_tp(tp);
8885 win_goto(aucmd_win);
8886 break;
8887 }
8888 }
8889 }
8890
8891 /* Remove the window and frame from the tree of frames. */
8892 (void)winframe_remove(curwin, &dummy, NULL);
8893 win_remove(curwin, NULL);
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008894 aucmd_win_used = FALSE;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008895 last_status(FALSE); /* may need to remove last status line */
8896 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
8897 (void)win_comp_pos(); /* recompute window positions */
Bram Moolenaar2bc76e62009-07-01 15:13:56 +00008898 unblock_autocmds();
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008899
8900 if (win_valid(aco->save_curwin))
8901 curwin = aco->save_curwin;
8902 else
8903 /* Hmm, original window disappeared. Just use the first one. */
8904 curwin = firstwin;
8905# ifdef FEAT_EVAL
8906 vars_clear(&aucmd_win->w_vars.dv_hashtab); /* free all w: variables */
Bram Moolenaar50daf402009-11-17 13:57:22 +00008907 hash_init(&aucmd_win->w_vars.dv_hashtab); /* re-use the hashtab */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008908# endif
8909#else
8910 curwin = aco->save_curwin;
8911#endif
8912 curbuf = curwin->w_buffer;
8913
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008914 vim_free(globaldir);
8915 globaldir = aco->globaldir;
8916
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008917 /* the buffer contents may have changed */
8918 check_cursor();
8919 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
8920 {
8921 curwin->w_topline = curbuf->b_ml.ml_line_count;
8922#ifdef FEAT_DIFF
8923 curwin->w_topfill = 0;
8924#endif
8925 }
8926#if defined(FEAT_GUI)
8927 /* Hide the scrollbars from the aucmd_win and update. */
8928 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
8929 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
8930 gui_may_update_scrollbars();
8931#endif
8932 }
8933 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00008934 {
8935 /* restore curwin */
8936#ifdef FEAT_WINDOWS
8937 if (win_valid(aco->save_curwin))
8938#endif
8939 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008940 /* Restore the buffer which was previously edited by curwin, if
Bram Moolenaar6bef63c2009-07-29 10:10:29 +00008941 * it was changed, we are still the same window and the buffer is
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008942 * valid. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008943 if (curwin == aco->new_curwin
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008944 && curbuf != aco->new_curbuf
8945 && buf_valid(aco->new_curbuf)
8946 && aco->new_curbuf->b_ml.ml_mfp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008947 {
8948 --curbuf->b_nwindows;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00008949 curbuf = aco->new_curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008950 curwin->w_buffer = curbuf;
8951 ++curbuf->b_nwindows;
8952 }
8953
8954 curwin = aco->save_curwin;
8955 curbuf = curwin->w_buffer;
8956 }
8957 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008958}
8959
8960static int autocmd_nested = FALSE;
8961
8962/*
8963 * Execute autocommands for "event" and file name "fname".
8964 * Return TRUE if some commands were executed.
8965 */
8966 int
8967apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008968 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008969 char_u *fname; /* NULL or empty means use actual file name */
8970 char_u *fname_io; /* fname to use for <afile> on cmdline */
8971 int force; /* when TRUE, ignore autocmd_busy */
8972 buf_T *buf; /* buffer for <abuf> */
8973{
8974 return apply_autocmds_group(event, fname, fname_io, force,
8975 AUGROUP_ALL, buf, NULL);
8976}
8977
8978/*
8979 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8980 * setting v:filearg.
8981 */
8982 static int
8983apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008984 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008985 char_u *fname;
8986 char_u *fname_io;
8987 int force;
8988 buf_T *buf;
8989 exarg_T *eap;
8990{
8991 return apply_autocmds_group(event, fname, fname_io, force,
8992 AUGROUP_ALL, buf, eap);
8993}
8994
8995/*
8996 * Like apply_autocmds(), but handles the caller's retval. If the script
8997 * processing is being aborted or if retval is FAIL when inside a try
8998 * conditional, no autocommands are executed. If otherwise the autocommands
8999 * cause the script to be aborted, retval is set to FAIL.
9000 */
9001 int
9002apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00009003 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009004 char_u *fname; /* NULL or empty means use actual file name */
9005 char_u *fname_io; /* fname to use for <afile> on cmdline */
9006 int force; /* when TRUE, ignore autocmd_busy */
9007 buf_T *buf; /* buffer for <abuf> */
9008 int *retval; /* pointer to caller's retval */
9009{
9010 int did_cmd;
9011
Bram Moolenaar1e015462005-09-25 22:16:38 +00009012#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00009013 if (should_abort(*retval))
9014 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00009015#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009016
9017 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
9018 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00009019 if (did_cmd
9020#ifdef FEAT_EVAL
9021 && aborting()
9022#endif
9023 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00009024 *retval = FAIL;
9025 return did_cmd;
9026}
9027
Bram Moolenaard35f9712005-12-18 22:02:33 +00009028/*
9029 * Return TRUE when there is a CursorHold autocommand defined.
9030 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009031 int
9032has_cursorhold()
9033{
Bram Moolenaar754b5602006-02-09 23:53:20 +00009034 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
9035 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009036}
Bram Moolenaard35f9712005-12-18 22:02:33 +00009037
9038/*
9039 * Return TRUE if the CursorHold event can be triggered.
9040 */
9041 int
9042trigger_cursorhold()
9043{
Bram Moolenaar754b5602006-02-09 23:53:20 +00009044 int state;
9045
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00009046 if (!did_cursorhold && has_cursorhold() && !Recording
9047#ifdef FEAT_INS_EXPAND
9048 && !ins_compl_active()
9049#endif
9050 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00009051 {
9052 state = get_real_state();
9053 if (state == NORMAL_BUSY || (state & INSERT) != 0)
9054 return TRUE;
9055 }
9056 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00009057}
Bram Moolenaar754b5602006-02-09 23:53:20 +00009058
9059/*
9060 * Return TRUE when there is a CursorMoved autocommand defined.
9061 */
9062 int
9063has_cursormoved()
9064{
9065 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
9066}
9067
9068/*
9069 * Return TRUE when there is a CursorMovedI autocommand defined.
9070 */
9071 int
9072has_cursormovedI()
9073{
9074 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
9075}
Bram Moolenaar071d4272004-06-13 20:20:40 +00009076
9077 static int
9078apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00009079 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009080 char_u *fname; /* NULL or empty means use actual file name */
9081 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
9082 use fname */
9083 int force; /* when TRUE, ignore autocmd_busy */
9084 int group; /* group ID, or AUGROUP_ALL */
9085 buf_T *buf; /* buffer for <abuf> */
9086 exarg_T *eap; /* command arguments */
9087{
9088 char_u *sfname = NULL; /* short file name */
9089 char_u *tail;
9090 int save_changed;
9091 buf_T *old_curbuf;
9092 int retval = FALSE;
9093 char_u *save_sourcing_name;
9094 linenr_T save_sourcing_lnum;
9095 char_u *save_autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009096 int save_autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009097 int save_autocmd_bufnr;
9098 char_u *save_autocmd_match;
9099 int save_autocmd_busy;
9100 int save_autocmd_nested;
9101 static int nesting = 0;
9102 AutoPatCmd patcmd;
9103 AutoPat *ap;
9104#ifdef FEAT_EVAL
9105 scid_T save_current_SID;
9106 void *save_funccalp;
9107 char_u *save_cmdarg;
9108 long save_cmdbang;
9109#endif
9110 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00009111#ifdef FEAT_PROFILE
9112 proftime_T wait_time;
9113#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009114
9115 /*
9116 * Quickly return if there are no autocommands for this event or
9117 * autocommands are blocked.
9118 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00009119 if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009120 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009121
9122 /*
9123 * When autocommands are busy, new autocommands are only executed when
9124 * explicitly enabled with the "nested" flag.
9125 */
9126 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009127 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009128
9129#ifdef FEAT_EVAL
9130 /*
Bram Moolenaar7263a772007-05-10 17:35:54 +00009131 * Quickly return when immediately aborting on error, or when an interrupt
Bram Moolenaar071d4272004-06-13 20:20:40 +00009132 * occurred or an exception was thrown but not caught.
9133 */
9134 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009135 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009136#endif
9137
9138 /*
9139 * FileChangedShell never nests, because it can create an endless loop.
9140 */
Bram Moolenaar56718732006-03-15 22:53:57 +00009141 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
9142 || event == EVENT_FILECHANGEDSHELLPOST))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009143 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009144
9145 /*
9146 * Ignore events in 'eventignore'.
9147 */
9148 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009149 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009150
9151 /*
9152 * Allow nesting of autocommands, but restrict the depth, because it's
9153 * possible to create an endless loop.
9154 */
9155 if (nesting == 10)
9156 {
9157 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009158 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009159 }
9160
9161 /*
9162 * Check if these autocommands are disabled. Used when doing ":all" or
9163 * ":ball".
9164 */
9165 if ( (autocmd_no_enter
9166 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
9167 || (autocmd_no_leave
9168 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009169 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009170
9171 /*
9172 * Save the autocmd_* variables and info about the current buffer.
9173 */
9174 save_autocmd_fname = autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009175 save_autocmd_fname_full = autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009176 save_autocmd_bufnr = autocmd_bufnr;
9177 save_autocmd_match = autocmd_match;
9178 save_autocmd_busy = autocmd_busy;
9179 save_autocmd_nested = autocmd_nested;
9180 save_changed = curbuf->b_changed;
9181 old_curbuf = curbuf;
9182
9183 /*
9184 * Set the file name to be used for <afile>.
Bram Moolenaara0174af2008-01-02 20:08:25 +00009185 * Make a copy to avoid that changing a buffer name or directory makes it
9186 * invalid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009187 */
9188 if (fname_io == NULL)
9189 {
9190 if (fname != NULL && *fname != NUL)
9191 autocmd_fname = fname;
9192 else if (buf != NULL)
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009193 autocmd_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009194 else
9195 autocmd_fname = NULL;
9196 }
9197 else
9198 autocmd_fname = fname_io;
Bram Moolenaara0174af2008-01-02 20:08:25 +00009199 if (autocmd_fname != NULL)
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009200 autocmd_fname = vim_strsave(autocmd_fname);
9201 autocmd_fname_full = FALSE; /* call FullName_save() later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009202
9203 /*
9204 * Set the buffer number to be used for <abuf>.
9205 */
9206 if (buf == NULL)
9207 autocmd_bufnr = 0;
9208 else
9209 autocmd_bufnr = buf->b_fnum;
9210
9211 /*
9212 * When the file name is NULL or empty, use the file name of buffer "buf".
9213 * Always use the full path of the file name to match with, in case
9214 * "allow_dirs" is set.
9215 */
9216 if (fname == NULL || *fname == NUL)
9217 {
9218 if (buf == NULL)
9219 fname = NULL;
9220 else
9221 {
9222#ifdef FEAT_SYN_HL
9223 if (event == EVENT_SYNTAX)
9224 fname = buf->b_p_syn;
9225 else
9226#endif
9227 if (event == EVENT_FILETYPE)
9228 fname = buf->b_p_ft;
9229 else
9230 {
9231 if (buf->b_sfname != NULL)
9232 sfname = vim_strsave(buf->b_sfname);
9233 fname = buf->b_ffname;
9234 }
9235 }
9236 if (fname == NULL)
9237 fname = (char_u *)"";
9238 fname = vim_strsave(fname); /* make a copy, so we can change it */
9239 }
9240 else
9241 {
9242 sfname = vim_strsave(fname);
Bram Moolenaar5135d462009-04-29 16:03:38 +00009243 /* Don't try expanding FileType, Syntax, FuncUndefined, WindowID or
9244 * QuickFixCmd* */
Bram Moolenaar7c626922005-02-07 22:01:03 +00009245 if (event == EVENT_FILETYPE
9246 || event == EVENT_SYNTAX
Bram Moolenaar5135d462009-04-29 16:03:38 +00009247 || event == EVENT_FUNCUNDEFINED
Bram Moolenaar7c626922005-02-07 22:01:03 +00009248 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00009249 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00009250 || event == EVENT_QUICKFIXCMDPRE
9251 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009252 fname = vim_strsave(fname);
9253 else
9254 fname = FullName_save(fname, FALSE);
9255 }
9256 if (fname == NULL) /* out of memory */
9257 {
9258 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009259 retval = FALSE;
9260 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009261 }
9262
9263#ifdef BACKSLASH_IN_FILENAME
9264 /*
9265 * Replace all backslashes with forward slashes. This makes the
9266 * autocommand patterns portable between Unix and MS-DOS.
9267 */
9268 if (sfname != NULL)
9269 forward_slash(sfname);
9270 forward_slash(fname);
9271#endif
9272
9273#ifdef VMS
9274 /* remove version for correct match */
9275 if (sfname != NULL)
9276 vms_remove_version(sfname);
9277 vms_remove_version(fname);
9278#endif
9279
9280 /*
9281 * Set the name to be used for <amatch>.
9282 */
9283 autocmd_match = fname;
9284
9285
9286 /* Don't redraw while doing auto commands. */
9287 ++RedrawingDisabled;
9288 save_sourcing_name = sourcing_name;
9289 sourcing_name = NULL; /* don't free this one */
9290 save_sourcing_lnum = sourcing_lnum;
9291 sourcing_lnum = 0; /* no line number here */
9292
9293#ifdef FEAT_EVAL
9294 save_current_SID = current_SID;
9295
Bram Moolenaar05159a02005-02-26 23:04:13 +00009296# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00009297 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00009298 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
9299# endif
9300
Bram Moolenaar071d4272004-06-13 20:20:40 +00009301 /* Don't use local function variables, if called from a function */
9302 save_funccalp = save_funccal();
9303#endif
9304
9305 /*
9306 * When starting to execute autocommands, save the search patterns.
9307 */
9308 if (!autocmd_busy)
9309 {
9310 save_search_patterns();
9311 saveRedobuff();
9312 did_filetype = keep_filetype;
9313 }
9314
9315 /*
9316 * Note that we are applying autocmds. Some commands need to know.
9317 */
9318 autocmd_busy = TRUE;
9319 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
9320 ++nesting; /* see matching decrement below */
9321
9322 /* Remember that FileType was triggered. Used for did_filetype(). */
9323 if (event == EVENT_FILETYPE)
9324 did_filetype = TRUE;
9325
9326 tail = gettail(fname);
9327
9328 /* Find first autocommand that matches */
9329 patcmd.curpat = first_autopat[(int)event];
9330 patcmd.nextcmd = NULL;
9331 patcmd.group = group;
9332 patcmd.fname = fname;
9333 patcmd.sfname = sfname;
9334 patcmd.tail = tail;
9335 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009336 patcmd.arg_bufnr = autocmd_bufnr;
9337 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009338 auto_next_pat(&patcmd, FALSE);
9339
9340 /* found one, start executing the autocommands */
9341 if (patcmd.curpat != NULL)
9342 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009343 /* add to active_apc_list */
9344 patcmd.next = active_apc_list;
9345 active_apc_list = &patcmd;
9346
Bram Moolenaar071d4272004-06-13 20:20:40 +00009347#ifdef FEAT_EVAL
9348 /* set v:cmdarg (only when there is a matching pattern) */
9349 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
9350 if (eap != NULL)
9351 {
9352 save_cmdarg = set_cmdarg(eap, NULL);
9353 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
9354 }
9355 else
9356 save_cmdarg = NULL; /* avoid gcc warning */
9357#endif
9358 retval = TRUE;
9359 /* mark the last pattern, to avoid an endless loop when more patterns
9360 * are added when executing autocommands */
9361 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
9362 ap->last = FALSE;
9363 ap->last = TRUE;
9364 check_lnums(TRUE); /* make sure cursor and topline are valid */
9365 do_cmdline(NULL, getnextac, (void *)&patcmd,
9366 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
9367#ifdef FEAT_EVAL
9368 if (eap != NULL)
9369 {
9370 (void)set_cmdarg(NULL, save_cmdarg);
9371 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
9372 }
9373#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009374 /* delete from active_apc_list */
9375 if (active_apc_list == &patcmd) /* just in case */
9376 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009377 }
9378
9379 --RedrawingDisabled;
9380 autocmd_busy = save_autocmd_busy;
9381 filechangeshell_busy = FALSE;
9382 autocmd_nested = save_autocmd_nested;
9383 vim_free(sourcing_name);
9384 sourcing_name = save_sourcing_name;
9385 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaara0174af2008-01-02 20:08:25 +00009386 vim_free(autocmd_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009387 autocmd_fname = save_autocmd_fname;
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009388 autocmd_fname_full = save_autocmd_fname_full;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009389 autocmd_bufnr = save_autocmd_bufnr;
9390 autocmd_match = save_autocmd_match;
9391#ifdef FEAT_EVAL
9392 current_SID = save_current_SID;
9393 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00009394# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00009395 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00009396 prof_child_exit(&wait_time);
9397# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00009398#endif
9399 vim_free(fname);
9400 vim_free(sfname);
9401 --nesting; /* see matching increment above */
9402
9403 /*
9404 * When stopping to execute autocommands, restore the search patterns and
9405 * the redo buffer.
9406 */
9407 if (!autocmd_busy)
9408 {
9409 restore_search_patterns();
9410 restoreRedobuff();
9411 did_filetype = FALSE;
9412 }
9413
9414 /*
9415 * Some events don't set or reset the Changed flag.
9416 * Check if still in the same buffer!
9417 */
9418 if (curbuf == old_curbuf
9419 && (event == EVENT_BUFREADPOST
9420 || event == EVENT_BUFWRITEPOST
9421 || event == EVENT_FILEAPPENDPOST
9422 || event == EVENT_VIMLEAVE
9423 || event == EVENT_VIMLEAVEPRE))
9424 {
9425#ifdef FEAT_TITLE
9426 if (curbuf->b_changed != save_changed)
9427 need_maketitle = TRUE;
9428#endif
9429 curbuf->b_changed = save_changed;
9430 }
9431
9432 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009433
9434BYPASS_AU:
9435 /* When wiping out a buffer make sure all its buffer-local autocommands
9436 * are deleted. */
9437 if (event == EVENT_BUFWIPEOUT && buf != NULL)
9438 aubuflocal_remove(buf);
9439
Bram Moolenaar071d4272004-06-13 20:20:40 +00009440 return retval;
9441}
9442
Bram Moolenaar78ab3312007-09-29 12:16:41 +00009443# ifdef FEAT_EVAL
9444static char_u *old_termresponse = NULL;
9445# endif
9446
9447/*
9448 * Block triggering autocommands until unblock_autocmd() is called.
9449 * Can be used recursively, so long as it's symmetric.
9450 */
9451 void
9452block_autocmds()
9453{
9454# ifdef FEAT_EVAL
9455 /* Remember the value of v:termresponse. */
9456 if (autocmd_blocked == 0)
9457 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
9458# endif
9459 ++autocmd_blocked;
9460}
9461
9462 void
9463unblock_autocmds()
9464{
9465 --autocmd_blocked;
9466
9467# ifdef FEAT_EVAL
9468 /* When v:termresponse was set while autocommands were blocked, trigger
9469 * the autocommands now. Esp. useful when executing a shell command
9470 * during startup (vimdiff). */
9471 if (autocmd_blocked == 0
9472 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
9473 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
9474# endif
9475}
9476
Bram Moolenaar071d4272004-06-13 20:20:40 +00009477/*
9478 * Find next autocommand pattern that matches.
9479 */
9480 static void
9481auto_next_pat(apc, stop_at_last)
9482 AutoPatCmd *apc;
9483 int stop_at_last; /* stop when 'last' flag is set */
9484{
9485 AutoPat *ap;
9486 AutoCmd *cp;
9487 char_u *name;
9488 char *s;
9489
9490 vim_free(sourcing_name);
9491 sourcing_name = NULL;
9492
9493 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
9494 {
9495 apc->curpat = NULL;
9496
Bram Moolenaarf6dad432008-09-18 19:29:58 +00009497 /* Only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009498 * the group matches. For buffer-local autocommands only check the
9499 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009500 if (ap->pat != NULL && ap->cmds != NULL
9501 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
9502 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009503 /* execution-condition */
9504 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00009505 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
9506 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009507 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009508 {
9509 name = event_nr2name(apc->event);
9510 s = _("%s Auto commands for \"%s\"");
9511 sourcing_name = alloc((unsigned)(STRLEN(s)
9512 + STRLEN(name) + ap->patlen + 1));
9513 if (sourcing_name != NULL)
9514 {
9515 sprintf((char *)sourcing_name, s,
9516 (char *)name, (char *)ap->pat);
9517 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009518 {
9519 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00009520 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009521 verbose_leave();
9522 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009523 }
9524
9525 apc->curpat = ap;
9526 apc->nextcmd = ap->cmds;
9527 /* mark last command */
9528 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
9529 cp->last = FALSE;
9530 cp->last = TRUE;
9531 }
9532 line_breakcheck();
9533 if (apc->curpat != NULL) /* found a match */
9534 break;
9535 }
9536 if (stop_at_last && ap->last)
9537 break;
9538 }
9539}
9540
9541/*
9542 * Get next autocommand command.
9543 * Called by do_cmdline() to get the next line for ":if".
9544 * Returns allocated string, or NULL for end of autocommands.
9545 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009546 static char_u *
9547getnextac(c, cookie, indent)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009548 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009549 void *cookie;
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009550 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009551{
9552 AutoPatCmd *acp = (AutoPatCmd *)cookie;
9553 char_u *retval;
9554 AutoCmd *ac;
9555
9556 /* Can be called again after returning the last line. */
9557 if (acp->curpat == NULL)
9558 return NULL;
9559
9560 /* repeat until we find an autocommand to execute */
9561 for (;;)
9562 {
9563 /* skip removed commands */
9564 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
9565 if (acp->nextcmd->last)
9566 acp->nextcmd = NULL;
9567 else
9568 acp->nextcmd = acp->nextcmd->next;
9569
9570 if (acp->nextcmd != NULL)
9571 break;
9572
9573 /* at end of commands, find next pattern that matches */
9574 if (acp->curpat->last)
9575 acp->curpat = NULL;
9576 else
9577 acp->curpat = acp->curpat->next;
9578 if (acp->curpat != NULL)
9579 auto_next_pat(acp, TRUE);
9580 if (acp->curpat == NULL)
9581 return NULL;
9582 }
9583
9584 ac = acp->nextcmd;
9585
9586 if (p_verbose >= 9)
9587 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009588 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00009589 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009590 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00009591 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00009592 }
9593 retval = vim_strsave(ac->cmd);
9594 autocmd_nested = ac->nested;
9595#ifdef FEAT_EVAL
9596 current_SID = ac->scriptID;
9597#endif
9598 if (ac->last)
9599 acp->nextcmd = NULL;
9600 else
9601 acp->nextcmd = ac->next;
9602 return retval;
9603}
9604
9605/*
9606 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009607 * To account for buffer-local autocommands, function needs to know
9608 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009609 */
9610 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009611has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00009612 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009613 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009614 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009615{
9616 AutoPat *ap;
9617 char_u *fname;
9618 char_u *tail = gettail(sfname);
9619 int retval = FALSE;
9620
9621 fname = FullName_save(sfname, FALSE);
9622 if (fname == NULL)
9623 return FALSE;
9624
9625#ifdef BACKSLASH_IN_FILENAME
9626 /*
9627 * Replace all backslashes with forward slashes. This makes the
9628 * autocommand patterns portable between Unix and MS-DOS.
9629 */
9630 sfname = vim_strsave(sfname);
9631 if (sfname != NULL)
9632 forward_slash(sfname);
9633 forward_slash(fname);
9634#endif
9635
9636 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
9637 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009638 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00009639 ? match_file_pat(NULL, ap->reg_prog,
9640 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009641 : buf != NULL && ap->buflocal_nr == buf->b_fnum
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009642 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009643 {
9644 retval = TRUE;
9645 break;
9646 }
9647
9648 vim_free(fname);
9649#ifdef BACKSLASH_IN_FILENAME
9650 vim_free(sfname);
9651#endif
9652
9653 return retval;
9654}
9655
9656#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
9657/*
9658 * Function given to ExpandGeneric() to obtain the list of autocommand group
9659 * names.
9660 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009661 char_u *
9662get_augroup_name(xp, idx)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009663 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009664 int idx;
9665{
9666 if (idx == augroups.ga_len) /* add "END" add the end */
9667 return (char_u *)"END";
9668 if (idx >= augroups.ga_len) /* end of list */
9669 return NULL;
9670 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
9671 return (char_u *)"";
9672 return AUGROUP_NAME(idx); /* return a name */
9673}
9674
9675static int include_groups = FALSE;
9676
9677 char_u *
9678set_context_in_autocmd(xp, arg, doautocmd)
9679 expand_T *xp;
9680 char_u *arg;
Bram Moolenaard812df62008-11-09 12:46:09 +00009681 int doautocmd; /* TRUE for :doauto*, FALSE for :autocmd */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009682{
9683 char_u *p;
9684 int group;
9685
9686 /* check for a group name, skip it if present */
9687 include_groups = FALSE;
9688 p = arg;
9689 group = au_get_grouparg(&arg);
9690 if (group == AUGROUP_ERROR)
9691 return NULL;
9692 /* If there only is a group name that's what we expand. */
9693 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
9694 {
9695 arg = p;
9696 group = AUGROUP_ALL;
9697 }
9698
9699 /* skip over event name */
9700 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
9701 if (*p == ',')
9702 arg = p + 1;
9703 if (*p == NUL)
9704 {
9705 if (group == AUGROUP_ALL)
9706 include_groups = TRUE;
9707 xp->xp_context = EXPAND_EVENTS; /* expand event name */
9708 xp->xp_pattern = arg;
9709 return NULL;
9710 }
9711
9712 /* skip over pattern */
9713 arg = skipwhite(p);
9714 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
9715 arg++;
9716 if (*arg)
9717 return arg; /* expand (next) command */
9718
9719 if (doautocmd)
9720 xp->xp_context = EXPAND_FILES; /* expand file names */
9721 else
9722 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
9723 return NULL;
9724}
9725
9726/*
9727 * Function given to ExpandGeneric() to obtain the list of event names.
9728 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009729 char_u *
9730get_event_name(xp, idx)
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00009731 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009732 int idx;
9733{
9734 if (idx < augroups.ga_len) /* First list group names, if wanted */
9735 {
9736 if (!include_groups || AUGROUP_NAME(idx) == NULL)
9737 return (char_u *)""; /* skip deleted entries */
9738 return AUGROUP_NAME(idx); /* return a name */
9739 }
9740 return (char_u *)event_names[idx - augroups.ga_len].name;
9741}
9742
9743#endif /* FEAT_CMDL_COMPL */
9744
9745/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009746 * Return TRUE if autocmd is supported.
9747 */
9748 int
9749autocmd_supported(name)
9750 char_u *name;
9751{
9752 char_u *p;
9753
9754 return (event_name2nr(name, &p) != NUM_EVENTS);
9755}
9756
9757/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00009758 * Return TRUE if an autocommand is defined for a group, event and
9759 * pattern: The group can be omitted to accept any group. "event" and "pattern"
9760 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
9761 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
9762 * Used for:
9763 * exists("#Group") or
9764 * exists("#Group#Event") or
9765 * exists("#Group#Event#pat") or
9766 * exists("#Event") or
9767 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00009768 */
9769 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00009770au_exists(arg)
9771 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009772{
Bram Moolenaar195d6352005-12-19 22:08:24 +00009773 char_u *arg_save;
9774 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009775 char_u *event_name;
9776 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00009777 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009778 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009779 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00009780 int group;
9781 int retval = FALSE;
9782
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009783 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009784 arg_save = vim_strsave(arg);
9785 if (arg_save == NULL)
9786 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009787 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00009788 if (p != NULL)
9789 *p++ = NUL;
9790
9791 /* First, look for an autocmd group name */
9792 group = au_find_group(arg_save);
9793 if (group == AUGROUP_ERROR)
9794 {
9795 /* Didn't match a group name, assume the first argument is an event. */
9796 group = AUGROUP_ALL;
9797 event_name = arg_save;
9798 }
9799 else
9800 {
9801 if (p == NULL)
9802 {
9803 /* "Group": group name is present and it's recognized */
9804 retval = TRUE;
9805 goto theend;
9806 }
9807
9808 /* Must be "Group#Event" or "Group#Event#pat". */
9809 event_name = p;
9810 p = vim_strchr(event_name, '#');
9811 if (p != NULL)
9812 *p++ = NUL; /* "Group#Event#pat" */
9813 }
9814
9815 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009816
9817 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009818 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009819
9820 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009821 if (event == NUM_EVENTS)
9822 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009823
9824 /* Find the first autocommand for this event.
9825 * If there isn't any, return FALSE;
9826 * If there is one and no pattern given, return TRUE; */
9827 ap = first_autopat[(int)event];
9828 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009829 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009830
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009831 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
9832 /* for pattern "<buffer=N>, fnamecmp() will work fine */
Bram Moolenaar5b7880d2009-09-11 15:24:31 +00009833 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009834 buflocal_buf = curbuf;
9835
Bram Moolenaar071d4272004-06-13 20:20:40 +00009836 /* Check if there is an autocommand with the given pattern. */
9837 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009838 /* only use a pattern when it has not been removed and has commands. */
9839 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009840 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009841 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaar5b7880d2009-09-11 15:24:31 +00009842 && (pattern == NULL
9843 || (buflocal_buf == NULL
9844 ? fnamecmp(ap->pat, pattern) == 0
9845 : ap->buflocal_nr == buflocal_buf->b_fnum)))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009846 {
9847 retval = TRUE;
9848 break;
9849 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009850
Bram Moolenaar195d6352005-12-19 22:08:24 +00009851theend:
9852 vim_free(arg_save);
9853 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009854}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009855
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009856#else /* FEAT_AUTOCMD */
9857
9858/*
9859 * Prepare for executing commands for (hidden) buffer "buf".
9860 * This is the non-autocommand version, it simply saves "curbuf" and sets
9861 * "curbuf" and "curwin" to match "buf".
9862 */
9863 void
9864aucmd_prepbuf(aco, buf)
9865 aco_save_T *aco; /* structure to save values in */
9866 buf_T *buf; /* new curbuf */
9867{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009868 aco->save_curbuf = curbuf;
9869 --curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009870 curbuf = buf;
9871 curwin->w_buffer = buf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009872 ++curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009873}
9874
9875/*
9876 * Restore after executing commands for a (hidden) buffer.
9877 * This is the non-autocommand version.
9878 */
9879 void
9880aucmd_restbuf(aco)
9881 aco_save_T *aco; /* structure holding saved values */
9882{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009883 --curbuf->b_nwindows;
9884 curbuf = aco->save_curbuf;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009885 curwin->w_buffer = curbuf;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00009886 ++curbuf->b_nwindows;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009887}
9888
Bram Moolenaar071d4272004-06-13 20:20:40 +00009889#endif /* FEAT_AUTOCMD */
9890
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009891
Bram Moolenaar071d4272004-06-13 20:20:40 +00009892#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9893/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009894 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9895 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9896 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009897 * Used for autocommands and 'wildignore'.
9898 * Returns TRUE if there is a match, FALSE otherwise.
9899 */
9900 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009901match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009902 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009903 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009904 char_u *fname; /* full path of file name */
9905 char_u *sfname; /* short file name or NULL */
9906 char_u *tail; /* tail of path */
9907 int allow_dirs; /* allow matching with dir */
9908{
9909 regmatch_T regmatch;
9910 int result = FALSE;
9911#ifdef FEAT_OSFILETYPE
9912 int no_pattern = FALSE; /* TRUE if check is filetype only */
9913 char_u *type_start;
9914 char_u c;
9915 int match = FALSE;
9916#endif
9917
9918#ifdef CASE_INSENSITIVE_FILENAME
9919 regmatch.rm_ic = TRUE; /* Always ignore case */
9920#else
9921 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9922#endif
9923#ifdef FEAT_OSFILETYPE
9924 if (*pattern == '<')
9925 {
9926 /* There is a filetype condition specified with this pattern.
9927 * Check the filetype matches first. If not, don't bother with the
9928 * pattern (set regprog to NULL).
9929 * Always use magic for the regexp.
9930 */
9931
9932 for (type_start = pattern + 1; (c = *pattern); pattern++)
9933 {
9934 if ((c == ';' || c == '>') && match == FALSE)
9935 {
9936 *pattern = NUL; /* Terminate the string */
9937 match = mch_check_filetype(fname, type_start);
9938 *pattern = c; /* Restore the terminator */
9939 type_start = pattern + 1;
9940 }
9941 if (c == '>')
9942 break;
9943 }
9944
9945 /* (c should never be NUL, but check anyway) */
9946 if (match == FALSE || c == NUL)
9947 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9948 else if (*pattern == NUL)
9949 {
9950 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9951 no_pattern = TRUE; /* Always matches - don't check pat. */
9952 }
9953 else
9954 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9955 }
9956 else
9957#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009958 {
9959 if (prog != NULL)
9960 regmatch.regprog = prog;
9961 else
9962 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9963 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009964
9965 /*
9966 * Try for a match with the pattern with:
9967 * 1. the full file name, when the pattern has a '/'.
9968 * 2. the short file name, when the pattern has a '/'.
9969 * 3. the tail of the file name, when the pattern has no '/'.
9970 */
9971 if (
9972#ifdef FEAT_OSFILETYPE
9973 /* If the check is for a filetype only and we don't care
9974 * about the path then skip all the regexp stuff.
9975 */
9976 no_pattern ||
9977#endif
9978 (regmatch.regprog != NULL
9979 && ((allow_dirs
9980 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9981 || (sfname != NULL
9982 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9983 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9984 result = TRUE;
9985
Bram Moolenaar748bf032005-02-02 23:04:36 +00009986 if (prog == NULL)
9987 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009988 return result;
9989}
9990#endif
9991
9992#if defined(FEAT_WILDIGN) || defined(PROTO)
9993/*
9994 * Return TRUE if a file matches with a pattern in "list".
9995 * "list" is a comma-separated list of patterns, like 'wildignore'.
9996 * "sfname" is the short file name or NULL, "ffname" the long file name.
9997 */
9998 int
9999match_file_list(list, sfname, ffname)
10000 char_u *list;
10001 char_u *sfname;
10002 char_u *ffname;
10003{
10004 char_u buf[100];
10005 char_u *tail;
10006 char_u *regpat;
10007 char allow_dirs;
10008 int match;
10009 char_u *p;
10010
10011 tail = gettail(sfname);
10012
10013 /* try all patterns in 'wildignore' */
10014 p = list;
10015 while (*p)
10016 {
10017 copy_option_part(&p, buf, 100, ",");
10018 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
10019 if (regpat == NULL)
10020 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +000010021 match = match_file_pat(regpat, NULL, ffname, sfname,
10022 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +000010023 vim_free(regpat);
10024 if (match)
10025 return TRUE;
10026 }
10027 return FALSE;
10028}
10029#endif
10030
10031/*
10032 * Convert the given pattern "pat" which has shell style wildcards in it, into
10033 * a regular expression, and return the result in allocated memory. If there
10034 * is a directory path separator to be matched, then TRUE is put in
10035 * allow_dirs, otherwise FALSE is put there -- webb.
10036 * Handle backslashes before special characters, like "\*" and "\ ".
10037 *
10038 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
10039 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
10040 *
10041 * Returns NULL when out of memory.
10042 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010043 char_u *
10044file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
10045 char_u *pat;
10046 char_u *pat_end; /* first char after pattern or NULL */
10047 char *allow_dirs; /* Result passed back out in here */
Bram Moolenaar78a15312009-05-15 19:33:18 +000010048 int no_bslash UNUSED; /* Don't use a backward slash as pathsep */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010049{
10050 int size;
10051 char_u *endp;
10052 char_u *reg_pat;
10053 char_u *p;
10054 int i;
10055 int nested = 0;
10056 int add_dollar = TRUE;
10057#ifdef FEAT_OSFILETYPE
10058 int check_length = 0;
10059#endif
10060
10061 if (allow_dirs != NULL)
10062 *allow_dirs = FALSE;
10063 if (pat_end == NULL)
10064 pat_end = pat + STRLEN(pat);
10065
10066#ifdef FEAT_OSFILETYPE
10067 /* Find out how much of the string is the filetype check */
10068 if (*pat == '<')
10069 {
10070 /* Count chars until the next '>' */
10071 for (p = pat + 1; p < pat_end && *p != '>'; p++)
10072 ;
10073 if (p < pat_end)
10074 {
10075 /* Pattern is of the form <.*>.* */
10076 check_length = p - pat + 1;
10077 if (p + 1 >= pat_end)
10078 {
10079 /* The 'pattern' is a filetype check ONLY */
10080 reg_pat = (char_u *)alloc(check_length + 1);
10081 if (reg_pat != NULL)
10082 {
10083 mch_memmove(reg_pat, pat, (size_t)check_length);
10084 reg_pat[check_length] = NUL;
10085 }
10086 return reg_pat;
10087 }
10088 }
10089 /* else: there was no closing '>' - assume it was a normal pattern */
10090
10091 }
10092 pat += check_length;
10093 size = 2 + check_length;
10094#else
10095 size = 2; /* '^' at start, '$' at end */
10096#endif
10097
10098 for (p = pat; p < pat_end; p++)
10099 {
10100 switch (*p)
10101 {
10102 case '*':
10103 case '.':
10104 case ',':
10105 case '{':
10106 case '}':
10107 case '~':
10108 size += 2; /* extra backslash */
10109 break;
10110#ifdef BACKSLASH_IN_FILENAME
10111 case '\\':
10112 case '/':
10113 size += 4; /* could become "[\/]" */
10114 break;
10115#endif
10116 default:
10117 size++;
10118# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000010119 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010120 {
10121 ++p;
10122 ++size;
10123 }
10124# endif
10125 break;
10126 }
10127 }
10128 reg_pat = alloc(size + 1);
10129 if (reg_pat == NULL)
10130 return NULL;
10131
10132#ifdef FEAT_OSFILETYPE
10133 /* Copy the type check in to the start. */
10134 if (check_length)
10135 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
10136 i = check_length;
10137#else
10138 i = 0;
10139#endif
10140
10141 if (pat[0] == '*')
10142 while (pat[0] == '*' && pat < pat_end - 1)
10143 pat++;
10144 else
10145 reg_pat[i++] = '^';
10146 endp = pat_end - 1;
10147 if (*endp == '*')
10148 {
10149 while (endp - pat > 0 && *endp == '*')
10150 endp--;
10151 add_dollar = FALSE;
10152 }
10153 for (p = pat; *p && nested >= 0 && p <= endp; p++)
10154 {
10155 switch (*p)
10156 {
10157 case '*':
10158 reg_pat[i++] = '.';
10159 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +000010160 while (p[1] == '*') /* "**" matches like "*" */
10161 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010162 break;
10163 case '.':
Bram Moolenaar071d4272004-06-13 20:20:40 +000010164 case '~':
10165 reg_pat[i++] = '\\';
10166 reg_pat[i++] = *p;
10167 break;
10168 case '?':
Bram Moolenaar071d4272004-06-13 20:20:40 +000010169 reg_pat[i++] = '.';
10170 break;
10171 case '\\':
10172 if (p[1] == NUL)
10173 break;
10174#ifdef BACKSLASH_IN_FILENAME
10175 if (!no_bslash)
10176 {
10177 /* translate:
10178 * "\x" to "\\x" e.g., "dir\file"
10179 * "\*" to "\\.*" e.g., "dir\*.c"
10180 * "\?" to "\\." e.g., "dir\??.c"
10181 * "\+" to "\+" e.g., "fileX\+.c"
10182 */
10183 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
10184 && p[1] != '+')
10185 {
10186 reg_pat[i++] = '[';
10187 reg_pat[i++] = '\\';
10188 reg_pat[i++] = '/';
10189 reg_pat[i++] = ']';
10190 if (allow_dirs != NULL)
10191 *allow_dirs = TRUE;
10192 break;
10193 }
10194 }
10195#endif
Bram Moolenaar8cd213c2010-06-01 21:57:09 +020010196 /* Undo escaping from ExpandEscape():
10197 * foo\?bar -> foo?bar
10198 * foo\%bar -> foo%bar
10199 * foo\,bar -> foo,bar
10200 * foo\ bar -> foo bar
10201 * Don't unescape \, * and others that are also special in a
10202 * regexp. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000010203 if (*++p == '?'
10204#ifdef BACKSLASH_IN_FILENAME
10205 && no_bslash
10206#endif
10207 )
10208 reg_pat[i++] = '?';
10209 else
Bram Moolenaar8cd213c2010-06-01 21:57:09 +020010210 if (*p == ',' || *p == '%' || *p == '#' || *p == ' ')
10211 reg_pat[i++] = *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +000010212 else
10213 {
10214 if (allow_dirs != NULL && vim_ispathsep(*p)
10215#ifdef BACKSLASH_IN_FILENAME
10216 && (!no_bslash || *p != '\\')
10217#endif
10218 )
10219 *allow_dirs = TRUE;
10220 reg_pat[i++] = '\\';
10221 reg_pat[i++] = *p;
10222 }
10223 break;
10224#ifdef BACKSLASH_IN_FILENAME
10225 case '/':
10226 reg_pat[i++] = '[';
10227 reg_pat[i++] = '\\';
10228 reg_pat[i++] = '/';
10229 reg_pat[i++] = ']';
10230 if (allow_dirs != NULL)
10231 *allow_dirs = TRUE;
10232 break;
10233#endif
10234 case '{':
10235 reg_pat[i++] = '\\';
10236 reg_pat[i++] = '(';
10237 nested++;
10238 break;
10239 case '}':
10240 reg_pat[i++] = '\\';
10241 reg_pat[i++] = ')';
10242 --nested;
10243 break;
10244 case ',':
10245 if (nested)
10246 {
10247 reg_pat[i++] = '\\';
10248 reg_pat[i++] = '|';
10249 }
10250 else
10251 reg_pat[i++] = ',';
10252 break;
10253 default:
10254# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +000010255 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +000010256 reg_pat[i++] = *p++;
10257 else
10258# endif
10259 if (allow_dirs != NULL && vim_ispathsep(*p))
10260 *allow_dirs = TRUE;
10261 reg_pat[i++] = *p;
10262 break;
10263 }
10264 }
10265 if (add_dollar)
10266 reg_pat[i++] = '$';
10267 reg_pat[i] = NUL;
10268 if (nested != 0)
10269 {
10270 if (nested < 0)
10271 EMSG(_("E219: Missing {."));
10272 else
10273 EMSG(_("E220: Missing }."));
10274 vim_free(reg_pat);
10275 reg_pat = NULL;
10276 }
10277 return reg_pat;
10278}
Bram Moolenaar540fc6f2010-12-17 16:27:16 +010010279
10280#if defined(EINTR) || defined(PROTO)
10281/*
10282 * Version of read() that retries when interrupted by EINTR (possibly
10283 * by a SIGWINCH).
10284 */
10285 long
10286read_eintr(fd, buf, bufsize)
10287 int fd;
10288 void *buf;
10289 size_t bufsize;
10290{
10291 long ret;
10292
10293 for (;;)
10294 {
10295 ret = vim_read(fd, buf, bufsize);
10296 if (ret >= 0 || errno != EINTR)
10297 break;
10298 }
10299 return ret;
10300}
10301
10302/*
10303 * Version of write() that retries when interrupted by EINTR (possibly
10304 * by a SIGWINCH).
10305 */
10306 long
10307write_eintr(fd, buf, bufsize)
10308 int fd;
10309 void *buf;
10310 size_t bufsize;
10311{
10312 long ret = 0;
10313 long wlen;
10314
10315 /* Repeat the write() so long it didn't fail, other than being interrupted
10316 * by a signal. */
10317 while (ret < (long)bufsize)
10318 {
Bram Moolenaar9c263032010-12-17 18:06:06 +010010319 wlen = vim_write(fd, (char *)buf + ret, bufsize - ret);
Bram Moolenaar540fc6f2010-12-17 16:27:16 +010010320 if (wlen < 0)
10321 {
10322 if (errno != EINTR)
10323 break;
10324 }
10325 else
10326 ret += wlen;
10327 }
10328 return ret;
10329}
10330#endif