blob: 42181e17b22fa9afc7cf2be75b74a9d61058bd88 [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)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000015# include "vimio.h" /* for lseek(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#if defined __EMX__
Bram Moolenaar362e1a32006-03-06 23:29:24 +000019# include "vimio.h" /* for mktemp(), CJW 1997-12-03 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000020#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);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000220 int set_options = newfile || (eap != NULL && eap->read_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221 int check_readonly;
222 int filtering = (flags & READ_FILTER);
223 int read_stdin = (flags & READ_STDIN);
224 int read_buffer = (flags & READ_BUFFER);
225 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
226 colnr_T read_buf_col = 0; /* next char to read from this line */
227 char_u c;
228 linenr_T lnum = from;
229 char_u *ptr = NULL; /* pointer into read buffer */
230 char_u *buffer = NULL; /* read buffer */
231 char_u *new_buffer = NULL; /* init to shut up gcc */
232 char_u *line_start = NULL; /* init to shut up gcc */
233 int wasempty; /* buffer was empty before reading */
234 colnr_T len;
235 long size = 0;
236 char_u *p;
237 long filesize = 0;
238 int skip_read = FALSE;
239#ifdef FEAT_CRYPT
240 char_u *cryptkey = NULL;
241#endif
242 int split = 0; /* number of split lines */
243#define UNKNOWN 0x0fffffff /* file size is unknown */
244 linenr_T linecnt;
245 int error = FALSE; /* errors encountered */
246 int ff_error = EOL_UNKNOWN; /* file format with errors */
247 long linerest = 0; /* remaining chars in line */
248#ifdef UNIX
249 int perm = 0;
250 int swap_mode = -1; /* protection bits for swap file */
251#else
252 int perm;
253#endif
254 int fileformat = 0; /* end-of-line format */
255 int keep_fileformat = FALSE;
256 struct stat st;
257 int file_readonly;
258 linenr_T skip_count = 0;
259 linenr_T read_count = 0;
260 int msg_save = msg_scroll;
261 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
262 * last read was missing the eol */
263 int try_mac = (vim_strchr(p_ffs, 'm') != NULL);
264 int try_dos = (vim_strchr(p_ffs, 'd') != NULL);
265 int try_unix = (vim_strchr(p_ffs, 'x') != NULL);
266 int file_rewind = FALSE;
267#ifdef FEAT_MBYTE
268 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000269 linenr_T conv_error = 0; /* line nr with conversion error */
270 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
272 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000273 int bad_char_behavior = BAD_REPLACE;
274 /* BAD_KEEP, BAD_DROP or character to
275 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 char_u *tmpname = NULL; /* name of 'charconvert' output file */
277 int fio_flags = 0;
278 char_u *fenc; /* fileencoding to use */
279 int fenc_alloced; /* fenc_next is in allocated memory */
280 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
281 int advance_fenc = FALSE;
282 long real_size = 0;
283# ifdef USE_ICONV
284 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
285# ifdef FEAT_EVAL
286 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
287 'charconvert' next */
288# endif
289# endif
290 int converted = FALSE; /* TRUE if conversion done */
291 int notconverted = FALSE; /* TRUE if conversion wanted but it
292 wasn't possible */
293 char_u conv_rest[CONV_RESTLEN];
294 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
295#endif
296
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297 write_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298
299 /*
300 * If there is no file name yet, use the one for the read file.
301 * BF_NOTEDITED is set to reflect this.
302 * Don't do this for a read from a filter.
303 * Only do this when 'cpoptions' contains the 'f' flag.
304 */
305 if (curbuf->b_ffname == NULL
306 && !filtering
307 && fname != NULL
308 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
309 && !(flags & READ_DUMMY))
310 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000311 if (set_rw_fname(fname, sfname) == FAIL)
312 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313 }
314
Bram Moolenaardf177f62005-02-22 08:39:57 +0000315 /* After reading a file the cursor line changes but we don't want to
316 * display the line. */
317 ex_no_reprint = TRUE;
318
Bram Moolenaar55b7cf82006-09-09 12:52:42 +0000319 /* don't display the file info for another buffer now */
320 need_fileinfo = FALSE;
321
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 /*
323 * For Unix: Use the short file name whenever possible.
324 * Avoids problems with networks and when directory names are changed.
325 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
326 * another directory, which we don't detect.
327 */
328 if (sfname == NULL)
329 sfname = fname;
330#if defined(UNIX) || defined(__EMX__)
331 fname = sfname;
332#endif
333
334#ifdef FEAT_AUTOCMD
335 /*
336 * The BufReadCmd and FileReadCmd events intercept the reading process by
337 * executing the associated commands instead.
338 */
339 if (!filtering && !read_stdin && !read_buffer)
340 {
341 pos_T pos;
342
343 pos = curbuf->b_op_start;
344
345 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
346 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
347 curbuf->b_op_start.col = 0;
348
349 if (newfile)
350 {
351 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
352 FALSE, curbuf, eap))
353#ifdef FEAT_EVAL
354 return aborting() ? FAIL : OK;
355#else
356 return OK;
357#endif
358 }
359 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
360 FALSE, NULL, eap))
361#ifdef FEAT_EVAL
362 return aborting() ? FAIL : OK;
363#else
364 return OK;
365#endif
366
367 curbuf->b_op_start = pos;
368 }
369#endif
370
371 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
372 msg_scroll = FALSE; /* overwrite previous file message */
373 else
374 msg_scroll = TRUE; /* don't overwrite previous file message */
375
376 /*
377 * If the name ends in a path separator, we can't open it. Check here,
378 * because reading the file may actually work, but then creating the swap
379 * file may destroy it! Reported on MS-DOS and Win 95.
380 * If the name is too long we might crash further on, quit here.
381 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000382 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000384 p = fname + STRLEN(fname);
385 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000386 {
387 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
388 msg_end();
389 msg_scroll = msg_save;
390 return FAIL;
391 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 }
393
394#ifdef UNIX
395 /*
396 * On Unix it is possible to read a directory, so we have to
397 * check for it before the mch_open().
398 */
399 if (!read_stdin && !read_buffer)
400 {
401 perm = mch_getperm(fname);
402 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
403# ifdef S_ISFIFO
404 && !S_ISFIFO(perm) /* ... or fifo */
405# endif
406# ifdef S_ISSOCK
407 && !S_ISSOCK(perm) /* ... or socket */
408# endif
409 )
410 {
411 if (S_ISDIR(perm))
412 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
413 else
414 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
415 msg_end();
416 msg_scroll = msg_save;
417 return FAIL;
418 }
419 }
420#endif
421
422 /* set default 'fileformat' */
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000423 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 {
425 if (eap != NULL && eap->force_ff != 0)
426 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
427 else if (*p_ffs != NUL)
428 set_fileformat(default_fileformat(), OPT_LOCAL);
429 }
430
431 /* set or reset 'binary' */
432 if (eap != NULL && eap->force_bin != 0)
433 {
434 int oldval = curbuf->b_p_bin;
435
436 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
437 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
438 }
439
440 /*
441 * When opening a new file we take the readonly flag from the file.
442 * Default is r/w, can be set to r/o below.
443 * Don't reset it when in readonly mode
444 * Only set/reset b_p_ro when BF_CHECK_RO is set.
445 */
446 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000447 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448 curbuf->b_p_ro = FALSE;
449
450 if (newfile && !read_stdin && !read_buffer)
451 {
452 /* Remember time of file.
453 * For RISCOS, also remember the filetype.
454 */
455 if (mch_stat((char *)fname, &st) >= 0)
456 {
457 buf_store_time(curbuf, &st, fname);
458 curbuf->b_mtime_read = curbuf->b_mtime;
459
460#if defined(RISCOS) && defined(FEAT_OSFILETYPE)
461 /* Read the filetype into the buffer local filetype option. */
462 mch_read_filetype(fname);
463#endif
464#ifdef UNIX
465 /*
466 * Use the protection bits of the original file for the swap file.
467 * This makes it possible for others to read the name of the
468 * edited file from the swapfile, but only if they can read the
469 * edited file.
470 * Remove the "write" and "execute" bits for group and others
471 * (they must not write the swapfile).
472 * Add the "read" and "write" bits for the user, otherwise we may
473 * not be able to write to the file ourselves.
474 * Setting the bits is done below, after creating the swap file.
475 */
476 swap_mode = (st.st_mode & 0644) | 0600;
477#endif
478#ifdef FEAT_CW_EDITOR
479 /* Get the FSSpec on MacOS
480 * TODO: Update it properly when the buffer name changes
481 */
482 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
483#endif
484#ifdef VMS
485 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000486 curbuf->b_fab_rat = st.st_fab_rat;
487 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488#endif
489 }
490 else
491 {
492 curbuf->b_mtime = 0;
493 curbuf->b_mtime_read = 0;
494 curbuf->b_orig_size = 0;
495 curbuf->b_orig_mode = 0;
496 }
497
498 /* Reset the "new file" flag. It will be set again below when the
499 * file doesn't exist. */
500 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
501 }
502
503/*
504 * for UNIX: check readonly with perm and mch_access()
505 * for RISCOS: same as Unix, otherwise file gets re-datestamped!
506 * for MSDOS and Amiga: check readonly by trying to open the file for writing
507 */
508 file_readonly = FALSE;
509 if (read_stdin)
510 {
511#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
512 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
513 setmode(0, O_BINARY);
514#endif
515 }
516 else if (!read_buffer)
517 {
518#ifdef USE_MCH_ACCESS
519 if (
520# ifdef UNIX
521 !(perm & 0222) ||
522# endif
523 mch_access((char *)fname, W_OK))
524 file_readonly = TRUE;
525 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
526#else
527 if (!newfile
528 || readonlymode
529 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
530 {
531 file_readonly = TRUE;
532 /* try to open ro */
533 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
534 }
535#endif
536 }
537
538 if (fd < 0) /* cannot open at all */
539 {
540#ifndef UNIX
541 int isdir_f;
542#endif
543 msg_scroll = msg_save;
544#ifndef UNIX
545 /*
546 * On MSDOS and Amiga we can't open a directory, check here.
547 */
548 isdir_f = (mch_isdir(fname));
549 perm = mch_getperm(fname); /* check if the file exists */
550 if (isdir_f)
551 {
552 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
553 curbuf->b_p_ro = TRUE; /* must use "w!" now */
554 }
555 else
556#endif
557 if (newfile)
558 {
559 if (perm < 0)
560 {
561 /*
562 * Set the 'new-file' flag, so that when the file has
563 * been created by someone else, a ":w" will complain.
564 */
565 curbuf->b_flags |= BF_NEW;
566
567 /* Create a swap file now, so that other Vims are warned
568 * that we are editing this file. Don't do this for a
569 * "nofile" or "nowrite" buffer type. */
570#ifdef FEAT_QUICKFIX
571 if (!bt_dontwrite(curbuf))
572#endif
573 check_need_swap(newfile);
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000574 if (dir_of_file_exists(fname))
575 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
576 else
577 filemess(curbuf, sfname,
578 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579#ifdef FEAT_VIMINFO
580 /* Even though this is a new file, it might have been
581 * edited before and deleted. Get the old marks. */
582 check_marks_read();
583#endif
584#ifdef FEAT_MBYTE
585 if (eap != NULL && eap->force_enc != 0)
586 {
587 /* set forced 'fileencoding' */
588 fenc = enc_canonize(eap->cmd + eap->force_enc);
589 if (fenc != NULL)
590 set_string_option_direct((char_u *)"fenc", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000591 fenc, OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 vim_free(fenc);
593 }
594#endif
595#ifdef FEAT_AUTOCMD
596 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
597 FALSE, curbuf, eap);
598#endif
599 /* remember the current fileformat */
600 save_file_ff(curbuf);
601
602#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
603 if (aborting()) /* autocmds may abort script processing */
604 return FAIL;
605#endif
606 return OK; /* a new file is not an error */
607 }
608 else
609 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000610 filemess(curbuf, sfname, (char_u *)(
611# ifdef EFBIG
612 (errno == EFBIG) ? _("[File too big]") :
613# endif
614 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 curbuf->b_p_ro = TRUE; /* must use "w!" now */
616 }
617 }
618
619 return FAIL;
620 }
621
622 /*
623 * Only set the 'ro' flag for readonly files the first time they are
624 * loaded. Help files always get readonly mode
625 */
626 if ((check_readonly && file_readonly) || curbuf->b_help)
627 curbuf->b_p_ro = TRUE;
628
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000629 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 {
631 curbuf->b_p_eol = TRUE;
632 curbuf->b_start_eol = TRUE;
633#ifdef FEAT_MBYTE
634 curbuf->b_p_bomb = FALSE;
635#endif
636 }
637
638 /* Create a swap file now, so that other Vims are warned that we are
639 * editing this file.
640 * Don't do this for a "nofile" or "nowrite" buffer type. */
641#ifdef FEAT_QUICKFIX
642 if (!bt_dontwrite(curbuf))
643#endif
644 {
645 check_need_swap(newfile);
646#ifdef UNIX
647 /* Set swap file protection bits after creating it. */
648 if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
649 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
650#endif
651 }
652
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000653#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654 /* If "Quit" selected at ATTENTION dialog, don't load the file */
655 if (swap_exists_action == SEA_QUIT)
656 {
657 if (!read_buffer && !read_stdin)
658 close(fd);
659 return FAIL;
660 }
661#endif
662
663 ++no_wait_return; /* don't wait for return yet */
664
665 /*
666 * Set '[ mark to the line above where the lines go (line 1 if zero).
667 */
668 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
669 curbuf->b_op_start.col = 0;
670
671#ifdef FEAT_AUTOCMD
672 if (!read_buffer)
673 {
674 int m = msg_scroll;
675 int n = msg_scrolled;
676 buf_T *old_curbuf = curbuf;
677
678 /*
679 * The file must be closed again, the autocommands may want to change
680 * the file before reading it.
681 */
682 if (!read_stdin)
683 close(fd); /* ignore errors */
684
685 /*
686 * The output from the autocommands should not overwrite anything and
687 * should not be overwritten: Set msg_scroll, restore its value if no
688 * output was done.
689 */
690 msg_scroll = TRUE;
691 if (filtering)
692 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
693 FALSE, curbuf, eap);
694 else if (read_stdin)
695 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
696 FALSE, curbuf, eap);
697 else if (newfile)
698 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
699 FALSE, curbuf, eap);
700 else
701 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
702 FALSE, NULL, eap);
703 if (msg_scrolled == n)
704 msg_scroll = m;
705
706#ifdef FEAT_EVAL
707 if (aborting()) /* autocmds may abort script processing */
708 {
709 --no_wait_return;
710 msg_scroll = msg_save;
711 curbuf->b_p_ro = TRUE; /* must use "w!" now */
712 return FAIL;
713 }
714#endif
715 /*
716 * Don't allow the autocommands to change the current buffer.
717 * Try to re-open the file.
718 */
719 if (!read_stdin && (curbuf != old_curbuf
720 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
721 {
722 --no_wait_return;
723 msg_scroll = msg_save;
724 if (fd < 0)
725 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
726 else
727 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
728 curbuf->b_p_ro = TRUE; /* must use "w!" now */
729 return FAIL;
730 }
731 }
732#endif /* FEAT_AUTOCMD */
733
734 /* Autocommands may add lines to the file, need to check if it is empty */
735 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
736
737 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
738 {
739 /*
740 * Show the user that we are busy reading the input. Sometimes this
741 * may take a while. When reading from stdin another program may
742 * still be running, don't move the cursor to the last line, unless
743 * always using the GUI.
744 */
745 if (read_stdin)
746 {
747#ifndef ALWAYS_USE_GUI
748 mch_msg(_("Vim: Reading from stdin...\n"));
749#endif
750#ifdef FEAT_GUI
751 /* Also write a message in the GUI window, if there is one. */
752 if (gui.in_use && !gui.dying && !gui.starting)
753 {
754 p = (char_u *)_("Reading from stdin...");
755 gui_write(p, (int)STRLEN(p));
756 }
757#endif
758 }
759 else if (!read_buffer)
760 filemess(curbuf, sfname, (char_u *)"", 0);
761 }
762
763 msg_scroll = FALSE; /* overwrite the file message */
764
765 /*
766 * Set linecnt now, before the "retry" caused by a wrong guess for
767 * fileformat, and after the autocommands, which may change them.
768 */
769 linecnt = curbuf->b_ml.ml_line_count;
770
771#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000772 /* "++bad=" argument. */
773 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000774 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000775 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000776 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000777 curbuf->b_bad_char = eap->bad_char;
778 }
779 else
780 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000781
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000783 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 */
785 if (eap != NULL && eap->force_enc != 0)
786 {
787 fenc = enc_canonize(eap->cmd + eap->force_enc);
788 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000789 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 }
791 else if (curbuf->b_p_bin)
792 {
793 fenc = (char_u *)""; /* binary: don't convert */
794 fenc_alloced = FALSE;
795 }
796 else if (curbuf->b_help)
797 {
798 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000799 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800
801 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
802 * fails it must be latin1.
803 * Always do this when 'encoding' is "utf-8". Otherwise only do
804 * this when needed to avoid [converted] remarks all the time.
805 * It is needed when the first line contains non-ASCII characters.
806 * That is only in *.??x files. */
807 fenc = (char_u *)"latin1";
808 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000809 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000811 fc = fname[STRLEN(fname) - 1];
812 if (TOLOWER_ASC(fc) == 'x')
813 {
814 /* Read the first line (and a bit more). Immediately rewind to
815 * the start of the file. If the read() fails "len" is -1. */
816 len = vim_read(fd, firstline, 80);
817 lseek(fd, (off_t)0L, SEEK_SET);
818 for (p = firstline; p < firstline + len; ++p)
819 if (*p >= 0x80)
820 {
821 c = TRUE;
822 break;
823 }
824 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 }
826
827 if (c)
828 {
829 fenc_next = fenc;
830 fenc = (char_u *)"utf-8";
831
832 /* When the file is utf-8 but a character doesn't fit in
833 * 'encoding' don't retry. In help text editing utf-8 bytes
834 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000835 if (!enc_utf8)
836 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 }
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
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000892 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 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
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001120 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 {
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 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001150 real_size = (int)size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151# 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. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001207 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208 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 */
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001266# ifdef USE_ICONV
1267 if (iconv_fd != (iconv_t)-1)
1268 {
1269 iconv_close(iconv_fd);
1270 iconv_fd = (iconv_t)-1;
1271 }
1272# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001273 if (bad_char_behavior == BAD_KEEP)
1274 {
1275 /* Keep the trailing bytes as-is. */
1276 size = conv_restlen;
1277 ptr -= conv_restlen;
1278 }
1279 else
1280 {
1281 /* Replace the trailing bytes with the
1282 * replacement character. */
1283 size = 1;
1284 *--ptr = bad_char_behavior;
1285 }
1286 conv_restlen = 0;
1287 }
1288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289#endif
1290 }
1291
1292#ifdef FEAT_CRYPT
1293 /*
1294 * At start of file: Check for magic number of encryption.
1295 */
1296 if (filesize == 0)
1297 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1298 &filesize, newfile);
1299 /*
1300 * Decrypt the read bytes.
1301 */
1302 if (cryptkey != NULL && size > 0)
1303 for (p = ptr; p < ptr + size; ++p)
1304 ZDECODE(*p);
1305#endif
1306 }
1307 skip_read = FALSE;
1308
1309#ifdef FEAT_MBYTE
1310 /*
1311 * At start of file (or after crypt magic number): Check for BOM.
1312 * Also check for a BOM for other Unicode encodings, but not after
1313 * converting with 'charconvert' or when a BOM has already been
1314 * found.
1315 */
1316 if ((filesize == 0
1317# ifdef FEAT_CRYPT
1318 || (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
1319# endif
1320 )
1321 && (fio_flags == FIO_UCSBOM
1322 || (!curbuf->b_p_bomb
1323 && tmpname == NULL
1324 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1325 {
1326 char_u *ccname;
1327 int blen;
1328
1329 /* no BOM detection in a short file or in binary mode */
1330 if (size < 2 || curbuf->b_p_bin)
1331 ccname = NULL;
1332 else
1333 ccname = check_for_bom(ptr, size, &blen,
1334 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1335 if (ccname != NULL)
1336 {
1337 /* Remove BOM from the text */
1338 filesize += blen;
1339 size -= blen;
1340 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001341 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 curbuf->b_p_bomb = TRUE;
1343 }
1344
1345 if (fio_flags == FIO_UCSBOM)
1346 {
1347 if (ccname == NULL)
1348 {
1349 /* No BOM detected: retry with next encoding. */
1350 advance_fenc = TRUE;
1351 }
1352 else
1353 {
1354 /* BOM detected: set "fenc" and jump back */
1355 if (fenc_alloced)
1356 vim_free(fenc);
1357 fenc = ccname;
1358 fenc_alloced = FALSE;
1359 }
1360 /* retry reading without getting new bytes or rewinding */
1361 skip_read = TRUE;
1362 goto retry;
1363 }
1364 }
1365#endif
1366 /*
1367 * Break here for a read error or end-of-file.
1368 */
1369 if (size <= 0)
1370 break;
1371
1372#ifdef FEAT_MBYTE
1373
1374 /* Include not converted bytes. */
1375 ptr -= conv_restlen;
1376 size += conv_restlen;
1377 conv_restlen = 0;
1378
1379# ifdef USE_ICONV
1380 if (iconv_fd != (iconv_t)-1)
1381 {
1382 /*
1383 * Attempt conversion of the read bytes to 'encoding' using
1384 * iconv().
1385 */
1386 const char *fromp;
1387 char *top;
1388 size_t from_size;
1389 size_t to_size;
1390
1391 fromp = (char *)ptr;
1392 from_size = size;
1393 ptr += size;
1394 top = (char *)ptr;
1395 to_size = real_size - size;
1396
1397 /*
1398 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001399 * another conversion. Except for when there is no
1400 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001402 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1403 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1405 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001406 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001407 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001408 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001409 if (conv_error == 0)
1410 conv_error = readfile_linenr(linecnt,
1411 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001412
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001413 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001414 ++fromp;
1415 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001416 if (bad_char_behavior == BAD_KEEP)
1417 {
1418 *top++ = *(fromp - 1);
1419 --to_size;
1420 }
1421 else if (bad_char_behavior != BAD_DROP)
1422 {
1423 *top++ = bad_char_behavior;
1424 --to_size;
1425 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001426 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427
1428 if (from_size > 0)
1429 {
1430 /* Some remaining characters, keep them for the next
1431 * round. */
1432 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1433 conv_restlen = (int)from_size;
1434 }
1435
1436 /* move the linerest to before the converted characters */
1437 line_start = ptr - linerest;
1438 mch_memmove(line_start, buffer, (size_t)linerest);
1439 size = (long)((char_u *)top - ptr);
1440 }
1441# endif
1442
1443# ifdef WIN3264
1444 if (fio_flags & FIO_CODEPAGE)
1445 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001446 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001447 WCHAR ucs2buf[3];
1448 int ucs2len;
1449 int codepage = FIO_GET_CP(fio_flags);
1450 int bytelen;
1451 int found_bad;
1452 char replstr[2];
1453
Bram Moolenaar071d4272004-06-13 20:20:40 +00001454 /*
1455 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001456 * a codepage, using standard MS-Windows functions. This
1457 * requires two steps:
1458 * 1. convert from 'fileencoding' to ucs-2
1459 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001461 * Because there may be illegal bytes AND an incomplete byte
1462 * sequence at the end, we may have to do the conversion one
1463 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001464 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001466 /* Replacement string for WideCharToMultiByte(). */
1467 if (bad_char_behavior > 0)
1468 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001470 replstr[0] = '?';
1471 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472
1473 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001474 * Move the bytes to the end of the buffer, so that we have
1475 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001477 src = ptr + real_size - size;
1478 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001479
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001480 /*
1481 * Do the conversion.
1482 */
1483 dst = ptr;
1484 size = size;
1485 while (size > 0)
1486 {
1487 found_bad = FALSE;
1488
1489# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1490 if (codepage == CP_UTF8)
1491 {
1492 /* Handle CP_UTF8 input ourselves to be able to handle
1493 * trailing bytes properly.
1494 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001495 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001496 if (bytelen > size)
1497 {
1498 /* Only got some bytes of a character. Normally
1499 * it's put in "conv_rest", but if it's too long
1500 * deal with it as if they were illegal bytes. */
1501 if (bytelen <= CONV_RESTLEN)
1502 break;
1503
1504 /* weird overlong byte sequence */
1505 bytelen = size;
1506 found_bad = TRUE;
1507 }
1508 else
1509 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001510 int u8c = utf_ptr2char(src);
1511
Bram Moolenaar86e01082005-12-29 22:45:34 +00001512 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001513 found_bad = TRUE;
1514 ucs2buf[0] = u8c;
1515 ucs2len = 1;
1516 }
1517 }
1518 else
1519# endif
1520 {
1521 /* We don't know how long the byte sequence is, try
1522 * from one to three bytes. */
1523 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1524 ++bytelen)
1525 {
1526 ucs2len = MultiByteToWideChar(codepage,
1527 MB_ERR_INVALID_CHARS,
1528 (LPCSTR)src, bytelen,
1529 ucs2buf, 3);
1530 if (ucs2len > 0)
1531 break;
1532 }
1533 if (ucs2len == 0)
1534 {
1535 /* If we have only one byte then it's probably an
1536 * incomplete byte sequence. Otherwise discard
1537 * one byte as a bad character. */
1538 if (size == 1)
1539 break;
1540 found_bad = TRUE;
1541 bytelen = 1;
1542 }
1543 }
1544
1545 if (!found_bad)
1546 {
1547 int i;
1548
1549 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1550 if (enc_utf8)
1551 {
1552 /* From UCS-2 to UTF-8. Cannot fail. */
1553 for (i = 0; i < ucs2len; ++i)
1554 dst += utf_char2bytes(ucs2buf[i], dst);
1555 }
1556 else
1557 {
1558 BOOL bad = FALSE;
1559 int dstlen;
1560
1561 /* From UCS-2 to "enc_codepage". If the
1562 * conversion uses the default character "?",
1563 * the data doesn't fit in this encoding. */
1564 dstlen = WideCharToMultiByte(enc_codepage, 0,
1565 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001566 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001567 replstr, &bad);
1568 if (bad)
1569 found_bad = TRUE;
1570 else
1571 dst += dstlen;
1572 }
1573 }
1574
1575 if (found_bad)
1576 {
1577 /* Deal with bytes we can't convert. */
1578 if (can_retry)
1579 goto rewind_retry;
1580 if (conv_error == 0)
1581 conv_error = readfile_linenr(linecnt, ptr, dst);
1582 if (bad_char_behavior != BAD_DROP)
1583 {
1584 if (bad_char_behavior == BAD_KEEP)
1585 {
1586 mch_memmove(dst, src, bytelen);
1587 dst += bytelen;
1588 }
1589 else
1590 *dst++ = bad_char_behavior;
1591 }
1592 }
1593
1594 src += bytelen;
1595 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001597
1598 if (size > 0)
1599 {
1600 /* An incomplete byte sequence remaining. */
1601 mch_memmove(conv_rest, src, size);
1602 conv_restlen = size;
1603 }
1604
1605 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001606 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607 }
1608 else
1609# endif
Bram Moolenaar56718732006-03-15 22:53:57 +00001610# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611 if (fio_flags & FIO_MACROMAN)
1612 {
1613 /*
1614 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001615 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001617 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 }
1620 else
1621# endif
1622 if (fio_flags != 0)
1623 {
1624 int u8c;
1625 char_u *dest;
1626 char_u *tail = NULL;
1627
1628 /*
1629 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1630 * "enc_utf8" not set: Convert Unicode to Latin1.
1631 * Go from end to start through the buffer, because the number
1632 * of bytes may increase.
1633 * "dest" points to after where the UTF-8 bytes go, "p" points
1634 * to after the next character to convert.
1635 */
1636 dest = ptr + real_size;
1637 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1638 {
1639 p = ptr + size;
1640 if (fio_flags == FIO_UTF8)
1641 {
1642 /* Check for a trailing incomplete UTF-8 sequence */
1643 tail = ptr + size - 1;
1644 while (tail > ptr && (*tail & 0xc0) == 0x80)
1645 --tail;
1646 if (tail + utf_byte2len(*tail) <= ptr + size)
1647 tail = NULL;
1648 else
1649 p = tail;
1650 }
1651 }
1652 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1653 {
1654 /* Check for a trailing byte */
1655 p = ptr + (size & ~1);
1656 if (size & 1)
1657 tail = p;
1658 if ((fio_flags & FIO_UTF16) && p > ptr)
1659 {
1660 /* Check for a trailing leading word */
1661 if (fio_flags & FIO_ENDIAN_L)
1662 {
1663 u8c = (*--p << 8);
1664 u8c += *--p;
1665 }
1666 else
1667 {
1668 u8c = *--p;
1669 u8c += (*--p << 8);
1670 }
1671 if (u8c >= 0xd800 && u8c <= 0xdbff)
1672 tail = p;
1673 else
1674 p += 2;
1675 }
1676 }
1677 else /* FIO_UCS4 */
1678 {
1679 /* Check for trailing 1, 2 or 3 bytes */
1680 p = ptr + (size & ~3);
1681 if (size & 3)
1682 tail = p;
1683 }
1684
1685 /* If there is a trailing incomplete sequence move it to
1686 * conv_rest[]. */
1687 if (tail != NULL)
1688 {
1689 conv_restlen = (int)((ptr + size) - tail);
1690 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1691 size -= conv_restlen;
1692 }
1693
1694
1695 while (p > ptr)
1696 {
1697 if (fio_flags & FIO_LATIN1)
1698 u8c = *--p;
1699 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1700 {
1701 if (fio_flags & FIO_ENDIAN_L)
1702 {
1703 u8c = (*--p << 8);
1704 u8c += *--p;
1705 }
1706 else
1707 {
1708 u8c = *--p;
1709 u8c += (*--p << 8);
1710 }
1711 if ((fio_flags & FIO_UTF16)
1712 && u8c >= 0xdc00 && u8c <= 0xdfff)
1713 {
1714 int u16c;
1715
1716 if (p == ptr)
1717 {
1718 /* Missing leading word. */
1719 if (can_retry)
1720 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001721 if (conv_error == 0)
1722 conv_error = readfile_linenr(linecnt,
1723 ptr, p);
1724 if (bad_char_behavior == BAD_DROP)
1725 continue;
1726 if (bad_char_behavior != BAD_KEEP)
1727 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 }
1729
1730 /* found second word of double-word, get the first
1731 * word and compute the resulting character */
1732 if (fio_flags & FIO_ENDIAN_L)
1733 {
1734 u16c = (*--p << 8);
1735 u16c += *--p;
1736 }
1737 else
1738 {
1739 u16c = *--p;
1740 u16c += (*--p << 8);
1741 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001742 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1743 + (u8c & 0x3ff);
1744
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 /* Check if the word is indeed a leading word. */
1746 if (u16c < 0xd800 || u16c > 0xdbff)
1747 {
1748 if (can_retry)
1749 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001750 if (conv_error == 0)
1751 conv_error = readfile_linenr(linecnt,
1752 ptr, p);
1753 if (bad_char_behavior == BAD_DROP)
1754 continue;
1755 if (bad_char_behavior != BAD_KEEP)
1756 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758 }
1759 }
1760 else if (fio_flags & FIO_UCS4)
1761 {
1762 if (fio_flags & FIO_ENDIAN_L)
1763 {
1764 u8c = (*--p << 24);
1765 u8c += (*--p << 16);
1766 u8c += (*--p << 8);
1767 u8c += *--p;
1768 }
1769 else /* big endian */
1770 {
1771 u8c = *--p;
1772 u8c += (*--p << 8);
1773 u8c += (*--p << 16);
1774 u8c += (*--p << 24);
1775 }
1776 }
1777 else /* UTF-8 */
1778 {
1779 if (*--p < 0x80)
1780 u8c = *p;
1781 else
1782 {
1783 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001784 p -= len;
1785 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786 if (len == 0)
1787 {
1788 /* Not a valid UTF-8 character, retry with
1789 * another fenc when possible, otherwise just
1790 * report the error. */
1791 if (can_retry)
1792 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001793 if (conv_error == 0)
1794 conv_error = readfile_linenr(linecnt,
1795 ptr, p);
1796 if (bad_char_behavior == BAD_DROP)
1797 continue;
1798 if (bad_char_behavior != BAD_KEEP)
1799 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 }
1802 }
1803 if (enc_utf8) /* produce UTF-8 */
1804 {
1805 dest -= utf_char2len(u8c);
1806 (void)utf_char2bytes(u8c, dest);
1807 }
1808 else /* produce Latin1 */
1809 {
1810 --dest;
1811 if (u8c >= 0x100)
1812 {
1813 /* character doesn't fit in latin1, retry with
1814 * another fenc when possible, otherwise just
1815 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001816 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001818 if (conv_error == 0)
1819 conv_error = readfile_linenr(linecnt, ptr, p);
1820 if (bad_char_behavior == BAD_DROP)
1821 ++dest;
1822 else if (bad_char_behavior == BAD_KEEP)
1823 *dest = u8c;
1824 else if (eap != NULL && eap->bad_char != 0)
1825 *dest = bad_char_behavior;
1826 else
1827 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 }
1829 else
1830 *dest = u8c;
1831 }
1832 }
1833
1834 /* move the linerest to before the converted characters */
1835 line_start = dest - linerest;
1836 mch_memmove(line_start, buffer, (size_t)linerest);
1837 size = (long)((ptr + real_size) - dest);
1838 ptr = dest;
1839 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001840 else if (enc_utf8 && conv_error == 0 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841 {
1842 /* Reading UTF-8: Check if the bytes are valid UTF-8.
1843 * Need to start before "ptr" when part of the character was
1844 * read in the previous read() call. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001845 for (p = ptr - utf_head_off(buffer, ptr); ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001847 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001848 int l;
1849
1850 if (todo <= 0)
1851 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 if (*p >= 0x80)
1853 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 /* A length of 1 means it's an illegal byte. Accept
1855 * an incomplete character at the end though, the next
1856 * read() will get the next bytes, we'll check it
1857 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001858 l = utf_ptr2len_len(p, todo);
1859 if (l > todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001861 /* Incomplete byte sequence, the next read()
1862 * should get them and check the bytes. */
1863 p += todo;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 break;
1865 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001866 if (l == 1)
1867 {
1868 /* Illegal byte. If we can try another encoding
1869 * do that. */
1870 if (can_retry)
1871 break;
1872
1873 /* Remember the first linenr with an illegal byte */
1874 if (illegal_byte == 0)
1875 illegal_byte = readfile_linenr(linecnt, ptr, p);
1876# ifdef USE_ICONV
1877 /* When we did a conversion report an error. */
1878 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
1879 conv_error = readfile_linenr(linecnt, ptr, p);
1880# endif
1881
1882 /* Drop, keep or replace the bad byte. */
1883 if (bad_char_behavior == BAD_DROP)
1884 {
1885 mch_memmove(p, p+1, todo - 1);
1886 --p;
1887 --size;
1888 }
1889 else if (bad_char_behavior != BAD_KEEP)
1890 *p = bad_char_behavior;
1891 }
1892 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 }
1894 }
1895 if (p < ptr + size)
1896 {
1897 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001899 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001901 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
1902 /* iconv() failed, try 'charconvert' */
1903 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 else
1905# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001906 /* use next item from 'fileencodings' */
1907 advance_fenc = TRUE;
1908 file_rewind = TRUE;
1909 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 }
1911 }
1912#endif
1913
1914 /* count the number of characters (after conversion!) */
1915 filesize += size;
1916
1917 /*
1918 * when reading the first part of a file: guess EOL type
1919 */
1920 if (fileformat == EOL_UNKNOWN)
1921 {
1922 /* First try finding a NL, for Dos and Unix */
1923 if (try_dos || try_unix)
1924 {
1925 for (p = ptr; p < ptr + size; ++p)
1926 {
1927 if (*p == NL)
1928 {
1929 if (!try_unix
1930 || (try_dos && p > ptr && p[-1] == CAR))
1931 fileformat = EOL_DOS;
1932 else
1933 fileformat = EOL_UNIX;
1934 break;
1935 }
1936 }
1937
1938 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
1939 if (fileformat == EOL_UNIX && try_mac)
1940 {
1941 /* Need to reset the counters when retrying fenc. */
1942 try_mac = 1;
1943 try_unix = 1;
1944 for (; p >= ptr && *p != CAR; p--)
1945 ;
1946 if (p >= ptr)
1947 {
1948 for (p = ptr; p < ptr + size; ++p)
1949 {
1950 if (*p == NL)
1951 try_unix++;
1952 else if (*p == CAR)
1953 try_mac++;
1954 }
1955 if (try_mac > try_unix)
1956 fileformat = EOL_MAC;
1957 }
1958 }
1959 }
1960
1961 /* No NL found: may use Mac format */
1962 if (fileformat == EOL_UNKNOWN && try_mac)
1963 fileformat = EOL_MAC;
1964
1965 /* Still nothing found? Use first format in 'ffs' */
1966 if (fileformat == EOL_UNKNOWN)
1967 fileformat = default_fileformat();
1968
1969 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001970 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 set_fileformat(fileformat, OPT_LOCAL);
1972 }
1973 }
1974
1975 /*
1976 * This loop is executed once for every character read.
1977 * Keep it fast!
1978 */
1979 if (fileformat == EOL_MAC)
1980 {
1981 --ptr;
1982 while (++ptr, --size >= 0)
1983 {
1984 /* catch most common case first */
1985 if ((c = *ptr) != NUL && c != CAR && c != NL)
1986 continue;
1987 if (c == NUL)
1988 *ptr = NL; /* NULs are replaced by newlines! */
1989 else if (c == NL)
1990 *ptr = CAR; /* NLs are replaced by CRs! */
1991 else
1992 {
1993 if (skip_count == 0)
1994 {
1995 *ptr = NUL; /* end of line */
1996 len = (colnr_T) (ptr - line_start + 1);
1997 if (ml_append(lnum, line_start, len, newfile) == FAIL)
1998 {
1999 error = TRUE;
2000 break;
2001 }
2002 ++lnum;
2003 if (--read_count == 0)
2004 {
2005 error = TRUE; /* break loop */
2006 line_start = ptr; /* nothing left to write */
2007 break;
2008 }
2009 }
2010 else
2011 --skip_count;
2012 line_start = ptr + 1;
2013 }
2014 }
2015 }
2016 else
2017 {
2018 --ptr;
2019 while (++ptr, --size >= 0)
2020 {
2021 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2022 continue;
2023 if (c == NUL)
2024 *ptr = NL; /* NULs are replaced by newlines! */
2025 else
2026 {
2027 if (skip_count == 0)
2028 {
2029 *ptr = NUL; /* end of line */
2030 len = (colnr_T)(ptr - line_start + 1);
2031 if (fileformat == EOL_DOS)
2032 {
2033 if (ptr[-1] == CAR) /* remove CR */
2034 {
2035 ptr[-1] = NUL;
2036 --len;
2037 }
2038 /*
2039 * Reading in Dos format, but no CR-LF found!
2040 * When 'fileformats' includes "unix", delete all
2041 * the lines read so far and start all over again.
2042 * Otherwise give an error message later.
2043 */
2044 else if (ff_error != EOL_DOS)
2045 {
2046 if ( try_unix
2047 && !read_stdin
2048 && (read_buffer
2049 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2050 {
2051 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002052 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 set_fileformat(EOL_UNIX, OPT_LOCAL);
2054 file_rewind = TRUE;
2055 keep_fileformat = TRUE;
2056 goto retry;
2057 }
2058 ff_error = EOL_DOS;
2059 }
2060 }
2061 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2062 {
2063 error = TRUE;
2064 break;
2065 }
2066 ++lnum;
2067 if (--read_count == 0)
2068 {
2069 error = TRUE; /* break loop */
2070 line_start = ptr; /* nothing left to write */
2071 break;
2072 }
2073 }
2074 else
2075 --skip_count;
2076 line_start = ptr + 1;
2077 }
2078 }
2079 }
2080 linerest = (long)(ptr - line_start);
2081 ui_breakcheck();
2082 }
2083
2084failed:
2085 /* not an error, max. number of lines reached */
2086 if (error && read_count == 0)
2087 error = FALSE;
2088
2089 /*
2090 * If we get EOF in the middle of a line, note the fact and
2091 * complete the line ourselves.
2092 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2093 */
2094 if (!error
2095 && !got_int
2096 && linerest != 0
2097 && !(!curbuf->b_p_bin
2098 && fileformat == EOL_DOS
2099 && *line_start == Ctrl_Z
2100 && ptr == line_start + 1))
2101 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002102 /* remember for when writing */
2103 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 curbuf->b_p_eol = FALSE;
2105 *ptr = NUL;
2106 if (ml_append(lnum, line_start,
2107 (colnr_T)(ptr - line_start + 1), newfile) == FAIL)
2108 error = TRUE;
2109 else
2110 read_no_eol_lnum = ++lnum;
2111 }
2112
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002113 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114 save_file_ff(curbuf); /* remember the current file format */
2115
2116#ifdef FEAT_CRYPT
2117 if (cryptkey != curbuf->b_p_key)
2118 vim_free(cryptkey);
2119#endif
2120
2121#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002122 /* If editing a new file: set 'fenc' for the current buffer.
2123 * Also for ":read ++edit file". */
2124 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002126 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 if (fenc_alloced)
2128 vim_free(fenc);
2129# ifdef USE_ICONV
2130 if (iconv_fd != (iconv_t)-1)
2131 {
2132 iconv_close(iconv_fd);
2133 iconv_fd = (iconv_t)-1;
2134 }
2135# endif
2136#endif
2137
2138 if (!read_buffer && !read_stdin)
2139 close(fd); /* errors are ignored */
2140 vim_free(buffer);
2141
2142#ifdef HAVE_DUP
2143 if (read_stdin)
2144 {
2145 /* Use stderr for stdin, makes shell commands work. */
2146 close(0);
2147 dup(2);
2148 }
2149#endif
2150
2151#ifdef FEAT_MBYTE
2152 if (tmpname != NULL)
2153 {
2154 mch_remove(tmpname); /* delete converted file */
2155 vim_free(tmpname);
2156 }
2157#endif
2158 --no_wait_return; /* may wait for return now */
2159
2160 /*
2161 * In recovery mode everything but autocommands is skipped.
2162 */
2163 if (!recoverymode)
2164 {
2165 /* need to delete the last line, which comes from the empty buffer */
2166 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2167 {
2168#ifdef FEAT_NETBEANS_INTG
2169 netbeansFireChanges = 0;
2170#endif
2171 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2172#ifdef FEAT_NETBEANS_INTG
2173 netbeansFireChanges = 1;
2174#endif
2175 --linecnt;
2176 }
2177 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2178 if (filesize == 0)
2179 linecnt = 0;
2180 if (newfile || read_buffer)
2181 redraw_curbuf_later(NOT_VALID);
2182 else if (linecnt) /* appended at least one line */
2183 appended_lines_mark(from, linecnt);
2184
2185#ifdef FEAT_DIFF
2186 /* After reading the text into the buffer the diff info needs to be
2187 * updated. */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002188 if (newfile || read_buffer)
2189 diff_invalidate(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190#endif
2191#ifndef ALWAYS_USE_GUI
2192 /*
2193 * If we were reading from the same terminal as where messages go,
2194 * the screen will have been messed up.
2195 * Switch on raw mode now and clear the screen.
2196 */
2197 if (read_stdin)
2198 {
2199 settmode(TMODE_RAW); /* set to raw mode */
2200 starttermcap();
2201 screenclear();
2202 }
2203#endif
2204
2205 if (got_int)
2206 {
2207 if (!(flags & READ_DUMMY))
2208 {
2209 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2210 if (newfile)
2211 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2212 }
2213 msg_scroll = msg_save;
2214#ifdef FEAT_VIMINFO
2215 check_marks_read();
2216#endif
2217 return OK; /* an interrupt isn't really an error */
2218 }
2219
2220 if (!filtering && !(flags & READ_DUMMY))
2221 {
2222 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2223 c = FALSE;
2224
2225#ifdef UNIX
2226# ifdef S_ISFIFO
2227 if (S_ISFIFO(perm)) /* fifo or socket */
2228 {
2229 STRCAT(IObuff, _("[fifo/socket]"));
2230 c = TRUE;
2231 }
2232# else
2233# ifdef S_IFIFO
2234 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2235 {
2236 STRCAT(IObuff, _("[fifo]"));
2237 c = TRUE;
2238 }
2239# endif
2240# ifdef S_IFSOCK
2241 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2242 {
2243 STRCAT(IObuff, _("[socket]"));
2244 c = TRUE;
2245 }
2246# endif
2247# endif
2248#endif
2249 if (curbuf->b_p_ro)
2250 {
2251 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2252 c = TRUE;
2253 }
2254 if (read_no_eol_lnum)
2255 {
2256 msg_add_eol();
2257 c = TRUE;
2258 }
2259 if (ff_error == EOL_DOS)
2260 {
2261 STRCAT(IObuff, _("[CR missing]"));
2262 c = TRUE;
2263 }
2264 if (ff_error == EOL_MAC)
2265 {
2266 STRCAT(IObuff, _("[NL found]"));
2267 c = TRUE;
2268 }
2269 if (split)
2270 {
2271 STRCAT(IObuff, _("[long lines split]"));
2272 c = TRUE;
2273 }
2274#ifdef FEAT_MBYTE
2275 if (notconverted)
2276 {
2277 STRCAT(IObuff, _("[NOT converted]"));
2278 c = TRUE;
2279 }
2280 else if (converted)
2281 {
2282 STRCAT(IObuff, _("[converted]"));
2283 c = TRUE;
2284 }
2285#endif
2286#ifdef FEAT_CRYPT
2287 if (cryptkey != NULL)
2288 {
2289 STRCAT(IObuff, _("[crypted]"));
2290 c = TRUE;
2291 }
2292#endif
2293#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002294 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002296 sprintf((char *)IObuff + STRLEN(IObuff),
2297 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 c = TRUE;
2299 }
2300 else if (illegal_byte > 0)
2301 {
2302 sprintf((char *)IObuff + STRLEN(IObuff),
2303 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2304 c = TRUE;
2305 }
2306 else
2307#endif
2308 if (error)
2309 {
2310 STRCAT(IObuff, _("[READ ERRORS]"));
2311 c = TRUE;
2312 }
2313 if (msg_add_fileformat(fileformat))
2314 c = TRUE;
2315#ifdef FEAT_CRYPT
2316 if (cryptkey != NULL)
2317 msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
2318 else
2319#endif
2320 msg_add_lines(c, (long)linecnt, filesize);
2321
2322 vim_free(keep_msg);
2323 keep_msg = NULL;
2324 msg_scrolled_ign = TRUE;
2325#ifdef ALWAYS_USE_GUI
2326 /* Don't show the message when reading stdin, it would end up in a
2327 * message box (which might be shown when exiting!) */
2328 if (read_stdin || read_buffer)
2329 p = msg_may_trunc(FALSE, IObuff);
2330 else
2331#endif
2332 p = msg_trunc_attr(IObuff, FALSE, 0);
2333 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002334 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 /* Need to repeat the message after redrawing when:
2336 * - When reading from stdin (the screen will be cleared next).
2337 * - When restart_edit is set (otherwise there will be a delay
2338 * before redrawing).
2339 * - When the screen was scrolled but there is no wait-return
2340 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002341 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 msg_scrolled_ign = FALSE;
2343 }
2344
2345 /* with errors writing the file requires ":w!" */
2346 if (newfile && (error
2347#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002348 || conv_error != 0
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002349 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350#endif
2351 ))
2352 curbuf->b_p_ro = TRUE;
2353
2354 u_clearline(); /* cannot use "U" command after adding lines */
2355
2356 /*
2357 * In Ex mode: cursor at last new line.
2358 * Otherwise: cursor at first new line.
2359 */
2360 if (exmode_active)
2361 curwin->w_cursor.lnum = from + linecnt;
2362 else
2363 curwin->w_cursor.lnum = from + 1;
2364 check_cursor_lnum();
2365 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2366
2367 /*
2368 * Set '[ and '] marks to the newly read lines.
2369 */
2370 curbuf->b_op_start.lnum = from + 1;
2371 curbuf->b_op_start.col = 0;
2372 curbuf->b_op_end.lnum = from + linecnt;
2373 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002374
2375#ifdef WIN32
2376 /*
2377 * Work around a weird problem: When a file has two links (only
2378 * possible on NTFS) and we write through one link, then stat() it
2379 * throught the other link, the timestamp information may be wrong.
2380 * It's correct again after reading the file, thus reset the timestamp
2381 * here.
2382 */
2383 if (newfile && !read_stdin && !read_buffer
2384 && mch_stat((char *)fname, &st) >= 0)
2385 {
2386 buf_store_time(curbuf, &st, fname);
2387 curbuf->b_mtime_read = curbuf->b_mtime;
2388 }
2389#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 }
2391 msg_scroll = msg_save;
2392
2393#ifdef FEAT_VIMINFO
2394 /*
2395 * Get the marks before executing autocommands, so they can be used there.
2396 */
2397 check_marks_read();
2398#endif
2399
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 /*
2401 * Trick: We remember if the last line of the read didn't have
2402 * an eol for when writing it again. This is required for
2403 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2404 */
2405 write_no_eol_lnum = read_no_eol_lnum;
2406
Bram Moolenaardf177f62005-02-22 08:39:57 +00002407#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 if (!read_stdin && !read_buffer)
2409 {
2410 int m = msg_scroll;
2411 int n = msg_scrolled;
2412
2413 /* Save the fileformat now, otherwise the buffer will be considered
2414 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002415 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 save_file_ff(curbuf);
2417
2418 /*
2419 * The output from the autocommands should not overwrite anything and
2420 * should not be overwritten: Set msg_scroll, restore its value if no
2421 * output was done.
2422 */
2423 msg_scroll = TRUE;
2424 if (filtering)
2425 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2426 FALSE, curbuf, eap);
2427 else if (newfile)
2428 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2429 FALSE, curbuf, eap);
2430 else
2431 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2432 FALSE, NULL, eap);
2433 if (msg_scrolled == n)
2434 msg_scroll = m;
2435#ifdef FEAT_EVAL
2436 if (aborting()) /* autocmds may abort script processing */
2437 return FAIL;
2438#endif
2439 }
2440#endif
2441
2442 if (recoverymode && error)
2443 return FAIL;
2444 return OK;
2445}
2446
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002447#ifdef FEAT_MBYTE
2448
2449/*
2450 * From the current line count and characters read after that, estimate the
2451 * line number where we are now.
2452 * Used for error messages that include a line number.
2453 */
2454 static linenr_T
2455readfile_linenr(linecnt, p, endp)
2456 linenr_T linecnt; /* line count before reading more bytes */
2457 char_u *p; /* start of more bytes read */
2458 char_u *endp; /* end of more bytes read */
2459{
2460 char_u *s;
2461 linenr_T lnum;
2462
2463 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2464 for (s = p; s < endp; ++s)
2465 if (*s == '\n')
2466 ++lnum;
2467 return lnum;
2468}
2469#endif
2470
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002472 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2473 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 * Returns OK or FAIL.
2475 */
2476 int
2477prep_exarg(eap, buf)
2478 exarg_T *eap;
2479 buf_T *buf;
2480{
2481 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2482#ifdef FEAT_MBYTE
2483 + STRLEN(buf->b_p_fenc)
2484#endif
2485 + 15));
2486 if (eap->cmd == NULL)
2487 return FAIL;
2488
2489#ifdef FEAT_MBYTE
2490 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2491 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002492 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493#else
2494 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2495#endif
2496 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002497
2498 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002499 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002500 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501 return OK;
2502}
2503
2504#ifdef FEAT_MBYTE
2505/*
2506 * Find next fileencoding to use from 'fileencodings'.
2507 * "pp" points to fenc_next. It's advanced to the next item.
2508 * When there are no more items, an empty string is returned and *pp is set to
2509 * NULL.
2510 * When *pp is not set to NULL, the result is in allocated memory.
2511 */
2512 static char_u *
2513next_fenc(pp)
2514 char_u **pp;
2515{
2516 char_u *p;
2517 char_u *r;
2518
2519 if (**pp == NUL)
2520 {
2521 *pp = NULL;
2522 return (char_u *)"";
2523 }
2524 p = vim_strchr(*pp, ',');
2525 if (p == NULL)
2526 {
2527 r = enc_canonize(*pp);
2528 *pp += STRLEN(*pp);
2529 }
2530 else
2531 {
2532 r = vim_strnsave(*pp, (int)(p - *pp));
2533 *pp = p + 1;
2534 if (r != NULL)
2535 {
2536 p = enc_canonize(r);
2537 vim_free(r);
2538 r = p;
2539 }
2540 }
2541 if (r == NULL) /* out of memory */
2542 {
2543 r = (char_u *)"";
2544 *pp = NULL;
2545 }
2546 return r;
2547}
2548
2549# ifdef FEAT_EVAL
2550/*
2551 * Convert a file with the 'charconvert' expression.
2552 * This closes the file which is to be read, converts it and opens the
2553 * resulting file for reading.
2554 * Returns name of the resulting converted file (the caller should delete it
2555 * after reading it).
2556 * Returns NULL if the conversion failed ("*fdp" is not set) .
2557 */
2558 static char_u *
2559readfile_charconvert(fname, fenc, fdp)
2560 char_u *fname; /* name of input file */
2561 char_u *fenc; /* converted from */
2562 int *fdp; /* in/out: file descriptor of file */
2563{
2564 char_u *tmpname;
2565 char_u *errmsg = NULL;
2566
2567 tmpname = vim_tempname('r');
2568 if (tmpname == NULL)
2569 errmsg = (char_u *)_("Can't find temp file for conversion");
2570 else
2571 {
2572 close(*fdp); /* close the input file, ignore errors */
2573 *fdp = -1;
2574 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2575 fname, tmpname) == FAIL)
2576 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2577 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2578 O_RDONLY | O_EXTRA, 0)) < 0)
2579 errmsg = (char_u *)_("can't read output of 'charconvert'");
2580 }
2581
2582 if (errmsg != NULL)
2583 {
2584 /* Don't use emsg(), it breaks mappings, the retry with
2585 * another type of conversion might still work. */
2586 MSG(errmsg);
2587 if (tmpname != NULL)
2588 {
2589 mch_remove(tmpname); /* delete converted file */
2590 vim_free(tmpname);
2591 tmpname = NULL;
2592 }
2593 }
2594
2595 /* If the input file is closed, open it (caller should check for error). */
2596 if (*fdp < 0)
2597 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2598
2599 return tmpname;
2600}
2601# endif
2602
2603#endif
2604
2605#ifdef FEAT_VIMINFO
2606/*
2607 * Read marks for the current buffer from the viminfo file, when we support
2608 * buffer marks and the buffer has a name.
2609 */
2610 static void
2611check_marks_read()
2612{
2613 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2614 && curbuf->b_ffname != NULL)
2615 read_viminfo(NULL, FALSE, TRUE, FALSE);
2616
2617 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2618 * the ' parameter after opening a buffer. */
2619 curbuf->b_marks_read = TRUE;
2620}
2621#endif
2622
2623#ifdef FEAT_CRYPT
2624/*
2625 * Check for magic number used for encryption.
2626 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2627 * *filesizep are updated.
2628 * Return the (new) encryption key, NULL for no encryption.
2629 */
2630 static char_u *
2631check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile)
2632 char_u *cryptkey; /* previous encryption key or NULL */
2633 char_u *ptr; /* pointer to read bytes */
2634 long *sizep; /* length of read bytes */
2635 long *filesizep; /* nr of bytes used from file */
2636 int newfile; /* editing a new buffer */
2637{
2638 if (*sizep >= CRYPT_MAGIC_LEN
2639 && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
2640 {
2641 if (cryptkey == NULL)
2642 {
2643 if (*curbuf->b_p_key)
2644 cryptkey = curbuf->b_p_key;
2645 else
2646 {
2647 /* When newfile is TRUE, store the typed key
2648 * in the 'key' option and don't free it. */
2649 cryptkey = get_crypt_key(newfile, FALSE);
2650 /* check if empty key entered */
2651 if (cryptkey != NULL && *cryptkey == NUL)
2652 {
2653 if (cryptkey != curbuf->b_p_key)
2654 vim_free(cryptkey);
2655 cryptkey = NULL;
2656 }
2657 }
2658 }
2659
2660 if (cryptkey != NULL)
2661 {
2662 crypt_init_keys(cryptkey);
2663
2664 /* Remove magic number from the text */
2665 *filesizep += CRYPT_MAGIC_LEN;
2666 *sizep -= CRYPT_MAGIC_LEN;
2667 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
2668 }
2669 }
2670 /* When starting to edit a new file which does not have
2671 * encryption, clear the 'key' option, except when
2672 * starting up (called with -x argument) */
2673 else if (newfile && *curbuf->b_p_key && !starting)
2674 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2675
2676 return cryptkey;
2677}
2678#endif
2679
2680#ifdef UNIX
2681 static void
2682set_file_time(fname, atime, mtime)
2683 char_u *fname;
2684 time_t atime; /* access time */
2685 time_t mtime; /* modification time */
2686{
2687# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2688 struct utimbuf buf;
2689
2690 buf.actime = atime;
2691 buf.modtime = mtime;
2692 (void)utime((char *)fname, &buf);
2693# else
2694# if defined(HAVE_UTIMES)
2695 struct timeval tvp[2];
2696
2697 tvp[0].tv_sec = atime;
2698 tvp[0].tv_usec = 0;
2699 tvp[1].tv_sec = mtime;
2700 tvp[1].tv_usec = 0;
2701# ifdef NeXT
2702 (void)utimes((char *)fname, tvp);
2703# else
2704 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2705# endif
2706# endif
2707# endif
2708}
2709#endif /* UNIX */
2710
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002711#if defined(VMS) && !defined(MIN)
2712/* Older DECC compiler for VAX doesn't define MIN() */
2713# define MIN(a, b) ((a) < (b) ? (a) : (b))
2714#endif
2715
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00002717 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 *
2719 * We do our own buffering here because fwrite() is so slow.
2720 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00002721 * If "forceit" is true, we don't care for errors when attempting backups.
2722 * In case of an error everything possible is done to restore the original
2723 * file. But when "forceit" is TRUE, we risk loosing it.
2724 *
2725 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
2726 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 *
2728 * This function must NOT use NameBuff (because it's called by autowrite()).
2729 *
2730 * return FAIL for failure, OK otherwise
2731 */
2732 int
2733buf_write(buf, fname, sfname, start, end, eap, append, forceit,
2734 reset_changed, filtering)
2735 buf_T *buf;
2736 char_u *fname;
2737 char_u *sfname;
2738 linenr_T start, end;
2739 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
2740 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00002741 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 int forceit;
2743 int reset_changed;
2744 int filtering;
2745{
2746 int fd;
2747 char_u *backup = NULL;
2748 int backup_copy = FALSE; /* copy the original file? */
2749 int dobackup;
2750 char_u *ffname;
2751 char_u *wfname = NULL; /* name of file to write to */
2752 char_u *s;
2753 char_u *ptr;
2754 char_u c;
2755 int len;
2756 linenr_T lnum;
2757 long nchars;
2758 char_u *errmsg = NULL;
2759 char_u *errnum = NULL;
2760 char_u *buffer;
2761 char_u smallbuf[SMBUFSIZE];
2762 char_u *backup_ext;
2763 int bufsize;
2764 long perm; /* file permissions */
2765 int retval = OK;
2766 int newfile = FALSE; /* TRUE if file doesn't exist yet */
2767 int msg_save = msg_scroll;
2768 int overwriting; /* TRUE if writing over original */
2769 int no_eol = FALSE; /* no end-of-line written */
2770 int device = FALSE; /* writing to a device */
2771 struct stat st_old;
2772 int prev_got_int = got_int;
2773 int file_readonly = FALSE; /* overwritten file is read-only */
2774 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
2775#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
2776 int made_writable = FALSE; /* 'w' bit has been set */
2777#endif
2778 /* writing everything */
2779 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
2780#ifdef FEAT_AUTOCMD
2781 linenr_T old_line_count = buf->b_ml.ml_line_count;
2782#endif
2783 int attr;
2784 int fileformat;
2785 int write_bin;
2786 struct bw_info write_info; /* info for buf_write_bytes() */
2787#ifdef FEAT_MBYTE
2788 int converted = FALSE;
2789 int notconverted = FALSE;
2790 char_u *fenc; /* effective 'fileencoding' */
2791 char_u *fenc_tofree = NULL; /* allocated "fenc" */
2792#endif
2793#ifdef HAS_BW_FLAGS
2794 int wb_flags = 0;
2795#endif
2796#ifdef HAVE_ACL
2797 vim_acl_T acl = NULL; /* ACL copied from original file to
2798 backup or new file */
2799#endif
2800
2801 if (fname == NULL || *fname == NUL) /* safety check */
2802 return FAIL;
2803
2804 /*
2805 * Disallow writing from .exrc and .vimrc in current directory for
2806 * security reasons.
2807 */
2808 if (check_secure())
2809 return FAIL;
2810
2811 /* Avoid a crash for a long name. */
2812 if (STRLEN(fname) >= MAXPATHL)
2813 {
2814 EMSG(_(e_longname));
2815 return FAIL;
2816 }
2817
2818#ifdef FEAT_MBYTE
2819 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
2820 write_info.bw_conv_buf = NULL;
2821 write_info.bw_conv_error = FALSE;
2822 write_info.bw_restlen = 0;
2823# ifdef USE_ICONV
2824 write_info.bw_iconv_fd = (iconv_t)-1;
2825# endif
2826#endif
2827
Bram Moolenaardf177f62005-02-22 08:39:57 +00002828 /* After writing a file changedtick changes but we don't want to display
2829 * the line. */
2830 ex_no_reprint = TRUE;
2831
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 /*
2833 * If there is no file name yet, use the one for the written file.
2834 * BF_NOTEDITED is set to reflect this (in case the write fails).
2835 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00002836 * Don't do this when appending.
2837 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002839 if (buf->b_ffname == NULL
2840 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 && whole
2842 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002843#ifdef FEAT_QUICKFIX
2844 && !bt_nofile(buf)
2845#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00002847 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
2849 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002850 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002852 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 }
2854
2855 if (sfname == NULL)
2856 sfname = fname;
2857 /*
2858 * For Unix: Use the short file name whenever possible.
2859 * Avoids problems with networks and when directory names are changed.
2860 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
2861 * another directory, which we don't detect
2862 */
2863 ffname = fname; /* remember full fname */
2864#ifdef UNIX
2865 fname = sfname;
2866#endif
2867
2868 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
2869 overwriting = TRUE;
2870 else
2871 overwriting = FALSE;
2872
2873 if (exiting)
2874 settmode(TMODE_COOK); /* when exiting allow typahead now */
2875
2876 ++no_wait_return; /* don't wait for return yet */
2877
2878 /*
2879 * Set '[ and '] marks to the lines to be written.
2880 */
2881 buf->b_op_start.lnum = start;
2882 buf->b_op_start.col = 0;
2883 buf->b_op_end.lnum = end;
2884 buf->b_op_end.col = 0;
2885
2886#ifdef FEAT_AUTOCMD
2887 {
2888 aco_save_T aco;
2889 int buf_ffname = FALSE;
2890 int buf_sfname = FALSE;
2891 int buf_fname_f = FALSE;
2892 int buf_fname_s = FALSE;
2893 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002894 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002895 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
2897 /*
2898 * Apply PRE aucocommands.
2899 * Set curbuf to the buffer to be written.
2900 * Careful: The autocommands may call buf_write() recursively!
2901 */
2902 if (ffname == buf->b_ffname)
2903 buf_ffname = TRUE;
2904 if (sfname == buf->b_sfname)
2905 buf_sfname = TRUE;
2906 if (fname == buf->b_ffname)
2907 buf_fname_f = TRUE;
2908 if (fname == buf->b_sfname)
2909 buf_fname_s = TRUE;
2910
2911 /* set curwin/curbuf to buf and save a few things */
2912 aucmd_prepbuf(&aco, buf);
2913
2914 if (append)
2915 {
2916 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
2917 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002918 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002919#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002920 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002921 nofile_err = TRUE;
2922 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002923#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002924 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002926 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 }
2928 else if (filtering)
2929 {
2930 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
2931 NULL, sfname, FALSE, curbuf, eap);
2932 }
2933 else if (reset_changed && whole)
2934 {
2935 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
2936 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002937 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002938#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002939 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002940 nofile_err = TRUE;
2941 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002942#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002943 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002945 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 }
2947 else
2948 {
2949 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
2950 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002951 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002952#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002953 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002954 nofile_err = TRUE;
2955 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002956#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002957 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002959 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 }
2961
2962 /* restore curwin/curbuf and a few other things */
2963 aucmd_restbuf(&aco);
2964
2965 /*
2966 * In three situations we return here and don't write the file:
2967 * 1. the autocommands deleted or unloaded the buffer.
2968 * 2. The autocommands abort script processing.
2969 * 3. If one of the "Cmd" autocommands was executed.
2970 */
2971 if (!buf_valid(buf))
2972 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002973 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00002974 || did_cmd || nofile_err
2975#ifdef FEAT_EVAL
2976 || aborting()
2977#endif
2978 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 {
2980 --no_wait_return;
2981 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002982 if (nofile_err)
2983 EMSG(_("E676: No matching autocommands for acwrite buffer"));
2984
Bram Moolenaar1e015462005-09-25 22:16:38 +00002985 if (nofile_err
2986#ifdef FEAT_EVAL
2987 || aborting()
2988#endif
2989 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 /* An aborting error, interrupt or exception in the
2991 * autocommands. */
2992 return FAIL;
2993 if (did_cmd)
2994 {
2995 if (buf == NULL)
2996 /* The buffer was deleted. We assume it was written
2997 * (can't retry anyway). */
2998 return OK;
2999 if (overwriting)
3000 {
3001 /* Assume the buffer was written, update the timestamp. */
3002 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003003 if (append)
3004 buf->b_flags &= ~BF_NEW;
3005 else
3006 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003008 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003009 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 /* Buffer still changed, the autocommands didn't work
3011 * properly. */
3012 return FAIL;
3013 return OK;
3014 }
3015#ifdef FEAT_EVAL
3016 if (!aborting())
3017#endif
3018 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
3019 return FAIL;
3020 }
3021
3022 /*
3023 * The autocommands may have changed the number of lines in the file.
3024 * When writing the whole file, adjust the end.
3025 * When writing part of the file, assume that the autocommands only
3026 * changed the number of lines that are to be written (tricky!).
3027 */
3028 if (buf->b_ml.ml_line_count != old_line_count)
3029 {
3030 if (whole) /* write all */
3031 end = buf->b_ml.ml_line_count;
3032 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3033 end += buf->b_ml.ml_line_count - old_line_count;
3034 else /* less lines */
3035 {
3036 end -= old_line_count - buf->b_ml.ml_line_count;
3037 if (end < start)
3038 {
3039 --no_wait_return;
3040 msg_scroll = msg_save;
3041 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3042 return FAIL;
3043 }
3044 }
3045 }
3046
3047 /*
3048 * The autocommands may have changed the name of the buffer, which may
3049 * be kept in fname, ffname and sfname.
3050 */
3051 if (buf_ffname)
3052 ffname = buf->b_ffname;
3053 if (buf_sfname)
3054 sfname = buf->b_sfname;
3055 if (buf_fname_f)
3056 fname = buf->b_ffname;
3057 if (buf_fname_s)
3058 fname = buf->b_sfname;
3059 }
3060#endif
3061
3062#ifdef FEAT_NETBEANS_INTG
3063 if (usingNetbeans && isNetbeansBuffer(buf))
3064 {
3065 if (whole)
3066 {
3067 /*
3068 * b_changed can be 0 after an undo, but we still need to write
3069 * the buffer to NetBeans.
3070 */
3071 if (buf->b_changed || isNetbeansModified(buf))
3072 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003073 --no_wait_return; /* may wait for return now */
3074 msg_scroll = msg_save;
3075 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 return retval;
3077 }
3078 else
3079 {
3080 errnum = (char_u *)"E656: ";
3081 errmsg = (char_u *)_("NetBeans dissallows writes of unmodified buffers");
3082 buffer = NULL;
3083 goto fail;
3084 }
3085 }
3086 else
3087 {
3088 errnum = (char_u *)"E657: ";
3089 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3090 buffer = NULL;
3091 goto fail;
3092 }
3093 }
3094#endif
3095
3096 if (shortmess(SHM_OVER) && !exiting)
3097 msg_scroll = FALSE; /* overwrite previous file message */
3098 else
3099 msg_scroll = TRUE; /* don't overwrite previous file message */
3100 if (!filtering)
3101 filemess(buf,
3102#ifndef UNIX
3103 sfname,
3104#else
3105 fname,
3106#endif
3107 (char_u *)"", 0); /* show that we are busy */
3108 msg_scroll = FALSE; /* always overwrite the file message now */
3109
3110 buffer = alloc(BUFSIZE);
3111 if (buffer == NULL) /* can't allocate big buffer, use small
3112 * one (to be able to write when out of
3113 * memory) */
3114 {
3115 buffer = smallbuf;
3116 bufsize = SMBUFSIZE;
3117 }
3118 else
3119 bufsize = BUFSIZE;
3120
3121 /*
3122 * Get information about original file (if there is one).
3123 */
3124#if defined(UNIX) && !defined(ARCHIE)
3125 st_old.st_dev = st_old.st_ino = 0;
3126 perm = -1;
3127 if (mch_stat((char *)fname, &st_old) < 0)
3128 newfile = TRUE;
3129 else
3130 {
3131 perm = st_old.st_mode;
3132 if (!S_ISREG(st_old.st_mode)) /* not a file */
3133 {
3134 if (S_ISDIR(st_old.st_mode))
3135 {
3136 errnum = (char_u *)"E502: ";
3137 errmsg = (char_u *)_("is a directory");
3138 goto fail;
3139 }
3140 if (mch_nodetype(fname) != NODE_WRITABLE)
3141 {
3142 errnum = (char_u *)"E503: ";
3143 errmsg = (char_u *)_("is not a file or writable device");
3144 goto fail;
3145 }
3146 /* It's a device of some kind (or a fifo) which we can write to
3147 * but for which we can't make a backup. */
3148 device = TRUE;
3149 newfile = TRUE;
3150 perm = -1;
3151 }
3152 }
3153#else /* !UNIX */
3154 /*
3155 * Check for a writable device name.
3156 */
3157 c = mch_nodetype(fname);
3158 if (c == NODE_OTHER)
3159 {
3160 errnum = (char_u *)"E503: ";
3161 errmsg = (char_u *)_("is not a file or writable device");
3162 goto fail;
3163 }
3164 if (c == NODE_WRITABLE)
3165 {
3166 device = TRUE;
3167 newfile = TRUE;
3168 perm = -1;
3169 }
3170 else
3171 {
3172 perm = mch_getperm(fname);
3173 if (perm < 0)
3174 newfile = TRUE;
3175 else if (mch_isdir(fname))
3176 {
3177 errnum = (char_u *)"E502: ";
3178 errmsg = (char_u *)_("is a directory");
3179 goto fail;
3180 }
3181 if (overwriting)
3182 (void)mch_stat((char *)fname, &st_old);
3183 }
3184#endif /* !UNIX */
3185
3186 if (!device && !newfile)
3187 {
3188 /*
3189 * Check if the file is really writable (when renaming the file to
3190 * make a backup we won't discover it later).
3191 */
3192 file_readonly = (
3193# ifdef USE_MCH_ACCESS
3194# ifdef UNIX
3195 (perm & 0222) == 0 ||
3196# endif
3197 mch_access((char *)fname, W_OK)
3198# else
3199 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
3200 ? TRUE : (close(fd), FALSE)
3201# endif
3202 );
3203 if (!forceit && file_readonly)
3204 {
3205 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3206 {
3207 errnum = (char_u *)"E504: ";
3208 errmsg = (char_u *)_(err_readonly);
3209 }
3210 else
3211 {
3212 errnum = (char_u *)"E505: ";
3213 errmsg = (char_u *)_("is read-only (add ! to override)");
3214 }
3215 goto fail;
3216 }
3217
3218 /*
3219 * Check if the timestamp hasn't changed since reading the file.
3220 */
3221 if (overwriting)
3222 {
3223 retval = check_mtime(buf, &st_old);
3224 if (retval == FAIL)
3225 goto fail;
3226 }
3227 }
3228
3229#ifdef HAVE_ACL
3230 /*
3231 * For systems that support ACL: get the ACL from the original file.
3232 */
3233 if (!newfile)
3234 acl = mch_get_acl(fname);
3235#endif
3236
3237 /*
3238 * If 'backupskip' is not empty, don't make a backup for some files.
3239 */
3240 dobackup = (p_wb || p_bk || *p_pm != NUL);
3241#ifdef FEAT_WILDIGN
3242 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3243 dobackup = FALSE;
3244#endif
3245
3246 /*
3247 * Save the value of got_int and reset it. We don't want a previous
3248 * interruption cancel writing, only hitting CTRL-C while writing should
3249 * abort it.
3250 */
3251 prev_got_int = got_int;
3252 got_int = FALSE;
3253
3254 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3255 buf->b_saving = TRUE;
3256
3257 /*
3258 * If we are not appending or filtering, the file exists, and the
3259 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3260 * When 'patchmode' is set also make a backup when appending.
3261 *
3262 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3263 * off. This helps when editing large files on almost-full disks.
3264 */
3265 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3266 {
3267#if defined(UNIX) || defined(WIN32)
3268 struct stat st;
3269#endif
3270
3271 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3272 backup_copy = TRUE;
3273#if defined(UNIX) || defined(WIN32)
3274 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3275 {
3276 int i;
3277
3278# ifdef UNIX
3279 /*
3280 * Don't rename the file when:
3281 * - it's a hard link
3282 * - it's a symbolic link
3283 * - we don't have write permission in the directory
3284 * - we can't set the owner/group of the new file
3285 */
3286 if (st_old.st_nlink > 1
3287 || mch_lstat((char *)fname, &st) < 0
3288 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003289 || st.st_ino != st_old.st_ino
3290# ifndef HAVE_FCHOWN
3291 || st.st_uid != st_old.st_uid
3292 || st.st_gid != st_old.st_gid
3293# endif
3294 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 backup_copy = TRUE;
3296 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003297# else
3298# ifdef WIN32
3299 /* On NTFS file systems hard links are possible. */
3300 if (mch_is_linked(fname))
3301 backup_copy = TRUE;
3302 else
3303# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304# endif
3305 {
3306 /*
3307 * Check if we can create a file and set the owner/group to
3308 * the ones from the original file.
3309 * First find a file name that doesn't exist yet (use some
3310 * arbitrary numbers).
3311 */
3312 STRCPY(IObuff, fname);
3313 for (i = 4913; ; i += 123)
3314 {
3315 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003316 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 break;
3318 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003319 fd = mch_open((char *)IObuff,
3320 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 if (fd < 0) /* can't write in directory */
3322 backup_copy = TRUE;
3323 else
3324 {
3325# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003326# ifdef HAVE_FCHOWN
3327 fchown(fd, st_old.st_uid, st_old.st_gid);
3328# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329 if (mch_stat((char *)IObuff, &st) < 0
3330 || st.st_uid != st_old.st_uid
3331 || st.st_gid != st_old.st_gid
3332 || st.st_mode != perm)
3333 backup_copy = TRUE;
3334# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003335 /* Close the file before removing it, on MS-Windows we
3336 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003337 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003338 mch_remove(IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 }
3340 }
3341 }
3342
3343# ifdef UNIX
3344 /*
3345 * Break symlinks and/or hardlinks if we've been asked to.
3346 */
3347 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3348 {
3349 int lstat_res;
3350
3351 lstat_res = mch_lstat((char *)fname, &st);
3352
3353 /* Symlinks. */
3354 if ((bkc_flags & BKC_BREAKSYMLINK)
3355 && lstat_res == 0
3356 && st.st_ino != st_old.st_ino)
3357 backup_copy = FALSE;
3358
3359 /* Hardlinks. */
3360 if ((bkc_flags & BKC_BREAKHARDLINK)
3361 && st_old.st_nlink > 1
3362 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3363 backup_copy = FALSE;
3364 }
3365#endif
3366
3367#endif
3368
3369 /* make sure we have a valid backup extension to use */
3370 if (*p_bex == NUL)
3371 {
3372#ifdef RISCOS
3373 backup_ext = (char_u *)"/bak";
3374#else
3375 backup_ext = (char_u *)".bak";
3376#endif
3377 }
3378 else
3379 backup_ext = p_bex;
3380
3381 if (backup_copy
3382 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3383 {
3384 int bfd;
3385 char_u *copybuf, *wp;
3386 int some_error = FALSE;
3387 struct stat st_new;
3388 char_u *dirp;
3389 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003390#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 int did_set_shortname;
3392#endif
3393
3394 copybuf = alloc(BUFSIZE + 1);
3395 if (copybuf == NULL)
3396 {
3397 some_error = TRUE; /* out of memory */
3398 goto nobackup;
3399 }
3400
3401 /*
3402 * Try to make the backup in each directory in the 'bdir' option.
3403 *
3404 * Unix semantics has it, that we may have a writable file,
3405 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3406 * - the directory is not writable,
3407 * - the file may be a symbolic link,
3408 * - the file may belong to another user/group, etc.
3409 *
3410 * For these reasons, the existing writable file must be truncated
3411 * and reused. Creation of a backup COPY will be attempted.
3412 */
3413 dirp = p_bdir;
3414 while (*dirp)
3415 {
3416#ifdef UNIX
3417 st_new.st_ino = 0;
3418 st_new.st_dev = 0;
3419 st_new.st_gid = 0;
3420#endif
3421
3422 /*
3423 * Isolate one directory name, using an entry in 'bdir'.
3424 */
3425 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3426 rootname = get_file_in_dir(fname, copybuf);
3427 if (rootname == NULL)
3428 {
3429 some_error = TRUE; /* out of memory */
3430 goto nobackup;
3431 }
3432
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003433#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 did_set_shortname = FALSE;
3435#endif
3436
3437 /*
3438 * May try twice if 'shortname' not set.
3439 */
3440 for (;;)
3441 {
3442 /*
3443 * Make backup file name.
3444 */
3445 backup = buf_modname(
3446#ifdef SHORT_FNAME
3447 TRUE,
3448#else
3449 (buf->b_p_sn || buf->b_shortname),
3450#endif
3451 rootname, backup_ext, FALSE);
3452 if (backup == NULL)
3453 {
3454 vim_free(rootname);
3455 some_error = TRUE; /* out of memory */
3456 goto nobackup;
3457 }
3458
3459 /*
3460 * Check if backup file already exists.
3461 */
3462 if (mch_stat((char *)backup, &st_new) >= 0)
3463 {
3464#ifdef UNIX
3465 /*
3466 * Check if backup file is same as original file.
3467 * May happen when modname() gave the same file back.
3468 * E.g. silly link, or file name-length reached.
3469 * If we don't check here, we either ruin the file
3470 * when copying or erase it after writing. jw.
3471 */
3472 if (st_new.st_dev == st_old.st_dev
3473 && st_new.st_ino == st_old.st_ino)
3474 {
3475 vim_free(backup);
3476 backup = NULL; /* no backup file to delete */
3477# ifndef SHORT_FNAME
3478 /*
3479 * may try again with 'shortname' set
3480 */
3481 if (!(buf->b_shortname || buf->b_p_sn))
3482 {
3483 buf->b_shortname = TRUE;
3484 did_set_shortname = TRUE;
3485 continue;
3486 }
3487 /* setting shortname didn't help */
3488 if (did_set_shortname)
3489 buf->b_shortname = FALSE;
3490# endif
3491 break;
3492 }
3493#endif
3494
3495 /*
3496 * If we are not going to keep the backup file, don't
3497 * delete an existing one, try to use another name.
3498 * Change one character, just before the extension.
3499 */
3500 if (!p_bk)
3501 {
3502 wp = backup + STRLEN(backup) - 1
3503 - STRLEN(backup_ext);
3504 if (wp < backup) /* empty file name ??? */
3505 wp = backup;
3506 *wp = 'z';
3507 while (*wp > 'a'
3508 && mch_stat((char *)backup, &st_new) >= 0)
3509 --*wp;
3510 /* They all exist??? Must be something wrong. */
3511 if (*wp == 'a')
3512 {
3513 vim_free(backup);
3514 backup = NULL;
3515 }
3516 }
3517 }
3518 break;
3519 }
3520 vim_free(rootname);
3521
3522 /*
3523 * Try to create the backup file
3524 */
3525 if (backup != NULL)
3526 {
3527 /* remove old backup, if present */
3528 mch_remove(backup);
3529 /* Open with O_EXCL to avoid the file being created while
3530 * we were sleeping (symlink hacker attack?) */
3531 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003532 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3533 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534 if (bfd < 0)
3535 {
3536 vim_free(backup);
3537 backup = NULL;
3538 }
3539 else
3540 {
3541 /* set file protection same as original file, but
3542 * strip s-bit */
3543 (void)mch_setperm(backup, perm & 0777);
3544
3545#ifdef UNIX
3546 /*
3547 * Try to set the group of the backup same as the
3548 * original file. If this fails, set the protection
3549 * bits for the group same as the protection bits for
3550 * others.
3551 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003552 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003554 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555# endif
3556 )
3557 mch_setperm(backup,
3558 (perm & 0707) | ((perm & 07) << 3));
3559#endif
3560
3561 /*
3562 * copy the file.
3563 */
3564 write_info.bw_fd = bfd;
3565 write_info.bw_buf = copybuf;
3566#ifdef HAS_BW_FLAGS
3567 write_info.bw_flags = FIO_NOCONVERT;
3568#endif
3569 while ((write_info.bw_len = vim_read(fd, copybuf,
3570 BUFSIZE)) > 0)
3571 {
3572 if (buf_write_bytes(&write_info) == FAIL)
3573 {
3574 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3575 break;
3576 }
3577 ui_breakcheck();
3578 if (got_int)
3579 {
3580 errmsg = (char_u *)_(e_interr);
3581 break;
3582 }
3583 }
3584
3585 if (close(bfd) < 0 && errmsg == NULL)
3586 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3587 if (write_info.bw_len < 0)
3588 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3589#ifdef UNIX
3590 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3591#endif
3592#ifdef HAVE_ACL
3593 mch_set_acl(backup, acl);
3594#endif
3595 break;
3596 }
3597 }
3598 }
3599 nobackup:
3600 close(fd); /* ignore errors for closing read file */
3601 vim_free(copybuf);
3602
3603 if (backup == NULL && errmsg == NULL)
3604 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3605 /* ignore errors when forceit is TRUE */
3606 if ((some_error || errmsg != NULL) && !forceit)
3607 {
3608 retval = FAIL;
3609 goto fail;
3610 }
3611 errmsg = NULL;
3612 }
3613 else
3614 {
3615 char_u *dirp;
3616 char_u *p;
3617 char_u *rootname;
3618
3619 /*
3620 * Make a backup by renaming the original file.
3621 */
3622 /*
3623 * If 'cpoptions' includes the "W" flag, we don't want to
3624 * overwrite a read-only file. But rename may be possible
3625 * anyway, thus we need an extra check here.
3626 */
3627 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3628 {
3629 errnum = (char_u *)"E504: ";
3630 errmsg = (char_u *)_(err_readonly);
3631 goto fail;
3632 }
3633
3634 /*
3635 *
3636 * Form the backup file name - change path/fo.o.h to
3637 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3638 * that works is used.
3639 */
3640 dirp = p_bdir;
3641 while (*dirp)
3642 {
3643 /*
3644 * Isolate one directory name and make the backup file name.
3645 */
3646 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
3647 rootname = get_file_in_dir(fname, IObuff);
3648 if (rootname == NULL)
3649 backup = NULL;
3650 else
3651 {
3652 backup = buf_modname(
3653#ifdef SHORT_FNAME
3654 TRUE,
3655#else
3656 (buf->b_p_sn || buf->b_shortname),
3657#endif
3658 rootname, backup_ext, FALSE);
3659 vim_free(rootname);
3660 }
3661
3662 if (backup != NULL)
3663 {
3664 /*
3665 * If we are not going to keep the backup file, don't
3666 * delete an existing one, try to use another name.
3667 * Change one character, just before the extension.
3668 */
3669 if (!p_bk && mch_getperm(backup) >= 0)
3670 {
3671 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
3672 if (p < backup) /* empty file name ??? */
3673 p = backup;
3674 *p = 'z';
3675 while (*p > 'a' && mch_getperm(backup) >= 0)
3676 --*p;
3677 /* They all exist??? Must be something wrong! */
3678 if (*p == 'a')
3679 {
3680 vim_free(backup);
3681 backup = NULL;
3682 }
3683 }
3684 }
3685 if (backup != NULL)
3686 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003688 * Delete any existing backup and move the current version
3689 * to the backup. For safety, we don't remove the backup
3690 * until the write has finished successfully. And if the
3691 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 */
3693 /*
3694 * If the renaming of the original file to the backup file
3695 * works, quit here.
3696 */
3697 if (vim_rename(fname, backup) == 0)
3698 break;
3699
3700 vim_free(backup); /* don't do the rename below */
3701 backup = NULL;
3702 }
3703 }
3704 if (backup == NULL && !forceit)
3705 {
3706 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
3707 goto fail;
3708 }
3709 }
3710 }
3711
3712#if defined(UNIX) && !defined(ARCHIE)
3713 /* When using ":w!" and the file was read-only: make it writable */
3714 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
3715 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
3716 {
3717 perm |= 0200;
3718 (void)mch_setperm(fname, perm);
3719 made_writable = TRUE;
3720 }
3721#endif
3722
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003723 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003724 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
3725 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726 {
3727 buf->b_p_ro = FALSE;
3728#ifdef FEAT_TITLE
3729 need_maketitle = TRUE; /* set window title later */
3730#endif
3731#ifdef FEAT_WINDOWS
3732 status_redraw_all(); /* redraw status lines later */
3733#endif
3734 }
3735
3736 if (end > buf->b_ml.ml_line_count)
3737 end = buf->b_ml.ml_line_count;
3738 if (buf->b_ml.ml_flags & ML_EMPTY)
3739 start = end + 1;
3740
3741 /*
3742 * If the original file is being overwritten, there is a small chance that
3743 * we crash in the middle of writing. Therefore the file is preserved now.
3744 * This makes all block numbers positive so that recovery does not need
3745 * the original file.
3746 * Don't do this if there is a backup file and we are exiting.
3747 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003748 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 && !(exiting && backup != NULL))
3750 {
3751 ml_preserve(buf, FALSE);
3752 if (got_int)
3753 {
3754 errmsg = (char_u *)_(e_interr);
3755 goto restore_backup;
3756 }
3757 }
3758
3759#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
3760 /*
3761 * Before risking to lose the original file verify if there's
3762 * a resource fork to preserve, and if cannot be done warn
3763 * the users. This happens when overwriting without backups.
3764 */
3765 if (backup == NULL && overwriting && !append)
3766 if (mch_has_resource_fork(fname))
3767 {
3768 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
3769 goto restore_backup;
3770 }
3771#endif
3772
3773#ifdef VMS
3774 vms_remove_version(fname); /* remove version */
3775#endif
3776 /* Default: write the the file directly. May write to a temp file for
3777 * multi-byte conversion. */
3778 wfname = fname;
3779
3780#ifdef FEAT_MBYTE
3781 /* Check for forced 'fileencoding' from "++opt=val" argument. */
3782 if (eap != NULL && eap->force_enc != 0)
3783 {
3784 fenc = eap->cmd + eap->force_enc;
3785 fenc = enc_canonize(fenc);
3786 fenc_tofree = fenc;
3787 }
3788 else
3789 fenc = buf->b_p_fenc;
3790
3791 /*
3792 * The file needs to be converted when 'fileencoding' is set and
3793 * 'fileencoding' differs from 'encoding'.
3794 */
3795 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
3796
3797 /*
3798 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
3799 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
3800 * Prepare the flags for it and allocate bw_conv_buf when needed.
3801 */
3802 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
3803 {
3804 wb_flags = get_fio_flags(fenc);
3805 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
3806 {
3807 /* Need to allocate a buffer to translate into. */
3808 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
3809 write_info.bw_conv_buflen = bufsize * 2;
3810 else /* FIO_UCS4 */
3811 write_info.bw_conv_buflen = bufsize * 4;
3812 write_info.bw_conv_buf
3813 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3814 if (write_info.bw_conv_buf == NULL)
3815 end = 0;
3816 }
3817 }
3818
3819# ifdef WIN3264
3820 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
3821 {
3822 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
3823 write_info.bw_conv_buflen = bufsize * 4;
3824 write_info.bw_conv_buf
3825 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3826 if (write_info.bw_conv_buf == NULL)
3827 end = 0;
3828 }
3829# endif
3830
3831# ifdef MACOS_X
3832 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
3833 {
3834 write_info.bw_conv_buflen = bufsize * 3;
3835 write_info.bw_conv_buf
3836 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3837 if (write_info.bw_conv_buf == NULL)
3838 end = 0;
3839 }
3840# endif
3841
3842# if defined(FEAT_EVAL) || defined(USE_ICONV)
3843 if (converted && wb_flags == 0)
3844 {
3845# ifdef USE_ICONV
3846 /*
3847 * Use iconv() conversion when conversion is needed and it's not done
3848 * internally.
3849 */
3850 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
3851 enc_utf8 ? (char_u *)"utf-8" : p_enc);
3852 if (write_info.bw_iconv_fd != (iconv_t)-1)
3853 {
3854 /* We're going to use iconv(), allocate a buffer to convert in. */
3855 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
3856 write_info.bw_conv_buf
3857 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3858 if (write_info.bw_conv_buf == NULL)
3859 end = 0;
3860 write_info.bw_first = TRUE;
3861 }
3862# ifdef FEAT_EVAL
3863 else
3864# endif
3865# endif
3866
3867# ifdef FEAT_EVAL
3868 /*
3869 * When the file needs to be converted with 'charconvert' after
3870 * writing, write to a temp file instead and let the conversion
3871 * overwrite the original file.
3872 */
3873 if (*p_ccv != NUL)
3874 {
3875 wfname = vim_tempname('w');
3876 if (wfname == NULL) /* Can't write without a tempfile! */
3877 {
3878 errmsg = (char_u *)_("E214: Can't find temp file for writing");
3879 goto restore_backup;
3880 }
3881 }
3882# endif
3883 }
3884# endif
3885 if (converted && wb_flags == 0
3886# ifdef USE_ICONV
3887 && write_info.bw_iconv_fd == (iconv_t)-1
3888# endif
3889# ifdef FEAT_EVAL
3890 && wfname == fname
3891# endif
3892 )
3893 {
3894 if (!forceit)
3895 {
3896 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
3897 goto restore_backup;
3898 }
3899 notconverted = TRUE;
3900 }
3901#endif
3902
3903 /*
3904 * Open the file "wfname" for writing.
3905 * We may try to open the file twice: If we can't write to the
3906 * file and forceit is TRUE we delete the existing file and try to create
3907 * a new one. If this still fails we may have lost the original file!
3908 * (this may happen when the user reached his quotum for number of files).
3909 * Appending will fail if the file does not exist and forceit is FALSE.
3910 */
3911 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
3912 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
3913 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00003914 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915 {
3916 /*
3917 * A forced write will try to create a new file if the old one is
3918 * still readonly. This may also happen when the directory is
3919 * read-only. In that case the mch_remove() will fail.
3920 */
3921 if (errmsg == NULL)
3922 {
3923#ifdef UNIX
3924 struct stat st;
3925
3926 /* Don't delete the file when it's a hard or symbolic link. */
3927 if ((!newfile && st_old.st_nlink > 1)
3928 || (mch_lstat((char *)fname, &st) == 0
3929 && (st.st_dev != st_old.st_dev
3930 || st.st_ino != st_old.st_ino)))
3931 errmsg = (char_u *)_("E166: Can't open linked file for writing");
3932 else
3933#endif
3934 {
3935 errmsg = (char_u *)_("E212: Can't open file for writing");
3936 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
3937 && perm >= 0)
3938 {
3939#ifdef UNIX
3940 /* we write to the file, thus it should be marked
3941 writable after all */
3942 if (!(perm & 0200))
3943 made_writable = TRUE;
3944 perm |= 0200;
3945 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
3946 perm &= 0777;
3947#endif
3948 if (!append) /* don't remove when appending */
3949 mch_remove(wfname);
3950 continue;
3951 }
3952 }
3953 }
3954
3955restore_backup:
3956 {
3957 struct stat st;
3958
3959 /*
3960 * If we failed to open the file, we don't need a backup. Throw it
3961 * away. If we moved or removed the original file try to put the
3962 * backup in its place.
3963 */
3964 if (backup != NULL && wfname == fname)
3965 {
3966 if (backup_copy)
3967 {
3968 /*
3969 * There is a small chance that we removed the original,
3970 * try to move the copy in its place.
3971 * This may not work if the vim_rename() fails.
3972 * In that case we leave the copy around.
3973 */
3974 /* If file does not exist, put the copy in its place */
3975 if (mch_stat((char *)fname, &st) < 0)
3976 vim_rename(backup, fname);
3977 /* if original file does exist throw away the copy */
3978 if (mch_stat((char *)fname, &st) >= 0)
3979 mch_remove(backup);
3980 }
3981 else
3982 {
3983 /* try to put the original file back */
3984 vim_rename(backup, fname);
3985 }
3986 }
3987
3988 /* if original file no longer exists give an extra warning */
3989 if (!newfile && mch_stat((char *)fname, &st) < 0)
3990 end = 0;
3991 }
3992
3993#ifdef FEAT_MBYTE
3994 if (wfname != fname)
3995 vim_free(wfname);
3996#endif
3997 goto fail;
3998 }
3999 errmsg = NULL;
4000
4001#if defined(MACOS_CLASSIC) || defined(WIN3264)
4002 /* TODO: Is it need for MACOS_X? (Dany) */
4003 /*
4004 * On macintosh copy the original files attributes (i.e. the backup)
4005 * This is done in order to preserve the ressource fork and the
4006 * Finder attribute (label, comments, custom icons, file creatore)
4007 */
4008 if (backup != NULL && overwriting && !append)
4009 {
4010 if (backup_copy)
4011 (void)mch_copy_file_attribute(wfname, backup);
4012 else
4013 (void)mch_copy_file_attribute(backup, wfname);
4014 }
4015
4016 if (!overwriting && !append)
4017 {
4018 if (buf->b_ffname != NULL)
4019 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
4020 /* Should copy ressource fork */
4021 }
4022#endif
4023
4024 write_info.bw_fd = fd;
4025
4026#ifdef FEAT_CRYPT
4027 if (*buf->b_p_key && !filtering)
4028 {
4029 crypt_init_keys(buf->b_p_key);
4030 /* Write magic number, so that Vim knows that this file is encrypted
4031 * when reading it again. This also undergoes utf-8 to ucs-2/4
4032 * conversion when needed. */
4033 write_info.bw_buf = (char_u *)CRYPT_MAGIC;
4034 write_info.bw_len = CRYPT_MAGIC_LEN;
4035 write_info.bw_flags = FIO_NOCONVERT;
4036 if (buf_write_bytes(&write_info) == FAIL)
4037 end = 0;
4038 wb_flags |= FIO_ENCRYPTED;
4039 }
4040#endif
4041
4042 write_info.bw_buf = buffer;
4043 nchars = 0;
4044
4045 /* use "++bin", "++nobin" or 'binary' */
4046 if (eap != NULL && eap->force_bin != 0)
4047 write_bin = (eap->force_bin == FORCE_BIN);
4048 else
4049 write_bin = buf->b_p_bin;
4050
4051#ifdef FEAT_MBYTE
4052 /*
4053 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004054 * Skip it when appending and the file already existed, the BOM only makes
4055 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004057 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004058 {
4059 write_info.bw_len = make_bom(buffer, fenc);
4060 if (write_info.bw_len > 0)
4061 {
4062 /* don't convert, do encryption */
4063 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4064 if (buf_write_bytes(&write_info) == FAIL)
4065 end = 0;
4066 else
4067 nchars += write_info.bw_len;
4068 }
4069 }
4070#endif
4071
4072 write_info.bw_len = bufsize;
4073#ifdef HAS_BW_FLAGS
4074 write_info.bw_flags = wb_flags;
4075#endif
4076 fileformat = get_fileformat_force(buf, eap);
4077 s = buffer;
4078 len = 0;
4079 for (lnum = start; lnum <= end; ++lnum)
4080 {
4081 /*
4082 * The next while loop is done once for each character written.
4083 * Keep it fast!
4084 */
4085 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4086 while ((c = *++ptr) != NUL)
4087 {
4088 if (c == NL)
4089 *s = NUL; /* replace newlines with NULs */
4090 else if (c == CAR && fileformat == EOL_MAC)
4091 *s = NL; /* Mac: replace CRs with NLs */
4092 else
4093 *s = c;
4094 ++s;
4095 if (++len != bufsize)
4096 continue;
4097 if (buf_write_bytes(&write_info) == FAIL)
4098 {
4099 end = 0; /* write error: break loop */
4100 break;
4101 }
4102 nchars += bufsize;
4103 s = buffer;
4104 len = 0;
4105 }
4106 /* write failed or last line has no EOL: stop here */
4107 if (end == 0
4108 || (lnum == end
4109 && write_bin
4110 && (lnum == write_no_eol_lnum
4111 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4112 {
4113 ++lnum; /* written the line, count it */
4114 no_eol = TRUE;
4115 break;
4116 }
4117 if (fileformat == EOL_UNIX)
4118 *s++ = NL;
4119 else
4120 {
4121 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4122 if (fileformat == EOL_DOS) /* write CR-NL */
4123 {
4124 if (++len == bufsize)
4125 {
4126 if (buf_write_bytes(&write_info) == FAIL)
4127 {
4128 end = 0; /* write error: break loop */
4129 break;
4130 }
4131 nchars += bufsize;
4132 s = buffer;
4133 len = 0;
4134 }
4135 *s++ = NL;
4136 }
4137 }
4138 if (++len == bufsize && end)
4139 {
4140 if (buf_write_bytes(&write_info) == FAIL)
4141 {
4142 end = 0; /* write error: break loop */
4143 break;
4144 }
4145 nchars += bufsize;
4146 s = buffer;
4147 len = 0;
4148
4149 ui_breakcheck();
4150 if (got_int)
4151 {
4152 end = 0; /* Interrupted, break loop */
4153 break;
4154 }
4155 }
4156#ifdef VMS
4157 /*
4158 * On VMS there is a problem: newlines get added when writing blocks
4159 * at a time. Fix it by writing a line at a time.
4160 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004161 * Explanation: VAX/DECC RTL insists that records in some RMS
4162 * structures end with a newline (carriage return) character, and if
4163 * they don't it adds one.
4164 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004166 if ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004168 int b2write;
4169
4170 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4171 ? MIN(4096, bufsize)
4172 : MIN(buf->b_fab_mrs, bufsize));
4173
4174 b2write = len;
4175 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004177 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4178 if (buf_write_bytes(&write_info) == FAIL)
4179 {
4180 end = 0;
4181 break;
4182 }
4183 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 }
4185 write_info.bw_len = bufsize;
4186 nchars += len;
4187 s = buffer;
4188 len = 0;
4189 }
4190#endif
4191 }
4192 if (len > 0 && end > 0)
4193 {
4194 write_info.bw_len = len;
4195 if (buf_write_bytes(&write_info) == FAIL)
4196 end = 0; /* write error */
4197 nchars += len;
4198 }
4199
4200#if defined(UNIX) && defined(HAVE_FSYNC)
4201 /* On many journalling file systems there is a bug that causes both the
4202 * original and the backup file to be lost when halting the system right
4203 * after writing the file. That's because only the meta-data is
4204 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004205 * been written to disk and we don't lose it.
4206 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004207 * (could be a pipe).
4208 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4209 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210 {
4211 errmsg = (char_u *)_("E667: Fsync failed");
4212 end = 0;
4213 }
4214#endif
4215
Bram Moolenaara5792f52005-11-23 21:25:05 +00004216#ifdef UNIX
4217 /* When creating a new file, set its owner/group to that of the original
4218 * file. Get the new device and inode number. */
4219 if (backup != NULL && !backup_copy)
4220 {
4221# ifdef HAVE_FCHOWN
4222 struct stat st;
4223
4224 /* don't change the owner when it's already OK, some systems remove
4225 * permission or ACL stuff */
4226 if (mch_stat((char *)wfname, &st) < 0
4227 || st.st_uid != st_old.st_uid
4228 || st.st_gid != st_old.st_gid)
4229 {
4230 fchown(fd, st_old.st_uid, st_old.st_gid);
4231 if (perm >= 0) /* set permission again, may have changed */
4232 (void)mch_setperm(wfname, perm);
4233 }
4234# endif
4235 buf_setino(buf);
4236 }
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004237 else if (buf->b_dev < 0)
4238 /* Set the inode when creating a new file. */
4239 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004240#endif
4241
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 if (close(fd) != 0)
4243 {
4244 errmsg = (char_u *)_("E512: Close failed");
4245 end = 0;
4246 }
4247
4248#ifdef UNIX
4249 if (made_writable)
4250 perm &= ~0200; /* reset 'w' bit for security reasons */
4251#endif
4252 if (perm >= 0) /* set perm. of new file same as old file */
4253 (void)mch_setperm(wfname, perm);
4254#ifdef RISCOS
4255 if (!append && !filtering)
4256 /* Set the filetype after writing the file. */
4257 mch_set_filetype(wfname, buf->b_p_oft);
4258#endif
4259#ifdef HAVE_ACL
4260 /* Probably need to set the ACL before changing the user (can't set the
4261 * ACL on a file the user doesn't own). */
4262 if (!backup_copy)
4263 mch_set_acl(wfname, acl);
4264#endif
4265
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266
4267#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4268 if (wfname != fname)
4269 {
4270 /*
4271 * The file was written to a temp file, now it needs to be converted
4272 * with 'charconvert' to (overwrite) the output file.
4273 */
4274 if (end != 0)
4275 {
4276 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4277 wfname, fname) == FAIL)
4278 {
4279 write_info.bw_conv_error = TRUE;
4280 end = 0;
4281 }
4282 }
4283 mch_remove(wfname);
4284 vim_free(wfname);
4285 }
4286#endif
4287
4288 if (end == 0)
4289 {
4290 if (errmsg == NULL)
4291 {
4292#ifdef FEAT_MBYTE
4293 if (write_info.bw_conv_error)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00004294 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 else
4296#endif
4297 if (got_int)
4298 errmsg = (char_u *)_(e_interr);
4299 else
4300 errmsg = (char_u *)_("E514: write error (file system full?)");
4301 }
4302
4303 /*
4304 * If we have a backup file, try to put it in place of the new file,
4305 * because the new file is probably corrupt. This avoids loosing the
4306 * original file when trying to make a backup when writing the file a
4307 * second time.
4308 * When "backup_copy" is set we need to copy the backup over the new
4309 * file. Otherwise rename the backup file.
4310 * If this is OK, don't give the extra warning message.
4311 */
4312 if (backup != NULL)
4313 {
4314 if (backup_copy)
4315 {
4316 /* This may take a while, if we were interrupted let the user
4317 * know we got the message. */
4318 if (got_int)
4319 {
4320 MSG(_(e_interr));
4321 out_flush();
4322 }
4323 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4324 {
4325 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004326 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4327 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 {
4329 /* copy the file. */
4330 write_info.bw_buf = smallbuf;
4331#ifdef HAS_BW_FLAGS
4332 write_info.bw_flags = FIO_NOCONVERT;
4333#endif
4334 while ((write_info.bw_len = vim_read(fd, smallbuf,
4335 SMBUFSIZE)) > 0)
4336 if (buf_write_bytes(&write_info) == FAIL)
4337 break;
4338
4339 if (close(write_info.bw_fd) >= 0
4340 && write_info.bw_len == 0)
4341 end = 1; /* success */
4342 }
4343 close(fd); /* ignore errors for closing read file */
4344 }
4345 }
4346 else
4347 {
4348 if (vim_rename(backup, fname) == 0)
4349 end = 1;
4350 }
4351 }
4352 goto fail;
4353 }
4354
4355 lnum -= start; /* compute number of written lines */
4356 --no_wait_return; /* may wait for return now */
4357
4358#if !(defined(UNIX) || defined(VMS))
4359 fname = sfname; /* use shortname now, for the messages */
4360#endif
4361 if (!filtering)
4362 {
4363 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4364 c = FALSE;
4365#ifdef FEAT_MBYTE
4366 if (write_info.bw_conv_error)
4367 {
4368 STRCAT(IObuff, _(" CONVERSION ERROR"));
4369 c = TRUE;
4370 }
4371 else if (notconverted)
4372 {
4373 STRCAT(IObuff, _("[NOT converted]"));
4374 c = TRUE;
4375 }
4376 else if (converted)
4377 {
4378 STRCAT(IObuff, _("[converted]"));
4379 c = TRUE;
4380 }
4381#endif
4382 if (device)
4383 {
4384 STRCAT(IObuff, _("[Device]"));
4385 c = TRUE;
4386 }
4387 else if (newfile)
4388 {
4389 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4390 c = TRUE;
4391 }
4392 if (no_eol)
4393 {
4394 msg_add_eol();
4395 c = TRUE;
4396 }
4397 /* may add [unix/dos/mac] */
4398 if (msg_add_fileformat(fileformat))
4399 c = TRUE;
4400#ifdef FEAT_CRYPT
4401 if (wb_flags & FIO_ENCRYPTED)
4402 {
4403 STRCAT(IObuff, _("[crypted]"));
4404 c = TRUE;
4405 }
4406#endif
4407 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4408 if (!shortmess(SHM_WRITE))
4409 {
4410 if (append)
4411 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4412 else
4413 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4414 }
4415
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00004416 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417 }
4418
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004419 /* When written everything correctly: reset 'modified'. Unless not
4420 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004421 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422#ifdef FEAT_MBYTE
4423 && !write_info.bw_conv_error
4424#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004425 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4426 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004427 {
4428 unchanged(buf, TRUE);
4429 u_unchanged(buf);
4430 }
4431
4432 /*
4433 * If written to the current file, update the timestamp of the swap file
4434 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4435 */
4436 if (overwriting)
4437 {
4438 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004439 if (append)
4440 buf->b_flags &= ~BF_NEW;
4441 else
4442 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 }
4444
4445 /*
4446 * If we kept a backup until now, and we are in patch mode, then we make
4447 * the backup file our 'original' file.
4448 */
4449 if (*p_pm && dobackup)
4450 {
4451 char *org = (char *)buf_modname(
4452#ifdef SHORT_FNAME
4453 TRUE,
4454#else
4455 (buf->b_p_sn || buf->b_shortname),
4456#endif
4457 fname, p_pm, FALSE);
4458
4459 if (backup != NULL)
4460 {
4461 struct stat st;
4462
4463 /*
4464 * If the original file does not exist yet
4465 * the current backup file becomes the original file
4466 */
4467 if (org == NULL)
4468 EMSG(_("E205: Patchmode: can't save original file"));
4469 else if (mch_stat(org, &st) < 0)
4470 {
4471 vim_rename(backup, (char_u *)org);
4472 vim_free(backup); /* don't delete the file */
4473 backup = NULL;
4474#ifdef UNIX
4475 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4476#endif
4477 }
4478 }
4479 /*
4480 * If there is no backup file, remember that a (new) file was
4481 * created.
4482 */
4483 else
4484 {
4485 int empty_fd;
4486
4487 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004488 || (empty_fd = mch_open(org,
4489 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004490 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 EMSG(_("E206: patchmode: can't touch empty original file"));
4492 else
4493 close(empty_fd);
4494 }
4495 if (org != NULL)
4496 {
4497 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4498 vim_free(org);
4499 }
4500 }
4501
4502 /*
4503 * Remove the backup unless 'backup' option is set
4504 */
4505 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4506 EMSG(_("E207: Can't delete backup file"));
4507
4508#ifdef FEAT_SUN_WORKSHOP
4509 if (usingSunWorkShop)
4510 workshop_file_saved((char *) ffname);
4511#endif
4512
4513 goto nofail;
4514
4515 /*
4516 * Finish up. We get here either after failure or success.
4517 */
4518fail:
4519 --no_wait_return; /* may wait for return now */
4520nofail:
4521
4522 /* Done saving, we accept changed buffer warnings again */
4523 buf->b_saving = FALSE;
4524
4525 vim_free(backup);
4526 if (buffer != smallbuf)
4527 vim_free(buffer);
4528#ifdef FEAT_MBYTE
4529 vim_free(fenc_tofree);
4530 vim_free(write_info.bw_conv_buf);
4531# ifdef USE_ICONV
4532 if (write_info.bw_iconv_fd != (iconv_t)-1)
4533 {
4534 iconv_close(write_info.bw_iconv_fd);
4535 write_info.bw_iconv_fd = (iconv_t)-1;
4536 }
4537# endif
4538#endif
4539#ifdef HAVE_ACL
4540 mch_free_acl(acl);
4541#endif
4542
4543 if (errmsg != NULL)
4544 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004545 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546
4547 attr = hl_attr(HLF_E); /* set highlight for error messages */
4548 msg_add_fname(buf,
4549#ifndef UNIX
4550 sfname
4551#else
4552 fname
4553#endif
4554 ); /* put file name in IObuff with quotes */
4555 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4556 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4557 /* If the error message has the form "is ...", put the error number in
4558 * front of the file name. */
4559 if (errnum != NULL)
4560 {
4561 mch_memmove(IObuff + numlen, IObuff, STRLEN(IObuff) + 1);
4562 mch_memmove(IObuff, errnum, (size_t)numlen);
4563 }
4564 STRCAT(IObuff, errmsg);
4565 emsg(IObuff);
4566
4567 retval = FAIL;
4568 if (end == 0)
4569 {
4570 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4571 attr | MSG_HIST);
4572 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4573 attr | MSG_HIST);
4574
4575 /* Update the timestamp to avoid an "overwrite changed file"
4576 * prompt when writing again. */
4577 if (mch_stat((char *)fname, &st_old) >= 0)
4578 {
4579 buf_store_time(buf, &st_old, fname);
4580 buf->b_mtime_read = buf->b_mtime;
4581 }
4582 }
4583 }
4584 msg_scroll = msg_save;
4585
4586#ifdef FEAT_AUTOCMD
4587#ifdef FEAT_EVAL
4588 if (!should_abort(retval))
4589#else
4590 if (!got_int)
4591#endif
4592 {
4593 aco_save_T aco;
4594
4595 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4596
4597 /*
4598 * Apply POST autocommands.
4599 * Careful: The autocommands may call buf_write() recursively!
4600 */
4601 aucmd_prepbuf(&aco, buf);
4602
4603 if (append)
4604 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4605 FALSE, curbuf, eap);
4606 else if (filtering)
4607 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4608 FALSE, curbuf, eap);
4609 else if (reset_changed && whole)
4610 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4611 FALSE, curbuf, eap);
4612 else
4613 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4614 FALSE, curbuf, eap);
4615
4616 /* restore curwin/curbuf and a few other things */
4617 aucmd_restbuf(&aco);
4618
4619#ifdef FEAT_EVAL
4620 if (aborting()) /* autocmds may abort script processing */
4621 retval = FALSE;
4622#endif
4623 }
4624#endif
4625
4626 got_int |= prev_got_int;
4627
4628#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4629 /* Update machine specific information. */
4630 mch_post_buffer_write(buf);
4631#endif
4632 return retval;
4633}
4634
4635/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004636 * Set the name of the current buffer. Use when the buffer doesn't have a
4637 * name and a ":r" or ":w" command with a file name is used.
4638 */
4639 static int
4640set_rw_fname(fname, sfname)
4641 char_u *fname;
4642 char_u *sfname;
4643{
4644#ifdef FEAT_AUTOCMD
4645 /* It's like the unnamed buffer is deleted.... */
4646 if (curbuf->b_p_bl)
4647 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
4648 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
4649# ifdef FEAT_EVAL
4650 if (aborting()) /* autocmds may abort script processing */
4651 return FAIL;
4652# endif
4653#endif
4654
4655 if (setfname(curbuf, fname, sfname, FALSE) == OK)
4656 curbuf->b_flags |= BF_NOTEDITED;
4657
4658#ifdef FEAT_AUTOCMD
4659 /* ....and a new named one is created */
4660 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
4661 if (curbuf->b_p_bl)
4662 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
4663# ifdef FEAT_EVAL
4664 if (aborting()) /* autocmds may abort script processing */
4665 return FAIL;
4666# endif
4667
4668 /* Do filetype detection now if 'filetype' is empty. */
4669 if (*curbuf->b_p_ft == NUL)
4670 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004671 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar70836c82006-02-20 21:28:49 +00004672 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00004673 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004674 }
4675#endif
4676
4677 return OK;
4678}
4679
4680/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681 * Put file name into IObuff with quotes.
4682 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004683 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684msg_add_fname(buf, fname)
4685 buf_T *buf;
4686 char_u *fname;
4687{
4688 if (fname == NULL)
4689 fname = (char_u *)"-stdin-";
4690 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4691 IObuff[0] = '"';
4692 STRCAT(IObuff, "\" ");
4693}
4694
4695/*
4696 * Append message for text mode to IObuff.
4697 * Return TRUE if something appended.
4698 */
4699 static int
4700msg_add_fileformat(eol_type)
4701 int eol_type;
4702{
4703#ifndef USE_CRNL
4704 if (eol_type == EOL_DOS)
4705 {
4706 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4707 return TRUE;
4708 }
4709#endif
4710#ifndef USE_CR
4711 if (eol_type == EOL_MAC)
4712 {
4713 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4714 return TRUE;
4715 }
4716#endif
4717#if defined(USE_CRNL) || defined(USE_CR)
4718 if (eol_type == EOL_UNIX)
4719 {
4720 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4721 return TRUE;
4722 }
4723#endif
4724 return FALSE;
4725}
4726
4727/*
4728 * Append line and character count to IObuff.
4729 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004730 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731msg_add_lines(insert_space, lnum, nchars)
4732 int insert_space;
4733 long lnum;
4734 long nchars;
4735{
4736 char_u *p;
4737
4738 p = IObuff + STRLEN(IObuff);
4739
4740 if (insert_space)
4741 *p++ = ' ';
4742 if (shortmess(SHM_LINES))
4743 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4744 else
4745 {
4746 if (lnum == 1)
4747 STRCPY(p, _("1 line, "));
4748 else
4749 sprintf((char *)p, _("%ld lines, "), lnum);
4750 p += STRLEN(p);
4751 if (nchars == 1)
4752 STRCPY(p, _("1 character"));
4753 else
4754 sprintf((char *)p, _("%ld characters"), nchars);
4755 }
4756}
4757
4758/*
4759 * Append message for missing line separator to IObuff.
4760 */
4761 static void
4762msg_add_eol()
4763{
4764 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4765}
4766
4767/*
4768 * Check modification time of file, before writing to it.
4769 * The size isn't checked, because using a tool like "gzip" takes care of
4770 * using the same timestamp but can't set the size.
4771 */
4772 static int
4773check_mtime(buf, st)
4774 buf_T *buf;
4775 struct stat *st;
4776{
4777 if (buf->b_mtime_read != 0
4778 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4779 {
4780 msg_scroll = TRUE; /* don't overwrite messages here */
4781 msg_silent = 0; /* must give this prompt */
4782 /* don't use emsg() here, don't want to flush the buffers */
4783 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
4784 hl_attr(HLF_E));
4785 if (ask_yesno((char_u *)_("Do you really want to write to it"),
4786 TRUE) == 'n')
4787 return FAIL;
4788 msg_scroll = FALSE; /* always overwrite the file message now */
4789 }
4790 return OK;
4791}
4792
4793 static int
4794time_differs(t1, t2)
4795 long t1, t2;
4796{
4797#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
4798 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
4799 * the seconds. Since the roundoff is done when flushing the inode, the
4800 * time may change unexpectedly by one second!!! */
4801 return (t1 - t2 > 1 || t2 - t1 > 1);
4802#else
4803 return (t1 != t2);
4804#endif
4805}
4806
4807/*
4808 * Call write() to write a number of bytes to the file.
4809 * Also handles encryption and 'encoding' conversion.
4810 *
4811 * Return FAIL for failure, OK otherwise.
4812 */
4813 static int
4814buf_write_bytes(ip)
4815 struct bw_info *ip;
4816{
4817 int wlen;
4818 char_u *buf = ip->bw_buf; /* data to write */
4819 int len = ip->bw_len; /* length of data */
4820#ifdef HAS_BW_FLAGS
4821 int flags = ip->bw_flags; /* extra flags */
4822#endif
4823
4824#ifdef FEAT_MBYTE
4825 /*
4826 * Skip conversion when writing the crypt magic number or the BOM.
4827 */
4828 if (!(flags & FIO_NOCONVERT))
4829 {
4830 char_u *p;
4831 unsigned c;
4832 int n;
4833
4834 if (flags & FIO_UTF8)
4835 {
4836 /*
4837 * Convert latin1 in the buffer to UTF-8 in the file.
4838 */
4839 p = ip->bw_conv_buf; /* translate to buffer */
4840 for (wlen = 0; wlen < len; ++wlen)
4841 p += utf_char2bytes(buf[wlen], p);
4842 buf = ip->bw_conv_buf;
4843 len = (int)(p - ip->bw_conv_buf);
4844 }
4845 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
4846 {
4847 /*
4848 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
4849 * Latin1 chars in the file.
4850 */
4851 if (flags & FIO_LATIN1)
4852 p = buf; /* translate in-place (can only get shorter) */
4853 else
4854 p = ip->bw_conv_buf; /* translate to buffer */
4855 for (wlen = 0; wlen < len; wlen += n)
4856 {
4857 if (wlen == 0 && ip->bw_restlen != 0)
4858 {
4859 int l;
4860
4861 /* Use remainder of previous call. Append the start of
4862 * buf[] to get a full sequence. Might still be too
4863 * short! */
4864 l = CONV_RESTLEN - ip->bw_restlen;
4865 if (l > len)
4866 l = len;
4867 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004868 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869 if (n > ip->bw_restlen + len)
4870 {
4871 /* We have an incomplete byte sequence at the end to
4872 * be written. We can't convert it without the
4873 * remaining bytes. Keep them for the next call. */
4874 if (ip->bw_restlen + len > CONV_RESTLEN)
4875 return FAIL;
4876 ip->bw_restlen += len;
4877 break;
4878 }
4879 if (n > 1)
4880 c = utf_ptr2char(ip->bw_rest);
4881 else
4882 c = ip->bw_rest[0];
4883 if (n >= ip->bw_restlen)
4884 {
4885 n -= ip->bw_restlen;
4886 ip->bw_restlen = 0;
4887 }
4888 else
4889 {
4890 ip->bw_restlen -= n;
4891 mch_memmove(ip->bw_rest, ip->bw_rest + n,
4892 (size_t)ip->bw_restlen);
4893 n = 0;
4894 }
4895 }
4896 else
4897 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004898 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004899 if (n > len - wlen)
4900 {
4901 /* We have an incomplete byte sequence at the end to
4902 * be written. We can't convert it without the
4903 * remaining bytes. Keep them for the next call. */
4904 if (len - wlen > CONV_RESTLEN)
4905 return FAIL;
4906 ip->bw_restlen = len - wlen;
4907 mch_memmove(ip->bw_rest, buf + wlen,
4908 (size_t)ip->bw_restlen);
4909 break;
4910 }
4911 if (n > 1)
4912 c = utf_ptr2char(buf + wlen);
4913 else
4914 c = buf[wlen];
4915 }
4916
4917 ip->bw_conv_error |= ucs2bytes(c, &p, flags);
4918 }
4919 if (flags & FIO_LATIN1)
4920 len = (int)(p - buf);
4921 else
4922 {
4923 buf = ip->bw_conv_buf;
4924 len = (int)(p - ip->bw_conv_buf);
4925 }
4926 }
4927
4928# ifdef WIN3264
4929 else if (flags & FIO_CODEPAGE)
4930 {
4931 /*
4932 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
4933 * codepage.
4934 */
4935 char_u *from;
4936 size_t fromlen;
4937 char_u *to;
4938 int u8c;
4939 BOOL bad = FALSE;
4940 int needed;
4941
4942 if (ip->bw_restlen > 0)
4943 {
4944 /* Need to concatenate the remainder of the previous call and
4945 * the bytes of the current call. Use the end of the
4946 * conversion buffer for this. */
4947 fromlen = len + ip->bw_restlen;
4948 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
4949 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
4950 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
4951 }
4952 else
4953 {
4954 from = buf;
4955 fromlen = len;
4956 }
4957
4958 to = ip->bw_conv_buf;
4959 if (enc_utf8)
4960 {
4961 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
4962 * The buffer has been allocated to be big enough. */
4963 while (fromlen > 0)
4964 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004965 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 if (n > (int)fromlen) /* incomplete byte sequence */
4967 break;
4968 u8c = utf_ptr2char(from);
4969 *to++ = (u8c & 0xff);
4970 *to++ = (u8c >> 8);
4971 fromlen -= n;
4972 from += n;
4973 }
4974
4975 /* Copy remainder to ip->bw_rest[] to be used for the next
4976 * call. */
4977 if (fromlen > CONV_RESTLEN)
4978 {
4979 /* weird overlong sequence */
4980 ip->bw_conv_error = TRUE;
4981 return FAIL;
4982 }
4983 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004984 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985 }
4986 else
4987 {
4988 /* Convert from enc_codepage to UCS-2, to the start of the
4989 * buffer. The buffer has been allocated to be big enough. */
4990 ip->bw_restlen = 0;
4991 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004992 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004993 NULL, 0);
4994 if (needed == 0)
4995 {
4996 /* When conversion fails there may be a trailing byte. */
4997 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004998 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 NULL, 0);
5000 if (needed == 0)
5001 {
5002 /* Conversion doesn't work. */
5003 ip->bw_conv_error = TRUE;
5004 return FAIL;
5005 }
5006 /* Save the trailing byte for the next call. */
5007 ip->bw_rest[0] = from[fromlen - 1];
5008 ip->bw_restlen = 1;
5009 }
5010 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005011 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 (LPWSTR)to, needed);
5013 if (needed == 0)
5014 {
5015 /* Safety check: Conversion doesn't work. */
5016 ip->bw_conv_error = TRUE;
5017 return FAIL;
5018 }
5019 to += needed * 2;
5020 }
5021
5022 fromlen = to - ip->bw_conv_buf;
5023 buf = to;
5024# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5025 if (FIO_GET_CP(flags) == CP_UTF8)
5026 {
5027 /* Convert from UCS-2 to UTF-8, using the remainder of the
5028 * conversion buffer. Fails when out of space. */
5029 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5030 {
5031 u8c = *from++;
5032 u8c += (*from++ << 8);
5033 to += utf_char2bytes(u8c, to);
5034 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5035 {
5036 ip->bw_conv_error = TRUE;
5037 return FAIL;
5038 }
5039 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005040 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041 }
5042 else
5043#endif
5044 {
5045 /* Convert from UCS-2 to the codepage, using the remainder of
5046 * the conversion buffer. If the conversion uses the default
5047 * character "0", the data doesn't fit in this encoding, so
5048 * fail. */
5049 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5050 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005051 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0, &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 if (bad)
5053 {
5054 ip->bw_conv_error = TRUE;
5055 return FAIL;
5056 }
5057 }
5058 }
5059# endif
5060
Bram Moolenaar56718732006-03-15 22:53:57 +00005061# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 else if (flags & FIO_MACROMAN)
5063 {
5064 /*
5065 * Convert UTF-8 or latin1 to Apple MacRoman.
5066 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067 char_u *from;
5068 size_t fromlen;
5069
5070 if (ip->bw_restlen > 0)
5071 {
5072 /* Need to concatenate the remainder of the previous call and
5073 * the bytes of the current call. Use the end of the
5074 * conversion buffer for this. */
5075 fromlen = len + ip->bw_restlen;
5076 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5077 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5078 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5079 }
5080 else
5081 {
5082 from = buf;
5083 fromlen = len;
5084 }
5085
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005086 if (enc2macroman(from, fromlen,
5087 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5088 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 {
5090 ip->bw_conv_error = TRUE;
5091 return FAIL;
5092 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094 }
5095# endif
5096
5097# ifdef USE_ICONV
5098 if (ip->bw_iconv_fd != (iconv_t)-1)
5099 {
5100 const char *from;
5101 size_t fromlen;
5102 char *to;
5103 size_t tolen;
5104
5105 /* Convert with iconv(). */
5106 if (ip->bw_restlen > 0)
5107 {
5108 /* Need to concatenate the remainder of the previous call and
5109 * the bytes of the current call. Use the end of the
5110 * conversion buffer for this. */
5111 fromlen = len + ip->bw_restlen;
5112 from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5113 mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
5114 mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
5115 tolen = ip->bw_conv_buflen - fromlen;
5116 }
5117 else
5118 {
5119 from = (const char *)buf;
5120 fromlen = len;
5121 tolen = ip->bw_conv_buflen;
5122 }
5123 to = (char *)ip->bw_conv_buf;
5124
5125 if (ip->bw_first)
5126 {
5127 size_t save_len = tolen;
5128
5129 /* output the initial shift state sequence */
5130 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5131
5132 /* There is a bug in iconv() on Linux (which appears to be
5133 * wide-spread) which sets "to" to NULL and messes up "tolen".
5134 */
5135 if (to == NULL)
5136 {
5137 to = (char *)ip->bw_conv_buf;
5138 tolen = save_len;
5139 }
5140 ip->bw_first = FALSE;
5141 }
5142
5143 /*
5144 * If iconv() has an error or there is not enough room, fail.
5145 */
5146 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5147 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5148 || fromlen > CONV_RESTLEN)
5149 {
5150 ip->bw_conv_error = TRUE;
5151 return FAIL;
5152 }
5153
5154 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5155 if (fromlen > 0)
5156 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5157 ip->bw_restlen = (int)fromlen;
5158
5159 buf = ip->bw_conv_buf;
5160 len = (int)((char_u *)to - ip->bw_conv_buf);
5161 }
5162# endif
5163 }
5164#endif /* FEAT_MBYTE */
5165
5166#ifdef FEAT_CRYPT
5167 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5168 {
5169 int ztemp, t, i;
5170
5171 for (i = 0; i < len; i++)
5172 {
5173 ztemp = buf[i];
5174 buf[i] = ZENCODE(ztemp, t);
5175 }
5176 }
5177#endif
5178
5179 /* Repeat the write(), it may be interrupted by a signal. */
5180 while (len)
5181 {
5182 wlen = vim_write(ip->bw_fd, buf, len);
5183 if (wlen <= 0) /* error! */
5184 return FAIL;
5185 len -= wlen;
5186 buf += wlen;
5187 }
5188 return OK;
5189}
5190
5191#ifdef FEAT_MBYTE
5192/*
5193 * Convert a Unicode character to bytes.
5194 */
5195 static int
5196ucs2bytes(c, pp, flags)
5197 unsigned c; /* in: character */
5198 char_u **pp; /* in/out: pointer to result */
5199 int flags; /* FIO_ flags */
5200{
5201 char_u *p = *pp;
5202 int error = FALSE;
5203 int cc;
5204
5205
5206 if (flags & FIO_UCS4)
5207 {
5208 if (flags & FIO_ENDIAN_L)
5209 {
5210 *p++ = c;
5211 *p++ = (c >> 8);
5212 *p++ = (c >> 16);
5213 *p++ = (c >> 24);
5214 }
5215 else
5216 {
5217 *p++ = (c >> 24);
5218 *p++ = (c >> 16);
5219 *p++ = (c >> 8);
5220 *p++ = c;
5221 }
5222 }
5223 else if (flags & (FIO_UCS2 | FIO_UTF16))
5224 {
5225 if (c >= 0x10000)
5226 {
5227 if (flags & FIO_UTF16)
5228 {
5229 /* Make two words, ten bits of the character in each. First
5230 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5231 c -= 0x10000;
5232 if (c >= 0x100000)
5233 error = TRUE;
5234 cc = ((c >> 10) & 0x3ff) + 0xd800;
5235 if (flags & FIO_ENDIAN_L)
5236 {
5237 *p++ = cc;
5238 *p++ = ((unsigned)cc >> 8);
5239 }
5240 else
5241 {
5242 *p++ = ((unsigned)cc >> 8);
5243 *p++ = cc;
5244 }
5245 c = (c & 0x3ff) + 0xdc00;
5246 }
5247 else
5248 error = TRUE;
5249 }
5250 if (flags & FIO_ENDIAN_L)
5251 {
5252 *p++ = c;
5253 *p++ = (c >> 8);
5254 }
5255 else
5256 {
5257 *p++ = (c >> 8);
5258 *p++ = c;
5259 }
5260 }
5261 else /* Latin1 */
5262 {
5263 if (c >= 0x100)
5264 {
5265 error = TRUE;
5266 *p++ = 0xBF;
5267 }
5268 else
5269 *p++ = c;
5270 }
5271
5272 *pp = p;
5273 return error;
5274}
5275
5276/*
5277 * Return TRUE if "a" and "b" are the same 'encoding'.
5278 * Ignores difference between "ansi" and "latin1", "ucs-4" and "ucs-4be", etc.
5279 */
5280 static int
5281same_encoding(a, b)
5282 char_u *a;
5283 char_u *b;
5284{
5285 int f;
5286
5287 if (STRCMP(a, b) == 0)
5288 return TRUE;
5289 f = get_fio_flags(a);
5290 return (f != 0 && get_fio_flags(b) == f);
5291}
5292
5293/*
5294 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5295 * internal conversion.
5296 * if "ptr" is an empty string, use 'encoding'.
5297 */
5298 static int
5299get_fio_flags(ptr)
5300 char_u *ptr;
5301{
5302 int prop;
5303
5304 if (*ptr == NUL)
5305 ptr = p_enc;
5306
5307 prop = enc_canon_props(ptr);
5308 if (prop & ENC_UNICODE)
5309 {
5310 if (prop & ENC_2BYTE)
5311 {
5312 if (prop & ENC_ENDIAN_L)
5313 return FIO_UCS2 | FIO_ENDIAN_L;
5314 return FIO_UCS2;
5315 }
5316 if (prop & ENC_4BYTE)
5317 {
5318 if (prop & ENC_ENDIAN_L)
5319 return FIO_UCS4 | FIO_ENDIAN_L;
5320 return FIO_UCS4;
5321 }
5322 if (prop & ENC_2WORD)
5323 {
5324 if (prop & ENC_ENDIAN_L)
5325 return FIO_UTF16 | FIO_ENDIAN_L;
5326 return FIO_UTF16;
5327 }
5328 return FIO_UTF8;
5329 }
5330 if (prop & ENC_LATIN1)
5331 return FIO_LATIN1;
5332 /* must be ENC_DBCS, requires iconv() */
5333 return 0;
5334}
5335
5336#ifdef WIN3264
5337/*
5338 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5339 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5340 * Used for conversion between 'encoding' and 'fileencoding'.
5341 */
5342 static int
5343get_win_fio_flags(ptr)
5344 char_u *ptr;
5345{
5346 int cp;
5347
5348 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5349 if (!enc_utf8 && enc_codepage <= 0)
5350 return 0;
5351
5352 cp = encname2codepage(ptr);
5353 if (cp == 0)
5354 {
5355# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5356 if (STRCMP(ptr, "utf-8") == 0)
5357 cp = CP_UTF8;
5358 else
5359# endif
5360 return 0;
5361 }
5362 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5363}
5364#endif
5365
5366#ifdef MACOS_X
5367/*
5368 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5369 * needed for the internal conversion to/from utf-8 or latin1.
5370 */
5371 static int
5372get_mac_fio_flags(ptr)
5373 char_u *ptr;
5374{
5375 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5376 && (enc_canon_props(ptr) & ENC_MACROMAN))
5377 return FIO_MACROMAN;
5378 return 0;
5379}
5380#endif
5381
5382/*
5383 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5384 * "size" must be at least 2.
5385 * Return the name of the encoding and set "*lenp" to the length.
5386 * Returns NULL when no BOM found.
5387 */
5388 static char_u *
5389check_for_bom(p, size, lenp, flags)
5390 char_u *p;
5391 long size;
5392 int *lenp;
5393 int flags;
5394{
5395 char *name = NULL;
5396 int len = 2;
5397
5398 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
5399 && (flags == FIO_ALL || flags == 0))
5400 {
5401 name = "utf-8"; /* EF BB BF */
5402 len = 3;
5403 }
5404 else if (p[0] == 0xff && p[1] == 0xfe)
5405 {
5406 if (size >= 4 && p[2] == 0 && p[3] == 0
5407 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5408 {
5409 name = "ucs-4le"; /* FF FE 00 00 */
5410 len = 4;
5411 }
5412 else if (flags == FIO_ALL || flags == (FIO_UCS2 | FIO_ENDIAN_L))
5413 name = "ucs-2le"; /* FF FE */
5414 else if (flags == (FIO_UTF16 | FIO_ENDIAN_L))
5415 name = "utf-16le"; /* FF FE */
5416 }
5417 else if (p[0] == 0xfe && p[1] == 0xff
5418 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5419 {
5420 if (flags == FIO_UTF16)
5421 name = "utf-16"; /* FE FF */
5422 else
5423 name = "ucs-2"; /* FE FF */
5424 }
5425 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5426 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5427 {
5428 name = "ucs-4"; /* 00 00 FE FF */
5429 len = 4;
5430 }
5431
5432 *lenp = len;
5433 return (char_u *)name;
5434}
5435
5436/*
5437 * Generate a BOM in "buf[4]" for encoding "name".
5438 * Return the length of the BOM (zero when no BOM).
5439 */
5440 static int
5441make_bom(buf, name)
5442 char_u *buf;
5443 char_u *name;
5444{
5445 int flags;
5446 char_u *p;
5447
5448 flags = get_fio_flags(name);
5449
5450 /* Can't put a BOM in a non-Unicode file. */
5451 if (flags == FIO_LATIN1 || flags == 0)
5452 return 0;
5453
5454 if (flags == FIO_UTF8) /* UTF-8 */
5455 {
5456 buf[0] = 0xef;
5457 buf[1] = 0xbb;
5458 buf[2] = 0xbf;
5459 return 3;
5460 }
5461 p = buf;
5462 (void)ucs2bytes(0xfeff, &p, flags);
5463 return (int)(p - buf);
5464}
5465#endif
5466
5467/*
5468 * Try to find a shortname by comparing the fullname with the current
5469 * directory.
5470 * Returns NULL if not shorter name possible, pointer into "full_path"
5471 * otherwise.
5472 */
5473 char_u *
5474shorten_fname(full_path, dir_name)
5475 char_u *full_path;
5476 char_u *dir_name;
5477{
5478 int len;
5479 char_u *p;
5480
5481 if (full_path == NULL)
5482 return NULL;
5483 len = (int)STRLEN(dir_name);
5484 if (fnamencmp(dir_name, full_path, len) == 0)
5485 {
5486 p = full_path + len;
5487#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5488 /*
5489 * MSDOS: when a file is in the root directory, dir_name will end in a
5490 * slash, since C: by itself does not define a specific dir. In this
5491 * case p may already be correct. <negri>
5492 */
5493 if (!((len > 2) && (*(p - 2) == ':')))
5494#endif
5495 {
5496 if (vim_ispathsep(*p))
5497 ++p;
5498#ifndef VMS /* the path separator is always part of the path */
5499 else
5500 p = NULL;
5501#endif
5502 }
5503 }
5504#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5505 /*
5506 * When using a file in the current drive, remove the drive name:
5507 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5508 * a floppy from "A:\dir" to "B:\dir".
5509 */
5510 else if (len > 3
5511 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5512 && full_path[1] == ':'
5513 && vim_ispathsep(full_path[2]))
5514 p = full_path + 2;
5515#endif
5516 else
5517 p = NULL;
5518 return p;
5519}
5520
5521/*
5522 * Shorten filenames for all buffers.
5523 * When "force" is TRUE: Use full path from now on for files currently being
5524 * edited, both for file name and swap file name. Try to shorten the file
5525 * names a bit, if safe to do so.
5526 * When "force" is FALSE: Only try to shorten absolute file names.
5527 * For buffers that have buftype "nofile" or "scratch": never change the file
5528 * name.
5529 */
5530 void
5531shorten_fnames(force)
5532 int force;
5533{
5534 char_u dirname[MAXPATHL];
5535 buf_T *buf;
5536 char_u *p;
5537
5538 mch_dirname(dirname, MAXPATHL);
5539 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5540 {
5541 if (buf->b_fname != NULL
5542#ifdef FEAT_QUICKFIX
5543 && !bt_nofile(buf)
5544#endif
5545 && !path_with_url(buf->b_fname)
5546 && (force
5547 || buf->b_sfname == NULL
5548 || mch_isFullName(buf->b_sfname)))
5549 {
5550 vim_free(buf->b_sfname);
5551 buf->b_sfname = NULL;
5552 p = shorten_fname(buf->b_ffname, dirname);
5553 if (p != NULL)
5554 {
5555 buf->b_sfname = vim_strsave(p);
5556 buf->b_fname = buf->b_sfname;
5557 }
5558 if (p == NULL || buf->b_fname == NULL)
5559 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005560 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005561
5562 /* Always make the swap file name a full path, a "nofile" buffer may
5563 * also have a swap file. */
5564 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005565 }
5566#ifdef FEAT_WINDOWS
5567 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005568 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005569#endif
5570}
5571
5572#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5573 || defined(FEAT_GUI_MSWIN) \
5574 || defined(FEAT_GUI_MAC) \
5575 || defined(PROTO)
5576/*
5577 * Shorten all filenames in "fnames[count]" by current directory.
5578 */
5579 void
5580shorten_filenames(fnames, count)
5581 char_u **fnames;
5582 int count;
5583{
5584 int i;
5585 char_u dirname[MAXPATHL];
5586 char_u *p;
5587
5588 if (fnames == NULL || count < 1)
5589 return;
5590 mch_dirname(dirname, sizeof(dirname));
5591 for (i = 0; i < count; ++i)
5592 {
5593 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5594 {
5595 /* shorten_fname() returns pointer in given "fnames[i]". If free
5596 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5597 * "p" first then free fnames[i]. */
5598 p = vim_strsave(p);
5599 vim_free(fnames[i]);
5600 fnames[i] = p;
5601 }
5602 }
5603}
5604#endif
5605
5606/*
5607 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5608 * fo_o_h.ext for MSDOS or when shortname option set.
5609 *
5610 * Assumed that fname is a valid name found in the filesystem we assure that
5611 * the return value is a different name and ends in 'ext'.
5612 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5613 * characters otherwise.
5614 * Space for the returned name is allocated, must be freed later.
5615 * Returns NULL when out of memory.
5616 */
5617 char_u *
5618modname(fname, ext, prepend_dot)
5619 char_u *fname, *ext;
5620 int prepend_dot; /* may prepend a '.' to file name */
5621{
5622 return buf_modname(
5623#ifdef SHORT_FNAME
5624 TRUE,
5625#else
5626 (curbuf->b_p_sn || curbuf->b_shortname),
5627#endif
5628 fname, ext, prepend_dot);
5629}
5630
5631 char_u *
5632buf_modname(shortname, fname, ext, prepend_dot)
5633 int shortname; /* use 8.3 file name */
5634 char_u *fname, *ext;
5635 int prepend_dot; /* may prepend a '.' to file name */
5636{
5637 char_u *retval;
5638 char_u *s;
5639 char_u *e;
5640 char_u *ptr;
5641 int fnamelen, extlen;
5642
5643 extlen = (int)STRLEN(ext);
5644
5645 /*
5646 * If there is no file name we must get the name of the current directory
5647 * (we need the full path in case :cd is used).
5648 */
5649 if (fname == NULL || *fname == NUL)
5650 {
5651 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5652 if (retval == NULL)
5653 return NULL;
5654 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5655 (fnamelen = (int)STRLEN(retval)) == 0)
5656 {
5657 vim_free(retval);
5658 return NULL;
5659 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005660 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 {
5662 retval[fnamelen++] = PATHSEP;
5663 retval[fnamelen] = NUL;
5664 }
5665#ifndef SHORT_FNAME
5666 prepend_dot = FALSE; /* nothing to prepend a dot to */
5667#endif
5668 }
5669 else
5670 {
5671 fnamelen = (int)STRLEN(fname);
5672 retval = alloc((unsigned)(fnamelen + extlen + 3));
5673 if (retval == NULL)
5674 return NULL;
5675 STRCPY(retval, fname);
5676#ifdef VMS
5677 vms_remove_version(retval); /* we do not need versions here */
5678#endif
5679 }
5680
5681 /*
5682 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5683 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5684 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5685 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5686 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005687 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688 {
5689#ifndef RISCOS
5690 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005691# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005693# else
5694# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005696# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005698 )
5699 if (*ptr == '.') /* replace '.' by '_' */
5700 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005701#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005702 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005703 {
5704 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005706 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005707 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708
5709 /* the file name has at most BASENAMELEN characters. */
5710#ifndef SHORT_FNAME
5711 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5712 ptr[BASENAMELEN] = '\0';
5713#endif
5714
5715 s = ptr + STRLEN(ptr);
5716
5717 /*
5718 * For 8.3 file names we may have to reduce the length.
5719 */
5720#ifdef USE_LONG_FNAME
5721 if (!USE_LONG_FNAME || shortname)
5722#else
5723# ifndef SHORT_FNAME
5724 if (shortname)
5725# endif
5726#endif
5727 {
5728 /*
5729 * If there is no file name, or the file name ends in '/', and the
5730 * extension starts with '.', put a '_' before the dot, because just
5731 * ".ext" is invalid.
5732 */
5733 if (fname == NULL || *fname == NUL
5734 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5735 {
5736#ifdef RISCOS
5737 if (*ext == '/')
5738#else
5739 if (*ext == '.')
5740#endif
5741 *s++ = '_';
5742 }
5743 /*
5744 * If the extension starts with '.', truncate the base name at 8
5745 * characters
5746 */
5747#ifdef RISCOS
5748 /* We normally use '/', but swap files are '_' */
5749 else if (*ext == '/' || *ext == '_')
5750#else
5751 else if (*ext == '.')
5752#endif
5753 {
5754 if (s - ptr > (size_t)8)
5755 {
5756 s = ptr + 8;
5757 *s = '\0';
5758 }
5759 }
5760 /*
5761 * If the extension doesn't start with '.', and the file name
5762 * doesn't have an extension yet, append a '.'
5763 */
5764#ifdef RISCOS
5765 else if ((e = vim_strchr(ptr, '/')) == NULL)
5766 *s++ = '/';
5767#else
5768 else if ((e = vim_strchr(ptr, '.')) == NULL)
5769 *s++ = '.';
5770#endif
5771 /*
5772 * If the extension doesn't start with '.', and there already is an
5773 * extension, it may need to be tructated
5774 */
5775 else if ((int)STRLEN(e) + extlen > 4)
5776 s = e + 4 - extlen;
5777 }
5778#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5779 /*
5780 * If there is no file name, and the extension starts with '.', put a
5781 * '_' before the dot, because just ".ext" may be invalid if it's on a
5782 * FAT partition, and on HPFS it doesn't matter.
5783 */
5784 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5785 *s++ = '_';
5786#endif
5787
5788 /*
5789 * Append the extention.
5790 * ext can start with '.' and cannot exceed 3 more characters.
5791 */
5792 STRCPY(s, ext);
5793
5794#ifndef SHORT_FNAME
5795 /*
5796 * Prepend the dot.
5797 */
5798 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5799#ifdef RISCOS
5800 '/'
5801#else
5802 '.'
5803#endif
5804#ifdef USE_LONG_FNAME
5805 && USE_LONG_FNAME
5806#endif
5807 )
5808 {
5809 mch_memmove(e + 1, e, STRLEN(e) + 1);
5810#ifdef RISCOS
5811 *e = '/';
5812#else
5813 *e = '.';
5814#endif
5815 }
5816#endif
5817
5818 /*
5819 * Check that, after appending the extension, the file name is really
5820 * different.
5821 */
5822 if (fname != NULL && STRCMP(fname, retval) == 0)
5823 {
5824 /* we search for a character that can be replaced by '_' */
5825 while (--s >= ptr)
5826 {
5827 if (*s != '_')
5828 {
5829 *s = '_';
5830 break;
5831 }
5832 }
5833 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5834 *ptr = 'v';
5835 }
5836 return retval;
5837}
5838
5839/*
5840 * Like fgets(), but if the file line is too long, it is truncated and the
5841 * rest of the line is thrown away. Returns TRUE for end-of-file.
5842 */
5843 int
5844vim_fgets(buf, size, fp)
5845 char_u *buf;
5846 int size;
5847 FILE *fp;
5848{
5849 char *eof;
5850#define FGETS_SIZE 200
5851 char tbuf[FGETS_SIZE];
5852
5853 buf[size - 2] = NUL;
5854#ifdef USE_CR
5855 eof = fgets_cr((char *)buf, size, fp);
5856#else
5857 eof = fgets((char *)buf, size, fp);
5858#endif
5859 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5860 {
5861 buf[size - 1] = NUL; /* Truncate the line */
5862
5863 /* Now throw away the rest of the line: */
5864 do
5865 {
5866 tbuf[FGETS_SIZE - 2] = NUL;
5867#ifdef USE_CR
5868 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
5869#else
5870 fgets((char *)tbuf, FGETS_SIZE, fp);
5871#endif
5872 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
5873 }
5874 return (eof == NULL);
5875}
5876
5877#if defined(USE_CR) || defined(PROTO)
5878/*
5879 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
5880 * Returns TRUE for end-of-file.
5881 * Only used for the Mac, because it's much slower than vim_fgets().
5882 */
5883 int
5884tag_fgets(buf, size, fp)
5885 char_u *buf;
5886 int size;
5887 FILE *fp;
5888{
5889 int i = 0;
5890 int c;
5891 int eof = FALSE;
5892
5893 for (;;)
5894 {
5895 c = fgetc(fp);
5896 if (c == EOF)
5897 {
5898 eof = TRUE;
5899 break;
5900 }
5901 if (c == '\r')
5902 {
5903 /* Always store a NL for end-of-line. */
5904 if (i < size - 1)
5905 buf[i++] = '\n';
5906 c = fgetc(fp);
5907 if (c != '\n') /* Macintosh format: single CR. */
5908 ungetc(c, fp);
5909 break;
5910 }
5911 if (i < size - 1)
5912 buf[i++] = c;
5913 if (c == '\n')
5914 break;
5915 }
5916 buf[i] = NUL;
5917 return eof;
5918}
5919#endif
5920
5921/*
5922 * rename() only works if both files are on the same file system, this
5923 * function will (attempts to?) copy the file across if rename fails -- webb
5924 * Return -1 for failure, 0 for success.
5925 */
5926 int
5927vim_rename(from, to)
5928 char_u *from;
5929 char_u *to;
5930{
5931 int fd_in;
5932 int fd_out;
5933 int n;
5934 char *errmsg = NULL;
5935 char *buffer;
5936#ifdef AMIGA
5937 BPTR flock;
5938#endif
5939 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005940 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005941#ifdef HAVE_ACL
5942 vim_acl_T acl; /* ACL from original file */
5943#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944
5945 /*
5946 * When the names are identical, there is nothing to do.
5947 */
5948 if (fnamecmp(from, to) == 0)
5949 return 0;
5950
5951 /*
5952 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
5953 */
5954 if (mch_stat((char *)from, &st) < 0)
5955 return -1;
5956
5957 /*
5958 * Delete the "to" file, this is required on some systems to make the
5959 * mch_rename() work, on other systems it makes sure that we don't have
5960 * two files when the mch_rename() fails.
5961 */
5962
5963#ifdef AMIGA
5964 /*
5965 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
5966 * that the name of the "to" file is the same as the "from" file, even
5967 * though the names are different. To avoid the chance of accidently
5968 * deleting the "from" file (horror!) we lock it during the remove.
5969 *
5970 * When used for making a backup before writing the file: This should not
5971 * happen with ":w", because startscript() should detect this problem and
5972 * set buf->b_shortname, causing modname() to return a correct ".bak" file
5973 * name. This problem does exist with ":w filename", but then the
5974 * original file will be somewhere else so the backup isn't really
5975 * important. If autoscripting is off the rename may fail.
5976 */
5977 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
5978#endif
5979 mch_remove(to);
5980#ifdef AMIGA
5981 if (flock)
5982 UnLock(flock);
5983#endif
5984
5985 /*
5986 * First try a normal rename, return if it works.
5987 */
5988 if (mch_rename((char *)from, (char *)to) == 0)
5989 return 0;
5990
5991 /*
5992 * Rename() failed, try copying the file.
5993 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005994 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005995#ifdef HAVE_ACL
5996 /* For systems that support ACL: get the ACL from the original file. */
5997 acl = mch_get_acl(from);
5998#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005999 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6000 if (fd_in == -1)
6001 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006002
6003 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006004 fd_out = mch_open((char *)to,
6005 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006006 if (fd_out == -1)
6007 {
6008 close(fd_in);
6009 return -1;
6010 }
6011
6012 buffer = (char *)alloc(BUFSIZE);
6013 if (buffer == NULL)
6014 {
6015 close(fd_in);
6016 close(fd_out);
6017 return -1;
6018 }
6019
6020 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
6021 if (vim_write(fd_out, buffer, n) != n)
6022 {
6023 errmsg = _("E208: Error writing to \"%s\"");
6024 break;
6025 }
6026
6027 vim_free(buffer);
6028 close(fd_in);
6029 if (close(fd_out) < 0)
6030 errmsg = _("E209: Error closing \"%s\"");
6031 if (n < 0)
6032 {
6033 errmsg = _("E210: Error reading \"%s\"");
6034 to = from;
6035 }
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006036#ifndef UNIX /* for Unix mch_open() already set ther permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006037 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006038#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006039#ifdef HAVE_ACL
6040 mch_set_acl(to, acl);
6041#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006042 if (errmsg != NULL)
6043 {
6044 EMSG2(errmsg, to);
6045 return -1;
6046 }
6047 mch_remove(from);
6048 return 0;
6049}
6050
6051static int already_warned = FALSE;
6052
6053/*
6054 * Check if any not hidden buffer has been changed.
6055 * Postpone the check if there are characters in the stuff buffer, a global
6056 * command is being executed, a mapping is being executed or an autocommand is
6057 * busy.
6058 * Returns TRUE if some message was written (screen should be redrawn and
6059 * cursor positioned).
6060 */
6061 int
6062check_timestamps(focus)
6063 int focus; /* called for GUI focus event */
6064{
6065 buf_T *buf;
6066 int didit = 0;
6067 int n;
6068
6069 /* Don't check timestamps while system() or another low-level function may
6070 * cause us to lose and gain focus. */
6071 if (no_check_timestamps > 0)
6072 return FALSE;
6073
6074 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6075 * event and we would keep on checking if the file is steadily growing.
6076 * Do check again after typing something. */
6077 if (focus && did_check_timestamps)
6078 {
6079 need_check_timestamps = TRUE;
6080 return FALSE;
6081 }
6082
6083 if (!stuff_empty() || global_busy || !typebuf_typed()
6084#ifdef FEAT_AUTOCMD
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006085 || autocmd_busy || curbuf_lock > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006086#endif
6087 )
6088 need_check_timestamps = TRUE; /* check later */
6089 else
6090 {
6091 ++no_wait_return;
6092 did_check_timestamps = TRUE;
6093 already_warned = FALSE;
6094 for (buf = firstbuf; buf != NULL; )
6095 {
6096 /* Only check buffers in a window. */
6097 if (buf->b_nwindows > 0)
6098 {
6099 n = buf_check_timestamp(buf, focus);
6100 if (didit < n)
6101 didit = n;
6102 if (n > 0 && !buf_valid(buf))
6103 {
6104 /* Autocommands have removed the buffer, start at the
6105 * first one again. */
6106 buf = firstbuf;
6107 continue;
6108 }
6109 }
6110 buf = buf->b_next;
6111 }
6112 --no_wait_return;
6113 need_check_timestamps = FALSE;
6114 if (need_wait_return && didit == 2)
6115 {
6116 /* make sure msg isn't overwritten */
6117 msg_puts((char_u *)"\n");
6118 out_flush();
6119 }
6120 }
6121 return didit;
6122}
6123
6124/*
6125 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6126 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6127 * empty.
6128 */
6129 static int
6130move_lines(frombuf, tobuf)
6131 buf_T *frombuf;
6132 buf_T *tobuf;
6133{
6134 buf_T *tbuf = curbuf;
6135 int retval = OK;
6136 linenr_T lnum;
6137 char_u *p;
6138
6139 /* Copy the lines in "frombuf" to "tobuf". */
6140 curbuf = tobuf;
6141 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6142 {
6143 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6144 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6145 {
6146 vim_free(p);
6147 retval = FAIL;
6148 break;
6149 }
6150 vim_free(p);
6151 }
6152
6153 /* Delete all the lines in "frombuf". */
6154 if (retval != FAIL)
6155 {
6156 curbuf = frombuf;
6157 while (!bufempty())
6158 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE) == FAIL)
6159 {
6160 /* Oops! We could try putting back the saved lines, but that
6161 * might fail again... */
6162 retval = FAIL;
6163 break;
6164 }
6165 }
6166
6167 curbuf = tbuf;
6168 return retval;
6169}
6170
6171/*
6172 * Check if buffer "buf" has been changed.
6173 * Also check if the file for a new buffer unexpectedly appeared.
6174 * return 1 if a changed buffer was found.
6175 * return 2 if a message has been displayed.
6176 * return 0 otherwise.
6177 */
6178/*ARGSUSED*/
6179 int
6180buf_check_timestamp(buf, focus)
6181 buf_T *buf;
6182 int focus; /* called for GUI focus event */
6183{
6184 struct stat st;
6185 int stat_res;
6186 int retval = 0;
6187 char_u *path;
6188 char_u *tbuf;
6189 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006190 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006191 int helpmesg = FALSE;
6192 int reload = FALSE;
6193#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6194 int can_reload = FALSE;
6195#endif
6196 size_t orig_size = buf->b_orig_size;
6197 int orig_mode = buf->b_orig_mode;
6198#ifdef FEAT_GUI
6199 int save_mouse_correct = need_mouse_correct;
6200#endif
6201#ifdef FEAT_AUTOCMD
6202 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006203 int n;
6204 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006205#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006206 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006207
6208 /* If there is no file name, the buffer is not loaded, 'buftype' is
6209 * set, we are in the middle of a save or being called recursively: ignore
6210 * this buffer. */
6211 if (buf->b_ffname == NULL
6212 || buf->b_ml.ml_mfp == NULL
6213#if defined(FEAT_QUICKFIX)
6214 || *buf->b_p_bt != NUL
6215#endif
6216 || buf->b_saving
6217#ifdef FEAT_AUTOCMD
6218 || busy
6219#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006220#ifdef FEAT_NETBEANS_INTG
6221 || isNetbeansBuffer(buf)
6222#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223 )
6224 return 0;
6225
6226 if ( !(buf->b_flags & BF_NOTEDITED)
6227 && buf->b_mtime != 0
6228 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6229 || time_differs((long)st.st_mtime, buf->b_mtime)
6230#ifdef HAVE_ST_MODE
6231 || (int)st.st_mode != buf->b_orig_mode
6232#else
6233 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6234#endif
6235 ))
6236 {
6237 retval = 1;
6238
Bram Moolenaar316059c2006-01-14 21:18:42 +00006239 /* set b_mtime to stop further warnings (e.g., when executing
6240 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006241 if (stat_res < 0)
6242 {
6243 buf->b_mtime = 0;
6244 buf->b_orig_size = 0;
6245 buf->b_orig_mode = 0;
6246 }
6247 else
6248 buf_store_time(buf, &st, buf->b_ffname);
6249
6250 /* Don't do anything for a directory. Might contain the file
6251 * explorer. */
6252 if (mch_isdir(buf->b_fname))
6253 ;
6254
6255 /*
6256 * If 'autoread' is set, the buffer has no changes and the file still
6257 * exists, reload the buffer. Use the buffer-local option value if it
6258 * was set, the global option value otherwise.
6259 */
6260 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6261 && !bufIsChanged(buf) && stat_res >= 0)
6262 reload = TRUE;
6263 else
6264 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006265 if (stat_res < 0)
6266 reason = "deleted";
6267 else if (bufIsChanged(buf))
6268 reason = "conflict";
6269 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6270 reason = "changed";
6271 else if (orig_mode != buf->b_orig_mode)
6272 reason = "mode";
6273 else
6274 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006276#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277 /*
6278 * Only give the warning if there are no FileChangedShell
6279 * autocommands.
6280 * Avoid being called recursively by setting "busy".
6281 */
6282 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006283# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006284 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6285 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006286# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6288 buf->b_fname, buf->b_fname, FALSE, buf);
6289 busy = FALSE;
6290 if (n)
6291 {
6292 if (!buf_valid(buf))
6293 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006294# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006295 s = get_vim_var_str(VV_FCS_CHOICE);
6296 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6297 reload = TRUE;
6298 else if (STRCMP(s, "ask") == 0)
6299 n = FALSE;
6300 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006301# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006302 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006303 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006304 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006305#endif
6306 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006307 if (*reason == 'd')
6308 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309 else
6310 {
6311 helpmesg = TRUE;
6312#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6313 can_reload = TRUE;
6314#endif
6315 /*
6316 * Check if the file contents really changed to avoid
6317 * giving a warning when only the timestamp was set (e.g.,
6318 * checked out of CVS). Always warn when the buffer was
6319 * changed.
6320 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006321 if (reason[2] == 'n')
6322 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006324 mesg2 = _("See \":help W12\" for more info.");
6325 }
6326 else if (reason[1] == 'h')
6327 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006329 mesg2 = _("See \":help W11\" for more info.");
6330 }
6331 else if (*reason == 'm')
6332 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006333 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006334 mesg2 = _("See \":help W16\" for more info.");
6335 }
6336 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006337 }
6338 }
6339 }
6340
6341 }
6342 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6343 && vim_fexists(buf->b_ffname))
6344 {
6345 retval = 1;
6346 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6347 buf->b_flags |= BF_NEW_W;
6348#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6349 can_reload = TRUE;
6350#endif
6351 }
6352
6353 if (mesg != NULL)
6354 {
6355 path = home_replace_save(buf, buf->b_fname);
6356 if (path != NULL)
6357 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006358 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006359 mesg2 = "";
6360 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6361 + STRLEN(mesg2) + 2));
6362 sprintf((char *)tbuf, mesg, path);
6363#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6364 if (can_reload)
6365 {
6366 if (*mesg2 != NUL)
6367 {
6368 STRCAT(tbuf, "\n");
6369 STRCAT(tbuf, mesg2);
6370 }
6371 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6372 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6373 reload = TRUE;
6374 }
6375 else
6376#endif
6377 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6378 {
6379 if (*mesg2 != NUL)
6380 {
6381 STRCAT(tbuf, "; ");
6382 STRCAT(tbuf, mesg2);
6383 }
6384 EMSG(tbuf);
6385 retval = 2;
6386 }
6387 else
6388 {
Bram Moolenaared203462004-06-16 11:19:22 +00006389# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006391# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006392 {
6393 msg_start();
6394 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6395 if (*mesg2 != NUL)
6396 msg_puts_attr((char_u *)mesg2,
6397 hl_attr(HLF_W) + MSG_HIST);
6398 msg_clr_eos();
6399 (void)msg_end();
6400 if (emsg_silent == 0)
6401 {
6402 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006403# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006404 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006405# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006406 /* give the user some time to think about it */
6407 ui_delay(1000L, TRUE);
6408
6409 /* don't redraw and erase the message */
6410 redraw_cmdline = FALSE;
6411 }
6412 }
6413 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006414 }
6415
6416 vim_free(path);
6417 vim_free(tbuf);
6418 }
6419 }
6420
6421 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006422 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006423 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424
Bram Moolenaar56718732006-03-15 22:53:57 +00006425#ifdef FEAT_AUTOCMD
6426 if (buf_valid(buf))
6427 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6428 buf->b_fname, buf->b_fname, FALSE, buf);
6429#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006430#ifdef FEAT_GUI
6431 /* restore this in case an autocommand has set it; it would break
6432 * 'mousefocus' */
6433 need_mouse_correct = save_mouse_correct;
6434#endif
6435
6436 return retval;
6437}
6438
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006439/*
6440 * Reload a buffer that is already loaded.
6441 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006442 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6443 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006444 */
6445 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006446buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006447 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006448 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006449{
6450 exarg_T ea;
6451 pos_T old_cursor;
6452 linenr_T old_topline;
6453 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006454 buf_T *savebuf;
6455 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006456 aco_save_T aco;
6457
6458 /* set curwin/curbuf for "buf" and save some things */
6459 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006460
6461 /* We only want to read the text from the file, not reset the syntax
6462 * highlighting, clear marks, diff status, etc. Force the fileformat
6463 * and encoding to be the same. */
6464 if (prep_exarg(&ea, buf) == OK)
6465 {
6466 old_cursor = curwin->w_cursor;
6467 old_topline = curwin->w_topline;
6468
6469 /*
6470 * To behave like when a new file is edited (matters for
6471 * BufReadPost autocommands) we first need to delete the current
6472 * buffer contents. But if reading the file fails we should keep
6473 * the old contents. Can't use memory only, the file might be
6474 * too big. Use a hidden buffer to move the buffer contents to.
6475 */
6476 if (bufempty())
6477 savebuf = NULL;
6478 else
6479 {
6480 /* Allocate a buffer without putting it in the buffer list. */
6481 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006482 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006483 {
6484 /* Open the memline. */
6485 curbuf = savebuf;
6486 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006487 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006488 curbuf = buf;
6489 curwin->w_buffer = buf;
6490 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006491 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006492 || move_lines(buf, savebuf) == FAIL)
6493 {
6494 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6495 buf->b_fname);
6496 saved = FAIL;
6497 }
6498 }
6499
6500 if (saved == OK)
6501 {
6502 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6503#ifdef FEAT_AUTOCMD
6504 keep_filetype = TRUE; /* don't detect 'filetype' */
6505#endif
6506 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6507 (linenr_T)0,
6508 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6509 {
6510#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6511 if (!aborting())
6512#endif
6513 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006514 if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006515 {
6516 /* Put the text back from the save buffer. First
6517 * delete any lines that readfile() added. */
6518 while (!bufempty())
Bram Moolenaar8424a622006-04-19 21:23:36 +00006519 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006520 break;
6521 (void)move_lines(savebuf, buf);
6522 }
6523 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006524 else if (buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006525 {
6526 /* Mark the buffer as unmodified and free undo info. */
6527 unchanged(buf, TRUE);
6528 u_blockfree(buf);
6529 u_clearall(buf);
6530 }
6531 }
6532 vim_free(ea.cmd);
6533
Bram Moolenaar8424a622006-04-19 21:23:36 +00006534 if (savebuf != NULL && buf_valid(savebuf))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006535 wipe_buffer(savebuf, FALSE);
6536
6537#ifdef FEAT_DIFF
6538 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00006539 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006540#endif
6541
6542 /* Restore the topline and cursor position and check it (lines may
6543 * have been removed). */
6544 if (old_topline > curbuf->b_ml.ml_line_count)
6545 curwin->w_topline = curbuf->b_ml.ml_line_count;
6546 else
6547 curwin->w_topline = old_topline;
6548 curwin->w_cursor = old_cursor;
6549 check_cursor();
6550 update_topline();
6551#ifdef FEAT_AUTOCMD
6552 keep_filetype = FALSE;
6553#endif
6554#ifdef FEAT_FOLDING
6555 {
6556 win_T *wp;
6557
6558 /* Update folds unless they are defined manually. */
6559 FOR_ALL_WINDOWS(wp)
6560 if (wp->w_buffer == curwin->w_buffer
6561 && !foldmethodIsManual(wp))
6562 foldUpdateAll(wp);
6563 }
6564#endif
6565 /* If the mode didn't change and 'readonly' was set, keep the old
6566 * value; the user probably used the ":view" command. But don't
6567 * reset it, might have had a read error. */
6568 if (orig_mode == curbuf->b_orig_mode)
6569 curbuf->b_p_ro |= old_ro;
6570 }
6571
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006572 /* restore curwin/curbuf and a few other things */
6573 aucmd_restbuf(&aco);
6574 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006575}
6576
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577/*ARGSUSED*/
6578 void
6579buf_store_time(buf, st, fname)
6580 buf_T *buf;
6581 struct stat *st;
6582 char_u *fname;
6583{
6584 buf->b_mtime = (long)st->st_mtime;
6585 buf->b_orig_size = (size_t)st->st_size;
6586#ifdef HAVE_ST_MODE
6587 buf->b_orig_mode = (int)st->st_mode;
6588#else
6589 buf->b_orig_mode = mch_getperm(fname);
6590#endif
6591}
6592
6593/*
6594 * Adjust the line with missing eol, used for the next write.
6595 * Used for do_filter(), when the input lines for the filter are deleted.
6596 */
6597 void
6598write_lnum_adjust(offset)
6599 linenr_T offset;
6600{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006601 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006602 write_no_eol_lnum += offset;
6603}
6604
6605#if defined(TEMPDIRNAMES) || defined(PROTO)
6606static long temp_count = 0; /* Temp filename counter. */
6607
6608/*
6609 * Delete the temp directory and all files it contains.
6610 */
6611 void
6612vim_deltempdir()
6613{
6614 char_u **files;
6615 int file_count;
6616 int i;
6617
6618 if (vim_tempdir != NULL)
6619 {
6620 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6621 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6622 EW_DIR|EW_FILE|EW_SILENT) == OK)
6623 {
6624 for (i = 0; i < file_count; ++i)
6625 mch_remove(files[i]);
6626 FreeWild(file_count, files);
6627 }
6628 gettail(NameBuff)[-1] = NUL;
6629 (void)mch_rmdir(NameBuff);
6630
6631 vim_free(vim_tempdir);
6632 vim_tempdir = NULL;
6633 }
6634}
6635#endif
6636
6637/*
6638 * vim_tempname(): Return a unique name that can be used for a temp file.
6639 *
6640 * The temp file is NOT created.
6641 *
6642 * The returned pointer is to allocated memory.
6643 * The returned pointer is NULL if no valid name was found.
6644 */
6645/*ARGSUSED*/
6646 char_u *
6647vim_tempname(extra_char)
6648 int extra_char; /* character to use in the name instead of '?' */
6649{
6650#ifdef USE_TMPNAM
6651 char_u itmp[L_tmpnam]; /* use tmpnam() */
6652#else
6653 char_u itmp[TEMPNAMELEN];
6654#endif
6655
6656#ifdef TEMPDIRNAMES
6657 static char *(tempdirs[]) = {TEMPDIRNAMES};
6658 int i;
6659 long nr;
6660 long off;
6661# ifndef EEXIST
6662 struct stat st;
6663# endif
6664
6665 /*
6666 * This will create a directory for private use by this instance of Vim.
6667 * This is done once, and the same directory is used for all temp files.
6668 * This method avoids security problems because of symlink attacks et al.
6669 * It's also a bit faster, because we only need to check for an existing
6670 * file when creating the directory and not for each temp file.
6671 */
6672 if (vim_tempdir == NULL)
6673 {
6674 /*
6675 * Try the entries in TEMPDIRNAMES to create the temp directory.
6676 */
6677 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6678 {
6679 /* expand $TMP, leave room for "/v1100000/999999999" */
6680 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6681 if (mch_isdir(itmp)) /* directory exists */
6682 {
6683# ifdef __EMX__
6684 /* If $TMP contains a forward slash (perhaps using bash or
6685 * tcsh), don't add a backslash, use a forward slash!
6686 * Adding 2 backslashes didn't work. */
6687 if (vim_strchr(itmp, '/') != NULL)
6688 STRCAT(itmp, "/");
6689 else
6690# endif
6691 add_pathsep(itmp);
6692
6693 /* Get an arbitrary number of up to 6 digits. When it's
6694 * unlikely that it already exists it will be faster,
6695 * otherwise it doesn't matter. The use of mkdir() avoids any
6696 * security problems because of the predictable number. */
6697 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6698
6699 /* Try up to 10000 different values until we find a name that
6700 * doesn't exist. */
6701 for (off = 0; off < 10000L; ++off)
6702 {
6703 int r;
6704#if defined(UNIX) || defined(VMS)
6705 mode_t umask_save;
6706#endif
6707
6708 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6709# ifndef EEXIST
6710 /* If mkdir() does not set errno to EEXIST, check for
6711 * existing file here. There is a race condition then,
6712 * although it's fail-safe. */
6713 if (mch_stat((char *)itmp, &st) >= 0)
6714 continue;
6715# endif
6716#if defined(UNIX) || defined(VMS)
6717 /* Make sure the umask doesn't remove the executable bit.
6718 * "repl" has been reported to use "177". */
6719 umask_save = umask(077);
6720#endif
6721 r = vim_mkdir(itmp, 0700);
6722#if defined(UNIX) || defined(VMS)
6723 (void)umask(umask_save);
6724#endif
6725 if (r == 0)
6726 {
6727 char_u *buf;
6728
6729 /* Directory was created, use this name.
6730 * Expand to full path; When using the current
6731 * directory a ":cd" would confuse us. */
6732 buf = alloc((unsigned)MAXPATHL + 1);
6733 if (buf != NULL)
6734 {
6735 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6736 == FAIL)
6737 STRCPY(buf, itmp);
6738# ifdef __EMX__
6739 if (vim_strchr(buf, '/') != NULL)
6740 STRCAT(buf, "/");
6741 else
6742# endif
6743 add_pathsep(buf);
6744 vim_tempdir = vim_strsave(buf);
6745 vim_free(buf);
6746 }
6747 break;
6748 }
6749# ifdef EEXIST
6750 /* If the mkdir() didn't fail because the file/dir exists,
6751 * we probably can't create any dir here, try another
6752 * place. */
6753 if (errno != EEXIST)
6754# endif
6755 break;
6756 }
6757 if (vim_tempdir != NULL)
6758 break;
6759 }
6760 }
6761 }
6762
6763 if (vim_tempdir != NULL)
6764 {
6765 /* There is no need to check if the file exists, because we own the
6766 * directory and nobody else creates a file in it. */
6767 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6768 return vim_strsave(itmp);
6769 }
6770
6771 return NULL;
6772
6773#else /* TEMPDIRNAMES */
6774
6775# ifdef WIN3264
6776 char szTempFile[_MAX_PATH + 1];
6777 char buf4[4];
6778 char_u *retval;
6779 char_u *p;
6780
6781 STRCPY(itmp, "");
6782 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6783 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6784 strcpy(buf4, "VIM");
6785 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6786 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6787 return NULL;
6788 /* GetTempFileName() will create the file, we don't want that */
6789 (void)DeleteFile(itmp);
6790
6791 /* Backslashes in a temp file name cause problems when filtering with
6792 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6793 * didn't set 'shellslash'. */
6794 retval = vim_strsave(itmp);
6795 if (*p_shcf == '-' || p_ssl)
6796 for (p = retval; *p; ++p)
6797 if (*p == '\\')
6798 *p = '/';
6799 return retval;
6800
6801# else /* WIN3264 */
6802
6803# ifdef USE_TMPNAM
6804 /* tmpnam() will make its own name */
6805 if (*tmpnam((char *)itmp) == NUL)
6806 return NULL;
6807# else
6808 char_u *p;
6809
6810# ifdef VMS_TEMPNAM
6811 /* mktemp() is not working on VMS. It seems to be
6812 * a do-nothing function. Therefore we use tempnam().
6813 */
6814 sprintf((char *)itmp, "VIM%c", extra_char);
6815 p = (char_u *)tempnam("tmp:", (char *)itmp);
6816 if (p != NULL)
6817 {
6818 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6819 * and VIM will then be unable to find the file later */
6820 STRCPY(itmp, p);
6821 STRCAT(itmp, ".txt");
6822 free(p);
6823 }
6824 else
6825 return NULL;
6826# else
6827 STRCPY(itmp, TEMPNAME);
6828 if ((p = vim_strchr(itmp, '?')) != NULL)
6829 *p = extra_char;
6830 if (mktemp((char *)itmp) == NULL)
6831 return NULL;
6832# endif
6833# endif
6834
6835 return vim_strsave(itmp);
6836# endif /* WIN3264 */
6837#endif /* TEMPDIRNAMES */
6838}
6839
6840#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6841/*
6842 * Convert all backslashes in fname to forward slashes in-place.
6843 */
6844 void
6845forward_slash(fname)
6846 char_u *fname;
6847{
6848 char_u *p;
6849
6850 for (p = fname; *p != NUL; ++p)
6851# ifdef FEAT_MBYTE
6852 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006853 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006854 ++p;
6855 else
6856# endif
6857 if (*p == '\\')
6858 *p = '/';
6859}
6860#endif
6861
6862
6863/*
6864 * Code for automatic commands.
6865 *
6866 * Only included when "FEAT_AUTOCMD" has been defined.
6867 */
6868
6869#if defined(FEAT_AUTOCMD) || defined(PROTO)
6870
6871/*
6872 * The autocommands are stored in a list for each event.
6873 * Autocommands for the same pattern, that are consecutive, are joined
6874 * together, to avoid having to match the pattern too often.
6875 * The result is an array of Autopat lists, which point to AutoCmd lists:
6876 *
6877 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
6878 * Autopat.cmds Autopat.cmds
6879 * | |
6880 * V V
6881 * AutoCmd.next AutoCmd.next
6882 * | |
6883 * V V
6884 * AutoCmd.next NULL
6885 * |
6886 * V
6887 * NULL
6888 *
6889 * first_autopat[1] --> Autopat.next --> NULL
6890 * Autopat.cmds
6891 * |
6892 * V
6893 * AutoCmd.next
6894 * |
6895 * V
6896 * NULL
6897 * etc.
6898 *
6899 * The order of AutoCmds is important, this is the order in which they were
6900 * defined and will have to be executed.
6901 */
6902typedef struct AutoCmd
6903{
6904 char_u *cmd; /* The command to be executed (NULL
6905 when command has been removed) */
6906 char nested; /* If autocommands nest here */
6907 char last; /* last command in list */
6908#ifdef FEAT_EVAL
6909 scid_T scriptID; /* script ID where defined */
6910#endif
6911 struct AutoCmd *next; /* Next AutoCmd in list */
6912} AutoCmd;
6913
6914typedef struct AutoPat
6915{
6916 int group; /* group ID */
6917 char_u *pat; /* pattern as typed (NULL when pattern
6918 has been removed) */
6919 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00006920 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921 char allow_dirs; /* Pattern may match whole path */
6922 char last; /* last pattern for apply_autocmds() */
6923 AutoCmd *cmds; /* list of commands to do */
6924 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006925 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926} AutoPat;
6927
6928static struct event_name
6929{
6930 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006931 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006932} event_names[] =
6933{
6934 {"BufAdd", EVENT_BUFADD},
6935 {"BufCreate", EVENT_BUFADD},
6936 {"BufDelete", EVENT_BUFDELETE},
6937 {"BufEnter", EVENT_BUFENTER},
6938 {"BufFilePost", EVENT_BUFFILEPOST},
6939 {"BufFilePre", EVENT_BUFFILEPRE},
6940 {"BufHidden", EVENT_BUFHIDDEN},
6941 {"BufLeave", EVENT_BUFLEAVE},
6942 {"BufNew", EVENT_BUFNEW},
6943 {"BufNewFile", EVENT_BUFNEWFILE},
6944 {"BufRead", EVENT_BUFREADPOST},
6945 {"BufReadCmd", EVENT_BUFREADCMD},
6946 {"BufReadPost", EVENT_BUFREADPOST},
6947 {"BufReadPre", EVENT_BUFREADPRE},
6948 {"BufUnload", EVENT_BUFUNLOAD},
6949 {"BufWinEnter", EVENT_BUFWINENTER},
6950 {"BufWinLeave", EVENT_BUFWINLEAVE},
6951 {"BufWipeout", EVENT_BUFWIPEOUT},
6952 {"BufWrite", EVENT_BUFWRITEPRE},
6953 {"BufWritePost", EVENT_BUFWRITEPOST},
6954 {"BufWritePre", EVENT_BUFWRITEPRE},
6955 {"BufWriteCmd", EVENT_BUFWRITECMD},
6956 {"CmdwinEnter", EVENT_CMDWINENTER},
6957 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006958 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006959 {"CursorHold", EVENT_CURSORHOLD},
6960 {"CursorHoldI", EVENT_CURSORHOLDI},
6961 {"CursorMoved", EVENT_CURSORMOVED},
6962 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006963 {"EncodingChanged", EVENT_ENCODINGCHANGED},
6964 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006965 {"FileAppendPost", EVENT_FILEAPPENDPOST},
6966 {"FileAppendPre", EVENT_FILEAPPENDPRE},
6967 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
6968 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
Bram Moolenaar56718732006-03-15 22:53:57 +00006969 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006970 {"FileChangedRO", EVENT_FILECHANGEDRO},
6971 {"FileReadPost", EVENT_FILEREADPOST},
6972 {"FileReadPre", EVENT_FILEREADPRE},
6973 {"FileReadCmd", EVENT_FILEREADCMD},
6974 {"FileType", EVENT_FILETYPE},
6975 {"FileWritePost", EVENT_FILEWRITEPOST},
6976 {"FileWritePre", EVENT_FILEWRITEPRE},
6977 {"FileWriteCmd", EVENT_FILEWRITECMD},
6978 {"FilterReadPost", EVENT_FILTERREADPOST},
6979 {"FilterReadPre", EVENT_FILTERREADPRE},
6980 {"FilterWritePost", EVENT_FILTERWRITEPOST},
6981 {"FilterWritePre", EVENT_FILTERWRITEPRE},
6982 {"FocusGained", EVENT_FOCUSGAINED},
6983 {"FocusLost", EVENT_FOCUSLOST},
6984 {"FuncUndefined", EVENT_FUNCUNDEFINED},
6985 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar265e5072006-08-29 16:13:22 +00006986 {"GUIFailed", EVENT_GUIFAILED},
Bram Moolenaar843ee412004-06-30 16:16:41 +00006987 {"InsertChange", EVENT_INSERTCHANGE},
6988 {"InsertEnter", EVENT_INSERTENTER},
6989 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00006990 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00006991 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
6992 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006993 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00006994 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar5c4bab02006-03-10 21:37:46 +00006995 {"ShellCmdPost", EVENT_SHELLCMDPOST},
6996 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaara2031822006-03-07 22:29:51 +00006997 {"SourcePre", EVENT_SOURCEPRE},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00006998 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006999 {"StdinReadPost", EVENT_STDINREADPOST},
7000 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00007001 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00007002 {"Syntax", EVENT_SYNTAX},
Bram Moolenaar70836c82006-02-20 21:28:49 +00007003 {"TabEnter", EVENT_TABENTER},
7004 {"TabLeave", EVENT_TABLEAVE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007005 {"TermChanged", EVENT_TERMCHANGED},
7006 {"TermResponse", EVENT_TERMRESPONSE},
7007 {"User", EVENT_USER},
7008 {"VimEnter", EVENT_VIMENTER},
7009 {"VimLeave", EVENT_VIMLEAVE},
7010 {"VimLeavePre", EVENT_VIMLEAVEPRE},
7011 {"WinEnter", EVENT_WINENTER},
7012 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar56718732006-03-15 22:53:57 +00007013 {"VimResized", EVENT_VIMRESIZED},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007014 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007015};
7016
7017static AutoPat *first_autopat[NUM_EVENTS] =
7018{
7019 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7020 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7021 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7022 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007023 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7024 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007025};
7026
7027/*
7028 * struct used to keep status while executing autocommands for an event.
7029 */
7030typedef struct AutoPatCmd
7031{
7032 AutoPat *curpat; /* next AutoPat to examine */
7033 AutoCmd *nextcmd; /* next AutoCmd to execute */
7034 int group; /* group being used */
7035 char_u *fname; /* fname to match with */
7036 char_u *sfname; /* sfname to match with */
7037 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007038 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007039 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7040 buf is deleted */
7041 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042} AutoPatCmd;
7043
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007044static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007045
Bram Moolenaar071d4272004-06-13 20:20:40 +00007046/*
7047 * augroups stores a list of autocmd group names.
7048 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007049static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007050#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7051
7052/*
7053 * The ID of the current group. Group 0 is the default one.
7054 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055static int current_augroup = AUGROUP_DEFAULT;
7056
7057static int au_need_clean = FALSE; /* need to delete marked patterns */
7058
Bram Moolenaar754b5602006-02-09 23:53:20 +00007059static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007060static void au_remove_pat __ARGS((AutoPat *ap));
7061static void au_remove_cmds __ARGS((AutoPat *ap));
7062static void au_cleanup __ARGS((void));
7063static int au_new_group __ARGS((char_u *name));
7064static void au_del_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007065static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7066static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007068static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007070static 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 +00007071static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007072static 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 +00007073static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7074
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007075
Bram Moolenaar754b5602006-02-09 23:53:20 +00007076static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007077static int last_group;
7078
7079/*
7080 * Show the autocommands for one AutoPat.
7081 */
7082 static void
7083show_autocmd(ap, event)
7084 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007085 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007086{
7087 AutoCmd *ac;
7088
7089 /* Check for "got_int" (here and at various places below), which is set
7090 * when "q" has been hit for the "--more--" prompt */
7091 if (got_int)
7092 return;
7093 if (ap->pat == NULL) /* pattern has been removed */
7094 return;
7095
7096 msg_putchar('\n');
7097 if (got_int)
7098 return;
7099 if (event != last_event || ap->group != last_group)
7100 {
7101 if (ap->group != AUGROUP_DEFAULT)
7102 {
7103 if (AUGROUP_NAME(ap->group) == NULL)
7104 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7105 else
7106 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7107 msg_puts((char_u *)" ");
7108 }
7109 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7110 last_event = event;
7111 last_group = ap->group;
7112 msg_putchar('\n');
7113 if (got_int)
7114 return;
7115 }
7116 msg_col = 4;
7117 msg_outtrans(ap->pat);
7118
7119 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7120 {
7121 if (ac->cmd != NULL) /* skip removed commands */
7122 {
7123 if (msg_col >= 14)
7124 msg_putchar('\n');
7125 msg_col = 14;
7126 if (got_int)
7127 return;
7128 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007129#ifdef FEAT_EVAL
7130 if (p_verbose > 0)
7131 last_set_msg(ac->scriptID);
7132#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007133 if (got_int)
7134 return;
7135 if (ac->next != NULL)
7136 {
7137 msg_putchar('\n');
7138 if (got_int)
7139 return;
7140 }
7141 }
7142 }
7143}
7144
7145/*
7146 * Mark an autocommand pattern for deletion.
7147 */
7148 static void
7149au_remove_pat(ap)
7150 AutoPat *ap;
7151{
7152 vim_free(ap->pat);
7153 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007154 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007155 au_need_clean = TRUE;
7156}
7157
7158/*
7159 * Mark all commands for a pattern for deletion.
7160 */
7161 static void
7162au_remove_cmds(ap)
7163 AutoPat *ap;
7164{
7165 AutoCmd *ac;
7166
7167 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7168 {
7169 vim_free(ac->cmd);
7170 ac->cmd = NULL;
7171 }
7172 au_need_clean = TRUE;
7173}
7174
7175/*
7176 * Cleanup autocommands and patterns that have been deleted.
7177 * This is only done when not executing autocommands.
7178 */
7179 static void
7180au_cleanup()
7181{
7182 AutoPat *ap, **prev_ap;
7183 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007184 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007185
7186 if (autocmd_busy || !au_need_clean)
7187 return;
7188
7189 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007190 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7191 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007192 {
7193 /* loop over all autocommand patterns */
7194 prev_ap = &(first_autopat[(int)event]);
7195 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7196 {
7197 /* loop over all commands for this pattern */
7198 prev_ac = &(ap->cmds);
7199 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7200 {
7201 /* remove the command if the pattern is to be deleted or when
7202 * the command has been marked for deletion */
7203 if (ap->pat == NULL || ac->cmd == NULL)
7204 {
7205 *prev_ac = ac->next;
7206 vim_free(ac->cmd);
7207 vim_free(ac);
7208 }
7209 else
7210 prev_ac = &(ac->next);
7211 }
7212
7213 /* remove the pattern if it has been marked for deletion */
7214 if (ap->pat == NULL)
7215 {
7216 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007217 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007218 vim_free(ap);
7219 }
7220 else
7221 prev_ap = &(ap->next);
7222 }
7223 }
7224
7225 au_need_clean = FALSE;
7226}
7227
7228/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007229 * Called when buffer is freed, to remove/invalidate related buffer-local
7230 * autocmds.
7231 */
7232 void
7233aubuflocal_remove(buf)
7234 buf_T *buf;
7235{
7236 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007237 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007238 AutoPatCmd *apc;
7239
7240 /* invalidate currently executing autocommands */
7241 for (apc = active_apc_list; apc; apc = apc->next)
7242 if (buf->b_fnum == apc->arg_bufnr)
7243 apc->arg_bufnr = 0;
7244
7245 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007246 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7247 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007248 /* loop over all autocommand patterns */
7249 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7250 if (ap->buflocal_nr == buf->b_fnum)
7251 {
7252 au_remove_pat(ap);
7253 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007254 {
7255 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007256 smsg((char_u *)
7257 _("auto-removing autocommand: %s <buffer=%d>"),
7258 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007259 verbose_leave();
7260 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007261 }
7262 au_cleanup();
7263}
7264
7265/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007266 * Add an autocmd group name.
7267 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7268 */
7269 static int
7270au_new_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 yet, add it */
7277 {
7278 /* First try using a free entry. */
7279 for (i = 0; i < augroups.ga_len; ++i)
7280 if (AUGROUP_NAME(i) == NULL)
7281 break;
7282 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7283 return AUGROUP_ERROR;
7284
7285 AUGROUP_NAME(i) = vim_strsave(name);
7286 if (AUGROUP_NAME(i) == NULL)
7287 return AUGROUP_ERROR;
7288 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007289 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007290 }
7291
7292 return i;
7293}
7294
7295 static void
7296au_del_group(name)
7297 char_u *name;
7298{
7299 int i;
7300
7301 i = au_find_group(name);
7302 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7303 EMSG2(_("E367: No such group: \"%s\""), name);
7304 else
7305 {
7306 vim_free(AUGROUP_NAME(i));
7307 AUGROUP_NAME(i) = NULL;
7308 }
7309}
7310
7311/*
7312 * Find the ID of an autocmd group name.
7313 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7314 */
7315 static int
7316au_find_group(name)
7317 char_u *name;
7318{
7319 int i;
7320
7321 for (i = 0; i < augroups.ga_len; ++i)
7322 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7323 return i;
7324 return AUGROUP_ERROR;
7325}
7326
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007327/*
7328 * Return TRUE if augroup "name" exists.
7329 */
7330 int
7331au_has_group(name)
7332 char_u *name;
7333{
7334 return au_find_group(name) != AUGROUP_ERROR;
7335}
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007336
Bram Moolenaar071d4272004-06-13 20:20:40 +00007337/*
7338 * ":augroup {name}".
7339 */
7340 void
7341do_augroup(arg, del_group)
7342 char_u *arg;
7343 int del_group;
7344{
7345 int i;
7346
7347 if (del_group)
7348 {
7349 if (*arg == NUL)
7350 EMSG(_(e_argreq));
7351 else
7352 au_del_group(arg);
7353 }
7354 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7355 current_augroup = AUGROUP_DEFAULT;
7356 else if (*arg) /* ":aug xxx": switch to group xxx */
7357 {
7358 i = au_new_group(arg);
7359 if (i != AUGROUP_ERROR)
7360 current_augroup = i;
7361 }
7362 else /* ":aug": list the group names */
7363 {
7364 msg_start();
7365 for (i = 0; i < augroups.ga_len; ++i)
7366 {
7367 if (AUGROUP_NAME(i) != NULL)
7368 {
7369 msg_puts(AUGROUP_NAME(i));
7370 msg_puts((char_u *)" ");
7371 }
7372 }
7373 msg_clr_eos();
7374 msg_end();
7375 }
7376}
7377
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007378#if defined(EXITFREE) || defined(PROTO)
7379 void
7380free_all_autocmds()
7381{
7382 for (current_augroup = -1; current_augroup < augroups.ga_len;
7383 ++current_augroup)
7384 do_autocmd((char_u *)"", TRUE);
7385 ga_clear_strings(&augroups);
7386}
7387#endif
7388
Bram Moolenaar071d4272004-06-13 20:20:40 +00007389/*
7390 * Return the event number for event name "start".
7391 * Return NUM_EVENTS if the event name was not found.
7392 * Return a pointer to the next event name in "end".
7393 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007394 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007395event_name2nr(start, end)
7396 char_u *start;
7397 char_u **end;
7398{
7399 char_u *p;
7400 int i;
7401 int len;
7402
7403 /* the event name ends with end of line, a blank or a comma */
7404 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7405 ;
7406 for (i = 0; event_names[i].name != NULL; ++i)
7407 {
7408 len = (int)STRLEN(event_names[i].name);
7409 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7410 break;
7411 }
7412 if (*p == ',')
7413 ++p;
7414 *end = p;
7415 if (event_names[i].name == NULL)
7416 return NUM_EVENTS;
7417 return event_names[i].event;
7418}
7419
7420/*
7421 * Return the name for event "event".
7422 */
7423 static char_u *
7424event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007425 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007426{
7427 int i;
7428
7429 for (i = 0; event_names[i].name != NULL; ++i)
7430 if (event_names[i].event == event)
7431 return (char_u *)event_names[i].name;
7432 return (char_u *)"Unknown";
7433}
7434
7435/*
7436 * Scan over the events. "*" stands for all events.
7437 */
7438 static char_u *
7439find_end_event(arg, have_group)
7440 char_u *arg;
7441 int have_group; /* TRUE when group name was found */
7442{
7443 char_u *pat;
7444 char_u *p;
7445
7446 if (*arg == '*')
7447 {
7448 if (arg[1] && !vim_iswhite(arg[1]))
7449 {
7450 EMSG2(_("E215: Illegal character after *: %s"), arg);
7451 return NULL;
7452 }
7453 pat = arg + 1;
7454 }
7455 else
7456 {
7457 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7458 {
7459 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7460 {
7461 if (have_group)
7462 EMSG2(_("E216: No such event: %s"), pat);
7463 else
7464 EMSG2(_("E216: No such group or event: %s"), pat);
7465 return NULL;
7466 }
7467 }
7468 }
7469 return pat;
7470}
7471
7472/*
7473 * Return TRUE if "event" is included in 'eventignore'.
7474 */
7475 static int
7476event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007477 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007478{
7479 char_u *p = p_ei;
7480
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007481 while (*p != NUL)
7482 {
7483 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7484 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007485 if (event_name2nr(p, &p) == event)
7486 return TRUE;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007487 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007488
7489 return FALSE;
7490}
7491
7492/*
7493 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7494 */
7495 int
7496check_ei()
7497{
7498 char_u *p = p_ei;
7499
Bram Moolenaar071d4272004-06-13 20:20:40 +00007500 while (*p)
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007501 {
7502 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7503 {
7504 p += 3;
7505 if (*p == ',')
7506 ++p;
7507 }
7508 else if (event_name2nr(p, &p) == NUM_EVENTS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007509 return FAIL;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007510 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007511
7512 return OK;
7513}
7514
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007515# if defined(FEAT_SYN_HL) || defined(PROTO)
7516
7517/*
7518 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7519 * buffer loaded into the window. "what" must start with a comma.
7520 * Returns the old value of 'eventignore' in allocated memory.
7521 */
7522 char_u *
7523au_event_disable(what)
7524 char *what;
7525{
7526 char_u *new_ei;
7527 char_u *save_ei;
7528
7529 save_ei = vim_strsave(p_ei);
7530 if (save_ei != NULL)
7531 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007532 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007533 if (new_ei != NULL)
7534 {
7535 STRCAT(new_ei, what);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007536 set_string_option_direct((char_u *)"ei", -1, new_ei,
7537 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007538 vim_free(new_ei);
7539 }
7540 }
7541 return save_ei;
7542}
7543
7544 void
7545au_event_restore(old_ei)
7546 char_u *old_ei;
7547{
7548 if (old_ei != NULL)
7549 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007550 set_string_option_direct((char_u *)"ei", -1, old_ei,
7551 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007552 vim_free(old_ei);
7553 }
7554}
7555# endif /* FEAT_SYN_HL */
7556
Bram Moolenaar071d4272004-06-13 20:20:40 +00007557/*
7558 * do_autocmd() -- implements the :autocmd command. Can be used in the
7559 * following ways:
7560 *
7561 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7562 * will be automatically executed for <event>
7563 * when editing a file matching <pat>, in
7564 * the current group.
7565 * :autocmd <event> <pat> Show the auto-commands associated with
7566 * <event> and <pat>.
7567 * :autocmd <event> Show the auto-commands associated with
7568 * <event>.
7569 * :autocmd Show all auto-commands.
7570 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7571 * <event> and <pat>, and add the command
7572 * <cmd>, for the current group.
7573 * :autocmd! <event> <pat> Remove all auto-commands associated with
7574 * <event> and <pat> for the current group.
7575 * :autocmd! <event> Remove all auto-commands associated with
7576 * <event> for the current group.
7577 * :autocmd! Remove ALL auto-commands for the current
7578 * group.
7579 *
7580 * Multiple events and patterns may be given separated by commas. Here are
7581 * some examples:
7582 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7583 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7584 *
7585 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007586 *
7587 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007588 */
7589 void
7590do_autocmd(arg, forceit)
7591 char_u *arg;
7592 int forceit;
7593{
7594 char_u *pat;
7595 char_u *envpat = NULL;
7596 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007597 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007598 int need_free = FALSE;
7599 int nested = FALSE;
7600 int group;
7601
7602 /*
7603 * Check for a legal group name. If not, use AUGROUP_ALL.
7604 */
7605 group = au_get_grouparg(&arg);
7606 if (arg == NULL) /* out of memory */
7607 return;
7608
7609 /*
7610 * Scan over the events.
7611 * If we find an illegal name, return here, don't do anything.
7612 */
7613 pat = find_end_event(arg, group != AUGROUP_ALL);
7614 if (pat == NULL)
7615 return;
7616
7617 /*
7618 * Scan over the pattern. Put a NUL at the end.
7619 */
7620 pat = skipwhite(pat);
7621 cmd = pat;
7622 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7623 cmd++;
7624 if (*cmd)
7625 *cmd++ = NUL;
7626
7627 /* Expand environment variables in the pattern. Set 'shellslash', we want
7628 * forward slashes here. */
7629 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7630 {
7631#ifdef BACKSLASH_IN_FILENAME
7632 int p_ssl_save = p_ssl;
7633
7634 p_ssl = TRUE;
7635#endif
7636 envpat = expand_env_save(pat);
7637#ifdef BACKSLASH_IN_FILENAME
7638 p_ssl = p_ssl_save;
7639#endif
7640 if (envpat != NULL)
7641 pat = envpat;
7642 }
7643
7644 /*
7645 * Check for "nested" flag.
7646 */
7647 cmd = skipwhite(cmd);
7648 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7649 {
7650 nested = TRUE;
7651 cmd = skipwhite(cmd + 6);
7652 }
7653
7654 /*
7655 * Find the start of the commands.
7656 * Expand <sfile> in it.
7657 */
7658 if (*cmd != NUL)
7659 {
7660 cmd = expand_sfile(cmd);
7661 if (cmd == NULL) /* some error */
7662 return;
7663 need_free = TRUE;
7664 }
7665
7666 /*
7667 * Print header when showing autocommands.
7668 */
7669 if (!forceit && *cmd == NUL)
7670 {
7671 /* Highlight title */
7672 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7673 }
7674
7675 /*
7676 * Loop over the events.
7677 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007678 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007679 last_group = AUGROUP_ERROR; /* for listing the group name */
7680 if (*arg == '*' || *arg == NUL)
7681 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00007682 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7683 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007684 if (do_autocmd_event(event, pat,
7685 nested, cmd, forceit, group) == FAIL)
7686 break;
7687 }
7688 else
7689 {
7690 while (*arg && !vim_iswhite(*arg))
7691 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7692 nested, cmd, forceit, group) == FAIL)
7693 break;
7694 }
7695
7696 if (need_free)
7697 vim_free(cmd);
7698 vim_free(envpat);
7699}
7700
7701/*
7702 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7703 * The "argp" argument is advanced to the following argument.
7704 *
7705 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7706 */
7707 static int
7708au_get_grouparg(argp)
7709 char_u **argp;
7710{
7711 char_u *group_name;
7712 char_u *p;
7713 char_u *arg = *argp;
7714 int group = AUGROUP_ALL;
7715
7716 p = skiptowhite(arg);
7717 if (p > arg)
7718 {
7719 group_name = vim_strnsave(arg, (int)(p - arg));
7720 if (group_name == NULL) /* out of memory */
7721 return AUGROUP_ERROR;
7722 group = au_find_group(group_name);
7723 if (group == AUGROUP_ERROR)
7724 group = AUGROUP_ALL; /* no match, use all groups */
7725 else
7726 *argp = skipwhite(p); /* match, skip over group name */
7727 vim_free(group_name);
7728 }
7729 return group;
7730}
7731
7732/*
7733 * do_autocmd() for one event.
7734 * If *pat == NUL do for all patterns.
7735 * If *cmd == NUL show entries.
7736 * If forceit == TRUE delete entries.
7737 * If group is not AUGROUP_ALL, only use this group.
7738 */
7739 static int
7740do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007741 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007742 char_u *pat;
7743 int nested;
7744 char_u *cmd;
7745 int forceit;
7746 int group;
7747{
7748 AutoPat *ap;
7749 AutoPat **prev_ap;
7750 AutoCmd *ac;
7751 AutoCmd **prev_ac;
7752 int brace_level;
7753 char_u *endpat;
7754 int findgroup;
7755 int allgroups;
7756 int patlen;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00007757 int is_buflocal;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007758 int buflocal_nr;
7759 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007760
7761 if (group == AUGROUP_ALL)
7762 findgroup = current_augroup;
7763 else
7764 findgroup = group;
7765 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7766
7767 /*
7768 * Show or delete all patterns for an event.
7769 */
7770 if (*pat == NUL)
7771 {
7772 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7773 {
7774 if (forceit) /* delete the AutoPat, if it's in the current group */
7775 {
7776 if (ap->group == findgroup)
7777 au_remove_pat(ap);
7778 }
7779 else if (group == AUGROUP_ALL || ap->group == group)
7780 show_autocmd(ap, event);
7781 }
7782 }
7783
7784 /*
7785 * Loop through all the specified patterns.
7786 */
7787 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7788 {
7789 /*
7790 * Find end of the pattern.
7791 * Watch out for a comma in braces, like "*.\{obj,o\}".
7792 */
7793 brace_level = 0;
7794 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7795 || endpat[-1] == '\\'); ++endpat)
7796 {
7797 if (*endpat == '{')
7798 brace_level++;
7799 else if (*endpat == '}')
7800 brace_level--;
7801 }
7802 if (pat == endpat) /* ignore single comma */
7803 continue;
7804 patlen = (int)(endpat - pat);
7805
7806 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007807 * detect special <buflocal[=X]> buffer-local patterns
7808 */
7809 is_buflocal = FALSE;
7810 buflocal_nr = 0;
7811
7812 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7813 && pat[patlen - 1] == '>')
7814 {
7815 /* Error will be printed only for addition. printing and removing
7816 * will proceed silently. */
7817 is_buflocal = TRUE;
7818 if (patlen == 8)
7819 buflocal_nr = curbuf->b_fnum;
7820 else if (patlen > 9 && pat[7] == '=')
7821 {
7822 /* <buffer=abuf> */
7823 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7824 buflocal_nr = autocmd_bufnr;
7825 /* <buffer=123> */
7826 else if (skipdigits(pat + 8) == pat + patlen - 1)
7827 buflocal_nr = atoi((char *)pat + 8);
7828 }
7829 }
7830
7831 if (is_buflocal)
7832 {
7833 /* normalize pat into standard "<buffer>#N" form */
7834 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7835 pat = buflocal_pat; /* can modify pat and patlen */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00007836 patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007837 }
7838
7839 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007840 * Find AutoPat entries with this pattern.
7841 */
7842 prev_ap = &first_autopat[(int)event];
7843 while ((ap = *prev_ap) != NULL)
7844 {
7845 if (ap->pat != NULL)
7846 {
7847 /* Accept a pattern when:
7848 * - a group was specified and it's that group, or a group was
7849 * not specified and it's the current group, or a group was
7850 * not specified and we are listing
7851 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007852 * - the pattern matches.
7853 * For <buffer[=X]>, this condition works because we normalize
7854 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855 */
7856 if ((allgroups || ap->group == findgroup)
7857 && ap->patlen == patlen
7858 && STRNCMP(pat, ap->pat, patlen) == 0)
7859 {
7860 /*
7861 * Remove existing autocommands.
7862 * If adding any new autocmd's for this AutoPat, don't
7863 * delete the pattern from the autopat list, append to
7864 * this list.
7865 */
7866 if (forceit)
7867 {
7868 if (*cmd != NUL && ap->next == NULL)
7869 {
7870 au_remove_cmds(ap);
7871 break;
7872 }
7873 au_remove_pat(ap);
7874 }
7875
7876 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007877 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878 */
7879 else if (*cmd == NUL)
7880 show_autocmd(ap, event);
7881
7882 /*
7883 * Add autocmd to this autopat, if it's the last one.
7884 */
7885 else if (ap->next == NULL)
7886 break;
7887 }
7888 }
7889 prev_ap = &ap->next;
7890 }
7891
7892 /*
7893 * Add a new command.
7894 */
7895 if (*cmd != NUL)
7896 {
7897 /*
7898 * If the pattern we want to add a command to does appear at the
7899 * end of the list (or not is not in the list at all), add the
7900 * pattern at the end of the list.
7901 */
7902 if (ap == NULL)
7903 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007904 /* refuse to add buffer-local ap if buffer number is invalid */
7905 if (is_buflocal && (buflocal_nr == 0
7906 || buflist_findnr(buflocal_nr) == NULL))
7907 {
7908 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7909 buflocal_nr);
7910 return FAIL;
7911 }
7912
Bram Moolenaar071d4272004-06-13 20:20:40 +00007913 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7914 if (ap == NULL)
7915 return FAIL;
7916 ap->pat = vim_strnsave(pat, patlen);
7917 ap->patlen = patlen;
7918 if (ap->pat == NULL)
7919 {
7920 vim_free(ap);
7921 return FAIL;
7922 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007923
7924 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007925 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007926 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007927 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007928 }
7929 else
7930 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007931 char_u *reg_pat;
7932
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007933 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007934 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007935 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007936 if (reg_pat != NULL)
7937 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007938 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007939 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007940 {
7941 vim_free(ap->pat);
7942 vim_free(ap);
7943 return FAIL;
7944 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007945 }
7946 ap->cmds = NULL;
7947 *prev_ap = ap;
7948 ap->next = NULL;
7949 if (group == AUGROUP_ALL)
7950 ap->group = current_augroup;
7951 else
7952 ap->group = group;
7953 }
7954
7955 /*
7956 * Add the autocmd at the end of the AutoCmd list.
7957 */
7958 prev_ac = &(ap->cmds);
7959 while ((ac = *prev_ac) != NULL)
7960 prev_ac = &ac->next;
7961 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7962 if (ac == NULL)
7963 return FAIL;
7964 ac->cmd = vim_strsave(cmd);
7965#ifdef FEAT_EVAL
7966 ac->scriptID = current_SID;
7967#endif
7968 if (ac->cmd == NULL)
7969 {
7970 vim_free(ac);
7971 return FAIL;
7972 }
7973 ac->next = NULL;
7974 *prev_ac = ac;
7975 ac->nested = nested;
7976 }
7977 }
7978
7979 au_cleanup(); /* may really delete removed patterns/commands now */
7980 return OK;
7981}
7982
7983/*
7984 * Implementation of ":doautocmd [group] event [fname]".
7985 * Return OK for success, FAIL for failure;
7986 */
7987 int
7988do_doautocmd(arg, do_msg)
7989 char_u *arg;
7990 int do_msg; /* give message for no matching autocmds? */
7991{
7992 char_u *fname;
7993 int nothing_done = TRUE;
7994 int group;
7995
7996 /*
7997 * Check for a legal group name. If not, use AUGROUP_ALL.
7998 */
7999 group = au_get_grouparg(&arg);
8000 if (arg == NULL) /* out of memory */
8001 return FAIL;
8002
8003 if (*arg == '*')
8004 {
8005 EMSG(_("E217: Can't execute autocommands for ALL events"));
8006 return FAIL;
8007 }
8008
8009 /*
8010 * Scan over the events.
8011 * If we find an illegal name, return here, don't do anything.
8012 */
8013 fname = find_end_event(arg, group != AUGROUP_ALL);
8014 if (fname == NULL)
8015 return FAIL;
8016
8017 fname = skipwhite(fname);
8018
8019 /*
8020 * Loop over the events.
8021 */
8022 while (*arg && !vim_iswhite(*arg))
8023 if (apply_autocmds_group(event_name2nr(arg, &arg),
8024 fname, NULL, TRUE, group, curbuf, NULL))
8025 nothing_done = FALSE;
8026
8027 if (nothing_done && do_msg)
8028 MSG(_("No matching autocommands"));
8029
8030#ifdef FEAT_EVAL
8031 return aborting() ? FAIL : OK;
8032#else
8033 return OK;
8034#endif
8035}
8036
8037/*
8038 * ":doautoall": execute autocommands for each loaded buffer.
8039 */
8040 void
8041ex_doautoall(eap)
8042 exarg_T *eap;
8043{
8044 int retval;
8045 aco_save_T aco;
8046 buf_T *buf;
8047
8048 /*
8049 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8050 * equal to curbuf, but for some buffers there may not be a window.
8051 * So we change the buffer for the current window for a moment. This
8052 * gives problems when the autocommands make changes to the list of
8053 * buffers or windows...
8054 */
8055 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8056 {
8057 if (curbuf->b_ml.ml_mfp != NULL)
8058 {
8059 /* find a window for this buffer and save some values */
8060 aucmd_prepbuf(&aco, buf);
8061
8062 /* execute the autocommands for this buffer */
8063 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00008064 do_modelines(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008065
8066 /* restore the current window */
8067 aucmd_restbuf(&aco);
8068
8069 /* stop if there is some error or buffer was deleted */
8070 if (retval == FAIL || !buf_valid(buf))
8071 break;
8072 }
8073 }
8074
8075 check_cursor(); /* just in case lines got deleted */
8076}
8077
8078/*
8079 * Prepare for executing autocommands for (hidden) buffer "buf".
8080 * Search a window for the current buffer. Save the cursor position and
8081 * screen offset.
8082 * Set "curbuf" and "curwin" to match "buf".
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008083 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008084 */
8085 void
8086aucmd_prepbuf(aco, buf)
8087 aco_save_T *aco; /* structure to save values in */
8088 buf_T *buf; /* new curbuf */
8089{
8090 win_T *win;
8091
8092 aco->new_curbuf = buf;
8093
8094 /* Find a window that is for the new buffer */
8095 if (buf == curbuf) /* be quick when buf is curbuf */
8096 win = curwin;
8097 else
8098#ifdef FEAT_WINDOWS
8099 for (win = firstwin; win != NULL; win = win->w_next)
8100 if (win->w_buffer == buf)
8101 break;
8102#else
8103 win = NULL;
8104#endif
8105
8106 /*
8107 * Prefer to use an existing window for the buffer, it has the least side
8108 * effects (esp. if "buf" is curbuf).
8109 * Otherwise, use curwin for "buf". It might make some items in the
8110 * window invalid. At least save the cursor and topline.
8111 */
8112 if (win != NULL)
8113 {
8114 /* there is a window for "buf", make it the curwin */
8115 aco->save_curwin = curwin;
8116 curwin = win;
8117 aco->save_buf = win->w_buffer;
8118 aco->new_curwin = win;
8119 }
8120 else
8121 {
8122 /* there is no window for "buf", use curwin */
8123 aco->save_curwin = NULL;
8124 aco->save_buf = curbuf;
8125 --curbuf->b_nwindows;
8126 curwin->w_buffer = buf;
8127 ++buf->b_nwindows;
8128
8129 /* save cursor and topline, set them to safe values */
8130 aco->save_cursor = curwin->w_cursor;
8131 curwin->w_cursor.lnum = 1;
8132 curwin->w_cursor.col = 0;
8133 aco->save_topline = curwin->w_topline;
8134 curwin->w_topline = 1;
8135#ifdef FEAT_DIFF
8136 aco->save_topfill = curwin->w_topfill;
8137 curwin->w_topfill = 0;
8138#endif
8139 }
8140
8141 curbuf = buf;
8142}
8143
8144/*
8145 * Cleanup after executing autocommands for a (hidden) buffer.
8146 * Restore the window as it was (if possible).
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00008147 * When FEAT_AUTOCMD is not defined another version is used, see below.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008148 */
8149 void
8150aucmd_restbuf(aco)
8151 aco_save_T *aco; /* structure holding saved values */
8152{
8153 if (aco->save_curwin != NULL)
8154 {
8155 /* restore curwin */
8156#ifdef FEAT_WINDOWS
8157 if (win_valid(aco->save_curwin))
8158#endif
8159 {
8160 /* restore the buffer which was previously edited by curwin, if
8161 * it's still the same window and it's valid */
8162 if (curwin == aco->new_curwin
8163 && buf_valid(aco->save_buf)
8164 && aco->save_buf->b_ml.ml_mfp != NULL)
8165 {
8166 --curbuf->b_nwindows;
8167 curbuf = aco->save_buf;
8168 curwin->w_buffer = curbuf;
8169 ++curbuf->b_nwindows;
8170 }
8171
8172 curwin = aco->save_curwin;
8173 curbuf = curwin->w_buffer;
8174 }
8175 }
8176 else
8177 {
8178 /* restore buffer for curwin if it still exists and is loaded */
8179 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8180 {
8181 --curbuf->b_nwindows;
8182 curbuf = aco->save_buf;
8183 curwin->w_buffer = curbuf;
8184 ++curbuf->b_nwindows;
8185 curwin->w_cursor = aco->save_cursor;
8186 check_cursor();
8187 /* check topline < line_count, in case lines got deleted */
8188 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8189 {
8190 curwin->w_topline = aco->save_topline;
8191#ifdef FEAT_DIFF
8192 curwin->w_topfill = aco->save_topfill;
8193#endif
8194 }
8195 else
8196 {
8197 curwin->w_topline = curbuf->b_ml.ml_line_count;
8198#ifdef FEAT_DIFF
8199 curwin->w_topfill = 0;
8200#endif
8201 }
8202 }
8203 }
8204}
8205
8206static int autocmd_nested = FALSE;
8207
8208/*
8209 * Execute autocommands for "event" and file name "fname".
8210 * Return TRUE if some commands were executed.
8211 */
8212 int
8213apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008214 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008215 char_u *fname; /* NULL or empty means use actual file name */
8216 char_u *fname_io; /* fname to use for <afile> on cmdline */
8217 int force; /* when TRUE, ignore autocmd_busy */
8218 buf_T *buf; /* buffer for <abuf> */
8219{
8220 return apply_autocmds_group(event, fname, fname_io, force,
8221 AUGROUP_ALL, buf, NULL);
8222}
8223
8224/*
8225 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8226 * setting v:filearg.
8227 */
8228 static int
8229apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008230 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008231 char_u *fname;
8232 char_u *fname_io;
8233 int force;
8234 buf_T *buf;
8235 exarg_T *eap;
8236{
8237 return apply_autocmds_group(event, fname, fname_io, force,
8238 AUGROUP_ALL, buf, eap);
8239}
8240
8241/*
8242 * Like apply_autocmds(), but handles the caller's retval. If the script
8243 * processing is being aborted or if retval is FAIL when inside a try
8244 * conditional, no autocommands are executed. If otherwise the autocommands
8245 * cause the script to be aborted, retval is set to FAIL.
8246 */
8247 int
8248apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008249 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008250 char_u *fname; /* NULL or empty means use actual file name */
8251 char_u *fname_io; /* fname to use for <afile> on cmdline */
8252 int force; /* when TRUE, ignore autocmd_busy */
8253 buf_T *buf; /* buffer for <abuf> */
8254 int *retval; /* pointer to caller's retval */
8255{
8256 int did_cmd;
8257
Bram Moolenaar1e015462005-09-25 22:16:38 +00008258#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008259 if (should_abort(*retval))
8260 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008261#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008262
8263 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8264 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008265 if (did_cmd
8266#ifdef FEAT_EVAL
8267 && aborting()
8268#endif
8269 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008270 *retval = FAIL;
8271 return did_cmd;
8272}
8273
Bram Moolenaard35f9712005-12-18 22:02:33 +00008274/*
8275 * Return TRUE when there is a CursorHold autocommand defined.
8276 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008277 int
8278has_cursorhold()
8279{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008280 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8281 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008282}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008283
8284/*
8285 * Return TRUE if the CursorHold event can be triggered.
8286 */
8287 int
8288trigger_cursorhold()
8289{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008290 int state;
8291
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00008292 if (!did_cursorhold && has_cursorhold() && !Recording
8293#ifdef FEAT_INS_EXPAND
8294 && !ins_compl_active()
8295#endif
8296 )
Bram Moolenaar754b5602006-02-09 23:53:20 +00008297 {
8298 state = get_real_state();
8299 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8300 return TRUE;
8301 }
8302 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008303}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008304
8305/*
8306 * Return TRUE when there is a CursorMoved autocommand defined.
8307 */
8308 int
8309has_cursormoved()
8310{
8311 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8312}
8313
8314/*
8315 * Return TRUE when there is a CursorMovedI autocommand defined.
8316 */
8317 int
8318has_cursormovedI()
8319{
8320 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8321}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008322
8323 static int
8324apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008325 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008326 char_u *fname; /* NULL or empty means use actual file name */
8327 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8328 use fname */
8329 int force; /* when TRUE, ignore autocmd_busy */
8330 int group; /* group ID, or AUGROUP_ALL */
8331 buf_T *buf; /* buffer for <abuf> */
8332 exarg_T *eap; /* command arguments */
8333{
8334 char_u *sfname = NULL; /* short file name */
8335 char_u *tail;
8336 int save_changed;
8337 buf_T *old_curbuf;
8338 int retval = FALSE;
8339 char_u *save_sourcing_name;
8340 linenr_T save_sourcing_lnum;
8341 char_u *save_autocmd_fname;
8342 int save_autocmd_bufnr;
8343 char_u *save_autocmd_match;
8344 int save_autocmd_busy;
8345 int save_autocmd_nested;
8346 static int nesting = 0;
8347 AutoPatCmd patcmd;
8348 AutoPat *ap;
8349#ifdef FEAT_EVAL
8350 scid_T save_current_SID;
8351 void *save_funccalp;
8352 char_u *save_cmdarg;
8353 long save_cmdbang;
8354#endif
8355 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008356#ifdef FEAT_PROFILE
8357 proftime_T wait_time;
8358#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008359
8360 /*
8361 * Quickly return if there are no autocommands for this event or
8362 * autocommands are blocked.
8363 */
8364 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008365 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008366
8367 /*
8368 * When autocommands are busy, new autocommands are only executed when
8369 * explicitly enabled with the "nested" flag.
8370 */
8371 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008372 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008373
8374#ifdef FEAT_EVAL
8375 /*
8376 * Quickly return when immdediately aborting on error, or when an interrupt
8377 * occurred or an exception was thrown but not caught.
8378 */
8379 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008380 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008381#endif
8382
8383 /*
8384 * FileChangedShell never nests, because it can create an endless loop.
8385 */
Bram Moolenaar56718732006-03-15 22:53:57 +00008386 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
8387 || event == EVENT_FILECHANGEDSHELLPOST))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008388 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008389
8390 /*
8391 * Ignore events in 'eventignore'.
8392 */
8393 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008394 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008395
8396 /*
8397 * Allow nesting of autocommands, but restrict the depth, because it's
8398 * possible to create an endless loop.
8399 */
8400 if (nesting == 10)
8401 {
8402 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008403 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008404 }
8405
8406 /*
8407 * Check if these autocommands are disabled. Used when doing ":all" or
8408 * ":ball".
8409 */
8410 if ( (autocmd_no_enter
8411 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8412 || (autocmd_no_leave
8413 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008414 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008415
8416 /*
8417 * Save the autocmd_* variables and info about the current buffer.
8418 */
8419 save_autocmd_fname = autocmd_fname;
8420 save_autocmd_bufnr = autocmd_bufnr;
8421 save_autocmd_match = autocmd_match;
8422 save_autocmd_busy = autocmd_busy;
8423 save_autocmd_nested = autocmd_nested;
8424 save_changed = curbuf->b_changed;
8425 old_curbuf = curbuf;
8426
8427 /*
8428 * Set the file name to be used for <afile>.
8429 */
8430 if (fname_io == NULL)
8431 {
8432 if (fname != NULL && *fname != NUL)
8433 autocmd_fname = fname;
8434 else if (buf != NULL)
8435 autocmd_fname = buf->b_fname;
8436 else
8437 autocmd_fname = NULL;
8438 }
8439 else
8440 autocmd_fname = fname_io;
8441
8442 /*
8443 * Set the buffer number to be used for <abuf>.
8444 */
8445 if (buf == NULL)
8446 autocmd_bufnr = 0;
8447 else
8448 autocmd_bufnr = buf->b_fnum;
8449
8450 /*
8451 * When the file name is NULL or empty, use the file name of buffer "buf".
8452 * Always use the full path of the file name to match with, in case
8453 * "allow_dirs" is set.
8454 */
8455 if (fname == NULL || *fname == NUL)
8456 {
8457 if (buf == NULL)
8458 fname = NULL;
8459 else
8460 {
8461#ifdef FEAT_SYN_HL
8462 if (event == EVENT_SYNTAX)
8463 fname = buf->b_p_syn;
8464 else
8465#endif
8466 if (event == EVENT_FILETYPE)
8467 fname = buf->b_p_ft;
8468 else
8469 {
8470 if (buf->b_sfname != NULL)
8471 sfname = vim_strsave(buf->b_sfname);
8472 fname = buf->b_ffname;
8473 }
8474 }
8475 if (fname == NULL)
8476 fname = (char_u *)"";
8477 fname = vim_strsave(fname); /* make a copy, so we can change it */
8478 }
8479 else
8480 {
8481 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008482 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8483 if (event == EVENT_FILETYPE
8484 || event == EVENT_SYNTAX
8485 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008486 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008487 || event == EVENT_QUICKFIXCMDPRE
8488 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008489 fname = vim_strsave(fname);
8490 else
8491 fname = FullName_save(fname, FALSE);
8492 }
8493 if (fname == NULL) /* out of memory */
8494 {
8495 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008496 retval = FALSE;
8497 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008498 }
8499
8500#ifdef BACKSLASH_IN_FILENAME
8501 /*
8502 * Replace all backslashes with forward slashes. This makes the
8503 * autocommand patterns portable between Unix and MS-DOS.
8504 */
8505 if (sfname != NULL)
8506 forward_slash(sfname);
8507 forward_slash(fname);
8508#endif
8509
8510#ifdef VMS
8511 /* remove version for correct match */
8512 if (sfname != NULL)
8513 vms_remove_version(sfname);
8514 vms_remove_version(fname);
8515#endif
8516
8517 /*
8518 * Set the name to be used for <amatch>.
8519 */
8520 autocmd_match = fname;
8521
8522
8523 /* Don't redraw while doing auto commands. */
8524 ++RedrawingDisabled;
8525 save_sourcing_name = sourcing_name;
8526 sourcing_name = NULL; /* don't free this one */
8527 save_sourcing_lnum = sourcing_lnum;
8528 sourcing_lnum = 0; /* no line number here */
8529
8530#ifdef FEAT_EVAL
8531 save_current_SID = current_SID;
8532
Bram Moolenaar05159a02005-02-26 23:04:13 +00008533# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008534 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008535 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8536# endif
8537
Bram Moolenaar071d4272004-06-13 20:20:40 +00008538 /* Don't use local function variables, if called from a function */
8539 save_funccalp = save_funccal();
8540#endif
8541
8542 /*
8543 * When starting to execute autocommands, save the search patterns.
8544 */
8545 if (!autocmd_busy)
8546 {
8547 save_search_patterns();
8548 saveRedobuff();
8549 did_filetype = keep_filetype;
8550 }
8551
8552 /*
8553 * Note that we are applying autocmds. Some commands need to know.
8554 */
8555 autocmd_busy = TRUE;
8556 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8557 ++nesting; /* see matching decrement below */
8558
8559 /* Remember that FileType was triggered. Used for did_filetype(). */
8560 if (event == EVENT_FILETYPE)
8561 did_filetype = TRUE;
8562
8563 tail = gettail(fname);
8564
8565 /* Find first autocommand that matches */
8566 patcmd.curpat = first_autopat[(int)event];
8567 patcmd.nextcmd = NULL;
8568 patcmd.group = group;
8569 patcmd.fname = fname;
8570 patcmd.sfname = sfname;
8571 patcmd.tail = tail;
8572 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008573 patcmd.arg_bufnr = autocmd_bufnr;
8574 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008575 auto_next_pat(&patcmd, FALSE);
8576
8577 /* found one, start executing the autocommands */
8578 if (patcmd.curpat != NULL)
8579 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008580 /* add to active_apc_list */
8581 patcmd.next = active_apc_list;
8582 active_apc_list = &patcmd;
8583
Bram Moolenaar071d4272004-06-13 20:20:40 +00008584#ifdef FEAT_EVAL
8585 /* set v:cmdarg (only when there is a matching pattern) */
8586 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8587 if (eap != NULL)
8588 {
8589 save_cmdarg = set_cmdarg(eap, NULL);
8590 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8591 }
8592 else
8593 save_cmdarg = NULL; /* avoid gcc warning */
8594#endif
8595 retval = TRUE;
8596 /* mark the last pattern, to avoid an endless loop when more patterns
8597 * are added when executing autocommands */
8598 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8599 ap->last = FALSE;
8600 ap->last = TRUE;
8601 check_lnums(TRUE); /* make sure cursor and topline are valid */
8602 do_cmdline(NULL, getnextac, (void *)&patcmd,
8603 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8604#ifdef FEAT_EVAL
8605 if (eap != NULL)
8606 {
8607 (void)set_cmdarg(NULL, save_cmdarg);
8608 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8609 }
8610#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008611 /* delete from active_apc_list */
8612 if (active_apc_list == &patcmd) /* just in case */
8613 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008614 }
8615
8616 --RedrawingDisabled;
8617 autocmd_busy = save_autocmd_busy;
8618 filechangeshell_busy = FALSE;
8619 autocmd_nested = save_autocmd_nested;
8620 vim_free(sourcing_name);
8621 sourcing_name = save_sourcing_name;
8622 sourcing_lnum = save_sourcing_lnum;
8623 autocmd_fname = save_autocmd_fname;
8624 autocmd_bufnr = save_autocmd_bufnr;
8625 autocmd_match = save_autocmd_match;
8626#ifdef FEAT_EVAL
8627 current_SID = save_current_SID;
8628 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008629# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008630 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008631 prof_child_exit(&wait_time);
8632# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008633#endif
8634 vim_free(fname);
8635 vim_free(sfname);
8636 --nesting; /* see matching increment above */
8637
8638 /*
8639 * When stopping to execute autocommands, restore the search patterns and
8640 * the redo buffer.
8641 */
8642 if (!autocmd_busy)
8643 {
8644 restore_search_patterns();
8645 restoreRedobuff();
8646 did_filetype = FALSE;
8647 }
8648
8649 /*
8650 * Some events don't set or reset the Changed flag.
8651 * Check if still in the same buffer!
8652 */
8653 if (curbuf == old_curbuf
8654 && (event == EVENT_BUFREADPOST
8655 || event == EVENT_BUFWRITEPOST
8656 || event == EVENT_FILEAPPENDPOST
8657 || event == EVENT_VIMLEAVE
8658 || event == EVENT_VIMLEAVEPRE))
8659 {
8660#ifdef FEAT_TITLE
8661 if (curbuf->b_changed != save_changed)
8662 need_maketitle = TRUE;
8663#endif
8664 curbuf->b_changed = save_changed;
8665 }
8666
8667 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008668
8669BYPASS_AU:
8670 /* When wiping out a buffer make sure all its buffer-local autocommands
8671 * are deleted. */
8672 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8673 aubuflocal_remove(buf);
8674
Bram Moolenaar071d4272004-06-13 20:20:40 +00008675 return retval;
8676}
8677
8678/*
8679 * Find next autocommand pattern that matches.
8680 */
8681 static void
8682auto_next_pat(apc, stop_at_last)
8683 AutoPatCmd *apc;
8684 int stop_at_last; /* stop when 'last' flag is set */
8685{
8686 AutoPat *ap;
8687 AutoCmd *cp;
8688 char_u *name;
8689 char *s;
8690
8691 vim_free(sourcing_name);
8692 sourcing_name = NULL;
8693
8694 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8695 {
8696 apc->curpat = NULL;
8697
8698 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008699 * the group matches. For buffer-local autocommands only check the
8700 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008701 if (ap->pat != NULL && ap->cmds != NULL
8702 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8703 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008704 /* execution-condition */
8705 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008706 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8707 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008708 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008709 {
8710 name = event_nr2name(apc->event);
8711 s = _("%s Auto commands for \"%s\"");
8712 sourcing_name = alloc((unsigned)(STRLEN(s)
8713 + STRLEN(name) + ap->patlen + 1));
8714 if (sourcing_name != NULL)
8715 {
8716 sprintf((char *)sourcing_name, s,
8717 (char *)name, (char *)ap->pat);
8718 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008719 {
8720 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008721 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008722 verbose_leave();
8723 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008724 }
8725
8726 apc->curpat = ap;
8727 apc->nextcmd = ap->cmds;
8728 /* mark last command */
8729 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8730 cp->last = FALSE;
8731 cp->last = TRUE;
8732 }
8733 line_breakcheck();
8734 if (apc->curpat != NULL) /* found a match */
8735 break;
8736 }
8737 if (stop_at_last && ap->last)
8738 break;
8739 }
8740}
8741
8742/*
8743 * Get next autocommand command.
8744 * Called by do_cmdline() to get the next line for ":if".
8745 * Returns allocated string, or NULL for end of autocommands.
8746 */
8747/* ARGSUSED */
8748 static char_u *
8749getnextac(c, cookie, indent)
8750 int c; /* not used */
8751 void *cookie;
8752 int indent; /* not used */
8753{
8754 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8755 char_u *retval;
8756 AutoCmd *ac;
8757
8758 /* Can be called again after returning the last line. */
8759 if (acp->curpat == NULL)
8760 return NULL;
8761
8762 /* repeat until we find an autocommand to execute */
8763 for (;;)
8764 {
8765 /* skip removed commands */
8766 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8767 if (acp->nextcmd->last)
8768 acp->nextcmd = NULL;
8769 else
8770 acp->nextcmd = acp->nextcmd->next;
8771
8772 if (acp->nextcmd != NULL)
8773 break;
8774
8775 /* at end of commands, find next pattern that matches */
8776 if (acp->curpat->last)
8777 acp->curpat = NULL;
8778 else
8779 acp->curpat = acp->curpat->next;
8780 if (acp->curpat != NULL)
8781 auto_next_pat(acp, TRUE);
8782 if (acp->curpat == NULL)
8783 return NULL;
8784 }
8785
8786 ac = acp->nextcmd;
8787
8788 if (p_verbose >= 9)
8789 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008790 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008791 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008792 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008793 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008794 }
8795 retval = vim_strsave(ac->cmd);
8796 autocmd_nested = ac->nested;
8797#ifdef FEAT_EVAL
8798 current_SID = ac->scriptID;
8799#endif
8800 if (ac->last)
8801 acp->nextcmd = NULL;
8802 else
8803 acp->nextcmd = ac->next;
8804 return retval;
8805}
8806
8807/*
8808 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008809 * To account for buffer-local autocommands, function needs to know
8810 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008811 */
8812 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008813has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008814 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008815 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008816 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008817{
8818 AutoPat *ap;
8819 char_u *fname;
8820 char_u *tail = gettail(sfname);
8821 int retval = FALSE;
8822
8823 fname = FullName_save(sfname, FALSE);
8824 if (fname == NULL)
8825 return FALSE;
8826
8827#ifdef BACKSLASH_IN_FILENAME
8828 /*
8829 * Replace all backslashes with forward slashes. This makes the
8830 * autocommand patterns portable between Unix and MS-DOS.
8831 */
8832 sfname = vim_strsave(sfname);
8833 if (sfname != NULL)
8834 forward_slash(sfname);
8835 forward_slash(fname);
8836#endif
8837
8838 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8839 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00008840 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008841 ? match_file_pat(NULL, ap->reg_prog,
8842 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00008843 : buf != NULL && ap->buflocal_nr == buf->b_fnum
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008844 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008845 {
8846 retval = TRUE;
8847 break;
8848 }
8849
8850 vim_free(fname);
8851#ifdef BACKSLASH_IN_FILENAME
8852 vim_free(sfname);
8853#endif
8854
8855 return retval;
8856}
8857
8858#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8859/*
8860 * Function given to ExpandGeneric() to obtain the list of autocommand group
8861 * names.
8862 */
8863/*ARGSUSED*/
8864 char_u *
8865get_augroup_name(xp, idx)
8866 expand_T *xp;
8867 int idx;
8868{
8869 if (idx == augroups.ga_len) /* add "END" add the end */
8870 return (char_u *)"END";
8871 if (idx >= augroups.ga_len) /* end of list */
8872 return NULL;
8873 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8874 return (char_u *)"";
8875 return AUGROUP_NAME(idx); /* return a name */
8876}
8877
8878static int include_groups = FALSE;
8879
8880 char_u *
8881set_context_in_autocmd(xp, arg, doautocmd)
8882 expand_T *xp;
8883 char_u *arg;
8884 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8885{
8886 char_u *p;
8887 int group;
8888
8889 /* check for a group name, skip it if present */
8890 include_groups = FALSE;
8891 p = arg;
8892 group = au_get_grouparg(&arg);
8893 if (group == AUGROUP_ERROR)
8894 return NULL;
8895 /* If there only is a group name that's what we expand. */
8896 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8897 {
8898 arg = p;
8899 group = AUGROUP_ALL;
8900 }
8901
8902 /* skip over event name */
8903 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8904 if (*p == ',')
8905 arg = p + 1;
8906 if (*p == NUL)
8907 {
8908 if (group == AUGROUP_ALL)
8909 include_groups = TRUE;
8910 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8911 xp->xp_pattern = arg;
8912 return NULL;
8913 }
8914
8915 /* skip over pattern */
8916 arg = skipwhite(p);
8917 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8918 arg++;
8919 if (*arg)
8920 return arg; /* expand (next) command */
8921
8922 if (doautocmd)
8923 xp->xp_context = EXPAND_FILES; /* expand file names */
8924 else
8925 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8926 return NULL;
8927}
8928
8929/*
8930 * Function given to ExpandGeneric() to obtain the list of event names.
8931 */
8932/*ARGSUSED*/
8933 char_u *
8934get_event_name(xp, idx)
8935 expand_T *xp;
8936 int idx;
8937{
8938 if (idx < augroups.ga_len) /* First list group names, if wanted */
8939 {
8940 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8941 return (char_u *)""; /* skip deleted entries */
8942 return AUGROUP_NAME(idx); /* return a name */
8943 }
8944 return (char_u *)event_names[idx - augroups.ga_len].name;
8945}
8946
8947#endif /* FEAT_CMDL_COMPL */
8948
8949/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008950 * Return TRUE if autocmd is supported.
8951 */
8952 int
8953autocmd_supported(name)
8954 char_u *name;
8955{
8956 char_u *p;
8957
8958 return (event_name2nr(name, &p) != NUM_EVENTS);
8959}
8960
8961/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008962 * Return TRUE if an autocommand is defined for a group, event and
8963 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8964 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8965 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8966 * Used for:
8967 * exists("#Group") or
8968 * exists("#Group#Event") or
8969 * exists("#Group#Event#pat") or
8970 * exists("#Event") or
8971 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008972 */
8973 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008974au_exists(arg)
8975 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008976{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008977 char_u *arg_save;
8978 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008979 char_u *event_name;
8980 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00008981 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008982 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008983 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008984 int group;
8985 int retval = FALSE;
8986
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008987 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008988 arg_save = vim_strsave(arg);
8989 if (arg_save == NULL)
8990 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008991 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008992 if (p != NULL)
8993 *p++ = NUL;
8994
8995 /* First, look for an autocmd group name */
8996 group = au_find_group(arg_save);
8997 if (group == AUGROUP_ERROR)
8998 {
8999 /* Didn't match a group name, assume the first argument is an event. */
9000 group = AUGROUP_ALL;
9001 event_name = arg_save;
9002 }
9003 else
9004 {
9005 if (p == NULL)
9006 {
9007 /* "Group": group name is present and it's recognized */
9008 retval = TRUE;
9009 goto theend;
9010 }
9011
9012 /* Must be "Group#Event" or "Group#Event#pat". */
9013 event_name = p;
9014 p = vim_strchr(event_name, '#');
9015 if (p != NULL)
9016 *p++ = NUL; /* "Group#Event#pat" */
9017 }
9018
9019 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009020
9021 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009022 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009023
9024 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009025 if (event == NUM_EVENTS)
9026 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009027
9028 /* Find the first autocommand for this event.
9029 * If there isn't any, return FALSE;
9030 * If there is one and no pattern given, return TRUE; */
9031 ap = first_autopat[(int)event];
9032 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009033 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009034 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009035 {
9036 retval = TRUE;
9037 goto theend;
9038 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009039
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009040 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
9041 /* for pattern "<buffer=N>, fnamecmp() will work fine */
9042 if (STRICMP(pattern, "<buffer>") == 0)
9043 buflocal_buf = curbuf;
9044
Bram Moolenaar071d4272004-06-13 20:20:40 +00009045 /* Check if there is an autocommand with the given pattern. */
9046 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009047 /* only use a pattern when it has not been removed and has commands. */
9048 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009049 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009050 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009051 && (buflocal_buf == NULL
9052 ? fnamecmp(ap->pat, pattern) == 0
9053 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009054 {
9055 retval = TRUE;
9056 break;
9057 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009058
Bram Moolenaar195d6352005-12-19 22:08:24 +00009059theend:
9060 vim_free(arg_save);
9061 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009062}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009063
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009064#else /* FEAT_AUTOCMD */
9065
9066/*
9067 * Prepare for executing commands for (hidden) buffer "buf".
9068 * This is the non-autocommand version, it simply saves "curbuf" and sets
9069 * "curbuf" and "curwin" to match "buf".
9070 */
9071 void
9072aucmd_prepbuf(aco, buf)
9073 aco_save_T *aco; /* structure to save values in */
9074 buf_T *buf; /* new curbuf */
9075{
9076 aco->save_buf = buf;
9077 curbuf = buf;
9078 curwin->w_buffer = buf;
9079}
9080
9081/*
9082 * Restore after executing commands for a (hidden) buffer.
9083 * This is the non-autocommand version.
9084 */
9085 void
9086aucmd_restbuf(aco)
9087 aco_save_T *aco; /* structure holding saved values */
9088{
9089 curbuf = aco->save_buf;
9090 curwin->w_buffer = curbuf;
9091}
9092
Bram Moolenaar071d4272004-06-13 20:20:40 +00009093#endif /* FEAT_AUTOCMD */
9094
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00009095
Bram Moolenaar071d4272004-06-13 20:20:40 +00009096#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9097/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009098 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9099 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9100 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009101 * Used for autocommands and 'wildignore'.
9102 * Returns TRUE if there is a match, FALSE otherwise.
9103 */
9104 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009105match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009106 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009107 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009108 char_u *fname; /* full path of file name */
9109 char_u *sfname; /* short file name or NULL */
9110 char_u *tail; /* tail of path */
9111 int allow_dirs; /* allow matching with dir */
9112{
9113 regmatch_T regmatch;
9114 int result = FALSE;
9115#ifdef FEAT_OSFILETYPE
9116 int no_pattern = FALSE; /* TRUE if check is filetype only */
9117 char_u *type_start;
9118 char_u c;
9119 int match = FALSE;
9120#endif
9121
9122#ifdef CASE_INSENSITIVE_FILENAME
9123 regmatch.rm_ic = TRUE; /* Always ignore case */
9124#else
9125 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9126#endif
9127#ifdef FEAT_OSFILETYPE
9128 if (*pattern == '<')
9129 {
9130 /* There is a filetype condition specified with this pattern.
9131 * Check the filetype matches first. If not, don't bother with the
9132 * pattern (set regprog to NULL).
9133 * Always use magic for the regexp.
9134 */
9135
9136 for (type_start = pattern + 1; (c = *pattern); pattern++)
9137 {
9138 if ((c == ';' || c == '>') && match == FALSE)
9139 {
9140 *pattern = NUL; /* Terminate the string */
9141 match = mch_check_filetype(fname, type_start);
9142 *pattern = c; /* Restore the terminator */
9143 type_start = pattern + 1;
9144 }
9145 if (c == '>')
9146 break;
9147 }
9148
9149 /* (c should never be NUL, but check anyway) */
9150 if (match == FALSE || c == NUL)
9151 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9152 else if (*pattern == NUL)
9153 {
9154 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9155 no_pattern = TRUE; /* Always matches - don't check pat. */
9156 }
9157 else
9158 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9159 }
9160 else
9161#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009162 {
9163 if (prog != NULL)
9164 regmatch.regprog = prog;
9165 else
9166 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009168
9169 /*
9170 * Try for a match with the pattern with:
9171 * 1. the full file name, when the pattern has a '/'.
9172 * 2. the short file name, when the pattern has a '/'.
9173 * 3. the tail of the file name, when the pattern has no '/'.
9174 */
9175 if (
9176#ifdef FEAT_OSFILETYPE
9177 /* If the check is for a filetype only and we don't care
9178 * about the path then skip all the regexp stuff.
9179 */
9180 no_pattern ||
9181#endif
9182 (regmatch.regprog != NULL
9183 && ((allow_dirs
9184 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9185 || (sfname != NULL
9186 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9187 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9188 result = TRUE;
9189
Bram Moolenaar748bf032005-02-02 23:04:36 +00009190 if (prog == NULL)
9191 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009192 return result;
9193}
9194#endif
9195
9196#if defined(FEAT_WILDIGN) || defined(PROTO)
9197/*
9198 * Return TRUE if a file matches with a pattern in "list".
9199 * "list" is a comma-separated list of patterns, like 'wildignore'.
9200 * "sfname" is the short file name or NULL, "ffname" the long file name.
9201 */
9202 int
9203match_file_list(list, sfname, ffname)
9204 char_u *list;
9205 char_u *sfname;
9206 char_u *ffname;
9207{
9208 char_u buf[100];
9209 char_u *tail;
9210 char_u *regpat;
9211 char allow_dirs;
9212 int match;
9213 char_u *p;
9214
9215 tail = gettail(sfname);
9216
9217 /* try all patterns in 'wildignore' */
9218 p = list;
9219 while (*p)
9220 {
9221 copy_option_part(&p, buf, 100, ",");
9222 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9223 if (regpat == NULL)
9224 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009225 match = match_file_pat(regpat, NULL, ffname, sfname,
9226 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009227 vim_free(regpat);
9228 if (match)
9229 return TRUE;
9230 }
9231 return FALSE;
9232}
9233#endif
9234
9235/*
9236 * Convert the given pattern "pat" which has shell style wildcards in it, into
9237 * a regular expression, and return the result in allocated memory. If there
9238 * is a directory path separator to be matched, then TRUE is put in
9239 * allow_dirs, otherwise FALSE is put there -- webb.
9240 * Handle backslashes before special characters, like "\*" and "\ ".
9241 *
9242 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9243 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9244 *
9245 * Returns NULL when out of memory.
9246 */
9247/*ARGSUSED*/
9248 char_u *
9249file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9250 char_u *pat;
9251 char_u *pat_end; /* first char after pattern or NULL */
9252 char *allow_dirs; /* Result passed back out in here */
9253 int no_bslash; /* Don't use a backward slash as pathsep */
9254{
9255 int size;
9256 char_u *endp;
9257 char_u *reg_pat;
9258 char_u *p;
9259 int i;
9260 int nested = 0;
9261 int add_dollar = TRUE;
9262#ifdef FEAT_OSFILETYPE
9263 int check_length = 0;
9264#endif
9265
9266 if (allow_dirs != NULL)
9267 *allow_dirs = FALSE;
9268 if (pat_end == NULL)
9269 pat_end = pat + STRLEN(pat);
9270
9271#ifdef FEAT_OSFILETYPE
9272 /* Find out how much of the string is the filetype check */
9273 if (*pat == '<')
9274 {
9275 /* Count chars until the next '>' */
9276 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9277 ;
9278 if (p < pat_end)
9279 {
9280 /* Pattern is of the form <.*>.* */
9281 check_length = p - pat + 1;
9282 if (p + 1 >= pat_end)
9283 {
9284 /* The 'pattern' is a filetype check ONLY */
9285 reg_pat = (char_u *)alloc(check_length + 1);
9286 if (reg_pat != NULL)
9287 {
9288 mch_memmove(reg_pat, pat, (size_t)check_length);
9289 reg_pat[check_length] = NUL;
9290 }
9291 return reg_pat;
9292 }
9293 }
9294 /* else: there was no closing '>' - assume it was a normal pattern */
9295
9296 }
9297 pat += check_length;
9298 size = 2 + check_length;
9299#else
9300 size = 2; /* '^' at start, '$' at end */
9301#endif
9302
9303 for (p = pat; p < pat_end; p++)
9304 {
9305 switch (*p)
9306 {
9307 case '*':
9308 case '.':
9309 case ',':
9310 case '{':
9311 case '}':
9312 case '~':
9313 size += 2; /* extra backslash */
9314 break;
9315#ifdef BACKSLASH_IN_FILENAME
9316 case '\\':
9317 case '/':
9318 size += 4; /* could become "[\/]" */
9319 break;
9320#endif
9321 default:
9322 size++;
9323# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009324 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009325 {
9326 ++p;
9327 ++size;
9328 }
9329# endif
9330 break;
9331 }
9332 }
9333 reg_pat = alloc(size + 1);
9334 if (reg_pat == NULL)
9335 return NULL;
9336
9337#ifdef FEAT_OSFILETYPE
9338 /* Copy the type check in to the start. */
9339 if (check_length)
9340 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9341 i = check_length;
9342#else
9343 i = 0;
9344#endif
9345
9346 if (pat[0] == '*')
9347 while (pat[0] == '*' && pat < pat_end - 1)
9348 pat++;
9349 else
9350 reg_pat[i++] = '^';
9351 endp = pat_end - 1;
9352 if (*endp == '*')
9353 {
9354 while (endp - pat > 0 && *endp == '*')
9355 endp--;
9356 add_dollar = FALSE;
9357 }
9358 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9359 {
9360 switch (*p)
9361 {
9362 case '*':
9363 reg_pat[i++] = '.';
9364 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009365 while (p[1] == '*') /* "**" matches like "*" */
9366 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009367 break;
9368 case '.':
9369#ifdef RISCOS
9370 if (allow_dirs != NULL)
9371 *allow_dirs = TRUE;
9372 /* FALLTHROUGH */
9373#endif
9374 case '~':
9375 reg_pat[i++] = '\\';
9376 reg_pat[i++] = *p;
9377 break;
9378 case '?':
9379#ifdef RISCOS
9380 case '#':
9381#endif
9382 reg_pat[i++] = '.';
9383 break;
9384 case '\\':
9385 if (p[1] == NUL)
9386 break;
9387#ifdef BACKSLASH_IN_FILENAME
9388 if (!no_bslash)
9389 {
9390 /* translate:
9391 * "\x" to "\\x" e.g., "dir\file"
9392 * "\*" to "\\.*" e.g., "dir\*.c"
9393 * "\?" to "\\." e.g., "dir\??.c"
9394 * "\+" to "\+" e.g., "fileX\+.c"
9395 */
9396 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9397 && p[1] != '+')
9398 {
9399 reg_pat[i++] = '[';
9400 reg_pat[i++] = '\\';
9401 reg_pat[i++] = '/';
9402 reg_pat[i++] = ']';
9403 if (allow_dirs != NULL)
9404 *allow_dirs = TRUE;
9405 break;
9406 }
9407 }
9408#endif
9409 if (*++p == '?'
9410#ifdef BACKSLASH_IN_FILENAME
9411 && no_bslash
9412#endif
9413 )
9414 reg_pat[i++] = '?';
9415 else
9416 if (*p == ',')
9417 reg_pat[i++] = ',';
9418 else
9419 {
9420 if (allow_dirs != NULL && vim_ispathsep(*p)
9421#ifdef BACKSLASH_IN_FILENAME
9422 && (!no_bslash || *p != '\\')
9423#endif
9424 )
9425 *allow_dirs = TRUE;
9426 reg_pat[i++] = '\\';
9427 reg_pat[i++] = *p;
9428 }
9429 break;
9430#ifdef BACKSLASH_IN_FILENAME
9431 case '/':
9432 reg_pat[i++] = '[';
9433 reg_pat[i++] = '\\';
9434 reg_pat[i++] = '/';
9435 reg_pat[i++] = ']';
9436 if (allow_dirs != NULL)
9437 *allow_dirs = TRUE;
9438 break;
9439#endif
9440 case '{':
9441 reg_pat[i++] = '\\';
9442 reg_pat[i++] = '(';
9443 nested++;
9444 break;
9445 case '}':
9446 reg_pat[i++] = '\\';
9447 reg_pat[i++] = ')';
9448 --nested;
9449 break;
9450 case ',':
9451 if (nested)
9452 {
9453 reg_pat[i++] = '\\';
9454 reg_pat[i++] = '|';
9455 }
9456 else
9457 reg_pat[i++] = ',';
9458 break;
9459 default:
9460# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009461 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009462 reg_pat[i++] = *p++;
9463 else
9464# endif
9465 if (allow_dirs != NULL && vim_ispathsep(*p))
9466 *allow_dirs = TRUE;
9467 reg_pat[i++] = *p;
9468 break;
9469 }
9470 }
9471 if (add_dollar)
9472 reg_pat[i++] = '$';
9473 reg_pat[i] = NUL;
9474 if (nested != 0)
9475 {
9476 if (nested < 0)
9477 EMSG(_("E219: Missing {."));
9478 else
9479 EMSG(_("E220: Missing }."));
9480 vim_free(reg_pat);
9481 reg_pat = NULL;
9482 }
9483 return reg_pat;
9484}