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