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