blob: 95970a3fdb83793ad868f4e8725f8ab62f30c7c0 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * fileio.c: read from and write to a file
12 */
13
14#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000015# include "vimio.h" /* for lseek(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#if defined __EMX__
Bram Moolenaar362e1a32006-03-06 23:29:24 +000019# include "vimio.h" /* for mktemp(), CJW 1997-12-03 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000020#endif
21
22#include "vim.h"
23
24#ifdef HAVE_FCNTL_H
25# include <fcntl.h>
26#endif
27
28#ifdef __TANDEM
29# include <limits.h> /* for SSIZE_MAX */
30#endif
31
32#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
33# include <utime.h> /* for struct utimbuf */
34#endif
35
36#define BUFSIZE 8192 /* size of normal write buffer */
37#define SMBUFSIZE 256 /* size of emergency write buffer */
38
39#ifdef FEAT_CRYPT
40# define CRYPT_MAGIC "VimCrypt~01!" /* "01" is the version nr */
41# define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */
42#endif
43
44/* Is there any system that doesn't have access()? */
Bram Moolenaar9372a112005-12-06 19:59:18 +000045#define USE_MCH_ACCESS
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +000047#if defined(sun) && defined(S_ISCHR)
48# define OPEN_CHR_FILES
49static int is_dev_fd_file(char_u *fname);
50#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000051#ifdef FEAT_MBYTE
52static char_u *next_fenc __ARGS((char_u **pp));
53# ifdef FEAT_EVAL
54static char_u *readfile_charconvert __ARGS((char_u *fname, char_u *fenc, int *fdp));
55# endif
56#endif
57#ifdef FEAT_VIMINFO
58static void check_marks_read __ARGS((void));
59#endif
60#ifdef FEAT_CRYPT
61static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, long *filesizep, int newfile));
62#endif
63#ifdef UNIX
64static void set_file_time __ARGS((char_u *fname, time_t atime, time_t mtime));
65#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +000066static int set_rw_fname __ARGS((char_u *fname, char_u *sfname));
Bram Moolenaar071d4272004-06-13 20:20:40 +000067static int msg_add_fileformat __ARGS((int eol_type));
Bram Moolenaar071d4272004-06-13 20:20:40 +000068static void msg_add_eol __ARGS((void));
69static int check_mtime __ARGS((buf_T *buf, struct stat *s));
70static int time_differs __ARGS((long t1, long t2));
71#ifdef FEAT_AUTOCMD
Bram Moolenaar754b5602006-02-09 23:53:20 +000072static 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 +000073static int au_find_group __ARGS((char_u *name));
74
75# define AUGROUP_DEFAULT -1 /* default autocmd group */
76# define AUGROUP_ERROR -2 /* errornouse autocmd group */
77# define AUGROUP_ALL -3 /* all autocmd groups */
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#endif
79
80#if defined(FEAT_CRYPT) || defined(FEAT_MBYTE)
81# define HAS_BW_FLAGS
82# define FIO_LATIN1 0x01 /* convert Latin1 */
83# define FIO_UTF8 0x02 /* convert UTF-8 */
84# define FIO_UCS2 0x04 /* convert UCS-2 */
85# define FIO_UCS4 0x08 /* convert UCS-4 */
86# define FIO_UTF16 0x10 /* convert UTF-16 */
87# ifdef WIN3264
88# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
89# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
90# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
91# endif
92# ifdef MACOS_X
93# define FIO_MACROMAN 0x20 /* convert MacRoman */
94# endif
95# define FIO_ENDIAN_L 0x80 /* little endian */
96# define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
97# define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
98# define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
99# define FIO_ALL -1 /* allow all formats */
100#endif
101
102/* When converting, a read() or write() may leave some bytes to be converted
103 * for the next call. The value is guessed... */
104#define CONV_RESTLEN 30
105
106/* We have to guess how much a sequence of bytes may expand when converting
107 * with iconv() to be able to allocate a buffer. */
108#define ICONV_MULT 8
109
110/*
111 * Structure to pass arguments from buf_write() to buf_write_bytes().
112 */
113struct bw_info
114{
115 int bw_fd; /* file descriptor */
116 char_u *bw_buf; /* buffer with data to be written */
Bram Moolenaard089d9b2007-09-30 12:02:55 +0000117 int bw_len; /* length of data */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118#ifdef HAS_BW_FLAGS
119 int bw_flags; /* FIO_ flags */
120#endif
121#ifdef FEAT_MBYTE
122 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
123 int bw_restlen; /* nr of bytes in bw_rest[] */
124 int bw_first; /* first write call */
125 char_u *bw_conv_buf; /* buffer for writing converted chars */
126 int bw_conv_buflen; /* size of bw_conv_buf */
127 int bw_conv_error; /* set for conversion error */
128# 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));
139static int same_encoding __ARGS((char_u *a, char_u *b));
140static 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));
151
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000152
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 void
154filemess(buf, name, s, attr)
155 buf_T *buf;
156 char_u *name;
157 char_u *s;
158 int attr;
159{
160 int msg_scroll_save;
161
162 if (msg_silent != 0)
163 return;
164 msg_add_fname(buf, name); /* put file name in IObuff with quotes */
165 /* If it's extremely long, truncate it. */
166 if (STRLEN(IObuff) > IOSIZE - 80)
167 IObuff[IOSIZE - 80] = NUL;
168 STRCAT(IObuff, s);
169 /*
170 * For the first message may have to start a new line.
171 * For further ones overwrite the previous one, reset msg_scroll before
172 * calling filemess().
173 */
174 msg_scroll_save = msg_scroll;
175 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
176 msg_scroll = FALSE;
177 if (!msg_scroll) /* wait a bit when overwriting an error msg */
178 check_for_delay(FALSE);
179 msg_start();
180 msg_scroll = msg_scroll_save;
181 msg_scrolled_ign = TRUE;
182 /* may truncate the message to avoid a hit-return prompt */
183 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
184 msg_clr_eos();
185 out_flush();
186 msg_scrolled_ign = FALSE;
187}
188
189/*
190 * Read lines from file "fname" into the buffer after line "from".
191 *
192 * 1. We allocate blocks with lalloc, as big as possible.
193 * 2. Each block is filled with characters from the file with a single read().
194 * 3. The lines are inserted in the buffer with ml_append().
195 *
196 * (caller must check that fname != NULL, unless READ_STDIN is used)
197 *
198 * "lines_to_skip" is the number of lines that must be skipped
199 * "lines_to_read" is the number of lines that are appended
200 * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
201 *
202 * flags:
203 * READ_NEW starting to edit a new buffer
204 * READ_FILTER reading filter output
205 * READ_STDIN read from stdin instead of a file
206 * READ_BUFFER read from curbuf instead of a file (converting after reading
207 * stdin)
208 * READ_DUMMY read into a dummy buffer (to check if file contents changed)
209 *
210 * return FAIL for failure, OK otherwise
211 */
212 int
213readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
214 char_u *fname;
215 char_u *sfname;
216 linenr_T from;
217 linenr_T lines_to_skip;
218 linenr_T lines_to_read;
219 exarg_T *eap; /* can be NULL! */
220 int flags;
221{
222 int fd = 0;
223 int newfile = (flags & READ_NEW);
224 int check_readonly;
225 int filtering = (flags & READ_FILTER);
226 int read_stdin = (flags & READ_STDIN);
227 int read_buffer = (flags & READ_BUFFER);
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000228 int set_options = newfile || read_buffer
229 || (eap != NULL && eap->read_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
231 colnr_T read_buf_col = 0; /* next char to read from this line */
232 char_u c;
233 linenr_T lnum = from;
234 char_u *ptr = NULL; /* pointer into read buffer */
235 char_u *buffer = NULL; /* read buffer */
236 char_u *new_buffer = NULL; /* init to shut up gcc */
237 char_u *line_start = NULL; /* init to shut up gcc */
238 int wasempty; /* buffer was empty before reading */
239 colnr_T len;
240 long size = 0;
241 char_u *p;
242 long filesize = 0;
243 int skip_read = FALSE;
244#ifdef FEAT_CRYPT
245 char_u *cryptkey = NULL;
246#endif
247 int split = 0; /* number of split lines */
248#define UNKNOWN 0x0fffffff /* file size is unknown */
249 linenr_T linecnt;
250 int error = FALSE; /* errors encountered */
251 int ff_error = EOL_UNKNOWN; /* file format with errors */
252 long linerest = 0; /* remaining chars in line */
253#ifdef UNIX
254 int perm = 0;
255 int swap_mode = -1; /* protection bits for swap file */
256#else
257 int perm;
258#endif
259 int fileformat = 0; /* end-of-line format */
260 int keep_fileformat = FALSE;
261 struct stat st;
262 int file_readonly;
263 linenr_T skip_count = 0;
264 linenr_T read_count = 0;
265 int msg_save = msg_scroll;
266 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
267 * last read was missing the eol */
268 int try_mac = (vim_strchr(p_ffs, 'm') != NULL);
269 int try_dos = (vim_strchr(p_ffs, 'd') != NULL);
270 int try_unix = (vim_strchr(p_ffs, 'x') != NULL);
271 int file_rewind = FALSE;
272#ifdef FEAT_MBYTE
273 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000274 linenr_T conv_error = 0; /* line nr with conversion error */
275 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
277 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000278 int bad_char_behavior = BAD_REPLACE;
279 /* BAD_KEEP, BAD_DROP or character to
280 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000281 char_u *tmpname = NULL; /* name of 'charconvert' output file */
282 int fio_flags = 0;
283 char_u *fenc; /* fileencoding to use */
284 int fenc_alloced; /* fenc_next is in allocated memory */
285 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
286 int advance_fenc = FALSE;
287 long real_size = 0;
288# ifdef USE_ICONV
289 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
290# ifdef FEAT_EVAL
291 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
292 'charconvert' next */
293# endif
294# endif
295 int converted = FALSE; /* TRUE if conversion done */
296 int notconverted = FALSE; /* TRUE if conversion wanted but it
297 wasn't possible */
298 char_u conv_rest[CONV_RESTLEN];
299 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
300#endif
301
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 write_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303
304 /*
305 * If there is no file name yet, use the one for the read file.
306 * BF_NOTEDITED is set to reflect this.
307 * Don't do this for a read from a filter.
308 * Only do this when 'cpoptions' contains the 'f' flag.
309 */
310 if (curbuf->b_ffname == NULL
311 && !filtering
312 && fname != NULL
313 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
314 && !(flags & READ_DUMMY))
315 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000316 if (set_rw_fname(fname, sfname) == FAIL)
317 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318 }
319
Bram Moolenaardf177f62005-02-22 08:39:57 +0000320 /* After reading a file the cursor line changes but we don't want to
321 * display the line. */
322 ex_no_reprint = TRUE;
323
Bram Moolenaar55b7cf82006-09-09 12:52:42 +0000324 /* don't display the file info for another buffer now */
325 need_fileinfo = FALSE;
326
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327 /*
328 * For Unix: Use the short file name whenever possible.
329 * Avoids problems with networks and when directory names are changed.
330 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
331 * another directory, which we don't detect.
332 */
333 if (sfname == NULL)
334 sfname = fname;
335#if defined(UNIX) || defined(__EMX__)
336 fname = sfname;
337#endif
338
339#ifdef FEAT_AUTOCMD
340 /*
341 * The BufReadCmd and FileReadCmd events intercept the reading process by
342 * executing the associated commands instead.
343 */
344 if (!filtering && !read_stdin && !read_buffer)
345 {
346 pos_T pos;
347
348 pos = curbuf->b_op_start;
349
350 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
351 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
352 curbuf->b_op_start.col = 0;
353
354 if (newfile)
355 {
356 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
357 FALSE, curbuf, eap))
358#ifdef FEAT_EVAL
359 return aborting() ? FAIL : OK;
360#else
361 return OK;
362#endif
363 }
364 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
365 FALSE, NULL, eap))
366#ifdef FEAT_EVAL
367 return aborting() ? FAIL : OK;
368#else
369 return OK;
370#endif
371
372 curbuf->b_op_start = pos;
373 }
374#endif
375
376 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
377 msg_scroll = FALSE; /* overwrite previous file message */
378 else
379 msg_scroll = TRUE; /* don't overwrite previous file message */
380
381 /*
382 * If the name ends in a path separator, we can't open it. Check here,
383 * because reading the file may actually work, but then creating the swap
384 * file may destroy it! Reported on MS-DOS and Win 95.
385 * If the name is too long we might crash further on, quit here.
386 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000387 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000389 p = fname + STRLEN(fname);
390 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000391 {
392 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
393 msg_end();
394 msg_scroll = msg_save;
395 return FAIL;
396 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 }
398
399#ifdef UNIX
400 /*
401 * On Unix it is possible to read a directory, so we have to
402 * check for it before the mch_open().
403 */
404 if (!read_stdin && !read_buffer)
405 {
406 perm = mch_getperm(fname);
407 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
408# ifdef S_ISFIFO
409 && !S_ISFIFO(perm) /* ... or fifo */
410# endif
411# ifdef S_ISSOCK
412 && !S_ISSOCK(perm) /* ... or socket */
413# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +0000414# ifdef OPEN_CHR_FILES
415 && !(S_ISCHR(perm) && is_dev_fd_file(fname))
416 /* ... or a character special file named /dev/fd/<n> */
417# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 )
419 {
420 if (S_ISDIR(perm))
421 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
422 else
423 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
424 msg_end();
425 msg_scroll = msg_save;
426 return FAIL;
427 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000429# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
430 /*
431 * MS-Windows allows opening a device, but we will probably get stuck
432 * trying to read it.
433 */
434 if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
435 {
Bram Moolenaar5386a122007-06-28 20:02:32 +0000436 filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000437 msg_end();
438 msg_scroll = msg_save;
439 return FAIL;
440 }
441# endif
Bram Moolenaar043545e2006-10-10 16:44:07 +0000442 }
443#endif
444
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 /* set default 'fileformat' */
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000446 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447 {
448 if (eap != NULL && eap->force_ff != 0)
449 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
450 else if (*p_ffs != NUL)
451 set_fileformat(default_fileformat(), OPT_LOCAL);
452 }
453
454 /* set or reset 'binary' */
455 if (eap != NULL && eap->force_bin != 0)
456 {
457 int oldval = curbuf->b_p_bin;
458
459 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
460 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
461 }
462
463 /*
464 * When opening a new file we take the readonly flag from the file.
465 * Default is r/w, can be set to r/o below.
466 * Don't reset it when in readonly mode
467 * Only set/reset b_p_ro when BF_CHECK_RO is set.
468 */
469 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000470 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471 curbuf->b_p_ro = FALSE;
472
473 if (newfile && !read_stdin && !read_buffer)
474 {
475 /* Remember time of file.
476 * For RISCOS, also remember the filetype.
477 */
478 if (mch_stat((char *)fname, &st) >= 0)
479 {
480 buf_store_time(curbuf, &st, fname);
481 curbuf->b_mtime_read = curbuf->b_mtime;
482
483#if defined(RISCOS) && defined(FEAT_OSFILETYPE)
484 /* Read the filetype into the buffer local filetype option. */
485 mch_read_filetype(fname);
486#endif
487#ifdef UNIX
488 /*
489 * Use the protection bits of the original file for the swap file.
490 * This makes it possible for others to read the name of the
491 * edited file from the swapfile, but only if they can read the
492 * edited file.
493 * Remove the "write" and "execute" bits for group and others
494 * (they must not write the swapfile).
495 * Add the "read" and "write" bits for the user, otherwise we may
496 * not be able to write to the file ourselves.
497 * Setting the bits is done below, after creating the swap file.
498 */
499 swap_mode = (st.st_mode & 0644) | 0600;
500#endif
501#ifdef FEAT_CW_EDITOR
502 /* Get the FSSpec on MacOS
503 * TODO: Update it properly when the buffer name changes
504 */
505 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
506#endif
507#ifdef VMS
508 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000509 curbuf->b_fab_rat = st.st_fab_rat;
510 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511#endif
512 }
513 else
514 {
515 curbuf->b_mtime = 0;
516 curbuf->b_mtime_read = 0;
517 curbuf->b_orig_size = 0;
518 curbuf->b_orig_mode = 0;
519 }
520
521 /* Reset the "new file" flag. It will be set again below when the
522 * file doesn't exist. */
523 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
524 }
525
526/*
527 * for UNIX: check readonly with perm and mch_access()
528 * for RISCOS: same as Unix, otherwise file gets re-datestamped!
529 * for MSDOS and Amiga: check readonly by trying to open the file for writing
530 */
531 file_readonly = FALSE;
532 if (read_stdin)
533 {
534#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
535 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
536 setmode(0, O_BINARY);
537#endif
538 }
539 else if (!read_buffer)
540 {
541#ifdef USE_MCH_ACCESS
542 if (
543# ifdef UNIX
544 !(perm & 0222) ||
545# endif
546 mch_access((char *)fname, W_OK))
547 file_readonly = TRUE;
548 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
549#else
550 if (!newfile
551 || readonlymode
552 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
553 {
554 file_readonly = TRUE;
555 /* try to open ro */
556 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
557 }
558#endif
559 }
560
561 if (fd < 0) /* cannot open at all */
562 {
563#ifndef UNIX
564 int isdir_f;
565#endif
566 msg_scroll = msg_save;
567#ifndef UNIX
568 /*
569 * On MSDOS and Amiga we can't open a directory, check here.
570 */
571 isdir_f = (mch_isdir(fname));
572 perm = mch_getperm(fname); /* check if the file exists */
573 if (isdir_f)
574 {
575 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
576 curbuf->b_p_ro = TRUE; /* must use "w!" now */
577 }
578 else
579#endif
580 if (newfile)
581 {
582 if (perm < 0)
583 {
584 /*
585 * Set the 'new-file' flag, so that when the file has
586 * been created by someone else, a ":w" will complain.
587 */
588 curbuf->b_flags |= BF_NEW;
589
590 /* Create a swap file now, so that other Vims are warned
591 * that we are editing this file. Don't do this for a
592 * "nofile" or "nowrite" buffer type. */
593#ifdef FEAT_QUICKFIX
594 if (!bt_dontwrite(curbuf))
595#endif
596 check_need_swap(newfile);
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000597 if (dir_of_file_exists(fname))
598 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
599 else
600 filemess(curbuf, sfname,
601 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602#ifdef FEAT_VIMINFO
603 /* Even though this is a new file, it might have been
604 * edited before and deleted. Get the old marks. */
605 check_marks_read();
606#endif
607#ifdef FEAT_MBYTE
608 if (eap != NULL && eap->force_enc != 0)
609 {
610 /* set forced 'fileencoding' */
611 fenc = enc_canonize(eap->cmd + eap->force_enc);
612 if (fenc != NULL)
613 set_string_option_direct((char_u *)"fenc", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000614 fenc, OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 vim_free(fenc);
616 }
617#endif
618#ifdef FEAT_AUTOCMD
619 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
620 FALSE, curbuf, eap);
621#endif
622 /* remember the current fileformat */
623 save_file_ff(curbuf);
624
625#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
626 if (aborting()) /* autocmds may abort script processing */
627 return FAIL;
628#endif
629 return OK; /* a new file is not an error */
630 }
631 else
632 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000633 filemess(curbuf, sfname, (char_u *)(
634# ifdef EFBIG
635 (errno == EFBIG) ? _("[File too big]") :
636# endif
637 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 curbuf->b_p_ro = TRUE; /* must use "w!" now */
639 }
640 }
641
642 return FAIL;
643 }
644
645 /*
646 * Only set the 'ro' flag for readonly files the first time they are
647 * loaded. Help files always get readonly mode
648 */
649 if ((check_readonly && file_readonly) || curbuf->b_help)
650 curbuf->b_p_ro = TRUE;
651
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000652 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653 {
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000654 /* Don't change 'eol' if reading from buffer as it will already be
655 * correctly set when reading stdin. */
656 if (!read_buffer)
657 {
658 curbuf->b_p_eol = TRUE;
659 curbuf->b_start_eol = TRUE;
660 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661#ifdef FEAT_MBYTE
662 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000663 curbuf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664#endif
665 }
666
667 /* Create a swap file now, so that other Vims are warned that we are
668 * editing this file.
669 * Don't do this for a "nofile" or "nowrite" buffer type. */
670#ifdef FEAT_QUICKFIX
671 if (!bt_dontwrite(curbuf))
672#endif
673 {
674 check_need_swap(newfile);
675#ifdef UNIX
676 /* Set swap file protection bits after creating it. */
677 if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
678 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
679#endif
680 }
681
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000682#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 /* If "Quit" selected at ATTENTION dialog, don't load the file */
684 if (swap_exists_action == SEA_QUIT)
685 {
686 if (!read_buffer && !read_stdin)
687 close(fd);
688 return FAIL;
689 }
690#endif
691
692 ++no_wait_return; /* don't wait for return yet */
693
694 /*
695 * Set '[ mark to the line above where the lines go (line 1 if zero).
696 */
697 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
698 curbuf->b_op_start.col = 0;
699
700#ifdef FEAT_AUTOCMD
701 if (!read_buffer)
702 {
703 int m = msg_scroll;
704 int n = msg_scrolled;
705 buf_T *old_curbuf = curbuf;
706
707 /*
708 * The file must be closed again, the autocommands may want to change
709 * the file before reading it.
710 */
711 if (!read_stdin)
712 close(fd); /* ignore errors */
713
714 /*
715 * The output from the autocommands should not overwrite anything and
716 * should not be overwritten: Set msg_scroll, restore its value if no
717 * output was done.
718 */
719 msg_scroll = TRUE;
720 if (filtering)
721 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
722 FALSE, curbuf, eap);
723 else if (read_stdin)
724 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
725 FALSE, curbuf, eap);
726 else if (newfile)
727 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
728 FALSE, curbuf, eap);
729 else
730 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
731 FALSE, NULL, eap);
732 if (msg_scrolled == n)
733 msg_scroll = m;
734
735#ifdef FEAT_EVAL
736 if (aborting()) /* autocmds may abort script processing */
737 {
738 --no_wait_return;
739 msg_scroll = msg_save;
740 curbuf->b_p_ro = TRUE; /* must use "w!" now */
741 return FAIL;
742 }
743#endif
744 /*
745 * Don't allow the autocommands to change the current buffer.
746 * Try to re-open the file.
747 */
748 if (!read_stdin && (curbuf != old_curbuf
749 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
750 {
751 --no_wait_return;
752 msg_scroll = msg_save;
753 if (fd < 0)
754 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
755 else
756 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
757 curbuf->b_p_ro = TRUE; /* must use "w!" now */
758 return FAIL;
759 }
760 }
761#endif /* FEAT_AUTOCMD */
762
763 /* Autocommands may add lines to the file, need to check if it is empty */
764 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
765
766 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
767 {
768 /*
769 * Show the user that we are busy reading the input. Sometimes this
770 * may take a while. When reading from stdin another program may
771 * still be running, don't move the cursor to the last line, unless
772 * always using the GUI.
773 */
774 if (read_stdin)
775 {
776#ifndef ALWAYS_USE_GUI
777 mch_msg(_("Vim: Reading from stdin...\n"));
778#endif
779#ifdef FEAT_GUI
780 /* Also write a message in the GUI window, if there is one. */
781 if (gui.in_use && !gui.dying && !gui.starting)
782 {
783 p = (char_u *)_("Reading from stdin...");
784 gui_write(p, (int)STRLEN(p));
785 }
786#endif
787 }
788 else if (!read_buffer)
789 filemess(curbuf, sfname, (char_u *)"", 0);
790 }
791
792 msg_scroll = FALSE; /* overwrite the file message */
793
794 /*
795 * Set linecnt now, before the "retry" caused by a wrong guess for
796 * fileformat, and after the autocommands, which may change them.
797 */
798 linecnt = curbuf->b_ml.ml_line_count;
799
800#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000801 /* "++bad=" argument. */
802 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000803 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000804 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000805 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000806 curbuf->b_bad_char = eap->bad_char;
807 }
808 else
809 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000810
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000812 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 */
814 if (eap != NULL && eap->force_enc != 0)
815 {
816 fenc = enc_canonize(eap->cmd + eap->force_enc);
817 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000818 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 }
820 else if (curbuf->b_p_bin)
821 {
822 fenc = (char_u *)""; /* binary: don't convert */
823 fenc_alloced = FALSE;
824 }
825 else if (curbuf->b_help)
826 {
827 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000828 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829
830 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
831 * fails it must be latin1.
832 * Always do this when 'encoding' is "utf-8". Otherwise only do
833 * this when needed to avoid [converted] remarks all the time.
834 * It is needed when the first line contains non-ASCII characters.
835 * That is only in *.??x files. */
836 fenc = (char_u *)"latin1";
837 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000838 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000840 fc = fname[STRLEN(fname) - 1];
841 if (TOLOWER_ASC(fc) == 'x')
842 {
843 /* Read the first line (and a bit more). Immediately rewind to
844 * the start of the file. If the read() fails "len" is -1. */
845 len = vim_read(fd, firstline, 80);
846 lseek(fd, (off_t)0L, SEEK_SET);
847 for (p = firstline; p < firstline + len; ++p)
848 if (*p >= 0x80)
849 {
850 c = TRUE;
851 break;
852 }
853 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 }
855
856 if (c)
857 {
858 fenc_next = fenc;
859 fenc = (char_u *)"utf-8";
860
861 /* When the file is utf-8 but a character doesn't fit in
862 * 'encoding' don't retry. In help text editing utf-8 bytes
863 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000864 if (!enc_utf8)
865 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866 }
867 fenc_alloced = FALSE;
868 }
869 else if (*p_fencs == NUL)
870 {
871 fenc = curbuf->b_p_fenc; /* use format from buffer */
872 fenc_alloced = FALSE;
873 }
874 else
875 {
876 fenc_next = p_fencs; /* try items in 'fileencodings' */
877 fenc = next_fenc(&fenc_next);
878 fenc_alloced = TRUE;
879 }
880#endif
881
882 /*
883 * Jump back here to retry reading the file in different ways.
884 * Reasons to retry:
885 * - encoding conversion failed: try another one from "fenc_next"
886 * - BOM detected and fenc was set, need to setup conversion
887 * - "fileformat" check failed: try another
888 *
889 * Variables set for special retry actions:
890 * "file_rewind" Rewind the file to start reading it again.
891 * "advance_fenc" Advance "fenc" using "fenc_next".
892 * "skip_read" Re-use already read bytes (BOM detected).
893 * "did_iconv" iconv() conversion failed, try 'charconvert'.
894 * "keep_fileformat" Don't reset "fileformat".
895 *
896 * Other status indicators:
897 * "tmpname" When != NULL did conversion with 'charconvert'.
898 * Output file has to be deleted afterwards.
899 * "iconv_fd" When != -1 did conversion with iconv().
900 */
901retry:
902
903 if (file_rewind)
904 {
905 if (read_buffer)
906 {
907 read_buf_lnum = 1;
908 read_buf_col = 0;
909 }
910 else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0)
911 {
912 /* Can't rewind the file, give up. */
913 error = TRUE;
914 goto failed;
915 }
916 /* Delete the previously read lines. */
917 while (lnum > from)
918 ml_delete(lnum--, FALSE);
919 file_rewind = FALSE;
920#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000921 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000922 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000924 curbuf->b_start_bomb = FALSE;
925 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000926 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927#endif
928 }
929
930 /*
931 * When retrying with another "fenc" and the first time "fileformat"
932 * will be reset.
933 */
934 if (keep_fileformat)
935 keep_fileformat = FALSE;
936 else
937 {
938 if (eap != NULL && eap->force_ff != 0)
939 fileformat = get_fileformat_force(curbuf, eap);
940 else if (curbuf->b_p_bin)
941 fileformat = EOL_UNIX; /* binary: use Unix format */
942 else if (*p_ffs == NUL)
943 fileformat = get_fileformat(curbuf);/* use format from buffer */
944 else
945 fileformat = EOL_UNKNOWN; /* detect from file */
946 }
947
948#ifdef FEAT_MBYTE
949# ifdef USE_ICONV
950 if (iconv_fd != (iconv_t)-1)
951 {
952 /* aborted conversion with iconv(), close the descriptor */
953 iconv_close(iconv_fd);
954 iconv_fd = (iconv_t)-1;
955 }
956# endif
957
958 if (advance_fenc)
959 {
960 /*
961 * Try the next entry in 'fileencodings'.
962 */
963 advance_fenc = FALSE;
964
965 if (eap != NULL && eap->force_enc != 0)
966 {
967 /* Conversion given with "++cc=" wasn't possible, read
968 * without conversion. */
969 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000970 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 if (fenc_alloced)
972 vim_free(fenc);
973 fenc = (char_u *)"";
974 fenc_alloced = FALSE;
975 }
976 else
977 {
978 if (fenc_alloced)
979 vim_free(fenc);
980 if (fenc_next != NULL)
981 {
982 fenc = next_fenc(&fenc_next);
983 fenc_alloced = (fenc_next != NULL);
984 }
985 else
986 {
987 fenc = (char_u *)"";
988 fenc_alloced = FALSE;
989 }
990 }
991 if (tmpname != NULL)
992 {
993 mch_remove(tmpname); /* delete converted file */
994 vim_free(tmpname);
995 tmpname = NULL;
996 }
997 }
998
999 /*
1000 * Conversion is required when the encoding of the file is different
1001 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4 (requires
1002 * conversion to UTF-8).
1003 */
1004 fio_flags = 0;
1005 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
1006 if (converted || enc_unicode != 0)
1007 {
1008
1009 /* "ucs-bom" means we need to check the first bytes of the file
1010 * for a BOM. */
1011 if (STRCMP(fenc, ENC_UCSBOM) == 0)
1012 fio_flags = FIO_UCSBOM;
1013
1014 /*
1015 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
1016 * done. This is handled below after read(). Prepare the
1017 * fio_flags to avoid having to parse the string each time.
1018 * Also check for Unicode to Latin1 conversion, because iconv()
1019 * appears not to handle this correctly. This works just like
1020 * conversion to UTF-8 except how the resulting character is put in
1021 * the buffer.
1022 */
1023 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
1024 fio_flags = get_fio_flags(fenc);
1025
1026# ifdef WIN3264
1027 /*
1028 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
1029 * is handled with MultiByteToWideChar().
1030 */
1031 if (fio_flags == 0)
1032 fio_flags = get_win_fio_flags(fenc);
1033# endif
1034
1035# ifdef MACOS_X
1036 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1037 if (fio_flags == 0)
1038 fio_flags = get_mac_fio_flags(fenc);
1039# endif
1040
1041# ifdef USE_ICONV
1042 /*
1043 * Try using iconv() if we can't convert internally.
1044 */
1045 if (fio_flags == 0
1046# ifdef FEAT_EVAL
1047 && !did_iconv
1048# endif
1049 )
1050 iconv_fd = (iconv_t)my_iconv_open(
1051 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
1052# endif
1053
1054# ifdef FEAT_EVAL
1055 /*
1056 * Use the 'charconvert' expression when conversion is required
1057 * and we can't do it internally or with iconv().
1058 */
1059 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
1060# ifdef USE_ICONV
1061 && iconv_fd == (iconv_t)-1
1062# endif
1063 )
1064 {
1065# ifdef USE_ICONV
1066 did_iconv = FALSE;
1067# endif
1068 /* Skip conversion when it's already done (retry for wrong
1069 * "fileformat"). */
1070 if (tmpname == NULL)
1071 {
1072 tmpname = readfile_charconvert(fname, fenc, &fd);
1073 if (tmpname == NULL)
1074 {
1075 /* Conversion failed. Try another one. */
1076 advance_fenc = TRUE;
1077 if (fd < 0)
1078 {
1079 /* Re-opening the original file failed! */
1080 EMSG(_("E202: Conversion made file unreadable!"));
1081 error = TRUE;
1082 goto failed;
1083 }
1084 goto retry;
1085 }
1086 }
1087 }
1088 else
1089# endif
1090 {
1091 if (fio_flags == 0
1092# ifdef USE_ICONV
1093 && iconv_fd == (iconv_t)-1
1094# endif
1095 )
1096 {
1097 /* Conversion wanted but we can't.
1098 * Try the next conversion in 'fileencodings' */
1099 advance_fenc = TRUE;
1100 goto retry;
1101 }
1102 }
1103 }
1104
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001105 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001107 * stdin or fixed at a specific encoding. */
1108 can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109#endif
1110
1111 if (!skip_read)
1112 {
1113 linerest = 0;
1114 filesize = 0;
1115 skip_count = lines_to_skip;
1116 read_count = lines_to_read;
1117#ifdef FEAT_MBYTE
1118 conv_restlen = 0;
1119#endif
1120 }
1121
1122 while (!error && !got_int)
1123 {
1124 /*
1125 * We allocate as much space for the file as we can get, plus
1126 * space for the old line plus room for one terminating NUL.
1127 * The amount is limited by the fact that read() only can read
1128 * upto max_unsigned characters (and other things).
1129 */
1130#if SIZEOF_INT <= 2
1131 if (linerest >= 0x7ff0)
1132 {
1133 ++split;
1134 *ptr = NL; /* split line by inserting a NL */
1135 size = 1;
1136 }
1137 else
1138#endif
1139 {
1140 if (!skip_read)
1141 {
1142#if SIZEOF_INT > 2
Bram Moolenaar311d9822007-02-27 15:48:28 +00001143# if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 size = SSIZE_MAX; /* use max I/O size, 52K */
1145# else
1146 size = 0x10000L; /* use buffer >= 64K */
1147# endif
1148#else
1149 size = 0x7ff0L - linerest; /* limit buffer to 32K */
1150#endif
1151
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001152 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 {
1154 if ((new_buffer = lalloc((long_u)(size + linerest + 1),
1155 FALSE)) != NULL)
1156 break;
1157 }
1158 if (new_buffer == NULL)
1159 {
1160 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1161 error = TRUE;
1162 break;
1163 }
1164 if (linerest) /* copy characters from the previous buffer */
1165 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1166 vim_free(buffer);
1167 buffer = new_buffer;
1168 ptr = buffer + linerest;
1169 line_start = buffer;
1170
1171#ifdef FEAT_MBYTE
1172 /* May need room to translate into.
1173 * For iconv() we don't really know the required space, use a
1174 * factor ICONV_MULT.
1175 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1176 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1177 * become up to 4 bytes, size must be multiple of 2
1178 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1179 * multiple of 2
1180 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1181 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001182 real_size = (int)size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183# ifdef USE_ICONV
1184 if (iconv_fd != (iconv_t)-1)
1185 size = size / ICONV_MULT;
1186 else
1187# endif
1188 if (fio_flags & FIO_LATIN1)
1189 size = size / 2;
1190 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1191 size = (size * 2 / 3) & ~1;
1192 else if (fio_flags & FIO_UCS4)
1193 size = (size * 2 / 3) & ~3;
1194 else if (fio_flags == FIO_UCSBOM)
1195 size = size / ICONV_MULT; /* worst case */
1196# ifdef WIN3264
1197 else if (fio_flags & FIO_CODEPAGE)
1198 size = size / ICONV_MULT; /* also worst case */
1199# endif
1200# ifdef MACOS_X
1201 else if (fio_flags & FIO_MACROMAN)
1202 size = size / ICONV_MULT; /* also worst case */
1203# endif
1204#endif
1205
1206#ifdef FEAT_MBYTE
1207 if (conv_restlen > 0)
1208 {
1209 /* Insert unconverted bytes from previous line. */
1210 mch_memmove(ptr, conv_rest, conv_restlen);
1211 ptr += conv_restlen;
1212 size -= conv_restlen;
1213 }
1214#endif
1215
1216 if (read_buffer)
1217 {
1218 /*
1219 * Read bytes from curbuf. Used for converting text read
1220 * from stdin.
1221 */
1222 if (read_buf_lnum > from)
1223 size = 0;
1224 else
1225 {
1226 int n, ni;
1227 long tlen;
1228
1229 tlen = 0;
1230 for (;;)
1231 {
1232 p = ml_get(read_buf_lnum) + read_buf_col;
1233 n = (int)STRLEN(p);
1234 if ((int)tlen + n + 1 > size)
1235 {
1236 /* Filled up to "size", append partial line.
1237 * Change NL to NUL to reverse the effect done
1238 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001239 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 for (ni = 0; ni < n; ++ni)
1241 {
1242 if (p[ni] == NL)
1243 ptr[tlen++] = NUL;
1244 else
1245 ptr[tlen++] = p[ni];
1246 }
1247 read_buf_col += n;
1248 break;
1249 }
1250 else
1251 {
1252 /* Append whole line and new-line. Change NL
1253 * to NUL to reverse the effect done below. */
1254 for (ni = 0; ni < n; ++ni)
1255 {
1256 if (p[ni] == NL)
1257 ptr[tlen++] = NUL;
1258 else
1259 ptr[tlen++] = p[ni];
1260 }
1261 ptr[tlen++] = NL;
1262 read_buf_col = 0;
1263 if (++read_buf_lnum > from)
1264 {
1265 /* When the last line didn't have an
1266 * end-of-line don't add it now either. */
1267 if (!curbuf->b_p_eol)
1268 --tlen;
1269 size = tlen;
1270 break;
1271 }
1272 }
1273 }
1274 }
1275 }
1276 else
1277 {
1278 /*
1279 * Read bytes from the file.
1280 */
1281 size = vim_read(fd, ptr, size);
1282 }
1283
1284 if (size <= 0)
1285 {
1286 if (size < 0) /* read error */
1287 error = TRUE;
1288#ifdef FEAT_MBYTE
1289 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001290 {
1291 /* Reached end-of-file but some trailing bytes could
Bram Moolenaar7263a772007-05-10 17:35:54 +00001292 * not be converted. Truncated file? */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001293 if (conv_error == 0)
1294 conv_error = linecnt;
1295 if (bad_char_behavior != BAD_DROP)
1296 {
1297 fio_flags = 0; /* don't convert this */
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001298# ifdef USE_ICONV
1299 if (iconv_fd != (iconv_t)-1)
1300 {
1301 iconv_close(iconv_fd);
1302 iconv_fd = (iconv_t)-1;
1303 }
1304# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001305 if (bad_char_behavior == BAD_KEEP)
1306 {
1307 /* Keep the trailing bytes as-is. */
1308 size = conv_restlen;
1309 ptr -= conv_restlen;
1310 }
1311 else
1312 {
1313 /* Replace the trailing bytes with the
1314 * replacement character. */
1315 size = 1;
1316 *--ptr = bad_char_behavior;
1317 }
1318 conv_restlen = 0;
1319 }
1320 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321#endif
1322 }
1323
1324#ifdef FEAT_CRYPT
1325 /*
1326 * At start of file: Check for magic number of encryption.
1327 */
1328 if (filesize == 0)
1329 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1330 &filesize, newfile);
1331 /*
1332 * Decrypt the read bytes.
1333 */
1334 if (cryptkey != NULL && size > 0)
1335 for (p = ptr; p < ptr + size; ++p)
1336 ZDECODE(*p);
1337#endif
1338 }
1339 skip_read = FALSE;
1340
1341#ifdef FEAT_MBYTE
1342 /*
1343 * At start of file (or after crypt magic number): Check for BOM.
1344 * Also check for a BOM for other Unicode encodings, but not after
1345 * converting with 'charconvert' or when a BOM has already been
1346 * found.
1347 */
1348 if ((filesize == 0
1349# ifdef FEAT_CRYPT
1350 || (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
1351# endif
1352 )
1353 && (fio_flags == FIO_UCSBOM
1354 || (!curbuf->b_p_bomb
1355 && tmpname == NULL
1356 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1357 {
1358 char_u *ccname;
1359 int blen;
1360
1361 /* no BOM detection in a short file or in binary mode */
1362 if (size < 2 || curbuf->b_p_bin)
1363 ccname = NULL;
1364 else
1365 ccname = check_for_bom(ptr, size, &blen,
1366 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1367 if (ccname != NULL)
1368 {
1369 /* Remove BOM from the text */
1370 filesize += blen;
1371 size -= blen;
1372 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001373 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001374 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375 curbuf->b_p_bomb = TRUE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001376 curbuf->b_start_bomb = TRUE;
1377 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378 }
1379
1380 if (fio_flags == FIO_UCSBOM)
1381 {
1382 if (ccname == NULL)
1383 {
1384 /* No BOM detected: retry with next encoding. */
1385 advance_fenc = TRUE;
1386 }
1387 else
1388 {
1389 /* BOM detected: set "fenc" and jump back */
1390 if (fenc_alloced)
1391 vim_free(fenc);
1392 fenc = ccname;
1393 fenc_alloced = FALSE;
1394 }
1395 /* retry reading without getting new bytes or rewinding */
1396 skip_read = TRUE;
1397 goto retry;
1398 }
1399 }
1400#endif
1401 /*
1402 * Break here for a read error or end-of-file.
1403 */
1404 if (size <= 0)
1405 break;
1406
1407#ifdef FEAT_MBYTE
1408
1409 /* Include not converted bytes. */
1410 ptr -= conv_restlen;
1411 size += conv_restlen;
1412 conv_restlen = 0;
1413
1414# ifdef USE_ICONV
1415 if (iconv_fd != (iconv_t)-1)
1416 {
1417 /*
1418 * Attempt conversion of the read bytes to 'encoding' using
1419 * iconv().
1420 */
1421 const char *fromp;
1422 char *top;
1423 size_t from_size;
1424 size_t to_size;
1425
1426 fromp = (char *)ptr;
1427 from_size = size;
1428 ptr += size;
1429 top = (char *)ptr;
1430 to_size = real_size - size;
1431
1432 /*
1433 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001434 * another conversion. Except for when there is no
1435 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001436 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001437 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1438 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001439 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1440 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001441 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001442 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001443 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001444 if (conv_error == 0)
1445 conv_error = readfile_linenr(linecnt,
1446 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001447
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001448 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001449 ++fromp;
1450 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001451 if (bad_char_behavior == BAD_KEEP)
1452 {
1453 *top++ = *(fromp - 1);
1454 --to_size;
1455 }
1456 else if (bad_char_behavior != BAD_DROP)
1457 {
1458 *top++ = bad_char_behavior;
1459 --to_size;
1460 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001461 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462
1463 if (from_size > 0)
1464 {
1465 /* Some remaining characters, keep them for the next
1466 * round. */
1467 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1468 conv_restlen = (int)from_size;
1469 }
1470
1471 /* move the linerest to before the converted characters */
1472 line_start = ptr - linerest;
1473 mch_memmove(line_start, buffer, (size_t)linerest);
1474 size = (long)((char_u *)top - ptr);
1475 }
1476# endif
1477
1478# ifdef WIN3264
1479 if (fio_flags & FIO_CODEPAGE)
1480 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001481 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001482 WCHAR ucs2buf[3];
1483 int ucs2len;
1484 int codepage = FIO_GET_CP(fio_flags);
1485 int bytelen;
1486 int found_bad;
1487 char replstr[2];
1488
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489 /*
1490 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001491 * a codepage, using standard MS-Windows functions. This
1492 * requires two steps:
1493 * 1. convert from 'fileencoding' to ucs-2
1494 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001496 * Because there may be illegal bytes AND an incomplete byte
1497 * sequence at the end, we may have to do the conversion one
1498 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001499 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001501 /* Replacement string for WideCharToMultiByte(). */
1502 if (bad_char_behavior > 0)
1503 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001505 replstr[0] = '?';
1506 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507
1508 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001509 * Move the bytes to the end of the buffer, so that we have
1510 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001512 src = ptr + real_size - size;
1513 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001515 /*
1516 * Do the conversion.
1517 */
1518 dst = ptr;
1519 size = size;
1520 while (size > 0)
1521 {
1522 found_bad = FALSE;
1523
1524# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1525 if (codepage == CP_UTF8)
1526 {
1527 /* Handle CP_UTF8 input ourselves to be able to handle
1528 * trailing bytes properly.
1529 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001530 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001531 if (bytelen > size)
1532 {
1533 /* Only got some bytes of a character. Normally
1534 * it's put in "conv_rest", but if it's too long
1535 * deal with it as if they were illegal bytes. */
1536 if (bytelen <= CONV_RESTLEN)
1537 break;
1538
1539 /* weird overlong byte sequence */
1540 bytelen = size;
1541 found_bad = TRUE;
1542 }
1543 else
1544 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001545 int u8c = utf_ptr2char(src);
1546
Bram Moolenaar86e01082005-12-29 22:45:34 +00001547 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001548 found_bad = TRUE;
1549 ucs2buf[0] = u8c;
1550 ucs2len = 1;
1551 }
1552 }
1553 else
1554# endif
1555 {
1556 /* We don't know how long the byte sequence is, try
1557 * from one to three bytes. */
1558 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1559 ++bytelen)
1560 {
1561 ucs2len = MultiByteToWideChar(codepage,
1562 MB_ERR_INVALID_CHARS,
1563 (LPCSTR)src, bytelen,
1564 ucs2buf, 3);
1565 if (ucs2len > 0)
1566 break;
1567 }
1568 if (ucs2len == 0)
1569 {
1570 /* If we have only one byte then it's probably an
1571 * incomplete byte sequence. Otherwise discard
1572 * one byte as a bad character. */
1573 if (size == 1)
1574 break;
1575 found_bad = TRUE;
1576 bytelen = 1;
1577 }
1578 }
1579
1580 if (!found_bad)
1581 {
1582 int i;
1583
1584 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1585 if (enc_utf8)
1586 {
1587 /* From UCS-2 to UTF-8. Cannot fail. */
1588 for (i = 0; i < ucs2len; ++i)
1589 dst += utf_char2bytes(ucs2buf[i], dst);
1590 }
1591 else
1592 {
1593 BOOL bad = FALSE;
1594 int dstlen;
1595
1596 /* From UCS-2 to "enc_codepage". If the
1597 * conversion uses the default character "?",
1598 * the data doesn't fit in this encoding. */
1599 dstlen = WideCharToMultiByte(enc_codepage, 0,
1600 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001601 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001602 replstr, &bad);
1603 if (bad)
1604 found_bad = TRUE;
1605 else
1606 dst += dstlen;
1607 }
1608 }
1609
1610 if (found_bad)
1611 {
1612 /* Deal with bytes we can't convert. */
1613 if (can_retry)
1614 goto rewind_retry;
1615 if (conv_error == 0)
1616 conv_error = readfile_linenr(linecnt, ptr, dst);
1617 if (bad_char_behavior != BAD_DROP)
1618 {
1619 if (bad_char_behavior == BAD_KEEP)
1620 {
1621 mch_memmove(dst, src, bytelen);
1622 dst += bytelen;
1623 }
1624 else
1625 *dst++ = bad_char_behavior;
1626 }
1627 }
1628
1629 src += bytelen;
1630 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001632
1633 if (size > 0)
1634 {
1635 /* An incomplete byte sequence remaining. */
1636 mch_memmove(conv_rest, src, size);
1637 conv_restlen = size;
1638 }
1639
1640 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001641 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001642 }
1643 else
1644# endif
Bram Moolenaar56718732006-03-15 22:53:57 +00001645# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 if (fio_flags & FIO_MACROMAN)
1647 {
1648 /*
1649 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001650 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001652 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 }
1655 else
1656# endif
1657 if (fio_flags != 0)
1658 {
1659 int u8c;
1660 char_u *dest;
1661 char_u *tail = NULL;
1662
1663 /*
1664 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1665 * "enc_utf8" not set: Convert Unicode to Latin1.
1666 * Go from end to start through the buffer, because the number
1667 * of bytes may increase.
1668 * "dest" points to after where the UTF-8 bytes go, "p" points
1669 * to after the next character to convert.
1670 */
1671 dest = ptr + real_size;
1672 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1673 {
1674 p = ptr + size;
1675 if (fio_flags == FIO_UTF8)
1676 {
1677 /* Check for a trailing incomplete UTF-8 sequence */
1678 tail = ptr + size - 1;
1679 while (tail > ptr && (*tail & 0xc0) == 0x80)
1680 --tail;
1681 if (tail + utf_byte2len(*tail) <= ptr + size)
1682 tail = NULL;
1683 else
1684 p = tail;
1685 }
1686 }
1687 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1688 {
1689 /* Check for a trailing byte */
1690 p = ptr + (size & ~1);
1691 if (size & 1)
1692 tail = p;
1693 if ((fio_flags & FIO_UTF16) && p > ptr)
1694 {
1695 /* Check for a trailing leading word */
1696 if (fio_flags & FIO_ENDIAN_L)
1697 {
1698 u8c = (*--p << 8);
1699 u8c += *--p;
1700 }
1701 else
1702 {
1703 u8c = *--p;
1704 u8c += (*--p << 8);
1705 }
1706 if (u8c >= 0xd800 && u8c <= 0xdbff)
1707 tail = p;
1708 else
1709 p += 2;
1710 }
1711 }
1712 else /* FIO_UCS4 */
1713 {
1714 /* Check for trailing 1, 2 or 3 bytes */
1715 p = ptr + (size & ~3);
1716 if (size & 3)
1717 tail = p;
1718 }
1719
1720 /* If there is a trailing incomplete sequence move it to
1721 * conv_rest[]. */
1722 if (tail != NULL)
1723 {
1724 conv_restlen = (int)((ptr + size) - tail);
1725 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1726 size -= conv_restlen;
1727 }
1728
1729
1730 while (p > ptr)
1731 {
1732 if (fio_flags & FIO_LATIN1)
1733 u8c = *--p;
1734 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1735 {
1736 if (fio_flags & FIO_ENDIAN_L)
1737 {
1738 u8c = (*--p << 8);
1739 u8c += *--p;
1740 }
1741 else
1742 {
1743 u8c = *--p;
1744 u8c += (*--p << 8);
1745 }
1746 if ((fio_flags & FIO_UTF16)
1747 && u8c >= 0xdc00 && u8c <= 0xdfff)
1748 {
1749 int u16c;
1750
1751 if (p == ptr)
1752 {
1753 /* Missing leading word. */
1754 if (can_retry)
1755 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001756 if (conv_error == 0)
1757 conv_error = readfile_linenr(linecnt,
1758 ptr, p);
1759 if (bad_char_behavior == BAD_DROP)
1760 continue;
1761 if (bad_char_behavior != BAD_KEEP)
1762 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 }
1764
1765 /* found second word of double-word, get the first
1766 * word and compute the resulting character */
1767 if (fio_flags & FIO_ENDIAN_L)
1768 {
1769 u16c = (*--p << 8);
1770 u16c += *--p;
1771 }
1772 else
1773 {
1774 u16c = *--p;
1775 u16c += (*--p << 8);
1776 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001777 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1778 + (u8c & 0x3ff);
1779
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 /* Check if the word is indeed a leading word. */
1781 if (u16c < 0xd800 || u16c > 0xdbff)
1782 {
1783 if (can_retry)
1784 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001785 if (conv_error == 0)
1786 conv_error = readfile_linenr(linecnt,
1787 ptr, p);
1788 if (bad_char_behavior == BAD_DROP)
1789 continue;
1790 if (bad_char_behavior != BAD_KEEP)
1791 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 }
1794 }
1795 else if (fio_flags & FIO_UCS4)
1796 {
1797 if (fio_flags & FIO_ENDIAN_L)
1798 {
1799 u8c = (*--p << 24);
1800 u8c += (*--p << 16);
1801 u8c += (*--p << 8);
1802 u8c += *--p;
1803 }
1804 else /* big endian */
1805 {
1806 u8c = *--p;
1807 u8c += (*--p << 8);
1808 u8c += (*--p << 16);
1809 u8c += (*--p << 24);
1810 }
1811 }
1812 else /* UTF-8 */
1813 {
1814 if (*--p < 0x80)
1815 u8c = *p;
1816 else
1817 {
1818 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001819 p -= len;
1820 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 if (len == 0)
1822 {
1823 /* Not a valid UTF-8 character, retry with
1824 * another fenc when possible, otherwise just
1825 * report the error. */
1826 if (can_retry)
1827 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001828 if (conv_error == 0)
1829 conv_error = readfile_linenr(linecnt,
1830 ptr, p);
1831 if (bad_char_behavior == BAD_DROP)
1832 continue;
1833 if (bad_char_behavior != BAD_KEEP)
1834 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836 }
1837 }
1838 if (enc_utf8) /* produce UTF-8 */
1839 {
1840 dest -= utf_char2len(u8c);
1841 (void)utf_char2bytes(u8c, dest);
1842 }
1843 else /* produce Latin1 */
1844 {
1845 --dest;
1846 if (u8c >= 0x100)
1847 {
1848 /* character doesn't fit in latin1, retry with
1849 * another fenc when possible, otherwise just
1850 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001851 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001853 if (conv_error == 0)
1854 conv_error = readfile_linenr(linecnt, ptr, p);
1855 if (bad_char_behavior == BAD_DROP)
1856 ++dest;
1857 else if (bad_char_behavior == BAD_KEEP)
1858 *dest = u8c;
1859 else if (eap != NULL && eap->bad_char != 0)
1860 *dest = bad_char_behavior;
1861 else
1862 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 }
1864 else
1865 *dest = u8c;
1866 }
1867 }
1868
1869 /* move the linerest to before the converted characters */
1870 line_start = dest - linerest;
1871 mch_memmove(line_start, buffer, (size_t)linerest);
1872 size = (long)((ptr + real_size) - dest);
1873 ptr = dest;
1874 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001875 else if (enc_utf8 && conv_error == 0 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 {
1877 /* Reading UTF-8: Check if the bytes are valid UTF-8.
1878 * Need to start before "ptr" when part of the character was
1879 * read in the previous read() call. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001880 for (p = ptr - utf_head_off(buffer, ptr); ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001882 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001883 int l;
1884
1885 if (todo <= 0)
1886 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 if (*p >= 0x80)
1888 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 /* A length of 1 means it's an illegal byte. Accept
1890 * an incomplete character at the end though, the next
1891 * read() will get the next bytes, we'll check it
1892 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001893 l = utf_ptr2len_len(p, todo);
1894 if (l > todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001896 /* Incomplete byte sequence, the next read()
1897 * should get them and check the bytes. */
1898 p += todo;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 break;
1900 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001901 if (l == 1)
1902 {
1903 /* Illegal byte. If we can try another encoding
1904 * do that. */
1905 if (can_retry)
1906 break;
1907
1908 /* Remember the first linenr with an illegal byte */
1909 if (illegal_byte == 0)
1910 illegal_byte = readfile_linenr(linecnt, ptr, p);
1911# ifdef USE_ICONV
1912 /* When we did a conversion report an error. */
1913 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
1914 conv_error = readfile_linenr(linecnt, ptr, p);
1915# endif
1916
1917 /* Drop, keep or replace the bad byte. */
1918 if (bad_char_behavior == BAD_DROP)
1919 {
1920 mch_memmove(p, p+1, todo - 1);
1921 --p;
1922 --size;
1923 }
1924 else if (bad_char_behavior != BAD_KEEP)
1925 *p = bad_char_behavior;
1926 }
1927 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 }
1929 }
1930 if (p < ptr + size)
1931 {
1932 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001934 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001936 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
1937 /* iconv() failed, try 'charconvert' */
1938 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 else
1940# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001941 /* use next item from 'fileencodings' */
1942 advance_fenc = TRUE;
1943 file_rewind = TRUE;
1944 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 }
1946 }
1947#endif
1948
1949 /* count the number of characters (after conversion!) */
1950 filesize += size;
1951
1952 /*
1953 * when reading the first part of a file: guess EOL type
1954 */
1955 if (fileformat == EOL_UNKNOWN)
1956 {
1957 /* First try finding a NL, for Dos and Unix */
1958 if (try_dos || try_unix)
1959 {
1960 for (p = ptr; p < ptr + size; ++p)
1961 {
1962 if (*p == NL)
1963 {
1964 if (!try_unix
1965 || (try_dos && p > ptr && p[-1] == CAR))
1966 fileformat = EOL_DOS;
1967 else
1968 fileformat = EOL_UNIX;
1969 break;
1970 }
1971 }
1972
1973 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
1974 if (fileformat == EOL_UNIX && try_mac)
1975 {
1976 /* Need to reset the counters when retrying fenc. */
1977 try_mac = 1;
1978 try_unix = 1;
1979 for (; p >= ptr && *p != CAR; p--)
1980 ;
1981 if (p >= ptr)
1982 {
1983 for (p = ptr; p < ptr + size; ++p)
1984 {
1985 if (*p == NL)
1986 try_unix++;
1987 else if (*p == CAR)
1988 try_mac++;
1989 }
1990 if (try_mac > try_unix)
1991 fileformat = EOL_MAC;
1992 }
1993 }
1994 }
1995
1996 /* No NL found: may use Mac format */
1997 if (fileformat == EOL_UNKNOWN && try_mac)
1998 fileformat = EOL_MAC;
1999
2000 /* Still nothing found? Use first format in 'ffs' */
2001 if (fileformat == EOL_UNKNOWN)
2002 fileformat = default_fileformat();
2003
2004 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002005 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 set_fileformat(fileformat, OPT_LOCAL);
2007 }
2008 }
2009
2010 /*
2011 * This loop is executed once for every character read.
2012 * Keep it fast!
2013 */
2014 if (fileformat == EOL_MAC)
2015 {
2016 --ptr;
2017 while (++ptr, --size >= 0)
2018 {
2019 /* catch most common case first */
2020 if ((c = *ptr) != NUL && c != CAR && c != NL)
2021 continue;
2022 if (c == NUL)
2023 *ptr = NL; /* NULs are replaced by newlines! */
2024 else if (c == NL)
2025 *ptr = CAR; /* NLs are replaced by CRs! */
2026 else
2027 {
2028 if (skip_count == 0)
2029 {
2030 *ptr = NUL; /* end of line */
2031 len = (colnr_T) (ptr - line_start + 1);
2032 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2033 {
2034 error = TRUE;
2035 break;
2036 }
2037 ++lnum;
2038 if (--read_count == 0)
2039 {
2040 error = TRUE; /* break loop */
2041 line_start = ptr; /* nothing left to write */
2042 break;
2043 }
2044 }
2045 else
2046 --skip_count;
2047 line_start = ptr + 1;
2048 }
2049 }
2050 }
2051 else
2052 {
2053 --ptr;
2054 while (++ptr, --size >= 0)
2055 {
2056 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2057 continue;
2058 if (c == NUL)
2059 *ptr = NL; /* NULs are replaced by newlines! */
2060 else
2061 {
2062 if (skip_count == 0)
2063 {
2064 *ptr = NUL; /* end of line */
2065 len = (colnr_T)(ptr - line_start + 1);
2066 if (fileformat == EOL_DOS)
2067 {
2068 if (ptr[-1] == CAR) /* remove CR */
2069 {
2070 ptr[-1] = NUL;
2071 --len;
2072 }
2073 /*
2074 * Reading in Dos format, but no CR-LF found!
2075 * When 'fileformats' includes "unix", delete all
2076 * the lines read so far and start all over again.
2077 * Otherwise give an error message later.
2078 */
2079 else if (ff_error != EOL_DOS)
2080 {
2081 if ( try_unix
2082 && !read_stdin
2083 && (read_buffer
2084 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2085 {
2086 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002087 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 set_fileformat(EOL_UNIX, OPT_LOCAL);
2089 file_rewind = TRUE;
2090 keep_fileformat = TRUE;
2091 goto retry;
2092 }
2093 ff_error = EOL_DOS;
2094 }
2095 }
2096 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2097 {
2098 error = TRUE;
2099 break;
2100 }
2101 ++lnum;
2102 if (--read_count == 0)
2103 {
2104 error = TRUE; /* break loop */
2105 line_start = ptr; /* nothing left to write */
2106 break;
2107 }
2108 }
2109 else
2110 --skip_count;
2111 line_start = ptr + 1;
2112 }
2113 }
2114 }
2115 linerest = (long)(ptr - line_start);
2116 ui_breakcheck();
2117 }
2118
2119failed:
2120 /* not an error, max. number of lines reached */
2121 if (error && read_count == 0)
2122 error = FALSE;
2123
2124 /*
2125 * If we get EOF in the middle of a line, note the fact and
2126 * complete the line ourselves.
2127 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2128 */
2129 if (!error
2130 && !got_int
2131 && linerest != 0
2132 && !(!curbuf->b_p_bin
2133 && fileformat == EOL_DOS
2134 && *line_start == Ctrl_Z
2135 && ptr == line_start + 1))
2136 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002137 /* remember for when writing */
2138 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 curbuf->b_p_eol = FALSE;
2140 *ptr = NUL;
2141 if (ml_append(lnum, line_start,
2142 (colnr_T)(ptr - line_start + 1), newfile) == FAIL)
2143 error = TRUE;
2144 else
2145 read_no_eol_lnum = ++lnum;
2146 }
2147
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002148 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149 save_file_ff(curbuf); /* remember the current file format */
2150
2151#ifdef FEAT_CRYPT
2152 if (cryptkey != curbuf->b_p_key)
2153 vim_free(cryptkey);
2154#endif
2155
2156#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002157 /* If editing a new file: set 'fenc' for the current buffer.
2158 * Also for ":read ++edit file". */
2159 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002161 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 if (fenc_alloced)
2163 vim_free(fenc);
2164# ifdef USE_ICONV
2165 if (iconv_fd != (iconv_t)-1)
2166 {
2167 iconv_close(iconv_fd);
2168 iconv_fd = (iconv_t)-1;
2169 }
2170# endif
2171#endif
2172
2173 if (!read_buffer && !read_stdin)
2174 close(fd); /* errors are ignored */
2175 vim_free(buffer);
2176
2177#ifdef HAVE_DUP
2178 if (read_stdin)
2179 {
2180 /* Use stderr for stdin, makes shell commands work. */
2181 close(0);
2182 dup(2);
2183 }
2184#endif
2185
2186#ifdef FEAT_MBYTE
2187 if (tmpname != NULL)
2188 {
2189 mch_remove(tmpname); /* delete converted file */
2190 vim_free(tmpname);
2191 }
2192#endif
2193 --no_wait_return; /* may wait for return now */
2194
2195 /*
2196 * In recovery mode everything but autocommands is skipped.
2197 */
2198 if (!recoverymode)
2199 {
2200 /* need to delete the last line, which comes from the empty buffer */
2201 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2202 {
2203#ifdef FEAT_NETBEANS_INTG
2204 netbeansFireChanges = 0;
2205#endif
2206 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2207#ifdef FEAT_NETBEANS_INTG
2208 netbeansFireChanges = 1;
2209#endif
2210 --linecnt;
2211 }
2212 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2213 if (filesize == 0)
2214 linecnt = 0;
2215 if (newfile || read_buffer)
Bram Moolenaar7263a772007-05-10 17:35:54 +00002216 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 redraw_curbuf_later(NOT_VALID);
Bram Moolenaar7263a772007-05-10 17:35:54 +00002218#ifdef FEAT_DIFF
2219 /* After reading the text into the buffer the diff info needs to
2220 * be updated. */
2221 diff_invalidate(curbuf);
2222#endif
2223#ifdef FEAT_FOLDING
2224 /* All folds in the window are invalid now. Mark them for update
2225 * before triggering autocommands. */
2226 foldUpdateAll(curwin);
2227#endif
2228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 else if (linecnt) /* appended at least one line */
2230 appended_lines_mark(from, linecnt);
2231
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232#ifndef ALWAYS_USE_GUI
2233 /*
2234 * If we were reading from the same terminal as where messages go,
2235 * the screen will have been messed up.
2236 * Switch on raw mode now and clear the screen.
2237 */
2238 if (read_stdin)
2239 {
2240 settmode(TMODE_RAW); /* set to raw mode */
2241 starttermcap();
2242 screenclear();
2243 }
2244#endif
2245
2246 if (got_int)
2247 {
2248 if (!(flags & READ_DUMMY))
2249 {
2250 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2251 if (newfile)
2252 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2253 }
2254 msg_scroll = msg_save;
2255#ifdef FEAT_VIMINFO
2256 check_marks_read();
2257#endif
2258 return OK; /* an interrupt isn't really an error */
2259 }
2260
2261 if (!filtering && !(flags & READ_DUMMY))
2262 {
2263 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2264 c = FALSE;
2265
2266#ifdef UNIX
2267# ifdef S_ISFIFO
2268 if (S_ISFIFO(perm)) /* fifo or socket */
2269 {
2270 STRCAT(IObuff, _("[fifo/socket]"));
2271 c = TRUE;
2272 }
2273# else
2274# ifdef S_IFIFO
2275 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2276 {
2277 STRCAT(IObuff, _("[fifo]"));
2278 c = TRUE;
2279 }
2280# endif
2281# ifdef S_IFSOCK
2282 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2283 {
2284 STRCAT(IObuff, _("[socket]"));
2285 c = TRUE;
2286 }
2287# endif
2288# endif
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002289# ifdef OPEN_CHR_FILES
2290 if (S_ISCHR(perm)) /* or character special */
2291 {
2292 STRCAT(IObuff, _("[character special]"));
2293 c = TRUE;
2294 }
2295# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296#endif
2297 if (curbuf->b_p_ro)
2298 {
2299 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2300 c = TRUE;
2301 }
2302 if (read_no_eol_lnum)
2303 {
2304 msg_add_eol();
2305 c = TRUE;
2306 }
2307 if (ff_error == EOL_DOS)
2308 {
2309 STRCAT(IObuff, _("[CR missing]"));
2310 c = TRUE;
2311 }
2312 if (ff_error == EOL_MAC)
2313 {
2314 STRCAT(IObuff, _("[NL found]"));
2315 c = TRUE;
2316 }
2317 if (split)
2318 {
2319 STRCAT(IObuff, _("[long lines split]"));
2320 c = TRUE;
2321 }
2322#ifdef FEAT_MBYTE
2323 if (notconverted)
2324 {
2325 STRCAT(IObuff, _("[NOT converted]"));
2326 c = TRUE;
2327 }
2328 else if (converted)
2329 {
2330 STRCAT(IObuff, _("[converted]"));
2331 c = TRUE;
2332 }
2333#endif
2334#ifdef FEAT_CRYPT
2335 if (cryptkey != NULL)
2336 {
2337 STRCAT(IObuff, _("[crypted]"));
2338 c = TRUE;
2339 }
2340#endif
2341#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002342 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002344 sprintf((char *)IObuff + STRLEN(IObuff),
2345 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 c = TRUE;
2347 }
2348 else if (illegal_byte > 0)
2349 {
2350 sprintf((char *)IObuff + STRLEN(IObuff),
2351 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2352 c = TRUE;
2353 }
2354 else
2355#endif
2356 if (error)
2357 {
2358 STRCAT(IObuff, _("[READ ERRORS]"));
2359 c = TRUE;
2360 }
2361 if (msg_add_fileformat(fileformat))
2362 c = TRUE;
2363#ifdef FEAT_CRYPT
2364 if (cryptkey != NULL)
2365 msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
2366 else
2367#endif
2368 msg_add_lines(c, (long)linecnt, filesize);
2369
2370 vim_free(keep_msg);
2371 keep_msg = NULL;
2372 msg_scrolled_ign = TRUE;
2373#ifdef ALWAYS_USE_GUI
2374 /* Don't show the message when reading stdin, it would end up in a
2375 * message box (which might be shown when exiting!) */
2376 if (read_stdin || read_buffer)
2377 p = msg_may_trunc(FALSE, IObuff);
2378 else
2379#endif
2380 p = msg_trunc_attr(IObuff, FALSE, 0);
2381 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002382 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 /* Need to repeat the message after redrawing when:
2384 * - When reading from stdin (the screen will be cleared next).
2385 * - When restart_edit is set (otherwise there will be a delay
2386 * before redrawing).
2387 * - When the screen was scrolled but there is no wait-return
2388 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002389 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 msg_scrolled_ign = FALSE;
2391 }
2392
2393 /* with errors writing the file requires ":w!" */
2394 if (newfile && (error
2395#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002396 || conv_error != 0
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002397 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398#endif
2399 ))
2400 curbuf->b_p_ro = TRUE;
2401
2402 u_clearline(); /* cannot use "U" command after adding lines */
2403
2404 /*
2405 * In Ex mode: cursor at last new line.
2406 * Otherwise: cursor at first new line.
2407 */
2408 if (exmode_active)
2409 curwin->w_cursor.lnum = from + linecnt;
2410 else
2411 curwin->w_cursor.lnum = from + 1;
2412 check_cursor_lnum();
2413 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2414
2415 /*
2416 * Set '[ and '] marks to the newly read lines.
2417 */
2418 curbuf->b_op_start.lnum = from + 1;
2419 curbuf->b_op_start.col = 0;
2420 curbuf->b_op_end.lnum = from + linecnt;
2421 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002422
2423#ifdef WIN32
2424 /*
2425 * Work around a weird problem: When a file has two links (only
2426 * possible on NTFS) and we write through one link, then stat() it
2427 * throught the other link, the timestamp information may be wrong.
2428 * It's correct again after reading the file, thus reset the timestamp
2429 * here.
2430 */
2431 if (newfile && !read_stdin && !read_buffer
2432 && mch_stat((char *)fname, &st) >= 0)
2433 {
2434 buf_store_time(curbuf, &st, fname);
2435 curbuf->b_mtime_read = curbuf->b_mtime;
2436 }
2437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 }
2439 msg_scroll = msg_save;
2440
2441#ifdef FEAT_VIMINFO
2442 /*
2443 * Get the marks before executing autocommands, so they can be used there.
2444 */
2445 check_marks_read();
2446#endif
2447
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 /*
2449 * Trick: We remember if the last line of the read didn't have
2450 * an eol for when writing it again. This is required for
2451 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2452 */
2453 write_no_eol_lnum = read_no_eol_lnum;
2454
Bram Moolenaardf177f62005-02-22 08:39:57 +00002455#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 if (!read_stdin && !read_buffer)
2457 {
2458 int m = msg_scroll;
2459 int n = msg_scrolled;
2460
2461 /* Save the fileformat now, otherwise the buffer will be considered
2462 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002463 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 save_file_ff(curbuf);
2465
2466 /*
2467 * The output from the autocommands should not overwrite anything and
2468 * should not be overwritten: Set msg_scroll, restore its value if no
2469 * output was done.
2470 */
2471 msg_scroll = TRUE;
2472 if (filtering)
2473 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2474 FALSE, curbuf, eap);
2475 else if (newfile)
2476 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2477 FALSE, curbuf, eap);
2478 else
2479 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2480 FALSE, NULL, eap);
2481 if (msg_scrolled == n)
2482 msg_scroll = m;
2483#ifdef FEAT_EVAL
2484 if (aborting()) /* autocmds may abort script processing */
2485 return FAIL;
2486#endif
2487 }
2488#endif
2489
2490 if (recoverymode && error)
2491 return FAIL;
2492 return OK;
2493}
2494
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002495#ifdef OPEN_CHR_FILES
2496/*
2497 * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
2498 * which is the name of files used for process substitution output by
2499 * some shells on some operating systems, e.g., bash on SunOS.
2500 * Do not accept "/dev/fd/[012]", opening these may hang Vim.
2501 */
2502 static int
2503is_dev_fd_file(fname)
2504 char_u *fname;
2505{
2506 return (STRNCMP(fname, "/dev/fd/", 8) == 0
2507 && VIM_ISDIGIT(fname[8])
2508 && *skipdigits(fname + 9) == NUL
2509 && (fname[9] != NUL
2510 || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
2511}
2512#endif
2513
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002514#ifdef FEAT_MBYTE
2515
2516/*
2517 * From the current line count and characters read after that, estimate the
2518 * line number where we are now.
2519 * Used for error messages that include a line number.
2520 */
2521 static linenr_T
2522readfile_linenr(linecnt, p, endp)
2523 linenr_T linecnt; /* line count before reading more bytes */
2524 char_u *p; /* start of more bytes read */
2525 char_u *endp; /* end of more bytes read */
2526{
2527 char_u *s;
2528 linenr_T lnum;
2529
2530 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2531 for (s = p; s < endp; ++s)
2532 if (*s == '\n')
2533 ++lnum;
2534 return lnum;
2535}
2536#endif
2537
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002539 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2540 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 * Returns OK or FAIL.
2542 */
2543 int
2544prep_exarg(eap, buf)
2545 exarg_T *eap;
2546 buf_T *buf;
2547{
2548 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2549#ifdef FEAT_MBYTE
2550 + STRLEN(buf->b_p_fenc)
2551#endif
2552 + 15));
2553 if (eap->cmd == NULL)
2554 return FAIL;
2555
2556#ifdef FEAT_MBYTE
2557 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2558 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002559 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560#else
2561 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2562#endif
2563 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002564
2565 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002566 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002567 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 return OK;
2569}
2570
2571#ifdef FEAT_MBYTE
2572/*
2573 * Find next fileencoding to use from 'fileencodings'.
2574 * "pp" points to fenc_next. It's advanced to the next item.
2575 * When there are no more items, an empty string is returned and *pp is set to
2576 * NULL.
2577 * When *pp is not set to NULL, the result is in allocated memory.
2578 */
2579 static char_u *
2580next_fenc(pp)
2581 char_u **pp;
2582{
2583 char_u *p;
2584 char_u *r;
2585
2586 if (**pp == NUL)
2587 {
2588 *pp = NULL;
2589 return (char_u *)"";
2590 }
2591 p = vim_strchr(*pp, ',');
2592 if (p == NULL)
2593 {
2594 r = enc_canonize(*pp);
2595 *pp += STRLEN(*pp);
2596 }
2597 else
2598 {
2599 r = vim_strnsave(*pp, (int)(p - *pp));
2600 *pp = p + 1;
2601 if (r != NULL)
2602 {
2603 p = enc_canonize(r);
2604 vim_free(r);
2605 r = p;
2606 }
2607 }
2608 if (r == NULL) /* out of memory */
2609 {
2610 r = (char_u *)"";
2611 *pp = NULL;
2612 }
2613 return r;
2614}
2615
2616# ifdef FEAT_EVAL
2617/*
2618 * Convert a file with the 'charconvert' expression.
2619 * This closes the file which is to be read, converts it and opens the
2620 * resulting file for reading.
2621 * Returns name of the resulting converted file (the caller should delete it
2622 * after reading it).
2623 * Returns NULL if the conversion failed ("*fdp" is not set) .
2624 */
2625 static char_u *
2626readfile_charconvert(fname, fenc, fdp)
2627 char_u *fname; /* name of input file */
2628 char_u *fenc; /* converted from */
2629 int *fdp; /* in/out: file descriptor of file */
2630{
2631 char_u *tmpname;
2632 char_u *errmsg = NULL;
2633
2634 tmpname = vim_tempname('r');
2635 if (tmpname == NULL)
2636 errmsg = (char_u *)_("Can't find temp file for conversion");
2637 else
2638 {
2639 close(*fdp); /* close the input file, ignore errors */
2640 *fdp = -1;
2641 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2642 fname, tmpname) == FAIL)
2643 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2644 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2645 O_RDONLY | O_EXTRA, 0)) < 0)
2646 errmsg = (char_u *)_("can't read output of 'charconvert'");
2647 }
2648
2649 if (errmsg != NULL)
2650 {
2651 /* Don't use emsg(), it breaks mappings, the retry with
2652 * another type of conversion might still work. */
2653 MSG(errmsg);
2654 if (tmpname != NULL)
2655 {
2656 mch_remove(tmpname); /* delete converted file */
2657 vim_free(tmpname);
2658 tmpname = NULL;
2659 }
2660 }
2661
2662 /* If the input file is closed, open it (caller should check for error). */
2663 if (*fdp < 0)
2664 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2665
2666 return tmpname;
2667}
2668# endif
2669
2670#endif
2671
2672#ifdef FEAT_VIMINFO
2673/*
2674 * Read marks for the current buffer from the viminfo file, when we support
2675 * buffer marks and the buffer has a name.
2676 */
2677 static void
2678check_marks_read()
2679{
2680 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2681 && curbuf->b_ffname != NULL)
2682 read_viminfo(NULL, FALSE, TRUE, FALSE);
2683
2684 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2685 * the ' parameter after opening a buffer. */
2686 curbuf->b_marks_read = TRUE;
2687}
2688#endif
2689
2690#ifdef FEAT_CRYPT
2691/*
2692 * Check for magic number used for encryption.
2693 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2694 * *filesizep are updated.
2695 * Return the (new) encryption key, NULL for no encryption.
2696 */
2697 static char_u *
2698check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile)
2699 char_u *cryptkey; /* previous encryption key or NULL */
2700 char_u *ptr; /* pointer to read bytes */
2701 long *sizep; /* length of read bytes */
2702 long *filesizep; /* nr of bytes used from file */
2703 int newfile; /* editing a new buffer */
2704{
2705 if (*sizep >= CRYPT_MAGIC_LEN
2706 && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
2707 {
2708 if (cryptkey == NULL)
2709 {
2710 if (*curbuf->b_p_key)
2711 cryptkey = curbuf->b_p_key;
2712 else
2713 {
2714 /* When newfile is TRUE, store the typed key
2715 * in the 'key' option and don't free it. */
2716 cryptkey = get_crypt_key(newfile, FALSE);
2717 /* check if empty key entered */
2718 if (cryptkey != NULL && *cryptkey == NUL)
2719 {
2720 if (cryptkey != curbuf->b_p_key)
2721 vim_free(cryptkey);
2722 cryptkey = NULL;
2723 }
2724 }
2725 }
2726
2727 if (cryptkey != NULL)
2728 {
2729 crypt_init_keys(cryptkey);
2730
2731 /* Remove magic number from the text */
2732 *filesizep += CRYPT_MAGIC_LEN;
2733 *sizep -= CRYPT_MAGIC_LEN;
2734 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
2735 }
2736 }
2737 /* When starting to edit a new file which does not have
2738 * encryption, clear the 'key' option, except when
2739 * starting up (called with -x argument) */
2740 else if (newfile && *curbuf->b_p_key && !starting)
2741 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2742
2743 return cryptkey;
2744}
2745#endif
2746
2747#ifdef UNIX
2748 static void
2749set_file_time(fname, atime, mtime)
2750 char_u *fname;
2751 time_t atime; /* access time */
2752 time_t mtime; /* modification time */
2753{
2754# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2755 struct utimbuf buf;
2756
2757 buf.actime = atime;
2758 buf.modtime = mtime;
2759 (void)utime((char *)fname, &buf);
2760# else
2761# if defined(HAVE_UTIMES)
2762 struct timeval tvp[2];
2763
2764 tvp[0].tv_sec = atime;
2765 tvp[0].tv_usec = 0;
2766 tvp[1].tv_sec = mtime;
2767 tvp[1].tv_usec = 0;
2768# ifdef NeXT
2769 (void)utimes((char *)fname, tvp);
2770# else
2771 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2772# endif
2773# endif
2774# endif
2775}
2776#endif /* UNIX */
2777
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002778#if defined(VMS) && !defined(MIN)
2779/* Older DECC compiler for VAX doesn't define MIN() */
2780# define MIN(a, b) ((a) < (b) ? (a) : (b))
2781#endif
2782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00002784 * Return TRUE if a file appears to be read-only from the file permissions.
2785 */
2786 int
2787check_file_readonly(fname, perm)
2788 char_u *fname; /* full path to file */
2789 int perm; /* known permissions on file */
2790{
2791#ifndef USE_MCH_ACCESS
2792 int fd = 0;
2793#endif
2794
2795 return (
2796#ifdef USE_MCH_ACCESS
2797# ifdef UNIX
2798 (perm & 0222) == 0 ||
2799# endif
2800 mch_access((char *)fname, W_OK)
2801#else
2802 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
2803 ? TRUE : (close(fd), FALSE)
2804#endif
2805 );
2806}
2807
2808
2809/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00002810 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 *
2812 * We do our own buffering here because fwrite() is so slow.
2813 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00002814 * If "forceit" is true, we don't care for errors when attempting backups.
2815 * In case of an error everything possible is done to restore the original
2816 * file. But when "forceit" is TRUE, we risk loosing it.
2817 *
2818 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
2819 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820 *
2821 * This function must NOT use NameBuff (because it's called by autowrite()).
2822 *
2823 * return FAIL for failure, OK otherwise
2824 */
2825 int
2826buf_write(buf, fname, sfname, start, end, eap, append, forceit,
2827 reset_changed, filtering)
2828 buf_T *buf;
2829 char_u *fname;
2830 char_u *sfname;
2831 linenr_T start, end;
2832 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
2833 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00002834 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 int forceit;
2836 int reset_changed;
2837 int filtering;
2838{
2839 int fd;
2840 char_u *backup = NULL;
2841 int backup_copy = FALSE; /* copy the original file? */
2842 int dobackup;
2843 char_u *ffname;
2844 char_u *wfname = NULL; /* name of file to write to */
2845 char_u *s;
2846 char_u *ptr;
2847 char_u c;
2848 int len;
2849 linenr_T lnum;
2850 long nchars;
2851 char_u *errmsg = NULL;
2852 char_u *errnum = NULL;
2853 char_u *buffer;
2854 char_u smallbuf[SMBUFSIZE];
2855 char_u *backup_ext;
2856 int bufsize;
2857 long perm; /* file permissions */
2858 int retval = OK;
2859 int newfile = FALSE; /* TRUE if file doesn't exist yet */
2860 int msg_save = msg_scroll;
2861 int overwriting; /* TRUE if writing over original */
2862 int no_eol = FALSE; /* no end-of-line written */
2863 int device = FALSE; /* writing to a device */
2864 struct stat st_old;
2865 int prev_got_int = got_int;
2866 int file_readonly = FALSE; /* overwritten file is read-only */
2867 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
2868#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
2869 int made_writable = FALSE; /* 'w' bit has been set */
2870#endif
2871 /* writing everything */
2872 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
2873#ifdef FEAT_AUTOCMD
2874 linenr_T old_line_count = buf->b_ml.ml_line_count;
2875#endif
2876 int attr;
2877 int fileformat;
2878 int write_bin;
2879 struct bw_info write_info; /* info for buf_write_bytes() */
2880#ifdef FEAT_MBYTE
2881 int converted = FALSE;
2882 int notconverted = FALSE;
2883 char_u *fenc; /* effective 'fileencoding' */
2884 char_u *fenc_tofree = NULL; /* allocated "fenc" */
2885#endif
2886#ifdef HAS_BW_FLAGS
2887 int wb_flags = 0;
2888#endif
2889#ifdef HAVE_ACL
2890 vim_acl_T acl = NULL; /* ACL copied from original file to
2891 backup or new file */
2892#endif
2893
2894 if (fname == NULL || *fname == NUL) /* safety check */
2895 return FAIL;
2896
2897 /*
2898 * Disallow writing from .exrc and .vimrc in current directory for
2899 * security reasons.
2900 */
2901 if (check_secure())
2902 return FAIL;
2903
2904 /* Avoid a crash for a long name. */
2905 if (STRLEN(fname) >= MAXPATHL)
2906 {
2907 EMSG(_(e_longname));
2908 return FAIL;
2909 }
2910
2911#ifdef FEAT_MBYTE
2912 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
2913 write_info.bw_conv_buf = NULL;
2914 write_info.bw_conv_error = FALSE;
2915 write_info.bw_restlen = 0;
2916# ifdef USE_ICONV
2917 write_info.bw_iconv_fd = (iconv_t)-1;
2918# endif
2919#endif
2920
Bram Moolenaardf177f62005-02-22 08:39:57 +00002921 /* After writing a file changedtick changes but we don't want to display
2922 * the line. */
2923 ex_no_reprint = TRUE;
2924
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 /*
2926 * If there is no file name yet, use the one for the written file.
2927 * BF_NOTEDITED is set to reflect this (in case the write fails).
2928 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00002929 * Don't do this when appending.
2930 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002932 if (buf->b_ffname == NULL
2933 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934 && whole
2935 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002936#ifdef FEAT_QUICKFIX
2937 && !bt_nofile(buf)
2938#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00002940 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
2942 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002943 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002945 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 }
2947
2948 if (sfname == NULL)
2949 sfname = fname;
2950 /*
2951 * For Unix: Use the short file name whenever possible.
2952 * Avoids problems with networks and when directory names are changed.
2953 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
2954 * another directory, which we don't detect
2955 */
2956 ffname = fname; /* remember full fname */
2957#ifdef UNIX
2958 fname = sfname;
2959#endif
2960
2961 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
2962 overwriting = TRUE;
2963 else
2964 overwriting = FALSE;
2965
2966 if (exiting)
2967 settmode(TMODE_COOK); /* when exiting allow typahead now */
2968
2969 ++no_wait_return; /* don't wait for return yet */
2970
2971 /*
2972 * Set '[ and '] marks to the lines to be written.
2973 */
2974 buf->b_op_start.lnum = start;
2975 buf->b_op_start.col = 0;
2976 buf->b_op_end.lnum = end;
2977 buf->b_op_end.col = 0;
2978
2979#ifdef FEAT_AUTOCMD
2980 {
2981 aco_save_T aco;
2982 int buf_ffname = FALSE;
2983 int buf_sfname = FALSE;
2984 int buf_fname_f = FALSE;
2985 int buf_fname_s = FALSE;
2986 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002987 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002988 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989
2990 /*
2991 * Apply PRE aucocommands.
2992 * Set curbuf to the buffer to be written.
2993 * Careful: The autocommands may call buf_write() recursively!
2994 */
2995 if (ffname == buf->b_ffname)
2996 buf_ffname = TRUE;
2997 if (sfname == buf->b_sfname)
2998 buf_sfname = TRUE;
2999 if (fname == buf->b_ffname)
3000 buf_fname_f = TRUE;
3001 if (fname == buf->b_sfname)
3002 buf_fname_s = TRUE;
3003
3004 /* set curwin/curbuf to buf and save a few things */
3005 aucmd_prepbuf(&aco, buf);
3006
3007 if (append)
3008 {
3009 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
3010 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003011 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003012#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00003013 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003014 nofile_err = TRUE;
3015 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003016#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003017 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003019 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 }
3021 else if (filtering)
3022 {
3023 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
3024 NULL, sfname, FALSE, curbuf, eap);
3025 }
3026 else if (reset_changed && whole)
3027 {
3028 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
3029 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003030 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003031#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003032 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003033 nofile_err = TRUE;
3034 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003035#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003036 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003038 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039 }
3040 else
3041 {
3042 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
3043 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003044 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003045#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00003046 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003047 nofile_err = TRUE;
3048 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003049#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003050 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003052 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053 }
3054
3055 /* restore curwin/curbuf and a few other things */
3056 aucmd_restbuf(&aco);
3057
3058 /*
3059 * In three situations we return here and don't write the file:
3060 * 1. the autocommands deleted or unloaded the buffer.
3061 * 2. The autocommands abort script processing.
3062 * 3. If one of the "Cmd" autocommands was executed.
3063 */
3064 if (!buf_valid(buf))
3065 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003066 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00003067 || did_cmd || nofile_err
3068#ifdef FEAT_EVAL
3069 || aborting()
3070#endif
3071 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 {
3073 --no_wait_return;
3074 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003075 if (nofile_err)
3076 EMSG(_("E676: No matching autocommands for acwrite buffer"));
3077
Bram Moolenaar1e015462005-09-25 22:16:38 +00003078 if (nofile_err
3079#ifdef FEAT_EVAL
3080 || aborting()
3081#endif
3082 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 /* An aborting error, interrupt or exception in the
3084 * autocommands. */
3085 return FAIL;
3086 if (did_cmd)
3087 {
3088 if (buf == NULL)
3089 /* The buffer was deleted. We assume it was written
3090 * (can't retry anyway). */
3091 return OK;
3092 if (overwriting)
3093 {
3094 /* Assume the buffer was written, update the timestamp. */
3095 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003096 if (append)
3097 buf->b_flags &= ~BF_NEW;
3098 else
3099 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003101 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003102 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103 /* Buffer still changed, the autocommands didn't work
3104 * properly. */
3105 return FAIL;
3106 return OK;
3107 }
3108#ifdef FEAT_EVAL
3109 if (!aborting())
3110#endif
3111 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
3112 return FAIL;
3113 }
3114
3115 /*
3116 * The autocommands may have changed the number of lines in the file.
3117 * When writing the whole file, adjust the end.
3118 * When writing part of the file, assume that the autocommands only
3119 * changed the number of lines that are to be written (tricky!).
3120 */
3121 if (buf->b_ml.ml_line_count != old_line_count)
3122 {
3123 if (whole) /* write all */
3124 end = buf->b_ml.ml_line_count;
3125 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3126 end += buf->b_ml.ml_line_count - old_line_count;
3127 else /* less lines */
3128 {
3129 end -= old_line_count - buf->b_ml.ml_line_count;
3130 if (end < start)
3131 {
3132 --no_wait_return;
3133 msg_scroll = msg_save;
3134 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3135 return FAIL;
3136 }
3137 }
3138 }
3139
3140 /*
3141 * The autocommands may have changed the name of the buffer, which may
3142 * be kept in fname, ffname and sfname.
3143 */
3144 if (buf_ffname)
3145 ffname = buf->b_ffname;
3146 if (buf_sfname)
3147 sfname = buf->b_sfname;
3148 if (buf_fname_f)
3149 fname = buf->b_ffname;
3150 if (buf_fname_s)
3151 fname = buf->b_sfname;
3152 }
3153#endif
3154
3155#ifdef FEAT_NETBEANS_INTG
3156 if (usingNetbeans && isNetbeansBuffer(buf))
3157 {
3158 if (whole)
3159 {
3160 /*
3161 * b_changed can be 0 after an undo, but we still need to write
3162 * the buffer to NetBeans.
3163 */
3164 if (buf->b_changed || isNetbeansModified(buf))
3165 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003166 --no_wait_return; /* may wait for return now */
3167 msg_scroll = msg_save;
3168 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 return retval;
3170 }
3171 else
3172 {
3173 errnum = (char_u *)"E656: ";
3174 errmsg = (char_u *)_("NetBeans dissallows writes of unmodified buffers");
3175 buffer = NULL;
3176 goto fail;
3177 }
3178 }
3179 else
3180 {
3181 errnum = (char_u *)"E657: ";
3182 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3183 buffer = NULL;
3184 goto fail;
3185 }
3186 }
3187#endif
3188
3189 if (shortmess(SHM_OVER) && !exiting)
3190 msg_scroll = FALSE; /* overwrite previous file message */
3191 else
3192 msg_scroll = TRUE; /* don't overwrite previous file message */
3193 if (!filtering)
3194 filemess(buf,
3195#ifndef UNIX
3196 sfname,
3197#else
3198 fname,
3199#endif
3200 (char_u *)"", 0); /* show that we are busy */
3201 msg_scroll = FALSE; /* always overwrite the file message now */
3202
3203 buffer = alloc(BUFSIZE);
3204 if (buffer == NULL) /* can't allocate big buffer, use small
3205 * one (to be able to write when out of
3206 * memory) */
3207 {
3208 buffer = smallbuf;
3209 bufsize = SMBUFSIZE;
3210 }
3211 else
3212 bufsize = BUFSIZE;
3213
3214 /*
3215 * Get information about original file (if there is one).
3216 */
3217#if defined(UNIX) && !defined(ARCHIE)
Bram Moolenaar6f192452007-11-08 19:49:02 +00003218 st_old.st_dev = 0;
3219 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 perm = -1;
3221 if (mch_stat((char *)fname, &st_old) < 0)
3222 newfile = TRUE;
3223 else
3224 {
3225 perm = st_old.st_mode;
3226 if (!S_ISREG(st_old.st_mode)) /* not a file */
3227 {
3228 if (S_ISDIR(st_old.st_mode))
3229 {
3230 errnum = (char_u *)"E502: ";
3231 errmsg = (char_u *)_("is a directory");
3232 goto fail;
3233 }
3234 if (mch_nodetype(fname) != NODE_WRITABLE)
3235 {
3236 errnum = (char_u *)"E503: ";
3237 errmsg = (char_u *)_("is not a file or writable device");
3238 goto fail;
3239 }
3240 /* It's a device of some kind (or a fifo) which we can write to
3241 * but for which we can't make a backup. */
3242 device = TRUE;
3243 newfile = TRUE;
3244 perm = -1;
3245 }
3246 }
3247#else /* !UNIX */
3248 /*
3249 * Check for a writable device name.
3250 */
3251 c = mch_nodetype(fname);
3252 if (c == NODE_OTHER)
3253 {
3254 errnum = (char_u *)"E503: ";
3255 errmsg = (char_u *)_("is not a file or writable device");
3256 goto fail;
3257 }
3258 if (c == NODE_WRITABLE)
3259 {
Bram Moolenaar043545e2006-10-10 16:44:07 +00003260# if defined(MSDOS) || defined(MSWIN) || defined(OS2)
3261 /* MS-Windows allows opening a device, but we will probably get stuck
3262 * trying to write to it. */
3263 if (!p_odev)
3264 {
3265 errnum = (char_u *)"E796: ";
3266 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
3267 goto fail;
3268 }
3269# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270 device = TRUE;
3271 newfile = TRUE;
3272 perm = -1;
3273 }
3274 else
3275 {
3276 perm = mch_getperm(fname);
3277 if (perm < 0)
3278 newfile = TRUE;
3279 else if (mch_isdir(fname))
3280 {
3281 errnum = (char_u *)"E502: ";
3282 errmsg = (char_u *)_("is a directory");
3283 goto fail;
3284 }
3285 if (overwriting)
3286 (void)mch_stat((char *)fname, &st_old);
3287 }
3288#endif /* !UNIX */
3289
3290 if (!device && !newfile)
3291 {
3292 /*
3293 * Check if the file is really writable (when renaming the file to
3294 * make a backup we won't discover it later).
3295 */
Bram Moolenaar5386a122007-06-28 20:02:32 +00003296 file_readonly = check_file_readonly(fname, (int)perm);
3297
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 if (!forceit && file_readonly)
3299 {
3300 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3301 {
3302 errnum = (char_u *)"E504: ";
3303 errmsg = (char_u *)_(err_readonly);
3304 }
3305 else
3306 {
3307 errnum = (char_u *)"E505: ";
3308 errmsg = (char_u *)_("is read-only (add ! to override)");
3309 }
3310 goto fail;
3311 }
3312
3313 /*
3314 * Check if the timestamp hasn't changed since reading the file.
3315 */
3316 if (overwriting)
3317 {
3318 retval = check_mtime(buf, &st_old);
3319 if (retval == FAIL)
3320 goto fail;
3321 }
3322 }
3323
3324#ifdef HAVE_ACL
3325 /*
3326 * For systems that support ACL: get the ACL from the original file.
3327 */
3328 if (!newfile)
3329 acl = mch_get_acl(fname);
3330#endif
3331
3332 /*
3333 * If 'backupskip' is not empty, don't make a backup for some files.
3334 */
3335 dobackup = (p_wb || p_bk || *p_pm != NUL);
3336#ifdef FEAT_WILDIGN
3337 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3338 dobackup = FALSE;
3339#endif
3340
3341 /*
3342 * Save the value of got_int and reset it. We don't want a previous
3343 * interruption cancel writing, only hitting CTRL-C while writing should
3344 * abort it.
3345 */
3346 prev_got_int = got_int;
3347 got_int = FALSE;
3348
3349 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3350 buf->b_saving = TRUE;
3351
3352 /*
3353 * If we are not appending or filtering, the file exists, and the
3354 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3355 * When 'patchmode' is set also make a backup when appending.
3356 *
3357 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3358 * off. This helps when editing large files on almost-full disks.
3359 */
3360 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3361 {
3362#if defined(UNIX) || defined(WIN32)
3363 struct stat st;
3364#endif
3365
3366 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3367 backup_copy = TRUE;
3368#if defined(UNIX) || defined(WIN32)
3369 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3370 {
3371 int i;
3372
3373# ifdef UNIX
3374 /*
3375 * Don't rename the file when:
3376 * - it's a hard link
3377 * - it's a symbolic link
3378 * - we don't have write permission in the directory
3379 * - we can't set the owner/group of the new file
3380 */
3381 if (st_old.st_nlink > 1
3382 || mch_lstat((char *)fname, &st) < 0
3383 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003384 || st.st_ino != st_old.st_ino
3385# ifndef HAVE_FCHOWN
3386 || st.st_uid != st_old.st_uid
3387 || st.st_gid != st_old.st_gid
3388# endif
3389 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390 backup_copy = TRUE;
3391 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003392# else
3393# ifdef WIN32
3394 /* On NTFS file systems hard links are possible. */
3395 if (mch_is_linked(fname))
3396 backup_copy = TRUE;
3397 else
3398# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003399# endif
3400 {
3401 /*
3402 * Check if we can create a file and set the owner/group to
3403 * the ones from the original file.
3404 * First find a file name that doesn't exist yet (use some
3405 * arbitrary numbers).
3406 */
3407 STRCPY(IObuff, fname);
3408 for (i = 4913; ; i += 123)
3409 {
3410 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003411 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 break;
3413 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003414 fd = mch_open((char *)IObuff,
3415 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 if (fd < 0) /* can't write in directory */
3417 backup_copy = TRUE;
3418 else
3419 {
3420# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003421# ifdef HAVE_FCHOWN
3422 fchown(fd, st_old.st_uid, st_old.st_gid);
3423# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 if (mch_stat((char *)IObuff, &st) < 0
3425 || st.st_uid != st_old.st_uid
3426 || st.st_gid != st_old.st_gid
3427 || st.st_mode != perm)
3428 backup_copy = TRUE;
3429# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003430 /* Close the file before removing it, on MS-Windows we
3431 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003432 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003433 mch_remove(IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 }
3435 }
3436 }
3437
3438# ifdef UNIX
3439 /*
3440 * Break symlinks and/or hardlinks if we've been asked to.
3441 */
3442 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3443 {
3444 int lstat_res;
3445
3446 lstat_res = mch_lstat((char *)fname, &st);
3447
3448 /* Symlinks. */
3449 if ((bkc_flags & BKC_BREAKSYMLINK)
3450 && lstat_res == 0
3451 && st.st_ino != st_old.st_ino)
3452 backup_copy = FALSE;
3453
3454 /* Hardlinks. */
3455 if ((bkc_flags & BKC_BREAKHARDLINK)
3456 && st_old.st_nlink > 1
3457 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3458 backup_copy = FALSE;
3459 }
3460#endif
3461
3462#endif
3463
3464 /* make sure we have a valid backup extension to use */
3465 if (*p_bex == NUL)
3466 {
3467#ifdef RISCOS
3468 backup_ext = (char_u *)"/bak";
3469#else
3470 backup_ext = (char_u *)".bak";
3471#endif
3472 }
3473 else
3474 backup_ext = p_bex;
3475
3476 if (backup_copy
3477 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3478 {
3479 int bfd;
3480 char_u *copybuf, *wp;
3481 int some_error = FALSE;
3482 struct stat st_new;
3483 char_u *dirp;
3484 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003485#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486 int did_set_shortname;
3487#endif
3488
3489 copybuf = alloc(BUFSIZE + 1);
3490 if (copybuf == NULL)
3491 {
3492 some_error = TRUE; /* out of memory */
3493 goto nobackup;
3494 }
3495
3496 /*
3497 * Try to make the backup in each directory in the 'bdir' option.
3498 *
3499 * Unix semantics has it, that we may have a writable file,
3500 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3501 * - the directory is not writable,
3502 * - the file may be a symbolic link,
3503 * - the file may belong to another user/group, etc.
3504 *
3505 * For these reasons, the existing writable file must be truncated
3506 * and reused. Creation of a backup COPY will be attempted.
3507 */
3508 dirp = p_bdir;
3509 while (*dirp)
3510 {
3511#ifdef UNIX
3512 st_new.st_ino = 0;
3513 st_new.st_dev = 0;
3514 st_new.st_gid = 0;
3515#endif
3516
3517 /*
3518 * Isolate one directory name, using an entry in 'bdir'.
3519 */
3520 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3521 rootname = get_file_in_dir(fname, copybuf);
3522 if (rootname == NULL)
3523 {
3524 some_error = TRUE; /* out of memory */
3525 goto nobackup;
3526 }
3527
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003528#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 did_set_shortname = FALSE;
3530#endif
3531
3532 /*
3533 * May try twice if 'shortname' not set.
3534 */
3535 for (;;)
3536 {
3537 /*
3538 * Make backup file name.
3539 */
3540 backup = buf_modname(
3541#ifdef SHORT_FNAME
3542 TRUE,
3543#else
3544 (buf->b_p_sn || buf->b_shortname),
3545#endif
3546 rootname, backup_ext, FALSE);
3547 if (backup == NULL)
3548 {
3549 vim_free(rootname);
3550 some_error = TRUE; /* out of memory */
3551 goto nobackup;
3552 }
3553
3554 /*
3555 * Check if backup file already exists.
3556 */
3557 if (mch_stat((char *)backup, &st_new) >= 0)
3558 {
3559#ifdef UNIX
3560 /*
3561 * Check if backup file is same as original file.
3562 * May happen when modname() gave the same file back.
3563 * E.g. silly link, or file name-length reached.
3564 * If we don't check here, we either ruin the file
3565 * when copying or erase it after writing. jw.
3566 */
3567 if (st_new.st_dev == st_old.st_dev
3568 && st_new.st_ino == st_old.st_ino)
3569 {
3570 vim_free(backup);
3571 backup = NULL; /* no backup file to delete */
3572# ifndef SHORT_FNAME
3573 /*
3574 * may try again with 'shortname' set
3575 */
3576 if (!(buf->b_shortname || buf->b_p_sn))
3577 {
3578 buf->b_shortname = TRUE;
3579 did_set_shortname = TRUE;
3580 continue;
3581 }
3582 /* setting shortname didn't help */
3583 if (did_set_shortname)
3584 buf->b_shortname = FALSE;
3585# endif
3586 break;
3587 }
3588#endif
3589
3590 /*
3591 * If we are not going to keep the backup file, don't
3592 * delete an existing one, try to use another name.
3593 * Change one character, just before the extension.
3594 */
3595 if (!p_bk)
3596 {
3597 wp = backup + STRLEN(backup) - 1
3598 - STRLEN(backup_ext);
3599 if (wp < backup) /* empty file name ??? */
3600 wp = backup;
3601 *wp = 'z';
3602 while (*wp > 'a'
3603 && mch_stat((char *)backup, &st_new) >= 0)
3604 --*wp;
3605 /* They all exist??? Must be something wrong. */
3606 if (*wp == 'a')
3607 {
3608 vim_free(backup);
3609 backup = NULL;
3610 }
3611 }
3612 }
3613 break;
3614 }
3615 vim_free(rootname);
3616
3617 /*
3618 * Try to create the backup file
3619 */
3620 if (backup != NULL)
3621 {
3622 /* remove old backup, if present */
3623 mch_remove(backup);
3624 /* Open with O_EXCL to avoid the file being created while
3625 * we were sleeping (symlink hacker attack?) */
3626 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003627 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3628 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629 if (bfd < 0)
3630 {
3631 vim_free(backup);
3632 backup = NULL;
3633 }
3634 else
3635 {
3636 /* set file protection same as original file, but
3637 * strip s-bit */
3638 (void)mch_setperm(backup, perm & 0777);
3639
3640#ifdef UNIX
3641 /*
3642 * Try to set the group of the backup same as the
3643 * original file. If this fails, set the protection
3644 * bits for the group same as the protection bits for
3645 * others.
3646 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003647 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003649 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650# endif
3651 )
3652 mch_setperm(backup,
3653 (perm & 0707) | ((perm & 07) << 3));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003654# ifdef HAVE_SELINUX
3655 mch_copy_sec(fname, backup);
3656# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657#endif
3658
3659 /*
3660 * copy the file.
3661 */
3662 write_info.bw_fd = bfd;
3663 write_info.bw_buf = copybuf;
3664#ifdef HAS_BW_FLAGS
3665 write_info.bw_flags = FIO_NOCONVERT;
3666#endif
3667 while ((write_info.bw_len = vim_read(fd, copybuf,
3668 BUFSIZE)) > 0)
3669 {
3670 if (buf_write_bytes(&write_info) == FAIL)
3671 {
3672 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3673 break;
3674 }
3675 ui_breakcheck();
3676 if (got_int)
3677 {
3678 errmsg = (char_u *)_(e_interr);
3679 break;
3680 }
3681 }
3682
3683 if (close(bfd) < 0 && errmsg == NULL)
3684 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3685 if (write_info.bw_len < 0)
3686 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3687#ifdef UNIX
3688 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3689#endif
3690#ifdef HAVE_ACL
3691 mch_set_acl(backup, acl);
3692#endif
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003693#ifdef HAVE_SELINUX
3694 mch_copy_sec(fname, backup);
3695#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696 break;
3697 }
3698 }
3699 }
3700 nobackup:
3701 close(fd); /* ignore errors for closing read file */
3702 vim_free(copybuf);
3703
3704 if (backup == NULL && errmsg == NULL)
3705 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3706 /* ignore errors when forceit is TRUE */
3707 if ((some_error || errmsg != NULL) && !forceit)
3708 {
3709 retval = FAIL;
3710 goto fail;
3711 }
3712 errmsg = NULL;
3713 }
3714 else
3715 {
3716 char_u *dirp;
3717 char_u *p;
3718 char_u *rootname;
3719
3720 /*
3721 * Make a backup by renaming the original file.
3722 */
3723 /*
3724 * If 'cpoptions' includes the "W" flag, we don't want to
3725 * overwrite a read-only file. But rename may be possible
3726 * anyway, thus we need an extra check here.
3727 */
3728 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3729 {
3730 errnum = (char_u *)"E504: ";
3731 errmsg = (char_u *)_(err_readonly);
3732 goto fail;
3733 }
3734
3735 /*
3736 *
3737 * Form the backup file name - change path/fo.o.h to
3738 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3739 * that works is used.
3740 */
3741 dirp = p_bdir;
3742 while (*dirp)
3743 {
3744 /*
3745 * Isolate one directory name and make the backup file name.
3746 */
3747 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
3748 rootname = get_file_in_dir(fname, IObuff);
3749 if (rootname == NULL)
3750 backup = NULL;
3751 else
3752 {
3753 backup = buf_modname(
3754#ifdef SHORT_FNAME
3755 TRUE,
3756#else
3757 (buf->b_p_sn || buf->b_shortname),
3758#endif
3759 rootname, backup_ext, FALSE);
3760 vim_free(rootname);
3761 }
3762
3763 if (backup != NULL)
3764 {
3765 /*
3766 * If we are not going to keep the backup file, don't
3767 * delete an existing one, try to use another name.
3768 * Change one character, just before the extension.
3769 */
3770 if (!p_bk && mch_getperm(backup) >= 0)
3771 {
3772 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
3773 if (p < backup) /* empty file name ??? */
3774 p = backup;
3775 *p = 'z';
3776 while (*p > 'a' && mch_getperm(backup) >= 0)
3777 --*p;
3778 /* They all exist??? Must be something wrong! */
3779 if (*p == 'a')
3780 {
3781 vim_free(backup);
3782 backup = NULL;
3783 }
3784 }
3785 }
3786 if (backup != NULL)
3787 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003789 * Delete any existing backup and move the current version
3790 * to the backup. For safety, we don't remove the backup
3791 * until the write has finished successfully. And if the
3792 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793 */
3794 /*
3795 * If the renaming of the original file to the backup file
3796 * works, quit here.
3797 */
3798 if (vim_rename(fname, backup) == 0)
3799 break;
3800
3801 vim_free(backup); /* don't do the rename below */
3802 backup = NULL;
3803 }
3804 }
3805 if (backup == NULL && !forceit)
3806 {
3807 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
3808 goto fail;
3809 }
3810 }
3811 }
3812
3813#if defined(UNIX) && !defined(ARCHIE)
3814 /* When using ":w!" and the file was read-only: make it writable */
3815 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
3816 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
3817 {
3818 perm |= 0200;
3819 (void)mch_setperm(fname, perm);
3820 made_writable = TRUE;
3821 }
3822#endif
3823
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003824 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003825 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
3826 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 {
3828 buf->b_p_ro = FALSE;
3829#ifdef FEAT_TITLE
3830 need_maketitle = TRUE; /* set window title later */
3831#endif
3832#ifdef FEAT_WINDOWS
3833 status_redraw_all(); /* redraw status lines later */
3834#endif
3835 }
3836
3837 if (end > buf->b_ml.ml_line_count)
3838 end = buf->b_ml.ml_line_count;
3839 if (buf->b_ml.ml_flags & ML_EMPTY)
3840 start = end + 1;
3841
3842 /*
3843 * If the original file is being overwritten, there is a small chance that
3844 * we crash in the middle of writing. Therefore the file is preserved now.
3845 * This makes all block numbers positive so that recovery does not need
3846 * the original file.
3847 * Don't do this if there is a backup file and we are exiting.
3848 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003849 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 && !(exiting && backup != NULL))
3851 {
3852 ml_preserve(buf, FALSE);
3853 if (got_int)
3854 {
3855 errmsg = (char_u *)_(e_interr);
3856 goto restore_backup;
3857 }
3858 }
3859
3860#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
3861 /*
3862 * Before risking to lose the original file verify if there's
3863 * a resource fork to preserve, and if cannot be done warn
3864 * the users. This happens when overwriting without backups.
3865 */
3866 if (backup == NULL && overwriting && !append)
3867 if (mch_has_resource_fork(fname))
3868 {
3869 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
3870 goto restore_backup;
3871 }
3872#endif
3873
3874#ifdef VMS
3875 vms_remove_version(fname); /* remove version */
3876#endif
3877 /* Default: write the the file directly. May write to a temp file for
3878 * multi-byte conversion. */
3879 wfname = fname;
3880
3881#ifdef FEAT_MBYTE
3882 /* Check for forced 'fileencoding' from "++opt=val" argument. */
3883 if (eap != NULL && eap->force_enc != 0)
3884 {
3885 fenc = eap->cmd + eap->force_enc;
3886 fenc = enc_canonize(fenc);
3887 fenc_tofree = fenc;
3888 }
3889 else
3890 fenc = buf->b_p_fenc;
3891
3892 /*
3893 * The file needs to be converted when 'fileencoding' is set and
3894 * 'fileencoding' differs from 'encoding'.
3895 */
3896 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
3897
3898 /*
3899 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
3900 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
3901 * Prepare the flags for it and allocate bw_conv_buf when needed.
3902 */
3903 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
3904 {
3905 wb_flags = get_fio_flags(fenc);
3906 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
3907 {
3908 /* Need to allocate a buffer to translate into. */
3909 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
3910 write_info.bw_conv_buflen = bufsize * 2;
3911 else /* FIO_UCS4 */
3912 write_info.bw_conv_buflen = bufsize * 4;
3913 write_info.bw_conv_buf
3914 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3915 if (write_info.bw_conv_buf == NULL)
3916 end = 0;
3917 }
3918 }
3919
3920# ifdef WIN3264
3921 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
3922 {
3923 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
3924 write_info.bw_conv_buflen = bufsize * 4;
3925 write_info.bw_conv_buf
3926 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3927 if (write_info.bw_conv_buf == NULL)
3928 end = 0;
3929 }
3930# endif
3931
3932# ifdef MACOS_X
3933 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
3934 {
3935 write_info.bw_conv_buflen = bufsize * 3;
3936 write_info.bw_conv_buf
3937 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3938 if (write_info.bw_conv_buf == NULL)
3939 end = 0;
3940 }
3941# endif
3942
3943# if defined(FEAT_EVAL) || defined(USE_ICONV)
3944 if (converted && wb_flags == 0)
3945 {
3946# ifdef USE_ICONV
3947 /*
3948 * Use iconv() conversion when conversion is needed and it's not done
3949 * internally.
3950 */
3951 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
3952 enc_utf8 ? (char_u *)"utf-8" : p_enc);
3953 if (write_info.bw_iconv_fd != (iconv_t)-1)
3954 {
3955 /* We're going to use iconv(), allocate a buffer to convert in. */
3956 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
3957 write_info.bw_conv_buf
3958 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3959 if (write_info.bw_conv_buf == NULL)
3960 end = 0;
3961 write_info.bw_first = TRUE;
3962 }
3963# ifdef FEAT_EVAL
3964 else
3965# endif
3966# endif
3967
3968# ifdef FEAT_EVAL
3969 /*
3970 * When the file needs to be converted with 'charconvert' after
3971 * writing, write to a temp file instead and let the conversion
3972 * overwrite the original file.
3973 */
3974 if (*p_ccv != NUL)
3975 {
3976 wfname = vim_tempname('w');
3977 if (wfname == NULL) /* Can't write without a tempfile! */
3978 {
3979 errmsg = (char_u *)_("E214: Can't find temp file for writing");
3980 goto restore_backup;
3981 }
3982 }
3983# endif
3984 }
3985# endif
3986 if (converted && wb_flags == 0
3987# ifdef USE_ICONV
3988 && write_info.bw_iconv_fd == (iconv_t)-1
3989# endif
3990# ifdef FEAT_EVAL
3991 && wfname == fname
3992# endif
3993 )
3994 {
3995 if (!forceit)
3996 {
3997 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
3998 goto restore_backup;
3999 }
4000 notconverted = TRUE;
4001 }
4002#endif
4003
4004 /*
4005 * Open the file "wfname" for writing.
4006 * We may try to open the file twice: If we can't write to the
4007 * file and forceit is TRUE we delete the existing file and try to create
4008 * a new one. If this still fails we may have lost the original file!
4009 * (this may happen when the user reached his quotum for number of files).
4010 * Appending will fail if the file does not exist and forceit is FALSE.
4011 */
4012 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
4013 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
4014 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004015 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 {
4017 /*
4018 * A forced write will try to create a new file if the old one is
4019 * still readonly. This may also happen when the directory is
4020 * read-only. In that case the mch_remove() will fail.
4021 */
4022 if (errmsg == NULL)
4023 {
4024#ifdef UNIX
4025 struct stat st;
4026
4027 /* Don't delete the file when it's a hard or symbolic link. */
4028 if ((!newfile && st_old.st_nlink > 1)
4029 || (mch_lstat((char *)fname, &st) == 0
4030 && (st.st_dev != st_old.st_dev
4031 || st.st_ino != st_old.st_ino)))
4032 errmsg = (char_u *)_("E166: Can't open linked file for writing");
4033 else
4034#endif
4035 {
4036 errmsg = (char_u *)_("E212: Can't open file for writing");
4037 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
4038 && perm >= 0)
4039 {
4040#ifdef UNIX
4041 /* we write to the file, thus it should be marked
4042 writable after all */
4043 if (!(perm & 0200))
4044 made_writable = TRUE;
4045 perm |= 0200;
4046 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
4047 perm &= 0777;
4048#endif
4049 if (!append) /* don't remove when appending */
4050 mch_remove(wfname);
4051 continue;
4052 }
4053 }
4054 }
4055
4056restore_backup:
4057 {
4058 struct stat st;
4059
4060 /*
4061 * If we failed to open the file, we don't need a backup. Throw it
4062 * away. If we moved or removed the original file try to put the
4063 * backup in its place.
4064 */
4065 if (backup != NULL && wfname == fname)
4066 {
4067 if (backup_copy)
4068 {
4069 /*
4070 * There is a small chance that we removed the original,
4071 * try to move the copy in its place.
4072 * This may not work if the vim_rename() fails.
4073 * In that case we leave the copy around.
4074 */
4075 /* If file does not exist, put the copy in its place */
4076 if (mch_stat((char *)fname, &st) < 0)
4077 vim_rename(backup, fname);
4078 /* if original file does exist throw away the copy */
4079 if (mch_stat((char *)fname, &st) >= 0)
4080 mch_remove(backup);
4081 }
4082 else
4083 {
4084 /* try to put the original file back */
4085 vim_rename(backup, fname);
4086 }
4087 }
4088
4089 /* if original file no longer exists give an extra warning */
4090 if (!newfile && mch_stat((char *)fname, &st) < 0)
4091 end = 0;
4092 }
4093
4094#ifdef FEAT_MBYTE
4095 if (wfname != fname)
4096 vim_free(wfname);
4097#endif
4098 goto fail;
4099 }
4100 errmsg = NULL;
4101
4102#if defined(MACOS_CLASSIC) || defined(WIN3264)
4103 /* TODO: Is it need for MACOS_X? (Dany) */
4104 /*
4105 * On macintosh copy the original files attributes (i.e. the backup)
Bram Moolenaar7263a772007-05-10 17:35:54 +00004106 * This is done in order to preserve the resource fork and the
4107 * Finder attribute (label, comments, custom icons, file creator)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 */
4109 if (backup != NULL && overwriting && !append)
4110 {
4111 if (backup_copy)
4112 (void)mch_copy_file_attribute(wfname, backup);
4113 else
4114 (void)mch_copy_file_attribute(backup, wfname);
4115 }
4116
4117 if (!overwriting && !append)
4118 {
4119 if (buf->b_ffname != NULL)
4120 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
Bram Moolenaar7263a772007-05-10 17:35:54 +00004121 /* Should copy resource fork */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 }
4123#endif
4124
4125 write_info.bw_fd = fd;
4126
4127#ifdef FEAT_CRYPT
4128 if (*buf->b_p_key && !filtering)
4129 {
4130 crypt_init_keys(buf->b_p_key);
4131 /* Write magic number, so that Vim knows that this file is encrypted
4132 * when reading it again. This also undergoes utf-8 to ucs-2/4
4133 * conversion when needed. */
4134 write_info.bw_buf = (char_u *)CRYPT_MAGIC;
4135 write_info.bw_len = CRYPT_MAGIC_LEN;
4136 write_info.bw_flags = FIO_NOCONVERT;
4137 if (buf_write_bytes(&write_info) == FAIL)
4138 end = 0;
4139 wb_flags |= FIO_ENCRYPTED;
4140 }
4141#endif
4142
4143 write_info.bw_buf = buffer;
4144 nchars = 0;
4145
4146 /* use "++bin", "++nobin" or 'binary' */
4147 if (eap != NULL && eap->force_bin != 0)
4148 write_bin = (eap->force_bin == FORCE_BIN);
4149 else
4150 write_bin = buf->b_p_bin;
4151
4152#ifdef FEAT_MBYTE
4153 /*
4154 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004155 * Skip it when appending and the file already existed, the BOM only makes
4156 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004158 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 {
4160 write_info.bw_len = make_bom(buffer, fenc);
4161 if (write_info.bw_len > 0)
4162 {
4163 /* don't convert, do encryption */
4164 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4165 if (buf_write_bytes(&write_info) == FAIL)
4166 end = 0;
4167 else
4168 nchars += write_info.bw_len;
4169 }
4170 }
4171#endif
4172
4173 write_info.bw_len = bufsize;
4174#ifdef HAS_BW_FLAGS
4175 write_info.bw_flags = wb_flags;
4176#endif
4177 fileformat = get_fileformat_force(buf, eap);
4178 s = buffer;
4179 len = 0;
4180 for (lnum = start; lnum <= end; ++lnum)
4181 {
4182 /*
4183 * The next while loop is done once for each character written.
4184 * Keep it fast!
4185 */
4186 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4187 while ((c = *++ptr) != NUL)
4188 {
4189 if (c == NL)
4190 *s = NUL; /* replace newlines with NULs */
4191 else if (c == CAR && fileformat == EOL_MAC)
4192 *s = NL; /* Mac: replace CRs with NLs */
4193 else
4194 *s = c;
4195 ++s;
4196 if (++len != bufsize)
4197 continue;
4198 if (buf_write_bytes(&write_info) == FAIL)
4199 {
4200 end = 0; /* write error: break loop */
4201 break;
4202 }
4203 nchars += bufsize;
4204 s = buffer;
4205 len = 0;
4206 }
4207 /* write failed or last line has no EOL: stop here */
4208 if (end == 0
4209 || (lnum == end
4210 && write_bin
4211 && (lnum == write_no_eol_lnum
4212 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4213 {
4214 ++lnum; /* written the line, count it */
4215 no_eol = TRUE;
4216 break;
4217 }
4218 if (fileformat == EOL_UNIX)
4219 *s++ = NL;
4220 else
4221 {
4222 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4223 if (fileformat == EOL_DOS) /* write CR-NL */
4224 {
4225 if (++len == bufsize)
4226 {
4227 if (buf_write_bytes(&write_info) == FAIL)
4228 {
4229 end = 0; /* write error: break loop */
4230 break;
4231 }
4232 nchars += bufsize;
4233 s = buffer;
4234 len = 0;
4235 }
4236 *s++ = NL;
4237 }
4238 }
4239 if (++len == bufsize && end)
4240 {
4241 if (buf_write_bytes(&write_info) == FAIL)
4242 {
4243 end = 0; /* write error: break loop */
4244 break;
4245 }
4246 nchars += bufsize;
4247 s = buffer;
4248 len = 0;
4249
4250 ui_breakcheck();
4251 if (got_int)
4252 {
4253 end = 0; /* Interrupted, break loop */
4254 break;
4255 }
4256 }
4257#ifdef VMS
4258 /*
4259 * On VMS there is a problem: newlines get added when writing blocks
4260 * at a time. Fix it by writing a line at a time.
4261 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004262 * Explanation: VAX/DECC RTL insists that records in some RMS
4263 * structures end with a newline (carriage return) character, and if
4264 * they don't it adds one.
4265 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266 */
Bram Moolenaarb52e2602007-10-29 21:38:54 +00004267 if (buf->b_fab_rfm == FAB$C_VFC
4268 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004270 int b2write;
4271
4272 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4273 ? MIN(4096, bufsize)
4274 : MIN(buf->b_fab_mrs, bufsize));
4275
4276 b2write = len;
4277 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004279 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4280 if (buf_write_bytes(&write_info) == FAIL)
4281 {
4282 end = 0;
4283 break;
4284 }
4285 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 }
4287 write_info.bw_len = bufsize;
4288 nchars += len;
4289 s = buffer;
4290 len = 0;
4291 }
4292#endif
4293 }
4294 if (len > 0 && end > 0)
4295 {
4296 write_info.bw_len = len;
4297 if (buf_write_bytes(&write_info) == FAIL)
4298 end = 0; /* write error */
4299 nchars += len;
4300 }
4301
4302#if defined(UNIX) && defined(HAVE_FSYNC)
4303 /* On many journalling file systems there is a bug that causes both the
4304 * original and the backup file to be lost when halting the system right
4305 * after writing the file. That's because only the meta-data is
4306 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004307 * been written to disk and we don't lose it.
4308 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004309 * (could be a pipe).
4310 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4311 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 {
4313 errmsg = (char_u *)_("E667: Fsync failed");
4314 end = 0;
4315 }
4316#endif
4317
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004318#ifdef HAVE_SELINUX
4319 /* Probably need to set the security context. */
4320 if (!backup_copy)
4321 mch_copy_sec(backup, wfname);
4322#endif
4323
Bram Moolenaara5792f52005-11-23 21:25:05 +00004324#ifdef UNIX
4325 /* When creating a new file, set its owner/group to that of the original
4326 * file. Get the new device and inode number. */
4327 if (backup != NULL && !backup_copy)
4328 {
4329# ifdef HAVE_FCHOWN
4330 struct stat st;
4331
4332 /* don't change the owner when it's already OK, some systems remove
4333 * permission or ACL stuff */
4334 if (mch_stat((char *)wfname, &st) < 0
4335 || st.st_uid != st_old.st_uid
4336 || st.st_gid != st_old.st_gid)
4337 {
4338 fchown(fd, st_old.st_uid, st_old.st_gid);
4339 if (perm >= 0) /* set permission again, may have changed */
4340 (void)mch_setperm(wfname, perm);
4341 }
4342# endif
4343 buf_setino(buf);
4344 }
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004345 else if (buf->b_dev < 0)
4346 /* Set the inode when creating a new file. */
4347 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004348#endif
4349
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 if (close(fd) != 0)
4351 {
4352 errmsg = (char_u *)_("E512: Close failed");
4353 end = 0;
4354 }
4355
4356#ifdef UNIX
4357 if (made_writable)
4358 perm &= ~0200; /* reset 'w' bit for security reasons */
4359#endif
4360 if (perm >= 0) /* set perm. of new file same as old file */
4361 (void)mch_setperm(wfname, perm);
4362#ifdef RISCOS
4363 if (!append && !filtering)
4364 /* Set the filetype after writing the file. */
4365 mch_set_filetype(wfname, buf->b_p_oft);
4366#endif
4367#ifdef HAVE_ACL
4368 /* Probably need to set the ACL before changing the user (can't set the
4369 * ACL on a file the user doesn't own). */
4370 if (!backup_copy)
4371 mch_set_acl(wfname, acl);
4372#endif
4373
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374
4375#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4376 if (wfname != fname)
4377 {
4378 /*
4379 * The file was written to a temp file, now it needs to be converted
4380 * with 'charconvert' to (overwrite) the output file.
4381 */
4382 if (end != 0)
4383 {
4384 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4385 wfname, fname) == FAIL)
4386 {
4387 write_info.bw_conv_error = TRUE;
4388 end = 0;
4389 }
4390 }
4391 mch_remove(wfname);
4392 vim_free(wfname);
4393 }
4394#endif
4395
4396 if (end == 0)
4397 {
4398 if (errmsg == NULL)
4399 {
4400#ifdef FEAT_MBYTE
4401 if (write_info.bw_conv_error)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00004402 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 else
4404#endif
4405 if (got_int)
4406 errmsg = (char_u *)_(e_interr);
4407 else
4408 errmsg = (char_u *)_("E514: write error (file system full?)");
4409 }
4410
4411 /*
4412 * If we have a backup file, try to put it in place of the new file,
4413 * because the new file is probably corrupt. This avoids loosing the
4414 * original file when trying to make a backup when writing the file a
4415 * second time.
4416 * When "backup_copy" is set we need to copy the backup over the new
4417 * file. Otherwise rename the backup file.
4418 * If this is OK, don't give the extra warning message.
4419 */
4420 if (backup != NULL)
4421 {
4422 if (backup_copy)
4423 {
4424 /* This may take a while, if we were interrupted let the user
4425 * know we got the message. */
4426 if (got_int)
4427 {
4428 MSG(_(e_interr));
4429 out_flush();
4430 }
4431 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4432 {
4433 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004434 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4435 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 {
4437 /* copy the file. */
4438 write_info.bw_buf = smallbuf;
4439#ifdef HAS_BW_FLAGS
4440 write_info.bw_flags = FIO_NOCONVERT;
4441#endif
4442 while ((write_info.bw_len = vim_read(fd, smallbuf,
4443 SMBUFSIZE)) > 0)
4444 if (buf_write_bytes(&write_info) == FAIL)
4445 break;
4446
4447 if (close(write_info.bw_fd) >= 0
4448 && write_info.bw_len == 0)
4449 end = 1; /* success */
4450 }
4451 close(fd); /* ignore errors for closing read file */
4452 }
4453 }
4454 else
4455 {
4456 if (vim_rename(backup, fname) == 0)
4457 end = 1;
4458 }
4459 }
4460 goto fail;
4461 }
4462
4463 lnum -= start; /* compute number of written lines */
4464 --no_wait_return; /* may wait for return now */
4465
4466#if !(defined(UNIX) || defined(VMS))
4467 fname = sfname; /* use shortname now, for the messages */
4468#endif
4469 if (!filtering)
4470 {
4471 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4472 c = FALSE;
4473#ifdef FEAT_MBYTE
4474 if (write_info.bw_conv_error)
4475 {
4476 STRCAT(IObuff, _(" CONVERSION ERROR"));
4477 c = TRUE;
4478 }
4479 else if (notconverted)
4480 {
4481 STRCAT(IObuff, _("[NOT converted]"));
4482 c = TRUE;
4483 }
4484 else if (converted)
4485 {
4486 STRCAT(IObuff, _("[converted]"));
4487 c = TRUE;
4488 }
4489#endif
4490 if (device)
4491 {
4492 STRCAT(IObuff, _("[Device]"));
4493 c = TRUE;
4494 }
4495 else if (newfile)
4496 {
4497 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4498 c = TRUE;
4499 }
4500 if (no_eol)
4501 {
4502 msg_add_eol();
4503 c = TRUE;
4504 }
4505 /* may add [unix/dos/mac] */
4506 if (msg_add_fileformat(fileformat))
4507 c = TRUE;
4508#ifdef FEAT_CRYPT
4509 if (wb_flags & FIO_ENCRYPTED)
4510 {
4511 STRCAT(IObuff, _("[crypted]"));
4512 c = TRUE;
4513 }
4514#endif
4515 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4516 if (!shortmess(SHM_WRITE))
4517 {
4518 if (append)
4519 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4520 else
4521 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4522 }
4523
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00004524 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 }
4526
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004527 /* When written everything correctly: reset 'modified'. Unless not
4528 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004529 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530#ifdef FEAT_MBYTE
4531 && !write_info.bw_conv_error
4532#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004533 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4534 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535 {
4536 unchanged(buf, TRUE);
4537 u_unchanged(buf);
4538 }
4539
4540 /*
4541 * If written to the current file, update the timestamp of the swap file
4542 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4543 */
4544 if (overwriting)
4545 {
4546 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004547 if (append)
4548 buf->b_flags &= ~BF_NEW;
4549 else
4550 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 }
4552
4553 /*
4554 * If we kept a backup until now, and we are in patch mode, then we make
4555 * the backup file our 'original' file.
4556 */
4557 if (*p_pm && dobackup)
4558 {
4559 char *org = (char *)buf_modname(
4560#ifdef SHORT_FNAME
4561 TRUE,
4562#else
4563 (buf->b_p_sn || buf->b_shortname),
4564#endif
4565 fname, p_pm, FALSE);
4566
4567 if (backup != NULL)
4568 {
4569 struct stat st;
4570
4571 /*
4572 * If the original file does not exist yet
4573 * the current backup file becomes the original file
4574 */
4575 if (org == NULL)
4576 EMSG(_("E205: Patchmode: can't save original file"));
4577 else if (mch_stat(org, &st) < 0)
4578 {
4579 vim_rename(backup, (char_u *)org);
4580 vim_free(backup); /* don't delete the file */
4581 backup = NULL;
4582#ifdef UNIX
4583 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4584#endif
4585 }
4586 }
4587 /*
4588 * If there is no backup file, remember that a (new) file was
4589 * created.
4590 */
4591 else
4592 {
4593 int empty_fd;
4594
4595 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004596 || (empty_fd = mch_open(org,
4597 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004598 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 EMSG(_("E206: patchmode: can't touch empty original file"));
4600 else
4601 close(empty_fd);
4602 }
4603 if (org != NULL)
4604 {
4605 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4606 vim_free(org);
4607 }
4608 }
4609
4610 /*
4611 * Remove the backup unless 'backup' option is set
4612 */
4613 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4614 EMSG(_("E207: Can't delete backup file"));
4615
4616#ifdef FEAT_SUN_WORKSHOP
4617 if (usingSunWorkShop)
4618 workshop_file_saved((char *) ffname);
4619#endif
4620
4621 goto nofail;
4622
4623 /*
4624 * Finish up. We get here either after failure or success.
4625 */
4626fail:
4627 --no_wait_return; /* may wait for return now */
4628nofail:
4629
4630 /* Done saving, we accept changed buffer warnings again */
4631 buf->b_saving = FALSE;
4632
4633 vim_free(backup);
4634 if (buffer != smallbuf)
4635 vim_free(buffer);
4636#ifdef FEAT_MBYTE
4637 vim_free(fenc_tofree);
4638 vim_free(write_info.bw_conv_buf);
4639# ifdef USE_ICONV
4640 if (write_info.bw_iconv_fd != (iconv_t)-1)
4641 {
4642 iconv_close(write_info.bw_iconv_fd);
4643 write_info.bw_iconv_fd = (iconv_t)-1;
4644 }
4645# endif
4646#endif
4647#ifdef HAVE_ACL
4648 mch_free_acl(acl);
4649#endif
4650
4651 if (errmsg != NULL)
4652 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004653 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654
4655 attr = hl_attr(HLF_E); /* set highlight for error messages */
4656 msg_add_fname(buf,
4657#ifndef UNIX
4658 sfname
4659#else
4660 fname
4661#endif
4662 ); /* put file name in IObuff with quotes */
4663 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4664 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4665 /* If the error message has the form "is ...", put the error number in
4666 * front of the file name. */
4667 if (errnum != NULL)
4668 {
4669 mch_memmove(IObuff + numlen, IObuff, STRLEN(IObuff) + 1);
4670 mch_memmove(IObuff, errnum, (size_t)numlen);
4671 }
4672 STRCAT(IObuff, errmsg);
4673 emsg(IObuff);
4674
4675 retval = FAIL;
4676 if (end == 0)
4677 {
4678 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4679 attr | MSG_HIST);
4680 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4681 attr | MSG_HIST);
4682
4683 /* Update the timestamp to avoid an "overwrite changed file"
4684 * prompt when writing again. */
4685 if (mch_stat((char *)fname, &st_old) >= 0)
4686 {
4687 buf_store_time(buf, &st_old, fname);
4688 buf->b_mtime_read = buf->b_mtime;
4689 }
4690 }
4691 }
4692 msg_scroll = msg_save;
4693
4694#ifdef FEAT_AUTOCMD
4695#ifdef FEAT_EVAL
4696 if (!should_abort(retval))
4697#else
4698 if (!got_int)
4699#endif
4700 {
4701 aco_save_T aco;
4702
4703 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4704
4705 /*
4706 * Apply POST autocommands.
4707 * Careful: The autocommands may call buf_write() recursively!
4708 */
4709 aucmd_prepbuf(&aco, buf);
4710
4711 if (append)
4712 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4713 FALSE, curbuf, eap);
4714 else if (filtering)
4715 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4716 FALSE, curbuf, eap);
4717 else if (reset_changed && whole)
4718 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4719 FALSE, curbuf, eap);
4720 else
4721 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4722 FALSE, curbuf, eap);
4723
4724 /* restore curwin/curbuf and a few other things */
4725 aucmd_restbuf(&aco);
4726
4727#ifdef FEAT_EVAL
4728 if (aborting()) /* autocmds may abort script processing */
4729 retval = FALSE;
4730#endif
4731 }
4732#endif
4733
4734 got_int |= prev_got_int;
4735
4736#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4737 /* Update machine specific information. */
4738 mch_post_buffer_write(buf);
4739#endif
4740 return retval;
4741}
4742
4743/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004744 * Set the name of the current buffer. Use when the buffer doesn't have a
4745 * name and a ":r" or ":w" command with a file name is used.
4746 */
4747 static int
4748set_rw_fname(fname, sfname)
4749 char_u *fname;
4750 char_u *sfname;
4751{
4752#ifdef FEAT_AUTOCMD
4753 /* It's like the unnamed buffer is deleted.... */
4754 if (curbuf->b_p_bl)
4755 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
4756 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
4757# ifdef FEAT_EVAL
4758 if (aborting()) /* autocmds may abort script processing */
4759 return FAIL;
4760# endif
4761#endif
4762
4763 if (setfname(curbuf, fname, sfname, FALSE) == OK)
4764 curbuf->b_flags |= BF_NOTEDITED;
4765
4766#ifdef FEAT_AUTOCMD
4767 /* ....and a new named one is created */
4768 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
4769 if (curbuf->b_p_bl)
4770 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
4771# ifdef FEAT_EVAL
4772 if (aborting()) /* autocmds may abort script processing */
4773 return FAIL;
4774# endif
4775
4776 /* Do filetype detection now if 'filetype' is empty. */
4777 if (*curbuf->b_p_ft == NUL)
4778 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004779 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar70836c82006-02-20 21:28:49 +00004780 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00004781 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004782 }
4783#endif
4784
4785 return OK;
4786}
4787
4788/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 * Put file name into IObuff with quotes.
4790 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004791 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792msg_add_fname(buf, fname)
4793 buf_T *buf;
4794 char_u *fname;
4795{
4796 if (fname == NULL)
4797 fname = (char_u *)"-stdin-";
4798 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4799 IObuff[0] = '"';
4800 STRCAT(IObuff, "\" ");
4801}
4802
4803/*
4804 * Append message for text mode to IObuff.
4805 * Return TRUE if something appended.
4806 */
4807 static int
4808msg_add_fileformat(eol_type)
4809 int eol_type;
4810{
4811#ifndef USE_CRNL
4812 if (eol_type == EOL_DOS)
4813 {
4814 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4815 return TRUE;
4816 }
4817#endif
4818#ifndef USE_CR
4819 if (eol_type == EOL_MAC)
4820 {
4821 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4822 return TRUE;
4823 }
4824#endif
4825#if defined(USE_CRNL) || defined(USE_CR)
4826 if (eol_type == EOL_UNIX)
4827 {
4828 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4829 return TRUE;
4830 }
4831#endif
4832 return FALSE;
4833}
4834
4835/*
4836 * Append line and character count to IObuff.
4837 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004838 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839msg_add_lines(insert_space, lnum, nchars)
4840 int insert_space;
4841 long lnum;
4842 long nchars;
4843{
4844 char_u *p;
4845
4846 p = IObuff + STRLEN(IObuff);
4847
4848 if (insert_space)
4849 *p++ = ' ';
4850 if (shortmess(SHM_LINES))
4851 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4852 else
4853 {
4854 if (lnum == 1)
4855 STRCPY(p, _("1 line, "));
4856 else
4857 sprintf((char *)p, _("%ld lines, "), lnum);
4858 p += STRLEN(p);
4859 if (nchars == 1)
4860 STRCPY(p, _("1 character"));
4861 else
4862 sprintf((char *)p, _("%ld characters"), nchars);
4863 }
4864}
4865
4866/*
4867 * Append message for missing line separator to IObuff.
4868 */
4869 static void
4870msg_add_eol()
4871{
4872 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4873}
4874
4875/*
4876 * Check modification time of file, before writing to it.
4877 * The size isn't checked, because using a tool like "gzip" takes care of
4878 * using the same timestamp but can't set the size.
4879 */
4880 static int
4881check_mtime(buf, st)
4882 buf_T *buf;
4883 struct stat *st;
4884{
4885 if (buf->b_mtime_read != 0
4886 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4887 {
4888 msg_scroll = TRUE; /* don't overwrite messages here */
4889 msg_silent = 0; /* must give this prompt */
4890 /* don't use emsg() here, don't want to flush the buffers */
4891 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
4892 hl_attr(HLF_E));
4893 if (ask_yesno((char_u *)_("Do you really want to write to it"),
4894 TRUE) == 'n')
4895 return FAIL;
4896 msg_scroll = FALSE; /* always overwrite the file message now */
4897 }
4898 return OK;
4899}
4900
4901 static int
4902time_differs(t1, t2)
4903 long t1, t2;
4904{
4905#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
4906 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
4907 * the seconds. Since the roundoff is done when flushing the inode, the
4908 * time may change unexpectedly by one second!!! */
4909 return (t1 - t2 > 1 || t2 - t1 > 1);
4910#else
4911 return (t1 != t2);
4912#endif
4913}
4914
4915/*
4916 * Call write() to write a number of bytes to the file.
4917 * Also handles encryption and 'encoding' conversion.
4918 *
4919 * Return FAIL for failure, OK otherwise.
4920 */
4921 static int
4922buf_write_bytes(ip)
4923 struct bw_info *ip;
4924{
4925 int wlen;
4926 char_u *buf = ip->bw_buf; /* data to write */
4927 int len = ip->bw_len; /* length of data */
4928#ifdef HAS_BW_FLAGS
4929 int flags = ip->bw_flags; /* extra flags */
4930#endif
4931
4932#ifdef FEAT_MBYTE
4933 /*
4934 * Skip conversion when writing the crypt magic number or the BOM.
4935 */
4936 if (!(flags & FIO_NOCONVERT))
4937 {
4938 char_u *p;
4939 unsigned c;
4940 int n;
4941
4942 if (flags & FIO_UTF8)
4943 {
4944 /*
4945 * Convert latin1 in the buffer to UTF-8 in the file.
4946 */
4947 p = ip->bw_conv_buf; /* translate to buffer */
4948 for (wlen = 0; wlen < len; ++wlen)
4949 p += utf_char2bytes(buf[wlen], p);
4950 buf = ip->bw_conv_buf;
4951 len = (int)(p - ip->bw_conv_buf);
4952 }
4953 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
4954 {
4955 /*
4956 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
4957 * Latin1 chars in the file.
4958 */
4959 if (flags & FIO_LATIN1)
4960 p = buf; /* translate in-place (can only get shorter) */
4961 else
4962 p = ip->bw_conv_buf; /* translate to buffer */
4963 for (wlen = 0; wlen < len; wlen += n)
4964 {
4965 if (wlen == 0 && ip->bw_restlen != 0)
4966 {
4967 int l;
4968
4969 /* Use remainder of previous call. Append the start of
4970 * buf[] to get a full sequence. Might still be too
4971 * short! */
4972 l = CONV_RESTLEN - ip->bw_restlen;
4973 if (l > len)
4974 l = len;
4975 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004976 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 if (n > ip->bw_restlen + len)
4978 {
4979 /* We have an incomplete byte sequence at the end to
4980 * be written. We can't convert it without the
4981 * remaining bytes. Keep them for the next call. */
4982 if (ip->bw_restlen + len > CONV_RESTLEN)
4983 return FAIL;
4984 ip->bw_restlen += len;
4985 break;
4986 }
4987 if (n > 1)
4988 c = utf_ptr2char(ip->bw_rest);
4989 else
4990 c = ip->bw_rest[0];
4991 if (n >= ip->bw_restlen)
4992 {
4993 n -= ip->bw_restlen;
4994 ip->bw_restlen = 0;
4995 }
4996 else
4997 {
4998 ip->bw_restlen -= n;
4999 mch_memmove(ip->bw_rest, ip->bw_rest + n,
5000 (size_t)ip->bw_restlen);
5001 n = 0;
5002 }
5003 }
5004 else
5005 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005006 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 if (n > len - wlen)
5008 {
5009 /* We have an incomplete byte sequence at the end to
5010 * be written. We can't convert it without the
5011 * remaining bytes. Keep them for the next call. */
5012 if (len - wlen > CONV_RESTLEN)
5013 return FAIL;
5014 ip->bw_restlen = len - wlen;
5015 mch_memmove(ip->bw_rest, buf + wlen,
5016 (size_t)ip->bw_restlen);
5017 break;
5018 }
5019 if (n > 1)
5020 c = utf_ptr2char(buf + wlen);
5021 else
5022 c = buf[wlen];
5023 }
5024
5025 ip->bw_conv_error |= ucs2bytes(c, &p, flags);
5026 }
5027 if (flags & FIO_LATIN1)
5028 len = (int)(p - buf);
5029 else
5030 {
5031 buf = ip->bw_conv_buf;
5032 len = (int)(p - ip->bw_conv_buf);
5033 }
5034 }
5035
5036# ifdef WIN3264
5037 else if (flags & FIO_CODEPAGE)
5038 {
5039 /*
5040 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
5041 * codepage.
5042 */
5043 char_u *from;
5044 size_t fromlen;
5045 char_u *to;
5046 int u8c;
5047 BOOL bad = FALSE;
5048 int needed;
5049
5050 if (ip->bw_restlen > 0)
5051 {
5052 /* Need to concatenate the remainder of the previous call and
5053 * the bytes of the current call. Use the end of the
5054 * conversion buffer for this. */
5055 fromlen = len + ip->bw_restlen;
5056 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5057 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5058 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5059 }
5060 else
5061 {
5062 from = buf;
5063 fromlen = len;
5064 }
5065
5066 to = ip->bw_conv_buf;
5067 if (enc_utf8)
5068 {
5069 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
5070 * The buffer has been allocated to be big enough. */
5071 while (fromlen > 0)
5072 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005073 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005074 if (n > (int)fromlen) /* incomplete byte sequence */
5075 break;
5076 u8c = utf_ptr2char(from);
5077 *to++ = (u8c & 0xff);
5078 *to++ = (u8c >> 8);
5079 fromlen -= n;
5080 from += n;
5081 }
5082
5083 /* Copy remainder to ip->bw_rest[] to be used for the next
5084 * call. */
5085 if (fromlen > CONV_RESTLEN)
5086 {
5087 /* weird overlong sequence */
5088 ip->bw_conv_error = TRUE;
5089 return FAIL;
5090 }
5091 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005092 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 }
5094 else
5095 {
5096 /* Convert from enc_codepage to UCS-2, to the start of the
5097 * buffer. The buffer has been allocated to be big enough. */
5098 ip->bw_restlen = 0;
5099 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005100 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 NULL, 0);
5102 if (needed == 0)
5103 {
5104 /* When conversion fails there may be a trailing byte. */
5105 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005106 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107 NULL, 0);
5108 if (needed == 0)
5109 {
5110 /* Conversion doesn't work. */
5111 ip->bw_conv_error = TRUE;
5112 return FAIL;
5113 }
5114 /* Save the trailing byte for the next call. */
5115 ip->bw_rest[0] = from[fromlen - 1];
5116 ip->bw_restlen = 1;
5117 }
5118 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005119 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120 (LPWSTR)to, needed);
5121 if (needed == 0)
5122 {
5123 /* Safety check: Conversion doesn't work. */
5124 ip->bw_conv_error = TRUE;
5125 return FAIL;
5126 }
5127 to += needed * 2;
5128 }
5129
5130 fromlen = to - ip->bw_conv_buf;
5131 buf = to;
5132# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5133 if (FIO_GET_CP(flags) == CP_UTF8)
5134 {
5135 /* Convert from UCS-2 to UTF-8, using the remainder of the
5136 * conversion buffer. Fails when out of space. */
5137 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5138 {
5139 u8c = *from++;
5140 u8c += (*from++ << 8);
5141 to += utf_char2bytes(u8c, to);
5142 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5143 {
5144 ip->bw_conv_error = TRUE;
5145 return FAIL;
5146 }
5147 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005148 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 }
5150 else
5151#endif
5152 {
5153 /* Convert from UCS-2 to the codepage, using the remainder of
5154 * the conversion buffer. If the conversion uses the default
5155 * character "0", the data doesn't fit in this encoding, so
5156 * fail. */
5157 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5158 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005159 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
5160 &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161 if (bad)
5162 {
5163 ip->bw_conv_error = TRUE;
5164 return FAIL;
5165 }
5166 }
5167 }
5168# endif
5169
Bram Moolenaar56718732006-03-15 22:53:57 +00005170# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 else if (flags & FIO_MACROMAN)
5172 {
5173 /*
5174 * Convert UTF-8 or latin1 to Apple MacRoman.
5175 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005176 char_u *from;
5177 size_t fromlen;
5178
5179 if (ip->bw_restlen > 0)
5180 {
5181 /* Need to concatenate the remainder of the previous call and
5182 * the bytes of the current call. Use the end of the
5183 * conversion buffer for this. */
5184 fromlen = len + ip->bw_restlen;
5185 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5186 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5187 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5188 }
5189 else
5190 {
5191 from = buf;
5192 fromlen = len;
5193 }
5194
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005195 if (enc2macroman(from, fromlen,
5196 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5197 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005198 {
5199 ip->bw_conv_error = TRUE;
5200 return FAIL;
5201 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005202 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 }
5204# endif
5205
5206# ifdef USE_ICONV
5207 if (ip->bw_iconv_fd != (iconv_t)-1)
5208 {
5209 const char *from;
5210 size_t fromlen;
5211 char *to;
5212 size_t tolen;
5213
5214 /* Convert with iconv(). */
5215 if (ip->bw_restlen > 0)
5216 {
5217 /* Need to concatenate the remainder of the previous call and
5218 * the bytes of the current call. Use the end of the
5219 * conversion buffer for this. */
5220 fromlen = len + ip->bw_restlen;
5221 from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5222 mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
5223 mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
5224 tolen = ip->bw_conv_buflen - fromlen;
5225 }
5226 else
5227 {
5228 from = (const char *)buf;
5229 fromlen = len;
5230 tolen = ip->bw_conv_buflen;
5231 }
5232 to = (char *)ip->bw_conv_buf;
5233
5234 if (ip->bw_first)
5235 {
5236 size_t save_len = tolen;
5237
5238 /* output the initial shift state sequence */
5239 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5240
5241 /* There is a bug in iconv() on Linux (which appears to be
5242 * wide-spread) which sets "to" to NULL and messes up "tolen".
5243 */
5244 if (to == NULL)
5245 {
5246 to = (char *)ip->bw_conv_buf;
5247 tolen = save_len;
5248 }
5249 ip->bw_first = FALSE;
5250 }
5251
5252 /*
5253 * If iconv() has an error or there is not enough room, fail.
5254 */
5255 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5256 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5257 || fromlen > CONV_RESTLEN)
5258 {
5259 ip->bw_conv_error = TRUE;
5260 return FAIL;
5261 }
5262
5263 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5264 if (fromlen > 0)
5265 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5266 ip->bw_restlen = (int)fromlen;
5267
5268 buf = ip->bw_conv_buf;
5269 len = (int)((char_u *)to - ip->bw_conv_buf);
5270 }
5271# endif
5272 }
5273#endif /* FEAT_MBYTE */
5274
5275#ifdef FEAT_CRYPT
5276 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5277 {
5278 int ztemp, t, i;
5279
5280 for (i = 0; i < len; i++)
5281 {
5282 ztemp = buf[i];
5283 buf[i] = ZENCODE(ztemp, t);
5284 }
5285 }
5286#endif
5287
5288 /* Repeat the write(), it may be interrupted by a signal. */
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005289 while (len > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290 {
5291 wlen = vim_write(ip->bw_fd, buf, len);
5292 if (wlen <= 0) /* error! */
5293 return FAIL;
5294 len -= wlen;
5295 buf += wlen;
5296 }
5297 return OK;
5298}
5299
5300#ifdef FEAT_MBYTE
5301/*
5302 * Convert a Unicode character to bytes.
5303 */
5304 static int
5305ucs2bytes(c, pp, flags)
5306 unsigned c; /* in: character */
5307 char_u **pp; /* in/out: pointer to result */
5308 int flags; /* FIO_ flags */
5309{
5310 char_u *p = *pp;
5311 int error = FALSE;
5312 int cc;
5313
5314
5315 if (flags & FIO_UCS4)
5316 {
5317 if (flags & FIO_ENDIAN_L)
5318 {
5319 *p++ = c;
5320 *p++ = (c >> 8);
5321 *p++ = (c >> 16);
5322 *p++ = (c >> 24);
5323 }
5324 else
5325 {
5326 *p++ = (c >> 24);
5327 *p++ = (c >> 16);
5328 *p++ = (c >> 8);
5329 *p++ = c;
5330 }
5331 }
5332 else if (flags & (FIO_UCS2 | FIO_UTF16))
5333 {
5334 if (c >= 0x10000)
5335 {
5336 if (flags & FIO_UTF16)
5337 {
5338 /* Make two words, ten bits of the character in each. First
5339 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5340 c -= 0x10000;
5341 if (c >= 0x100000)
5342 error = TRUE;
5343 cc = ((c >> 10) & 0x3ff) + 0xd800;
5344 if (flags & FIO_ENDIAN_L)
5345 {
5346 *p++ = cc;
5347 *p++ = ((unsigned)cc >> 8);
5348 }
5349 else
5350 {
5351 *p++ = ((unsigned)cc >> 8);
5352 *p++ = cc;
5353 }
5354 c = (c & 0x3ff) + 0xdc00;
5355 }
5356 else
5357 error = TRUE;
5358 }
5359 if (flags & FIO_ENDIAN_L)
5360 {
5361 *p++ = c;
5362 *p++ = (c >> 8);
5363 }
5364 else
5365 {
5366 *p++ = (c >> 8);
5367 *p++ = c;
5368 }
5369 }
5370 else /* Latin1 */
5371 {
5372 if (c >= 0x100)
5373 {
5374 error = TRUE;
5375 *p++ = 0xBF;
5376 }
5377 else
5378 *p++ = c;
5379 }
5380
5381 *pp = p;
5382 return error;
5383}
5384
5385/*
5386 * Return TRUE if "a" and "b" are the same 'encoding'.
5387 * Ignores difference between "ansi" and "latin1", "ucs-4" and "ucs-4be", etc.
5388 */
5389 static int
5390same_encoding(a, b)
5391 char_u *a;
5392 char_u *b;
5393{
5394 int f;
5395
5396 if (STRCMP(a, b) == 0)
5397 return TRUE;
5398 f = get_fio_flags(a);
5399 return (f != 0 && get_fio_flags(b) == f);
5400}
5401
5402/*
5403 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5404 * internal conversion.
5405 * if "ptr" is an empty string, use 'encoding'.
5406 */
5407 static int
5408get_fio_flags(ptr)
5409 char_u *ptr;
5410{
5411 int prop;
5412
5413 if (*ptr == NUL)
5414 ptr = p_enc;
5415
5416 prop = enc_canon_props(ptr);
5417 if (prop & ENC_UNICODE)
5418 {
5419 if (prop & ENC_2BYTE)
5420 {
5421 if (prop & ENC_ENDIAN_L)
5422 return FIO_UCS2 | FIO_ENDIAN_L;
5423 return FIO_UCS2;
5424 }
5425 if (prop & ENC_4BYTE)
5426 {
5427 if (prop & ENC_ENDIAN_L)
5428 return FIO_UCS4 | FIO_ENDIAN_L;
5429 return FIO_UCS4;
5430 }
5431 if (prop & ENC_2WORD)
5432 {
5433 if (prop & ENC_ENDIAN_L)
5434 return FIO_UTF16 | FIO_ENDIAN_L;
5435 return FIO_UTF16;
5436 }
5437 return FIO_UTF8;
5438 }
5439 if (prop & ENC_LATIN1)
5440 return FIO_LATIN1;
5441 /* must be ENC_DBCS, requires iconv() */
5442 return 0;
5443}
5444
5445#ifdef WIN3264
5446/*
5447 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5448 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5449 * Used for conversion between 'encoding' and 'fileencoding'.
5450 */
5451 static int
5452get_win_fio_flags(ptr)
5453 char_u *ptr;
5454{
5455 int cp;
5456
5457 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5458 if (!enc_utf8 && enc_codepage <= 0)
5459 return 0;
5460
5461 cp = encname2codepage(ptr);
5462 if (cp == 0)
5463 {
5464# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5465 if (STRCMP(ptr, "utf-8") == 0)
5466 cp = CP_UTF8;
5467 else
5468# endif
5469 return 0;
5470 }
5471 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5472}
5473#endif
5474
5475#ifdef MACOS_X
5476/*
5477 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5478 * needed for the internal conversion to/from utf-8 or latin1.
5479 */
5480 static int
5481get_mac_fio_flags(ptr)
5482 char_u *ptr;
5483{
5484 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5485 && (enc_canon_props(ptr) & ENC_MACROMAN))
5486 return FIO_MACROMAN;
5487 return 0;
5488}
5489#endif
5490
5491/*
5492 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5493 * "size" must be at least 2.
5494 * Return the name of the encoding and set "*lenp" to the length.
5495 * Returns NULL when no BOM found.
5496 */
5497 static char_u *
5498check_for_bom(p, size, lenp, flags)
5499 char_u *p;
5500 long size;
5501 int *lenp;
5502 int flags;
5503{
5504 char *name = NULL;
5505 int len = 2;
5506
5507 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
5508 && (flags == FIO_ALL || flags == 0))
5509 {
5510 name = "utf-8"; /* EF BB BF */
5511 len = 3;
5512 }
5513 else if (p[0] == 0xff && p[1] == 0xfe)
5514 {
5515 if (size >= 4 && p[2] == 0 && p[3] == 0
5516 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5517 {
5518 name = "ucs-4le"; /* FF FE 00 00 */
5519 len = 4;
5520 }
5521 else if (flags == FIO_ALL || flags == (FIO_UCS2 | FIO_ENDIAN_L))
5522 name = "ucs-2le"; /* FF FE */
5523 else if (flags == (FIO_UTF16 | FIO_ENDIAN_L))
5524 name = "utf-16le"; /* FF FE */
5525 }
5526 else if (p[0] == 0xfe && p[1] == 0xff
5527 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5528 {
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005529 /* Default to utf-16, it works also for ucs-2 text. */
5530 if (flags == FIO_UCS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531 name = "ucs-2"; /* FE FF */
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005532 else
5533 name = "utf-16"; /* FE FF */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534 }
5535 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5536 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5537 {
5538 name = "ucs-4"; /* 00 00 FE FF */
5539 len = 4;
5540 }
5541
5542 *lenp = len;
5543 return (char_u *)name;
5544}
5545
5546/*
5547 * Generate a BOM in "buf[4]" for encoding "name".
5548 * Return the length of the BOM (zero when no BOM).
5549 */
5550 static int
5551make_bom(buf, name)
5552 char_u *buf;
5553 char_u *name;
5554{
5555 int flags;
5556 char_u *p;
5557
5558 flags = get_fio_flags(name);
5559
5560 /* Can't put a BOM in a non-Unicode file. */
5561 if (flags == FIO_LATIN1 || flags == 0)
5562 return 0;
5563
5564 if (flags == FIO_UTF8) /* UTF-8 */
5565 {
5566 buf[0] = 0xef;
5567 buf[1] = 0xbb;
5568 buf[2] = 0xbf;
5569 return 3;
5570 }
5571 p = buf;
5572 (void)ucs2bytes(0xfeff, &p, flags);
5573 return (int)(p - buf);
5574}
5575#endif
5576
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00005577#if defined(FEAT_VIMINFO) || defined(FEAT_BROWSE) || \
Bram Moolenaara0174af2008-01-02 20:08:25 +00005578 defined(FEAT_QUICKFIX) || defined(FEAT_AUTOCMD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005579/*
5580 * Try to find a shortname by comparing the fullname with the current
5581 * directory.
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005582 * Returns "full_path" or pointer into "full_path" if shortened.
5583 */
5584 char_u *
5585shorten_fname1(full_path)
5586 char_u *full_path;
5587{
5588 char_u dirname[MAXPATHL];
5589 char_u *p = full_path;
5590
5591 if (mch_dirname(dirname, MAXPATHL) == OK)
5592 {
5593 p = shorten_fname(full_path, dirname);
5594 if (p == NULL || *p == NUL)
5595 p = full_path;
5596 }
5597 return p;
5598}
Bram Moolenaard4cacdf2007-10-03 10:50:10 +00005599#endif
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005600
5601/*
5602 * Try to find a shortname by comparing the fullname with the current
5603 * directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604 * Returns NULL if not shorter name possible, pointer into "full_path"
5605 * otherwise.
5606 */
5607 char_u *
5608shorten_fname(full_path, dir_name)
5609 char_u *full_path;
5610 char_u *dir_name;
5611{
5612 int len;
5613 char_u *p;
5614
5615 if (full_path == NULL)
5616 return NULL;
5617 len = (int)STRLEN(dir_name);
5618 if (fnamencmp(dir_name, full_path, len) == 0)
5619 {
5620 p = full_path + len;
5621#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5622 /*
5623 * MSDOS: when a file is in the root directory, dir_name will end in a
5624 * slash, since C: by itself does not define a specific dir. In this
5625 * case p may already be correct. <negri>
5626 */
5627 if (!((len > 2) && (*(p - 2) == ':')))
5628#endif
5629 {
5630 if (vim_ispathsep(*p))
5631 ++p;
5632#ifndef VMS /* the path separator is always part of the path */
5633 else
5634 p = NULL;
5635#endif
5636 }
5637 }
5638#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5639 /*
5640 * When using a file in the current drive, remove the drive name:
5641 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5642 * a floppy from "A:\dir" to "B:\dir".
5643 */
5644 else if (len > 3
5645 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5646 && full_path[1] == ':'
5647 && vim_ispathsep(full_path[2]))
5648 p = full_path + 2;
5649#endif
5650 else
5651 p = NULL;
5652 return p;
5653}
5654
5655/*
5656 * Shorten filenames for all buffers.
5657 * When "force" is TRUE: Use full path from now on for files currently being
5658 * edited, both for file name and swap file name. Try to shorten the file
5659 * names a bit, if safe to do so.
5660 * When "force" is FALSE: Only try to shorten absolute file names.
5661 * For buffers that have buftype "nofile" or "scratch": never change the file
5662 * name.
5663 */
5664 void
5665shorten_fnames(force)
5666 int force;
5667{
5668 char_u dirname[MAXPATHL];
5669 buf_T *buf;
5670 char_u *p;
5671
5672 mch_dirname(dirname, MAXPATHL);
5673 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5674 {
5675 if (buf->b_fname != NULL
5676#ifdef FEAT_QUICKFIX
5677 && !bt_nofile(buf)
5678#endif
5679 && !path_with_url(buf->b_fname)
5680 && (force
5681 || buf->b_sfname == NULL
5682 || mch_isFullName(buf->b_sfname)))
5683 {
5684 vim_free(buf->b_sfname);
5685 buf->b_sfname = NULL;
5686 p = shorten_fname(buf->b_ffname, dirname);
5687 if (p != NULL)
5688 {
5689 buf->b_sfname = vim_strsave(p);
5690 buf->b_fname = buf->b_sfname;
5691 }
5692 if (p == NULL || buf->b_fname == NULL)
5693 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005694 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005695
5696 /* Always make the swap file name a full path, a "nofile" buffer may
5697 * also have a swap file. */
5698 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699 }
5700#ifdef FEAT_WINDOWS
5701 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005702 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005703#endif
5704}
5705
5706#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5707 || defined(FEAT_GUI_MSWIN) \
5708 || defined(FEAT_GUI_MAC) \
5709 || defined(PROTO)
5710/*
5711 * Shorten all filenames in "fnames[count]" by current directory.
5712 */
5713 void
5714shorten_filenames(fnames, count)
5715 char_u **fnames;
5716 int count;
5717{
5718 int i;
5719 char_u dirname[MAXPATHL];
5720 char_u *p;
5721
5722 if (fnames == NULL || count < 1)
5723 return;
5724 mch_dirname(dirname, sizeof(dirname));
5725 for (i = 0; i < count; ++i)
5726 {
5727 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5728 {
5729 /* shorten_fname() returns pointer in given "fnames[i]". If free
5730 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5731 * "p" first then free fnames[i]. */
5732 p = vim_strsave(p);
5733 vim_free(fnames[i]);
5734 fnames[i] = p;
5735 }
5736 }
5737}
5738#endif
5739
5740/*
5741 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5742 * fo_o_h.ext for MSDOS or when shortname option set.
5743 *
5744 * Assumed that fname is a valid name found in the filesystem we assure that
5745 * the return value is a different name and ends in 'ext'.
5746 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5747 * characters otherwise.
5748 * Space for the returned name is allocated, must be freed later.
5749 * Returns NULL when out of memory.
5750 */
5751 char_u *
5752modname(fname, ext, prepend_dot)
5753 char_u *fname, *ext;
5754 int prepend_dot; /* may prepend a '.' to file name */
5755{
5756 return buf_modname(
5757#ifdef SHORT_FNAME
5758 TRUE,
5759#else
5760 (curbuf->b_p_sn || curbuf->b_shortname),
5761#endif
5762 fname, ext, prepend_dot);
5763}
5764
5765 char_u *
5766buf_modname(shortname, fname, ext, prepend_dot)
5767 int shortname; /* use 8.3 file name */
5768 char_u *fname, *ext;
5769 int prepend_dot; /* may prepend a '.' to file name */
5770{
5771 char_u *retval;
5772 char_u *s;
5773 char_u *e;
5774 char_u *ptr;
5775 int fnamelen, extlen;
5776
5777 extlen = (int)STRLEN(ext);
5778
5779 /*
5780 * If there is no file name we must get the name of the current directory
5781 * (we need the full path in case :cd is used).
5782 */
5783 if (fname == NULL || *fname == NUL)
5784 {
5785 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5786 if (retval == NULL)
5787 return NULL;
5788 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5789 (fnamelen = (int)STRLEN(retval)) == 0)
5790 {
5791 vim_free(retval);
5792 return NULL;
5793 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005794 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005795 {
5796 retval[fnamelen++] = PATHSEP;
5797 retval[fnamelen] = NUL;
5798 }
5799#ifndef SHORT_FNAME
5800 prepend_dot = FALSE; /* nothing to prepend a dot to */
5801#endif
5802 }
5803 else
5804 {
5805 fnamelen = (int)STRLEN(fname);
5806 retval = alloc((unsigned)(fnamelen + extlen + 3));
5807 if (retval == NULL)
5808 return NULL;
5809 STRCPY(retval, fname);
5810#ifdef VMS
5811 vms_remove_version(retval); /* we do not need versions here */
5812#endif
5813 }
5814
5815 /*
5816 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5817 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5818 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5819 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5820 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005821 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822 {
5823#ifndef RISCOS
5824 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005825# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005827# else
5828# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005830# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005831# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832 )
5833 if (*ptr == '.') /* replace '.' by '_' */
5834 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005835#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005836 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005837 {
5838 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005840 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005841 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842
5843 /* the file name has at most BASENAMELEN characters. */
5844#ifndef SHORT_FNAME
5845 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5846 ptr[BASENAMELEN] = '\0';
5847#endif
5848
5849 s = ptr + STRLEN(ptr);
5850
5851 /*
5852 * For 8.3 file names we may have to reduce the length.
5853 */
5854#ifdef USE_LONG_FNAME
5855 if (!USE_LONG_FNAME || shortname)
5856#else
5857# ifndef SHORT_FNAME
5858 if (shortname)
5859# endif
5860#endif
5861 {
5862 /*
5863 * If there is no file name, or the file name ends in '/', and the
5864 * extension starts with '.', put a '_' before the dot, because just
5865 * ".ext" is invalid.
5866 */
5867 if (fname == NULL || *fname == NUL
5868 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5869 {
5870#ifdef RISCOS
5871 if (*ext == '/')
5872#else
5873 if (*ext == '.')
5874#endif
5875 *s++ = '_';
5876 }
5877 /*
5878 * If the extension starts with '.', truncate the base name at 8
5879 * characters
5880 */
5881#ifdef RISCOS
5882 /* We normally use '/', but swap files are '_' */
5883 else if (*ext == '/' || *ext == '_')
5884#else
5885 else if (*ext == '.')
5886#endif
5887 {
5888 if (s - ptr > (size_t)8)
5889 {
5890 s = ptr + 8;
5891 *s = '\0';
5892 }
5893 }
5894 /*
5895 * If the extension doesn't start with '.', and the file name
5896 * doesn't have an extension yet, append a '.'
5897 */
5898#ifdef RISCOS
5899 else if ((e = vim_strchr(ptr, '/')) == NULL)
5900 *s++ = '/';
5901#else
5902 else if ((e = vim_strchr(ptr, '.')) == NULL)
5903 *s++ = '.';
5904#endif
5905 /*
5906 * If the extension doesn't start with '.', and there already is an
Bram Moolenaar7263a772007-05-10 17:35:54 +00005907 * extension, it may need to be truncated
Bram Moolenaar071d4272004-06-13 20:20:40 +00005908 */
5909 else if ((int)STRLEN(e) + extlen > 4)
5910 s = e + 4 - extlen;
5911 }
5912#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5913 /*
5914 * If there is no file name, and the extension starts with '.', put a
5915 * '_' before the dot, because just ".ext" may be invalid if it's on a
5916 * FAT partition, and on HPFS it doesn't matter.
5917 */
5918 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5919 *s++ = '_';
5920#endif
5921
5922 /*
5923 * Append the extention.
5924 * ext can start with '.' and cannot exceed 3 more characters.
5925 */
5926 STRCPY(s, ext);
5927
5928#ifndef SHORT_FNAME
5929 /*
5930 * Prepend the dot.
5931 */
5932 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5933#ifdef RISCOS
5934 '/'
5935#else
5936 '.'
5937#endif
5938#ifdef USE_LONG_FNAME
5939 && USE_LONG_FNAME
5940#endif
5941 )
5942 {
5943 mch_memmove(e + 1, e, STRLEN(e) + 1);
5944#ifdef RISCOS
5945 *e = '/';
5946#else
5947 *e = '.';
5948#endif
5949 }
5950#endif
5951
5952 /*
5953 * Check that, after appending the extension, the file name is really
5954 * different.
5955 */
5956 if (fname != NULL && STRCMP(fname, retval) == 0)
5957 {
5958 /* we search for a character that can be replaced by '_' */
5959 while (--s >= ptr)
5960 {
5961 if (*s != '_')
5962 {
5963 *s = '_';
5964 break;
5965 }
5966 }
5967 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5968 *ptr = 'v';
5969 }
5970 return retval;
5971}
5972
5973/*
5974 * Like fgets(), but if the file line is too long, it is truncated and the
5975 * rest of the line is thrown away. Returns TRUE for end-of-file.
5976 */
5977 int
5978vim_fgets(buf, size, fp)
5979 char_u *buf;
5980 int size;
5981 FILE *fp;
5982{
5983 char *eof;
5984#define FGETS_SIZE 200
5985 char tbuf[FGETS_SIZE];
5986
5987 buf[size - 2] = NUL;
5988#ifdef USE_CR
5989 eof = fgets_cr((char *)buf, size, fp);
5990#else
5991 eof = fgets((char *)buf, size, fp);
5992#endif
5993 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5994 {
5995 buf[size - 1] = NUL; /* Truncate the line */
5996
5997 /* Now throw away the rest of the line: */
5998 do
5999 {
6000 tbuf[FGETS_SIZE - 2] = NUL;
6001#ifdef USE_CR
6002 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
6003#else
6004 fgets((char *)tbuf, FGETS_SIZE, fp);
6005#endif
6006 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
6007 }
6008 return (eof == NULL);
6009}
6010
6011#if defined(USE_CR) || defined(PROTO)
6012/*
6013 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
6014 * Returns TRUE for end-of-file.
6015 * Only used for the Mac, because it's much slower than vim_fgets().
6016 */
6017 int
6018tag_fgets(buf, size, fp)
6019 char_u *buf;
6020 int size;
6021 FILE *fp;
6022{
6023 int i = 0;
6024 int c;
6025 int eof = FALSE;
6026
6027 for (;;)
6028 {
6029 c = fgetc(fp);
6030 if (c == EOF)
6031 {
6032 eof = TRUE;
6033 break;
6034 }
6035 if (c == '\r')
6036 {
6037 /* Always store a NL for end-of-line. */
6038 if (i < size - 1)
6039 buf[i++] = '\n';
6040 c = fgetc(fp);
6041 if (c != '\n') /* Macintosh format: single CR. */
6042 ungetc(c, fp);
6043 break;
6044 }
6045 if (i < size - 1)
6046 buf[i++] = c;
6047 if (c == '\n')
6048 break;
6049 }
6050 buf[i] = NUL;
6051 return eof;
6052}
6053#endif
6054
6055/*
6056 * rename() only works if both files are on the same file system, this
6057 * function will (attempts to?) copy the file across if rename fails -- webb
6058 * Return -1 for failure, 0 for success.
6059 */
6060 int
6061vim_rename(from, to)
6062 char_u *from;
6063 char_u *to;
6064{
6065 int fd_in;
6066 int fd_out;
6067 int n;
6068 char *errmsg = NULL;
6069 char *buffer;
6070#ifdef AMIGA
6071 BPTR flock;
6072#endif
6073 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006074 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006075#ifdef HAVE_ACL
6076 vim_acl_T acl; /* ACL from original file */
6077#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006078
6079 /*
6080 * When the names are identical, there is nothing to do.
6081 */
6082 if (fnamecmp(from, to) == 0)
6083 return 0;
6084
6085 /*
6086 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
6087 */
6088 if (mch_stat((char *)from, &st) < 0)
6089 return -1;
6090
6091 /*
6092 * Delete the "to" file, this is required on some systems to make the
6093 * mch_rename() work, on other systems it makes sure that we don't have
6094 * two files when the mch_rename() fails.
6095 */
6096
6097#ifdef AMIGA
6098 /*
6099 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
6100 * that the name of the "to" file is the same as the "from" file, even
Bram Moolenaar7263a772007-05-10 17:35:54 +00006101 * though the names are different. To avoid the chance of accidentally
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102 * deleting the "from" file (horror!) we lock it during the remove.
6103 *
6104 * When used for making a backup before writing the file: This should not
6105 * happen with ":w", because startscript() should detect this problem and
6106 * set buf->b_shortname, causing modname() to return a correct ".bak" file
6107 * name. This problem does exist with ":w filename", but then the
6108 * original file will be somewhere else so the backup isn't really
6109 * important. If autoscripting is off the rename may fail.
6110 */
6111 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
6112#endif
6113 mch_remove(to);
6114#ifdef AMIGA
6115 if (flock)
6116 UnLock(flock);
6117#endif
6118
6119 /*
6120 * First try a normal rename, return if it works.
6121 */
6122 if (mch_rename((char *)from, (char *)to) == 0)
6123 return 0;
6124
6125 /*
6126 * Rename() failed, try copying the file.
6127 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006128 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006129#ifdef HAVE_ACL
6130 /* For systems that support ACL: get the ACL from the original file. */
6131 acl = mch_get_acl(from);
6132#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6134 if (fd_in == -1)
6135 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006136
6137 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006138 fd_out = mch_open((char *)to,
6139 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 if (fd_out == -1)
6141 {
6142 close(fd_in);
6143 return -1;
6144 }
6145
6146 buffer = (char *)alloc(BUFSIZE);
6147 if (buffer == NULL)
6148 {
6149 close(fd_in);
6150 close(fd_out);
6151 return -1;
6152 }
6153
6154 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
6155 if (vim_write(fd_out, buffer, n) != n)
6156 {
6157 errmsg = _("E208: Error writing to \"%s\"");
6158 break;
6159 }
6160
6161 vim_free(buffer);
6162 close(fd_in);
6163 if (close(fd_out) < 0)
6164 errmsg = _("E209: Error closing \"%s\"");
6165 if (n < 0)
6166 {
6167 errmsg = _("E210: Error reading \"%s\"");
6168 to = from;
6169 }
Bram Moolenaar7263a772007-05-10 17:35:54 +00006170#ifndef UNIX /* for Unix mch_open() already set the permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006171 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006172#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006173#ifdef HAVE_ACL
6174 mch_set_acl(to, acl);
6175#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006176 if (errmsg != NULL)
6177 {
6178 EMSG2(errmsg, to);
6179 return -1;
6180 }
6181 mch_remove(from);
6182 return 0;
6183}
6184
6185static int already_warned = FALSE;
6186
6187/*
6188 * Check if any not hidden buffer has been changed.
6189 * Postpone the check if there are characters in the stuff buffer, a global
6190 * command is being executed, a mapping is being executed or an autocommand is
6191 * busy.
6192 * Returns TRUE if some message was written (screen should be redrawn and
6193 * cursor positioned).
6194 */
6195 int
6196check_timestamps(focus)
6197 int focus; /* called for GUI focus event */
6198{
6199 buf_T *buf;
6200 int didit = 0;
6201 int n;
6202
6203 /* Don't check timestamps while system() or another low-level function may
6204 * cause us to lose and gain focus. */
6205 if (no_check_timestamps > 0)
6206 return FALSE;
6207
6208 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6209 * event and we would keep on checking if the file is steadily growing.
6210 * Do check again after typing something. */
6211 if (focus && did_check_timestamps)
6212 {
6213 need_check_timestamps = TRUE;
6214 return FALSE;
6215 }
6216
6217 if (!stuff_empty() || global_busy || !typebuf_typed()
6218#ifdef FEAT_AUTOCMD
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006219 || autocmd_busy || curbuf_lock > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006220#endif
6221 )
6222 need_check_timestamps = TRUE; /* check later */
6223 else
6224 {
6225 ++no_wait_return;
6226 did_check_timestamps = TRUE;
6227 already_warned = FALSE;
6228 for (buf = firstbuf; buf != NULL; )
6229 {
6230 /* Only check buffers in a window. */
6231 if (buf->b_nwindows > 0)
6232 {
6233 n = buf_check_timestamp(buf, focus);
6234 if (didit < n)
6235 didit = n;
6236 if (n > 0 && !buf_valid(buf))
6237 {
6238 /* Autocommands have removed the buffer, start at the
6239 * first one again. */
6240 buf = firstbuf;
6241 continue;
6242 }
6243 }
6244 buf = buf->b_next;
6245 }
6246 --no_wait_return;
6247 need_check_timestamps = FALSE;
6248 if (need_wait_return && didit == 2)
6249 {
6250 /* make sure msg isn't overwritten */
6251 msg_puts((char_u *)"\n");
6252 out_flush();
6253 }
6254 }
6255 return didit;
6256}
6257
6258/*
6259 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6260 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6261 * empty.
6262 */
6263 static int
6264move_lines(frombuf, tobuf)
6265 buf_T *frombuf;
6266 buf_T *tobuf;
6267{
6268 buf_T *tbuf = curbuf;
6269 int retval = OK;
6270 linenr_T lnum;
6271 char_u *p;
6272
6273 /* Copy the lines in "frombuf" to "tobuf". */
6274 curbuf = tobuf;
6275 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6276 {
6277 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6278 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6279 {
6280 vim_free(p);
6281 retval = FAIL;
6282 break;
6283 }
6284 vim_free(p);
6285 }
6286
6287 /* Delete all the lines in "frombuf". */
6288 if (retval != FAIL)
6289 {
6290 curbuf = frombuf;
Bram Moolenaar9460b9d2007-01-09 14:37:01 +00006291 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
6292 if (ml_delete(lnum, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006293 {
6294 /* Oops! We could try putting back the saved lines, but that
6295 * might fail again... */
6296 retval = FAIL;
6297 break;
6298 }
6299 }
6300
6301 curbuf = tbuf;
6302 return retval;
6303}
6304
6305/*
6306 * Check if buffer "buf" has been changed.
6307 * Also check if the file for a new buffer unexpectedly appeared.
6308 * return 1 if a changed buffer was found.
6309 * return 2 if a message has been displayed.
6310 * return 0 otherwise.
6311 */
6312/*ARGSUSED*/
6313 int
6314buf_check_timestamp(buf, focus)
6315 buf_T *buf;
6316 int focus; /* called for GUI focus event */
6317{
6318 struct stat st;
6319 int stat_res;
6320 int retval = 0;
6321 char_u *path;
6322 char_u *tbuf;
6323 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006324 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325 int helpmesg = FALSE;
6326 int reload = FALSE;
6327#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6328 int can_reload = FALSE;
6329#endif
6330 size_t orig_size = buf->b_orig_size;
6331 int orig_mode = buf->b_orig_mode;
6332#ifdef FEAT_GUI
6333 int save_mouse_correct = need_mouse_correct;
6334#endif
6335#ifdef FEAT_AUTOCMD
6336 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006337 int n;
6338 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006339#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006340 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006341
6342 /* If there is no file name, the buffer is not loaded, 'buftype' is
6343 * set, we are in the middle of a save or being called recursively: ignore
6344 * this buffer. */
6345 if (buf->b_ffname == NULL
6346 || buf->b_ml.ml_mfp == NULL
6347#if defined(FEAT_QUICKFIX)
6348 || *buf->b_p_bt != NUL
6349#endif
6350 || buf->b_saving
6351#ifdef FEAT_AUTOCMD
6352 || busy
6353#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006354#ifdef FEAT_NETBEANS_INTG
6355 || isNetbeansBuffer(buf)
6356#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006357 )
6358 return 0;
6359
6360 if ( !(buf->b_flags & BF_NOTEDITED)
6361 && buf->b_mtime != 0
6362 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6363 || time_differs((long)st.st_mtime, buf->b_mtime)
6364#ifdef HAVE_ST_MODE
6365 || (int)st.st_mode != buf->b_orig_mode
6366#else
6367 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6368#endif
6369 ))
6370 {
6371 retval = 1;
6372
Bram Moolenaar316059c2006-01-14 21:18:42 +00006373 /* set b_mtime to stop further warnings (e.g., when executing
6374 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006375 if (stat_res < 0)
6376 {
6377 buf->b_mtime = 0;
6378 buf->b_orig_size = 0;
6379 buf->b_orig_mode = 0;
6380 }
6381 else
6382 buf_store_time(buf, &st, buf->b_ffname);
6383
6384 /* Don't do anything for a directory. Might contain the file
6385 * explorer. */
6386 if (mch_isdir(buf->b_fname))
6387 ;
6388
6389 /*
6390 * If 'autoread' is set, the buffer has no changes and the file still
6391 * exists, reload the buffer. Use the buffer-local option value if it
6392 * was set, the global option value otherwise.
6393 */
6394 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6395 && !bufIsChanged(buf) && stat_res >= 0)
6396 reload = TRUE;
6397 else
6398 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006399 if (stat_res < 0)
6400 reason = "deleted";
6401 else if (bufIsChanged(buf))
6402 reason = "conflict";
6403 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6404 reason = "changed";
6405 else if (orig_mode != buf->b_orig_mode)
6406 reason = "mode";
6407 else
6408 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006409
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006410#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006411 /*
6412 * Only give the warning if there are no FileChangedShell
6413 * autocommands.
6414 * Avoid being called recursively by setting "busy".
6415 */
6416 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006417# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006418 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6419 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006420# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006421 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6422 buf->b_fname, buf->b_fname, FALSE, buf);
6423 busy = FALSE;
6424 if (n)
6425 {
6426 if (!buf_valid(buf))
6427 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006428# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006429 s = get_vim_var_str(VV_FCS_CHOICE);
6430 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6431 reload = TRUE;
6432 else if (STRCMP(s, "ask") == 0)
6433 n = FALSE;
6434 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006435# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006436 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006438 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439#endif
6440 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006441 if (*reason == 'd')
6442 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006443 else
6444 {
6445 helpmesg = TRUE;
6446#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6447 can_reload = TRUE;
6448#endif
6449 /*
6450 * Check if the file contents really changed to avoid
6451 * giving a warning when only the timestamp was set (e.g.,
6452 * checked out of CVS). Always warn when the buffer was
6453 * changed.
6454 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006455 if (reason[2] == 'n')
6456 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006457 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006458 mesg2 = _("See \":help W12\" for more info.");
6459 }
6460 else if (reason[1] == 'h')
6461 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006462 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006463 mesg2 = _("See \":help W11\" for more info.");
6464 }
6465 else if (*reason == 'm')
6466 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006467 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006468 mesg2 = _("See \":help W16\" for more info.");
6469 }
6470 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006471 }
6472 }
6473 }
6474
6475 }
6476 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6477 && vim_fexists(buf->b_ffname))
6478 {
6479 retval = 1;
6480 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6481 buf->b_flags |= BF_NEW_W;
6482#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6483 can_reload = TRUE;
6484#endif
6485 }
6486
6487 if (mesg != NULL)
6488 {
6489 path = home_replace_save(buf, buf->b_fname);
6490 if (path != NULL)
6491 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006492 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006493 mesg2 = "";
6494 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6495 + STRLEN(mesg2) + 2));
6496 sprintf((char *)tbuf, mesg, path);
6497#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6498 if (can_reload)
6499 {
6500 if (*mesg2 != NUL)
6501 {
6502 STRCAT(tbuf, "\n");
6503 STRCAT(tbuf, mesg2);
6504 }
6505 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6506 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6507 reload = TRUE;
6508 }
6509 else
6510#endif
6511 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6512 {
6513 if (*mesg2 != NUL)
6514 {
6515 STRCAT(tbuf, "; ");
6516 STRCAT(tbuf, mesg2);
6517 }
6518 EMSG(tbuf);
6519 retval = 2;
6520 }
6521 else
6522 {
Bram Moolenaared203462004-06-16 11:19:22 +00006523# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006524 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006525# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006526 {
6527 msg_start();
6528 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6529 if (*mesg2 != NUL)
6530 msg_puts_attr((char_u *)mesg2,
6531 hl_attr(HLF_W) + MSG_HIST);
6532 msg_clr_eos();
6533 (void)msg_end();
6534 if (emsg_silent == 0)
6535 {
6536 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006537# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006539# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006540 /* give the user some time to think about it */
6541 ui_delay(1000L, TRUE);
6542
6543 /* don't redraw and erase the message */
6544 redraw_cmdline = FALSE;
6545 }
6546 }
6547 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006548 }
6549
6550 vim_free(path);
6551 vim_free(tbuf);
6552 }
6553 }
6554
6555 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006556 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006557 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006558
Bram Moolenaar56718732006-03-15 22:53:57 +00006559#ifdef FEAT_AUTOCMD
6560 if (buf_valid(buf))
6561 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6562 buf->b_fname, buf->b_fname, FALSE, buf);
6563#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006564#ifdef FEAT_GUI
6565 /* restore this in case an autocommand has set it; it would break
6566 * 'mousefocus' */
6567 need_mouse_correct = save_mouse_correct;
6568#endif
6569
6570 return retval;
6571}
6572
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006573/*
6574 * Reload a buffer that is already loaded.
6575 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006576 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6577 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006578 */
6579 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006580buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006581 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006582 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006583{
6584 exarg_T ea;
6585 pos_T old_cursor;
6586 linenr_T old_topline;
6587 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006588 buf_T *savebuf;
6589 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006590 aco_save_T aco;
6591
6592 /* set curwin/curbuf for "buf" and save some things */
6593 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006594
6595 /* We only want to read the text from the file, not reset the syntax
6596 * highlighting, clear marks, diff status, etc. Force the fileformat
6597 * and encoding to be the same. */
6598 if (prep_exarg(&ea, buf) == OK)
6599 {
6600 old_cursor = curwin->w_cursor;
6601 old_topline = curwin->w_topline;
6602
6603 /*
6604 * To behave like when a new file is edited (matters for
6605 * BufReadPost autocommands) we first need to delete the current
6606 * buffer contents. But if reading the file fails we should keep
6607 * the old contents. Can't use memory only, the file might be
6608 * too big. Use a hidden buffer to move the buffer contents to.
6609 */
6610 if (bufempty())
6611 savebuf = NULL;
6612 else
6613 {
6614 /* Allocate a buffer without putting it in the buffer list. */
6615 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006616 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006617 {
6618 /* Open the memline. */
6619 curbuf = savebuf;
6620 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006621 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006622 curbuf = buf;
6623 curwin->w_buffer = buf;
6624 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006625 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006626 || move_lines(buf, savebuf) == FAIL)
6627 {
6628 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6629 buf->b_fname);
6630 saved = FAIL;
6631 }
6632 }
6633
6634 if (saved == OK)
6635 {
6636 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6637#ifdef FEAT_AUTOCMD
6638 keep_filetype = TRUE; /* don't detect 'filetype' */
6639#endif
6640 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6641 (linenr_T)0,
6642 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6643 {
6644#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6645 if (!aborting())
6646#endif
6647 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006648 if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006649 {
6650 /* Put the text back from the save buffer. First
6651 * delete any lines that readfile() added. */
6652 while (!bufempty())
Bram Moolenaar8424a622006-04-19 21:23:36 +00006653 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006654 break;
6655 (void)move_lines(savebuf, buf);
6656 }
6657 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006658 else if (buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006659 {
6660 /* Mark the buffer as unmodified and free undo info. */
6661 unchanged(buf, TRUE);
6662 u_blockfree(buf);
6663 u_clearall(buf);
6664 }
6665 }
6666 vim_free(ea.cmd);
6667
Bram Moolenaar8424a622006-04-19 21:23:36 +00006668 if (savebuf != NULL && buf_valid(savebuf))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006669 wipe_buffer(savebuf, FALSE);
6670
6671#ifdef FEAT_DIFF
6672 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00006673 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006674#endif
6675
6676 /* Restore the topline and cursor position and check it (lines may
6677 * have been removed). */
6678 if (old_topline > curbuf->b_ml.ml_line_count)
6679 curwin->w_topline = curbuf->b_ml.ml_line_count;
6680 else
6681 curwin->w_topline = old_topline;
6682 curwin->w_cursor = old_cursor;
6683 check_cursor();
6684 update_topline();
6685#ifdef FEAT_AUTOCMD
6686 keep_filetype = FALSE;
6687#endif
6688#ifdef FEAT_FOLDING
6689 {
6690 win_T *wp;
6691
6692 /* Update folds unless they are defined manually. */
6693 FOR_ALL_WINDOWS(wp)
6694 if (wp->w_buffer == curwin->w_buffer
6695 && !foldmethodIsManual(wp))
6696 foldUpdateAll(wp);
6697 }
6698#endif
6699 /* If the mode didn't change and 'readonly' was set, keep the old
6700 * value; the user probably used the ":view" command. But don't
6701 * reset it, might have had a read error. */
6702 if (orig_mode == curbuf->b_orig_mode)
6703 curbuf->b_p_ro |= old_ro;
6704 }
6705
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006706 /* restore curwin/curbuf and a few other things */
6707 aucmd_restbuf(&aco);
6708 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006709}
6710
Bram Moolenaar071d4272004-06-13 20:20:40 +00006711/*ARGSUSED*/
6712 void
6713buf_store_time(buf, st, fname)
6714 buf_T *buf;
6715 struct stat *st;
6716 char_u *fname;
6717{
6718 buf->b_mtime = (long)st->st_mtime;
6719 buf->b_orig_size = (size_t)st->st_size;
6720#ifdef HAVE_ST_MODE
6721 buf->b_orig_mode = (int)st->st_mode;
6722#else
6723 buf->b_orig_mode = mch_getperm(fname);
6724#endif
6725}
6726
6727/*
6728 * Adjust the line with missing eol, used for the next write.
6729 * Used for do_filter(), when the input lines for the filter are deleted.
6730 */
6731 void
6732write_lnum_adjust(offset)
6733 linenr_T offset;
6734{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006735 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006736 write_no_eol_lnum += offset;
6737}
6738
6739#if defined(TEMPDIRNAMES) || defined(PROTO)
6740static long temp_count = 0; /* Temp filename counter. */
6741
6742/*
6743 * Delete the temp directory and all files it contains.
6744 */
6745 void
6746vim_deltempdir()
6747{
6748 char_u **files;
6749 int file_count;
6750 int i;
6751
6752 if (vim_tempdir != NULL)
6753 {
6754 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6755 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6756 EW_DIR|EW_FILE|EW_SILENT) == OK)
6757 {
6758 for (i = 0; i < file_count; ++i)
6759 mch_remove(files[i]);
6760 FreeWild(file_count, files);
6761 }
6762 gettail(NameBuff)[-1] = NUL;
6763 (void)mch_rmdir(NameBuff);
6764
6765 vim_free(vim_tempdir);
6766 vim_tempdir = NULL;
6767 }
6768}
6769#endif
6770
6771/*
6772 * vim_tempname(): Return a unique name that can be used for a temp file.
6773 *
6774 * The temp file is NOT created.
6775 *
6776 * The returned pointer is to allocated memory.
6777 * The returned pointer is NULL if no valid name was found.
6778 */
6779/*ARGSUSED*/
6780 char_u *
6781vim_tempname(extra_char)
6782 int extra_char; /* character to use in the name instead of '?' */
6783{
6784#ifdef USE_TMPNAM
6785 char_u itmp[L_tmpnam]; /* use tmpnam() */
6786#else
6787 char_u itmp[TEMPNAMELEN];
6788#endif
6789
6790#ifdef TEMPDIRNAMES
6791 static char *(tempdirs[]) = {TEMPDIRNAMES};
6792 int i;
6793 long nr;
6794 long off;
6795# ifndef EEXIST
6796 struct stat st;
6797# endif
6798
6799 /*
6800 * This will create a directory for private use by this instance of Vim.
6801 * This is done once, and the same directory is used for all temp files.
6802 * This method avoids security problems because of symlink attacks et al.
6803 * It's also a bit faster, because we only need to check for an existing
6804 * file when creating the directory and not for each temp file.
6805 */
6806 if (vim_tempdir == NULL)
6807 {
6808 /*
6809 * Try the entries in TEMPDIRNAMES to create the temp directory.
6810 */
6811 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6812 {
6813 /* expand $TMP, leave room for "/v1100000/999999999" */
6814 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6815 if (mch_isdir(itmp)) /* directory exists */
6816 {
6817# ifdef __EMX__
6818 /* If $TMP contains a forward slash (perhaps using bash or
6819 * tcsh), don't add a backslash, use a forward slash!
6820 * Adding 2 backslashes didn't work. */
6821 if (vim_strchr(itmp, '/') != NULL)
6822 STRCAT(itmp, "/");
6823 else
6824# endif
6825 add_pathsep(itmp);
6826
6827 /* Get an arbitrary number of up to 6 digits. When it's
6828 * unlikely that it already exists it will be faster,
6829 * otherwise it doesn't matter. The use of mkdir() avoids any
6830 * security problems because of the predictable number. */
6831 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6832
6833 /* Try up to 10000 different values until we find a name that
6834 * doesn't exist. */
6835 for (off = 0; off < 10000L; ++off)
6836 {
6837 int r;
6838#if defined(UNIX) || defined(VMS)
6839 mode_t umask_save;
6840#endif
6841
6842 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6843# ifndef EEXIST
6844 /* If mkdir() does not set errno to EEXIST, check for
6845 * existing file here. There is a race condition then,
6846 * although it's fail-safe. */
6847 if (mch_stat((char *)itmp, &st) >= 0)
6848 continue;
6849# endif
6850#if defined(UNIX) || defined(VMS)
6851 /* Make sure the umask doesn't remove the executable bit.
6852 * "repl" has been reported to use "177". */
6853 umask_save = umask(077);
6854#endif
6855 r = vim_mkdir(itmp, 0700);
6856#if defined(UNIX) || defined(VMS)
6857 (void)umask(umask_save);
6858#endif
6859 if (r == 0)
6860 {
6861 char_u *buf;
6862
6863 /* Directory was created, use this name.
6864 * Expand to full path; When using the current
6865 * directory a ":cd" would confuse us. */
6866 buf = alloc((unsigned)MAXPATHL + 1);
6867 if (buf != NULL)
6868 {
6869 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6870 == FAIL)
6871 STRCPY(buf, itmp);
6872# ifdef __EMX__
6873 if (vim_strchr(buf, '/') != NULL)
6874 STRCAT(buf, "/");
6875 else
6876# endif
6877 add_pathsep(buf);
6878 vim_tempdir = vim_strsave(buf);
6879 vim_free(buf);
6880 }
6881 break;
6882 }
6883# ifdef EEXIST
6884 /* If the mkdir() didn't fail because the file/dir exists,
6885 * we probably can't create any dir here, try another
6886 * place. */
6887 if (errno != EEXIST)
6888# endif
6889 break;
6890 }
6891 if (vim_tempdir != NULL)
6892 break;
6893 }
6894 }
6895 }
6896
6897 if (vim_tempdir != NULL)
6898 {
6899 /* There is no need to check if the file exists, because we own the
6900 * directory and nobody else creates a file in it. */
6901 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6902 return vim_strsave(itmp);
6903 }
6904
6905 return NULL;
6906
6907#else /* TEMPDIRNAMES */
6908
6909# ifdef WIN3264
6910 char szTempFile[_MAX_PATH + 1];
6911 char buf4[4];
6912 char_u *retval;
6913 char_u *p;
6914
6915 STRCPY(itmp, "");
6916 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6917 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6918 strcpy(buf4, "VIM");
6919 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6920 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6921 return NULL;
6922 /* GetTempFileName() will create the file, we don't want that */
6923 (void)DeleteFile(itmp);
6924
6925 /* Backslashes in a temp file name cause problems when filtering with
6926 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6927 * didn't set 'shellslash'. */
6928 retval = vim_strsave(itmp);
6929 if (*p_shcf == '-' || p_ssl)
6930 for (p = retval; *p; ++p)
6931 if (*p == '\\')
6932 *p = '/';
6933 return retval;
6934
6935# else /* WIN3264 */
6936
6937# ifdef USE_TMPNAM
6938 /* tmpnam() will make its own name */
6939 if (*tmpnam((char *)itmp) == NUL)
6940 return NULL;
6941# else
6942 char_u *p;
6943
6944# ifdef VMS_TEMPNAM
6945 /* mktemp() is not working on VMS. It seems to be
6946 * a do-nothing function. Therefore we use tempnam().
6947 */
6948 sprintf((char *)itmp, "VIM%c", extra_char);
6949 p = (char_u *)tempnam("tmp:", (char *)itmp);
6950 if (p != NULL)
6951 {
6952 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6953 * and VIM will then be unable to find the file later */
6954 STRCPY(itmp, p);
6955 STRCAT(itmp, ".txt");
6956 free(p);
6957 }
6958 else
6959 return NULL;
6960# else
6961 STRCPY(itmp, TEMPNAME);
6962 if ((p = vim_strchr(itmp, '?')) != NULL)
6963 *p = extra_char;
6964 if (mktemp((char *)itmp) == NULL)
6965 return NULL;
6966# endif
6967# endif
6968
6969 return vim_strsave(itmp);
6970# endif /* WIN3264 */
6971#endif /* TEMPDIRNAMES */
6972}
6973
6974#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6975/*
6976 * Convert all backslashes in fname to forward slashes in-place.
6977 */
6978 void
6979forward_slash(fname)
6980 char_u *fname;
6981{
6982 char_u *p;
6983
6984 for (p = fname; *p != NUL; ++p)
6985# ifdef FEAT_MBYTE
6986 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006987 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006988 ++p;
6989 else
6990# endif
6991 if (*p == '\\')
6992 *p = '/';
6993}
6994#endif
6995
6996
6997/*
6998 * Code for automatic commands.
6999 *
7000 * Only included when "FEAT_AUTOCMD" has been defined.
7001 */
7002
7003#if defined(FEAT_AUTOCMD) || defined(PROTO)
7004
7005/*
7006 * The autocommands are stored in a list for each event.
7007 * Autocommands for the same pattern, that are consecutive, are joined
7008 * together, to avoid having to match the pattern too often.
7009 * The result is an array of Autopat lists, which point to AutoCmd lists:
7010 *
7011 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
7012 * Autopat.cmds Autopat.cmds
7013 * | |
7014 * V V
7015 * AutoCmd.next AutoCmd.next
7016 * | |
7017 * V V
7018 * AutoCmd.next NULL
7019 * |
7020 * V
7021 * NULL
7022 *
7023 * first_autopat[1] --> Autopat.next --> NULL
7024 * Autopat.cmds
7025 * |
7026 * V
7027 * AutoCmd.next
7028 * |
7029 * V
7030 * NULL
7031 * etc.
7032 *
7033 * The order of AutoCmds is important, this is the order in which they were
7034 * defined and will have to be executed.
7035 */
7036typedef struct AutoCmd
7037{
7038 char_u *cmd; /* The command to be executed (NULL
7039 when command has been removed) */
7040 char nested; /* If autocommands nest here */
7041 char last; /* last command in list */
7042#ifdef FEAT_EVAL
7043 scid_T scriptID; /* script ID where defined */
7044#endif
7045 struct AutoCmd *next; /* Next AutoCmd in list */
7046} AutoCmd;
7047
7048typedef struct AutoPat
7049{
7050 int group; /* group ID */
7051 char_u *pat; /* pattern as typed (NULL when pattern
7052 has been removed) */
7053 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00007054 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055 char allow_dirs; /* Pattern may match whole path */
7056 char last; /* last pattern for apply_autocmds() */
7057 AutoCmd *cmds; /* list of commands to do */
7058 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007059 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007060} AutoPat;
7061
7062static struct event_name
7063{
7064 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007065 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066} event_names[] =
7067{
7068 {"BufAdd", EVENT_BUFADD},
7069 {"BufCreate", EVENT_BUFADD},
7070 {"BufDelete", EVENT_BUFDELETE},
7071 {"BufEnter", EVENT_BUFENTER},
7072 {"BufFilePost", EVENT_BUFFILEPOST},
7073 {"BufFilePre", EVENT_BUFFILEPRE},
7074 {"BufHidden", EVENT_BUFHIDDEN},
7075 {"BufLeave", EVENT_BUFLEAVE},
7076 {"BufNew", EVENT_BUFNEW},
7077 {"BufNewFile", EVENT_BUFNEWFILE},
7078 {"BufRead", EVENT_BUFREADPOST},
7079 {"BufReadCmd", EVENT_BUFREADCMD},
7080 {"BufReadPost", EVENT_BUFREADPOST},
7081 {"BufReadPre", EVENT_BUFREADPRE},
7082 {"BufUnload", EVENT_BUFUNLOAD},
7083 {"BufWinEnter", EVENT_BUFWINENTER},
7084 {"BufWinLeave", EVENT_BUFWINLEAVE},
7085 {"BufWipeout", EVENT_BUFWIPEOUT},
7086 {"BufWrite", EVENT_BUFWRITEPRE},
7087 {"BufWritePost", EVENT_BUFWRITEPOST},
7088 {"BufWritePre", EVENT_BUFWRITEPRE},
7089 {"BufWriteCmd", EVENT_BUFWRITECMD},
7090 {"CmdwinEnter", EVENT_CMDWINENTER},
7091 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007092 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007093 {"CursorHold", EVENT_CURSORHOLD},
7094 {"CursorHoldI", EVENT_CURSORHOLDI},
7095 {"CursorMoved", EVENT_CURSORMOVED},
7096 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007097 {"EncodingChanged", EVENT_ENCODINGCHANGED},
7098 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007099 {"FileAppendPost", EVENT_FILEAPPENDPOST},
7100 {"FileAppendPre", EVENT_FILEAPPENDPRE},
7101 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
7102 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
Bram Moolenaar56718732006-03-15 22:53:57 +00007103 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007104 {"FileChangedRO", EVENT_FILECHANGEDRO},
7105 {"FileReadPost", EVENT_FILEREADPOST},
7106 {"FileReadPre", EVENT_FILEREADPRE},
7107 {"FileReadCmd", EVENT_FILEREADCMD},
7108 {"FileType", EVENT_FILETYPE},
7109 {"FileWritePost", EVENT_FILEWRITEPOST},
7110 {"FileWritePre", EVENT_FILEWRITEPRE},
7111 {"FileWriteCmd", EVENT_FILEWRITECMD},
7112 {"FilterReadPost", EVENT_FILTERREADPOST},
7113 {"FilterReadPre", EVENT_FILTERREADPRE},
7114 {"FilterWritePost", EVENT_FILTERWRITEPOST},
7115 {"FilterWritePre", EVENT_FILTERWRITEPRE},
7116 {"FocusGained", EVENT_FOCUSGAINED},
7117 {"FocusLost", EVENT_FOCUSLOST},
7118 {"FuncUndefined", EVENT_FUNCUNDEFINED},
7119 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar265e5072006-08-29 16:13:22 +00007120 {"GUIFailed", EVENT_GUIFAILED},
Bram Moolenaar843ee412004-06-30 16:16:41 +00007121 {"InsertChange", EVENT_INSERTCHANGE},
7122 {"InsertEnter", EVENT_INSERTENTER},
7123 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00007124 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00007125 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
7126 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007127 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00007128 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar5c4bab02006-03-10 21:37:46 +00007129 {"ShellCmdPost", EVENT_SHELLCMDPOST},
7130 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaara2031822006-03-07 22:29:51 +00007131 {"SourcePre", EVENT_SOURCEPRE},
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00007132 {"SourceCmd", EVENT_SOURCECMD},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00007133 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007134 {"StdinReadPost", EVENT_STDINREADPOST},
7135 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00007136 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00007137 {"Syntax", EVENT_SYNTAX},
Bram Moolenaar70836c82006-02-20 21:28:49 +00007138 {"TabEnter", EVENT_TABENTER},
7139 {"TabLeave", EVENT_TABLEAVE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007140 {"TermChanged", EVENT_TERMCHANGED},
7141 {"TermResponse", EVENT_TERMRESPONSE},
7142 {"User", EVENT_USER},
7143 {"VimEnter", EVENT_VIMENTER},
7144 {"VimLeave", EVENT_VIMLEAVE},
7145 {"VimLeavePre", EVENT_VIMLEAVEPRE},
7146 {"WinEnter", EVENT_WINENTER},
7147 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar56718732006-03-15 22:53:57 +00007148 {"VimResized", EVENT_VIMRESIZED},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007149 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007150};
7151
7152static AutoPat *first_autopat[NUM_EVENTS] =
7153{
7154 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7155 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7156 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7157 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007158 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7159 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007160};
7161
7162/*
7163 * struct used to keep status while executing autocommands for an event.
7164 */
7165typedef struct AutoPatCmd
7166{
7167 AutoPat *curpat; /* next AutoPat to examine */
7168 AutoCmd *nextcmd; /* next AutoCmd to execute */
7169 int group; /* group being used */
7170 char_u *fname; /* fname to match with */
7171 char_u *sfname; /* sfname to match with */
7172 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007173 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007174 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7175 buf is deleted */
7176 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007177} AutoPatCmd;
7178
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007179static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007180
Bram Moolenaar071d4272004-06-13 20:20:40 +00007181/*
7182 * augroups stores a list of autocmd group names.
7183 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007184static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007185#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7186
7187/*
7188 * The ID of the current group. Group 0 is the default one.
7189 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007190static int current_augroup = AUGROUP_DEFAULT;
7191
7192static int au_need_clean = FALSE; /* need to delete marked patterns */
7193
Bram Moolenaar754b5602006-02-09 23:53:20 +00007194static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007195static void au_remove_pat __ARGS((AutoPat *ap));
7196static void au_remove_cmds __ARGS((AutoPat *ap));
7197static void au_cleanup __ARGS((void));
7198static int au_new_group __ARGS((char_u *name));
7199static void au_del_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007200static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7201static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007202static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007203static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007204static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007205static 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 +00007206static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007207static 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 +00007208static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7209
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007210
Bram Moolenaar754b5602006-02-09 23:53:20 +00007211static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007212static int last_group;
Bram Moolenaar78ab3312007-09-29 12:16:41 +00007213static int autocmd_blocked = 0; /* block all autocmds */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007214
7215/*
7216 * Show the autocommands for one AutoPat.
7217 */
7218 static void
7219show_autocmd(ap, event)
7220 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007221 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007222{
7223 AutoCmd *ac;
7224
7225 /* Check for "got_int" (here and at various places below), which is set
7226 * when "q" has been hit for the "--more--" prompt */
7227 if (got_int)
7228 return;
7229 if (ap->pat == NULL) /* pattern has been removed */
7230 return;
7231
7232 msg_putchar('\n');
7233 if (got_int)
7234 return;
7235 if (event != last_event || ap->group != last_group)
7236 {
7237 if (ap->group != AUGROUP_DEFAULT)
7238 {
7239 if (AUGROUP_NAME(ap->group) == NULL)
7240 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7241 else
7242 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7243 msg_puts((char_u *)" ");
7244 }
7245 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7246 last_event = event;
7247 last_group = ap->group;
7248 msg_putchar('\n');
7249 if (got_int)
7250 return;
7251 }
7252 msg_col = 4;
7253 msg_outtrans(ap->pat);
7254
7255 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7256 {
7257 if (ac->cmd != NULL) /* skip removed commands */
7258 {
7259 if (msg_col >= 14)
7260 msg_putchar('\n');
7261 msg_col = 14;
7262 if (got_int)
7263 return;
7264 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007265#ifdef FEAT_EVAL
7266 if (p_verbose > 0)
7267 last_set_msg(ac->scriptID);
7268#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007269 if (got_int)
7270 return;
7271 if (ac->next != NULL)
7272 {
7273 msg_putchar('\n');
7274 if (got_int)
7275 return;
7276 }
7277 }
7278 }
7279}
7280
7281/*
7282 * Mark an autocommand pattern for deletion.
7283 */
7284 static void
7285au_remove_pat(ap)
7286 AutoPat *ap;
7287{
7288 vim_free(ap->pat);
7289 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007290 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007291 au_need_clean = TRUE;
7292}
7293
7294/*
7295 * Mark all commands for a pattern for deletion.
7296 */
7297 static void
7298au_remove_cmds(ap)
7299 AutoPat *ap;
7300{
7301 AutoCmd *ac;
7302
7303 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7304 {
7305 vim_free(ac->cmd);
7306 ac->cmd = NULL;
7307 }
7308 au_need_clean = TRUE;
7309}
7310
7311/*
7312 * Cleanup autocommands and patterns that have been deleted.
7313 * This is only done when not executing autocommands.
7314 */
7315 static void
7316au_cleanup()
7317{
7318 AutoPat *ap, **prev_ap;
7319 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007320 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007321
7322 if (autocmd_busy || !au_need_clean)
7323 return;
7324
7325 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007326 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7327 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007328 {
7329 /* loop over all autocommand patterns */
7330 prev_ap = &(first_autopat[(int)event]);
7331 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7332 {
7333 /* loop over all commands for this pattern */
7334 prev_ac = &(ap->cmds);
7335 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7336 {
7337 /* remove the command if the pattern is to be deleted or when
7338 * the command has been marked for deletion */
7339 if (ap->pat == NULL || ac->cmd == NULL)
7340 {
7341 *prev_ac = ac->next;
7342 vim_free(ac->cmd);
7343 vim_free(ac);
7344 }
7345 else
7346 prev_ac = &(ac->next);
7347 }
7348
7349 /* remove the pattern if it has been marked for deletion */
7350 if (ap->pat == NULL)
7351 {
7352 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007353 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007354 vim_free(ap);
7355 }
7356 else
7357 prev_ap = &(ap->next);
7358 }
7359 }
7360
7361 au_need_clean = FALSE;
7362}
7363
7364/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007365 * Called when buffer is freed, to remove/invalidate related buffer-local
7366 * autocmds.
7367 */
7368 void
7369aubuflocal_remove(buf)
7370 buf_T *buf;
7371{
7372 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007373 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007374 AutoPatCmd *apc;
7375
7376 /* invalidate currently executing autocommands */
7377 for (apc = active_apc_list; apc; apc = apc->next)
7378 if (buf->b_fnum == apc->arg_bufnr)
7379 apc->arg_bufnr = 0;
7380
7381 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007382 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7383 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007384 /* loop over all autocommand patterns */
7385 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7386 if (ap->buflocal_nr == buf->b_fnum)
7387 {
7388 au_remove_pat(ap);
7389 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007390 {
7391 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007392 smsg((char_u *)
7393 _("auto-removing autocommand: %s <buffer=%d>"),
7394 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007395 verbose_leave();
7396 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007397 }
7398 au_cleanup();
7399}
7400
7401/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007402 * Add an autocmd group name.
7403 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7404 */
7405 static int
7406au_new_group(name)
7407 char_u *name;
7408{
7409 int i;
7410
7411 i = au_find_group(name);
7412 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7413 {
7414 /* First try using a free entry. */
7415 for (i = 0; i < augroups.ga_len; ++i)
7416 if (AUGROUP_NAME(i) == NULL)
7417 break;
7418 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7419 return AUGROUP_ERROR;
7420
7421 AUGROUP_NAME(i) = vim_strsave(name);
7422 if (AUGROUP_NAME(i) == NULL)
7423 return AUGROUP_ERROR;
7424 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007425 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007426 }
7427
7428 return i;
7429}
7430
7431 static void
7432au_del_group(name)
7433 char_u *name;
7434{
7435 int i;
7436
7437 i = au_find_group(name);
7438 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7439 EMSG2(_("E367: No such group: \"%s\""), name);
7440 else
7441 {
7442 vim_free(AUGROUP_NAME(i));
7443 AUGROUP_NAME(i) = NULL;
7444 }
7445}
7446
7447/*
7448 * Find the ID of an autocmd group name.
7449 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7450 */
7451 static int
7452au_find_group(name)
7453 char_u *name;
7454{
7455 int i;
7456
7457 for (i = 0; i < augroups.ga_len; ++i)
7458 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7459 return i;
7460 return AUGROUP_ERROR;
7461}
7462
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007463/*
7464 * Return TRUE if augroup "name" exists.
7465 */
7466 int
7467au_has_group(name)
7468 char_u *name;
7469{
7470 return au_find_group(name) != AUGROUP_ERROR;
7471}
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007472
Bram Moolenaar071d4272004-06-13 20:20:40 +00007473/*
7474 * ":augroup {name}".
7475 */
7476 void
7477do_augroup(arg, del_group)
7478 char_u *arg;
7479 int del_group;
7480{
7481 int i;
7482
7483 if (del_group)
7484 {
7485 if (*arg == NUL)
7486 EMSG(_(e_argreq));
7487 else
7488 au_del_group(arg);
7489 }
7490 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7491 current_augroup = AUGROUP_DEFAULT;
7492 else if (*arg) /* ":aug xxx": switch to group xxx */
7493 {
7494 i = au_new_group(arg);
7495 if (i != AUGROUP_ERROR)
7496 current_augroup = i;
7497 }
7498 else /* ":aug": list the group names */
7499 {
7500 msg_start();
7501 for (i = 0; i < augroups.ga_len; ++i)
7502 {
7503 if (AUGROUP_NAME(i) != NULL)
7504 {
7505 msg_puts(AUGROUP_NAME(i));
7506 msg_puts((char_u *)" ");
7507 }
7508 }
7509 msg_clr_eos();
7510 msg_end();
7511 }
7512}
7513
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007514#if defined(EXITFREE) || defined(PROTO)
7515 void
7516free_all_autocmds()
7517{
7518 for (current_augroup = -1; current_augroup < augroups.ga_len;
7519 ++current_augroup)
7520 do_autocmd((char_u *)"", TRUE);
7521 ga_clear_strings(&augroups);
7522}
7523#endif
7524
Bram Moolenaar071d4272004-06-13 20:20:40 +00007525/*
7526 * Return the event number for event name "start".
7527 * Return NUM_EVENTS if the event name was not found.
7528 * Return a pointer to the next event name in "end".
7529 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007530 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007531event_name2nr(start, end)
7532 char_u *start;
7533 char_u **end;
7534{
7535 char_u *p;
7536 int i;
7537 int len;
7538
7539 /* the event name ends with end of line, a blank or a comma */
7540 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7541 ;
7542 for (i = 0; event_names[i].name != NULL; ++i)
7543 {
7544 len = (int)STRLEN(event_names[i].name);
7545 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7546 break;
7547 }
7548 if (*p == ',')
7549 ++p;
7550 *end = p;
7551 if (event_names[i].name == NULL)
7552 return NUM_EVENTS;
7553 return event_names[i].event;
7554}
7555
7556/*
7557 * Return the name for event "event".
7558 */
7559 static char_u *
7560event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007561 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007562{
7563 int i;
7564
7565 for (i = 0; event_names[i].name != NULL; ++i)
7566 if (event_names[i].event == event)
7567 return (char_u *)event_names[i].name;
7568 return (char_u *)"Unknown";
7569}
7570
7571/*
7572 * Scan over the events. "*" stands for all events.
7573 */
7574 static char_u *
7575find_end_event(arg, have_group)
7576 char_u *arg;
7577 int have_group; /* TRUE when group name was found */
7578{
7579 char_u *pat;
7580 char_u *p;
7581
7582 if (*arg == '*')
7583 {
7584 if (arg[1] && !vim_iswhite(arg[1]))
7585 {
7586 EMSG2(_("E215: Illegal character after *: %s"), arg);
7587 return NULL;
7588 }
7589 pat = arg + 1;
7590 }
7591 else
7592 {
7593 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7594 {
7595 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7596 {
7597 if (have_group)
7598 EMSG2(_("E216: No such event: %s"), pat);
7599 else
7600 EMSG2(_("E216: No such group or event: %s"), pat);
7601 return NULL;
7602 }
7603 }
7604 }
7605 return pat;
7606}
7607
7608/*
7609 * Return TRUE if "event" is included in 'eventignore'.
7610 */
7611 static int
7612event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007613 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007614{
7615 char_u *p = p_ei;
7616
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007617 while (*p != NUL)
7618 {
7619 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7620 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007621 if (event_name2nr(p, &p) == event)
7622 return TRUE;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007623 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007624
7625 return FALSE;
7626}
7627
7628/*
7629 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7630 */
7631 int
7632check_ei()
7633{
7634 char_u *p = p_ei;
7635
Bram Moolenaar071d4272004-06-13 20:20:40 +00007636 while (*p)
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007637 {
7638 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7639 {
7640 p += 3;
7641 if (*p == ',')
7642 ++p;
7643 }
7644 else if (event_name2nr(p, &p) == NUM_EVENTS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007645 return FAIL;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007646 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007647
7648 return OK;
7649}
7650
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007651# if defined(FEAT_SYN_HL) || defined(PROTO)
7652
7653/*
7654 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7655 * buffer loaded into the window. "what" must start with a comma.
7656 * Returns the old value of 'eventignore' in allocated memory.
7657 */
7658 char_u *
7659au_event_disable(what)
7660 char *what;
7661{
7662 char_u *new_ei;
7663 char_u *save_ei;
7664
7665 save_ei = vim_strsave(p_ei);
7666 if (save_ei != NULL)
7667 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007668 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007669 if (new_ei != NULL)
7670 {
7671 STRCAT(new_ei, what);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007672 set_string_option_direct((char_u *)"ei", -1, new_ei,
7673 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007674 vim_free(new_ei);
7675 }
7676 }
7677 return save_ei;
7678}
7679
7680 void
7681au_event_restore(old_ei)
7682 char_u *old_ei;
7683{
7684 if (old_ei != NULL)
7685 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007686 set_string_option_direct((char_u *)"ei", -1, old_ei,
7687 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007688 vim_free(old_ei);
7689 }
7690}
7691# endif /* FEAT_SYN_HL */
7692
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693/*
7694 * do_autocmd() -- implements the :autocmd command. Can be used in the
7695 * following ways:
7696 *
7697 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7698 * will be automatically executed for <event>
7699 * when editing a file matching <pat>, in
7700 * the current group.
7701 * :autocmd <event> <pat> Show the auto-commands associated with
7702 * <event> and <pat>.
7703 * :autocmd <event> Show the auto-commands associated with
7704 * <event>.
7705 * :autocmd Show all auto-commands.
7706 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7707 * <event> and <pat>, and add the command
7708 * <cmd>, for the current group.
7709 * :autocmd! <event> <pat> Remove all auto-commands associated with
7710 * <event> and <pat> for the current group.
7711 * :autocmd! <event> Remove all auto-commands associated with
7712 * <event> for the current group.
7713 * :autocmd! Remove ALL auto-commands for the current
7714 * group.
7715 *
7716 * Multiple events and patterns may be given separated by commas. Here are
7717 * some examples:
7718 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7719 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7720 *
7721 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007722 *
7723 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007724 */
7725 void
7726do_autocmd(arg, forceit)
7727 char_u *arg;
7728 int forceit;
7729{
7730 char_u *pat;
7731 char_u *envpat = NULL;
7732 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007733 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007734 int need_free = FALSE;
7735 int nested = FALSE;
7736 int group;
7737
7738 /*
7739 * Check for a legal group name. If not, use AUGROUP_ALL.
7740 */
7741 group = au_get_grouparg(&arg);
7742 if (arg == NULL) /* out of memory */
7743 return;
7744
7745 /*
7746 * Scan over the events.
7747 * If we find an illegal name, return here, don't do anything.
7748 */
7749 pat = find_end_event(arg, group != AUGROUP_ALL);
7750 if (pat == NULL)
7751 return;
7752
7753 /*
7754 * Scan over the pattern. Put a NUL at the end.
7755 */
7756 pat = skipwhite(pat);
7757 cmd = pat;
7758 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7759 cmd++;
7760 if (*cmd)
7761 *cmd++ = NUL;
7762
7763 /* Expand environment variables in the pattern. Set 'shellslash', we want
7764 * forward slashes here. */
7765 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7766 {
7767#ifdef BACKSLASH_IN_FILENAME
7768 int p_ssl_save = p_ssl;
7769
7770 p_ssl = TRUE;
7771#endif
7772 envpat = expand_env_save(pat);
7773#ifdef BACKSLASH_IN_FILENAME
7774 p_ssl = p_ssl_save;
7775#endif
7776 if (envpat != NULL)
7777 pat = envpat;
7778 }
7779
7780 /*
7781 * Check for "nested" flag.
7782 */
7783 cmd = skipwhite(cmd);
7784 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7785 {
7786 nested = TRUE;
7787 cmd = skipwhite(cmd + 6);
7788 }
7789
7790 /*
7791 * Find the start of the commands.
7792 * Expand <sfile> in it.
7793 */
7794 if (*cmd != NUL)
7795 {
7796 cmd = expand_sfile(cmd);
7797 if (cmd == NULL) /* some error */
7798 return;
7799 need_free = TRUE;
7800 }
7801
7802 /*
7803 * Print header when showing autocommands.
7804 */
7805 if (!forceit && *cmd == NUL)
7806 {
7807 /* Highlight title */
7808 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7809 }
7810
7811 /*
7812 * Loop over the events.
7813 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007814 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007815 last_group = AUGROUP_ERROR; /* for listing the group name */
7816 if (*arg == '*' || *arg == NUL)
7817 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00007818 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7819 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007820 if (do_autocmd_event(event, pat,
7821 nested, cmd, forceit, group) == FAIL)
7822 break;
7823 }
7824 else
7825 {
7826 while (*arg && !vim_iswhite(*arg))
7827 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7828 nested, cmd, forceit, group) == FAIL)
7829 break;
7830 }
7831
7832 if (need_free)
7833 vim_free(cmd);
7834 vim_free(envpat);
7835}
7836
7837/*
7838 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7839 * The "argp" argument is advanced to the following argument.
7840 *
7841 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7842 */
7843 static int
7844au_get_grouparg(argp)
7845 char_u **argp;
7846{
7847 char_u *group_name;
7848 char_u *p;
7849 char_u *arg = *argp;
7850 int group = AUGROUP_ALL;
7851
7852 p = skiptowhite(arg);
7853 if (p > arg)
7854 {
7855 group_name = vim_strnsave(arg, (int)(p - arg));
7856 if (group_name == NULL) /* out of memory */
7857 return AUGROUP_ERROR;
7858 group = au_find_group(group_name);
7859 if (group == AUGROUP_ERROR)
7860 group = AUGROUP_ALL; /* no match, use all groups */
7861 else
7862 *argp = skipwhite(p); /* match, skip over group name */
7863 vim_free(group_name);
7864 }
7865 return group;
7866}
7867
7868/*
7869 * do_autocmd() for one event.
7870 * If *pat == NUL do for all patterns.
7871 * If *cmd == NUL show entries.
7872 * If forceit == TRUE delete entries.
7873 * If group is not AUGROUP_ALL, only use this group.
7874 */
7875 static int
7876do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007877 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878 char_u *pat;
7879 int nested;
7880 char_u *cmd;
7881 int forceit;
7882 int group;
7883{
7884 AutoPat *ap;
7885 AutoPat **prev_ap;
7886 AutoCmd *ac;
7887 AutoCmd **prev_ac;
7888 int brace_level;
7889 char_u *endpat;
7890 int findgroup;
7891 int allgroups;
7892 int patlen;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00007893 int is_buflocal;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007894 int buflocal_nr;
7895 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007896
7897 if (group == AUGROUP_ALL)
7898 findgroup = current_augroup;
7899 else
7900 findgroup = group;
7901 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7902
7903 /*
7904 * Show or delete all patterns for an event.
7905 */
7906 if (*pat == NUL)
7907 {
7908 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7909 {
7910 if (forceit) /* delete the AutoPat, if it's in the current group */
7911 {
7912 if (ap->group == findgroup)
7913 au_remove_pat(ap);
7914 }
7915 else if (group == AUGROUP_ALL || ap->group == group)
7916 show_autocmd(ap, event);
7917 }
7918 }
7919
7920 /*
7921 * Loop through all the specified patterns.
7922 */
7923 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7924 {
7925 /*
7926 * Find end of the pattern.
7927 * Watch out for a comma in braces, like "*.\{obj,o\}".
7928 */
7929 brace_level = 0;
7930 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7931 || endpat[-1] == '\\'); ++endpat)
7932 {
7933 if (*endpat == '{')
7934 brace_level++;
7935 else if (*endpat == '}')
7936 brace_level--;
7937 }
7938 if (pat == endpat) /* ignore single comma */
7939 continue;
7940 patlen = (int)(endpat - pat);
7941
7942 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007943 * detect special <buflocal[=X]> buffer-local patterns
7944 */
7945 is_buflocal = FALSE;
7946 buflocal_nr = 0;
7947
7948 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7949 && pat[patlen - 1] == '>')
7950 {
7951 /* Error will be printed only for addition. printing and removing
7952 * will proceed silently. */
7953 is_buflocal = TRUE;
7954 if (patlen == 8)
7955 buflocal_nr = curbuf->b_fnum;
7956 else if (patlen > 9 && pat[7] == '=')
7957 {
7958 /* <buffer=abuf> */
7959 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7960 buflocal_nr = autocmd_bufnr;
7961 /* <buffer=123> */
7962 else if (skipdigits(pat + 8) == pat + patlen - 1)
7963 buflocal_nr = atoi((char *)pat + 8);
7964 }
7965 }
7966
7967 if (is_buflocal)
7968 {
7969 /* normalize pat into standard "<buffer>#N" form */
7970 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7971 pat = buflocal_pat; /* can modify pat and patlen */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00007972 patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007973 }
7974
7975 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007976 * Find AutoPat entries with this pattern.
7977 */
7978 prev_ap = &first_autopat[(int)event];
7979 while ((ap = *prev_ap) != NULL)
7980 {
7981 if (ap->pat != NULL)
7982 {
7983 /* Accept a pattern when:
7984 * - a group was specified and it's that group, or a group was
7985 * not specified and it's the current group, or a group was
7986 * not specified and we are listing
7987 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007988 * - the pattern matches.
7989 * For <buffer[=X]>, this condition works because we normalize
7990 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007991 */
7992 if ((allgroups || ap->group == findgroup)
7993 && ap->patlen == patlen
7994 && STRNCMP(pat, ap->pat, patlen) == 0)
7995 {
7996 /*
7997 * Remove existing autocommands.
7998 * If adding any new autocmd's for this AutoPat, don't
7999 * delete the pattern from the autopat list, append to
8000 * this list.
8001 */
8002 if (forceit)
8003 {
8004 if (*cmd != NUL && ap->next == NULL)
8005 {
8006 au_remove_cmds(ap);
8007 break;
8008 }
8009 au_remove_pat(ap);
8010 }
8011
8012 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008013 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00008014 */
8015 else if (*cmd == NUL)
8016 show_autocmd(ap, event);
8017
8018 /*
8019 * Add autocmd to this autopat, if it's the last one.
8020 */
8021 else if (ap->next == NULL)
8022 break;
8023 }
8024 }
8025 prev_ap = &ap->next;
8026 }
8027
8028 /*
8029 * Add a new command.
8030 */
8031 if (*cmd != NUL)
8032 {
8033 /*
8034 * If the pattern we want to add a command to does appear at the
8035 * end of the list (or not is not in the list at all), add the
8036 * pattern at the end of the list.
8037 */
8038 if (ap == NULL)
8039 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008040 /* refuse to add buffer-local ap if buffer number is invalid */
8041 if (is_buflocal && (buflocal_nr == 0
8042 || buflist_findnr(buflocal_nr) == NULL))
8043 {
8044 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
8045 buflocal_nr);
8046 return FAIL;
8047 }
8048
Bram Moolenaar071d4272004-06-13 20:20:40 +00008049 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
8050 if (ap == NULL)
8051 return FAIL;
8052 ap->pat = vim_strnsave(pat, patlen);
8053 ap->patlen = patlen;
8054 if (ap->pat == NULL)
8055 {
8056 vim_free(ap);
8057 return FAIL;
8058 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008059
8060 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008061 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008062 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008063 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008064 }
8065 else
8066 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00008067 char_u *reg_pat;
8068
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008069 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00008070 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008071 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008072 if (reg_pat != NULL)
8073 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00008074 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00008075 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008076 {
8077 vim_free(ap->pat);
8078 vim_free(ap);
8079 return FAIL;
8080 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008081 }
8082 ap->cmds = NULL;
8083 *prev_ap = ap;
8084 ap->next = NULL;
8085 if (group == AUGROUP_ALL)
8086 ap->group = current_augroup;
8087 else
8088 ap->group = group;
8089 }
8090
8091 /*
8092 * Add the autocmd at the end of the AutoCmd list.
8093 */
8094 prev_ac = &(ap->cmds);
8095 while ((ac = *prev_ac) != NULL)
8096 prev_ac = &ac->next;
8097 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
8098 if (ac == NULL)
8099 return FAIL;
8100 ac->cmd = vim_strsave(cmd);
8101#ifdef FEAT_EVAL
8102 ac->scriptID = current_SID;
8103#endif
8104 if (ac->cmd == NULL)
8105 {
8106 vim_free(ac);
8107 return FAIL;
8108 }
8109 ac->next = NULL;
8110 *prev_ac = ac;
8111 ac->nested = nested;
8112 }
8113 }
8114
8115 au_cleanup(); /* may really delete removed patterns/commands now */
8116 return OK;
8117}
8118
8119/*
8120 * Implementation of ":doautocmd [group] event [fname]".
8121 * Return OK for success, FAIL for failure;
8122 */
8123 int
8124do_doautocmd(arg, do_msg)
8125 char_u *arg;
8126 int do_msg; /* give message for no matching autocmds? */
8127{
8128 char_u *fname;
8129 int nothing_done = TRUE;
8130 int group;
8131
8132 /*
8133 * Check for a legal group name. If not, use AUGROUP_ALL.
8134 */
8135 group = au_get_grouparg(&arg);
8136 if (arg == NULL) /* out of memory */
8137 return FAIL;
8138
8139 if (*arg == '*')
8140 {
8141 EMSG(_("E217: Can't execute autocommands for ALL events"));
8142 return FAIL;
8143 }
8144
8145 /*
8146 * Scan over the events.
8147 * If we find an illegal name, return here, don't do anything.
8148 */
8149 fname = find_end_event(arg, group != AUGROUP_ALL);
8150 if (fname == NULL)
8151 return FAIL;
8152
8153 fname = skipwhite(fname);
8154
8155 /*
8156 * Loop over the events.
8157 */
8158 while (*arg && !vim_iswhite(*arg))
8159 if (apply_autocmds_group(event_name2nr(arg, &arg),
8160 fname, NULL, TRUE, group, curbuf, NULL))
8161 nothing_done = FALSE;
8162
8163 if (nothing_done && do_msg)
8164 MSG(_("No matching autocommands"));
8165
8166#ifdef FEAT_EVAL
8167 return aborting() ? FAIL : OK;
8168#else
8169 return OK;
8170#endif
8171}
8172
8173/*
8174 * ":doautoall": execute autocommands for each loaded buffer.
8175 */
8176 void
8177ex_doautoall(eap)
8178 exarg_T *eap;
8179{
8180 int retval;
8181 aco_save_T aco;
8182 buf_T *buf;
8183
8184 /*
8185 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8186 * equal to curbuf, but for some buffers there may not be a window.
8187 * So we change the buffer for the current window for a moment. This
8188 * gives problems when the autocommands make changes to the list of
8189 * buffers or windows...
8190 */
8191 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8192 {
8193 if (curbuf->b_ml.ml_mfp != NULL)
8194 {
8195 /* find a window for this buffer and save some values */
8196 aucmd_prepbuf(&aco, buf);
8197
8198 /* execute the autocommands for this buffer */
8199 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaareeefcc72007-05-01 21:21:21 +00008200
8201 /* Execute the modeline settings, but don't set window-local
8202 * options if we are using the current window for another buffer. */
8203 do_modelines(aco.save_curwin == NULL ? OPT_NOWIN : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008204
8205 /* restore the current window */
8206 aucmd_restbuf(&aco);
8207
8208 /* stop if there is some error or buffer was deleted */
8209 if (retval == FAIL || !buf_valid(buf))
8210 break;
8211 }
8212 }
8213
8214 check_cursor(); /* just in case lines got deleted */
8215}
8216
8217/*
8218 * Prepare for executing autocommands for (hidden) buffer "buf".
8219 * Search a window for the current buffer. Save the cursor position and
8220 * screen offset.
8221 * Set "curbuf" and "curwin" to match "buf".
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008222 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008223 */
8224 void
8225aucmd_prepbuf(aco, buf)
8226 aco_save_T *aco; /* structure to save values in */
8227 buf_T *buf; /* new curbuf */
8228{
8229 win_T *win;
8230
8231 aco->new_curbuf = buf;
8232
8233 /* Find a window that is for the new buffer */
8234 if (buf == curbuf) /* be quick when buf is curbuf */
8235 win = curwin;
8236 else
8237#ifdef FEAT_WINDOWS
8238 for (win = firstwin; win != NULL; win = win->w_next)
8239 if (win->w_buffer == buf)
8240 break;
8241#else
8242 win = NULL;
8243#endif
8244
8245 /*
8246 * Prefer to use an existing window for the buffer, it has the least side
8247 * effects (esp. if "buf" is curbuf).
8248 * Otherwise, use curwin for "buf". It might make some items in the
8249 * window invalid. At least save the cursor and topline.
8250 */
8251 if (win != NULL)
8252 {
8253 /* there is a window for "buf", make it the curwin */
8254 aco->save_curwin = curwin;
8255 curwin = win;
8256 aco->save_buf = win->w_buffer;
8257 aco->new_curwin = win;
8258 }
8259 else
8260 {
8261 /* there is no window for "buf", use curwin */
8262 aco->save_curwin = NULL;
8263 aco->save_buf = curbuf;
8264 --curbuf->b_nwindows;
8265 curwin->w_buffer = buf;
8266 ++buf->b_nwindows;
8267
8268 /* save cursor and topline, set them to safe values */
8269 aco->save_cursor = curwin->w_cursor;
8270 curwin->w_cursor.lnum = 1;
8271 curwin->w_cursor.col = 0;
8272 aco->save_topline = curwin->w_topline;
8273 curwin->w_topline = 1;
8274#ifdef FEAT_DIFF
8275 aco->save_topfill = curwin->w_topfill;
8276 curwin->w_topfill = 0;
8277#endif
8278 }
8279
8280 curbuf = buf;
8281}
8282
8283/*
8284 * Cleanup after executing autocommands for a (hidden) buffer.
8285 * Restore the window as it was (if possible).
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008286 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008287 */
8288 void
8289aucmd_restbuf(aco)
8290 aco_save_T *aco; /* structure holding saved values */
8291{
8292 if (aco->save_curwin != NULL)
8293 {
8294 /* restore curwin */
8295#ifdef FEAT_WINDOWS
8296 if (win_valid(aco->save_curwin))
8297#endif
8298 {
8299 /* restore the buffer which was previously edited by curwin, if
8300 * it's still the same window and it's valid */
8301 if (curwin == aco->new_curwin
8302 && buf_valid(aco->save_buf)
8303 && aco->save_buf->b_ml.ml_mfp != NULL)
8304 {
8305 --curbuf->b_nwindows;
8306 curbuf = aco->save_buf;
8307 curwin->w_buffer = curbuf;
8308 ++curbuf->b_nwindows;
8309 }
8310
8311 curwin = aco->save_curwin;
8312 curbuf = curwin->w_buffer;
8313 }
8314 }
8315 else
8316 {
8317 /* restore buffer for curwin if it still exists and is loaded */
8318 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8319 {
8320 --curbuf->b_nwindows;
8321 curbuf = aco->save_buf;
8322 curwin->w_buffer = curbuf;
8323 ++curbuf->b_nwindows;
8324 curwin->w_cursor = aco->save_cursor;
8325 check_cursor();
8326 /* check topline < line_count, in case lines got deleted */
8327 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8328 {
8329 curwin->w_topline = aco->save_topline;
8330#ifdef FEAT_DIFF
8331 curwin->w_topfill = aco->save_topfill;
8332#endif
8333 }
8334 else
8335 {
8336 curwin->w_topline = curbuf->b_ml.ml_line_count;
8337#ifdef FEAT_DIFF
8338 curwin->w_topfill = 0;
8339#endif
8340 }
8341 }
8342 }
8343}
8344
8345static int autocmd_nested = FALSE;
8346
8347/*
8348 * Execute autocommands for "event" and file name "fname".
8349 * Return TRUE if some commands were executed.
8350 */
8351 int
8352apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008353 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008354 char_u *fname; /* NULL or empty means use actual file name */
8355 char_u *fname_io; /* fname to use for <afile> on cmdline */
8356 int force; /* when TRUE, ignore autocmd_busy */
8357 buf_T *buf; /* buffer for <abuf> */
8358{
8359 return apply_autocmds_group(event, fname, fname_io, force,
8360 AUGROUP_ALL, buf, NULL);
8361}
8362
8363/*
8364 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8365 * setting v:filearg.
8366 */
8367 static int
8368apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008369 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008370 char_u *fname;
8371 char_u *fname_io;
8372 int force;
8373 buf_T *buf;
8374 exarg_T *eap;
8375{
8376 return apply_autocmds_group(event, fname, fname_io, force,
8377 AUGROUP_ALL, buf, eap);
8378}
8379
8380/*
8381 * Like apply_autocmds(), but handles the caller's retval. If the script
8382 * processing is being aborted or if retval is FAIL when inside a try
8383 * conditional, no autocommands are executed. If otherwise the autocommands
8384 * cause the script to be aborted, retval is set to FAIL.
8385 */
8386 int
8387apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008388 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008389 char_u *fname; /* NULL or empty means use actual file name */
8390 char_u *fname_io; /* fname to use for <afile> on cmdline */
8391 int force; /* when TRUE, ignore autocmd_busy */
8392 buf_T *buf; /* buffer for <abuf> */
8393 int *retval; /* pointer to caller's retval */
8394{
8395 int did_cmd;
8396
Bram Moolenaar1e015462005-09-25 22:16:38 +00008397#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008398 if (should_abort(*retval))
8399 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008400#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008401
8402 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8403 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008404 if (did_cmd
8405#ifdef FEAT_EVAL
8406 && aborting()
8407#endif
8408 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008409 *retval = FAIL;
8410 return did_cmd;
8411}
8412
Bram Moolenaard35f9712005-12-18 22:02:33 +00008413/*
8414 * Return TRUE when there is a CursorHold autocommand defined.
8415 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008416 int
8417has_cursorhold()
8418{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008419 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8420 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008421}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008422
8423/*
8424 * Return TRUE if the CursorHold event can be triggered.
8425 */
8426 int
8427trigger_cursorhold()
8428{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008429 int state;
8430
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00008431 if (!did_cursorhold && has_cursorhold() && !Recording
8432#ifdef FEAT_INS_EXPAND
8433 && !ins_compl_active()
8434#endif
8435 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00008436 {
8437 state = get_real_state();
8438 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8439 return TRUE;
8440 }
8441 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008442}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008443
8444/*
8445 * Return TRUE when there is a CursorMoved autocommand defined.
8446 */
8447 int
8448has_cursormoved()
8449{
8450 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8451}
8452
8453/*
8454 * Return TRUE when there is a CursorMovedI autocommand defined.
8455 */
8456 int
8457has_cursormovedI()
8458{
8459 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8460}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008461
8462 static int
8463apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008464 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008465 char_u *fname; /* NULL or empty means use actual file name */
8466 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8467 use fname */
8468 int force; /* when TRUE, ignore autocmd_busy */
8469 int group; /* group ID, or AUGROUP_ALL */
8470 buf_T *buf; /* buffer for <abuf> */
8471 exarg_T *eap; /* command arguments */
8472{
8473 char_u *sfname = NULL; /* short file name */
8474 char_u *tail;
8475 int save_changed;
8476 buf_T *old_curbuf;
8477 int retval = FALSE;
8478 char_u *save_sourcing_name;
8479 linenr_T save_sourcing_lnum;
8480 char_u *save_autocmd_fname;
8481 int save_autocmd_bufnr;
8482 char_u *save_autocmd_match;
8483 int save_autocmd_busy;
8484 int save_autocmd_nested;
8485 static int nesting = 0;
8486 AutoPatCmd patcmd;
8487 AutoPat *ap;
8488#ifdef FEAT_EVAL
8489 scid_T save_current_SID;
8490 void *save_funccalp;
8491 char_u *save_cmdarg;
8492 long save_cmdbang;
8493#endif
8494 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008495#ifdef FEAT_PROFILE
8496 proftime_T wait_time;
8497#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008498
8499 /*
8500 * Quickly return if there are no autocommands for this event or
8501 * autocommands are blocked.
8502 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00008503 if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008504 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008505
8506 /*
8507 * When autocommands are busy, new autocommands are only executed when
8508 * explicitly enabled with the "nested" flag.
8509 */
8510 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008511 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008512
8513#ifdef FEAT_EVAL
8514 /*
Bram Moolenaar7263a772007-05-10 17:35:54 +00008515 * Quickly return when immediately aborting on error, or when an interrupt
Bram Moolenaar071d4272004-06-13 20:20:40 +00008516 * occurred or an exception was thrown but not caught.
8517 */
8518 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008519 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008520#endif
8521
8522 /*
8523 * FileChangedShell never nests, because it can create an endless loop.
8524 */
Bram Moolenaar56718732006-03-15 22:53:57 +00008525 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
8526 || event == EVENT_FILECHANGEDSHELLPOST))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008527 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008528
8529 /*
8530 * Ignore events in 'eventignore'.
8531 */
8532 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008533 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008534
8535 /*
8536 * Allow nesting of autocommands, but restrict the depth, because it's
8537 * possible to create an endless loop.
8538 */
8539 if (nesting == 10)
8540 {
8541 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008542 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008543 }
8544
8545 /*
8546 * Check if these autocommands are disabled. Used when doing ":all" or
8547 * ":ball".
8548 */
8549 if ( (autocmd_no_enter
8550 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8551 || (autocmd_no_leave
8552 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008553 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008554
8555 /*
8556 * Save the autocmd_* variables and info about the current buffer.
8557 */
8558 save_autocmd_fname = autocmd_fname;
8559 save_autocmd_bufnr = autocmd_bufnr;
8560 save_autocmd_match = autocmd_match;
8561 save_autocmd_busy = autocmd_busy;
8562 save_autocmd_nested = autocmd_nested;
8563 save_changed = curbuf->b_changed;
8564 old_curbuf = curbuf;
8565
8566 /*
8567 * Set the file name to be used for <afile>.
Bram Moolenaara0174af2008-01-02 20:08:25 +00008568 * Make a copy to avoid that changing a buffer name or directory makes it
8569 * invalid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008570 */
8571 if (fname_io == NULL)
8572 {
8573 if (fname != NULL && *fname != NUL)
8574 autocmd_fname = fname;
8575 else if (buf != NULL)
8576 autocmd_fname = buf->b_fname;
8577 else
8578 autocmd_fname = NULL;
8579 }
8580 else
8581 autocmd_fname = fname_io;
Bram Moolenaara0174af2008-01-02 20:08:25 +00008582 if (autocmd_fname != NULL)
8583 autocmd_fname = FullName_save(autocmd_fname, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008584
8585 /*
8586 * Set the buffer number to be used for <abuf>.
8587 */
8588 if (buf == NULL)
8589 autocmd_bufnr = 0;
8590 else
8591 autocmd_bufnr = buf->b_fnum;
8592
8593 /*
8594 * When the file name is NULL or empty, use the file name of buffer "buf".
8595 * Always use the full path of the file name to match with, in case
8596 * "allow_dirs" is set.
8597 */
8598 if (fname == NULL || *fname == NUL)
8599 {
8600 if (buf == NULL)
8601 fname = NULL;
8602 else
8603 {
8604#ifdef FEAT_SYN_HL
8605 if (event == EVENT_SYNTAX)
8606 fname = buf->b_p_syn;
8607 else
8608#endif
8609 if (event == EVENT_FILETYPE)
8610 fname = buf->b_p_ft;
8611 else
8612 {
8613 if (buf->b_sfname != NULL)
8614 sfname = vim_strsave(buf->b_sfname);
8615 fname = buf->b_ffname;
8616 }
8617 }
8618 if (fname == NULL)
8619 fname = (char_u *)"";
8620 fname = vim_strsave(fname); /* make a copy, so we can change it */
8621 }
8622 else
8623 {
8624 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008625 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8626 if (event == EVENT_FILETYPE
8627 || event == EVENT_SYNTAX
8628 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008629 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008630 || event == EVENT_QUICKFIXCMDPRE
8631 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008632 fname = vim_strsave(fname);
8633 else
8634 fname = FullName_save(fname, FALSE);
8635 }
8636 if (fname == NULL) /* out of memory */
8637 {
8638 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008639 retval = FALSE;
8640 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008641 }
8642
8643#ifdef BACKSLASH_IN_FILENAME
8644 /*
8645 * Replace all backslashes with forward slashes. This makes the
8646 * autocommand patterns portable between Unix and MS-DOS.
8647 */
8648 if (sfname != NULL)
8649 forward_slash(sfname);
8650 forward_slash(fname);
8651#endif
8652
8653#ifdef VMS
8654 /* remove version for correct match */
8655 if (sfname != NULL)
8656 vms_remove_version(sfname);
8657 vms_remove_version(fname);
8658#endif
8659
8660 /*
8661 * Set the name to be used for <amatch>.
8662 */
8663 autocmd_match = fname;
8664
8665
8666 /* Don't redraw while doing auto commands. */
8667 ++RedrawingDisabled;
8668 save_sourcing_name = sourcing_name;
8669 sourcing_name = NULL; /* don't free this one */
8670 save_sourcing_lnum = sourcing_lnum;
8671 sourcing_lnum = 0; /* no line number here */
8672
8673#ifdef FEAT_EVAL
8674 save_current_SID = current_SID;
8675
Bram Moolenaar05159a02005-02-26 23:04:13 +00008676# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008677 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008678 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8679# endif
8680
Bram Moolenaar071d4272004-06-13 20:20:40 +00008681 /* Don't use local function variables, if called from a function */
8682 save_funccalp = save_funccal();
8683#endif
8684
8685 /*
8686 * When starting to execute autocommands, save the search patterns.
8687 */
8688 if (!autocmd_busy)
8689 {
8690 save_search_patterns();
8691 saveRedobuff();
8692 did_filetype = keep_filetype;
8693 }
8694
8695 /*
8696 * Note that we are applying autocmds. Some commands need to know.
8697 */
8698 autocmd_busy = TRUE;
8699 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8700 ++nesting; /* see matching decrement below */
8701
8702 /* Remember that FileType was triggered. Used for did_filetype(). */
8703 if (event == EVENT_FILETYPE)
8704 did_filetype = TRUE;
8705
8706 tail = gettail(fname);
8707
8708 /* Find first autocommand that matches */
8709 patcmd.curpat = first_autopat[(int)event];
8710 patcmd.nextcmd = NULL;
8711 patcmd.group = group;
8712 patcmd.fname = fname;
8713 patcmd.sfname = sfname;
8714 patcmd.tail = tail;
8715 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008716 patcmd.arg_bufnr = autocmd_bufnr;
8717 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008718 auto_next_pat(&patcmd, FALSE);
8719
8720 /* found one, start executing the autocommands */
8721 if (patcmd.curpat != NULL)
8722 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008723 /* add to active_apc_list */
8724 patcmd.next = active_apc_list;
8725 active_apc_list = &patcmd;
8726
Bram Moolenaar071d4272004-06-13 20:20:40 +00008727#ifdef FEAT_EVAL
8728 /* set v:cmdarg (only when there is a matching pattern) */
8729 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8730 if (eap != NULL)
8731 {
8732 save_cmdarg = set_cmdarg(eap, NULL);
8733 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8734 }
8735 else
8736 save_cmdarg = NULL; /* avoid gcc warning */
8737#endif
8738 retval = TRUE;
8739 /* mark the last pattern, to avoid an endless loop when more patterns
8740 * are added when executing autocommands */
8741 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8742 ap->last = FALSE;
8743 ap->last = TRUE;
8744 check_lnums(TRUE); /* make sure cursor and topline are valid */
8745 do_cmdline(NULL, getnextac, (void *)&patcmd,
8746 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8747#ifdef FEAT_EVAL
8748 if (eap != NULL)
8749 {
8750 (void)set_cmdarg(NULL, save_cmdarg);
8751 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8752 }
8753#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008754 /* delete from active_apc_list */
8755 if (active_apc_list == &patcmd) /* just in case */
8756 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008757 }
8758
8759 --RedrawingDisabled;
8760 autocmd_busy = save_autocmd_busy;
8761 filechangeshell_busy = FALSE;
8762 autocmd_nested = save_autocmd_nested;
8763 vim_free(sourcing_name);
8764 sourcing_name = save_sourcing_name;
8765 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaara0174af2008-01-02 20:08:25 +00008766 vim_free(autocmd_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008767 autocmd_fname = save_autocmd_fname;
8768 autocmd_bufnr = save_autocmd_bufnr;
8769 autocmd_match = save_autocmd_match;
8770#ifdef FEAT_EVAL
8771 current_SID = save_current_SID;
8772 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008773# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008774 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008775 prof_child_exit(&wait_time);
8776# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008777#endif
8778 vim_free(fname);
8779 vim_free(sfname);
8780 --nesting; /* see matching increment above */
8781
8782 /*
8783 * When stopping to execute autocommands, restore the search patterns and
8784 * the redo buffer.
8785 */
8786 if (!autocmd_busy)
8787 {
8788 restore_search_patterns();
8789 restoreRedobuff();
8790 did_filetype = FALSE;
8791 }
8792
8793 /*
8794 * Some events don't set or reset the Changed flag.
8795 * Check if still in the same buffer!
8796 */
8797 if (curbuf == old_curbuf
8798 && (event == EVENT_BUFREADPOST
8799 || event == EVENT_BUFWRITEPOST
8800 || event == EVENT_FILEAPPENDPOST
8801 || event == EVENT_VIMLEAVE
8802 || event == EVENT_VIMLEAVEPRE))
8803 {
8804#ifdef FEAT_TITLE
8805 if (curbuf->b_changed != save_changed)
8806 need_maketitle = TRUE;
8807#endif
8808 curbuf->b_changed = save_changed;
8809 }
8810
8811 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008812
8813BYPASS_AU:
8814 /* When wiping out a buffer make sure all its buffer-local autocommands
8815 * are deleted. */
8816 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8817 aubuflocal_remove(buf);
8818
Bram Moolenaar071d4272004-06-13 20:20:40 +00008819 return retval;
8820}
8821
Bram Moolenaar78ab3312007-09-29 12:16:41 +00008822# ifdef FEAT_EVAL
8823static char_u *old_termresponse = NULL;
8824# endif
8825
8826/*
8827 * Block triggering autocommands until unblock_autocmd() is called.
8828 * Can be used recursively, so long as it's symmetric.
8829 */
8830 void
8831block_autocmds()
8832{
8833# ifdef FEAT_EVAL
8834 /* Remember the value of v:termresponse. */
8835 if (autocmd_blocked == 0)
8836 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
8837# endif
8838 ++autocmd_blocked;
8839}
8840
8841 void
8842unblock_autocmds()
8843{
8844 --autocmd_blocked;
8845
8846# ifdef FEAT_EVAL
8847 /* When v:termresponse was set while autocommands were blocked, trigger
8848 * the autocommands now. Esp. useful when executing a shell command
8849 * during startup (vimdiff). */
8850 if (autocmd_blocked == 0
8851 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
8852 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
8853# endif
8854}
8855
Bram Moolenaar071d4272004-06-13 20:20:40 +00008856/*
8857 * Find next autocommand pattern that matches.
8858 */
8859 static void
8860auto_next_pat(apc, stop_at_last)
8861 AutoPatCmd *apc;
8862 int stop_at_last; /* stop when 'last' flag is set */
8863{
8864 AutoPat *ap;
8865 AutoCmd *cp;
8866 char_u *name;
8867 char *s;
8868
8869 vim_free(sourcing_name);
8870 sourcing_name = NULL;
8871
8872 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8873 {
8874 apc->curpat = NULL;
8875
8876 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008877 * the group matches. For buffer-local autocommands only check the
8878 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008879 if (ap->pat != NULL && ap->cmds != NULL
8880 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8881 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008882 /* execution-condition */
8883 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008884 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8885 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008886 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008887 {
8888 name = event_nr2name(apc->event);
8889 s = _("%s Auto commands for \"%s\"");
8890 sourcing_name = alloc((unsigned)(STRLEN(s)
8891 + STRLEN(name) + ap->patlen + 1));
8892 if (sourcing_name != NULL)
8893 {
8894 sprintf((char *)sourcing_name, s,
8895 (char *)name, (char *)ap->pat);
8896 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008897 {
8898 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008899 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008900 verbose_leave();
8901 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008902 }
8903
8904 apc->curpat = ap;
8905 apc->nextcmd = ap->cmds;
8906 /* mark last command */
8907 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8908 cp->last = FALSE;
8909 cp->last = TRUE;
8910 }
8911 line_breakcheck();
8912 if (apc->curpat != NULL) /* found a match */
8913 break;
8914 }
8915 if (stop_at_last && ap->last)
8916 break;
8917 }
8918}
8919
8920/*
8921 * Get next autocommand command.
8922 * Called by do_cmdline() to get the next line for ":if".
8923 * Returns allocated string, or NULL for end of autocommands.
8924 */
8925/* ARGSUSED */
8926 static char_u *
8927getnextac(c, cookie, indent)
8928 int c; /* not used */
8929 void *cookie;
8930 int indent; /* not used */
8931{
8932 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8933 char_u *retval;
8934 AutoCmd *ac;
8935
8936 /* Can be called again after returning the last line. */
8937 if (acp->curpat == NULL)
8938 return NULL;
8939
8940 /* repeat until we find an autocommand to execute */
8941 for (;;)
8942 {
8943 /* skip removed commands */
8944 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8945 if (acp->nextcmd->last)
8946 acp->nextcmd = NULL;
8947 else
8948 acp->nextcmd = acp->nextcmd->next;
8949
8950 if (acp->nextcmd != NULL)
8951 break;
8952
8953 /* at end of commands, find next pattern that matches */
8954 if (acp->curpat->last)
8955 acp->curpat = NULL;
8956 else
8957 acp->curpat = acp->curpat->next;
8958 if (acp->curpat != NULL)
8959 auto_next_pat(acp, TRUE);
8960 if (acp->curpat == NULL)
8961 return NULL;
8962 }
8963
8964 ac = acp->nextcmd;
8965
8966 if (p_verbose >= 9)
8967 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008968 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008969 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008970 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008971 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008972 }
8973 retval = vim_strsave(ac->cmd);
8974 autocmd_nested = ac->nested;
8975#ifdef FEAT_EVAL
8976 current_SID = ac->scriptID;
8977#endif
8978 if (ac->last)
8979 acp->nextcmd = NULL;
8980 else
8981 acp->nextcmd = ac->next;
8982 return retval;
8983}
8984
8985/*
8986 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008987 * To account for buffer-local autocommands, function needs to know
8988 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008989 */
8990 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008991has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008992 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008993 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008994 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008995{
8996 AutoPat *ap;
8997 char_u *fname;
8998 char_u *tail = gettail(sfname);
8999 int retval = FALSE;
9000
9001 fname = FullName_save(sfname, FALSE);
9002 if (fname == NULL)
9003 return FALSE;
9004
9005#ifdef BACKSLASH_IN_FILENAME
9006 /*
9007 * Replace all backslashes with forward slashes. This makes the
9008 * autocommand patterns portable between Unix and MS-DOS.
9009 */
9010 sfname = vim_strsave(sfname);
9011 if (sfname != NULL)
9012 forward_slash(sfname);
9013 forward_slash(fname);
9014#endif
9015
9016 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
9017 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009018 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00009019 ? match_file_pat(NULL, ap->reg_prog,
9020 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00009021 : buf != NULL && ap->buflocal_nr == buf->b_fnum
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009022 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009023 {
9024 retval = TRUE;
9025 break;
9026 }
9027
9028 vim_free(fname);
9029#ifdef BACKSLASH_IN_FILENAME
9030 vim_free(sfname);
9031#endif
9032
9033 return retval;
9034}
9035
9036#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
9037/*
9038 * Function given to ExpandGeneric() to obtain the list of autocommand group
9039 * names.
9040 */
9041/*ARGSUSED*/
9042 char_u *
9043get_augroup_name(xp, idx)
9044 expand_T *xp;
9045 int idx;
9046{
9047 if (idx == augroups.ga_len) /* add "END" add the end */
9048 return (char_u *)"END";
9049 if (idx >= augroups.ga_len) /* end of list */
9050 return NULL;
9051 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
9052 return (char_u *)"";
9053 return AUGROUP_NAME(idx); /* return a name */
9054}
9055
9056static int include_groups = FALSE;
9057
9058 char_u *
9059set_context_in_autocmd(xp, arg, doautocmd)
9060 expand_T *xp;
9061 char_u *arg;
9062 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
9063{
9064 char_u *p;
9065 int group;
9066
9067 /* check for a group name, skip it if present */
9068 include_groups = FALSE;
9069 p = arg;
9070 group = au_get_grouparg(&arg);
9071 if (group == AUGROUP_ERROR)
9072 return NULL;
9073 /* If there only is a group name that's what we expand. */
9074 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
9075 {
9076 arg = p;
9077 group = AUGROUP_ALL;
9078 }
9079
9080 /* skip over event name */
9081 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
9082 if (*p == ',')
9083 arg = p + 1;
9084 if (*p == NUL)
9085 {
9086 if (group == AUGROUP_ALL)
9087 include_groups = TRUE;
9088 xp->xp_context = EXPAND_EVENTS; /* expand event name */
9089 xp->xp_pattern = arg;
9090 return NULL;
9091 }
9092
9093 /* skip over pattern */
9094 arg = skipwhite(p);
9095 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
9096 arg++;
9097 if (*arg)
9098 return arg; /* expand (next) command */
9099
9100 if (doautocmd)
9101 xp->xp_context = EXPAND_FILES; /* expand file names */
9102 else
9103 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
9104 return NULL;
9105}
9106
9107/*
9108 * Function given to ExpandGeneric() to obtain the list of event names.
9109 */
9110/*ARGSUSED*/
9111 char_u *
9112get_event_name(xp, idx)
9113 expand_T *xp;
9114 int idx;
9115{
9116 if (idx < augroups.ga_len) /* First list group names, if wanted */
9117 {
9118 if (!include_groups || AUGROUP_NAME(idx) == NULL)
9119 return (char_u *)""; /* skip deleted entries */
9120 return AUGROUP_NAME(idx); /* return a name */
9121 }
9122 return (char_u *)event_names[idx - augroups.ga_len].name;
9123}
9124
9125#endif /* FEAT_CMDL_COMPL */
9126
9127/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009128 * Return TRUE if autocmd is supported.
9129 */
9130 int
9131autocmd_supported(name)
9132 char_u *name;
9133{
9134 char_u *p;
9135
9136 return (event_name2nr(name, &p) != NUM_EVENTS);
9137}
9138
9139/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00009140 * Return TRUE if an autocommand is defined for a group, event and
9141 * pattern: The group can be omitted to accept any group. "event" and "pattern"
9142 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
9143 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
9144 * Used for:
9145 * exists("#Group") or
9146 * exists("#Group#Event") or
9147 * exists("#Group#Event#pat") or
9148 * exists("#Event") or
9149 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00009150 */
9151 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00009152au_exists(arg)
9153 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009154{
Bram Moolenaar195d6352005-12-19 22:08:24 +00009155 char_u *arg_save;
9156 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009157 char_u *event_name;
9158 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00009159 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009160 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009161 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00009162 int group;
9163 int retval = FALSE;
9164
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009165 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009166 arg_save = vim_strsave(arg);
9167 if (arg_save == NULL)
9168 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00009169 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00009170 if (p != NULL)
9171 *p++ = NUL;
9172
9173 /* First, look for an autocmd group name */
9174 group = au_find_group(arg_save);
9175 if (group == AUGROUP_ERROR)
9176 {
9177 /* Didn't match a group name, assume the first argument is an event. */
9178 group = AUGROUP_ALL;
9179 event_name = arg_save;
9180 }
9181 else
9182 {
9183 if (p == NULL)
9184 {
9185 /* "Group": group name is present and it's recognized */
9186 retval = TRUE;
9187 goto theend;
9188 }
9189
9190 /* Must be "Group#Event" or "Group#Event#pat". */
9191 event_name = p;
9192 p = vim_strchr(event_name, '#');
9193 if (p != NULL)
9194 *p++ = NUL; /* "Group#Event#pat" */
9195 }
9196
9197 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009198
9199 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009200 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009201
9202 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009203 if (event == NUM_EVENTS)
9204 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009205
9206 /* Find the first autocommand for this event.
9207 * If there isn't any, return FALSE;
9208 * If there is one and no pattern given, return TRUE; */
9209 ap = first_autopat[(int)event];
9210 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009211 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009212 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009213 {
9214 retval = TRUE;
9215 goto theend;
9216 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009217
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009218 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
9219 /* for pattern "<buffer=N>, fnamecmp() will work fine */
9220 if (STRICMP(pattern, "<buffer>") == 0)
9221 buflocal_buf = curbuf;
9222
Bram Moolenaar071d4272004-06-13 20:20:40 +00009223 /* Check if there is an autocommand with the given pattern. */
9224 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009225 /* only use a pattern when it has not been removed and has commands. */
9226 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009227 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009228 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009229 && (buflocal_buf == NULL
9230 ? fnamecmp(ap->pat, pattern) == 0
9231 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009232 {
9233 retval = TRUE;
9234 break;
9235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009236
Bram Moolenaar195d6352005-12-19 22:08:24 +00009237theend:
9238 vim_free(arg_save);
9239 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009240}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009241
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009242#else /* FEAT_AUTOCMD */
9243
9244/*
9245 * Prepare for executing commands for (hidden) buffer "buf".
9246 * This is the non-autocommand version, it simply saves "curbuf" and sets
9247 * "curbuf" and "curwin" to match "buf".
9248 */
9249 void
9250aucmd_prepbuf(aco, buf)
9251 aco_save_T *aco; /* structure to save values in */
9252 buf_T *buf; /* new curbuf */
9253{
Bram Moolenaar6ae90982008-03-11 21:02:00 +00009254 aco->save_buf = curbuf;
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009255 curbuf = buf;
9256 curwin->w_buffer = buf;
9257}
9258
9259/*
9260 * Restore after executing commands for a (hidden) buffer.
9261 * This is the non-autocommand version.
9262 */
9263 void
9264aucmd_restbuf(aco)
9265 aco_save_T *aco; /* structure holding saved values */
9266{
9267 curbuf = aco->save_buf;
9268 curwin->w_buffer = curbuf;
9269}
9270
Bram Moolenaar071d4272004-06-13 20:20:40 +00009271#endif /* FEAT_AUTOCMD */
9272
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009273
Bram Moolenaar071d4272004-06-13 20:20:40 +00009274#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9275/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009276 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9277 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9278 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009279 * Used for autocommands and 'wildignore'.
9280 * Returns TRUE if there is a match, FALSE otherwise.
9281 */
9282 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009283match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009284 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009285 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009286 char_u *fname; /* full path of file name */
9287 char_u *sfname; /* short file name or NULL */
9288 char_u *tail; /* tail of path */
9289 int allow_dirs; /* allow matching with dir */
9290{
9291 regmatch_T regmatch;
9292 int result = FALSE;
9293#ifdef FEAT_OSFILETYPE
9294 int no_pattern = FALSE; /* TRUE if check is filetype only */
9295 char_u *type_start;
9296 char_u c;
9297 int match = FALSE;
9298#endif
9299
9300#ifdef CASE_INSENSITIVE_FILENAME
9301 regmatch.rm_ic = TRUE; /* Always ignore case */
9302#else
9303 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9304#endif
9305#ifdef FEAT_OSFILETYPE
9306 if (*pattern == '<')
9307 {
9308 /* There is a filetype condition specified with this pattern.
9309 * Check the filetype matches first. If not, don't bother with the
9310 * pattern (set regprog to NULL).
9311 * Always use magic for the regexp.
9312 */
9313
9314 for (type_start = pattern + 1; (c = *pattern); pattern++)
9315 {
9316 if ((c == ';' || c == '>') && match == FALSE)
9317 {
9318 *pattern = NUL; /* Terminate the string */
9319 match = mch_check_filetype(fname, type_start);
9320 *pattern = c; /* Restore the terminator */
9321 type_start = pattern + 1;
9322 }
9323 if (c == '>')
9324 break;
9325 }
9326
9327 /* (c should never be NUL, but check anyway) */
9328 if (match == FALSE || c == NUL)
9329 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9330 else if (*pattern == NUL)
9331 {
9332 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9333 no_pattern = TRUE; /* Always matches - don't check pat. */
9334 }
9335 else
9336 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9337 }
9338 else
9339#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009340 {
9341 if (prog != NULL)
9342 regmatch.regprog = prog;
9343 else
9344 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9345 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009346
9347 /*
9348 * Try for a match with the pattern with:
9349 * 1. the full file name, when the pattern has a '/'.
9350 * 2. the short file name, when the pattern has a '/'.
9351 * 3. the tail of the file name, when the pattern has no '/'.
9352 */
9353 if (
9354#ifdef FEAT_OSFILETYPE
9355 /* If the check is for a filetype only and we don't care
9356 * about the path then skip all the regexp stuff.
9357 */
9358 no_pattern ||
9359#endif
9360 (regmatch.regprog != NULL
9361 && ((allow_dirs
9362 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9363 || (sfname != NULL
9364 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9365 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9366 result = TRUE;
9367
Bram Moolenaar748bf032005-02-02 23:04:36 +00009368 if (prog == NULL)
9369 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009370 return result;
9371}
9372#endif
9373
9374#if defined(FEAT_WILDIGN) || defined(PROTO)
9375/*
9376 * Return TRUE if a file matches with a pattern in "list".
9377 * "list" is a comma-separated list of patterns, like 'wildignore'.
9378 * "sfname" is the short file name or NULL, "ffname" the long file name.
9379 */
9380 int
9381match_file_list(list, sfname, ffname)
9382 char_u *list;
9383 char_u *sfname;
9384 char_u *ffname;
9385{
9386 char_u buf[100];
9387 char_u *tail;
9388 char_u *regpat;
9389 char allow_dirs;
9390 int match;
9391 char_u *p;
9392
9393 tail = gettail(sfname);
9394
9395 /* try all patterns in 'wildignore' */
9396 p = list;
9397 while (*p)
9398 {
9399 copy_option_part(&p, buf, 100, ",");
9400 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9401 if (regpat == NULL)
9402 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009403 match = match_file_pat(regpat, NULL, ffname, sfname,
9404 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009405 vim_free(regpat);
9406 if (match)
9407 return TRUE;
9408 }
9409 return FALSE;
9410}
9411#endif
9412
9413/*
9414 * Convert the given pattern "pat" which has shell style wildcards in it, into
9415 * a regular expression, and return the result in allocated memory. If there
9416 * is a directory path separator to be matched, then TRUE is put in
9417 * allow_dirs, otherwise FALSE is put there -- webb.
9418 * Handle backslashes before special characters, like "\*" and "\ ".
9419 *
9420 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9421 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9422 *
9423 * Returns NULL when out of memory.
9424 */
9425/*ARGSUSED*/
9426 char_u *
9427file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9428 char_u *pat;
9429 char_u *pat_end; /* first char after pattern or NULL */
9430 char *allow_dirs; /* Result passed back out in here */
9431 int no_bslash; /* Don't use a backward slash as pathsep */
9432{
9433 int size;
9434 char_u *endp;
9435 char_u *reg_pat;
9436 char_u *p;
9437 int i;
9438 int nested = 0;
9439 int add_dollar = TRUE;
9440#ifdef FEAT_OSFILETYPE
9441 int check_length = 0;
9442#endif
9443
9444 if (allow_dirs != NULL)
9445 *allow_dirs = FALSE;
9446 if (pat_end == NULL)
9447 pat_end = pat + STRLEN(pat);
9448
9449#ifdef FEAT_OSFILETYPE
9450 /* Find out how much of the string is the filetype check */
9451 if (*pat == '<')
9452 {
9453 /* Count chars until the next '>' */
9454 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9455 ;
9456 if (p < pat_end)
9457 {
9458 /* Pattern is of the form <.*>.* */
9459 check_length = p - pat + 1;
9460 if (p + 1 >= pat_end)
9461 {
9462 /* The 'pattern' is a filetype check ONLY */
9463 reg_pat = (char_u *)alloc(check_length + 1);
9464 if (reg_pat != NULL)
9465 {
9466 mch_memmove(reg_pat, pat, (size_t)check_length);
9467 reg_pat[check_length] = NUL;
9468 }
9469 return reg_pat;
9470 }
9471 }
9472 /* else: there was no closing '>' - assume it was a normal pattern */
9473
9474 }
9475 pat += check_length;
9476 size = 2 + check_length;
9477#else
9478 size = 2; /* '^' at start, '$' at end */
9479#endif
9480
9481 for (p = pat; p < pat_end; p++)
9482 {
9483 switch (*p)
9484 {
9485 case '*':
9486 case '.':
9487 case ',':
9488 case '{':
9489 case '}':
9490 case '~':
9491 size += 2; /* extra backslash */
9492 break;
9493#ifdef BACKSLASH_IN_FILENAME
9494 case '\\':
9495 case '/':
9496 size += 4; /* could become "[\/]" */
9497 break;
9498#endif
9499 default:
9500 size++;
9501# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009502 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009503 {
9504 ++p;
9505 ++size;
9506 }
9507# endif
9508 break;
9509 }
9510 }
9511 reg_pat = alloc(size + 1);
9512 if (reg_pat == NULL)
9513 return NULL;
9514
9515#ifdef FEAT_OSFILETYPE
9516 /* Copy the type check in to the start. */
9517 if (check_length)
9518 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9519 i = check_length;
9520#else
9521 i = 0;
9522#endif
9523
9524 if (pat[0] == '*')
9525 while (pat[0] == '*' && pat < pat_end - 1)
9526 pat++;
9527 else
9528 reg_pat[i++] = '^';
9529 endp = pat_end - 1;
9530 if (*endp == '*')
9531 {
9532 while (endp - pat > 0 && *endp == '*')
9533 endp--;
9534 add_dollar = FALSE;
9535 }
9536 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9537 {
9538 switch (*p)
9539 {
9540 case '*':
9541 reg_pat[i++] = '.';
9542 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009543 while (p[1] == '*') /* "**" matches like "*" */
9544 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009545 break;
9546 case '.':
9547#ifdef RISCOS
9548 if (allow_dirs != NULL)
9549 *allow_dirs = TRUE;
9550 /* FALLTHROUGH */
9551#endif
9552 case '~':
9553 reg_pat[i++] = '\\';
9554 reg_pat[i++] = *p;
9555 break;
9556 case '?':
9557#ifdef RISCOS
9558 case '#':
9559#endif
9560 reg_pat[i++] = '.';
9561 break;
9562 case '\\':
9563 if (p[1] == NUL)
9564 break;
9565#ifdef BACKSLASH_IN_FILENAME
9566 if (!no_bslash)
9567 {
9568 /* translate:
9569 * "\x" to "\\x" e.g., "dir\file"
9570 * "\*" to "\\.*" e.g., "dir\*.c"
9571 * "\?" to "\\." e.g., "dir\??.c"
9572 * "\+" to "\+" e.g., "fileX\+.c"
9573 */
9574 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9575 && p[1] != '+')
9576 {
9577 reg_pat[i++] = '[';
9578 reg_pat[i++] = '\\';
9579 reg_pat[i++] = '/';
9580 reg_pat[i++] = ']';
9581 if (allow_dirs != NULL)
9582 *allow_dirs = TRUE;
9583 break;
9584 }
9585 }
9586#endif
9587 if (*++p == '?'
9588#ifdef BACKSLASH_IN_FILENAME
9589 && no_bslash
9590#endif
9591 )
9592 reg_pat[i++] = '?';
9593 else
9594 if (*p == ',')
9595 reg_pat[i++] = ',';
9596 else
9597 {
9598 if (allow_dirs != NULL && vim_ispathsep(*p)
9599#ifdef BACKSLASH_IN_FILENAME
9600 && (!no_bslash || *p != '\\')
9601#endif
9602 )
9603 *allow_dirs = TRUE;
9604 reg_pat[i++] = '\\';
9605 reg_pat[i++] = *p;
9606 }
9607 break;
9608#ifdef BACKSLASH_IN_FILENAME
9609 case '/':
9610 reg_pat[i++] = '[';
9611 reg_pat[i++] = '\\';
9612 reg_pat[i++] = '/';
9613 reg_pat[i++] = ']';
9614 if (allow_dirs != NULL)
9615 *allow_dirs = TRUE;
9616 break;
9617#endif
9618 case '{':
9619 reg_pat[i++] = '\\';
9620 reg_pat[i++] = '(';
9621 nested++;
9622 break;
9623 case '}':
9624 reg_pat[i++] = '\\';
9625 reg_pat[i++] = ')';
9626 --nested;
9627 break;
9628 case ',':
9629 if (nested)
9630 {
9631 reg_pat[i++] = '\\';
9632 reg_pat[i++] = '|';
9633 }
9634 else
9635 reg_pat[i++] = ',';
9636 break;
9637 default:
9638# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009639 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009640 reg_pat[i++] = *p++;
9641 else
9642# endif
9643 if (allow_dirs != NULL && vim_ispathsep(*p))
9644 *allow_dirs = TRUE;
9645 reg_pat[i++] = *p;
9646 break;
9647 }
9648 }
9649 if (add_dollar)
9650 reg_pat[i++] = '$';
9651 reg_pat[i] = NUL;
9652 if (nested != 0)
9653 {
9654 if (nested < 0)
9655 EMSG(_("E219: Missing {."));
9656 else
9657 EMSG(_("E220: Missing }."));
9658 vim_free(reg_pat);
9659 reg_pat = NULL;
9660 }
9661 return reg_pat;
9662}