blob: aeb5dc9a2267532e6c707d024bd79b1f77b69613 [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. */
2169 if ((newfile || read_buffer))
2170 diff_invalidate();
2171#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();
5527#endif
5528}
5529
5530#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5531 || defined(FEAT_GUI_MSWIN) \
5532 || defined(FEAT_GUI_MAC) \
5533 || defined(PROTO)
5534/*
5535 * Shorten all filenames in "fnames[count]" by current directory.
5536 */
5537 void
5538shorten_filenames(fnames, count)
5539 char_u **fnames;
5540 int count;
5541{
5542 int i;
5543 char_u dirname[MAXPATHL];
5544 char_u *p;
5545
5546 if (fnames == NULL || count < 1)
5547 return;
5548 mch_dirname(dirname, sizeof(dirname));
5549 for (i = 0; i < count; ++i)
5550 {
5551 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5552 {
5553 /* shorten_fname() returns pointer in given "fnames[i]". If free
5554 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5555 * "p" first then free fnames[i]. */
5556 p = vim_strsave(p);
5557 vim_free(fnames[i]);
5558 fnames[i] = p;
5559 }
5560 }
5561}
5562#endif
5563
5564/*
5565 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5566 * fo_o_h.ext for MSDOS or when shortname option set.
5567 *
5568 * Assumed that fname is a valid name found in the filesystem we assure that
5569 * the return value is a different name and ends in 'ext'.
5570 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5571 * characters otherwise.
5572 * Space for the returned name is allocated, must be freed later.
5573 * Returns NULL when out of memory.
5574 */
5575 char_u *
5576modname(fname, ext, prepend_dot)
5577 char_u *fname, *ext;
5578 int prepend_dot; /* may prepend a '.' to file name */
5579{
5580 return buf_modname(
5581#ifdef SHORT_FNAME
5582 TRUE,
5583#else
5584 (curbuf->b_p_sn || curbuf->b_shortname),
5585#endif
5586 fname, ext, prepend_dot);
5587}
5588
5589 char_u *
5590buf_modname(shortname, fname, ext, prepend_dot)
5591 int shortname; /* use 8.3 file name */
5592 char_u *fname, *ext;
5593 int prepend_dot; /* may prepend a '.' to file name */
5594{
5595 char_u *retval;
5596 char_u *s;
5597 char_u *e;
5598 char_u *ptr;
5599 int fnamelen, extlen;
5600
5601 extlen = (int)STRLEN(ext);
5602
5603 /*
5604 * If there is no file name we must get the name of the current directory
5605 * (we need the full path in case :cd is used).
5606 */
5607 if (fname == NULL || *fname == NUL)
5608 {
5609 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5610 if (retval == NULL)
5611 return NULL;
5612 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5613 (fnamelen = (int)STRLEN(retval)) == 0)
5614 {
5615 vim_free(retval);
5616 return NULL;
5617 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005618 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 {
5620 retval[fnamelen++] = PATHSEP;
5621 retval[fnamelen] = NUL;
5622 }
5623#ifndef SHORT_FNAME
5624 prepend_dot = FALSE; /* nothing to prepend a dot to */
5625#endif
5626 }
5627 else
5628 {
5629 fnamelen = (int)STRLEN(fname);
5630 retval = alloc((unsigned)(fnamelen + extlen + 3));
5631 if (retval == NULL)
5632 return NULL;
5633 STRCPY(retval, fname);
5634#ifdef VMS
5635 vms_remove_version(retval); /* we do not need versions here */
5636#endif
5637 }
5638
5639 /*
5640 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5641 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5642 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5643 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5644 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005645 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005646 {
5647#ifndef RISCOS
5648 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005649# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005650 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005651# else
5652# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005654# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005655# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005656 )
5657 if (*ptr == '.') /* replace '.' by '_' */
5658 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005659#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005661 {
5662 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005663 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666
5667 /* the file name has at most BASENAMELEN characters. */
5668#ifndef SHORT_FNAME
5669 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5670 ptr[BASENAMELEN] = '\0';
5671#endif
5672
5673 s = ptr + STRLEN(ptr);
5674
5675 /*
5676 * For 8.3 file names we may have to reduce the length.
5677 */
5678#ifdef USE_LONG_FNAME
5679 if (!USE_LONG_FNAME || shortname)
5680#else
5681# ifndef SHORT_FNAME
5682 if (shortname)
5683# endif
5684#endif
5685 {
5686 /*
5687 * If there is no file name, or the file name ends in '/', and the
5688 * extension starts with '.', put a '_' before the dot, because just
5689 * ".ext" is invalid.
5690 */
5691 if (fname == NULL || *fname == NUL
5692 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5693 {
5694#ifdef RISCOS
5695 if (*ext == '/')
5696#else
5697 if (*ext == '.')
5698#endif
5699 *s++ = '_';
5700 }
5701 /*
5702 * If the extension starts with '.', truncate the base name at 8
5703 * characters
5704 */
5705#ifdef RISCOS
5706 /* We normally use '/', but swap files are '_' */
5707 else if (*ext == '/' || *ext == '_')
5708#else
5709 else if (*ext == '.')
5710#endif
5711 {
5712 if (s - ptr > (size_t)8)
5713 {
5714 s = ptr + 8;
5715 *s = '\0';
5716 }
5717 }
5718 /*
5719 * If the extension doesn't start with '.', and the file name
5720 * doesn't have an extension yet, append a '.'
5721 */
5722#ifdef RISCOS
5723 else if ((e = vim_strchr(ptr, '/')) == NULL)
5724 *s++ = '/';
5725#else
5726 else if ((e = vim_strchr(ptr, '.')) == NULL)
5727 *s++ = '.';
5728#endif
5729 /*
5730 * If the extension doesn't start with '.', and there already is an
5731 * extension, it may need to be tructated
5732 */
5733 else if ((int)STRLEN(e) + extlen > 4)
5734 s = e + 4 - extlen;
5735 }
5736#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5737 /*
5738 * If there is no file name, and the extension starts with '.', put a
5739 * '_' before the dot, because just ".ext" may be invalid if it's on a
5740 * FAT partition, and on HPFS it doesn't matter.
5741 */
5742 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5743 *s++ = '_';
5744#endif
5745
5746 /*
5747 * Append the extention.
5748 * ext can start with '.' and cannot exceed 3 more characters.
5749 */
5750 STRCPY(s, ext);
5751
5752#ifndef SHORT_FNAME
5753 /*
5754 * Prepend the dot.
5755 */
5756 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5757#ifdef RISCOS
5758 '/'
5759#else
5760 '.'
5761#endif
5762#ifdef USE_LONG_FNAME
5763 && USE_LONG_FNAME
5764#endif
5765 )
5766 {
5767 mch_memmove(e + 1, e, STRLEN(e) + 1);
5768#ifdef RISCOS
5769 *e = '/';
5770#else
5771 *e = '.';
5772#endif
5773 }
5774#endif
5775
5776 /*
5777 * Check that, after appending the extension, the file name is really
5778 * different.
5779 */
5780 if (fname != NULL && STRCMP(fname, retval) == 0)
5781 {
5782 /* we search for a character that can be replaced by '_' */
5783 while (--s >= ptr)
5784 {
5785 if (*s != '_')
5786 {
5787 *s = '_';
5788 break;
5789 }
5790 }
5791 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5792 *ptr = 'v';
5793 }
5794 return retval;
5795}
5796
5797/*
5798 * Like fgets(), but if the file line is too long, it is truncated and the
5799 * rest of the line is thrown away. Returns TRUE for end-of-file.
5800 */
5801 int
5802vim_fgets(buf, size, fp)
5803 char_u *buf;
5804 int size;
5805 FILE *fp;
5806{
5807 char *eof;
5808#define FGETS_SIZE 200
5809 char tbuf[FGETS_SIZE];
5810
5811 buf[size - 2] = NUL;
5812#ifdef USE_CR
5813 eof = fgets_cr((char *)buf, size, fp);
5814#else
5815 eof = fgets((char *)buf, size, fp);
5816#endif
5817 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5818 {
5819 buf[size - 1] = NUL; /* Truncate the line */
5820
5821 /* Now throw away the rest of the line: */
5822 do
5823 {
5824 tbuf[FGETS_SIZE - 2] = NUL;
5825#ifdef USE_CR
5826 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
5827#else
5828 fgets((char *)tbuf, FGETS_SIZE, fp);
5829#endif
5830 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
5831 }
5832 return (eof == NULL);
5833}
5834
5835#if defined(USE_CR) || defined(PROTO)
5836/*
5837 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
5838 * Returns TRUE for end-of-file.
5839 * Only used for the Mac, because it's much slower than vim_fgets().
5840 */
5841 int
5842tag_fgets(buf, size, fp)
5843 char_u *buf;
5844 int size;
5845 FILE *fp;
5846{
5847 int i = 0;
5848 int c;
5849 int eof = FALSE;
5850
5851 for (;;)
5852 {
5853 c = fgetc(fp);
5854 if (c == EOF)
5855 {
5856 eof = TRUE;
5857 break;
5858 }
5859 if (c == '\r')
5860 {
5861 /* Always store a NL for end-of-line. */
5862 if (i < size - 1)
5863 buf[i++] = '\n';
5864 c = fgetc(fp);
5865 if (c != '\n') /* Macintosh format: single CR. */
5866 ungetc(c, fp);
5867 break;
5868 }
5869 if (i < size - 1)
5870 buf[i++] = c;
5871 if (c == '\n')
5872 break;
5873 }
5874 buf[i] = NUL;
5875 return eof;
5876}
5877#endif
5878
5879/*
5880 * rename() only works if both files are on the same file system, this
5881 * function will (attempts to?) copy the file across if rename fails -- webb
5882 * Return -1 for failure, 0 for success.
5883 */
5884 int
5885vim_rename(from, to)
5886 char_u *from;
5887 char_u *to;
5888{
5889 int fd_in;
5890 int fd_out;
5891 int n;
5892 char *errmsg = NULL;
5893 char *buffer;
5894#ifdef AMIGA
5895 BPTR flock;
5896#endif
5897 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005898 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005899#ifdef HAVE_ACL
5900 vim_acl_T acl; /* ACL from original file */
5901#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902
5903 /*
5904 * When the names are identical, there is nothing to do.
5905 */
5906 if (fnamecmp(from, to) == 0)
5907 return 0;
5908
5909 /*
5910 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
5911 */
5912 if (mch_stat((char *)from, &st) < 0)
5913 return -1;
5914
5915 /*
5916 * Delete the "to" file, this is required on some systems to make the
5917 * mch_rename() work, on other systems it makes sure that we don't have
5918 * two files when the mch_rename() fails.
5919 */
5920
5921#ifdef AMIGA
5922 /*
5923 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
5924 * that the name of the "to" file is the same as the "from" file, even
5925 * though the names are different. To avoid the chance of accidently
5926 * deleting the "from" file (horror!) we lock it during the remove.
5927 *
5928 * When used for making a backup before writing the file: This should not
5929 * happen with ":w", because startscript() should detect this problem and
5930 * set buf->b_shortname, causing modname() to return a correct ".bak" file
5931 * name. This problem does exist with ":w filename", but then the
5932 * original file will be somewhere else so the backup isn't really
5933 * important. If autoscripting is off the rename may fail.
5934 */
5935 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
5936#endif
5937 mch_remove(to);
5938#ifdef AMIGA
5939 if (flock)
5940 UnLock(flock);
5941#endif
5942
5943 /*
5944 * First try a normal rename, return if it works.
5945 */
5946 if (mch_rename((char *)from, (char *)to) == 0)
5947 return 0;
5948
5949 /*
5950 * Rename() failed, try copying the file.
5951 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005952 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005953#ifdef HAVE_ACL
5954 /* For systems that support ACL: get the ACL from the original file. */
5955 acl = mch_get_acl(from);
5956#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005957 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
5958 if (fd_in == -1)
5959 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005960
5961 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00005962 fd_out = mch_open((char *)to,
5963 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964 if (fd_out == -1)
5965 {
5966 close(fd_in);
5967 return -1;
5968 }
5969
5970 buffer = (char *)alloc(BUFSIZE);
5971 if (buffer == NULL)
5972 {
5973 close(fd_in);
5974 close(fd_out);
5975 return -1;
5976 }
5977
5978 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
5979 if (vim_write(fd_out, buffer, n) != n)
5980 {
5981 errmsg = _("E208: Error writing to \"%s\"");
5982 break;
5983 }
5984
5985 vim_free(buffer);
5986 close(fd_in);
5987 if (close(fd_out) < 0)
5988 errmsg = _("E209: Error closing \"%s\"");
5989 if (n < 0)
5990 {
5991 errmsg = _("E210: Error reading \"%s\"");
5992 to = from;
5993 }
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005994#ifndef UNIX /* for Unix mch_open() already set ther permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005995 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005996#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005997#ifdef HAVE_ACL
5998 mch_set_acl(to, acl);
5999#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006000 if (errmsg != NULL)
6001 {
6002 EMSG2(errmsg, to);
6003 return -1;
6004 }
6005 mch_remove(from);
6006 return 0;
6007}
6008
6009static int already_warned = FALSE;
6010
6011/*
6012 * Check if any not hidden buffer has been changed.
6013 * Postpone the check if there are characters in the stuff buffer, a global
6014 * command is being executed, a mapping is being executed or an autocommand is
6015 * busy.
6016 * Returns TRUE if some message was written (screen should be redrawn and
6017 * cursor positioned).
6018 */
6019 int
6020check_timestamps(focus)
6021 int focus; /* called for GUI focus event */
6022{
6023 buf_T *buf;
6024 int didit = 0;
6025 int n;
6026
6027 /* Don't check timestamps while system() or another low-level function may
6028 * cause us to lose and gain focus. */
6029 if (no_check_timestamps > 0)
6030 return FALSE;
6031
6032 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6033 * event and we would keep on checking if the file is steadily growing.
6034 * Do check again after typing something. */
6035 if (focus && did_check_timestamps)
6036 {
6037 need_check_timestamps = TRUE;
6038 return FALSE;
6039 }
6040
6041 if (!stuff_empty() || global_busy || !typebuf_typed()
6042#ifdef FEAT_AUTOCMD
6043 || autocmd_busy
6044#endif
6045 )
6046 need_check_timestamps = TRUE; /* check later */
6047 else
6048 {
6049 ++no_wait_return;
6050 did_check_timestamps = TRUE;
6051 already_warned = FALSE;
6052 for (buf = firstbuf; buf != NULL; )
6053 {
6054 /* Only check buffers in a window. */
6055 if (buf->b_nwindows > 0)
6056 {
6057 n = buf_check_timestamp(buf, focus);
6058 if (didit < n)
6059 didit = n;
6060 if (n > 0 && !buf_valid(buf))
6061 {
6062 /* Autocommands have removed the buffer, start at the
6063 * first one again. */
6064 buf = firstbuf;
6065 continue;
6066 }
6067 }
6068 buf = buf->b_next;
6069 }
6070 --no_wait_return;
6071 need_check_timestamps = FALSE;
6072 if (need_wait_return && didit == 2)
6073 {
6074 /* make sure msg isn't overwritten */
6075 msg_puts((char_u *)"\n");
6076 out_flush();
6077 }
6078 }
6079 return didit;
6080}
6081
6082/*
6083 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6084 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6085 * empty.
6086 */
6087 static int
6088move_lines(frombuf, tobuf)
6089 buf_T *frombuf;
6090 buf_T *tobuf;
6091{
6092 buf_T *tbuf = curbuf;
6093 int retval = OK;
6094 linenr_T lnum;
6095 char_u *p;
6096
6097 /* Copy the lines in "frombuf" to "tobuf". */
6098 curbuf = tobuf;
6099 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6100 {
6101 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6102 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6103 {
6104 vim_free(p);
6105 retval = FAIL;
6106 break;
6107 }
6108 vim_free(p);
6109 }
6110
6111 /* Delete all the lines in "frombuf". */
6112 if (retval != FAIL)
6113 {
6114 curbuf = frombuf;
6115 while (!bufempty())
6116 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE) == FAIL)
6117 {
6118 /* Oops! We could try putting back the saved lines, but that
6119 * might fail again... */
6120 retval = FAIL;
6121 break;
6122 }
6123 }
6124
6125 curbuf = tbuf;
6126 return retval;
6127}
6128
6129/*
6130 * Check if buffer "buf" has been changed.
6131 * Also check if the file for a new buffer unexpectedly appeared.
6132 * return 1 if a changed buffer was found.
6133 * return 2 if a message has been displayed.
6134 * return 0 otherwise.
6135 */
6136/*ARGSUSED*/
6137 int
6138buf_check_timestamp(buf, focus)
6139 buf_T *buf;
6140 int focus; /* called for GUI focus event */
6141{
6142 struct stat st;
6143 int stat_res;
6144 int retval = 0;
6145 char_u *path;
6146 char_u *tbuf;
6147 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006148 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006149 int helpmesg = FALSE;
6150 int reload = FALSE;
6151#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6152 int can_reload = FALSE;
6153#endif
6154 size_t orig_size = buf->b_orig_size;
6155 int orig_mode = buf->b_orig_mode;
6156#ifdef FEAT_GUI
6157 int save_mouse_correct = need_mouse_correct;
6158#endif
6159#ifdef FEAT_AUTOCMD
6160 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006161 int n;
6162 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006164 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165
6166 /* If there is no file name, the buffer is not loaded, 'buftype' is
6167 * set, we are in the middle of a save or being called recursively: ignore
6168 * this buffer. */
6169 if (buf->b_ffname == NULL
6170 || buf->b_ml.ml_mfp == NULL
6171#if defined(FEAT_QUICKFIX)
6172 || *buf->b_p_bt != NUL
6173#endif
6174 || buf->b_saving
6175#ifdef FEAT_AUTOCMD
6176 || busy
6177#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006178#ifdef FEAT_NETBEANS_INTG
6179 || isNetbeansBuffer(buf)
6180#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181 )
6182 return 0;
6183
6184 if ( !(buf->b_flags & BF_NOTEDITED)
6185 && buf->b_mtime != 0
6186 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6187 || time_differs((long)st.st_mtime, buf->b_mtime)
6188#ifdef HAVE_ST_MODE
6189 || (int)st.st_mode != buf->b_orig_mode
6190#else
6191 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6192#endif
6193 ))
6194 {
6195 retval = 1;
6196
Bram Moolenaar316059c2006-01-14 21:18:42 +00006197 /* set b_mtime to stop further warnings (e.g., when executing
6198 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006199 if (stat_res < 0)
6200 {
6201 buf->b_mtime = 0;
6202 buf->b_orig_size = 0;
6203 buf->b_orig_mode = 0;
6204 }
6205 else
6206 buf_store_time(buf, &st, buf->b_ffname);
6207
6208 /* Don't do anything for a directory. Might contain the file
6209 * explorer. */
6210 if (mch_isdir(buf->b_fname))
6211 ;
6212
6213 /*
6214 * If 'autoread' is set, the buffer has no changes and the file still
6215 * exists, reload the buffer. Use the buffer-local option value if it
6216 * was set, the global option value otherwise.
6217 */
6218 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6219 && !bufIsChanged(buf) && stat_res >= 0)
6220 reload = TRUE;
6221 else
6222 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006223 if (stat_res < 0)
6224 reason = "deleted";
6225 else if (bufIsChanged(buf))
6226 reason = "conflict";
6227 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6228 reason = "changed";
6229 else if (orig_mode != buf->b_orig_mode)
6230 reason = "mode";
6231 else
6232 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006233
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006234#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235 /*
6236 * Only give the warning if there are no FileChangedShell
6237 * autocommands.
6238 * Avoid being called recursively by setting "busy".
6239 */
6240 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006241# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006242 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6243 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006244# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6246 buf->b_fname, buf->b_fname, FALSE, buf);
6247 busy = FALSE;
6248 if (n)
6249 {
6250 if (!buf_valid(buf))
6251 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006252# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006253 s = get_vim_var_str(VV_FCS_CHOICE);
6254 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6255 reload = TRUE;
6256 else if (STRCMP(s, "ask") == 0)
6257 n = FALSE;
6258 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006259# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006260 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006261 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006262 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006263#endif
6264 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006265 if (*reason == 'd')
6266 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006267 else
6268 {
6269 helpmesg = TRUE;
6270#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6271 can_reload = TRUE;
6272#endif
6273 /*
6274 * Check if the file contents really changed to avoid
6275 * giving a warning when only the timestamp was set (e.g.,
6276 * checked out of CVS). Always warn when the buffer was
6277 * changed.
6278 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006279 if (reason[2] == 'n')
6280 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006281 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006282 mesg2 = _("See \":help W12\" for more info.");
6283 }
6284 else if (reason[1] == 'h')
6285 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006286 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006287 mesg2 = _("See \":help W11\" for more info.");
6288 }
6289 else if (*reason == 'm')
6290 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006292 mesg2 = _("See \":help W16\" for more info.");
6293 }
6294 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006295 }
6296 }
6297 }
6298
6299 }
6300 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6301 && vim_fexists(buf->b_ffname))
6302 {
6303 retval = 1;
6304 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6305 buf->b_flags |= BF_NEW_W;
6306#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6307 can_reload = TRUE;
6308#endif
6309 }
6310
6311 if (mesg != NULL)
6312 {
6313 path = home_replace_save(buf, buf->b_fname);
6314 if (path != NULL)
6315 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006316 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006317 mesg2 = "";
6318 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6319 + STRLEN(mesg2) + 2));
6320 sprintf((char *)tbuf, mesg, path);
6321#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6322 if (can_reload)
6323 {
6324 if (*mesg2 != NUL)
6325 {
6326 STRCAT(tbuf, "\n");
6327 STRCAT(tbuf, mesg2);
6328 }
6329 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6330 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6331 reload = TRUE;
6332 }
6333 else
6334#endif
6335 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6336 {
6337 if (*mesg2 != NUL)
6338 {
6339 STRCAT(tbuf, "; ");
6340 STRCAT(tbuf, mesg2);
6341 }
6342 EMSG(tbuf);
6343 retval = 2;
6344 }
6345 else
6346 {
Bram Moolenaared203462004-06-16 11:19:22 +00006347# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006348 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006349# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006350 {
6351 msg_start();
6352 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6353 if (*mesg2 != NUL)
6354 msg_puts_attr((char_u *)mesg2,
6355 hl_attr(HLF_W) + MSG_HIST);
6356 msg_clr_eos();
6357 (void)msg_end();
6358 if (emsg_silent == 0)
6359 {
6360 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006361# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006362 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006363# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006364 /* give the user some time to think about it */
6365 ui_delay(1000L, TRUE);
6366
6367 /* don't redraw and erase the message */
6368 redraw_cmdline = FALSE;
6369 }
6370 }
6371 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006372 }
6373
6374 vim_free(path);
6375 vim_free(tbuf);
6376 }
6377 }
6378
6379 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006380 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006381 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006382
6383#ifdef FEAT_GUI
6384 /* restore this in case an autocommand has set it; it would break
6385 * 'mousefocus' */
6386 need_mouse_correct = save_mouse_correct;
6387#endif
6388
6389 return retval;
6390}
6391
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006392/*
6393 * Reload a buffer that is already loaded.
6394 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006395 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6396 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006397 */
6398 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006399buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006400 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006401 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006402{
6403 exarg_T ea;
6404 pos_T old_cursor;
6405 linenr_T old_topline;
6406 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006407 buf_T *savebuf;
6408 int saved = OK;
6409#ifdef FEAT_AUTOCMD
6410 aco_save_T aco;
6411
6412 /* set curwin/curbuf for "buf" and save some things */
6413 aucmd_prepbuf(&aco, buf);
6414#else
6415 buf_T *save_curbuf = curbuf;
6416
6417 curbuf = buf;
6418 curwin->w_buffer = buf;
6419#endif
6420
6421 /* We only want to read the text from the file, not reset the syntax
6422 * highlighting, clear marks, diff status, etc. Force the fileformat
6423 * and encoding to be the same. */
6424 if (prep_exarg(&ea, buf) == OK)
6425 {
6426 old_cursor = curwin->w_cursor;
6427 old_topline = curwin->w_topline;
6428
6429 /*
6430 * To behave like when a new file is edited (matters for
6431 * BufReadPost autocommands) we first need to delete the current
6432 * buffer contents. But if reading the file fails we should keep
6433 * the old contents. Can't use memory only, the file might be
6434 * too big. Use a hidden buffer to move the buffer contents to.
6435 */
6436 if (bufempty())
6437 savebuf = NULL;
6438 else
6439 {
6440 /* Allocate a buffer without putting it in the buffer list. */
6441 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
6442 if (savebuf != NULL)
6443 {
6444 /* Open the memline. */
6445 curbuf = savebuf;
6446 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006447 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006448 curbuf = buf;
6449 curwin->w_buffer = buf;
6450 }
6451 if (savebuf == NULL || saved == FAIL
6452 || move_lines(buf, savebuf) == FAIL)
6453 {
6454 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6455 buf->b_fname);
6456 saved = FAIL;
6457 }
6458 }
6459
6460 if (saved == OK)
6461 {
6462 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6463#ifdef FEAT_AUTOCMD
6464 keep_filetype = TRUE; /* don't detect 'filetype' */
6465#endif
6466 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6467 (linenr_T)0,
6468 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6469 {
6470#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6471 if (!aborting())
6472#endif
6473 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
6474 if (savebuf != NULL)
6475 {
6476 /* Put the text back from the save buffer. First
6477 * delete any lines that readfile() added. */
6478 while (!bufempty())
6479 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE)
6480 == FAIL)
6481 break;
6482 (void)move_lines(savebuf, buf);
6483 }
6484 }
6485 else
6486 {
6487 /* Mark the buffer as unmodified and free undo info. */
6488 unchanged(buf, TRUE);
6489 u_blockfree(buf);
6490 u_clearall(buf);
6491 }
6492 }
6493 vim_free(ea.cmd);
6494
6495 if (savebuf != NULL)
6496 wipe_buffer(savebuf, FALSE);
6497
6498#ifdef FEAT_DIFF
6499 /* Invalidate diff info if necessary. */
6500 diff_invalidate();
6501#endif
6502
6503 /* Restore the topline and cursor position and check it (lines may
6504 * have been removed). */
6505 if (old_topline > curbuf->b_ml.ml_line_count)
6506 curwin->w_topline = curbuf->b_ml.ml_line_count;
6507 else
6508 curwin->w_topline = old_topline;
6509 curwin->w_cursor = old_cursor;
6510 check_cursor();
6511 update_topline();
6512#ifdef FEAT_AUTOCMD
6513 keep_filetype = FALSE;
6514#endif
6515#ifdef FEAT_FOLDING
6516 {
6517 win_T *wp;
6518
6519 /* Update folds unless they are defined manually. */
6520 FOR_ALL_WINDOWS(wp)
6521 if (wp->w_buffer == curwin->w_buffer
6522 && !foldmethodIsManual(wp))
6523 foldUpdateAll(wp);
6524 }
6525#endif
6526 /* If the mode didn't change and 'readonly' was set, keep the old
6527 * value; the user probably used the ":view" command. But don't
6528 * reset it, might have had a read error. */
6529 if (orig_mode == curbuf->b_orig_mode)
6530 curbuf->b_p_ro |= old_ro;
6531 }
6532
6533#ifdef FEAT_AUTOCMD
6534 /* restore curwin/curbuf and a few other things */
6535 aucmd_restbuf(&aco);
6536 /* Careful: autocommands may have made "buf" invalid! */
6537#else
6538 curwin->w_buffer = save_curbuf;
6539 curbuf = save_curbuf;
6540#endif
6541}
6542
Bram Moolenaar071d4272004-06-13 20:20:40 +00006543/*ARGSUSED*/
6544 void
6545buf_store_time(buf, st, fname)
6546 buf_T *buf;
6547 struct stat *st;
6548 char_u *fname;
6549{
6550 buf->b_mtime = (long)st->st_mtime;
6551 buf->b_orig_size = (size_t)st->st_size;
6552#ifdef HAVE_ST_MODE
6553 buf->b_orig_mode = (int)st->st_mode;
6554#else
6555 buf->b_orig_mode = mch_getperm(fname);
6556#endif
6557}
6558
6559/*
6560 * Adjust the line with missing eol, used for the next write.
6561 * Used for do_filter(), when the input lines for the filter are deleted.
6562 */
6563 void
6564write_lnum_adjust(offset)
6565 linenr_T offset;
6566{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006567 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006568 write_no_eol_lnum += offset;
6569}
6570
6571#if defined(TEMPDIRNAMES) || defined(PROTO)
6572static long temp_count = 0; /* Temp filename counter. */
6573
6574/*
6575 * Delete the temp directory and all files it contains.
6576 */
6577 void
6578vim_deltempdir()
6579{
6580 char_u **files;
6581 int file_count;
6582 int i;
6583
6584 if (vim_tempdir != NULL)
6585 {
6586 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6587 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6588 EW_DIR|EW_FILE|EW_SILENT) == OK)
6589 {
6590 for (i = 0; i < file_count; ++i)
6591 mch_remove(files[i]);
6592 FreeWild(file_count, files);
6593 }
6594 gettail(NameBuff)[-1] = NUL;
6595 (void)mch_rmdir(NameBuff);
6596
6597 vim_free(vim_tempdir);
6598 vim_tempdir = NULL;
6599 }
6600}
6601#endif
6602
6603/*
6604 * vim_tempname(): Return a unique name that can be used for a temp file.
6605 *
6606 * The temp file is NOT created.
6607 *
6608 * The returned pointer is to allocated memory.
6609 * The returned pointer is NULL if no valid name was found.
6610 */
6611/*ARGSUSED*/
6612 char_u *
6613vim_tempname(extra_char)
6614 int extra_char; /* character to use in the name instead of '?' */
6615{
6616#ifdef USE_TMPNAM
6617 char_u itmp[L_tmpnam]; /* use tmpnam() */
6618#else
6619 char_u itmp[TEMPNAMELEN];
6620#endif
6621
6622#ifdef TEMPDIRNAMES
6623 static char *(tempdirs[]) = {TEMPDIRNAMES};
6624 int i;
6625 long nr;
6626 long off;
6627# ifndef EEXIST
6628 struct stat st;
6629# endif
6630
6631 /*
6632 * This will create a directory for private use by this instance of Vim.
6633 * This is done once, and the same directory is used for all temp files.
6634 * This method avoids security problems because of symlink attacks et al.
6635 * It's also a bit faster, because we only need to check for an existing
6636 * file when creating the directory and not for each temp file.
6637 */
6638 if (vim_tempdir == NULL)
6639 {
6640 /*
6641 * Try the entries in TEMPDIRNAMES to create the temp directory.
6642 */
6643 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6644 {
6645 /* expand $TMP, leave room for "/v1100000/999999999" */
6646 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6647 if (mch_isdir(itmp)) /* directory exists */
6648 {
6649# ifdef __EMX__
6650 /* If $TMP contains a forward slash (perhaps using bash or
6651 * tcsh), don't add a backslash, use a forward slash!
6652 * Adding 2 backslashes didn't work. */
6653 if (vim_strchr(itmp, '/') != NULL)
6654 STRCAT(itmp, "/");
6655 else
6656# endif
6657 add_pathsep(itmp);
6658
6659 /* Get an arbitrary number of up to 6 digits. When it's
6660 * unlikely that it already exists it will be faster,
6661 * otherwise it doesn't matter. The use of mkdir() avoids any
6662 * security problems because of the predictable number. */
6663 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6664
6665 /* Try up to 10000 different values until we find a name that
6666 * doesn't exist. */
6667 for (off = 0; off < 10000L; ++off)
6668 {
6669 int r;
6670#if defined(UNIX) || defined(VMS)
6671 mode_t umask_save;
6672#endif
6673
6674 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6675# ifndef EEXIST
6676 /* If mkdir() does not set errno to EEXIST, check for
6677 * existing file here. There is a race condition then,
6678 * although it's fail-safe. */
6679 if (mch_stat((char *)itmp, &st) >= 0)
6680 continue;
6681# endif
6682#if defined(UNIX) || defined(VMS)
6683 /* Make sure the umask doesn't remove the executable bit.
6684 * "repl" has been reported to use "177". */
6685 umask_save = umask(077);
6686#endif
6687 r = vim_mkdir(itmp, 0700);
6688#if defined(UNIX) || defined(VMS)
6689 (void)umask(umask_save);
6690#endif
6691 if (r == 0)
6692 {
6693 char_u *buf;
6694
6695 /* Directory was created, use this name.
6696 * Expand to full path; When using the current
6697 * directory a ":cd" would confuse us. */
6698 buf = alloc((unsigned)MAXPATHL + 1);
6699 if (buf != NULL)
6700 {
6701 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6702 == FAIL)
6703 STRCPY(buf, itmp);
6704# ifdef __EMX__
6705 if (vim_strchr(buf, '/') != NULL)
6706 STRCAT(buf, "/");
6707 else
6708# endif
6709 add_pathsep(buf);
6710 vim_tempdir = vim_strsave(buf);
6711 vim_free(buf);
6712 }
6713 break;
6714 }
6715# ifdef EEXIST
6716 /* If the mkdir() didn't fail because the file/dir exists,
6717 * we probably can't create any dir here, try another
6718 * place. */
6719 if (errno != EEXIST)
6720# endif
6721 break;
6722 }
6723 if (vim_tempdir != NULL)
6724 break;
6725 }
6726 }
6727 }
6728
6729 if (vim_tempdir != NULL)
6730 {
6731 /* There is no need to check if the file exists, because we own the
6732 * directory and nobody else creates a file in it. */
6733 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6734 return vim_strsave(itmp);
6735 }
6736
6737 return NULL;
6738
6739#else /* TEMPDIRNAMES */
6740
6741# ifdef WIN3264
6742 char szTempFile[_MAX_PATH + 1];
6743 char buf4[4];
6744 char_u *retval;
6745 char_u *p;
6746
6747 STRCPY(itmp, "");
6748 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6749 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6750 strcpy(buf4, "VIM");
6751 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6752 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6753 return NULL;
6754 /* GetTempFileName() will create the file, we don't want that */
6755 (void)DeleteFile(itmp);
6756
6757 /* Backslashes in a temp file name cause problems when filtering with
6758 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6759 * didn't set 'shellslash'. */
6760 retval = vim_strsave(itmp);
6761 if (*p_shcf == '-' || p_ssl)
6762 for (p = retval; *p; ++p)
6763 if (*p == '\\')
6764 *p = '/';
6765 return retval;
6766
6767# else /* WIN3264 */
6768
6769# ifdef USE_TMPNAM
6770 /* tmpnam() will make its own name */
6771 if (*tmpnam((char *)itmp) == NUL)
6772 return NULL;
6773# else
6774 char_u *p;
6775
6776# ifdef VMS_TEMPNAM
6777 /* mktemp() is not working on VMS. It seems to be
6778 * a do-nothing function. Therefore we use tempnam().
6779 */
6780 sprintf((char *)itmp, "VIM%c", extra_char);
6781 p = (char_u *)tempnam("tmp:", (char *)itmp);
6782 if (p != NULL)
6783 {
6784 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6785 * and VIM will then be unable to find the file later */
6786 STRCPY(itmp, p);
6787 STRCAT(itmp, ".txt");
6788 free(p);
6789 }
6790 else
6791 return NULL;
6792# else
6793 STRCPY(itmp, TEMPNAME);
6794 if ((p = vim_strchr(itmp, '?')) != NULL)
6795 *p = extra_char;
6796 if (mktemp((char *)itmp) == NULL)
6797 return NULL;
6798# endif
6799# endif
6800
6801 return vim_strsave(itmp);
6802# endif /* WIN3264 */
6803#endif /* TEMPDIRNAMES */
6804}
6805
6806#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6807/*
6808 * Convert all backslashes in fname to forward slashes in-place.
6809 */
6810 void
6811forward_slash(fname)
6812 char_u *fname;
6813{
6814 char_u *p;
6815
6816 for (p = fname; *p != NUL; ++p)
6817# ifdef FEAT_MBYTE
6818 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006819 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006820 ++p;
6821 else
6822# endif
6823 if (*p == '\\')
6824 *p = '/';
6825}
6826#endif
6827
6828
6829/*
6830 * Code for automatic commands.
6831 *
6832 * Only included when "FEAT_AUTOCMD" has been defined.
6833 */
6834
6835#if defined(FEAT_AUTOCMD) || defined(PROTO)
6836
6837/*
6838 * The autocommands are stored in a list for each event.
6839 * Autocommands for the same pattern, that are consecutive, are joined
6840 * together, to avoid having to match the pattern too often.
6841 * The result is an array of Autopat lists, which point to AutoCmd lists:
6842 *
6843 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
6844 * Autopat.cmds Autopat.cmds
6845 * | |
6846 * V V
6847 * AutoCmd.next AutoCmd.next
6848 * | |
6849 * V V
6850 * AutoCmd.next NULL
6851 * |
6852 * V
6853 * NULL
6854 *
6855 * first_autopat[1] --> Autopat.next --> NULL
6856 * Autopat.cmds
6857 * |
6858 * V
6859 * AutoCmd.next
6860 * |
6861 * V
6862 * NULL
6863 * etc.
6864 *
6865 * The order of AutoCmds is important, this is the order in which they were
6866 * defined and will have to be executed.
6867 */
6868typedef struct AutoCmd
6869{
6870 char_u *cmd; /* The command to be executed (NULL
6871 when command has been removed) */
6872 char nested; /* If autocommands nest here */
6873 char last; /* last command in list */
6874#ifdef FEAT_EVAL
6875 scid_T scriptID; /* script ID where defined */
6876#endif
6877 struct AutoCmd *next; /* Next AutoCmd in list */
6878} AutoCmd;
6879
6880typedef struct AutoPat
6881{
6882 int group; /* group ID */
6883 char_u *pat; /* pattern as typed (NULL when pattern
6884 has been removed) */
6885 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00006886 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006887 char allow_dirs; /* Pattern may match whole path */
6888 char last; /* last pattern for apply_autocmds() */
6889 AutoCmd *cmds; /* list of commands to do */
6890 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006891 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006892} AutoPat;
6893
6894static struct event_name
6895{
6896 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006897 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006898} event_names[] =
6899{
6900 {"BufAdd", EVENT_BUFADD},
6901 {"BufCreate", EVENT_BUFADD},
6902 {"BufDelete", EVENT_BUFDELETE},
6903 {"BufEnter", EVENT_BUFENTER},
6904 {"BufFilePost", EVENT_BUFFILEPOST},
6905 {"BufFilePre", EVENT_BUFFILEPRE},
6906 {"BufHidden", EVENT_BUFHIDDEN},
6907 {"BufLeave", EVENT_BUFLEAVE},
6908 {"BufNew", EVENT_BUFNEW},
6909 {"BufNewFile", EVENT_BUFNEWFILE},
6910 {"BufRead", EVENT_BUFREADPOST},
6911 {"BufReadCmd", EVENT_BUFREADCMD},
6912 {"BufReadPost", EVENT_BUFREADPOST},
6913 {"BufReadPre", EVENT_BUFREADPRE},
6914 {"BufUnload", EVENT_BUFUNLOAD},
6915 {"BufWinEnter", EVENT_BUFWINENTER},
6916 {"BufWinLeave", EVENT_BUFWINLEAVE},
6917 {"BufWipeout", EVENT_BUFWIPEOUT},
6918 {"BufWrite", EVENT_BUFWRITEPRE},
6919 {"BufWritePost", EVENT_BUFWRITEPOST},
6920 {"BufWritePre", EVENT_BUFWRITEPRE},
6921 {"BufWriteCmd", EVENT_BUFWRITECMD},
6922 {"CmdwinEnter", EVENT_CMDWINENTER},
6923 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006924 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006925 {"CursorHold", EVENT_CURSORHOLD},
6926 {"CursorHoldI", EVENT_CURSORHOLDI},
6927 {"CursorMoved", EVENT_CURSORMOVED},
6928 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006929 {"EncodingChanged", EVENT_ENCODINGCHANGED},
6930 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006931 {"FileAppendPost", EVENT_FILEAPPENDPOST},
6932 {"FileAppendPre", EVENT_FILEAPPENDPRE},
6933 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
6934 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
6935 {"FileChangedRO", EVENT_FILECHANGEDRO},
6936 {"FileReadPost", EVENT_FILEREADPOST},
6937 {"FileReadPre", EVENT_FILEREADPRE},
6938 {"FileReadCmd", EVENT_FILEREADCMD},
6939 {"FileType", EVENT_FILETYPE},
6940 {"FileWritePost", EVENT_FILEWRITEPOST},
6941 {"FileWritePre", EVENT_FILEWRITEPRE},
6942 {"FileWriteCmd", EVENT_FILEWRITECMD},
6943 {"FilterReadPost", EVENT_FILTERREADPOST},
6944 {"FilterReadPre", EVENT_FILTERREADPRE},
6945 {"FilterWritePost", EVENT_FILTERWRITEPOST},
6946 {"FilterWritePre", EVENT_FILTERWRITEPRE},
6947 {"FocusGained", EVENT_FOCUSGAINED},
6948 {"FocusLost", EVENT_FOCUSLOST},
6949 {"FuncUndefined", EVENT_FUNCUNDEFINED},
6950 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar843ee412004-06-30 16:16:41 +00006951 {"InsertChange", EVENT_INSERTCHANGE},
6952 {"InsertEnter", EVENT_INSERTENTER},
6953 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00006954 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00006955 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
6956 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006957 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00006958 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00006959 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006960 {"StdinReadPost", EVENT_STDINREADPOST},
6961 {"StdinReadPre", EVENT_STDINREADPRE},
6962 {"Syntax", EVENT_SYNTAX},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00006963 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006964 {"TermChanged", EVENT_TERMCHANGED},
6965 {"TermResponse", EVENT_TERMRESPONSE},
6966 {"User", EVENT_USER},
6967 {"VimEnter", EVENT_VIMENTER},
6968 {"VimLeave", EVENT_VIMLEAVE},
6969 {"VimLeavePre", EVENT_VIMLEAVEPRE},
6970 {"WinEnter", EVENT_WINENTER},
6971 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006972 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006973};
6974
6975static AutoPat *first_autopat[NUM_EVENTS] =
6976{
6977 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6978 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6979 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6980 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00006981 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6982 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006983};
6984
6985/*
6986 * struct used to keep status while executing autocommands for an event.
6987 */
6988typedef struct AutoPatCmd
6989{
6990 AutoPat *curpat; /* next AutoPat to examine */
6991 AutoCmd *nextcmd; /* next AutoCmd to execute */
6992 int group; /* group being used */
6993 char_u *fname; /* fname to match with */
6994 char_u *sfname; /* sfname to match with */
6995 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006996 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006997 int arg_bufnr; /* initially equal to <abuf>, set to zero when
6998 buf is deleted */
6999 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000} AutoPatCmd;
7001
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007002static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007003
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004/*
7005 * augroups stores a list of autocmd group names.
7006 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007007static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7009
7010/*
7011 * The ID of the current group. Group 0 is the default one.
7012 */
7013#define AUGROUP_DEFAULT -1 /* default autocmd group */
7014#define AUGROUP_ERROR -2 /* errornouse autocmd group */
7015#define AUGROUP_ALL -3 /* all autocmd groups */
7016static int current_augroup = AUGROUP_DEFAULT;
7017
7018static int au_need_clean = FALSE; /* need to delete marked patterns */
7019
Bram Moolenaar754b5602006-02-09 23:53:20 +00007020static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007021static void au_remove_pat __ARGS((AutoPat *ap));
7022static void au_remove_cmds __ARGS((AutoPat *ap));
7023static void au_cleanup __ARGS((void));
7024static int au_new_group __ARGS((char_u *name));
7025static void au_del_group __ARGS((char_u *name));
7026static int au_find_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007027static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7028static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007029static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007030static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007031static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007032static 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 +00007033static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007034static 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 +00007035static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7036
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007037
Bram Moolenaar754b5602006-02-09 23:53:20 +00007038static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007039static int last_group;
7040
7041/*
7042 * Show the autocommands for one AutoPat.
7043 */
7044 static void
7045show_autocmd(ap, event)
7046 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007047 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007048{
7049 AutoCmd *ac;
7050
7051 /* Check for "got_int" (here and at various places below), which is set
7052 * when "q" has been hit for the "--more--" prompt */
7053 if (got_int)
7054 return;
7055 if (ap->pat == NULL) /* pattern has been removed */
7056 return;
7057
7058 msg_putchar('\n');
7059 if (got_int)
7060 return;
7061 if (event != last_event || ap->group != last_group)
7062 {
7063 if (ap->group != AUGROUP_DEFAULT)
7064 {
7065 if (AUGROUP_NAME(ap->group) == NULL)
7066 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7067 else
7068 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7069 msg_puts((char_u *)" ");
7070 }
7071 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7072 last_event = event;
7073 last_group = ap->group;
7074 msg_putchar('\n');
7075 if (got_int)
7076 return;
7077 }
7078 msg_col = 4;
7079 msg_outtrans(ap->pat);
7080
7081 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7082 {
7083 if (ac->cmd != NULL) /* skip removed commands */
7084 {
7085 if (msg_col >= 14)
7086 msg_putchar('\n');
7087 msg_col = 14;
7088 if (got_int)
7089 return;
7090 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007091#ifdef FEAT_EVAL
7092 if (p_verbose > 0)
7093 last_set_msg(ac->scriptID);
7094#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095 if (got_int)
7096 return;
7097 if (ac->next != NULL)
7098 {
7099 msg_putchar('\n');
7100 if (got_int)
7101 return;
7102 }
7103 }
7104 }
7105}
7106
7107/*
7108 * Mark an autocommand pattern for deletion.
7109 */
7110 static void
7111au_remove_pat(ap)
7112 AutoPat *ap;
7113{
7114 vim_free(ap->pat);
7115 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007116 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117 au_need_clean = TRUE;
7118}
7119
7120/*
7121 * Mark all commands for a pattern for deletion.
7122 */
7123 static void
7124au_remove_cmds(ap)
7125 AutoPat *ap;
7126{
7127 AutoCmd *ac;
7128
7129 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7130 {
7131 vim_free(ac->cmd);
7132 ac->cmd = NULL;
7133 }
7134 au_need_clean = TRUE;
7135}
7136
7137/*
7138 * Cleanup autocommands and patterns that have been deleted.
7139 * This is only done when not executing autocommands.
7140 */
7141 static void
7142au_cleanup()
7143{
7144 AutoPat *ap, **prev_ap;
7145 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007146 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007147
7148 if (autocmd_busy || !au_need_clean)
7149 return;
7150
7151 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007152 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7153 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154 {
7155 /* loop over all autocommand patterns */
7156 prev_ap = &(first_autopat[(int)event]);
7157 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7158 {
7159 /* loop over all commands for this pattern */
7160 prev_ac = &(ap->cmds);
7161 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7162 {
7163 /* remove the command if the pattern is to be deleted or when
7164 * the command has been marked for deletion */
7165 if (ap->pat == NULL || ac->cmd == NULL)
7166 {
7167 *prev_ac = ac->next;
7168 vim_free(ac->cmd);
7169 vim_free(ac);
7170 }
7171 else
7172 prev_ac = &(ac->next);
7173 }
7174
7175 /* remove the pattern if it has been marked for deletion */
7176 if (ap->pat == NULL)
7177 {
7178 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007179 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007180 vim_free(ap);
7181 }
7182 else
7183 prev_ap = &(ap->next);
7184 }
7185 }
7186
7187 au_need_clean = FALSE;
7188}
7189
7190/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007191 * Called when buffer is freed, to remove/invalidate related buffer-local
7192 * autocmds.
7193 */
7194 void
7195aubuflocal_remove(buf)
7196 buf_T *buf;
7197{
7198 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007199 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007200 AutoPatCmd *apc;
7201
7202 /* invalidate currently executing autocommands */
7203 for (apc = active_apc_list; apc; apc = apc->next)
7204 if (buf->b_fnum == apc->arg_bufnr)
7205 apc->arg_bufnr = 0;
7206
7207 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007208 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7209 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007210 /* loop over all autocommand patterns */
7211 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7212 if (ap->buflocal_nr == buf->b_fnum)
7213 {
7214 au_remove_pat(ap);
7215 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007216 {
7217 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007218 smsg((char_u *)
7219 _("auto-removing autocommand: %s <buffer=%d>"),
7220 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007221 verbose_leave();
7222 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007223 }
7224 au_cleanup();
7225}
7226
7227/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007228 * Add an autocmd group name.
7229 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7230 */
7231 static int
7232au_new_group(name)
7233 char_u *name;
7234{
7235 int i;
7236
7237 i = au_find_group(name);
7238 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7239 {
7240 /* First try using a free entry. */
7241 for (i = 0; i < augroups.ga_len; ++i)
7242 if (AUGROUP_NAME(i) == NULL)
7243 break;
7244 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7245 return AUGROUP_ERROR;
7246
7247 AUGROUP_NAME(i) = vim_strsave(name);
7248 if (AUGROUP_NAME(i) == NULL)
7249 return AUGROUP_ERROR;
7250 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007251 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007252 }
7253
7254 return i;
7255}
7256
7257 static void
7258au_del_group(name)
7259 char_u *name;
7260{
7261 int i;
7262
7263 i = au_find_group(name);
7264 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7265 EMSG2(_("E367: No such group: \"%s\""), name);
7266 else
7267 {
7268 vim_free(AUGROUP_NAME(i));
7269 AUGROUP_NAME(i) = NULL;
7270 }
7271}
7272
7273/*
7274 * Find the ID of an autocmd group name.
7275 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7276 */
7277 static int
7278au_find_group(name)
7279 char_u *name;
7280{
7281 int i;
7282
7283 for (i = 0; i < augroups.ga_len; ++i)
7284 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7285 return i;
7286 return AUGROUP_ERROR;
7287}
7288
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007289#if defined(FEAT_BROWSE) || defined(PROTO)
7290/*
7291 * Return TRUE if augroup "name" exists.
7292 */
7293 int
7294au_has_group(name)
7295 char_u *name;
7296{
7297 return au_find_group(name) != AUGROUP_ERROR;
7298}
7299#endif
7300
Bram Moolenaar071d4272004-06-13 20:20:40 +00007301/*
7302 * ":augroup {name}".
7303 */
7304 void
7305do_augroup(arg, del_group)
7306 char_u *arg;
7307 int del_group;
7308{
7309 int i;
7310
7311 if (del_group)
7312 {
7313 if (*arg == NUL)
7314 EMSG(_(e_argreq));
7315 else
7316 au_del_group(arg);
7317 }
7318 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7319 current_augroup = AUGROUP_DEFAULT;
7320 else if (*arg) /* ":aug xxx": switch to group xxx */
7321 {
7322 i = au_new_group(arg);
7323 if (i != AUGROUP_ERROR)
7324 current_augroup = i;
7325 }
7326 else /* ":aug": list the group names */
7327 {
7328 msg_start();
7329 for (i = 0; i < augroups.ga_len; ++i)
7330 {
7331 if (AUGROUP_NAME(i) != NULL)
7332 {
7333 msg_puts(AUGROUP_NAME(i));
7334 msg_puts((char_u *)" ");
7335 }
7336 }
7337 msg_clr_eos();
7338 msg_end();
7339 }
7340}
7341
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007342#if defined(EXITFREE) || defined(PROTO)
7343 void
7344free_all_autocmds()
7345{
7346 for (current_augroup = -1; current_augroup < augroups.ga_len;
7347 ++current_augroup)
7348 do_autocmd((char_u *)"", TRUE);
7349 ga_clear_strings(&augroups);
7350}
7351#endif
7352
Bram Moolenaar071d4272004-06-13 20:20:40 +00007353/*
7354 * Return the event number for event name "start".
7355 * Return NUM_EVENTS if the event name was not found.
7356 * Return a pointer to the next event name in "end".
7357 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007358 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007359event_name2nr(start, end)
7360 char_u *start;
7361 char_u **end;
7362{
7363 char_u *p;
7364 int i;
7365 int len;
7366
7367 /* the event name ends with end of line, a blank or a comma */
7368 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7369 ;
7370 for (i = 0; event_names[i].name != NULL; ++i)
7371 {
7372 len = (int)STRLEN(event_names[i].name);
7373 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7374 break;
7375 }
7376 if (*p == ',')
7377 ++p;
7378 *end = p;
7379 if (event_names[i].name == NULL)
7380 return NUM_EVENTS;
7381 return event_names[i].event;
7382}
7383
7384/*
7385 * Return the name for event "event".
7386 */
7387 static char_u *
7388event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007389 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007390{
7391 int i;
7392
7393 for (i = 0; event_names[i].name != NULL; ++i)
7394 if (event_names[i].event == event)
7395 return (char_u *)event_names[i].name;
7396 return (char_u *)"Unknown";
7397}
7398
7399/*
7400 * Scan over the events. "*" stands for all events.
7401 */
7402 static char_u *
7403find_end_event(arg, have_group)
7404 char_u *arg;
7405 int have_group; /* TRUE when group name was found */
7406{
7407 char_u *pat;
7408 char_u *p;
7409
7410 if (*arg == '*')
7411 {
7412 if (arg[1] && !vim_iswhite(arg[1]))
7413 {
7414 EMSG2(_("E215: Illegal character after *: %s"), arg);
7415 return NULL;
7416 }
7417 pat = arg + 1;
7418 }
7419 else
7420 {
7421 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7422 {
7423 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7424 {
7425 if (have_group)
7426 EMSG2(_("E216: No such event: %s"), pat);
7427 else
7428 EMSG2(_("E216: No such group or event: %s"), pat);
7429 return NULL;
7430 }
7431 }
7432 }
7433 return pat;
7434}
7435
7436/*
7437 * Return TRUE if "event" is included in 'eventignore'.
7438 */
7439 static int
7440event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007441 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007442{
7443 char_u *p = p_ei;
7444
7445 if (STRICMP(p_ei, "all") == 0)
7446 return TRUE;
7447
7448 while (*p)
7449 if (event_name2nr(p, &p) == event)
7450 return TRUE;
7451
7452 return FALSE;
7453}
7454
7455/*
7456 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7457 */
7458 int
7459check_ei()
7460{
7461 char_u *p = p_ei;
7462
7463 if (STRICMP(p_ei, "all") == 0)
7464 return OK;
7465
7466 while (*p)
7467 if (event_name2nr(p, &p) == NUM_EVENTS)
7468 return FAIL;
7469
7470 return OK;
7471}
7472
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007473# if defined(FEAT_SYN_HL) || defined(PROTO)
7474
7475/*
7476 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7477 * buffer loaded into the window. "what" must start with a comma.
7478 * Returns the old value of 'eventignore' in allocated memory.
7479 */
7480 char_u *
7481au_event_disable(what)
7482 char *what;
7483{
7484 char_u *new_ei;
7485 char_u *save_ei;
7486
7487 save_ei = vim_strsave(p_ei);
7488 if (save_ei != NULL)
7489 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007490 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007491 if (new_ei != NULL)
7492 {
7493 STRCAT(new_ei, what);
7494 set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
7495 vim_free(new_ei);
7496 }
7497 }
7498 return save_ei;
7499}
7500
7501 void
7502au_event_restore(old_ei)
7503 char_u *old_ei;
7504{
7505 if (old_ei != NULL)
7506 {
7507 set_string_option_direct((char_u *)"ei", -1, old_ei, OPT_FREE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007508 vim_free(old_ei);
7509 }
7510}
7511# endif /* FEAT_SYN_HL */
7512
Bram Moolenaar071d4272004-06-13 20:20:40 +00007513/*
7514 * do_autocmd() -- implements the :autocmd command. Can be used in the
7515 * following ways:
7516 *
7517 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7518 * will be automatically executed for <event>
7519 * when editing a file matching <pat>, in
7520 * the current group.
7521 * :autocmd <event> <pat> Show the auto-commands associated with
7522 * <event> and <pat>.
7523 * :autocmd <event> Show the auto-commands associated with
7524 * <event>.
7525 * :autocmd Show all auto-commands.
7526 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7527 * <event> and <pat>, and add the command
7528 * <cmd>, for the current group.
7529 * :autocmd! <event> <pat> Remove all auto-commands associated with
7530 * <event> and <pat> for the current group.
7531 * :autocmd! <event> Remove all auto-commands associated with
7532 * <event> for the current group.
7533 * :autocmd! Remove ALL auto-commands for the current
7534 * group.
7535 *
7536 * Multiple events and patterns may be given separated by commas. Here are
7537 * some examples:
7538 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7539 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7540 *
7541 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007542 *
7543 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007544 */
7545 void
7546do_autocmd(arg, forceit)
7547 char_u *arg;
7548 int forceit;
7549{
7550 char_u *pat;
7551 char_u *envpat = NULL;
7552 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007553 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007554 int need_free = FALSE;
7555 int nested = FALSE;
7556 int group;
7557
7558 /*
7559 * Check for a legal group name. If not, use AUGROUP_ALL.
7560 */
7561 group = au_get_grouparg(&arg);
7562 if (arg == NULL) /* out of memory */
7563 return;
7564
7565 /*
7566 * Scan over the events.
7567 * If we find an illegal name, return here, don't do anything.
7568 */
7569 pat = find_end_event(arg, group != AUGROUP_ALL);
7570 if (pat == NULL)
7571 return;
7572
7573 /*
7574 * Scan over the pattern. Put a NUL at the end.
7575 */
7576 pat = skipwhite(pat);
7577 cmd = pat;
7578 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7579 cmd++;
7580 if (*cmd)
7581 *cmd++ = NUL;
7582
7583 /* Expand environment variables in the pattern. Set 'shellslash', we want
7584 * forward slashes here. */
7585 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7586 {
7587#ifdef BACKSLASH_IN_FILENAME
7588 int p_ssl_save = p_ssl;
7589
7590 p_ssl = TRUE;
7591#endif
7592 envpat = expand_env_save(pat);
7593#ifdef BACKSLASH_IN_FILENAME
7594 p_ssl = p_ssl_save;
7595#endif
7596 if (envpat != NULL)
7597 pat = envpat;
7598 }
7599
7600 /*
7601 * Check for "nested" flag.
7602 */
7603 cmd = skipwhite(cmd);
7604 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7605 {
7606 nested = TRUE;
7607 cmd = skipwhite(cmd + 6);
7608 }
7609
7610 /*
7611 * Find the start of the commands.
7612 * Expand <sfile> in it.
7613 */
7614 if (*cmd != NUL)
7615 {
7616 cmd = expand_sfile(cmd);
7617 if (cmd == NULL) /* some error */
7618 return;
7619 need_free = TRUE;
7620 }
7621
7622 /*
7623 * Print header when showing autocommands.
7624 */
7625 if (!forceit && *cmd == NUL)
7626 {
7627 /* Highlight title */
7628 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7629 }
7630
7631 /*
7632 * Loop over the events.
7633 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007634 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007635 last_group = AUGROUP_ERROR; /* for listing the group name */
7636 if (*arg == '*' || *arg == NUL)
7637 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00007638 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7639 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640 if (do_autocmd_event(event, pat,
7641 nested, cmd, forceit, group) == FAIL)
7642 break;
7643 }
7644 else
7645 {
7646 while (*arg && !vim_iswhite(*arg))
7647 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7648 nested, cmd, forceit, group) == FAIL)
7649 break;
7650 }
7651
7652 if (need_free)
7653 vim_free(cmd);
7654 vim_free(envpat);
7655}
7656
7657/*
7658 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7659 * The "argp" argument is advanced to the following argument.
7660 *
7661 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7662 */
7663 static int
7664au_get_grouparg(argp)
7665 char_u **argp;
7666{
7667 char_u *group_name;
7668 char_u *p;
7669 char_u *arg = *argp;
7670 int group = AUGROUP_ALL;
7671
7672 p = skiptowhite(arg);
7673 if (p > arg)
7674 {
7675 group_name = vim_strnsave(arg, (int)(p - arg));
7676 if (group_name == NULL) /* out of memory */
7677 return AUGROUP_ERROR;
7678 group = au_find_group(group_name);
7679 if (group == AUGROUP_ERROR)
7680 group = AUGROUP_ALL; /* no match, use all groups */
7681 else
7682 *argp = skipwhite(p); /* match, skip over group name */
7683 vim_free(group_name);
7684 }
7685 return group;
7686}
7687
7688/*
7689 * do_autocmd() for one event.
7690 * If *pat == NUL do for all patterns.
7691 * If *cmd == NUL show entries.
7692 * If forceit == TRUE delete entries.
7693 * If group is not AUGROUP_ALL, only use this group.
7694 */
7695 static int
7696do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007697 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007698 char_u *pat;
7699 int nested;
7700 char_u *cmd;
7701 int forceit;
7702 int group;
7703{
7704 AutoPat *ap;
7705 AutoPat **prev_ap;
7706 AutoCmd *ac;
7707 AutoCmd **prev_ac;
7708 int brace_level;
7709 char_u *endpat;
7710 int findgroup;
7711 int allgroups;
7712 int patlen;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007713 int is_buflocal;
7714 int buflocal_nr;
7715 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007716
7717 if (group == AUGROUP_ALL)
7718 findgroup = current_augroup;
7719 else
7720 findgroup = group;
7721 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7722
7723 /*
7724 * Show or delete all patterns for an event.
7725 */
7726 if (*pat == NUL)
7727 {
7728 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7729 {
7730 if (forceit) /* delete the AutoPat, if it's in the current group */
7731 {
7732 if (ap->group == findgroup)
7733 au_remove_pat(ap);
7734 }
7735 else if (group == AUGROUP_ALL || ap->group == group)
7736 show_autocmd(ap, event);
7737 }
7738 }
7739
7740 /*
7741 * Loop through all the specified patterns.
7742 */
7743 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7744 {
7745 /*
7746 * Find end of the pattern.
7747 * Watch out for a comma in braces, like "*.\{obj,o\}".
7748 */
7749 brace_level = 0;
7750 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7751 || endpat[-1] == '\\'); ++endpat)
7752 {
7753 if (*endpat == '{')
7754 brace_level++;
7755 else if (*endpat == '}')
7756 brace_level--;
7757 }
7758 if (pat == endpat) /* ignore single comma */
7759 continue;
7760 patlen = (int)(endpat - pat);
7761
7762 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007763 * detect special <buflocal[=X]> buffer-local patterns
7764 */
7765 is_buflocal = FALSE;
7766 buflocal_nr = 0;
7767
7768 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7769 && pat[patlen - 1] == '>')
7770 {
7771 /* Error will be printed only for addition. printing and removing
7772 * will proceed silently. */
7773 is_buflocal = TRUE;
7774 if (patlen == 8)
7775 buflocal_nr = curbuf->b_fnum;
7776 else if (patlen > 9 && pat[7] == '=')
7777 {
7778 /* <buffer=abuf> */
7779 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7780 buflocal_nr = autocmd_bufnr;
7781 /* <buffer=123> */
7782 else if (skipdigits(pat + 8) == pat + patlen - 1)
7783 buflocal_nr = atoi((char *)pat + 8);
7784 }
7785 }
7786
7787 if (is_buflocal)
7788 {
7789 /* normalize pat into standard "<buffer>#N" form */
7790 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7791 pat = buflocal_pat; /* can modify pat and patlen */
7792 patlen = STRLEN(buflocal_pat); /* but not endpat */
7793 }
7794
7795 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007796 * Find AutoPat entries with this pattern.
7797 */
7798 prev_ap = &first_autopat[(int)event];
7799 while ((ap = *prev_ap) != NULL)
7800 {
7801 if (ap->pat != NULL)
7802 {
7803 /* Accept a pattern when:
7804 * - a group was specified and it's that group, or a group was
7805 * not specified and it's the current group, or a group was
7806 * not specified and we are listing
7807 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007808 * - the pattern matches.
7809 * For <buffer[=X]>, this condition works because we normalize
7810 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007811 */
7812 if ((allgroups || ap->group == findgroup)
7813 && ap->patlen == patlen
7814 && STRNCMP(pat, ap->pat, patlen) == 0)
7815 {
7816 /*
7817 * Remove existing autocommands.
7818 * If adding any new autocmd's for this AutoPat, don't
7819 * delete the pattern from the autopat list, append to
7820 * this list.
7821 */
7822 if (forceit)
7823 {
7824 if (*cmd != NUL && ap->next == NULL)
7825 {
7826 au_remove_cmds(ap);
7827 break;
7828 }
7829 au_remove_pat(ap);
7830 }
7831
7832 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007833 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007834 */
7835 else if (*cmd == NUL)
7836 show_autocmd(ap, event);
7837
7838 /*
7839 * Add autocmd to this autopat, if it's the last one.
7840 */
7841 else if (ap->next == NULL)
7842 break;
7843 }
7844 }
7845 prev_ap = &ap->next;
7846 }
7847
7848 /*
7849 * Add a new command.
7850 */
7851 if (*cmd != NUL)
7852 {
7853 /*
7854 * If the pattern we want to add a command to does appear at the
7855 * end of the list (or not is not in the list at all), add the
7856 * pattern at the end of the list.
7857 */
7858 if (ap == NULL)
7859 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007860 /* refuse to add buffer-local ap if buffer number is invalid */
7861 if (is_buflocal && (buflocal_nr == 0
7862 || buflist_findnr(buflocal_nr) == NULL))
7863 {
7864 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7865 buflocal_nr);
7866 return FAIL;
7867 }
7868
Bram Moolenaar071d4272004-06-13 20:20:40 +00007869 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7870 if (ap == NULL)
7871 return FAIL;
7872 ap->pat = vim_strnsave(pat, patlen);
7873 ap->patlen = patlen;
7874 if (ap->pat == NULL)
7875 {
7876 vim_free(ap);
7877 return FAIL;
7878 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007879
7880 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007881 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007882 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007883 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007884 }
7885 else
7886 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007887 char_u *reg_pat;
7888
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007889 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007890 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007891 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007892 if (reg_pat != NULL)
7893 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007894 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007895 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007896 {
7897 vim_free(ap->pat);
7898 vim_free(ap);
7899 return FAIL;
7900 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007901 }
7902 ap->cmds = NULL;
7903 *prev_ap = ap;
7904 ap->next = NULL;
7905 if (group == AUGROUP_ALL)
7906 ap->group = current_augroup;
7907 else
7908 ap->group = group;
7909 }
7910
7911 /*
7912 * Add the autocmd at the end of the AutoCmd list.
7913 */
7914 prev_ac = &(ap->cmds);
7915 while ((ac = *prev_ac) != NULL)
7916 prev_ac = &ac->next;
7917 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7918 if (ac == NULL)
7919 return FAIL;
7920 ac->cmd = vim_strsave(cmd);
7921#ifdef FEAT_EVAL
7922 ac->scriptID = current_SID;
7923#endif
7924 if (ac->cmd == NULL)
7925 {
7926 vim_free(ac);
7927 return FAIL;
7928 }
7929 ac->next = NULL;
7930 *prev_ac = ac;
7931 ac->nested = nested;
7932 }
7933 }
7934
7935 au_cleanup(); /* may really delete removed patterns/commands now */
7936 return OK;
7937}
7938
7939/*
7940 * Implementation of ":doautocmd [group] event [fname]".
7941 * Return OK for success, FAIL for failure;
7942 */
7943 int
7944do_doautocmd(arg, do_msg)
7945 char_u *arg;
7946 int do_msg; /* give message for no matching autocmds? */
7947{
7948 char_u *fname;
7949 int nothing_done = TRUE;
7950 int group;
7951
7952 /*
7953 * Check for a legal group name. If not, use AUGROUP_ALL.
7954 */
7955 group = au_get_grouparg(&arg);
7956 if (arg == NULL) /* out of memory */
7957 return FAIL;
7958
7959 if (*arg == '*')
7960 {
7961 EMSG(_("E217: Can't execute autocommands for ALL events"));
7962 return FAIL;
7963 }
7964
7965 /*
7966 * Scan over the events.
7967 * If we find an illegal name, return here, don't do anything.
7968 */
7969 fname = find_end_event(arg, group != AUGROUP_ALL);
7970 if (fname == NULL)
7971 return FAIL;
7972
7973 fname = skipwhite(fname);
7974
7975 /*
7976 * Loop over the events.
7977 */
7978 while (*arg && !vim_iswhite(*arg))
7979 if (apply_autocmds_group(event_name2nr(arg, &arg),
7980 fname, NULL, TRUE, group, curbuf, NULL))
7981 nothing_done = FALSE;
7982
7983 if (nothing_done && do_msg)
7984 MSG(_("No matching autocommands"));
7985
7986#ifdef FEAT_EVAL
7987 return aborting() ? FAIL : OK;
7988#else
7989 return OK;
7990#endif
7991}
7992
7993/*
7994 * ":doautoall": execute autocommands for each loaded buffer.
7995 */
7996 void
7997ex_doautoall(eap)
7998 exarg_T *eap;
7999{
8000 int retval;
8001 aco_save_T aco;
8002 buf_T *buf;
8003
8004 /*
8005 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8006 * equal to curbuf, but for some buffers there may not be a window.
8007 * So we change the buffer for the current window for a moment. This
8008 * gives problems when the autocommands make changes to the list of
8009 * buffers or windows...
8010 */
8011 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8012 {
8013 if (curbuf->b_ml.ml_mfp != NULL)
8014 {
8015 /* find a window for this buffer and save some values */
8016 aucmd_prepbuf(&aco, buf);
8017
8018 /* execute the autocommands for this buffer */
8019 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00008020 do_modelines(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008021
8022 /* restore the current window */
8023 aucmd_restbuf(&aco);
8024
8025 /* stop if there is some error or buffer was deleted */
8026 if (retval == FAIL || !buf_valid(buf))
8027 break;
8028 }
8029 }
8030
8031 check_cursor(); /* just in case lines got deleted */
8032}
8033
8034/*
8035 * Prepare for executing autocommands for (hidden) buffer "buf".
8036 * Search a window for the current buffer. Save the cursor position and
8037 * screen offset.
8038 * Set "curbuf" and "curwin" to match "buf".
8039 */
8040 void
8041aucmd_prepbuf(aco, buf)
8042 aco_save_T *aco; /* structure to save values in */
8043 buf_T *buf; /* new curbuf */
8044{
8045 win_T *win;
8046
8047 aco->new_curbuf = buf;
8048
8049 /* Find a window that is for the new buffer */
8050 if (buf == curbuf) /* be quick when buf is curbuf */
8051 win = curwin;
8052 else
8053#ifdef FEAT_WINDOWS
8054 for (win = firstwin; win != NULL; win = win->w_next)
8055 if (win->w_buffer == buf)
8056 break;
8057#else
8058 win = NULL;
8059#endif
8060
8061 /*
8062 * Prefer to use an existing window for the buffer, it has the least side
8063 * effects (esp. if "buf" is curbuf).
8064 * Otherwise, use curwin for "buf". It might make some items in the
8065 * window invalid. At least save the cursor and topline.
8066 */
8067 if (win != NULL)
8068 {
8069 /* there is a window for "buf", make it the curwin */
8070 aco->save_curwin = curwin;
8071 curwin = win;
8072 aco->save_buf = win->w_buffer;
8073 aco->new_curwin = win;
8074 }
8075 else
8076 {
8077 /* there is no window for "buf", use curwin */
8078 aco->save_curwin = NULL;
8079 aco->save_buf = curbuf;
8080 --curbuf->b_nwindows;
8081 curwin->w_buffer = buf;
8082 ++buf->b_nwindows;
8083
8084 /* save cursor and topline, set them to safe values */
8085 aco->save_cursor = curwin->w_cursor;
8086 curwin->w_cursor.lnum = 1;
8087 curwin->w_cursor.col = 0;
8088 aco->save_topline = curwin->w_topline;
8089 curwin->w_topline = 1;
8090#ifdef FEAT_DIFF
8091 aco->save_topfill = curwin->w_topfill;
8092 curwin->w_topfill = 0;
8093#endif
8094 }
8095
8096 curbuf = buf;
8097}
8098
8099/*
8100 * Cleanup after executing autocommands for a (hidden) buffer.
8101 * Restore the window as it was (if possible).
8102 */
8103 void
8104aucmd_restbuf(aco)
8105 aco_save_T *aco; /* structure holding saved values */
8106{
8107 if (aco->save_curwin != NULL)
8108 {
8109 /* restore curwin */
8110#ifdef FEAT_WINDOWS
8111 if (win_valid(aco->save_curwin))
8112#endif
8113 {
8114 /* restore the buffer which was previously edited by curwin, if
8115 * it's still the same window and it's valid */
8116 if (curwin == aco->new_curwin
8117 && buf_valid(aco->save_buf)
8118 && aco->save_buf->b_ml.ml_mfp != NULL)
8119 {
8120 --curbuf->b_nwindows;
8121 curbuf = aco->save_buf;
8122 curwin->w_buffer = curbuf;
8123 ++curbuf->b_nwindows;
8124 }
8125
8126 curwin = aco->save_curwin;
8127 curbuf = curwin->w_buffer;
8128 }
8129 }
8130 else
8131 {
8132 /* restore buffer for curwin if it still exists and is loaded */
8133 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8134 {
8135 --curbuf->b_nwindows;
8136 curbuf = aco->save_buf;
8137 curwin->w_buffer = curbuf;
8138 ++curbuf->b_nwindows;
8139 curwin->w_cursor = aco->save_cursor;
8140 check_cursor();
8141 /* check topline < line_count, in case lines got deleted */
8142 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8143 {
8144 curwin->w_topline = aco->save_topline;
8145#ifdef FEAT_DIFF
8146 curwin->w_topfill = aco->save_topfill;
8147#endif
8148 }
8149 else
8150 {
8151 curwin->w_topline = curbuf->b_ml.ml_line_count;
8152#ifdef FEAT_DIFF
8153 curwin->w_topfill = 0;
8154#endif
8155 }
8156 }
8157 }
8158}
8159
8160static int autocmd_nested = FALSE;
8161
8162/*
8163 * Execute autocommands for "event" and file name "fname".
8164 * Return TRUE if some commands were executed.
8165 */
8166 int
8167apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008168 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008169 char_u *fname; /* NULL or empty means use actual file name */
8170 char_u *fname_io; /* fname to use for <afile> on cmdline */
8171 int force; /* when TRUE, ignore autocmd_busy */
8172 buf_T *buf; /* buffer for <abuf> */
8173{
8174 return apply_autocmds_group(event, fname, fname_io, force,
8175 AUGROUP_ALL, buf, NULL);
8176}
8177
8178/*
8179 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8180 * setting v:filearg.
8181 */
8182 static int
8183apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008184 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008185 char_u *fname;
8186 char_u *fname_io;
8187 int force;
8188 buf_T *buf;
8189 exarg_T *eap;
8190{
8191 return apply_autocmds_group(event, fname, fname_io, force,
8192 AUGROUP_ALL, buf, eap);
8193}
8194
8195/*
8196 * Like apply_autocmds(), but handles the caller's retval. If the script
8197 * processing is being aborted or if retval is FAIL when inside a try
8198 * conditional, no autocommands are executed. If otherwise the autocommands
8199 * cause the script to be aborted, retval is set to FAIL.
8200 */
8201 int
8202apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008203 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008204 char_u *fname; /* NULL or empty means use actual file name */
8205 char_u *fname_io; /* fname to use for <afile> on cmdline */
8206 int force; /* when TRUE, ignore autocmd_busy */
8207 buf_T *buf; /* buffer for <abuf> */
8208 int *retval; /* pointer to caller's retval */
8209{
8210 int did_cmd;
8211
Bram Moolenaar1e015462005-09-25 22:16:38 +00008212#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008213 if (should_abort(*retval))
8214 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008215#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008216
8217 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8218 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008219 if (did_cmd
8220#ifdef FEAT_EVAL
8221 && aborting()
8222#endif
8223 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008224 *retval = FAIL;
8225 return did_cmd;
8226}
8227
Bram Moolenaard35f9712005-12-18 22:02:33 +00008228/*
8229 * Return TRUE when there is a CursorHold autocommand defined.
8230 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008231 int
8232has_cursorhold()
8233{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008234 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8235 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008236}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008237
8238/*
8239 * Return TRUE if the CursorHold event can be triggered.
8240 */
8241 int
8242trigger_cursorhold()
8243{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008244 int state;
8245
8246 if (!did_cursorhold && has_cursorhold() && !Recording)
8247 {
8248 state = get_real_state();
8249 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8250 return TRUE;
8251 }
8252 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008253}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008254
8255/*
8256 * Return TRUE when there is a CursorMoved autocommand defined.
8257 */
8258 int
8259has_cursormoved()
8260{
8261 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8262}
8263
8264/*
8265 * Return TRUE when there is a CursorMovedI autocommand defined.
8266 */
8267 int
8268has_cursormovedI()
8269{
8270 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8271}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008272
8273 static int
8274apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008275 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008276 char_u *fname; /* NULL or empty means use actual file name */
8277 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8278 use fname */
8279 int force; /* when TRUE, ignore autocmd_busy */
8280 int group; /* group ID, or AUGROUP_ALL */
8281 buf_T *buf; /* buffer for <abuf> */
8282 exarg_T *eap; /* command arguments */
8283{
8284 char_u *sfname = NULL; /* short file name */
8285 char_u *tail;
8286 int save_changed;
8287 buf_T *old_curbuf;
8288 int retval = FALSE;
8289 char_u *save_sourcing_name;
8290 linenr_T save_sourcing_lnum;
8291 char_u *save_autocmd_fname;
8292 int save_autocmd_bufnr;
8293 char_u *save_autocmd_match;
8294 int save_autocmd_busy;
8295 int save_autocmd_nested;
8296 static int nesting = 0;
8297 AutoPatCmd patcmd;
8298 AutoPat *ap;
8299#ifdef FEAT_EVAL
8300 scid_T save_current_SID;
8301 void *save_funccalp;
8302 char_u *save_cmdarg;
8303 long save_cmdbang;
8304#endif
8305 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008306#ifdef FEAT_PROFILE
8307 proftime_T wait_time;
8308#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008309
8310 /*
8311 * Quickly return if there are no autocommands for this event or
8312 * autocommands are blocked.
8313 */
8314 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008315 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008316
8317 /*
8318 * When autocommands are busy, new autocommands are only executed when
8319 * explicitly enabled with the "nested" flag.
8320 */
8321 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008322 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008323
8324#ifdef FEAT_EVAL
8325 /*
8326 * Quickly return when immdediately aborting on error, or when an interrupt
8327 * occurred or an exception was thrown but not caught.
8328 */
8329 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008330 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008331#endif
8332
8333 /*
8334 * FileChangedShell never nests, because it can create an endless loop.
8335 */
8336 if (filechangeshell_busy && event == EVENT_FILECHANGEDSHELL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008337 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008338
8339 /*
8340 * Ignore events in 'eventignore'.
8341 */
8342 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008343 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008344
8345 /*
8346 * Allow nesting of autocommands, but restrict the depth, because it's
8347 * possible to create an endless loop.
8348 */
8349 if (nesting == 10)
8350 {
8351 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008352 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008353 }
8354
8355 /*
8356 * Check if these autocommands are disabled. Used when doing ":all" or
8357 * ":ball".
8358 */
8359 if ( (autocmd_no_enter
8360 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8361 || (autocmd_no_leave
8362 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008363 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008364
8365 /*
8366 * Save the autocmd_* variables and info about the current buffer.
8367 */
8368 save_autocmd_fname = autocmd_fname;
8369 save_autocmd_bufnr = autocmd_bufnr;
8370 save_autocmd_match = autocmd_match;
8371 save_autocmd_busy = autocmd_busy;
8372 save_autocmd_nested = autocmd_nested;
8373 save_changed = curbuf->b_changed;
8374 old_curbuf = curbuf;
8375
8376 /*
8377 * Set the file name to be used for <afile>.
8378 */
8379 if (fname_io == NULL)
8380 {
8381 if (fname != NULL && *fname != NUL)
8382 autocmd_fname = fname;
8383 else if (buf != NULL)
8384 autocmd_fname = buf->b_fname;
8385 else
8386 autocmd_fname = NULL;
8387 }
8388 else
8389 autocmd_fname = fname_io;
8390
8391 /*
8392 * Set the buffer number to be used for <abuf>.
8393 */
8394 if (buf == NULL)
8395 autocmd_bufnr = 0;
8396 else
8397 autocmd_bufnr = buf->b_fnum;
8398
8399 /*
8400 * When the file name is NULL or empty, use the file name of buffer "buf".
8401 * Always use the full path of the file name to match with, in case
8402 * "allow_dirs" is set.
8403 */
8404 if (fname == NULL || *fname == NUL)
8405 {
8406 if (buf == NULL)
8407 fname = NULL;
8408 else
8409 {
8410#ifdef FEAT_SYN_HL
8411 if (event == EVENT_SYNTAX)
8412 fname = buf->b_p_syn;
8413 else
8414#endif
8415 if (event == EVENT_FILETYPE)
8416 fname = buf->b_p_ft;
8417 else
8418 {
8419 if (buf->b_sfname != NULL)
8420 sfname = vim_strsave(buf->b_sfname);
8421 fname = buf->b_ffname;
8422 }
8423 }
8424 if (fname == NULL)
8425 fname = (char_u *)"";
8426 fname = vim_strsave(fname); /* make a copy, so we can change it */
8427 }
8428 else
8429 {
8430 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008431 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8432 if (event == EVENT_FILETYPE
8433 || event == EVENT_SYNTAX
8434 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008435 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008436 || event == EVENT_QUICKFIXCMDPRE
8437 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008438 fname = vim_strsave(fname);
8439 else
8440 fname = FullName_save(fname, FALSE);
8441 }
8442 if (fname == NULL) /* out of memory */
8443 {
8444 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008445 retval = FALSE;
8446 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008447 }
8448
8449#ifdef BACKSLASH_IN_FILENAME
8450 /*
8451 * Replace all backslashes with forward slashes. This makes the
8452 * autocommand patterns portable between Unix and MS-DOS.
8453 */
8454 if (sfname != NULL)
8455 forward_slash(sfname);
8456 forward_slash(fname);
8457#endif
8458
8459#ifdef VMS
8460 /* remove version for correct match */
8461 if (sfname != NULL)
8462 vms_remove_version(sfname);
8463 vms_remove_version(fname);
8464#endif
8465
8466 /*
8467 * Set the name to be used for <amatch>.
8468 */
8469 autocmd_match = fname;
8470
8471
8472 /* Don't redraw while doing auto commands. */
8473 ++RedrawingDisabled;
8474 save_sourcing_name = sourcing_name;
8475 sourcing_name = NULL; /* don't free this one */
8476 save_sourcing_lnum = sourcing_lnum;
8477 sourcing_lnum = 0; /* no line number here */
8478
8479#ifdef FEAT_EVAL
8480 save_current_SID = current_SID;
8481
Bram Moolenaar05159a02005-02-26 23:04:13 +00008482# ifdef FEAT_PROFILE
8483 if (do_profiling)
8484 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8485# endif
8486
Bram Moolenaar071d4272004-06-13 20:20:40 +00008487 /* Don't use local function variables, if called from a function */
8488 save_funccalp = save_funccal();
8489#endif
8490
8491 /*
8492 * When starting to execute autocommands, save the search patterns.
8493 */
8494 if (!autocmd_busy)
8495 {
8496 save_search_patterns();
8497 saveRedobuff();
8498 did_filetype = keep_filetype;
8499 }
8500
8501 /*
8502 * Note that we are applying autocmds. Some commands need to know.
8503 */
8504 autocmd_busy = TRUE;
8505 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8506 ++nesting; /* see matching decrement below */
8507
8508 /* Remember that FileType was triggered. Used for did_filetype(). */
8509 if (event == EVENT_FILETYPE)
8510 did_filetype = TRUE;
8511
8512 tail = gettail(fname);
8513
8514 /* Find first autocommand that matches */
8515 patcmd.curpat = first_autopat[(int)event];
8516 patcmd.nextcmd = NULL;
8517 patcmd.group = group;
8518 patcmd.fname = fname;
8519 patcmd.sfname = sfname;
8520 patcmd.tail = tail;
8521 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008522 patcmd.arg_bufnr = autocmd_bufnr;
8523 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008524 auto_next_pat(&patcmd, FALSE);
8525
8526 /* found one, start executing the autocommands */
8527 if (patcmd.curpat != NULL)
8528 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008529 /* add to active_apc_list */
8530 patcmd.next = active_apc_list;
8531 active_apc_list = &patcmd;
8532
Bram Moolenaar071d4272004-06-13 20:20:40 +00008533#ifdef FEAT_EVAL
8534 /* set v:cmdarg (only when there is a matching pattern) */
8535 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8536 if (eap != NULL)
8537 {
8538 save_cmdarg = set_cmdarg(eap, NULL);
8539 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8540 }
8541 else
8542 save_cmdarg = NULL; /* avoid gcc warning */
8543#endif
8544 retval = TRUE;
8545 /* mark the last pattern, to avoid an endless loop when more patterns
8546 * are added when executing autocommands */
8547 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8548 ap->last = FALSE;
8549 ap->last = TRUE;
8550 check_lnums(TRUE); /* make sure cursor and topline are valid */
8551 do_cmdline(NULL, getnextac, (void *)&patcmd,
8552 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8553#ifdef FEAT_EVAL
8554 if (eap != NULL)
8555 {
8556 (void)set_cmdarg(NULL, save_cmdarg);
8557 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8558 }
8559#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008560 /* delete from active_apc_list */
8561 if (active_apc_list == &patcmd) /* just in case */
8562 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008563 }
8564
8565 --RedrawingDisabled;
8566 autocmd_busy = save_autocmd_busy;
8567 filechangeshell_busy = FALSE;
8568 autocmd_nested = save_autocmd_nested;
8569 vim_free(sourcing_name);
8570 sourcing_name = save_sourcing_name;
8571 sourcing_lnum = save_sourcing_lnum;
8572 autocmd_fname = save_autocmd_fname;
8573 autocmd_bufnr = save_autocmd_bufnr;
8574 autocmd_match = save_autocmd_match;
8575#ifdef FEAT_EVAL
8576 current_SID = save_current_SID;
8577 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008578# ifdef FEAT_PROFILE
8579 if (do_profiling)
8580 prof_child_exit(&wait_time);
8581# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008582#endif
8583 vim_free(fname);
8584 vim_free(sfname);
8585 --nesting; /* see matching increment above */
8586
8587 /*
8588 * When stopping to execute autocommands, restore the search patterns and
8589 * the redo buffer.
8590 */
8591 if (!autocmd_busy)
8592 {
8593 restore_search_patterns();
8594 restoreRedobuff();
8595 did_filetype = FALSE;
8596 }
8597
8598 /*
8599 * Some events don't set or reset the Changed flag.
8600 * Check if still in the same buffer!
8601 */
8602 if (curbuf == old_curbuf
8603 && (event == EVENT_BUFREADPOST
8604 || event == EVENT_BUFWRITEPOST
8605 || event == EVENT_FILEAPPENDPOST
8606 || event == EVENT_VIMLEAVE
8607 || event == EVENT_VIMLEAVEPRE))
8608 {
8609#ifdef FEAT_TITLE
8610 if (curbuf->b_changed != save_changed)
8611 need_maketitle = TRUE;
8612#endif
8613 curbuf->b_changed = save_changed;
8614 }
8615
8616 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008617
8618BYPASS_AU:
8619 /* When wiping out a buffer make sure all its buffer-local autocommands
8620 * are deleted. */
8621 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8622 aubuflocal_remove(buf);
8623
Bram Moolenaar071d4272004-06-13 20:20:40 +00008624 return retval;
8625}
8626
8627/*
8628 * Find next autocommand pattern that matches.
8629 */
8630 static void
8631auto_next_pat(apc, stop_at_last)
8632 AutoPatCmd *apc;
8633 int stop_at_last; /* stop when 'last' flag is set */
8634{
8635 AutoPat *ap;
8636 AutoCmd *cp;
8637 char_u *name;
8638 char *s;
8639
8640 vim_free(sourcing_name);
8641 sourcing_name = NULL;
8642
8643 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8644 {
8645 apc->curpat = NULL;
8646
8647 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008648 * the group matches. For buffer-local autocommands only check the
8649 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008650 if (ap->pat != NULL && ap->cmds != NULL
8651 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8652 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008653 /* execution-condition */
8654 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008655 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8656 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008657 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008658 {
8659 name = event_nr2name(apc->event);
8660 s = _("%s Auto commands for \"%s\"");
8661 sourcing_name = alloc((unsigned)(STRLEN(s)
8662 + STRLEN(name) + ap->patlen + 1));
8663 if (sourcing_name != NULL)
8664 {
8665 sprintf((char *)sourcing_name, s,
8666 (char *)name, (char *)ap->pat);
8667 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008668 {
8669 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008670 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008671 verbose_leave();
8672 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008673 }
8674
8675 apc->curpat = ap;
8676 apc->nextcmd = ap->cmds;
8677 /* mark last command */
8678 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8679 cp->last = FALSE;
8680 cp->last = TRUE;
8681 }
8682 line_breakcheck();
8683 if (apc->curpat != NULL) /* found a match */
8684 break;
8685 }
8686 if (stop_at_last && ap->last)
8687 break;
8688 }
8689}
8690
8691/*
8692 * Get next autocommand command.
8693 * Called by do_cmdline() to get the next line for ":if".
8694 * Returns allocated string, or NULL for end of autocommands.
8695 */
8696/* ARGSUSED */
8697 static char_u *
8698getnextac(c, cookie, indent)
8699 int c; /* not used */
8700 void *cookie;
8701 int indent; /* not used */
8702{
8703 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8704 char_u *retval;
8705 AutoCmd *ac;
8706
8707 /* Can be called again after returning the last line. */
8708 if (acp->curpat == NULL)
8709 return NULL;
8710
8711 /* repeat until we find an autocommand to execute */
8712 for (;;)
8713 {
8714 /* skip removed commands */
8715 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8716 if (acp->nextcmd->last)
8717 acp->nextcmd = NULL;
8718 else
8719 acp->nextcmd = acp->nextcmd->next;
8720
8721 if (acp->nextcmd != NULL)
8722 break;
8723
8724 /* at end of commands, find next pattern that matches */
8725 if (acp->curpat->last)
8726 acp->curpat = NULL;
8727 else
8728 acp->curpat = acp->curpat->next;
8729 if (acp->curpat != NULL)
8730 auto_next_pat(acp, TRUE);
8731 if (acp->curpat == NULL)
8732 return NULL;
8733 }
8734
8735 ac = acp->nextcmd;
8736
8737 if (p_verbose >= 9)
8738 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008739 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008740 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008741 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008742 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008743 }
8744 retval = vim_strsave(ac->cmd);
8745 autocmd_nested = ac->nested;
8746#ifdef FEAT_EVAL
8747 current_SID = ac->scriptID;
8748#endif
8749 if (ac->last)
8750 acp->nextcmd = NULL;
8751 else
8752 acp->nextcmd = ac->next;
8753 return retval;
8754}
8755
8756/*
8757 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008758 * To account for buffer-local autocommands, function needs to know
8759 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008760 */
8761 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008762has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008763 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008764 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008765 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008766{
8767 AutoPat *ap;
8768 char_u *fname;
8769 char_u *tail = gettail(sfname);
8770 int retval = FALSE;
8771
8772 fname = FullName_save(sfname, FALSE);
8773 if (fname == NULL)
8774 return FALSE;
8775
8776#ifdef BACKSLASH_IN_FILENAME
8777 /*
8778 * Replace all backslashes with forward slashes. This makes the
8779 * autocommand patterns portable between Unix and MS-DOS.
8780 */
8781 sfname = vim_strsave(sfname);
8782 if (sfname != NULL)
8783 forward_slash(sfname);
8784 forward_slash(fname);
8785#endif
8786
8787 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8788 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008789 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008790 ? match_file_pat(NULL, ap->reg_prog,
8791 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008792 : buf != NULL && ap->buflocal_nr == buf->b_fnum
8793 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008794 {
8795 retval = TRUE;
8796 break;
8797 }
8798
8799 vim_free(fname);
8800#ifdef BACKSLASH_IN_FILENAME
8801 vim_free(sfname);
8802#endif
8803
8804 return retval;
8805}
8806
8807#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8808/*
8809 * Function given to ExpandGeneric() to obtain the list of autocommand group
8810 * names.
8811 */
8812/*ARGSUSED*/
8813 char_u *
8814get_augroup_name(xp, idx)
8815 expand_T *xp;
8816 int idx;
8817{
8818 if (idx == augroups.ga_len) /* add "END" add the end */
8819 return (char_u *)"END";
8820 if (idx >= augroups.ga_len) /* end of list */
8821 return NULL;
8822 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8823 return (char_u *)"";
8824 return AUGROUP_NAME(idx); /* return a name */
8825}
8826
8827static int include_groups = FALSE;
8828
8829 char_u *
8830set_context_in_autocmd(xp, arg, doautocmd)
8831 expand_T *xp;
8832 char_u *arg;
8833 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8834{
8835 char_u *p;
8836 int group;
8837
8838 /* check for a group name, skip it if present */
8839 include_groups = FALSE;
8840 p = arg;
8841 group = au_get_grouparg(&arg);
8842 if (group == AUGROUP_ERROR)
8843 return NULL;
8844 /* If there only is a group name that's what we expand. */
8845 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8846 {
8847 arg = p;
8848 group = AUGROUP_ALL;
8849 }
8850
8851 /* skip over event name */
8852 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8853 if (*p == ',')
8854 arg = p + 1;
8855 if (*p == NUL)
8856 {
8857 if (group == AUGROUP_ALL)
8858 include_groups = TRUE;
8859 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8860 xp->xp_pattern = arg;
8861 return NULL;
8862 }
8863
8864 /* skip over pattern */
8865 arg = skipwhite(p);
8866 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8867 arg++;
8868 if (*arg)
8869 return arg; /* expand (next) command */
8870
8871 if (doautocmd)
8872 xp->xp_context = EXPAND_FILES; /* expand file names */
8873 else
8874 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8875 return NULL;
8876}
8877
8878/*
8879 * Function given to ExpandGeneric() to obtain the list of event names.
8880 */
8881/*ARGSUSED*/
8882 char_u *
8883get_event_name(xp, idx)
8884 expand_T *xp;
8885 int idx;
8886{
8887 if (idx < augroups.ga_len) /* First list group names, if wanted */
8888 {
8889 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8890 return (char_u *)""; /* skip deleted entries */
8891 return AUGROUP_NAME(idx); /* return a name */
8892 }
8893 return (char_u *)event_names[idx - augroups.ga_len].name;
8894}
8895
8896#endif /* FEAT_CMDL_COMPL */
8897
8898/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008899 * Return TRUE if autocmd is supported.
8900 */
8901 int
8902autocmd_supported(name)
8903 char_u *name;
8904{
8905 char_u *p;
8906
8907 return (event_name2nr(name, &p) != NUM_EVENTS);
8908}
8909
8910/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008911 * Return TRUE if an autocommand is defined for a group, event and
8912 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8913 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8914 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8915 * Used for:
8916 * exists("#Group") or
8917 * exists("#Group#Event") or
8918 * exists("#Group#Event#pat") or
8919 * exists("#Event") or
8920 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008921 */
8922 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008923au_exists(arg)
8924 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008925{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008926 char_u *arg_save;
8927 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008928 char_u *event_name;
8929 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00008930 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008931 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008932 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008933 int group;
8934 int retval = FALSE;
8935
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008936 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008937 arg_save = vim_strsave(arg);
8938 if (arg_save == NULL)
8939 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008940 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008941 if (p != NULL)
8942 *p++ = NUL;
8943
8944 /* First, look for an autocmd group name */
8945 group = au_find_group(arg_save);
8946 if (group == AUGROUP_ERROR)
8947 {
8948 /* Didn't match a group name, assume the first argument is an event. */
8949 group = AUGROUP_ALL;
8950 event_name = arg_save;
8951 }
8952 else
8953 {
8954 if (p == NULL)
8955 {
8956 /* "Group": group name is present and it's recognized */
8957 retval = TRUE;
8958 goto theend;
8959 }
8960
8961 /* Must be "Group#Event" or "Group#Event#pat". */
8962 event_name = p;
8963 p = vim_strchr(event_name, '#');
8964 if (p != NULL)
8965 *p++ = NUL; /* "Group#Event#pat" */
8966 }
8967
8968 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008969
8970 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008971 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008972
8973 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008974 if (event == NUM_EVENTS)
8975 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008976
8977 /* Find the first autocommand for this event.
8978 * If there isn't any, return FALSE;
8979 * If there is one and no pattern given, return TRUE; */
8980 ap = first_autopat[(int)event];
8981 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008982 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008983 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008984 {
8985 retval = TRUE;
8986 goto theend;
8987 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008988
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008989 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
8990 /* for pattern "<buffer=N>, fnamecmp() will work fine */
8991 if (STRICMP(pattern, "<buffer>") == 0)
8992 buflocal_buf = curbuf;
8993
Bram Moolenaar071d4272004-06-13 20:20:40 +00008994 /* Check if there is an autocommand with the given pattern. */
8995 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008996 /* only use a pattern when it has not been removed and has commands. */
8997 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008998 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00008999 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009000 && (buflocal_buf == NULL
9001 ? fnamecmp(ap->pat, pattern) == 0
9002 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009003 {
9004 retval = TRUE;
9005 break;
9006 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009007
Bram Moolenaar195d6352005-12-19 22:08:24 +00009008theend:
9009 vim_free(arg_save);
9010 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009011}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009012
Bram Moolenaar071d4272004-06-13 20:20:40 +00009013#endif /* FEAT_AUTOCMD */
9014
9015#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9016/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009017 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9018 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9019 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009020 * Used for autocommands and 'wildignore'.
9021 * Returns TRUE if there is a match, FALSE otherwise.
9022 */
9023 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009024match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009025 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009026 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009027 char_u *fname; /* full path of file name */
9028 char_u *sfname; /* short file name or NULL */
9029 char_u *tail; /* tail of path */
9030 int allow_dirs; /* allow matching with dir */
9031{
9032 regmatch_T regmatch;
9033 int result = FALSE;
9034#ifdef FEAT_OSFILETYPE
9035 int no_pattern = FALSE; /* TRUE if check is filetype only */
9036 char_u *type_start;
9037 char_u c;
9038 int match = FALSE;
9039#endif
9040
9041#ifdef CASE_INSENSITIVE_FILENAME
9042 regmatch.rm_ic = TRUE; /* Always ignore case */
9043#else
9044 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9045#endif
9046#ifdef FEAT_OSFILETYPE
9047 if (*pattern == '<')
9048 {
9049 /* There is a filetype condition specified with this pattern.
9050 * Check the filetype matches first. If not, don't bother with the
9051 * pattern (set regprog to NULL).
9052 * Always use magic for the regexp.
9053 */
9054
9055 for (type_start = pattern + 1; (c = *pattern); pattern++)
9056 {
9057 if ((c == ';' || c == '>') && match == FALSE)
9058 {
9059 *pattern = NUL; /* Terminate the string */
9060 match = mch_check_filetype(fname, type_start);
9061 *pattern = c; /* Restore the terminator */
9062 type_start = pattern + 1;
9063 }
9064 if (c == '>')
9065 break;
9066 }
9067
9068 /* (c should never be NUL, but check anyway) */
9069 if (match == FALSE || c == NUL)
9070 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9071 else if (*pattern == NUL)
9072 {
9073 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9074 no_pattern = TRUE; /* Always matches - don't check pat. */
9075 }
9076 else
9077 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9078 }
9079 else
9080#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009081 {
9082 if (prog != NULL)
9083 regmatch.regprog = prog;
9084 else
9085 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9086 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009087
9088 /*
9089 * Try for a match with the pattern with:
9090 * 1. the full file name, when the pattern has a '/'.
9091 * 2. the short file name, when the pattern has a '/'.
9092 * 3. the tail of the file name, when the pattern has no '/'.
9093 */
9094 if (
9095#ifdef FEAT_OSFILETYPE
9096 /* If the check is for a filetype only and we don't care
9097 * about the path then skip all the regexp stuff.
9098 */
9099 no_pattern ||
9100#endif
9101 (regmatch.regprog != NULL
9102 && ((allow_dirs
9103 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9104 || (sfname != NULL
9105 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9106 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9107 result = TRUE;
9108
Bram Moolenaar748bf032005-02-02 23:04:36 +00009109 if (prog == NULL)
9110 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009111 return result;
9112}
9113#endif
9114
9115#if defined(FEAT_WILDIGN) || defined(PROTO)
9116/*
9117 * Return TRUE if a file matches with a pattern in "list".
9118 * "list" is a comma-separated list of patterns, like 'wildignore'.
9119 * "sfname" is the short file name or NULL, "ffname" the long file name.
9120 */
9121 int
9122match_file_list(list, sfname, ffname)
9123 char_u *list;
9124 char_u *sfname;
9125 char_u *ffname;
9126{
9127 char_u buf[100];
9128 char_u *tail;
9129 char_u *regpat;
9130 char allow_dirs;
9131 int match;
9132 char_u *p;
9133
9134 tail = gettail(sfname);
9135
9136 /* try all patterns in 'wildignore' */
9137 p = list;
9138 while (*p)
9139 {
9140 copy_option_part(&p, buf, 100, ",");
9141 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9142 if (regpat == NULL)
9143 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009144 match = match_file_pat(regpat, NULL, ffname, sfname,
9145 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009146 vim_free(regpat);
9147 if (match)
9148 return TRUE;
9149 }
9150 return FALSE;
9151}
9152#endif
9153
9154/*
9155 * Convert the given pattern "pat" which has shell style wildcards in it, into
9156 * a regular expression, and return the result in allocated memory. If there
9157 * is a directory path separator to be matched, then TRUE is put in
9158 * allow_dirs, otherwise FALSE is put there -- webb.
9159 * Handle backslashes before special characters, like "\*" and "\ ".
9160 *
9161 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9162 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9163 *
9164 * Returns NULL when out of memory.
9165 */
9166/*ARGSUSED*/
9167 char_u *
9168file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9169 char_u *pat;
9170 char_u *pat_end; /* first char after pattern or NULL */
9171 char *allow_dirs; /* Result passed back out in here */
9172 int no_bslash; /* Don't use a backward slash as pathsep */
9173{
9174 int size;
9175 char_u *endp;
9176 char_u *reg_pat;
9177 char_u *p;
9178 int i;
9179 int nested = 0;
9180 int add_dollar = TRUE;
9181#ifdef FEAT_OSFILETYPE
9182 int check_length = 0;
9183#endif
9184
9185 if (allow_dirs != NULL)
9186 *allow_dirs = FALSE;
9187 if (pat_end == NULL)
9188 pat_end = pat + STRLEN(pat);
9189
9190#ifdef FEAT_OSFILETYPE
9191 /* Find out how much of the string is the filetype check */
9192 if (*pat == '<')
9193 {
9194 /* Count chars until the next '>' */
9195 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9196 ;
9197 if (p < pat_end)
9198 {
9199 /* Pattern is of the form <.*>.* */
9200 check_length = p - pat + 1;
9201 if (p + 1 >= pat_end)
9202 {
9203 /* The 'pattern' is a filetype check ONLY */
9204 reg_pat = (char_u *)alloc(check_length + 1);
9205 if (reg_pat != NULL)
9206 {
9207 mch_memmove(reg_pat, pat, (size_t)check_length);
9208 reg_pat[check_length] = NUL;
9209 }
9210 return reg_pat;
9211 }
9212 }
9213 /* else: there was no closing '>' - assume it was a normal pattern */
9214
9215 }
9216 pat += check_length;
9217 size = 2 + check_length;
9218#else
9219 size = 2; /* '^' at start, '$' at end */
9220#endif
9221
9222 for (p = pat; p < pat_end; p++)
9223 {
9224 switch (*p)
9225 {
9226 case '*':
9227 case '.':
9228 case ',':
9229 case '{':
9230 case '}':
9231 case '~':
9232 size += 2; /* extra backslash */
9233 break;
9234#ifdef BACKSLASH_IN_FILENAME
9235 case '\\':
9236 case '/':
9237 size += 4; /* could become "[\/]" */
9238 break;
9239#endif
9240 default:
9241 size++;
9242# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009243 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009244 {
9245 ++p;
9246 ++size;
9247 }
9248# endif
9249 break;
9250 }
9251 }
9252 reg_pat = alloc(size + 1);
9253 if (reg_pat == NULL)
9254 return NULL;
9255
9256#ifdef FEAT_OSFILETYPE
9257 /* Copy the type check in to the start. */
9258 if (check_length)
9259 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9260 i = check_length;
9261#else
9262 i = 0;
9263#endif
9264
9265 if (pat[0] == '*')
9266 while (pat[0] == '*' && pat < pat_end - 1)
9267 pat++;
9268 else
9269 reg_pat[i++] = '^';
9270 endp = pat_end - 1;
9271 if (*endp == '*')
9272 {
9273 while (endp - pat > 0 && *endp == '*')
9274 endp--;
9275 add_dollar = FALSE;
9276 }
9277 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9278 {
9279 switch (*p)
9280 {
9281 case '*':
9282 reg_pat[i++] = '.';
9283 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009284 while (p[1] == '*') /* "**" matches like "*" */
9285 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009286 break;
9287 case '.':
9288#ifdef RISCOS
9289 if (allow_dirs != NULL)
9290 *allow_dirs = TRUE;
9291 /* FALLTHROUGH */
9292#endif
9293 case '~':
9294 reg_pat[i++] = '\\';
9295 reg_pat[i++] = *p;
9296 break;
9297 case '?':
9298#ifdef RISCOS
9299 case '#':
9300#endif
9301 reg_pat[i++] = '.';
9302 break;
9303 case '\\':
9304 if (p[1] == NUL)
9305 break;
9306#ifdef BACKSLASH_IN_FILENAME
9307 if (!no_bslash)
9308 {
9309 /* translate:
9310 * "\x" to "\\x" e.g., "dir\file"
9311 * "\*" to "\\.*" e.g., "dir\*.c"
9312 * "\?" to "\\." e.g., "dir\??.c"
9313 * "\+" to "\+" e.g., "fileX\+.c"
9314 */
9315 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9316 && p[1] != '+')
9317 {
9318 reg_pat[i++] = '[';
9319 reg_pat[i++] = '\\';
9320 reg_pat[i++] = '/';
9321 reg_pat[i++] = ']';
9322 if (allow_dirs != NULL)
9323 *allow_dirs = TRUE;
9324 break;
9325 }
9326 }
9327#endif
9328 if (*++p == '?'
9329#ifdef BACKSLASH_IN_FILENAME
9330 && no_bslash
9331#endif
9332 )
9333 reg_pat[i++] = '?';
9334 else
9335 if (*p == ',')
9336 reg_pat[i++] = ',';
9337 else
9338 {
9339 if (allow_dirs != NULL && vim_ispathsep(*p)
9340#ifdef BACKSLASH_IN_FILENAME
9341 && (!no_bslash || *p != '\\')
9342#endif
9343 )
9344 *allow_dirs = TRUE;
9345 reg_pat[i++] = '\\';
9346 reg_pat[i++] = *p;
9347 }
9348 break;
9349#ifdef BACKSLASH_IN_FILENAME
9350 case '/':
9351 reg_pat[i++] = '[';
9352 reg_pat[i++] = '\\';
9353 reg_pat[i++] = '/';
9354 reg_pat[i++] = ']';
9355 if (allow_dirs != NULL)
9356 *allow_dirs = TRUE;
9357 break;
9358#endif
9359 case '{':
9360 reg_pat[i++] = '\\';
9361 reg_pat[i++] = '(';
9362 nested++;
9363 break;
9364 case '}':
9365 reg_pat[i++] = '\\';
9366 reg_pat[i++] = ')';
9367 --nested;
9368 break;
9369 case ',':
9370 if (nested)
9371 {
9372 reg_pat[i++] = '\\';
9373 reg_pat[i++] = '|';
9374 }
9375 else
9376 reg_pat[i++] = ',';
9377 break;
9378 default:
9379# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009380 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009381 reg_pat[i++] = *p++;
9382 else
9383# endif
9384 if (allow_dirs != NULL && vim_ispathsep(*p))
9385 *allow_dirs = TRUE;
9386 reg_pat[i++] = *p;
9387 break;
9388 }
9389 }
9390 if (add_dollar)
9391 reg_pat[i++] = '$';
9392 reg_pat[i] = NUL;
9393 if (nested != 0)
9394 {
9395 if (nested < 0)
9396 EMSG(_("E219: Missing {."));
9397 else
9398 EMSG(_("E220: Missing }."));
9399 vim_free(reg_pat);
9400 reg_pat = NULL;
9401 }
9402 return reg_pat;
9403}