blob: de101c8f32f6ddb42610d5fb1d8d1d9873cb092e [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)
15# include <io.h> /* for lseek(), must be before vim.h */
16#endif
17
18#if defined __EMX__
19# include <io.h> /* for mktemp(), CJW 1997-12-03 */
20#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
47#ifdef FEAT_MBYTE
48static char_u *next_fenc __ARGS((char_u **pp));
49# ifdef FEAT_EVAL
50static char_u *readfile_charconvert __ARGS((char_u *fname, char_u *fenc, int *fdp));
51# endif
52#endif
53#ifdef FEAT_VIMINFO
54static void check_marks_read __ARGS((void));
55#endif
56#ifdef FEAT_CRYPT
57static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, long *filesizep, int newfile));
58#endif
59#ifdef UNIX
60static void set_file_time __ARGS((char_u *fname, time_t atime, time_t mtime));
61#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +000062static int set_rw_fname __ARGS((char_u *fname, char_u *sfname));
Bram Moolenaar071d4272004-06-13 20:20:40 +000063static int msg_add_fileformat __ARGS((int eol_type));
Bram Moolenaar071d4272004-06-13 20:20:40 +000064static void msg_add_eol __ARGS((void));
65static int check_mtime __ARGS((buf_T *buf, struct stat *s));
66static int time_differs __ARGS((long t1, long t2));
67#ifdef FEAT_AUTOCMD
Bram Moolenaar754b5602006-02-09 23:53:20 +000068static int apply_autocmds_exarg __ARGS((event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap));
Bram Moolenaar071d4272004-06-13 20:20:40 +000069#endif
70
71#if defined(FEAT_CRYPT) || defined(FEAT_MBYTE)
72# define HAS_BW_FLAGS
73# define FIO_LATIN1 0x01 /* convert Latin1 */
74# define FIO_UTF8 0x02 /* convert UTF-8 */
75# define FIO_UCS2 0x04 /* convert UCS-2 */
76# define FIO_UCS4 0x08 /* convert UCS-4 */
77# define FIO_UTF16 0x10 /* convert UTF-16 */
78# ifdef WIN3264
79# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
80# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
81# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
82# endif
83# ifdef MACOS_X
84# define FIO_MACROMAN 0x20 /* convert MacRoman */
85# endif
86# define FIO_ENDIAN_L 0x80 /* little endian */
87# define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
88# define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
89# define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
90# define FIO_ALL -1 /* allow all formats */
91#endif
92
93/* When converting, a read() or write() may leave some bytes to be converted
94 * for the next call. The value is guessed... */
95#define CONV_RESTLEN 30
96
97/* We have to guess how much a sequence of bytes may expand when converting
98 * with iconv() to be able to allocate a buffer. */
99#define ICONV_MULT 8
100
101/*
102 * Structure to pass arguments from buf_write() to buf_write_bytes().
103 */
104struct bw_info
105{
106 int bw_fd; /* file descriptor */
107 char_u *bw_buf; /* buffer with data to be written */
108 int bw_len; /* lenght of data */
109#ifdef HAS_BW_FLAGS
110 int bw_flags; /* FIO_ flags */
111#endif
112#ifdef FEAT_MBYTE
113 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
114 int bw_restlen; /* nr of bytes in bw_rest[] */
115 int bw_first; /* first write call */
116 char_u *bw_conv_buf; /* buffer for writing converted chars */
117 int bw_conv_buflen; /* size of bw_conv_buf */
118 int bw_conv_error; /* set for conversion error */
119# ifdef USE_ICONV
120 iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
121# endif
122#endif
123};
124
125static int buf_write_bytes __ARGS((struct bw_info *ip));
126
127#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000128static linenr_T readfile_linenr __ARGS((linenr_T linecnt, char_u *p, char_u *endp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129static int ucs2bytes __ARGS((unsigned c, char_u **pp, int flags));
130static int same_encoding __ARGS((char_u *a, char_u *b));
131static int get_fio_flags __ARGS((char_u *ptr));
132static char_u *check_for_bom __ARGS((char_u *p, long size, int *lenp, int flags));
133static int make_bom __ARGS((char_u *buf, char_u *name));
134# ifdef WIN3264
135static int get_win_fio_flags __ARGS((char_u *ptr));
136# endif
137# ifdef MACOS_X
138static int get_mac_fio_flags __ARGS((char_u *ptr));
139# endif
140#endif
141static int move_lines __ARGS((buf_T *frombuf, buf_T *tobuf));
142
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000143
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 void
145filemess(buf, name, s, attr)
146 buf_T *buf;
147 char_u *name;
148 char_u *s;
149 int attr;
150{
151 int msg_scroll_save;
152
153 if (msg_silent != 0)
154 return;
155 msg_add_fname(buf, name); /* put file name in IObuff with quotes */
156 /* If it's extremely long, truncate it. */
157 if (STRLEN(IObuff) > IOSIZE - 80)
158 IObuff[IOSIZE - 80] = NUL;
159 STRCAT(IObuff, s);
160 /*
161 * For the first message may have to start a new line.
162 * For further ones overwrite the previous one, reset msg_scroll before
163 * calling filemess().
164 */
165 msg_scroll_save = msg_scroll;
166 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
167 msg_scroll = FALSE;
168 if (!msg_scroll) /* wait a bit when overwriting an error msg */
169 check_for_delay(FALSE);
170 msg_start();
171 msg_scroll = msg_scroll_save;
172 msg_scrolled_ign = TRUE;
173 /* may truncate the message to avoid a hit-return prompt */
174 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
175 msg_clr_eos();
176 out_flush();
177 msg_scrolled_ign = FALSE;
178}
179
180/*
181 * Read lines from file "fname" into the buffer after line "from".
182 *
183 * 1. We allocate blocks with lalloc, as big as possible.
184 * 2. Each block is filled with characters from the file with a single read().
185 * 3. The lines are inserted in the buffer with ml_append().
186 *
187 * (caller must check that fname != NULL, unless READ_STDIN is used)
188 *
189 * "lines_to_skip" is the number of lines that must be skipped
190 * "lines_to_read" is the number of lines that are appended
191 * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
192 *
193 * flags:
194 * READ_NEW starting to edit a new buffer
195 * READ_FILTER reading filter output
196 * READ_STDIN read from stdin instead of a file
197 * READ_BUFFER read from curbuf instead of a file (converting after reading
198 * stdin)
199 * READ_DUMMY read into a dummy buffer (to check if file contents changed)
200 *
201 * return FAIL for failure, OK otherwise
202 */
203 int
204readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
205 char_u *fname;
206 char_u *sfname;
207 linenr_T from;
208 linenr_T lines_to_skip;
209 linenr_T lines_to_read;
210 exarg_T *eap; /* can be NULL! */
211 int flags;
212{
213 int fd = 0;
214 int newfile = (flags & READ_NEW);
215 int check_readonly;
216 int filtering = (flags & READ_FILTER);
217 int read_stdin = (flags & READ_STDIN);
218 int read_buffer = (flags & READ_BUFFER);
219 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
220 colnr_T read_buf_col = 0; /* next char to read from this line */
221 char_u c;
222 linenr_T lnum = from;
223 char_u *ptr = NULL; /* pointer into read buffer */
224 char_u *buffer = NULL; /* read buffer */
225 char_u *new_buffer = NULL; /* init to shut up gcc */
226 char_u *line_start = NULL; /* init to shut up gcc */
227 int wasempty; /* buffer was empty before reading */
228 colnr_T len;
229 long size = 0;
230 char_u *p;
231 long filesize = 0;
232 int skip_read = FALSE;
233#ifdef FEAT_CRYPT
234 char_u *cryptkey = NULL;
235#endif
236 int split = 0; /* number of split lines */
237#define UNKNOWN 0x0fffffff /* file size is unknown */
238 linenr_T linecnt;
239 int error = FALSE; /* errors encountered */
240 int ff_error = EOL_UNKNOWN; /* file format with errors */
241 long linerest = 0; /* remaining chars in line */
242#ifdef UNIX
243 int perm = 0;
244 int swap_mode = -1; /* protection bits for swap file */
245#else
246 int perm;
247#endif
248 int fileformat = 0; /* end-of-line format */
249 int keep_fileformat = FALSE;
250 struct stat st;
251 int file_readonly;
252 linenr_T skip_count = 0;
253 linenr_T read_count = 0;
254 int msg_save = msg_scroll;
255 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
256 * last read was missing the eol */
257 int try_mac = (vim_strchr(p_ffs, 'm') != NULL);
258 int try_dos = (vim_strchr(p_ffs, 'd') != NULL);
259 int try_unix = (vim_strchr(p_ffs, 'x') != NULL);
260 int file_rewind = FALSE;
261#ifdef FEAT_MBYTE
262 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000263 linenr_T conv_error = 0; /* line nr with conversion error */
264 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
266 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000267 int bad_char_behavior = BAD_REPLACE;
268 /* BAD_KEEP, BAD_DROP or character to
269 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270 char_u *tmpname = NULL; /* name of 'charconvert' output file */
271 int fio_flags = 0;
272 char_u *fenc; /* fileencoding to use */
273 int fenc_alloced; /* fenc_next is in allocated memory */
274 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
275 int advance_fenc = FALSE;
276 long real_size = 0;
277# ifdef USE_ICONV
278 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
279# ifdef FEAT_EVAL
280 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
281 'charconvert' next */
282# endif
283# endif
284 int converted = FALSE; /* TRUE if conversion done */
285 int notconverted = FALSE; /* TRUE if conversion wanted but it
286 wasn't possible */
287 char_u conv_rest[CONV_RESTLEN];
288 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
289#endif
290
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291 write_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292
293 /*
294 * If there is no file name yet, use the one for the read file.
295 * BF_NOTEDITED is set to reflect this.
296 * Don't do this for a read from a filter.
297 * Only do this when 'cpoptions' contains the 'f' flag.
298 */
299 if (curbuf->b_ffname == NULL
300 && !filtering
301 && fname != NULL
302 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
303 && !(flags & READ_DUMMY))
304 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000305 if (set_rw_fname(fname, sfname) == FAIL)
306 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 }
308
Bram Moolenaardf177f62005-02-22 08:39:57 +0000309 /* After reading a file the cursor line changes but we don't want to
310 * display the line. */
311 ex_no_reprint = TRUE;
312
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313 /*
314 * For Unix: Use the short file name whenever possible.
315 * Avoids problems with networks and when directory names are changed.
316 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
317 * another directory, which we don't detect.
318 */
319 if (sfname == NULL)
320 sfname = fname;
321#if defined(UNIX) || defined(__EMX__)
322 fname = sfname;
323#endif
324
325#ifdef FEAT_AUTOCMD
326 /*
327 * The BufReadCmd and FileReadCmd events intercept the reading process by
328 * executing the associated commands instead.
329 */
330 if (!filtering && !read_stdin && !read_buffer)
331 {
332 pos_T pos;
333
334 pos = curbuf->b_op_start;
335
336 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
337 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
338 curbuf->b_op_start.col = 0;
339
340 if (newfile)
341 {
342 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
343 FALSE, curbuf, eap))
344#ifdef FEAT_EVAL
345 return aborting() ? FAIL : OK;
346#else
347 return OK;
348#endif
349 }
350 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
351 FALSE, NULL, eap))
352#ifdef FEAT_EVAL
353 return aborting() ? FAIL : OK;
354#else
355 return OK;
356#endif
357
358 curbuf->b_op_start = pos;
359 }
360#endif
361
362 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
363 msg_scroll = FALSE; /* overwrite previous file message */
364 else
365 msg_scroll = TRUE; /* don't overwrite previous file message */
366
367 /*
368 * If the name ends in a path separator, we can't open it. Check here,
369 * because reading the file may actually work, but then creating the swap
370 * file may destroy it! Reported on MS-DOS and Win 95.
371 * If the name is too long we might crash further on, quit here.
372 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000373 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000375 p = fname + STRLEN(fname);
376 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000377 {
378 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
379 msg_end();
380 msg_scroll = msg_save;
381 return FAIL;
382 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 }
384
385#ifdef UNIX
386 /*
387 * On Unix it is possible to read a directory, so we have to
388 * check for it before the mch_open().
389 */
390 if (!read_stdin && !read_buffer)
391 {
392 perm = mch_getperm(fname);
393 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
394# ifdef S_ISFIFO
395 && !S_ISFIFO(perm) /* ... or fifo */
396# endif
397# ifdef S_ISSOCK
398 && !S_ISSOCK(perm) /* ... or socket */
399# endif
400 )
401 {
402 if (S_ISDIR(perm))
403 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
404 else
405 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
406 msg_end();
407 msg_scroll = msg_save;
408 return FAIL;
409 }
410 }
411#endif
412
413 /* set default 'fileformat' */
414 if (newfile)
415 {
416 if (eap != NULL && eap->force_ff != 0)
417 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
418 else if (*p_ffs != NUL)
419 set_fileformat(default_fileformat(), OPT_LOCAL);
420 }
421
422 /* set or reset 'binary' */
423 if (eap != NULL && eap->force_bin != 0)
424 {
425 int oldval = curbuf->b_p_bin;
426
427 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
428 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
429 }
430
431 /*
432 * When opening a new file we take the readonly flag from the file.
433 * Default is r/w, can be set to r/o below.
434 * Don't reset it when in readonly mode
435 * Only set/reset b_p_ro when BF_CHECK_RO is set.
436 */
437 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000438 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 curbuf->b_p_ro = FALSE;
440
441 if (newfile && !read_stdin && !read_buffer)
442 {
443 /* Remember time of file.
444 * For RISCOS, also remember the filetype.
445 */
446 if (mch_stat((char *)fname, &st) >= 0)
447 {
448 buf_store_time(curbuf, &st, fname);
449 curbuf->b_mtime_read = curbuf->b_mtime;
450
451#if defined(RISCOS) && defined(FEAT_OSFILETYPE)
452 /* Read the filetype into the buffer local filetype option. */
453 mch_read_filetype(fname);
454#endif
455#ifdef UNIX
456 /*
457 * Use the protection bits of the original file for the swap file.
458 * This makes it possible for others to read the name of the
459 * edited file from the swapfile, but only if they can read the
460 * edited file.
461 * Remove the "write" and "execute" bits for group and others
462 * (they must not write the swapfile).
463 * Add the "read" and "write" bits for the user, otherwise we may
464 * not be able to write to the file ourselves.
465 * Setting the bits is done below, after creating the swap file.
466 */
467 swap_mode = (st.st_mode & 0644) | 0600;
468#endif
469#ifdef FEAT_CW_EDITOR
470 /* Get the FSSpec on MacOS
471 * TODO: Update it properly when the buffer name changes
472 */
473 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
474#endif
475#ifdef VMS
476 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000477 curbuf->b_fab_rat = st.st_fab_rat;
478 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479#endif
480 }
481 else
482 {
483 curbuf->b_mtime = 0;
484 curbuf->b_mtime_read = 0;
485 curbuf->b_orig_size = 0;
486 curbuf->b_orig_mode = 0;
487 }
488
489 /* Reset the "new file" flag. It will be set again below when the
490 * file doesn't exist. */
491 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
492 }
493
494/*
495 * for UNIX: check readonly with perm and mch_access()
496 * for RISCOS: same as Unix, otherwise file gets re-datestamped!
497 * for MSDOS and Amiga: check readonly by trying to open the file for writing
498 */
499 file_readonly = FALSE;
500 if (read_stdin)
501 {
502#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
503 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
504 setmode(0, O_BINARY);
505#endif
506 }
507 else if (!read_buffer)
508 {
509#ifdef USE_MCH_ACCESS
510 if (
511# ifdef UNIX
512 !(perm & 0222) ||
513# endif
514 mch_access((char *)fname, W_OK))
515 file_readonly = TRUE;
516 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
517#else
518 if (!newfile
519 || readonlymode
520 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
521 {
522 file_readonly = TRUE;
523 /* try to open ro */
524 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
525 }
526#endif
527 }
528
529 if (fd < 0) /* cannot open at all */
530 {
531#ifndef UNIX
532 int isdir_f;
533#endif
534 msg_scroll = msg_save;
535#ifndef UNIX
536 /*
537 * On MSDOS and Amiga we can't open a directory, check here.
538 */
539 isdir_f = (mch_isdir(fname));
540 perm = mch_getperm(fname); /* check if the file exists */
541 if (isdir_f)
542 {
543 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
544 curbuf->b_p_ro = TRUE; /* must use "w!" now */
545 }
546 else
547#endif
548 if (newfile)
549 {
550 if (perm < 0)
551 {
552 /*
553 * Set the 'new-file' flag, so that when the file has
554 * been created by someone else, a ":w" will complain.
555 */
556 curbuf->b_flags |= BF_NEW;
557
558 /* Create a swap file now, so that other Vims are warned
559 * that we are editing this file. Don't do this for a
560 * "nofile" or "nowrite" buffer type. */
561#ifdef FEAT_QUICKFIX
562 if (!bt_dontwrite(curbuf))
563#endif
564 check_need_swap(newfile);
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000565 if (dir_of_file_exists(fname))
566 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
567 else
568 filemess(curbuf, sfname,
569 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570#ifdef FEAT_VIMINFO
571 /* Even though this is a new file, it might have been
572 * edited before and deleted. Get the old marks. */
573 check_marks_read();
574#endif
575#ifdef FEAT_MBYTE
576 if (eap != NULL && eap->force_enc != 0)
577 {
578 /* set forced 'fileencoding' */
579 fenc = enc_canonize(eap->cmd + eap->force_enc);
580 if (fenc != NULL)
581 set_string_option_direct((char_u *)"fenc", -1,
582 fenc, OPT_FREE|OPT_LOCAL);
583 vim_free(fenc);
584 }
585#endif
586#ifdef FEAT_AUTOCMD
587 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
588 FALSE, curbuf, eap);
589#endif
590 /* remember the current fileformat */
591 save_file_ff(curbuf);
592
593#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
594 if (aborting()) /* autocmds may abort script processing */
595 return FAIL;
596#endif
597 return OK; /* a new file is not an error */
598 }
599 else
600 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000601 filemess(curbuf, sfname, (char_u *)(
602# ifdef EFBIG
603 (errno == EFBIG) ? _("[File too big]") :
604# endif
605 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 curbuf->b_p_ro = TRUE; /* must use "w!" now */
607 }
608 }
609
610 return FAIL;
611 }
612
613 /*
614 * Only set the 'ro' flag for readonly files the first time they are
615 * loaded. Help files always get readonly mode
616 */
617 if ((check_readonly && file_readonly) || curbuf->b_help)
618 curbuf->b_p_ro = TRUE;
619
620 if (newfile)
621 {
622 curbuf->b_p_eol = TRUE;
623 curbuf->b_start_eol = TRUE;
624#ifdef FEAT_MBYTE
625 curbuf->b_p_bomb = FALSE;
626#endif
627 }
628
629 /* Create a swap file now, so that other Vims are warned that we are
630 * editing this file.
631 * Don't do this for a "nofile" or "nowrite" buffer type. */
632#ifdef FEAT_QUICKFIX
633 if (!bt_dontwrite(curbuf))
634#endif
635 {
636 check_need_swap(newfile);
637#ifdef UNIX
638 /* Set swap file protection bits after creating it. */
639 if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
640 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
641#endif
642 }
643
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000644#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 /* If "Quit" selected at ATTENTION dialog, don't load the file */
646 if (swap_exists_action == SEA_QUIT)
647 {
648 if (!read_buffer && !read_stdin)
649 close(fd);
650 return FAIL;
651 }
652#endif
653
654 ++no_wait_return; /* don't wait for return yet */
655
656 /*
657 * Set '[ mark to the line above where the lines go (line 1 if zero).
658 */
659 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
660 curbuf->b_op_start.col = 0;
661
662#ifdef FEAT_AUTOCMD
663 if (!read_buffer)
664 {
665 int m = msg_scroll;
666 int n = msg_scrolled;
667 buf_T *old_curbuf = curbuf;
668
669 /*
670 * The file must be closed again, the autocommands may want to change
671 * the file before reading it.
672 */
673 if (!read_stdin)
674 close(fd); /* ignore errors */
675
676 /*
677 * The output from the autocommands should not overwrite anything and
678 * should not be overwritten: Set msg_scroll, restore its value if no
679 * output was done.
680 */
681 msg_scroll = TRUE;
682 if (filtering)
683 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
684 FALSE, curbuf, eap);
685 else if (read_stdin)
686 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
687 FALSE, curbuf, eap);
688 else if (newfile)
689 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
690 FALSE, curbuf, eap);
691 else
692 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
693 FALSE, NULL, eap);
694 if (msg_scrolled == n)
695 msg_scroll = m;
696
697#ifdef FEAT_EVAL
698 if (aborting()) /* autocmds may abort script processing */
699 {
700 --no_wait_return;
701 msg_scroll = msg_save;
702 curbuf->b_p_ro = TRUE; /* must use "w!" now */
703 return FAIL;
704 }
705#endif
706 /*
707 * Don't allow the autocommands to change the current buffer.
708 * Try to re-open the file.
709 */
710 if (!read_stdin && (curbuf != old_curbuf
711 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
712 {
713 --no_wait_return;
714 msg_scroll = msg_save;
715 if (fd < 0)
716 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
717 else
718 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
719 curbuf->b_p_ro = TRUE; /* must use "w!" now */
720 return FAIL;
721 }
722 }
723#endif /* FEAT_AUTOCMD */
724
725 /* Autocommands may add lines to the file, need to check if it is empty */
726 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
727
728 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
729 {
730 /*
731 * Show the user that we are busy reading the input. Sometimes this
732 * may take a while. When reading from stdin another program may
733 * still be running, don't move the cursor to the last line, unless
734 * always using the GUI.
735 */
736 if (read_stdin)
737 {
738#ifndef ALWAYS_USE_GUI
739 mch_msg(_("Vim: Reading from stdin...\n"));
740#endif
741#ifdef FEAT_GUI
742 /* Also write a message in the GUI window, if there is one. */
743 if (gui.in_use && !gui.dying && !gui.starting)
744 {
745 p = (char_u *)_("Reading from stdin...");
746 gui_write(p, (int)STRLEN(p));
747 }
748#endif
749 }
750 else if (!read_buffer)
751 filemess(curbuf, sfname, (char_u *)"", 0);
752 }
753
754 msg_scroll = FALSE; /* overwrite the file message */
755
756 /*
757 * Set linecnt now, before the "retry" caused by a wrong guess for
758 * fileformat, and after the autocommands, which may change them.
759 */
760 linecnt = curbuf->b_ml.ml_line_count;
761
762#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000763 /* "++bad=" argument. */
764 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000765 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000766 bad_char_behavior = eap->bad_char;
Bram Moolenaar195d6352005-12-19 22:08:24 +0000767 if (newfile)
768 curbuf->b_bad_char = eap->bad_char;
769 }
770 else
771 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000772
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000774 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 */
776 if (eap != NULL && eap->force_enc != 0)
777 {
778 fenc = enc_canonize(eap->cmd + eap->force_enc);
779 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000780 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 }
782 else if (curbuf->b_p_bin)
783 {
784 fenc = (char_u *)""; /* binary: don't convert */
785 fenc_alloced = FALSE;
786 }
787 else if (curbuf->b_help)
788 {
789 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000790 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791
792 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
793 * fails it must be latin1.
794 * Always do this when 'encoding' is "utf-8". Otherwise only do
795 * this when needed to avoid [converted] remarks all the time.
796 * It is needed when the first line contains non-ASCII characters.
797 * That is only in *.??x files. */
798 fenc = (char_u *)"latin1";
799 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000800 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000802 fc = fname[STRLEN(fname) - 1];
803 if (TOLOWER_ASC(fc) == 'x')
804 {
805 /* Read the first line (and a bit more). Immediately rewind to
806 * the start of the file. If the read() fails "len" is -1. */
807 len = vim_read(fd, firstline, 80);
808 lseek(fd, (off_t)0L, SEEK_SET);
809 for (p = firstline; p < firstline + len; ++p)
810 if (*p >= 0x80)
811 {
812 c = TRUE;
813 break;
814 }
815 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816 }
817
818 if (c)
819 {
820 fenc_next = fenc;
821 fenc = (char_u *)"utf-8";
822
823 /* When the file is utf-8 but a character doesn't fit in
824 * 'encoding' don't retry. In help text editing utf-8 bytes
825 * doesn't make sense. */
826 keep_dest_enc = TRUE;
827 }
828 fenc_alloced = FALSE;
829 }
830 else if (*p_fencs == NUL)
831 {
832 fenc = curbuf->b_p_fenc; /* use format from buffer */
833 fenc_alloced = FALSE;
834 }
835 else
836 {
837 fenc_next = p_fencs; /* try items in 'fileencodings' */
838 fenc = next_fenc(&fenc_next);
839 fenc_alloced = TRUE;
840 }
841#endif
842
843 /*
844 * Jump back here to retry reading the file in different ways.
845 * Reasons to retry:
846 * - encoding conversion failed: try another one from "fenc_next"
847 * - BOM detected and fenc was set, need to setup conversion
848 * - "fileformat" check failed: try another
849 *
850 * Variables set for special retry actions:
851 * "file_rewind" Rewind the file to start reading it again.
852 * "advance_fenc" Advance "fenc" using "fenc_next".
853 * "skip_read" Re-use already read bytes (BOM detected).
854 * "did_iconv" iconv() conversion failed, try 'charconvert'.
855 * "keep_fileformat" Don't reset "fileformat".
856 *
857 * Other status indicators:
858 * "tmpname" When != NULL did conversion with 'charconvert'.
859 * Output file has to be deleted afterwards.
860 * "iconv_fd" When != -1 did conversion with iconv().
861 */
862retry:
863
864 if (file_rewind)
865 {
866 if (read_buffer)
867 {
868 read_buf_lnum = 1;
869 read_buf_col = 0;
870 }
871 else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0)
872 {
873 /* Can't rewind the file, give up. */
874 error = TRUE;
875 goto failed;
876 }
877 /* Delete the previously read lines. */
878 while (lnum > from)
879 ml_delete(lnum--, FALSE);
880 file_rewind = FALSE;
881#ifdef FEAT_MBYTE
882 if (newfile)
883 curbuf->b_p_bomb = FALSE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000884 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885#endif
886 }
887
888 /*
889 * When retrying with another "fenc" and the first time "fileformat"
890 * will be reset.
891 */
892 if (keep_fileformat)
893 keep_fileformat = FALSE;
894 else
895 {
896 if (eap != NULL && eap->force_ff != 0)
897 fileformat = get_fileformat_force(curbuf, eap);
898 else if (curbuf->b_p_bin)
899 fileformat = EOL_UNIX; /* binary: use Unix format */
900 else if (*p_ffs == NUL)
901 fileformat = get_fileformat(curbuf);/* use format from buffer */
902 else
903 fileformat = EOL_UNKNOWN; /* detect from file */
904 }
905
906#ifdef FEAT_MBYTE
907# ifdef USE_ICONV
908 if (iconv_fd != (iconv_t)-1)
909 {
910 /* aborted conversion with iconv(), close the descriptor */
911 iconv_close(iconv_fd);
912 iconv_fd = (iconv_t)-1;
913 }
914# endif
915
916 if (advance_fenc)
917 {
918 /*
919 * Try the next entry in 'fileencodings'.
920 */
921 advance_fenc = FALSE;
922
923 if (eap != NULL && eap->force_enc != 0)
924 {
925 /* Conversion given with "++cc=" wasn't possible, read
926 * without conversion. */
927 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000928 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000929 if (fenc_alloced)
930 vim_free(fenc);
931 fenc = (char_u *)"";
932 fenc_alloced = FALSE;
933 }
934 else
935 {
936 if (fenc_alloced)
937 vim_free(fenc);
938 if (fenc_next != NULL)
939 {
940 fenc = next_fenc(&fenc_next);
941 fenc_alloced = (fenc_next != NULL);
942 }
943 else
944 {
945 fenc = (char_u *)"";
946 fenc_alloced = FALSE;
947 }
948 }
949 if (tmpname != NULL)
950 {
951 mch_remove(tmpname); /* delete converted file */
952 vim_free(tmpname);
953 tmpname = NULL;
954 }
955 }
956
957 /*
958 * Conversion is required when the encoding of the file is different
959 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4 (requires
960 * conversion to UTF-8).
961 */
962 fio_flags = 0;
963 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
964 if (converted || enc_unicode != 0)
965 {
966
967 /* "ucs-bom" means we need to check the first bytes of the file
968 * for a BOM. */
969 if (STRCMP(fenc, ENC_UCSBOM) == 0)
970 fio_flags = FIO_UCSBOM;
971
972 /*
973 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
974 * done. This is handled below after read(). Prepare the
975 * fio_flags to avoid having to parse the string each time.
976 * Also check for Unicode to Latin1 conversion, because iconv()
977 * appears not to handle this correctly. This works just like
978 * conversion to UTF-8 except how the resulting character is put in
979 * the buffer.
980 */
981 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
982 fio_flags = get_fio_flags(fenc);
983
984# ifdef WIN3264
985 /*
986 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
987 * is handled with MultiByteToWideChar().
988 */
989 if (fio_flags == 0)
990 fio_flags = get_win_fio_flags(fenc);
991# endif
992
993# ifdef MACOS_X
994 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
995 if (fio_flags == 0)
996 fio_flags = get_mac_fio_flags(fenc);
997# endif
998
999# ifdef USE_ICONV
1000 /*
1001 * Try using iconv() if we can't convert internally.
1002 */
1003 if (fio_flags == 0
1004# ifdef FEAT_EVAL
1005 && !did_iconv
1006# endif
1007 )
1008 iconv_fd = (iconv_t)my_iconv_open(
1009 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
1010# endif
1011
1012# ifdef FEAT_EVAL
1013 /*
1014 * Use the 'charconvert' expression when conversion is required
1015 * and we can't do it internally or with iconv().
1016 */
1017 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
1018# ifdef USE_ICONV
1019 && iconv_fd == (iconv_t)-1
1020# endif
1021 )
1022 {
1023# ifdef USE_ICONV
1024 did_iconv = FALSE;
1025# endif
1026 /* Skip conversion when it's already done (retry for wrong
1027 * "fileformat"). */
1028 if (tmpname == NULL)
1029 {
1030 tmpname = readfile_charconvert(fname, fenc, &fd);
1031 if (tmpname == NULL)
1032 {
1033 /* Conversion failed. Try another one. */
1034 advance_fenc = TRUE;
1035 if (fd < 0)
1036 {
1037 /* Re-opening the original file failed! */
1038 EMSG(_("E202: Conversion made file unreadable!"));
1039 error = TRUE;
1040 goto failed;
1041 }
1042 goto retry;
1043 }
1044 }
1045 }
1046 else
1047# endif
1048 {
1049 if (fio_flags == 0
1050# ifdef USE_ICONV
1051 && iconv_fd == (iconv_t)-1
1052# endif
1053 )
1054 {
1055 /* Conversion wanted but we can't.
1056 * Try the next conversion in 'fileencodings' */
1057 advance_fenc = TRUE;
1058 goto retry;
1059 }
1060 }
1061 }
1062
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001063 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001065 * stdin or fixed at a specific encoding. */
1066 can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067#endif
1068
1069 if (!skip_read)
1070 {
1071 linerest = 0;
1072 filesize = 0;
1073 skip_count = lines_to_skip;
1074 read_count = lines_to_read;
1075#ifdef FEAT_MBYTE
1076 conv_restlen = 0;
1077#endif
1078 }
1079
1080 while (!error && !got_int)
1081 {
1082 /*
1083 * We allocate as much space for the file as we can get, plus
1084 * space for the old line plus room for one terminating NUL.
1085 * The amount is limited by the fact that read() only can read
1086 * upto max_unsigned characters (and other things).
1087 */
1088#if SIZEOF_INT <= 2
1089 if (linerest >= 0x7ff0)
1090 {
1091 ++split;
1092 *ptr = NL; /* split line by inserting a NL */
1093 size = 1;
1094 }
1095 else
1096#endif
1097 {
1098 if (!skip_read)
1099 {
1100#if SIZEOF_INT > 2
1101# ifdef __TANDEM
1102 size = SSIZE_MAX; /* use max I/O size, 52K */
1103# else
1104 size = 0x10000L; /* use buffer >= 64K */
1105# endif
1106#else
1107 size = 0x7ff0L - linerest; /* limit buffer to 32K */
1108#endif
1109
1110 for ( ; size >= 10; size = (long_u)size >> 1)
1111 {
1112 if ((new_buffer = lalloc((long_u)(size + linerest + 1),
1113 FALSE)) != NULL)
1114 break;
1115 }
1116 if (new_buffer == NULL)
1117 {
1118 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1119 error = TRUE;
1120 break;
1121 }
1122 if (linerest) /* copy characters from the previous buffer */
1123 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1124 vim_free(buffer);
1125 buffer = new_buffer;
1126 ptr = buffer + linerest;
1127 line_start = buffer;
1128
1129#ifdef FEAT_MBYTE
1130 /* May need room to translate into.
1131 * For iconv() we don't really know the required space, use a
1132 * factor ICONV_MULT.
1133 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1134 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1135 * become up to 4 bytes, size must be multiple of 2
1136 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1137 * multiple of 2
1138 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1139 * multiple of 4 */
1140 real_size = size;
1141# ifdef USE_ICONV
1142 if (iconv_fd != (iconv_t)-1)
1143 size = size / ICONV_MULT;
1144 else
1145# endif
1146 if (fio_flags & FIO_LATIN1)
1147 size = size / 2;
1148 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1149 size = (size * 2 / 3) & ~1;
1150 else if (fio_flags & FIO_UCS4)
1151 size = (size * 2 / 3) & ~3;
1152 else if (fio_flags == FIO_UCSBOM)
1153 size = size / ICONV_MULT; /* worst case */
1154# ifdef WIN3264
1155 else if (fio_flags & FIO_CODEPAGE)
1156 size = size / ICONV_MULT; /* also worst case */
1157# endif
1158# ifdef MACOS_X
1159 else if (fio_flags & FIO_MACROMAN)
1160 size = size / ICONV_MULT; /* also worst case */
1161# endif
1162#endif
1163
1164#ifdef FEAT_MBYTE
1165 if (conv_restlen > 0)
1166 {
1167 /* Insert unconverted bytes from previous line. */
1168 mch_memmove(ptr, conv_rest, conv_restlen);
1169 ptr += conv_restlen;
1170 size -= conv_restlen;
1171 }
1172#endif
1173
1174 if (read_buffer)
1175 {
1176 /*
1177 * Read bytes from curbuf. Used for converting text read
1178 * from stdin.
1179 */
1180 if (read_buf_lnum > from)
1181 size = 0;
1182 else
1183 {
1184 int n, ni;
1185 long tlen;
1186
1187 tlen = 0;
1188 for (;;)
1189 {
1190 p = ml_get(read_buf_lnum) + read_buf_col;
1191 n = (int)STRLEN(p);
1192 if ((int)tlen + n + 1 > size)
1193 {
1194 /* Filled up to "size", append partial line.
1195 * Change NL to NUL to reverse the effect done
1196 * below. */
1197 n = size - tlen;
1198 for (ni = 0; ni < n; ++ni)
1199 {
1200 if (p[ni] == NL)
1201 ptr[tlen++] = NUL;
1202 else
1203 ptr[tlen++] = p[ni];
1204 }
1205 read_buf_col += n;
1206 break;
1207 }
1208 else
1209 {
1210 /* Append whole line and new-line. Change NL
1211 * to NUL to reverse the effect done below. */
1212 for (ni = 0; ni < n; ++ni)
1213 {
1214 if (p[ni] == NL)
1215 ptr[tlen++] = NUL;
1216 else
1217 ptr[tlen++] = p[ni];
1218 }
1219 ptr[tlen++] = NL;
1220 read_buf_col = 0;
1221 if (++read_buf_lnum > from)
1222 {
1223 /* When the last line didn't have an
1224 * end-of-line don't add it now either. */
1225 if (!curbuf->b_p_eol)
1226 --tlen;
1227 size = tlen;
1228 break;
1229 }
1230 }
1231 }
1232 }
1233 }
1234 else
1235 {
1236 /*
1237 * Read bytes from the file.
1238 */
1239 size = vim_read(fd, ptr, size);
1240 }
1241
1242 if (size <= 0)
1243 {
1244 if (size < 0) /* read error */
1245 error = TRUE;
1246#ifdef FEAT_MBYTE
1247 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001248 {
1249 /* Reached end-of-file but some trailing bytes could
1250 * not be converted. Trucated file? */
1251 if (conv_error == 0)
1252 conv_error = linecnt;
1253 if (bad_char_behavior != BAD_DROP)
1254 {
1255 fio_flags = 0; /* don't convert this */
1256 if (bad_char_behavior == BAD_KEEP)
1257 {
1258 /* Keep the trailing bytes as-is. */
1259 size = conv_restlen;
1260 ptr -= conv_restlen;
1261 }
1262 else
1263 {
1264 /* Replace the trailing bytes with the
1265 * replacement character. */
1266 size = 1;
1267 *--ptr = bad_char_behavior;
1268 }
1269 conv_restlen = 0;
1270 }
1271 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272#endif
1273 }
1274
1275#ifdef FEAT_CRYPT
1276 /*
1277 * At start of file: Check for magic number of encryption.
1278 */
1279 if (filesize == 0)
1280 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1281 &filesize, newfile);
1282 /*
1283 * Decrypt the read bytes.
1284 */
1285 if (cryptkey != NULL && size > 0)
1286 for (p = ptr; p < ptr + size; ++p)
1287 ZDECODE(*p);
1288#endif
1289 }
1290 skip_read = FALSE;
1291
1292#ifdef FEAT_MBYTE
1293 /*
1294 * At start of file (or after crypt magic number): Check for BOM.
1295 * Also check for a BOM for other Unicode encodings, but not after
1296 * converting with 'charconvert' or when a BOM has already been
1297 * found.
1298 */
1299 if ((filesize == 0
1300# ifdef FEAT_CRYPT
1301 || (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
1302# endif
1303 )
1304 && (fio_flags == FIO_UCSBOM
1305 || (!curbuf->b_p_bomb
1306 && tmpname == NULL
1307 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1308 {
1309 char_u *ccname;
1310 int blen;
1311
1312 /* no BOM detection in a short file or in binary mode */
1313 if (size < 2 || curbuf->b_p_bin)
1314 ccname = NULL;
1315 else
1316 ccname = check_for_bom(ptr, size, &blen,
1317 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1318 if (ccname != NULL)
1319 {
1320 /* Remove BOM from the text */
1321 filesize += blen;
1322 size -= blen;
1323 mch_memmove(ptr, ptr + blen, (size_t)size);
1324 if (newfile)
1325 curbuf->b_p_bomb = TRUE;
1326 }
1327
1328 if (fio_flags == FIO_UCSBOM)
1329 {
1330 if (ccname == NULL)
1331 {
1332 /* No BOM detected: retry with next encoding. */
1333 advance_fenc = TRUE;
1334 }
1335 else
1336 {
1337 /* BOM detected: set "fenc" and jump back */
1338 if (fenc_alloced)
1339 vim_free(fenc);
1340 fenc = ccname;
1341 fenc_alloced = FALSE;
1342 }
1343 /* retry reading without getting new bytes or rewinding */
1344 skip_read = TRUE;
1345 goto retry;
1346 }
1347 }
1348#endif
1349 /*
1350 * Break here for a read error or end-of-file.
1351 */
1352 if (size <= 0)
1353 break;
1354
1355#ifdef FEAT_MBYTE
1356
1357 /* Include not converted bytes. */
1358 ptr -= conv_restlen;
1359 size += conv_restlen;
1360 conv_restlen = 0;
1361
1362# ifdef USE_ICONV
1363 if (iconv_fd != (iconv_t)-1)
1364 {
1365 /*
1366 * Attempt conversion of the read bytes to 'encoding' using
1367 * iconv().
1368 */
1369 const char *fromp;
1370 char *top;
1371 size_t from_size;
1372 size_t to_size;
1373
1374 fromp = (char *)ptr;
1375 from_size = size;
1376 ptr += size;
1377 top = (char *)ptr;
1378 to_size = real_size - size;
1379
1380 /*
1381 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001382 * another conversion. Except for when there is no
1383 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001385 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1386 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1388 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001389 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001390 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001391 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001392 if (conv_error == 0)
1393 conv_error = readfile_linenr(linecnt,
1394 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001395
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001396 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001397 ++fromp;
1398 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001399 if (bad_char_behavior == BAD_KEEP)
1400 {
1401 *top++ = *(fromp - 1);
1402 --to_size;
1403 }
1404 else if (bad_char_behavior != BAD_DROP)
1405 {
1406 *top++ = bad_char_behavior;
1407 --to_size;
1408 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001409 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001410
1411 if (from_size > 0)
1412 {
1413 /* Some remaining characters, keep them for the next
1414 * round. */
1415 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1416 conv_restlen = (int)from_size;
1417 }
1418
1419 /* move the linerest to before the converted characters */
1420 line_start = ptr - linerest;
1421 mch_memmove(line_start, buffer, (size_t)linerest);
1422 size = (long)((char_u *)top - ptr);
1423 }
1424# endif
1425
1426# ifdef WIN3264
1427 if (fio_flags & FIO_CODEPAGE)
1428 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001429 char_u *src, *dst;
1430 int u8c;
1431 WCHAR ucs2buf[3];
1432 int ucs2len;
1433 int codepage = FIO_GET_CP(fio_flags);
1434 int bytelen;
1435 int found_bad;
1436 char replstr[2];
1437
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438 /*
1439 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001440 * a codepage, using standard MS-Windows functions. This
1441 * requires two steps:
1442 * 1. convert from 'fileencoding' to ucs-2
1443 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001444 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001445 * Because there may be illegal bytes AND an incomplete byte
1446 * sequence at the end, we may have to do the conversion one
1447 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001450 /* Replacement string for WideCharToMultiByte(). */
1451 if (bad_char_behavior > 0)
1452 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001454 replstr[0] = '?';
1455 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456
1457 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001458 * Move the bytes to the end of the buffer, so that we have
1459 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001461 src = ptr + real_size - size;
1462 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001464 /*
1465 * Do the conversion.
1466 */
1467 dst = ptr;
1468 size = size;
1469 while (size > 0)
1470 {
1471 found_bad = FALSE;
1472
1473# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1474 if (codepage == CP_UTF8)
1475 {
1476 /* Handle CP_UTF8 input ourselves to be able to handle
1477 * trailing bytes properly.
1478 * Get one UTF-8 character from src. */
1479 bytelen = utf_ptr2len_len(src, size);
1480 if (bytelen > size)
1481 {
1482 /* Only got some bytes of a character. Normally
1483 * it's put in "conv_rest", but if it's too long
1484 * deal with it as if they were illegal bytes. */
1485 if (bytelen <= CONV_RESTLEN)
1486 break;
1487
1488 /* weird overlong byte sequence */
1489 bytelen = size;
1490 found_bad = TRUE;
1491 }
1492 else
1493 {
1494 u8c = utf_ptr2char(src);
Bram Moolenaar86e01082005-12-29 22:45:34 +00001495 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001496 found_bad = TRUE;
1497 ucs2buf[0] = u8c;
1498 ucs2len = 1;
1499 }
1500 }
1501 else
1502# endif
1503 {
1504 /* We don't know how long the byte sequence is, try
1505 * from one to three bytes. */
1506 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1507 ++bytelen)
1508 {
1509 ucs2len = MultiByteToWideChar(codepage,
1510 MB_ERR_INVALID_CHARS,
1511 (LPCSTR)src, bytelen,
1512 ucs2buf, 3);
1513 if (ucs2len > 0)
1514 break;
1515 }
1516 if (ucs2len == 0)
1517 {
1518 /* If we have only one byte then it's probably an
1519 * incomplete byte sequence. Otherwise discard
1520 * one byte as a bad character. */
1521 if (size == 1)
1522 break;
1523 found_bad = TRUE;
1524 bytelen = 1;
1525 }
1526 }
1527
1528 if (!found_bad)
1529 {
1530 int i;
1531
1532 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1533 if (enc_utf8)
1534 {
1535 /* From UCS-2 to UTF-8. Cannot fail. */
1536 for (i = 0; i < ucs2len; ++i)
1537 dst += utf_char2bytes(ucs2buf[i], dst);
1538 }
1539 else
1540 {
1541 BOOL bad = FALSE;
1542 int dstlen;
1543
1544 /* From UCS-2 to "enc_codepage". If the
1545 * conversion uses the default character "?",
1546 * the data doesn't fit in this encoding. */
1547 dstlen = WideCharToMultiByte(enc_codepage, 0,
1548 (LPCWSTR)ucs2buf, ucs2len,
1549 (LPSTR)dst, (src - dst),
1550 replstr, &bad);
1551 if (bad)
1552 found_bad = TRUE;
1553 else
1554 dst += dstlen;
1555 }
1556 }
1557
1558 if (found_bad)
1559 {
1560 /* Deal with bytes we can't convert. */
1561 if (can_retry)
1562 goto rewind_retry;
1563 if (conv_error == 0)
1564 conv_error = readfile_linenr(linecnt, ptr, dst);
1565 if (bad_char_behavior != BAD_DROP)
1566 {
1567 if (bad_char_behavior == BAD_KEEP)
1568 {
1569 mch_memmove(dst, src, bytelen);
1570 dst += bytelen;
1571 }
1572 else
1573 *dst++ = bad_char_behavior;
1574 }
1575 }
1576
1577 src += bytelen;
1578 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001580
1581 if (size > 0)
1582 {
1583 /* An incomplete byte sequence remaining. */
1584 mch_memmove(conv_rest, src, size);
1585 conv_restlen = size;
1586 }
1587
1588 /* The new size is equal to how much "dst" was advanced. */
1589 size = dst - ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 }
1591 else
1592# endif
1593# ifdef MACOS_X
1594 if (fio_flags & FIO_MACROMAN)
1595 {
1596 /*
1597 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001598 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001599 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001600 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 }
1603 else
1604# endif
1605 if (fio_flags != 0)
1606 {
1607 int u8c;
1608 char_u *dest;
1609 char_u *tail = NULL;
1610
1611 /*
1612 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1613 * "enc_utf8" not set: Convert Unicode to Latin1.
1614 * Go from end to start through the buffer, because the number
1615 * of bytes may increase.
1616 * "dest" points to after where the UTF-8 bytes go, "p" points
1617 * to after the next character to convert.
1618 */
1619 dest = ptr + real_size;
1620 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1621 {
1622 p = ptr + size;
1623 if (fio_flags == FIO_UTF8)
1624 {
1625 /* Check for a trailing incomplete UTF-8 sequence */
1626 tail = ptr + size - 1;
1627 while (tail > ptr && (*tail & 0xc0) == 0x80)
1628 --tail;
1629 if (tail + utf_byte2len(*tail) <= ptr + size)
1630 tail = NULL;
1631 else
1632 p = tail;
1633 }
1634 }
1635 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1636 {
1637 /* Check for a trailing byte */
1638 p = ptr + (size & ~1);
1639 if (size & 1)
1640 tail = p;
1641 if ((fio_flags & FIO_UTF16) && p > ptr)
1642 {
1643 /* Check for a trailing leading word */
1644 if (fio_flags & FIO_ENDIAN_L)
1645 {
1646 u8c = (*--p << 8);
1647 u8c += *--p;
1648 }
1649 else
1650 {
1651 u8c = *--p;
1652 u8c += (*--p << 8);
1653 }
1654 if (u8c >= 0xd800 && u8c <= 0xdbff)
1655 tail = p;
1656 else
1657 p += 2;
1658 }
1659 }
1660 else /* FIO_UCS4 */
1661 {
1662 /* Check for trailing 1, 2 or 3 bytes */
1663 p = ptr + (size & ~3);
1664 if (size & 3)
1665 tail = p;
1666 }
1667
1668 /* If there is a trailing incomplete sequence move it to
1669 * conv_rest[]. */
1670 if (tail != NULL)
1671 {
1672 conv_restlen = (int)((ptr + size) - tail);
1673 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1674 size -= conv_restlen;
1675 }
1676
1677
1678 while (p > ptr)
1679 {
1680 if (fio_flags & FIO_LATIN1)
1681 u8c = *--p;
1682 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1683 {
1684 if (fio_flags & FIO_ENDIAN_L)
1685 {
1686 u8c = (*--p << 8);
1687 u8c += *--p;
1688 }
1689 else
1690 {
1691 u8c = *--p;
1692 u8c += (*--p << 8);
1693 }
1694 if ((fio_flags & FIO_UTF16)
1695 && u8c >= 0xdc00 && u8c <= 0xdfff)
1696 {
1697 int u16c;
1698
1699 if (p == ptr)
1700 {
1701 /* Missing leading word. */
1702 if (can_retry)
1703 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001704 if (conv_error == 0)
1705 conv_error = readfile_linenr(linecnt,
1706 ptr, p);
1707 if (bad_char_behavior == BAD_DROP)
1708 continue;
1709 if (bad_char_behavior != BAD_KEEP)
1710 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 }
1712
1713 /* found second word of double-word, get the first
1714 * word and compute the resulting character */
1715 if (fio_flags & FIO_ENDIAN_L)
1716 {
1717 u16c = (*--p << 8);
1718 u16c += *--p;
1719 }
1720 else
1721 {
1722 u16c = *--p;
1723 u16c += (*--p << 8);
1724 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001725 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1726 + (u8c & 0x3ff);
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 /* Check if the word is indeed a leading word. */
1729 if (u16c < 0xd800 || u16c > 0xdbff)
1730 {
1731 if (can_retry)
1732 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001733 if (conv_error == 0)
1734 conv_error = readfile_linenr(linecnt,
1735 ptr, p);
1736 if (bad_char_behavior == BAD_DROP)
1737 continue;
1738 if (bad_char_behavior != BAD_KEEP)
1739 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 }
1742 }
1743 else if (fio_flags & FIO_UCS4)
1744 {
1745 if (fio_flags & FIO_ENDIAN_L)
1746 {
1747 u8c = (*--p << 24);
1748 u8c += (*--p << 16);
1749 u8c += (*--p << 8);
1750 u8c += *--p;
1751 }
1752 else /* big endian */
1753 {
1754 u8c = *--p;
1755 u8c += (*--p << 8);
1756 u8c += (*--p << 16);
1757 u8c += (*--p << 24);
1758 }
1759 }
1760 else /* UTF-8 */
1761 {
1762 if (*--p < 0x80)
1763 u8c = *p;
1764 else
1765 {
1766 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001767 p -= len;
1768 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769 if (len == 0)
1770 {
1771 /* Not a valid UTF-8 character, retry with
1772 * another fenc when possible, otherwise just
1773 * report the error. */
1774 if (can_retry)
1775 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001776 if (conv_error == 0)
1777 conv_error = readfile_linenr(linecnt,
1778 ptr, p);
1779 if (bad_char_behavior == BAD_DROP)
1780 continue;
1781 if (bad_char_behavior != BAD_KEEP)
1782 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784 }
1785 }
1786 if (enc_utf8) /* produce UTF-8 */
1787 {
1788 dest -= utf_char2len(u8c);
1789 (void)utf_char2bytes(u8c, dest);
1790 }
1791 else /* produce Latin1 */
1792 {
1793 --dest;
1794 if (u8c >= 0x100)
1795 {
1796 /* character doesn't fit in latin1, retry with
1797 * another fenc when possible, otherwise just
1798 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001799 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001801 if (conv_error == 0)
1802 conv_error = readfile_linenr(linecnt, ptr, p);
1803 if (bad_char_behavior == BAD_DROP)
1804 ++dest;
1805 else if (bad_char_behavior == BAD_KEEP)
1806 *dest = u8c;
1807 else if (eap != NULL && eap->bad_char != 0)
1808 *dest = bad_char_behavior;
1809 else
1810 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 }
1812 else
1813 *dest = u8c;
1814 }
1815 }
1816
1817 /* move the linerest to before the converted characters */
1818 line_start = dest - linerest;
1819 mch_memmove(line_start, buffer, (size_t)linerest);
1820 size = (long)((ptr + real_size) - dest);
1821 ptr = dest;
1822 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001823 else if (enc_utf8 && conv_error == 0 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 {
1825 /* Reading UTF-8: Check if the bytes are valid UTF-8.
1826 * Need to start before "ptr" when part of the character was
1827 * read in the previous read() call. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001828 for (p = ptr - utf_head_off(buffer, ptr); ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001830 int todo = (ptr + size) - p;
1831 int l;
1832
1833 if (todo <= 0)
1834 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835 if (*p >= 0x80)
1836 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 /* A length of 1 means it's an illegal byte. Accept
1838 * an incomplete character at the end though, the next
1839 * read() will get the next bytes, we'll check it
1840 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001841 l = utf_ptr2len_len(p, todo);
1842 if (l > todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001844 /* Incomplete byte sequence, the next read()
1845 * should get them and check the bytes. */
1846 p += todo;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 break;
1848 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001849 if (l == 1)
1850 {
1851 /* Illegal byte. If we can try another encoding
1852 * do that. */
1853 if (can_retry)
1854 break;
1855
1856 /* Remember the first linenr with an illegal byte */
1857 if (illegal_byte == 0)
1858 illegal_byte = readfile_linenr(linecnt, ptr, p);
1859# ifdef USE_ICONV
1860 /* When we did a conversion report an error. */
1861 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
1862 conv_error = readfile_linenr(linecnt, ptr, p);
1863# endif
1864
1865 /* Drop, keep or replace the bad byte. */
1866 if (bad_char_behavior == BAD_DROP)
1867 {
1868 mch_memmove(p, p+1, todo - 1);
1869 --p;
1870 --size;
1871 }
1872 else if (bad_char_behavior != BAD_KEEP)
1873 *p = bad_char_behavior;
1874 }
1875 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 }
1877 }
1878 if (p < ptr + size)
1879 {
1880 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001882 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001884 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
1885 /* iconv() failed, try 'charconvert' */
1886 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 else
1888# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001889 /* use next item from 'fileencodings' */
1890 advance_fenc = TRUE;
1891 file_rewind = TRUE;
1892 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 }
1894 }
1895#endif
1896
1897 /* count the number of characters (after conversion!) */
1898 filesize += size;
1899
1900 /*
1901 * when reading the first part of a file: guess EOL type
1902 */
1903 if (fileformat == EOL_UNKNOWN)
1904 {
1905 /* First try finding a NL, for Dos and Unix */
1906 if (try_dos || try_unix)
1907 {
1908 for (p = ptr; p < ptr + size; ++p)
1909 {
1910 if (*p == NL)
1911 {
1912 if (!try_unix
1913 || (try_dos && p > ptr && p[-1] == CAR))
1914 fileformat = EOL_DOS;
1915 else
1916 fileformat = EOL_UNIX;
1917 break;
1918 }
1919 }
1920
1921 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
1922 if (fileformat == EOL_UNIX && try_mac)
1923 {
1924 /* Need to reset the counters when retrying fenc. */
1925 try_mac = 1;
1926 try_unix = 1;
1927 for (; p >= ptr && *p != CAR; p--)
1928 ;
1929 if (p >= ptr)
1930 {
1931 for (p = ptr; p < ptr + size; ++p)
1932 {
1933 if (*p == NL)
1934 try_unix++;
1935 else if (*p == CAR)
1936 try_mac++;
1937 }
1938 if (try_mac > try_unix)
1939 fileformat = EOL_MAC;
1940 }
1941 }
1942 }
1943
1944 /* No NL found: may use Mac format */
1945 if (fileformat == EOL_UNKNOWN && try_mac)
1946 fileformat = EOL_MAC;
1947
1948 /* Still nothing found? Use first format in 'ffs' */
1949 if (fileformat == EOL_UNKNOWN)
1950 fileformat = default_fileformat();
1951
1952 /* if editing a new file: may set p_tx and p_ff */
1953 if (newfile)
1954 set_fileformat(fileformat, OPT_LOCAL);
1955 }
1956 }
1957
1958 /*
1959 * This loop is executed once for every character read.
1960 * Keep it fast!
1961 */
1962 if (fileformat == EOL_MAC)
1963 {
1964 --ptr;
1965 while (++ptr, --size >= 0)
1966 {
1967 /* catch most common case first */
1968 if ((c = *ptr) != NUL && c != CAR && c != NL)
1969 continue;
1970 if (c == NUL)
1971 *ptr = NL; /* NULs are replaced by newlines! */
1972 else if (c == NL)
1973 *ptr = CAR; /* NLs are replaced by CRs! */
1974 else
1975 {
1976 if (skip_count == 0)
1977 {
1978 *ptr = NUL; /* end of line */
1979 len = (colnr_T) (ptr - line_start + 1);
1980 if (ml_append(lnum, line_start, len, newfile) == FAIL)
1981 {
1982 error = TRUE;
1983 break;
1984 }
1985 ++lnum;
1986 if (--read_count == 0)
1987 {
1988 error = TRUE; /* break loop */
1989 line_start = ptr; /* nothing left to write */
1990 break;
1991 }
1992 }
1993 else
1994 --skip_count;
1995 line_start = ptr + 1;
1996 }
1997 }
1998 }
1999 else
2000 {
2001 --ptr;
2002 while (++ptr, --size >= 0)
2003 {
2004 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2005 continue;
2006 if (c == NUL)
2007 *ptr = NL; /* NULs are replaced by newlines! */
2008 else
2009 {
2010 if (skip_count == 0)
2011 {
2012 *ptr = NUL; /* end of line */
2013 len = (colnr_T)(ptr - line_start + 1);
2014 if (fileformat == EOL_DOS)
2015 {
2016 if (ptr[-1] == CAR) /* remove CR */
2017 {
2018 ptr[-1] = NUL;
2019 --len;
2020 }
2021 /*
2022 * Reading in Dos format, but no CR-LF found!
2023 * When 'fileformats' includes "unix", delete all
2024 * the lines read so far and start all over again.
2025 * Otherwise give an error message later.
2026 */
2027 else if (ff_error != EOL_DOS)
2028 {
2029 if ( try_unix
2030 && !read_stdin
2031 && (read_buffer
2032 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2033 {
2034 fileformat = EOL_UNIX;
2035 if (newfile)
2036 set_fileformat(EOL_UNIX, OPT_LOCAL);
2037 file_rewind = TRUE;
2038 keep_fileformat = TRUE;
2039 goto retry;
2040 }
2041 ff_error = EOL_DOS;
2042 }
2043 }
2044 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2045 {
2046 error = TRUE;
2047 break;
2048 }
2049 ++lnum;
2050 if (--read_count == 0)
2051 {
2052 error = TRUE; /* break loop */
2053 line_start = ptr; /* nothing left to write */
2054 break;
2055 }
2056 }
2057 else
2058 --skip_count;
2059 line_start = ptr + 1;
2060 }
2061 }
2062 }
2063 linerest = (long)(ptr - line_start);
2064 ui_breakcheck();
2065 }
2066
2067failed:
2068 /* not an error, max. number of lines reached */
2069 if (error && read_count == 0)
2070 error = FALSE;
2071
2072 /*
2073 * If we get EOF in the middle of a line, note the fact and
2074 * complete the line ourselves.
2075 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2076 */
2077 if (!error
2078 && !got_int
2079 && linerest != 0
2080 && !(!curbuf->b_p_bin
2081 && fileformat == EOL_DOS
2082 && *line_start == Ctrl_Z
2083 && ptr == line_start + 1))
2084 {
2085 if (newfile) /* remember for when writing */
2086 curbuf->b_p_eol = FALSE;
2087 *ptr = NUL;
2088 if (ml_append(lnum, line_start,
2089 (colnr_T)(ptr - line_start + 1), newfile) == FAIL)
2090 error = TRUE;
2091 else
2092 read_no_eol_lnum = ++lnum;
2093 }
2094
2095 if (newfile)
2096 save_file_ff(curbuf); /* remember the current file format */
2097
2098#ifdef FEAT_CRYPT
2099 if (cryptkey != curbuf->b_p_key)
2100 vim_free(cryptkey);
2101#endif
2102
2103#ifdef FEAT_MBYTE
2104 /* If editing a new file: set 'fenc' for the current buffer. */
2105 if (newfile)
2106 set_string_option_direct((char_u *)"fenc", -1, fenc,
2107 OPT_FREE|OPT_LOCAL);
2108 if (fenc_alloced)
2109 vim_free(fenc);
2110# ifdef USE_ICONV
2111 if (iconv_fd != (iconv_t)-1)
2112 {
2113 iconv_close(iconv_fd);
2114 iconv_fd = (iconv_t)-1;
2115 }
2116# endif
2117#endif
2118
2119 if (!read_buffer && !read_stdin)
2120 close(fd); /* errors are ignored */
2121 vim_free(buffer);
2122
2123#ifdef HAVE_DUP
2124 if (read_stdin)
2125 {
2126 /* Use stderr for stdin, makes shell commands work. */
2127 close(0);
2128 dup(2);
2129 }
2130#endif
2131
2132#ifdef FEAT_MBYTE
2133 if (tmpname != NULL)
2134 {
2135 mch_remove(tmpname); /* delete converted file */
2136 vim_free(tmpname);
2137 }
2138#endif
2139 --no_wait_return; /* may wait for return now */
2140
2141 /*
2142 * In recovery mode everything but autocommands is skipped.
2143 */
2144 if (!recoverymode)
2145 {
2146 /* need to delete the last line, which comes from the empty buffer */
2147 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2148 {
2149#ifdef FEAT_NETBEANS_INTG
2150 netbeansFireChanges = 0;
2151#endif
2152 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2153#ifdef FEAT_NETBEANS_INTG
2154 netbeansFireChanges = 1;
2155#endif
2156 --linecnt;
2157 }
2158 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2159 if (filesize == 0)
2160 linecnt = 0;
2161 if (newfile || read_buffer)
2162 redraw_curbuf_later(NOT_VALID);
2163 else if (linecnt) /* appended at least one line */
2164 appended_lines_mark(from, linecnt);
2165
2166#ifdef FEAT_DIFF
2167 /* After reading the text into the buffer the diff info needs to be
2168 * updated. */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002169 if (newfile || read_buffer)
2170 diff_invalidate(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171#endif
2172#ifndef ALWAYS_USE_GUI
2173 /*
2174 * If we were reading from the same terminal as where messages go,
2175 * the screen will have been messed up.
2176 * Switch on raw mode now and clear the screen.
2177 */
2178 if (read_stdin)
2179 {
2180 settmode(TMODE_RAW); /* set to raw mode */
2181 starttermcap();
2182 screenclear();
2183 }
2184#endif
2185
2186 if (got_int)
2187 {
2188 if (!(flags & READ_DUMMY))
2189 {
2190 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2191 if (newfile)
2192 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2193 }
2194 msg_scroll = msg_save;
2195#ifdef FEAT_VIMINFO
2196 check_marks_read();
2197#endif
2198 return OK; /* an interrupt isn't really an error */
2199 }
2200
2201 if (!filtering && !(flags & READ_DUMMY))
2202 {
2203 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2204 c = FALSE;
2205
2206#ifdef UNIX
2207# ifdef S_ISFIFO
2208 if (S_ISFIFO(perm)) /* fifo or socket */
2209 {
2210 STRCAT(IObuff, _("[fifo/socket]"));
2211 c = TRUE;
2212 }
2213# else
2214# ifdef S_IFIFO
2215 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2216 {
2217 STRCAT(IObuff, _("[fifo]"));
2218 c = TRUE;
2219 }
2220# endif
2221# ifdef S_IFSOCK
2222 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2223 {
2224 STRCAT(IObuff, _("[socket]"));
2225 c = TRUE;
2226 }
2227# endif
2228# endif
2229#endif
2230 if (curbuf->b_p_ro)
2231 {
2232 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2233 c = TRUE;
2234 }
2235 if (read_no_eol_lnum)
2236 {
2237 msg_add_eol();
2238 c = TRUE;
2239 }
2240 if (ff_error == EOL_DOS)
2241 {
2242 STRCAT(IObuff, _("[CR missing]"));
2243 c = TRUE;
2244 }
2245 if (ff_error == EOL_MAC)
2246 {
2247 STRCAT(IObuff, _("[NL found]"));
2248 c = TRUE;
2249 }
2250 if (split)
2251 {
2252 STRCAT(IObuff, _("[long lines split]"));
2253 c = TRUE;
2254 }
2255#ifdef FEAT_MBYTE
2256 if (notconverted)
2257 {
2258 STRCAT(IObuff, _("[NOT converted]"));
2259 c = TRUE;
2260 }
2261 else if (converted)
2262 {
2263 STRCAT(IObuff, _("[converted]"));
2264 c = TRUE;
2265 }
2266#endif
2267#ifdef FEAT_CRYPT
2268 if (cryptkey != NULL)
2269 {
2270 STRCAT(IObuff, _("[crypted]"));
2271 c = TRUE;
2272 }
2273#endif
2274#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002275 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002277 sprintf((char *)IObuff + STRLEN(IObuff),
2278 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 c = TRUE;
2280 }
2281 else if (illegal_byte > 0)
2282 {
2283 sprintf((char *)IObuff + STRLEN(IObuff),
2284 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2285 c = TRUE;
2286 }
2287 else
2288#endif
2289 if (error)
2290 {
2291 STRCAT(IObuff, _("[READ ERRORS]"));
2292 c = TRUE;
2293 }
2294 if (msg_add_fileformat(fileformat))
2295 c = TRUE;
2296#ifdef FEAT_CRYPT
2297 if (cryptkey != NULL)
2298 msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
2299 else
2300#endif
2301 msg_add_lines(c, (long)linecnt, filesize);
2302
2303 vim_free(keep_msg);
2304 keep_msg = NULL;
2305 msg_scrolled_ign = TRUE;
2306#ifdef ALWAYS_USE_GUI
2307 /* Don't show the message when reading stdin, it would end up in a
2308 * message box (which might be shown when exiting!) */
2309 if (read_stdin || read_buffer)
2310 p = msg_may_trunc(FALSE, IObuff);
2311 else
2312#endif
2313 p = msg_trunc_attr(IObuff, FALSE, 0);
2314 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002315 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 {
2317 /* Need to repeat the message after redrawing when:
2318 * - When reading from stdin (the screen will be cleared next).
2319 * - When restart_edit is set (otherwise there will be a delay
2320 * before redrawing).
2321 * - When the screen was scrolled but there is no wait-return
2322 * prompt. */
2323 set_keep_msg(p);
2324 keep_msg_attr = 0;
2325 }
2326 msg_scrolled_ign = FALSE;
2327 }
2328
2329 /* with errors writing the file requires ":w!" */
2330 if (newfile && (error
2331#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002332 || conv_error != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333#endif
2334 ))
2335 curbuf->b_p_ro = TRUE;
2336
2337 u_clearline(); /* cannot use "U" command after adding lines */
2338
2339 /*
2340 * In Ex mode: cursor at last new line.
2341 * Otherwise: cursor at first new line.
2342 */
2343 if (exmode_active)
2344 curwin->w_cursor.lnum = from + linecnt;
2345 else
2346 curwin->w_cursor.lnum = from + 1;
2347 check_cursor_lnum();
2348 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2349
2350 /*
2351 * Set '[ and '] marks to the newly read lines.
2352 */
2353 curbuf->b_op_start.lnum = from + 1;
2354 curbuf->b_op_start.col = 0;
2355 curbuf->b_op_end.lnum = from + linecnt;
2356 curbuf->b_op_end.col = 0;
2357 }
2358 msg_scroll = msg_save;
2359
2360#ifdef FEAT_VIMINFO
2361 /*
2362 * Get the marks before executing autocommands, so they can be used there.
2363 */
2364 check_marks_read();
2365#endif
2366
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 /*
2368 * Trick: We remember if the last line of the read didn't have
2369 * an eol for when writing it again. This is required for
2370 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2371 */
2372 write_no_eol_lnum = read_no_eol_lnum;
2373
Bram Moolenaardf177f62005-02-22 08:39:57 +00002374#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 if (!read_stdin && !read_buffer)
2376 {
2377 int m = msg_scroll;
2378 int n = msg_scrolled;
2379
2380 /* Save the fileformat now, otherwise the buffer will be considered
2381 * modified if the format/encoding was automatically detected. */
2382 if (newfile)
2383 save_file_ff(curbuf);
2384
2385 /*
2386 * The output from the autocommands should not overwrite anything and
2387 * should not be overwritten: Set msg_scroll, restore its value if no
2388 * output was done.
2389 */
2390 msg_scroll = TRUE;
2391 if (filtering)
2392 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2393 FALSE, curbuf, eap);
2394 else if (newfile)
2395 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2396 FALSE, curbuf, eap);
2397 else
2398 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2399 FALSE, NULL, eap);
2400 if (msg_scrolled == n)
2401 msg_scroll = m;
2402#ifdef FEAT_EVAL
2403 if (aborting()) /* autocmds may abort script processing */
2404 return FAIL;
2405#endif
2406 }
2407#endif
2408
2409 if (recoverymode && error)
2410 return FAIL;
2411 return OK;
2412}
2413
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002414#ifdef FEAT_MBYTE
2415
2416/*
2417 * From the current line count and characters read after that, estimate the
2418 * line number where we are now.
2419 * Used for error messages that include a line number.
2420 */
2421 static linenr_T
2422readfile_linenr(linecnt, p, endp)
2423 linenr_T linecnt; /* line count before reading more bytes */
2424 char_u *p; /* start of more bytes read */
2425 char_u *endp; /* end of more bytes read */
2426{
2427 char_u *s;
2428 linenr_T lnum;
2429
2430 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2431 for (s = p; s < endp; ++s)
2432 if (*s == '\n')
2433 ++lnum;
2434 return lnum;
2435}
2436#endif
2437
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002439 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2440 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 * Returns OK or FAIL.
2442 */
2443 int
2444prep_exarg(eap, buf)
2445 exarg_T *eap;
2446 buf_T *buf;
2447{
2448 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2449#ifdef FEAT_MBYTE
2450 + STRLEN(buf->b_p_fenc)
2451#endif
2452 + 15));
2453 if (eap->cmd == NULL)
2454 return FAIL;
2455
2456#ifdef FEAT_MBYTE
2457 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2458 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002459 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460#else
2461 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2462#endif
2463 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002464
2465 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
2466 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 return OK;
2468}
2469
2470#ifdef FEAT_MBYTE
2471/*
2472 * Find next fileencoding to use from 'fileencodings'.
2473 * "pp" points to fenc_next. It's advanced to the next item.
2474 * When there are no more items, an empty string is returned and *pp is set to
2475 * NULL.
2476 * When *pp is not set to NULL, the result is in allocated memory.
2477 */
2478 static char_u *
2479next_fenc(pp)
2480 char_u **pp;
2481{
2482 char_u *p;
2483 char_u *r;
2484
2485 if (**pp == NUL)
2486 {
2487 *pp = NULL;
2488 return (char_u *)"";
2489 }
2490 p = vim_strchr(*pp, ',');
2491 if (p == NULL)
2492 {
2493 r = enc_canonize(*pp);
2494 *pp += STRLEN(*pp);
2495 }
2496 else
2497 {
2498 r = vim_strnsave(*pp, (int)(p - *pp));
2499 *pp = p + 1;
2500 if (r != NULL)
2501 {
2502 p = enc_canonize(r);
2503 vim_free(r);
2504 r = p;
2505 }
2506 }
2507 if (r == NULL) /* out of memory */
2508 {
2509 r = (char_u *)"";
2510 *pp = NULL;
2511 }
2512 return r;
2513}
2514
2515# ifdef FEAT_EVAL
2516/*
2517 * Convert a file with the 'charconvert' expression.
2518 * This closes the file which is to be read, converts it and opens the
2519 * resulting file for reading.
2520 * Returns name of the resulting converted file (the caller should delete it
2521 * after reading it).
2522 * Returns NULL if the conversion failed ("*fdp" is not set) .
2523 */
2524 static char_u *
2525readfile_charconvert(fname, fenc, fdp)
2526 char_u *fname; /* name of input file */
2527 char_u *fenc; /* converted from */
2528 int *fdp; /* in/out: file descriptor of file */
2529{
2530 char_u *tmpname;
2531 char_u *errmsg = NULL;
2532
2533 tmpname = vim_tempname('r');
2534 if (tmpname == NULL)
2535 errmsg = (char_u *)_("Can't find temp file for conversion");
2536 else
2537 {
2538 close(*fdp); /* close the input file, ignore errors */
2539 *fdp = -1;
2540 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2541 fname, tmpname) == FAIL)
2542 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2543 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2544 O_RDONLY | O_EXTRA, 0)) < 0)
2545 errmsg = (char_u *)_("can't read output of 'charconvert'");
2546 }
2547
2548 if (errmsg != NULL)
2549 {
2550 /* Don't use emsg(), it breaks mappings, the retry with
2551 * another type of conversion might still work. */
2552 MSG(errmsg);
2553 if (tmpname != NULL)
2554 {
2555 mch_remove(tmpname); /* delete converted file */
2556 vim_free(tmpname);
2557 tmpname = NULL;
2558 }
2559 }
2560
2561 /* If the input file is closed, open it (caller should check for error). */
2562 if (*fdp < 0)
2563 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2564
2565 return tmpname;
2566}
2567# endif
2568
2569#endif
2570
2571#ifdef FEAT_VIMINFO
2572/*
2573 * Read marks for the current buffer from the viminfo file, when we support
2574 * buffer marks and the buffer has a name.
2575 */
2576 static void
2577check_marks_read()
2578{
2579 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2580 && curbuf->b_ffname != NULL)
2581 read_viminfo(NULL, FALSE, TRUE, FALSE);
2582
2583 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2584 * the ' parameter after opening a buffer. */
2585 curbuf->b_marks_read = TRUE;
2586}
2587#endif
2588
2589#ifdef FEAT_CRYPT
2590/*
2591 * Check for magic number used for encryption.
2592 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2593 * *filesizep are updated.
2594 * Return the (new) encryption key, NULL for no encryption.
2595 */
2596 static char_u *
2597check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile)
2598 char_u *cryptkey; /* previous encryption key or NULL */
2599 char_u *ptr; /* pointer to read bytes */
2600 long *sizep; /* length of read bytes */
2601 long *filesizep; /* nr of bytes used from file */
2602 int newfile; /* editing a new buffer */
2603{
2604 if (*sizep >= CRYPT_MAGIC_LEN
2605 && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
2606 {
2607 if (cryptkey == NULL)
2608 {
2609 if (*curbuf->b_p_key)
2610 cryptkey = curbuf->b_p_key;
2611 else
2612 {
2613 /* When newfile is TRUE, store the typed key
2614 * in the 'key' option and don't free it. */
2615 cryptkey = get_crypt_key(newfile, FALSE);
2616 /* check if empty key entered */
2617 if (cryptkey != NULL && *cryptkey == NUL)
2618 {
2619 if (cryptkey != curbuf->b_p_key)
2620 vim_free(cryptkey);
2621 cryptkey = NULL;
2622 }
2623 }
2624 }
2625
2626 if (cryptkey != NULL)
2627 {
2628 crypt_init_keys(cryptkey);
2629
2630 /* Remove magic number from the text */
2631 *filesizep += CRYPT_MAGIC_LEN;
2632 *sizep -= CRYPT_MAGIC_LEN;
2633 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
2634 }
2635 }
2636 /* When starting to edit a new file which does not have
2637 * encryption, clear the 'key' option, except when
2638 * starting up (called with -x argument) */
2639 else if (newfile && *curbuf->b_p_key && !starting)
2640 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2641
2642 return cryptkey;
2643}
2644#endif
2645
2646#ifdef UNIX
2647 static void
2648set_file_time(fname, atime, mtime)
2649 char_u *fname;
2650 time_t atime; /* access time */
2651 time_t mtime; /* modification time */
2652{
2653# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2654 struct utimbuf buf;
2655
2656 buf.actime = atime;
2657 buf.modtime = mtime;
2658 (void)utime((char *)fname, &buf);
2659# else
2660# if defined(HAVE_UTIMES)
2661 struct timeval tvp[2];
2662
2663 tvp[0].tv_sec = atime;
2664 tvp[0].tv_usec = 0;
2665 tvp[1].tv_sec = mtime;
2666 tvp[1].tv_usec = 0;
2667# ifdef NeXT
2668 (void)utimes((char *)fname, tvp);
2669# else
2670 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2671# endif
2672# endif
2673# endif
2674}
2675#endif /* UNIX */
2676
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002677#if defined(VMS) && !defined(MIN)
2678/* Older DECC compiler for VAX doesn't define MIN() */
2679# define MIN(a, b) ((a) < (b) ? (a) : (b))
2680#endif
2681
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00002683 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 *
2685 * We do our own buffering here because fwrite() is so slow.
2686 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00002687 * If "forceit" is true, we don't care for errors when attempting backups.
2688 * In case of an error everything possible is done to restore the original
2689 * file. But when "forceit" is TRUE, we risk loosing it.
2690 *
2691 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
2692 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 *
2694 * This function must NOT use NameBuff (because it's called by autowrite()).
2695 *
2696 * return FAIL for failure, OK otherwise
2697 */
2698 int
2699buf_write(buf, fname, sfname, start, end, eap, append, forceit,
2700 reset_changed, filtering)
2701 buf_T *buf;
2702 char_u *fname;
2703 char_u *sfname;
2704 linenr_T start, end;
2705 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
2706 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00002707 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 int forceit;
2709 int reset_changed;
2710 int filtering;
2711{
2712 int fd;
2713 char_u *backup = NULL;
2714 int backup_copy = FALSE; /* copy the original file? */
2715 int dobackup;
2716 char_u *ffname;
2717 char_u *wfname = NULL; /* name of file to write to */
2718 char_u *s;
2719 char_u *ptr;
2720 char_u c;
2721 int len;
2722 linenr_T lnum;
2723 long nchars;
2724 char_u *errmsg = NULL;
2725 char_u *errnum = NULL;
2726 char_u *buffer;
2727 char_u smallbuf[SMBUFSIZE];
2728 char_u *backup_ext;
2729 int bufsize;
2730 long perm; /* file permissions */
2731 int retval = OK;
2732 int newfile = FALSE; /* TRUE if file doesn't exist yet */
2733 int msg_save = msg_scroll;
2734 int overwriting; /* TRUE if writing over original */
2735 int no_eol = FALSE; /* no end-of-line written */
2736 int device = FALSE; /* writing to a device */
2737 struct stat st_old;
2738 int prev_got_int = got_int;
2739 int file_readonly = FALSE; /* overwritten file is read-only */
2740 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
2741#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
2742 int made_writable = FALSE; /* 'w' bit has been set */
2743#endif
2744 /* writing everything */
2745 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
2746#ifdef FEAT_AUTOCMD
2747 linenr_T old_line_count = buf->b_ml.ml_line_count;
2748#endif
2749 int attr;
2750 int fileformat;
2751 int write_bin;
2752 struct bw_info write_info; /* info for buf_write_bytes() */
2753#ifdef FEAT_MBYTE
2754 int converted = FALSE;
2755 int notconverted = FALSE;
2756 char_u *fenc; /* effective 'fileencoding' */
2757 char_u *fenc_tofree = NULL; /* allocated "fenc" */
2758#endif
2759#ifdef HAS_BW_FLAGS
2760 int wb_flags = 0;
2761#endif
2762#ifdef HAVE_ACL
2763 vim_acl_T acl = NULL; /* ACL copied from original file to
2764 backup or new file */
2765#endif
2766
2767 if (fname == NULL || *fname == NUL) /* safety check */
2768 return FAIL;
2769
2770 /*
2771 * Disallow writing from .exrc and .vimrc in current directory for
2772 * security reasons.
2773 */
2774 if (check_secure())
2775 return FAIL;
2776
2777 /* Avoid a crash for a long name. */
2778 if (STRLEN(fname) >= MAXPATHL)
2779 {
2780 EMSG(_(e_longname));
2781 return FAIL;
2782 }
2783
2784#ifdef FEAT_MBYTE
2785 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
2786 write_info.bw_conv_buf = NULL;
2787 write_info.bw_conv_error = FALSE;
2788 write_info.bw_restlen = 0;
2789# ifdef USE_ICONV
2790 write_info.bw_iconv_fd = (iconv_t)-1;
2791# endif
2792#endif
2793
Bram Moolenaardf177f62005-02-22 08:39:57 +00002794 /* After writing a file changedtick changes but we don't want to display
2795 * the line. */
2796 ex_no_reprint = TRUE;
2797
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 /*
2799 * If there is no file name yet, use the one for the written file.
2800 * BF_NOTEDITED is set to reflect this (in case the write fails).
2801 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00002802 * Don't do this when appending.
2803 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002805 if (buf->b_ffname == NULL
2806 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 && whole
2808 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002809#ifdef FEAT_QUICKFIX
2810 && !bt_nofile(buf)
2811#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00002813 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
2815 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002816 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002818 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819 }
2820
2821 if (sfname == NULL)
2822 sfname = fname;
2823 /*
2824 * For Unix: Use the short file name whenever possible.
2825 * Avoids problems with networks and when directory names are changed.
2826 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
2827 * another directory, which we don't detect
2828 */
2829 ffname = fname; /* remember full fname */
2830#ifdef UNIX
2831 fname = sfname;
2832#endif
2833
2834 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
2835 overwriting = TRUE;
2836 else
2837 overwriting = FALSE;
2838
2839 if (exiting)
2840 settmode(TMODE_COOK); /* when exiting allow typahead now */
2841
2842 ++no_wait_return; /* don't wait for return yet */
2843
2844 /*
2845 * Set '[ and '] marks to the lines to be written.
2846 */
2847 buf->b_op_start.lnum = start;
2848 buf->b_op_start.col = 0;
2849 buf->b_op_end.lnum = end;
2850 buf->b_op_end.col = 0;
2851
2852#ifdef FEAT_AUTOCMD
2853 {
2854 aco_save_T aco;
2855 int buf_ffname = FALSE;
2856 int buf_sfname = FALSE;
2857 int buf_fname_f = FALSE;
2858 int buf_fname_s = FALSE;
2859 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002860 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002861 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862
2863 /*
2864 * Apply PRE aucocommands.
2865 * Set curbuf to the buffer to be written.
2866 * Careful: The autocommands may call buf_write() recursively!
2867 */
2868 if (ffname == buf->b_ffname)
2869 buf_ffname = TRUE;
2870 if (sfname == buf->b_sfname)
2871 buf_sfname = TRUE;
2872 if (fname == buf->b_ffname)
2873 buf_fname_f = TRUE;
2874 if (fname == buf->b_sfname)
2875 buf_fname_s = TRUE;
2876
2877 /* set curwin/curbuf to buf and save a few things */
2878 aucmd_prepbuf(&aco, buf);
2879
2880 if (append)
2881 {
2882 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
2883 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002884 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002885#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002886 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002887 nofile_err = TRUE;
2888 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002889#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002890 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 }
2894 else if (filtering)
2895 {
2896 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
2897 NULL, sfname, FALSE, curbuf, eap);
2898 }
2899 else if (reset_changed && whole)
2900 {
2901 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
2902 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002903 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002904#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002905 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002906 nofile_err = TRUE;
2907 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002908#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002909 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002911 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 }
2913 else
2914 {
2915 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
2916 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002917 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002918#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002919 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002920 nofile_err = TRUE;
2921 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002922#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002923 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002925 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 }
2927
2928 /* restore curwin/curbuf and a few other things */
2929 aucmd_restbuf(&aco);
2930
2931 /*
2932 * In three situations we return here and don't write the file:
2933 * 1. the autocommands deleted or unloaded the buffer.
2934 * 2. The autocommands abort script processing.
2935 * 3. If one of the "Cmd" autocommands was executed.
2936 */
2937 if (!buf_valid(buf))
2938 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002939 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00002940 || did_cmd || nofile_err
2941#ifdef FEAT_EVAL
2942 || aborting()
2943#endif
2944 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 {
2946 --no_wait_return;
2947 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002948 if (nofile_err)
2949 EMSG(_("E676: No matching autocommands for acwrite buffer"));
2950
Bram Moolenaar1e015462005-09-25 22:16:38 +00002951 if (nofile_err
2952#ifdef FEAT_EVAL
2953 || aborting()
2954#endif
2955 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 /* An aborting error, interrupt or exception in the
2957 * autocommands. */
2958 return FAIL;
2959 if (did_cmd)
2960 {
2961 if (buf == NULL)
2962 /* The buffer was deleted. We assume it was written
2963 * (can't retry anyway). */
2964 return OK;
2965 if (overwriting)
2966 {
2967 /* Assume the buffer was written, update the timestamp. */
2968 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00002969 if (append)
2970 buf->b_flags &= ~BF_NEW;
2971 else
2972 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00002974 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002975 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976 /* Buffer still changed, the autocommands didn't work
2977 * properly. */
2978 return FAIL;
2979 return OK;
2980 }
2981#ifdef FEAT_EVAL
2982 if (!aborting())
2983#endif
2984 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
2985 return FAIL;
2986 }
2987
2988 /*
2989 * The autocommands may have changed the number of lines in the file.
2990 * When writing the whole file, adjust the end.
2991 * When writing part of the file, assume that the autocommands only
2992 * changed the number of lines that are to be written (tricky!).
2993 */
2994 if (buf->b_ml.ml_line_count != old_line_count)
2995 {
2996 if (whole) /* write all */
2997 end = buf->b_ml.ml_line_count;
2998 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
2999 end += buf->b_ml.ml_line_count - old_line_count;
3000 else /* less lines */
3001 {
3002 end -= old_line_count - buf->b_ml.ml_line_count;
3003 if (end < start)
3004 {
3005 --no_wait_return;
3006 msg_scroll = msg_save;
3007 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3008 return FAIL;
3009 }
3010 }
3011 }
3012
3013 /*
3014 * The autocommands may have changed the name of the buffer, which may
3015 * be kept in fname, ffname and sfname.
3016 */
3017 if (buf_ffname)
3018 ffname = buf->b_ffname;
3019 if (buf_sfname)
3020 sfname = buf->b_sfname;
3021 if (buf_fname_f)
3022 fname = buf->b_ffname;
3023 if (buf_fname_s)
3024 fname = buf->b_sfname;
3025 }
3026#endif
3027
3028#ifdef FEAT_NETBEANS_INTG
3029 if (usingNetbeans && isNetbeansBuffer(buf))
3030 {
3031 if (whole)
3032 {
3033 /*
3034 * b_changed can be 0 after an undo, but we still need to write
3035 * the buffer to NetBeans.
3036 */
3037 if (buf->b_changed || isNetbeansModified(buf))
3038 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003039 --no_wait_return; /* may wait for return now */
3040 msg_scroll = msg_save;
3041 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042 return retval;
3043 }
3044 else
3045 {
3046 errnum = (char_u *)"E656: ";
3047 errmsg = (char_u *)_("NetBeans dissallows writes of unmodified buffers");
3048 buffer = NULL;
3049 goto fail;
3050 }
3051 }
3052 else
3053 {
3054 errnum = (char_u *)"E657: ";
3055 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3056 buffer = NULL;
3057 goto fail;
3058 }
3059 }
3060#endif
3061
3062 if (shortmess(SHM_OVER) && !exiting)
3063 msg_scroll = FALSE; /* overwrite previous file message */
3064 else
3065 msg_scroll = TRUE; /* don't overwrite previous file message */
3066 if (!filtering)
3067 filemess(buf,
3068#ifndef UNIX
3069 sfname,
3070#else
3071 fname,
3072#endif
3073 (char_u *)"", 0); /* show that we are busy */
3074 msg_scroll = FALSE; /* always overwrite the file message now */
3075
3076 buffer = alloc(BUFSIZE);
3077 if (buffer == NULL) /* can't allocate big buffer, use small
3078 * one (to be able to write when out of
3079 * memory) */
3080 {
3081 buffer = smallbuf;
3082 bufsize = SMBUFSIZE;
3083 }
3084 else
3085 bufsize = BUFSIZE;
3086
3087 /*
3088 * Get information about original file (if there is one).
3089 */
3090#if defined(UNIX) && !defined(ARCHIE)
3091 st_old.st_dev = st_old.st_ino = 0;
3092 perm = -1;
3093 if (mch_stat((char *)fname, &st_old) < 0)
3094 newfile = TRUE;
3095 else
3096 {
3097 perm = st_old.st_mode;
3098 if (!S_ISREG(st_old.st_mode)) /* not a file */
3099 {
3100 if (S_ISDIR(st_old.st_mode))
3101 {
3102 errnum = (char_u *)"E502: ";
3103 errmsg = (char_u *)_("is a directory");
3104 goto fail;
3105 }
3106 if (mch_nodetype(fname) != NODE_WRITABLE)
3107 {
3108 errnum = (char_u *)"E503: ";
3109 errmsg = (char_u *)_("is not a file or writable device");
3110 goto fail;
3111 }
3112 /* It's a device of some kind (or a fifo) which we can write to
3113 * but for which we can't make a backup. */
3114 device = TRUE;
3115 newfile = TRUE;
3116 perm = -1;
3117 }
3118 }
3119#else /* !UNIX */
3120 /*
3121 * Check for a writable device name.
3122 */
3123 c = mch_nodetype(fname);
3124 if (c == NODE_OTHER)
3125 {
3126 errnum = (char_u *)"E503: ";
3127 errmsg = (char_u *)_("is not a file or writable device");
3128 goto fail;
3129 }
3130 if (c == NODE_WRITABLE)
3131 {
3132 device = TRUE;
3133 newfile = TRUE;
3134 perm = -1;
3135 }
3136 else
3137 {
3138 perm = mch_getperm(fname);
3139 if (perm < 0)
3140 newfile = TRUE;
3141 else if (mch_isdir(fname))
3142 {
3143 errnum = (char_u *)"E502: ";
3144 errmsg = (char_u *)_("is a directory");
3145 goto fail;
3146 }
3147 if (overwriting)
3148 (void)mch_stat((char *)fname, &st_old);
3149 }
3150#endif /* !UNIX */
3151
3152 if (!device && !newfile)
3153 {
3154 /*
3155 * Check if the file is really writable (when renaming the file to
3156 * make a backup we won't discover it later).
3157 */
3158 file_readonly = (
3159# ifdef USE_MCH_ACCESS
3160# ifdef UNIX
3161 (perm & 0222) == 0 ||
3162# endif
3163 mch_access((char *)fname, W_OK)
3164# else
3165 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
3166 ? TRUE : (close(fd), FALSE)
3167# endif
3168 );
3169 if (!forceit && file_readonly)
3170 {
3171 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3172 {
3173 errnum = (char_u *)"E504: ";
3174 errmsg = (char_u *)_(err_readonly);
3175 }
3176 else
3177 {
3178 errnum = (char_u *)"E505: ";
3179 errmsg = (char_u *)_("is read-only (add ! to override)");
3180 }
3181 goto fail;
3182 }
3183
3184 /*
3185 * Check if the timestamp hasn't changed since reading the file.
3186 */
3187 if (overwriting)
3188 {
3189 retval = check_mtime(buf, &st_old);
3190 if (retval == FAIL)
3191 goto fail;
3192 }
3193 }
3194
3195#ifdef HAVE_ACL
3196 /*
3197 * For systems that support ACL: get the ACL from the original file.
3198 */
3199 if (!newfile)
3200 acl = mch_get_acl(fname);
3201#endif
3202
3203 /*
3204 * If 'backupskip' is not empty, don't make a backup for some files.
3205 */
3206 dobackup = (p_wb || p_bk || *p_pm != NUL);
3207#ifdef FEAT_WILDIGN
3208 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3209 dobackup = FALSE;
3210#endif
3211
3212 /*
3213 * Save the value of got_int and reset it. We don't want a previous
3214 * interruption cancel writing, only hitting CTRL-C while writing should
3215 * abort it.
3216 */
3217 prev_got_int = got_int;
3218 got_int = FALSE;
3219
3220 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3221 buf->b_saving = TRUE;
3222
3223 /*
3224 * If we are not appending or filtering, the file exists, and the
3225 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3226 * When 'patchmode' is set also make a backup when appending.
3227 *
3228 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3229 * off. This helps when editing large files on almost-full disks.
3230 */
3231 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3232 {
3233#if defined(UNIX) || defined(WIN32)
3234 struct stat st;
3235#endif
3236
3237 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3238 backup_copy = TRUE;
3239#if defined(UNIX) || defined(WIN32)
3240 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3241 {
3242 int i;
3243
3244# ifdef UNIX
3245 /*
3246 * Don't rename the file when:
3247 * - it's a hard link
3248 * - it's a symbolic link
3249 * - we don't have write permission in the directory
3250 * - we can't set the owner/group of the new file
3251 */
3252 if (st_old.st_nlink > 1
3253 || mch_lstat((char *)fname, &st) < 0
3254 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003255 || st.st_ino != st_old.st_ino
3256# ifndef HAVE_FCHOWN
3257 || st.st_uid != st_old.st_uid
3258 || st.st_gid != st_old.st_gid
3259# endif
3260 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 backup_copy = TRUE;
3262 else
3263# endif
3264 {
3265 /*
3266 * Check if we can create a file and set the owner/group to
3267 * the ones from the original file.
3268 * First find a file name that doesn't exist yet (use some
3269 * arbitrary numbers).
3270 */
3271 STRCPY(IObuff, fname);
3272 for (i = 4913; ; i += 123)
3273 {
3274 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003275 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276 break;
3277 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003278 fd = mch_open((char *)IObuff,
3279 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280 if (fd < 0) /* can't write in directory */
3281 backup_copy = TRUE;
3282 else
3283 {
3284# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003285# ifdef HAVE_FCHOWN
3286 fchown(fd, st_old.st_uid, st_old.st_gid);
3287# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 if (mch_stat((char *)IObuff, &st) < 0
3289 || st.st_uid != st_old.st_uid
3290 || st.st_gid != st_old.st_gid
3291 || st.st_mode != perm)
3292 backup_copy = TRUE;
3293# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003294 /* Close the file before removing it, on MS-Windows we
3295 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003296 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003297 mch_remove(IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 }
3299 }
3300 }
3301
3302# ifdef UNIX
3303 /*
3304 * Break symlinks and/or hardlinks if we've been asked to.
3305 */
3306 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3307 {
3308 int lstat_res;
3309
3310 lstat_res = mch_lstat((char *)fname, &st);
3311
3312 /* Symlinks. */
3313 if ((bkc_flags & BKC_BREAKSYMLINK)
3314 && lstat_res == 0
3315 && st.st_ino != st_old.st_ino)
3316 backup_copy = FALSE;
3317
3318 /* Hardlinks. */
3319 if ((bkc_flags & BKC_BREAKHARDLINK)
3320 && st_old.st_nlink > 1
3321 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3322 backup_copy = FALSE;
3323 }
3324#endif
3325
3326#endif
3327
3328 /* make sure we have a valid backup extension to use */
3329 if (*p_bex == NUL)
3330 {
3331#ifdef RISCOS
3332 backup_ext = (char_u *)"/bak";
3333#else
3334 backup_ext = (char_u *)".bak";
3335#endif
3336 }
3337 else
3338 backup_ext = p_bex;
3339
3340 if (backup_copy
3341 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3342 {
3343 int bfd;
3344 char_u *copybuf, *wp;
3345 int some_error = FALSE;
3346 struct stat st_new;
3347 char_u *dirp;
3348 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003349#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350 int did_set_shortname;
3351#endif
3352
3353 copybuf = alloc(BUFSIZE + 1);
3354 if (copybuf == NULL)
3355 {
3356 some_error = TRUE; /* out of memory */
3357 goto nobackup;
3358 }
3359
3360 /*
3361 * Try to make the backup in each directory in the 'bdir' option.
3362 *
3363 * Unix semantics has it, that we may have a writable file,
3364 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3365 * - the directory is not writable,
3366 * - the file may be a symbolic link,
3367 * - the file may belong to another user/group, etc.
3368 *
3369 * For these reasons, the existing writable file must be truncated
3370 * and reused. Creation of a backup COPY will be attempted.
3371 */
3372 dirp = p_bdir;
3373 while (*dirp)
3374 {
3375#ifdef UNIX
3376 st_new.st_ino = 0;
3377 st_new.st_dev = 0;
3378 st_new.st_gid = 0;
3379#endif
3380
3381 /*
3382 * Isolate one directory name, using an entry in 'bdir'.
3383 */
3384 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3385 rootname = get_file_in_dir(fname, copybuf);
3386 if (rootname == NULL)
3387 {
3388 some_error = TRUE; /* out of memory */
3389 goto nobackup;
3390 }
3391
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003392#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 did_set_shortname = FALSE;
3394#endif
3395
3396 /*
3397 * May try twice if 'shortname' not set.
3398 */
3399 for (;;)
3400 {
3401 /*
3402 * Make backup file name.
3403 */
3404 backup = buf_modname(
3405#ifdef SHORT_FNAME
3406 TRUE,
3407#else
3408 (buf->b_p_sn || buf->b_shortname),
3409#endif
3410 rootname, backup_ext, FALSE);
3411 if (backup == NULL)
3412 {
3413 vim_free(rootname);
3414 some_error = TRUE; /* out of memory */
3415 goto nobackup;
3416 }
3417
3418 /*
3419 * Check if backup file already exists.
3420 */
3421 if (mch_stat((char *)backup, &st_new) >= 0)
3422 {
3423#ifdef UNIX
3424 /*
3425 * Check if backup file is same as original file.
3426 * May happen when modname() gave the same file back.
3427 * E.g. silly link, or file name-length reached.
3428 * If we don't check here, we either ruin the file
3429 * when copying or erase it after writing. jw.
3430 */
3431 if (st_new.st_dev == st_old.st_dev
3432 && st_new.st_ino == st_old.st_ino)
3433 {
3434 vim_free(backup);
3435 backup = NULL; /* no backup file to delete */
3436# ifndef SHORT_FNAME
3437 /*
3438 * may try again with 'shortname' set
3439 */
3440 if (!(buf->b_shortname || buf->b_p_sn))
3441 {
3442 buf->b_shortname = TRUE;
3443 did_set_shortname = TRUE;
3444 continue;
3445 }
3446 /* setting shortname didn't help */
3447 if (did_set_shortname)
3448 buf->b_shortname = FALSE;
3449# endif
3450 break;
3451 }
3452#endif
3453
3454 /*
3455 * If we are not going to keep the backup file, don't
3456 * delete an existing one, try to use another name.
3457 * Change one character, just before the extension.
3458 */
3459 if (!p_bk)
3460 {
3461 wp = backup + STRLEN(backup) - 1
3462 - STRLEN(backup_ext);
3463 if (wp < backup) /* empty file name ??? */
3464 wp = backup;
3465 *wp = 'z';
3466 while (*wp > 'a'
3467 && mch_stat((char *)backup, &st_new) >= 0)
3468 --*wp;
3469 /* They all exist??? Must be something wrong. */
3470 if (*wp == 'a')
3471 {
3472 vim_free(backup);
3473 backup = NULL;
3474 }
3475 }
3476 }
3477 break;
3478 }
3479 vim_free(rootname);
3480
3481 /*
3482 * Try to create the backup file
3483 */
3484 if (backup != NULL)
3485 {
3486 /* remove old backup, if present */
3487 mch_remove(backup);
3488 /* Open with O_EXCL to avoid the file being created while
3489 * we were sleeping (symlink hacker attack?) */
3490 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003491 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3492 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 if (bfd < 0)
3494 {
3495 vim_free(backup);
3496 backup = NULL;
3497 }
3498 else
3499 {
3500 /* set file protection same as original file, but
3501 * strip s-bit */
3502 (void)mch_setperm(backup, perm & 0777);
3503
3504#ifdef UNIX
3505 /*
3506 * Try to set the group of the backup same as the
3507 * original file. If this fails, set the protection
3508 * bits for the group same as the protection bits for
3509 * others.
3510 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003511 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003513 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514# endif
3515 )
3516 mch_setperm(backup,
3517 (perm & 0707) | ((perm & 07) << 3));
3518#endif
3519
3520 /*
3521 * copy the file.
3522 */
3523 write_info.bw_fd = bfd;
3524 write_info.bw_buf = copybuf;
3525#ifdef HAS_BW_FLAGS
3526 write_info.bw_flags = FIO_NOCONVERT;
3527#endif
3528 while ((write_info.bw_len = vim_read(fd, copybuf,
3529 BUFSIZE)) > 0)
3530 {
3531 if (buf_write_bytes(&write_info) == FAIL)
3532 {
3533 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3534 break;
3535 }
3536 ui_breakcheck();
3537 if (got_int)
3538 {
3539 errmsg = (char_u *)_(e_interr);
3540 break;
3541 }
3542 }
3543
3544 if (close(bfd) < 0 && errmsg == NULL)
3545 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3546 if (write_info.bw_len < 0)
3547 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3548#ifdef UNIX
3549 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3550#endif
3551#ifdef HAVE_ACL
3552 mch_set_acl(backup, acl);
3553#endif
3554 break;
3555 }
3556 }
3557 }
3558 nobackup:
3559 close(fd); /* ignore errors for closing read file */
3560 vim_free(copybuf);
3561
3562 if (backup == NULL && errmsg == NULL)
3563 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3564 /* ignore errors when forceit is TRUE */
3565 if ((some_error || errmsg != NULL) && !forceit)
3566 {
3567 retval = FAIL;
3568 goto fail;
3569 }
3570 errmsg = NULL;
3571 }
3572 else
3573 {
3574 char_u *dirp;
3575 char_u *p;
3576 char_u *rootname;
3577
3578 /*
3579 * Make a backup by renaming the original file.
3580 */
3581 /*
3582 * If 'cpoptions' includes the "W" flag, we don't want to
3583 * overwrite a read-only file. But rename may be possible
3584 * anyway, thus we need an extra check here.
3585 */
3586 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3587 {
3588 errnum = (char_u *)"E504: ";
3589 errmsg = (char_u *)_(err_readonly);
3590 goto fail;
3591 }
3592
3593 /*
3594 *
3595 * Form the backup file name - change path/fo.o.h to
3596 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3597 * that works is used.
3598 */
3599 dirp = p_bdir;
3600 while (*dirp)
3601 {
3602 /*
3603 * Isolate one directory name and make the backup file name.
3604 */
3605 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
3606 rootname = get_file_in_dir(fname, IObuff);
3607 if (rootname == NULL)
3608 backup = NULL;
3609 else
3610 {
3611 backup = buf_modname(
3612#ifdef SHORT_FNAME
3613 TRUE,
3614#else
3615 (buf->b_p_sn || buf->b_shortname),
3616#endif
3617 rootname, backup_ext, FALSE);
3618 vim_free(rootname);
3619 }
3620
3621 if (backup != NULL)
3622 {
3623 /*
3624 * If we are not going to keep the backup file, don't
3625 * delete an existing one, try to use another name.
3626 * Change one character, just before the extension.
3627 */
3628 if (!p_bk && mch_getperm(backup) >= 0)
3629 {
3630 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
3631 if (p < backup) /* empty file name ??? */
3632 p = backup;
3633 *p = 'z';
3634 while (*p > 'a' && mch_getperm(backup) >= 0)
3635 --*p;
3636 /* They all exist??? Must be something wrong! */
3637 if (*p == 'a')
3638 {
3639 vim_free(backup);
3640 backup = NULL;
3641 }
3642 }
3643 }
3644 if (backup != NULL)
3645 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003647 * Delete any existing backup and move the current version
3648 * to the backup. For safety, we don't remove the backup
3649 * until the write has finished successfully. And if the
3650 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651 */
3652 /*
3653 * If the renaming of the original file to the backup file
3654 * works, quit here.
3655 */
3656 if (vim_rename(fname, backup) == 0)
3657 break;
3658
3659 vim_free(backup); /* don't do the rename below */
3660 backup = NULL;
3661 }
3662 }
3663 if (backup == NULL && !forceit)
3664 {
3665 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
3666 goto fail;
3667 }
3668 }
3669 }
3670
3671#if defined(UNIX) && !defined(ARCHIE)
3672 /* When using ":w!" and the file was read-only: make it writable */
3673 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
3674 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
3675 {
3676 perm |= 0200;
3677 (void)mch_setperm(fname, perm);
3678 made_writable = TRUE;
3679 }
3680#endif
3681
3682 /* When using ":w!" and writing to the current file, readonly makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003683 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
3684 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 {
3686 buf->b_p_ro = FALSE;
3687#ifdef FEAT_TITLE
3688 need_maketitle = TRUE; /* set window title later */
3689#endif
3690#ifdef FEAT_WINDOWS
3691 status_redraw_all(); /* redraw status lines later */
3692#endif
3693 }
3694
3695 if (end > buf->b_ml.ml_line_count)
3696 end = buf->b_ml.ml_line_count;
3697 if (buf->b_ml.ml_flags & ML_EMPTY)
3698 start = end + 1;
3699
3700 /*
3701 * If the original file is being overwritten, there is a small chance that
3702 * we crash in the middle of writing. Therefore the file is preserved now.
3703 * This makes all block numbers positive so that recovery does not need
3704 * the original file.
3705 * Don't do this if there is a backup file and we are exiting.
3706 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003707 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 && !(exiting && backup != NULL))
3709 {
3710 ml_preserve(buf, FALSE);
3711 if (got_int)
3712 {
3713 errmsg = (char_u *)_(e_interr);
3714 goto restore_backup;
3715 }
3716 }
3717
3718#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
3719 /*
3720 * Before risking to lose the original file verify if there's
3721 * a resource fork to preserve, and if cannot be done warn
3722 * the users. This happens when overwriting without backups.
3723 */
3724 if (backup == NULL && overwriting && !append)
3725 if (mch_has_resource_fork(fname))
3726 {
3727 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
3728 goto restore_backup;
3729 }
3730#endif
3731
3732#ifdef VMS
3733 vms_remove_version(fname); /* remove version */
3734#endif
3735 /* Default: write the the file directly. May write to a temp file for
3736 * multi-byte conversion. */
3737 wfname = fname;
3738
3739#ifdef FEAT_MBYTE
3740 /* Check for forced 'fileencoding' from "++opt=val" argument. */
3741 if (eap != NULL && eap->force_enc != 0)
3742 {
3743 fenc = eap->cmd + eap->force_enc;
3744 fenc = enc_canonize(fenc);
3745 fenc_tofree = fenc;
3746 }
3747 else
3748 fenc = buf->b_p_fenc;
3749
3750 /*
3751 * The file needs to be converted when 'fileencoding' is set and
3752 * 'fileencoding' differs from 'encoding'.
3753 */
3754 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
3755
3756 /*
3757 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
3758 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
3759 * Prepare the flags for it and allocate bw_conv_buf when needed.
3760 */
3761 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
3762 {
3763 wb_flags = get_fio_flags(fenc);
3764 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
3765 {
3766 /* Need to allocate a buffer to translate into. */
3767 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
3768 write_info.bw_conv_buflen = bufsize * 2;
3769 else /* FIO_UCS4 */
3770 write_info.bw_conv_buflen = bufsize * 4;
3771 write_info.bw_conv_buf
3772 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3773 if (write_info.bw_conv_buf == NULL)
3774 end = 0;
3775 }
3776 }
3777
3778# ifdef WIN3264
3779 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
3780 {
3781 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
3782 write_info.bw_conv_buflen = bufsize * 4;
3783 write_info.bw_conv_buf
3784 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3785 if (write_info.bw_conv_buf == NULL)
3786 end = 0;
3787 }
3788# endif
3789
3790# ifdef MACOS_X
3791 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
3792 {
3793 write_info.bw_conv_buflen = bufsize * 3;
3794 write_info.bw_conv_buf
3795 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3796 if (write_info.bw_conv_buf == NULL)
3797 end = 0;
3798 }
3799# endif
3800
3801# if defined(FEAT_EVAL) || defined(USE_ICONV)
3802 if (converted && wb_flags == 0)
3803 {
3804# ifdef USE_ICONV
3805 /*
3806 * Use iconv() conversion when conversion is needed and it's not done
3807 * internally.
3808 */
3809 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
3810 enc_utf8 ? (char_u *)"utf-8" : p_enc);
3811 if (write_info.bw_iconv_fd != (iconv_t)-1)
3812 {
3813 /* We're going to use iconv(), allocate a buffer to convert in. */
3814 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
3815 write_info.bw_conv_buf
3816 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3817 if (write_info.bw_conv_buf == NULL)
3818 end = 0;
3819 write_info.bw_first = TRUE;
3820 }
3821# ifdef FEAT_EVAL
3822 else
3823# endif
3824# endif
3825
3826# ifdef FEAT_EVAL
3827 /*
3828 * When the file needs to be converted with 'charconvert' after
3829 * writing, write to a temp file instead and let the conversion
3830 * overwrite the original file.
3831 */
3832 if (*p_ccv != NUL)
3833 {
3834 wfname = vim_tempname('w');
3835 if (wfname == NULL) /* Can't write without a tempfile! */
3836 {
3837 errmsg = (char_u *)_("E214: Can't find temp file for writing");
3838 goto restore_backup;
3839 }
3840 }
3841# endif
3842 }
3843# endif
3844 if (converted && wb_flags == 0
3845# ifdef USE_ICONV
3846 && write_info.bw_iconv_fd == (iconv_t)-1
3847# endif
3848# ifdef FEAT_EVAL
3849 && wfname == fname
3850# endif
3851 )
3852 {
3853 if (!forceit)
3854 {
3855 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
3856 goto restore_backup;
3857 }
3858 notconverted = TRUE;
3859 }
3860#endif
3861
3862 /*
3863 * Open the file "wfname" for writing.
3864 * We may try to open the file twice: If we can't write to the
3865 * file and forceit is TRUE we delete the existing file and try to create
3866 * a new one. If this still fails we may have lost the original file!
3867 * (this may happen when the user reached his quotum for number of files).
3868 * Appending will fail if the file does not exist and forceit is FALSE.
3869 */
3870 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
3871 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
3872 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00003873 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 {
3875 /*
3876 * A forced write will try to create a new file if the old one is
3877 * still readonly. This may also happen when the directory is
3878 * read-only. In that case the mch_remove() will fail.
3879 */
3880 if (errmsg == NULL)
3881 {
3882#ifdef UNIX
3883 struct stat st;
3884
3885 /* Don't delete the file when it's a hard or symbolic link. */
3886 if ((!newfile && st_old.st_nlink > 1)
3887 || (mch_lstat((char *)fname, &st) == 0
3888 && (st.st_dev != st_old.st_dev
3889 || st.st_ino != st_old.st_ino)))
3890 errmsg = (char_u *)_("E166: Can't open linked file for writing");
3891 else
3892#endif
3893 {
3894 errmsg = (char_u *)_("E212: Can't open file for writing");
3895 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
3896 && perm >= 0)
3897 {
3898#ifdef UNIX
3899 /* we write to the file, thus it should be marked
3900 writable after all */
3901 if (!(perm & 0200))
3902 made_writable = TRUE;
3903 perm |= 0200;
3904 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
3905 perm &= 0777;
3906#endif
3907 if (!append) /* don't remove when appending */
3908 mch_remove(wfname);
3909 continue;
3910 }
3911 }
3912 }
3913
3914restore_backup:
3915 {
3916 struct stat st;
3917
3918 /*
3919 * If we failed to open the file, we don't need a backup. Throw it
3920 * away. If we moved or removed the original file try to put the
3921 * backup in its place.
3922 */
3923 if (backup != NULL && wfname == fname)
3924 {
3925 if (backup_copy)
3926 {
3927 /*
3928 * There is a small chance that we removed the original,
3929 * try to move the copy in its place.
3930 * This may not work if the vim_rename() fails.
3931 * In that case we leave the copy around.
3932 */
3933 /* If file does not exist, put the copy in its place */
3934 if (mch_stat((char *)fname, &st) < 0)
3935 vim_rename(backup, fname);
3936 /* if original file does exist throw away the copy */
3937 if (mch_stat((char *)fname, &st) >= 0)
3938 mch_remove(backup);
3939 }
3940 else
3941 {
3942 /* try to put the original file back */
3943 vim_rename(backup, fname);
3944 }
3945 }
3946
3947 /* if original file no longer exists give an extra warning */
3948 if (!newfile && mch_stat((char *)fname, &st) < 0)
3949 end = 0;
3950 }
3951
3952#ifdef FEAT_MBYTE
3953 if (wfname != fname)
3954 vim_free(wfname);
3955#endif
3956 goto fail;
3957 }
3958 errmsg = NULL;
3959
3960#if defined(MACOS_CLASSIC) || defined(WIN3264)
3961 /* TODO: Is it need for MACOS_X? (Dany) */
3962 /*
3963 * On macintosh copy the original files attributes (i.e. the backup)
3964 * This is done in order to preserve the ressource fork and the
3965 * Finder attribute (label, comments, custom icons, file creatore)
3966 */
3967 if (backup != NULL && overwriting && !append)
3968 {
3969 if (backup_copy)
3970 (void)mch_copy_file_attribute(wfname, backup);
3971 else
3972 (void)mch_copy_file_attribute(backup, wfname);
3973 }
3974
3975 if (!overwriting && !append)
3976 {
3977 if (buf->b_ffname != NULL)
3978 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
3979 /* Should copy ressource fork */
3980 }
3981#endif
3982
3983 write_info.bw_fd = fd;
3984
3985#ifdef FEAT_CRYPT
3986 if (*buf->b_p_key && !filtering)
3987 {
3988 crypt_init_keys(buf->b_p_key);
3989 /* Write magic number, so that Vim knows that this file is encrypted
3990 * when reading it again. This also undergoes utf-8 to ucs-2/4
3991 * conversion when needed. */
3992 write_info.bw_buf = (char_u *)CRYPT_MAGIC;
3993 write_info.bw_len = CRYPT_MAGIC_LEN;
3994 write_info.bw_flags = FIO_NOCONVERT;
3995 if (buf_write_bytes(&write_info) == FAIL)
3996 end = 0;
3997 wb_flags |= FIO_ENCRYPTED;
3998 }
3999#endif
4000
4001 write_info.bw_buf = buffer;
4002 nchars = 0;
4003
4004 /* use "++bin", "++nobin" or 'binary' */
4005 if (eap != NULL && eap->force_bin != 0)
4006 write_bin = (eap->force_bin == FORCE_BIN);
4007 else
4008 write_bin = buf->b_p_bin;
4009
4010#ifdef FEAT_MBYTE
4011 /*
4012 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004013 * Skip it when appending and the file already existed, the BOM only makes
4014 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004016 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 {
4018 write_info.bw_len = make_bom(buffer, fenc);
4019 if (write_info.bw_len > 0)
4020 {
4021 /* don't convert, do encryption */
4022 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4023 if (buf_write_bytes(&write_info) == FAIL)
4024 end = 0;
4025 else
4026 nchars += write_info.bw_len;
4027 }
4028 }
4029#endif
4030
4031 write_info.bw_len = bufsize;
4032#ifdef HAS_BW_FLAGS
4033 write_info.bw_flags = wb_flags;
4034#endif
4035 fileformat = get_fileformat_force(buf, eap);
4036 s = buffer;
4037 len = 0;
4038 for (lnum = start; lnum <= end; ++lnum)
4039 {
4040 /*
4041 * The next while loop is done once for each character written.
4042 * Keep it fast!
4043 */
4044 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4045 while ((c = *++ptr) != NUL)
4046 {
4047 if (c == NL)
4048 *s = NUL; /* replace newlines with NULs */
4049 else if (c == CAR && fileformat == EOL_MAC)
4050 *s = NL; /* Mac: replace CRs with NLs */
4051 else
4052 *s = c;
4053 ++s;
4054 if (++len != bufsize)
4055 continue;
4056 if (buf_write_bytes(&write_info) == FAIL)
4057 {
4058 end = 0; /* write error: break loop */
4059 break;
4060 }
4061 nchars += bufsize;
4062 s = buffer;
4063 len = 0;
4064 }
4065 /* write failed or last line has no EOL: stop here */
4066 if (end == 0
4067 || (lnum == end
4068 && write_bin
4069 && (lnum == write_no_eol_lnum
4070 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4071 {
4072 ++lnum; /* written the line, count it */
4073 no_eol = TRUE;
4074 break;
4075 }
4076 if (fileformat == EOL_UNIX)
4077 *s++ = NL;
4078 else
4079 {
4080 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4081 if (fileformat == EOL_DOS) /* write CR-NL */
4082 {
4083 if (++len == bufsize)
4084 {
4085 if (buf_write_bytes(&write_info) == FAIL)
4086 {
4087 end = 0; /* write error: break loop */
4088 break;
4089 }
4090 nchars += bufsize;
4091 s = buffer;
4092 len = 0;
4093 }
4094 *s++ = NL;
4095 }
4096 }
4097 if (++len == bufsize && end)
4098 {
4099 if (buf_write_bytes(&write_info) == FAIL)
4100 {
4101 end = 0; /* write error: break loop */
4102 break;
4103 }
4104 nchars += bufsize;
4105 s = buffer;
4106 len = 0;
4107
4108 ui_breakcheck();
4109 if (got_int)
4110 {
4111 end = 0; /* Interrupted, break loop */
4112 break;
4113 }
4114 }
4115#ifdef VMS
4116 /*
4117 * On VMS there is a problem: newlines get added when writing blocks
4118 * at a time. Fix it by writing a line at a time.
4119 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004120 * Explanation: VAX/DECC RTL insists that records in some RMS
4121 * structures end with a newline (carriage return) character, and if
4122 * they don't it adds one.
4123 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004124 */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004125 if ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004127 int b2write;
4128
4129 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4130 ? MIN(4096, bufsize)
4131 : MIN(buf->b_fab_mrs, bufsize));
4132
4133 b2write = len;
4134 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004136 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4137 if (buf_write_bytes(&write_info) == FAIL)
4138 {
4139 end = 0;
4140 break;
4141 }
4142 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143 }
4144 write_info.bw_len = bufsize;
4145 nchars += len;
4146 s = buffer;
4147 len = 0;
4148 }
4149#endif
4150 }
4151 if (len > 0 && end > 0)
4152 {
4153 write_info.bw_len = len;
4154 if (buf_write_bytes(&write_info) == FAIL)
4155 end = 0; /* write error */
4156 nchars += len;
4157 }
4158
4159#if defined(UNIX) && defined(HAVE_FSYNC)
4160 /* On many journalling file systems there is a bug that causes both the
4161 * original and the backup file to be lost when halting the system right
4162 * after writing the file. That's because only the meta-data is
4163 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004164 * been written to disk and we don't lose it.
4165 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004166 * (could be a pipe).
4167 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4168 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 {
4170 errmsg = (char_u *)_("E667: Fsync failed");
4171 end = 0;
4172 }
4173#endif
4174
Bram Moolenaara5792f52005-11-23 21:25:05 +00004175#ifdef UNIX
4176 /* When creating a new file, set its owner/group to that of the original
4177 * file. Get the new device and inode number. */
4178 if (backup != NULL && !backup_copy)
4179 {
4180# ifdef HAVE_FCHOWN
4181 struct stat st;
4182
4183 /* don't change the owner when it's already OK, some systems remove
4184 * permission or ACL stuff */
4185 if (mch_stat((char *)wfname, &st) < 0
4186 || st.st_uid != st_old.st_uid
4187 || st.st_gid != st_old.st_gid)
4188 {
4189 fchown(fd, st_old.st_uid, st_old.st_gid);
4190 if (perm >= 0) /* set permission again, may have changed */
4191 (void)mch_setperm(wfname, perm);
4192 }
4193# endif
4194 buf_setino(buf);
4195 }
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004196 else if (buf->b_dev < 0)
4197 /* Set the inode when creating a new file. */
4198 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004199#endif
4200
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 if (close(fd) != 0)
4202 {
4203 errmsg = (char_u *)_("E512: Close failed");
4204 end = 0;
4205 }
4206
4207#ifdef UNIX
4208 if (made_writable)
4209 perm &= ~0200; /* reset 'w' bit for security reasons */
4210#endif
4211 if (perm >= 0) /* set perm. of new file same as old file */
4212 (void)mch_setperm(wfname, perm);
4213#ifdef RISCOS
4214 if (!append && !filtering)
4215 /* Set the filetype after writing the file. */
4216 mch_set_filetype(wfname, buf->b_p_oft);
4217#endif
4218#ifdef HAVE_ACL
4219 /* Probably need to set the ACL before changing the user (can't set the
4220 * ACL on a file the user doesn't own). */
4221 if (!backup_copy)
4222 mch_set_acl(wfname, acl);
4223#endif
4224
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225
4226#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4227 if (wfname != fname)
4228 {
4229 /*
4230 * The file was written to a temp file, now it needs to be converted
4231 * with 'charconvert' to (overwrite) the output file.
4232 */
4233 if (end != 0)
4234 {
4235 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4236 wfname, fname) == FAIL)
4237 {
4238 write_info.bw_conv_error = TRUE;
4239 end = 0;
4240 }
4241 }
4242 mch_remove(wfname);
4243 vim_free(wfname);
4244 }
4245#endif
4246
4247 if (end == 0)
4248 {
4249 if (errmsg == NULL)
4250 {
4251#ifdef FEAT_MBYTE
4252 if (write_info.bw_conv_error)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00004253 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 else
4255#endif
4256 if (got_int)
4257 errmsg = (char_u *)_(e_interr);
4258 else
4259 errmsg = (char_u *)_("E514: write error (file system full?)");
4260 }
4261
4262 /*
4263 * If we have a backup file, try to put it in place of the new file,
4264 * because the new file is probably corrupt. This avoids loosing the
4265 * original file when trying to make a backup when writing the file a
4266 * second time.
4267 * When "backup_copy" is set we need to copy the backup over the new
4268 * file. Otherwise rename the backup file.
4269 * If this is OK, don't give the extra warning message.
4270 */
4271 if (backup != NULL)
4272 {
4273 if (backup_copy)
4274 {
4275 /* This may take a while, if we were interrupted let the user
4276 * know we got the message. */
4277 if (got_int)
4278 {
4279 MSG(_(e_interr));
4280 out_flush();
4281 }
4282 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4283 {
4284 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004285 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4286 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 {
4288 /* copy the file. */
4289 write_info.bw_buf = smallbuf;
4290#ifdef HAS_BW_FLAGS
4291 write_info.bw_flags = FIO_NOCONVERT;
4292#endif
4293 while ((write_info.bw_len = vim_read(fd, smallbuf,
4294 SMBUFSIZE)) > 0)
4295 if (buf_write_bytes(&write_info) == FAIL)
4296 break;
4297
4298 if (close(write_info.bw_fd) >= 0
4299 && write_info.bw_len == 0)
4300 end = 1; /* success */
4301 }
4302 close(fd); /* ignore errors for closing read file */
4303 }
4304 }
4305 else
4306 {
4307 if (vim_rename(backup, fname) == 0)
4308 end = 1;
4309 }
4310 }
4311 goto fail;
4312 }
4313
4314 lnum -= start; /* compute number of written lines */
4315 --no_wait_return; /* may wait for return now */
4316
4317#if !(defined(UNIX) || defined(VMS))
4318 fname = sfname; /* use shortname now, for the messages */
4319#endif
4320 if (!filtering)
4321 {
4322 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4323 c = FALSE;
4324#ifdef FEAT_MBYTE
4325 if (write_info.bw_conv_error)
4326 {
4327 STRCAT(IObuff, _(" CONVERSION ERROR"));
4328 c = TRUE;
4329 }
4330 else if (notconverted)
4331 {
4332 STRCAT(IObuff, _("[NOT converted]"));
4333 c = TRUE;
4334 }
4335 else if (converted)
4336 {
4337 STRCAT(IObuff, _("[converted]"));
4338 c = TRUE;
4339 }
4340#endif
4341 if (device)
4342 {
4343 STRCAT(IObuff, _("[Device]"));
4344 c = TRUE;
4345 }
4346 else if (newfile)
4347 {
4348 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4349 c = TRUE;
4350 }
4351 if (no_eol)
4352 {
4353 msg_add_eol();
4354 c = TRUE;
4355 }
4356 /* may add [unix/dos/mac] */
4357 if (msg_add_fileformat(fileformat))
4358 c = TRUE;
4359#ifdef FEAT_CRYPT
4360 if (wb_flags & FIO_ENCRYPTED)
4361 {
4362 STRCAT(IObuff, _("[crypted]"));
4363 c = TRUE;
4364 }
4365#endif
4366 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4367 if (!shortmess(SHM_WRITE))
4368 {
4369 if (append)
4370 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4371 else
4372 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4373 }
4374
4375 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0));
4376 keep_msg_attr = 0;
4377 }
4378
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004379 /* When written everything correctly: reset 'modified'. Unless not
4380 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004381 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382#ifdef FEAT_MBYTE
4383 && !write_info.bw_conv_error
4384#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004385 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4386 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387 {
4388 unchanged(buf, TRUE);
4389 u_unchanged(buf);
4390 }
4391
4392 /*
4393 * If written to the current file, update the timestamp of the swap file
4394 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4395 */
4396 if (overwriting)
4397 {
4398 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004399 if (append)
4400 buf->b_flags &= ~BF_NEW;
4401 else
4402 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 }
4404
4405 /*
4406 * If we kept a backup until now, and we are in patch mode, then we make
4407 * the backup file our 'original' file.
4408 */
4409 if (*p_pm && dobackup)
4410 {
4411 char *org = (char *)buf_modname(
4412#ifdef SHORT_FNAME
4413 TRUE,
4414#else
4415 (buf->b_p_sn || buf->b_shortname),
4416#endif
4417 fname, p_pm, FALSE);
4418
4419 if (backup != NULL)
4420 {
4421 struct stat st;
4422
4423 /*
4424 * If the original file does not exist yet
4425 * the current backup file becomes the original file
4426 */
4427 if (org == NULL)
4428 EMSG(_("E205: Patchmode: can't save original file"));
4429 else if (mch_stat(org, &st) < 0)
4430 {
4431 vim_rename(backup, (char_u *)org);
4432 vim_free(backup); /* don't delete the file */
4433 backup = NULL;
4434#ifdef UNIX
4435 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4436#endif
4437 }
4438 }
4439 /*
4440 * If there is no backup file, remember that a (new) file was
4441 * created.
4442 */
4443 else
4444 {
4445 int empty_fd;
4446
4447 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004448 || (empty_fd = mch_open(org,
4449 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004450 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004451 EMSG(_("E206: patchmode: can't touch empty original file"));
4452 else
4453 close(empty_fd);
4454 }
4455 if (org != NULL)
4456 {
4457 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4458 vim_free(org);
4459 }
4460 }
4461
4462 /*
4463 * Remove the backup unless 'backup' option is set
4464 */
4465 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4466 EMSG(_("E207: Can't delete backup file"));
4467
4468#ifdef FEAT_SUN_WORKSHOP
4469 if (usingSunWorkShop)
4470 workshop_file_saved((char *) ffname);
4471#endif
4472
4473 goto nofail;
4474
4475 /*
4476 * Finish up. We get here either after failure or success.
4477 */
4478fail:
4479 --no_wait_return; /* may wait for return now */
4480nofail:
4481
4482 /* Done saving, we accept changed buffer warnings again */
4483 buf->b_saving = FALSE;
4484
4485 vim_free(backup);
4486 if (buffer != smallbuf)
4487 vim_free(buffer);
4488#ifdef FEAT_MBYTE
4489 vim_free(fenc_tofree);
4490 vim_free(write_info.bw_conv_buf);
4491# ifdef USE_ICONV
4492 if (write_info.bw_iconv_fd != (iconv_t)-1)
4493 {
4494 iconv_close(write_info.bw_iconv_fd);
4495 write_info.bw_iconv_fd = (iconv_t)-1;
4496 }
4497# endif
4498#endif
4499#ifdef HAVE_ACL
4500 mch_free_acl(acl);
4501#endif
4502
4503 if (errmsg != NULL)
4504 {
4505 int numlen = errnum != NULL ? STRLEN(errnum) : 0;
4506
4507 attr = hl_attr(HLF_E); /* set highlight for error messages */
4508 msg_add_fname(buf,
4509#ifndef UNIX
4510 sfname
4511#else
4512 fname
4513#endif
4514 ); /* put file name in IObuff with quotes */
4515 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4516 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4517 /* If the error message has the form "is ...", put the error number in
4518 * front of the file name. */
4519 if (errnum != NULL)
4520 {
4521 mch_memmove(IObuff + numlen, IObuff, STRLEN(IObuff) + 1);
4522 mch_memmove(IObuff, errnum, (size_t)numlen);
4523 }
4524 STRCAT(IObuff, errmsg);
4525 emsg(IObuff);
4526
4527 retval = FAIL;
4528 if (end == 0)
4529 {
4530 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4531 attr | MSG_HIST);
4532 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4533 attr | MSG_HIST);
4534
4535 /* Update the timestamp to avoid an "overwrite changed file"
4536 * prompt when writing again. */
4537 if (mch_stat((char *)fname, &st_old) >= 0)
4538 {
4539 buf_store_time(buf, &st_old, fname);
4540 buf->b_mtime_read = buf->b_mtime;
4541 }
4542 }
4543 }
4544 msg_scroll = msg_save;
4545
4546#ifdef FEAT_AUTOCMD
4547#ifdef FEAT_EVAL
4548 if (!should_abort(retval))
4549#else
4550 if (!got_int)
4551#endif
4552 {
4553 aco_save_T aco;
4554
4555 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4556
4557 /*
4558 * Apply POST autocommands.
4559 * Careful: The autocommands may call buf_write() recursively!
4560 */
4561 aucmd_prepbuf(&aco, buf);
4562
4563 if (append)
4564 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4565 FALSE, curbuf, eap);
4566 else if (filtering)
4567 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4568 FALSE, curbuf, eap);
4569 else if (reset_changed && whole)
4570 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4571 FALSE, curbuf, eap);
4572 else
4573 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4574 FALSE, curbuf, eap);
4575
4576 /* restore curwin/curbuf and a few other things */
4577 aucmd_restbuf(&aco);
4578
4579#ifdef FEAT_EVAL
4580 if (aborting()) /* autocmds may abort script processing */
4581 retval = FALSE;
4582#endif
4583 }
4584#endif
4585
4586 got_int |= prev_got_int;
4587
4588#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4589 /* Update machine specific information. */
4590 mch_post_buffer_write(buf);
4591#endif
4592 return retval;
4593}
4594
4595/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004596 * Set the name of the current buffer. Use when the buffer doesn't have a
4597 * name and a ":r" or ":w" command with a file name is used.
4598 */
4599 static int
4600set_rw_fname(fname, sfname)
4601 char_u *fname;
4602 char_u *sfname;
4603{
4604#ifdef FEAT_AUTOCMD
4605 /* It's like the unnamed buffer is deleted.... */
4606 if (curbuf->b_p_bl)
4607 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
4608 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
4609# ifdef FEAT_EVAL
4610 if (aborting()) /* autocmds may abort script processing */
4611 return FAIL;
4612# endif
4613#endif
4614
4615 if (setfname(curbuf, fname, sfname, FALSE) == OK)
4616 curbuf->b_flags |= BF_NOTEDITED;
4617
4618#ifdef FEAT_AUTOCMD
4619 /* ....and a new named one is created */
4620 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
4621 if (curbuf->b_p_bl)
4622 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
4623# ifdef FEAT_EVAL
4624 if (aborting()) /* autocmds may abort script processing */
4625 return FAIL;
4626# endif
4627
4628 /* Do filetype detection now if 'filetype' is empty. */
4629 if (*curbuf->b_p_ft == NUL)
4630 {
4631 (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE);
4632 do_modelines(FALSE);
4633 }
4634#endif
4635
4636 return OK;
4637}
4638
4639/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640 * Put file name into IObuff with quotes.
4641 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004642 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643msg_add_fname(buf, fname)
4644 buf_T *buf;
4645 char_u *fname;
4646{
4647 if (fname == NULL)
4648 fname = (char_u *)"-stdin-";
4649 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4650 IObuff[0] = '"';
4651 STRCAT(IObuff, "\" ");
4652}
4653
4654/*
4655 * Append message for text mode to IObuff.
4656 * Return TRUE if something appended.
4657 */
4658 static int
4659msg_add_fileformat(eol_type)
4660 int eol_type;
4661{
4662#ifndef USE_CRNL
4663 if (eol_type == EOL_DOS)
4664 {
4665 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4666 return TRUE;
4667 }
4668#endif
4669#ifndef USE_CR
4670 if (eol_type == EOL_MAC)
4671 {
4672 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4673 return TRUE;
4674 }
4675#endif
4676#if defined(USE_CRNL) || defined(USE_CR)
4677 if (eol_type == EOL_UNIX)
4678 {
4679 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4680 return TRUE;
4681 }
4682#endif
4683 return FALSE;
4684}
4685
4686/*
4687 * Append line and character count to IObuff.
4688 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004689 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690msg_add_lines(insert_space, lnum, nchars)
4691 int insert_space;
4692 long lnum;
4693 long nchars;
4694{
4695 char_u *p;
4696
4697 p = IObuff + STRLEN(IObuff);
4698
4699 if (insert_space)
4700 *p++ = ' ';
4701 if (shortmess(SHM_LINES))
4702 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4703 else
4704 {
4705 if (lnum == 1)
4706 STRCPY(p, _("1 line, "));
4707 else
4708 sprintf((char *)p, _("%ld lines, "), lnum);
4709 p += STRLEN(p);
4710 if (nchars == 1)
4711 STRCPY(p, _("1 character"));
4712 else
4713 sprintf((char *)p, _("%ld characters"), nchars);
4714 }
4715}
4716
4717/*
4718 * Append message for missing line separator to IObuff.
4719 */
4720 static void
4721msg_add_eol()
4722{
4723 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4724}
4725
4726/*
4727 * Check modification time of file, before writing to it.
4728 * The size isn't checked, because using a tool like "gzip" takes care of
4729 * using the same timestamp but can't set the size.
4730 */
4731 static int
4732check_mtime(buf, st)
4733 buf_T *buf;
4734 struct stat *st;
4735{
4736 if (buf->b_mtime_read != 0
4737 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4738 {
4739 msg_scroll = TRUE; /* don't overwrite messages here */
4740 msg_silent = 0; /* must give this prompt */
4741 /* don't use emsg() here, don't want to flush the buffers */
4742 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
4743 hl_attr(HLF_E));
4744 if (ask_yesno((char_u *)_("Do you really want to write to it"),
4745 TRUE) == 'n')
4746 return FAIL;
4747 msg_scroll = FALSE; /* always overwrite the file message now */
4748 }
4749 return OK;
4750}
4751
4752 static int
4753time_differs(t1, t2)
4754 long t1, t2;
4755{
4756#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
4757 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
4758 * the seconds. Since the roundoff is done when flushing the inode, the
4759 * time may change unexpectedly by one second!!! */
4760 return (t1 - t2 > 1 || t2 - t1 > 1);
4761#else
4762 return (t1 != t2);
4763#endif
4764}
4765
4766/*
4767 * Call write() to write a number of bytes to the file.
4768 * Also handles encryption and 'encoding' conversion.
4769 *
4770 * Return FAIL for failure, OK otherwise.
4771 */
4772 static int
4773buf_write_bytes(ip)
4774 struct bw_info *ip;
4775{
4776 int wlen;
4777 char_u *buf = ip->bw_buf; /* data to write */
4778 int len = ip->bw_len; /* length of data */
4779#ifdef HAS_BW_FLAGS
4780 int flags = ip->bw_flags; /* extra flags */
4781#endif
4782
4783#ifdef FEAT_MBYTE
4784 /*
4785 * Skip conversion when writing the crypt magic number or the BOM.
4786 */
4787 if (!(flags & FIO_NOCONVERT))
4788 {
4789 char_u *p;
4790 unsigned c;
4791 int n;
4792
4793 if (flags & FIO_UTF8)
4794 {
4795 /*
4796 * Convert latin1 in the buffer to UTF-8 in the file.
4797 */
4798 p = ip->bw_conv_buf; /* translate to buffer */
4799 for (wlen = 0; wlen < len; ++wlen)
4800 p += utf_char2bytes(buf[wlen], p);
4801 buf = ip->bw_conv_buf;
4802 len = (int)(p - ip->bw_conv_buf);
4803 }
4804 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
4805 {
4806 /*
4807 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
4808 * Latin1 chars in the file.
4809 */
4810 if (flags & FIO_LATIN1)
4811 p = buf; /* translate in-place (can only get shorter) */
4812 else
4813 p = ip->bw_conv_buf; /* translate to buffer */
4814 for (wlen = 0; wlen < len; wlen += n)
4815 {
4816 if (wlen == 0 && ip->bw_restlen != 0)
4817 {
4818 int l;
4819
4820 /* Use remainder of previous call. Append the start of
4821 * buf[] to get a full sequence. Might still be too
4822 * short! */
4823 l = CONV_RESTLEN - ip->bw_restlen;
4824 if (l > len)
4825 l = len;
4826 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004827 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 if (n > ip->bw_restlen + len)
4829 {
4830 /* We have an incomplete byte sequence at the end to
4831 * be written. We can't convert it without the
4832 * remaining bytes. Keep them for the next call. */
4833 if (ip->bw_restlen + len > CONV_RESTLEN)
4834 return FAIL;
4835 ip->bw_restlen += len;
4836 break;
4837 }
4838 if (n > 1)
4839 c = utf_ptr2char(ip->bw_rest);
4840 else
4841 c = ip->bw_rest[0];
4842 if (n >= ip->bw_restlen)
4843 {
4844 n -= ip->bw_restlen;
4845 ip->bw_restlen = 0;
4846 }
4847 else
4848 {
4849 ip->bw_restlen -= n;
4850 mch_memmove(ip->bw_rest, ip->bw_rest + n,
4851 (size_t)ip->bw_restlen);
4852 n = 0;
4853 }
4854 }
4855 else
4856 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004857 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858 if (n > len - wlen)
4859 {
4860 /* We have an incomplete byte sequence at the end to
4861 * be written. We can't convert it without the
4862 * remaining bytes. Keep them for the next call. */
4863 if (len - wlen > CONV_RESTLEN)
4864 return FAIL;
4865 ip->bw_restlen = len - wlen;
4866 mch_memmove(ip->bw_rest, buf + wlen,
4867 (size_t)ip->bw_restlen);
4868 break;
4869 }
4870 if (n > 1)
4871 c = utf_ptr2char(buf + wlen);
4872 else
4873 c = buf[wlen];
4874 }
4875
4876 ip->bw_conv_error |= ucs2bytes(c, &p, flags);
4877 }
4878 if (flags & FIO_LATIN1)
4879 len = (int)(p - buf);
4880 else
4881 {
4882 buf = ip->bw_conv_buf;
4883 len = (int)(p - ip->bw_conv_buf);
4884 }
4885 }
4886
4887# ifdef WIN3264
4888 else if (flags & FIO_CODEPAGE)
4889 {
4890 /*
4891 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
4892 * codepage.
4893 */
4894 char_u *from;
4895 size_t fromlen;
4896 char_u *to;
4897 int u8c;
4898 BOOL bad = FALSE;
4899 int needed;
4900
4901 if (ip->bw_restlen > 0)
4902 {
4903 /* Need to concatenate the remainder of the previous call and
4904 * the bytes of the current call. Use the end of the
4905 * conversion buffer for this. */
4906 fromlen = len + ip->bw_restlen;
4907 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
4908 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
4909 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
4910 }
4911 else
4912 {
4913 from = buf;
4914 fromlen = len;
4915 }
4916
4917 to = ip->bw_conv_buf;
4918 if (enc_utf8)
4919 {
4920 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
4921 * The buffer has been allocated to be big enough. */
4922 while (fromlen > 0)
4923 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004924 n = utf_ptr2len_len(from, fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925 if (n > (int)fromlen) /* incomplete byte sequence */
4926 break;
4927 u8c = utf_ptr2char(from);
4928 *to++ = (u8c & 0xff);
4929 *to++ = (u8c >> 8);
4930 fromlen -= n;
4931 from += n;
4932 }
4933
4934 /* Copy remainder to ip->bw_rest[] to be used for the next
4935 * call. */
4936 if (fromlen > CONV_RESTLEN)
4937 {
4938 /* weird overlong sequence */
4939 ip->bw_conv_error = TRUE;
4940 return FAIL;
4941 }
4942 mch_memmove(ip->bw_rest, from, fromlen);
4943 ip->bw_restlen = fromlen;
4944 }
4945 else
4946 {
4947 /* Convert from enc_codepage to UCS-2, to the start of the
4948 * buffer. The buffer has been allocated to be big enough. */
4949 ip->bw_restlen = 0;
4950 needed = MultiByteToWideChar(enc_codepage,
4951 MB_ERR_INVALID_CHARS, (LPCSTR)from, fromlen,
4952 NULL, 0);
4953 if (needed == 0)
4954 {
4955 /* When conversion fails there may be a trailing byte. */
4956 needed = MultiByteToWideChar(enc_codepage,
4957 MB_ERR_INVALID_CHARS, (LPCSTR)from, fromlen - 1,
4958 NULL, 0);
4959 if (needed == 0)
4960 {
4961 /* Conversion doesn't work. */
4962 ip->bw_conv_error = TRUE;
4963 return FAIL;
4964 }
4965 /* Save the trailing byte for the next call. */
4966 ip->bw_rest[0] = from[fromlen - 1];
4967 ip->bw_restlen = 1;
4968 }
4969 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
4970 (LPCSTR)from, fromlen - ip->bw_restlen,
4971 (LPWSTR)to, needed);
4972 if (needed == 0)
4973 {
4974 /* Safety check: Conversion doesn't work. */
4975 ip->bw_conv_error = TRUE;
4976 return FAIL;
4977 }
4978 to += needed * 2;
4979 }
4980
4981 fromlen = to - ip->bw_conv_buf;
4982 buf = to;
4983# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
4984 if (FIO_GET_CP(flags) == CP_UTF8)
4985 {
4986 /* Convert from UCS-2 to UTF-8, using the remainder of the
4987 * conversion buffer. Fails when out of space. */
4988 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
4989 {
4990 u8c = *from++;
4991 u8c += (*from++ << 8);
4992 to += utf_char2bytes(u8c, to);
4993 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
4994 {
4995 ip->bw_conv_error = TRUE;
4996 return FAIL;
4997 }
4998 }
4999 len = to - buf;
5000 }
5001 else
5002#endif
5003 {
5004 /* Convert from UCS-2 to the codepage, using the remainder of
5005 * the conversion buffer. If the conversion uses the default
5006 * character "0", the data doesn't fit in this encoding, so
5007 * fail. */
5008 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5009 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
5010 (LPSTR)to, ip->bw_conv_buflen - fromlen, 0, &bad);
5011 if (bad)
5012 {
5013 ip->bw_conv_error = TRUE;
5014 return FAIL;
5015 }
5016 }
5017 }
5018# endif
5019
5020# ifdef MACOS_X
5021 else if (flags & FIO_MACROMAN)
5022 {
5023 /*
5024 * Convert UTF-8 or latin1 to Apple MacRoman.
5025 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005026 char_u *from;
5027 size_t fromlen;
5028
5029 if (ip->bw_restlen > 0)
5030 {
5031 /* Need to concatenate the remainder of the previous call and
5032 * the bytes of the current call. Use the end of the
5033 * conversion buffer for this. */
5034 fromlen = len + ip->bw_restlen;
5035 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5036 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5037 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5038 }
5039 else
5040 {
5041 from = buf;
5042 fromlen = len;
5043 }
5044
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005045 if (enc2macroman(from, fromlen,
5046 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5047 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048 {
5049 ip->bw_conv_error = TRUE;
5050 return FAIL;
5051 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 }
5054# endif
5055
5056# ifdef USE_ICONV
5057 if (ip->bw_iconv_fd != (iconv_t)-1)
5058 {
5059 const char *from;
5060 size_t fromlen;
5061 char *to;
5062 size_t tolen;
5063
5064 /* Convert with iconv(). */
5065 if (ip->bw_restlen > 0)
5066 {
5067 /* Need to concatenate the remainder of the previous call and
5068 * the bytes of the current call. Use the end of the
5069 * conversion buffer for this. */
5070 fromlen = len + ip->bw_restlen;
5071 from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5072 mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
5073 mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
5074 tolen = ip->bw_conv_buflen - fromlen;
5075 }
5076 else
5077 {
5078 from = (const char *)buf;
5079 fromlen = len;
5080 tolen = ip->bw_conv_buflen;
5081 }
5082 to = (char *)ip->bw_conv_buf;
5083
5084 if (ip->bw_first)
5085 {
5086 size_t save_len = tolen;
5087
5088 /* output the initial shift state sequence */
5089 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5090
5091 /* There is a bug in iconv() on Linux (which appears to be
5092 * wide-spread) which sets "to" to NULL and messes up "tolen".
5093 */
5094 if (to == NULL)
5095 {
5096 to = (char *)ip->bw_conv_buf;
5097 tolen = save_len;
5098 }
5099 ip->bw_first = FALSE;
5100 }
5101
5102 /*
5103 * If iconv() has an error or there is not enough room, fail.
5104 */
5105 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5106 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5107 || fromlen > CONV_RESTLEN)
5108 {
5109 ip->bw_conv_error = TRUE;
5110 return FAIL;
5111 }
5112
5113 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5114 if (fromlen > 0)
5115 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5116 ip->bw_restlen = (int)fromlen;
5117
5118 buf = ip->bw_conv_buf;
5119 len = (int)((char_u *)to - ip->bw_conv_buf);
5120 }
5121# endif
5122 }
5123#endif /* FEAT_MBYTE */
5124
5125#ifdef FEAT_CRYPT
5126 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5127 {
5128 int ztemp, t, i;
5129
5130 for (i = 0; i < len; i++)
5131 {
5132 ztemp = buf[i];
5133 buf[i] = ZENCODE(ztemp, t);
5134 }
5135 }
5136#endif
5137
5138 /* Repeat the write(), it may be interrupted by a signal. */
5139 while (len)
5140 {
5141 wlen = vim_write(ip->bw_fd, buf, len);
5142 if (wlen <= 0) /* error! */
5143 return FAIL;
5144 len -= wlen;
5145 buf += wlen;
5146 }
5147 return OK;
5148}
5149
5150#ifdef FEAT_MBYTE
5151/*
5152 * Convert a Unicode character to bytes.
5153 */
5154 static int
5155ucs2bytes(c, pp, flags)
5156 unsigned c; /* in: character */
5157 char_u **pp; /* in/out: pointer to result */
5158 int flags; /* FIO_ flags */
5159{
5160 char_u *p = *pp;
5161 int error = FALSE;
5162 int cc;
5163
5164
5165 if (flags & FIO_UCS4)
5166 {
5167 if (flags & FIO_ENDIAN_L)
5168 {
5169 *p++ = c;
5170 *p++ = (c >> 8);
5171 *p++ = (c >> 16);
5172 *p++ = (c >> 24);
5173 }
5174 else
5175 {
5176 *p++ = (c >> 24);
5177 *p++ = (c >> 16);
5178 *p++ = (c >> 8);
5179 *p++ = c;
5180 }
5181 }
5182 else if (flags & (FIO_UCS2 | FIO_UTF16))
5183 {
5184 if (c >= 0x10000)
5185 {
5186 if (flags & FIO_UTF16)
5187 {
5188 /* Make two words, ten bits of the character in each. First
5189 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5190 c -= 0x10000;
5191 if (c >= 0x100000)
5192 error = TRUE;
5193 cc = ((c >> 10) & 0x3ff) + 0xd800;
5194 if (flags & FIO_ENDIAN_L)
5195 {
5196 *p++ = cc;
5197 *p++ = ((unsigned)cc >> 8);
5198 }
5199 else
5200 {
5201 *p++ = ((unsigned)cc >> 8);
5202 *p++ = cc;
5203 }
5204 c = (c & 0x3ff) + 0xdc00;
5205 }
5206 else
5207 error = TRUE;
5208 }
5209 if (flags & FIO_ENDIAN_L)
5210 {
5211 *p++ = c;
5212 *p++ = (c >> 8);
5213 }
5214 else
5215 {
5216 *p++ = (c >> 8);
5217 *p++ = c;
5218 }
5219 }
5220 else /* Latin1 */
5221 {
5222 if (c >= 0x100)
5223 {
5224 error = TRUE;
5225 *p++ = 0xBF;
5226 }
5227 else
5228 *p++ = c;
5229 }
5230
5231 *pp = p;
5232 return error;
5233}
5234
5235/*
5236 * Return TRUE if "a" and "b" are the same 'encoding'.
5237 * Ignores difference between "ansi" and "latin1", "ucs-4" and "ucs-4be", etc.
5238 */
5239 static int
5240same_encoding(a, b)
5241 char_u *a;
5242 char_u *b;
5243{
5244 int f;
5245
5246 if (STRCMP(a, b) == 0)
5247 return TRUE;
5248 f = get_fio_flags(a);
5249 return (f != 0 && get_fio_flags(b) == f);
5250}
5251
5252/*
5253 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5254 * internal conversion.
5255 * if "ptr" is an empty string, use 'encoding'.
5256 */
5257 static int
5258get_fio_flags(ptr)
5259 char_u *ptr;
5260{
5261 int prop;
5262
5263 if (*ptr == NUL)
5264 ptr = p_enc;
5265
5266 prop = enc_canon_props(ptr);
5267 if (prop & ENC_UNICODE)
5268 {
5269 if (prop & ENC_2BYTE)
5270 {
5271 if (prop & ENC_ENDIAN_L)
5272 return FIO_UCS2 | FIO_ENDIAN_L;
5273 return FIO_UCS2;
5274 }
5275 if (prop & ENC_4BYTE)
5276 {
5277 if (prop & ENC_ENDIAN_L)
5278 return FIO_UCS4 | FIO_ENDIAN_L;
5279 return FIO_UCS4;
5280 }
5281 if (prop & ENC_2WORD)
5282 {
5283 if (prop & ENC_ENDIAN_L)
5284 return FIO_UTF16 | FIO_ENDIAN_L;
5285 return FIO_UTF16;
5286 }
5287 return FIO_UTF8;
5288 }
5289 if (prop & ENC_LATIN1)
5290 return FIO_LATIN1;
5291 /* must be ENC_DBCS, requires iconv() */
5292 return 0;
5293}
5294
5295#ifdef WIN3264
5296/*
5297 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5298 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5299 * Used for conversion between 'encoding' and 'fileencoding'.
5300 */
5301 static int
5302get_win_fio_flags(ptr)
5303 char_u *ptr;
5304{
5305 int cp;
5306
5307 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5308 if (!enc_utf8 && enc_codepage <= 0)
5309 return 0;
5310
5311 cp = encname2codepage(ptr);
5312 if (cp == 0)
5313 {
5314# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5315 if (STRCMP(ptr, "utf-8") == 0)
5316 cp = CP_UTF8;
5317 else
5318# endif
5319 return 0;
5320 }
5321 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5322}
5323#endif
5324
5325#ifdef MACOS_X
5326/*
5327 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5328 * needed for the internal conversion to/from utf-8 or latin1.
5329 */
5330 static int
5331get_mac_fio_flags(ptr)
5332 char_u *ptr;
5333{
5334 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5335 && (enc_canon_props(ptr) & ENC_MACROMAN))
5336 return FIO_MACROMAN;
5337 return 0;
5338}
5339#endif
5340
5341/*
5342 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5343 * "size" must be at least 2.
5344 * Return the name of the encoding and set "*lenp" to the length.
5345 * Returns NULL when no BOM found.
5346 */
5347 static char_u *
5348check_for_bom(p, size, lenp, flags)
5349 char_u *p;
5350 long size;
5351 int *lenp;
5352 int flags;
5353{
5354 char *name = NULL;
5355 int len = 2;
5356
5357 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
5358 && (flags == FIO_ALL || flags == 0))
5359 {
5360 name = "utf-8"; /* EF BB BF */
5361 len = 3;
5362 }
5363 else if (p[0] == 0xff && p[1] == 0xfe)
5364 {
5365 if (size >= 4 && p[2] == 0 && p[3] == 0
5366 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5367 {
5368 name = "ucs-4le"; /* FF FE 00 00 */
5369 len = 4;
5370 }
5371 else if (flags == FIO_ALL || flags == (FIO_UCS2 | FIO_ENDIAN_L))
5372 name = "ucs-2le"; /* FF FE */
5373 else if (flags == (FIO_UTF16 | FIO_ENDIAN_L))
5374 name = "utf-16le"; /* FF FE */
5375 }
5376 else if (p[0] == 0xfe && p[1] == 0xff
5377 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5378 {
5379 if (flags == FIO_UTF16)
5380 name = "utf-16"; /* FE FF */
5381 else
5382 name = "ucs-2"; /* FE FF */
5383 }
5384 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5385 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5386 {
5387 name = "ucs-4"; /* 00 00 FE FF */
5388 len = 4;
5389 }
5390
5391 *lenp = len;
5392 return (char_u *)name;
5393}
5394
5395/*
5396 * Generate a BOM in "buf[4]" for encoding "name".
5397 * Return the length of the BOM (zero when no BOM).
5398 */
5399 static int
5400make_bom(buf, name)
5401 char_u *buf;
5402 char_u *name;
5403{
5404 int flags;
5405 char_u *p;
5406
5407 flags = get_fio_flags(name);
5408
5409 /* Can't put a BOM in a non-Unicode file. */
5410 if (flags == FIO_LATIN1 || flags == 0)
5411 return 0;
5412
5413 if (flags == FIO_UTF8) /* UTF-8 */
5414 {
5415 buf[0] = 0xef;
5416 buf[1] = 0xbb;
5417 buf[2] = 0xbf;
5418 return 3;
5419 }
5420 p = buf;
5421 (void)ucs2bytes(0xfeff, &p, flags);
5422 return (int)(p - buf);
5423}
5424#endif
5425
5426/*
5427 * Try to find a shortname by comparing the fullname with the current
5428 * directory.
5429 * Returns NULL if not shorter name possible, pointer into "full_path"
5430 * otherwise.
5431 */
5432 char_u *
5433shorten_fname(full_path, dir_name)
5434 char_u *full_path;
5435 char_u *dir_name;
5436{
5437 int len;
5438 char_u *p;
5439
5440 if (full_path == NULL)
5441 return NULL;
5442 len = (int)STRLEN(dir_name);
5443 if (fnamencmp(dir_name, full_path, len) == 0)
5444 {
5445 p = full_path + len;
5446#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5447 /*
5448 * MSDOS: when a file is in the root directory, dir_name will end in a
5449 * slash, since C: by itself does not define a specific dir. In this
5450 * case p may already be correct. <negri>
5451 */
5452 if (!((len > 2) && (*(p - 2) == ':')))
5453#endif
5454 {
5455 if (vim_ispathsep(*p))
5456 ++p;
5457#ifndef VMS /* the path separator is always part of the path */
5458 else
5459 p = NULL;
5460#endif
5461 }
5462 }
5463#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5464 /*
5465 * When using a file in the current drive, remove the drive name:
5466 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5467 * a floppy from "A:\dir" to "B:\dir".
5468 */
5469 else if (len > 3
5470 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5471 && full_path[1] == ':'
5472 && vim_ispathsep(full_path[2]))
5473 p = full_path + 2;
5474#endif
5475 else
5476 p = NULL;
5477 return p;
5478}
5479
5480/*
5481 * Shorten filenames for all buffers.
5482 * When "force" is TRUE: Use full path from now on for files currently being
5483 * edited, both for file name and swap file name. Try to shorten the file
5484 * names a bit, if safe to do so.
5485 * When "force" is FALSE: Only try to shorten absolute file names.
5486 * For buffers that have buftype "nofile" or "scratch": never change the file
5487 * name.
5488 */
5489 void
5490shorten_fnames(force)
5491 int force;
5492{
5493 char_u dirname[MAXPATHL];
5494 buf_T *buf;
5495 char_u *p;
5496
5497 mch_dirname(dirname, MAXPATHL);
5498 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5499 {
5500 if (buf->b_fname != NULL
5501#ifdef FEAT_QUICKFIX
5502 && !bt_nofile(buf)
5503#endif
5504 && !path_with_url(buf->b_fname)
5505 && (force
5506 || buf->b_sfname == NULL
5507 || mch_isFullName(buf->b_sfname)))
5508 {
5509 vim_free(buf->b_sfname);
5510 buf->b_sfname = NULL;
5511 p = shorten_fname(buf->b_ffname, dirname);
5512 if (p != NULL)
5513 {
5514 buf->b_sfname = vim_strsave(p);
5515 buf->b_fname = buf->b_sfname;
5516 }
5517 if (p == NULL || buf->b_fname == NULL)
5518 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005519 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005520
5521 /* Always make the swap file name a full path, a "nofile" buffer may
5522 * also have a swap file. */
5523 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005524 }
5525#ifdef FEAT_WINDOWS
5526 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005527 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005528#endif
5529}
5530
5531#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5532 || defined(FEAT_GUI_MSWIN) \
5533 || defined(FEAT_GUI_MAC) \
5534 || defined(PROTO)
5535/*
5536 * Shorten all filenames in "fnames[count]" by current directory.
5537 */
5538 void
5539shorten_filenames(fnames, count)
5540 char_u **fnames;
5541 int count;
5542{
5543 int i;
5544 char_u dirname[MAXPATHL];
5545 char_u *p;
5546
5547 if (fnames == NULL || count < 1)
5548 return;
5549 mch_dirname(dirname, sizeof(dirname));
5550 for (i = 0; i < count; ++i)
5551 {
5552 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5553 {
5554 /* shorten_fname() returns pointer in given "fnames[i]". If free
5555 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5556 * "p" first then free fnames[i]. */
5557 p = vim_strsave(p);
5558 vim_free(fnames[i]);
5559 fnames[i] = p;
5560 }
5561 }
5562}
5563#endif
5564
5565/*
5566 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5567 * fo_o_h.ext for MSDOS or when shortname option set.
5568 *
5569 * Assumed that fname is a valid name found in the filesystem we assure that
5570 * the return value is a different name and ends in 'ext'.
5571 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5572 * characters otherwise.
5573 * Space for the returned name is allocated, must be freed later.
5574 * Returns NULL when out of memory.
5575 */
5576 char_u *
5577modname(fname, ext, prepend_dot)
5578 char_u *fname, *ext;
5579 int prepend_dot; /* may prepend a '.' to file name */
5580{
5581 return buf_modname(
5582#ifdef SHORT_FNAME
5583 TRUE,
5584#else
5585 (curbuf->b_p_sn || curbuf->b_shortname),
5586#endif
5587 fname, ext, prepend_dot);
5588}
5589
5590 char_u *
5591buf_modname(shortname, fname, ext, prepend_dot)
5592 int shortname; /* use 8.3 file name */
5593 char_u *fname, *ext;
5594 int prepend_dot; /* may prepend a '.' to file name */
5595{
5596 char_u *retval;
5597 char_u *s;
5598 char_u *e;
5599 char_u *ptr;
5600 int fnamelen, extlen;
5601
5602 extlen = (int)STRLEN(ext);
5603
5604 /*
5605 * If there is no file name we must get the name of the current directory
5606 * (we need the full path in case :cd is used).
5607 */
5608 if (fname == NULL || *fname == NUL)
5609 {
5610 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5611 if (retval == NULL)
5612 return NULL;
5613 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5614 (fnamelen = (int)STRLEN(retval)) == 0)
5615 {
5616 vim_free(retval);
5617 return NULL;
5618 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005619 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005620 {
5621 retval[fnamelen++] = PATHSEP;
5622 retval[fnamelen] = NUL;
5623 }
5624#ifndef SHORT_FNAME
5625 prepend_dot = FALSE; /* nothing to prepend a dot to */
5626#endif
5627 }
5628 else
5629 {
5630 fnamelen = (int)STRLEN(fname);
5631 retval = alloc((unsigned)(fnamelen + extlen + 3));
5632 if (retval == NULL)
5633 return NULL;
5634 STRCPY(retval, fname);
5635#ifdef VMS
5636 vms_remove_version(retval); /* we do not need versions here */
5637#endif
5638 }
5639
5640 /*
5641 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5642 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5643 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5644 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5645 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005646 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 {
5648#ifndef RISCOS
5649 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005650# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005651 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005652# else
5653# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005654 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005655# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005656# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657 )
5658 if (*ptr == '.') /* replace '.' by '_' */
5659 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005660#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005662 {
5663 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005664 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005665 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667
5668 /* the file name has at most BASENAMELEN characters. */
5669#ifndef SHORT_FNAME
5670 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5671 ptr[BASENAMELEN] = '\0';
5672#endif
5673
5674 s = ptr + STRLEN(ptr);
5675
5676 /*
5677 * For 8.3 file names we may have to reduce the length.
5678 */
5679#ifdef USE_LONG_FNAME
5680 if (!USE_LONG_FNAME || shortname)
5681#else
5682# ifndef SHORT_FNAME
5683 if (shortname)
5684# endif
5685#endif
5686 {
5687 /*
5688 * If there is no file name, or the file name ends in '/', and the
5689 * extension starts with '.', put a '_' before the dot, because just
5690 * ".ext" is invalid.
5691 */
5692 if (fname == NULL || *fname == NUL
5693 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5694 {
5695#ifdef RISCOS
5696 if (*ext == '/')
5697#else
5698 if (*ext == '.')
5699#endif
5700 *s++ = '_';
5701 }
5702 /*
5703 * If the extension starts with '.', truncate the base name at 8
5704 * characters
5705 */
5706#ifdef RISCOS
5707 /* We normally use '/', but swap files are '_' */
5708 else if (*ext == '/' || *ext == '_')
5709#else
5710 else if (*ext == '.')
5711#endif
5712 {
5713 if (s - ptr > (size_t)8)
5714 {
5715 s = ptr + 8;
5716 *s = '\0';
5717 }
5718 }
5719 /*
5720 * If the extension doesn't start with '.', and the file name
5721 * doesn't have an extension yet, append a '.'
5722 */
5723#ifdef RISCOS
5724 else if ((e = vim_strchr(ptr, '/')) == NULL)
5725 *s++ = '/';
5726#else
5727 else if ((e = vim_strchr(ptr, '.')) == NULL)
5728 *s++ = '.';
5729#endif
5730 /*
5731 * If the extension doesn't start with '.', and there already is an
5732 * extension, it may need to be tructated
5733 */
5734 else if ((int)STRLEN(e) + extlen > 4)
5735 s = e + 4 - extlen;
5736 }
5737#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5738 /*
5739 * If there is no file name, and the extension starts with '.', put a
5740 * '_' before the dot, because just ".ext" may be invalid if it's on a
5741 * FAT partition, and on HPFS it doesn't matter.
5742 */
5743 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5744 *s++ = '_';
5745#endif
5746
5747 /*
5748 * Append the extention.
5749 * ext can start with '.' and cannot exceed 3 more characters.
5750 */
5751 STRCPY(s, ext);
5752
5753#ifndef SHORT_FNAME
5754 /*
5755 * Prepend the dot.
5756 */
5757 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5758#ifdef RISCOS
5759 '/'
5760#else
5761 '.'
5762#endif
5763#ifdef USE_LONG_FNAME
5764 && USE_LONG_FNAME
5765#endif
5766 )
5767 {
5768 mch_memmove(e + 1, e, STRLEN(e) + 1);
5769#ifdef RISCOS
5770 *e = '/';
5771#else
5772 *e = '.';
5773#endif
5774 }
5775#endif
5776
5777 /*
5778 * Check that, after appending the extension, the file name is really
5779 * different.
5780 */
5781 if (fname != NULL && STRCMP(fname, retval) == 0)
5782 {
5783 /* we search for a character that can be replaced by '_' */
5784 while (--s >= ptr)
5785 {
5786 if (*s != '_')
5787 {
5788 *s = '_';
5789 break;
5790 }
5791 }
5792 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5793 *ptr = 'v';
5794 }
5795 return retval;
5796}
5797
5798/*
5799 * Like fgets(), but if the file line is too long, it is truncated and the
5800 * rest of the line is thrown away. Returns TRUE for end-of-file.
5801 */
5802 int
5803vim_fgets(buf, size, fp)
5804 char_u *buf;
5805 int size;
5806 FILE *fp;
5807{
5808 char *eof;
5809#define FGETS_SIZE 200
5810 char tbuf[FGETS_SIZE];
5811
5812 buf[size - 2] = NUL;
5813#ifdef USE_CR
5814 eof = fgets_cr((char *)buf, size, fp);
5815#else
5816 eof = fgets((char *)buf, size, fp);
5817#endif
5818 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5819 {
5820 buf[size - 1] = NUL; /* Truncate the line */
5821
5822 /* Now throw away the rest of the line: */
5823 do
5824 {
5825 tbuf[FGETS_SIZE - 2] = NUL;
5826#ifdef USE_CR
5827 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
5828#else
5829 fgets((char *)tbuf, FGETS_SIZE, fp);
5830#endif
5831 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
5832 }
5833 return (eof == NULL);
5834}
5835
5836#if defined(USE_CR) || defined(PROTO)
5837/*
5838 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
5839 * Returns TRUE for end-of-file.
5840 * Only used for the Mac, because it's much slower than vim_fgets().
5841 */
5842 int
5843tag_fgets(buf, size, fp)
5844 char_u *buf;
5845 int size;
5846 FILE *fp;
5847{
5848 int i = 0;
5849 int c;
5850 int eof = FALSE;
5851
5852 for (;;)
5853 {
5854 c = fgetc(fp);
5855 if (c == EOF)
5856 {
5857 eof = TRUE;
5858 break;
5859 }
5860 if (c == '\r')
5861 {
5862 /* Always store a NL for end-of-line. */
5863 if (i < size - 1)
5864 buf[i++] = '\n';
5865 c = fgetc(fp);
5866 if (c != '\n') /* Macintosh format: single CR. */
5867 ungetc(c, fp);
5868 break;
5869 }
5870 if (i < size - 1)
5871 buf[i++] = c;
5872 if (c == '\n')
5873 break;
5874 }
5875 buf[i] = NUL;
5876 return eof;
5877}
5878#endif
5879
5880/*
5881 * rename() only works if both files are on the same file system, this
5882 * function will (attempts to?) copy the file across if rename fails -- webb
5883 * Return -1 for failure, 0 for success.
5884 */
5885 int
5886vim_rename(from, to)
5887 char_u *from;
5888 char_u *to;
5889{
5890 int fd_in;
5891 int fd_out;
5892 int n;
5893 char *errmsg = NULL;
5894 char *buffer;
5895#ifdef AMIGA
5896 BPTR flock;
5897#endif
5898 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005899 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005900#ifdef HAVE_ACL
5901 vim_acl_T acl; /* ACL from original file */
5902#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903
5904 /*
5905 * When the names are identical, there is nothing to do.
5906 */
5907 if (fnamecmp(from, to) == 0)
5908 return 0;
5909
5910 /*
5911 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
5912 */
5913 if (mch_stat((char *)from, &st) < 0)
5914 return -1;
5915
5916 /*
5917 * Delete the "to" file, this is required on some systems to make the
5918 * mch_rename() work, on other systems it makes sure that we don't have
5919 * two files when the mch_rename() fails.
5920 */
5921
5922#ifdef AMIGA
5923 /*
5924 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
5925 * that the name of the "to" file is the same as the "from" file, even
5926 * though the names are different. To avoid the chance of accidently
5927 * deleting the "from" file (horror!) we lock it during the remove.
5928 *
5929 * When used for making a backup before writing the file: This should not
5930 * happen with ":w", because startscript() should detect this problem and
5931 * set buf->b_shortname, causing modname() to return a correct ".bak" file
5932 * name. This problem does exist with ":w filename", but then the
5933 * original file will be somewhere else so the backup isn't really
5934 * important. If autoscripting is off the rename may fail.
5935 */
5936 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
5937#endif
5938 mch_remove(to);
5939#ifdef AMIGA
5940 if (flock)
5941 UnLock(flock);
5942#endif
5943
5944 /*
5945 * First try a normal rename, return if it works.
5946 */
5947 if (mch_rename((char *)from, (char *)to) == 0)
5948 return 0;
5949
5950 /*
5951 * Rename() failed, try copying the file.
5952 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005953 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005954#ifdef HAVE_ACL
5955 /* For systems that support ACL: get the ACL from the original file. */
5956 acl = mch_get_acl(from);
5957#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005958 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
5959 if (fd_in == -1)
5960 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005961
5962 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00005963 fd_out = mch_open((char *)to,
5964 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965 if (fd_out == -1)
5966 {
5967 close(fd_in);
5968 return -1;
5969 }
5970
5971 buffer = (char *)alloc(BUFSIZE);
5972 if (buffer == NULL)
5973 {
5974 close(fd_in);
5975 close(fd_out);
5976 return -1;
5977 }
5978
5979 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
5980 if (vim_write(fd_out, buffer, n) != n)
5981 {
5982 errmsg = _("E208: Error writing to \"%s\"");
5983 break;
5984 }
5985
5986 vim_free(buffer);
5987 close(fd_in);
5988 if (close(fd_out) < 0)
5989 errmsg = _("E209: Error closing \"%s\"");
5990 if (n < 0)
5991 {
5992 errmsg = _("E210: Error reading \"%s\"");
5993 to = from;
5994 }
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005995#ifndef UNIX /* for Unix mch_open() already set ther permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005996 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005997#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005998#ifdef HAVE_ACL
5999 mch_set_acl(to, acl);
6000#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001 if (errmsg != NULL)
6002 {
6003 EMSG2(errmsg, to);
6004 return -1;
6005 }
6006 mch_remove(from);
6007 return 0;
6008}
6009
6010static int already_warned = FALSE;
6011
6012/*
6013 * Check if any not hidden buffer has been changed.
6014 * Postpone the check if there are characters in the stuff buffer, a global
6015 * command is being executed, a mapping is being executed or an autocommand is
6016 * busy.
6017 * Returns TRUE if some message was written (screen should be redrawn and
6018 * cursor positioned).
6019 */
6020 int
6021check_timestamps(focus)
6022 int focus; /* called for GUI focus event */
6023{
6024 buf_T *buf;
6025 int didit = 0;
6026 int n;
6027
6028 /* Don't check timestamps while system() or another low-level function may
6029 * cause us to lose and gain focus. */
6030 if (no_check_timestamps > 0)
6031 return FALSE;
6032
6033 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6034 * event and we would keep on checking if the file is steadily growing.
6035 * Do check again after typing something. */
6036 if (focus && did_check_timestamps)
6037 {
6038 need_check_timestamps = TRUE;
6039 return FALSE;
6040 }
6041
6042 if (!stuff_empty() || global_busy || !typebuf_typed()
6043#ifdef FEAT_AUTOCMD
6044 || autocmd_busy
6045#endif
6046 )
6047 need_check_timestamps = TRUE; /* check later */
6048 else
6049 {
6050 ++no_wait_return;
6051 did_check_timestamps = TRUE;
6052 already_warned = FALSE;
6053 for (buf = firstbuf; buf != NULL; )
6054 {
6055 /* Only check buffers in a window. */
6056 if (buf->b_nwindows > 0)
6057 {
6058 n = buf_check_timestamp(buf, focus);
6059 if (didit < n)
6060 didit = n;
6061 if (n > 0 && !buf_valid(buf))
6062 {
6063 /* Autocommands have removed the buffer, start at the
6064 * first one again. */
6065 buf = firstbuf;
6066 continue;
6067 }
6068 }
6069 buf = buf->b_next;
6070 }
6071 --no_wait_return;
6072 need_check_timestamps = FALSE;
6073 if (need_wait_return && didit == 2)
6074 {
6075 /* make sure msg isn't overwritten */
6076 msg_puts((char_u *)"\n");
6077 out_flush();
6078 }
6079 }
6080 return didit;
6081}
6082
6083/*
6084 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6085 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6086 * empty.
6087 */
6088 static int
6089move_lines(frombuf, tobuf)
6090 buf_T *frombuf;
6091 buf_T *tobuf;
6092{
6093 buf_T *tbuf = curbuf;
6094 int retval = OK;
6095 linenr_T lnum;
6096 char_u *p;
6097
6098 /* Copy the lines in "frombuf" to "tobuf". */
6099 curbuf = tobuf;
6100 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6101 {
6102 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6103 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6104 {
6105 vim_free(p);
6106 retval = FAIL;
6107 break;
6108 }
6109 vim_free(p);
6110 }
6111
6112 /* Delete all the lines in "frombuf". */
6113 if (retval != FAIL)
6114 {
6115 curbuf = frombuf;
6116 while (!bufempty())
6117 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE) == FAIL)
6118 {
6119 /* Oops! We could try putting back the saved lines, but that
6120 * might fail again... */
6121 retval = FAIL;
6122 break;
6123 }
6124 }
6125
6126 curbuf = tbuf;
6127 return retval;
6128}
6129
6130/*
6131 * Check if buffer "buf" has been changed.
6132 * Also check if the file for a new buffer unexpectedly appeared.
6133 * return 1 if a changed buffer was found.
6134 * return 2 if a message has been displayed.
6135 * return 0 otherwise.
6136 */
6137/*ARGSUSED*/
6138 int
6139buf_check_timestamp(buf, focus)
6140 buf_T *buf;
6141 int focus; /* called for GUI focus event */
6142{
6143 struct stat st;
6144 int stat_res;
6145 int retval = 0;
6146 char_u *path;
6147 char_u *tbuf;
6148 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006149 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150 int helpmesg = FALSE;
6151 int reload = FALSE;
6152#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6153 int can_reload = FALSE;
6154#endif
6155 size_t orig_size = buf->b_orig_size;
6156 int orig_mode = buf->b_orig_mode;
6157#ifdef FEAT_GUI
6158 int save_mouse_correct = need_mouse_correct;
6159#endif
6160#ifdef FEAT_AUTOCMD
6161 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006162 int n;
6163 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006164#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006165 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006166
6167 /* If there is no file name, the buffer is not loaded, 'buftype' is
6168 * set, we are in the middle of a save or being called recursively: ignore
6169 * this buffer. */
6170 if (buf->b_ffname == NULL
6171 || buf->b_ml.ml_mfp == NULL
6172#if defined(FEAT_QUICKFIX)
6173 || *buf->b_p_bt != NUL
6174#endif
6175 || buf->b_saving
6176#ifdef FEAT_AUTOCMD
6177 || busy
6178#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006179#ifdef FEAT_NETBEANS_INTG
6180 || isNetbeansBuffer(buf)
6181#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006182 )
6183 return 0;
6184
6185 if ( !(buf->b_flags & BF_NOTEDITED)
6186 && buf->b_mtime != 0
6187 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6188 || time_differs((long)st.st_mtime, buf->b_mtime)
6189#ifdef HAVE_ST_MODE
6190 || (int)st.st_mode != buf->b_orig_mode
6191#else
6192 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6193#endif
6194 ))
6195 {
6196 retval = 1;
6197
Bram Moolenaar316059c2006-01-14 21:18:42 +00006198 /* set b_mtime to stop further warnings (e.g., when executing
6199 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200 if (stat_res < 0)
6201 {
6202 buf->b_mtime = 0;
6203 buf->b_orig_size = 0;
6204 buf->b_orig_mode = 0;
6205 }
6206 else
6207 buf_store_time(buf, &st, buf->b_ffname);
6208
6209 /* Don't do anything for a directory. Might contain the file
6210 * explorer. */
6211 if (mch_isdir(buf->b_fname))
6212 ;
6213
6214 /*
6215 * If 'autoread' is set, the buffer has no changes and the file still
6216 * exists, reload the buffer. Use the buffer-local option value if it
6217 * was set, the global option value otherwise.
6218 */
6219 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6220 && !bufIsChanged(buf) && stat_res >= 0)
6221 reload = TRUE;
6222 else
6223 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006224 if (stat_res < 0)
6225 reason = "deleted";
6226 else if (bufIsChanged(buf))
6227 reason = "conflict";
6228 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6229 reason = "changed";
6230 else if (orig_mode != buf->b_orig_mode)
6231 reason = "mode";
6232 else
6233 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006234
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006235#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006236 /*
6237 * Only give the warning if there are no FileChangedShell
6238 * autocommands.
6239 * Avoid being called recursively by setting "busy".
6240 */
6241 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006242# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006243 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6244 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006245# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6247 buf->b_fname, buf->b_fname, FALSE, buf);
6248 busy = FALSE;
6249 if (n)
6250 {
6251 if (!buf_valid(buf))
6252 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006253# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006254 s = get_vim_var_str(VV_FCS_CHOICE);
6255 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6256 reload = TRUE;
6257 else if (STRCMP(s, "ask") == 0)
6258 n = FALSE;
6259 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006260# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006261 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006262 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006263 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006264#endif
6265 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006266 if (*reason == 'd')
6267 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268 else
6269 {
6270 helpmesg = TRUE;
6271#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6272 can_reload = TRUE;
6273#endif
6274 /*
6275 * Check if the file contents really changed to avoid
6276 * giving a warning when only the timestamp was set (e.g.,
6277 * checked out of CVS). Always warn when the buffer was
6278 * changed.
6279 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006280 if (reason[2] == 'n')
6281 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006282 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006283 mesg2 = _("See \":help W12\" for more info.");
6284 }
6285 else if (reason[1] == 'h')
6286 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006288 mesg2 = _("See \":help W11\" for more info.");
6289 }
6290 else if (*reason == 'm')
6291 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006293 mesg2 = _("See \":help W16\" for more info.");
6294 }
6295 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 }
6297 }
6298 }
6299
6300 }
6301 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6302 && vim_fexists(buf->b_ffname))
6303 {
6304 retval = 1;
6305 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6306 buf->b_flags |= BF_NEW_W;
6307#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6308 can_reload = TRUE;
6309#endif
6310 }
6311
6312 if (mesg != NULL)
6313 {
6314 path = home_replace_save(buf, buf->b_fname);
6315 if (path != NULL)
6316 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006317 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318 mesg2 = "";
6319 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6320 + STRLEN(mesg2) + 2));
6321 sprintf((char *)tbuf, mesg, path);
6322#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6323 if (can_reload)
6324 {
6325 if (*mesg2 != NUL)
6326 {
6327 STRCAT(tbuf, "\n");
6328 STRCAT(tbuf, mesg2);
6329 }
6330 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6331 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6332 reload = TRUE;
6333 }
6334 else
6335#endif
6336 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6337 {
6338 if (*mesg2 != NUL)
6339 {
6340 STRCAT(tbuf, "; ");
6341 STRCAT(tbuf, mesg2);
6342 }
6343 EMSG(tbuf);
6344 retval = 2;
6345 }
6346 else
6347 {
Bram Moolenaared203462004-06-16 11:19:22 +00006348# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006349 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006350# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006351 {
6352 msg_start();
6353 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6354 if (*mesg2 != NUL)
6355 msg_puts_attr((char_u *)mesg2,
6356 hl_attr(HLF_W) + MSG_HIST);
6357 msg_clr_eos();
6358 (void)msg_end();
6359 if (emsg_silent == 0)
6360 {
6361 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006362# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006363 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006364# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006365 /* give the user some time to think about it */
6366 ui_delay(1000L, TRUE);
6367
6368 /* don't redraw and erase the message */
6369 redraw_cmdline = FALSE;
6370 }
6371 }
6372 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006373 }
6374
6375 vim_free(path);
6376 vim_free(tbuf);
6377 }
6378 }
6379
6380 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006381 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006382 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006383
6384#ifdef FEAT_GUI
6385 /* restore this in case an autocommand has set it; it would break
6386 * 'mousefocus' */
6387 need_mouse_correct = save_mouse_correct;
6388#endif
6389
6390 return retval;
6391}
6392
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006393/*
6394 * Reload a buffer that is already loaded.
6395 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006396 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6397 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006398 */
6399 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006400buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006401 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006402 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006403{
6404 exarg_T ea;
6405 pos_T old_cursor;
6406 linenr_T old_topline;
6407 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006408 buf_T *savebuf;
6409 int saved = OK;
6410#ifdef FEAT_AUTOCMD
6411 aco_save_T aco;
6412
6413 /* set curwin/curbuf for "buf" and save some things */
6414 aucmd_prepbuf(&aco, buf);
6415#else
6416 buf_T *save_curbuf = curbuf;
6417
6418 curbuf = buf;
6419 curwin->w_buffer = buf;
6420#endif
6421
6422 /* We only want to read the text from the file, not reset the syntax
6423 * highlighting, clear marks, diff status, etc. Force the fileformat
6424 * and encoding to be the same. */
6425 if (prep_exarg(&ea, buf) == OK)
6426 {
6427 old_cursor = curwin->w_cursor;
6428 old_topline = curwin->w_topline;
6429
6430 /*
6431 * To behave like when a new file is edited (matters for
6432 * BufReadPost autocommands) we first need to delete the current
6433 * buffer contents. But if reading the file fails we should keep
6434 * the old contents. Can't use memory only, the file might be
6435 * too big. Use a hidden buffer to move the buffer contents to.
6436 */
6437 if (bufempty())
6438 savebuf = NULL;
6439 else
6440 {
6441 /* Allocate a buffer without putting it in the buffer list. */
6442 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
6443 if (savebuf != NULL)
6444 {
6445 /* Open the memline. */
6446 curbuf = savebuf;
6447 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006448 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006449 curbuf = buf;
6450 curwin->w_buffer = buf;
6451 }
6452 if (savebuf == NULL || saved == FAIL
6453 || move_lines(buf, savebuf) == FAIL)
6454 {
6455 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6456 buf->b_fname);
6457 saved = FAIL;
6458 }
6459 }
6460
6461 if (saved == OK)
6462 {
6463 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6464#ifdef FEAT_AUTOCMD
6465 keep_filetype = TRUE; /* don't detect 'filetype' */
6466#endif
6467 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6468 (linenr_T)0,
6469 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6470 {
6471#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6472 if (!aborting())
6473#endif
6474 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
6475 if (savebuf != NULL)
6476 {
6477 /* Put the text back from the save buffer. First
6478 * delete any lines that readfile() added. */
6479 while (!bufempty())
6480 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE)
6481 == FAIL)
6482 break;
6483 (void)move_lines(savebuf, buf);
6484 }
6485 }
6486 else
6487 {
6488 /* Mark the buffer as unmodified and free undo info. */
6489 unchanged(buf, TRUE);
6490 u_blockfree(buf);
6491 u_clearall(buf);
6492 }
6493 }
6494 vim_free(ea.cmd);
6495
6496 if (savebuf != NULL)
6497 wipe_buffer(savebuf, FALSE);
6498
6499#ifdef FEAT_DIFF
6500 /* Invalidate diff info if necessary. */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006501 diff_invalidate(buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006502#endif
6503
6504 /* Restore the topline and cursor position and check it (lines may
6505 * have been removed). */
6506 if (old_topline > curbuf->b_ml.ml_line_count)
6507 curwin->w_topline = curbuf->b_ml.ml_line_count;
6508 else
6509 curwin->w_topline = old_topline;
6510 curwin->w_cursor = old_cursor;
6511 check_cursor();
6512 update_topline();
6513#ifdef FEAT_AUTOCMD
6514 keep_filetype = FALSE;
6515#endif
6516#ifdef FEAT_FOLDING
6517 {
6518 win_T *wp;
6519
6520 /* Update folds unless they are defined manually. */
6521 FOR_ALL_WINDOWS(wp)
6522 if (wp->w_buffer == curwin->w_buffer
6523 && !foldmethodIsManual(wp))
6524 foldUpdateAll(wp);
6525 }
6526#endif
6527 /* If the mode didn't change and 'readonly' was set, keep the old
6528 * value; the user probably used the ":view" command. But don't
6529 * reset it, might have had a read error. */
6530 if (orig_mode == curbuf->b_orig_mode)
6531 curbuf->b_p_ro |= old_ro;
6532 }
6533
6534#ifdef FEAT_AUTOCMD
6535 /* restore curwin/curbuf and a few other things */
6536 aucmd_restbuf(&aco);
6537 /* Careful: autocommands may have made "buf" invalid! */
6538#else
6539 curwin->w_buffer = save_curbuf;
6540 curbuf = save_curbuf;
6541#endif
6542}
6543
Bram Moolenaar071d4272004-06-13 20:20:40 +00006544/*ARGSUSED*/
6545 void
6546buf_store_time(buf, st, fname)
6547 buf_T *buf;
6548 struct stat *st;
6549 char_u *fname;
6550{
6551 buf->b_mtime = (long)st->st_mtime;
6552 buf->b_orig_size = (size_t)st->st_size;
6553#ifdef HAVE_ST_MODE
6554 buf->b_orig_mode = (int)st->st_mode;
6555#else
6556 buf->b_orig_mode = mch_getperm(fname);
6557#endif
6558}
6559
6560/*
6561 * Adjust the line with missing eol, used for the next write.
6562 * Used for do_filter(), when the input lines for the filter are deleted.
6563 */
6564 void
6565write_lnum_adjust(offset)
6566 linenr_T offset;
6567{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006568 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006569 write_no_eol_lnum += offset;
6570}
6571
6572#if defined(TEMPDIRNAMES) || defined(PROTO)
6573static long temp_count = 0; /* Temp filename counter. */
6574
6575/*
6576 * Delete the temp directory and all files it contains.
6577 */
6578 void
6579vim_deltempdir()
6580{
6581 char_u **files;
6582 int file_count;
6583 int i;
6584
6585 if (vim_tempdir != NULL)
6586 {
6587 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6588 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6589 EW_DIR|EW_FILE|EW_SILENT) == OK)
6590 {
6591 for (i = 0; i < file_count; ++i)
6592 mch_remove(files[i]);
6593 FreeWild(file_count, files);
6594 }
6595 gettail(NameBuff)[-1] = NUL;
6596 (void)mch_rmdir(NameBuff);
6597
6598 vim_free(vim_tempdir);
6599 vim_tempdir = NULL;
6600 }
6601}
6602#endif
6603
6604/*
6605 * vim_tempname(): Return a unique name that can be used for a temp file.
6606 *
6607 * The temp file is NOT created.
6608 *
6609 * The returned pointer is to allocated memory.
6610 * The returned pointer is NULL if no valid name was found.
6611 */
6612/*ARGSUSED*/
6613 char_u *
6614vim_tempname(extra_char)
6615 int extra_char; /* character to use in the name instead of '?' */
6616{
6617#ifdef USE_TMPNAM
6618 char_u itmp[L_tmpnam]; /* use tmpnam() */
6619#else
6620 char_u itmp[TEMPNAMELEN];
6621#endif
6622
6623#ifdef TEMPDIRNAMES
6624 static char *(tempdirs[]) = {TEMPDIRNAMES};
6625 int i;
6626 long nr;
6627 long off;
6628# ifndef EEXIST
6629 struct stat st;
6630# endif
6631
6632 /*
6633 * This will create a directory for private use by this instance of Vim.
6634 * This is done once, and the same directory is used for all temp files.
6635 * This method avoids security problems because of symlink attacks et al.
6636 * It's also a bit faster, because we only need to check for an existing
6637 * file when creating the directory and not for each temp file.
6638 */
6639 if (vim_tempdir == NULL)
6640 {
6641 /*
6642 * Try the entries in TEMPDIRNAMES to create the temp directory.
6643 */
6644 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6645 {
6646 /* expand $TMP, leave room for "/v1100000/999999999" */
6647 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6648 if (mch_isdir(itmp)) /* directory exists */
6649 {
6650# ifdef __EMX__
6651 /* If $TMP contains a forward slash (perhaps using bash or
6652 * tcsh), don't add a backslash, use a forward slash!
6653 * Adding 2 backslashes didn't work. */
6654 if (vim_strchr(itmp, '/') != NULL)
6655 STRCAT(itmp, "/");
6656 else
6657# endif
6658 add_pathsep(itmp);
6659
6660 /* Get an arbitrary number of up to 6 digits. When it's
6661 * unlikely that it already exists it will be faster,
6662 * otherwise it doesn't matter. The use of mkdir() avoids any
6663 * security problems because of the predictable number. */
6664 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6665
6666 /* Try up to 10000 different values until we find a name that
6667 * doesn't exist. */
6668 for (off = 0; off < 10000L; ++off)
6669 {
6670 int r;
6671#if defined(UNIX) || defined(VMS)
6672 mode_t umask_save;
6673#endif
6674
6675 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6676# ifndef EEXIST
6677 /* If mkdir() does not set errno to EEXIST, check for
6678 * existing file here. There is a race condition then,
6679 * although it's fail-safe. */
6680 if (mch_stat((char *)itmp, &st) >= 0)
6681 continue;
6682# endif
6683#if defined(UNIX) || defined(VMS)
6684 /* Make sure the umask doesn't remove the executable bit.
6685 * "repl" has been reported to use "177". */
6686 umask_save = umask(077);
6687#endif
6688 r = vim_mkdir(itmp, 0700);
6689#if defined(UNIX) || defined(VMS)
6690 (void)umask(umask_save);
6691#endif
6692 if (r == 0)
6693 {
6694 char_u *buf;
6695
6696 /* Directory was created, use this name.
6697 * Expand to full path; When using the current
6698 * directory a ":cd" would confuse us. */
6699 buf = alloc((unsigned)MAXPATHL + 1);
6700 if (buf != NULL)
6701 {
6702 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6703 == FAIL)
6704 STRCPY(buf, itmp);
6705# ifdef __EMX__
6706 if (vim_strchr(buf, '/') != NULL)
6707 STRCAT(buf, "/");
6708 else
6709# endif
6710 add_pathsep(buf);
6711 vim_tempdir = vim_strsave(buf);
6712 vim_free(buf);
6713 }
6714 break;
6715 }
6716# ifdef EEXIST
6717 /* If the mkdir() didn't fail because the file/dir exists,
6718 * we probably can't create any dir here, try another
6719 * place. */
6720 if (errno != EEXIST)
6721# endif
6722 break;
6723 }
6724 if (vim_tempdir != NULL)
6725 break;
6726 }
6727 }
6728 }
6729
6730 if (vim_tempdir != NULL)
6731 {
6732 /* There is no need to check if the file exists, because we own the
6733 * directory and nobody else creates a file in it. */
6734 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6735 return vim_strsave(itmp);
6736 }
6737
6738 return NULL;
6739
6740#else /* TEMPDIRNAMES */
6741
6742# ifdef WIN3264
6743 char szTempFile[_MAX_PATH + 1];
6744 char buf4[4];
6745 char_u *retval;
6746 char_u *p;
6747
6748 STRCPY(itmp, "");
6749 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6750 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6751 strcpy(buf4, "VIM");
6752 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6753 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6754 return NULL;
6755 /* GetTempFileName() will create the file, we don't want that */
6756 (void)DeleteFile(itmp);
6757
6758 /* Backslashes in a temp file name cause problems when filtering with
6759 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6760 * didn't set 'shellslash'. */
6761 retval = vim_strsave(itmp);
6762 if (*p_shcf == '-' || p_ssl)
6763 for (p = retval; *p; ++p)
6764 if (*p == '\\')
6765 *p = '/';
6766 return retval;
6767
6768# else /* WIN3264 */
6769
6770# ifdef USE_TMPNAM
6771 /* tmpnam() will make its own name */
6772 if (*tmpnam((char *)itmp) == NUL)
6773 return NULL;
6774# else
6775 char_u *p;
6776
6777# ifdef VMS_TEMPNAM
6778 /* mktemp() is not working on VMS. It seems to be
6779 * a do-nothing function. Therefore we use tempnam().
6780 */
6781 sprintf((char *)itmp, "VIM%c", extra_char);
6782 p = (char_u *)tempnam("tmp:", (char *)itmp);
6783 if (p != NULL)
6784 {
6785 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6786 * and VIM will then be unable to find the file later */
6787 STRCPY(itmp, p);
6788 STRCAT(itmp, ".txt");
6789 free(p);
6790 }
6791 else
6792 return NULL;
6793# else
6794 STRCPY(itmp, TEMPNAME);
6795 if ((p = vim_strchr(itmp, '?')) != NULL)
6796 *p = extra_char;
6797 if (mktemp((char *)itmp) == NULL)
6798 return NULL;
6799# endif
6800# endif
6801
6802 return vim_strsave(itmp);
6803# endif /* WIN3264 */
6804#endif /* TEMPDIRNAMES */
6805}
6806
6807#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6808/*
6809 * Convert all backslashes in fname to forward slashes in-place.
6810 */
6811 void
6812forward_slash(fname)
6813 char_u *fname;
6814{
6815 char_u *p;
6816
6817 for (p = fname; *p != NUL; ++p)
6818# ifdef FEAT_MBYTE
6819 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006820 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006821 ++p;
6822 else
6823# endif
6824 if (*p == '\\')
6825 *p = '/';
6826}
6827#endif
6828
6829
6830/*
6831 * Code for automatic commands.
6832 *
6833 * Only included when "FEAT_AUTOCMD" has been defined.
6834 */
6835
6836#if defined(FEAT_AUTOCMD) || defined(PROTO)
6837
6838/*
6839 * The autocommands are stored in a list for each event.
6840 * Autocommands for the same pattern, that are consecutive, are joined
6841 * together, to avoid having to match the pattern too often.
6842 * The result is an array of Autopat lists, which point to AutoCmd lists:
6843 *
6844 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
6845 * Autopat.cmds Autopat.cmds
6846 * | |
6847 * V V
6848 * AutoCmd.next AutoCmd.next
6849 * | |
6850 * V V
6851 * AutoCmd.next NULL
6852 * |
6853 * V
6854 * NULL
6855 *
6856 * first_autopat[1] --> Autopat.next --> NULL
6857 * Autopat.cmds
6858 * |
6859 * V
6860 * AutoCmd.next
6861 * |
6862 * V
6863 * NULL
6864 * etc.
6865 *
6866 * The order of AutoCmds is important, this is the order in which they were
6867 * defined and will have to be executed.
6868 */
6869typedef struct AutoCmd
6870{
6871 char_u *cmd; /* The command to be executed (NULL
6872 when command has been removed) */
6873 char nested; /* If autocommands nest here */
6874 char last; /* last command in list */
6875#ifdef FEAT_EVAL
6876 scid_T scriptID; /* script ID where defined */
6877#endif
6878 struct AutoCmd *next; /* Next AutoCmd in list */
6879} AutoCmd;
6880
6881typedef struct AutoPat
6882{
6883 int group; /* group ID */
6884 char_u *pat; /* pattern as typed (NULL when pattern
6885 has been removed) */
6886 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00006887 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006888 char allow_dirs; /* Pattern may match whole path */
6889 char last; /* last pattern for apply_autocmds() */
6890 AutoCmd *cmds; /* list of commands to do */
6891 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006892 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006893} AutoPat;
6894
6895static struct event_name
6896{
6897 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006898 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899} event_names[] =
6900{
6901 {"BufAdd", EVENT_BUFADD},
6902 {"BufCreate", EVENT_BUFADD},
6903 {"BufDelete", EVENT_BUFDELETE},
6904 {"BufEnter", EVENT_BUFENTER},
6905 {"BufFilePost", EVENT_BUFFILEPOST},
6906 {"BufFilePre", EVENT_BUFFILEPRE},
6907 {"BufHidden", EVENT_BUFHIDDEN},
6908 {"BufLeave", EVENT_BUFLEAVE},
6909 {"BufNew", EVENT_BUFNEW},
6910 {"BufNewFile", EVENT_BUFNEWFILE},
6911 {"BufRead", EVENT_BUFREADPOST},
6912 {"BufReadCmd", EVENT_BUFREADCMD},
6913 {"BufReadPost", EVENT_BUFREADPOST},
6914 {"BufReadPre", EVENT_BUFREADPRE},
6915 {"BufUnload", EVENT_BUFUNLOAD},
6916 {"BufWinEnter", EVENT_BUFWINENTER},
6917 {"BufWinLeave", EVENT_BUFWINLEAVE},
6918 {"BufWipeout", EVENT_BUFWIPEOUT},
6919 {"BufWrite", EVENT_BUFWRITEPRE},
6920 {"BufWritePost", EVENT_BUFWRITEPOST},
6921 {"BufWritePre", EVENT_BUFWRITEPRE},
6922 {"BufWriteCmd", EVENT_BUFWRITECMD},
6923 {"CmdwinEnter", EVENT_CMDWINENTER},
6924 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006925 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006926 {"CursorHold", EVENT_CURSORHOLD},
6927 {"CursorHoldI", EVENT_CURSORHOLDI},
6928 {"CursorMoved", EVENT_CURSORMOVED},
6929 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 {"EncodingChanged", EVENT_ENCODINGCHANGED},
6931 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006932 {"FileAppendPost", EVENT_FILEAPPENDPOST},
6933 {"FileAppendPre", EVENT_FILEAPPENDPRE},
6934 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
6935 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
6936 {"FileChangedRO", EVENT_FILECHANGEDRO},
6937 {"FileReadPost", EVENT_FILEREADPOST},
6938 {"FileReadPre", EVENT_FILEREADPRE},
6939 {"FileReadCmd", EVENT_FILEREADCMD},
6940 {"FileType", EVENT_FILETYPE},
6941 {"FileWritePost", EVENT_FILEWRITEPOST},
6942 {"FileWritePre", EVENT_FILEWRITEPRE},
6943 {"FileWriteCmd", EVENT_FILEWRITECMD},
6944 {"FilterReadPost", EVENT_FILTERREADPOST},
6945 {"FilterReadPre", EVENT_FILTERREADPRE},
6946 {"FilterWritePost", EVENT_FILTERWRITEPOST},
6947 {"FilterWritePre", EVENT_FILTERWRITEPRE},
6948 {"FocusGained", EVENT_FOCUSGAINED},
6949 {"FocusLost", EVENT_FOCUSLOST},
6950 {"FuncUndefined", EVENT_FUNCUNDEFINED},
6951 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar843ee412004-06-30 16:16:41 +00006952 {"InsertChange", EVENT_INSERTCHANGE},
6953 {"InsertEnter", EVENT_INSERTENTER},
6954 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00006955 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00006956 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
6957 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006958 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00006959 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00006960 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 {"StdinReadPost", EVENT_STDINREADPOST},
6962 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00006963 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00006964 {"Syntax", EVENT_SYNTAX},
6965 {"TabEnterPost", EVENT_TABENTERPOST},
6966 {"TabLeavePre", EVENT_TABLEAVEPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006967 {"TermChanged", EVENT_TERMCHANGED},
6968 {"TermResponse", EVENT_TERMRESPONSE},
6969 {"User", EVENT_USER},
6970 {"VimEnter", EVENT_VIMENTER},
6971 {"VimLeave", EVENT_VIMLEAVE},
6972 {"VimLeavePre", EVENT_VIMLEAVEPRE},
6973 {"WinEnter", EVENT_WINENTER},
6974 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006975 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006976};
6977
6978static AutoPat *first_autopat[NUM_EVENTS] =
6979{
6980 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6981 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6982 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6983 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00006984 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6985 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006986};
6987
6988/*
6989 * struct used to keep status while executing autocommands for an event.
6990 */
6991typedef struct AutoPatCmd
6992{
6993 AutoPat *curpat; /* next AutoPat to examine */
6994 AutoCmd *nextcmd; /* next AutoCmd to execute */
6995 int group; /* group being used */
6996 char_u *fname; /* fname to match with */
6997 char_u *sfname; /* sfname to match with */
6998 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006999 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007000 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7001 buf is deleted */
7002 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003} AutoPatCmd;
7004
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007005static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007006
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007/*
7008 * augroups stores a list of autocmd group names.
7009 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007010static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007011#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7012
7013/*
7014 * The ID of the current group. Group 0 is the default one.
7015 */
7016#define AUGROUP_DEFAULT -1 /* default autocmd group */
7017#define AUGROUP_ERROR -2 /* errornouse autocmd group */
7018#define AUGROUP_ALL -3 /* all autocmd groups */
7019static int current_augroup = AUGROUP_DEFAULT;
7020
7021static int au_need_clean = FALSE; /* need to delete marked patterns */
7022
Bram Moolenaar754b5602006-02-09 23:53:20 +00007023static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007024static void au_remove_pat __ARGS((AutoPat *ap));
7025static void au_remove_cmds __ARGS((AutoPat *ap));
7026static void au_cleanup __ARGS((void));
7027static int au_new_group __ARGS((char_u *name));
7028static void au_del_group __ARGS((char_u *name));
7029static int au_find_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007030static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7031static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007032static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007033static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007035static 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 +00007036static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007037static 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 +00007038static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7039
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007040
Bram Moolenaar754b5602006-02-09 23:53:20 +00007041static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042static int last_group;
7043
7044/*
7045 * Show the autocommands for one AutoPat.
7046 */
7047 static void
7048show_autocmd(ap, event)
7049 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007050 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007051{
7052 AutoCmd *ac;
7053
7054 /* Check for "got_int" (here and at various places below), which is set
7055 * when "q" has been hit for the "--more--" prompt */
7056 if (got_int)
7057 return;
7058 if (ap->pat == NULL) /* pattern has been removed */
7059 return;
7060
7061 msg_putchar('\n');
7062 if (got_int)
7063 return;
7064 if (event != last_event || ap->group != last_group)
7065 {
7066 if (ap->group != AUGROUP_DEFAULT)
7067 {
7068 if (AUGROUP_NAME(ap->group) == NULL)
7069 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7070 else
7071 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7072 msg_puts((char_u *)" ");
7073 }
7074 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7075 last_event = event;
7076 last_group = ap->group;
7077 msg_putchar('\n');
7078 if (got_int)
7079 return;
7080 }
7081 msg_col = 4;
7082 msg_outtrans(ap->pat);
7083
7084 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7085 {
7086 if (ac->cmd != NULL) /* skip removed commands */
7087 {
7088 if (msg_col >= 14)
7089 msg_putchar('\n');
7090 msg_col = 14;
7091 if (got_int)
7092 return;
7093 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007094#ifdef FEAT_EVAL
7095 if (p_verbose > 0)
7096 last_set_msg(ac->scriptID);
7097#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007098 if (got_int)
7099 return;
7100 if (ac->next != NULL)
7101 {
7102 msg_putchar('\n');
7103 if (got_int)
7104 return;
7105 }
7106 }
7107 }
7108}
7109
7110/*
7111 * Mark an autocommand pattern for deletion.
7112 */
7113 static void
7114au_remove_pat(ap)
7115 AutoPat *ap;
7116{
7117 vim_free(ap->pat);
7118 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007119 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120 au_need_clean = TRUE;
7121}
7122
7123/*
7124 * Mark all commands for a pattern for deletion.
7125 */
7126 static void
7127au_remove_cmds(ap)
7128 AutoPat *ap;
7129{
7130 AutoCmd *ac;
7131
7132 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7133 {
7134 vim_free(ac->cmd);
7135 ac->cmd = NULL;
7136 }
7137 au_need_clean = TRUE;
7138}
7139
7140/*
7141 * Cleanup autocommands and patterns that have been deleted.
7142 * This is only done when not executing autocommands.
7143 */
7144 static void
7145au_cleanup()
7146{
7147 AutoPat *ap, **prev_ap;
7148 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007149 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007150
7151 if (autocmd_busy || !au_need_clean)
7152 return;
7153
7154 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007155 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7156 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007157 {
7158 /* loop over all autocommand patterns */
7159 prev_ap = &(first_autopat[(int)event]);
7160 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7161 {
7162 /* loop over all commands for this pattern */
7163 prev_ac = &(ap->cmds);
7164 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7165 {
7166 /* remove the command if the pattern is to be deleted or when
7167 * the command has been marked for deletion */
7168 if (ap->pat == NULL || ac->cmd == NULL)
7169 {
7170 *prev_ac = ac->next;
7171 vim_free(ac->cmd);
7172 vim_free(ac);
7173 }
7174 else
7175 prev_ac = &(ac->next);
7176 }
7177
7178 /* remove the pattern if it has been marked for deletion */
7179 if (ap->pat == NULL)
7180 {
7181 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007182 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007183 vim_free(ap);
7184 }
7185 else
7186 prev_ap = &(ap->next);
7187 }
7188 }
7189
7190 au_need_clean = FALSE;
7191}
7192
7193/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007194 * Called when buffer is freed, to remove/invalidate related buffer-local
7195 * autocmds.
7196 */
7197 void
7198aubuflocal_remove(buf)
7199 buf_T *buf;
7200{
7201 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007202 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007203 AutoPatCmd *apc;
7204
7205 /* invalidate currently executing autocommands */
7206 for (apc = active_apc_list; apc; apc = apc->next)
7207 if (buf->b_fnum == apc->arg_bufnr)
7208 apc->arg_bufnr = 0;
7209
7210 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007211 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7212 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007213 /* loop over all autocommand patterns */
7214 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7215 if (ap->buflocal_nr == buf->b_fnum)
7216 {
7217 au_remove_pat(ap);
7218 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007219 {
7220 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007221 smsg((char_u *)
7222 _("auto-removing autocommand: %s <buffer=%d>"),
7223 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007224 verbose_leave();
7225 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007226 }
7227 au_cleanup();
7228}
7229
7230/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007231 * Add an autocmd group name.
7232 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7233 */
7234 static int
7235au_new_group(name)
7236 char_u *name;
7237{
7238 int i;
7239
7240 i = au_find_group(name);
7241 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7242 {
7243 /* First try using a free entry. */
7244 for (i = 0; i < augroups.ga_len; ++i)
7245 if (AUGROUP_NAME(i) == NULL)
7246 break;
7247 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7248 return AUGROUP_ERROR;
7249
7250 AUGROUP_NAME(i) = vim_strsave(name);
7251 if (AUGROUP_NAME(i) == NULL)
7252 return AUGROUP_ERROR;
7253 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007254 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007255 }
7256
7257 return i;
7258}
7259
7260 static void
7261au_del_group(name)
7262 char_u *name;
7263{
7264 int i;
7265
7266 i = au_find_group(name);
7267 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7268 EMSG2(_("E367: No such group: \"%s\""), name);
7269 else
7270 {
7271 vim_free(AUGROUP_NAME(i));
7272 AUGROUP_NAME(i) = NULL;
7273 }
7274}
7275
7276/*
7277 * Find the ID of an autocmd group name.
7278 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7279 */
7280 static int
7281au_find_group(name)
7282 char_u *name;
7283{
7284 int i;
7285
7286 for (i = 0; i < augroups.ga_len; ++i)
7287 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7288 return i;
7289 return AUGROUP_ERROR;
7290}
7291
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007292#if defined(FEAT_BROWSE) || defined(PROTO)
7293/*
7294 * Return TRUE if augroup "name" exists.
7295 */
7296 int
7297au_has_group(name)
7298 char_u *name;
7299{
7300 return au_find_group(name) != AUGROUP_ERROR;
7301}
7302#endif
7303
Bram Moolenaar071d4272004-06-13 20:20:40 +00007304/*
7305 * ":augroup {name}".
7306 */
7307 void
7308do_augroup(arg, del_group)
7309 char_u *arg;
7310 int del_group;
7311{
7312 int i;
7313
7314 if (del_group)
7315 {
7316 if (*arg == NUL)
7317 EMSG(_(e_argreq));
7318 else
7319 au_del_group(arg);
7320 }
7321 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7322 current_augroup = AUGROUP_DEFAULT;
7323 else if (*arg) /* ":aug xxx": switch to group xxx */
7324 {
7325 i = au_new_group(arg);
7326 if (i != AUGROUP_ERROR)
7327 current_augroup = i;
7328 }
7329 else /* ":aug": list the group names */
7330 {
7331 msg_start();
7332 for (i = 0; i < augroups.ga_len; ++i)
7333 {
7334 if (AUGROUP_NAME(i) != NULL)
7335 {
7336 msg_puts(AUGROUP_NAME(i));
7337 msg_puts((char_u *)" ");
7338 }
7339 }
7340 msg_clr_eos();
7341 msg_end();
7342 }
7343}
7344
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007345#if defined(EXITFREE) || defined(PROTO)
7346 void
7347free_all_autocmds()
7348{
7349 for (current_augroup = -1; current_augroup < augroups.ga_len;
7350 ++current_augroup)
7351 do_autocmd((char_u *)"", TRUE);
7352 ga_clear_strings(&augroups);
7353}
7354#endif
7355
Bram Moolenaar071d4272004-06-13 20:20:40 +00007356/*
7357 * Return the event number for event name "start".
7358 * Return NUM_EVENTS if the event name was not found.
7359 * Return a pointer to the next event name in "end".
7360 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007361 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007362event_name2nr(start, end)
7363 char_u *start;
7364 char_u **end;
7365{
7366 char_u *p;
7367 int i;
7368 int len;
7369
7370 /* the event name ends with end of line, a blank or a comma */
7371 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7372 ;
7373 for (i = 0; event_names[i].name != NULL; ++i)
7374 {
7375 len = (int)STRLEN(event_names[i].name);
7376 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7377 break;
7378 }
7379 if (*p == ',')
7380 ++p;
7381 *end = p;
7382 if (event_names[i].name == NULL)
7383 return NUM_EVENTS;
7384 return event_names[i].event;
7385}
7386
7387/*
7388 * Return the name for event "event".
7389 */
7390 static char_u *
7391event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007392 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007393{
7394 int i;
7395
7396 for (i = 0; event_names[i].name != NULL; ++i)
7397 if (event_names[i].event == event)
7398 return (char_u *)event_names[i].name;
7399 return (char_u *)"Unknown";
7400}
7401
7402/*
7403 * Scan over the events. "*" stands for all events.
7404 */
7405 static char_u *
7406find_end_event(arg, have_group)
7407 char_u *arg;
7408 int have_group; /* TRUE when group name was found */
7409{
7410 char_u *pat;
7411 char_u *p;
7412
7413 if (*arg == '*')
7414 {
7415 if (arg[1] && !vim_iswhite(arg[1]))
7416 {
7417 EMSG2(_("E215: Illegal character after *: %s"), arg);
7418 return NULL;
7419 }
7420 pat = arg + 1;
7421 }
7422 else
7423 {
7424 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7425 {
7426 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7427 {
7428 if (have_group)
7429 EMSG2(_("E216: No such event: %s"), pat);
7430 else
7431 EMSG2(_("E216: No such group or event: %s"), pat);
7432 return NULL;
7433 }
7434 }
7435 }
7436 return pat;
7437}
7438
7439/*
7440 * Return TRUE if "event" is included in 'eventignore'.
7441 */
7442 static int
7443event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007444 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007445{
7446 char_u *p = p_ei;
7447
7448 if (STRICMP(p_ei, "all") == 0)
7449 return TRUE;
7450
7451 while (*p)
7452 if (event_name2nr(p, &p) == event)
7453 return TRUE;
7454
7455 return FALSE;
7456}
7457
7458/*
7459 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7460 */
7461 int
7462check_ei()
7463{
7464 char_u *p = p_ei;
7465
7466 if (STRICMP(p_ei, "all") == 0)
7467 return OK;
7468
7469 while (*p)
7470 if (event_name2nr(p, &p) == NUM_EVENTS)
7471 return FAIL;
7472
7473 return OK;
7474}
7475
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007476# if defined(FEAT_SYN_HL) || defined(PROTO)
7477
7478/*
7479 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7480 * buffer loaded into the window. "what" must start with a comma.
7481 * Returns the old value of 'eventignore' in allocated memory.
7482 */
7483 char_u *
7484au_event_disable(what)
7485 char *what;
7486{
7487 char_u *new_ei;
7488 char_u *save_ei;
7489
7490 save_ei = vim_strsave(p_ei);
7491 if (save_ei != NULL)
7492 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007493 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007494 if (new_ei != NULL)
7495 {
7496 STRCAT(new_ei, what);
7497 set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
7498 vim_free(new_ei);
7499 }
7500 }
7501 return save_ei;
7502}
7503
7504 void
7505au_event_restore(old_ei)
7506 char_u *old_ei;
7507{
7508 if (old_ei != NULL)
7509 {
7510 set_string_option_direct((char_u *)"ei", -1, old_ei, OPT_FREE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007511 vim_free(old_ei);
7512 }
7513}
7514# endif /* FEAT_SYN_HL */
7515
Bram Moolenaar071d4272004-06-13 20:20:40 +00007516/*
7517 * do_autocmd() -- implements the :autocmd command. Can be used in the
7518 * following ways:
7519 *
7520 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7521 * will be automatically executed for <event>
7522 * when editing a file matching <pat>, in
7523 * the current group.
7524 * :autocmd <event> <pat> Show the auto-commands associated with
7525 * <event> and <pat>.
7526 * :autocmd <event> Show the auto-commands associated with
7527 * <event>.
7528 * :autocmd Show all auto-commands.
7529 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7530 * <event> and <pat>, and add the command
7531 * <cmd>, for the current group.
7532 * :autocmd! <event> <pat> Remove all auto-commands associated with
7533 * <event> and <pat> for the current group.
7534 * :autocmd! <event> Remove all auto-commands associated with
7535 * <event> for the current group.
7536 * :autocmd! Remove ALL auto-commands for the current
7537 * group.
7538 *
7539 * Multiple events and patterns may be given separated by commas. Here are
7540 * some examples:
7541 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7542 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7543 *
7544 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007545 *
7546 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547 */
7548 void
7549do_autocmd(arg, forceit)
7550 char_u *arg;
7551 int forceit;
7552{
7553 char_u *pat;
7554 char_u *envpat = NULL;
7555 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007556 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007557 int need_free = FALSE;
7558 int nested = FALSE;
7559 int group;
7560
7561 /*
7562 * Check for a legal group name. If not, use AUGROUP_ALL.
7563 */
7564 group = au_get_grouparg(&arg);
7565 if (arg == NULL) /* out of memory */
7566 return;
7567
7568 /*
7569 * Scan over the events.
7570 * If we find an illegal name, return here, don't do anything.
7571 */
7572 pat = find_end_event(arg, group != AUGROUP_ALL);
7573 if (pat == NULL)
7574 return;
7575
7576 /*
7577 * Scan over the pattern. Put a NUL at the end.
7578 */
7579 pat = skipwhite(pat);
7580 cmd = pat;
7581 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7582 cmd++;
7583 if (*cmd)
7584 *cmd++ = NUL;
7585
7586 /* Expand environment variables in the pattern. Set 'shellslash', we want
7587 * forward slashes here. */
7588 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7589 {
7590#ifdef BACKSLASH_IN_FILENAME
7591 int p_ssl_save = p_ssl;
7592
7593 p_ssl = TRUE;
7594#endif
7595 envpat = expand_env_save(pat);
7596#ifdef BACKSLASH_IN_FILENAME
7597 p_ssl = p_ssl_save;
7598#endif
7599 if (envpat != NULL)
7600 pat = envpat;
7601 }
7602
7603 /*
7604 * Check for "nested" flag.
7605 */
7606 cmd = skipwhite(cmd);
7607 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7608 {
7609 nested = TRUE;
7610 cmd = skipwhite(cmd + 6);
7611 }
7612
7613 /*
7614 * Find the start of the commands.
7615 * Expand <sfile> in it.
7616 */
7617 if (*cmd != NUL)
7618 {
7619 cmd = expand_sfile(cmd);
7620 if (cmd == NULL) /* some error */
7621 return;
7622 need_free = TRUE;
7623 }
7624
7625 /*
7626 * Print header when showing autocommands.
7627 */
7628 if (!forceit && *cmd == NUL)
7629 {
7630 /* Highlight title */
7631 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7632 }
7633
7634 /*
7635 * Loop over the events.
7636 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007637 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007638 last_group = AUGROUP_ERROR; /* for listing the group name */
7639 if (*arg == '*' || *arg == NUL)
7640 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00007641 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7642 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007643 if (do_autocmd_event(event, pat,
7644 nested, cmd, forceit, group) == FAIL)
7645 break;
7646 }
7647 else
7648 {
7649 while (*arg && !vim_iswhite(*arg))
7650 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7651 nested, cmd, forceit, group) == FAIL)
7652 break;
7653 }
7654
7655 if (need_free)
7656 vim_free(cmd);
7657 vim_free(envpat);
7658}
7659
7660/*
7661 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7662 * The "argp" argument is advanced to the following argument.
7663 *
7664 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7665 */
7666 static int
7667au_get_grouparg(argp)
7668 char_u **argp;
7669{
7670 char_u *group_name;
7671 char_u *p;
7672 char_u *arg = *argp;
7673 int group = AUGROUP_ALL;
7674
7675 p = skiptowhite(arg);
7676 if (p > arg)
7677 {
7678 group_name = vim_strnsave(arg, (int)(p - arg));
7679 if (group_name == NULL) /* out of memory */
7680 return AUGROUP_ERROR;
7681 group = au_find_group(group_name);
7682 if (group == AUGROUP_ERROR)
7683 group = AUGROUP_ALL; /* no match, use all groups */
7684 else
7685 *argp = skipwhite(p); /* match, skip over group name */
7686 vim_free(group_name);
7687 }
7688 return group;
7689}
7690
7691/*
7692 * do_autocmd() for one event.
7693 * If *pat == NUL do for all patterns.
7694 * If *cmd == NUL show entries.
7695 * If forceit == TRUE delete entries.
7696 * If group is not AUGROUP_ALL, only use this group.
7697 */
7698 static int
7699do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007700 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007701 char_u *pat;
7702 int nested;
7703 char_u *cmd;
7704 int forceit;
7705 int group;
7706{
7707 AutoPat *ap;
7708 AutoPat **prev_ap;
7709 AutoCmd *ac;
7710 AutoCmd **prev_ac;
7711 int brace_level;
7712 char_u *endpat;
7713 int findgroup;
7714 int allgroups;
7715 int patlen;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007716 int is_buflocal;
7717 int buflocal_nr;
7718 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007719
7720 if (group == AUGROUP_ALL)
7721 findgroup = current_augroup;
7722 else
7723 findgroup = group;
7724 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7725
7726 /*
7727 * Show or delete all patterns for an event.
7728 */
7729 if (*pat == NUL)
7730 {
7731 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7732 {
7733 if (forceit) /* delete the AutoPat, if it's in the current group */
7734 {
7735 if (ap->group == findgroup)
7736 au_remove_pat(ap);
7737 }
7738 else if (group == AUGROUP_ALL || ap->group == group)
7739 show_autocmd(ap, event);
7740 }
7741 }
7742
7743 /*
7744 * Loop through all the specified patterns.
7745 */
7746 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7747 {
7748 /*
7749 * Find end of the pattern.
7750 * Watch out for a comma in braces, like "*.\{obj,o\}".
7751 */
7752 brace_level = 0;
7753 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7754 || endpat[-1] == '\\'); ++endpat)
7755 {
7756 if (*endpat == '{')
7757 brace_level++;
7758 else if (*endpat == '}')
7759 brace_level--;
7760 }
7761 if (pat == endpat) /* ignore single comma */
7762 continue;
7763 patlen = (int)(endpat - pat);
7764
7765 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007766 * detect special <buflocal[=X]> buffer-local patterns
7767 */
7768 is_buflocal = FALSE;
7769 buflocal_nr = 0;
7770
7771 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7772 && pat[patlen - 1] == '>')
7773 {
7774 /* Error will be printed only for addition. printing and removing
7775 * will proceed silently. */
7776 is_buflocal = TRUE;
7777 if (patlen == 8)
7778 buflocal_nr = curbuf->b_fnum;
7779 else if (patlen > 9 && pat[7] == '=')
7780 {
7781 /* <buffer=abuf> */
7782 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7783 buflocal_nr = autocmd_bufnr;
7784 /* <buffer=123> */
7785 else if (skipdigits(pat + 8) == pat + patlen - 1)
7786 buflocal_nr = atoi((char *)pat + 8);
7787 }
7788 }
7789
7790 if (is_buflocal)
7791 {
7792 /* normalize pat into standard "<buffer>#N" form */
7793 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7794 pat = buflocal_pat; /* can modify pat and patlen */
7795 patlen = STRLEN(buflocal_pat); /* but not endpat */
7796 }
7797
7798 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007799 * Find AutoPat entries with this pattern.
7800 */
7801 prev_ap = &first_autopat[(int)event];
7802 while ((ap = *prev_ap) != NULL)
7803 {
7804 if (ap->pat != NULL)
7805 {
7806 /* Accept a pattern when:
7807 * - a group was specified and it's that group, or a group was
7808 * not specified and it's the current group, or a group was
7809 * not specified and we are listing
7810 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007811 * - the pattern matches.
7812 * For <buffer[=X]>, this condition works because we normalize
7813 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007814 */
7815 if ((allgroups || ap->group == findgroup)
7816 && ap->patlen == patlen
7817 && STRNCMP(pat, ap->pat, patlen) == 0)
7818 {
7819 /*
7820 * Remove existing autocommands.
7821 * If adding any new autocmd's for this AutoPat, don't
7822 * delete the pattern from the autopat list, append to
7823 * this list.
7824 */
7825 if (forceit)
7826 {
7827 if (*cmd != NUL && ap->next == NULL)
7828 {
7829 au_remove_cmds(ap);
7830 break;
7831 }
7832 au_remove_pat(ap);
7833 }
7834
7835 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007836 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007837 */
7838 else if (*cmd == NUL)
7839 show_autocmd(ap, event);
7840
7841 /*
7842 * Add autocmd to this autopat, if it's the last one.
7843 */
7844 else if (ap->next == NULL)
7845 break;
7846 }
7847 }
7848 prev_ap = &ap->next;
7849 }
7850
7851 /*
7852 * Add a new command.
7853 */
7854 if (*cmd != NUL)
7855 {
7856 /*
7857 * If the pattern we want to add a command to does appear at the
7858 * end of the list (or not is not in the list at all), add the
7859 * pattern at the end of the list.
7860 */
7861 if (ap == NULL)
7862 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007863 /* refuse to add buffer-local ap if buffer number is invalid */
7864 if (is_buflocal && (buflocal_nr == 0
7865 || buflist_findnr(buflocal_nr) == NULL))
7866 {
7867 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7868 buflocal_nr);
7869 return FAIL;
7870 }
7871
Bram Moolenaar071d4272004-06-13 20:20:40 +00007872 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7873 if (ap == NULL)
7874 return FAIL;
7875 ap->pat = vim_strnsave(pat, patlen);
7876 ap->patlen = patlen;
7877 if (ap->pat == NULL)
7878 {
7879 vim_free(ap);
7880 return FAIL;
7881 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007882
7883 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007884 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007885 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007886 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007887 }
7888 else
7889 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007890 char_u *reg_pat;
7891
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007892 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007893 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007894 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007895 if (reg_pat != NULL)
7896 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007897 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007898 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007899 {
7900 vim_free(ap->pat);
7901 vim_free(ap);
7902 return FAIL;
7903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007904 }
7905 ap->cmds = NULL;
7906 *prev_ap = ap;
7907 ap->next = NULL;
7908 if (group == AUGROUP_ALL)
7909 ap->group = current_augroup;
7910 else
7911 ap->group = group;
7912 }
7913
7914 /*
7915 * Add the autocmd at the end of the AutoCmd list.
7916 */
7917 prev_ac = &(ap->cmds);
7918 while ((ac = *prev_ac) != NULL)
7919 prev_ac = &ac->next;
7920 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7921 if (ac == NULL)
7922 return FAIL;
7923 ac->cmd = vim_strsave(cmd);
7924#ifdef FEAT_EVAL
7925 ac->scriptID = current_SID;
7926#endif
7927 if (ac->cmd == NULL)
7928 {
7929 vim_free(ac);
7930 return FAIL;
7931 }
7932 ac->next = NULL;
7933 *prev_ac = ac;
7934 ac->nested = nested;
7935 }
7936 }
7937
7938 au_cleanup(); /* may really delete removed patterns/commands now */
7939 return OK;
7940}
7941
7942/*
7943 * Implementation of ":doautocmd [group] event [fname]".
7944 * Return OK for success, FAIL for failure;
7945 */
7946 int
7947do_doautocmd(arg, do_msg)
7948 char_u *arg;
7949 int do_msg; /* give message for no matching autocmds? */
7950{
7951 char_u *fname;
7952 int nothing_done = TRUE;
7953 int group;
7954
7955 /*
7956 * Check for a legal group name. If not, use AUGROUP_ALL.
7957 */
7958 group = au_get_grouparg(&arg);
7959 if (arg == NULL) /* out of memory */
7960 return FAIL;
7961
7962 if (*arg == '*')
7963 {
7964 EMSG(_("E217: Can't execute autocommands for ALL events"));
7965 return FAIL;
7966 }
7967
7968 /*
7969 * Scan over the events.
7970 * If we find an illegal name, return here, don't do anything.
7971 */
7972 fname = find_end_event(arg, group != AUGROUP_ALL);
7973 if (fname == NULL)
7974 return FAIL;
7975
7976 fname = skipwhite(fname);
7977
7978 /*
7979 * Loop over the events.
7980 */
7981 while (*arg && !vim_iswhite(*arg))
7982 if (apply_autocmds_group(event_name2nr(arg, &arg),
7983 fname, NULL, TRUE, group, curbuf, NULL))
7984 nothing_done = FALSE;
7985
7986 if (nothing_done && do_msg)
7987 MSG(_("No matching autocommands"));
7988
7989#ifdef FEAT_EVAL
7990 return aborting() ? FAIL : OK;
7991#else
7992 return OK;
7993#endif
7994}
7995
7996/*
7997 * ":doautoall": execute autocommands for each loaded buffer.
7998 */
7999 void
8000ex_doautoall(eap)
8001 exarg_T *eap;
8002{
8003 int retval;
8004 aco_save_T aco;
8005 buf_T *buf;
8006
8007 /*
8008 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8009 * equal to curbuf, but for some buffers there may not be a window.
8010 * So we change the buffer for the current window for a moment. This
8011 * gives problems when the autocommands make changes to the list of
8012 * buffers or windows...
8013 */
8014 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8015 {
8016 if (curbuf->b_ml.ml_mfp != NULL)
8017 {
8018 /* find a window for this buffer and save some values */
8019 aucmd_prepbuf(&aco, buf);
8020
8021 /* execute the autocommands for this buffer */
8022 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00008023 do_modelines(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008024
8025 /* restore the current window */
8026 aucmd_restbuf(&aco);
8027
8028 /* stop if there is some error or buffer was deleted */
8029 if (retval == FAIL || !buf_valid(buf))
8030 break;
8031 }
8032 }
8033
8034 check_cursor(); /* just in case lines got deleted */
8035}
8036
8037/*
8038 * Prepare for executing autocommands for (hidden) buffer "buf".
8039 * Search a window for the current buffer. Save the cursor position and
8040 * screen offset.
8041 * Set "curbuf" and "curwin" to match "buf".
8042 */
8043 void
8044aucmd_prepbuf(aco, buf)
8045 aco_save_T *aco; /* structure to save values in */
8046 buf_T *buf; /* new curbuf */
8047{
8048 win_T *win;
8049
8050 aco->new_curbuf = buf;
8051
8052 /* Find a window that is for the new buffer */
8053 if (buf == curbuf) /* be quick when buf is curbuf */
8054 win = curwin;
8055 else
8056#ifdef FEAT_WINDOWS
8057 for (win = firstwin; win != NULL; win = win->w_next)
8058 if (win->w_buffer == buf)
8059 break;
8060#else
8061 win = NULL;
8062#endif
8063
8064 /*
8065 * Prefer to use an existing window for the buffer, it has the least side
8066 * effects (esp. if "buf" is curbuf).
8067 * Otherwise, use curwin for "buf". It might make some items in the
8068 * window invalid. At least save the cursor and topline.
8069 */
8070 if (win != NULL)
8071 {
8072 /* there is a window for "buf", make it the curwin */
8073 aco->save_curwin = curwin;
8074 curwin = win;
8075 aco->save_buf = win->w_buffer;
8076 aco->new_curwin = win;
8077 }
8078 else
8079 {
8080 /* there is no window for "buf", use curwin */
8081 aco->save_curwin = NULL;
8082 aco->save_buf = curbuf;
8083 --curbuf->b_nwindows;
8084 curwin->w_buffer = buf;
8085 ++buf->b_nwindows;
8086
8087 /* save cursor and topline, set them to safe values */
8088 aco->save_cursor = curwin->w_cursor;
8089 curwin->w_cursor.lnum = 1;
8090 curwin->w_cursor.col = 0;
8091 aco->save_topline = curwin->w_topline;
8092 curwin->w_topline = 1;
8093#ifdef FEAT_DIFF
8094 aco->save_topfill = curwin->w_topfill;
8095 curwin->w_topfill = 0;
8096#endif
8097 }
8098
8099 curbuf = buf;
8100}
8101
8102/*
8103 * Cleanup after executing autocommands for a (hidden) buffer.
8104 * Restore the window as it was (if possible).
8105 */
8106 void
8107aucmd_restbuf(aco)
8108 aco_save_T *aco; /* structure holding saved values */
8109{
8110 if (aco->save_curwin != NULL)
8111 {
8112 /* restore curwin */
8113#ifdef FEAT_WINDOWS
8114 if (win_valid(aco->save_curwin))
8115#endif
8116 {
8117 /* restore the buffer which was previously edited by curwin, if
8118 * it's still the same window and it's valid */
8119 if (curwin == aco->new_curwin
8120 && buf_valid(aco->save_buf)
8121 && aco->save_buf->b_ml.ml_mfp != NULL)
8122 {
8123 --curbuf->b_nwindows;
8124 curbuf = aco->save_buf;
8125 curwin->w_buffer = curbuf;
8126 ++curbuf->b_nwindows;
8127 }
8128
8129 curwin = aco->save_curwin;
8130 curbuf = curwin->w_buffer;
8131 }
8132 }
8133 else
8134 {
8135 /* restore buffer for curwin if it still exists and is loaded */
8136 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8137 {
8138 --curbuf->b_nwindows;
8139 curbuf = aco->save_buf;
8140 curwin->w_buffer = curbuf;
8141 ++curbuf->b_nwindows;
8142 curwin->w_cursor = aco->save_cursor;
8143 check_cursor();
8144 /* check topline < line_count, in case lines got deleted */
8145 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8146 {
8147 curwin->w_topline = aco->save_topline;
8148#ifdef FEAT_DIFF
8149 curwin->w_topfill = aco->save_topfill;
8150#endif
8151 }
8152 else
8153 {
8154 curwin->w_topline = curbuf->b_ml.ml_line_count;
8155#ifdef FEAT_DIFF
8156 curwin->w_topfill = 0;
8157#endif
8158 }
8159 }
8160 }
8161}
8162
8163static int autocmd_nested = FALSE;
8164
8165/*
8166 * Execute autocommands for "event" and file name "fname".
8167 * Return TRUE if some commands were executed.
8168 */
8169 int
8170apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008171 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008172 char_u *fname; /* NULL or empty means use actual file name */
8173 char_u *fname_io; /* fname to use for <afile> on cmdline */
8174 int force; /* when TRUE, ignore autocmd_busy */
8175 buf_T *buf; /* buffer for <abuf> */
8176{
8177 return apply_autocmds_group(event, fname, fname_io, force,
8178 AUGROUP_ALL, buf, NULL);
8179}
8180
8181/*
8182 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8183 * setting v:filearg.
8184 */
8185 static int
8186apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008187 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008188 char_u *fname;
8189 char_u *fname_io;
8190 int force;
8191 buf_T *buf;
8192 exarg_T *eap;
8193{
8194 return apply_autocmds_group(event, fname, fname_io, force,
8195 AUGROUP_ALL, buf, eap);
8196}
8197
8198/*
8199 * Like apply_autocmds(), but handles the caller's retval. If the script
8200 * processing is being aborted or if retval is FAIL when inside a try
8201 * conditional, no autocommands are executed. If otherwise the autocommands
8202 * cause the script to be aborted, retval is set to FAIL.
8203 */
8204 int
8205apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008206 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008207 char_u *fname; /* NULL or empty means use actual file name */
8208 char_u *fname_io; /* fname to use for <afile> on cmdline */
8209 int force; /* when TRUE, ignore autocmd_busy */
8210 buf_T *buf; /* buffer for <abuf> */
8211 int *retval; /* pointer to caller's retval */
8212{
8213 int did_cmd;
8214
Bram Moolenaar1e015462005-09-25 22:16:38 +00008215#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008216 if (should_abort(*retval))
8217 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008218#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008219
8220 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8221 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008222 if (did_cmd
8223#ifdef FEAT_EVAL
8224 && aborting()
8225#endif
8226 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008227 *retval = FAIL;
8228 return did_cmd;
8229}
8230
Bram Moolenaard35f9712005-12-18 22:02:33 +00008231/*
8232 * Return TRUE when there is a CursorHold autocommand defined.
8233 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008234 int
8235has_cursorhold()
8236{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008237 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8238 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008239}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008240
8241/*
8242 * Return TRUE if the CursorHold event can be triggered.
8243 */
8244 int
8245trigger_cursorhold()
8246{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008247 int state;
8248
8249 if (!did_cursorhold && has_cursorhold() && !Recording)
8250 {
8251 state = get_real_state();
8252 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8253 return TRUE;
8254 }
8255 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008256}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008257
8258/*
8259 * Return TRUE when there is a CursorMoved autocommand defined.
8260 */
8261 int
8262has_cursormoved()
8263{
8264 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8265}
8266
8267/*
8268 * Return TRUE when there is a CursorMovedI autocommand defined.
8269 */
8270 int
8271has_cursormovedI()
8272{
8273 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8274}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008275
8276 static int
8277apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008278 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008279 char_u *fname; /* NULL or empty means use actual file name */
8280 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8281 use fname */
8282 int force; /* when TRUE, ignore autocmd_busy */
8283 int group; /* group ID, or AUGROUP_ALL */
8284 buf_T *buf; /* buffer for <abuf> */
8285 exarg_T *eap; /* command arguments */
8286{
8287 char_u *sfname = NULL; /* short file name */
8288 char_u *tail;
8289 int save_changed;
8290 buf_T *old_curbuf;
8291 int retval = FALSE;
8292 char_u *save_sourcing_name;
8293 linenr_T save_sourcing_lnum;
8294 char_u *save_autocmd_fname;
8295 int save_autocmd_bufnr;
8296 char_u *save_autocmd_match;
8297 int save_autocmd_busy;
8298 int save_autocmd_nested;
8299 static int nesting = 0;
8300 AutoPatCmd patcmd;
8301 AutoPat *ap;
8302#ifdef FEAT_EVAL
8303 scid_T save_current_SID;
8304 void *save_funccalp;
8305 char_u *save_cmdarg;
8306 long save_cmdbang;
8307#endif
8308 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008309#ifdef FEAT_PROFILE
8310 proftime_T wait_time;
8311#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008312
8313 /*
8314 * Quickly return if there are no autocommands for this event or
8315 * autocommands are blocked.
8316 */
8317 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008318 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008319
8320 /*
8321 * When autocommands are busy, new autocommands are only executed when
8322 * explicitly enabled with the "nested" flag.
8323 */
8324 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008325 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008326
8327#ifdef FEAT_EVAL
8328 /*
8329 * Quickly return when immdediately aborting on error, or when an interrupt
8330 * occurred or an exception was thrown but not caught.
8331 */
8332 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008333 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008334#endif
8335
8336 /*
8337 * FileChangedShell never nests, because it can create an endless loop.
8338 */
8339 if (filechangeshell_busy && event == EVENT_FILECHANGEDSHELL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008340 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008341
8342 /*
8343 * Ignore events in 'eventignore'.
8344 */
8345 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008346 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008347
8348 /*
8349 * Allow nesting of autocommands, but restrict the depth, because it's
8350 * possible to create an endless loop.
8351 */
8352 if (nesting == 10)
8353 {
8354 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008355 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008356 }
8357
8358 /*
8359 * Check if these autocommands are disabled. Used when doing ":all" or
8360 * ":ball".
8361 */
8362 if ( (autocmd_no_enter
8363 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8364 || (autocmd_no_leave
8365 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008366 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008367
8368 /*
8369 * Save the autocmd_* variables and info about the current buffer.
8370 */
8371 save_autocmd_fname = autocmd_fname;
8372 save_autocmd_bufnr = autocmd_bufnr;
8373 save_autocmd_match = autocmd_match;
8374 save_autocmd_busy = autocmd_busy;
8375 save_autocmd_nested = autocmd_nested;
8376 save_changed = curbuf->b_changed;
8377 old_curbuf = curbuf;
8378
8379 /*
8380 * Set the file name to be used for <afile>.
8381 */
8382 if (fname_io == NULL)
8383 {
8384 if (fname != NULL && *fname != NUL)
8385 autocmd_fname = fname;
8386 else if (buf != NULL)
8387 autocmd_fname = buf->b_fname;
8388 else
8389 autocmd_fname = NULL;
8390 }
8391 else
8392 autocmd_fname = fname_io;
8393
8394 /*
8395 * Set the buffer number to be used for <abuf>.
8396 */
8397 if (buf == NULL)
8398 autocmd_bufnr = 0;
8399 else
8400 autocmd_bufnr = buf->b_fnum;
8401
8402 /*
8403 * When the file name is NULL or empty, use the file name of buffer "buf".
8404 * Always use the full path of the file name to match with, in case
8405 * "allow_dirs" is set.
8406 */
8407 if (fname == NULL || *fname == NUL)
8408 {
8409 if (buf == NULL)
8410 fname = NULL;
8411 else
8412 {
8413#ifdef FEAT_SYN_HL
8414 if (event == EVENT_SYNTAX)
8415 fname = buf->b_p_syn;
8416 else
8417#endif
8418 if (event == EVENT_FILETYPE)
8419 fname = buf->b_p_ft;
8420 else
8421 {
8422 if (buf->b_sfname != NULL)
8423 sfname = vim_strsave(buf->b_sfname);
8424 fname = buf->b_ffname;
8425 }
8426 }
8427 if (fname == NULL)
8428 fname = (char_u *)"";
8429 fname = vim_strsave(fname); /* make a copy, so we can change it */
8430 }
8431 else
8432 {
8433 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008434 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8435 if (event == EVENT_FILETYPE
8436 || event == EVENT_SYNTAX
8437 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008438 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008439 || event == EVENT_QUICKFIXCMDPRE
8440 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008441 fname = vim_strsave(fname);
8442 else
8443 fname = FullName_save(fname, FALSE);
8444 }
8445 if (fname == NULL) /* out of memory */
8446 {
8447 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008448 retval = FALSE;
8449 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008450 }
8451
8452#ifdef BACKSLASH_IN_FILENAME
8453 /*
8454 * Replace all backslashes with forward slashes. This makes the
8455 * autocommand patterns portable between Unix and MS-DOS.
8456 */
8457 if (sfname != NULL)
8458 forward_slash(sfname);
8459 forward_slash(fname);
8460#endif
8461
8462#ifdef VMS
8463 /* remove version for correct match */
8464 if (sfname != NULL)
8465 vms_remove_version(sfname);
8466 vms_remove_version(fname);
8467#endif
8468
8469 /*
8470 * Set the name to be used for <amatch>.
8471 */
8472 autocmd_match = fname;
8473
8474
8475 /* Don't redraw while doing auto commands. */
8476 ++RedrawingDisabled;
8477 save_sourcing_name = sourcing_name;
8478 sourcing_name = NULL; /* don't free this one */
8479 save_sourcing_lnum = sourcing_lnum;
8480 sourcing_lnum = 0; /* no line number here */
8481
8482#ifdef FEAT_EVAL
8483 save_current_SID = current_SID;
8484
Bram Moolenaar05159a02005-02-26 23:04:13 +00008485# ifdef FEAT_PROFILE
8486 if (do_profiling)
8487 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8488# endif
8489
Bram Moolenaar071d4272004-06-13 20:20:40 +00008490 /* Don't use local function variables, if called from a function */
8491 save_funccalp = save_funccal();
8492#endif
8493
8494 /*
8495 * When starting to execute autocommands, save the search patterns.
8496 */
8497 if (!autocmd_busy)
8498 {
8499 save_search_patterns();
8500 saveRedobuff();
8501 did_filetype = keep_filetype;
8502 }
8503
8504 /*
8505 * Note that we are applying autocmds. Some commands need to know.
8506 */
8507 autocmd_busy = TRUE;
8508 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8509 ++nesting; /* see matching decrement below */
8510
8511 /* Remember that FileType was triggered. Used for did_filetype(). */
8512 if (event == EVENT_FILETYPE)
8513 did_filetype = TRUE;
8514
8515 tail = gettail(fname);
8516
8517 /* Find first autocommand that matches */
8518 patcmd.curpat = first_autopat[(int)event];
8519 patcmd.nextcmd = NULL;
8520 patcmd.group = group;
8521 patcmd.fname = fname;
8522 patcmd.sfname = sfname;
8523 patcmd.tail = tail;
8524 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008525 patcmd.arg_bufnr = autocmd_bufnr;
8526 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008527 auto_next_pat(&patcmd, FALSE);
8528
8529 /* found one, start executing the autocommands */
8530 if (patcmd.curpat != NULL)
8531 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008532 /* add to active_apc_list */
8533 patcmd.next = active_apc_list;
8534 active_apc_list = &patcmd;
8535
Bram Moolenaar071d4272004-06-13 20:20:40 +00008536#ifdef FEAT_EVAL
8537 /* set v:cmdarg (only when there is a matching pattern) */
8538 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8539 if (eap != NULL)
8540 {
8541 save_cmdarg = set_cmdarg(eap, NULL);
8542 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8543 }
8544 else
8545 save_cmdarg = NULL; /* avoid gcc warning */
8546#endif
8547 retval = TRUE;
8548 /* mark the last pattern, to avoid an endless loop when more patterns
8549 * are added when executing autocommands */
8550 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8551 ap->last = FALSE;
8552 ap->last = TRUE;
8553 check_lnums(TRUE); /* make sure cursor and topline are valid */
8554 do_cmdline(NULL, getnextac, (void *)&patcmd,
8555 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8556#ifdef FEAT_EVAL
8557 if (eap != NULL)
8558 {
8559 (void)set_cmdarg(NULL, save_cmdarg);
8560 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8561 }
8562#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008563 /* delete from active_apc_list */
8564 if (active_apc_list == &patcmd) /* just in case */
8565 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008566 }
8567
8568 --RedrawingDisabled;
8569 autocmd_busy = save_autocmd_busy;
8570 filechangeshell_busy = FALSE;
8571 autocmd_nested = save_autocmd_nested;
8572 vim_free(sourcing_name);
8573 sourcing_name = save_sourcing_name;
8574 sourcing_lnum = save_sourcing_lnum;
8575 autocmd_fname = save_autocmd_fname;
8576 autocmd_bufnr = save_autocmd_bufnr;
8577 autocmd_match = save_autocmd_match;
8578#ifdef FEAT_EVAL
8579 current_SID = save_current_SID;
8580 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008581# ifdef FEAT_PROFILE
8582 if (do_profiling)
8583 prof_child_exit(&wait_time);
8584# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008585#endif
8586 vim_free(fname);
8587 vim_free(sfname);
8588 --nesting; /* see matching increment above */
8589
8590 /*
8591 * When stopping to execute autocommands, restore the search patterns and
8592 * the redo buffer.
8593 */
8594 if (!autocmd_busy)
8595 {
8596 restore_search_patterns();
8597 restoreRedobuff();
8598 did_filetype = FALSE;
8599 }
8600
8601 /*
8602 * Some events don't set or reset the Changed flag.
8603 * Check if still in the same buffer!
8604 */
8605 if (curbuf == old_curbuf
8606 && (event == EVENT_BUFREADPOST
8607 || event == EVENT_BUFWRITEPOST
8608 || event == EVENT_FILEAPPENDPOST
8609 || event == EVENT_VIMLEAVE
8610 || event == EVENT_VIMLEAVEPRE))
8611 {
8612#ifdef FEAT_TITLE
8613 if (curbuf->b_changed != save_changed)
8614 need_maketitle = TRUE;
8615#endif
8616 curbuf->b_changed = save_changed;
8617 }
8618
8619 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008620
8621BYPASS_AU:
8622 /* When wiping out a buffer make sure all its buffer-local autocommands
8623 * are deleted. */
8624 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8625 aubuflocal_remove(buf);
8626
Bram Moolenaar071d4272004-06-13 20:20:40 +00008627 return retval;
8628}
8629
8630/*
8631 * Find next autocommand pattern that matches.
8632 */
8633 static void
8634auto_next_pat(apc, stop_at_last)
8635 AutoPatCmd *apc;
8636 int stop_at_last; /* stop when 'last' flag is set */
8637{
8638 AutoPat *ap;
8639 AutoCmd *cp;
8640 char_u *name;
8641 char *s;
8642
8643 vim_free(sourcing_name);
8644 sourcing_name = NULL;
8645
8646 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8647 {
8648 apc->curpat = NULL;
8649
8650 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008651 * the group matches. For buffer-local autocommands only check the
8652 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008653 if (ap->pat != NULL && ap->cmds != NULL
8654 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8655 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008656 /* execution-condition */
8657 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008658 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8659 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008660 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008661 {
8662 name = event_nr2name(apc->event);
8663 s = _("%s Auto commands for \"%s\"");
8664 sourcing_name = alloc((unsigned)(STRLEN(s)
8665 + STRLEN(name) + ap->patlen + 1));
8666 if (sourcing_name != NULL)
8667 {
8668 sprintf((char *)sourcing_name, s,
8669 (char *)name, (char *)ap->pat);
8670 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008671 {
8672 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008673 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008674 verbose_leave();
8675 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008676 }
8677
8678 apc->curpat = ap;
8679 apc->nextcmd = ap->cmds;
8680 /* mark last command */
8681 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8682 cp->last = FALSE;
8683 cp->last = TRUE;
8684 }
8685 line_breakcheck();
8686 if (apc->curpat != NULL) /* found a match */
8687 break;
8688 }
8689 if (stop_at_last && ap->last)
8690 break;
8691 }
8692}
8693
8694/*
8695 * Get next autocommand command.
8696 * Called by do_cmdline() to get the next line for ":if".
8697 * Returns allocated string, or NULL for end of autocommands.
8698 */
8699/* ARGSUSED */
8700 static char_u *
8701getnextac(c, cookie, indent)
8702 int c; /* not used */
8703 void *cookie;
8704 int indent; /* not used */
8705{
8706 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8707 char_u *retval;
8708 AutoCmd *ac;
8709
8710 /* Can be called again after returning the last line. */
8711 if (acp->curpat == NULL)
8712 return NULL;
8713
8714 /* repeat until we find an autocommand to execute */
8715 for (;;)
8716 {
8717 /* skip removed commands */
8718 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8719 if (acp->nextcmd->last)
8720 acp->nextcmd = NULL;
8721 else
8722 acp->nextcmd = acp->nextcmd->next;
8723
8724 if (acp->nextcmd != NULL)
8725 break;
8726
8727 /* at end of commands, find next pattern that matches */
8728 if (acp->curpat->last)
8729 acp->curpat = NULL;
8730 else
8731 acp->curpat = acp->curpat->next;
8732 if (acp->curpat != NULL)
8733 auto_next_pat(acp, TRUE);
8734 if (acp->curpat == NULL)
8735 return NULL;
8736 }
8737
8738 ac = acp->nextcmd;
8739
8740 if (p_verbose >= 9)
8741 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008742 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008743 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008744 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008745 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008746 }
8747 retval = vim_strsave(ac->cmd);
8748 autocmd_nested = ac->nested;
8749#ifdef FEAT_EVAL
8750 current_SID = ac->scriptID;
8751#endif
8752 if (ac->last)
8753 acp->nextcmd = NULL;
8754 else
8755 acp->nextcmd = ac->next;
8756 return retval;
8757}
8758
8759/*
8760 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008761 * To account for buffer-local autocommands, function needs to know
8762 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008763 */
8764 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008765has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008766 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008767 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008768 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008769{
8770 AutoPat *ap;
8771 char_u *fname;
8772 char_u *tail = gettail(sfname);
8773 int retval = FALSE;
8774
8775 fname = FullName_save(sfname, FALSE);
8776 if (fname == NULL)
8777 return FALSE;
8778
8779#ifdef BACKSLASH_IN_FILENAME
8780 /*
8781 * Replace all backslashes with forward slashes. This makes the
8782 * autocommand patterns portable between Unix and MS-DOS.
8783 */
8784 sfname = vim_strsave(sfname);
8785 if (sfname != NULL)
8786 forward_slash(sfname);
8787 forward_slash(fname);
8788#endif
8789
8790 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8791 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008792 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008793 ? match_file_pat(NULL, ap->reg_prog,
8794 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008795 : buf != NULL && ap->buflocal_nr == buf->b_fnum
8796 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008797 {
8798 retval = TRUE;
8799 break;
8800 }
8801
8802 vim_free(fname);
8803#ifdef BACKSLASH_IN_FILENAME
8804 vim_free(sfname);
8805#endif
8806
8807 return retval;
8808}
8809
8810#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8811/*
8812 * Function given to ExpandGeneric() to obtain the list of autocommand group
8813 * names.
8814 */
8815/*ARGSUSED*/
8816 char_u *
8817get_augroup_name(xp, idx)
8818 expand_T *xp;
8819 int idx;
8820{
8821 if (idx == augroups.ga_len) /* add "END" add the end */
8822 return (char_u *)"END";
8823 if (idx >= augroups.ga_len) /* end of list */
8824 return NULL;
8825 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8826 return (char_u *)"";
8827 return AUGROUP_NAME(idx); /* return a name */
8828}
8829
8830static int include_groups = FALSE;
8831
8832 char_u *
8833set_context_in_autocmd(xp, arg, doautocmd)
8834 expand_T *xp;
8835 char_u *arg;
8836 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8837{
8838 char_u *p;
8839 int group;
8840
8841 /* check for a group name, skip it if present */
8842 include_groups = FALSE;
8843 p = arg;
8844 group = au_get_grouparg(&arg);
8845 if (group == AUGROUP_ERROR)
8846 return NULL;
8847 /* If there only is a group name that's what we expand. */
8848 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8849 {
8850 arg = p;
8851 group = AUGROUP_ALL;
8852 }
8853
8854 /* skip over event name */
8855 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8856 if (*p == ',')
8857 arg = p + 1;
8858 if (*p == NUL)
8859 {
8860 if (group == AUGROUP_ALL)
8861 include_groups = TRUE;
8862 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8863 xp->xp_pattern = arg;
8864 return NULL;
8865 }
8866
8867 /* skip over pattern */
8868 arg = skipwhite(p);
8869 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8870 arg++;
8871 if (*arg)
8872 return arg; /* expand (next) command */
8873
8874 if (doautocmd)
8875 xp->xp_context = EXPAND_FILES; /* expand file names */
8876 else
8877 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8878 return NULL;
8879}
8880
8881/*
8882 * Function given to ExpandGeneric() to obtain the list of event names.
8883 */
8884/*ARGSUSED*/
8885 char_u *
8886get_event_name(xp, idx)
8887 expand_T *xp;
8888 int idx;
8889{
8890 if (idx < augroups.ga_len) /* First list group names, if wanted */
8891 {
8892 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8893 return (char_u *)""; /* skip deleted entries */
8894 return AUGROUP_NAME(idx); /* return a name */
8895 }
8896 return (char_u *)event_names[idx - augroups.ga_len].name;
8897}
8898
8899#endif /* FEAT_CMDL_COMPL */
8900
8901/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008902 * Return TRUE if autocmd is supported.
8903 */
8904 int
8905autocmd_supported(name)
8906 char_u *name;
8907{
8908 char_u *p;
8909
8910 return (event_name2nr(name, &p) != NUM_EVENTS);
8911}
8912
8913/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008914 * Return TRUE if an autocommand is defined for a group, event and
8915 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8916 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8917 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8918 * Used for:
8919 * exists("#Group") or
8920 * exists("#Group#Event") or
8921 * exists("#Group#Event#pat") or
8922 * exists("#Event") or
8923 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008924 */
8925 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008926au_exists(arg)
8927 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008928{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008929 char_u *arg_save;
8930 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008931 char_u *event_name;
8932 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00008933 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008934 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008935 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008936 int group;
8937 int retval = FALSE;
8938
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008939 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008940 arg_save = vim_strsave(arg);
8941 if (arg_save == NULL)
8942 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008943 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008944 if (p != NULL)
8945 *p++ = NUL;
8946
8947 /* First, look for an autocmd group name */
8948 group = au_find_group(arg_save);
8949 if (group == AUGROUP_ERROR)
8950 {
8951 /* Didn't match a group name, assume the first argument is an event. */
8952 group = AUGROUP_ALL;
8953 event_name = arg_save;
8954 }
8955 else
8956 {
8957 if (p == NULL)
8958 {
8959 /* "Group": group name is present and it's recognized */
8960 retval = TRUE;
8961 goto theend;
8962 }
8963
8964 /* Must be "Group#Event" or "Group#Event#pat". */
8965 event_name = p;
8966 p = vim_strchr(event_name, '#');
8967 if (p != NULL)
8968 *p++ = NUL; /* "Group#Event#pat" */
8969 }
8970
8971 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008972
8973 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008974 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008975
8976 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008977 if (event == NUM_EVENTS)
8978 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008979
8980 /* Find the first autocommand for this event.
8981 * If there isn't any, return FALSE;
8982 * If there is one and no pattern given, return TRUE; */
8983 ap = first_autopat[(int)event];
8984 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008985 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008986 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008987 {
8988 retval = TRUE;
8989 goto theend;
8990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008991
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008992 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
8993 /* for pattern "<buffer=N>, fnamecmp() will work fine */
8994 if (STRICMP(pattern, "<buffer>") == 0)
8995 buflocal_buf = curbuf;
8996
Bram Moolenaar071d4272004-06-13 20:20:40 +00008997 /* Check if there is an autocommand with the given pattern. */
8998 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008999 /* only use a pattern when it has not been removed and has commands. */
9000 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009001 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009002 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009003 && (buflocal_buf == NULL
9004 ? fnamecmp(ap->pat, pattern) == 0
9005 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009006 {
9007 retval = TRUE;
9008 break;
9009 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009010
Bram Moolenaar195d6352005-12-19 22:08:24 +00009011theend:
9012 vim_free(arg_save);
9013 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009014}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009015
Bram Moolenaar071d4272004-06-13 20:20:40 +00009016#endif /* FEAT_AUTOCMD */
9017
9018#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9019/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009020 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9021 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9022 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009023 * Used for autocommands and 'wildignore'.
9024 * Returns TRUE if there is a match, FALSE otherwise.
9025 */
9026 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009027match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009028 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009029 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009030 char_u *fname; /* full path of file name */
9031 char_u *sfname; /* short file name or NULL */
9032 char_u *tail; /* tail of path */
9033 int allow_dirs; /* allow matching with dir */
9034{
9035 regmatch_T regmatch;
9036 int result = FALSE;
9037#ifdef FEAT_OSFILETYPE
9038 int no_pattern = FALSE; /* TRUE if check is filetype only */
9039 char_u *type_start;
9040 char_u c;
9041 int match = FALSE;
9042#endif
9043
9044#ifdef CASE_INSENSITIVE_FILENAME
9045 regmatch.rm_ic = TRUE; /* Always ignore case */
9046#else
9047 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9048#endif
9049#ifdef FEAT_OSFILETYPE
9050 if (*pattern == '<')
9051 {
9052 /* There is a filetype condition specified with this pattern.
9053 * Check the filetype matches first. If not, don't bother with the
9054 * pattern (set regprog to NULL).
9055 * Always use magic for the regexp.
9056 */
9057
9058 for (type_start = pattern + 1; (c = *pattern); pattern++)
9059 {
9060 if ((c == ';' || c == '>') && match == FALSE)
9061 {
9062 *pattern = NUL; /* Terminate the string */
9063 match = mch_check_filetype(fname, type_start);
9064 *pattern = c; /* Restore the terminator */
9065 type_start = pattern + 1;
9066 }
9067 if (c == '>')
9068 break;
9069 }
9070
9071 /* (c should never be NUL, but check anyway) */
9072 if (match == FALSE || c == NUL)
9073 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9074 else if (*pattern == NUL)
9075 {
9076 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9077 no_pattern = TRUE; /* Always matches - don't check pat. */
9078 }
9079 else
9080 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9081 }
9082 else
9083#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009084 {
9085 if (prog != NULL)
9086 regmatch.regprog = prog;
9087 else
9088 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9089 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009090
9091 /*
9092 * Try for a match with the pattern with:
9093 * 1. the full file name, when the pattern has a '/'.
9094 * 2. the short file name, when the pattern has a '/'.
9095 * 3. the tail of the file name, when the pattern has no '/'.
9096 */
9097 if (
9098#ifdef FEAT_OSFILETYPE
9099 /* If the check is for a filetype only and we don't care
9100 * about the path then skip all the regexp stuff.
9101 */
9102 no_pattern ||
9103#endif
9104 (regmatch.regprog != NULL
9105 && ((allow_dirs
9106 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9107 || (sfname != NULL
9108 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9109 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9110 result = TRUE;
9111
Bram Moolenaar748bf032005-02-02 23:04:36 +00009112 if (prog == NULL)
9113 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009114 return result;
9115}
9116#endif
9117
9118#if defined(FEAT_WILDIGN) || defined(PROTO)
9119/*
9120 * Return TRUE if a file matches with a pattern in "list".
9121 * "list" is a comma-separated list of patterns, like 'wildignore'.
9122 * "sfname" is the short file name or NULL, "ffname" the long file name.
9123 */
9124 int
9125match_file_list(list, sfname, ffname)
9126 char_u *list;
9127 char_u *sfname;
9128 char_u *ffname;
9129{
9130 char_u buf[100];
9131 char_u *tail;
9132 char_u *regpat;
9133 char allow_dirs;
9134 int match;
9135 char_u *p;
9136
9137 tail = gettail(sfname);
9138
9139 /* try all patterns in 'wildignore' */
9140 p = list;
9141 while (*p)
9142 {
9143 copy_option_part(&p, buf, 100, ",");
9144 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9145 if (regpat == NULL)
9146 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009147 match = match_file_pat(regpat, NULL, ffname, sfname,
9148 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009149 vim_free(regpat);
9150 if (match)
9151 return TRUE;
9152 }
9153 return FALSE;
9154}
9155#endif
9156
9157/*
9158 * Convert the given pattern "pat" which has shell style wildcards in it, into
9159 * a regular expression, and return the result in allocated memory. If there
9160 * is a directory path separator to be matched, then TRUE is put in
9161 * allow_dirs, otherwise FALSE is put there -- webb.
9162 * Handle backslashes before special characters, like "\*" and "\ ".
9163 *
9164 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9165 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9166 *
9167 * Returns NULL when out of memory.
9168 */
9169/*ARGSUSED*/
9170 char_u *
9171file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9172 char_u *pat;
9173 char_u *pat_end; /* first char after pattern or NULL */
9174 char *allow_dirs; /* Result passed back out in here */
9175 int no_bslash; /* Don't use a backward slash as pathsep */
9176{
9177 int size;
9178 char_u *endp;
9179 char_u *reg_pat;
9180 char_u *p;
9181 int i;
9182 int nested = 0;
9183 int add_dollar = TRUE;
9184#ifdef FEAT_OSFILETYPE
9185 int check_length = 0;
9186#endif
9187
9188 if (allow_dirs != NULL)
9189 *allow_dirs = FALSE;
9190 if (pat_end == NULL)
9191 pat_end = pat + STRLEN(pat);
9192
9193#ifdef FEAT_OSFILETYPE
9194 /* Find out how much of the string is the filetype check */
9195 if (*pat == '<')
9196 {
9197 /* Count chars until the next '>' */
9198 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9199 ;
9200 if (p < pat_end)
9201 {
9202 /* Pattern is of the form <.*>.* */
9203 check_length = p - pat + 1;
9204 if (p + 1 >= pat_end)
9205 {
9206 /* The 'pattern' is a filetype check ONLY */
9207 reg_pat = (char_u *)alloc(check_length + 1);
9208 if (reg_pat != NULL)
9209 {
9210 mch_memmove(reg_pat, pat, (size_t)check_length);
9211 reg_pat[check_length] = NUL;
9212 }
9213 return reg_pat;
9214 }
9215 }
9216 /* else: there was no closing '>' - assume it was a normal pattern */
9217
9218 }
9219 pat += check_length;
9220 size = 2 + check_length;
9221#else
9222 size = 2; /* '^' at start, '$' at end */
9223#endif
9224
9225 for (p = pat; p < pat_end; p++)
9226 {
9227 switch (*p)
9228 {
9229 case '*':
9230 case '.':
9231 case ',':
9232 case '{':
9233 case '}':
9234 case '~':
9235 size += 2; /* extra backslash */
9236 break;
9237#ifdef BACKSLASH_IN_FILENAME
9238 case '\\':
9239 case '/':
9240 size += 4; /* could become "[\/]" */
9241 break;
9242#endif
9243 default:
9244 size++;
9245# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009246 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009247 {
9248 ++p;
9249 ++size;
9250 }
9251# endif
9252 break;
9253 }
9254 }
9255 reg_pat = alloc(size + 1);
9256 if (reg_pat == NULL)
9257 return NULL;
9258
9259#ifdef FEAT_OSFILETYPE
9260 /* Copy the type check in to the start. */
9261 if (check_length)
9262 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9263 i = check_length;
9264#else
9265 i = 0;
9266#endif
9267
9268 if (pat[0] == '*')
9269 while (pat[0] == '*' && pat < pat_end - 1)
9270 pat++;
9271 else
9272 reg_pat[i++] = '^';
9273 endp = pat_end - 1;
9274 if (*endp == '*')
9275 {
9276 while (endp - pat > 0 && *endp == '*')
9277 endp--;
9278 add_dollar = FALSE;
9279 }
9280 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9281 {
9282 switch (*p)
9283 {
9284 case '*':
9285 reg_pat[i++] = '.';
9286 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009287 while (p[1] == '*') /* "**" matches like "*" */
9288 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009289 break;
9290 case '.':
9291#ifdef RISCOS
9292 if (allow_dirs != NULL)
9293 *allow_dirs = TRUE;
9294 /* FALLTHROUGH */
9295#endif
9296 case '~':
9297 reg_pat[i++] = '\\';
9298 reg_pat[i++] = *p;
9299 break;
9300 case '?':
9301#ifdef RISCOS
9302 case '#':
9303#endif
9304 reg_pat[i++] = '.';
9305 break;
9306 case '\\':
9307 if (p[1] == NUL)
9308 break;
9309#ifdef BACKSLASH_IN_FILENAME
9310 if (!no_bslash)
9311 {
9312 /* translate:
9313 * "\x" to "\\x" e.g., "dir\file"
9314 * "\*" to "\\.*" e.g., "dir\*.c"
9315 * "\?" to "\\." e.g., "dir\??.c"
9316 * "\+" to "\+" e.g., "fileX\+.c"
9317 */
9318 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9319 && p[1] != '+')
9320 {
9321 reg_pat[i++] = '[';
9322 reg_pat[i++] = '\\';
9323 reg_pat[i++] = '/';
9324 reg_pat[i++] = ']';
9325 if (allow_dirs != NULL)
9326 *allow_dirs = TRUE;
9327 break;
9328 }
9329 }
9330#endif
9331 if (*++p == '?'
9332#ifdef BACKSLASH_IN_FILENAME
9333 && no_bslash
9334#endif
9335 )
9336 reg_pat[i++] = '?';
9337 else
9338 if (*p == ',')
9339 reg_pat[i++] = ',';
9340 else
9341 {
9342 if (allow_dirs != NULL && vim_ispathsep(*p)
9343#ifdef BACKSLASH_IN_FILENAME
9344 && (!no_bslash || *p != '\\')
9345#endif
9346 )
9347 *allow_dirs = TRUE;
9348 reg_pat[i++] = '\\';
9349 reg_pat[i++] = *p;
9350 }
9351 break;
9352#ifdef BACKSLASH_IN_FILENAME
9353 case '/':
9354 reg_pat[i++] = '[';
9355 reg_pat[i++] = '\\';
9356 reg_pat[i++] = '/';
9357 reg_pat[i++] = ']';
9358 if (allow_dirs != NULL)
9359 *allow_dirs = TRUE;
9360 break;
9361#endif
9362 case '{':
9363 reg_pat[i++] = '\\';
9364 reg_pat[i++] = '(';
9365 nested++;
9366 break;
9367 case '}':
9368 reg_pat[i++] = '\\';
9369 reg_pat[i++] = ')';
9370 --nested;
9371 break;
9372 case ',':
9373 if (nested)
9374 {
9375 reg_pat[i++] = '\\';
9376 reg_pat[i++] = '|';
9377 }
9378 else
9379 reg_pat[i++] = ',';
9380 break;
9381 default:
9382# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009383 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009384 reg_pat[i++] = *p++;
9385 else
9386# endif
9387 if (allow_dirs != NULL && vim_ispathsep(*p))
9388 *allow_dirs = TRUE;
9389 reg_pat[i++] = *p;
9390 break;
9391 }
9392 }
9393 if (add_dollar)
9394 reg_pat[i++] = '$';
9395 reg_pat[i] = NUL;
9396 if (nested != 0)
9397 {
9398 if (nested < 0)
9399 EMSG(_("E219: Missing {."));
9400 else
9401 EMSG(_("E220: Missing }."));
9402 vim_free(reg_pat);
9403 reg_pat = NULL;
9404 }
9405 return reg_pat;
9406}