blob: c5c926299835044de642aba8fa4eaded6f5f8947 [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);
Bram Moolenaar86e01082005-12-29 22:45:34 +00001494 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001495 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 }
Bram Moolenaar8fa04452005-12-23 22:13:51 +00004204 else if (buf->b_dev < 0)
4205 /* Set the inode when creating a new file. */
4206 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004207#endif
4208
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209 if (close(fd) != 0)
4210 {
4211 errmsg = (char_u *)_("E512: Close failed");
4212 end = 0;
4213 }
4214
4215#ifdef UNIX
4216 if (made_writable)
4217 perm &= ~0200; /* reset 'w' bit for security reasons */
4218#endif
4219 if (perm >= 0) /* set perm. of new file same as old file */
4220 (void)mch_setperm(wfname, perm);
4221#ifdef RISCOS
4222 if (!append && !filtering)
4223 /* Set the filetype after writing the file. */
4224 mch_set_filetype(wfname, buf->b_p_oft);
4225#endif
4226#ifdef HAVE_ACL
4227 /* Probably need to set the ACL before changing the user (can't set the
4228 * ACL on a file the user doesn't own). */
4229 if (!backup_copy)
4230 mch_set_acl(wfname, acl);
4231#endif
4232
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233
4234#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4235 if (wfname != fname)
4236 {
4237 /*
4238 * The file was written to a temp file, now it needs to be converted
4239 * with 'charconvert' to (overwrite) the output file.
4240 */
4241 if (end != 0)
4242 {
4243 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
4244 wfname, fname) == FAIL)
4245 {
4246 write_info.bw_conv_error = TRUE;
4247 end = 0;
4248 }
4249 }
4250 mch_remove(wfname);
4251 vim_free(wfname);
4252 }
4253#endif
4254
4255 if (end == 0)
4256 {
4257 if (errmsg == NULL)
4258 {
4259#ifdef FEAT_MBYTE
4260 if (write_info.bw_conv_error)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00004261 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 else
4263#endif
4264 if (got_int)
4265 errmsg = (char_u *)_(e_interr);
4266 else
4267 errmsg = (char_u *)_("E514: write error (file system full?)");
4268 }
4269
4270 /*
4271 * If we have a backup file, try to put it in place of the new file,
4272 * because the new file is probably corrupt. This avoids loosing the
4273 * original file when trying to make a backup when writing the file a
4274 * second time.
4275 * When "backup_copy" is set we need to copy the backup over the new
4276 * file. Otherwise rename the backup file.
4277 * If this is OK, don't give the extra warning message.
4278 */
4279 if (backup != NULL)
4280 {
4281 if (backup_copy)
4282 {
4283 /* This may take a while, if we were interrupted let the user
4284 * know we got the message. */
4285 if (got_int)
4286 {
4287 MSG(_(e_interr));
4288 out_flush();
4289 }
4290 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4291 {
4292 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004293 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4294 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 {
4296 /* copy the file. */
4297 write_info.bw_buf = smallbuf;
4298#ifdef HAS_BW_FLAGS
4299 write_info.bw_flags = FIO_NOCONVERT;
4300#endif
4301 while ((write_info.bw_len = vim_read(fd, smallbuf,
4302 SMBUFSIZE)) > 0)
4303 if (buf_write_bytes(&write_info) == FAIL)
4304 break;
4305
4306 if (close(write_info.bw_fd) >= 0
4307 && write_info.bw_len == 0)
4308 end = 1; /* success */
4309 }
4310 close(fd); /* ignore errors for closing read file */
4311 }
4312 }
4313 else
4314 {
4315 if (vim_rename(backup, fname) == 0)
4316 end = 1;
4317 }
4318 }
4319 goto fail;
4320 }
4321
4322 lnum -= start; /* compute number of written lines */
4323 --no_wait_return; /* may wait for return now */
4324
4325#if !(defined(UNIX) || defined(VMS))
4326 fname = sfname; /* use shortname now, for the messages */
4327#endif
4328 if (!filtering)
4329 {
4330 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4331 c = FALSE;
4332#ifdef FEAT_MBYTE
4333 if (write_info.bw_conv_error)
4334 {
4335 STRCAT(IObuff, _(" CONVERSION ERROR"));
4336 c = TRUE;
4337 }
4338 else if (notconverted)
4339 {
4340 STRCAT(IObuff, _("[NOT converted]"));
4341 c = TRUE;
4342 }
4343 else if (converted)
4344 {
4345 STRCAT(IObuff, _("[converted]"));
4346 c = TRUE;
4347 }
4348#endif
4349 if (device)
4350 {
4351 STRCAT(IObuff, _("[Device]"));
4352 c = TRUE;
4353 }
4354 else if (newfile)
4355 {
4356 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4357 c = TRUE;
4358 }
4359 if (no_eol)
4360 {
4361 msg_add_eol();
4362 c = TRUE;
4363 }
4364 /* may add [unix/dos/mac] */
4365 if (msg_add_fileformat(fileformat))
4366 c = TRUE;
4367#ifdef FEAT_CRYPT
4368 if (wb_flags & FIO_ENCRYPTED)
4369 {
4370 STRCAT(IObuff, _("[crypted]"));
4371 c = TRUE;
4372 }
4373#endif
4374 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4375 if (!shortmess(SHM_WRITE))
4376 {
4377 if (append)
4378 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4379 else
4380 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4381 }
4382
4383 set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0));
4384 keep_msg_attr = 0;
4385 }
4386
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004387 /* When written everything correctly: reset 'modified'. Unless not
4388 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004389 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390#ifdef FEAT_MBYTE
4391 && !write_info.bw_conv_error
4392#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004393 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)
4394 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395 {
4396 unchanged(buf, TRUE);
4397 u_unchanged(buf);
4398 }
4399
4400 /*
4401 * If written to the current file, update the timestamp of the swap file
4402 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4403 */
4404 if (overwriting)
4405 {
4406 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004407 if (append)
4408 buf->b_flags &= ~BF_NEW;
4409 else
4410 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411 }
4412
4413 /*
4414 * If we kept a backup until now, and we are in patch mode, then we make
4415 * the backup file our 'original' file.
4416 */
4417 if (*p_pm && dobackup)
4418 {
4419 char *org = (char *)buf_modname(
4420#ifdef SHORT_FNAME
4421 TRUE,
4422#else
4423 (buf->b_p_sn || buf->b_shortname),
4424#endif
4425 fname, p_pm, FALSE);
4426
4427 if (backup != NULL)
4428 {
4429 struct stat st;
4430
4431 /*
4432 * If the original file does not exist yet
4433 * the current backup file becomes the original file
4434 */
4435 if (org == NULL)
4436 EMSG(_("E205: Patchmode: can't save original file"));
4437 else if (mch_stat(org, &st) < 0)
4438 {
4439 vim_rename(backup, (char_u *)org);
4440 vim_free(backup); /* don't delete the file */
4441 backup = NULL;
4442#ifdef UNIX
4443 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4444#endif
4445 }
4446 }
4447 /*
4448 * If there is no backup file, remember that a (new) file was
4449 * created.
4450 */
4451 else
4452 {
4453 int empty_fd;
4454
4455 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004456 || (empty_fd = mch_open(org,
4457 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004458 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459 EMSG(_("E206: patchmode: can't touch empty original file"));
4460 else
4461 close(empty_fd);
4462 }
4463 if (org != NULL)
4464 {
4465 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4466 vim_free(org);
4467 }
4468 }
4469
4470 /*
4471 * Remove the backup unless 'backup' option is set
4472 */
4473 if (!p_bk && backup != NULL && mch_remove(backup) != 0)
4474 EMSG(_("E207: Can't delete backup file"));
4475
4476#ifdef FEAT_SUN_WORKSHOP
4477 if (usingSunWorkShop)
4478 workshop_file_saved((char *) ffname);
4479#endif
4480
4481 goto nofail;
4482
4483 /*
4484 * Finish up. We get here either after failure or success.
4485 */
4486fail:
4487 --no_wait_return; /* may wait for return now */
4488nofail:
4489
4490 /* Done saving, we accept changed buffer warnings again */
4491 buf->b_saving = FALSE;
4492
4493 vim_free(backup);
4494 if (buffer != smallbuf)
4495 vim_free(buffer);
4496#ifdef FEAT_MBYTE
4497 vim_free(fenc_tofree);
4498 vim_free(write_info.bw_conv_buf);
4499# ifdef USE_ICONV
4500 if (write_info.bw_iconv_fd != (iconv_t)-1)
4501 {
4502 iconv_close(write_info.bw_iconv_fd);
4503 write_info.bw_iconv_fd = (iconv_t)-1;
4504 }
4505# endif
4506#endif
4507#ifdef HAVE_ACL
4508 mch_free_acl(acl);
4509#endif
4510
4511 if (errmsg != NULL)
4512 {
4513 int numlen = errnum != NULL ? STRLEN(errnum) : 0;
4514
4515 attr = hl_attr(HLF_E); /* set highlight for error messages */
4516 msg_add_fname(buf,
4517#ifndef UNIX
4518 sfname
4519#else
4520 fname
4521#endif
4522 ); /* put file name in IObuff with quotes */
4523 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
4524 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
4525 /* If the error message has the form "is ...", put the error number in
4526 * front of the file name. */
4527 if (errnum != NULL)
4528 {
4529 mch_memmove(IObuff + numlen, IObuff, STRLEN(IObuff) + 1);
4530 mch_memmove(IObuff, errnum, (size_t)numlen);
4531 }
4532 STRCAT(IObuff, errmsg);
4533 emsg(IObuff);
4534
4535 retval = FAIL;
4536 if (end == 0)
4537 {
4538 MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
4539 attr | MSG_HIST);
4540 MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
4541 attr | MSG_HIST);
4542
4543 /* Update the timestamp to avoid an "overwrite changed file"
4544 * prompt when writing again. */
4545 if (mch_stat((char *)fname, &st_old) >= 0)
4546 {
4547 buf_store_time(buf, &st_old, fname);
4548 buf->b_mtime_read = buf->b_mtime;
4549 }
4550 }
4551 }
4552 msg_scroll = msg_save;
4553
4554#ifdef FEAT_AUTOCMD
4555#ifdef FEAT_EVAL
4556 if (!should_abort(retval))
4557#else
4558 if (!got_int)
4559#endif
4560 {
4561 aco_save_T aco;
4562
4563 write_no_eol_lnum = 0; /* in case it was set by the previous read */
4564
4565 /*
4566 * Apply POST autocommands.
4567 * Careful: The autocommands may call buf_write() recursively!
4568 */
4569 aucmd_prepbuf(&aco, buf);
4570
4571 if (append)
4572 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
4573 FALSE, curbuf, eap);
4574 else if (filtering)
4575 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
4576 FALSE, curbuf, eap);
4577 else if (reset_changed && whole)
4578 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
4579 FALSE, curbuf, eap);
4580 else
4581 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
4582 FALSE, curbuf, eap);
4583
4584 /* restore curwin/curbuf and a few other things */
4585 aucmd_restbuf(&aco);
4586
4587#ifdef FEAT_EVAL
4588 if (aborting()) /* autocmds may abort script processing */
4589 retval = FALSE;
4590#endif
4591 }
4592#endif
4593
4594 got_int |= prev_got_int;
4595
4596#ifdef MACOS_CLASSIC /* TODO: Is it need for MACOS_X? (Dany) */
4597 /* Update machine specific information. */
4598 mch_post_buffer_write(buf);
4599#endif
4600 return retval;
4601}
4602
4603/*
4604 * Put file name into IObuff with quotes.
4605 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004606 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607msg_add_fname(buf, fname)
4608 buf_T *buf;
4609 char_u *fname;
4610{
4611 if (fname == NULL)
4612 fname = (char_u *)"-stdin-";
4613 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
4614 IObuff[0] = '"';
4615 STRCAT(IObuff, "\" ");
4616}
4617
4618/*
4619 * Append message for text mode to IObuff.
4620 * Return TRUE if something appended.
4621 */
4622 static int
4623msg_add_fileformat(eol_type)
4624 int eol_type;
4625{
4626#ifndef USE_CRNL
4627 if (eol_type == EOL_DOS)
4628 {
4629 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
4630 return TRUE;
4631 }
4632#endif
4633#ifndef USE_CR
4634 if (eol_type == EOL_MAC)
4635 {
4636 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
4637 return TRUE;
4638 }
4639#endif
4640#if defined(USE_CRNL) || defined(USE_CR)
4641 if (eol_type == EOL_UNIX)
4642 {
4643 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
4644 return TRUE;
4645 }
4646#endif
4647 return FALSE;
4648}
4649
4650/*
4651 * Append line and character count to IObuff.
4652 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00004653 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654msg_add_lines(insert_space, lnum, nchars)
4655 int insert_space;
4656 long lnum;
4657 long nchars;
4658{
4659 char_u *p;
4660
4661 p = IObuff + STRLEN(IObuff);
4662
4663 if (insert_space)
4664 *p++ = ' ';
4665 if (shortmess(SHM_LINES))
4666 sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
4667 else
4668 {
4669 if (lnum == 1)
4670 STRCPY(p, _("1 line, "));
4671 else
4672 sprintf((char *)p, _("%ld lines, "), lnum);
4673 p += STRLEN(p);
4674 if (nchars == 1)
4675 STRCPY(p, _("1 character"));
4676 else
4677 sprintf((char *)p, _("%ld characters"), nchars);
4678 }
4679}
4680
4681/*
4682 * Append message for missing line separator to IObuff.
4683 */
4684 static void
4685msg_add_eol()
4686{
4687 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
4688}
4689
4690/*
4691 * Check modification time of file, before writing to it.
4692 * The size isn't checked, because using a tool like "gzip" takes care of
4693 * using the same timestamp but can't set the size.
4694 */
4695 static int
4696check_mtime(buf, st)
4697 buf_T *buf;
4698 struct stat *st;
4699{
4700 if (buf->b_mtime_read != 0
4701 && time_differs((long)st->st_mtime, buf->b_mtime_read))
4702 {
4703 msg_scroll = TRUE; /* don't overwrite messages here */
4704 msg_silent = 0; /* must give this prompt */
4705 /* don't use emsg() here, don't want to flush the buffers */
4706 MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
4707 hl_attr(HLF_E));
4708 if (ask_yesno((char_u *)_("Do you really want to write to it"),
4709 TRUE) == 'n')
4710 return FAIL;
4711 msg_scroll = FALSE; /* always overwrite the file message now */
4712 }
4713 return OK;
4714}
4715
4716 static int
4717time_differs(t1, t2)
4718 long t1, t2;
4719{
4720#if defined(__linux__) || defined(MSDOS) || defined(MSWIN)
4721 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
4722 * the seconds. Since the roundoff is done when flushing the inode, the
4723 * time may change unexpectedly by one second!!! */
4724 return (t1 - t2 > 1 || t2 - t1 > 1);
4725#else
4726 return (t1 != t2);
4727#endif
4728}
4729
4730/*
4731 * Call write() to write a number of bytes to the file.
4732 * Also handles encryption and 'encoding' conversion.
4733 *
4734 * Return FAIL for failure, OK otherwise.
4735 */
4736 static int
4737buf_write_bytes(ip)
4738 struct bw_info *ip;
4739{
4740 int wlen;
4741 char_u *buf = ip->bw_buf; /* data to write */
4742 int len = ip->bw_len; /* length of data */
4743#ifdef HAS_BW_FLAGS
4744 int flags = ip->bw_flags; /* extra flags */
4745#endif
4746
4747#ifdef FEAT_MBYTE
4748 /*
4749 * Skip conversion when writing the crypt magic number or the BOM.
4750 */
4751 if (!(flags & FIO_NOCONVERT))
4752 {
4753 char_u *p;
4754 unsigned c;
4755 int n;
4756
4757 if (flags & FIO_UTF8)
4758 {
4759 /*
4760 * Convert latin1 in the buffer to UTF-8 in the file.
4761 */
4762 p = ip->bw_conv_buf; /* translate to buffer */
4763 for (wlen = 0; wlen < len; ++wlen)
4764 p += utf_char2bytes(buf[wlen], p);
4765 buf = ip->bw_conv_buf;
4766 len = (int)(p - ip->bw_conv_buf);
4767 }
4768 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
4769 {
4770 /*
4771 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
4772 * Latin1 chars in the file.
4773 */
4774 if (flags & FIO_LATIN1)
4775 p = buf; /* translate in-place (can only get shorter) */
4776 else
4777 p = ip->bw_conv_buf; /* translate to buffer */
4778 for (wlen = 0; wlen < len; wlen += n)
4779 {
4780 if (wlen == 0 && ip->bw_restlen != 0)
4781 {
4782 int l;
4783
4784 /* Use remainder of previous call. Append the start of
4785 * buf[] to get a full sequence. Might still be too
4786 * short! */
4787 l = CONV_RESTLEN - ip->bw_restlen;
4788 if (l > len)
4789 l = len;
4790 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004791 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 if (n > ip->bw_restlen + len)
4793 {
4794 /* We have an incomplete byte sequence at the end to
4795 * be written. We can't convert it without the
4796 * remaining bytes. Keep them for the next call. */
4797 if (ip->bw_restlen + len > CONV_RESTLEN)
4798 return FAIL;
4799 ip->bw_restlen += len;
4800 break;
4801 }
4802 if (n > 1)
4803 c = utf_ptr2char(ip->bw_rest);
4804 else
4805 c = ip->bw_rest[0];
4806 if (n >= ip->bw_restlen)
4807 {
4808 n -= ip->bw_restlen;
4809 ip->bw_restlen = 0;
4810 }
4811 else
4812 {
4813 ip->bw_restlen -= n;
4814 mch_memmove(ip->bw_rest, ip->bw_rest + n,
4815 (size_t)ip->bw_restlen);
4816 n = 0;
4817 }
4818 }
4819 else
4820 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004821 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 if (n > len - wlen)
4823 {
4824 /* We have an incomplete byte sequence at the end to
4825 * be written. We can't convert it without the
4826 * remaining bytes. Keep them for the next call. */
4827 if (len - wlen > CONV_RESTLEN)
4828 return FAIL;
4829 ip->bw_restlen = len - wlen;
4830 mch_memmove(ip->bw_rest, buf + wlen,
4831 (size_t)ip->bw_restlen);
4832 break;
4833 }
4834 if (n > 1)
4835 c = utf_ptr2char(buf + wlen);
4836 else
4837 c = buf[wlen];
4838 }
4839
4840 ip->bw_conv_error |= ucs2bytes(c, &p, flags);
4841 }
4842 if (flags & FIO_LATIN1)
4843 len = (int)(p - buf);
4844 else
4845 {
4846 buf = ip->bw_conv_buf;
4847 len = (int)(p - ip->bw_conv_buf);
4848 }
4849 }
4850
4851# ifdef WIN3264
4852 else if (flags & FIO_CODEPAGE)
4853 {
4854 /*
4855 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
4856 * codepage.
4857 */
4858 char_u *from;
4859 size_t fromlen;
4860 char_u *to;
4861 int u8c;
4862 BOOL bad = FALSE;
4863 int needed;
4864
4865 if (ip->bw_restlen > 0)
4866 {
4867 /* Need to concatenate the remainder of the previous call and
4868 * the bytes of the current call. Use the end of the
4869 * conversion buffer for this. */
4870 fromlen = len + ip->bw_restlen;
4871 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
4872 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
4873 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
4874 }
4875 else
4876 {
4877 from = buf;
4878 fromlen = len;
4879 }
4880
4881 to = ip->bw_conv_buf;
4882 if (enc_utf8)
4883 {
4884 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
4885 * The buffer has been allocated to be big enough. */
4886 while (fromlen > 0)
4887 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004888 n = utf_ptr2len_len(from, fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 if (n > (int)fromlen) /* incomplete byte sequence */
4890 break;
4891 u8c = utf_ptr2char(from);
4892 *to++ = (u8c & 0xff);
4893 *to++ = (u8c >> 8);
4894 fromlen -= n;
4895 from += n;
4896 }
4897
4898 /* Copy remainder to ip->bw_rest[] to be used for the next
4899 * call. */
4900 if (fromlen > CONV_RESTLEN)
4901 {
4902 /* weird overlong sequence */
4903 ip->bw_conv_error = TRUE;
4904 return FAIL;
4905 }
4906 mch_memmove(ip->bw_rest, from, fromlen);
4907 ip->bw_restlen = fromlen;
4908 }
4909 else
4910 {
4911 /* Convert from enc_codepage to UCS-2, to the start of the
4912 * buffer. The buffer has been allocated to be big enough. */
4913 ip->bw_restlen = 0;
4914 needed = MultiByteToWideChar(enc_codepage,
4915 MB_ERR_INVALID_CHARS, (LPCSTR)from, fromlen,
4916 NULL, 0);
4917 if (needed == 0)
4918 {
4919 /* When conversion fails there may be a trailing byte. */
4920 needed = MultiByteToWideChar(enc_codepage,
4921 MB_ERR_INVALID_CHARS, (LPCSTR)from, fromlen - 1,
4922 NULL, 0);
4923 if (needed == 0)
4924 {
4925 /* Conversion doesn't work. */
4926 ip->bw_conv_error = TRUE;
4927 return FAIL;
4928 }
4929 /* Save the trailing byte for the next call. */
4930 ip->bw_rest[0] = from[fromlen - 1];
4931 ip->bw_restlen = 1;
4932 }
4933 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
4934 (LPCSTR)from, fromlen - ip->bw_restlen,
4935 (LPWSTR)to, needed);
4936 if (needed == 0)
4937 {
4938 /* Safety check: Conversion doesn't work. */
4939 ip->bw_conv_error = TRUE;
4940 return FAIL;
4941 }
4942 to += needed * 2;
4943 }
4944
4945 fromlen = to - ip->bw_conv_buf;
4946 buf = to;
4947# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
4948 if (FIO_GET_CP(flags) == CP_UTF8)
4949 {
4950 /* Convert from UCS-2 to UTF-8, using the remainder of the
4951 * conversion buffer. Fails when out of space. */
4952 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
4953 {
4954 u8c = *from++;
4955 u8c += (*from++ << 8);
4956 to += utf_char2bytes(u8c, to);
4957 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
4958 {
4959 ip->bw_conv_error = TRUE;
4960 return FAIL;
4961 }
4962 }
4963 len = to - buf;
4964 }
4965 else
4966#endif
4967 {
4968 /* Convert from UCS-2 to the codepage, using the remainder of
4969 * the conversion buffer. If the conversion uses the default
4970 * character "0", the data doesn't fit in this encoding, so
4971 * fail. */
4972 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
4973 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
4974 (LPSTR)to, ip->bw_conv_buflen - fromlen, 0, &bad);
4975 if (bad)
4976 {
4977 ip->bw_conv_error = TRUE;
4978 return FAIL;
4979 }
4980 }
4981 }
4982# endif
4983
4984# ifdef MACOS_X
4985 else if (flags & FIO_MACROMAN)
4986 {
4987 /*
4988 * Convert UTF-8 or latin1 to Apple MacRoman.
4989 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990 char_u *from;
4991 size_t fromlen;
4992
4993 if (ip->bw_restlen > 0)
4994 {
4995 /* Need to concatenate the remainder of the previous call and
4996 * the bytes of the current call. Use the end of the
4997 * conversion buffer for this. */
4998 fromlen = len + ip->bw_restlen;
4999 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5000 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5001 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5002 }
5003 else
5004 {
5005 from = buf;
5006 fromlen = len;
5007 }
5008
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005009 if (enc2macroman(from, fromlen,
5010 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5011 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 {
5013 ip->bw_conv_error = TRUE;
5014 return FAIL;
5015 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 }
5018# endif
5019
5020# ifdef USE_ICONV
5021 if (ip->bw_iconv_fd != (iconv_t)-1)
5022 {
5023 const char *from;
5024 size_t fromlen;
5025 char *to;
5026 size_t tolen;
5027
5028 /* Convert with iconv(). */
5029 if (ip->bw_restlen > 0)
5030 {
5031 /* Need to concatenate the remainder of the previous call and
5032 * the bytes of the current call. Use the end of the
5033 * conversion buffer for this. */
5034 fromlen = len + ip->bw_restlen;
5035 from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5036 mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
5037 mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
5038 tolen = ip->bw_conv_buflen - fromlen;
5039 }
5040 else
5041 {
5042 from = (const char *)buf;
5043 fromlen = len;
5044 tolen = ip->bw_conv_buflen;
5045 }
5046 to = (char *)ip->bw_conv_buf;
5047
5048 if (ip->bw_first)
5049 {
5050 size_t save_len = tolen;
5051
5052 /* output the initial shift state sequence */
5053 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5054
5055 /* There is a bug in iconv() on Linux (which appears to be
5056 * wide-spread) which sets "to" to NULL and messes up "tolen".
5057 */
5058 if (to == NULL)
5059 {
5060 to = (char *)ip->bw_conv_buf;
5061 tolen = save_len;
5062 }
5063 ip->bw_first = FALSE;
5064 }
5065
5066 /*
5067 * If iconv() has an error or there is not enough room, fail.
5068 */
5069 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5070 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5071 || fromlen > CONV_RESTLEN)
5072 {
5073 ip->bw_conv_error = TRUE;
5074 return FAIL;
5075 }
5076
5077 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5078 if (fromlen > 0)
5079 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5080 ip->bw_restlen = (int)fromlen;
5081
5082 buf = ip->bw_conv_buf;
5083 len = (int)((char_u *)to - ip->bw_conv_buf);
5084 }
5085# endif
5086 }
5087#endif /* FEAT_MBYTE */
5088
5089#ifdef FEAT_CRYPT
5090 if (flags & FIO_ENCRYPTED) /* encrypt the data */
5091 {
5092 int ztemp, t, i;
5093
5094 for (i = 0; i < len; i++)
5095 {
5096 ztemp = buf[i];
5097 buf[i] = ZENCODE(ztemp, t);
5098 }
5099 }
5100#endif
5101
5102 /* Repeat the write(), it may be interrupted by a signal. */
5103 while (len)
5104 {
5105 wlen = vim_write(ip->bw_fd, buf, len);
5106 if (wlen <= 0) /* error! */
5107 return FAIL;
5108 len -= wlen;
5109 buf += wlen;
5110 }
5111 return OK;
5112}
5113
5114#ifdef FEAT_MBYTE
5115/*
5116 * Convert a Unicode character to bytes.
5117 */
5118 static int
5119ucs2bytes(c, pp, flags)
5120 unsigned c; /* in: character */
5121 char_u **pp; /* in/out: pointer to result */
5122 int flags; /* FIO_ flags */
5123{
5124 char_u *p = *pp;
5125 int error = FALSE;
5126 int cc;
5127
5128
5129 if (flags & FIO_UCS4)
5130 {
5131 if (flags & FIO_ENDIAN_L)
5132 {
5133 *p++ = c;
5134 *p++ = (c >> 8);
5135 *p++ = (c >> 16);
5136 *p++ = (c >> 24);
5137 }
5138 else
5139 {
5140 *p++ = (c >> 24);
5141 *p++ = (c >> 16);
5142 *p++ = (c >> 8);
5143 *p++ = c;
5144 }
5145 }
5146 else if (flags & (FIO_UCS2 | FIO_UTF16))
5147 {
5148 if (c >= 0x10000)
5149 {
5150 if (flags & FIO_UTF16)
5151 {
5152 /* Make two words, ten bits of the character in each. First
5153 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5154 c -= 0x10000;
5155 if (c >= 0x100000)
5156 error = TRUE;
5157 cc = ((c >> 10) & 0x3ff) + 0xd800;
5158 if (flags & FIO_ENDIAN_L)
5159 {
5160 *p++ = cc;
5161 *p++ = ((unsigned)cc >> 8);
5162 }
5163 else
5164 {
5165 *p++ = ((unsigned)cc >> 8);
5166 *p++ = cc;
5167 }
5168 c = (c & 0x3ff) + 0xdc00;
5169 }
5170 else
5171 error = TRUE;
5172 }
5173 if (flags & FIO_ENDIAN_L)
5174 {
5175 *p++ = c;
5176 *p++ = (c >> 8);
5177 }
5178 else
5179 {
5180 *p++ = (c >> 8);
5181 *p++ = c;
5182 }
5183 }
5184 else /* Latin1 */
5185 {
5186 if (c >= 0x100)
5187 {
5188 error = TRUE;
5189 *p++ = 0xBF;
5190 }
5191 else
5192 *p++ = c;
5193 }
5194
5195 *pp = p;
5196 return error;
5197}
5198
5199/*
5200 * Return TRUE if "a" and "b" are the same 'encoding'.
5201 * Ignores difference between "ansi" and "latin1", "ucs-4" and "ucs-4be", etc.
5202 */
5203 static int
5204same_encoding(a, b)
5205 char_u *a;
5206 char_u *b;
5207{
5208 int f;
5209
5210 if (STRCMP(a, b) == 0)
5211 return TRUE;
5212 f = get_fio_flags(a);
5213 return (f != 0 && get_fio_flags(b) == f);
5214}
5215
5216/*
5217 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5218 * internal conversion.
5219 * if "ptr" is an empty string, use 'encoding'.
5220 */
5221 static int
5222get_fio_flags(ptr)
5223 char_u *ptr;
5224{
5225 int prop;
5226
5227 if (*ptr == NUL)
5228 ptr = p_enc;
5229
5230 prop = enc_canon_props(ptr);
5231 if (prop & ENC_UNICODE)
5232 {
5233 if (prop & ENC_2BYTE)
5234 {
5235 if (prop & ENC_ENDIAN_L)
5236 return FIO_UCS2 | FIO_ENDIAN_L;
5237 return FIO_UCS2;
5238 }
5239 if (prop & ENC_4BYTE)
5240 {
5241 if (prop & ENC_ENDIAN_L)
5242 return FIO_UCS4 | FIO_ENDIAN_L;
5243 return FIO_UCS4;
5244 }
5245 if (prop & ENC_2WORD)
5246 {
5247 if (prop & ENC_ENDIAN_L)
5248 return FIO_UTF16 | FIO_ENDIAN_L;
5249 return FIO_UTF16;
5250 }
5251 return FIO_UTF8;
5252 }
5253 if (prop & ENC_LATIN1)
5254 return FIO_LATIN1;
5255 /* must be ENC_DBCS, requires iconv() */
5256 return 0;
5257}
5258
5259#ifdef WIN3264
5260/*
5261 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5262 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5263 * Used for conversion between 'encoding' and 'fileencoding'.
5264 */
5265 static int
5266get_win_fio_flags(ptr)
5267 char_u *ptr;
5268{
5269 int cp;
5270
5271 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5272 if (!enc_utf8 && enc_codepage <= 0)
5273 return 0;
5274
5275 cp = encname2codepage(ptr);
5276 if (cp == 0)
5277 {
5278# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5279 if (STRCMP(ptr, "utf-8") == 0)
5280 cp = CP_UTF8;
5281 else
5282# endif
5283 return 0;
5284 }
5285 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5286}
5287#endif
5288
5289#ifdef MACOS_X
5290/*
5291 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5292 * needed for the internal conversion to/from utf-8 or latin1.
5293 */
5294 static int
5295get_mac_fio_flags(ptr)
5296 char_u *ptr;
5297{
5298 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5299 && (enc_canon_props(ptr) & ENC_MACROMAN))
5300 return FIO_MACROMAN;
5301 return 0;
5302}
5303#endif
5304
5305/*
5306 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5307 * "size" must be at least 2.
5308 * Return the name of the encoding and set "*lenp" to the length.
5309 * Returns NULL when no BOM found.
5310 */
5311 static char_u *
5312check_for_bom(p, size, lenp, flags)
5313 char_u *p;
5314 long size;
5315 int *lenp;
5316 int flags;
5317{
5318 char *name = NULL;
5319 int len = 2;
5320
5321 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
5322 && (flags == FIO_ALL || flags == 0))
5323 {
5324 name = "utf-8"; /* EF BB BF */
5325 len = 3;
5326 }
5327 else if (p[0] == 0xff && p[1] == 0xfe)
5328 {
5329 if (size >= 4 && p[2] == 0 && p[3] == 0
5330 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5331 {
5332 name = "ucs-4le"; /* FF FE 00 00 */
5333 len = 4;
5334 }
5335 else if (flags == FIO_ALL || flags == (FIO_UCS2 | FIO_ENDIAN_L))
5336 name = "ucs-2le"; /* FF FE */
5337 else if (flags == (FIO_UTF16 | FIO_ENDIAN_L))
5338 name = "utf-16le"; /* FF FE */
5339 }
5340 else if (p[0] == 0xfe && p[1] == 0xff
5341 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5342 {
5343 if (flags == FIO_UTF16)
5344 name = "utf-16"; /* FE FF */
5345 else
5346 name = "ucs-2"; /* FE FF */
5347 }
5348 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5349 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5350 {
5351 name = "ucs-4"; /* 00 00 FE FF */
5352 len = 4;
5353 }
5354
5355 *lenp = len;
5356 return (char_u *)name;
5357}
5358
5359/*
5360 * Generate a BOM in "buf[4]" for encoding "name".
5361 * Return the length of the BOM (zero when no BOM).
5362 */
5363 static int
5364make_bom(buf, name)
5365 char_u *buf;
5366 char_u *name;
5367{
5368 int flags;
5369 char_u *p;
5370
5371 flags = get_fio_flags(name);
5372
5373 /* Can't put a BOM in a non-Unicode file. */
5374 if (flags == FIO_LATIN1 || flags == 0)
5375 return 0;
5376
5377 if (flags == FIO_UTF8) /* UTF-8 */
5378 {
5379 buf[0] = 0xef;
5380 buf[1] = 0xbb;
5381 buf[2] = 0xbf;
5382 return 3;
5383 }
5384 p = buf;
5385 (void)ucs2bytes(0xfeff, &p, flags);
5386 return (int)(p - buf);
5387}
5388#endif
5389
5390/*
5391 * Try to find a shortname by comparing the fullname with the current
5392 * directory.
5393 * Returns NULL if not shorter name possible, pointer into "full_path"
5394 * otherwise.
5395 */
5396 char_u *
5397shorten_fname(full_path, dir_name)
5398 char_u *full_path;
5399 char_u *dir_name;
5400{
5401 int len;
5402 char_u *p;
5403
5404 if (full_path == NULL)
5405 return NULL;
5406 len = (int)STRLEN(dir_name);
5407 if (fnamencmp(dir_name, full_path, len) == 0)
5408 {
5409 p = full_path + len;
5410#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5411 /*
5412 * MSDOS: when a file is in the root directory, dir_name will end in a
5413 * slash, since C: by itself does not define a specific dir. In this
5414 * case p may already be correct. <negri>
5415 */
5416 if (!((len > 2) && (*(p - 2) == ':')))
5417#endif
5418 {
5419 if (vim_ispathsep(*p))
5420 ++p;
5421#ifndef VMS /* the path separator is always part of the path */
5422 else
5423 p = NULL;
5424#endif
5425 }
5426 }
5427#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
5428 /*
5429 * When using a file in the current drive, remove the drive name:
5430 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
5431 * a floppy from "A:\dir" to "B:\dir".
5432 */
5433 else if (len > 3
5434 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
5435 && full_path[1] == ':'
5436 && vim_ispathsep(full_path[2]))
5437 p = full_path + 2;
5438#endif
5439 else
5440 p = NULL;
5441 return p;
5442}
5443
5444/*
5445 * Shorten filenames for all buffers.
5446 * When "force" is TRUE: Use full path from now on for files currently being
5447 * edited, both for file name and swap file name. Try to shorten the file
5448 * names a bit, if safe to do so.
5449 * When "force" is FALSE: Only try to shorten absolute file names.
5450 * For buffers that have buftype "nofile" or "scratch": never change the file
5451 * name.
5452 */
5453 void
5454shorten_fnames(force)
5455 int force;
5456{
5457 char_u dirname[MAXPATHL];
5458 buf_T *buf;
5459 char_u *p;
5460
5461 mch_dirname(dirname, MAXPATHL);
5462 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5463 {
5464 if (buf->b_fname != NULL
5465#ifdef FEAT_QUICKFIX
5466 && !bt_nofile(buf)
5467#endif
5468 && !path_with_url(buf->b_fname)
5469 && (force
5470 || buf->b_sfname == NULL
5471 || mch_isFullName(buf->b_sfname)))
5472 {
5473 vim_free(buf->b_sfname);
5474 buf->b_sfname = NULL;
5475 p = shorten_fname(buf->b_ffname, dirname);
5476 if (p != NULL)
5477 {
5478 buf->b_sfname = vim_strsave(p);
5479 buf->b_fname = buf->b_sfname;
5480 }
5481 if (p == NULL || buf->b_fname == NULL)
5482 buf->b_fname = buf->b_ffname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005484
5485 /* Always make the swap file name a full path, a "nofile" buffer may
5486 * also have a swap file. */
5487 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005488 }
5489#ifdef FEAT_WINDOWS
5490 status_redraw_all();
5491#endif
5492}
5493
5494#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5495 || defined(FEAT_GUI_MSWIN) \
5496 || defined(FEAT_GUI_MAC) \
5497 || defined(PROTO)
5498/*
5499 * Shorten all filenames in "fnames[count]" by current directory.
5500 */
5501 void
5502shorten_filenames(fnames, count)
5503 char_u **fnames;
5504 int count;
5505{
5506 int i;
5507 char_u dirname[MAXPATHL];
5508 char_u *p;
5509
5510 if (fnames == NULL || count < 1)
5511 return;
5512 mch_dirname(dirname, sizeof(dirname));
5513 for (i = 0; i < count; ++i)
5514 {
5515 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
5516 {
5517 /* shorten_fname() returns pointer in given "fnames[i]". If free
5518 * "fnames[i]" first, "p" becomes invalid. So we need to copy
5519 * "p" first then free fnames[i]. */
5520 p = vim_strsave(p);
5521 vim_free(fnames[i]);
5522 fnames[i] = p;
5523 }
5524 }
5525}
5526#endif
5527
5528/*
5529 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
5530 * fo_o_h.ext for MSDOS or when shortname option set.
5531 *
5532 * Assumed that fname is a valid name found in the filesystem we assure that
5533 * the return value is a different name and ends in 'ext'.
5534 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
5535 * characters otherwise.
5536 * Space for the returned name is allocated, must be freed later.
5537 * Returns NULL when out of memory.
5538 */
5539 char_u *
5540modname(fname, ext, prepend_dot)
5541 char_u *fname, *ext;
5542 int prepend_dot; /* may prepend a '.' to file name */
5543{
5544 return buf_modname(
5545#ifdef SHORT_FNAME
5546 TRUE,
5547#else
5548 (curbuf->b_p_sn || curbuf->b_shortname),
5549#endif
5550 fname, ext, prepend_dot);
5551}
5552
5553 char_u *
5554buf_modname(shortname, fname, ext, prepend_dot)
5555 int shortname; /* use 8.3 file name */
5556 char_u *fname, *ext;
5557 int prepend_dot; /* may prepend a '.' to file name */
5558{
5559 char_u *retval;
5560 char_u *s;
5561 char_u *e;
5562 char_u *ptr;
5563 int fnamelen, extlen;
5564
5565 extlen = (int)STRLEN(ext);
5566
5567 /*
5568 * If there is no file name we must get the name of the current directory
5569 * (we need the full path in case :cd is used).
5570 */
5571 if (fname == NULL || *fname == NUL)
5572 {
5573 retval = alloc((unsigned)(MAXPATHL + extlen + 3));
5574 if (retval == NULL)
5575 return NULL;
5576 if (mch_dirname(retval, MAXPATHL) == FAIL ||
5577 (fnamelen = (int)STRLEN(retval)) == 0)
5578 {
5579 vim_free(retval);
5580 return NULL;
5581 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005582 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005583 {
5584 retval[fnamelen++] = PATHSEP;
5585 retval[fnamelen] = NUL;
5586 }
5587#ifndef SHORT_FNAME
5588 prepend_dot = FALSE; /* nothing to prepend a dot to */
5589#endif
5590 }
5591 else
5592 {
5593 fnamelen = (int)STRLEN(fname);
5594 retval = alloc((unsigned)(fnamelen + extlen + 3));
5595 if (retval == NULL)
5596 return NULL;
5597 STRCPY(retval, fname);
5598#ifdef VMS
5599 vms_remove_version(retval); /* we do not need versions here */
5600#endif
5601 }
5602
5603 /*
5604 * search backwards until we hit a '/', '\' or ':' replacing all '.'
5605 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
5606 * Then truncate what is after the '/', '\' or ':' to 8 characters for
5607 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
5608 */
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005609 for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005610 {
5611#ifndef RISCOS
5612 if (*ext == '.'
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005613# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005614 && (!USE_LONG_FNAME || shortname)
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005615# else
5616# ifndef SHORT_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 && shortname
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005618# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005620 )
5621 if (*ptr == '.') /* replace '.' by '_' */
5622 *ptr = '_';
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005623#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005625 {
5626 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005627 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00005628 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630
5631 /* the file name has at most BASENAMELEN characters. */
5632#ifndef SHORT_FNAME
5633 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
5634 ptr[BASENAMELEN] = '\0';
5635#endif
5636
5637 s = ptr + STRLEN(ptr);
5638
5639 /*
5640 * For 8.3 file names we may have to reduce the length.
5641 */
5642#ifdef USE_LONG_FNAME
5643 if (!USE_LONG_FNAME || shortname)
5644#else
5645# ifndef SHORT_FNAME
5646 if (shortname)
5647# endif
5648#endif
5649 {
5650 /*
5651 * If there is no file name, or the file name ends in '/', and the
5652 * extension starts with '.', put a '_' before the dot, because just
5653 * ".ext" is invalid.
5654 */
5655 if (fname == NULL || *fname == NUL
5656 || vim_ispathsep(fname[STRLEN(fname) - 1]))
5657 {
5658#ifdef RISCOS
5659 if (*ext == '/')
5660#else
5661 if (*ext == '.')
5662#endif
5663 *s++ = '_';
5664 }
5665 /*
5666 * If the extension starts with '.', truncate the base name at 8
5667 * characters
5668 */
5669#ifdef RISCOS
5670 /* We normally use '/', but swap files are '_' */
5671 else if (*ext == '/' || *ext == '_')
5672#else
5673 else if (*ext == '.')
5674#endif
5675 {
5676 if (s - ptr > (size_t)8)
5677 {
5678 s = ptr + 8;
5679 *s = '\0';
5680 }
5681 }
5682 /*
5683 * If the extension doesn't start with '.', and the file name
5684 * doesn't have an extension yet, append a '.'
5685 */
5686#ifdef RISCOS
5687 else if ((e = vim_strchr(ptr, '/')) == NULL)
5688 *s++ = '/';
5689#else
5690 else if ((e = vim_strchr(ptr, '.')) == NULL)
5691 *s++ = '.';
5692#endif
5693 /*
5694 * If the extension doesn't start with '.', and there already is an
5695 * extension, it may need to be tructated
5696 */
5697 else if ((int)STRLEN(e) + extlen > 4)
5698 s = e + 4 - extlen;
5699 }
5700#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN3264)
5701 /*
5702 * If there is no file name, and the extension starts with '.', put a
5703 * '_' before the dot, because just ".ext" may be invalid if it's on a
5704 * FAT partition, and on HPFS it doesn't matter.
5705 */
5706 else if ((fname == NULL || *fname == NUL) && *ext == '.')
5707 *s++ = '_';
5708#endif
5709
5710 /*
5711 * Append the extention.
5712 * ext can start with '.' and cannot exceed 3 more characters.
5713 */
5714 STRCPY(s, ext);
5715
5716#ifndef SHORT_FNAME
5717 /*
5718 * Prepend the dot.
5719 */
5720 if (prepend_dot && !shortname && *(e = gettail(retval)) !=
5721#ifdef RISCOS
5722 '/'
5723#else
5724 '.'
5725#endif
5726#ifdef USE_LONG_FNAME
5727 && USE_LONG_FNAME
5728#endif
5729 )
5730 {
5731 mch_memmove(e + 1, e, STRLEN(e) + 1);
5732#ifdef RISCOS
5733 *e = '/';
5734#else
5735 *e = '.';
5736#endif
5737 }
5738#endif
5739
5740 /*
5741 * Check that, after appending the extension, the file name is really
5742 * different.
5743 */
5744 if (fname != NULL && STRCMP(fname, retval) == 0)
5745 {
5746 /* we search for a character that can be replaced by '_' */
5747 while (--s >= ptr)
5748 {
5749 if (*s != '_')
5750 {
5751 *s = '_';
5752 break;
5753 }
5754 }
5755 if (s < ptr) /* fname was "________.<ext>", how tricky! */
5756 *ptr = 'v';
5757 }
5758 return retval;
5759}
5760
5761/*
5762 * Like fgets(), but if the file line is too long, it is truncated and the
5763 * rest of the line is thrown away. Returns TRUE for end-of-file.
5764 */
5765 int
5766vim_fgets(buf, size, fp)
5767 char_u *buf;
5768 int size;
5769 FILE *fp;
5770{
5771 char *eof;
5772#define FGETS_SIZE 200
5773 char tbuf[FGETS_SIZE];
5774
5775 buf[size - 2] = NUL;
5776#ifdef USE_CR
5777 eof = fgets_cr((char *)buf, size, fp);
5778#else
5779 eof = fgets((char *)buf, size, fp);
5780#endif
5781 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
5782 {
5783 buf[size - 1] = NUL; /* Truncate the line */
5784
5785 /* Now throw away the rest of the line: */
5786 do
5787 {
5788 tbuf[FGETS_SIZE - 2] = NUL;
5789#ifdef USE_CR
5790 fgets_cr((char *)tbuf, FGETS_SIZE, fp);
5791#else
5792 fgets((char *)tbuf, FGETS_SIZE, fp);
5793#endif
5794 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
5795 }
5796 return (eof == NULL);
5797}
5798
5799#if defined(USE_CR) || defined(PROTO)
5800/*
5801 * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
5802 * Returns TRUE for end-of-file.
5803 * Only used for the Mac, because it's much slower than vim_fgets().
5804 */
5805 int
5806tag_fgets(buf, size, fp)
5807 char_u *buf;
5808 int size;
5809 FILE *fp;
5810{
5811 int i = 0;
5812 int c;
5813 int eof = FALSE;
5814
5815 for (;;)
5816 {
5817 c = fgetc(fp);
5818 if (c == EOF)
5819 {
5820 eof = TRUE;
5821 break;
5822 }
5823 if (c == '\r')
5824 {
5825 /* Always store a NL for end-of-line. */
5826 if (i < size - 1)
5827 buf[i++] = '\n';
5828 c = fgetc(fp);
5829 if (c != '\n') /* Macintosh format: single CR. */
5830 ungetc(c, fp);
5831 break;
5832 }
5833 if (i < size - 1)
5834 buf[i++] = c;
5835 if (c == '\n')
5836 break;
5837 }
5838 buf[i] = NUL;
5839 return eof;
5840}
5841#endif
5842
5843/*
5844 * rename() only works if both files are on the same file system, this
5845 * function will (attempts to?) copy the file across if rename fails -- webb
5846 * Return -1 for failure, 0 for success.
5847 */
5848 int
5849vim_rename(from, to)
5850 char_u *from;
5851 char_u *to;
5852{
5853 int fd_in;
5854 int fd_out;
5855 int n;
5856 char *errmsg = NULL;
5857 char *buffer;
5858#ifdef AMIGA
5859 BPTR flock;
5860#endif
5861 struct stat st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005862 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005863#ifdef HAVE_ACL
5864 vim_acl_T acl; /* ACL from original file */
5865#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005866
5867 /*
5868 * When the names are identical, there is nothing to do.
5869 */
5870 if (fnamecmp(from, to) == 0)
5871 return 0;
5872
5873 /*
5874 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
5875 */
5876 if (mch_stat((char *)from, &st) < 0)
5877 return -1;
5878
5879 /*
5880 * Delete the "to" file, this is required on some systems to make the
5881 * mch_rename() work, on other systems it makes sure that we don't have
5882 * two files when the mch_rename() fails.
5883 */
5884
5885#ifdef AMIGA
5886 /*
5887 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
5888 * that the name of the "to" file is the same as the "from" file, even
5889 * though the names are different. To avoid the chance of accidently
5890 * deleting the "from" file (horror!) we lock it during the remove.
5891 *
5892 * When used for making a backup before writing the file: This should not
5893 * happen with ":w", because startscript() should detect this problem and
5894 * set buf->b_shortname, causing modname() to return a correct ".bak" file
5895 * name. This problem does exist with ":w filename", but then the
5896 * original file will be somewhere else so the backup isn't really
5897 * important. If autoscripting is off the rename may fail.
5898 */
5899 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
5900#endif
5901 mch_remove(to);
5902#ifdef AMIGA
5903 if (flock)
5904 UnLock(flock);
5905#endif
5906
5907 /*
5908 * First try a normal rename, return if it works.
5909 */
5910 if (mch_rename((char *)from, (char *)to) == 0)
5911 return 0;
5912
5913 /*
5914 * Rename() failed, try copying the file.
5915 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005916 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005917#ifdef HAVE_ACL
5918 /* For systems that support ACL: get the ACL from the original file. */
5919 acl = mch_get_acl(from);
5920#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005921 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
5922 if (fd_in == -1)
5923 return -1;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005924
5925 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00005926 fd_out = mch_open((char *)to,
5927 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928 if (fd_out == -1)
5929 {
5930 close(fd_in);
5931 return -1;
5932 }
5933
5934 buffer = (char *)alloc(BUFSIZE);
5935 if (buffer == NULL)
5936 {
5937 close(fd_in);
5938 close(fd_out);
5939 return -1;
5940 }
5941
5942 while ((n = vim_read(fd_in, buffer, BUFSIZE)) > 0)
5943 if (vim_write(fd_out, buffer, n) != n)
5944 {
5945 errmsg = _("E208: Error writing to \"%s\"");
5946 break;
5947 }
5948
5949 vim_free(buffer);
5950 close(fd_in);
5951 if (close(fd_out) < 0)
5952 errmsg = _("E209: Error closing \"%s\"");
5953 if (n < 0)
5954 {
5955 errmsg = _("E210: Error reading \"%s\"");
5956 to = from;
5957 }
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005958#ifndef UNIX /* for Unix mch_open() already set ther permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00005959 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00005960#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00005961#ifdef HAVE_ACL
5962 mch_set_acl(to, acl);
5963#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964 if (errmsg != NULL)
5965 {
5966 EMSG2(errmsg, to);
5967 return -1;
5968 }
5969 mch_remove(from);
5970 return 0;
5971}
5972
5973static int already_warned = FALSE;
5974
5975/*
5976 * Check if any not hidden buffer has been changed.
5977 * Postpone the check if there are characters in the stuff buffer, a global
5978 * command is being executed, a mapping is being executed or an autocommand is
5979 * busy.
5980 * Returns TRUE if some message was written (screen should be redrawn and
5981 * cursor positioned).
5982 */
5983 int
5984check_timestamps(focus)
5985 int focus; /* called for GUI focus event */
5986{
5987 buf_T *buf;
5988 int didit = 0;
5989 int n;
5990
5991 /* Don't check timestamps while system() or another low-level function may
5992 * cause us to lose and gain focus. */
5993 if (no_check_timestamps > 0)
5994 return FALSE;
5995
5996 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
5997 * event and we would keep on checking if the file is steadily growing.
5998 * Do check again after typing something. */
5999 if (focus && did_check_timestamps)
6000 {
6001 need_check_timestamps = TRUE;
6002 return FALSE;
6003 }
6004
6005 if (!stuff_empty() || global_busy || !typebuf_typed()
6006#ifdef FEAT_AUTOCMD
6007 || autocmd_busy
6008#endif
6009 )
6010 need_check_timestamps = TRUE; /* check later */
6011 else
6012 {
6013 ++no_wait_return;
6014 did_check_timestamps = TRUE;
6015 already_warned = FALSE;
6016 for (buf = firstbuf; buf != NULL; )
6017 {
6018 /* Only check buffers in a window. */
6019 if (buf->b_nwindows > 0)
6020 {
6021 n = buf_check_timestamp(buf, focus);
6022 if (didit < n)
6023 didit = n;
6024 if (n > 0 && !buf_valid(buf))
6025 {
6026 /* Autocommands have removed the buffer, start at the
6027 * first one again. */
6028 buf = firstbuf;
6029 continue;
6030 }
6031 }
6032 buf = buf->b_next;
6033 }
6034 --no_wait_return;
6035 need_check_timestamps = FALSE;
6036 if (need_wait_return && didit == 2)
6037 {
6038 /* make sure msg isn't overwritten */
6039 msg_puts((char_u *)"\n");
6040 out_flush();
6041 }
6042 }
6043 return didit;
6044}
6045
6046/*
6047 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6048 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6049 * empty.
6050 */
6051 static int
6052move_lines(frombuf, tobuf)
6053 buf_T *frombuf;
6054 buf_T *tobuf;
6055{
6056 buf_T *tbuf = curbuf;
6057 int retval = OK;
6058 linenr_T lnum;
6059 char_u *p;
6060
6061 /* Copy the lines in "frombuf" to "tobuf". */
6062 curbuf = tobuf;
6063 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6064 {
6065 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6066 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6067 {
6068 vim_free(p);
6069 retval = FAIL;
6070 break;
6071 }
6072 vim_free(p);
6073 }
6074
6075 /* Delete all the lines in "frombuf". */
6076 if (retval != FAIL)
6077 {
6078 curbuf = frombuf;
6079 while (!bufempty())
6080 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE) == FAIL)
6081 {
6082 /* Oops! We could try putting back the saved lines, but that
6083 * might fail again... */
6084 retval = FAIL;
6085 break;
6086 }
6087 }
6088
6089 curbuf = tbuf;
6090 return retval;
6091}
6092
6093/*
6094 * Check if buffer "buf" has been changed.
6095 * Also check if the file for a new buffer unexpectedly appeared.
6096 * return 1 if a changed buffer was found.
6097 * return 2 if a message has been displayed.
6098 * return 0 otherwise.
6099 */
6100/*ARGSUSED*/
6101 int
6102buf_check_timestamp(buf, focus)
6103 buf_T *buf;
6104 int focus; /* called for GUI focus event */
6105{
6106 struct stat st;
6107 int stat_res;
6108 int retval = 0;
6109 char_u *path;
6110 char_u *tbuf;
6111 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006112 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006113 int helpmesg = FALSE;
6114 int reload = FALSE;
6115#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6116 int can_reload = FALSE;
6117#endif
6118 size_t orig_size = buf->b_orig_size;
6119 int orig_mode = buf->b_orig_mode;
6120#ifdef FEAT_GUI
6121 int save_mouse_correct = need_mouse_correct;
6122#endif
6123#ifdef FEAT_AUTOCMD
6124 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006125 int n;
6126 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006127#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006128 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006129
6130 /* If there is no file name, the buffer is not loaded, 'buftype' is
6131 * set, we are in the middle of a save or being called recursively: ignore
6132 * this buffer. */
6133 if (buf->b_ffname == NULL
6134 || buf->b_ml.ml_mfp == NULL
6135#if defined(FEAT_QUICKFIX)
6136 || *buf->b_p_bt != NUL
6137#endif
6138 || buf->b_saving
6139#ifdef FEAT_AUTOCMD
6140 || busy
6141#endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00006142#ifdef FEAT_NETBEANS_INTG
6143 || isNetbeansBuffer(buf)
6144#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006145 )
6146 return 0;
6147
6148 if ( !(buf->b_flags & BF_NOTEDITED)
6149 && buf->b_mtime != 0
6150 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6151 || time_differs((long)st.st_mtime, buf->b_mtime)
6152#ifdef HAVE_ST_MODE
6153 || (int)st.st_mode != buf->b_orig_mode
6154#else
6155 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6156#endif
6157 ))
6158 {
6159 retval = 1;
6160
6161 /* set b_mtime to stop further warnings */
6162 if (stat_res < 0)
6163 {
6164 buf->b_mtime = 0;
6165 buf->b_orig_size = 0;
6166 buf->b_orig_mode = 0;
6167 }
6168 else
6169 buf_store_time(buf, &st, buf->b_ffname);
6170
6171 /* Don't do anything for a directory. Might contain the file
6172 * explorer. */
6173 if (mch_isdir(buf->b_fname))
6174 ;
6175
6176 /*
6177 * If 'autoread' is set, the buffer has no changes and the file still
6178 * exists, reload the buffer. Use the buffer-local option value if it
6179 * was set, the global option value otherwise.
6180 */
6181 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6182 && !bufIsChanged(buf) && stat_res >= 0)
6183 reload = TRUE;
6184 else
6185 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006186 if (stat_res < 0)
6187 reason = "deleted";
6188 else if (bufIsChanged(buf))
6189 reason = "conflict";
6190 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6191 reason = "changed";
6192 else if (orig_mode != buf->b_orig_mode)
6193 reason = "mode";
6194 else
6195 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006197#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198 /*
6199 * Only give the warning if there are no FileChangedShell
6200 * autocommands.
6201 * Avoid being called recursively by setting "busy".
6202 */
6203 busy = TRUE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00006204# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006205 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6206 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaar1e015462005-09-25 22:16:38 +00006207# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6209 buf->b_fname, buf->b_fname, FALSE, buf);
6210 busy = FALSE;
6211 if (n)
6212 {
6213 if (!buf_valid(buf))
6214 EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaar1e015462005-09-25 22:16:38 +00006215# ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006216 s = get_vim_var_str(VV_FCS_CHOICE);
6217 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6218 reload = TRUE;
6219 else if (STRCMP(s, "ask") == 0)
6220 n = FALSE;
6221 else
Bram Moolenaar1e015462005-09-25 22:16:38 +00006222# endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006223 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006224 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006225 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226#endif
6227 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006228 if (*reason == 'd')
6229 mesg = _("E211: File \"%s\" no longer available");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230 else
6231 {
6232 helpmesg = TRUE;
6233#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6234 can_reload = TRUE;
6235#endif
6236 /*
6237 * Check if the file contents really changed to avoid
6238 * giving a warning when only the timestamp was set (e.g.,
6239 * checked out of CVS). Always warn when the buffer was
6240 * changed.
6241 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006242 if (reason[2] == 'n')
6243 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006245 mesg2 = _("See \":help W12\" for more info.");
6246 }
6247 else if (reason[1] == 'h')
6248 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006250 mesg2 = _("See \":help W11\" for more info.");
6251 }
6252 else if (*reason == 'm')
6253 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006255 mesg2 = _("See \":help W16\" for more info.");
6256 }
6257 /* Else: only timestamp changed, ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258 }
6259 }
6260 }
6261
6262 }
6263 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6264 && vim_fexists(buf->b_ffname))
6265 {
6266 retval = 1;
6267 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6268 buf->b_flags |= BF_NEW_W;
6269#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6270 can_reload = TRUE;
6271#endif
6272 }
6273
6274 if (mesg != NULL)
6275 {
6276 path = home_replace_save(buf, buf->b_fname);
6277 if (path != NULL)
6278 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006279 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006280 mesg2 = "";
6281 tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
6282 + STRLEN(mesg2) + 2));
6283 sprintf((char *)tbuf, mesg, path);
6284#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6285 if (can_reload)
6286 {
6287 if (*mesg2 != NUL)
6288 {
6289 STRCAT(tbuf, "\n");
6290 STRCAT(tbuf, mesg2);
6291 }
6292 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
6293 (char_u *)_("&OK\n&Load File"), 1, NULL) == 2)
6294 reload = TRUE;
6295 }
6296 else
6297#endif
6298 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6299 {
6300 if (*mesg2 != NUL)
6301 {
6302 STRCAT(tbuf, "; ");
6303 STRCAT(tbuf, mesg2);
6304 }
6305 EMSG(tbuf);
6306 retval = 2;
6307 }
6308 else
6309 {
Bram Moolenaared203462004-06-16 11:19:22 +00006310# ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311 if (!autocmd_busy)
Bram Moolenaared203462004-06-16 11:19:22 +00006312# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006313 {
6314 msg_start();
6315 msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
6316 if (*mesg2 != NUL)
6317 msg_puts_attr((char_u *)mesg2,
6318 hl_attr(HLF_W) + MSG_HIST);
6319 msg_clr_eos();
6320 (void)msg_end();
6321 if (emsg_silent == 0)
6322 {
6323 out_flush();
Bram Moolenaared203462004-06-16 11:19:22 +00006324# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325 if (!focus)
Bram Moolenaared203462004-06-16 11:19:22 +00006326# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006327 /* give the user some time to think about it */
6328 ui_delay(1000L, TRUE);
6329
6330 /* don't redraw and erase the message */
6331 redraw_cmdline = FALSE;
6332 }
6333 }
6334 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335 }
6336
6337 vim_free(path);
6338 vim_free(tbuf);
6339 }
6340 }
6341
6342 if (reload)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006343 /* Reload the buffer. */
6344 buf_reload(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006345
6346#ifdef FEAT_GUI
6347 /* restore this in case an autocommand has set it; it would break
6348 * 'mousefocus' */
6349 need_mouse_correct = save_mouse_correct;
6350#endif
6351
6352 return retval;
6353}
6354
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006355/*
6356 * Reload a buffer that is already loaded.
6357 * Used when the file was changed outside of Vim.
6358 */
6359 void
6360buf_reload(buf)
6361 buf_T *buf;
6362{
6363 exarg_T ea;
6364 pos_T old_cursor;
6365 linenr_T old_topline;
6366 int old_ro = buf->b_p_ro;
6367 int orig_mode = buf->b_orig_mode;
6368 buf_T *savebuf;
6369 int saved = OK;
6370#ifdef FEAT_AUTOCMD
6371 aco_save_T aco;
6372
6373 /* set curwin/curbuf for "buf" and save some things */
6374 aucmd_prepbuf(&aco, buf);
6375#else
6376 buf_T *save_curbuf = curbuf;
6377
6378 curbuf = buf;
6379 curwin->w_buffer = buf;
6380#endif
6381
6382 /* We only want to read the text from the file, not reset the syntax
6383 * highlighting, clear marks, diff status, etc. Force the fileformat
6384 * and encoding to be the same. */
6385 if (prep_exarg(&ea, buf) == OK)
6386 {
6387 old_cursor = curwin->w_cursor;
6388 old_topline = curwin->w_topline;
6389
6390 /*
6391 * To behave like when a new file is edited (matters for
6392 * BufReadPost autocommands) we first need to delete the current
6393 * buffer contents. But if reading the file fails we should keep
6394 * the old contents. Can't use memory only, the file might be
6395 * too big. Use a hidden buffer to move the buffer contents to.
6396 */
6397 if (bufempty())
6398 savebuf = NULL;
6399 else
6400 {
6401 /* Allocate a buffer without putting it in the buffer list. */
6402 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
6403 if (savebuf != NULL)
6404 {
6405 /* Open the memline. */
6406 curbuf = savebuf;
6407 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00006408 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006409 curbuf = buf;
6410 curwin->w_buffer = buf;
6411 }
6412 if (savebuf == NULL || saved == FAIL
6413 || move_lines(buf, savebuf) == FAIL)
6414 {
6415 EMSG2(_("E462: Could not prepare for reloading \"%s\""),
6416 buf->b_fname);
6417 saved = FAIL;
6418 }
6419 }
6420
6421 if (saved == OK)
6422 {
6423 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
6424#ifdef FEAT_AUTOCMD
6425 keep_filetype = TRUE; /* don't detect 'filetype' */
6426#endif
6427 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
6428 (linenr_T)0,
6429 (linenr_T)MAXLNUM, &ea, READ_NEW) == FAIL)
6430 {
6431#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
6432 if (!aborting())
6433#endif
6434 EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
6435 if (savebuf != NULL)
6436 {
6437 /* Put the text back from the save buffer. First
6438 * delete any lines that readfile() added. */
6439 while (!bufempty())
6440 if (ml_delete(curbuf->b_ml.ml_line_count, FALSE)
6441 == FAIL)
6442 break;
6443 (void)move_lines(savebuf, buf);
6444 }
6445 }
6446 else
6447 {
6448 /* Mark the buffer as unmodified and free undo info. */
6449 unchanged(buf, TRUE);
6450 u_blockfree(buf);
6451 u_clearall(buf);
6452 }
6453 }
6454 vim_free(ea.cmd);
6455
6456 if (savebuf != NULL)
6457 wipe_buffer(savebuf, FALSE);
6458
6459#ifdef FEAT_DIFF
6460 /* Invalidate diff info if necessary. */
6461 diff_invalidate();
6462#endif
6463
6464 /* Restore the topline and cursor position and check it (lines may
6465 * have been removed). */
6466 if (old_topline > curbuf->b_ml.ml_line_count)
6467 curwin->w_topline = curbuf->b_ml.ml_line_count;
6468 else
6469 curwin->w_topline = old_topline;
6470 curwin->w_cursor = old_cursor;
6471 check_cursor();
6472 update_topline();
6473#ifdef FEAT_AUTOCMD
6474 keep_filetype = FALSE;
6475#endif
6476#ifdef FEAT_FOLDING
6477 {
6478 win_T *wp;
6479
6480 /* Update folds unless they are defined manually. */
6481 FOR_ALL_WINDOWS(wp)
6482 if (wp->w_buffer == curwin->w_buffer
6483 && !foldmethodIsManual(wp))
6484 foldUpdateAll(wp);
6485 }
6486#endif
6487 /* If the mode didn't change and 'readonly' was set, keep the old
6488 * value; the user probably used the ":view" command. But don't
6489 * reset it, might have had a read error. */
6490 if (orig_mode == curbuf->b_orig_mode)
6491 curbuf->b_p_ro |= old_ro;
6492 }
6493
6494#ifdef FEAT_AUTOCMD
6495 /* restore curwin/curbuf and a few other things */
6496 aucmd_restbuf(&aco);
6497 /* Careful: autocommands may have made "buf" invalid! */
6498#else
6499 curwin->w_buffer = save_curbuf;
6500 curbuf = save_curbuf;
6501#endif
6502}
6503
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504/*ARGSUSED*/
6505 void
6506buf_store_time(buf, st, fname)
6507 buf_T *buf;
6508 struct stat *st;
6509 char_u *fname;
6510{
6511 buf->b_mtime = (long)st->st_mtime;
6512 buf->b_orig_size = (size_t)st->st_size;
6513#ifdef HAVE_ST_MODE
6514 buf->b_orig_mode = (int)st->st_mode;
6515#else
6516 buf->b_orig_mode = mch_getperm(fname);
6517#endif
6518}
6519
6520/*
6521 * Adjust the line with missing eol, used for the next write.
6522 * Used for do_filter(), when the input lines for the filter are deleted.
6523 */
6524 void
6525write_lnum_adjust(offset)
6526 linenr_T offset;
6527{
Bram Moolenaardf177f62005-02-22 08:39:57 +00006528 if (write_no_eol_lnum != 0) /* only if there is a missing eol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006529 write_no_eol_lnum += offset;
6530}
6531
6532#if defined(TEMPDIRNAMES) || defined(PROTO)
6533static long temp_count = 0; /* Temp filename counter. */
6534
6535/*
6536 * Delete the temp directory and all files it contains.
6537 */
6538 void
6539vim_deltempdir()
6540{
6541 char_u **files;
6542 int file_count;
6543 int i;
6544
6545 if (vim_tempdir != NULL)
6546 {
6547 sprintf((char *)NameBuff, "%s*", vim_tempdir);
6548 if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
6549 EW_DIR|EW_FILE|EW_SILENT) == OK)
6550 {
6551 for (i = 0; i < file_count; ++i)
6552 mch_remove(files[i]);
6553 FreeWild(file_count, files);
6554 }
6555 gettail(NameBuff)[-1] = NUL;
6556 (void)mch_rmdir(NameBuff);
6557
6558 vim_free(vim_tempdir);
6559 vim_tempdir = NULL;
6560 }
6561}
6562#endif
6563
6564/*
6565 * vim_tempname(): Return a unique name that can be used for a temp file.
6566 *
6567 * The temp file is NOT created.
6568 *
6569 * The returned pointer is to allocated memory.
6570 * The returned pointer is NULL if no valid name was found.
6571 */
6572/*ARGSUSED*/
6573 char_u *
6574vim_tempname(extra_char)
6575 int extra_char; /* character to use in the name instead of '?' */
6576{
6577#ifdef USE_TMPNAM
6578 char_u itmp[L_tmpnam]; /* use tmpnam() */
6579#else
6580 char_u itmp[TEMPNAMELEN];
6581#endif
6582
6583#ifdef TEMPDIRNAMES
6584 static char *(tempdirs[]) = {TEMPDIRNAMES};
6585 int i;
6586 long nr;
6587 long off;
6588# ifndef EEXIST
6589 struct stat st;
6590# endif
6591
6592 /*
6593 * This will create a directory for private use by this instance of Vim.
6594 * This is done once, and the same directory is used for all temp files.
6595 * This method avoids security problems because of symlink attacks et al.
6596 * It's also a bit faster, because we only need to check for an existing
6597 * file when creating the directory and not for each temp file.
6598 */
6599 if (vim_tempdir == NULL)
6600 {
6601 /*
6602 * Try the entries in TEMPDIRNAMES to create the temp directory.
6603 */
6604 for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i)
6605 {
6606 /* expand $TMP, leave room for "/v1100000/999999999" */
6607 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
6608 if (mch_isdir(itmp)) /* directory exists */
6609 {
6610# ifdef __EMX__
6611 /* If $TMP contains a forward slash (perhaps using bash or
6612 * tcsh), don't add a backslash, use a forward slash!
6613 * Adding 2 backslashes didn't work. */
6614 if (vim_strchr(itmp, '/') != NULL)
6615 STRCAT(itmp, "/");
6616 else
6617# endif
6618 add_pathsep(itmp);
6619
6620 /* Get an arbitrary number of up to 6 digits. When it's
6621 * unlikely that it already exists it will be faster,
6622 * otherwise it doesn't matter. The use of mkdir() avoids any
6623 * security problems because of the predictable number. */
6624 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
6625
6626 /* Try up to 10000 different values until we find a name that
6627 * doesn't exist. */
6628 for (off = 0; off < 10000L; ++off)
6629 {
6630 int r;
6631#if defined(UNIX) || defined(VMS)
6632 mode_t umask_save;
6633#endif
6634
6635 sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off);
6636# ifndef EEXIST
6637 /* If mkdir() does not set errno to EEXIST, check for
6638 * existing file here. There is a race condition then,
6639 * although it's fail-safe. */
6640 if (mch_stat((char *)itmp, &st) >= 0)
6641 continue;
6642# endif
6643#if defined(UNIX) || defined(VMS)
6644 /* Make sure the umask doesn't remove the executable bit.
6645 * "repl" has been reported to use "177". */
6646 umask_save = umask(077);
6647#endif
6648 r = vim_mkdir(itmp, 0700);
6649#if defined(UNIX) || defined(VMS)
6650 (void)umask(umask_save);
6651#endif
6652 if (r == 0)
6653 {
6654 char_u *buf;
6655
6656 /* Directory was created, use this name.
6657 * Expand to full path; When using the current
6658 * directory a ":cd" would confuse us. */
6659 buf = alloc((unsigned)MAXPATHL + 1);
6660 if (buf != NULL)
6661 {
6662 if (vim_FullName(itmp, buf, MAXPATHL, FALSE)
6663 == FAIL)
6664 STRCPY(buf, itmp);
6665# ifdef __EMX__
6666 if (vim_strchr(buf, '/') != NULL)
6667 STRCAT(buf, "/");
6668 else
6669# endif
6670 add_pathsep(buf);
6671 vim_tempdir = vim_strsave(buf);
6672 vim_free(buf);
6673 }
6674 break;
6675 }
6676# ifdef EEXIST
6677 /* If the mkdir() didn't fail because the file/dir exists,
6678 * we probably can't create any dir here, try another
6679 * place. */
6680 if (errno != EEXIST)
6681# endif
6682 break;
6683 }
6684 if (vim_tempdir != NULL)
6685 break;
6686 }
6687 }
6688 }
6689
6690 if (vim_tempdir != NULL)
6691 {
6692 /* There is no need to check if the file exists, because we own the
6693 * directory and nobody else creates a file in it. */
6694 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
6695 return vim_strsave(itmp);
6696 }
6697
6698 return NULL;
6699
6700#else /* TEMPDIRNAMES */
6701
6702# ifdef WIN3264
6703 char szTempFile[_MAX_PATH + 1];
6704 char buf4[4];
6705 char_u *retval;
6706 char_u *p;
6707
6708 STRCPY(itmp, "");
6709 if (GetTempPath(_MAX_PATH, szTempFile) == 0)
6710 szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */
6711 strcpy(buf4, "VIM");
6712 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
6713 if (GetTempFileName(szTempFile, buf4, 0, itmp) == 0)
6714 return NULL;
6715 /* GetTempFileName() will create the file, we don't want that */
6716 (void)DeleteFile(itmp);
6717
6718 /* Backslashes in a temp file name cause problems when filtering with
6719 * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
6720 * didn't set 'shellslash'. */
6721 retval = vim_strsave(itmp);
6722 if (*p_shcf == '-' || p_ssl)
6723 for (p = retval; *p; ++p)
6724 if (*p == '\\')
6725 *p = '/';
6726 return retval;
6727
6728# else /* WIN3264 */
6729
6730# ifdef USE_TMPNAM
6731 /* tmpnam() will make its own name */
6732 if (*tmpnam((char *)itmp) == NUL)
6733 return NULL;
6734# else
6735 char_u *p;
6736
6737# ifdef VMS_TEMPNAM
6738 /* mktemp() is not working on VMS. It seems to be
6739 * a do-nothing function. Therefore we use tempnam().
6740 */
6741 sprintf((char *)itmp, "VIM%c", extra_char);
6742 p = (char_u *)tempnam("tmp:", (char *)itmp);
6743 if (p != NULL)
6744 {
6745 /* VMS will use '.LOG' if we don't explicitly specify an extension,
6746 * and VIM will then be unable to find the file later */
6747 STRCPY(itmp, p);
6748 STRCAT(itmp, ".txt");
6749 free(p);
6750 }
6751 else
6752 return NULL;
6753# else
6754 STRCPY(itmp, TEMPNAME);
6755 if ((p = vim_strchr(itmp, '?')) != NULL)
6756 *p = extra_char;
6757 if (mktemp((char *)itmp) == NULL)
6758 return NULL;
6759# endif
6760# endif
6761
6762 return vim_strsave(itmp);
6763# endif /* WIN3264 */
6764#endif /* TEMPDIRNAMES */
6765}
6766
6767#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
6768/*
6769 * Convert all backslashes in fname to forward slashes in-place.
6770 */
6771 void
6772forward_slash(fname)
6773 char_u *fname;
6774{
6775 char_u *p;
6776
6777 for (p = fname; *p != NUL; ++p)
6778# ifdef FEAT_MBYTE
6779 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006780 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006781 ++p;
6782 else
6783# endif
6784 if (*p == '\\')
6785 *p = '/';
6786}
6787#endif
6788
6789
6790/*
6791 * Code for automatic commands.
6792 *
6793 * Only included when "FEAT_AUTOCMD" has been defined.
6794 */
6795
6796#if defined(FEAT_AUTOCMD) || defined(PROTO)
6797
6798/*
6799 * The autocommands are stored in a list for each event.
6800 * Autocommands for the same pattern, that are consecutive, are joined
6801 * together, to avoid having to match the pattern too often.
6802 * The result is an array of Autopat lists, which point to AutoCmd lists:
6803 *
6804 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
6805 * Autopat.cmds Autopat.cmds
6806 * | |
6807 * V V
6808 * AutoCmd.next AutoCmd.next
6809 * | |
6810 * V V
6811 * AutoCmd.next NULL
6812 * |
6813 * V
6814 * NULL
6815 *
6816 * first_autopat[1] --> Autopat.next --> NULL
6817 * Autopat.cmds
6818 * |
6819 * V
6820 * AutoCmd.next
6821 * |
6822 * V
6823 * NULL
6824 * etc.
6825 *
6826 * The order of AutoCmds is important, this is the order in which they were
6827 * defined and will have to be executed.
6828 */
6829typedef struct AutoCmd
6830{
6831 char_u *cmd; /* The command to be executed (NULL
6832 when command has been removed) */
6833 char nested; /* If autocommands nest here */
6834 char last; /* last command in list */
6835#ifdef FEAT_EVAL
6836 scid_T scriptID; /* script ID where defined */
6837#endif
6838 struct AutoCmd *next; /* Next AutoCmd in list */
6839} AutoCmd;
6840
6841typedef struct AutoPat
6842{
6843 int group; /* group ID */
6844 char_u *pat; /* pattern as typed (NULL when pattern
6845 has been removed) */
6846 int patlen; /* strlen() of pat */
Bram Moolenaar748bf032005-02-02 23:04:36 +00006847 regprog_T *reg_prog; /* compiled regprog for pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 char allow_dirs; /* Pattern may match whole path */
6849 char last; /* last pattern for apply_autocmds() */
6850 AutoCmd *cmds; /* list of commands to do */
6851 struct AutoPat *next; /* next AutoPat in AutoPat list */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006852 int buflocal_nr; /* !=0 for buffer-local AutoPat */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006853} AutoPat;
6854
6855static struct event_name
6856{
6857 char *name; /* event name */
6858 EVENT_T event; /* event number */
6859} event_names[] =
6860{
6861 {"BufAdd", EVENT_BUFADD},
6862 {"BufCreate", EVENT_BUFADD},
6863 {"BufDelete", EVENT_BUFDELETE},
6864 {"BufEnter", EVENT_BUFENTER},
6865 {"BufFilePost", EVENT_BUFFILEPOST},
6866 {"BufFilePre", EVENT_BUFFILEPRE},
6867 {"BufHidden", EVENT_BUFHIDDEN},
6868 {"BufLeave", EVENT_BUFLEAVE},
6869 {"BufNew", EVENT_BUFNEW},
6870 {"BufNewFile", EVENT_BUFNEWFILE},
6871 {"BufRead", EVENT_BUFREADPOST},
6872 {"BufReadCmd", EVENT_BUFREADCMD},
6873 {"BufReadPost", EVENT_BUFREADPOST},
6874 {"BufReadPre", EVENT_BUFREADPRE},
6875 {"BufUnload", EVENT_BUFUNLOAD},
6876 {"BufWinEnter", EVENT_BUFWINENTER},
6877 {"BufWinLeave", EVENT_BUFWINLEAVE},
6878 {"BufWipeout", EVENT_BUFWIPEOUT},
6879 {"BufWrite", EVENT_BUFWRITEPRE},
6880 {"BufWritePost", EVENT_BUFWRITEPOST},
6881 {"BufWritePre", EVENT_BUFWRITEPRE},
6882 {"BufWriteCmd", EVENT_BUFWRITECMD},
6883 {"CmdwinEnter", EVENT_CMDWINENTER},
6884 {"CmdwinLeave", EVENT_CMDWINLEAVE},
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006885 {"ColorScheme", EVENT_COLORSCHEME},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006886 {"EncodingChanged", EVENT_ENCODINGCHANGED},
6887 {"FileEncoding", EVENT_ENCODINGCHANGED},
6888 {"CursorHold", EVENT_CURSORHOLD},
6889 {"FileAppendPost", EVENT_FILEAPPENDPOST},
6890 {"FileAppendPre", EVENT_FILEAPPENDPRE},
6891 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
6892 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
6893 {"FileChangedRO", EVENT_FILECHANGEDRO},
6894 {"FileReadPost", EVENT_FILEREADPOST},
6895 {"FileReadPre", EVENT_FILEREADPRE},
6896 {"FileReadCmd", EVENT_FILEREADCMD},
6897 {"FileType", EVENT_FILETYPE},
6898 {"FileWritePost", EVENT_FILEWRITEPOST},
6899 {"FileWritePre", EVENT_FILEWRITEPRE},
6900 {"FileWriteCmd", EVENT_FILEWRITECMD},
6901 {"FilterReadPost", EVENT_FILTERREADPOST},
6902 {"FilterReadPre", EVENT_FILTERREADPRE},
6903 {"FilterWritePost", EVENT_FILTERWRITEPOST},
6904 {"FilterWritePre", EVENT_FILTERWRITEPRE},
6905 {"FocusGained", EVENT_FOCUSGAINED},
6906 {"FocusLost", EVENT_FOCUSLOST},
6907 {"FuncUndefined", EVENT_FUNCUNDEFINED},
6908 {"GUIEnter", EVENT_GUIENTER},
Bram Moolenaar843ee412004-06-30 16:16:41 +00006909 {"InsertChange", EVENT_INSERTCHANGE},
6910 {"InsertEnter", EVENT_INSERTENTER},
6911 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaara3ffd9c2005-07-21 21:03:15 +00006912 {"MenuPopup", EVENT_MENUPOPUP},
Bram Moolenaar7c626922005-02-07 22:01:03 +00006913 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
6914 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006915 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar9372a112005-12-06 19:59:18 +00006916 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006917 {"StdinReadPost", EVENT_STDINREADPOST},
6918 {"StdinReadPre", EVENT_STDINREADPRE},
6919 {"Syntax", EVENT_SYNTAX},
Bram Moolenaarb815dac2005-12-07 20:59:24 +00006920 {"SwapExists", EVENT_SWAPEXISTS},
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921 {"TermChanged", EVENT_TERMCHANGED},
6922 {"TermResponse", EVENT_TERMRESPONSE},
6923 {"User", EVENT_USER},
6924 {"VimEnter", EVENT_VIMENTER},
6925 {"VimLeave", EVENT_VIMLEAVE},
6926 {"VimLeavePre", EVENT_VIMLEAVEPRE},
6927 {"WinEnter", EVENT_WINENTER},
6928 {"WinLeave", EVENT_WINLEAVE},
6929 {NULL, (EVENT_T)0}
6930};
6931
6932static AutoPat *first_autopat[NUM_EVENTS] =
6933{
6934 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6935 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6936 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6937 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00006938 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
6939 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006940};
6941
6942/*
6943 * struct used to keep status while executing autocommands for an event.
6944 */
6945typedef struct AutoPatCmd
6946{
6947 AutoPat *curpat; /* next AutoPat to examine */
6948 AutoCmd *nextcmd; /* next AutoCmd to execute */
6949 int group; /* group being used */
6950 char_u *fname; /* fname to match with */
6951 char_u *sfname; /* sfname to match with */
6952 char_u *tail; /* tail of fname */
6953 EVENT_T event; /* current event */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006954 int arg_bufnr; /* initially equal to <abuf>, set to zero when
6955 buf is deleted */
6956 struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006957} AutoPatCmd;
6958
Bram Moolenaard6f676d2005-06-01 21:51:55 +00006959static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006960
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961/*
6962 * augroups stores a list of autocmd group names.
6963 */
Bram Moolenaard6f676d2005-06-01 21:51:55 +00006964static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00006965#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
6966
6967/*
6968 * The ID of the current group. Group 0 is the default one.
6969 */
6970#define AUGROUP_DEFAULT -1 /* default autocmd group */
6971#define AUGROUP_ERROR -2 /* errornouse autocmd group */
6972#define AUGROUP_ALL -3 /* all autocmd groups */
6973static int current_augroup = AUGROUP_DEFAULT;
6974
6975static int au_need_clean = FALSE; /* need to delete marked patterns */
6976
6977static void show_autocmd __ARGS((AutoPat *ap, EVENT_T event));
6978static void au_remove_pat __ARGS((AutoPat *ap));
6979static void au_remove_cmds __ARGS((AutoPat *ap));
6980static void au_cleanup __ARGS((void));
6981static int au_new_group __ARGS((char_u *name));
6982static void au_del_group __ARGS((char_u *name));
6983static int au_find_group __ARGS((char_u *name));
6984static EVENT_T event_name2nr __ARGS((char_u *start, char_u **end));
6985static char_u *event_nr2name __ARGS((EVENT_T event));
6986static char_u *find_end_event __ARGS((char_u *arg, int have_group));
6987static int event_ignored __ARGS((EVENT_T event));
6988static int au_get_grouparg __ARGS((char_u **argp));
6989static int do_autocmd_event __ARGS((EVENT_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group));
6990static char_u *getnextac __ARGS((int c, void *cookie, int indent));
6991static 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));
6992static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
6993
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006994
Bram Moolenaar071d4272004-06-13 20:20:40 +00006995static EVENT_T last_event;
6996static int last_group;
6997
6998/*
6999 * Show the autocommands for one AutoPat.
7000 */
7001 static void
7002show_autocmd(ap, event)
7003 AutoPat *ap;
7004 EVENT_T event;
7005{
7006 AutoCmd *ac;
7007
7008 /* Check for "got_int" (here and at various places below), which is set
7009 * when "q" has been hit for the "--more--" prompt */
7010 if (got_int)
7011 return;
7012 if (ap->pat == NULL) /* pattern has been removed */
7013 return;
7014
7015 msg_putchar('\n');
7016 if (got_int)
7017 return;
7018 if (event != last_event || ap->group != last_group)
7019 {
7020 if (ap->group != AUGROUP_DEFAULT)
7021 {
7022 if (AUGROUP_NAME(ap->group) == NULL)
7023 msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
7024 else
7025 msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
7026 msg_puts((char_u *)" ");
7027 }
7028 msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
7029 last_event = event;
7030 last_group = ap->group;
7031 msg_putchar('\n');
7032 if (got_int)
7033 return;
7034 }
7035 msg_col = 4;
7036 msg_outtrans(ap->pat);
7037
7038 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7039 {
7040 if (ac->cmd != NULL) /* skip removed commands */
7041 {
7042 if (msg_col >= 14)
7043 msg_putchar('\n');
7044 msg_col = 14;
7045 if (got_int)
7046 return;
7047 msg_outtrans(ac->cmd);
Bram Moolenaarac6e65f2005-08-29 22:25:38 +00007048#ifdef FEAT_EVAL
7049 if (p_verbose > 0)
7050 last_set_msg(ac->scriptID);
7051#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007052 if (got_int)
7053 return;
7054 if (ac->next != NULL)
7055 {
7056 msg_putchar('\n');
7057 if (got_int)
7058 return;
7059 }
7060 }
7061 }
7062}
7063
7064/*
7065 * Mark an autocommand pattern for deletion.
7066 */
7067 static void
7068au_remove_pat(ap)
7069 AutoPat *ap;
7070{
7071 vim_free(ap->pat);
7072 ap->pat = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007073 ap->buflocal_nr = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 au_need_clean = TRUE;
7075}
7076
7077/*
7078 * Mark all commands for a pattern for deletion.
7079 */
7080 static void
7081au_remove_cmds(ap)
7082 AutoPat *ap;
7083{
7084 AutoCmd *ac;
7085
7086 for (ac = ap->cmds; ac != NULL; ac = ac->next)
7087 {
7088 vim_free(ac->cmd);
7089 ac->cmd = NULL;
7090 }
7091 au_need_clean = TRUE;
7092}
7093
7094/*
7095 * Cleanup autocommands and patterns that have been deleted.
7096 * This is only done when not executing autocommands.
7097 */
7098 static void
7099au_cleanup()
7100{
7101 AutoPat *ap, **prev_ap;
7102 AutoCmd *ac, **prev_ac;
7103 EVENT_T event;
7104
7105 if (autocmd_busy || !au_need_clean)
7106 return;
7107
7108 /* loop over all events */
7109 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7110 event = (EVENT_T)((int)event + 1))
7111 {
7112 /* loop over all autocommand patterns */
7113 prev_ap = &(first_autopat[(int)event]);
7114 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
7115 {
7116 /* loop over all commands for this pattern */
7117 prev_ac = &(ap->cmds);
7118 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
7119 {
7120 /* remove the command if the pattern is to be deleted or when
7121 * the command has been marked for deletion */
7122 if (ap->pat == NULL || ac->cmd == NULL)
7123 {
7124 *prev_ac = ac->next;
7125 vim_free(ac->cmd);
7126 vim_free(ac);
7127 }
7128 else
7129 prev_ac = &(ac->next);
7130 }
7131
7132 /* remove the pattern if it has been marked for deletion */
7133 if (ap->pat == NULL)
7134 {
7135 *prev_ap = ap->next;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007136 vim_free(ap->reg_prog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007137 vim_free(ap);
7138 }
7139 else
7140 prev_ap = &(ap->next);
7141 }
7142 }
7143
7144 au_need_clean = FALSE;
7145}
7146
7147/*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007148 * Called when buffer is freed, to remove/invalidate related buffer-local
7149 * autocmds.
7150 */
7151 void
7152aubuflocal_remove(buf)
7153 buf_T *buf;
7154{
7155 AutoPat *ap;
7156 EVENT_T event;
7157 AutoPatCmd *apc;
7158
7159 /* invalidate currently executing autocommands */
7160 for (apc = active_apc_list; apc; apc = apc->next)
7161 if (buf->b_fnum == apc->arg_bufnr)
7162 apc->arg_bufnr = 0;
7163
7164 /* invalidate buflocals looping through events */
7165 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7166 event = (EVENT_T)((int)event + 1))
7167 /* loop over all autocommand patterns */
7168 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7169 if (ap->buflocal_nr == buf->b_fnum)
7170 {
7171 au_remove_pat(ap);
7172 if (p_verbose >= 6)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007173 {
7174 verbose_enter();
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007175 smsg((char_u *)
7176 _("auto-removing autocommand: %s <buffer=%d>"),
7177 event_nr2name(event), buf->b_fnum);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007178 verbose_leave();
7179 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007180 }
7181 au_cleanup();
7182}
7183
7184/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007185 * Add an autocmd group name.
7186 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7187 */
7188 static int
7189au_new_group(name)
7190 char_u *name;
7191{
7192 int i;
7193
7194 i = au_find_group(name);
7195 if (i == AUGROUP_ERROR) /* the group doesn't exist yet, add it */
7196 {
7197 /* First try using a free entry. */
7198 for (i = 0; i < augroups.ga_len; ++i)
7199 if (AUGROUP_NAME(i) == NULL)
7200 break;
7201 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
7202 return AUGROUP_ERROR;
7203
7204 AUGROUP_NAME(i) = vim_strsave(name);
7205 if (AUGROUP_NAME(i) == NULL)
7206 return AUGROUP_ERROR;
7207 if (i == augroups.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007208 ++augroups.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007209 }
7210
7211 return i;
7212}
7213
7214 static void
7215au_del_group(name)
7216 char_u *name;
7217{
7218 int i;
7219
7220 i = au_find_group(name);
7221 if (i == AUGROUP_ERROR) /* the group doesn't exist */
7222 EMSG2(_("E367: No such group: \"%s\""), name);
7223 else
7224 {
7225 vim_free(AUGROUP_NAME(i));
7226 AUGROUP_NAME(i) = NULL;
7227 }
7228}
7229
7230/*
7231 * Find the ID of an autocmd group name.
7232 * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
7233 */
7234 static int
7235au_find_group(name)
7236 char_u *name;
7237{
7238 int i;
7239
7240 for (i = 0; i < augroups.ga_len; ++i)
7241 if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0)
7242 return i;
7243 return AUGROUP_ERROR;
7244}
7245
Bram Moolenaar1d94f9b2005-08-04 21:29:45 +00007246#if defined(FEAT_BROWSE) || defined(PROTO)
7247/*
7248 * Return TRUE if augroup "name" exists.
7249 */
7250 int
7251au_has_group(name)
7252 char_u *name;
7253{
7254 return au_find_group(name) != AUGROUP_ERROR;
7255}
7256#endif
7257
Bram Moolenaar071d4272004-06-13 20:20:40 +00007258/*
7259 * ":augroup {name}".
7260 */
7261 void
7262do_augroup(arg, del_group)
7263 char_u *arg;
7264 int del_group;
7265{
7266 int i;
7267
7268 if (del_group)
7269 {
7270 if (*arg == NUL)
7271 EMSG(_(e_argreq));
7272 else
7273 au_del_group(arg);
7274 }
7275 else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */
7276 current_augroup = AUGROUP_DEFAULT;
7277 else if (*arg) /* ":aug xxx": switch to group xxx */
7278 {
7279 i = au_new_group(arg);
7280 if (i != AUGROUP_ERROR)
7281 current_augroup = i;
7282 }
7283 else /* ":aug": list the group names */
7284 {
7285 msg_start();
7286 for (i = 0; i < augroups.ga_len; ++i)
7287 {
7288 if (AUGROUP_NAME(i) != NULL)
7289 {
7290 msg_puts(AUGROUP_NAME(i));
7291 msg_puts((char_u *)" ");
7292 }
7293 }
7294 msg_clr_eos();
7295 msg_end();
7296 }
7297}
7298
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007299#if defined(EXITFREE) || defined(PROTO)
7300 void
7301free_all_autocmds()
7302{
7303 for (current_augroup = -1; current_augroup < augroups.ga_len;
7304 ++current_augroup)
7305 do_autocmd((char_u *)"", TRUE);
7306 ga_clear_strings(&augroups);
7307}
7308#endif
7309
Bram Moolenaar071d4272004-06-13 20:20:40 +00007310/*
7311 * Return the event number for event name "start".
7312 * Return NUM_EVENTS if the event name was not found.
7313 * Return a pointer to the next event name in "end".
7314 */
7315 static EVENT_T
7316event_name2nr(start, end)
7317 char_u *start;
7318 char_u **end;
7319{
7320 char_u *p;
7321 int i;
7322 int len;
7323
7324 /* the event name ends with end of line, a blank or a comma */
7325 for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p)
7326 ;
7327 for (i = 0; event_names[i].name != NULL; ++i)
7328 {
7329 len = (int)STRLEN(event_names[i].name);
7330 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
7331 break;
7332 }
7333 if (*p == ',')
7334 ++p;
7335 *end = p;
7336 if (event_names[i].name == NULL)
7337 return NUM_EVENTS;
7338 return event_names[i].event;
7339}
7340
7341/*
7342 * Return the name for event "event".
7343 */
7344 static char_u *
7345event_nr2name(event)
7346 EVENT_T event;
7347{
7348 int i;
7349
7350 for (i = 0; event_names[i].name != NULL; ++i)
7351 if (event_names[i].event == event)
7352 return (char_u *)event_names[i].name;
7353 return (char_u *)"Unknown";
7354}
7355
7356/*
7357 * Scan over the events. "*" stands for all events.
7358 */
7359 static char_u *
7360find_end_event(arg, have_group)
7361 char_u *arg;
7362 int have_group; /* TRUE when group name was found */
7363{
7364 char_u *pat;
7365 char_u *p;
7366
7367 if (*arg == '*')
7368 {
7369 if (arg[1] && !vim_iswhite(arg[1]))
7370 {
7371 EMSG2(_("E215: Illegal character after *: %s"), arg);
7372 return NULL;
7373 }
7374 pat = arg + 1;
7375 }
7376 else
7377 {
7378 for (pat = arg; *pat && !vim_iswhite(*pat); pat = p)
7379 {
7380 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
7381 {
7382 if (have_group)
7383 EMSG2(_("E216: No such event: %s"), pat);
7384 else
7385 EMSG2(_("E216: No such group or event: %s"), pat);
7386 return NULL;
7387 }
7388 }
7389 }
7390 return pat;
7391}
7392
7393/*
7394 * Return TRUE if "event" is included in 'eventignore'.
7395 */
7396 static int
7397event_ignored(event)
7398 EVENT_T event;
7399{
7400 char_u *p = p_ei;
7401
7402 if (STRICMP(p_ei, "all") == 0)
7403 return TRUE;
7404
7405 while (*p)
7406 if (event_name2nr(p, &p) == event)
7407 return TRUE;
7408
7409 return FALSE;
7410}
7411
7412/*
7413 * Return OK when the contents of p_ei is valid, FAIL otherwise.
7414 */
7415 int
7416check_ei()
7417{
7418 char_u *p = p_ei;
7419
7420 if (STRICMP(p_ei, "all") == 0)
7421 return OK;
7422
7423 while (*p)
7424 if (event_name2nr(p, &p) == NUM_EVENTS)
7425 return FAIL;
7426
7427 return OK;
7428}
7429
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007430# if defined(FEAT_SYN_HL) || defined(PROTO)
7431
7432/*
7433 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
7434 * buffer loaded into the window. "what" must start with a comma.
7435 * Returns the old value of 'eventignore' in allocated memory.
7436 */
7437 char_u *
7438au_event_disable(what)
7439 char *what;
7440{
7441 char_u *new_ei;
7442 char_u *save_ei;
7443
7444 save_ei = vim_strsave(p_ei);
7445 if (save_ei != NULL)
7446 {
Bram Moolenaara5792f52005-11-23 21:25:05 +00007447 new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007448 if (new_ei != NULL)
7449 {
7450 STRCAT(new_ei, what);
7451 set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
7452 vim_free(new_ei);
7453 }
7454 }
7455 return save_ei;
7456}
7457
7458 void
7459au_event_restore(old_ei)
7460 char_u *old_ei;
7461{
7462 if (old_ei != NULL)
7463 {
7464 set_string_option_direct((char_u *)"ei", -1, old_ei, OPT_FREE);
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00007465 vim_free(old_ei);
7466 }
7467}
7468# endif /* FEAT_SYN_HL */
7469
Bram Moolenaar071d4272004-06-13 20:20:40 +00007470/*
7471 * do_autocmd() -- implements the :autocmd command. Can be used in the
7472 * following ways:
7473 *
7474 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
7475 * will be automatically executed for <event>
7476 * when editing a file matching <pat>, in
7477 * the current group.
7478 * :autocmd <event> <pat> Show the auto-commands associated with
7479 * <event> and <pat>.
7480 * :autocmd <event> Show the auto-commands associated with
7481 * <event>.
7482 * :autocmd Show all auto-commands.
7483 * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
7484 * <event> and <pat>, and add the command
7485 * <cmd>, for the current group.
7486 * :autocmd! <event> <pat> Remove all auto-commands associated with
7487 * <event> and <pat> for the current group.
7488 * :autocmd! <event> Remove all auto-commands associated with
7489 * <event> for the current group.
7490 * :autocmd! Remove ALL auto-commands for the current
7491 * group.
7492 *
7493 * Multiple events and patterns may be given separated by commas. Here are
7494 * some examples:
7495 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
7496 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
7497 *
7498 * :autocmd * *.c show all autocommands for *.c files.
Bram Moolenaard35f9712005-12-18 22:02:33 +00007499 *
7500 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007501 */
7502 void
7503do_autocmd(arg, forceit)
7504 char_u *arg;
7505 int forceit;
7506{
7507 char_u *pat;
7508 char_u *envpat = NULL;
7509 char_u *cmd;
7510 EVENT_T event;
7511 int need_free = FALSE;
7512 int nested = FALSE;
7513 int group;
7514
7515 /*
7516 * Check for a legal group name. If not, use AUGROUP_ALL.
7517 */
7518 group = au_get_grouparg(&arg);
7519 if (arg == NULL) /* out of memory */
7520 return;
7521
7522 /*
7523 * Scan over the events.
7524 * If we find an illegal name, return here, don't do anything.
7525 */
7526 pat = find_end_event(arg, group != AUGROUP_ALL);
7527 if (pat == NULL)
7528 return;
7529
7530 /*
7531 * Scan over the pattern. Put a NUL at the end.
7532 */
7533 pat = skipwhite(pat);
7534 cmd = pat;
7535 while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\'))
7536 cmd++;
7537 if (*cmd)
7538 *cmd++ = NUL;
7539
7540 /* Expand environment variables in the pattern. Set 'shellslash', we want
7541 * forward slashes here. */
7542 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
7543 {
7544#ifdef BACKSLASH_IN_FILENAME
7545 int p_ssl_save = p_ssl;
7546
7547 p_ssl = TRUE;
7548#endif
7549 envpat = expand_env_save(pat);
7550#ifdef BACKSLASH_IN_FILENAME
7551 p_ssl = p_ssl_save;
7552#endif
7553 if (envpat != NULL)
7554 pat = envpat;
7555 }
7556
7557 /*
7558 * Check for "nested" flag.
7559 */
7560 cmd = skipwhite(cmd);
7561 if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && vim_iswhite(cmd[6]))
7562 {
7563 nested = TRUE;
7564 cmd = skipwhite(cmd + 6);
7565 }
7566
7567 /*
7568 * Find the start of the commands.
7569 * Expand <sfile> in it.
7570 */
7571 if (*cmd != NUL)
7572 {
7573 cmd = expand_sfile(cmd);
7574 if (cmd == NULL) /* some error */
7575 return;
7576 need_free = TRUE;
7577 }
7578
7579 /*
7580 * Print header when showing autocommands.
7581 */
7582 if (!forceit && *cmd == NUL)
7583 {
7584 /* Highlight title */
7585 MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
7586 }
7587
7588 /*
7589 * Loop over the events.
7590 */
7591 last_event = (EVENT_T)-1; /* for listing the event name */
7592 last_group = AUGROUP_ERROR; /* for listing the group name */
7593 if (*arg == '*' || *arg == NUL)
7594 {
7595 for (event = (EVENT_T)0; (int)event < (int)NUM_EVENTS;
7596 event = (EVENT_T)((int)event + 1))
7597 if (do_autocmd_event(event, pat,
7598 nested, cmd, forceit, group) == FAIL)
7599 break;
7600 }
7601 else
7602 {
7603 while (*arg && !vim_iswhite(*arg))
7604 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
7605 nested, cmd, forceit, group) == FAIL)
7606 break;
7607 }
7608
7609 if (need_free)
7610 vim_free(cmd);
7611 vim_free(envpat);
7612}
7613
7614/*
7615 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
7616 * The "argp" argument is advanced to the following argument.
7617 *
7618 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
7619 */
7620 static int
7621au_get_grouparg(argp)
7622 char_u **argp;
7623{
7624 char_u *group_name;
7625 char_u *p;
7626 char_u *arg = *argp;
7627 int group = AUGROUP_ALL;
7628
7629 p = skiptowhite(arg);
7630 if (p > arg)
7631 {
7632 group_name = vim_strnsave(arg, (int)(p - arg));
7633 if (group_name == NULL) /* out of memory */
7634 return AUGROUP_ERROR;
7635 group = au_find_group(group_name);
7636 if (group == AUGROUP_ERROR)
7637 group = AUGROUP_ALL; /* no match, use all groups */
7638 else
7639 *argp = skipwhite(p); /* match, skip over group name */
7640 vim_free(group_name);
7641 }
7642 return group;
7643}
7644
7645/*
7646 * do_autocmd() for one event.
7647 * If *pat == NUL do for all patterns.
7648 * If *cmd == NUL show entries.
7649 * If forceit == TRUE delete entries.
7650 * If group is not AUGROUP_ALL, only use this group.
7651 */
7652 static int
7653do_autocmd_event(event, pat, nested, cmd, forceit, group)
7654 EVENT_T event;
7655 char_u *pat;
7656 int nested;
7657 char_u *cmd;
7658 int forceit;
7659 int group;
7660{
7661 AutoPat *ap;
7662 AutoPat **prev_ap;
7663 AutoCmd *ac;
7664 AutoCmd **prev_ac;
7665 int brace_level;
7666 char_u *endpat;
7667 int findgroup;
7668 int allgroups;
7669 int patlen;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007670 int is_buflocal;
7671 int buflocal_nr;
7672 char_u buflocal_pat[25]; /* for "<buffer=X>" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007673
7674 if (group == AUGROUP_ALL)
7675 findgroup = current_augroup;
7676 else
7677 findgroup = group;
7678 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
7679
7680 /*
7681 * Show or delete all patterns for an event.
7682 */
7683 if (*pat == NUL)
7684 {
7685 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
7686 {
7687 if (forceit) /* delete the AutoPat, if it's in the current group */
7688 {
7689 if (ap->group == findgroup)
7690 au_remove_pat(ap);
7691 }
7692 else if (group == AUGROUP_ALL || ap->group == group)
7693 show_autocmd(ap, event);
7694 }
7695 }
7696
7697 /*
7698 * Loop through all the specified patterns.
7699 */
7700 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
7701 {
7702 /*
7703 * Find end of the pattern.
7704 * Watch out for a comma in braces, like "*.\{obj,o\}".
7705 */
7706 brace_level = 0;
7707 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
7708 || endpat[-1] == '\\'); ++endpat)
7709 {
7710 if (*endpat == '{')
7711 brace_level++;
7712 else if (*endpat == '}')
7713 brace_level--;
7714 }
7715 if (pat == endpat) /* ignore single comma */
7716 continue;
7717 patlen = (int)(endpat - pat);
7718
7719 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007720 * detect special <buflocal[=X]> buffer-local patterns
7721 */
7722 is_buflocal = FALSE;
7723 buflocal_nr = 0;
7724
7725 if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0
7726 && pat[patlen - 1] == '>')
7727 {
7728 /* Error will be printed only for addition. printing and removing
7729 * will proceed silently. */
7730 is_buflocal = TRUE;
7731 if (patlen == 8)
7732 buflocal_nr = curbuf->b_fnum;
7733 else if (patlen > 9 && pat[7] == '=')
7734 {
7735 /* <buffer=abuf> */
7736 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13))
7737 buflocal_nr = autocmd_bufnr;
7738 /* <buffer=123> */
7739 else if (skipdigits(pat + 8) == pat + patlen - 1)
7740 buflocal_nr = atoi((char *)pat + 8);
7741 }
7742 }
7743
7744 if (is_buflocal)
7745 {
7746 /* normalize pat into standard "<buffer>#N" form */
7747 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
7748 pat = buflocal_pat; /* can modify pat and patlen */
7749 patlen = STRLEN(buflocal_pat); /* but not endpat */
7750 }
7751
7752 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007753 * Find AutoPat entries with this pattern.
7754 */
7755 prev_ap = &first_autopat[(int)event];
7756 while ((ap = *prev_ap) != NULL)
7757 {
7758 if (ap->pat != NULL)
7759 {
7760 /* Accept a pattern when:
7761 * - a group was specified and it's that group, or a group was
7762 * not specified and it's the current group, or a group was
7763 * not specified and we are listing
7764 * - the length of the pattern matches
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007765 * - the pattern matches.
7766 * For <buffer[=X]>, this condition works because we normalize
7767 * all buffer-local patterns.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768 */
7769 if ((allgroups || ap->group == findgroup)
7770 && ap->patlen == patlen
7771 && STRNCMP(pat, ap->pat, patlen) == 0)
7772 {
7773 /*
7774 * Remove existing autocommands.
7775 * If adding any new autocmd's for this AutoPat, don't
7776 * delete the pattern from the autopat list, append to
7777 * this list.
7778 */
7779 if (forceit)
7780 {
7781 if (*cmd != NUL && ap->next == NULL)
7782 {
7783 au_remove_cmds(ap);
7784 break;
7785 }
7786 au_remove_pat(ap);
7787 }
7788
7789 /*
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007790 * Show autocmd's for this autopat, or buflocals <buffer=X>
Bram Moolenaar071d4272004-06-13 20:20:40 +00007791 */
7792 else if (*cmd == NUL)
7793 show_autocmd(ap, event);
7794
7795 /*
7796 * Add autocmd to this autopat, if it's the last one.
7797 */
7798 else if (ap->next == NULL)
7799 break;
7800 }
7801 }
7802 prev_ap = &ap->next;
7803 }
7804
7805 /*
7806 * Add a new command.
7807 */
7808 if (*cmd != NUL)
7809 {
7810 /*
7811 * If the pattern we want to add a command to does appear at the
7812 * end of the list (or not is not in the list at all), add the
7813 * pattern at the end of the list.
7814 */
7815 if (ap == NULL)
7816 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007817 /* refuse to add buffer-local ap if buffer number is invalid */
7818 if (is_buflocal && (buflocal_nr == 0
7819 || buflist_findnr(buflocal_nr) == NULL))
7820 {
7821 EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
7822 buflocal_nr);
7823 return FAIL;
7824 }
7825
Bram Moolenaar071d4272004-06-13 20:20:40 +00007826 ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
7827 if (ap == NULL)
7828 return FAIL;
7829 ap->pat = vim_strnsave(pat, patlen);
7830 ap->patlen = patlen;
7831 if (ap->pat == NULL)
7832 {
7833 vim_free(ap);
7834 return FAIL;
7835 }
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007836
7837 if (is_buflocal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007838 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007839 ap->buflocal_nr = buflocal_nr;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007840 ap->reg_prog = NULL;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007841 }
7842 else
7843 {
Bram Moolenaar748bf032005-02-02 23:04:36 +00007844 char_u *reg_pat;
7845
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007846 ap->buflocal_nr = 0;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007847 reg_pat = file_pat_to_reg_pat(pat, endpat,
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007848 &ap->allow_dirs, TRUE);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007849 if (reg_pat != NULL)
7850 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00007851 vim_free(reg_pat);
Bram Moolenaar748bf032005-02-02 23:04:36 +00007852 if (reg_pat == NULL || ap->reg_prog == NULL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00007853 {
7854 vim_free(ap->pat);
7855 vim_free(ap);
7856 return FAIL;
7857 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007858 }
7859 ap->cmds = NULL;
7860 *prev_ap = ap;
7861 ap->next = NULL;
7862 if (group == AUGROUP_ALL)
7863 ap->group = current_augroup;
7864 else
7865 ap->group = group;
7866 }
7867
7868 /*
7869 * Add the autocmd at the end of the AutoCmd list.
7870 */
7871 prev_ac = &(ap->cmds);
7872 while ((ac = *prev_ac) != NULL)
7873 prev_ac = &ac->next;
7874 ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
7875 if (ac == NULL)
7876 return FAIL;
7877 ac->cmd = vim_strsave(cmd);
7878#ifdef FEAT_EVAL
7879 ac->scriptID = current_SID;
7880#endif
7881 if (ac->cmd == NULL)
7882 {
7883 vim_free(ac);
7884 return FAIL;
7885 }
7886 ac->next = NULL;
7887 *prev_ac = ac;
7888 ac->nested = nested;
7889 }
7890 }
7891
7892 au_cleanup(); /* may really delete removed patterns/commands now */
7893 return OK;
7894}
7895
7896/*
7897 * Implementation of ":doautocmd [group] event [fname]".
7898 * Return OK for success, FAIL for failure;
7899 */
7900 int
7901do_doautocmd(arg, do_msg)
7902 char_u *arg;
7903 int do_msg; /* give message for no matching autocmds? */
7904{
7905 char_u *fname;
7906 int nothing_done = TRUE;
7907 int group;
7908
7909 /*
7910 * Check for a legal group name. If not, use AUGROUP_ALL.
7911 */
7912 group = au_get_grouparg(&arg);
7913 if (arg == NULL) /* out of memory */
7914 return FAIL;
7915
7916 if (*arg == '*')
7917 {
7918 EMSG(_("E217: Can't execute autocommands for ALL events"));
7919 return FAIL;
7920 }
7921
7922 /*
7923 * Scan over the events.
7924 * If we find an illegal name, return here, don't do anything.
7925 */
7926 fname = find_end_event(arg, group != AUGROUP_ALL);
7927 if (fname == NULL)
7928 return FAIL;
7929
7930 fname = skipwhite(fname);
7931
7932 /*
7933 * Loop over the events.
7934 */
7935 while (*arg && !vim_iswhite(*arg))
7936 if (apply_autocmds_group(event_name2nr(arg, &arg),
7937 fname, NULL, TRUE, group, curbuf, NULL))
7938 nothing_done = FALSE;
7939
7940 if (nothing_done && do_msg)
7941 MSG(_("No matching autocommands"));
7942
7943#ifdef FEAT_EVAL
7944 return aborting() ? FAIL : OK;
7945#else
7946 return OK;
7947#endif
7948}
7949
7950/*
7951 * ":doautoall": execute autocommands for each loaded buffer.
7952 */
7953 void
7954ex_doautoall(eap)
7955 exarg_T *eap;
7956{
7957 int retval;
7958 aco_save_T aco;
7959 buf_T *buf;
7960
7961 /*
7962 * This is a bit tricky: For some commands curwin->w_buffer needs to be
7963 * equal to curbuf, but for some buffers there may not be a window.
7964 * So we change the buffer for the current window for a moment. This
7965 * gives problems when the autocommands make changes to the list of
7966 * buffers or windows...
7967 */
7968 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
7969 {
7970 if (curbuf->b_ml.ml_mfp != NULL)
7971 {
7972 /* find a window for this buffer and save some values */
7973 aucmd_prepbuf(&aco, buf);
7974
7975 /* execute the autocommands for this buffer */
7976 retval = do_doautocmd(eap->arg, FALSE);
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00007977 do_modelines(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007978
7979 /* restore the current window */
7980 aucmd_restbuf(&aco);
7981
7982 /* stop if there is some error or buffer was deleted */
7983 if (retval == FAIL || !buf_valid(buf))
7984 break;
7985 }
7986 }
7987
7988 check_cursor(); /* just in case lines got deleted */
7989}
7990
7991/*
7992 * Prepare for executing autocommands for (hidden) buffer "buf".
7993 * Search a window for the current buffer. Save the cursor position and
7994 * screen offset.
7995 * Set "curbuf" and "curwin" to match "buf".
7996 */
7997 void
7998aucmd_prepbuf(aco, buf)
7999 aco_save_T *aco; /* structure to save values in */
8000 buf_T *buf; /* new curbuf */
8001{
8002 win_T *win;
8003
8004 aco->new_curbuf = buf;
8005
8006 /* Find a window that is for the new buffer */
8007 if (buf == curbuf) /* be quick when buf is curbuf */
8008 win = curwin;
8009 else
8010#ifdef FEAT_WINDOWS
8011 for (win = firstwin; win != NULL; win = win->w_next)
8012 if (win->w_buffer == buf)
8013 break;
8014#else
8015 win = NULL;
8016#endif
8017
8018 /*
8019 * Prefer to use an existing window for the buffer, it has the least side
8020 * effects (esp. if "buf" is curbuf).
8021 * Otherwise, use curwin for "buf". It might make some items in the
8022 * window invalid. At least save the cursor and topline.
8023 */
8024 if (win != NULL)
8025 {
8026 /* there is a window for "buf", make it the curwin */
8027 aco->save_curwin = curwin;
8028 curwin = win;
8029 aco->save_buf = win->w_buffer;
8030 aco->new_curwin = win;
8031 }
8032 else
8033 {
8034 /* there is no window for "buf", use curwin */
8035 aco->save_curwin = NULL;
8036 aco->save_buf = curbuf;
8037 --curbuf->b_nwindows;
8038 curwin->w_buffer = buf;
8039 ++buf->b_nwindows;
8040
8041 /* save cursor and topline, set them to safe values */
8042 aco->save_cursor = curwin->w_cursor;
8043 curwin->w_cursor.lnum = 1;
8044 curwin->w_cursor.col = 0;
8045 aco->save_topline = curwin->w_topline;
8046 curwin->w_topline = 1;
8047#ifdef FEAT_DIFF
8048 aco->save_topfill = curwin->w_topfill;
8049 curwin->w_topfill = 0;
8050#endif
8051 }
8052
8053 curbuf = buf;
8054}
8055
8056/*
8057 * Cleanup after executing autocommands for a (hidden) buffer.
8058 * Restore the window as it was (if possible).
8059 */
8060 void
8061aucmd_restbuf(aco)
8062 aco_save_T *aco; /* structure holding saved values */
8063{
8064 if (aco->save_curwin != NULL)
8065 {
8066 /* restore curwin */
8067#ifdef FEAT_WINDOWS
8068 if (win_valid(aco->save_curwin))
8069#endif
8070 {
8071 /* restore the buffer which was previously edited by curwin, if
8072 * it's still the same window and it's valid */
8073 if (curwin == aco->new_curwin
8074 && buf_valid(aco->save_buf)
8075 && aco->save_buf->b_ml.ml_mfp != NULL)
8076 {
8077 --curbuf->b_nwindows;
8078 curbuf = aco->save_buf;
8079 curwin->w_buffer = curbuf;
8080 ++curbuf->b_nwindows;
8081 }
8082
8083 curwin = aco->save_curwin;
8084 curbuf = curwin->w_buffer;
8085 }
8086 }
8087 else
8088 {
8089 /* restore buffer for curwin if it still exists and is loaded */
8090 if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
8091 {
8092 --curbuf->b_nwindows;
8093 curbuf = aco->save_buf;
8094 curwin->w_buffer = curbuf;
8095 ++curbuf->b_nwindows;
8096 curwin->w_cursor = aco->save_cursor;
8097 check_cursor();
8098 /* check topline < line_count, in case lines got deleted */
8099 if (aco->save_topline <= curbuf->b_ml.ml_line_count)
8100 {
8101 curwin->w_topline = aco->save_topline;
8102#ifdef FEAT_DIFF
8103 curwin->w_topfill = aco->save_topfill;
8104#endif
8105 }
8106 else
8107 {
8108 curwin->w_topline = curbuf->b_ml.ml_line_count;
8109#ifdef FEAT_DIFF
8110 curwin->w_topfill = 0;
8111#endif
8112 }
8113 }
8114 }
8115}
8116
8117static int autocmd_nested = FALSE;
8118
8119/*
8120 * Execute autocommands for "event" and file name "fname".
8121 * Return TRUE if some commands were executed.
8122 */
8123 int
8124apply_autocmds(event, fname, fname_io, force, buf)
8125 EVENT_T event;
8126 char_u *fname; /* NULL or empty means use actual file name */
8127 char_u *fname_io; /* fname to use for <afile> on cmdline */
8128 int force; /* when TRUE, ignore autocmd_busy */
8129 buf_T *buf; /* buffer for <abuf> */
8130{
8131 return apply_autocmds_group(event, fname, fname_io, force,
8132 AUGROUP_ALL, buf, NULL);
8133}
8134
8135/*
8136 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
8137 * setting v:filearg.
8138 */
8139 static int
8140apply_autocmds_exarg(event, fname, fname_io, force, buf, eap)
8141 EVENT_T event;
8142 char_u *fname;
8143 char_u *fname_io;
8144 int force;
8145 buf_T *buf;
8146 exarg_T *eap;
8147{
8148 return apply_autocmds_group(event, fname, fname_io, force,
8149 AUGROUP_ALL, buf, eap);
8150}
8151
8152/*
8153 * Like apply_autocmds(), but handles the caller's retval. If the script
8154 * processing is being aborted or if retval is FAIL when inside a try
8155 * conditional, no autocommands are executed. If otherwise the autocommands
8156 * cause the script to be aborted, retval is set to FAIL.
8157 */
8158 int
8159apply_autocmds_retval(event, fname, fname_io, force, buf, retval)
8160 EVENT_T event;
8161 char_u *fname; /* NULL or empty means use actual file name */
8162 char_u *fname_io; /* fname to use for <afile> on cmdline */
8163 int force; /* when TRUE, ignore autocmd_busy */
8164 buf_T *buf; /* buffer for <abuf> */
8165 int *retval; /* pointer to caller's retval */
8166{
8167 int did_cmd;
8168
Bram Moolenaar1e015462005-09-25 22:16:38 +00008169#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008170 if (should_abort(*retval))
8171 return FALSE;
Bram Moolenaar1e015462005-09-25 22:16:38 +00008172#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008173
8174 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
8175 AUGROUP_ALL, buf, NULL);
Bram Moolenaar1e015462005-09-25 22:16:38 +00008176 if (did_cmd
8177#ifdef FEAT_EVAL
8178 && aborting()
8179#endif
8180 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00008181 *retval = FAIL;
8182 return did_cmd;
8183}
8184
8185#if defined(FEAT_AUTOCMD) || defined(PROTO)
Bram Moolenaard35f9712005-12-18 22:02:33 +00008186/*
8187 * Return TRUE when there is a CursorHold autocommand defined.
8188 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008189 int
8190has_cursorhold()
8191{
8192 return (first_autopat[(int)EVENT_CURSORHOLD] != NULL);
8193}
Bram Moolenaard35f9712005-12-18 22:02:33 +00008194
8195/*
8196 * Return TRUE if the CursorHold event can be triggered.
8197 */
8198 int
8199trigger_cursorhold()
8200{
8201 return (!did_cursorhold
8202 && has_cursorhold()
8203 && !Recording
8204 && get_real_state() == NORMAL_BUSY);
8205}
Bram Moolenaar071d4272004-06-13 20:20:40 +00008206#endif
8207
8208 static int
8209apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
8210 EVENT_T event;
8211 char_u *fname; /* NULL or empty means use actual file name */
8212 char_u *fname_io; /* fname to use for <afile> on cmdline, NULL means
8213 use fname */
8214 int force; /* when TRUE, ignore autocmd_busy */
8215 int group; /* group ID, or AUGROUP_ALL */
8216 buf_T *buf; /* buffer for <abuf> */
8217 exarg_T *eap; /* command arguments */
8218{
8219 char_u *sfname = NULL; /* short file name */
8220 char_u *tail;
8221 int save_changed;
8222 buf_T *old_curbuf;
8223 int retval = FALSE;
8224 char_u *save_sourcing_name;
8225 linenr_T save_sourcing_lnum;
8226 char_u *save_autocmd_fname;
8227 int save_autocmd_bufnr;
8228 char_u *save_autocmd_match;
8229 int save_autocmd_busy;
8230 int save_autocmd_nested;
8231 static int nesting = 0;
8232 AutoPatCmd patcmd;
8233 AutoPat *ap;
8234#ifdef FEAT_EVAL
8235 scid_T save_current_SID;
8236 void *save_funccalp;
8237 char_u *save_cmdarg;
8238 long save_cmdbang;
8239#endif
8240 static int filechangeshell_busy = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00008241#ifdef FEAT_PROFILE
8242 proftime_T wait_time;
8243#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008244
8245 /*
8246 * Quickly return if there are no autocommands for this event or
8247 * autocommands are blocked.
8248 */
8249 if (first_autopat[(int)event] == NULL || autocmd_block > 0)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008250 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008251
8252 /*
8253 * When autocommands are busy, new autocommands are only executed when
8254 * explicitly enabled with the "nested" flag.
8255 */
8256 if (autocmd_busy && !(force || autocmd_nested))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008257 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008258
8259#ifdef FEAT_EVAL
8260 /*
8261 * Quickly return when immdediately aborting on error, or when an interrupt
8262 * occurred or an exception was thrown but not caught.
8263 */
8264 if (aborting())
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008265 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008266#endif
8267
8268 /*
8269 * FileChangedShell never nests, because it can create an endless loop.
8270 */
8271 if (filechangeshell_busy && event == EVENT_FILECHANGEDSHELL)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008272 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008273
8274 /*
8275 * Ignore events in 'eventignore'.
8276 */
8277 if (event_ignored(event))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008278 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008279
8280 /*
8281 * Allow nesting of autocommands, but restrict the depth, because it's
8282 * possible to create an endless loop.
8283 */
8284 if (nesting == 10)
8285 {
8286 EMSG(_("E218: autocommand nesting too deep"));
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008287 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008288 }
8289
8290 /*
8291 * Check if these autocommands are disabled. Used when doing ":all" or
8292 * ":ball".
8293 */
8294 if ( (autocmd_no_enter
8295 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
8296 || (autocmd_no_leave
8297 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008298 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008299
8300 /*
8301 * Save the autocmd_* variables and info about the current buffer.
8302 */
8303 save_autocmd_fname = autocmd_fname;
8304 save_autocmd_bufnr = autocmd_bufnr;
8305 save_autocmd_match = autocmd_match;
8306 save_autocmd_busy = autocmd_busy;
8307 save_autocmd_nested = autocmd_nested;
8308 save_changed = curbuf->b_changed;
8309 old_curbuf = curbuf;
8310
8311 /*
8312 * Set the file name to be used for <afile>.
8313 */
8314 if (fname_io == NULL)
8315 {
8316 if (fname != NULL && *fname != NUL)
8317 autocmd_fname = fname;
8318 else if (buf != NULL)
8319 autocmd_fname = buf->b_fname;
8320 else
8321 autocmd_fname = NULL;
8322 }
8323 else
8324 autocmd_fname = fname_io;
8325
8326 /*
8327 * Set the buffer number to be used for <abuf>.
8328 */
8329 if (buf == NULL)
8330 autocmd_bufnr = 0;
8331 else
8332 autocmd_bufnr = buf->b_fnum;
8333
8334 /*
8335 * When the file name is NULL or empty, use the file name of buffer "buf".
8336 * Always use the full path of the file name to match with, in case
8337 * "allow_dirs" is set.
8338 */
8339 if (fname == NULL || *fname == NUL)
8340 {
8341 if (buf == NULL)
8342 fname = NULL;
8343 else
8344 {
8345#ifdef FEAT_SYN_HL
8346 if (event == EVENT_SYNTAX)
8347 fname = buf->b_p_syn;
8348 else
8349#endif
8350 if (event == EVENT_FILETYPE)
8351 fname = buf->b_p_ft;
8352 else
8353 {
8354 if (buf->b_sfname != NULL)
8355 sfname = vim_strsave(buf->b_sfname);
8356 fname = buf->b_ffname;
8357 }
8358 }
8359 if (fname == NULL)
8360 fname = (char_u *)"";
8361 fname = vim_strsave(fname); /* make a copy, so we can change it */
8362 }
8363 else
8364 {
8365 sfname = vim_strsave(fname);
Bram Moolenaar7c626922005-02-07 22:01:03 +00008366 /* Don't try expanding FileType, Syntax, WindowID or QuickFixCmd* */
8367 if (event == EVENT_FILETYPE
8368 || event == EVENT_SYNTAX
8369 || event == EVENT_REMOTEREPLY
8370 || event == EVENT_QUICKFIXCMDPRE
8371 || event == EVENT_QUICKFIXCMDPOST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008372 fname = vim_strsave(fname);
8373 else
8374 fname = FullName_save(fname, FALSE);
8375 }
8376 if (fname == NULL) /* out of memory */
8377 {
8378 vim_free(sfname);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008379 retval = FALSE;
8380 goto BYPASS_AU;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008381 }
8382
8383#ifdef BACKSLASH_IN_FILENAME
8384 /*
8385 * Replace all backslashes with forward slashes. This makes the
8386 * autocommand patterns portable between Unix and MS-DOS.
8387 */
8388 if (sfname != NULL)
8389 forward_slash(sfname);
8390 forward_slash(fname);
8391#endif
8392
8393#ifdef VMS
8394 /* remove version for correct match */
8395 if (sfname != NULL)
8396 vms_remove_version(sfname);
8397 vms_remove_version(fname);
8398#endif
8399
8400 /*
8401 * Set the name to be used for <amatch>.
8402 */
8403 autocmd_match = fname;
8404
8405
8406 /* Don't redraw while doing auto commands. */
8407 ++RedrawingDisabled;
8408 save_sourcing_name = sourcing_name;
8409 sourcing_name = NULL; /* don't free this one */
8410 save_sourcing_lnum = sourcing_lnum;
8411 sourcing_lnum = 0; /* no line number here */
8412
8413#ifdef FEAT_EVAL
8414 save_current_SID = current_SID;
8415
Bram Moolenaar05159a02005-02-26 23:04:13 +00008416# ifdef FEAT_PROFILE
8417 if (do_profiling)
8418 prof_child_enter(&wait_time); /* doesn't count for the caller itself */
8419# endif
8420
Bram Moolenaar071d4272004-06-13 20:20:40 +00008421 /* Don't use local function variables, if called from a function */
8422 save_funccalp = save_funccal();
8423#endif
8424
8425 /*
8426 * When starting to execute autocommands, save the search patterns.
8427 */
8428 if (!autocmd_busy)
8429 {
8430 save_search_patterns();
8431 saveRedobuff();
8432 did_filetype = keep_filetype;
8433 }
8434
8435 /*
8436 * Note that we are applying autocmds. Some commands need to know.
8437 */
8438 autocmd_busy = TRUE;
8439 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
8440 ++nesting; /* see matching decrement below */
8441
8442 /* Remember that FileType was triggered. Used for did_filetype(). */
8443 if (event == EVENT_FILETYPE)
8444 did_filetype = TRUE;
8445
8446 tail = gettail(fname);
8447
8448 /* Find first autocommand that matches */
8449 patcmd.curpat = first_autopat[(int)event];
8450 patcmd.nextcmd = NULL;
8451 patcmd.group = group;
8452 patcmd.fname = fname;
8453 patcmd.sfname = sfname;
8454 patcmd.tail = tail;
8455 patcmd.event = event;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008456 patcmd.arg_bufnr = autocmd_bufnr;
8457 patcmd.next = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008458 auto_next_pat(&patcmd, FALSE);
8459
8460 /* found one, start executing the autocommands */
8461 if (patcmd.curpat != NULL)
8462 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008463 /* add to active_apc_list */
8464 patcmd.next = active_apc_list;
8465 active_apc_list = &patcmd;
8466
Bram Moolenaar071d4272004-06-13 20:20:40 +00008467#ifdef FEAT_EVAL
8468 /* set v:cmdarg (only when there is a matching pattern) */
8469 save_cmdbang = get_vim_var_nr(VV_CMDBANG);
8470 if (eap != NULL)
8471 {
8472 save_cmdarg = set_cmdarg(eap, NULL);
8473 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
8474 }
8475 else
8476 save_cmdarg = NULL; /* avoid gcc warning */
8477#endif
8478 retval = TRUE;
8479 /* mark the last pattern, to avoid an endless loop when more patterns
8480 * are added when executing autocommands */
8481 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
8482 ap->last = FALSE;
8483 ap->last = TRUE;
8484 check_lnums(TRUE); /* make sure cursor and topline are valid */
8485 do_cmdline(NULL, getnextac, (void *)&patcmd,
8486 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
8487#ifdef FEAT_EVAL
8488 if (eap != NULL)
8489 {
8490 (void)set_cmdarg(NULL, save_cmdarg);
8491 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
8492 }
8493#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008494 /* delete from active_apc_list */
8495 if (active_apc_list == &patcmd) /* just in case */
8496 active_apc_list = patcmd.next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008497 }
8498
8499 --RedrawingDisabled;
8500 autocmd_busy = save_autocmd_busy;
8501 filechangeshell_busy = FALSE;
8502 autocmd_nested = save_autocmd_nested;
8503 vim_free(sourcing_name);
8504 sourcing_name = save_sourcing_name;
8505 sourcing_lnum = save_sourcing_lnum;
8506 autocmd_fname = save_autocmd_fname;
8507 autocmd_bufnr = save_autocmd_bufnr;
8508 autocmd_match = save_autocmd_match;
8509#ifdef FEAT_EVAL
8510 current_SID = save_current_SID;
8511 restore_funccal(save_funccalp);
Bram Moolenaar05159a02005-02-26 23:04:13 +00008512# ifdef FEAT_PROFILE
8513 if (do_profiling)
8514 prof_child_exit(&wait_time);
8515# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008516#endif
8517 vim_free(fname);
8518 vim_free(sfname);
8519 --nesting; /* see matching increment above */
8520
8521 /*
8522 * When stopping to execute autocommands, restore the search patterns and
8523 * the redo buffer.
8524 */
8525 if (!autocmd_busy)
8526 {
8527 restore_search_patterns();
8528 restoreRedobuff();
8529 did_filetype = FALSE;
8530 }
8531
8532 /*
8533 * Some events don't set or reset the Changed flag.
8534 * Check if still in the same buffer!
8535 */
8536 if (curbuf == old_curbuf
8537 && (event == EVENT_BUFREADPOST
8538 || event == EVENT_BUFWRITEPOST
8539 || event == EVENT_FILEAPPENDPOST
8540 || event == EVENT_VIMLEAVE
8541 || event == EVENT_VIMLEAVEPRE))
8542 {
8543#ifdef FEAT_TITLE
8544 if (curbuf->b_changed != save_changed)
8545 need_maketitle = TRUE;
8546#endif
8547 curbuf->b_changed = save_changed;
8548 }
8549
8550 au_cleanup(); /* may really delete removed patterns/commands now */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008551
8552BYPASS_AU:
8553 /* When wiping out a buffer make sure all its buffer-local autocommands
8554 * are deleted. */
8555 if (event == EVENT_BUFWIPEOUT && buf != NULL)
8556 aubuflocal_remove(buf);
8557
Bram Moolenaar071d4272004-06-13 20:20:40 +00008558 return retval;
8559}
8560
8561/*
8562 * Find next autocommand pattern that matches.
8563 */
8564 static void
8565auto_next_pat(apc, stop_at_last)
8566 AutoPatCmd *apc;
8567 int stop_at_last; /* stop when 'last' flag is set */
8568{
8569 AutoPat *ap;
8570 AutoCmd *cp;
8571 char_u *name;
8572 char *s;
8573
8574 vim_free(sourcing_name);
8575 sourcing_name = NULL;
8576
8577 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
8578 {
8579 apc->curpat = NULL;
8580
8581 /* only use a pattern when it has not been removed, has commands and
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008582 * the group matches. For buffer-local autocommands only check the
8583 * buffer number. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008584 if (ap->pat != NULL && ap->cmds != NULL
8585 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
8586 {
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008587 /* execution-condition */
8588 if (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008589 ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
8590 apc->sfname, apc->tail, ap->allow_dirs))
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008591 : ap->buflocal_nr == apc->arg_bufnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008592 {
8593 name = event_nr2name(apc->event);
8594 s = _("%s Auto commands for \"%s\"");
8595 sourcing_name = alloc((unsigned)(STRLEN(s)
8596 + STRLEN(name) + ap->patlen + 1));
8597 if (sourcing_name != NULL)
8598 {
8599 sprintf((char *)sourcing_name, s,
8600 (char *)name, (char *)ap->pat);
8601 if (p_verbose >= 8)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008602 {
8603 verbose_enter();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008604 smsg((char_u *)_("Executing %s"), sourcing_name);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008605 verbose_leave();
8606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008607 }
8608
8609 apc->curpat = ap;
8610 apc->nextcmd = ap->cmds;
8611 /* mark last command */
8612 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
8613 cp->last = FALSE;
8614 cp->last = TRUE;
8615 }
8616 line_breakcheck();
8617 if (apc->curpat != NULL) /* found a match */
8618 break;
8619 }
8620 if (stop_at_last && ap->last)
8621 break;
8622 }
8623}
8624
8625/*
8626 * Get next autocommand command.
8627 * Called by do_cmdline() to get the next line for ":if".
8628 * Returns allocated string, or NULL for end of autocommands.
8629 */
8630/* ARGSUSED */
8631 static char_u *
8632getnextac(c, cookie, indent)
8633 int c; /* not used */
8634 void *cookie;
8635 int indent; /* not used */
8636{
8637 AutoPatCmd *acp = (AutoPatCmd *)cookie;
8638 char_u *retval;
8639 AutoCmd *ac;
8640
8641 /* Can be called again after returning the last line. */
8642 if (acp->curpat == NULL)
8643 return NULL;
8644
8645 /* repeat until we find an autocommand to execute */
8646 for (;;)
8647 {
8648 /* skip removed commands */
8649 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
8650 if (acp->nextcmd->last)
8651 acp->nextcmd = NULL;
8652 else
8653 acp->nextcmd = acp->nextcmd->next;
8654
8655 if (acp->nextcmd != NULL)
8656 break;
8657
8658 /* at end of commands, find next pattern that matches */
8659 if (acp->curpat->last)
8660 acp->curpat = NULL;
8661 else
8662 acp->curpat = acp->curpat->next;
8663 if (acp->curpat != NULL)
8664 auto_next_pat(acp, TRUE);
8665 if (acp->curpat == NULL)
8666 return NULL;
8667 }
8668
8669 ac = acp->nextcmd;
8670
8671 if (p_verbose >= 9)
8672 {
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008673 verbose_enter_scroll();
Bram Moolenaar051b7822005-05-19 21:00:46 +00008674 smsg((char_u *)_("autocommand %s"), ac->cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008675 msg_puts((char_u *)"\n"); /* don't overwrite this either */
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008676 verbose_leave_scroll();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008677 }
8678 retval = vim_strsave(ac->cmd);
8679 autocmd_nested = ac->nested;
8680#ifdef FEAT_EVAL
8681 current_SID = ac->scriptID;
8682#endif
8683 if (ac->last)
8684 acp->nextcmd = NULL;
8685 else
8686 acp->nextcmd = ac->next;
8687 return retval;
8688}
8689
8690/*
8691 * Return TRUE if there is a matching autocommand for "fname".
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008692 * To account for buffer-local autocommands, function needs to know
8693 * in which buffer the file will be opened.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008694 */
8695 int
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008696has_autocmd(event, sfname, buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008697 EVENT_T event;
8698 char_u *sfname;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008699 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008700{
8701 AutoPat *ap;
8702 char_u *fname;
8703 char_u *tail = gettail(sfname);
8704 int retval = FALSE;
8705
8706 fname = FullName_save(sfname, FALSE);
8707 if (fname == NULL)
8708 return FALSE;
8709
8710#ifdef BACKSLASH_IN_FILENAME
8711 /*
8712 * Replace all backslashes with forward slashes. This makes the
8713 * autocommand patterns portable between Unix and MS-DOS.
8714 */
8715 sfname = vim_strsave(sfname);
8716 if (sfname != NULL)
8717 forward_slash(sfname);
8718 forward_slash(fname);
8719#endif
8720
8721 for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
8722 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008723 && (ap->buflocal_nr == 0
Bram Moolenaar748bf032005-02-02 23:04:36 +00008724 ? match_file_pat(NULL, ap->reg_prog,
8725 fname, sfname, tail, ap->allow_dirs)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008726 : buf != NULL && ap->buflocal_nr == buf->b_fnum
8727 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00008728 {
8729 retval = TRUE;
8730 break;
8731 }
8732
8733 vim_free(fname);
8734#ifdef BACKSLASH_IN_FILENAME
8735 vim_free(sfname);
8736#endif
8737
8738 return retval;
8739}
8740
8741#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8742/*
8743 * Function given to ExpandGeneric() to obtain the list of autocommand group
8744 * names.
8745 */
8746/*ARGSUSED*/
8747 char_u *
8748get_augroup_name(xp, idx)
8749 expand_T *xp;
8750 int idx;
8751{
8752 if (idx == augroups.ga_len) /* add "END" add the end */
8753 return (char_u *)"END";
8754 if (idx >= augroups.ga_len) /* end of list */
8755 return NULL;
8756 if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
8757 return (char_u *)"";
8758 return AUGROUP_NAME(idx); /* return a name */
8759}
8760
8761static int include_groups = FALSE;
8762
8763 char_u *
8764set_context_in_autocmd(xp, arg, doautocmd)
8765 expand_T *xp;
8766 char_u *arg;
8767 int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */
8768{
8769 char_u *p;
8770 int group;
8771
8772 /* check for a group name, skip it if present */
8773 include_groups = FALSE;
8774 p = arg;
8775 group = au_get_grouparg(&arg);
8776 if (group == AUGROUP_ERROR)
8777 return NULL;
8778 /* If there only is a group name that's what we expand. */
8779 if (*arg == NUL && group != AUGROUP_ALL && !vim_iswhite(arg[-1]))
8780 {
8781 arg = p;
8782 group = AUGROUP_ALL;
8783 }
8784
8785 /* skip over event name */
8786 for (p = arg; *p != NUL && !vim_iswhite(*p); ++p)
8787 if (*p == ',')
8788 arg = p + 1;
8789 if (*p == NUL)
8790 {
8791 if (group == AUGROUP_ALL)
8792 include_groups = TRUE;
8793 xp->xp_context = EXPAND_EVENTS; /* expand event name */
8794 xp->xp_pattern = arg;
8795 return NULL;
8796 }
8797
8798 /* skip over pattern */
8799 arg = skipwhite(p);
8800 while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\'))
8801 arg++;
8802 if (*arg)
8803 return arg; /* expand (next) command */
8804
8805 if (doautocmd)
8806 xp->xp_context = EXPAND_FILES; /* expand file names */
8807 else
8808 xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */
8809 return NULL;
8810}
8811
8812/*
8813 * Function given to ExpandGeneric() to obtain the list of event names.
8814 */
8815/*ARGSUSED*/
8816 char_u *
8817get_event_name(xp, idx)
8818 expand_T *xp;
8819 int idx;
8820{
8821 if (idx < augroups.ga_len) /* First list group names, if wanted */
8822 {
8823 if (!include_groups || AUGROUP_NAME(idx) == NULL)
8824 return (char_u *)""; /* skip deleted entries */
8825 return AUGROUP_NAME(idx); /* return a name */
8826 }
8827 return (char_u *)event_names[idx - augroups.ga_len].name;
8828}
8829
8830#endif /* FEAT_CMDL_COMPL */
8831
8832/*
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008833 * Return TRUE if autocmd is supported.
8834 */
8835 int
8836autocmd_supported(name)
8837 char_u *name;
8838{
8839 char_u *p;
8840
8841 return (event_name2nr(name, &p) != NUM_EVENTS);
8842}
8843
8844/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00008845 * Return TRUE if an autocommand is defined for a group, event and
8846 * pattern: The group can be omitted to accept any group. "event" and "pattern"
8847 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
8848 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
8849 * Used for:
8850 * exists("#Group") or
8851 * exists("#Group#Event") or
8852 * exists("#Group#Event#pat") or
8853 * exists("#Event") or
8854 * exists("#Event#pat")
Bram Moolenaar071d4272004-06-13 20:20:40 +00008855 */
8856 int
Bram Moolenaar195d6352005-12-19 22:08:24 +00008857au_exists(arg)
8858 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008859{
Bram Moolenaar195d6352005-12-19 22:08:24 +00008860 char_u *arg_save;
8861 char_u *pattern = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008862 char_u *event_name;
8863 char_u *p;
8864 EVENT_T event;
8865 AutoPat *ap;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008866 buf_T *buflocal_buf = NULL;
Bram Moolenaar195d6352005-12-19 22:08:24 +00008867 int group;
8868 int retval = FALSE;
8869
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008870 /* Make a copy so that we can change the '#' chars to a NUL. */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008871 arg_save = vim_strsave(arg);
8872 if (arg_save == NULL)
8873 return FALSE;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00008874 p = vim_strchr(arg_save, '#');
Bram Moolenaar195d6352005-12-19 22:08:24 +00008875 if (p != NULL)
8876 *p++ = NUL;
8877
8878 /* First, look for an autocmd group name */
8879 group = au_find_group(arg_save);
8880 if (group == AUGROUP_ERROR)
8881 {
8882 /* Didn't match a group name, assume the first argument is an event. */
8883 group = AUGROUP_ALL;
8884 event_name = arg_save;
8885 }
8886 else
8887 {
8888 if (p == NULL)
8889 {
8890 /* "Group": group name is present and it's recognized */
8891 retval = TRUE;
8892 goto theend;
8893 }
8894
8895 /* Must be "Group#Event" or "Group#Event#pat". */
8896 event_name = p;
8897 p = vim_strchr(event_name, '#');
8898 if (p != NULL)
8899 *p++ = NUL; /* "Group#Event#pat" */
8900 }
8901
8902 pattern = p; /* "pattern" is NULL when there is no pattern */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008903
8904 /* find the index (enum) for the event name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008905 event = event_name2nr(event_name, &p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008906
8907 /* return FALSE if the event name is not recognized */
Bram Moolenaar195d6352005-12-19 22:08:24 +00008908 if (event == NUM_EVENTS)
8909 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008910
8911 /* Find the first autocommand for this event.
8912 * If there isn't any, return FALSE;
8913 * If there is one and no pattern given, return TRUE; */
8914 ap = first_autopat[(int)event];
8915 if (ap == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008916 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008917 if (pattern == NULL)
Bram Moolenaar195d6352005-12-19 22:08:24 +00008918 {
8919 retval = TRUE;
8920 goto theend;
8921 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008922
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008923 /* if pattern is "<buffer>", special handling is needed which uses curbuf */
8924 /* for pattern "<buffer=N>, fnamecmp() will work fine */
8925 if (STRICMP(pattern, "<buffer>") == 0)
8926 buflocal_buf = curbuf;
8927
Bram Moolenaar071d4272004-06-13 20:20:40 +00008928 /* Check if there is an autocommand with the given pattern. */
8929 for ( ; ap != NULL; ap = ap->next)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008930 /* only use a pattern when it has not been removed and has commands. */
8931 /* For buffer-local autocommands, fnamecmp() works fine. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008932 if (ap->pat != NULL && ap->cmds != NULL
Bram Moolenaar195d6352005-12-19 22:08:24 +00008933 && (group == AUGROUP_ALL || ap->group == group)
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008934 && (buflocal_buf == NULL
8935 ? fnamecmp(ap->pat, pattern) == 0
8936 : ap->buflocal_nr == buflocal_buf->b_fnum))
Bram Moolenaar195d6352005-12-19 22:08:24 +00008937 {
8938 retval = TRUE;
8939 break;
8940 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008941
Bram Moolenaar195d6352005-12-19 22:08:24 +00008942theend:
8943 vim_free(arg_save);
8944 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008945}
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00008946
Bram Moolenaar071d4272004-06-13 20:20:40 +00008947#endif /* FEAT_AUTOCMD */
8948
8949#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN) || defined(PROTO)
8950/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00008951 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
8952 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
8953 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008954 * Used for autocommands and 'wildignore'.
8955 * Returns TRUE if there is a match, FALSE otherwise.
8956 */
8957 int
Bram Moolenaar748bf032005-02-02 23:04:36 +00008958match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008959 char_u *pattern; /* pattern to match with */
Bram Moolenaar748bf032005-02-02 23:04:36 +00008960 regprog_T *prog; /* pre-compiled regprog or NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008961 char_u *fname; /* full path of file name */
8962 char_u *sfname; /* short file name or NULL */
8963 char_u *tail; /* tail of path */
8964 int allow_dirs; /* allow matching with dir */
8965{
8966 regmatch_T regmatch;
8967 int result = FALSE;
8968#ifdef FEAT_OSFILETYPE
8969 int no_pattern = FALSE; /* TRUE if check is filetype only */
8970 char_u *type_start;
8971 char_u c;
8972 int match = FALSE;
8973#endif
8974
8975#ifdef CASE_INSENSITIVE_FILENAME
8976 regmatch.rm_ic = TRUE; /* Always ignore case */
8977#else
8978 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
8979#endif
8980#ifdef FEAT_OSFILETYPE
8981 if (*pattern == '<')
8982 {
8983 /* There is a filetype condition specified with this pattern.
8984 * Check the filetype matches first. If not, don't bother with the
8985 * pattern (set regprog to NULL).
8986 * Always use magic for the regexp.
8987 */
8988
8989 for (type_start = pattern + 1; (c = *pattern); pattern++)
8990 {
8991 if ((c == ';' || c == '>') && match == FALSE)
8992 {
8993 *pattern = NUL; /* Terminate the string */
8994 match = mch_check_filetype(fname, type_start);
8995 *pattern = c; /* Restore the terminator */
8996 type_start = pattern + 1;
8997 }
8998 if (c == '>')
8999 break;
9000 }
9001
9002 /* (c should never be NUL, but check anyway) */
9003 if (match == FALSE || c == NUL)
9004 regmatch.regprog = NULL; /* Doesn't match - don't check pat. */
9005 else if (*pattern == NUL)
9006 {
9007 regmatch.regprog = NULL; /* Vim will try to free regprog later */
9008 no_pattern = TRUE; /* Always matches - don't check pat. */
9009 }
9010 else
9011 regmatch.regprog = vim_regcomp(pattern + 1, RE_MAGIC);
9012 }
9013 else
9014#endif
Bram Moolenaar748bf032005-02-02 23:04:36 +00009015 {
9016 if (prog != NULL)
9017 regmatch.regprog = prog;
9018 else
9019 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
9020 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00009021
9022 /*
9023 * Try for a match with the pattern with:
9024 * 1. the full file name, when the pattern has a '/'.
9025 * 2. the short file name, when the pattern has a '/'.
9026 * 3. the tail of the file name, when the pattern has no '/'.
9027 */
9028 if (
9029#ifdef FEAT_OSFILETYPE
9030 /* If the check is for a filetype only and we don't care
9031 * about the path then skip all the regexp stuff.
9032 */
9033 no_pattern ||
9034#endif
9035 (regmatch.regprog != NULL
9036 && ((allow_dirs
9037 && (vim_regexec(&regmatch, fname, (colnr_T)0)
9038 || (sfname != NULL
9039 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
9040 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
9041 result = TRUE;
9042
Bram Moolenaar748bf032005-02-02 23:04:36 +00009043 if (prog == NULL)
9044 vim_free(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009045 return result;
9046}
9047#endif
9048
9049#if defined(FEAT_WILDIGN) || defined(PROTO)
9050/*
9051 * Return TRUE if a file matches with a pattern in "list".
9052 * "list" is a comma-separated list of patterns, like 'wildignore'.
9053 * "sfname" is the short file name or NULL, "ffname" the long file name.
9054 */
9055 int
9056match_file_list(list, sfname, ffname)
9057 char_u *list;
9058 char_u *sfname;
9059 char_u *ffname;
9060{
9061 char_u buf[100];
9062 char_u *tail;
9063 char_u *regpat;
9064 char allow_dirs;
9065 int match;
9066 char_u *p;
9067
9068 tail = gettail(sfname);
9069
9070 /* try all patterns in 'wildignore' */
9071 p = list;
9072 while (*p)
9073 {
9074 copy_option_part(&p, buf, 100, ",");
9075 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
9076 if (regpat == NULL)
9077 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00009078 match = match_file_pat(regpat, NULL, ffname, sfname,
9079 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009080 vim_free(regpat);
9081 if (match)
9082 return TRUE;
9083 }
9084 return FALSE;
9085}
9086#endif
9087
9088/*
9089 * Convert the given pattern "pat" which has shell style wildcards in it, into
9090 * a regular expression, and return the result in allocated memory. If there
9091 * is a directory path separator to be matched, then TRUE is put in
9092 * allow_dirs, otherwise FALSE is put there -- webb.
9093 * Handle backslashes before special characters, like "\*" and "\ ".
9094 *
9095 * If FEAT_OSFILETYPE defined then pass initial <type> through unchanged. Eg:
9096 * '<html>myfile' becomes '<html>^myfile$' -- leonard.
9097 *
9098 * Returns NULL when out of memory.
9099 */
9100/*ARGSUSED*/
9101 char_u *
9102file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash)
9103 char_u *pat;
9104 char_u *pat_end; /* first char after pattern or NULL */
9105 char *allow_dirs; /* Result passed back out in here */
9106 int no_bslash; /* Don't use a backward slash as pathsep */
9107{
9108 int size;
9109 char_u *endp;
9110 char_u *reg_pat;
9111 char_u *p;
9112 int i;
9113 int nested = 0;
9114 int add_dollar = TRUE;
9115#ifdef FEAT_OSFILETYPE
9116 int check_length = 0;
9117#endif
9118
9119 if (allow_dirs != NULL)
9120 *allow_dirs = FALSE;
9121 if (pat_end == NULL)
9122 pat_end = pat + STRLEN(pat);
9123
9124#ifdef FEAT_OSFILETYPE
9125 /* Find out how much of the string is the filetype check */
9126 if (*pat == '<')
9127 {
9128 /* Count chars until the next '>' */
9129 for (p = pat + 1; p < pat_end && *p != '>'; p++)
9130 ;
9131 if (p < pat_end)
9132 {
9133 /* Pattern is of the form <.*>.* */
9134 check_length = p - pat + 1;
9135 if (p + 1 >= pat_end)
9136 {
9137 /* The 'pattern' is a filetype check ONLY */
9138 reg_pat = (char_u *)alloc(check_length + 1);
9139 if (reg_pat != NULL)
9140 {
9141 mch_memmove(reg_pat, pat, (size_t)check_length);
9142 reg_pat[check_length] = NUL;
9143 }
9144 return reg_pat;
9145 }
9146 }
9147 /* else: there was no closing '>' - assume it was a normal pattern */
9148
9149 }
9150 pat += check_length;
9151 size = 2 + check_length;
9152#else
9153 size = 2; /* '^' at start, '$' at end */
9154#endif
9155
9156 for (p = pat; p < pat_end; p++)
9157 {
9158 switch (*p)
9159 {
9160 case '*':
9161 case '.':
9162 case ',':
9163 case '{':
9164 case '}':
9165 case '~':
9166 size += 2; /* extra backslash */
9167 break;
9168#ifdef BACKSLASH_IN_FILENAME
9169 case '\\':
9170 case '/':
9171 size += 4; /* could become "[\/]" */
9172 break;
9173#endif
9174 default:
9175 size++;
9176# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009177 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009178 {
9179 ++p;
9180 ++size;
9181 }
9182# endif
9183 break;
9184 }
9185 }
9186 reg_pat = alloc(size + 1);
9187 if (reg_pat == NULL)
9188 return NULL;
9189
9190#ifdef FEAT_OSFILETYPE
9191 /* Copy the type check in to the start. */
9192 if (check_length)
9193 mch_memmove(reg_pat, pat - check_length, (size_t)check_length);
9194 i = check_length;
9195#else
9196 i = 0;
9197#endif
9198
9199 if (pat[0] == '*')
9200 while (pat[0] == '*' && pat < pat_end - 1)
9201 pat++;
9202 else
9203 reg_pat[i++] = '^';
9204 endp = pat_end - 1;
9205 if (*endp == '*')
9206 {
9207 while (endp - pat > 0 && *endp == '*')
9208 endp--;
9209 add_dollar = FALSE;
9210 }
9211 for (p = pat; *p && nested >= 0 && p <= endp; p++)
9212 {
9213 switch (*p)
9214 {
9215 case '*':
9216 reg_pat[i++] = '.';
9217 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00009218 while (p[1] == '*') /* "**" matches like "*" */
9219 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00009220 break;
9221 case '.':
9222#ifdef RISCOS
9223 if (allow_dirs != NULL)
9224 *allow_dirs = TRUE;
9225 /* FALLTHROUGH */
9226#endif
9227 case '~':
9228 reg_pat[i++] = '\\';
9229 reg_pat[i++] = *p;
9230 break;
9231 case '?':
9232#ifdef RISCOS
9233 case '#':
9234#endif
9235 reg_pat[i++] = '.';
9236 break;
9237 case '\\':
9238 if (p[1] == NUL)
9239 break;
9240#ifdef BACKSLASH_IN_FILENAME
9241 if (!no_bslash)
9242 {
9243 /* translate:
9244 * "\x" to "\\x" e.g., "dir\file"
9245 * "\*" to "\\.*" e.g., "dir\*.c"
9246 * "\?" to "\\." e.g., "dir\??.c"
9247 * "\+" to "\+" e.g., "fileX\+.c"
9248 */
9249 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
9250 && p[1] != '+')
9251 {
9252 reg_pat[i++] = '[';
9253 reg_pat[i++] = '\\';
9254 reg_pat[i++] = '/';
9255 reg_pat[i++] = ']';
9256 if (allow_dirs != NULL)
9257 *allow_dirs = TRUE;
9258 break;
9259 }
9260 }
9261#endif
9262 if (*++p == '?'
9263#ifdef BACKSLASH_IN_FILENAME
9264 && no_bslash
9265#endif
9266 )
9267 reg_pat[i++] = '?';
9268 else
9269 if (*p == ',')
9270 reg_pat[i++] = ',';
9271 else
9272 {
9273 if (allow_dirs != NULL && vim_ispathsep(*p)
9274#ifdef BACKSLASH_IN_FILENAME
9275 && (!no_bslash || *p != '\\')
9276#endif
9277 )
9278 *allow_dirs = TRUE;
9279 reg_pat[i++] = '\\';
9280 reg_pat[i++] = *p;
9281 }
9282 break;
9283#ifdef BACKSLASH_IN_FILENAME
9284 case '/':
9285 reg_pat[i++] = '[';
9286 reg_pat[i++] = '\\';
9287 reg_pat[i++] = '/';
9288 reg_pat[i++] = ']';
9289 if (allow_dirs != NULL)
9290 *allow_dirs = TRUE;
9291 break;
9292#endif
9293 case '{':
9294 reg_pat[i++] = '\\';
9295 reg_pat[i++] = '(';
9296 nested++;
9297 break;
9298 case '}':
9299 reg_pat[i++] = '\\';
9300 reg_pat[i++] = ')';
9301 --nested;
9302 break;
9303 case ',':
9304 if (nested)
9305 {
9306 reg_pat[i++] = '\\';
9307 reg_pat[i++] = '|';
9308 }
9309 else
9310 reg_pat[i++] = ',';
9311 break;
9312 default:
9313# ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00009314 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00009315 reg_pat[i++] = *p++;
9316 else
9317# endif
9318 if (allow_dirs != NULL && vim_ispathsep(*p))
9319 *allow_dirs = TRUE;
9320 reg_pat[i++] = *p;
9321 break;
9322 }
9323 }
9324 if (add_dollar)
9325 reg_pat[i++] = '$';
9326 reg_pat[i] = NUL;
9327 if (nested != 0)
9328 {
9329 if (nested < 0)
9330 EMSG(_("E219: Missing {."));
9331 else
9332 EMSG(_("E220: Missing }."));
9333 vim_free(reg_pat);
9334 reg_pat = NULL;
9335 }
9336 return reg_pat;
9337}