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