blob: 868b649891d9bcc7bfbf2dbcc03486b8ccd185b3 [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 Moolenaar071d4272004-06-13 20:20:40 +00006956 {"StdinReadPost", EVENT_STDINREADPOST},
6957 {"StdinReadPre", EVENT_STDINREADPRE},
6958 {"Syntax", EVENT_SYNTAX},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00006959 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006960 {"TermChanged", EVENT_TERMCHANGED},
6961 {"TermResponse", EVENT_TERMRESPONSE},
6962 {"User", EVENT_USER},
6963 {"VimEnter", EVENT_VIMENTER},
6964 {"VimLeave", EVENT_VIMLEAVE},
6965 {"VimLeavePre", EVENT_VIMLEAVEPRE},
6966 {"WinEnter", EVENT_WINENTER},
6967 {"WinLeave", EVENT_WINLEAVE},
6968 {NULL, (EVENT_T)0}
6969};
6970
6971static AutoPat *first_autopat[NUM_EVENTS] =
6972{
6973 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
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,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00006977 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6978 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006979};
6980
6981/*
6982 * struct used to keep status while executing autocommands for an event.
6983 */
6984typedef struct AutoPatCmd
6985{
6986 AutoPat *curpat; /* next AutoPat to examine */
6987 AutoCmd *nextcmd; /* next AutoCmd to execute */
6988 int group; /* group being used */
6989 char_u *fname; /* fname to match with */
6990 char_u *sfname; /* sfname to match with */
6991 char_u *tail; /* tail of fname */
6992 EVENT_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006993 int arg_bufnr; /* initially equal to <abuf>, set to zero when
6994 buf is deleted */
6995 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006996} AutoPatCmd;
6997
Bram Moolenaard6f676d2005-06-01 21:51:55 +00006998static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006999
Bram Moolenaar071d4272004-06-13 20:20:40 +00007000/*
7001 * augroups stores a list of autocmd group names.
7002 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007003static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7005
7006/*
7007 * The ID of the current group. Group 0 is the default one.
7008 */
7009#define AUGROUP_DEFAULT -1 /* default autocmd group */
7010#define AUGROUP_ERROR -2 /* errornouse autocmd group */
7011#define AUGROUP_ALL -3 /* all autocmd groups */
7012static int current_augroup = AUGROUP_DEFAULT;
7013
7014static int au_need_clean = FALSE; /* need to delete marked patterns */
7015
7016static void show_autocmd __ARGS((AutoPat *ap, EVENT_T event));
7017static void au_remove_pat __ARGS((AutoPat *ap));
7018static void au_remove_cmds __ARGS((AutoPat *ap));
7019static void au_cleanup __ARGS((void));
7020static int au_new_group __ARGS((char_u *name));
7021static void au_del_group __ARGS((char_u *name));
7022static int au_find_group __ARGS((char_u *name));
7023static EVENT_T event_name2nr __ARGS((char_u *start, char_u **end));
7024static char_u *event_nr2name __ARGS((EVENT_T event));
7025static char_u *find_end_event __ARGS((char_u *arg, int have_group));
7026static int event_ignored __ARGS((EVENT_T event));
7027static int au_get_grouparg __ARGS((char_u **argp));
7028static int do_autocmd_event __ARGS((EVENT_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group));
7029static char_u *getnextac __ARGS((int c, void *cookie, int indent));
7030static 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));
7031static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7032
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007033
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034static EVENT_T last_event;
7035static int last_group;
7036
7037/*
7038 * Show the autocommands for one AutoPat.
7039 */
7040 static void
7041show_autocmd(ap, event)
7042 AutoPat *ap;
7043 EVENT_T event;
7044{
7045 AutoCmd *ac;
7046
7047 /* Check for "got_int" (here and at various places below), which is set
7048 * when "q" has been hit for the "--more--" prompt */
7049 if (got_int)
7050 return;
7051 if (ap->pat == NULL) /* pattern has been removed */
7052 return;
7053
7054 msg_putchar('\n');
7055 if (got_int)
7056 return;
7057 if (event != last_event || ap->group != last_group)
7058 {
7059 if (ap->group != AUGROUP_DEFAULT)
7060 {
7061 if (AUGROUP_NAME(ap->group) == NULL)
7062 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7063 else
7064 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7065 msg_puts((char_u *)" ");
7066 }
7067 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7068 last_event = event;
7069 last_group = ap->group;
7070 msg_putchar('\n');
7071 if (got_int)
7072 return;
7073 }
7074 msg_col = 4;
7075 msg_outtrans(ap->pat);
7076
7077 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7078 {
7079 if (ac->cmd != NULL) /* skip removed commands */
7080 {
7081 if (msg_col >= 14)
7082 msg_putchar('\n');
7083 msg_col = 14;
7084 if (got_int)
7085 return;
7086 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007087#ifdef FEAT_EVAL
7088 if (p_verbose > 0)
7089 last_set_msg(ac->scriptID);
7090#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007091 if (got_int)
7092 return;
7093 if (ac->next != NULL)
7094 {
7095 msg_putchar('\n');
7096 if (got_int)
7097 return;
7098 }
7099 }
7100 }
7101}
7102
7103/*
7104 * Mark an autocommand pattern for deletion.
7105 */
7106 static void
7107au_remove_pat(ap)
7108 AutoPat *ap;
7109{
7110 vim_free(ap->pat);
7111 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007112 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007113 au_need_clean = TRUE;
7114}
7115
7116/*
7117 * Mark all commands for a pattern for deletion.
7118 */
7119 static void
7120au_remove_cmds(ap)
7121 AutoPat *ap;
7122{
7123 AutoCmd *ac;
7124
7125 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7126 {
7127 vim_free(ac->cmd);
7128 ac->cmd = NULL;
7129 }
7130 au_need_clean = TRUE;
7131}
7132
7133/*
7134 * Cleanup autocommands and patterns that have been deleted.
7135 * This is only done when not executing autocommands.
7136 */
7137 static void
7138au_cleanup()
7139{
7140 AutoPat *ap, **prev_ap;
7141 AutoCmd *ac, **prev_ac;
7142 EVENT_T event;
7143
7144 if (autocmd_busy || !au_need_clean)
7145 return;
7146
7147 /* loop over all events */
7148 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7149 event = (EVENT_T)((int)event + 1))
7150 {
7151 /* loop over all autocommand patterns */
7152 prev_ap = &(first_autopat[(int)event]);
7153 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7154 {
7155 /* loop over all commands for this pattern */
7156 prev_ac = &(ap->cmds);
7157 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7158 {
7159 /* remove the command if the pattern is to be deleted or when
7160 * the command has been marked for deletion */
7161 if (ap->pat == NULL || ac->cmd == NULL)
7162 {
7163 *prev_ac = ac->next;
7164 vim_free(ac->cmd);
7165 vim_free(ac);
7166 }
7167 else
7168 prev_ac = &(ac->next);
7169 }
7170
7171 /* remove the pattern if it has been marked for deletion */
7172 if (ap->pat == NULL)
7173 {
7174 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007175 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007176 vim_free(ap);
7177 }
7178 else
7179 prev_ap = &(ap->next);
7180 }
7181 }
7182
7183 au_need_clean = FALSE;
7184}
7185
7186/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007187 * Called when buffer is freed, to remove/invalidate related buffer-local
7188 * autocmds.
7189 */
7190 void
7191aubuflocal_remove(buf)
7192 buf_T *buf;
7193{
7194 AutoPat *ap;
7195 EVENT_T event;
7196 AutoPatCmd *apc;
7197
7198 /* invalidate currently executing autocommands */
7199 for (apc = active_apc_list; apc; apc = apc->next)
7200 if (buf->b_fnum == apc->arg_bufnr)
7201 apc->arg_bufnr = 0;
7202
7203 /* invalidate buflocals looping through events */
7204 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7205 event = (EVENT_T)((int)event + 1))
7206 /* loop over all autocommand patterns */
7207 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7208 if (ap->buflocal_nr == buf->b_fnum)
7209 {
7210 au_remove_pat(ap);
7211 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007212 {
7213 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007214 smsg((char_u *)
7215 _("auto-removing autocommand: %s <buffer=%d>"),
7216 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007217 verbose_leave();
7218 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007219 }
7220 au_cleanup();
7221}
7222
7223/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007224 * Add an autocmd group name.
7225 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7226 */
7227 static int
7228au_new_group(name)
7229 char_u *name;
7230{
7231 int i;
7232
7233 i = au_find_group(name);
7234 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7235 {
7236 /* First try using a free entry. */
7237 for (i = 0; i < augroups.ga_len; ++i)
7238 if (AUGROUP_NAME(i) == NULL)
7239 break;
7240 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7241 return AUGROUP_ERROR;
7242
7243 AUGROUP_NAME(i) = vim_strsave(name);
7244 if (AUGROUP_NAME(i) == NULL)
7245 return AUGROUP_ERROR;
7246 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007247 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007248 }
7249
7250 return i;
7251}
7252
7253 static void
7254au_del_group(name)
7255 char_u *name;
7256{
7257 int i;
7258
7259 i = au_find_group(name);
7260 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7261 EMSG2(_("E367: No such group: \"%s\""), name);
7262 else
7263 {
7264 vim_free(AUGROUP_NAME(i));
7265 AUGROUP_NAME(i) = NULL;
7266 }
7267}
7268
7269/*
7270 * Find the ID of an autocmd group name.
7271 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7272 */
7273 static int
7274au_find_group(name)
7275 char_u *name;
7276{
7277 int i;
7278
7279 for (i = 0; i < augroups.ga_len; ++i)
7280 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7281 return i;
7282 return AUGROUP_ERROR;
7283}
7284
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007285#if defined(FEAT_BROWSE) || defined(PROTO)
7286/*
7287 * Return TRUE if augroup "name" exists.
7288 */
7289 int
7290au_has_group(name)
7291 char_u *name;
7292{
7293 return au_find_group(name) != AUGROUP_ERROR;
7294}
7295#endif
7296
Bram Moolenaar071d4272004-06-13 20:20:40 +00007297/*
7298 * ":augroup {name}".
7299 */
7300 void
7301do_augroup(arg, del_group)
7302 char_u *arg;
7303 int del_group;
7304{
7305 int i;
7306
7307 if (del_group)
7308 {
7309 if (*arg == NUL)
7310 EMSG(_(e_argreq));
7311 else
7312 au_del_group(arg);
7313 }
7314 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7315 current_augroup = AUGROUP_DEFAULT;
7316 else if (*arg) /* ":aug xxx": switch to group xxx */
7317 {
7318 i = au_new_group(arg);
7319 if (i != AUGROUP_ERROR)
7320 current_augroup = i;
7321 }
7322 else /* ":aug": list the group names */
7323 {
7324 msg_start();
7325 for (i = 0; i < augroups.ga_len; ++i)
7326 {
7327 if (AUGROUP_NAME(i) != NULL)
7328 {
7329 msg_puts(AUGROUP_NAME(i));
7330 msg_puts((char_u *)" ");
7331 }
7332 }
7333 msg_clr_eos();
7334 msg_end();
7335 }
7336}
7337
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007338#if defined(EXITFREE) || defined(PROTO)
7339 void
7340free_all_autocmds()
7341{
7342 for (current_augroup = -1; current_augroup < augroups.ga_len;
7343 ++current_augroup)
7344 do_autocmd((char_u *)"", TRUE);
7345 ga_clear_strings(&augroups);
7346}
7347#endif
7348
Bram Moolenaar071d4272004-06-13 20:20:40 +00007349/*
7350 * Return the event number for event name "start".
7351 * Return NUM_EVENTS if the event name was not found.
7352 * Return a pointer to the next event name in "end".
7353 */
7354 static EVENT_T
7355event_name2nr(start, end)
7356 char_u *start;
7357 char_u **end;
7358{
7359 char_u *p;
7360 int i;
7361 int len;
7362
7363 /* the event name ends with end of line, a blank or a comma */
7364 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7365 ;
7366 for (i = 0; event_names[i].name != NULL; ++i)
7367 {
7368 len = (int)STRLEN(event_names[i].name);
7369 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7370 break;
7371 }
7372 if (*p == ',')
7373 ++p;
7374 *end = p;
7375 if (event_names[i].name == NULL)
7376 return NUM_EVENTS;
7377 return event_names[i].event;
7378}
7379
7380/*
7381 * Return the name for event "event".
7382 */
7383 static char_u *
7384event_nr2name(event)
7385 EVENT_T event;
7386{
7387 int i;
7388
7389 for (i = 0; event_names[i].name != NULL; ++i)
7390 if (event_names[i].event == event)
7391 return (char_u *)event_names[i].name;
7392 return (char_u *)"Unknown";
7393}
7394
7395/*
7396 * Scan over the events. "*" stands for all events.
7397 */
7398 static char_u *
7399find_end_event(arg, have_group)
7400 char_u *arg;
7401 int have_group; /* TRUE when group name was found */
7402{
7403 char_u *pat;
7404 char_u *p;
7405
7406 if (*arg == '*')
7407 {
7408 if (arg[1] && !vim_iswhite(arg[1]))
7409 {
7410 EMSG2(_("E215: Illegal character after *: %s"), arg);
7411 return NULL;
7412 }
7413 pat = arg + 1;
7414 }
7415 else
7416 {
7417 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7418 {
7419 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7420 {
7421 if (have_group)
7422 EMSG2(_("E216: No such event: %s"), pat);
7423 else
7424 EMSG2(_("E216: No such group or event: %s"), pat);
7425 return NULL;
7426 }
7427 }
7428 }
7429 return pat;
7430}
7431
7432/*
7433 * Return TRUE if "event" is included in 'eventignore'.
7434 */
7435 static int
7436event_ignored(event)
7437 EVENT_T event;
7438{
7439 char_u *p = p_ei;
7440
7441 if (STRICMP(p_ei, "all") == 0)
7442 return TRUE;
7443
7444 while (*p)
7445 if (event_name2nr(p, &p) == event)
7446 return TRUE;
7447
7448 return FALSE;
7449}
7450
7451/*
7452 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7453 */
7454 int
7455check_ei()
7456{
7457 char_u *p = p_ei;
7458
7459 if (STRICMP(p_ei, "all") == 0)
7460 return OK;
7461
7462 while (*p)
7463 if (event_name2nr(p, &p) == NUM_EVENTS)
7464 return FAIL;
7465
7466 return OK;
7467}
7468
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007469# if defined(FEAT_SYN_HL) || defined(PROTO)
7470
7471/*
7472 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7473 * buffer loaded into the window. "what" must start with a comma.
7474 * Returns the old value of 'eventignore' in allocated memory.
7475 */
7476 char_u *
7477au_event_disable(what)
7478 char *what;
7479{
7480 char_u *new_ei;
7481 char_u *save_ei;
7482
7483 save_ei = vim_strsave(p_ei);
7484 if (save_ei != NULL)
7485 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007486 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007487 if (new_ei != NULL)
7488 {
7489 STRCAT(new_ei, what);
7490 set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
7491 vim_free(new_ei);
7492 }
7493 }
7494 return save_ei;
7495}
7496
7497 void
7498au_event_restore(old_ei)
7499 char_u *old_ei;
7500{
7501 if (old_ei != NULL)
7502 {
7503 set_string_option_direct((char_u *)"ei", -1, old_ei, OPT_FREE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007504 vim_free(old_ei);
7505 }
7506}
7507# endif /* FEAT_SYN_HL */
7508
Bram Moolenaar071d4272004-06-13 20:20:40 +00007509/*
7510 * do_autocmd() -- implements the :autocmd command. Can be used in the
7511 * following ways:
7512 *
7513 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7514 * will be automatically executed for <event>
7515 * when editing a file matching <pat>, in
7516 * the current group.
7517 * :autocmd <event> <pat> Show the auto-commands associated with
7518 * <event> and <pat>.
7519 * :autocmd <event> Show the auto-commands associated with
7520 * <event>.
7521 * :autocmd Show all auto-commands.
7522 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7523 * <event> and <pat>, and add the command
7524 * <cmd>, for the current group.
7525 * :autocmd! <event> <pat> Remove all auto-commands associated with
7526 * <event> and <pat> for the current group.
7527 * :autocmd! <event> Remove all auto-commands associated with
7528 * <event> for the current group.
7529 * :autocmd! Remove ALL auto-commands for the current
7530 * group.
7531 *
7532 * Multiple events and patterns may be given separated by commas. Here are
7533 * some examples:
7534 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7535 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7536 *
7537 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007538 *
7539 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007540 */
7541 void
7542do_autocmd(arg, forceit)
7543 char_u *arg;
7544 int forceit;
7545{
7546 char_u *pat;
7547 char_u *envpat = NULL;
7548 char_u *cmd;
7549 EVENT_T event;
7550 int need_free = FALSE;
7551 int nested = FALSE;
7552 int group;
7553
7554 /*
7555 * Check for a legal group name. If not, use AUGROUP_ALL.
7556 */
7557 group = au_get_grouparg(&arg);
7558 if (arg == NULL) /* out of memory */
7559 return;
7560
7561 /*
7562 * Scan over the events.
7563 * If we find an illegal name, return here, don't do anything.
7564 */
7565 pat = find_end_event(arg, group != AUGROUP_ALL);
7566 if (pat == NULL)
7567 return;
7568
7569 /*
7570 * Scan over the pattern. Put a NUL at the end.
7571 */
7572 pat = skipwhite(pat);
7573 cmd = pat;
7574 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7575 cmd++;
7576 if (*cmd)
7577 *cmd++ = NUL;
7578
7579 /* Expand environment variables in the pattern. Set 'shellslash', we want
7580 * forward slashes here. */
7581 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7582 {
7583#ifdef BACKSLASH_IN_FILENAME
7584 int p_ssl_save = p_ssl;
7585
7586 p_ssl = TRUE;
7587#endif
7588 envpat = expand_env_save(pat);
7589#ifdef BACKSLASH_IN_FILENAME
7590 p_ssl = p_ssl_save;
7591#endif
7592 if (envpat != NULL)
7593 pat = envpat;
7594 }
7595
7596 /*
7597 * Check for "nested" flag.
7598 */
7599 cmd = skipwhite(cmd);
7600 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7601 {
7602 nested = TRUE;
7603 cmd = skipwhite(cmd + 6);
7604 }
7605
7606 /*
7607 * Find the start of the commands.
7608 * Expand <sfile> in it.
7609 */
7610 if (*cmd != NUL)
7611 {
7612 cmd = expand_sfile(cmd);
7613 if (cmd == NULL) /* some error */
7614 return;
7615 need_free = TRUE;
7616 }
7617
7618 /*
7619 * Print header when showing autocommands.
7620 */
7621 if (!forceit && *cmd == NUL)
7622 {
7623 /* Highlight title */
7624 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7625 }
7626
7627 /*
7628 * Loop over the events.
7629 */
7630 last_event = (EVENT_T)-1; /* for listing the event name */
7631 last_group = AUGROUP_ERROR; /* for listing the group name */
7632 if (*arg == '*' || *arg == NUL)
7633 {
7634 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7635 event = (EVENT_T)((int)event + 1))
7636 if (do_autocmd_event(event, pat,
7637 nested, cmd, forceit, group) == FAIL)
7638 break;
7639 }
7640 else
7641 {
7642 while (*arg && !vim_iswhite(*arg))
7643 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7644 nested, cmd, forceit, group) == FAIL)
7645 break;
7646 }
7647
7648 if (need_free)
7649 vim_free(cmd);
7650 vim_free(envpat);
7651}
7652
7653/*
7654 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7655 * The "argp" argument is advanced to the following argument.
7656 *
7657 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7658 */
7659 static int
7660au_get_grouparg(argp)
7661 char_u **argp;
7662{
7663 char_u *group_name;
7664 char_u *p;
7665 char_u *arg = *argp;
7666 int group = AUGROUP_ALL;
7667
7668 p = skiptowhite(arg);
7669 if (p > arg)
7670 {
7671 group_name = vim_strnsave(arg, (int)(p - arg));
7672 if (group_name == NULL) /* out of memory */
7673 return AUGROUP_ERROR;
7674 group = au_find_group(group_name);
7675 if (group == AUGROUP_ERROR)
7676 group = AUGROUP_ALL; /* no match, use all groups */
7677 else
7678 *argp = skipwhite(p); /* match, skip over group name */
7679 vim_free(group_name);
7680 }
7681 return group;
7682}
7683
7684/*
7685 * do_autocmd() for one event.
7686 * If *pat == NUL do for all patterns.
7687 * If *cmd == NUL show entries.
7688 * If forceit == TRUE delete entries.
7689 * If group is not AUGROUP_ALL, only use this group.
7690 */
7691 static int
7692do_autocmd_event(event, pat, nested, cmd, forceit, group)
7693 EVENT_T event;
7694 char_u *pat;
7695 int nested;
7696 char_u *cmd;
7697 int forceit;
7698 int group;
7699{
7700 AutoPat *ap;
7701 AutoPat **prev_ap;
7702 AutoCmd *ac;
7703 AutoCmd **prev_ac;
7704 int brace_level;
7705 char_u *endpat;
7706 int findgroup;
7707 int allgroups;
7708 int patlen;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007709 int is_buflocal;
7710 int buflocal_nr;
7711 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007712
7713 if (group == AUGROUP_ALL)
7714 findgroup = current_augroup;
7715 else
7716 findgroup = group;
7717 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7718
7719 /*
7720 * Show or delete all patterns for an event.
7721 */
7722 if (*pat == NUL)
7723 {
7724 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7725 {
7726 if (forceit) /* delete the AutoPat, if it's in the current group */
7727 {
7728 if (ap->group == findgroup)
7729 au_remove_pat(ap);
7730 }
7731 else if (group == AUGROUP_ALL || ap->group == group)
7732 show_autocmd(ap, event);
7733 }
7734 }
7735
7736 /*
7737 * Loop through all the specified patterns.
7738 */
7739 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7740 {
7741 /*
7742 * Find end of the pattern.
7743 * Watch out for a comma in braces, like "*.\{obj,o\}".
7744 */
7745 brace_level = 0;
7746 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7747 || endpat[-1] == '\\'); ++endpat)
7748 {
7749 if (*endpat == '{')
7750 brace_level++;
7751 else if (*endpat == '}')
7752 brace_level--;
7753 }
7754 if (pat == endpat) /* ignore single comma */
7755 continue;
7756 patlen = (int)(endpat - pat);
7757
7758 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007759 * detect special <buflocal[=X]> buffer-local patterns
7760 */
7761 is_buflocal = FALSE;
7762 buflocal_nr = 0;
7763
7764 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7765 && pat[patlen - 1] == '>')
7766 {
7767 /* Error will be printed only for addition. printing and removing
7768 * will proceed silently. */
7769 is_buflocal = TRUE;
7770 if (patlen == 8)
7771 buflocal_nr = curbuf->b_fnum;
7772 else if (patlen > 9 && pat[7] == '=')
7773 {
7774 /* <buffer=abuf> */
7775 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7776 buflocal_nr = autocmd_bufnr;
7777 /* <buffer=123> */
7778 else if (skipdigits(pat + 8) == pat + patlen - 1)
7779 buflocal_nr = atoi((char *)pat + 8);
7780 }
7781 }
7782
7783 if (is_buflocal)
7784 {
7785 /* normalize pat into standard "<buffer>#N" form */
7786 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7787 pat = buflocal_pat; /* can modify pat and patlen */
7788 patlen = STRLEN(buflocal_pat); /* but not endpat */
7789 }
7790
7791 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007792 * Find AutoPat entries with this pattern.
7793 */
7794 prev_ap = &first_autopat[(int)event];
7795 while ((ap = *prev_ap) != NULL)
7796 {
7797 if (ap->pat != NULL)
7798 {
7799 /* Accept a pattern when:
7800 * - a group was specified and it's that group, or a group was
7801 * not specified and it's the current group, or a group was
7802 * not specified and we are listing
7803 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007804 * - the pattern matches.
7805 * For <buffer[=X]>, this condition works because we normalize
7806 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007807 */
7808 if ((allgroups || ap->group == findgroup)
7809 && ap->patlen == patlen
7810 && STRNCMP(pat, ap->pat, patlen) == 0)
7811 {
7812 /*
7813 * Remove existing autocommands.
7814 * If adding any new autocmd's for this AutoPat, don't
7815 * delete the pattern from the autopat list, append to
7816 * this list.
7817 */
7818 if (forceit)
7819 {
7820 if (*cmd != NUL && ap->next == NULL)
7821 {
7822 au_remove_cmds(ap);
7823 break;
7824 }
7825 au_remove_pat(ap);
7826 }
7827
7828 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007829 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007830 */
7831 else if (*cmd == NUL)
7832 show_autocmd(ap, event);
7833
7834 /*
7835 * Add autocmd to this autopat, if it's the last one.
7836 */
7837 else if (ap->next == NULL)
7838 break;
7839 }
7840 }
7841 prev_ap = &ap->next;
7842 }
7843
7844 /*
7845 * Add a new command.
7846 */
7847 if (*cmd != NUL)
7848 {
7849 /*
7850 * If the pattern we want to add a command to does appear at the
7851 * end of the list (or not is not in the list at all), add the
7852 * pattern at the end of the list.
7853 */
7854 if (ap == NULL)
7855 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007856 /* refuse to add buffer-local ap if buffer number is invalid */
7857 if (is_buflocal && (buflocal_nr == 0
7858 || buflist_findnr(buflocal_nr) == NULL))
7859 {
7860 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7861 buflocal_nr);
7862 return FAIL;
7863 }
7864
Bram Moolenaar071d4272004-06-13 20:20:40 +00007865 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7866 if (ap == NULL)
7867 return FAIL;
7868 ap->pat = vim_strnsave(pat, patlen);
7869 ap->patlen = patlen;
7870 if (ap->pat == NULL)
7871 {
7872 vim_free(ap);
7873 return FAIL;
7874 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007875
7876 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007877 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007878 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007879 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007880 }
7881 else
7882 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007883 char_u *reg_pat;
7884
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007885 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007886 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007887 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007888 if (reg_pat != NULL)
7889 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007890 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007891 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007892 {
7893 vim_free(ap->pat);
7894 vim_free(ap);
7895 return FAIL;
7896 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007897 }
7898 ap->cmds = NULL;
7899 *prev_ap = ap;
7900 ap->next = NULL;
7901 if (group == AUGROUP_ALL)
7902 ap->group = current_augroup;
7903 else
7904 ap->group = group;
7905 }
7906
7907 /*
7908 * Add the autocmd at the end of the AutoCmd list.
7909 */
7910 prev_ac = &(ap->cmds);
7911 while ((ac = *prev_ac) != NULL)
7912 prev_ac = &ac->next;
7913 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7914 if (ac == NULL)
7915 return FAIL;
7916 ac->cmd = vim_strsave(cmd);
7917#ifdef FEAT_EVAL
7918 ac->scriptID = current_SID;
7919#endif
7920 if (ac->cmd == NULL)
7921 {
7922 vim_free(ac);
7923 return FAIL;
7924 }
7925 ac->next = NULL;
7926 *prev_ac = ac;
7927 ac->nested = nested;
7928 }
7929 }
7930
7931 au_cleanup(); /* may really delete removed patterns/commands now */
7932 return OK;
7933}
7934
7935/*
7936 * Implementation of ":doautocmd [group] event [fname]".
7937 * Return OK for success, FAIL for failure;
7938 */
7939 int
7940do_doautocmd(arg, do_msg)
7941 char_u *arg;
7942 int do_msg; /* give message for no matching autocmds? */
7943{
7944 char_u *fname;
7945 int nothing_done = TRUE;
7946 int group;
7947
7948 /*
7949 * Check for a legal group name. If not, use AUGROUP_ALL.
7950 */
7951 group = au_get_grouparg(&arg);
7952 if (arg == NULL) /* out of memory */
7953 return FAIL;
7954
7955 if (*arg == '*')
7956 {
7957 EMSG(_("E217: Can't execute autocommands for ALL events"));
7958 return FAIL;
7959 }
7960
7961 /*
7962 * Scan over the events.
7963 * If we find an illegal name, return here, don't do anything.
7964 */
7965 fname = find_end_event(arg, group != AUGROUP_ALL);
7966 if (fname == NULL)
7967 return FAIL;
7968
7969 fname = skipwhite(fname);
7970
7971 /*
7972 * Loop over the events.
7973 */
7974 while (*arg && !vim_iswhite(*arg))
7975 if (apply_autocmds_group(event_name2nr(arg, &arg),
7976 fname, NULL, TRUE, group, curbuf, NULL))
7977 nothing_done = FALSE;
7978
7979 if (nothing_done && do_msg)
7980 MSG(_("No matching autocommands"));
7981
7982#ifdef FEAT_EVAL
7983 return aborting() ? FAIL : OK;
7984#else
7985 return OK;
7986#endif
7987}
7988
7989/*
7990 * ":doautoall": execute autocommands for each loaded buffer.
7991 */
7992 void
7993ex_doautoall(eap)
7994 exarg_T *eap;
7995{
7996 int retval;
7997 aco_save_T aco;
7998 buf_T *buf;
7999
8000 /*
8001 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8002 * equal to curbuf, but for some buffers there may not be a window.
8003 * So we change the buffer for the current window for a moment. This
8004 * gives problems when the autocommands make changes to the list of
8005 * buffers or windows...
8006 */
8007 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8008 {
8009 if (curbuf->b_ml.ml_mfp != NULL)
8010 {
8011 /* find a window for this buffer and save some values */
8012 aucmd_prepbuf(&aco, buf);
8013
8014 /* execute the autocommands for this buffer */
8015 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00008016 do_modelines(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008017
8018 /* restore the current window */
8019 aucmd_restbuf(&aco);
8020
8021 /* stop if there is some error or buffer was deleted */
8022 if (retval == FAIL || !buf_valid(buf))
8023 break;
8024 }
8025 }
8026
8027 check_cursor(); /* just in case lines got deleted */
8028}
8029
8030/*
8031 * Prepare for executing autocommands for (hidden) buffer "buf".
8032 * Search a window for the current buffer. Save the cursor position and
8033 * screen offset.
8034 * Set "curbuf" and "curwin" to match "buf".
8035 */
8036 void
8037aucmd_prepbuf(aco, buf)
8038 aco_save_T *aco; /* structure to save values in */
8039 buf_T *buf; /* new curbuf */
8040{
8041 win_T *win;
8042
8043 aco->new_curbuf = buf;
8044
8045 /* Find a window that is for the new buffer */
8046 if (buf == curbuf) /* be quick when buf is curbuf */
8047 win = curwin;
8048 else
8049#ifdef FEAT_WINDOWS
8050 for (win = firstwin; win != NULL; win = win->w_next)
8051 if (win->w_buffer == buf)
8052 break;
8053#else
8054 win = NULL;
8055#endif
8056
8057 /*
8058 * Prefer to use an existing window for the buffer, it has the least side
8059 * effects (esp. if "buf" is curbuf).
8060 * Otherwise, use curwin for "buf". It might make some items in the
8061 * window invalid. At least save the cursor and topline.
8062 */
8063 if (win != NULL)
8064 {
8065 /* there is a window for "buf", make it the curwin */
8066 aco->save_curwin = curwin;
8067 curwin = win;
8068 aco->save_buf = win->w_buffer;
8069 aco->new_curwin = win;
8070 }
8071 else
8072 {
8073 /* there is no window for "buf", use curwin */
8074 aco->save_curwin = NULL;
8075 aco->save_buf = curbuf;
8076 --curbuf->b_nwindows;
8077 curwin->w_buffer = buf;
8078 ++buf->b_nwindows;
8079
8080 /* save cursor and topline, set them to safe values */
8081 aco->save_cursor = curwin->w_cursor;
8082 curwin->w_cursor.lnum = 1;
8083 curwin->w_cursor.col = 0;
8084 aco->save_topline = curwin->w_topline;
8085 curwin->w_topline = 1;
8086#ifdef FEAT_DIFF
8087 aco->save_topfill = curwin->w_topfill;
8088 curwin->w_topfill = 0;
8089#endif
8090 }
8091
8092 curbuf = buf;
8093}
8094
8095/*
8096 * Cleanup after executing autocommands for a (hidden) buffer.
8097 * Restore the window as it was (if possible).
8098 */
8099 void
8100aucmd_restbuf(aco)
8101 aco_save_T *aco; /* structure holding saved values */
8102{
8103 if (aco->save_curwin != NULL)
8104 {
8105 /* restore curwin */
8106#ifdef FEAT_WINDOWS
8107 if (win_valid(aco->save_curwin))
8108#endif
8109 {
8110 /* restore the buffer which was previously edited by curwin, if
8111 * it's still the same window and it's valid */
8112 if (curwin == aco->new_curwin
8113 && buf_valid(aco->save_buf)
8114 && aco->save_buf->b_ml.ml_mfp != NULL)
8115 {
8116 --curbuf->b_nwindows;
8117 curbuf = aco->save_buf;
8118 curwin->w_buffer = curbuf;
8119 ++curbuf->b_nwindows;
8120 }
8121
8122 curwin = aco->save_curwin;
8123 curbuf = curwin->w_buffer;
8124 }
8125 }
8126 else
8127 {
8128 /* restore buffer for curwin if it still exists and is loaded */
8129 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8130 {
8131 --curbuf->b_nwindows;
8132 curbuf = aco->save_buf;
8133 curwin->w_buffer = curbuf;
8134 ++curbuf->b_nwindows;
8135 curwin->w_cursor = aco->save_cursor;
8136 check_cursor();
8137 /* check topline < line_count, in case lines got deleted */
8138 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8139 {
8140 curwin->w_topline = aco->save_topline;
8141#ifdef FEAT_DIFF
8142 curwin->w_topfill = aco->save_topfill;
8143#endif
8144 }
8145 else
8146 {
8147 curwin->w_topline = curbuf->b_ml.ml_line_count;
8148#ifdef FEAT_DIFF
8149 curwin->w_topfill = 0;
8150#endif
8151 }
8152 }
8153 }
8154}
8155
8156static int autocmd_nested = FALSE;
8157
8158/*
8159 * Execute autocommands for "event" and file name "fname".
8160 * Return TRUE if some commands were executed.
8161 */
8162 int
8163apply_autocmds(event, fname, fname_io, force, buf)
8164 EVENT_T event;
8165 char_u *fname; /* NULL or empty means use actual file name */
8166 char_u *fname_io; /* fname to use for <afile> on cmdline */
8167 int force; /* when TRUE, ignore autocmd_busy */
8168 buf_T *buf; /* buffer for <abuf> */
8169{
8170 return apply_autocmds_group(event, fname, fname_io, force,
8171 AUGROUP_ALL, buf, NULL);
8172}
8173
8174/*
8175 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8176 * setting v:filearg.
8177 */
8178 static int
8179apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
8180 EVENT_T event;
8181 char_u *fname;
8182 char_u *fname_io;
8183 int force;
8184 buf_T *buf;
8185 exarg_T *eap;
8186{
8187 return apply_autocmds_group(event, fname, fname_io, force,
8188 AUGROUP_ALL, buf, eap);
8189}
8190
8191/*
8192 * Like apply_autocmds(), but handles the caller's retval. If the script
8193 * processing is being aborted or if retval is FAIL when inside a try
8194 * conditional, no autocommands are executed. If otherwise the autocommands
8195 * cause the script to be aborted, retval is set to FAIL.
8196 */
8197 int
8198apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
8199 EVENT_T event;
8200 char_u *fname; /* NULL or empty means use actual file name */
8201 char_u *fname_io; /* fname to use for <afile> on cmdline */
8202 int force; /* when TRUE, ignore autocmd_busy */
8203 buf_T *buf; /* buffer for <abuf> */
8204 int *retval; /* pointer to caller's retval */
8205{
8206 int did_cmd;
8207
Bram Moolenaar1e015462005-09-25 22:16:38 +00008208#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008209 if (should_abort(*retval))
8210 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008211#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008212
8213 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8214 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008215 if (did_cmd
8216#ifdef FEAT_EVAL
8217 && aborting()
8218#endif
8219 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008220 *retval = FAIL;
8221 return did_cmd;
8222}
8223
8224#if defined(FEAT_AUTOCMD) || defined(PROTO)
Bram Moolenaard35f9712005-12-18 22:02:33 +00008225/*
8226 * Return TRUE when there is a CursorHold autocommand defined.
8227 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008228 int
8229has_cursorhold()
8230{
8231 return (first_autopat[(int)EVENT_CURSORHOLD] != NULL);
8232}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008233
8234/*
8235 * Return TRUE if the CursorHold event can be triggered.
8236 */
8237 int
8238trigger_cursorhold()
8239{
8240 return (!did_cursorhold
8241 && has_cursorhold()
8242 && !Recording
8243 && get_real_state() == NORMAL_BUSY);
8244}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008245#endif
8246
8247 static int
8248apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
8249 EVENT_T event;
8250 char_u *fname; /* NULL or empty means use actual file name */
8251 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8252 use fname */
8253 int force; /* when TRUE, ignore autocmd_busy */
8254 int group; /* group ID, or AUGROUP_ALL */
8255 buf_T *buf; /* buffer for <abuf> */
8256 exarg_T *eap; /* command arguments */
8257{
8258 char_u *sfname = NULL; /* short file name */
8259 char_u *tail;
8260 int save_changed;
8261 buf_T *old_curbuf;
8262 int retval = FALSE;
8263 char_u *save_sourcing_name;
8264 linenr_T save_sourcing_lnum;
8265 char_u *save_autocmd_fname;
8266 int save_autocmd_bufnr;
8267 char_u *save_autocmd_match;
8268 int save_autocmd_busy;
8269 int save_autocmd_nested;
8270 static int nesting = 0;
8271 AutoPatCmd patcmd;
8272 AutoPat *ap;
8273#ifdef FEAT_EVAL
8274 scid_T save_current_SID;
8275 void *save_funccalp;
8276 char_u *save_cmdarg;
8277 long save_cmdbang;
8278#endif
8279 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008280#ifdef FEAT_PROFILE
8281 proftime_T wait_time;
8282#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008283
8284 /*
8285 * Quickly return if there are no autocommands for this event or
8286 * autocommands are blocked.
8287 */
8288 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008289 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008290
8291 /*
8292 * When autocommands are busy, new autocommands are only executed when
8293 * explicitly enabled with the "nested" flag.
8294 */
8295 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008296 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008297
8298#ifdef FEAT_EVAL
8299 /*
8300 * Quickly return when immdediately aborting on error, or when an interrupt
8301 * occurred or an exception was thrown but not caught.
8302 */
8303 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008304 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008305#endif
8306
8307 /*
8308 * FileChangedShell never nests, because it can create an endless loop.
8309 */
8310 if (filechangeshell_busy && event == EVENT_FILECHANGEDSHELL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008311 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008312
8313 /*
8314 * Ignore events in 'eventignore'.
8315 */
8316 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008317 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008318
8319 /*
8320 * Allow nesting of autocommands, but restrict the depth, because it's
8321 * possible to create an endless loop.
8322 */
8323 if (nesting == 10)
8324 {
8325 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008326 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008327 }
8328
8329 /*
8330 * Check if these autocommands are disabled. Used when doing ":all" or
8331 * ":ball".
8332 */
8333 if ( (autocmd_no_enter
8334 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8335 || (autocmd_no_leave
8336 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008337 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008338
8339 /*
8340 * Save the autocmd_* variables and info about the current buffer.
8341 */
8342 save_autocmd_fname = autocmd_fname;
8343 save_autocmd_bufnr = autocmd_bufnr;
8344 save_autocmd_match = autocmd_match;
8345 save_autocmd_busy = autocmd_busy;
8346 save_autocmd_nested = autocmd_nested;
8347 save_changed = curbuf->b_changed;
8348 old_curbuf = curbuf;
8349
8350 /*
8351 * Set the file name to be used for <afile>.
8352 */
8353 if (fname_io == NULL)
8354 {
8355 if (fname != NULL && *fname != NUL)
8356 autocmd_fname = fname;
8357 else if (buf != NULL)
8358 autocmd_fname = buf->b_fname;
8359 else
8360 autocmd_fname = NULL;
8361 }
8362 else
8363 autocmd_fname = fname_io;
8364
8365 /*
8366 * Set the buffer number to be used for <abuf>.
8367 */
8368 if (buf == NULL)
8369 autocmd_bufnr = 0;
8370 else
8371 autocmd_bufnr = buf->b_fnum;
8372
8373 /*
8374 * When the file name is NULL or empty, use the file name of buffer "buf".
8375 * Always use the full path of the file name to match with, in case
8376 * "allow_dirs" is set.
8377 */
8378 if (fname == NULL || *fname == NUL)
8379 {
8380 if (buf == NULL)
8381 fname = NULL;
8382 else
8383 {
8384#ifdef FEAT_SYN_HL
8385 if (event == EVENT_SYNTAX)
8386 fname = buf->b_p_syn;
8387 else
8388#endif
8389 if (event == EVENT_FILETYPE)
8390 fname = buf->b_p_ft;
8391 else
8392 {
8393 if (buf->b_sfname != NULL)
8394 sfname = vim_strsave(buf->b_sfname);
8395 fname = buf->b_ffname;
8396 }
8397 }
8398 if (fname == NULL)
8399 fname = (char_u *)"";
8400 fname = vim_strsave(fname); /* make a copy, so we can change it */
8401 }
8402 else
8403 {
8404 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008405 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8406 if (event == EVENT_FILETYPE
8407 || event == EVENT_SYNTAX
8408 || event == EVENT_REMOTEREPLY
8409 || event == EVENT_QUICKFIXCMDPRE
8410 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008411 fname = vim_strsave(fname);
8412 else
8413 fname = FullName_save(fname, FALSE);
8414 }
8415 if (fname == NULL) /* out of memory */
8416 {
8417 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008418 retval = FALSE;
8419 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008420 }
8421
8422#ifdef BACKSLASH_IN_FILENAME
8423 /*
8424 * Replace all backslashes with forward slashes. This makes the
8425 * autocommand patterns portable between Unix and MS-DOS.
8426 */
8427 if (sfname != NULL)
8428 forward_slash(sfname);
8429 forward_slash(fname);
8430#endif
8431
8432#ifdef VMS
8433 /* remove version for correct match */
8434 if (sfname != NULL)
8435 vms_remove_version(sfname);
8436 vms_remove_version(fname);
8437#endif
8438
8439 /*
8440 * Set the name to be used for <amatch>.
8441 */
8442 autocmd_match = fname;
8443
8444
8445 /* Don't redraw while doing auto commands. */
8446 ++RedrawingDisabled;
8447 save_sourcing_name = sourcing_name;
8448 sourcing_name = NULL; /* don't free this one */
8449 save_sourcing_lnum = sourcing_lnum;
8450 sourcing_lnum = 0; /* no line number here */
8451
8452#ifdef FEAT_EVAL
8453 save_current_SID = current_SID;
8454
Bram Moolenaar05159a02005-02-26 23:04:13 +00008455# ifdef FEAT_PROFILE
8456 if (do_profiling)
8457 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8458# endif
8459
Bram Moolenaar071d4272004-06-13 20:20:40 +00008460 /* Don't use local function variables, if called from a function */
8461 save_funccalp = save_funccal();
8462#endif
8463
8464 /*
8465 * When starting to execute autocommands, save the search patterns.
8466 */
8467 if (!autocmd_busy)
8468 {
8469 save_search_patterns();
8470 saveRedobuff();
8471 did_filetype = keep_filetype;
8472 }
8473
8474 /*
8475 * Note that we are applying autocmds. Some commands need to know.
8476 */
8477 autocmd_busy = TRUE;
8478 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8479 ++nesting; /* see matching decrement below */
8480
8481 /* Remember that FileType was triggered. Used for did_filetype(). */
8482 if (event == EVENT_FILETYPE)
8483 did_filetype = TRUE;
8484
8485 tail = gettail(fname);
8486
8487 /* Find first autocommand that matches */
8488 patcmd.curpat = first_autopat[(int)event];
8489 patcmd.nextcmd = NULL;
8490 patcmd.group = group;
8491 patcmd.fname = fname;
8492 patcmd.sfname = sfname;
8493 patcmd.tail = tail;
8494 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008495 patcmd.arg_bufnr = autocmd_bufnr;
8496 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008497 auto_next_pat(&patcmd, FALSE);
8498
8499 /* found one, start executing the autocommands */
8500 if (patcmd.curpat != NULL)
8501 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008502 /* add to active_apc_list */
8503 patcmd.next = active_apc_list;
8504 active_apc_list = &patcmd;
8505
Bram Moolenaar071d4272004-06-13 20:20:40 +00008506#ifdef FEAT_EVAL
8507 /* set v:cmdarg (only when there is a matching pattern) */
8508 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8509 if (eap != NULL)
8510 {
8511 save_cmdarg = set_cmdarg(eap, NULL);
8512 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8513 }
8514 else
8515 save_cmdarg = NULL; /* avoid gcc warning */
8516#endif
8517 retval = TRUE;
8518 /* mark the last pattern, to avoid an endless loop when more patterns
8519 * are added when executing autocommands */
8520 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8521 ap->last = FALSE;
8522 ap->last = TRUE;
8523 check_lnums(TRUE); /* make sure cursor and topline are valid */
8524 do_cmdline(NULL, getnextac, (void *)&patcmd,
8525 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8526#ifdef FEAT_EVAL
8527 if (eap != NULL)
8528 {
8529 (void)set_cmdarg(NULL, save_cmdarg);
8530 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8531 }
8532#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008533 /* delete from active_apc_list */
8534 if (active_apc_list == &patcmd) /* just in case */
8535 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008536 }
8537
8538 --RedrawingDisabled;
8539 autocmd_busy = save_autocmd_busy;
8540 filechangeshell_busy = FALSE;
8541 autocmd_nested = save_autocmd_nested;
8542 vim_free(sourcing_name);
8543 sourcing_name = save_sourcing_name;
8544 sourcing_lnum = save_sourcing_lnum;
8545 autocmd_fname = save_autocmd_fname;
8546 autocmd_bufnr = save_autocmd_bufnr;
8547 autocmd_match = save_autocmd_match;
8548#ifdef FEAT_EVAL
8549 current_SID = save_current_SID;
8550 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008551# ifdef FEAT_PROFILE
8552 if (do_profiling)
8553 prof_child_exit(&wait_time);
8554# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008555#endif
8556 vim_free(fname);
8557 vim_free(sfname);
8558 --nesting; /* see matching increment above */
8559
8560 /*
8561 * When stopping to execute autocommands, restore the search patterns and
8562 * the redo buffer.
8563 */
8564 if (!autocmd_busy)
8565 {
8566 restore_search_patterns();
8567 restoreRedobuff();
8568 did_filetype = FALSE;
8569 }
8570
8571 /*
8572 * Some events don't set or reset the Changed flag.
8573 * Check if still in the same buffer!
8574 */
8575 if (curbuf == old_curbuf
8576 && (event == EVENT_BUFREADPOST
8577 || event == EVENT_BUFWRITEPOST
8578 || event == EVENT_FILEAPPENDPOST
8579 || event == EVENT_VIMLEAVE
8580 || event == EVENT_VIMLEAVEPRE))
8581 {
8582#ifdef FEAT_TITLE
8583 if (curbuf->b_changed != save_changed)
8584 need_maketitle = TRUE;
8585#endif
8586 curbuf->b_changed = save_changed;
8587 }
8588
8589 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008590
8591BYPASS_AU:
8592 /* When wiping out a buffer make sure all its buffer-local autocommands
8593 * are deleted. */
8594 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8595 aubuflocal_remove(buf);
8596
Bram Moolenaar071d4272004-06-13 20:20:40 +00008597 return retval;
8598}
8599
8600/*
8601 * Find next autocommand pattern that matches.
8602 */
8603 static void
8604auto_next_pat(apc, stop_at_last)
8605 AutoPatCmd *apc;
8606 int stop_at_last; /* stop when 'last' flag is set */
8607{
8608 AutoPat *ap;
8609 AutoCmd *cp;
8610 char_u *name;
8611 char *s;
8612
8613 vim_free(sourcing_name);
8614 sourcing_name = NULL;
8615
8616 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8617 {
8618 apc->curpat = NULL;
8619
8620 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008621 * the group matches. For buffer-local autocommands only check the
8622 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008623 if (ap->pat != NULL && ap->cmds != NULL
8624 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8625 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008626 /* execution-condition */
8627 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008628 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8629 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008630 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008631 {
8632 name = event_nr2name(apc->event);
8633 s = _("%s Auto commands for \"%s\"");
8634 sourcing_name = alloc((unsigned)(STRLEN(s)
8635 + STRLEN(name) + ap->patlen + 1));
8636 if (sourcing_name != NULL)
8637 {
8638 sprintf((char *)sourcing_name, s,
8639 (char *)name, (char *)ap->pat);
8640 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008641 {
8642 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008643 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008644 verbose_leave();
8645 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008646 }
8647
8648 apc->curpat = ap;
8649 apc->nextcmd = ap->cmds;
8650 /* mark last command */
8651 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8652 cp->last = FALSE;
8653 cp->last = TRUE;
8654 }
8655 line_breakcheck();
8656 if (apc->curpat != NULL) /* found a match */
8657 break;
8658 }
8659 if (stop_at_last && ap->last)
8660 break;
8661 }
8662}
8663
8664/*
8665 * Get next autocommand command.
8666 * Called by do_cmdline() to get the next line for ":if".
8667 * Returns allocated string, or NULL for end of autocommands.
8668 */
8669/* ARGSUSED */
8670 static char_u *
8671getnextac(c, cookie, indent)
8672 int c; /* not used */
8673 void *cookie;
8674 int indent; /* not used */
8675{
8676 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8677 char_u *retval;
8678 AutoCmd *ac;
8679
8680 /* Can be called again after returning the last line. */
8681 if (acp->curpat == NULL)
8682 return NULL;
8683
8684 /* repeat until we find an autocommand to execute */
8685 for (;;)
8686 {
8687 /* skip removed commands */
8688 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8689 if (acp->nextcmd->last)
8690 acp->nextcmd = NULL;
8691 else
8692 acp->nextcmd = acp->nextcmd->next;
8693
8694 if (acp->nextcmd != NULL)
8695 break;
8696
8697 /* at end of commands, find next pattern that matches */
8698 if (acp->curpat->last)
8699 acp->curpat = NULL;
8700 else
8701 acp->curpat = acp->curpat->next;
8702 if (acp->curpat != NULL)
8703 auto_next_pat(acp, TRUE);
8704 if (acp->curpat == NULL)
8705 return NULL;
8706 }
8707
8708 ac = acp->nextcmd;
8709
8710 if (p_verbose >= 9)
8711 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008712 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008713 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008714 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008715 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008716 }
8717 retval = vim_strsave(ac->cmd);
8718 autocmd_nested = ac->nested;
8719#ifdef FEAT_EVAL
8720 current_SID = ac->scriptID;
8721#endif
8722 if (ac->last)
8723 acp->nextcmd = NULL;
8724 else
8725 acp->nextcmd = ac->next;
8726 return retval;
8727}
8728
8729/*
8730 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008731 * To account for buffer-local autocommands, function needs to know
8732 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008733 */
8734 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008735has_autocmd(event, sfname, buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008736 EVENT_T event;
8737 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008738 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008739{
8740 AutoPat *ap;
8741 char_u *fname;
8742 char_u *tail = gettail(sfname);
8743 int retval = FALSE;
8744
8745 fname = FullName_save(sfname, FALSE);
8746 if (fname == NULL)
8747 return FALSE;
8748
8749#ifdef BACKSLASH_IN_FILENAME
8750 /*
8751 * Replace all backslashes with forward slashes. This makes the
8752 * autocommand patterns portable between Unix and MS-DOS.
8753 */
8754 sfname = vim_strsave(sfname);
8755 if (sfname != NULL)
8756 forward_slash(sfname);
8757 forward_slash(fname);
8758#endif
8759
8760 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8761 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008762 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008763 ? match_file_pat(NULL, ap->reg_prog,
8764 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008765 : buf != NULL && ap->buflocal_nr == buf->b_fnum
8766 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008767 {
8768 retval = TRUE;
8769 break;
8770 }
8771
8772 vim_free(fname);
8773#ifdef BACKSLASH_IN_FILENAME
8774 vim_free(sfname);
8775#endif
8776
8777 return retval;
8778}
8779
8780#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8781/*
8782 * Function given to ExpandGeneric() to obtain the list of autocommand group
8783 * names.
8784 */
8785/*ARGSUSED*/
8786 char_u *
8787get_augroup_name(xp, idx)
8788 expand_T *xp;
8789 int idx;
8790{
8791 if (idx == augroups.ga_len) /* add "END" add the end */
8792 return (char_u *)"END";
8793 if (idx >= augroups.ga_len) /* end of list */
8794 return NULL;
8795 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8796 return (char_u *)"";
8797 return AUGROUP_NAME(idx); /* return a name */
8798}
8799
8800static int include_groups = FALSE;
8801
8802 char_u *
8803set_context_in_autocmd(xp, arg, doautocmd)
8804 expand_T *xp;
8805 char_u *arg;
8806 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8807{
8808 char_u *p;
8809 int group;
8810
8811 /* check for a group name, skip it if present */
8812 include_groups = FALSE;
8813 p = arg;
8814 group = au_get_grouparg(&arg);
8815 if (group == AUGROUP_ERROR)
8816 return NULL;
8817 /* If there only is a group name that's what we expand. */
8818 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8819 {
8820 arg = p;
8821 group = AUGROUP_ALL;
8822 }
8823
8824 /* skip over event name */
8825 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8826 if (*p == ',')
8827 arg = p + 1;
8828 if (*p == NUL)
8829 {
8830 if (group == AUGROUP_ALL)
8831 include_groups = TRUE;
8832 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8833 xp->xp_pattern = arg;
8834 return NULL;
8835 }
8836
8837 /* skip over pattern */
8838 arg = skipwhite(p);
8839 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8840 arg++;
8841 if (*arg)
8842 return arg; /* expand (next) command */
8843
8844 if (doautocmd)
8845 xp->xp_context = EXPAND_FILES; /* expand file names */
8846 else
8847 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8848 return NULL;
8849}
8850
8851/*
8852 * Function given to ExpandGeneric() to obtain the list of event names.
8853 */
8854/*ARGSUSED*/
8855 char_u *
8856get_event_name(xp, idx)
8857 expand_T *xp;
8858 int idx;
8859{
8860 if (idx < augroups.ga_len) /* First list group names, if wanted */
8861 {
8862 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8863 return (char_u *)""; /* skip deleted entries */
8864 return AUGROUP_NAME(idx); /* return a name */
8865 }
8866 return (char_u *)event_names[idx - augroups.ga_len].name;
8867}
8868
8869#endif /* FEAT_CMDL_COMPL */
8870
8871/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008872 * Return TRUE if autocmd is supported.
8873 */
8874 int
8875autocmd_supported(name)
8876 char_u *name;
8877{
8878 char_u *p;
8879
8880 return (event_name2nr(name, &p) != NUM_EVENTS);
8881}
8882
8883/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008884 * Return TRUE if an autocommand is defined for a group, event and
8885 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8886 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8887 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8888 * Used for:
8889 * exists("#Group") or
8890 * exists("#Group#Event") or
8891 * exists("#Group#Event#pat") or
8892 * exists("#Event") or
8893 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008894 */
8895 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008896au_exists(arg)
8897 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008898{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008899 char_u *arg_save;
8900 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008901 char_u *event_name;
8902 char_u *p;
8903 EVENT_T event;
8904 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008905 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008906 int group;
8907 int retval = FALSE;
8908
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008909 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008910 arg_save = vim_strsave(arg);
8911 if (arg_save == NULL)
8912 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008913 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008914 if (p != NULL)
8915 *p++ = NUL;
8916
8917 /* First, look for an autocmd group name */
8918 group = au_find_group(arg_save);
8919 if (group == AUGROUP_ERROR)
8920 {
8921 /* Didn't match a group name, assume the first argument is an event. */
8922 group = AUGROUP_ALL;
8923 event_name = arg_save;
8924 }
8925 else
8926 {
8927 if (p == NULL)
8928 {
8929 /* "Group": group name is present and it's recognized */
8930 retval = TRUE;
8931 goto theend;
8932 }
8933
8934 /* Must be "Group#Event" or "Group#Event#pat". */
8935 event_name = p;
8936 p = vim_strchr(event_name, '#');
8937 if (p != NULL)
8938 *p++ = NUL; /* "Group#Event#pat" */
8939 }
8940
8941 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008942
8943 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008944 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008945
8946 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008947 if (event == NUM_EVENTS)
8948 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008949
8950 /* Find the first autocommand for this event.
8951 * If there isn't any, return FALSE;
8952 * If there is one and no pattern given, return TRUE; */
8953 ap = first_autopat[(int)event];
8954 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008955 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008956 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008957 {
8958 retval = TRUE;
8959 goto theend;
8960 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008961
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008962 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
8963 /* for pattern "<buffer=N>, fnamecmp() will work fine */
8964 if (STRICMP(pattern, "<buffer>") == 0)
8965 buflocal_buf = curbuf;
8966
Bram Moolenaar071d4272004-06-13 20:20:40 +00008967 /* Check if there is an autocommand with the given pattern. */
8968 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008969 /* only use a pattern when it has not been removed and has commands. */
8970 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008971 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00008972 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008973 && (buflocal_buf == NULL
8974 ? fnamecmp(ap->pat, pattern) == 0
8975 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00008976 {
8977 retval = TRUE;
8978 break;
8979 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008980
Bram Moolenaar195d6352005-12-19 22:08:24 +00008981theend:
8982 vim_free(arg_save);
8983 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008984}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008985
Bram Moolenaar071d4272004-06-13 20:20:40 +00008986#endif /* FEAT_AUTOCMD */
8987
8988#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
8989/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00008990 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
8991 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
8992 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008993 * Used for autocommands and 'wildignore'.
8994 * Returns TRUE if there is a match, FALSE otherwise.
8995 */
8996 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00008997match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008998 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00008999 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009000 char_u *fname; /* full path of file name */
9001 char_u *sfname; /* short file name or NULL */
9002 char_u *tail; /* tail of path */
9003 int allow_dirs; /* allow matching with dir */
9004{
9005 regmatch_T regmatch;
9006 int result = FALSE;
9007#ifdef FEAT_OSFILETYPE
9008 int no_pattern = FALSE; /* TRUE if check is filetype only */
9009 char_u *type_start;
9010 char_u c;
9011 int match = FALSE;
9012#endif
9013
9014#ifdef CASE_INSENSITIVE_FILENAME
9015 regmatch.rm_ic = TRUE; /* Always ignore case */
9016#else
9017 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9018#endif
9019#ifdef FEAT_OSFILETYPE
9020 if (*pattern == '<')
9021 {
9022 /* There is a filetype condition specified with this pattern.
9023 * Check the filetype matches first. If not, don't bother with the
9024 * pattern (set regprog to NULL).
9025 * Always use magic for the regexp.
9026 */
9027
9028 for (type_start = pattern + 1; (c = *pattern); pattern++)
9029 {
9030 if ((c == ';' || c == '>') && match == FALSE)
9031 {
9032 *pattern = NUL; /* Terminate the string */
9033 match = mch_check_filetype(fname, type_start);
9034 *pattern = c; /* Restore the terminator */
9035 type_start = pattern + 1;
9036 }
9037 if (c == '>')
9038 break;
9039 }
9040
9041 /* (c should never be NUL, but check anyway) */
9042 if (match == FALSE || c == NUL)
9043 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9044 else if (*pattern == NUL)
9045 {
9046 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9047 no_pattern = TRUE; /* Always matches - don't check pat. */
9048 }
9049 else
9050 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9051 }
9052 else
9053#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009054 {
9055 if (prog != NULL)
9056 regmatch.regprog = prog;
9057 else
9058 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9059 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009060
9061 /*
9062 * Try for a match with the pattern with:
9063 * 1. the full file name, when the pattern has a '/'.
9064 * 2. the short file name, when the pattern has a '/'.
9065 * 3. the tail of the file name, when the pattern has no '/'.
9066 */
9067 if (
9068#ifdef FEAT_OSFILETYPE
9069 /* If the check is for a filetype only and we don't care
9070 * about the path then skip all the regexp stuff.
9071 */
9072 no_pattern ||
9073#endif
9074 (regmatch.regprog != NULL
9075 && ((allow_dirs
9076 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9077 || (sfname != NULL
9078 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9079 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9080 result = TRUE;
9081
Bram Moolenaar748bf032005-02-02 23:04:36 +00009082 if (prog == NULL)
9083 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009084 return result;
9085}
9086#endif
9087
9088#if defined(FEAT_WILDIGN) || defined(PROTO)
9089/*
9090 * Return TRUE if a file matches with a pattern in "list".
9091 * "list" is a comma-separated list of patterns, like 'wildignore'.
9092 * "sfname" is the short file name or NULL, "ffname" the long file name.
9093 */
9094 int
9095match_file_list(list, sfname, ffname)
9096 char_u *list;
9097 char_u *sfname;
9098 char_u *ffname;
9099{
9100 char_u buf[100];
9101 char_u *tail;
9102 char_u *regpat;
9103 char allow_dirs;
9104 int match;
9105 char_u *p;
9106
9107 tail = gettail(sfname);
9108
9109 /* try all patterns in 'wildignore' */
9110 p = list;
9111 while (*p)
9112 {
9113 copy_option_part(&p, buf, 100, ",");
9114 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9115 if (regpat == NULL)
9116 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009117 match = match_file_pat(regpat, NULL, ffname, sfname,
9118 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009119 vim_free(regpat);
9120 if (match)
9121 return TRUE;
9122 }
9123 return FALSE;
9124}
9125#endif
9126
9127/*
9128 * Convert the given pattern "pat" which has shell style wildcards in it, into
9129 * a regular expression, and return the result in allocated memory. If there
9130 * is a directory path separator to be matched, then TRUE is put in
9131 * allow_dirs, otherwise FALSE is put there -- webb.
9132 * Handle backslashes before special characters, like "\*" and "\ ".
9133 *
9134 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9135 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9136 *
9137 * Returns NULL when out of memory.
9138 */
9139/*ARGSUSED*/
9140 char_u *
9141file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9142 char_u *pat;
9143 char_u *pat_end; /* first char after pattern or NULL */
9144 char *allow_dirs; /* Result passed back out in here */
9145 int no_bslash; /* Don't use a backward slash as pathsep */
9146{
9147 int size;
9148 char_u *endp;
9149 char_u *reg_pat;
9150 char_u *p;
9151 int i;
9152 int nested = 0;
9153 int add_dollar = TRUE;
9154#ifdef FEAT_OSFILETYPE
9155 int check_length = 0;
9156#endif
9157
9158 if (allow_dirs != NULL)
9159 *allow_dirs = FALSE;
9160 if (pat_end == NULL)
9161 pat_end = pat + STRLEN(pat);
9162
9163#ifdef FEAT_OSFILETYPE
9164 /* Find out how much of the string is the filetype check */
9165 if (*pat == '<')
9166 {
9167 /* Count chars until the next '>' */
9168 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9169 ;
9170 if (p < pat_end)
9171 {
9172 /* Pattern is of the form <.*>.* */
9173 check_length = p - pat + 1;
9174 if (p + 1 >= pat_end)
9175 {
9176 /* The 'pattern' is a filetype check ONLY */
9177 reg_pat = (char_u *)alloc(check_length + 1);
9178 if (reg_pat != NULL)
9179 {
9180 mch_memmove(reg_pat, pat, (size_t)check_length);
9181 reg_pat[check_length] = NUL;
9182 }
9183 return reg_pat;
9184 }
9185 }
9186 /* else: there was no closing '>' - assume it was a normal pattern */
9187
9188 }
9189 pat += check_length;
9190 size = 2 + check_length;
9191#else
9192 size = 2; /* '^' at start, '$' at end */
9193#endif
9194
9195 for (p = pat; p < pat_end; p++)
9196 {
9197 switch (*p)
9198 {
9199 case '*':
9200 case '.':
9201 case ',':
9202 case '{':
9203 case '}':
9204 case '~':
9205 size += 2; /* extra backslash */
9206 break;
9207#ifdef BACKSLASH_IN_FILENAME
9208 case '\\':
9209 case '/':
9210 size += 4; /* could become "[\/]" */
9211 break;
9212#endif
9213 default:
9214 size++;
9215# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009216 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009217 {
9218 ++p;
9219 ++size;
9220 }
9221# endif
9222 break;
9223 }
9224 }
9225 reg_pat = alloc(size + 1);
9226 if (reg_pat == NULL)
9227 return NULL;
9228
9229#ifdef FEAT_OSFILETYPE
9230 /* Copy the type check in to the start. */
9231 if (check_length)
9232 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9233 i = check_length;
9234#else
9235 i = 0;
9236#endif
9237
9238 if (pat[0] == '*')
9239 while (pat[0] == '*' && pat < pat_end - 1)
9240 pat++;
9241 else
9242 reg_pat[i++] = '^';
9243 endp = pat_end - 1;
9244 if (*endp == '*')
9245 {
9246 while (endp - pat > 0 && *endp == '*')
9247 endp--;
9248 add_dollar = FALSE;
9249 }
9250 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9251 {
9252 switch (*p)
9253 {
9254 case '*':
9255 reg_pat[i++] = '.';
9256 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009257 while (p[1] == '*') /* "**" matches like "*" */
9258 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009259 break;
9260 case '.':
9261#ifdef RISCOS
9262 if (allow_dirs != NULL)
9263 *allow_dirs = TRUE;
9264 /* FALLTHROUGH */
9265#endif
9266 case '~':
9267 reg_pat[i++] = '\\';
9268 reg_pat[i++] = *p;
9269 break;
9270 case '?':
9271#ifdef RISCOS
9272 case '#':
9273#endif
9274 reg_pat[i++] = '.';
9275 break;
9276 case '\\':
9277 if (p[1] == NUL)
9278 break;
9279#ifdef BACKSLASH_IN_FILENAME
9280 if (!no_bslash)
9281 {
9282 /* translate:
9283 * "\x" to "\\x" e.g., "dir\file"
9284 * "\*" to "\\.*" e.g., "dir\*.c"
9285 * "\?" to "\\." e.g., "dir\??.c"
9286 * "\+" to "\+" e.g., "fileX\+.c"
9287 */
9288 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9289 && p[1] != '+')
9290 {
9291 reg_pat[i++] = '[';
9292 reg_pat[i++] = '\\';
9293 reg_pat[i++] = '/';
9294 reg_pat[i++] = ']';
9295 if (allow_dirs != NULL)
9296 *allow_dirs = TRUE;
9297 break;
9298 }
9299 }
9300#endif
9301 if (*++p == '?'
9302#ifdef BACKSLASH_IN_FILENAME
9303 && no_bslash
9304#endif
9305 )
9306 reg_pat[i++] = '?';
9307 else
9308 if (*p == ',')
9309 reg_pat[i++] = ',';
9310 else
9311 {
9312 if (allow_dirs != NULL && vim_ispathsep(*p)
9313#ifdef BACKSLASH_IN_FILENAME
9314 && (!no_bslash || *p != '\\')
9315#endif
9316 )
9317 *allow_dirs = TRUE;
9318 reg_pat[i++] = '\\';
9319 reg_pat[i++] = *p;
9320 }
9321 break;
9322#ifdef BACKSLASH_IN_FILENAME
9323 case '/':
9324 reg_pat[i++] = '[';
9325 reg_pat[i++] = '\\';
9326 reg_pat[i++] = '/';
9327 reg_pat[i++] = ']';
9328 if (allow_dirs != NULL)
9329 *allow_dirs = TRUE;
9330 break;
9331#endif
9332 case '{':
9333 reg_pat[i++] = '\\';
9334 reg_pat[i++] = '(';
9335 nested++;
9336 break;
9337 case '}':
9338 reg_pat[i++] = '\\';
9339 reg_pat[i++] = ')';
9340 --nested;
9341 break;
9342 case ',':
9343 if (nested)
9344 {
9345 reg_pat[i++] = '\\';
9346 reg_pat[i++] = '|';
9347 }
9348 else
9349 reg_pat[i++] = ',';
9350 break;
9351 default:
9352# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009353 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009354 reg_pat[i++] = *p++;
9355 else
9356# endif
9357 if (allow_dirs != NULL && vim_ispathsep(*p))
9358 *allow_dirs = TRUE;
9359 reg_pat[i++] = *p;
9360 break;
9361 }
9362 }
9363 if (add_dollar)
9364 reg_pat[i++] = '$';
9365 reg_pat[i] = NUL;
9366 if (nested != 0)
9367 {
9368 if (nested < 0)
9369 EMSG(_("E219: Missing {."));
9370 else
9371 EMSG(_("E220: Missing }."));
9372 vim_free(reg_pat);
9373 reg_pat = NULL;
9374 }
9375 return reg_pat;
9376}