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