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