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