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