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