blob: 01953f381a48e43a056f4b0adc0dcc24506fad14 [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 Moolenaar071d4272004-06-13 20:20:40 +0000319 /*
320 * For Unix: Use the short file name whenever possible.
321 * Avoids problems with networks and when directory names are changed.
322 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
323 * another directory, which we don't detect.
324 */
325 if (sfname == NULL)
326 sfname = fname;
327#if defined(UNIX) || defined(__EMX__)
328 fname = sfname;
329#endif
330
331#ifdef FEAT_AUTOCMD
332 /*
333 * The BufReadCmd and FileReadCmd events intercept the reading process by
334 * executing the associated commands instead.
335 */
336 if (!filtering && !read_stdin && !read_buffer)
337 {
338 pos_T pos;
339
340 pos = curbuf->b_op_start;
341
342 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
343 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
344 curbuf->b_op_start.col = 0;
345
346 if (newfile)
347 {
348 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
349 FALSE, curbuf, eap))
350#ifdef FEAT_EVAL
351 return aborting() ? FAIL : OK;
352#else
353 return OK;
354#endif
355 }
356 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
357 FALSE, NULL, eap))
358#ifdef FEAT_EVAL
359 return aborting() ? FAIL : OK;
360#else
361 return OK;
362#endif
363
364 curbuf->b_op_start = pos;
365 }
366#endif
367
368 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
369 msg_scroll = FALSE; /* overwrite previous file message */
370 else
371 msg_scroll = TRUE; /* don't overwrite previous file message */
372
373 /*
374 * If the name ends in a path separator, we can't open it. Check here,
375 * because reading the file may actually work, but then creating the swap
376 * file may destroy it! Reported on MS-DOS and Win 95.
377 * If the name is too long we might crash further on, quit here.
378 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000379 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000381 p = fname + STRLEN(fname);
382 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000383 {
384 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
385 msg_end();
386 msg_scroll = msg_save;
387 return FAIL;
388 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 }
390
391#ifdef UNIX
392 /*
393 * On Unix it is possible to read a directory, so we have to
394 * check for it before the mch_open().
395 */
396 if (!read_stdin && !read_buffer)
397 {
398 perm = mch_getperm(fname);
399 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
400# ifdef S_ISFIFO
401 && !S_ISFIFO(perm) /* ... or fifo */
402# endif
403# ifdef S_ISSOCK
404 && !S_ISSOCK(perm) /* ... or socket */
405# endif
406 )
407 {
408 if (S_ISDIR(perm))
409 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
410 else
411 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
412 msg_end();
413 msg_scroll = msg_save;
414 return FAIL;
415 }
416 }
417#endif
418
419 /* set default 'fileformat' */
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000420 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421 {
422 if (eap != NULL && eap->force_ff != 0)
423 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
424 else if (*p_ffs != NUL)
425 set_fileformat(default_fileformat(), OPT_LOCAL);
426 }
427
428 /* set or reset 'binary' */
429 if (eap != NULL && eap->force_bin != 0)
430 {
431 int oldval = curbuf->b_p_bin;
432
433 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
434 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
435 }
436
437 /*
438 * When opening a new file we take the readonly flag from the file.
439 * Default is r/w, can be set to r/o below.
440 * Don't reset it when in readonly mode
441 * Only set/reset b_p_ro when BF_CHECK_RO is set.
442 */
443 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000444 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 curbuf->b_p_ro = FALSE;
446
447 if (newfile && !read_stdin && !read_buffer)
448 {
449 /* Remember time of file.
450 * For RISCOS, also remember the filetype.
451 */
452 if (mch_stat((char *)fname, &st) >= 0)
453 {
454 buf_store_time(curbuf, &st, fname);
455 curbuf->b_mtime_read = curbuf->b_mtime;
456
457#if defined(RISCOS) && defined(FEAT_OSFILETYPE)
458 /* Read the filetype into the buffer local filetype option. */
459 mch_read_filetype(fname);
460#endif
461#ifdef UNIX
462 /*
463 * Use the protection bits of the original file for the swap file.
464 * This makes it possible for others to read the name of the
465 * edited file from the swapfile, but only if they can read the
466 * edited file.
467 * Remove the "write" and "execute" bits for group and others
468 * (they must not write the swapfile).
469 * Add the "read" and "write" bits for the user, otherwise we may
470 * not be able to write to the file ourselves.
471 * Setting the bits is done below, after creating the swap file.
472 */
473 swap_mode = (st.st_mode & 0644) | 0600;
474#endif
475#ifdef FEAT_CW_EDITOR
476 /* Get the FSSpec on MacOS
477 * TODO: Update it properly when the buffer name changes
478 */
479 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
480#endif
481#ifdef VMS
482 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000483 curbuf->b_fab_rat = st.st_fab_rat;
484 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485#endif
486 }
487 else
488 {
489 curbuf->b_mtime = 0;
490 curbuf->b_mtime_read = 0;
491 curbuf->b_orig_size = 0;
492 curbuf->b_orig_mode = 0;
493 }
494
495 /* Reset the "new file" flag. It will be set again below when the
496 * file doesn't exist. */
497 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
498 }
499
500/*
501 * for UNIX: check readonly with perm and mch_access()
502 * for RISCOS: same as Unix, otherwise file gets re-datestamped!
503 * for MSDOS and Amiga: check readonly by trying to open the file for writing
504 */
505 file_readonly = FALSE;
506 if (read_stdin)
507 {
508#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
509 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
510 setmode(0, O_BINARY);
511#endif
512 }
513 else if (!read_buffer)
514 {
515#ifdef USE_MCH_ACCESS
516 if (
517# ifdef UNIX
518 !(perm & 0222) ||
519# endif
520 mch_access((char *)fname, W_OK))
521 file_readonly = TRUE;
522 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
523#else
524 if (!newfile
525 || readonlymode
526 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
527 {
528 file_readonly = TRUE;
529 /* try to open ro */
530 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
531 }
532#endif
533 }
534
535 if (fd < 0) /* cannot open at all */
536 {
537#ifndef UNIX
538 int isdir_f;
539#endif
540 msg_scroll = msg_save;
541#ifndef UNIX
542 /*
543 * On MSDOS and Amiga we can't open a directory, check here.
544 */
545 isdir_f = (mch_isdir(fname));
546 perm = mch_getperm(fname); /* check if the file exists */
547 if (isdir_f)
548 {
549 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
550 curbuf->b_p_ro = TRUE; /* must use "w!" now */
551 }
552 else
553#endif
554 if (newfile)
555 {
556 if (perm < 0)
557 {
558 /*
559 * Set the 'new-file' flag, so that when the file has
560 * been created by someone else, a ":w" will complain.
561 */
562 curbuf->b_flags |= BF_NEW;
563
564 /* Create a swap file now, so that other Vims are warned
565 * that we are editing this file. Don't do this for a
566 * "nofile" or "nowrite" buffer type. */
567#ifdef FEAT_QUICKFIX
568 if (!bt_dontwrite(curbuf))
569#endif
570 check_need_swap(newfile);
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000571 if (dir_of_file_exists(fname))
572 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
573 else
574 filemess(curbuf, sfname,
575 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576#ifdef FEAT_VIMINFO
577 /* Even though this is a new file, it might have been
578 * edited before and deleted. Get the old marks. */
579 check_marks_read();
580#endif
581#ifdef FEAT_MBYTE
582 if (eap != NULL && eap->force_enc != 0)
583 {
584 /* set forced 'fileencoding' */
585 fenc = enc_canonize(eap->cmd + eap->force_enc);
586 if (fenc != NULL)
587 set_string_option_direct((char_u *)"fenc", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000588 fenc, OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589 vim_free(fenc);
590 }
591#endif
592#ifdef FEAT_AUTOCMD
593 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
594 FALSE, curbuf, eap);
595#endif
596 /* remember the current fileformat */
597 save_file_ff(curbuf);
598
599#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
600 if (aborting()) /* autocmds may abort script processing */
601 return FAIL;
602#endif
603 return OK; /* a new file is not an error */
604 }
605 else
606 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000607 filemess(curbuf, sfname, (char_u *)(
608# ifdef EFBIG
609 (errno == EFBIG) ? _("[File too big]") :
610# endif
611 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 curbuf->b_p_ro = TRUE; /* must use "w!" now */
613 }
614 }
615
616 return FAIL;
617 }
618
619 /*
620 * Only set the 'ro' flag for readonly files the first time they are
621 * loaded. Help files always get readonly mode
622 */
623 if ((check_readonly && file_readonly) || curbuf->b_help)
624 curbuf->b_p_ro = TRUE;
625
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000626 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 {
628 curbuf->b_p_eol = TRUE;
629 curbuf->b_start_eol = TRUE;
630#ifdef FEAT_MBYTE
631 curbuf->b_p_bomb = FALSE;
632#endif
633 }
634
635 /* Create a swap file now, so that other Vims are warned that we are
636 * editing this file.
637 * Don't do this for a "nofile" or "nowrite" buffer type. */
638#ifdef FEAT_QUICKFIX
639 if (!bt_dontwrite(curbuf))
640#endif
641 {
642 check_need_swap(newfile);
643#ifdef UNIX
644 /* Set swap file protection bits after creating it. */
645 if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
646 (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
647#endif
648 }
649
Bram Moolenaarb815dac2005-12-07 20:59:24 +0000650#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 /* If "Quit" selected at ATTENTION dialog, don't load the file */
652 if (swap_exists_action == SEA_QUIT)
653 {
654 if (!read_buffer && !read_stdin)
655 close(fd);
656 return FAIL;
657 }
658#endif
659
660 ++no_wait_return; /* don't wait for return yet */
661
662 /*
663 * Set '[ mark to the line above where the lines go (line 1 if zero).
664 */
665 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
666 curbuf->b_op_start.col = 0;
667
668#ifdef FEAT_AUTOCMD
669 if (!read_buffer)
670 {
671 int m = msg_scroll;
672 int n = msg_scrolled;
673 buf_T *old_curbuf = curbuf;
674
675 /*
676 * The file must be closed again, the autocommands may want to change
677 * the file before reading it.
678 */
679 if (!read_stdin)
680 close(fd); /* ignore errors */
681
682 /*
683 * The output from the autocommands should not overwrite anything and
684 * should not be overwritten: Set msg_scroll, restore its value if no
685 * output was done.
686 */
687 msg_scroll = TRUE;
688 if (filtering)
689 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
690 FALSE, curbuf, eap);
691 else if (read_stdin)
692 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
693 FALSE, curbuf, eap);
694 else if (newfile)
695 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
696 FALSE, curbuf, eap);
697 else
698 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
699 FALSE, NULL, eap);
700 if (msg_scrolled == n)
701 msg_scroll = m;
702
703#ifdef FEAT_EVAL
704 if (aborting()) /* autocmds may abort script processing */
705 {
706 --no_wait_return;
707 msg_scroll = msg_save;
708 curbuf->b_p_ro = TRUE; /* must use "w!" now */
709 return FAIL;
710 }
711#endif
712 /*
713 * Don't allow the autocommands to change the current buffer.
714 * Try to re-open the file.
715 */
716 if (!read_stdin && (curbuf != old_curbuf
717 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
718 {
719 --no_wait_return;
720 msg_scroll = msg_save;
721 if (fd < 0)
722 EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
723 else
724 EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
725 curbuf->b_p_ro = TRUE; /* must use "w!" now */
726 return FAIL;
727 }
728 }
729#endif /* FEAT_AUTOCMD */
730
731 /* Autocommands may add lines to the file, need to check if it is empty */
732 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
733
734 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
735 {
736 /*
737 * Show the user that we are busy reading the input. Sometimes this
738 * may take a while. When reading from stdin another program may
739 * still be running, don't move the cursor to the last line, unless
740 * always using the GUI.
741 */
742 if (read_stdin)
743 {
744#ifndef ALWAYS_USE_GUI
745 mch_msg(_("Vim: Reading from stdin...\n"));
746#endif
747#ifdef FEAT_GUI
748 /* Also write a message in the GUI window, if there is one. */
749 if (gui.in_use && !gui.dying && !gui.starting)
750 {
751 p = (char_u *)_("Reading from stdin...");
752 gui_write(p, (int)STRLEN(p));
753 }
754#endif
755 }
756 else if (!read_buffer)
757 filemess(curbuf, sfname, (char_u *)"", 0);
758 }
759
760 msg_scroll = FALSE; /* overwrite the file message */
761
762 /*
763 * Set linecnt now, before the "retry" caused by a wrong guess for
764 * fileformat, and after the autocommands, which may change them.
765 */
766 linecnt = curbuf->b_ml.ml_line_count;
767
768#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000769 /* "++bad=" argument. */
770 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000771 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000772 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000773 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000774 curbuf->b_bad_char = eap->bad_char;
775 }
776 else
777 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000778
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000780 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 */
782 if (eap != NULL && eap->force_enc != 0)
783 {
784 fenc = enc_canonize(eap->cmd + eap->force_enc);
785 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000786 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 }
788 else if (curbuf->b_p_bin)
789 {
790 fenc = (char_u *)""; /* binary: don't convert */
791 fenc_alloced = FALSE;
792 }
793 else if (curbuf->b_help)
794 {
795 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000796 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797
798 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
799 * fails it must be latin1.
800 * Always do this when 'encoding' is "utf-8". Otherwise only do
801 * this when needed to avoid [converted] remarks all the time.
802 * It is needed when the first line contains non-ASCII characters.
803 * That is only in *.??x files. */
804 fenc = (char_u *)"latin1";
805 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000806 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000808 fc = fname[STRLEN(fname) - 1];
809 if (TOLOWER_ASC(fc) == 'x')
810 {
811 /* Read the first line (and a bit more). Immediately rewind to
812 * the start of the file. If the read() fails "len" is -1. */
813 len = vim_read(fd, firstline, 80);
814 lseek(fd, (off_t)0L, SEEK_SET);
815 for (p = firstline; p < firstline + len; ++p)
816 if (*p >= 0x80)
817 {
818 c = TRUE;
819 break;
820 }
821 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 }
823
824 if (c)
825 {
826 fenc_next = fenc;
827 fenc = (char_u *)"utf-8";
828
829 /* When the file is utf-8 but a character doesn't fit in
830 * 'encoding' don't retry. In help text editing utf-8 bytes
831 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000832 if (!enc_utf8)
833 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 }
835 fenc_alloced = FALSE;
836 }
837 else if (*p_fencs == NUL)
838 {
839 fenc = curbuf->b_p_fenc; /* use format from buffer */
840 fenc_alloced = FALSE;
841 }
842 else
843 {
844 fenc_next = p_fencs; /* try items in 'fileencodings' */
845 fenc = next_fenc(&fenc_next);
846 fenc_alloced = TRUE;
847 }
848#endif
849
850 /*
851 * Jump back here to retry reading the file in different ways.
852 * Reasons to retry:
853 * - encoding conversion failed: try another one from "fenc_next"
854 * - BOM detected and fenc was set, need to setup conversion
855 * - "fileformat" check failed: try another
856 *
857 * Variables set for special retry actions:
858 * "file_rewind" Rewind the file to start reading it again.
859 * "advance_fenc" Advance "fenc" using "fenc_next".
860 * "skip_read" Re-use already read bytes (BOM detected).
861 * "did_iconv" iconv() conversion failed, try 'charconvert'.
862 * "keep_fileformat" Don't reset "fileformat".
863 *
864 * Other status indicators:
865 * "tmpname" When != NULL did conversion with 'charconvert'.
866 * Output file has to be deleted afterwards.
867 * "iconv_fd" When != -1 did conversion with iconv().
868 */
869retry:
870
871 if (file_rewind)
872 {
873 if (read_buffer)
874 {
875 read_buf_lnum = 1;
876 read_buf_col = 0;
877 }
878 else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0)
879 {
880 /* Can't rewind the file, give up. */
881 error = TRUE;
882 goto failed;
883 }
884 /* Delete the previously read lines. */
885 while (lnum > from)
886 ml_delete(lnum--, FALSE);
887 file_rewind = FALSE;
888#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000889 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 curbuf->b_p_bomb = FALSE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000891 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892#endif
893 }
894
895 /*
896 * When retrying with another "fenc" and the first time "fileformat"
897 * will be reset.
898 */
899 if (keep_fileformat)
900 keep_fileformat = FALSE;
901 else
902 {
903 if (eap != NULL && eap->force_ff != 0)
904 fileformat = get_fileformat_force(curbuf, eap);
905 else if (curbuf->b_p_bin)
906 fileformat = EOL_UNIX; /* binary: use Unix format */
907 else if (*p_ffs == NUL)
908 fileformat = get_fileformat(curbuf);/* use format from buffer */
909 else
910 fileformat = EOL_UNKNOWN; /* detect from file */
911 }
912
913#ifdef FEAT_MBYTE
914# ifdef USE_ICONV
915 if (iconv_fd != (iconv_t)-1)
916 {
917 /* aborted conversion with iconv(), close the descriptor */
918 iconv_close(iconv_fd);
919 iconv_fd = (iconv_t)-1;
920 }
921# endif
922
923 if (advance_fenc)
924 {
925 /*
926 * Try the next entry in 'fileencodings'.
927 */
928 advance_fenc = FALSE;
929
930 if (eap != NULL && eap->force_enc != 0)
931 {
932 /* Conversion given with "++cc=" wasn't possible, read
933 * without conversion. */
934 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000935 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 if (fenc_alloced)
937 vim_free(fenc);
938 fenc = (char_u *)"";
939 fenc_alloced = FALSE;
940 }
941 else
942 {
943 if (fenc_alloced)
944 vim_free(fenc);
945 if (fenc_next != NULL)
946 {
947 fenc = next_fenc(&fenc_next);
948 fenc_alloced = (fenc_next != NULL);
949 }
950 else
951 {
952 fenc = (char_u *)"";
953 fenc_alloced = FALSE;
954 }
955 }
956 if (tmpname != NULL)
957 {
958 mch_remove(tmpname); /* delete converted file */
959 vim_free(tmpname);
960 tmpname = NULL;
961 }
962 }
963
964 /*
965 * Conversion is required when the encoding of the file is different
966 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4 (requires
967 * conversion to UTF-8).
968 */
969 fio_flags = 0;
970 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
971 if (converted || enc_unicode != 0)
972 {
973
974 /* "ucs-bom" means we need to check the first bytes of the file
975 * for a BOM. */
976 if (STRCMP(fenc, ENC_UCSBOM) == 0)
977 fio_flags = FIO_UCSBOM;
978
979 /*
980 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
981 * done. This is handled below after read(). Prepare the
982 * fio_flags to avoid having to parse the string each time.
983 * Also check for Unicode to Latin1 conversion, because iconv()
984 * appears not to handle this correctly. This works just like
985 * conversion to UTF-8 except how the resulting character is put in
986 * the buffer.
987 */
988 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
989 fio_flags = get_fio_flags(fenc);
990
991# ifdef WIN3264
992 /*
993 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
994 * is handled with MultiByteToWideChar().
995 */
996 if (fio_flags == 0)
997 fio_flags = get_win_fio_flags(fenc);
998# endif
999
1000# ifdef MACOS_X
1001 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1002 if (fio_flags == 0)
1003 fio_flags = get_mac_fio_flags(fenc);
1004# endif
1005
1006# ifdef USE_ICONV
1007 /*
1008 * Try using iconv() if we can't convert internally.
1009 */
1010 if (fio_flags == 0
1011# ifdef FEAT_EVAL
1012 && !did_iconv
1013# endif
1014 )
1015 iconv_fd = (iconv_t)my_iconv_open(
1016 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
1017# endif
1018
1019# ifdef FEAT_EVAL
1020 /*
1021 * Use the 'charconvert' expression when conversion is required
1022 * and we can't do it internally or with iconv().
1023 */
1024 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
1025# ifdef USE_ICONV
1026 && iconv_fd == (iconv_t)-1
1027# endif
1028 )
1029 {
1030# ifdef USE_ICONV
1031 did_iconv = FALSE;
1032# endif
1033 /* Skip conversion when it's already done (retry for wrong
1034 * "fileformat"). */
1035 if (tmpname == NULL)
1036 {
1037 tmpname = readfile_charconvert(fname, fenc, &fd);
1038 if (tmpname == NULL)
1039 {
1040 /* Conversion failed. Try another one. */
1041 advance_fenc = TRUE;
1042 if (fd < 0)
1043 {
1044 /* Re-opening the original file failed! */
1045 EMSG(_("E202: Conversion made file unreadable!"));
1046 error = TRUE;
1047 goto failed;
1048 }
1049 goto retry;
1050 }
1051 }
1052 }
1053 else
1054# endif
1055 {
1056 if (fio_flags == 0
1057# ifdef USE_ICONV
1058 && iconv_fd == (iconv_t)-1
1059# endif
1060 )
1061 {
1062 /* Conversion wanted but we can't.
1063 * Try the next conversion in 'fileencodings' */
1064 advance_fenc = TRUE;
1065 goto retry;
1066 }
1067 }
1068 }
1069
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001070 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001072 * stdin or fixed at a specific encoding. */
1073 can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074#endif
1075
1076 if (!skip_read)
1077 {
1078 linerest = 0;
1079 filesize = 0;
1080 skip_count = lines_to_skip;
1081 read_count = lines_to_read;
1082#ifdef FEAT_MBYTE
1083 conv_restlen = 0;
1084#endif
1085 }
1086
1087 while (!error && !got_int)
1088 {
1089 /*
1090 * We allocate as much space for the file as we can get, plus
1091 * space for the old line plus room for one terminating NUL.
1092 * The amount is limited by the fact that read() only can read
1093 * upto max_unsigned characters (and other things).
1094 */
1095#if SIZEOF_INT <= 2
1096 if (linerest >= 0x7ff0)
1097 {
1098 ++split;
1099 *ptr = NL; /* split line by inserting a NL */
1100 size = 1;
1101 }
1102 else
1103#endif
1104 {
1105 if (!skip_read)
1106 {
1107#if SIZEOF_INT > 2
1108# ifdef __TANDEM
1109 size = SSIZE_MAX; /* use max I/O size, 52K */
1110# else
1111 size = 0x10000L; /* use buffer >= 64K */
1112# endif
1113#else
1114 size = 0x7ff0L - linerest; /* limit buffer to 32K */
1115#endif
1116
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001117 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 {
1119 if ((new_buffer = lalloc((long_u)(size + linerest + 1),
1120 FALSE)) != NULL)
1121 break;
1122 }
1123 if (new_buffer == NULL)
1124 {
1125 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1126 error = TRUE;
1127 break;
1128 }
1129 if (linerest) /* copy characters from the previous buffer */
1130 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1131 vim_free(buffer);
1132 buffer = new_buffer;
1133 ptr = buffer + linerest;
1134 line_start = buffer;
1135
1136#ifdef FEAT_MBYTE
1137 /* May need room to translate into.
1138 * For iconv() we don't really know the required space, use a
1139 * factor ICONV_MULT.
1140 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1141 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1142 * become up to 4 bytes, size must be multiple of 2
1143 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1144 * multiple of 2
1145 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1146 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001147 real_size = (int)size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148# ifdef USE_ICONV
1149 if (iconv_fd != (iconv_t)-1)
1150 size = size / ICONV_MULT;
1151 else
1152# endif
1153 if (fio_flags & FIO_LATIN1)
1154 size = size / 2;
1155 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1156 size = (size * 2 / 3) & ~1;
1157 else if (fio_flags & FIO_UCS4)
1158 size = (size * 2 / 3) & ~3;
1159 else if (fio_flags == FIO_UCSBOM)
1160 size = size / ICONV_MULT; /* worst case */
1161# ifdef WIN3264
1162 else if (fio_flags & FIO_CODEPAGE)
1163 size = size / ICONV_MULT; /* also worst case */
1164# endif
1165# ifdef MACOS_X
1166 else if (fio_flags & FIO_MACROMAN)
1167 size = size / ICONV_MULT; /* also worst case */
1168# endif
1169#endif
1170
1171#ifdef FEAT_MBYTE
1172 if (conv_restlen > 0)
1173 {
1174 /* Insert unconverted bytes from previous line. */
1175 mch_memmove(ptr, conv_rest, conv_restlen);
1176 ptr += conv_restlen;
1177 size -= conv_restlen;
1178 }
1179#endif
1180
1181 if (read_buffer)
1182 {
1183 /*
1184 * Read bytes from curbuf. Used for converting text read
1185 * from stdin.
1186 */
1187 if (read_buf_lnum > from)
1188 size = 0;
1189 else
1190 {
1191 int n, ni;
1192 long tlen;
1193
1194 tlen = 0;
1195 for (;;)
1196 {
1197 p = ml_get(read_buf_lnum) + read_buf_col;
1198 n = (int)STRLEN(p);
1199 if ((int)tlen + n + 1 > size)
1200 {
1201 /* Filled up to "size", append partial line.
1202 * Change NL to NUL to reverse the effect done
1203 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001204 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 for (ni = 0; ni < n; ++ni)
1206 {
1207 if (p[ni] == NL)
1208 ptr[tlen++] = NUL;
1209 else
1210 ptr[tlen++] = p[ni];
1211 }
1212 read_buf_col += n;
1213 break;
1214 }
1215 else
1216 {
1217 /* Append whole line and new-line. Change NL
1218 * to NUL to reverse the effect done below. */
1219 for (ni = 0; ni < n; ++ni)
1220 {
1221 if (p[ni] == NL)
1222 ptr[tlen++] = NUL;
1223 else
1224 ptr[tlen++] = p[ni];
1225 }
1226 ptr[tlen++] = NL;
1227 read_buf_col = 0;
1228 if (++read_buf_lnum > from)
1229 {
1230 /* When the last line didn't have an
1231 * end-of-line don't add it now either. */
1232 if (!curbuf->b_p_eol)
1233 --tlen;
1234 size = tlen;
1235 break;
1236 }
1237 }
1238 }
1239 }
1240 }
1241 else
1242 {
1243 /*
1244 * Read bytes from the file.
1245 */
1246 size = vim_read(fd, ptr, size);
1247 }
1248
1249 if (size <= 0)
1250 {
1251 if (size < 0) /* read error */
1252 error = TRUE;
1253#ifdef FEAT_MBYTE
1254 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001255 {
1256 /* Reached end-of-file but some trailing bytes could
1257 * not be converted. Trucated file? */
1258 if (conv_error == 0)
1259 conv_error = linecnt;
1260 if (bad_char_behavior != BAD_DROP)
1261 {
1262 fio_flags = 0; /* don't convert this */
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001263# ifdef USE_ICONV
1264 if (iconv_fd != (iconv_t)-1)
1265 {
1266 iconv_close(iconv_fd);
1267 iconv_fd = (iconv_t)-1;
1268 }
1269# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001270 if (bad_char_behavior == BAD_KEEP)
1271 {
1272 /* Keep the trailing bytes as-is. */
1273 size = conv_restlen;
1274 ptr -= conv_restlen;
1275 }
1276 else
1277 {
1278 /* Replace the trailing bytes with the
1279 * replacement character. */
1280 size = 1;
1281 *--ptr = bad_char_behavior;
1282 }
1283 conv_restlen = 0;
1284 }
1285 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286#endif
1287 }
1288
1289#ifdef FEAT_CRYPT
1290 /*
1291 * At start of file: Check for magic number of encryption.
1292 */
1293 if (filesize == 0)
1294 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1295 &filesize, newfile);
1296 /*
1297 * Decrypt the read bytes.
1298 */
1299 if (cryptkey != NULL && size > 0)
1300 for (p = ptr; p < ptr + size; ++p)
1301 ZDECODE(*p);
1302#endif
1303 }
1304 skip_read = FALSE;
1305
1306#ifdef FEAT_MBYTE
1307 /*
1308 * At start of file (or after crypt magic number): Check for BOM.
1309 * Also check for a BOM for other Unicode encodings, but not after
1310 * converting with 'charconvert' or when a BOM has already been
1311 * found.
1312 */
1313 if ((filesize == 0
1314# ifdef FEAT_CRYPT
1315 || (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
1316# endif
1317 )
1318 && (fio_flags == FIO_UCSBOM
1319 || (!curbuf->b_p_bomb
1320 && tmpname == NULL
1321 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1322 {
1323 char_u *ccname;
1324 int blen;
1325
1326 /* no BOM detection in a short file or in binary mode */
1327 if (size < 2 || curbuf->b_p_bin)
1328 ccname = NULL;
1329 else
1330 ccname = check_for_bom(ptr, size, &blen,
1331 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1332 if (ccname != NULL)
1333 {
1334 /* Remove BOM from the text */
1335 filesize += blen;
1336 size -= blen;
1337 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001338 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 curbuf->b_p_bomb = TRUE;
1340 }
1341
1342 if (fio_flags == FIO_UCSBOM)
1343 {
1344 if (ccname == NULL)
1345 {
1346 /* No BOM detected: retry with next encoding. */
1347 advance_fenc = TRUE;
1348 }
1349 else
1350 {
1351 /* BOM detected: set "fenc" and jump back */
1352 if (fenc_alloced)
1353 vim_free(fenc);
1354 fenc = ccname;
1355 fenc_alloced = FALSE;
1356 }
1357 /* retry reading without getting new bytes or rewinding */
1358 skip_read = TRUE;
1359 goto retry;
1360 }
1361 }
1362#endif
1363 /*
1364 * Break here for a read error or end-of-file.
1365 */
1366 if (size <= 0)
1367 break;
1368
1369#ifdef FEAT_MBYTE
1370
1371 /* Include not converted bytes. */
1372 ptr -= conv_restlen;
1373 size += conv_restlen;
1374 conv_restlen = 0;
1375
1376# ifdef USE_ICONV
1377 if (iconv_fd != (iconv_t)-1)
1378 {
1379 /*
1380 * Attempt conversion of the read bytes to 'encoding' using
1381 * iconv().
1382 */
1383 const char *fromp;
1384 char *top;
1385 size_t from_size;
1386 size_t to_size;
1387
1388 fromp = (char *)ptr;
1389 from_size = size;
1390 ptr += size;
1391 top = (char *)ptr;
1392 to_size = real_size - size;
1393
1394 /*
1395 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001396 * another conversion. Except for when there is no
1397 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001399 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1400 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1402 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001403 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001404 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001405 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001406 if (conv_error == 0)
1407 conv_error = readfile_linenr(linecnt,
1408 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001409
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001410 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001411 ++fromp;
1412 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001413 if (bad_char_behavior == BAD_KEEP)
1414 {
1415 *top++ = *(fromp - 1);
1416 --to_size;
1417 }
1418 else if (bad_char_behavior != BAD_DROP)
1419 {
1420 *top++ = bad_char_behavior;
1421 --to_size;
1422 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424
1425 if (from_size > 0)
1426 {
1427 /* Some remaining characters, keep them for the next
1428 * round. */
1429 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1430 conv_restlen = (int)from_size;
1431 }
1432
1433 /* move the linerest to before the converted characters */
1434 line_start = ptr - linerest;
1435 mch_memmove(line_start, buffer, (size_t)linerest);
1436 size = (long)((char_u *)top - ptr);
1437 }
1438# endif
1439
1440# ifdef WIN3264
1441 if (fio_flags & FIO_CODEPAGE)
1442 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001443 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001444 WCHAR ucs2buf[3];
1445 int ucs2len;
1446 int codepage = FIO_GET_CP(fio_flags);
1447 int bytelen;
1448 int found_bad;
1449 char replstr[2];
1450
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451 /*
1452 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001453 * a codepage, using standard MS-Windows functions. This
1454 * requires two steps:
1455 * 1. convert from 'fileencoding' to ucs-2
1456 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001458 * Because there may be illegal bytes AND an incomplete byte
1459 * sequence at the end, we may have to do the conversion one
1460 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001463 /* Replacement string for WideCharToMultiByte(). */
1464 if (bad_char_behavior > 0)
1465 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001467 replstr[0] = '?';
1468 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469
1470 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001471 * Move the bytes to the end of the buffer, so that we have
1472 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001474 src = ptr + real_size - size;
1475 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001477 /*
1478 * Do the conversion.
1479 */
1480 dst = ptr;
1481 size = size;
1482 while (size > 0)
1483 {
1484 found_bad = FALSE;
1485
1486# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1487 if (codepage == CP_UTF8)
1488 {
1489 /* Handle CP_UTF8 input ourselves to be able to handle
1490 * trailing bytes properly.
1491 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001492 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001493 if (bytelen > size)
1494 {
1495 /* Only got some bytes of a character. Normally
1496 * it's put in "conv_rest", but if it's too long
1497 * deal with it as if they were illegal bytes. */
1498 if (bytelen <= CONV_RESTLEN)
1499 break;
1500
1501 /* weird overlong byte sequence */
1502 bytelen = size;
1503 found_bad = TRUE;
1504 }
1505 else
1506 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001507 int u8c = utf_ptr2char(src);
1508
Bram Moolenaar86e01082005-12-29 22:45:34 +00001509 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001510 found_bad = TRUE;
1511 ucs2buf[0] = u8c;
1512 ucs2len = 1;
1513 }
1514 }
1515 else
1516# endif
1517 {
1518 /* We don't know how long the byte sequence is, try
1519 * from one to three bytes. */
1520 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1521 ++bytelen)
1522 {
1523 ucs2len = MultiByteToWideChar(codepage,
1524 MB_ERR_INVALID_CHARS,
1525 (LPCSTR)src, bytelen,
1526 ucs2buf, 3);
1527 if (ucs2len > 0)
1528 break;
1529 }
1530 if (ucs2len == 0)
1531 {
1532 /* If we have only one byte then it's probably an
1533 * incomplete byte sequence. Otherwise discard
1534 * one byte as a bad character. */
1535 if (size == 1)
1536 break;
1537 found_bad = TRUE;
1538 bytelen = 1;
1539 }
1540 }
1541
1542 if (!found_bad)
1543 {
1544 int i;
1545
1546 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1547 if (enc_utf8)
1548 {
1549 /* From UCS-2 to UTF-8. Cannot fail. */
1550 for (i = 0; i < ucs2len; ++i)
1551 dst += utf_char2bytes(ucs2buf[i], dst);
1552 }
1553 else
1554 {
1555 BOOL bad = FALSE;
1556 int dstlen;
1557
1558 /* From UCS-2 to "enc_codepage". If the
1559 * conversion uses the default character "?",
1560 * the data doesn't fit in this encoding. */
1561 dstlen = WideCharToMultiByte(enc_codepage, 0,
1562 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001563 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001564 replstr, &bad);
1565 if (bad)
1566 found_bad = TRUE;
1567 else
1568 dst += dstlen;
1569 }
1570 }
1571
1572 if (found_bad)
1573 {
1574 /* Deal with bytes we can't convert. */
1575 if (can_retry)
1576 goto rewind_retry;
1577 if (conv_error == 0)
1578 conv_error = readfile_linenr(linecnt, ptr, dst);
1579 if (bad_char_behavior != BAD_DROP)
1580 {
1581 if (bad_char_behavior == BAD_KEEP)
1582 {
1583 mch_memmove(dst, src, bytelen);
1584 dst += bytelen;
1585 }
1586 else
1587 *dst++ = bad_char_behavior;
1588 }
1589 }
1590
1591 src += bytelen;
1592 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001594
1595 if (size > 0)
1596 {
1597 /* An incomplete byte sequence remaining. */
1598 mch_memmove(conv_rest, src, size);
1599 conv_restlen = size;
1600 }
1601
1602 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001603 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604 }
1605 else
1606# endif
Bram Moolenaar56718732006-03-15 22:53:57 +00001607# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 if (fio_flags & FIO_MACROMAN)
1609 {
1610 /*
1611 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001612 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001614 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 }
1617 else
1618# endif
1619 if (fio_flags != 0)
1620 {
1621 int u8c;
1622 char_u *dest;
1623 char_u *tail = NULL;
1624
1625 /*
1626 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1627 * "enc_utf8" not set: Convert Unicode to Latin1.
1628 * Go from end to start through the buffer, because the number
1629 * of bytes may increase.
1630 * "dest" points to after where the UTF-8 bytes go, "p" points
1631 * to after the next character to convert.
1632 */
1633 dest = ptr + real_size;
1634 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1635 {
1636 p = ptr + size;
1637 if (fio_flags == FIO_UTF8)
1638 {
1639 /* Check for a trailing incomplete UTF-8 sequence */
1640 tail = ptr + size - 1;
1641 while (tail > ptr && (*tail & 0xc0) == 0x80)
1642 --tail;
1643 if (tail + utf_byte2len(*tail) <= ptr + size)
1644 tail = NULL;
1645 else
1646 p = tail;
1647 }
1648 }
1649 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1650 {
1651 /* Check for a trailing byte */
1652 p = ptr + (size & ~1);
1653 if (size & 1)
1654 tail = p;
1655 if ((fio_flags & FIO_UTF16) && p > ptr)
1656 {
1657 /* Check for a trailing leading word */
1658 if (fio_flags & FIO_ENDIAN_L)
1659 {
1660 u8c = (*--p << 8);
1661 u8c += *--p;
1662 }
1663 else
1664 {
1665 u8c = *--p;
1666 u8c += (*--p << 8);
1667 }
1668 if (u8c >= 0xd800 && u8c <= 0xdbff)
1669 tail = p;
1670 else
1671 p += 2;
1672 }
1673 }
1674 else /* FIO_UCS4 */
1675 {
1676 /* Check for trailing 1, 2 or 3 bytes */
1677 p = ptr + (size & ~3);
1678 if (size & 3)
1679 tail = p;
1680 }
1681
1682 /* If there is a trailing incomplete sequence move it to
1683 * conv_rest[]. */
1684 if (tail != NULL)
1685 {
1686 conv_restlen = (int)((ptr + size) - tail);
1687 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1688 size -= conv_restlen;
1689 }
1690
1691
1692 while (p > ptr)
1693 {
1694 if (fio_flags & FIO_LATIN1)
1695 u8c = *--p;
1696 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1697 {
1698 if (fio_flags & FIO_ENDIAN_L)
1699 {
1700 u8c = (*--p << 8);
1701 u8c += *--p;
1702 }
1703 else
1704 {
1705 u8c = *--p;
1706 u8c += (*--p << 8);
1707 }
1708 if ((fio_flags & FIO_UTF16)
1709 && u8c >= 0xdc00 && u8c <= 0xdfff)
1710 {
1711 int u16c;
1712
1713 if (p == ptr)
1714 {
1715 /* Missing leading word. */
1716 if (can_retry)
1717 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001718 if (conv_error == 0)
1719 conv_error = readfile_linenr(linecnt,
1720 ptr, p);
1721 if (bad_char_behavior == BAD_DROP)
1722 continue;
1723 if (bad_char_behavior != BAD_KEEP)
1724 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 }
1726
1727 /* found second word of double-word, get the first
1728 * word and compute the resulting character */
1729 if (fio_flags & FIO_ENDIAN_L)
1730 {
1731 u16c = (*--p << 8);
1732 u16c += *--p;
1733 }
1734 else
1735 {
1736 u16c = *--p;
1737 u16c += (*--p << 8);
1738 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001739 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1740 + (u8c & 0x3ff);
1741
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 /* Check if the word is indeed a leading word. */
1743 if (u16c < 0xd800 || u16c > 0xdbff)
1744 {
1745 if (can_retry)
1746 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001747 if (conv_error == 0)
1748 conv_error = readfile_linenr(linecnt,
1749 ptr, p);
1750 if (bad_char_behavior == BAD_DROP)
1751 continue;
1752 if (bad_char_behavior != BAD_KEEP)
1753 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 }
1756 }
1757 else if (fio_flags & FIO_UCS4)
1758 {
1759 if (fio_flags & FIO_ENDIAN_L)
1760 {
1761 u8c = (*--p << 24);
1762 u8c += (*--p << 16);
1763 u8c += (*--p << 8);
1764 u8c += *--p;
1765 }
1766 else /* big endian */
1767 {
1768 u8c = *--p;
1769 u8c += (*--p << 8);
1770 u8c += (*--p << 16);
1771 u8c += (*--p << 24);
1772 }
1773 }
1774 else /* UTF-8 */
1775 {
1776 if (*--p < 0x80)
1777 u8c = *p;
1778 else
1779 {
1780 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001781 p -= len;
1782 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 if (len == 0)
1784 {
1785 /* Not a valid UTF-8 character, retry with
1786 * another fenc when possible, otherwise just
1787 * report the error. */
1788 if (can_retry)
1789 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001790 if (conv_error == 0)
1791 conv_error = readfile_linenr(linecnt,
1792 ptr, p);
1793 if (bad_char_behavior == BAD_DROP)
1794 continue;
1795 if (bad_char_behavior != BAD_KEEP)
1796 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 }
1799 }
1800 if (enc_utf8) /* produce UTF-8 */
1801 {
1802 dest -= utf_char2len(u8c);
1803 (void)utf_char2bytes(u8c, dest);
1804 }
1805 else /* produce Latin1 */
1806 {
1807 --dest;
1808 if (u8c >= 0x100)
1809 {
1810 /* character doesn't fit in latin1, retry with
1811 * another fenc when possible, otherwise just
1812 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001813 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001815 if (conv_error == 0)
1816 conv_error = readfile_linenr(linecnt, ptr, p);
1817 if (bad_char_behavior == BAD_DROP)
1818 ++dest;
1819 else if (bad_char_behavior == BAD_KEEP)
1820 *dest = u8c;
1821 else if (eap != NULL && eap->bad_char != 0)
1822 *dest = bad_char_behavior;
1823 else
1824 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825 }
1826 else
1827 *dest = u8c;
1828 }
1829 }
1830
1831 /* move the linerest to before the converted characters */
1832 line_start = dest - linerest;
1833 mch_memmove(line_start, buffer, (size_t)linerest);
1834 size = (long)((ptr + real_size) - dest);
1835 ptr = dest;
1836 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001837 else if (enc_utf8 && conv_error == 0 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 {
1839 /* Reading UTF-8: Check if the bytes are valid UTF-8.
1840 * Need to start before "ptr" when part of the character was
1841 * read in the previous read() call. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001842 for (p = ptr - utf_head_off(buffer, ptr); ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001844 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001845 int l;
1846
1847 if (todo <= 0)
1848 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 if (*p >= 0x80)
1850 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 /* A length of 1 means it's an illegal byte. Accept
1852 * an incomplete character at the end though, the next
1853 * read() will get the next bytes, we'll check it
1854 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001855 l = utf_ptr2len_len(p, todo);
1856 if (l > todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001858 /* Incomplete byte sequence, the next read()
1859 * should get them and check the bytes. */
1860 p += todo;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 break;
1862 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001863 if (l == 1)
1864 {
1865 /* Illegal byte. If we can try another encoding
1866 * do that. */
1867 if (can_retry)
1868 break;
1869
1870 /* Remember the first linenr with an illegal byte */
1871 if (illegal_byte == 0)
1872 illegal_byte = readfile_linenr(linecnt, ptr, p);
1873# ifdef USE_ICONV
1874 /* When we did a conversion report an error. */
1875 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
1876 conv_error = readfile_linenr(linecnt, ptr, p);
1877# endif
1878
1879 /* Drop, keep or replace the bad byte. */
1880 if (bad_char_behavior == BAD_DROP)
1881 {
1882 mch_memmove(p, p+1, todo - 1);
1883 --p;
1884 --size;
1885 }
1886 else if (bad_char_behavior != BAD_KEEP)
1887 *p = bad_char_behavior;
1888 }
1889 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 }
1891 }
1892 if (p < ptr + size)
1893 {
1894 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001896 /* Retry reading with another conversion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897# if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001898 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
1899 /* iconv() failed, try 'charconvert' */
1900 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 else
1902# endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001903 /* use next item from 'fileencodings' */
1904 advance_fenc = TRUE;
1905 file_rewind = TRUE;
1906 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 }
1908 }
1909#endif
1910
1911 /* count the number of characters (after conversion!) */
1912 filesize += size;
1913
1914 /*
1915 * when reading the first part of a file: guess EOL type
1916 */
1917 if (fileformat == EOL_UNKNOWN)
1918 {
1919 /* First try finding a NL, for Dos and Unix */
1920 if (try_dos || try_unix)
1921 {
1922 for (p = ptr; p < ptr + size; ++p)
1923 {
1924 if (*p == NL)
1925 {
1926 if (!try_unix
1927 || (try_dos && p > ptr && p[-1] == CAR))
1928 fileformat = EOL_DOS;
1929 else
1930 fileformat = EOL_UNIX;
1931 break;
1932 }
1933 }
1934
1935 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
1936 if (fileformat == EOL_UNIX && try_mac)
1937 {
1938 /* Need to reset the counters when retrying fenc. */
1939 try_mac = 1;
1940 try_unix = 1;
1941 for (; p >= ptr && *p != CAR; p--)
1942 ;
1943 if (p >= ptr)
1944 {
1945 for (p = ptr; p < ptr + size; ++p)
1946 {
1947 if (*p == NL)
1948 try_unix++;
1949 else if (*p == CAR)
1950 try_mac++;
1951 }
1952 if (try_mac > try_unix)
1953 fileformat = EOL_MAC;
1954 }
1955 }
1956 }
1957
1958 /* No NL found: may use Mac format */
1959 if (fileformat == EOL_UNKNOWN && try_mac)
1960 fileformat = EOL_MAC;
1961
1962 /* Still nothing found? Use first format in 'ffs' */
1963 if (fileformat == EOL_UNKNOWN)
1964 fileformat = default_fileformat();
1965
1966 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001967 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968 set_fileformat(fileformat, OPT_LOCAL);
1969 }
1970 }
1971
1972 /*
1973 * This loop is executed once for every character read.
1974 * Keep it fast!
1975 */
1976 if (fileformat == EOL_MAC)
1977 {
1978 --ptr;
1979 while (++ptr, --size >= 0)
1980 {
1981 /* catch most common case first */
1982 if ((c = *ptr) != NUL && c != CAR && c != NL)
1983 continue;
1984 if (c == NUL)
1985 *ptr = NL; /* NULs are replaced by newlines! */
1986 else if (c == NL)
1987 *ptr = CAR; /* NLs are replaced by CRs! */
1988 else
1989 {
1990 if (skip_count == 0)
1991 {
1992 *ptr = NUL; /* end of line */
1993 len = (colnr_T) (ptr - line_start + 1);
1994 if (ml_append(lnum, line_start, len, newfile) == FAIL)
1995 {
1996 error = TRUE;
1997 break;
1998 }
1999 ++lnum;
2000 if (--read_count == 0)
2001 {
2002 error = TRUE; /* break loop */
2003 line_start = ptr; /* nothing left to write */
2004 break;
2005 }
2006 }
2007 else
2008 --skip_count;
2009 line_start = ptr + 1;
2010 }
2011 }
2012 }
2013 else
2014 {
2015 --ptr;
2016 while (++ptr, --size >= 0)
2017 {
2018 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2019 continue;
2020 if (c == NUL)
2021 *ptr = NL; /* NULs are replaced by newlines! */
2022 else
2023 {
2024 if (skip_count == 0)
2025 {
2026 *ptr = NUL; /* end of line */
2027 len = (colnr_T)(ptr - line_start + 1);
2028 if (fileformat == EOL_DOS)
2029 {
2030 if (ptr[-1] == CAR) /* remove CR */
2031 {
2032 ptr[-1] = NUL;
2033 --len;
2034 }
2035 /*
2036 * Reading in Dos format, but no CR-LF found!
2037 * When 'fileformats' includes "unix", delete all
2038 * the lines read so far and start all over again.
2039 * Otherwise give an error message later.
2040 */
2041 else if (ff_error != EOL_DOS)
2042 {
2043 if ( try_unix
2044 && !read_stdin
2045 && (read_buffer
2046 || lseek(fd, (off_t)0L, SEEK_SET) == 0))
2047 {
2048 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002049 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 set_fileformat(EOL_UNIX, OPT_LOCAL);
2051 file_rewind = TRUE;
2052 keep_fileformat = TRUE;
2053 goto retry;
2054 }
2055 ff_error = EOL_DOS;
2056 }
2057 }
2058 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2059 {
2060 error = TRUE;
2061 break;
2062 }
2063 ++lnum;
2064 if (--read_count == 0)
2065 {
2066 error = TRUE; /* break loop */
2067 line_start = ptr; /* nothing left to write */
2068 break;
2069 }
2070 }
2071 else
2072 --skip_count;
2073 line_start = ptr + 1;
2074 }
2075 }
2076 }
2077 linerest = (long)(ptr - line_start);
2078 ui_breakcheck();
2079 }
2080
2081failed:
2082 /* not an error, max. number of lines reached */
2083 if (error && read_count == 0)
2084 error = FALSE;
2085
2086 /*
2087 * If we get EOF in the middle of a line, note the fact and
2088 * complete the line ourselves.
2089 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2090 */
2091 if (!error
2092 && !got_int
2093 && linerest != 0
2094 && !(!curbuf->b_p_bin
2095 && fileformat == EOL_DOS
2096 && *line_start == Ctrl_Z
2097 && ptr == line_start + 1))
2098 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002099 /* remember for when writing */
2100 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101 curbuf->b_p_eol = FALSE;
2102 *ptr = NUL;
2103 if (ml_append(lnum, line_start,
2104 (colnr_T)(ptr - line_start + 1), newfile) == FAIL)
2105 error = TRUE;
2106 else
2107 read_no_eol_lnum = ++lnum;
2108 }
2109
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002110 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 save_file_ff(curbuf); /* remember the current file format */
2112
2113#ifdef FEAT_CRYPT
2114 if (cryptkey != curbuf->b_p_key)
2115 vim_free(cryptkey);
2116#endif
2117
2118#ifdef FEAT_MBYTE
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002119 /* If editing a new file: set 'fenc' for the current buffer.
2120 * Also for ":read ++edit file". */
2121 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002123 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 if (fenc_alloced)
2125 vim_free(fenc);
2126# ifdef USE_ICONV
2127 if (iconv_fd != (iconv_t)-1)
2128 {
2129 iconv_close(iconv_fd);
2130 iconv_fd = (iconv_t)-1;
2131 }
2132# endif
2133#endif
2134
2135 if (!read_buffer && !read_stdin)
2136 close(fd); /* errors are ignored */
2137 vim_free(buffer);
2138
2139#ifdef HAVE_DUP
2140 if (read_stdin)
2141 {
2142 /* Use stderr for stdin, makes shell commands work. */
2143 close(0);
2144 dup(2);
2145 }
2146#endif
2147
2148#ifdef FEAT_MBYTE
2149 if (tmpname != NULL)
2150 {
2151 mch_remove(tmpname); /* delete converted file */
2152 vim_free(tmpname);
2153 }
2154#endif
2155 --no_wait_return; /* may wait for return now */
2156
2157 /*
2158 * In recovery mode everything but autocommands is skipped.
2159 */
2160 if (!recoverymode)
2161 {
2162 /* need to delete the last line, which comes from the empty buffer */
2163 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2164 {
2165#ifdef FEAT_NETBEANS_INTG
2166 netbeansFireChanges = 0;
2167#endif
2168 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2169#ifdef FEAT_NETBEANS_INTG
2170 netbeansFireChanges = 1;
2171#endif
2172 --linecnt;
2173 }
2174 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2175 if (filesize == 0)
2176 linecnt = 0;
2177 if (newfile || read_buffer)
2178 redraw_curbuf_later(NOT_VALID);
2179 else if (linecnt) /* appended at least one line */
2180 appended_lines_mark(from, linecnt);
2181
2182#ifdef FEAT_DIFF
2183 /* After reading the text into the buffer the diff info needs to be
2184 * updated. */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002185 if (newfile || read_buffer)
2186 diff_invalidate(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187#endif
2188#ifndef ALWAYS_USE_GUI
2189 /*
2190 * If we were reading from the same terminal as where messages go,
2191 * the screen will have been messed up.
2192 * Switch on raw mode now and clear the screen.
2193 */
2194 if (read_stdin)
2195 {
2196 settmode(TMODE_RAW); /* set to raw mode */
2197 starttermcap();
2198 screenclear();
2199 }
2200#endif
2201
2202 if (got_int)
2203 {
2204 if (!(flags & READ_DUMMY))
2205 {
2206 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2207 if (newfile)
2208 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2209 }
2210 msg_scroll = msg_save;
2211#ifdef FEAT_VIMINFO
2212 check_marks_read();
2213#endif
2214 return OK; /* an interrupt isn't really an error */
2215 }
2216
2217 if (!filtering && !(flags & READ_DUMMY))
2218 {
2219 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2220 c = FALSE;
2221
2222#ifdef UNIX
2223# ifdef S_ISFIFO
2224 if (S_ISFIFO(perm)) /* fifo or socket */
2225 {
2226 STRCAT(IObuff, _("[fifo/socket]"));
2227 c = TRUE;
2228 }
2229# else
2230# ifdef S_IFIFO
2231 if ((perm & S_IFMT) == S_IFIFO) /* fifo */
2232 {
2233 STRCAT(IObuff, _("[fifo]"));
2234 c = TRUE;
2235 }
2236# endif
2237# ifdef S_IFSOCK
2238 if ((perm & S_IFMT) == S_IFSOCK) /* or socket */
2239 {
2240 STRCAT(IObuff, _("[socket]"));
2241 c = TRUE;
2242 }
2243# endif
2244# endif
2245#endif
2246 if (curbuf->b_p_ro)
2247 {
2248 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2249 c = TRUE;
2250 }
2251 if (read_no_eol_lnum)
2252 {
2253 msg_add_eol();
2254 c = TRUE;
2255 }
2256 if (ff_error == EOL_DOS)
2257 {
2258 STRCAT(IObuff, _("[CR missing]"));
2259 c = TRUE;
2260 }
2261 if (ff_error == EOL_MAC)
2262 {
2263 STRCAT(IObuff, _("[NL found]"));
2264 c = TRUE;
2265 }
2266 if (split)
2267 {
2268 STRCAT(IObuff, _("[long lines split]"));
2269 c = TRUE;
2270 }
2271#ifdef FEAT_MBYTE
2272 if (notconverted)
2273 {
2274 STRCAT(IObuff, _("[NOT converted]"));
2275 c = TRUE;
2276 }
2277 else if (converted)
2278 {
2279 STRCAT(IObuff, _("[converted]"));
2280 c = TRUE;
2281 }
2282#endif
2283#ifdef FEAT_CRYPT
2284 if (cryptkey != NULL)
2285 {
2286 STRCAT(IObuff, _("[crypted]"));
2287 c = TRUE;
2288 }
2289#endif
2290#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002291 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002293 sprintf((char *)IObuff + STRLEN(IObuff),
2294 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 c = TRUE;
2296 }
2297 else if (illegal_byte > 0)
2298 {
2299 sprintf((char *)IObuff + STRLEN(IObuff),
2300 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2301 c = TRUE;
2302 }
2303 else
2304#endif
2305 if (error)
2306 {
2307 STRCAT(IObuff, _("[READ ERRORS]"));
2308 c = TRUE;
2309 }
2310 if (msg_add_fileformat(fileformat))
2311 c = TRUE;
2312#ifdef FEAT_CRYPT
2313 if (cryptkey != NULL)
2314 msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
2315 else
2316#endif
2317 msg_add_lines(c, (long)linecnt, filesize);
2318
2319 vim_free(keep_msg);
2320 keep_msg = NULL;
2321 msg_scrolled_ign = TRUE;
2322#ifdef ALWAYS_USE_GUI
2323 /* Don't show the message when reading stdin, it would end up in a
2324 * message box (which might be shown when exiting!) */
2325 if (read_stdin || read_buffer)
2326 p = msg_may_trunc(FALSE, IObuff);
2327 else
2328#endif
2329 p = msg_trunc_attr(IObuff, FALSE, 0);
2330 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002331 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 /* Need to repeat the message after redrawing when:
2333 * - When reading from stdin (the screen will be cleared next).
2334 * - When restart_edit is set (otherwise there will be a delay
2335 * before redrawing).
2336 * - When the screen was scrolled but there is no wait-return
2337 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002338 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 msg_scrolled_ign = FALSE;
2340 }
2341
2342 /* with errors writing the file requires ":w!" */
2343 if (newfile && (error
2344#ifdef FEAT_MBYTE
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002345 || conv_error != 0
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002346 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347#endif
2348 ))
2349 curbuf->b_p_ro = TRUE;
2350
2351 u_clearline(); /* cannot use "U" command after adding lines */
2352
2353 /*
2354 * In Ex mode: cursor at last new line.
2355 * Otherwise: cursor at first new line.
2356 */
2357 if (exmode_active)
2358 curwin->w_cursor.lnum = from + linecnt;
2359 else
2360 curwin->w_cursor.lnum = from + 1;
2361 check_cursor_lnum();
2362 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2363
2364 /*
2365 * Set '[ and '] marks to the newly read lines.
2366 */
2367 curbuf->b_op_start.lnum = from + 1;
2368 curbuf->b_op_start.col = 0;
2369 curbuf->b_op_end.lnum = from + linecnt;
2370 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002371
2372#ifdef WIN32
2373 /*
2374 * Work around a weird problem: When a file has two links (only
2375 * possible on NTFS) and we write through one link, then stat() it
2376 * throught the other link, the timestamp information may be wrong.
2377 * It's correct again after reading the file, thus reset the timestamp
2378 * here.
2379 */
2380 if (newfile && !read_stdin && !read_buffer
2381 && mch_stat((char *)fname, &st) >= 0)
2382 {
2383 buf_store_time(curbuf, &st, fname);
2384 curbuf->b_mtime_read = curbuf->b_mtime;
2385 }
2386#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 }
2388 msg_scroll = msg_save;
2389
2390#ifdef FEAT_VIMINFO
2391 /*
2392 * Get the marks before executing autocommands, so they can be used there.
2393 */
2394 check_marks_read();
2395#endif
2396
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 /*
2398 * Trick: We remember if the last line of the read didn't have
2399 * an eol for when writing it again. This is required for
2400 * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
2401 */
2402 write_no_eol_lnum = read_no_eol_lnum;
2403
Bram Moolenaardf177f62005-02-22 08:39:57 +00002404#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 if (!read_stdin && !read_buffer)
2406 {
2407 int m = msg_scroll;
2408 int n = msg_scrolled;
2409
2410 /* Save the fileformat now, otherwise the buffer will be considered
2411 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002412 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 save_file_ff(curbuf);
2414
2415 /*
2416 * The output from the autocommands should not overwrite anything and
2417 * should not be overwritten: Set msg_scroll, restore its value if no
2418 * output was done.
2419 */
2420 msg_scroll = TRUE;
2421 if (filtering)
2422 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2423 FALSE, curbuf, eap);
2424 else if (newfile)
2425 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2426 FALSE, curbuf, eap);
2427 else
2428 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2429 FALSE, NULL, eap);
2430 if (msg_scrolled == n)
2431 msg_scroll = m;
2432#ifdef FEAT_EVAL
2433 if (aborting()) /* autocmds may abort script processing */
2434 return FAIL;
2435#endif
2436 }
2437#endif
2438
2439 if (recoverymode && error)
2440 return FAIL;
2441 return OK;
2442}
2443
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002444#ifdef FEAT_MBYTE
2445
2446/*
2447 * From the current line count and characters read after that, estimate the
2448 * line number where we are now.
2449 * Used for error messages that include a line number.
2450 */
2451 static linenr_T
2452readfile_linenr(linecnt, p, endp)
2453 linenr_T linecnt; /* line count before reading more bytes */
2454 char_u *p; /* start of more bytes read */
2455 char_u *endp; /* end of more bytes read */
2456{
2457 char_u *s;
2458 linenr_T lnum;
2459
2460 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2461 for (s = p; s < endp; ++s)
2462 if (*s == '\n')
2463 ++lnum;
2464 return lnum;
2465}
2466#endif
2467
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002469 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2470 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 * Returns OK or FAIL.
2472 */
2473 int
2474prep_exarg(eap, buf)
2475 exarg_T *eap;
2476 buf_T *buf;
2477{
2478 eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff)
2479#ifdef FEAT_MBYTE
2480 + STRLEN(buf->b_p_fenc)
2481#endif
2482 + 15));
2483 if (eap->cmd == NULL)
2484 return FAIL;
2485
2486#ifdef FEAT_MBYTE
2487 sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc);
2488 eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff);
Bram Moolenaar195d6352005-12-19 22:08:24 +00002489 eap->bad_char = buf->b_bad_char;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490#else
2491 sprintf((char *)eap->cmd, "e ++ff=%s", buf->b_p_ff);
2492#endif
2493 eap->force_ff = 7;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002494
2495 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002496 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002497 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 return OK;
2499}
2500
2501#ifdef FEAT_MBYTE
2502/*
2503 * Find next fileencoding to use from 'fileencodings'.
2504 * "pp" points to fenc_next. It's advanced to the next item.
2505 * When there are no more items, an empty string is returned and *pp is set to
2506 * NULL.
2507 * When *pp is not set to NULL, the result is in allocated memory.
2508 */
2509 static char_u *
2510next_fenc(pp)
2511 char_u **pp;
2512{
2513 char_u *p;
2514 char_u *r;
2515
2516 if (**pp == NUL)
2517 {
2518 *pp = NULL;
2519 return (char_u *)"";
2520 }
2521 p = vim_strchr(*pp, ',');
2522 if (p == NULL)
2523 {
2524 r = enc_canonize(*pp);
2525 *pp += STRLEN(*pp);
2526 }
2527 else
2528 {
2529 r = vim_strnsave(*pp, (int)(p - *pp));
2530 *pp = p + 1;
2531 if (r != NULL)
2532 {
2533 p = enc_canonize(r);
2534 vim_free(r);
2535 r = p;
2536 }
2537 }
2538 if (r == NULL) /* out of memory */
2539 {
2540 r = (char_u *)"";
2541 *pp = NULL;
2542 }
2543 return r;
2544}
2545
2546# ifdef FEAT_EVAL
2547/*
2548 * Convert a file with the 'charconvert' expression.
2549 * This closes the file which is to be read, converts it and opens the
2550 * resulting file for reading.
2551 * Returns name of the resulting converted file (the caller should delete it
2552 * after reading it).
2553 * Returns NULL if the conversion failed ("*fdp" is not set) .
2554 */
2555 static char_u *
2556readfile_charconvert(fname, fenc, fdp)
2557 char_u *fname; /* name of input file */
2558 char_u *fenc; /* converted from */
2559 int *fdp; /* in/out: file descriptor of file */
2560{
2561 char_u *tmpname;
2562 char_u *errmsg = NULL;
2563
2564 tmpname = vim_tempname('r');
2565 if (tmpname == NULL)
2566 errmsg = (char_u *)_("Can't find temp file for conversion");
2567 else
2568 {
2569 close(*fdp); /* close the input file, ignore errors */
2570 *fdp = -1;
2571 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2572 fname, tmpname) == FAIL)
2573 errmsg = (char_u *)_("Conversion with 'charconvert' failed");
2574 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2575 O_RDONLY | O_EXTRA, 0)) < 0)
2576 errmsg = (char_u *)_("can't read output of 'charconvert'");
2577 }
2578
2579 if (errmsg != NULL)
2580 {
2581 /* Don't use emsg(), it breaks mappings, the retry with
2582 * another type of conversion might still work. */
2583 MSG(errmsg);
2584 if (tmpname != NULL)
2585 {
2586 mch_remove(tmpname); /* delete converted file */
2587 vim_free(tmpname);
2588 tmpname = NULL;
2589 }
2590 }
2591
2592 /* If the input file is closed, open it (caller should check for error). */
2593 if (*fdp < 0)
2594 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2595
2596 return tmpname;
2597}
2598# endif
2599
2600#endif
2601
2602#ifdef FEAT_VIMINFO
2603/*
2604 * Read marks for the current buffer from the viminfo file, when we support
2605 * buffer marks and the buffer has a name.
2606 */
2607 static void
2608check_marks_read()
2609{
2610 if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
2611 && curbuf->b_ffname != NULL)
2612 read_viminfo(NULL, FALSE, TRUE, FALSE);
2613
2614 /* Always set b_marks_read; needed when 'viminfo' is changed to include
2615 * the ' parameter after opening a buffer. */
2616 curbuf->b_marks_read = TRUE;
2617}
2618#endif
2619
2620#ifdef FEAT_CRYPT
2621/*
2622 * Check for magic number used for encryption.
2623 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2624 * *filesizep are updated.
2625 * Return the (new) encryption key, NULL for no encryption.
2626 */
2627 static char_u *
2628check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile)
2629 char_u *cryptkey; /* previous encryption key or NULL */
2630 char_u *ptr; /* pointer to read bytes */
2631 long *sizep; /* length of read bytes */
2632 long *filesizep; /* nr of bytes used from file */
2633 int newfile; /* editing a new buffer */
2634{
2635 if (*sizep >= CRYPT_MAGIC_LEN
2636 && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
2637 {
2638 if (cryptkey == NULL)
2639 {
2640 if (*curbuf->b_p_key)
2641 cryptkey = curbuf->b_p_key;
2642 else
2643 {
2644 /* When newfile is TRUE, store the typed key
2645 * in the 'key' option and don't free it. */
2646 cryptkey = get_crypt_key(newfile, FALSE);
2647 /* check if empty key entered */
2648 if (cryptkey != NULL && *cryptkey == NUL)
2649 {
2650 if (cryptkey != curbuf->b_p_key)
2651 vim_free(cryptkey);
2652 cryptkey = NULL;
2653 }
2654 }
2655 }
2656
2657 if (cryptkey != NULL)
2658 {
2659 crypt_init_keys(cryptkey);
2660
2661 /* Remove magic number from the text */
2662 *filesizep += CRYPT_MAGIC_LEN;
2663 *sizep -= CRYPT_MAGIC_LEN;
2664 mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
2665 }
2666 }
2667 /* When starting to edit a new file which does not have
2668 * encryption, clear the 'key' option, except when
2669 * starting up (called with -x argument) */
2670 else if (newfile && *curbuf->b_p_key && !starting)
2671 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2672
2673 return cryptkey;
2674}
2675#endif
2676
2677#ifdef UNIX
2678 static void
2679set_file_time(fname, atime, mtime)
2680 char_u *fname;
2681 time_t atime; /* access time */
2682 time_t mtime; /* modification time */
2683{
2684# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2685 struct utimbuf buf;
2686
2687 buf.actime = atime;
2688 buf.modtime = mtime;
2689 (void)utime((char *)fname, &buf);
2690# else
2691# if defined(HAVE_UTIMES)
2692 struct timeval tvp[2];
2693
2694 tvp[0].tv_sec = atime;
2695 tvp[0].tv_usec = 0;
2696 tvp[1].tv_sec = mtime;
2697 tvp[1].tv_usec = 0;
2698# ifdef NeXT
2699 (void)utimes((char *)fname, tvp);
2700# else
2701 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2702# endif
2703# endif
2704# endif
2705}
2706#endif /* UNIX */
2707
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002708#if defined(VMS) && !defined(MIN)
2709/* Older DECC compiler for VAX doesn't define MIN() */
2710# define MIN(a, b) ((a) < (b) ? (a) : (b))
2711#endif
2712
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00002714 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 *
2716 * We do our own buffering here because fwrite() is so slow.
2717 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00002718 * If "forceit" is true, we don't care for errors when attempting backups.
2719 * In case of an error everything possible is done to restore the original
2720 * file. But when "forceit" is TRUE, we risk loosing it.
2721 *
2722 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
2723 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 *
2725 * This function must NOT use NameBuff (because it's called by autowrite()).
2726 *
2727 * return FAIL for failure, OK otherwise
2728 */
2729 int
2730buf_write(buf, fname, sfname, start, end, eap, append, forceit,
2731 reset_changed, filtering)
2732 buf_T *buf;
2733 char_u *fname;
2734 char_u *sfname;
2735 linenr_T start, end;
2736 exarg_T *eap; /* for forced 'ff' and 'fenc', can be
2737 NULL! */
Bram Moolenaar292ad192005-12-11 21:29:51 +00002738 int append; /* append to the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 int forceit;
2740 int reset_changed;
2741 int filtering;
2742{
2743 int fd;
2744 char_u *backup = NULL;
2745 int backup_copy = FALSE; /* copy the original file? */
2746 int dobackup;
2747 char_u *ffname;
2748 char_u *wfname = NULL; /* name of file to write to */
2749 char_u *s;
2750 char_u *ptr;
2751 char_u c;
2752 int len;
2753 linenr_T lnum;
2754 long nchars;
2755 char_u *errmsg = NULL;
2756 char_u *errnum = NULL;
2757 char_u *buffer;
2758 char_u smallbuf[SMBUFSIZE];
2759 char_u *backup_ext;
2760 int bufsize;
2761 long perm; /* file permissions */
2762 int retval = OK;
2763 int newfile = FALSE; /* TRUE if file doesn't exist yet */
2764 int msg_save = msg_scroll;
2765 int overwriting; /* TRUE if writing over original */
2766 int no_eol = FALSE; /* no end-of-line written */
2767 int device = FALSE; /* writing to a device */
2768 struct stat st_old;
2769 int prev_got_int = got_int;
2770 int file_readonly = FALSE; /* overwritten file is read-only */
2771 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
2772#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */
2773 int made_writable = FALSE; /* 'w' bit has been set */
2774#endif
2775 /* writing everything */
2776 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
2777#ifdef FEAT_AUTOCMD
2778 linenr_T old_line_count = buf->b_ml.ml_line_count;
2779#endif
2780 int attr;
2781 int fileformat;
2782 int write_bin;
2783 struct bw_info write_info; /* info for buf_write_bytes() */
2784#ifdef FEAT_MBYTE
2785 int converted = FALSE;
2786 int notconverted = FALSE;
2787 char_u *fenc; /* effective 'fileencoding' */
2788 char_u *fenc_tofree = NULL; /* allocated "fenc" */
2789#endif
2790#ifdef HAS_BW_FLAGS
2791 int wb_flags = 0;
2792#endif
2793#ifdef HAVE_ACL
2794 vim_acl_T acl = NULL; /* ACL copied from original file to
2795 backup or new file */
2796#endif
2797
2798 if (fname == NULL || *fname == NUL) /* safety check */
2799 return FAIL;
2800
2801 /*
2802 * Disallow writing from .exrc and .vimrc in current directory for
2803 * security reasons.
2804 */
2805 if (check_secure())
2806 return FAIL;
2807
2808 /* Avoid a crash for a long name. */
2809 if (STRLEN(fname) >= MAXPATHL)
2810 {
2811 EMSG(_(e_longname));
2812 return FAIL;
2813 }
2814
2815#ifdef FEAT_MBYTE
2816 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
2817 write_info.bw_conv_buf = NULL;
2818 write_info.bw_conv_error = FALSE;
2819 write_info.bw_restlen = 0;
2820# ifdef USE_ICONV
2821 write_info.bw_iconv_fd = (iconv_t)-1;
2822# endif
2823#endif
2824
Bram Moolenaardf177f62005-02-22 08:39:57 +00002825 /* After writing a file changedtick changes but we don't want to display
2826 * the line. */
2827 ex_no_reprint = TRUE;
2828
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 /*
2830 * If there is no file name yet, use the one for the written file.
2831 * BF_NOTEDITED is set to reflect this (in case the write fails).
2832 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00002833 * Don't do this when appending.
2834 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002836 if (buf->b_ffname == NULL
2837 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 && whole
2839 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002840#ifdef FEAT_QUICKFIX
2841 && !bt_nofile(buf)
2842#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00002844 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
2846 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002847 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002849 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 }
2851
2852 if (sfname == NULL)
2853 sfname = fname;
2854 /*
2855 * For Unix: Use the short file name whenever possible.
2856 * Avoids problems with networks and when directory names are changed.
2857 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
2858 * another directory, which we don't detect
2859 */
2860 ffname = fname; /* remember full fname */
2861#ifdef UNIX
2862 fname = sfname;
2863#endif
2864
2865 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
2866 overwriting = TRUE;
2867 else
2868 overwriting = FALSE;
2869
2870 if (exiting)
2871 settmode(TMODE_COOK); /* when exiting allow typahead now */
2872
2873 ++no_wait_return; /* don't wait for return yet */
2874
2875 /*
2876 * Set '[ and '] marks to the lines to be written.
2877 */
2878 buf->b_op_start.lnum = start;
2879 buf->b_op_start.col = 0;
2880 buf->b_op_end.lnum = end;
2881 buf->b_op_end.col = 0;
2882
2883#ifdef FEAT_AUTOCMD
2884 {
2885 aco_save_T aco;
2886 int buf_ffname = FALSE;
2887 int buf_sfname = FALSE;
2888 int buf_fname_f = FALSE;
2889 int buf_fname_s = FALSE;
2890 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002891 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002892 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893
2894 /*
2895 * Apply PRE aucocommands.
2896 * Set curbuf to the buffer to be written.
2897 * Careful: The autocommands may call buf_write() recursively!
2898 */
2899 if (ffname == buf->b_ffname)
2900 buf_ffname = TRUE;
2901 if (sfname == buf->b_sfname)
2902 buf_sfname = TRUE;
2903 if (fname == buf->b_ffname)
2904 buf_fname_f = TRUE;
2905 if (fname == buf->b_sfname)
2906 buf_fname_s = TRUE;
2907
2908 /* set curwin/curbuf to buf and save a few things */
2909 aucmd_prepbuf(&aco, buf);
2910
2911 if (append)
2912 {
2913 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
2914 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002915 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002916#ifdef FEAT_QUICKFIX
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002917 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002918 nofile_err = TRUE;
2919 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002920#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002921 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002923 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 }
2925 else if (filtering)
2926 {
2927 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
2928 NULL, sfname, FALSE, curbuf, eap);
2929 }
2930 else if (reset_changed && whole)
2931 {
2932 if (!(did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
2933 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002934 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002935#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002936 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002937 nofile_err = TRUE;
2938 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002939#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002940 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002942 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 }
2944 else
2945 {
2946 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
2947 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002948 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002949#ifdef FEAT_QUICKFIX
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002950 if (overwriting && bt_nofile(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002951 nofile_err = TRUE;
2952 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00002953#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002954 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002956 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 }
2958
2959 /* restore curwin/curbuf and a few other things */
2960 aucmd_restbuf(&aco);
2961
2962 /*
2963 * In three situations we return here and don't write the file:
2964 * 1. the autocommands deleted or unloaded the buffer.
2965 * 2. The autocommands abort script processing.
2966 * 3. If one of the "Cmd" autocommands was executed.
2967 */
2968 if (!buf_valid(buf))
2969 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00002970 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00002971 || did_cmd || nofile_err
2972#ifdef FEAT_EVAL
2973 || aborting()
2974#endif
2975 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976 {
2977 --no_wait_return;
2978 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00002979 if (nofile_err)
2980 EMSG(_("E676: No matching autocommands for acwrite buffer"));
2981
Bram Moolenaar1e015462005-09-25 22:16:38 +00002982 if (nofile_err
2983#ifdef FEAT_EVAL
2984 || aborting()
2985#endif
2986 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 /* An aborting error, interrupt or exception in the
2988 * autocommands. */
2989 return FAIL;
2990 if (did_cmd)
2991 {
2992 if (buf == NULL)
2993 /* The buffer was deleted. We assume it was written
2994 * (can't retry anyway). */
2995 return OK;
2996 if (overwriting)
2997 {
2998 /* Assume the buffer was written, update the timestamp. */
2999 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003000 if (append)
3001 buf->b_flags &= ~BF_NEW;
3002 else
3003 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003005 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003006 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 /* Buffer still changed, the autocommands didn't work
3008 * properly. */
3009 return FAIL;
3010 return OK;
3011 }
3012#ifdef FEAT_EVAL
3013 if (!aborting())
3014#endif
3015 EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
3016 return FAIL;
3017 }
3018
3019 /*
3020 * The autocommands may have changed the number of lines in the file.
3021 * When writing the whole file, adjust the end.
3022 * When writing part of the file, assume that the autocommands only
3023 * changed the number of lines that are to be written (tricky!).
3024 */
3025 if (buf->b_ml.ml_line_count != old_line_count)
3026 {
3027 if (whole) /* write all */
3028 end = buf->b_ml.ml_line_count;
3029 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3030 end += buf->b_ml.ml_line_count - old_line_count;
3031 else /* less lines */
3032 {
3033 end -= old_line_count - buf->b_ml.ml_line_count;
3034 if (end < start)
3035 {
3036 --no_wait_return;
3037 msg_scroll = msg_save;
3038 EMSG(_("E204: Autocommand changed number of lines in unexpected way"));
3039 return FAIL;
3040 }
3041 }
3042 }
3043
3044 /*
3045 * The autocommands may have changed the name of the buffer, which may
3046 * be kept in fname, ffname and sfname.
3047 */
3048 if (buf_ffname)
3049 ffname = buf->b_ffname;
3050 if (buf_sfname)
3051 sfname = buf->b_sfname;
3052 if (buf_fname_f)
3053 fname = buf->b_ffname;
3054 if (buf_fname_s)
3055 fname = buf->b_sfname;
3056 }
3057#endif
3058
3059#ifdef FEAT_NETBEANS_INTG
3060 if (usingNetbeans && isNetbeansBuffer(buf))
3061 {
3062 if (whole)
3063 {
3064 /*
3065 * b_changed can be 0 after an undo, but we still need to write
3066 * the buffer to NetBeans.
3067 */
3068 if (buf->b_changed || isNetbeansModified(buf))
3069 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003070 --no_wait_return; /* may wait for return now */
3071 msg_scroll = msg_save;
3072 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 return retval;
3074 }
3075 else
3076 {
3077 errnum = (char_u *)"E656: ";
3078 errmsg = (char_u *)_("NetBeans dissallows writes of unmodified buffers");
3079 buffer = NULL;
3080 goto fail;
3081 }
3082 }
3083 else
3084 {
3085 errnum = (char_u *)"E657: ";
3086 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3087 buffer = NULL;
3088 goto fail;
3089 }
3090 }
3091#endif
3092
3093 if (shortmess(SHM_OVER) && !exiting)
3094 msg_scroll = FALSE; /* overwrite previous file message */
3095 else
3096 msg_scroll = TRUE; /* don't overwrite previous file message */
3097 if (!filtering)
3098 filemess(buf,
3099#ifndef UNIX
3100 sfname,
3101#else
3102 fname,
3103#endif
3104 (char_u *)"", 0); /* show that we are busy */
3105 msg_scroll = FALSE; /* always overwrite the file message now */
3106
3107 buffer = alloc(BUFSIZE);
3108 if (buffer == NULL) /* can't allocate big buffer, use small
3109 * one (to be able to write when out of
3110 * memory) */
3111 {
3112 buffer = smallbuf;
3113 bufsize = SMBUFSIZE;
3114 }
3115 else
3116 bufsize = BUFSIZE;
3117
3118 /*
3119 * Get information about original file (if there is one).
3120 */
3121#if defined(UNIX) && !defined(ARCHIE)
3122 st_old.st_dev = st_old.st_ino = 0;
3123 perm = -1;
3124 if (mch_stat((char *)fname, &st_old) < 0)
3125 newfile = TRUE;
3126 else
3127 {
3128 perm = st_old.st_mode;
3129 if (!S_ISREG(st_old.st_mode)) /* not a file */
3130 {
3131 if (S_ISDIR(st_old.st_mode))
3132 {
3133 errnum = (char_u *)"E502: ";
3134 errmsg = (char_u *)_("is a directory");
3135 goto fail;
3136 }
3137 if (mch_nodetype(fname) != NODE_WRITABLE)
3138 {
3139 errnum = (char_u *)"E503: ";
3140 errmsg = (char_u *)_("is not a file or writable device");
3141 goto fail;
3142 }
3143 /* It's a device of some kind (or a fifo) which we can write to
3144 * but for which we can't make a backup. */
3145 device = TRUE;
3146 newfile = TRUE;
3147 perm = -1;
3148 }
3149 }
3150#else /* !UNIX */
3151 /*
3152 * Check for a writable device name.
3153 */
3154 c = mch_nodetype(fname);
3155 if (c == NODE_OTHER)
3156 {
3157 errnum = (char_u *)"E503: ";
3158 errmsg = (char_u *)_("is not a file or writable device");
3159 goto fail;
3160 }
3161 if (c == NODE_WRITABLE)
3162 {
3163 device = TRUE;
3164 newfile = TRUE;
3165 perm = -1;
3166 }
3167 else
3168 {
3169 perm = mch_getperm(fname);
3170 if (perm < 0)
3171 newfile = TRUE;
3172 else if (mch_isdir(fname))
3173 {
3174 errnum = (char_u *)"E502: ";
3175 errmsg = (char_u *)_("is a directory");
3176 goto fail;
3177 }
3178 if (overwriting)
3179 (void)mch_stat((char *)fname, &st_old);
3180 }
3181#endif /* !UNIX */
3182
3183 if (!device && !newfile)
3184 {
3185 /*
3186 * Check if the file is really writable (when renaming the file to
3187 * make a backup we won't discover it later).
3188 */
3189 file_readonly = (
3190# ifdef USE_MCH_ACCESS
3191# ifdef UNIX
3192 (perm & 0222) == 0 ||
3193# endif
3194 mch_access((char *)fname, W_OK)
3195# else
3196 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
3197 ? TRUE : (close(fd), FALSE)
3198# endif
3199 );
3200 if (!forceit && file_readonly)
3201 {
3202 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3203 {
3204 errnum = (char_u *)"E504: ";
3205 errmsg = (char_u *)_(err_readonly);
3206 }
3207 else
3208 {
3209 errnum = (char_u *)"E505: ";
3210 errmsg = (char_u *)_("is read-only (add ! to override)");
3211 }
3212 goto fail;
3213 }
3214
3215 /*
3216 * Check if the timestamp hasn't changed since reading the file.
3217 */
3218 if (overwriting)
3219 {
3220 retval = check_mtime(buf, &st_old);
3221 if (retval == FAIL)
3222 goto fail;
3223 }
3224 }
3225
3226#ifdef HAVE_ACL
3227 /*
3228 * For systems that support ACL: get the ACL from the original file.
3229 */
3230 if (!newfile)
3231 acl = mch_get_acl(fname);
3232#endif
3233
3234 /*
3235 * If 'backupskip' is not empty, don't make a backup for some files.
3236 */
3237 dobackup = (p_wb || p_bk || *p_pm != NUL);
3238#ifdef FEAT_WILDIGN
3239 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3240 dobackup = FALSE;
3241#endif
3242
3243 /*
3244 * Save the value of got_int and reset it. We don't want a previous
3245 * interruption cancel writing, only hitting CTRL-C while writing should
3246 * abort it.
3247 */
3248 prev_got_int = got_int;
3249 got_int = FALSE;
3250
3251 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3252 buf->b_saving = TRUE;
3253
3254 /*
3255 * If we are not appending or filtering, the file exists, and the
3256 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3257 * When 'patchmode' is set also make a backup when appending.
3258 *
3259 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3260 * off. This helps when editing large files on almost-full disks.
3261 */
3262 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3263 {
3264#if defined(UNIX) || defined(WIN32)
3265 struct stat st;
3266#endif
3267
3268 if ((bkc_flags & BKC_YES) || append) /* "yes" */
3269 backup_copy = TRUE;
3270#if defined(UNIX) || defined(WIN32)
3271 else if ((bkc_flags & BKC_AUTO)) /* "auto" */
3272 {
3273 int i;
3274
3275# ifdef UNIX
3276 /*
3277 * Don't rename the file when:
3278 * - it's a hard link
3279 * - it's a symbolic link
3280 * - we don't have write permission in the directory
3281 * - we can't set the owner/group of the new file
3282 */
3283 if (st_old.st_nlink > 1
3284 || mch_lstat((char *)fname, &st) < 0
3285 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003286 || st.st_ino != st_old.st_ino
3287# ifndef HAVE_FCHOWN
3288 || st.st_uid != st_old.st_uid
3289 || st.st_gid != st_old.st_gid
3290# endif
3291 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 backup_copy = TRUE;
3293 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003294# else
3295# ifdef WIN32
3296 /* On NTFS file systems hard links are possible. */
3297 if (mch_is_linked(fname))
3298 backup_copy = TRUE;
3299 else
3300# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301# endif
3302 {
3303 /*
3304 * Check if we can create a file and set the owner/group to
3305 * the ones from the original file.
3306 * First find a file name that doesn't exist yet (use some
3307 * arbitrary numbers).
3308 */
3309 STRCPY(IObuff, fname);
3310 for (i = 4913; ; i += 123)
3311 {
3312 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003313 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 break;
3315 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003316 fd = mch_open((char *)IObuff,
3317 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 if (fd < 0) /* can't write in directory */
3319 backup_copy = TRUE;
3320 else
3321 {
3322# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003323# ifdef HAVE_FCHOWN
3324 fchown(fd, st_old.st_uid, st_old.st_gid);
3325# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 if (mch_stat((char *)IObuff, &st) < 0
3327 || st.st_uid != st_old.st_uid
3328 || st.st_gid != st_old.st_gid
3329 || st.st_mode != perm)
3330 backup_copy = TRUE;
3331# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003332 /* Close the file before removing it, on MS-Windows we
3333 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003334 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003335 mch_remove(IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 }
3337 }
3338 }
3339
3340# ifdef UNIX
3341 /*
3342 * Break symlinks and/or hardlinks if we've been asked to.
3343 */
3344 if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK))
3345 {
3346 int lstat_res;
3347
3348 lstat_res = mch_lstat((char *)fname, &st);
3349
3350 /* Symlinks. */
3351 if ((bkc_flags & BKC_BREAKSYMLINK)
3352 && lstat_res == 0
3353 && st.st_ino != st_old.st_ino)
3354 backup_copy = FALSE;
3355
3356 /* Hardlinks. */
3357 if ((bkc_flags & BKC_BREAKHARDLINK)
3358 && st_old.st_nlink > 1
3359 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3360 backup_copy = FALSE;
3361 }
3362#endif
3363
3364#endif
3365
3366 /* make sure we have a valid backup extension to use */
3367 if (*p_bex == NUL)
3368 {
3369#ifdef RISCOS
3370 backup_ext = (char_u *)"/bak";
3371#else
3372 backup_ext = (char_u *)".bak";
3373#endif
3374 }
3375 else
3376 backup_ext = p_bex;
3377
3378 if (backup_copy
3379 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3380 {
3381 int bfd;
3382 char_u *copybuf, *wp;
3383 int some_error = FALSE;
3384 struct stat st_new;
3385 char_u *dirp;
3386 char_u *rootname;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003387#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388 int did_set_shortname;
3389#endif
3390
3391 copybuf = alloc(BUFSIZE + 1);
3392 if (copybuf == NULL)
3393 {
3394 some_error = TRUE; /* out of memory */
3395 goto nobackup;
3396 }
3397
3398 /*
3399 * Try to make the backup in each directory in the 'bdir' option.
3400 *
3401 * Unix semantics has it, that we may have a writable file,
3402 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3403 * - the directory is not writable,
3404 * - the file may be a symbolic link,
3405 * - the file may belong to another user/group, etc.
3406 *
3407 * For these reasons, the existing writable file must be truncated
3408 * and reused. Creation of a backup COPY will be attempted.
3409 */
3410 dirp = p_bdir;
3411 while (*dirp)
3412 {
3413#ifdef UNIX
3414 st_new.st_ino = 0;
3415 st_new.st_dev = 0;
3416 st_new.st_gid = 0;
3417#endif
3418
3419 /*
3420 * Isolate one directory name, using an entry in 'bdir'.
3421 */
3422 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
3423 rootname = get_file_in_dir(fname, copybuf);
3424 if (rootname == NULL)
3425 {
3426 some_error = TRUE; /* out of memory */
3427 goto nobackup;
3428 }
3429
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003430#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431 did_set_shortname = FALSE;
3432#endif
3433
3434 /*
3435 * May try twice if 'shortname' not set.
3436 */
3437 for (;;)
3438 {
3439 /*
3440 * Make backup file name.
3441 */
3442 backup = buf_modname(
3443#ifdef SHORT_FNAME
3444 TRUE,
3445#else
3446 (buf->b_p_sn || buf->b_shortname),
3447#endif
3448 rootname, backup_ext, FALSE);
3449 if (backup == NULL)
3450 {
3451 vim_free(rootname);
3452 some_error = TRUE; /* out of memory */
3453 goto nobackup;
3454 }
3455
3456 /*
3457 * Check if backup file already exists.
3458 */
3459 if (mch_stat((char *)backup, &st_new) >= 0)
3460 {
3461#ifdef UNIX
3462 /*
3463 * Check if backup file is same as original file.
3464 * May happen when modname() gave the same file back.
3465 * E.g. silly link, or file name-length reached.
3466 * If we don't check here, we either ruin the file
3467 * when copying or erase it after writing. jw.
3468 */
3469 if (st_new.st_dev == st_old.st_dev
3470 && st_new.st_ino == st_old.st_ino)
3471 {
3472 vim_free(backup);
3473 backup = NULL; /* no backup file to delete */
3474# ifndef SHORT_FNAME
3475 /*
3476 * may try again with 'shortname' set
3477 */
3478 if (!(buf->b_shortname || buf->b_p_sn))
3479 {
3480 buf->b_shortname = TRUE;
3481 did_set_shortname = TRUE;
3482 continue;
3483 }
3484 /* setting shortname didn't help */
3485 if (did_set_shortname)
3486 buf->b_shortname = FALSE;
3487# endif
3488 break;
3489 }
3490#endif
3491
3492 /*
3493 * If we are not going to keep the backup file, don't
3494 * delete an existing one, try to use another name.
3495 * Change one character, just before the extension.
3496 */
3497 if (!p_bk)
3498 {
3499 wp = backup + STRLEN(backup) - 1
3500 - STRLEN(backup_ext);
3501 if (wp < backup) /* empty file name ??? */
3502 wp = backup;
3503 *wp = 'z';
3504 while (*wp > 'a'
3505 && mch_stat((char *)backup, &st_new) >= 0)
3506 --*wp;
3507 /* They all exist??? Must be something wrong. */
3508 if (*wp == 'a')
3509 {
3510 vim_free(backup);
3511 backup = NULL;
3512 }
3513 }
3514 }
3515 break;
3516 }
3517 vim_free(rootname);
3518
3519 /*
3520 * Try to create the backup file
3521 */
3522 if (backup != NULL)
3523 {
3524 /* remove old backup, if present */
3525 mch_remove(backup);
3526 /* Open with O_EXCL to avoid the file being created while
3527 * we were sleeping (symlink hacker attack?) */
3528 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003529 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3530 perm & 0777);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 if (bfd < 0)
3532 {
3533 vim_free(backup);
3534 backup = NULL;
3535 }
3536 else
3537 {
3538 /* set file protection same as original file, but
3539 * strip s-bit */
3540 (void)mch_setperm(backup, perm & 0777);
3541
3542#ifdef UNIX
3543 /*
3544 * Try to set the group of the backup same as the
3545 * original file. If this fails, set the protection
3546 * bits for the group same as the protection bits for
3547 * others.
3548 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003549 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003550# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003551 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552# endif
3553 )
3554 mch_setperm(backup,
3555 (perm & 0707) | ((perm & 07) << 3));
3556#endif
3557
3558 /*
3559 * copy the file.
3560 */
3561 write_info.bw_fd = bfd;
3562 write_info.bw_buf = copybuf;
3563#ifdef HAS_BW_FLAGS
3564 write_info.bw_flags = FIO_NOCONVERT;
3565#endif
3566 while ((write_info.bw_len = vim_read(fd, copybuf,
3567 BUFSIZE)) > 0)
3568 {
3569 if (buf_write_bytes(&write_info) == FAIL)
3570 {
3571 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3572 break;
3573 }
3574 ui_breakcheck();
3575 if (got_int)
3576 {
3577 errmsg = (char_u *)_(e_interr);
3578 break;
3579 }
3580 }
3581
3582 if (close(bfd) < 0 && errmsg == NULL)
3583 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3584 if (write_info.bw_len < 0)
3585 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3586#ifdef UNIX
3587 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3588#endif
3589#ifdef HAVE_ACL
3590 mch_set_acl(backup, acl);
3591#endif
3592 break;
3593 }
3594 }
3595 }
3596 nobackup:
3597 close(fd); /* ignore errors for closing read file */
3598 vim_free(copybuf);
3599
3600 if (backup == NULL && errmsg == NULL)
3601 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3602 /* ignore errors when forceit is TRUE */
3603 if ((some_error || errmsg != NULL) && !forceit)
3604 {
3605 retval = FAIL;
3606 goto fail;
3607 }
3608 errmsg = NULL;
3609 }
3610 else
3611 {
3612 char_u *dirp;
3613 char_u *p;
3614 char_u *rootname;
3615
3616 /*
3617 * Make a backup by renaming the original file.
3618 */
3619 /*
3620 * If 'cpoptions' includes the "W" flag, we don't want to
3621 * overwrite a read-only file. But rename may be possible
3622 * anyway, thus we need an extra check here.
3623 */
3624 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3625 {
3626 errnum = (char_u *)"E504: ";
3627 errmsg = (char_u *)_(err_readonly);
3628 goto fail;
3629 }
3630
3631 /*
3632 *
3633 * Form the backup file name - change path/fo.o.h to
3634 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3635 * that works is used.
3636 */
3637 dirp = p_bdir;
3638 while (*dirp)
3639 {
3640 /*
3641 * Isolate one directory name and make the backup file name.
3642 */
3643 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
3644 rootname = get_file_in_dir(fname, IObuff);
3645 if (rootname == NULL)
3646 backup = NULL;
3647 else
3648 {
3649 backup = buf_modname(
3650#ifdef SHORT_FNAME
3651 TRUE,
3652#else
3653 (buf->b_p_sn || buf->b_shortname),
3654#endif
3655 rootname, backup_ext, FALSE);
3656 vim_free(rootname);
3657 }
3658
3659 if (backup != NULL)
3660 {
3661 /*
3662 * If we are not going to keep the backup file, don't
3663 * delete an existing one, try to use another name.
3664 * Change one character, just before the extension.
3665 */
3666 if (!p_bk && mch_getperm(backup) >= 0)
3667 {
3668 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
3669 if (p < backup) /* empty file name ??? */
3670 p = backup;
3671 *p = 'z';
3672 while (*p > 'a' && mch_getperm(backup) >= 0)
3673 --*p;
3674 /* They all exist??? Must be something wrong! */
3675 if (*p == 'a')
3676 {
3677 vim_free(backup);
3678 backup = NULL;
3679 }
3680 }
3681 }
3682 if (backup != NULL)
3683 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003685 * Delete any existing backup and move the current version
3686 * to the backup. For safety, we don't remove the backup
3687 * until the write has finished successfully. And if the
3688 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 */
3690 /*
3691 * If the renaming of the original file to the backup file
3692 * works, quit here.
3693 */
3694 if (vim_rename(fname, backup) == 0)
3695 break;
3696
3697 vim_free(backup); /* don't do the rename below */
3698 backup = NULL;
3699 }
3700 }
3701 if (backup == NULL && !forceit)
3702 {
3703 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
3704 goto fail;
3705 }
3706 }
3707 }
3708
3709#if defined(UNIX) && !defined(ARCHIE)
3710 /* When using ":w!" and the file was read-only: make it writable */
3711 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
3712 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
3713 {
3714 perm |= 0200;
3715 (void)mch_setperm(fname, perm);
3716 made_writable = TRUE;
3717 }
3718#endif
3719
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003720 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003721 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
3722 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 {
3724 buf->b_p_ro = FALSE;
3725#ifdef FEAT_TITLE
3726 need_maketitle = TRUE; /* set window title later */
3727#endif
3728#ifdef FEAT_WINDOWS
3729 status_redraw_all(); /* redraw status lines later */
3730#endif
3731 }
3732
3733 if (end > buf->b_ml.ml_line_count)
3734 end = buf->b_ml.ml_line_count;
3735 if (buf->b_ml.ml_flags & ML_EMPTY)
3736 start = end + 1;
3737
3738 /*
3739 * If the original file is being overwritten, there is a small chance that
3740 * we crash in the middle of writing. Therefore the file is preserved now.
3741 * This makes all block numbers positive so that recovery does not need
3742 * the original file.
3743 * Don't do this if there is a backup file and we are exiting.
3744 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003745 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 && !(exiting && backup != NULL))
3747 {
3748 ml_preserve(buf, FALSE);
3749 if (got_int)
3750 {
3751 errmsg = (char_u *)_(e_interr);
3752 goto restore_backup;
3753 }
3754 }
3755
3756#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
3757 /*
3758 * Before risking to lose the original file verify if there's
3759 * a resource fork to preserve, and if cannot be done warn
3760 * the users. This happens when overwriting without backups.
3761 */
3762 if (backup == NULL && overwriting && !append)
3763 if (mch_has_resource_fork(fname))
3764 {
3765 errmsg = (char_u *)_("E460: The resource fork would be lost (add ! to override)");
3766 goto restore_backup;
3767 }
3768#endif
3769
3770#ifdef VMS
3771 vms_remove_version(fname); /* remove version */
3772#endif
3773 /* Default: write the the file directly. May write to a temp file for
3774 * multi-byte conversion. */
3775 wfname = fname;
3776
3777#ifdef FEAT_MBYTE
3778 /* Check for forced 'fileencoding' from "++opt=val" argument. */
3779 if (eap != NULL && eap->force_enc != 0)
3780 {
3781 fenc = eap->cmd + eap->force_enc;
3782 fenc = enc_canonize(fenc);
3783 fenc_tofree = fenc;
3784 }
3785 else
3786 fenc = buf->b_p_fenc;
3787
3788 /*
3789 * The file needs to be converted when 'fileencoding' is set and
3790 * 'fileencoding' differs from 'encoding'.
3791 */
3792 converted = (*fenc != NUL && !same_encoding(p_enc, fenc));
3793
3794 /*
3795 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
3796 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
3797 * Prepare the flags for it and allocate bw_conv_buf when needed.
3798 */
3799 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
3800 {
3801 wb_flags = get_fio_flags(fenc);
3802 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
3803 {
3804 /* Need to allocate a buffer to translate into. */
3805 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
3806 write_info.bw_conv_buflen = bufsize * 2;
3807 else /* FIO_UCS4 */
3808 write_info.bw_conv_buflen = bufsize * 4;
3809 write_info.bw_conv_buf
3810 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3811 if (write_info.bw_conv_buf == NULL)
3812 end = 0;
3813 }
3814 }
3815
3816# ifdef WIN3264
3817 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
3818 {
3819 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
3820 write_info.bw_conv_buflen = bufsize * 4;
3821 write_info.bw_conv_buf
3822 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3823 if (write_info.bw_conv_buf == NULL)
3824 end = 0;
3825 }
3826# endif
3827
3828# ifdef MACOS_X
3829 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
3830 {
3831 write_info.bw_conv_buflen = bufsize * 3;
3832 write_info.bw_conv_buf
3833 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3834 if (write_info.bw_conv_buf == NULL)
3835 end = 0;
3836 }
3837# endif
3838
3839# if defined(FEAT_EVAL) || defined(USE_ICONV)
3840 if (converted && wb_flags == 0)
3841 {
3842# ifdef USE_ICONV
3843 /*
3844 * Use iconv() conversion when conversion is needed and it's not done
3845 * internally.
3846 */
3847 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
3848 enc_utf8 ? (char_u *)"utf-8" : p_enc);
3849 if (write_info.bw_iconv_fd != (iconv_t)-1)
3850 {
3851 /* We're going to use iconv(), allocate a buffer to convert in. */
3852 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
3853 write_info.bw_conv_buf
3854 = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
3855 if (write_info.bw_conv_buf == NULL)
3856 end = 0;
3857 write_info.bw_first = TRUE;
3858 }
3859# ifdef FEAT_EVAL
3860 else
3861# endif
3862# endif
3863
3864# ifdef FEAT_EVAL
3865 /*
3866 * When the file needs to be converted with 'charconvert' after
3867 * writing, write to a temp file instead and let the conversion
3868 * overwrite the original file.
3869 */
3870 if (*p_ccv != NUL)
3871 {
3872 wfname = vim_tempname('w');
3873 if (wfname == NULL) /* Can't write without a tempfile! */
3874 {
3875 errmsg = (char_u *)_("E214: Can't find temp file for writing");
3876 goto restore_backup;
3877 }
3878 }
3879# endif
3880 }
3881# endif
3882 if (converted && wb_flags == 0
3883# ifdef USE_ICONV
3884 && write_info.bw_iconv_fd == (iconv_t)-1
3885# endif
3886# ifdef FEAT_EVAL
3887 && wfname == fname
3888# endif
3889 )
3890 {
3891 if (!forceit)
3892 {
3893 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
3894 goto restore_backup;
3895 }
3896 notconverted = TRUE;
3897 }
3898#endif
3899
3900 /*
3901 * Open the file "wfname" for writing.
3902 * We may try to open the file twice: If we can't write to the
3903 * file and forceit is TRUE we delete the existing file and try to create
3904 * a new one. If this still fails we may have lost the original file!
3905 * (this may happen when the user reached his quotum for number of files).
3906 * Appending will fail if the file does not exist and forceit is FALSE.
3907 */
3908 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
3909 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
3910 : (O_CREAT | O_TRUNC))
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00003911 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912 {
3913 /*
3914 * A forced write will try to create a new file if the old one is
3915 * still readonly. This may also happen when the directory is
3916 * read-only. In that case the mch_remove() will fail.
3917 */
3918 if (errmsg == NULL)
3919 {
3920#ifdef UNIX
3921 struct stat st;
3922
3923 /* Don't delete the file when it's a hard or symbolic link. */
3924 if ((!newfile && st_old.st_nlink > 1)
3925 || (mch_lstat((char *)fname, &st) == 0
3926 && (st.st_dev != st_old.st_dev
3927 || st.st_ino != st_old.st_ino)))
3928 errmsg = (char_u *)_("E166: Can't open linked file for writing");
3929 else
3930#endif
3931 {
3932 errmsg = (char_u *)_("E212: Can't open file for writing");
3933 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
3934 && perm >= 0)
3935 {
3936#ifdef UNIX
3937 /* we write to the file, thus it should be marked
3938 writable after all */
3939 if (!(perm & 0200))
3940 made_writable = TRUE;
3941 perm |= 0200;
3942 if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
3943 perm &= 0777;
3944#endif
3945 if (!append) /* don't remove when appending */
3946 mch_remove(wfname);
3947 continue;
3948 }
3949 }
3950 }
3951
3952restore_backup:
3953 {
3954 struct stat st;
3955
3956 /*
3957 * If we failed to open the file, we don't need a backup. Throw it
3958 * away. If we moved or removed the original file try to put the
3959 * backup in its place.
3960 */
3961 if (backup != NULL && wfname == fname)
3962 {
3963 if (backup_copy)
3964 {
3965 /*
3966 * There is a small chance that we removed the original,
3967 * try to move the copy in its place.
3968 * This may not work if the vim_rename() fails.
3969 * In that case we leave the copy around.
3970 */
3971 /* If file does not exist, put the copy in its place */
3972 if (mch_stat((char *)fname, &st) < 0)
3973 vim_rename(backup, fname);
3974 /* if original file does exist throw away the copy */
3975 if (mch_stat((char *)fname, &st) >= 0)
3976 mch_remove(backup);
3977 }
3978 else
3979 {
3980 /* try to put the original file back */
3981 vim_rename(backup, fname);
3982 }
3983 }
3984
3985 /* if original file no longer exists give an extra warning */
3986 if (!newfile && mch_stat((char *)fname, &st) < 0)
3987 end = 0;
3988 }
3989
3990#ifdef FEAT_MBYTE
3991 if (wfname != fname)
3992 vim_free(wfname);
3993#endif
3994 goto fail;
3995 }
3996 errmsg = NULL;
3997
3998#if defined(MACOS_CLASSIC) || defined(WIN3264)
3999 /* TODO: Is it need for MACOS_X? (Dany) */
4000 /*
4001 * On macintosh copy the original files attributes (i.e. the backup)
4002 * This is done in order to preserve the ressource fork and the
4003 * Finder attribute (label, comments, custom icons, file creatore)
4004 */
4005 if (backup != NULL && overwriting && !append)
4006 {
4007 if (backup_copy)
4008 (void)mch_copy_file_attribute(wfname, backup);
4009 else
4010 (void)mch_copy_file_attribute(backup, wfname);
4011 }
4012
4013 if (!overwriting && !append)
4014 {
4015 if (buf->b_ffname != NULL)
4016 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
4017 /* Should copy ressource fork */
4018 }
4019#endif
4020
4021 write_info.bw_fd = fd;
4022
4023#ifdef FEAT_CRYPT
4024 if (*buf->b_p_key && !filtering)
4025 {
4026 crypt_init_keys(buf->b_p_key);
4027 /* Write magic number, so that Vim knows that this file is encrypted
4028 * when reading it again. This also undergoes utf-8 to ucs-2/4
4029 * conversion when needed. */
4030 write_info.bw_buf = (char_u *)CRYPT_MAGIC;
4031 write_info.bw_len = CRYPT_MAGIC_LEN;
4032 write_info.bw_flags = FIO_NOCONVERT;
4033 if (buf_write_bytes(&write_info) == FAIL)
4034 end = 0;
4035 wb_flags |= FIO_ENCRYPTED;
4036 }
4037#endif
4038
4039 write_info.bw_buf = buffer;
4040 nchars = 0;
4041
4042 /* use "++bin", "++nobin" or 'binary' */
4043 if (eap != NULL && eap->force_bin != 0)
4044 write_bin = (eap->force_bin == FORCE_BIN);
4045 else
4046 write_bin = buf->b_p_bin;
4047
4048#ifdef FEAT_MBYTE
4049 /*
4050 * The BOM is written just after the encryption magic number.
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004051 * Skip it when appending and the file already existed, the BOM only makes
4052 * sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053 */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00004054 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 {
4056 write_info.bw_len = make_bom(buffer, fenc);
4057 if (write_info.bw_len > 0)
4058 {
4059 /* don't convert, do encryption */
4060 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4061 if (buf_write_bytes(&write_info) == FAIL)
4062 end = 0;
4063 else
4064 nchars += write_info.bw_len;
4065 }
4066 }
4067#endif
4068
4069 write_info.bw_len = bufsize;
4070#ifdef HAS_BW_FLAGS
4071 write_info.bw_flags = wb_flags;
4072#endif
4073 fileformat = get_fileformat_force(buf, eap);
4074 s = buffer;
4075 len = 0;
4076 for (lnum = start; lnum <= end; ++lnum)
4077 {
4078 /*
4079 * The next while loop is done once for each character written.
4080 * Keep it fast!
4081 */
4082 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4083 while ((c = *++ptr) != NUL)
4084 {
4085 if (c == NL)
4086 *s = NUL; /* replace newlines with NULs */
4087 else if (c == CAR && fileformat == EOL_MAC)
4088 *s = NL; /* Mac: replace CRs with NLs */
4089 else
4090 *s = c;
4091 ++s;
4092 if (++len != bufsize)
4093 continue;
4094 if (buf_write_bytes(&write_info) == FAIL)
4095 {
4096 end = 0; /* write error: break loop */
4097 break;
4098 }
4099 nchars += bufsize;
4100 s = buffer;
4101 len = 0;
4102 }
4103 /* write failed or last line has no EOL: stop here */
4104 if (end == 0
4105 || (lnum == end
4106 && write_bin
4107 && (lnum == write_no_eol_lnum
4108 || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
4109 {
4110 ++lnum; /* written the line, count it */
4111 no_eol = TRUE;
4112 break;
4113 }
4114 if (fileformat == EOL_UNIX)
4115 *s++ = NL;
4116 else
4117 {
4118 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4119 if (fileformat == EOL_DOS) /* write CR-NL */
4120 {
4121 if (++len == bufsize)
4122 {
4123 if (buf_write_bytes(&write_info) == FAIL)
4124 {
4125 end = 0; /* write error: break loop */
4126 break;
4127 }
4128 nchars += bufsize;
4129 s = buffer;
4130 len = 0;
4131 }
4132 *s++ = NL;
4133 }
4134 }
4135 if (++len == bufsize && end)
4136 {
4137 if (buf_write_bytes(&write_info) == FAIL)
4138 {
4139 end = 0; /* write error: break loop */
4140 break;
4141 }
4142 nchars += bufsize;
4143 s = buffer;
4144 len = 0;
4145
4146 ui_breakcheck();
4147 if (got_int)
4148 {
4149 end = 0; /* Interrupted, break loop */
4150 break;
4151 }
4152 }
4153#ifdef VMS
4154 /*
4155 * On VMS there is a problem: newlines get added when writing blocks
4156 * at a time. Fix it by writing a line at a time.
4157 * This is much slower!
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004158 * Explanation: VAX/DECC RTL insists that records in some RMS
4159 * structures end with a newline (carriage return) character, and if
4160 * they don't it adds one.
4161 * With other RMS structures it works perfect without this fix.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004163 if ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004165 int b2write;
4166
4167 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4168 ? MIN(4096, bufsize)
4169 : MIN(buf->b_fab_mrs, bufsize));
4170
4171 b2write = len;
4172 while (b2write > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004174 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4175 if (buf_write_bytes(&write_info) == FAIL)
4176 {
4177 end = 0;
4178 break;
4179 }
4180 b2write -= MIN(b2write, buf->b_fab_mrs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 }
4182 write_info.bw_len = bufsize;
4183 nchars += len;
4184 s = buffer;
4185 len = 0;
4186 }
4187#endif
4188 }
4189 if (len > 0 && end > 0)
4190 {
4191 write_info.bw_len = len;
4192 if (buf_write_bytes(&write_info) == FAIL)
4193 end = 0; /* write error */
4194 nchars += len;
4195 }
4196
4197#if defined(UNIX) && defined(HAVE_FSYNC)
4198 /* On many journalling file systems there is a bug that causes both the
4199 * original and the backup file to be lost when halting the system right
4200 * after writing the file. That's because only the meta-data is
4201 * journalled. Syncing the file slows down the system, but assures it has
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004202 * been written to disk and we don't lose it.
4203 * For a device do try the fsync() but don't complain if it does not work
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004204 * (could be a pipe).
4205 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
4206 if (p_fs && fsync(fd) != 0 && !device)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207 {
4208 errmsg = (char_u *)_("E667: Fsync failed");
4209 end = 0;
4210 }
4211#endif
4212
Bram Moolenaara5792f52005-11-23 21:25:05 +00004213#ifdef UNIX
4214 /* When creating a new file, set its owner/group to that of the original
4215 * file. Get the new device and inode number. */
4216 if (backup != NULL && !backup_copy)
4217 {
4218# ifdef HAVE_FCHOWN
4219 struct stat st;
4220
4221 /* don't change the owner when it's already OK, some systems remove
4222 * permission or ACL stuff */
4223 if (mch_stat((char *)wfname, &st) < 0
4224 || st.st_uid != st_old.st_uid
4225 || st.st_gid != st_old.st_gid)
4226 {
4227 fchown(fd, st_old.st_uid, st_old.st_gid);
4228 if (perm >= 0) /* set permission again, may have changed */
4229 (void)mch_setperm(wfname, perm);
4230 }
4231# endif
4232 buf_setino(buf);
4233 }
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004234 else if (buf->b_dev < 0)
4235 /* Set the inode when creating a new file. */
4236 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004237#endif
4238
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 if (close(fd) != 0)
4240 {
4241 errmsg = (char_u *)_("E512: Close failed");
4242 end = 0;
4243 }
4244
4245#ifdef UNIX
4246 if (made_writable)
4247 perm &= ~0200; /* reset 'w' bit for security reasons */
4248#endif
4249 if (perm >= 0) /* set perm. of new file same as old file */
4250 (void)mch_setperm(wfname, perm);
4251#ifdef RISCOS
4252 if (!append && !filtering)
4253 /* Set the filetype after writing the file. */
4254 mch_set_filetype(wfname, buf->b_p_oft);
4255#endif
4256#ifdef HAVE_ACL
4257 /* Probably need to set the ACL before changing the user (can't set the
4258 * ACL on a file the user doesn't own). */
4259 if (!backup_copy)
4260 mch_set_acl(wfname, acl);
4261#endif
4262
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263
4264#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4265 if (wfname != fname)
4266 {
4267 /*
4268 * The file was written to a temp file, now it needs to be converted
4269 * with 'charconvert' to (overwrite) the output file.
4270 */
4271 if (end != 0)
4272 {
4273 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4274 wfname, fname) == FAIL)
4275 {
4276 write_info.bw_conv_error = TRUE;
4277 end = 0;
4278 }
4279 }
4280 mch_remove(wfname);
4281 vim_free(wfname);
4282 }
4283#endif
4284
4285 if (end == 0)
4286 {
4287 if (errmsg == NULL)
4288 {
4289#ifdef FEAT_MBYTE
4290 if (write_info.bw_conv_error)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00004291 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 else
4293#endif
4294 if (got_int)
4295 errmsg = (char_u *)_(e_interr);
4296 else
4297 errmsg = (char_u *)_("E514: write error (file system full?)");
4298 }
4299
4300 /*
4301 * If we have a backup file, try to put it in place of the new file,
4302 * because the new file is probably corrupt. This avoids loosing the
4303 * original file when trying to make a backup when writing the file a
4304 * second time.
4305 * When "backup_copy" is set we need to copy the backup over the new
4306 * file. Otherwise rename the backup file.
4307 * If this is OK, don't give the extra warning message.
4308 */
4309 if (backup != NULL)
4310 {
4311 if (backup_copy)
4312 {
4313 /* This may take a while, if we were interrupted let the user
4314 * know we got the message. */
4315 if (got_int)
4316 {
4317 MSG(_(e_interr));
4318 out_flush();
4319 }
4320 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4321 {
4322 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004323 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4324 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 {
4326 /* copy the file. */
4327 write_info.bw_buf = smallbuf;
4328#ifdef HAS_BW_FLAGS
4329 write_info.bw_flags = FIO_NOCONVERT;
4330#endif
4331 while ((write_info.bw_len = vim_read(fd, smallbuf,
4332 SMBUFSIZE)) > 0)
4333 if (buf_write_bytes(&write_info) == FAIL)
4334 break;
4335
4336 if (close(write_info.bw_fd) >= 0
4337 && write_info.bw_len == 0)
4338 end = 1; /* success */
4339 }
4340 close(fd); /* ignore errors for closing read file */
4341 }
4342 }
4343 else
4344 {
4345 if (vim_rename(backup, fname) == 0)
4346 end = 1;
4347 }
4348 }
4349 goto fail;
4350 }
4351
4352 lnum -= start; /* compute number of written lines */
4353 --no_wait_return; /* may wait for return now */
4354
4355#if !(defined(UNIX) || defined(VMS))
4356 fname = sfname; /* use shortname now, for the messages */
4357#endif
4358 if (!filtering)
4359 {
4360 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4361 c = FALSE;
4362#ifdef FEAT_MBYTE
4363 if (write_info.bw_conv_error)
4364 {
4365 STRCAT(IObuff, _(" CONVERSION ERROR"));
4366 c = TRUE;
4367 }
4368 else if (notconverted)
4369 {
4370 STRCAT(IObuff, _("[NOT converted]"));
4371 c = TRUE;
4372 }
4373 else if (converted)
4374 {
4375 STRCAT(IObuff, _("[converted]"));
4376 c = TRUE;
4377 }
4378#endif
4379 if (device)
4380 {
4381 STRCAT(IObuff, _("[Device]"));
4382 c = TRUE;
4383 }
4384 else if (newfile)
4385 {
4386 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4387 c = TRUE;
4388 }
4389 if (no_eol)
4390 {
4391 msg_add_eol();
4392 c = TRUE;
4393 }
4394 /* may add [unix/dos/mac] */
4395 if (msg_add_fileformat(fileformat))
4396 c = TRUE;
4397#ifdef FEAT_CRYPT
4398 if (wb_flags & FIO_ENCRYPTED)
4399 {
4400 STRCAT(IObuff, _("[crypted]"));
4401 c = TRUE;
4402 }
4403#endif
4404 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4405 if (!shortmess(SHM_WRITE))
4406 {
4407 if (append)
4408 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4409 else
4410 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4411 }
4412
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00004413 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 }
4415
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004416 /* When written everything correctly: reset 'modified'. Unless not
4417 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004418 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419#ifdef FEAT_MBYTE
4420 && !write_info.bw_conv_error
4421#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004422 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4423 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424 {
4425 unchanged(buf, TRUE);
4426 u_unchanged(buf);
4427 }
4428
4429 /*
4430 * If written to the current file, update the timestamp of the swap file
4431 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4432 */
4433 if (overwriting)
4434 {
4435 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004436 if (append)
4437 buf->b_flags &= ~BF_NEW;
4438 else
4439 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 }
4441
4442 /*
4443 * If we kept a backup until now, and we are in patch mode, then we make
4444 * the backup file our 'original' file.
4445 */
4446 if (*p_pm && dobackup)
4447 {
4448 char *org = (char *)buf_modname(
4449#ifdef SHORT_FNAME
4450 TRUE,
4451#else
4452 (buf->b_p_sn || buf->b_shortname),
4453#endif
4454 fname, p_pm, FALSE);
4455
4456 if (backup != NULL)
4457 {
4458 struct stat st;
4459
4460 /*
4461 * If the original file does not exist yet
4462 * the current backup file becomes the original file
4463 */
4464 if (org == NULL)
4465 EMSG(_("E205: Patchmode: can't save original file"));
4466 else if (mch_stat(org, &st) < 0)
4467 {
4468 vim_rename(backup, (char_u *)org);
4469 vim_free(backup); /* don't delete the file */
4470 backup = NULL;
4471#ifdef UNIX
4472 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4473#endif
4474 }
4475 }
4476 /*
4477 * If there is no backup file, remember that a (new) file was
4478 * created.
4479 */
4480 else
4481 {
4482 int empty_fd;
4483
4484 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004485 || (empty_fd = mch_open(org,
4486 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004487 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 EMSG(_("E206: patchmode: can't touch empty original file"));
4489 else
4490 close(empty_fd);
4491 }
4492 if (org != NULL)
4493 {
4494 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4495 vim_free(org);
4496 }
4497 }
4498
4499 /*
4500 * Remove the backup unless 'backup' option is set
4501 */
4502 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4503 EMSG(_("E207: Can't delete backup file"));
4504
4505#ifdef FEAT_SUN_WORKSHOP
4506 if (usingSunWorkShop)
4507 workshop_file_saved((char *) ffname);
4508#endif
4509
4510 goto nofail;
4511
4512 /*
4513 * Finish up. We get here either after failure or success.
4514 */
4515fail:
4516 --no_wait_return; /* may wait for return now */
4517nofail:
4518
4519 /* Done saving, we accept changed buffer warnings again */
4520 buf->b_saving = FALSE;
4521
4522 vim_free(backup);
4523 if (buffer != smallbuf)
4524 vim_free(buffer);
4525#ifdef FEAT_MBYTE
4526 vim_free(fenc_tofree);
4527 vim_free(write_info.bw_conv_buf);
4528# ifdef USE_ICONV
4529 if (write_info.bw_iconv_fd != (iconv_t)-1)
4530 {
4531 iconv_close(write_info.bw_iconv_fd);
4532 write_info.bw_iconv_fd = (iconv_t)-1;
4533 }
4534# endif
4535#endif
4536#ifdef HAVE_ACL
4537 mch_free_acl(acl);
4538#endif
4539
4540 if (errmsg != NULL)
4541 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004542 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543
4544 attr = hl_attr(HLF_E); /* set highlight for error messages */
4545 msg_add_fname(buf,
4546#ifndef UNIX
4547 sfname
4548#else
4549 fname
4550#endif
4551 ); /* put file name in IObuff with quotes */
4552 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4553 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4554 /* If the error message has the form "is ...", put the error number in
4555 * front of the file name. */
4556 if (errnum != NULL)
4557 {
4558 mch_memmove(IObuff + numlen, IObuff, STRLEN(IObuff) + 1);
4559 mch_memmove(IObuff, errnum, (size_t)numlen);
4560 }
4561 STRCAT(IObuff, errmsg);
4562 emsg(IObuff);
4563
4564 retval = FAIL;
4565 if (end == 0)
4566 {
4567 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4568 attr | MSG_HIST);
4569 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4570 attr | MSG_HIST);
4571
4572 /* Update the timestamp to avoid an "overwrite changed file"
4573 * prompt when writing again. */
4574 if (mch_stat((char *)fname, &st_old) >= 0)
4575 {
4576 buf_store_time(buf, &st_old, fname);
4577 buf->b_mtime_read = buf->b_mtime;
4578 }
4579 }
4580 }
4581 msg_scroll = msg_save;
4582
4583#ifdef FEAT_AUTOCMD
4584#ifdef FEAT_EVAL
4585 if (!should_abort(retval))
4586#else
4587 if (!got_int)
4588#endif
4589 {
4590 aco_save_T aco;
4591
4592 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4593
4594 /*
4595 * Apply POST autocommands.
4596 * Careful: The autocommands may call buf_write() recursively!
4597 */
4598 aucmd_prepbuf(&aco, buf);
4599
4600 if (append)
4601 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4602 FALSE, curbuf, eap);
4603 else if (filtering)
4604 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4605 FALSE, curbuf, eap);
4606 else if (reset_changed && whole)
4607 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4608 FALSE, curbuf, eap);
4609 else
4610 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4611 FALSE, curbuf, eap);
4612
4613 /* restore curwin/curbuf and a few other things */
4614 aucmd_restbuf(&aco);
4615
4616#ifdef FEAT_EVAL
4617 if (aborting()) /* autocmds may abort script processing */
4618 retval = FALSE;
4619#endif
4620 }
4621#endif
4622
4623 got_int |= prev_got_int;
4624
4625#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4626 /* Update machine specific information. */
4627 mch_post_buffer_write(buf);
4628#endif
4629 return retval;
4630}
4631
4632/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004633 * Set the name of the current buffer. Use when the buffer doesn't have a
4634 * name and a ":r" or ":w" command with a file name is used.
4635 */
4636 static int
4637set_rw_fname(fname, sfname)
4638 char_u *fname;
4639 char_u *sfname;
4640{
4641#ifdef FEAT_AUTOCMD
4642 /* It's like the unnamed buffer is deleted.... */
4643 if (curbuf->b_p_bl)
4644 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
4645 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
4646# ifdef FEAT_EVAL
4647 if (aborting()) /* autocmds may abort script processing */
4648 return FAIL;
4649# endif
4650#endif
4651
4652 if (setfname(curbuf, fname, sfname, FALSE) == OK)
4653 curbuf->b_flags |= BF_NOTEDITED;
4654
4655#ifdef FEAT_AUTOCMD
4656 /* ....and a new named one is created */
4657 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
4658 if (curbuf->b_p_bl)
4659 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
4660# ifdef FEAT_EVAL
4661 if (aborting()) /* autocmds may abort script processing */
4662 return FAIL;
4663# endif
4664
4665 /* Do filetype detection now if 'filetype' is empty. */
4666 if (*curbuf->b_p_ft == NUL)
4667 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004668 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar70836c82006-02-20 21:28:49 +00004669 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00004670 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004671 }
4672#endif
4673
4674 return OK;
4675}
4676
4677/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 * Put file name into IObuff with quotes.
4679 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004680 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681msg_add_fname(buf, fname)
4682 buf_T *buf;
4683 char_u *fname;
4684{
4685 if (fname == NULL)
4686 fname = (char_u *)"-stdin-";
4687 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4688 IObuff[0] = '"';
4689 STRCAT(IObuff, "\" ");
4690}
4691
4692/*
4693 * Append message for text mode to IObuff.
4694 * Return TRUE if something appended.
4695 */
4696 static int
4697msg_add_fileformat(eol_type)
4698 int eol_type;
4699{
4700#ifndef USE_CRNL
4701 if (eol_type == EOL_DOS)
4702 {
4703 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4704 return TRUE;
4705 }
4706#endif
4707#ifndef USE_CR
4708 if (eol_type == EOL_MAC)
4709 {
4710 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4711 return TRUE;
4712 }
4713#endif
4714#if defined(USE_CRNL) || defined(USE_CR)
4715 if (eol_type == EOL_UNIX)
4716 {
4717 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4718 return TRUE;
4719 }
4720#endif
4721 return FALSE;
4722}
4723
4724/*
4725 * Append line and character count to IObuff.
4726 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004727 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728msg_add_lines(insert_space, lnum, nchars)
4729 int insert_space;
4730 long lnum;
4731 long nchars;
4732{
4733 char_u *p;
4734
4735 p = IObuff + STRLEN(IObuff);
4736
4737 if (insert_space)
4738 *p++ = ' ';
4739 if (shortmess(SHM_LINES))
4740 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4741 else
4742 {
4743 if (lnum == 1)
4744 STRCPY(p, _("1 line, "));
4745 else
4746 sprintf((char *)p, _("%ld lines, "), lnum);
4747 p += STRLEN(p);
4748 if (nchars == 1)
4749 STRCPY(p, _("1 character"));
4750 else
4751 sprintf((char *)p, _("%ld characters"), nchars);
4752 }
4753}
4754
4755/*
4756 * Append message for missing line separator to IObuff.
4757 */
4758 static void
4759msg_add_eol()
4760{
4761 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4762}
4763
4764/*
4765 * Check modification time of file, before writing to it.
4766 * The size isn't checked, because using a tool like "gzip" takes care of
4767 * using the same timestamp but can't set the size.
4768 */
4769 static int
4770check_mtime(buf, st)
4771 buf_T *buf;
4772 struct stat *st;
4773{
4774 if (buf->b_mtime_read != 0
4775 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4776 {
4777 msg_scroll = TRUE; /* don't overwrite messages here */
4778 msg_silent = 0; /* must give this prompt */
4779 /* don't use emsg() here, don't want to flush the buffers */
4780 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
4781 hl_attr(HLF_E));
4782 if (ask_yesno((char_u *)_("Do you really want to write to it"),
4783 TRUE) == 'n')
4784 return FAIL;
4785 msg_scroll = FALSE; /* always overwrite the file message now */
4786 }
4787 return OK;
4788}
4789
4790 static int
4791time_differs(t1, t2)
4792 long t1, t2;
4793{
4794#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
4795 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
4796 * the seconds. Since the roundoff is done when flushing the inode, the
4797 * time may change unexpectedly by one second!!! */
4798 return (t1 - t2 > 1 || t2 - t1 > 1);
4799#else
4800 return (t1 != t2);
4801#endif
4802}
4803
4804/*
4805 * Call write() to write a number of bytes to the file.
4806 * Also handles encryption and 'encoding' conversion.
4807 *
4808 * Return FAIL for failure, OK otherwise.
4809 */
4810 static int
4811buf_write_bytes(ip)
4812 struct bw_info *ip;
4813{
4814 int wlen;
4815 char_u *buf = ip->bw_buf; /* data to write */
4816 int len = ip->bw_len; /* length of data */
4817#ifdef HAS_BW_FLAGS
4818 int flags = ip->bw_flags; /* extra flags */
4819#endif
4820
4821#ifdef FEAT_MBYTE
4822 /*
4823 * Skip conversion when writing the crypt magic number or the BOM.
4824 */
4825 if (!(flags & FIO_NOCONVERT))
4826 {
4827 char_u *p;
4828 unsigned c;
4829 int n;
4830
4831 if (flags & FIO_UTF8)
4832 {
4833 /*
4834 * Convert latin1 in the buffer to UTF-8 in the file.
4835 */
4836 p = ip->bw_conv_buf; /* translate to buffer */
4837 for (wlen = 0; wlen < len; ++wlen)
4838 p += utf_char2bytes(buf[wlen], p);
4839 buf = ip->bw_conv_buf;
4840 len = (int)(p - ip->bw_conv_buf);
4841 }
4842 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
4843 {
4844 /*
4845 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
4846 * Latin1 chars in the file.
4847 */
4848 if (flags & FIO_LATIN1)
4849 p = buf; /* translate in-place (can only get shorter) */
4850 else
4851 p = ip->bw_conv_buf; /* translate to buffer */
4852 for (wlen = 0; wlen < len; wlen += n)
4853 {
4854 if (wlen == 0 && ip->bw_restlen != 0)
4855 {
4856 int l;
4857
4858 /* Use remainder of previous call. Append the start of
4859 * buf[] to get a full sequence. Might still be too
4860 * short! */
4861 l = CONV_RESTLEN - ip->bw_restlen;
4862 if (l > len)
4863 l = len;
4864 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004865 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 if (n > ip->bw_restlen + len)
4867 {
4868 /* We have an incomplete byte sequence at the end to
4869 * be written. We can't convert it without the
4870 * remaining bytes. Keep them for the next call. */
4871 if (ip->bw_restlen + len > CONV_RESTLEN)
4872 return FAIL;
4873 ip->bw_restlen += len;
4874 break;
4875 }
4876 if (n > 1)
4877 c = utf_ptr2char(ip->bw_rest);
4878 else
4879 c = ip->bw_rest[0];
4880 if (n >= ip->bw_restlen)
4881 {
4882 n -= ip->bw_restlen;
4883 ip->bw_restlen = 0;
4884 }
4885 else
4886 {
4887 ip->bw_restlen -= n;
4888 mch_memmove(ip->bw_rest, ip->bw_rest + n,
4889 (size_t)ip->bw_restlen);
4890 n = 0;
4891 }
4892 }
4893 else
4894 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004895 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896 if (n > len - wlen)
4897 {
4898 /* We have an incomplete byte sequence at the end to
4899 * be written. We can't convert it without the
4900 * remaining bytes. Keep them for the next call. */
4901 if (len - wlen > CONV_RESTLEN)
4902 return FAIL;
4903 ip->bw_restlen = len - wlen;
4904 mch_memmove(ip->bw_rest, buf + wlen,
4905 (size_t)ip->bw_restlen);
4906 break;
4907 }
4908 if (n > 1)
4909 c = utf_ptr2char(buf + wlen);
4910 else
4911 c = buf[wlen];
4912 }
4913
4914 ip->bw_conv_error |= ucs2bytes(c, &p, flags);
4915 }
4916 if (flags & FIO_LATIN1)
4917 len = (int)(p - buf);
4918 else
4919 {
4920 buf = ip->bw_conv_buf;
4921 len = (int)(p - ip->bw_conv_buf);
4922 }
4923 }
4924
4925# ifdef WIN3264
4926 else if (flags & FIO_CODEPAGE)
4927 {
4928 /*
4929 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
4930 * codepage.
4931 */
4932 char_u *from;
4933 size_t fromlen;
4934 char_u *to;
4935 int u8c;
4936 BOOL bad = FALSE;
4937 int needed;
4938
4939 if (ip->bw_restlen > 0)
4940 {
4941 /* Need to concatenate the remainder of the previous call and
4942 * the bytes of the current call. Use the end of the
4943 * conversion buffer for this. */
4944 fromlen = len + ip->bw_restlen;
4945 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
4946 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
4947 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
4948 }
4949 else
4950 {
4951 from = buf;
4952 fromlen = len;
4953 }
4954
4955 to = ip->bw_conv_buf;
4956 if (enc_utf8)
4957 {
4958 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
4959 * The buffer has been allocated to be big enough. */
4960 while (fromlen > 0)
4961 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004962 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004963 if (n > (int)fromlen) /* incomplete byte sequence */
4964 break;
4965 u8c = utf_ptr2char(from);
4966 *to++ = (u8c & 0xff);
4967 *to++ = (u8c >> 8);
4968 fromlen -= n;
4969 from += n;
4970 }
4971
4972 /* Copy remainder to ip->bw_rest[] to be used for the next
4973 * call. */
4974 if (fromlen > CONV_RESTLEN)
4975 {
4976 /* weird overlong sequence */
4977 ip->bw_conv_error = TRUE;
4978 return FAIL;
4979 }
4980 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004981 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004982 }
4983 else
4984 {
4985 /* Convert from enc_codepage to UCS-2, to the start of the
4986 * buffer. The buffer has been allocated to be big enough. */
4987 ip->bw_restlen = 0;
4988 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004989 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990 NULL, 0);
4991 if (needed == 0)
4992 {
4993 /* When conversion fails there may be a trailing byte. */
4994 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004995 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996 NULL, 0);
4997 if (needed == 0)
4998 {
4999 /* Conversion doesn't work. */
5000 ip->bw_conv_error = TRUE;
5001 return FAIL;
5002 }
5003 /* Save the trailing byte for the next call. */
5004 ip->bw_rest[0] = from[fromlen - 1];
5005 ip->bw_restlen = 1;
5006 }
5007 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005008 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009 (LPWSTR)to, needed);
5010 if (needed == 0)
5011 {
5012 /* Safety check: Conversion doesn't work. */
5013 ip->bw_conv_error = TRUE;
5014 return FAIL;
5015 }
5016 to += needed * 2;
5017 }
5018
5019 fromlen = to - ip->bw_conv_buf;
5020 buf = to;
5021# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5022 if (FIO_GET_CP(flags) == CP_UTF8)
5023 {
5024 /* Convert from UCS-2 to UTF-8, using the remainder of the
5025 * conversion buffer. Fails when out of space. */
5026 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5027 {
5028 u8c = *from++;
5029 u8c += (*from++ << 8);
5030 to += utf_char2bytes(u8c, to);
5031 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5032 {
5033 ip->bw_conv_error = TRUE;
5034 return FAIL;
5035 }
5036 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005037 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038 }
5039 else
5040#endif
5041 {
5042 /* Convert from UCS-2 to the codepage, using the remainder of
5043 * the conversion buffer. If the conversion uses the default
5044 * character "0", the data doesn't fit in this encoding, so
5045 * fail. */
5046 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5047 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005048 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0, &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 if (bad)
5050 {
5051 ip->bw_conv_error = TRUE;
5052 return FAIL;
5053 }
5054 }
5055 }
5056# endif
5057
Bram Moolenaar56718732006-03-15 22:53:57 +00005058# ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005059 else if (flags & FIO_MACROMAN)
5060 {
5061 /*
5062 * Convert UTF-8 or latin1 to Apple MacRoman.
5063 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 char_u *from;
5065 size_t fromlen;
5066
5067 if (ip->bw_restlen > 0)
5068 {
5069 /* Need to concatenate the remainder of the previous call and
5070 * the bytes of the current call. Use the end of the
5071 * conversion buffer for this. */
5072 fromlen = len + ip->bw_restlen;
5073 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5074 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5075 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5076 }
5077 else
5078 {
5079 from = buf;
5080 fromlen = len;
5081 }
5082
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005083 if (enc2macroman(from, fromlen,
5084 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5085 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 {
5087 ip->bw_conv_error = TRUE;
5088 return FAIL;
5089 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091 }
5092# endif
5093
5094# ifdef USE_ICONV
5095 if (ip->bw_iconv_fd != (iconv_t)-1)
5096 {
5097 const char *from;
5098 size_t fromlen;
5099 char *to;
5100 size_t tolen;
5101
5102 /* Convert with iconv(). */
5103 if (ip->bw_restlen > 0)
5104 {
5105 /* Need to concatenate the remainder of the previous call and
5106 * the bytes of the current call. Use the end of the
5107 * conversion buffer for this. */
5108 fromlen = len + ip->bw_restlen;
5109 from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5110 mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
5111 mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
5112 tolen = ip->bw_conv_buflen - fromlen;
5113 }
5114 else
5115 {
5116 from = (const char *)buf;
5117 fromlen = len;
5118 tolen = ip->bw_conv_buflen;
5119 }
5120 to = (char *)ip->bw_conv_buf;
5121
5122 if (ip->bw_first)
5123 {
5124 size_t save_len = tolen;
5125
5126 /* output the initial shift state sequence */
5127 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5128
5129 /* There is a bug in iconv() on Linux (which appears to be
5130 * wide-spread) which sets "to" to NULL and messes up "tolen".
5131 */
5132 if (to == NULL)
5133 {
5134 to = (char *)ip->bw_conv_buf;
5135 tolen = save_len;
5136 }
5137 ip->bw_first = FALSE;
5138 }
5139
5140 /*
5141 * If iconv() has an error or there is not enough room, fail.
5142 */
5143 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5144 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5145 || fromlen > CONV_RESTLEN)
5146 {
5147 ip->bw_conv_error = TRUE;
5148 return FAIL;
5149 }
5150
5151 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5152 if (fromlen > 0)
5153 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5154 ip->bw_restlen = (int)fromlen;
5155
5156 buf = ip->bw_conv_buf;
5157 len = (int)((char_u *)to - ip->bw_conv_buf);
5158 }
5159# endif
5160 }
5161#endif /* FEAT_MBYTE */
5162
5163#ifdef FEAT_CRYPT
5164 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5165 {
5166 int ztemp, t, i;
5167
5168 for (i = 0; i < len; i++)
5169 {
5170 ztemp = buf[i];
5171 buf[i] = ZENCODE(ztemp, t);
5172 }
5173 }
5174#endif
5175
5176 /* Repeat the write(), it may be interrupted by a signal. */
5177 while (len)
5178 {
5179 wlen = vim_write(ip->bw_fd, buf, len);
5180 if (wlen <= 0) /* error! */
5181 return FAIL;
5182 len -= wlen;
5183 buf += wlen;
5184 }
5185 return OK;
5186}
5187
5188#ifdef FEAT_MBYTE
5189/*
5190 * Convert a Unicode character to bytes.
5191 */
5192 static int
5193ucs2bytes(c, pp, flags)
5194 unsigned c; /* in: character */
5195 char_u **pp; /* in/out: pointer to result */
5196 int flags; /* FIO_ flags */
5197{
5198 char_u *p = *pp;
5199 int error = FALSE;
5200 int cc;
5201
5202
5203 if (flags & FIO_UCS4)
5204 {
5205 if (flags & FIO_ENDIAN_L)
5206 {
5207 *p++ = c;
5208 *p++ = (c >> 8);
5209 *p++ = (c >> 16);
5210 *p++ = (c >> 24);
5211 }
5212 else
5213 {
5214 *p++ = (c >> 24);
5215 *p++ = (c >> 16);
5216 *p++ = (c >> 8);
5217 *p++ = c;
5218 }
5219 }
5220 else if (flags & (FIO_UCS2 | FIO_UTF16))
5221 {
5222 if (c >= 0x10000)
5223 {
5224 if (flags & FIO_UTF16)
5225 {
5226 /* Make two words, ten bits of the character in each. First
5227 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5228 c -= 0x10000;
5229 if (c >= 0x100000)
5230 error = TRUE;
5231 cc = ((c >> 10) & 0x3ff) + 0xd800;
5232 if (flags & FIO_ENDIAN_L)
5233 {
5234 *p++ = cc;
5235 *p++ = ((unsigned)cc >> 8);
5236 }
5237 else
5238 {
5239 *p++ = ((unsigned)cc >> 8);
5240 *p++ = cc;
5241 }
5242 c = (c & 0x3ff) + 0xdc00;
5243 }
5244 else
5245 error = TRUE;
5246 }
5247 if (flags & FIO_ENDIAN_L)
5248 {
5249 *p++ = c;
5250 *p++ = (c >> 8);
5251 }
5252 else
5253 {
5254 *p++ = (c >> 8);
5255 *p++ = c;
5256 }
5257 }
5258 else /* Latin1 */
5259 {
5260 if (c >= 0x100)
5261 {
5262 error = TRUE;
5263 *p++ = 0xBF;
5264 }
5265 else
5266 *p++ = c;
5267 }
5268
5269 *pp = p;
5270 return error;
5271}
5272
5273/*
5274 * Return TRUE if "a" and "b" are the same 'encoding'.
5275 * Ignores difference between "ansi" and "latin1", "ucs-4" and "ucs-4be", etc.
5276 */
5277 static int
5278same_encoding(a, b)
5279 char_u *a;
5280 char_u *b;
5281{
5282 int f;
5283
5284 if (STRCMP(a, b) == 0)
5285 return TRUE;
5286 f = get_fio_flags(a);
5287 return (f != 0 && get_fio_flags(b) == f);
5288}
5289
5290/*
5291 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5292 * internal conversion.
5293 * if "ptr" is an empty string, use 'encoding'.
5294 */
5295 static int
5296get_fio_flags(ptr)
5297 char_u *ptr;
5298{
5299 int prop;
5300
5301 if (*ptr == NUL)
5302 ptr = p_enc;
5303
5304 prop = enc_canon_props(ptr);
5305 if (prop & ENC_UNICODE)
5306 {
5307 if (prop & ENC_2BYTE)
5308 {
5309 if (prop & ENC_ENDIAN_L)
5310 return FIO_UCS2 | FIO_ENDIAN_L;
5311 return FIO_UCS2;
5312 }
5313 if (prop & ENC_4BYTE)
5314 {
5315 if (prop & ENC_ENDIAN_L)
5316 return FIO_UCS4 | FIO_ENDIAN_L;
5317 return FIO_UCS4;
5318 }
5319 if (prop & ENC_2WORD)
5320 {
5321 if (prop & ENC_ENDIAN_L)
5322 return FIO_UTF16 | FIO_ENDIAN_L;
5323 return FIO_UTF16;
5324 }
5325 return FIO_UTF8;
5326 }
5327 if (prop & ENC_LATIN1)
5328 return FIO_LATIN1;
5329 /* must be ENC_DBCS, requires iconv() */
5330 return 0;
5331}
5332
5333#ifdef WIN3264
5334/*
5335 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5336 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5337 * Used for conversion between 'encoding' and 'fileencoding'.
5338 */
5339 static int
5340get_win_fio_flags(ptr)
5341 char_u *ptr;
5342{
5343 int cp;
5344
5345 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5346 if (!enc_utf8 && enc_codepage <= 0)
5347 return 0;
5348
5349 cp = encname2codepage(ptr);
5350 if (cp == 0)
5351 {
5352# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5353 if (STRCMP(ptr, "utf-8") == 0)
5354 cp = CP_UTF8;
5355 else
5356# endif
5357 return 0;
5358 }
5359 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5360}
5361#endif
5362
5363#ifdef MACOS_X
5364/*
5365 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5366 * needed for the internal conversion to/from utf-8 or latin1.
5367 */
5368 static int
5369get_mac_fio_flags(ptr)
5370 char_u *ptr;
5371{
5372 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5373 && (enc_canon_props(ptr) & ENC_MACROMAN))
5374 return FIO_MACROMAN;
5375 return 0;
5376}
5377#endif
5378
5379/*
5380 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5381 * "size" must be at least 2.
5382 * Return the name of the encoding and set "*lenp" to the length.
5383 * Returns NULL when no BOM found.
5384 */
5385 static char_u *
5386check_for_bom(p, size, lenp, flags)
5387 char_u *p;
5388 long size;
5389 int *lenp;
5390 int flags;
5391{
5392 char *name = NULL;
5393 int len = 2;
5394
5395 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
5396 && (flags == FIO_ALL || flags == 0))
5397 {
5398 name = "utf-8"; /* EF BB BF */
5399 len = 3;
5400 }
5401 else if (p[0] == 0xff && p[1] == 0xfe)
5402 {
5403 if (size >= 4 && p[2] == 0 && p[3] == 0
5404 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5405 {
5406 name = "ucs-4le"; /* FF FE 00 00 */
5407 len = 4;
5408 }
5409 else if (flags == FIO_ALL || flags == (FIO_UCS2 | FIO_ENDIAN_L))
5410 name = "ucs-2le"; /* FF FE */
5411 else if (flags == (FIO_UTF16 | FIO_ENDIAN_L))
5412 name = "utf-16le"; /* FF FE */
5413 }
5414 else if (p[0] == 0xfe && p[1] == 0xff
5415 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5416 {
5417 if (flags == FIO_UTF16)
5418 name = "utf-16"; /* FE FF */
5419 else
5420 name = "ucs-2"; /* FE FF */
5421 }
5422 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5423 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5424 {
5425 name = "ucs-4"; /* 00 00 FE FF */
5426 len = 4;
5427 }
5428
5429 *lenp = len;
5430 return (char_u *)name;
5431}
5432
5433/*
5434 * Generate a BOM in "buf[4]" for encoding "name".
5435 * Return the length of the BOM (zero when no BOM).
5436 */
5437 static int
5438make_bom(buf, name)
5439 char_u *buf;
5440 char_u *name;
5441{
5442 int flags;
5443 char_u *p;
5444
5445 flags = get_fio_flags(name);
5446
5447 /* Can't put a BOM in a non-Unicode file. */
5448 if (flags == FIO_LATIN1 || flags == 0)
5449 return 0;
5450
5451 if (flags == FIO_UTF8) /* UTF-8 */
5452 {
5453 buf[0] = 0xef;
5454 buf[1] = 0xbb;
5455 buf[2] = 0xbf;
5456 return 3;
5457 }
5458 p = buf;
5459 (void)ucs2bytes(0xfeff, &p, flags);
5460 return (int)(p - buf);
5461}
5462#endif
5463
5464/*
5465 * Try to find a shortname by comparing the fullname with the current
5466 * directory.
5467 * Returns NULL if not shorter name possible, pointer into "full_path"
5468 * otherwise.
5469 */
5470 char_u *
5471shorten_fname(full_path, dir_name)
5472 char_u *full_path;
5473 char_u *dir_name;
5474{
5475 int len;
5476 char_u *p;
5477
5478 if (full_path == NULL)
5479 return NULL;
5480 len = (int)STRLEN(dir_name);
5481 if (fnamencmp(dir_name, full_path, len) == 0)
5482 {
5483 p = full_path + len;
5484#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5485 /*
5486 * MSDOS: when a file is in the root directory, dir_name will end in a
5487 * slash, since C: by itself does not define a specific dir. In this
5488 * case p may already be correct. <negri>
5489 */
5490 if (!((len > 2) && (*(p - 2) == ':')))
5491#endif
5492 {
5493 if (vim_ispathsep(*p))
5494 ++p;
5495#ifndef VMS /* the path separator is always part of the path */
5496 else
5497 p = NULL;
5498#endif
5499 }
5500 }
5501#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5502 /*
5503 * When using a file in the current drive, remove the drive name:
5504 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5505 * a floppy from "A:\dir" to "B:\dir".
5506 */
5507 else if (len > 3
5508 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5509 && full_path[1] == ':'
5510 && vim_ispathsep(full_path[2]))
5511 p = full_path + 2;
5512#endif
5513 else
5514 p = NULL;
5515 return p;
5516}
5517
5518/*
5519 * Shorten filenames for all buffers.
5520 * When "force" is TRUE: Use full path from now on for files currently being
5521 * edited, both for file name and swap file name. Try to shorten the file
5522 * names a bit, if safe to do so.
5523 * When "force" is FALSE: Only try to shorten absolute file names.
5524 * For buffers that have buftype "nofile" or "scratch": never change the file
5525 * name.
5526 */
5527 void
5528shorten_fnames(force)
5529 int force;
5530{
5531 char_u dirname[MAXPATHL];
5532 buf_T *buf;
5533 char_u *p;
5534
5535 mch_dirname(dirname, MAXPATHL);
5536 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5537 {
5538 if (buf->b_fname != NULL
5539#ifdef FEAT_QUICKFIX
5540 && !bt_nofile(buf)
5541#endif
5542 && !path_with_url(buf->b_fname)
5543 && (force
5544 || buf->b_sfname == NULL
5545 || mch_isFullName(buf->b_sfname)))
5546 {
5547 vim_free(buf->b_sfname);
5548 buf->b_sfname = NULL;
5549 p = shorten_fname(buf->b_ffname, dirname);
5550 if (p != NULL)
5551 {
5552 buf->b_sfname = vim_strsave(p);
5553 buf->b_fname = buf->b_sfname;
5554 }
5555 if (p == NULL || buf->b_fname == NULL)
5556 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005557 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005558
5559 /* Always make the swap file name a full path, a "nofile" buffer may
5560 * also have a swap file. */
5561 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005562 }
5563#ifdef FEAT_WINDOWS
5564 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005565 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005566#endif
5567}
5568
5569#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5570 || defined(FEAT_GUI_MSWIN) \
5571 || defined(FEAT_GUI_MAC) \
5572 || defined(PROTO)
5573/*
5574 * Shorten all filenames in "fnames[count]" by current directory.
5575 */
5576 void
5577shorten_filenames(fnames, count)
5578 char_u **fnames;
5579 int count;
5580{
5581 int i;
5582 char_u dirname[MAXPATHL];
5583 char_u *p;
5584
5585 if (fnames == NULL || count < 1)
5586 return;
5587 mch_dirname(dirname, sizeof(dirname));
5588 for (i = 0; i < count; ++i)
5589 {
5590 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5591 {
5592 /* shorten_fname() returns pointer in given "fnames[i]". If free
5593 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5594 * "p" first then free fnames[i]. */
5595 p = vim_strsave(p);
5596 vim_free(fnames[i]);
5597 fnames[i] = p;
5598 }
5599 }
5600}
5601#endif
5602
5603/*
5604 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5605 * fo_o_h.ext for MSDOS or when shortname option set.
5606 *
5607 * Assumed that fname is a valid name found in the filesystem we assure that
5608 * the return value is a different name and ends in 'ext'.
5609 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5610 * characters otherwise.
5611 * Space for the returned name is allocated, must be freed later.
5612 * Returns NULL when out of memory.
5613 */
5614 char_u *
5615modname(fname, ext, prepend_dot)
5616 char_u *fname, *ext;
5617 int prepend_dot; /* may prepend a '.' to file name */
5618{
5619 return buf_modname(
5620#ifdef SHORT_FNAME
5621 TRUE,
5622#else
5623 (curbuf->b_p_sn || curbuf->b_shortname),
5624#endif
5625 fname, ext, prepend_dot);
5626}
5627
5628 char_u *
5629buf_modname(shortname, fname, ext, prepend_dot)
5630 int shortname; /* use 8.3 file name */
5631 char_u *fname, *ext;
5632 int prepend_dot; /* may prepend a '.' to file name */
5633{
5634 char_u *retval;
5635 char_u *s;
5636 char_u *e;
5637 char_u *ptr;
5638 int fnamelen, extlen;
5639
5640 extlen = (int)STRLEN(ext);
5641
5642 /*
5643 * If there is no file name we must get the name of the current directory
5644 * (we need the full path in case :cd is used).
5645 */
5646 if (fname == NULL || *fname == NUL)
5647 {
5648 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5649 if (retval == NULL)
5650 return NULL;
5651 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5652 (fnamelen = (int)STRLEN(retval)) == 0)
5653 {
5654 vim_free(retval);
5655 return NULL;
5656 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005657 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658 {
5659 retval[fnamelen++] = PATHSEP;
5660 retval[fnamelen] = NUL;
5661 }
5662#ifndef SHORT_FNAME
5663 prepend_dot = FALSE; /* nothing to prepend a dot to */
5664#endif
5665 }
5666 else
5667 {
5668 fnamelen = (int)STRLEN(fname);
5669 retval = alloc((unsigned)(fnamelen + extlen + 3));
5670 if (retval == NULL)
5671 return NULL;
5672 STRCPY(retval, fname);
5673#ifdef VMS
5674 vms_remove_version(retval); /* we do not need versions here */
5675#endif
5676 }
5677
5678 /*
5679 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5680 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5681 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5682 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5683 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005684 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685 {
5686#ifndef RISCOS
5687 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005688# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005690# else
5691# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005693# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005694# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695 )
5696 if (*ptr == '.') /* replace '.' by '_' */
5697 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005698#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005700 {
5701 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005702 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005703 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705
5706 /* the file name has at most BASENAMELEN characters. */
5707#ifndef SHORT_FNAME
5708 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5709 ptr[BASENAMELEN] = '\0';
5710#endif
5711
5712 s = ptr + STRLEN(ptr);
5713
5714 /*
5715 * For 8.3 file names we may have to reduce the length.
5716 */
5717#ifdef USE_LONG_FNAME
5718 if (!USE_LONG_FNAME || shortname)
5719#else
5720# ifndef SHORT_FNAME
5721 if (shortname)
5722# endif
5723#endif
5724 {
5725 /*
5726 * If there is no file name, or the file name ends in '/', and the
5727 * extension starts with '.', put a '_' before the dot, because just
5728 * ".ext" is invalid.
5729 */
5730 if (fname == NULL || *fname == NUL
5731 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5732 {
5733#ifdef RISCOS
5734 if (*ext == '/')
5735#else
5736 if (*ext == '.')
5737#endif
5738 *s++ = '_';
5739 }
5740 /*
5741 * If the extension starts with '.', truncate the base name at 8
5742 * characters
5743 */
5744#ifdef RISCOS
5745 /* We normally use '/', but swap files are '_' */
5746 else if (*ext == '/' || *ext == '_')
5747#else
5748 else if (*ext == '.')
5749#endif
5750 {
5751 if (s - ptr > (size_t)8)
5752 {
5753 s = ptr + 8;
5754 *s = '\0';
5755 }
5756 }
5757 /*
5758 * If the extension doesn't start with '.', and the file name
5759 * doesn't have an extension yet, append a '.'
5760 */
5761#ifdef RISCOS
5762 else if ((e = vim_strchr(ptr, '/')) == NULL)
5763 *s++ = '/';
5764#else
5765 else if ((e = vim_strchr(ptr, '.')) == NULL)
5766 *s++ = '.';
5767#endif
5768 /*
5769 * If the extension doesn't start with '.', and there already is an
5770 * extension, it may need to be tructated
5771 */
5772 else if ((int)STRLEN(e) + extlen > 4)
5773 s = e + 4 - extlen;
5774 }
5775#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5776 /*
5777 * If there is no file name, and the extension starts with '.', put a
5778 * '_' before the dot, because just ".ext" may be invalid if it's on a
5779 * FAT partition, and on HPFS it doesn't matter.
5780 */
5781 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5782 *s++ = '_';
5783#endif
5784
5785 /*
5786 * Append the extention.
5787 * ext can start with '.' and cannot exceed 3 more characters.
5788 */
5789 STRCPY(s, ext);
5790
5791#ifndef SHORT_FNAME
5792 /*
5793 * Prepend the dot.
5794 */
5795 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5796#ifdef RISCOS
5797 '/'
5798#else
5799 '.'
5800#endif
5801#ifdef USE_LONG_FNAME
5802 && USE_LONG_FNAME
5803#endif
5804 )
5805 {
5806 mch_memmove(e + 1, e, STRLEN(e) + 1);
5807#ifdef RISCOS
5808 *e = '/';
5809#else
5810 *e = '.';
5811#endif
5812 }
5813#endif
5814
5815 /*
5816 * Check that, after appending the extension, the file name is really
5817 * different.
5818 */
5819 if (fname != NULL && STRCMP(fname, retval) == 0)
5820 {
5821 /* we search for a character that can be replaced by '_' */
5822 while (--s >= ptr)
5823 {
5824 if (*s != '_')
5825 {
5826 *s = '_';
5827 break;
5828 }
5829 }
5830 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5831 *ptr = 'v';
5832 }
5833 return retval;
5834}
5835
5836/*
5837 * Like fgets(), but if the file line is too long, it is truncated and the
5838 * rest of the line is thrown away. Returns TRUE for end-of-file.
5839 */
5840 int
5841vim_fgets(buf, size, fp)
5842 char_u *buf;
5843 int size;
5844 FILE *fp;
5845{
5846 char *eof;
5847#define FGETS_SIZE 200
5848 char tbuf[FGETS_SIZE];
5849
5850 buf[size - 2] = NUL;
5851#ifdef USE_CR
5852 eof = fgets_cr((char *)buf, size, fp);
5853#else
5854 eof = fgets((char *)buf, size, fp);
5855#endif
5856 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5857 {
5858 buf[size - 1] = NUL; /* Truncate the line */
5859
5860 /* Now throw away the rest of the line: */
5861 do
5862 {
5863 tbuf[FGETS_SIZE - 2] = NUL;
5864#ifdef USE_CR
5865 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
5866#else
5867 fgets((char *)tbuf, FGETS_SIZE, fp);
5868#endif
5869 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
5870 }
5871 return (eof == NULL);
5872}
5873
5874#if defined(USE_CR) || defined(PROTO)
5875/*
5876 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
5877 * Returns TRUE for end-of-file.
5878 * Only used for the Mac, because it's much slower than vim_fgets().
5879 */
5880 int
5881tag_fgets(buf, size, fp)
5882 char_u *buf;
5883 int size;
5884 FILE *fp;
5885{
5886 int i = 0;
5887 int c;
5888 int eof = FALSE;
5889
5890 for (;;)
5891 {
5892 c = fgetc(fp);
5893 if (c == EOF)
5894 {
5895 eof = TRUE;
5896 break;
5897 }
5898 if (c == '\r')
5899 {
5900 /* Always store a NL for end-of-line. */
5901 if (i < size - 1)
5902 buf[i++] = '\n';
5903 c = fgetc(fp);
5904 if (c != '\n') /* Macintosh format: single CR. */
5905 ungetc(c, fp);
5906 break;
5907 }
5908 if (i < size - 1)
5909 buf[i++] = c;
5910 if (c == '\n')
5911 break;
5912 }
5913 buf[i] = NUL;
5914 return eof;
5915}
5916#endif
5917
5918/*
5919 * rename() only works if both files are on the same file system, this
5920 * function will (attempts to?) copy the file across if rename fails -- webb
5921 * Return -1 for failure, 0 for success.
5922 */
5923 int
5924vim_rename(from, to)
5925 char_u *from;
5926 char_u *to;
5927{
5928 int fd_in;
5929 int fd_out;
5930 int n;
5931 char *errmsg = NULL;
5932 char *buffer;
5933#ifdef AMIGA
5934 BPTR flock;
5935#endif
5936 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005937 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005938#ifdef HAVE_ACL
5939 vim_acl_T acl; /* ACL from original file */
5940#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941
5942 /*
5943 * When the names are identical, there is nothing to do.
5944 */
5945 if (fnamecmp(from, to) == 0)
5946 return 0;
5947
5948 /*
5949 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
5950 */
5951 if (mch_stat((char *)from, &st) < 0)
5952 return -1;
5953
5954 /*
5955 * Delete the "to" file, this is required on some systems to make the
5956 * mch_rename() work, on other systems it makes sure that we don't have
5957 * two files when the mch_rename() fails.
5958 */
5959
5960#ifdef AMIGA
5961 /*
5962 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
5963 * that the name of the "to" file is the same as the "from" file, even
5964 * though the names are different. To avoid the chance of accidently
5965 * deleting the "from" file (horror!) we lock it during the remove.
5966 *
5967 * When used for making a backup before writing the file: This should not
5968 * happen with ":w", because startscript() should detect this problem and
5969 * set buf->b_shortname, causing modname() to return a correct ".bak" file
5970 * name. This problem does exist with ":w filename", but then the
5971 * original file will be somewhere else so the backup isn't really
5972 * important. If autoscripting is off the rename may fail.
5973 */
5974 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
5975#endif
5976 mch_remove(to);
5977#ifdef AMIGA
5978 if (flock)
5979 UnLock(flock);
5980#endif
5981
5982 /*
5983 * First try a normal rename, return if it works.
5984 */
5985 if (mch_rename((char *)from, (char *)to) == 0)
5986 return 0;
5987
5988 /*
5989 * Rename() failed, try copying the file.
5990 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005991 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005992#ifdef HAVE_ACL
5993 /* For systems that support ACL: get the ACL from the original file. */
5994 acl = mch_get_acl(from);
5995#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005996 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
5997 if (fd_in == -1)
5998 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005999
6000 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006001 fd_out = mch_open((char *)to,
6002 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003 if (fd_out == -1)
6004 {
6005 close(fd_in);
6006 return -1;
6007 }
6008
6009 buffer = (char *)alloc(BUFSIZE);
6010 if (buffer == NULL)
6011 {
6012 close(fd_in);
6013 close(fd_out);
6014 return -1;
6015 }
6016
6017 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
6018 if (vim_write(fd_out, buffer, n) != n)
6019 {
6020 errmsg = _("E208: Error writing to \"%s\"");
6021 break;
6022 }
6023
6024 vim_free(buffer);
6025 close(fd_in);
6026 if (close(fd_out) < 0)
6027 errmsg = _("E209: Error closing \"%s\"");
6028 if (n < 0)
6029 {
6030 errmsg = _("E210: Error reading \"%s\"");
6031 to = from;
6032 }
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006033#ifndef UNIX /* for Unix mch_open() already set ther permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006034 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006035#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006036#ifdef HAVE_ACL
6037 mch_set_acl(to, acl);
6038#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006039 if (errmsg != NULL)
6040 {
6041 EMSG2(errmsg, to);
6042 return -1;
6043 }
6044 mch_remove(from);
6045 return 0;
6046}
6047
6048static int already_warned = FALSE;
6049
6050/*
6051 * Check if any not hidden buffer has been changed.
6052 * Postpone the check if there are characters in the stuff buffer, a global
6053 * command is being executed, a mapping is being executed or an autocommand is
6054 * busy.
6055 * Returns TRUE if some message was written (screen should be redrawn and
6056 * cursor positioned).
6057 */
6058 int
6059check_timestamps(focus)
6060 int focus; /* called for GUI focus event */
6061{
6062 buf_T *buf;
6063 int didit = 0;
6064 int n;
6065
6066 /* Don't check timestamps while system() or another low-level function may
6067 * cause us to lose and gain focus. */
6068 if (no_check_timestamps > 0)
6069 return FALSE;
6070
6071 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6072 * event and we would keep on checking if the file is steadily growing.
6073 * Do check again after typing something. */
6074 if (focus && did_check_timestamps)
6075 {
6076 need_check_timestamps = TRUE;
6077 return FALSE;
6078 }
6079
6080 if (!stuff_empty() || global_busy || !typebuf_typed()
6081#ifdef FEAT_AUTOCMD
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006082 || autocmd_busy || curbuf_lock > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083#endif
6084 )
6085 need_check_timestamps = TRUE; /* check later */
6086 else
6087 {
6088 ++no_wait_return;
6089 did_check_timestamps = TRUE;
6090 already_warned = FALSE;
6091 for (buf = firstbuf; buf != NULL; )
6092 {
6093 /* Only check buffers in a window. */
6094 if (buf->b_nwindows > 0)
6095 {
6096 n = buf_check_timestamp(buf, focus);
6097 if (didit < n)
6098 didit = n;
6099 if (n > 0 && !buf_valid(buf))
6100 {
6101 /* Autocommands have removed the buffer, start at the
6102 * first one again. */
6103 buf = firstbuf;
6104 continue;
6105 }
6106 }
6107 buf = buf->b_next;
6108 }
6109 --no_wait_return;
6110 need_check_timestamps = FALSE;
6111 if (need_wait_return && didit == 2)
6112 {
6113 /* make sure msg isn't overwritten */
6114 msg_puts((char_u *)"\n");
6115 out_flush();
6116 }
6117 }
6118 return didit;
6119}
6120
6121/*
6122 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6123 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6124 * empty.
6125 */
6126 static int
6127move_lines(frombuf, tobuf)
6128 buf_T *frombuf;
6129 buf_T *tobuf;
6130{
6131 buf_T *tbuf = curbuf;
6132 int retval = OK;
6133 linenr_T lnum;
6134 char_u *p;
6135
6136 /* Copy the lines in "frombuf" to "tobuf". */
6137 curbuf = tobuf;
6138 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6139 {
6140 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6141 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6142 {
6143 vim_free(p);
6144 retval = FAIL;
6145 break;
6146 }
6147 vim_free(p);
6148 }
6149
6150 /* Delete all the lines in "frombuf". */
6151 if (retval != FAIL)
6152 {
6153 curbuf = frombuf;
6154 while (!bufempty())
6155 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE) == FAIL)
6156 {
6157 /* Oops! We could try putting back the saved lines, but that
6158 * might fail again... */
6159 retval = FAIL;
6160 break;
6161 }
6162 }
6163
6164 curbuf = tbuf;
6165 return retval;
6166}
6167
6168/*
6169 * Check if buffer "buf" has been changed.
6170 * Also check if the file for a new buffer unexpectedly appeared.
6171 * return 1 if a changed buffer was found.
6172 * return 2 if a message has been displayed.
6173 * return 0 otherwise.
6174 */
6175/*ARGSUSED*/
6176 int
6177buf_check_timestamp(buf, focus)
6178 buf_T *buf;
6179 int focus; /* called for GUI focus event */
6180{
6181 struct stat st;
6182 int stat_res;
6183 int retval = 0;
6184 char_u *path;
6185 char_u *tbuf;
6186 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006187 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188 int helpmesg = FALSE;
6189 int reload = FALSE;
6190#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6191 int can_reload = FALSE;
6192#endif
6193 size_t orig_size = buf->b_orig_size;
6194 int orig_mode = buf->b_orig_mode;
6195#ifdef FEAT_GUI
6196 int save_mouse_correct = need_mouse_correct;
6197#endif
6198#ifdef FEAT_AUTOCMD
6199 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006200 int n;
6201 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006202#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006203 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204
6205 /* If there is no file name, the buffer is not loaded, 'buftype' is
6206 * set, we are in the middle of a save or being called recursively: ignore
6207 * this buffer. */
6208 if (buf->b_ffname == NULL
6209 || buf->b_ml.ml_mfp == NULL
6210#if defined(FEAT_QUICKFIX)
6211 || *buf->b_p_bt != NUL
6212#endif
6213 || buf->b_saving
6214#ifdef FEAT_AUTOCMD
6215 || busy
6216#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006217#ifdef FEAT_NETBEANS_INTG
6218 || isNetbeansBuffer(buf)
6219#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006220 )
6221 return 0;
6222
6223 if ( !(buf->b_flags & BF_NOTEDITED)
6224 && buf->b_mtime != 0
6225 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6226 || time_differs((long)st.st_mtime, buf->b_mtime)
6227#ifdef HAVE_ST_MODE
6228 || (int)st.st_mode != buf->b_orig_mode
6229#else
6230 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6231#endif
6232 ))
6233 {
6234 retval = 1;
6235
Bram Moolenaar316059c2006-01-14 21:18:42 +00006236 /* set b_mtime to stop further warnings (e.g., when executing
6237 * FileChangedShell autocmd) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238 if (stat_res < 0)
6239 {
6240 buf->b_mtime = 0;
6241 buf->b_orig_size = 0;
6242 buf->b_orig_mode = 0;
6243 }
6244 else
6245 buf_store_time(buf, &st, buf->b_ffname);
6246
6247 /* Don't do anything for a directory. Might contain the file
6248 * explorer. */
6249 if (mch_isdir(buf->b_fname))
6250 ;
6251
6252 /*
6253 * If 'autoread' is set, the buffer has no changes and the file still
6254 * exists, reload the buffer. Use the buffer-local option value if it
6255 * was set, the global option value otherwise.
6256 */
6257 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6258 && !bufIsChanged(buf) && stat_res >= 0)
6259 reload = TRUE;
6260 else
6261 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006262 if (stat_res < 0)
6263 reason = "deleted";
6264 else if (bufIsChanged(buf))
6265 reason = "conflict";
6266 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6267 reason = "changed";
6268 else if (orig_mode != buf->b_orig_mode)
6269 reason = "mode";
6270 else
6271 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006273#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006274 /*
6275 * Only give the warning if there are no FileChangedShell
6276 * autocommands.
6277 * Avoid being called recursively by setting "busy".
6278 */
6279 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006280# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006281 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6282 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006283# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6285 buf->b_fname, buf->b_fname, FALSE, buf);
6286 busy = FALSE;
6287 if (n)
6288 {
6289 if (!buf_valid(buf))
6290 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006291# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006292 s = get_vim_var_str(VV_FCS_CHOICE);
6293 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6294 reload = TRUE;
6295 else if (STRCMP(s, "ask") == 0)
6296 n = FALSE;
6297 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006298# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006299 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006301 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006302#endif
6303 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006304 if (*reason == 'd')
6305 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306 else
6307 {
6308 helpmesg = TRUE;
6309#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6310 can_reload = TRUE;
6311#endif
6312 /*
6313 * Check if the file contents really changed to avoid
6314 * giving a warning when only the timestamp was set (e.g.,
6315 * checked out of CVS). Always warn when the buffer was
6316 * changed.
6317 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006318 if (reason[2] == 'n')
6319 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006321 mesg2 = _("See \":help W12\" for more info.");
6322 }
6323 else if (reason[1] == 'h')
6324 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006326 mesg2 = _("See \":help W11\" for more info.");
6327 }
6328 else if (*reason == 'm')
6329 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006330 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006331 mesg2 = _("See \":help W16\" for more info.");
6332 }
6333 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006334 }
6335 }
6336 }
6337
6338 }
6339 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6340 && vim_fexists(buf->b_ffname))
6341 {
6342 retval = 1;
6343 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6344 buf->b_flags |= BF_NEW_W;
6345#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6346 can_reload = TRUE;
6347#endif
6348 }
6349
6350 if (mesg != NULL)
6351 {
6352 path = home_replace_save(buf, buf->b_fname);
6353 if (path != NULL)
6354 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006355 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356 mesg2 = "";
6357 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6358 + STRLEN(mesg2) + 2));
6359 sprintf((char *)tbuf, mesg, path);
6360#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6361 if (can_reload)
6362 {
6363 if (*mesg2 != NUL)
6364 {
6365 STRCAT(tbuf, "\n");
6366 STRCAT(tbuf, mesg2);
6367 }
6368 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6369 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6370 reload = TRUE;
6371 }
6372 else
6373#endif
6374 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6375 {
6376 if (*mesg2 != NUL)
6377 {
6378 STRCAT(tbuf, "; ");
6379 STRCAT(tbuf, mesg2);
6380 }
6381 EMSG(tbuf);
6382 retval = 2;
6383 }
6384 else
6385 {
Bram Moolenaared203462004-06-16 11:19:22 +00006386# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006387 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006388# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006389 {
6390 msg_start();
6391 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6392 if (*mesg2 != NUL)
6393 msg_puts_attr((char_u *)mesg2,
6394 hl_attr(HLF_W) + MSG_HIST);
6395 msg_clr_eos();
6396 (void)msg_end();
6397 if (emsg_silent == 0)
6398 {
6399 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006400# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006401 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006402# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006403 /* give the user some time to think about it */
6404 ui_delay(1000L, TRUE);
6405
6406 /* don't redraw and erase the message */
6407 redraw_cmdline = FALSE;
6408 }
6409 }
6410 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006411 }
6412
6413 vim_free(path);
6414 vim_free(tbuf);
6415 }
6416 }
6417
6418 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006419 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006420 buf_reload(buf, orig_mode);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006421
Bram Moolenaar56718732006-03-15 22:53:57 +00006422#ifdef FEAT_AUTOCMD
6423 if (buf_valid(buf))
6424 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6425 buf->b_fname, buf->b_fname, FALSE, buf);
6426#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006427#ifdef FEAT_GUI
6428 /* restore this in case an autocommand has set it; it would break
6429 * 'mousefocus' */
6430 need_mouse_correct = save_mouse_correct;
6431#endif
6432
6433 return retval;
6434}
6435
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006436/*
6437 * Reload a buffer that is already loaded.
6438 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006439 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6440 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006441 */
6442 void
Bram Moolenaar316059c2006-01-14 21:18:42 +00006443buf_reload(buf, orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006444 buf_T *buf;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006445 int orig_mode;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006446{
6447 exarg_T ea;
6448 pos_T old_cursor;
6449 linenr_T old_topline;
6450 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006451 buf_T *savebuf;
6452 int saved = OK;
6453#ifdef FEAT_AUTOCMD
6454 aco_save_T aco;
6455
6456 /* set curwin/curbuf for "buf" and save some things */
6457 aucmd_prepbuf(&aco, buf);
6458#else
6459 buf_T *save_curbuf = curbuf;
6460
6461 curbuf = buf;
6462 curwin->w_buffer = buf;
6463#endif
6464
6465 /* We only want to read the text from the file, not reset the syntax
6466 * highlighting, clear marks, diff status, etc. Force the fileformat
6467 * and encoding to be the same. */
6468 if (prep_exarg(&ea, buf) == OK)
6469 {
6470 old_cursor = curwin->w_cursor;
6471 old_topline = curwin->w_topline;
6472
6473 /*
6474 * To behave like when a new file is edited (matters for
6475 * BufReadPost autocommands) we first need to delete the current
6476 * buffer contents. But if reading the file fails we should keep
6477 * the old contents. Can't use memory only, the file might be
6478 * too big. Use a hidden buffer to move the buffer contents to.
6479 */
6480 if (bufempty())
6481 savebuf = NULL;
6482 else
6483 {
6484 /* Allocate a buffer without putting it in the buffer list. */
6485 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006486 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006487 {
6488 /* Open the memline. */
6489 curbuf = savebuf;
6490 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006491 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006492 curbuf = buf;
6493 curwin->w_buffer = buf;
6494 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006495 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006496 || move_lines(buf, savebuf) == FAIL)
6497 {
6498 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6499 buf->b_fname);
6500 saved = FAIL;
6501 }
6502 }
6503
6504 if (saved == OK)
6505 {
6506 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6507#ifdef FEAT_AUTOCMD
6508 keep_filetype = TRUE; /* don't detect 'filetype' */
6509#endif
6510 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6511 (linenr_T)0,
6512 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6513 {
6514#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6515 if (!aborting())
6516#endif
6517 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar8424a622006-04-19 21:23:36 +00006518 if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006519 {
6520 /* Put the text back from the save buffer. First
6521 * delete any lines that readfile() added. */
6522 while (!bufempty())
Bram Moolenaar8424a622006-04-19 21:23:36 +00006523 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006524 break;
6525 (void)move_lines(savebuf, buf);
6526 }
6527 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00006528 else if (buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006529 {
6530 /* Mark the buffer as unmodified and free undo info. */
6531 unchanged(buf, TRUE);
6532 u_blockfree(buf);
6533 u_clearall(buf);
6534 }
6535 }
6536 vim_free(ea.cmd);
6537
Bram Moolenaar8424a622006-04-19 21:23:36 +00006538 if (savebuf != NULL && buf_valid(savebuf))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006539 wipe_buffer(savebuf, FALSE);
6540
6541#ifdef FEAT_DIFF
6542 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00006543 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006544#endif
6545
6546 /* Restore the topline and cursor position and check it (lines may
6547 * have been removed). */
6548 if (old_topline > curbuf->b_ml.ml_line_count)
6549 curwin->w_topline = curbuf->b_ml.ml_line_count;
6550 else
6551 curwin->w_topline = old_topline;
6552 curwin->w_cursor = old_cursor;
6553 check_cursor();
6554 update_topline();
6555#ifdef FEAT_AUTOCMD
6556 keep_filetype = FALSE;
6557#endif
6558#ifdef FEAT_FOLDING
6559 {
6560 win_T *wp;
6561
6562 /* Update folds unless they are defined manually. */
6563 FOR_ALL_WINDOWS(wp)
6564 if (wp->w_buffer == curwin->w_buffer
6565 && !foldmethodIsManual(wp))
6566 foldUpdateAll(wp);
6567 }
6568#endif
6569 /* If the mode didn't change and 'readonly' was set, keep the old
6570 * value; the user probably used the ":view" command. But don't
6571 * reset it, might have had a read error. */
6572 if (orig_mode == curbuf->b_orig_mode)
6573 curbuf->b_p_ro |= old_ro;
6574 }
6575
6576#ifdef FEAT_AUTOCMD
6577 /* restore curwin/curbuf and a few other things */
6578 aucmd_restbuf(&aco);
6579 /* Careful: autocommands may have made "buf" invalid! */
6580#else
6581 curwin->w_buffer = save_curbuf;
6582 curbuf = save_curbuf;
6583#endif
6584}
6585
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586/*ARGSUSED*/
6587 void
6588buf_store_time(buf, st, fname)
6589 buf_T *buf;
6590 struct stat *st;
6591 char_u *fname;
6592{
6593 buf->b_mtime = (long)st->st_mtime;
6594 buf->b_orig_size = (size_t)st->st_size;
6595#ifdef HAVE_ST_MODE
6596 buf->b_orig_mode = (int)st->st_mode;
6597#else
6598 buf->b_orig_mode = mch_getperm(fname);
6599#endif
6600}
6601
6602/*
6603 * Adjust the line with missing eol, used for the next write.
6604 * Used for do_filter(), when the input lines for the filter are deleted.
6605 */
6606 void
6607write_lnum_adjust(offset)
6608 linenr_T offset;
6609{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006610 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006611 write_no_eol_lnum += offset;
6612}
6613
6614#if defined(TEMPDIRNAMES) || defined(PROTO)
6615static long temp_count = 0; /* Temp filename counter. */
6616
6617/*
6618 * Delete the temp directory and all files it contains.
6619 */
6620 void
6621vim_deltempdir()
6622{
6623 char_u **files;
6624 int file_count;
6625 int i;
6626
6627 if (vim_tempdir != NULL)
6628 {
6629 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6630 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6631 EW_DIR|EW_FILE|EW_SILENT) == OK)
6632 {
6633 for (i = 0; i < file_count; ++i)
6634 mch_remove(files[i]);
6635 FreeWild(file_count, files);
6636 }
6637 gettail(NameBuff)[-1] = NUL;
6638 (void)mch_rmdir(NameBuff);
6639
6640 vim_free(vim_tempdir);
6641 vim_tempdir = NULL;
6642 }
6643}
6644#endif
6645
6646/*
6647 * vim_tempname(): Return a unique name that can be used for a temp file.
6648 *
6649 * The temp file is NOT created.
6650 *
6651 * The returned pointer is to allocated memory.
6652 * The returned pointer is NULL if no valid name was found.
6653 */
6654/*ARGSUSED*/
6655 char_u *
6656vim_tempname(extra_char)
6657 int extra_char; /* character to use in the name instead of '?' */
6658{
6659#ifdef USE_TMPNAM
6660 char_u itmp[L_tmpnam]; /* use tmpnam() */
6661#else
6662 char_u itmp[TEMPNAMELEN];
6663#endif
6664
6665#ifdef TEMPDIRNAMES
6666 static char *(tempdirs[]) = {TEMPDIRNAMES};
6667 int i;
6668 long nr;
6669 long off;
6670# ifndef EEXIST
6671 struct stat st;
6672# endif
6673
6674 /*
6675 * This will create a directory for private use by this instance of Vim.
6676 * This is done once, and the same directory is used for all temp files.
6677 * This method avoids security problems because of symlink attacks et al.
6678 * It's also a bit faster, because we only need to check for an existing
6679 * file when creating the directory and not for each temp file.
6680 */
6681 if (vim_tempdir == NULL)
6682 {
6683 /*
6684 * Try the entries in TEMPDIRNAMES to create the temp directory.
6685 */
6686 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6687 {
6688 /* expand $TMP, leave room for "/v1100000/999999999" */
6689 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6690 if (mch_isdir(itmp)) /* directory exists */
6691 {
6692# ifdef __EMX__
6693 /* If $TMP contains a forward slash (perhaps using bash or
6694 * tcsh), don't add a backslash, use a forward slash!
6695 * Adding 2 backslashes didn't work. */
6696 if (vim_strchr(itmp, '/') != NULL)
6697 STRCAT(itmp, "/");
6698 else
6699# endif
6700 add_pathsep(itmp);
6701
6702 /* Get an arbitrary number of up to 6 digits. When it's
6703 * unlikely that it already exists it will be faster,
6704 * otherwise it doesn't matter. The use of mkdir() avoids any
6705 * security problems because of the predictable number. */
6706 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6707
6708 /* Try up to 10000 different values until we find a name that
6709 * doesn't exist. */
6710 for (off = 0; off < 10000L; ++off)
6711 {
6712 int r;
6713#if defined(UNIX) || defined(VMS)
6714 mode_t umask_save;
6715#endif
6716
6717 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6718# ifndef EEXIST
6719 /* If mkdir() does not set errno to EEXIST, check for
6720 * existing file here. There is a race condition then,
6721 * although it's fail-safe. */
6722 if (mch_stat((char *)itmp, &st) >= 0)
6723 continue;
6724# endif
6725#if defined(UNIX) || defined(VMS)
6726 /* Make sure the umask doesn't remove the executable bit.
6727 * "repl" has been reported to use "177". */
6728 umask_save = umask(077);
6729#endif
6730 r = vim_mkdir(itmp, 0700);
6731#if defined(UNIX) || defined(VMS)
6732 (void)umask(umask_save);
6733#endif
6734 if (r == 0)
6735 {
6736 char_u *buf;
6737
6738 /* Directory was created, use this name.
6739 * Expand to full path; When using the current
6740 * directory a ":cd" would confuse us. */
6741 buf = alloc((unsigned)MAXPATHL + 1);
6742 if (buf != NULL)
6743 {
6744 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6745 == FAIL)
6746 STRCPY(buf, itmp);
6747# ifdef __EMX__
6748 if (vim_strchr(buf, '/') != NULL)
6749 STRCAT(buf, "/");
6750 else
6751# endif
6752 add_pathsep(buf);
6753 vim_tempdir = vim_strsave(buf);
6754 vim_free(buf);
6755 }
6756 break;
6757 }
6758# ifdef EEXIST
6759 /* If the mkdir() didn't fail because the file/dir exists,
6760 * we probably can't create any dir here, try another
6761 * place. */
6762 if (errno != EEXIST)
6763# endif
6764 break;
6765 }
6766 if (vim_tempdir != NULL)
6767 break;
6768 }
6769 }
6770 }
6771
6772 if (vim_tempdir != NULL)
6773 {
6774 /* There is no need to check if the file exists, because we own the
6775 * directory and nobody else creates a file in it. */
6776 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6777 return vim_strsave(itmp);
6778 }
6779
6780 return NULL;
6781
6782#else /* TEMPDIRNAMES */
6783
6784# ifdef WIN3264
6785 char szTempFile[_MAX_PATH + 1];
6786 char buf4[4];
6787 char_u *retval;
6788 char_u *p;
6789
6790 STRCPY(itmp, "");
6791 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6792 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6793 strcpy(buf4, "VIM");
6794 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6795 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6796 return NULL;
6797 /* GetTempFileName() will create the file, we don't want that */
6798 (void)DeleteFile(itmp);
6799
6800 /* Backslashes in a temp file name cause problems when filtering with
6801 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6802 * didn't set 'shellslash'. */
6803 retval = vim_strsave(itmp);
6804 if (*p_shcf == '-' || p_ssl)
6805 for (p = retval; *p; ++p)
6806 if (*p == '\\')
6807 *p = '/';
6808 return retval;
6809
6810# else /* WIN3264 */
6811
6812# ifdef USE_TMPNAM
6813 /* tmpnam() will make its own name */
6814 if (*tmpnam((char *)itmp) == NUL)
6815 return NULL;
6816# else
6817 char_u *p;
6818
6819# ifdef VMS_TEMPNAM
6820 /* mktemp() is not working on VMS. It seems to be
6821 * a do-nothing function. Therefore we use tempnam().
6822 */
6823 sprintf((char *)itmp, "VIM%c", extra_char);
6824 p = (char_u *)tempnam("tmp:", (char *)itmp);
6825 if (p != NULL)
6826 {
6827 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6828 * and VIM will then be unable to find the file later */
6829 STRCPY(itmp, p);
6830 STRCAT(itmp, ".txt");
6831 free(p);
6832 }
6833 else
6834 return NULL;
6835# else
6836 STRCPY(itmp, TEMPNAME);
6837 if ((p = vim_strchr(itmp, '?')) != NULL)
6838 *p = extra_char;
6839 if (mktemp((char *)itmp) == NULL)
6840 return NULL;
6841# endif
6842# endif
6843
6844 return vim_strsave(itmp);
6845# endif /* WIN3264 */
6846#endif /* TEMPDIRNAMES */
6847}
6848
6849#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6850/*
6851 * Convert all backslashes in fname to forward slashes in-place.
6852 */
6853 void
6854forward_slash(fname)
6855 char_u *fname;
6856{
6857 char_u *p;
6858
6859 for (p = fname; *p != NUL; ++p)
6860# ifdef FEAT_MBYTE
6861 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006862 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006863 ++p;
6864 else
6865# endif
6866 if (*p == '\\')
6867 *p = '/';
6868}
6869#endif
6870
6871
6872/*
6873 * Code for automatic commands.
6874 *
6875 * Only included when "FEAT_AUTOCMD" has been defined.
6876 */
6877
6878#if defined(FEAT_AUTOCMD) || defined(PROTO)
6879
6880/*
6881 * The autocommands are stored in a list for each event.
6882 * Autocommands for the same pattern, that are consecutive, are joined
6883 * together, to avoid having to match the pattern too often.
6884 * The result is an array of Autopat lists, which point to AutoCmd lists:
6885 *
6886 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
6887 * Autopat.cmds Autopat.cmds
6888 * | |
6889 * V V
6890 * AutoCmd.next AutoCmd.next
6891 * | |
6892 * V V
6893 * AutoCmd.next NULL
6894 * |
6895 * V
6896 * NULL
6897 *
6898 * first_autopat[1] --> Autopat.next --> NULL
6899 * Autopat.cmds
6900 * |
6901 * V
6902 * AutoCmd.next
6903 * |
6904 * V
6905 * NULL
6906 * etc.
6907 *
6908 * The order of AutoCmds is important, this is the order in which they were
6909 * defined and will have to be executed.
6910 */
6911typedef struct AutoCmd
6912{
6913 char_u *cmd; /* The command to be executed (NULL
6914 when command has been removed) */
6915 char nested; /* If autocommands nest here */
6916 char last; /* last command in list */
6917#ifdef FEAT_EVAL
6918 scid_T scriptID; /* script ID where defined */
6919#endif
6920 struct AutoCmd *next; /* Next AutoCmd in list */
6921} AutoCmd;
6922
6923typedef struct AutoPat
6924{
6925 int group; /* group ID */
6926 char_u *pat; /* pattern as typed (NULL when pattern
6927 has been removed) */
6928 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00006929 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 char allow_dirs; /* Pattern may match whole path */
6931 char last; /* last pattern for apply_autocmds() */
6932 AutoCmd *cmds; /* list of commands to do */
6933 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006934 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006935} AutoPat;
6936
6937static struct event_name
6938{
6939 char *name; /* event name */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006940 event_T event; /* event number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006941} event_names[] =
6942{
6943 {"BufAdd", EVENT_BUFADD},
6944 {"BufCreate", EVENT_BUFADD},
6945 {"BufDelete", EVENT_BUFDELETE},
6946 {"BufEnter", EVENT_BUFENTER},
6947 {"BufFilePost", EVENT_BUFFILEPOST},
6948 {"BufFilePre", EVENT_BUFFILEPRE},
6949 {"BufHidden", EVENT_BUFHIDDEN},
6950 {"BufLeave", EVENT_BUFLEAVE},
6951 {"BufNew", EVENT_BUFNEW},
6952 {"BufNewFile", EVENT_BUFNEWFILE},
6953 {"BufRead", EVENT_BUFREADPOST},
6954 {"BufReadCmd", EVENT_BUFREADCMD},
6955 {"BufReadPost", EVENT_BUFREADPOST},
6956 {"BufReadPre", EVENT_BUFREADPRE},
6957 {"BufUnload", EVENT_BUFUNLOAD},
6958 {"BufWinEnter", EVENT_BUFWINENTER},
6959 {"BufWinLeave", EVENT_BUFWINLEAVE},
6960 {"BufWipeout", EVENT_BUFWIPEOUT},
6961 {"BufWrite", EVENT_BUFWRITEPRE},
6962 {"BufWritePost", EVENT_BUFWRITEPOST},
6963 {"BufWritePre", EVENT_BUFWRITEPRE},
6964 {"BufWriteCmd", EVENT_BUFWRITECMD},
6965 {"CmdwinEnter", EVENT_CMDWINENTER},
6966 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006967 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar754b5602006-02-09 23:53:20 +00006968 {"CursorHold", EVENT_CURSORHOLD},
6969 {"CursorHoldI", EVENT_CURSORHOLDI},
6970 {"CursorMoved", EVENT_CURSORMOVED},
6971 {"CursorMovedI", EVENT_CURSORMOVEDI},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006972 {"EncodingChanged", EVENT_ENCODINGCHANGED},
6973 {"FileEncoding", EVENT_ENCODINGCHANGED},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006974 {"FileAppendPost", EVENT_FILEAPPENDPOST},
6975 {"FileAppendPre", EVENT_FILEAPPENDPRE},
6976 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
6977 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
Bram Moolenaar56718732006-03-15 22:53:57 +00006978 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006979 {"FileChangedRO", EVENT_FILECHANGEDRO},
6980 {"FileReadPost", EVENT_FILEREADPOST},
6981 {"FileReadPre", EVENT_FILEREADPRE},
6982 {"FileReadCmd", EVENT_FILEREADCMD},
6983 {"FileType", EVENT_FILETYPE},
6984 {"FileWritePost", EVENT_FILEWRITEPOST},
6985 {"FileWritePre", EVENT_FILEWRITEPRE},
6986 {"FileWriteCmd", EVENT_FILEWRITECMD},
6987 {"FilterReadPost", EVENT_FILTERREADPOST},
6988 {"FilterReadPre", EVENT_FILTERREADPRE},
6989 {"FilterWritePost", EVENT_FILTERWRITEPOST},
6990 {"FilterWritePre", EVENT_FILTERWRITEPRE},
6991 {"FocusGained", EVENT_FOCUSGAINED},
6992 {"FocusLost", EVENT_FOCUSLOST},
6993 {"FuncUndefined", EVENT_FUNCUNDEFINED},
6994 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar843ee412004-06-30 16:16:41 +00006995 {"InsertChange", EVENT_INSERTCHANGE},
6996 {"InsertEnter", EVENT_INSERTENTER},
6997 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00006998 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00006999 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
7000 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007001 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00007002 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar5c4bab02006-03-10 21:37:46 +00007003 {"ShellCmdPost", EVENT_SHELLCMDPOST},
7004 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaara2031822006-03-07 22:29:51 +00007005 {"SourcePre", EVENT_SOURCEPRE},
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00007006 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007 {"StdinReadPost", EVENT_STDINREADPOST},
7008 {"StdinReadPre", EVENT_STDINREADPRE},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00007009 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00007010 {"Syntax", EVENT_SYNTAX},
Bram Moolenaar70836c82006-02-20 21:28:49 +00007011 {"TabEnter", EVENT_TABENTER},
7012 {"TabLeave", EVENT_TABLEAVE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00007013 {"TermChanged", EVENT_TERMCHANGED},
7014 {"TermResponse", EVENT_TERMRESPONSE},
7015 {"User", EVENT_USER},
7016 {"VimEnter", EVENT_VIMENTER},
7017 {"VimLeave", EVENT_VIMLEAVE},
7018 {"VimLeavePre", EVENT_VIMLEAVEPRE},
7019 {"WinEnter", EVENT_WINENTER},
7020 {"WinLeave", EVENT_WINLEAVE},
Bram Moolenaar56718732006-03-15 22:53:57 +00007021 {"VimResized", EVENT_VIMRESIZED},
Bram Moolenaar754b5602006-02-09 23:53:20 +00007022 {NULL, (event_T)0}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007023};
7024
7025static AutoPat *first_autopat[NUM_EVENTS] =
7026{
7027 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7028 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7029 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7030 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007031 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7032 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033};
7034
7035/*
7036 * struct used to keep status while executing autocommands for an event.
7037 */
7038typedef struct AutoPatCmd
7039{
7040 AutoPat *curpat; /* next AutoPat to examine */
7041 AutoCmd *nextcmd; /* next AutoCmd to execute */
7042 int group; /* group being used */
7043 char_u *fname; /* fname to match with */
7044 char_u *sfname; /* sfname to match with */
7045 char_u *tail; /* tail of fname */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007046 event_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007047 int arg_bufnr; /* initially equal to <abuf>, set to zero when
7048 buf is deleted */
7049 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00007050} AutoPatCmd;
7051
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007052static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007053
Bram Moolenaar071d4272004-06-13 20:20:40 +00007054/*
7055 * augroups stores a list of autocmd group names.
7056 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00007057static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00007058#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
7059
7060/*
7061 * The ID of the current group. Group 0 is the default one.
7062 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007063static int current_augroup = AUGROUP_DEFAULT;
7064
7065static int au_need_clean = FALSE; /* need to delete marked patterns */
7066
Bram Moolenaar754b5602006-02-09 23:53:20 +00007067static void show_autocmd __ARGS((AutoPat *ap, event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007068static void au_remove_pat __ARGS((AutoPat *ap));
7069static void au_remove_cmds __ARGS((AutoPat *ap));
7070static void au_cleanup __ARGS((void));
7071static int au_new_group __ARGS((char_u *name));
7072static void au_del_group __ARGS((char_u *name));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007073static event_T event_name2nr __ARGS((char_u *start, char_u **end));
7074static char_u *event_nr2name __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007075static char_u *find_end_event __ARGS((char_u *arg, int have_group));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007076static int event_ignored __ARGS((event_T event));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007077static int au_get_grouparg __ARGS((char_u **argp));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007078static 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 +00007079static char_u *getnextac __ARGS((int c, void *cookie, int indent));
Bram Moolenaar754b5602006-02-09 23:53:20 +00007080static 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 +00007081static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
7082
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007083
Bram Moolenaar754b5602006-02-09 23:53:20 +00007084static event_T last_event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085static int last_group;
7086
7087/*
7088 * Show the autocommands for one AutoPat.
7089 */
7090 static void
7091show_autocmd(ap, event)
7092 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007093 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007094{
7095 AutoCmd *ac;
7096
7097 /* Check for "got_int" (here and at various places below), which is set
7098 * when "q" has been hit for the "--more--" prompt */
7099 if (got_int)
7100 return;
7101 if (ap->pat == NULL) /* pattern has been removed */
7102 return;
7103
7104 msg_putchar('\n');
7105 if (got_int)
7106 return;
7107 if (event != last_event || ap->group != last_group)
7108 {
7109 if (ap->group != AUGROUP_DEFAULT)
7110 {
7111 if (AUGROUP_NAME(ap->group) == NULL)
7112 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7113 else
7114 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7115 msg_puts((char_u *)" ");
7116 }
7117 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7118 last_event = event;
7119 last_group = ap->group;
7120 msg_putchar('\n');
7121 if (got_int)
7122 return;
7123 }
7124 msg_col = 4;
7125 msg_outtrans(ap->pat);
7126
7127 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7128 {
7129 if (ac->cmd != NULL) /* skip removed commands */
7130 {
7131 if (msg_col >= 14)
7132 msg_putchar('\n');
7133 msg_col = 14;
7134 if (got_int)
7135 return;
7136 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007137#ifdef FEAT_EVAL
7138 if (p_verbose > 0)
7139 last_set_msg(ac->scriptID);
7140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 if (got_int)
7142 return;
7143 if (ac->next != NULL)
7144 {
7145 msg_putchar('\n');
7146 if (got_int)
7147 return;
7148 }
7149 }
7150 }
7151}
7152
7153/*
7154 * Mark an autocommand pattern for deletion.
7155 */
7156 static void
7157au_remove_pat(ap)
7158 AutoPat *ap;
7159{
7160 vim_free(ap->pat);
7161 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007162 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007163 au_need_clean = TRUE;
7164}
7165
7166/*
7167 * Mark all commands for a pattern for deletion.
7168 */
7169 static void
7170au_remove_cmds(ap)
7171 AutoPat *ap;
7172{
7173 AutoCmd *ac;
7174
7175 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7176 {
7177 vim_free(ac->cmd);
7178 ac->cmd = NULL;
7179 }
7180 au_need_clean = TRUE;
7181}
7182
7183/*
7184 * Cleanup autocommands and patterns that have been deleted.
7185 * This is only done when not executing autocommands.
7186 */
7187 static void
7188au_cleanup()
7189{
7190 AutoPat *ap, **prev_ap;
7191 AutoCmd *ac, **prev_ac;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007192 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007193
7194 if (autocmd_busy || !au_need_clean)
7195 return;
7196
7197 /* loop over all events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007198 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7199 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007200 {
7201 /* loop over all autocommand patterns */
7202 prev_ap = &(first_autopat[(int)event]);
7203 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7204 {
7205 /* loop over all commands for this pattern */
7206 prev_ac = &(ap->cmds);
7207 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7208 {
7209 /* remove the command if the pattern is to be deleted or when
7210 * the command has been marked for deletion */
7211 if (ap->pat == NULL || ac->cmd == NULL)
7212 {
7213 *prev_ac = ac->next;
7214 vim_free(ac->cmd);
7215 vim_free(ac);
7216 }
7217 else
7218 prev_ac = &(ac->next);
7219 }
7220
7221 /* remove the pattern if it has been marked for deletion */
7222 if (ap->pat == NULL)
7223 {
7224 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007225 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007226 vim_free(ap);
7227 }
7228 else
7229 prev_ap = &(ap->next);
7230 }
7231 }
7232
7233 au_need_clean = FALSE;
7234}
7235
7236/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007237 * Called when buffer is freed, to remove/invalidate related buffer-local
7238 * autocmds.
7239 */
7240 void
7241aubuflocal_remove(buf)
7242 buf_T *buf;
7243{
7244 AutoPat *ap;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007245 event_T event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007246 AutoPatCmd *apc;
7247
7248 /* invalidate currently executing autocommands */
7249 for (apc = active_apc_list; apc; apc = apc->next)
7250 if (buf->b_fnum == apc->arg_bufnr)
7251 apc->arg_bufnr = 0;
7252
7253 /* invalidate buflocals looping through events */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007254 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7255 event = (event_T)((int)event + 1))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007256 /* loop over all autocommand patterns */
7257 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7258 if (ap->buflocal_nr == buf->b_fnum)
7259 {
7260 au_remove_pat(ap);
7261 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007262 {
7263 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007264 smsg((char_u *)
7265 _("auto-removing autocommand: %s <buffer=%d>"),
7266 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007267 verbose_leave();
7268 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007269 }
7270 au_cleanup();
7271}
7272
7273/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007274 * Add an autocmd group name.
7275 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7276 */
7277 static int
7278au_new_group(name)
7279 char_u *name;
7280{
7281 int i;
7282
7283 i = au_find_group(name);
7284 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7285 {
7286 /* First try using a free entry. */
7287 for (i = 0; i < augroups.ga_len; ++i)
7288 if (AUGROUP_NAME(i) == NULL)
7289 break;
7290 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7291 return AUGROUP_ERROR;
7292
7293 AUGROUP_NAME(i) = vim_strsave(name);
7294 if (AUGROUP_NAME(i) == NULL)
7295 return AUGROUP_ERROR;
7296 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007297 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007298 }
7299
7300 return i;
7301}
7302
7303 static void
7304au_del_group(name)
7305 char_u *name;
7306{
7307 int i;
7308
7309 i = au_find_group(name);
7310 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7311 EMSG2(_("E367: No such group: \"%s\""), name);
7312 else
7313 {
7314 vim_free(AUGROUP_NAME(i));
7315 AUGROUP_NAME(i) = NULL;
7316 }
7317}
7318
7319/*
7320 * Find the ID of an autocmd group name.
7321 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7322 */
7323 static int
7324au_find_group(name)
7325 char_u *name;
7326{
7327 int i;
7328
7329 for (i = 0; i < augroups.ga_len; ++i)
7330 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7331 return i;
7332 return AUGROUP_ERROR;
7333}
7334
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007335/*
7336 * Return TRUE if augroup "name" exists.
7337 */
7338 int
7339au_has_group(name)
7340 char_u *name;
7341{
7342 return au_find_group(name) != AUGROUP_ERROR;
7343}
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007344
Bram Moolenaar071d4272004-06-13 20:20:40 +00007345/*
7346 * ":augroup {name}".
7347 */
7348 void
7349do_augroup(arg, del_group)
7350 char_u *arg;
7351 int del_group;
7352{
7353 int i;
7354
7355 if (del_group)
7356 {
7357 if (*arg == NUL)
7358 EMSG(_(e_argreq));
7359 else
7360 au_del_group(arg);
7361 }
7362 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7363 current_augroup = AUGROUP_DEFAULT;
7364 else if (*arg) /* ":aug xxx": switch to group xxx */
7365 {
7366 i = au_new_group(arg);
7367 if (i != AUGROUP_ERROR)
7368 current_augroup = i;
7369 }
7370 else /* ":aug": list the group names */
7371 {
7372 msg_start();
7373 for (i = 0; i < augroups.ga_len; ++i)
7374 {
7375 if (AUGROUP_NAME(i) != NULL)
7376 {
7377 msg_puts(AUGROUP_NAME(i));
7378 msg_puts((char_u *)" ");
7379 }
7380 }
7381 msg_clr_eos();
7382 msg_end();
7383 }
7384}
7385
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007386#if defined(EXITFREE) || defined(PROTO)
7387 void
7388free_all_autocmds()
7389{
7390 for (current_augroup = -1; current_augroup < augroups.ga_len;
7391 ++current_augroup)
7392 do_autocmd((char_u *)"", TRUE);
7393 ga_clear_strings(&augroups);
7394}
7395#endif
7396
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397/*
7398 * Return the event number for event name "start".
7399 * Return NUM_EVENTS if the event name was not found.
7400 * Return a pointer to the next event name in "end".
7401 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007402 static event_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00007403event_name2nr(start, end)
7404 char_u *start;
7405 char_u **end;
7406{
7407 char_u *p;
7408 int i;
7409 int len;
7410
7411 /* the event name ends with end of line, a blank or a comma */
7412 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7413 ;
7414 for (i = 0; event_names[i].name != NULL; ++i)
7415 {
7416 len = (int)STRLEN(event_names[i].name);
7417 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7418 break;
7419 }
7420 if (*p == ',')
7421 ++p;
7422 *end = p;
7423 if (event_names[i].name == NULL)
7424 return NUM_EVENTS;
7425 return event_names[i].event;
7426}
7427
7428/*
7429 * Return the name for event "event".
7430 */
7431 static char_u *
7432event_nr2name(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007433 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007434{
7435 int i;
7436
7437 for (i = 0; event_names[i].name != NULL; ++i)
7438 if (event_names[i].event == event)
7439 return (char_u *)event_names[i].name;
7440 return (char_u *)"Unknown";
7441}
7442
7443/*
7444 * Scan over the events. "*" stands for all events.
7445 */
7446 static char_u *
7447find_end_event(arg, have_group)
7448 char_u *arg;
7449 int have_group; /* TRUE when group name was found */
7450{
7451 char_u *pat;
7452 char_u *p;
7453
7454 if (*arg == '*')
7455 {
7456 if (arg[1] && !vim_iswhite(arg[1]))
7457 {
7458 EMSG2(_("E215: Illegal character after *: %s"), arg);
7459 return NULL;
7460 }
7461 pat = arg + 1;
7462 }
7463 else
7464 {
7465 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7466 {
7467 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7468 {
7469 if (have_group)
7470 EMSG2(_("E216: No such event: %s"), pat);
7471 else
7472 EMSG2(_("E216: No such group or event: %s"), pat);
7473 return NULL;
7474 }
7475 }
7476 }
7477 return pat;
7478}
7479
7480/*
7481 * Return TRUE if "event" is included in 'eventignore'.
7482 */
7483 static int
7484event_ignored(event)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007485 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007486{
7487 char_u *p = p_ei;
7488
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007489 while (*p != NUL)
7490 {
7491 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7492 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007493 if (event_name2nr(p, &p) == event)
7494 return TRUE;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007495 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007496
7497 return FALSE;
7498}
7499
7500/*
7501 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7502 */
7503 int
7504check_ei()
7505{
7506 char_u *p = p_ei;
7507
Bram Moolenaar071d4272004-06-13 20:20:40 +00007508 while (*p)
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007509 {
7510 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
7511 {
7512 p += 3;
7513 if (*p == ',')
7514 ++p;
7515 }
7516 else if (event_name2nr(p, &p) == NUM_EVENTS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007517 return FAIL;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00007518 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007519
7520 return OK;
7521}
7522
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007523# if defined(FEAT_SYN_HL) || defined(PROTO)
7524
7525/*
7526 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7527 * buffer loaded into the window. "what" must start with a comma.
7528 * Returns the old value of 'eventignore' in allocated memory.
7529 */
7530 char_u *
7531au_event_disable(what)
7532 char *what;
7533{
7534 char_u *new_ei;
7535 char_u *save_ei;
7536
7537 save_ei = vim_strsave(p_ei);
7538 if (save_ei != NULL)
7539 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007540 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007541 if (new_ei != NULL)
7542 {
7543 STRCAT(new_ei, what);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007544 set_string_option_direct((char_u *)"ei", -1, new_ei,
7545 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007546 vim_free(new_ei);
7547 }
7548 }
7549 return save_ei;
7550}
7551
7552 void
7553au_event_restore(old_ei)
7554 char_u *old_ei;
7555{
7556 if (old_ei != NULL)
7557 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00007558 set_string_option_direct((char_u *)"ei", -1, old_ei,
7559 OPT_FREE, SID_NONE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007560 vim_free(old_ei);
7561 }
7562}
7563# endif /* FEAT_SYN_HL */
7564
Bram Moolenaar071d4272004-06-13 20:20:40 +00007565/*
7566 * do_autocmd() -- implements the :autocmd command. Can be used in the
7567 * following ways:
7568 *
7569 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7570 * will be automatically executed for <event>
7571 * when editing a file matching <pat>, in
7572 * the current group.
7573 * :autocmd <event> <pat> Show the auto-commands associated with
7574 * <event> and <pat>.
7575 * :autocmd <event> Show the auto-commands associated with
7576 * <event>.
7577 * :autocmd Show all auto-commands.
7578 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7579 * <event> and <pat>, and add the command
7580 * <cmd>, for the current group.
7581 * :autocmd! <event> <pat> Remove all auto-commands associated with
7582 * <event> and <pat> for the current group.
7583 * :autocmd! <event> Remove all auto-commands associated with
7584 * <event> for the current group.
7585 * :autocmd! Remove ALL auto-commands for the current
7586 * group.
7587 *
7588 * Multiple events and patterns may be given separated by commas. Here are
7589 * some examples:
7590 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7591 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7592 *
7593 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007594 *
7595 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007596 */
7597 void
7598do_autocmd(arg, forceit)
7599 char_u *arg;
7600 int forceit;
7601{
7602 char_u *pat;
7603 char_u *envpat = NULL;
7604 char_u *cmd;
Bram Moolenaar754b5602006-02-09 23:53:20 +00007605 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007606 int need_free = FALSE;
7607 int nested = FALSE;
7608 int group;
7609
7610 /*
7611 * Check for a legal group name. If not, use AUGROUP_ALL.
7612 */
7613 group = au_get_grouparg(&arg);
7614 if (arg == NULL) /* out of memory */
7615 return;
7616
7617 /*
7618 * Scan over the events.
7619 * If we find an illegal name, return here, don't do anything.
7620 */
7621 pat = find_end_event(arg, group != AUGROUP_ALL);
7622 if (pat == NULL)
7623 return;
7624
7625 /*
7626 * Scan over the pattern. Put a NUL at the end.
7627 */
7628 pat = skipwhite(pat);
7629 cmd = pat;
7630 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7631 cmd++;
7632 if (*cmd)
7633 *cmd++ = NUL;
7634
7635 /* Expand environment variables in the pattern. Set 'shellslash', we want
7636 * forward slashes here. */
7637 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7638 {
7639#ifdef BACKSLASH_IN_FILENAME
7640 int p_ssl_save = p_ssl;
7641
7642 p_ssl = TRUE;
7643#endif
7644 envpat = expand_env_save(pat);
7645#ifdef BACKSLASH_IN_FILENAME
7646 p_ssl = p_ssl_save;
7647#endif
7648 if (envpat != NULL)
7649 pat = envpat;
7650 }
7651
7652 /*
7653 * Check for "nested" flag.
7654 */
7655 cmd = skipwhite(cmd);
7656 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7657 {
7658 nested = TRUE;
7659 cmd = skipwhite(cmd + 6);
7660 }
7661
7662 /*
7663 * Find the start of the commands.
7664 * Expand <sfile> in it.
7665 */
7666 if (*cmd != NUL)
7667 {
7668 cmd = expand_sfile(cmd);
7669 if (cmd == NULL) /* some error */
7670 return;
7671 need_free = TRUE;
7672 }
7673
7674 /*
7675 * Print header when showing autocommands.
7676 */
7677 if (!forceit && *cmd == NUL)
7678 {
7679 /* Highlight title */
7680 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7681 }
7682
7683 /*
7684 * Loop over the events.
7685 */
Bram Moolenaar754b5602006-02-09 23:53:20 +00007686 last_event = (event_T)-1; /* for listing the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007687 last_group = AUGROUP_ERROR; /* for listing the group name */
7688 if (*arg == '*' || *arg == NUL)
7689 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00007690 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
7691 event = (event_T)((int)event + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007692 if (do_autocmd_event(event, pat,
7693 nested, cmd, forceit, group) == FAIL)
7694 break;
7695 }
7696 else
7697 {
7698 while (*arg && !vim_iswhite(*arg))
7699 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7700 nested, cmd, forceit, group) == FAIL)
7701 break;
7702 }
7703
7704 if (need_free)
7705 vim_free(cmd);
7706 vim_free(envpat);
7707}
7708
7709/*
7710 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7711 * The "argp" argument is advanced to the following argument.
7712 *
7713 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7714 */
7715 static int
7716au_get_grouparg(argp)
7717 char_u **argp;
7718{
7719 char_u *group_name;
7720 char_u *p;
7721 char_u *arg = *argp;
7722 int group = AUGROUP_ALL;
7723
7724 p = skiptowhite(arg);
7725 if (p > arg)
7726 {
7727 group_name = vim_strnsave(arg, (int)(p - arg));
7728 if (group_name == NULL) /* out of memory */
7729 return AUGROUP_ERROR;
7730 group = au_find_group(group_name);
7731 if (group == AUGROUP_ERROR)
7732 group = AUGROUP_ALL; /* no match, use all groups */
7733 else
7734 *argp = skipwhite(p); /* match, skip over group name */
7735 vim_free(group_name);
7736 }
7737 return group;
7738}
7739
7740/*
7741 * do_autocmd() for one event.
7742 * If *pat == NUL do for all patterns.
7743 * If *cmd == NUL show entries.
7744 * If forceit == TRUE delete entries.
7745 * If group is not AUGROUP_ALL, only use this group.
7746 */
7747 static int
7748do_autocmd_event(event, pat, nested, cmd, forceit, group)
Bram Moolenaar754b5602006-02-09 23:53:20 +00007749 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007750 char_u *pat;
7751 int nested;
7752 char_u *cmd;
7753 int forceit;
7754 int group;
7755{
7756 AutoPat *ap;
7757 AutoPat **prev_ap;
7758 AutoCmd *ac;
7759 AutoCmd **prev_ac;
7760 int brace_level;
7761 char_u *endpat;
7762 int findgroup;
7763 int allgroups;
7764 int patlen;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007765 int is_buflocal;
7766 int buflocal_nr;
7767 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768
7769 if (group == AUGROUP_ALL)
7770 findgroup = current_augroup;
7771 else
7772 findgroup = group;
7773 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7774
7775 /*
7776 * Show or delete all patterns for an event.
7777 */
7778 if (*pat == NUL)
7779 {
7780 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7781 {
7782 if (forceit) /* delete the AutoPat, if it's in the current group */
7783 {
7784 if (ap->group == findgroup)
7785 au_remove_pat(ap);
7786 }
7787 else if (group == AUGROUP_ALL || ap->group == group)
7788 show_autocmd(ap, event);
7789 }
7790 }
7791
7792 /*
7793 * Loop through all the specified patterns.
7794 */
7795 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7796 {
7797 /*
7798 * Find end of the pattern.
7799 * Watch out for a comma in braces, like "*.\{obj,o\}".
7800 */
7801 brace_level = 0;
7802 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7803 || endpat[-1] == '\\'); ++endpat)
7804 {
7805 if (*endpat == '{')
7806 brace_level++;
7807 else if (*endpat == '}')
7808 brace_level--;
7809 }
7810 if (pat == endpat) /* ignore single comma */
7811 continue;
7812 patlen = (int)(endpat - pat);
7813
7814 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007815 * detect special <buflocal[=X]> buffer-local patterns
7816 */
7817 is_buflocal = FALSE;
7818 buflocal_nr = 0;
7819
7820 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7821 && pat[patlen - 1] == '>')
7822 {
7823 /* Error will be printed only for addition. printing and removing
7824 * will proceed silently. */
7825 is_buflocal = TRUE;
7826 if (patlen == 8)
7827 buflocal_nr = curbuf->b_fnum;
7828 else if (patlen > 9 && pat[7] == '=')
7829 {
7830 /* <buffer=abuf> */
7831 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7832 buflocal_nr = autocmd_bufnr;
7833 /* <buffer=123> */
7834 else if (skipdigits(pat + 8) == pat + patlen - 1)
7835 buflocal_nr = atoi((char *)pat + 8);
7836 }
7837 }
7838
7839 if (is_buflocal)
7840 {
7841 /* normalize pat into standard "<buffer>#N" form */
7842 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7843 pat = buflocal_pat; /* can modify pat and patlen */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00007844 patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007845 }
7846
7847 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007848 * Find AutoPat entries with this pattern.
7849 */
7850 prev_ap = &first_autopat[(int)event];
7851 while ((ap = *prev_ap) != NULL)
7852 {
7853 if (ap->pat != NULL)
7854 {
7855 /* Accept a pattern when:
7856 * - a group was specified and it's that group, or a group was
7857 * not specified and it's the current group, or a group was
7858 * not specified and we are listing
7859 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007860 * - the pattern matches.
7861 * For <buffer[=X]>, this condition works because we normalize
7862 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007863 */
7864 if ((allgroups || ap->group == findgroup)
7865 && ap->patlen == patlen
7866 && STRNCMP(pat, ap->pat, patlen) == 0)
7867 {
7868 /*
7869 * Remove existing autocommands.
7870 * If adding any new autocmd's for this AutoPat, don't
7871 * delete the pattern from the autopat list, append to
7872 * this list.
7873 */
7874 if (forceit)
7875 {
7876 if (*cmd != NUL && ap->next == NULL)
7877 {
7878 au_remove_cmds(ap);
7879 break;
7880 }
7881 au_remove_pat(ap);
7882 }
7883
7884 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007885 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007886 */
7887 else if (*cmd == NUL)
7888 show_autocmd(ap, event);
7889
7890 /*
7891 * Add autocmd to this autopat, if it's the last one.
7892 */
7893 else if (ap->next == NULL)
7894 break;
7895 }
7896 }
7897 prev_ap = &ap->next;
7898 }
7899
7900 /*
7901 * Add a new command.
7902 */
7903 if (*cmd != NUL)
7904 {
7905 /*
7906 * If the pattern we want to add a command to does appear at the
7907 * end of the list (or not is not in the list at all), add the
7908 * pattern at the end of the list.
7909 */
7910 if (ap == NULL)
7911 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007912 /* refuse to add buffer-local ap if buffer number is invalid */
7913 if (is_buflocal && (buflocal_nr == 0
7914 || buflist_findnr(buflocal_nr) == NULL))
7915 {
7916 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7917 buflocal_nr);
7918 return FAIL;
7919 }
7920
Bram Moolenaar071d4272004-06-13 20:20:40 +00007921 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7922 if (ap == NULL)
7923 return FAIL;
7924 ap->pat = vim_strnsave(pat, patlen);
7925 ap->patlen = patlen;
7926 if (ap->pat == NULL)
7927 {
7928 vim_free(ap);
7929 return FAIL;
7930 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007931
7932 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007933 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007934 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007935 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007936 }
7937 else
7938 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007939 char_u *reg_pat;
7940
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007941 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007942 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007943 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007944 if (reg_pat != NULL)
7945 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007946 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007947 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007948 {
7949 vim_free(ap->pat);
7950 vim_free(ap);
7951 return FAIL;
7952 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007953 }
7954 ap->cmds = NULL;
7955 *prev_ap = ap;
7956 ap->next = NULL;
7957 if (group == AUGROUP_ALL)
7958 ap->group = current_augroup;
7959 else
7960 ap->group = group;
7961 }
7962
7963 /*
7964 * Add the autocmd at the end of the AutoCmd list.
7965 */
7966 prev_ac = &(ap->cmds);
7967 while ((ac = *prev_ac) != NULL)
7968 prev_ac = &ac->next;
7969 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7970 if (ac == NULL)
7971 return FAIL;
7972 ac->cmd = vim_strsave(cmd);
7973#ifdef FEAT_EVAL
7974 ac->scriptID = current_SID;
7975#endif
7976 if (ac->cmd == NULL)
7977 {
7978 vim_free(ac);
7979 return FAIL;
7980 }
7981 ac->next = NULL;
7982 *prev_ac = ac;
7983 ac->nested = nested;
7984 }
7985 }
7986
7987 au_cleanup(); /* may really delete removed patterns/commands now */
7988 return OK;
7989}
7990
7991/*
7992 * Implementation of ":doautocmd [group] event [fname]".
7993 * Return OK for success, FAIL for failure;
7994 */
7995 int
7996do_doautocmd(arg, do_msg)
7997 char_u *arg;
7998 int do_msg; /* give message for no matching autocmds? */
7999{
8000 char_u *fname;
8001 int nothing_done = TRUE;
8002 int group;
8003
8004 /*
8005 * Check for a legal group name. If not, use AUGROUP_ALL.
8006 */
8007 group = au_get_grouparg(&arg);
8008 if (arg == NULL) /* out of memory */
8009 return FAIL;
8010
8011 if (*arg == '*')
8012 {
8013 EMSG(_("E217: Can't execute autocommands for ALL events"));
8014 return FAIL;
8015 }
8016
8017 /*
8018 * Scan over the events.
8019 * If we find an illegal name, return here, don't do anything.
8020 */
8021 fname = find_end_event(arg, group != AUGROUP_ALL);
8022 if (fname == NULL)
8023 return FAIL;
8024
8025 fname = skipwhite(fname);
8026
8027 /*
8028 * Loop over the events.
8029 */
8030 while (*arg && !vim_iswhite(*arg))
8031 if (apply_autocmds_group(event_name2nr(arg, &arg),
8032 fname, NULL, TRUE, group, curbuf, NULL))
8033 nothing_done = FALSE;
8034
8035 if (nothing_done && do_msg)
8036 MSG(_("No matching autocommands"));
8037
8038#ifdef FEAT_EVAL
8039 return aborting() ? FAIL : OK;
8040#else
8041 return OK;
8042#endif
8043}
8044
8045/*
8046 * ":doautoall": execute autocommands for each loaded buffer.
8047 */
8048 void
8049ex_doautoall(eap)
8050 exarg_T *eap;
8051{
8052 int retval;
8053 aco_save_T aco;
8054 buf_T *buf;
8055
8056 /*
8057 * This is a bit tricky: For some commands curwin->w_buffer needs to be
8058 * equal to curbuf, but for some buffers there may not be a window.
8059 * So we change the buffer for the current window for a moment. This
8060 * gives problems when the autocommands make changes to the list of
8061 * buffers or windows...
8062 */
8063 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8064 {
8065 if (curbuf->b_ml.ml_mfp != NULL)
8066 {
8067 /* find a window for this buffer and save some values */
8068 aucmd_prepbuf(&aco, buf);
8069
8070 /* execute the autocommands for this buffer */
8071 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00008072 do_modelines(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008073
8074 /* restore the current window */
8075 aucmd_restbuf(&aco);
8076
8077 /* stop if there is some error or buffer was deleted */
8078 if (retval == FAIL || !buf_valid(buf))
8079 break;
8080 }
8081 }
8082
8083 check_cursor(); /* just in case lines got deleted */
8084}
8085
8086/*
8087 * Prepare for executing autocommands for (hidden) buffer "buf".
8088 * Search a window for the current buffer. Save the cursor position and
8089 * screen offset.
8090 * Set "curbuf" and "curwin" to match "buf".
8091 */
8092 void
8093aucmd_prepbuf(aco, buf)
8094 aco_save_T *aco; /* structure to save values in */
8095 buf_T *buf; /* new curbuf */
8096{
8097 win_T *win;
8098
8099 aco->new_curbuf = buf;
8100
8101 /* Find a window that is for the new buffer */
8102 if (buf == curbuf) /* be quick when buf is curbuf */
8103 win = curwin;
8104 else
8105#ifdef FEAT_WINDOWS
8106 for (win = firstwin; win != NULL; win = win->w_next)
8107 if (win->w_buffer == buf)
8108 break;
8109#else
8110 win = NULL;
8111#endif
8112
8113 /*
8114 * Prefer to use an existing window for the buffer, it has the least side
8115 * effects (esp. if "buf" is curbuf).
8116 * Otherwise, use curwin for "buf". It might make some items in the
8117 * window invalid. At least save the cursor and topline.
8118 */
8119 if (win != NULL)
8120 {
8121 /* there is a window for "buf", make it the curwin */
8122 aco->save_curwin = curwin;
8123 curwin = win;
8124 aco->save_buf = win->w_buffer;
8125 aco->new_curwin = win;
8126 }
8127 else
8128 {
8129 /* there is no window for "buf", use curwin */
8130 aco->save_curwin = NULL;
8131 aco->save_buf = curbuf;
8132 --curbuf->b_nwindows;
8133 curwin->w_buffer = buf;
8134 ++buf->b_nwindows;
8135
8136 /* save cursor and topline, set them to safe values */
8137 aco->save_cursor = curwin->w_cursor;
8138 curwin->w_cursor.lnum = 1;
8139 curwin->w_cursor.col = 0;
8140 aco->save_topline = curwin->w_topline;
8141 curwin->w_topline = 1;
8142#ifdef FEAT_DIFF
8143 aco->save_topfill = curwin->w_topfill;
8144 curwin->w_topfill = 0;
8145#endif
8146 }
8147
8148 curbuf = buf;
8149}
8150
8151/*
8152 * Cleanup after executing autocommands for a (hidden) buffer.
8153 * Restore the window as it was (if possible).
8154 */
8155 void
8156aucmd_restbuf(aco)
8157 aco_save_T *aco; /* structure holding saved values */
8158{
8159 if (aco->save_curwin != NULL)
8160 {
8161 /* restore curwin */
8162#ifdef FEAT_WINDOWS
8163 if (win_valid(aco->save_curwin))
8164#endif
8165 {
8166 /* restore the buffer which was previously edited by curwin, if
8167 * it's still the same window and it's valid */
8168 if (curwin == aco->new_curwin
8169 && buf_valid(aco->save_buf)
8170 && aco->save_buf->b_ml.ml_mfp != NULL)
8171 {
8172 --curbuf->b_nwindows;
8173 curbuf = aco->save_buf;
8174 curwin->w_buffer = curbuf;
8175 ++curbuf->b_nwindows;
8176 }
8177
8178 curwin = aco->save_curwin;
8179 curbuf = curwin->w_buffer;
8180 }
8181 }
8182 else
8183 {
8184 /* restore buffer for curwin if it still exists and is loaded */
8185 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8186 {
8187 --curbuf->b_nwindows;
8188 curbuf = aco->save_buf;
8189 curwin->w_buffer = curbuf;
8190 ++curbuf->b_nwindows;
8191 curwin->w_cursor = aco->save_cursor;
8192 check_cursor();
8193 /* check topline < line_count, in case lines got deleted */
8194 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8195 {
8196 curwin->w_topline = aco->save_topline;
8197#ifdef FEAT_DIFF
8198 curwin->w_topfill = aco->save_topfill;
8199#endif
8200 }
8201 else
8202 {
8203 curwin->w_topline = curbuf->b_ml.ml_line_count;
8204#ifdef FEAT_DIFF
8205 curwin->w_topfill = 0;
8206#endif
8207 }
8208 }
8209 }
8210}
8211
8212static int autocmd_nested = FALSE;
8213
8214/*
8215 * Execute autocommands for "event" and file name "fname".
8216 * Return TRUE if some commands were executed.
8217 */
8218 int
8219apply_autocmds(event, fname, fname_io, force, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008220 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008221 char_u *fname; /* NULL or empty means use actual file name */
8222 char_u *fname_io; /* fname to use for <afile> on cmdline */
8223 int force; /* when TRUE, ignore autocmd_busy */
8224 buf_T *buf; /* buffer for <abuf> */
8225{
8226 return apply_autocmds_group(event, fname, fname_io, force,
8227 AUGROUP_ALL, buf, NULL);
8228}
8229
8230/*
8231 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8232 * setting v:filearg.
8233 */
8234 static int
8235apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008236 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008237 char_u *fname;
8238 char_u *fname_io;
8239 int force;
8240 buf_T *buf;
8241 exarg_T *eap;
8242{
8243 return apply_autocmds_group(event, fname, fname_io, force,
8244 AUGROUP_ALL, buf, eap);
8245}
8246
8247/*
8248 * Like apply_autocmds(), but handles the caller's retval. If the script
8249 * processing is being aborted or if retval is FAIL when inside a try
8250 * conditional, no autocommands are executed. If otherwise the autocommands
8251 * cause the script to be aborted, retval is set to FAIL.
8252 */
8253 int
8254apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008255 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008256 char_u *fname; /* NULL or empty means use actual file name */
8257 char_u *fname_io; /* fname to use for <afile> on cmdline */
8258 int force; /* when TRUE, ignore autocmd_busy */
8259 buf_T *buf; /* buffer for <abuf> */
8260 int *retval; /* pointer to caller's retval */
8261{
8262 int did_cmd;
8263
Bram Moolenaar1e015462005-09-25 22:16:38 +00008264#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008265 if (should_abort(*retval))
8266 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008267#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008268
8269 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8270 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008271 if (did_cmd
8272#ifdef FEAT_EVAL
8273 && aborting()
8274#endif
8275 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008276 *retval = FAIL;
8277 return did_cmd;
8278}
8279
Bram Moolenaard35f9712005-12-18 22:02:33 +00008280/*
8281 * Return TRUE when there is a CursorHold autocommand defined.
8282 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008283 int
8284has_cursorhold()
8285{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008286 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
8287 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008288}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008289
8290/*
8291 * Return TRUE if the CursorHold event can be triggered.
8292 */
8293 int
8294trigger_cursorhold()
8295{
Bram Moolenaar754b5602006-02-09 23:53:20 +00008296 int state;
8297
8298 if (!did_cursorhold && has_cursorhold() && !Recording)
8299 {
8300 state = get_real_state();
8301 if (state == NORMAL_BUSY || (state & INSERT) != 0)
8302 return TRUE;
8303 }
8304 return FALSE;
Bram Moolenaard35f9712005-12-18 22:02:33 +00008305}
Bram Moolenaar754b5602006-02-09 23:53:20 +00008306
8307/*
8308 * Return TRUE when there is a CursorMoved autocommand defined.
8309 */
8310 int
8311has_cursormoved()
8312{
8313 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
8314}
8315
8316/*
8317 * Return TRUE when there is a CursorMovedI autocommand defined.
8318 */
8319 int
8320has_cursormovedI()
8321{
8322 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
8323}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008324
8325 static int
8326apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008327 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008328 char_u *fname; /* NULL or empty means use actual file name */
8329 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8330 use fname */
8331 int force; /* when TRUE, ignore autocmd_busy */
8332 int group; /* group ID, or AUGROUP_ALL */
8333 buf_T *buf; /* buffer for <abuf> */
8334 exarg_T *eap; /* command arguments */
8335{
8336 char_u *sfname = NULL; /* short file name */
8337 char_u *tail;
8338 int save_changed;
8339 buf_T *old_curbuf;
8340 int retval = FALSE;
8341 char_u *save_sourcing_name;
8342 linenr_T save_sourcing_lnum;
8343 char_u *save_autocmd_fname;
8344 int save_autocmd_bufnr;
8345 char_u *save_autocmd_match;
8346 int save_autocmd_busy;
8347 int save_autocmd_nested;
8348 static int nesting = 0;
8349 AutoPatCmd patcmd;
8350 AutoPat *ap;
8351#ifdef FEAT_EVAL
8352 scid_T save_current_SID;
8353 void *save_funccalp;
8354 char_u *save_cmdarg;
8355 long save_cmdbang;
8356#endif
8357 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008358#ifdef FEAT_PROFILE
8359 proftime_T wait_time;
8360#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008361
8362 /*
8363 * Quickly return if there are no autocommands for this event or
8364 * autocommands are blocked.
8365 */
8366 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008367 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008368
8369 /*
8370 * When autocommands are busy, new autocommands are only executed when
8371 * explicitly enabled with the "nested" flag.
8372 */
8373 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008374 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008375
8376#ifdef FEAT_EVAL
8377 /*
8378 * Quickly return when immdediately aborting on error, or when an interrupt
8379 * occurred or an exception was thrown but not caught.
8380 */
8381 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008382 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008383#endif
8384
8385 /*
8386 * FileChangedShell never nests, because it can create an endless loop.
8387 */
Bram Moolenaar56718732006-03-15 22:53:57 +00008388 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
8389 || event == EVENT_FILECHANGEDSHELLPOST))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008390 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008391
8392 /*
8393 * Ignore events in 'eventignore'.
8394 */
8395 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008396 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008397
8398 /*
8399 * Allow nesting of autocommands, but restrict the depth, because it's
8400 * possible to create an endless loop.
8401 */
8402 if (nesting == 10)
8403 {
8404 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008405 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008406 }
8407
8408 /*
8409 * Check if these autocommands are disabled. Used when doing ":all" or
8410 * ":ball".
8411 */
8412 if ( (autocmd_no_enter
8413 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8414 || (autocmd_no_leave
8415 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008416 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008417
8418 /*
8419 * Save the autocmd_* variables and info about the current buffer.
8420 */
8421 save_autocmd_fname = autocmd_fname;
8422 save_autocmd_bufnr = autocmd_bufnr;
8423 save_autocmd_match = autocmd_match;
8424 save_autocmd_busy = autocmd_busy;
8425 save_autocmd_nested = autocmd_nested;
8426 save_changed = curbuf->b_changed;
8427 old_curbuf = curbuf;
8428
8429 /*
8430 * Set the file name to be used for <afile>.
8431 */
8432 if (fname_io == NULL)
8433 {
8434 if (fname != NULL && *fname != NUL)
8435 autocmd_fname = fname;
8436 else if (buf != NULL)
8437 autocmd_fname = buf->b_fname;
8438 else
8439 autocmd_fname = NULL;
8440 }
8441 else
8442 autocmd_fname = fname_io;
8443
8444 /*
8445 * Set the buffer number to be used for <abuf>.
8446 */
8447 if (buf == NULL)
8448 autocmd_bufnr = 0;
8449 else
8450 autocmd_bufnr = buf->b_fnum;
8451
8452 /*
8453 * When the file name is NULL or empty, use the file name of buffer "buf".
8454 * Always use the full path of the file name to match with, in case
8455 * "allow_dirs" is set.
8456 */
8457 if (fname == NULL || *fname == NUL)
8458 {
8459 if (buf == NULL)
8460 fname = NULL;
8461 else
8462 {
8463#ifdef FEAT_SYN_HL
8464 if (event == EVENT_SYNTAX)
8465 fname = buf->b_p_syn;
8466 else
8467#endif
8468 if (event == EVENT_FILETYPE)
8469 fname = buf->b_p_ft;
8470 else
8471 {
8472 if (buf->b_sfname != NULL)
8473 sfname = vim_strsave(buf->b_sfname);
8474 fname = buf->b_ffname;
8475 }
8476 }
8477 if (fname == NULL)
8478 fname = (char_u *)"";
8479 fname = vim_strsave(fname); /* make a copy, so we can change it */
8480 }
8481 else
8482 {
8483 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008484 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8485 if (event == EVENT_FILETYPE
8486 || event == EVENT_SYNTAX
8487 || event == EVENT_REMOTEREPLY
Bram Moolenaarb8a7b562006-02-01 21:47:16 +00008488 || event == EVENT_SPELLFILEMISSING
Bram Moolenaar7c626922005-02-07 22:01:03 +00008489 || event == EVENT_QUICKFIXCMDPRE
8490 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008491 fname = vim_strsave(fname);
8492 else
8493 fname = FullName_save(fname, FALSE);
8494 }
8495 if (fname == NULL) /* out of memory */
8496 {
8497 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008498 retval = FALSE;
8499 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008500 }
8501
8502#ifdef BACKSLASH_IN_FILENAME
8503 /*
8504 * Replace all backslashes with forward slashes. This makes the
8505 * autocommand patterns portable between Unix and MS-DOS.
8506 */
8507 if (sfname != NULL)
8508 forward_slash(sfname);
8509 forward_slash(fname);
8510#endif
8511
8512#ifdef VMS
8513 /* remove version for correct match */
8514 if (sfname != NULL)
8515 vms_remove_version(sfname);
8516 vms_remove_version(fname);
8517#endif
8518
8519 /*
8520 * Set the name to be used for <amatch>.
8521 */
8522 autocmd_match = fname;
8523
8524
8525 /* Don't redraw while doing auto commands. */
8526 ++RedrawingDisabled;
8527 save_sourcing_name = sourcing_name;
8528 sourcing_name = NULL; /* don't free this one */
8529 save_sourcing_lnum = sourcing_lnum;
8530 sourcing_lnum = 0; /* no line number here */
8531
8532#ifdef FEAT_EVAL
8533 save_current_SID = current_SID;
8534
Bram Moolenaar05159a02005-02-26 23:04:13 +00008535# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008536 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008537 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8538# endif
8539
Bram Moolenaar071d4272004-06-13 20:20:40 +00008540 /* Don't use local function variables, if called from a function */
8541 save_funccalp = save_funccal();
8542#endif
8543
8544 /*
8545 * When starting to execute autocommands, save the search patterns.
8546 */
8547 if (!autocmd_busy)
8548 {
8549 save_search_patterns();
8550 saveRedobuff();
8551 did_filetype = keep_filetype;
8552 }
8553
8554 /*
8555 * Note that we are applying autocmds. Some commands need to know.
8556 */
8557 autocmd_busy = TRUE;
8558 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8559 ++nesting; /* see matching decrement below */
8560
8561 /* Remember that FileType was triggered. Used for did_filetype(). */
8562 if (event == EVENT_FILETYPE)
8563 did_filetype = TRUE;
8564
8565 tail = gettail(fname);
8566
8567 /* Find first autocommand that matches */
8568 patcmd.curpat = first_autopat[(int)event];
8569 patcmd.nextcmd = NULL;
8570 patcmd.group = group;
8571 patcmd.fname = fname;
8572 patcmd.sfname = sfname;
8573 patcmd.tail = tail;
8574 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008575 patcmd.arg_bufnr = autocmd_bufnr;
8576 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008577 auto_next_pat(&patcmd, FALSE);
8578
8579 /* found one, start executing the autocommands */
8580 if (patcmd.curpat != NULL)
8581 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008582 /* add to active_apc_list */
8583 patcmd.next = active_apc_list;
8584 active_apc_list = &patcmd;
8585
Bram Moolenaar071d4272004-06-13 20:20:40 +00008586#ifdef FEAT_EVAL
8587 /* set v:cmdarg (only when there is a matching pattern) */
8588 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8589 if (eap != NULL)
8590 {
8591 save_cmdarg = set_cmdarg(eap, NULL);
8592 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8593 }
8594 else
8595 save_cmdarg = NULL; /* avoid gcc warning */
8596#endif
8597 retval = TRUE;
8598 /* mark the last pattern, to avoid an endless loop when more patterns
8599 * are added when executing autocommands */
8600 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8601 ap->last = FALSE;
8602 ap->last = TRUE;
8603 check_lnums(TRUE); /* make sure cursor and topline are valid */
8604 do_cmdline(NULL, getnextac, (void *)&patcmd,
8605 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8606#ifdef FEAT_EVAL
8607 if (eap != NULL)
8608 {
8609 (void)set_cmdarg(NULL, save_cmdarg);
8610 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8611 }
8612#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008613 /* delete from active_apc_list */
8614 if (active_apc_list == &patcmd) /* just in case */
8615 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008616 }
8617
8618 --RedrawingDisabled;
8619 autocmd_busy = save_autocmd_busy;
8620 filechangeshell_busy = FALSE;
8621 autocmd_nested = save_autocmd_nested;
8622 vim_free(sourcing_name);
8623 sourcing_name = save_sourcing_name;
8624 sourcing_lnum = save_sourcing_lnum;
8625 autocmd_fname = save_autocmd_fname;
8626 autocmd_bufnr = save_autocmd_bufnr;
8627 autocmd_match = save_autocmd_match;
8628#ifdef FEAT_EVAL
8629 current_SID = save_current_SID;
8630 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008631# ifdef FEAT_PROFILE
Bram Moolenaar371d5402006-03-20 21:47:49 +00008632 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00008633 prof_child_exit(&wait_time);
8634# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008635#endif
8636 vim_free(fname);
8637 vim_free(sfname);
8638 --nesting; /* see matching increment above */
8639
8640 /*
8641 * When stopping to execute autocommands, restore the search patterns and
8642 * the redo buffer.
8643 */
8644 if (!autocmd_busy)
8645 {
8646 restore_search_patterns();
8647 restoreRedobuff();
8648 did_filetype = FALSE;
8649 }
8650
8651 /*
8652 * Some events don't set or reset the Changed flag.
8653 * Check if still in the same buffer!
8654 */
8655 if (curbuf == old_curbuf
8656 && (event == EVENT_BUFREADPOST
8657 || event == EVENT_BUFWRITEPOST
8658 || event == EVENT_FILEAPPENDPOST
8659 || event == EVENT_VIMLEAVE
8660 || event == EVENT_VIMLEAVEPRE))
8661 {
8662#ifdef FEAT_TITLE
8663 if (curbuf->b_changed != save_changed)
8664 need_maketitle = TRUE;
8665#endif
8666 curbuf->b_changed = save_changed;
8667 }
8668
8669 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008670
8671BYPASS_AU:
8672 /* When wiping out a buffer make sure all its buffer-local autocommands
8673 * are deleted. */
8674 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8675 aubuflocal_remove(buf);
8676
Bram Moolenaar071d4272004-06-13 20:20:40 +00008677 return retval;
8678}
8679
8680/*
8681 * Find next autocommand pattern that matches.
8682 */
8683 static void
8684auto_next_pat(apc, stop_at_last)
8685 AutoPatCmd *apc;
8686 int stop_at_last; /* stop when 'last' flag is set */
8687{
8688 AutoPat *ap;
8689 AutoCmd *cp;
8690 char_u *name;
8691 char *s;
8692
8693 vim_free(sourcing_name);
8694 sourcing_name = NULL;
8695
8696 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8697 {
8698 apc->curpat = NULL;
8699
8700 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008701 * the group matches. For buffer-local autocommands only check the
8702 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008703 if (ap->pat != NULL && ap->cmds != NULL
8704 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8705 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008706 /* execution-condition */
8707 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008708 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8709 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008710 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008711 {
8712 name = event_nr2name(apc->event);
8713 s = _("%s Auto commands for \"%s\"");
8714 sourcing_name = alloc((unsigned)(STRLEN(s)
8715 + STRLEN(name) + ap->patlen + 1));
8716 if (sourcing_name != NULL)
8717 {
8718 sprintf((char *)sourcing_name, s,
8719 (char *)name, (char *)ap->pat);
8720 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008721 {
8722 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008723 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008724 verbose_leave();
8725 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008726 }
8727
8728 apc->curpat = ap;
8729 apc->nextcmd = ap->cmds;
8730 /* mark last command */
8731 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8732 cp->last = FALSE;
8733 cp->last = TRUE;
8734 }
8735 line_breakcheck();
8736 if (apc->curpat != NULL) /* found a match */
8737 break;
8738 }
8739 if (stop_at_last && ap->last)
8740 break;
8741 }
8742}
8743
8744/*
8745 * Get next autocommand command.
8746 * Called by do_cmdline() to get the next line for ":if".
8747 * Returns allocated string, or NULL for end of autocommands.
8748 */
8749/* ARGSUSED */
8750 static char_u *
8751getnextac(c, cookie, indent)
8752 int c; /* not used */
8753 void *cookie;
8754 int indent; /* not used */
8755{
8756 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8757 char_u *retval;
8758 AutoCmd *ac;
8759
8760 /* Can be called again after returning the last line. */
8761 if (acp->curpat == NULL)
8762 return NULL;
8763
8764 /* repeat until we find an autocommand to execute */
8765 for (;;)
8766 {
8767 /* skip removed commands */
8768 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8769 if (acp->nextcmd->last)
8770 acp->nextcmd = NULL;
8771 else
8772 acp->nextcmd = acp->nextcmd->next;
8773
8774 if (acp->nextcmd != NULL)
8775 break;
8776
8777 /* at end of commands, find next pattern that matches */
8778 if (acp->curpat->last)
8779 acp->curpat = NULL;
8780 else
8781 acp->curpat = acp->curpat->next;
8782 if (acp->curpat != NULL)
8783 auto_next_pat(acp, TRUE);
8784 if (acp->curpat == NULL)
8785 return NULL;
8786 }
8787
8788 ac = acp->nextcmd;
8789
8790 if (p_verbose >= 9)
8791 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008792 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008793 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008794 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008795 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008796 }
8797 retval = vim_strsave(ac->cmd);
8798 autocmd_nested = ac->nested;
8799#ifdef FEAT_EVAL
8800 current_SID = ac->scriptID;
8801#endif
8802 if (ac->last)
8803 acp->nextcmd = NULL;
8804 else
8805 acp->nextcmd = ac->next;
8806 return retval;
8807}
8808
8809/*
8810 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008811 * To account for buffer-local autocommands, function needs to know
8812 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008813 */
8814 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008815has_autocmd(event, sfname, buf)
Bram Moolenaar754b5602006-02-09 23:53:20 +00008816 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008817 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008818 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008819{
8820 AutoPat *ap;
8821 char_u *fname;
8822 char_u *tail = gettail(sfname);
8823 int retval = FALSE;
8824
8825 fname = FullName_save(sfname, FALSE);
8826 if (fname == NULL)
8827 return FALSE;
8828
8829#ifdef BACKSLASH_IN_FILENAME
8830 /*
8831 * Replace all backslashes with forward slashes. This makes the
8832 * autocommand patterns portable between Unix and MS-DOS.
8833 */
8834 sfname = vim_strsave(sfname);
8835 if (sfname != NULL)
8836 forward_slash(sfname);
8837 forward_slash(fname);
8838#endif
8839
8840 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8841 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008842 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008843 ? match_file_pat(NULL, ap->reg_prog,
8844 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008845 : buf != NULL && ap->buflocal_nr == buf->b_fnum
8846 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008847 {
8848 retval = TRUE;
8849 break;
8850 }
8851
8852 vim_free(fname);
8853#ifdef BACKSLASH_IN_FILENAME
8854 vim_free(sfname);
8855#endif
8856
8857 return retval;
8858}
8859
8860#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8861/*
8862 * Function given to ExpandGeneric() to obtain the list of autocommand group
8863 * names.
8864 */
8865/*ARGSUSED*/
8866 char_u *
8867get_augroup_name(xp, idx)
8868 expand_T *xp;
8869 int idx;
8870{
8871 if (idx == augroups.ga_len) /* add "END" add the end */
8872 return (char_u *)"END";
8873 if (idx >= augroups.ga_len) /* end of list */
8874 return NULL;
8875 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8876 return (char_u *)"";
8877 return AUGROUP_NAME(idx); /* return a name */
8878}
8879
8880static int include_groups = FALSE;
8881
8882 char_u *
8883set_context_in_autocmd(xp, arg, doautocmd)
8884 expand_T *xp;
8885 char_u *arg;
8886 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8887{
8888 char_u *p;
8889 int group;
8890
8891 /* check for a group name, skip it if present */
8892 include_groups = FALSE;
8893 p = arg;
8894 group = au_get_grouparg(&arg);
8895 if (group == AUGROUP_ERROR)
8896 return NULL;
8897 /* If there only is a group name that's what we expand. */
8898 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8899 {
8900 arg = p;
8901 group = AUGROUP_ALL;
8902 }
8903
8904 /* skip over event name */
8905 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8906 if (*p == ',')
8907 arg = p + 1;
8908 if (*p == NUL)
8909 {
8910 if (group == AUGROUP_ALL)
8911 include_groups = TRUE;
8912 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8913 xp->xp_pattern = arg;
8914 return NULL;
8915 }
8916
8917 /* skip over pattern */
8918 arg = skipwhite(p);
8919 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8920 arg++;
8921 if (*arg)
8922 return arg; /* expand (next) command */
8923
8924 if (doautocmd)
8925 xp->xp_context = EXPAND_FILES; /* expand file names */
8926 else
8927 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8928 return NULL;
8929}
8930
8931/*
8932 * Function given to ExpandGeneric() to obtain the list of event names.
8933 */
8934/*ARGSUSED*/
8935 char_u *
8936get_event_name(xp, idx)
8937 expand_T *xp;
8938 int idx;
8939{
8940 if (idx < augroups.ga_len) /* First list group names, if wanted */
8941 {
8942 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8943 return (char_u *)""; /* skip deleted entries */
8944 return AUGROUP_NAME(idx); /* return a name */
8945 }
8946 return (char_u *)event_names[idx - augroups.ga_len].name;
8947}
8948
8949#endif /* FEAT_CMDL_COMPL */
8950
8951/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008952 * Return TRUE if autocmd is supported.
8953 */
8954 int
8955autocmd_supported(name)
8956 char_u *name;
8957{
8958 char_u *p;
8959
8960 return (event_name2nr(name, &p) != NUM_EVENTS);
8961}
8962
8963/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008964 * Return TRUE if an autocommand is defined for a group, event and
8965 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8966 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8967 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8968 * Used for:
8969 * exists("#Group") or
8970 * exists("#Group#Event") or
8971 * exists("#Group#Event#pat") or
8972 * exists("#Event") or
8973 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008974 */
8975 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008976au_exists(arg)
8977 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008978{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008979 char_u *arg_save;
8980 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008981 char_u *event_name;
8982 char_u *p;
Bram Moolenaar754b5602006-02-09 23:53:20 +00008983 event_T event;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008984 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008985 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008986 int group;
8987 int retval = FALSE;
8988
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008989 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008990 arg_save = vim_strsave(arg);
8991 if (arg_save == NULL)
8992 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008993 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008994 if (p != NULL)
8995 *p++ = NUL;
8996
8997 /* First, look for an autocmd group name */
8998 group = au_find_group(arg_save);
8999 if (group == AUGROUP_ERROR)
9000 {
9001 /* Didn't match a group name, assume the first argument is an event. */
9002 group = AUGROUP_ALL;
9003 event_name = arg_save;
9004 }
9005 else
9006 {
9007 if (p == NULL)
9008 {
9009 /* "Group": group name is present and it's recognized */
9010 retval = TRUE;
9011 goto theend;
9012 }
9013
9014 /* Must be "Group#Event" or "Group#Event#pat". */
9015 event_name = p;
9016 p = vim_strchr(event_name, '#');
9017 if (p != NULL)
9018 *p++ = NUL; /* "Group#Event#pat" */
9019 }
9020
9021 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009022
9023 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009024 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009025
9026 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00009027 if (event == NUM_EVENTS)
9028 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009029
9030 /* Find the first autocommand for this event.
9031 * If there isn't any, return FALSE;
9032 * If there is one and no pattern given, return TRUE; */
9033 ap = first_autopat[(int)event];
9034 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009035 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009036 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00009037 {
9038 retval = TRUE;
9039 goto theend;
9040 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009041
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009042 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
9043 /* for pattern "<buffer=N>, fnamecmp() will work fine */
9044 if (STRICMP(pattern, "<buffer>") == 0)
9045 buflocal_buf = curbuf;
9046
Bram Moolenaar071d4272004-06-13 20:20:40 +00009047 /* Check if there is an autocommand with the given pattern. */
9048 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009049 /* only use a pattern when it has not been removed and has commands. */
9050 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009051 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00009052 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009053 && (buflocal_buf == NULL
9054 ? fnamecmp(ap->pat, pattern) == 0
9055 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00009056 {
9057 retval = TRUE;
9058 break;
9059 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009060
Bram Moolenaar195d6352005-12-19 22:08:24 +00009061theend:
9062 vim_free(arg_save);
9063 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009064}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00009065
Bram Moolenaar071d4272004-06-13 20:20:40 +00009066#endif /* FEAT_AUTOCMD */
9067
9068#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
9069/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00009070 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
9071 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
9072 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009073 * Used for autocommands and 'wildignore'.
9074 * Returns TRUE if there is a match, FALSE otherwise.
9075 */
9076 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00009077match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009078 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00009079 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00009080 char_u *fname; /* full path of file name */
9081 char_u *sfname; /* short file name or NULL */
9082 char_u *tail; /* tail of path */
9083 int allow_dirs; /* allow matching with dir */
9084{
9085 regmatch_T regmatch;
9086 int result = FALSE;
9087#ifdef FEAT_OSFILETYPE
9088 int no_pattern = FALSE; /* TRUE if check is filetype only */
9089 char_u *type_start;
9090 char_u c;
9091 int match = FALSE;
9092#endif
9093
9094#ifdef CASE_INSENSITIVE_FILENAME
9095 regmatch.rm_ic = TRUE; /* Always ignore case */
9096#else
9097 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
9098#endif
9099#ifdef FEAT_OSFILETYPE
9100 if (*pattern == '<')
9101 {
9102 /* There is a filetype condition specified with this pattern.
9103 * Check the filetype matches first. If not, don't bother with the
9104 * pattern (set regprog to NULL).
9105 * Always use magic for the regexp.
9106 */
9107
9108 for (type_start = pattern + 1; (c = *pattern); pattern++)
9109 {
9110 if ((c == ';' || c == '>') && match == FALSE)
9111 {
9112 *pattern = NUL; /* Terminate the string */
9113 match = mch_check_filetype(fname, type_start);
9114 *pattern = c; /* Restore the terminator */
9115 type_start = pattern + 1;
9116 }
9117 if (c == '>')
9118 break;
9119 }
9120
9121 /* (c should never be NUL, but check anyway) */
9122 if (match == FALSE || c == NUL)
9123 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9124 else if (*pattern == NUL)
9125 {
9126 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9127 no_pattern = TRUE; /* Always matches - don't check pat. */
9128 }
9129 else
9130 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9131 }
9132 else
9133#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009134 {
9135 if (prog != NULL)
9136 regmatch.regprog = prog;
9137 else
9138 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9139 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009140
9141 /*
9142 * Try for a match with the pattern with:
9143 * 1. the full file name, when the pattern has a '/'.
9144 * 2. the short file name, when the pattern has a '/'.
9145 * 3. the tail of the file name, when the pattern has no '/'.
9146 */
9147 if (
9148#ifdef FEAT_OSFILETYPE
9149 /* If the check is for a filetype only and we don't care
9150 * about the path then skip all the regexp stuff.
9151 */
9152 no_pattern ||
9153#endif
9154 (regmatch.regprog != NULL
9155 && ((allow_dirs
9156 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9157 || (sfname != NULL
9158 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9159 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9160 result = TRUE;
9161
Bram Moolenaar748bf032005-02-02 23:04:36 +00009162 if (prog == NULL)
9163 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009164 return result;
9165}
9166#endif
9167
9168#if defined(FEAT_WILDIGN) || defined(PROTO)
9169/*
9170 * Return TRUE if a file matches with a pattern in "list".
9171 * "list" is a comma-separated list of patterns, like 'wildignore'.
9172 * "sfname" is the short file name or NULL, "ffname" the long file name.
9173 */
9174 int
9175match_file_list(list, sfname, ffname)
9176 char_u *list;
9177 char_u *sfname;
9178 char_u *ffname;
9179{
9180 char_u buf[100];
9181 char_u *tail;
9182 char_u *regpat;
9183 char allow_dirs;
9184 int match;
9185 char_u *p;
9186
9187 tail = gettail(sfname);
9188
9189 /* try all patterns in 'wildignore' */
9190 p = list;
9191 while (*p)
9192 {
9193 copy_option_part(&p, buf, 100, ",");
9194 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9195 if (regpat == NULL)
9196 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009197 match = match_file_pat(regpat, NULL, ffname, sfname,
9198 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009199 vim_free(regpat);
9200 if (match)
9201 return TRUE;
9202 }
9203 return FALSE;
9204}
9205#endif
9206
9207/*
9208 * Convert the given pattern "pat" which has shell style wildcards in it, into
9209 * a regular expression, and return the result in allocated memory. If there
9210 * is a directory path separator to be matched, then TRUE is put in
9211 * allow_dirs, otherwise FALSE is put there -- webb.
9212 * Handle backslashes before special characters, like "\*" and "\ ".
9213 *
9214 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9215 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9216 *
9217 * Returns NULL when out of memory.
9218 */
9219/*ARGSUSED*/
9220 char_u *
9221file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9222 char_u *pat;
9223 char_u *pat_end; /* first char after pattern or NULL */
9224 char *allow_dirs; /* Result passed back out in here */
9225 int no_bslash; /* Don't use a backward slash as pathsep */
9226{
9227 int size;
9228 char_u *endp;
9229 char_u *reg_pat;
9230 char_u *p;
9231 int i;
9232 int nested = 0;
9233 int add_dollar = TRUE;
9234#ifdef FEAT_OSFILETYPE
9235 int check_length = 0;
9236#endif
9237
9238 if (allow_dirs != NULL)
9239 *allow_dirs = FALSE;
9240 if (pat_end == NULL)
9241 pat_end = pat + STRLEN(pat);
9242
9243#ifdef FEAT_OSFILETYPE
9244 /* Find out how much of the string is the filetype check */
9245 if (*pat == '<')
9246 {
9247 /* Count chars until the next '>' */
9248 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9249 ;
9250 if (p < pat_end)
9251 {
9252 /* Pattern is of the form <.*>.* */
9253 check_length = p - pat + 1;
9254 if (p + 1 >= pat_end)
9255 {
9256 /* The 'pattern' is a filetype check ONLY */
9257 reg_pat = (char_u *)alloc(check_length + 1);
9258 if (reg_pat != NULL)
9259 {
9260 mch_memmove(reg_pat, pat, (size_t)check_length);
9261 reg_pat[check_length] = NUL;
9262 }
9263 return reg_pat;
9264 }
9265 }
9266 /* else: there was no closing '>' - assume it was a normal pattern */
9267
9268 }
9269 pat += check_length;
9270 size = 2 + check_length;
9271#else
9272 size = 2; /* '^' at start, '$' at end */
9273#endif
9274
9275 for (p = pat; p < pat_end; p++)
9276 {
9277 switch (*p)
9278 {
9279 case '*':
9280 case '.':
9281 case ',':
9282 case '{':
9283 case '}':
9284 case '~':
9285 size += 2; /* extra backslash */
9286 break;
9287#ifdef BACKSLASH_IN_FILENAME
9288 case '\\':
9289 case '/':
9290 size += 4; /* could become "[\/]" */
9291 break;
9292#endif
9293 default:
9294 size++;
9295# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009296 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009297 {
9298 ++p;
9299 ++size;
9300 }
9301# endif
9302 break;
9303 }
9304 }
9305 reg_pat = alloc(size + 1);
9306 if (reg_pat == NULL)
9307 return NULL;
9308
9309#ifdef FEAT_OSFILETYPE
9310 /* Copy the type check in to the start. */
9311 if (check_length)
9312 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9313 i = check_length;
9314#else
9315 i = 0;
9316#endif
9317
9318 if (pat[0] == '*')
9319 while (pat[0] == '*' && pat < pat_end - 1)
9320 pat++;
9321 else
9322 reg_pat[i++] = '^';
9323 endp = pat_end - 1;
9324 if (*endp == '*')
9325 {
9326 while (endp - pat > 0 && *endp == '*')
9327 endp--;
9328 add_dollar = FALSE;
9329 }
9330 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9331 {
9332 switch (*p)
9333 {
9334 case '*':
9335 reg_pat[i++] = '.';
9336 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009337 while (p[1] == '*') /* "**" matches like "*" */
9338 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009339 break;
9340 case '.':
9341#ifdef RISCOS
9342 if (allow_dirs != NULL)
9343 *allow_dirs = TRUE;
9344 /* FALLTHROUGH */
9345#endif
9346 case '~':
9347 reg_pat[i++] = '\\';
9348 reg_pat[i++] = *p;
9349 break;
9350 case '?':
9351#ifdef RISCOS
9352 case '#':
9353#endif
9354 reg_pat[i++] = '.';
9355 break;
9356 case '\\':
9357 if (p[1] == NUL)
9358 break;
9359#ifdef BACKSLASH_IN_FILENAME
9360 if (!no_bslash)
9361 {
9362 /* translate:
9363 * "\x" to "\\x" e.g., "dir\file"
9364 * "\*" to "\\.*" e.g., "dir\*.c"
9365 * "\?" to "\\." e.g., "dir\??.c"
9366 * "\+" to "\+" e.g., "fileX\+.c"
9367 */
9368 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9369 && p[1] != '+')
9370 {
9371 reg_pat[i++] = '[';
9372 reg_pat[i++] = '\\';
9373 reg_pat[i++] = '/';
9374 reg_pat[i++] = ']';
9375 if (allow_dirs != NULL)
9376 *allow_dirs = TRUE;
9377 break;
9378 }
9379 }
9380#endif
9381 if (*++p == '?'
9382#ifdef BACKSLASH_IN_FILENAME
9383 && no_bslash
9384#endif
9385 )
9386 reg_pat[i++] = '?';
9387 else
9388 if (*p == ',')
9389 reg_pat[i++] = ',';
9390 else
9391 {
9392 if (allow_dirs != NULL && vim_ispathsep(*p)
9393#ifdef BACKSLASH_IN_FILENAME
9394 && (!no_bslash || *p != '\\')
9395#endif
9396 )
9397 *allow_dirs = TRUE;
9398 reg_pat[i++] = '\\';
9399 reg_pat[i++] = *p;
9400 }
9401 break;
9402#ifdef BACKSLASH_IN_FILENAME
9403 case '/':
9404 reg_pat[i++] = '[';
9405 reg_pat[i++] = '\\';
9406 reg_pat[i++] = '/';
9407 reg_pat[i++] = ']';
9408 if (allow_dirs != NULL)
9409 *allow_dirs = TRUE;
9410 break;
9411#endif
9412 case '{':
9413 reg_pat[i++] = '\\';
9414 reg_pat[i++] = '(';
9415 nested++;
9416 break;
9417 case '}':
9418 reg_pat[i++] = '\\';
9419 reg_pat[i++] = ')';
9420 --nested;
9421 break;
9422 case ',':
9423 if (nested)
9424 {
9425 reg_pat[i++] = '\\';
9426 reg_pat[i++] = '|';
9427 }
9428 else
9429 reg_pat[i++] = ',';
9430 break;
9431 default:
9432# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009433 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009434 reg_pat[i++] = *p++;
9435 else
9436# endif
9437 if (allow_dirs != NULL && vim_ispathsep(*p))
9438 *allow_dirs = TRUE;
9439 reg_pat[i++] = *p;
9440 break;
9441 }
9442 }
9443 if (add_dollar)
9444 reg_pat[i++] = '$';
9445 reg_pat[i] = NUL;
9446 if (nested != 0)
9447 {
9448 if (nested < 0)
9449 EMSG(_("E219: Missing {."));
9450 else
9451 EMSG(_("E220: Missing }."));
9452 vim_free(reg_pat);
9453 reg_pat = NULL;
9454 }
9455 return reg_pat;
9456}