blob: bc0b15b91496f519a9ed27bda4920859cbb1b2fc [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
15
Bram Moolenaarf4888d02009-12-02 12:31:27 +000016#if defined(__TANDEM) || defined(__MINT__)
Bram Moolenaar071d4272004-06-13 20:20:40 +000017# include <limits.h> /* for SSIZE_MAX */
18#endif
19
20#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
21# include <utime.h> /* for struct utimbuf */
22#endif
23
24#define BUFSIZE 8192 /* size of normal write buffer */
25#define SMBUFSIZE 256 /* size of emergency write buffer */
26
Bram Moolenaar071d4272004-06-13 20:20:40 +000027/* Is there any system that doesn't have access()? */
Bram Moolenaar9372a112005-12-06 19:59:18 +000028#define USE_MCH_ACCESS
Bram Moolenaar071d4272004-06-13 20:20:40 +000029
Bram Moolenaard25c16e2016-01-29 22:13:30 +010030static char_u *next_fenc(char_u **pp);
Bram Moolenaar13505972019-01-24 15:04:48 +010031#ifdef FEAT_EVAL
Bram Moolenaard25c16e2016-01-29 22:13:30 +010032static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000033#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000034#ifdef FEAT_CRYPT
Bram Moolenaar8767f522016-07-01 17:17:39 +020035static char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask);
Bram Moolenaar071d4272004-06-13 20:20:40 +000036#endif
Bram Moolenaard25c16e2016-01-29 22:13:30 +010037static int set_rw_fname(char_u *fname, char_u *sfname);
38static int msg_add_fileformat(int eol_type);
39static void msg_add_eol(void);
Bram Moolenaar8767f522016-07-01 17:17:39 +020040static int check_mtime(buf_T *buf, stat_T *s);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010041static int time_differs(long t1, long t2);
Bram Moolenaar071d4272004-06-13 20:20:40 +000042
Bram Moolenaar13505972019-01-24 15:04:48 +010043#define HAS_BW_FLAGS
44#define FIO_LATIN1 0x01 /* convert Latin1 */
45#define FIO_UTF8 0x02 /* convert UTF-8 */
46#define FIO_UCS2 0x04 /* convert UCS-2 */
47#define FIO_UCS4 0x08 /* convert UCS-4 */
48#define FIO_UTF16 0x10 /* convert UTF-16 */
Bram Moolenaar4f974752019-02-17 17:44:42 +010049#ifdef MSWIN
Bram Moolenaar13505972019-01-24 15:04:48 +010050# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
51# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
52# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
Bram Moolenaar071d4272004-06-13 20:20:40 +000053#endif
Bram Moolenaar13505972019-01-24 15:04:48 +010054#ifdef MACOS_CONVERT
55# define FIO_MACROMAN 0x20 /* convert MacRoman */
56#endif
57#define FIO_ENDIAN_L 0x80 /* little endian */
58#define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
59#define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
60#define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
61#define FIO_ALL -1 /* allow all formats */
Bram Moolenaar071d4272004-06-13 20:20:40 +000062
63/* When converting, a read() or write() may leave some bytes to be converted
64 * for the next call. The value is guessed... */
65#define CONV_RESTLEN 30
66
67/* We have to guess how much a sequence of bytes may expand when converting
68 * with iconv() to be able to allocate a buffer. */
69#define ICONV_MULT 8
70
71/*
72 * Structure to pass arguments from buf_write() to buf_write_bytes().
73 */
74struct bw_info
75{
76 int bw_fd; /* file descriptor */
77 char_u *bw_buf; /* buffer with data to be written */
Bram Moolenaard089d9b2007-09-30 12:02:55 +000078 int bw_len; /* length of data */
Bram Moolenaar071d4272004-06-13 20:20:40 +000079#ifdef HAS_BW_FLAGS
80 int bw_flags; /* FIO_ flags */
81#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020082#ifdef FEAT_CRYPT
83 buf_T *bw_buffer; /* buffer being written */
84#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
86 int bw_restlen; /* nr of bytes in bw_rest[] */
87 int bw_first; /* first write call */
88 char_u *bw_conv_buf; /* buffer for writing converted chars */
Bram Moolenaar18a4ba22019-05-24 19:39:03 +020089 size_t bw_conv_buflen; /* size of bw_conv_buf */
Bram Moolenaar071d4272004-06-13 20:20:40 +000090 int bw_conv_error; /* set for conversion error */
Bram Moolenaar32b485f2009-07-29 16:06:27 +000091 linenr_T bw_conv_error_lnum; /* first line with error or zero */
92 linenr_T bw_start_lnum; /* line number at start of buffer */
Bram Moolenaar13505972019-01-24 15:04:48 +010093#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000095#endif
96};
97
Bram Moolenaard25c16e2016-01-29 22:13:30 +010098static int buf_write_bytes(struct bw_info *ip);
Bram Moolenaar071d4272004-06-13 20:20:40 +000099
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100100static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp);
101static int ucs2bytes(unsigned c, char_u **pp, int flags);
102static int need_conversion(char_u *fenc);
103static int get_fio_flags(char_u *ptr);
104static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags);
105static int make_bom(char_u *buf, char_u *name);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100106#ifdef MSWIN
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100107static int get_win_fio_flags(char_u *ptr);
Bram Moolenaar13505972019-01-24 15:04:48 +0100108#endif
109#ifdef MACOS_CONVERT
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100110static int get_mac_fio_flags(char_u *ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000112static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000113
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100115filemess(
116 buf_T *buf,
117 char_u *name,
118 char_u *s,
119 int attr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120{
121 int msg_scroll_save;
122
123 if (msg_silent != 0)
124 return;
125 msg_add_fname(buf, name); /* put file name in IObuff with quotes */
126 /* If it's extremely long, truncate it. */
127 if (STRLEN(IObuff) > IOSIZE - 80)
128 IObuff[IOSIZE - 80] = NUL;
129 STRCAT(IObuff, s);
130 /*
131 * For the first message may have to start a new line.
132 * For further ones overwrite the previous one, reset msg_scroll before
133 * calling filemess().
134 */
135 msg_scroll_save = msg_scroll;
136 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
137 msg_scroll = FALSE;
138 if (!msg_scroll) /* wait a bit when overwriting an error msg */
139 check_for_delay(FALSE);
140 msg_start();
141 msg_scroll = msg_scroll_save;
142 msg_scrolled_ign = TRUE;
143 /* may truncate the message to avoid a hit-return prompt */
144 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
145 msg_clr_eos();
146 out_flush();
147 msg_scrolled_ign = FALSE;
148}
149
150/*
151 * Read lines from file "fname" into the buffer after line "from".
152 *
153 * 1. We allocate blocks with lalloc, as big as possible.
154 * 2. Each block is filled with characters from the file with a single read().
155 * 3. The lines are inserted in the buffer with ml_append().
156 *
157 * (caller must check that fname != NULL, unless READ_STDIN is used)
158 *
159 * "lines_to_skip" is the number of lines that must be skipped
160 * "lines_to_read" is the number of lines that are appended
161 * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
162 *
163 * flags:
164 * READ_NEW starting to edit a new buffer
165 * READ_FILTER reading filter output
166 * READ_STDIN read from stdin instead of a file
167 * READ_BUFFER read from curbuf instead of a file (converting after reading
168 * stdin)
169 * READ_DUMMY read into a dummy buffer (to check if file contents changed)
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200170 * READ_KEEP_UNDO don't clear undo info or read it from a file
Bram Moolenaarf71d7b92016-08-09 22:14:05 +0200171 * READ_FIFO read from fifo/socket instead of a file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 *
Bram Moolenaare13b9af2017-01-13 22:01:02 +0100173 * return FAIL for failure, NOTDONE for directory (failure), or OK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 */
175 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100176readfile(
177 char_u *fname,
178 char_u *sfname,
179 linenr_T from,
180 linenr_T lines_to_skip,
181 linenr_T lines_to_read,
182 exarg_T *eap, /* can be NULL! */
183 int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184{
185 int fd = 0;
186 int newfile = (flags & READ_NEW);
187 int check_readonly;
188 int filtering = (flags & READ_FILTER);
189 int read_stdin = (flags & READ_STDIN);
190 int read_buffer = (flags & READ_BUFFER);
Bram Moolenaarf71d7b92016-08-09 22:14:05 +0200191 int read_fifo = (flags & READ_FIFO);
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000192 int set_options = newfile || read_buffer
193 || (eap != NULL && eap->read_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194 linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
195 colnr_T read_buf_col = 0; /* next char to read from this line */
196 char_u c;
197 linenr_T lnum = from;
198 char_u *ptr = NULL; /* pointer into read buffer */
199 char_u *buffer = NULL; /* read buffer */
200 char_u *new_buffer = NULL; /* init to shut up gcc */
201 char_u *line_start = NULL; /* init to shut up gcc */
202 int wasempty; /* buffer was empty before reading */
203 colnr_T len;
204 long size = 0;
205 char_u *p;
Bram Moolenaar8767f522016-07-01 17:17:39 +0200206 off_T filesize = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207 int skip_read = FALSE;
208#ifdef FEAT_CRYPT
209 char_u *cryptkey = NULL;
Bram Moolenaarf50a2532010-05-21 15:36:08 +0200210 int did_ask_for_key = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +0200212#ifdef FEAT_PERSISTENT_UNDO
213 context_sha256_T sha_ctx;
214 int read_undo_file = FALSE;
215#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 int split = 0; /* number of split lines */
217#define UNKNOWN 0x0fffffff /* file size is unknown */
218 linenr_T linecnt;
219 int error = FALSE; /* errors encountered */
220 int ff_error = EOL_UNKNOWN; /* file format with errors */
221 long linerest = 0; /* remaining chars in line */
222#ifdef UNIX
223 int perm = 0;
224 int swap_mode = -1; /* protection bits for swap file */
225#else
226 int perm;
227#endif
228 int fileformat = 0; /* end-of-line format */
229 int keep_fileformat = FALSE;
Bram Moolenaar8767f522016-07-01 17:17:39 +0200230 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 int file_readonly;
232 linenr_T skip_count = 0;
233 linenr_T read_count = 0;
234 int msg_save = msg_scroll;
235 linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
236 * last read was missing the eol */
Bram Moolenaar7a2699e2017-01-23 21:31:09 +0100237 int try_mac;
238 int try_dos;
239 int try_unix;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240 int file_rewind = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 int can_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000242 linenr_T conv_error = 0; /* line nr with conversion error */
243 linenr_T illegal_byte = 0; /* line nr with illegal byte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
245 in destination encoding */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000246 int bad_char_behavior = BAD_REPLACE;
247 /* BAD_KEEP, BAD_DROP or character to
248 * replace with */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249 char_u *tmpname = NULL; /* name of 'charconvert' output file */
250 int fio_flags = 0;
251 char_u *fenc; /* fileencoding to use */
252 int fenc_alloced; /* fenc_next is in allocated memory */
253 char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
254 int advance_fenc = FALSE;
255 long real_size = 0;
Bram Moolenaar13505972019-01-24 15:04:48 +0100256#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257 iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
Bram Moolenaar13505972019-01-24 15:04:48 +0100258# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 int did_iconv = FALSE; /* TRUE when iconv() failed and trying
260 'charconvert' next */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261# endif
Bram Moolenaar13505972019-01-24 15:04:48 +0100262#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263 int converted = FALSE; /* TRUE if conversion done */
264 int notconverted = FALSE; /* TRUE if conversion wanted but it
265 wasn't possible */
266 char_u conv_rest[CONV_RESTLEN];
267 int conv_restlen = 0; /* nr of bytes in conv_rest[] */
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200268 buf_T *old_curbuf;
269 char_u *old_b_ffname;
270 char_u *old_b_fname;
271 int using_b_ffname;
272 int using_b_fname;
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200273
Bram Moolenaarc3691332016-04-20 12:49:49 +0200274 au_did_filetype = FALSE; /* reset before triggering any autocommands */
Bram Moolenaarc3691332016-04-20 12:49:49 +0200275
Bram Moolenaarcab35ad2011-02-15 17:39:22 +0100276 curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277
278 /*
279 * If there is no file name yet, use the one for the read file.
280 * BF_NOTEDITED is set to reflect this.
281 * Don't do this for a read from a filter.
282 * Only do this when 'cpoptions' contains the 'f' flag.
283 */
284 if (curbuf->b_ffname == NULL
285 && !filtering
286 && fname != NULL
287 && vim_strchr(p_cpo, CPO_FNAMER) != NULL
288 && !(flags & READ_DUMMY))
289 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +0000290 if (set_rw_fname(fname, sfname) == FAIL)
291 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292 }
293
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200294 /* Remember the initial values of curbuf, curbuf->b_ffname and
295 * curbuf->b_fname to detect whether they are altered as a result of
296 * executing nasty autocommands. Also check if "fname" and "sfname"
297 * point to one of these values. */
298 old_curbuf = curbuf;
299 old_b_ffname = curbuf->b_ffname;
300 old_b_fname = curbuf->b_fname;
301 using_b_ffname = (fname == curbuf->b_ffname)
302 || (sfname == curbuf->b_ffname);
303 using_b_fname = (fname == curbuf->b_fname) || (sfname == curbuf->b_fname);
Bram Moolenaarbb3d5dc2010-08-14 14:32:54 +0200304
Bram Moolenaardf177f62005-02-22 08:39:57 +0000305 /* After reading a file the cursor line changes but we don't want to
306 * display the line. */
307 ex_no_reprint = TRUE;
308
Bram Moolenaar55b7cf82006-09-09 12:52:42 +0000309 /* don't display the file info for another buffer now */
310 need_fileinfo = FALSE;
311
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 /*
313 * For Unix: Use the short file name whenever possible.
314 * Avoids problems with networks and when directory names are changed.
315 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
316 * another directory, which we don't detect.
317 */
318 if (sfname == NULL)
319 sfname = fname;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200320#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321 fname = sfname;
322#endif
323
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324 /*
325 * The BufReadCmd and FileReadCmd events intercept the reading process by
326 * executing the associated commands instead.
327 */
328 if (!filtering && !read_stdin && !read_buffer)
329 {
330 pos_T pos;
331
332 pos = curbuf->b_op_start;
333
334 /* Set '[ mark to the line above where the lines go (line 1 if zero). */
335 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
336 curbuf->b_op_start.col = 0;
337
338 if (newfile)
339 {
340 if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
341 FALSE, curbuf, eap))
342#ifdef FEAT_EVAL
343 return aborting() ? FAIL : OK;
344#else
345 return OK;
346#endif
347 }
348 else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
349 FALSE, NULL, eap))
350#ifdef FEAT_EVAL
351 return aborting() ? FAIL : OK;
352#else
353 return OK;
354#endif
355
356 curbuf->b_op_start = pos;
357 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358
359 if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
360 msg_scroll = FALSE; /* overwrite previous file message */
361 else
362 msg_scroll = TRUE; /* don't overwrite previous file message */
363
364 /*
365 * If the name ends in a path separator, we can't open it. Check here,
366 * because reading the file may actually work, but then creating the swap
367 * file may destroy it! Reported on MS-DOS and Win 95.
368 * If the name is too long we might crash further on, quit here.
369 */
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000370 if (fname != NULL && *fname != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000372 p = fname + STRLEN(fname);
373 if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +0000374 {
375 filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
376 msg_end();
377 msg_scroll = msg_save;
378 return FAIL;
379 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 }
381
Bram Moolenaarf71d7b92016-08-09 22:14:05 +0200382 if (!read_stdin && !read_buffer && !read_fifo)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 {
Bram Moolenaar4e4f5292013-08-30 17:07:01 +0200384#ifdef UNIX
385 /*
386 * On Unix it is possible to read a directory, so we have to
387 * check for it before the mch_open().
388 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 perm = mch_getperm(fname);
390 if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391 && !S_ISFIFO(perm) /* ... or fifo */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 && !S_ISSOCK(perm) /* ... or socket */
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +0000393# ifdef OPEN_CHR_FILES
394 && !(S_ISCHR(perm) && is_dev_fd_file(fname))
395 /* ... or a character special file named /dev/fd/<n> */
396# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 )
398 {
Bram Moolenaare13b9af2017-01-13 22:01:02 +0100399 int retval = FAIL;
400
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401 if (S_ISDIR(perm))
Bram Moolenaare13b9af2017-01-13 22:01:02 +0100402 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
Bram Moolenaare13b9af2017-01-13 22:01:02 +0100404 retval = NOTDONE;
405 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 else
407 filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
408 msg_end();
409 msg_scroll = msg_save;
Bram Moolenaare13b9af2017-01-13 22:01:02 +0100410 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 }
Bram Moolenaar4e4f5292013-08-30 17:07:01 +0200412#endif
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100413#if defined(MSWIN)
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000414 /*
415 * MS-Windows allows opening a device, but we will probably get stuck
416 * trying to read it.
417 */
418 if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
419 {
Bram Moolenaar5386a122007-06-28 20:02:32 +0000420 filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
Bram Moolenaarc67764a2006-10-12 19:14:26 +0000421 msg_end();
422 msg_scroll = msg_save;
423 return FAIL;
424 }
Bram Moolenaar043545e2006-10-10 16:44:07 +0000425#endif
Bram Moolenaar4e4f5292013-08-30 17:07:01 +0200426 }
Bram Moolenaar043545e2006-10-10 16:44:07 +0000427
Bram Moolenaarad875fb2013-07-24 15:02:03 +0200428 /* Set default or forced 'fileformat' and 'binary'. */
429 set_file_options(set_options, eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430
431 /*
432 * When opening a new file we take the readonly flag from the file.
433 * Default is r/w, can be set to r/o below.
434 * Don't reset it when in readonly mode
435 * Only set/reset b_p_ro when BF_CHECK_RO is set.
436 */
437 check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000438 if (check_readonly && !readonlymode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 curbuf->b_p_ro = FALSE;
440
Bram Moolenaarf71d7b92016-08-09 22:14:05 +0200441 if (newfile && !read_stdin && !read_buffer && !read_fifo)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442 {
Bram Moolenaare60acc12011-05-10 16:41:25 +0200443 /* Remember time of file. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 if (mch_stat((char *)fname, &st) >= 0)
445 {
446 buf_store_time(curbuf, &st, fname);
447 curbuf->b_mtime_read = curbuf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448#ifdef UNIX
449 /*
450 * Use the protection bits of the original file for the swap file.
451 * This makes it possible for others to read the name of the
452 * edited file from the swapfile, but only if they can read the
453 * edited file.
454 * Remove the "write" and "execute" bits for group and others
455 * (they must not write the swapfile).
456 * Add the "read" and "write" bits for the user, otherwise we may
457 * not be able to write to the file ourselves.
458 * Setting the bits is done below, after creating the swap file.
459 */
460 swap_mode = (st.st_mode & 0644) | 0600;
461#endif
462#ifdef FEAT_CW_EDITOR
463 /* Get the FSSpec on MacOS
464 * TODO: Update it properly when the buffer name changes
465 */
466 (void)GetFSSpecFromPath(curbuf->b_ffname, &curbuf->b_FSSpec);
467#endif
468#ifdef VMS
469 curbuf->b_fab_rfm = st.st_fab_rfm;
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000470 curbuf->b_fab_rat = st.st_fab_rat;
471 curbuf->b_fab_mrs = st.st_fab_mrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472#endif
473 }
474 else
475 {
476 curbuf->b_mtime = 0;
477 curbuf->b_mtime_read = 0;
478 curbuf->b_orig_size = 0;
479 curbuf->b_orig_mode = 0;
480 }
481
482 /* Reset the "new file" flag. It will be set again below when the
483 * file doesn't exist. */
484 curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
485 }
486
487/*
488 * for UNIX: check readonly with perm and mch_access()
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100489 * for Amiga: check readonly by trying to open the file for writing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490 */
491 file_readonly = FALSE;
492 if (read_stdin)
493 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100494#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
496 setmode(0, O_BINARY);
497#endif
498 }
499 else if (!read_buffer)
500 {
501#ifdef USE_MCH_ACCESS
502 if (
503# ifdef UNIX
504 !(perm & 0222) ||
505# endif
506 mch_access((char *)fname, W_OK))
507 file_readonly = TRUE;
508 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
509#else
510 if (!newfile
511 || readonlymode
512 || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
513 {
514 file_readonly = TRUE;
515 /* try to open ro */
516 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
517 }
518#endif
519 }
520
521 if (fd < 0) /* cannot open at all */
522 {
523#ifndef UNIX
524 int isdir_f;
525#endif
526 msg_scroll = msg_save;
527#ifndef UNIX
528 /*
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100529 * On Amiga we can't open a directory, check here.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 */
531 isdir_f = (mch_isdir(fname));
532 perm = mch_getperm(fname); /* check if the file exists */
533 if (isdir_f)
534 {
535 filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
536 curbuf->b_p_ro = TRUE; /* must use "w!" now */
537 }
538 else
539#endif
540 if (newfile)
541 {
Bram Moolenaar2efbc662010-05-14 18:56:38 +0200542 if (perm < 0
543#ifdef ENOENT
544 && errno == ENOENT
545#endif
546 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 {
548 /*
549 * Set the 'new-file' flag, so that when the file has
550 * been created by someone else, a ":w" will complain.
551 */
552 curbuf->b_flags |= BF_NEW;
553
554 /* Create a swap file now, so that other Vims are warned
555 * that we are editing this file. Don't do this for a
556 * "nofile" or "nowrite" buffer type. */
557#ifdef FEAT_QUICKFIX
558 if (!bt_dontwrite(curbuf))
559#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000560 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000562 /* SwapExists autocommand may mess things up */
563 if (curbuf != old_curbuf
564 || (using_b_ffname
565 && (old_b_ffname != curbuf->b_ffname))
566 || (using_b_fname
567 && (old_b_fname != curbuf->b_fname)))
568 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100569 emsg(_(e_auchangedbuf));
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000570 return FAIL;
571 }
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000572 }
Bram Moolenaar5b962cf2005-12-12 21:58:40 +0000573 if (dir_of_file_exists(fname))
574 filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
575 else
576 filemess(curbuf, sfname,
577 (char_u *)_("[New DIRECTORY]"), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578#ifdef FEAT_VIMINFO
579 /* Even though this is a new file, it might have been
580 * edited before and deleted. Get the old marks. */
581 check_marks_read();
582#endif
Bram Moolenaarad875fb2013-07-24 15:02:03 +0200583 /* Set forced 'fileencoding'. */
584 if (eap != NULL)
585 set_forced_fenc(eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586 apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
587 FALSE, curbuf, eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 /* remember the current fileformat */
589 save_file_ff(curbuf);
590
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100591#if defined(FEAT_EVAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 if (aborting()) /* autocmds may abort script processing */
593 return FAIL;
594#endif
595 return OK; /* a new file is not an error */
596 }
597 else
598 {
Bram Moolenaar202795b2005-10-11 20:29:39 +0000599 filemess(curbuf, sfname, (char_u *)(
600# ifdef EFBIG
601 (errno == EFBIG) ? _("[File too big]") :
602# endif
Bram Moolenaar2efbc662010-05-14 18:56:38 +0200603# ifdef EOVERFLOW
604 (errno == EOVERFLOW) ? _("[File too big]") :
605# endif
Bram Moolenaar202795b2005-10-11 20:29:39 +0000606 _("[Permission Denied]")), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 curbuf->b_p_ro = TRUE; /* must use "w!" now */
608 }
609 }
610
611 return FAIL;
612 }
613
614 /*
615 * Only set the 'ro' flag for readonly files the first time they are
616 * loaded. Help files always get readonly mode
617 */
618 if ((check_readonly && file_readonly) || curbuf->b_help)
619 curbuf->b_p_ro = TRUE;
620
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000621 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 {
Bram Moolenaar690ffc02008-01-04 15:31:21 +0000623 /* Don't change 'eol' if reading from buffer as it will already be
624 * correctly set when reading stdin. */
625 if (!read_buffer)
626 {
627 curbuf->b_p_eol = TRUE;
628 curbuf->b_start_eol = TRUE;
629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000631 curbuf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 }
633
634 /* Create a swap file now, so that other Vims are warned that we are
635 * editing this file.
636 * Don't do this for a "nofile" or "nowrite" buffer type. */
637#ifdef FEAT_QUICKFIX
638 if (!bt_dontwrite(curbuf))
639#endif
640 {
641 check_need_swap(newfile);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000642 if (!read_stdin && (curbuf != old_curbuf
643 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
644 || (using_b_fname && (old_b_fname != curbuf->b_fname))))
645 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100646 emsg(_(e_auchangedbuf));
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000647 if (!read_buffer)
648 close(fd);
649 return FAIL;
650 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651#ifdef UNIX
652 /* Set swap file protection bits after creating it. */
Bram Moolenaarf061e0b2009-06-24 15:32:01 +0000653 if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
654 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
Bram Moolenaar5a73e0c2017-11-04 21:35:01 +0100655 {
656 char_u *swap_fname = curbuf->b_ml.ml_mfp->mf_fname;
657
658 /*
659 * If the group-read bit is set but not the world-read bit, then
660 * the group must be equal to the group of the original file. If
661 * we can't make that happen then reset the group-read bit. This
662 * avoids making the swap file readable to more users when the
663 * primary group of the user is too permissive.
664 */
665 if ((swap_mode & 044) == 040)
666 {
667 stat_T swap_st;
668
669 if (mch_stat((char *)swap_fname, &swap_st) >= 0
670 && st.st_gid != swap_st.st_gid
Bram Moolenaar02e802b2018-04-19 21:15:27 +0200671# ifdef HAVE_FCHOWN
Bram Moolenaar5a73e0c2017-11-04 21:35:01 +0100672 && fchown(curbuf->b_ml.ml_mfp->mf_fd, -1, st.st_gid)
Bram Moolenaar02e802b2018-04-19 21:15:27 +0200673 == -1
Bram Moolenaar1f131ae2018-05-21 13:39:40 +0200674# endif
Bram Moolenaar02e802b2018-04-19 21:15:27 +0200675 )
Bram Moolenaar5a73e0c2017-11-04 21:35:01 +0100676 swap_mode &= 0600;
677 }
678
679 (void)mch_setperm(swap_fname, (long)swap_mode);
680 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681#endif
682 }
683
Bram Moolenaar67cf86b2019-04-28 22:25:38 +0200684 // If "Quit" selected at ATTENTION dialog, don't load the file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685 if (swap_exists_action == SEA_QUIT)
686 {
687 if (!read_buffer && !read_stdin)
688 close(fd);
689 return FAIL;
690 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691
692 ++no_wait_return; /* don't wait for return yet */
693
694 /*
695 * Set '[ mark to the line above where the lines go (line 1 if zero).
696 */
697 curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
698 curbuf->b_op_start.col = 0;
699
Bram Moolenaar7a2699e2017-01-23 21:31:09 +0100700 try_mac = (vim_strchr(p_ffs, 'm') != NULL);
701 try_dos = (vim_strchr(p_ffs, 'd') != NULL);
702 try_unix = (vim_strchr(p_ffs, 'x') != NULL);
703
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 if (!read_buffer)
705 {
706 int m = msg_scroll;
707 int n = msg_scrolled;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708
709 /*
710 * The file must be closed again, the autocommands may want to change
711 * the file before reading it.
712 */
713 if (!read_stdin)
714 close(fd); /* ignore errors */
715
716 /*
717 * The output from the autocommands should not overwrite anything and
718 * should not be overwritten: Set msg_scroll, restore its value if no
719 * output was done.
720 */
721 msg_scroll = TRUE;
722 if (filtering)
723 apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
724 FALSE, curbuf, eap);
725 else if (read_stdin)
726 apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
727 FALSE, curbuf, eap);
728 else if (newfile)
729 apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
730 FALSE, curbuf, eap);
731 else
732 apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
733 FALSE, NULL, eap);
Bram Moolenaar7a2699e2017-01-23 21:31:09 +0100734 /* autocommands may have changed it */
735 try_mac = (vim_strchr(p_ffs, 'm') != NULL);
736 try_dos = (vim_strchr(p_ffs, 'd') != NULL);
737 try_unix = (vim_strchr(p_ffs, 'x') != NULL);
738
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 if (msg_scrolled == n)
740 msg_scroll = m;
741
742#ifdef FEAT_EVAL
743 if (aborting()) /* autocmds may abort script processing */
744 {
745 --no_wait_return;
746 msg_scroll = msg_save;
747 curbuf->b_p_ro = TRUE; /* must use "w!" now */
748 return FAIL;
749 }
750#endif
751 /*
752 * Don't allow the autocommands to change the current buffer.
753 * Try to re-open the file.
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000754 *
755 * Don't allow the autocommands to change the buffer name either
756 * (cd for example) if it invalidates fname or sfname.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 */
758 if (!read_stdin && (curbuf != old_curbuf
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +0000759 || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
760 || (using_b_fname && (old_b_fname != curbuf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761 || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
762 {
763 --no_wait_return;
764 msg_scroll = msg_save;
765 if (fd < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100766 emsg(_("E200: *ReadPre autocommands made the file unreadable"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100768 emsg(_("E201: *ReadPre autocommands must not change current buffer"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 curbuf->b_p_ro = TRUE; /* must use "w!" now */
770 return FAIL;
771 }
772 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773
774 /* Autocommands may add lines to the file, need to check if it is empty */
775 wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
776
777 if (!recoverymode && !filtering && !(flags & READ_DUMMY))
778 {
779 /*
780 * Show the user that we are busy reading the input. Sometimes this
781 * may take a while. When reading from stdin another program may
782 * still be running, don't move the cursor to the last line, unless
783 * always using the GUI.
784 */
785 if (read_stdin)
786 {
Bram Moolenaar234d1622017-11-18 14:55:23 +0100787 if (!is_not_a_term())
788 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789#ifndef ALWAYS_USE_GUI
Bram Moolenaarafde13b2019-04-28 19:46:49 +0200790# ifdef VIMDLL
791 if (!gui.in_use)
792# endif
793 mch_msg(_("Vim: Reading from stdin...\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794#endif
795#ifdef FEAT_GUI
Bram Moolenaar234d1622017-11-18 14:55:23 +0100796 /* Also write a message in the GUI window, if there is one. */
797 if (gui.in_use && !gui.dying && !gui.starting)
798 {
799 p = (char_u *)_("Reading from stdin...");
800 gui_write(p, (int)STRLEN(p));
801 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802#endif
Bram Moolenaar234d1622017-11-18 14:55:23 +0100803 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 }
805 else if (!read_buffer)
806 filemess(curbuf, sfname, (char_u *)"", 0);
807 }
808
809 msg_scroll = FALSE; /* overwrite the file message */
810
811 /*
812 * Set linecnt now, before the "retry" caused by a wrong guess for
813 * fileformat, and after the autocommands, which may change them.
814 */
815 linecnt = curbuf->b_ml.ml_line_count;
816
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000817 /* "++bad=" argument. */
818 if (eap != NULL && eap->bad_char != 0)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000819 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000820 bad_char_behavior = eap->bad_char;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000821 if (set_options)
Bram Moolenaar195d6352005-12-19 22:08:24 +0000822 curbuf->b_bad_char = eap->bad_char;
823 }
824 else
825 curbuf->b_bad_char = 0;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000826
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000828 * Decide which 'encoding' to use or use first.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 */
830 if (eap != NULL && eap->force_enc != 0)
831 {
832 fenc = enc_canonize(eap->cmd + eap->force_enc);
833 fenc_alloced = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000834 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 }
836 else if (curbuf->b_p_bin)
837 {
838 fenc = (char_u *)""; /* binary: don't convert */
839 fenc_alloced = FALSE;
840 }
841 else if (curbuf->b_help)
842 {
843 char_u firstline[80];
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000844 int fc;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845
846 /* Help files are either utf-8 or latin1. Try utf-8 first, if this
847 * fails it must be latin1.
848 * Always do this when 'encoding' is "utf-8". Otherwise only do
849 * this when needed to avoid [converted] remarks all the time.
850 * It is needed when the first line contains non-ASCII characters.
851 * That is only in *.??x files. */
852 fenc = (char_u *)"latin1";
853 c = enc_utf8;
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000854 if (!c && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000856 fc = fname[STRLEN(fname) - 1];
857 if (TOLOWER_ASC(fc) == 'x')
858 {
859 /* Read the first line (and a bit more). Immediately rewind to
860 * the start of the file. If the read() fails "len" is -1. */
Bram Moolenaar540fc6f2010-12-17 16:27:16 +0100861 len = read_eintr(fd, firstline, 80);
Bram Moolenaar8767f522016-07-01 17:17:39 +0200862 vim_lseek(fd, (off_T)0L, SEEK_SET);
Bram Moolenaar75c50c42005-06-04 22:06:24 +0000863 for (p = firstline; p < firstline + len; ++p)
864 if (*p >= 0x80)
865 {
866 c = TRUE;
867 break;
868 }
869 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 }
871
872 if (c)
873 {
874 fenc_next = fenc;
875 fenc = (char_u *)"utf-8";
876
877 /* When the file is utf-8 but a character doesn't fit in
878 * 'encoding' don't retry. In help text editing utf-8 bytes
879 * doesn't make sense. */
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000880 if (!enc_utf8)
881 keep_dest_enc = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882 }
883 fenc_alloced = FALSE;
884 }
885 else if (*p_fencs == NUL)
886 {
887 fenc = curbuf->b_p_fenc; /* use format from buffer */
888 fenc_alloced = FALSE;
889 }
890 else
891 {
892 fenc_next = p_fencs; /* try items in 'fileencodings' */
893 fenc = next_fenc(&fenc_next);
894 fenc_alloced = TRUE;
895 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896
897 /*
898 * Jump back here to retry reading the file in different ways.
899 * Reasons to retry:
900 * - encoding conversion failed: try another one from "fenc_next"
901 * - BOM detected and fenc was set, need to setup conversion
902 * - "fileformat" check failed: try another
903 *
904 * Variables set for special retry actions:
905 * "file_rewind" Rewind the file to start reading it again.
906 * "advance_fenc" Advance "fenc" using "fenc_next".
907 * "skip_read" Re-use already read bytes (BOM detected).
908 * "did_iconv" iconv() conversion failed, try 'charconvert'.
909 * "keep_fileformat" Don't reset "fileformat".
910 *
911 * Other status indicators:
912 * "tmpname" When != NULL did conversion with 'charconvert'.
913 * Output file has to be deleted afterwards.
914 * "iconv_fd" When != -1 did conversion with iconv().
915 */
916retry:
917
918 if (file_rewind)
919 {
920 if (read_buffer)
921 {
922 read_buf_lnum = 1;
923 read_buf_col = 0;
924 }
Bram Moolenaar8767f522016-07-01 17:17:39 +0200925 else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 {
927 /* Can't rewind the file, give up. */
928 error = TRUE;
929 goto failed;
930 }
931 /* Delete the previously read lines. */
932 while (lnum > from)
933 ml_delete(lnum--, FALSE);
934 file_rewind = FALSE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000935 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000936 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000938 curbuf->b_start_bomb = FALSE;
939 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000940 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941 }
942
943 /*
944 * When retrying with another "fenc" and the first time "fileformat"
945 * will be reset.
946 */
947 if (keep_fileformat)
948 keep_fileformat = FALSE;
949 else
950 {
951 if (eap != NULL && eap->force_ff != 0)
Bram Moolenaar1c860362008-11-12 15:05:21 +0000952 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 fileformat = get_fileformat_force(curbuf, eap);
Bram Moolenaar1c860362008-11-12 15:05:21 +0000954 try_unix = try_dos = try_mac = FALSE;
955 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 else if (curbuf->b_p_bin)
957 fileformat = EOL_UNIX; /* binary: use Unix format */
958 else if (*p_ffs == NUL)
959 fileformat = get_fileformat(curbuf);/* use format from buffer */
960 else
961 fileformat = EOL_UNKNOWN; /* detect from file */
962 }
963
Bram Moolenaar13505972019-01-24 15:04:48 +0100964#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965 if (iconv_fd != (iconv_t)-1)
966 {
967 /* aborted conversion with iconv(), close the descriptor */
968 iconv_close(iconv_fd);
969 iconv_fd = (iconv_t)-1;
970 }
Bram Moolenaar13505972019-01-24 15:04:48 +0100971#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972
973 if (advance_fenc)
974 {
975 /*
976 * Try the next entry in 'fileencodings'.
977 */
978 advance_fenc = FALSE;
979
980 if (eap != NULL && eap->force_enc != 0)
981 {
982 /* Conversion given with "++cc=" wasn't possible, read
983 * without conversion. */
984 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000985 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000986 if (fenc_alloced)
987 vim_free(fenc);
988 fenc = (char_u *)"";
989 fenc_alloced = FALSE;
990 }
991 else
992 {
993 if (fenc_alloced)
994 vim_free(fenc);
995 if (fenc_next != NULL)
996 {
997 fenc = next_fenc(&fenc_next);
998 fenc_alloced = (fenc_next != NULL);
999 }
1000 else
1001 {
1002 fenc = (char_u *)"";
1003 fenc_alloced = FALSE;
1004 }
1005 }
1006 if (tmpname != NULL)
1007 {
1008 mch_remove(tmpname); /* delete converted file */
Bram Moolenaard23a8232018-02-10 18:45:26 +01001009 VIM_CLEAR(tmpname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010 }
1011 }
1012
1013 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001014 * Conversion may be required when the encoding of the file is different
1015 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 */
1017 fio_flags = 0;
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001018 converted = need_conversion(fenc);
1019 if (converted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 {
1021
1022 /* "ucs-bom" means we need to check the first bytes of the file
1023 * for a BOM. */
1024 if (STRCMP(fenc, ENC_UCSBOM) == 0)
1025 fio_flags = FIO_UCSBOM;
1026
1027 /*
1028 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
1029 * done. This is handled below after read(). Prepare the
1030 * fio_flags to avoid having to parse the string each time.
1031 * Also check for Unicode to Latin1 conversion, because iconv()
1032 * appears not to handle this correctly. This works just like
1033 * conversion to UTF-8 except how the resulting character is put in
1034 * the buffer.
1035 */
1036 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
1037 fio_flags = get_fio_flags(fenc);
1038
Bram Moolenaar4f974752019-02-17 17:44:42 +01001039#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 /*
1041 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
1042 * is handled with MultiByteToWideChar().
1043 */
1044 if (fio_flags == 0)
1045 fio_flags = get_win_fio_flags(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001046#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047
Bram Moolenaar13505972019-01-24 15:04:48 +01001048#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1050 if (fio_flags == 0)
1051 fio_flags = get_mac_fio_flags(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001052#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053
Bram Moolenaar13505972019-01-24 15:04:48 +01001054#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055 /*
1056 * Try using iconv() if we can't convert internally.
1057 */
1058 if (fio_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001059# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 && !did_iconv
Bram Moolenaar13505972019-01-24 15:04:48 +01001061# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 )
1063 iconv_fd = (iconv_t)my_iconv_open(
1064 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001065#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066
Bram Moolenaar13505972019-01-24 15:04:48 +01001067#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 /*
1069 * Use the 'charconvert' expression when conversion is required
1070 * and we can't do it internally or with iconv().
1071 */
1072 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001073 && !read_fifo
Bram Moolenaar13505972019-01-24 15:04:48 +01001074# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 && iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001076# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 )
1078 {
Bram Moolenaar13505972019-01-24 15:04:48 +01001079# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080 did_iconv = FALSE;
Bram Moolenaar13505972019-01-24 15:04:48 +01001081# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 /* Skip conversion when it's already done (retry for wrong
1083 * "fileformat"). */
1084 if (tmpname == NULL)
1085 {
1086 tmpname = readfile_charconvert(fname, fenc, &fd);
1087 if (tmpname == NULL)
1088 {
1089 /* Conversion failed. Try another one. */
1090 advance_fenc = TRUE;
1091 if (fd < 0)
1092 {
1093 /* Re-opening the original file failed! */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001094 emsg(_("E202: Conversion made file unreadable!"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095 error = TRUE;
1096 goto failed;
1097 }
1098 goto retry;
1099 }
1100 }
1101 }
1102 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001103#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 {
1105 if (fio_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001106#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 && iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001108#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 )
1110 {
1111 /* Conversion wanted but we can't.
1112 * Try the next conversion in 'fileencodings' */
1113 advance_fenc = TRUE;
1114 goto retry;
1115 }
1116 }
1117 }
1118
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001119 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001121 * stdin or fixed at a specific encoding. */
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001122 can_retry = (*fenc != NUL && !read_stdin && !read_fifo && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123
1124 if (!skip_read)
1125 {
1126 linerest = 0;
1127 filesize = 0;
1128 skip_count = lines_to_skip;
1129 read_count = lines_to_read;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001130 conv_restlen = 0;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001131#ifdef FEAT_PERSISTENT_UNDO
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001132 read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0
1133 && curbuf->b_ffname != NULL
1134 && curbuf->b_p_udf
1135 && !filtering
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001136 && !read_fifo
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001137 && !read_stdin
1138 && !read_buffer);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001139 if (read_undo_file)
1140 sha256_start(&sha_ctx);
1141#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001142#ifdef FEAT_CRYPT
1143 if (curbuf->b_cryptstate != NULL)
1144 {
1145 /* Need to free the state, but keep the key, don't want to ask for
1146 * it again. */
1147 crypt_free_state(curbuf->b_cryptstate);
1148 curbuf->b_cryptstate = NULL;
1149 }
1150#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 }
1152
1153 while (!error && !got_int)
1154 {
1155 /*
1156 * We allocate as much space for the file as we can get, plus
1157 * space for the old line plus room for one terminating NUL.
1158 * The amount is limited by the fact that read() only can read
1159 * upto max_unsigned characters (and other things).
1160 */
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001161 if (!skip_read)
1162 {
Bram Moolenaar30276f22019-01-24 17:59:39 +01001163#if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001164 size = SSIZE_MAX; /* use max I/O size, 52K */
Bram Moolenaar30276f22019-01-24 17:59:39 +01001165#else
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001166 /* Use buffer >= 64K. Add linerest to double the size if the
1167 * line gets very long, to avoid a lot of copying. But don't
1168 * read more than 1 Mbyte at a time, so we can be interrupted.
1169 */
1170 size = 0x10000L + linerest;
1171 if (size > 0x100000L)
1172 size = 0x100000L;
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001173#endif
1174 }
1175
1176 /* Protect against the argument of lalloc() going negative. */
Bram Moolenaar30276f22019-01-24 17:59:39 +01001177 if (size < 0 || size + linerest + 1 < 0 || linerest >= MAXCOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 {
1179 ++split;
1180 *ptr = NL; /* split line by inserting a NL */
1181 size = 1;
1182 }
1183 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184 {
1185 if (!skip_read)
1186 {
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001187 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 {
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02001189 if ((new_buffer = lalloc(size + linerest + 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190 FALSE)) != NULL)
1191 break;
1192 }
1193 if (new_buffer == NULL)
1194 {
1195 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1196 error = TRUE;
1197 break;
1198 }
1199 if (linerest) /* copy characters from the previous buffer */
1200 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1201 vim_free(buffer);
1202 buffer = new_buffer;
1203 ptr = buffer + linerest;
1204 line_start = buffer;
1205
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 /* May need room to translate into.
1207 * For iconv() we don't really know the required space, use a
1208 * factor ICONV_MULT.
1209 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1210 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1211 * become up to 4 bytes, size must be multiple of 2
1212 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1213 * multiple of 2
1214 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1215 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001216 real_size = (int)size;
Bram Moolenaar13505972019-01-24 15:04:48 +01001217#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 if (iconv_fd != (iconv_t)-1)
1219 size = size / ICONV_MULT;
1220 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001221#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222 if (fio_flags & FIO_LATIN1)
1223 size = size / 2;
1224 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1225 size = (size * 2 / 3) & ~1;
1226 else if (fio_flags & FIO_UCS4)
1227 size = (size * 2 / 3) & ~3;
1228 else if (fio_flags == FIO_UCSBOM)
1229 size = size / ICONV_MULT; /* worst case */
Bram Moolenaar4f974752019-02-17 17:44:42 +01001230#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 else if (fio_flags & FIO_CODEPAGE)
1232 size = size / ICONV_MULT; /* also worst case */
Bram Moolenaar13505972019-01-24 15:04:48 +01001233#endif
1234#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 else if (fio_flags & FIO_MACROMAN)
1236 size = size / ICONV_MULT; /* also worst case */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237#endif
1238
Bram Moolenaar071d4272004-06-13 20:20:40 +00001239 if (conv_restlen > 0)
1240 {
1241 /* Insert unconverted bytes from previous line. */
1242 mch_memmove(ptr, conv_rest, conv_restlen);
1243 ptr += conv_restlen;
1244 size -= conv_restlen;
1245 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246
1247 if (read_buffer)
1248 {
1249 /*
1250 * Read bytes from curbuf. Used for converting text read
1251 * from stdin.
1252 */
1253 if (read_buf_lnum > from)
1254 size = 0;
1255 else
1256 {
1257 int n, ni;
1258 long tlen;
1259
1260 tlen = 0;
1261 for (;;)
1262 {
1263 p = ml_get(read_buf_lnum) + read_buf_col;
1264 n = (int)STRLEN(p);
1265 if ((int)tlen + n + 1 > size)
1266 {
1267 /* Filled up to "size", append partial line.
1268 * Change NL to NUL to reverse the effect done
1269 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001270 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 for (ni = 0; ni < n; ++ni)
1272 {
1273 if (p[ni] == NL)
1274 ptr[tlen++] = NUL;
1275 else
1276 ptr[tlen++] = p[ni];
1277 }
1278 read_buf_col += n;
1279 break;
1280 }
1281 else
1282 {
1283 /* Append whole line and new-line. Change NL
1284 * to NUL to reverse the effect done below. */
1285 for (ni = 0; ni < n; ++ni)
1286 {
1287 if (p[ni] == NL)
1288 ptr[tlen++] = NUL;
1289 else
1290 ptr[tlen++] = p[ni];
1291 }
1292 ptr[tlen++] = NL;
1293 read_buf_col = 0;
1294 if (++read_buf_lnum > from)
1295 {
1296 /* When the last line didn't have an
1297 * end-of-line don't add it now either. */
1298 if (!curbuf->b_p_eol)
1299 --tlen;
1300 size = tlen;
1301 break;
1302 }
1303 }
1304 }
1305 }
1306 }
1307 else
1308 {
1309 /*
1310 * Read bytes from the file.
1311 */
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01001312 size = read_eintr(fd, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 }
1314
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001315#ifdef FEAT_CRYPT
1316 /*
1317 * At start of file: Check for magic number of encryption.
1318 */
1319 if (filesize == 0 && size > 0)
1320 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1321 &filesize, newfile, sfname,
1322 &did_ask_for_key);
1323 /*
1324 * Decrypt the read bytes. This is done before checking for
1325 * EOF because the crypt layer may be buffering.
1326 */
Bram Moolenaar829aa642017-08-23 22:32:35 +02001327 if (cryptkey != NULL && curbuf->b_cryptstate != NULL
1328 && size > 0)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001329 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01001330# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001331 if (crypt_works_inplace(curbuf->b_cryptstate))
1332 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01001333# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001334 crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
Bram Moolenaar987411d2019-01-18 22:48:34 +01001335# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001336 }
1337 else
1338 {
1339 char_u *newptr = NULL;
1340 int decrypted_size;
1341
1342 decrypted_size = crypt_decode_alloc(
1343 curbuf->b_cryptstate, ptr, size, &newptr);
1344
1345 /* If the crypt layer is buffering, not producing
1346 * anything yet, need to read more. */
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +02001347 if (decrypted_size == 0)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001348 continue;
1349
1350 if (linerest == 0)
1351 {
1352 /* Simple case: reuse returned buffer (may be
1353 * NULL, checked later). */
1354 new_buffer = newptr;
1355 }
1356 else
1357 {
1358 long_u new_size;
1359
1360 /* Need new buffer to add bytes carried over. */
1361 new_size = (long_u)(decrypted_size + linerest + 1);
1362 new_buffer = lalloc(new_size, FALSE);
1363 if (new_buffer == NULL)
1364 {
1365 do_outofmem_msg(new_size);
1366 error = TRUE;
1367 break;
1368 }
1369
1370 mch_memmove(new_buffer, buffer, linerest);
1371 if (newptr != NULL)
1372 mch_memmove(new_buffer + linerest, newptr,
1373 decrypted_size);
1374 }
1375
1376 if (new_buffer != NULL)
1377 {
1378 vim_free(buffer);
1379 buffer = new_buffer;
1380 new_buffer = NULL;
1381 line_start = buffer;
1382 ptr = buffer + linerest;
1383 }
1384 size = decrypted_size;
1385 }
Bram Moolenaar987411d2019-01-18 22:48:34 +01001386# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001387 }
1388#endif
1389
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390 if (size <= 0)
1391 {
1392 if (size < 0) /* read error */
1393 error = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001395 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001396 /*
1397 * Reached end-of-file but some trailing bytes could
1398 * not be converted. Truncated file?
1399 */
1400
1401 /* When we did a conversion report an error. */
1402 if (fio_flags != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001403#ifdef USE_ICONV
Bram Moolenaarf453d352008-06-04 17:37:34 +00001404 || iconv_fd != (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001405#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00001406 )
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001407 {
Bram Moolenaare8d95302013-04-24 16:34:02 +02001408 if (can_retry)
1409 goto rewind_retry;
Bram Moolenaarf453d352008-06-04 17:37:34 +00001410 if (conv_error == 0)
1411 conv_error = curbuf->b_ml.ml_line_count
1412 - linecnt + 1;
1413 }
1414 /* Remember the first linenr with an illegal byte */
1415 else if (illegal_byte == 0)
1416 illegal_byte = curbuf->b_ml.ml_line_count
1417 - linecnt + 1;
1418 if (bad_char_behavior == BAD_DROP)
1419 {
1420 *(ptr - conv_restlen) = NUL;
1421 conv_restlen = 0;
1422 }
1423 else
1424 {
1425 /* Replace the trailing bytes with the replacement
1426 * character if we were converting; if we weren't,
1427 * leave the UTF8 checking code to do it, as it
1428 * works slightly differently. */
1429 if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001430#ifdef USE_ICONV
Bram Moolenaarf453d352008-06-04 17:37:34 +00001431 || iconv_fd != (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001432#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00001433 ))
1434 {
1435 while (conv_restlen > 0)
1436 {
1437 *(--ptr) = bad_char_behavior;
1438 --conv_restlen;
1439 }
1440 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001441 fio_flags = 0; /* don't convert this */
Bram Moolenaar13505972019-01-24 15:04:48 +01001442#ifdef USE_ICONV
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001443 if (iconv_fd != (iconv_t)-1)
1444 {
1445 iconv_close(iconv_fd);
1446 iconv_fd = (iconv_t)-1;
1447 }
Bram Moolenaar13505972019-01-24 15:04:48 +01001448#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001449 }
1450 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001452 }
1453 skip_read = FALSE;
1454
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 /*
1456 * At start of file (or after crypt magic number): Check for BOM.
1457 * Also check for a BOM for other Unicode encodings, but not after
1458 * converting with 'charconvert' or when a BOM has already been
1459 * found.
1460 */
1461 if ((filesize == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001462#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001463 || (cryptkey != NULL
1464 && filesize == crypt_get_header_len(
1465 crypt_get_method_nr(curbuf)))
Bram Moolenaar13505972019-01-24 15:04:48 +01001466#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467 )
1468 && (fio_flags == FIO_UCSBOM
1469 || (!curbuf->b_p_bomb
1470 && tmpname == NULL
1471 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1472 {
1473 char_u *ccname;
1474 int blen;
1475
1476 /* no BOM detection in a short file or in binary mode */
1477 if (size < 2 || curbuf->b_p_bin)
1478 ccname = NULL;
1479 else
1480 ccname = check_for_bom(ptr, size, &blen,
1481 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1482 if (ccname != NULL)
1483 {
1484 /* Remove BOM from the text */
1485 filesize += blen;
1486 size -= blen;
1487 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001488 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001489 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 curbuf->b_p_bomb = TRUE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001491 curbuf->b_start_bomb = TRUE;
1492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001493 }
1494
1495 if (fio_flags == FIO_UCSBOM)
1496 {
1497 if (ccname == NULL)
1498 {
1499 /* No BOM detected: retry with next encoding. */
1500 advance_fenc = TRUE;
1501 }
1502 else
1503 {
1504 /* BOM detected: set "fenc" and jump back */
1505 if (fenc_alloced)
1506 vim_free(fenc);
1507 fenc = ccname;
1508 fenc_alloced = FALSE;
1509 }
1510 /* retry reading without getting new bytes or rewinding */
1511 skip_read = TRUE;
1512 goto retry;
1513 }
1514 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001515
1516 /* Include not converted bytes. */
1517 ptr -= conv_restlen;
1518 size += conv_restlen;
1519 conv_restlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520 /*
1521 * Break here for a read error or end-of-file.
1522 */
1523 if (size <= 0)
1524 break;
1525
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526
Bram Moolenaar13505972019-01-24 15:04:48 +01001527#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528 if (iconv_fd != (iconv_t)-1)
1529 {
1530 /*
1531 * Attempt conversion of the read bytes to 'encoding' using
1532 * iconv().
1533 */
1534 const char *fromp;
1535 char *top;
1536 size_t from_size;
1537 size_t to_size;
1538
1539 fromp = (char *)ptr;
1540 from_size = size;
1541 ptr += size;
1542 top = (char *)ptr;
1543 to_size = real_size - size;
1544
1545 /*
1546 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001547 * another conversion. Except for when there is no
1548 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001550 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1551 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1553 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001554 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001555 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001556 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001557 if (conv_error == 0)
1558 conv_error = readfile_linenr(linecnt,
1559 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001560
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001561 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001562 ++fromp;
1563 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001564 if (bad_char_behavior == BAD_KEEP)
1565 {
1566 *top++ = *(fromp - 1);
1567 --to_size;
1568 }
1569 else if (bad_char_behavior != BAD_DROP)
1570 {
1571 *top++ = bad_char_behavior;
1572 --to_size;
1573 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575
1576 if (from_size > 0)
1577 {
1578 /* Some remaining characters, keep them for the next
1579 * round. */
1580 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1581 conv_restlen = (int)from_size;
1582 }
1583
1584 /* move the linerest to before the converted characters */
1585 line_start = ptr - linerest;
1586 mch_memmove(line_start, buffer, (size_t)linerest);
1587 size = (long)((char_u *)top - ptr);
1588 }
Bram Moolenaar13505972019-01-24 15:04:48 +01001589#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590
Bram Moolenaar4f974752019-02-17 17:44:42 +01001591#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592 if (fio_flags & FIO_CODEPAGE)
1593 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001594 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001595 WCHAR ucs2buf[3];
1596 int ucs2len;
1597 int codepage = FIO_GET_CP(fio_flags);
1598 int bytelen;
1599 int found_bad;
1600 char replstr[2];
1601
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 /*
1603 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001604 * a codepage, using standard MS-Windows functions. This
1605 * requires two steps:
1606 * 1. convert from 'fileencoding' to ucs-2
1607 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001609 * Because there may be illegal bytes AND an incomplete byte
1610 * sequence at the end, we may have to do the conversion one
1611 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001614 /* Replacement string for WideCharToMultiByte(). */
1615 if (bad_char_behavior > 0)
1616 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001618 replstr[0] = '?';
1619 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620
1621 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001622 * Move the bytes to the end of the buffer, so that we have
1623 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001624 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001625 src = ptr + real_size - size;
1626 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001628 /*
1629 * Do the conversion.
1630 */
1631 dst = ptr;
1632 size = size;
1633 while (size > 0)
1634 {
1635 found_bad = FALSE;
1636
1637# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1638 if (codepage == CP_UTF8)
1639 {
1640 /* Handle CP_UTF8 input ourselves to be able to handle
1641 * trailing bytes properly.
1642 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001643 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001644 if (bytelen > size)
1645 {
1646 /* Only got some bytes of a character. Normally
1647 * it's put in "conv_rest", but if it's too long
1648 * deal with it as if they were illegal bytes. */
1649 if (bytelen <= CONV_RESTLEN)
1650 break;
1651
1652 /* weird overlong byte sequence */
1653 bytelen = size;
1654 found_bad = TRUE;
1655 }
1656 else
1657 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001658 int u8c = utf_ptr2char(src);
1659
Bram Moolenaar86e01082005-12-29 22:45:34 +00001660 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001661 found_bad = TRUE;
1662 ucs2buf[0] = u8c;
1663 ucs2len = 1;
1664 }
1665 }
1666 else
1667# endif
1668 {
1669 /* We don't know how long the byte sequence is, try
1670 * from one to three bytes. */
1671 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1672 ++bytelen)
1673 {
1674 ucs2len = MultiByteToWideChar(codepage,
1675 MB_ERR_INVALID_CHARS,
1676 (LPCSTR)src, bytelen,
1677 ucs2buf, 3);
1678 if (ucs2len > 0)
1679 break;
1680 }
1681 if (ucs2len == 0)
1682 {
1683 /* If we have only one byte then it's probably an
1684 * incomplete byte sequence. Otherwise discard
1685 * one byte as a bad character. */
1686 if (size == 1)
1687 break;
1688 found_bad = TRUE;
1689 bytelen = 1;
1690 }
1691 }
1692
1693 if (!found_bad)
1694 {
1695 int i;
1696
1697 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1698 if (enc_utf8)
1699 {
1700 /* From UCS-2 to UTF-8. Cannot fail. */
1701 for (i = 0; i < ucs2len; ++i)
1702 dst += utf_char2bytes(ucs2buf[i], dst);
1703 }
1704 else
1705 {
1706 BOOL bad = FALSE;
1707 int dstlen;
1708
1709 /* From UCS-2 to "enc_codepage". If the
1710 * conversion uses the default character "?",
1711 * the data doesn't fit in this encoding. */
1712 dstlen = WideCharToMultiByte(enc_codepage, 0,
1713 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001714 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001715 replstr, &bad);
1716 if (bad)
1717 found_bad = TRUE;
1718 else
1719 dst += dstlen;
1720 }
1721 }
1722
1723 if (found_bad)
1724 {
1725 /* Deal with bytes we can't convert. */
1726 if (can_retry)
1727 goto rewind_retry;
1728 if (conv_error == 0)
1729 conv_error = readfile_linenr(linecnt, ptr, dst);
1730 if (bad_char_behavior != BAD_DROP)
1731 {
1732 if (bad_char_behavior == BAD_KEEP)
1733 {
1734 mch_memmove(dst, src, bytelen);
1735 dst += bytelen;
1736 }
1737 else
1738 *dst++ = bad_char_behavior;
1739 }
1740 }
1741
1742 src += bytelen;
1743 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001745
1746 if (size > 0)
1747 {
1748 /* An incomplete byte sequence remaining. */
1749 mch_memmove(conv_rest, src, size);
1750 conv_restlen = size;
1751 }
1752
1753 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001754 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 }
1756 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001757#endif
1758#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 if (fio_flags & FIO_MACROMAN)
1760 {
1761 /*
1762 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001763 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001765 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 }
1768 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001769#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 if (fio_flags != 0)
1771 {
1772 int u8c;
1773 char_u *dest;
1774 char_u *tail = NULL;
1775
1776 /*
1777 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1778 * "enc_utf8" not set: Convert Unicode to Latin1.
1779 * Go from end to start through the buffer, because the number
1780 * of bytes may increase.
1781 * "dest" points to after where the UTF-8 bytes go, "p" points
1782 * to after the next character to convert.
1783 */
1784 dest = ptr + real_size;
1785 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1786 {
1787 p = ptr + size;
1788 if (fio_flags == FIO_UTF8)
1789 {
1790 /* Check for a trailing incomplete UTF-8 sequence */
1791 tail = ptr + size - 1;
1792 while (tail > ptr && (*tail & 0xc0) == 0x80)
1793 --tail;
1794 if (tail + utf_byte2len(*tail) <= ptr + size)
1795 tail = NULL;
1796 else
1797 p = tail;
1798 }
1799 }
1800 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1801 {
1802 /* Check for a trailing byte */
1803 p = ptr + (size & ~1);
1804 if (size & 1)
1805 tail = p;
1806 if ((fio_flags & FIO_UTF16) && p > ptr)
1807 {
1808 /* Check for a trailing leading word */
1809 if (fio_flags & FIO_ENDIAN_L)
1810 {
1811 u8c = (*--p << 8);
1812 u8c += *--p;
1813 }
1814 else
1815 {
1816 u8c = *--p;
1817 u8c += (*--p << 8);
1818 }
1819 if (u8c >= 0xd800 && u8c <= 0xdbff)
1820 tail = p;
1821 else
1822 p += 2;
1823 }
1824 }
1825 else /* FIO_UCS4 */
1826 {
1827 /* Check for trailing 1, 2 or 3 bytes */
1828 p = ptr + (size & ~3);
1829 if (size & 3)
1830 tail = p;
1831 }
1832
1833 /* If there is a trailing incomplete sequence move it to
1834 * conv_rest[]. */
1835 if (tail != NULL)
1836 {
1837 conv_restlen = (int)((ptr + size) - tail);
1838 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1839 size -= conv_restlen;
1840 }
1841
1842
1843 while (p > ptr)
1844 {
1845 if (fio_flags & FIO_LATIN1)
1846 u8c = *--p;
1847 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1848 {
1849 if (fio_flags & FIO_ENDIAN_L)
1850 {
1851 u8c = (*--p << 8);
1852 u8c += *--p;
1853 }
1854 else
1855 {
1856 u8c = *--p;
1857 u8c += (*--p << 8);
1858 }
1859 if ((fio_flags & FIO_UTF16)
1860 && u8c >= 0xdc00 && u8c <= 0xdfff)
1861 {
1862 int u16c;
1863
1864 if (p == ptr)
1865 {
1866 /* Missing leading word. */
1867 if (can_retry)
1868 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001869 if (conv_error == 0)
1870 conv_error = readfile_linenr(linecnt,
1871 ptr, p);
1872 if (bad_char_behavior == BAD_DROP)
1873 continue;
1874 if (bad_char_behavior != BAD_KEEP)
1875 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 }
1877
1878 /* found second word of double-word, get the first
1879 * word and compute the resulting character */
1880 if (fio_flags & FIO_ENDIAN_L)
1881 {
1882 u16c = (*--p << 8);
1883 u16c += *--p;
1884 }
1885 else
1886 {
1887 u16c = *--p;
1888 u16c += (*--p << 8);
1889 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001890 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1891 + (u8c & 0x3ff);
1892
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 /* Check if the word is indeed a leading word. */
1894 if (u16c < 0xd800 || u16c > 0xdbff)
1895 {
1896 if (can_retry)
1897 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001898 if (conv_error == 0)
1899 conv_error = readfile_linenr(linecnt,
1900 ptr, p);
1901 if (bad_char_behavior == BAD_DROP)
1902 continue;
1903 if (bad_char_behavior != BAD_KEEP)
1904 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 }
1907 }
1908 else if (fio_flags & FIO_UCS4)
1909 {
1910 if (fio_flags & FIO_ENDIAN_L)
1911 {
Bram Moolenaardc1c9812017-10-27 22:15:24 +02001912 u8c = (unsigned)*--p << 24;
1913 u8c += (unsigned)*--p << 16;
1914 u8c += (unsigned)*--p << 8;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 u8c += *--p;
1916 }
1917 else /* big endian */
1918 {
1919 u8c = *--p;
Bram Moolenaardc1c9812017-10-27 22:15:24 +02001920 u8c += (unsigned)*--p << 8;
1921 u8c += (unsigned)*--p << 16;
1922 u8c += (unsigned)*--p << 24;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 }
1924 }
1925 else /* UTF-8 */
1926 {
1927 if (*--p < 0x80)
1928 u8c = *p;
1929 else
1930 {
1931 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001932 p -= len;
1933 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 if (len == 0)
1935 {
1936 /* Not a valid UTF-8 character, retry with
1937 * another fenc when possible, otherwise just
1938 * report the error. */
1939 if (can_retry)
1940 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001941 if (conv_error == 0)
1942 conv_error = readfile_linenr(linecnt,
1943 ptr, p);
1944 if (bad_char_behavior == BAD_DROP)
1945 continue;
1946 if (bad_char_behavior != BAD_KEEP)
1947 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 }
1950 }
1951 if (enc_utf8) /* produce UTF-8 */
1952 {
1953 dest -= utf_char2len(u8c);
1954 (void)utf_char2bytes(u8c, dest);
1955 }
1956 else /* produce Latin1 */
1957 {
1958 --dest;
1959 if (u8c >= 0x100)
1960 {
1961 /* character doesn't fit in latin1, retry with
1962 * another fenc when possible, otherwise just
1963 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001964 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001966 if (conv_error == 0)
1967 conv_error = readfile_linenr(linecnt, ptr, p);
1968 if (bad_char_behavior == BAD_DROP)
1969 ++dest;
1970 else if (bad_char_behavior == BAD_KEEP)
1971 *dest = u8c;
1972 else if (eap != NULL && eap->bad_char != 0)
1973 *dest = bad_char_behavior;
1974 else
1975 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 }
1977 else
1978 *dest = u8c;
1979 }
1980 }
1981
1982 /* move the linerest to before the converted characters */
1983 line_start = dest - linerest;
1984 mch_memmove(line_start, buffer, (size_t)linerest);
1985 size = (long)((ptr + real_size) - dest);
1986 ptr = dest;
1987 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001988 else if (enc_utf8 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001990 int incomplete_tail = FALSE;
1991
1992 /* Reading UTF-8: Check if the bytes are valid UTF-8. */
1993 for (p = ptr; ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001995 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001996 int l;
1997
1998 if (todo <= 0)
1999 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 if (*p >= 0x80)
2001 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 /* A length of 1 means it's an illegal byte. Accept
2003 * an incomplete character at the end though, the next
2004 * read() will get the next bytes, we'll check it
2005 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002006 l = utf_ptr2len_len(p, todo);
Bram Moolenaarf453d352008-06-04 17:37:34 +00002007 if (l > todo && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002009 /* Avoid retrying with a different encoding when
2010 * a truncated file is more likely, or attempting
2011 * to read the rest of an incomplete sequence when
2012 * we have already done so. */
2013 if (p > ptr || filesize > 0)
2014 incomplete_tail = TRUE;
2015 /* Incomplete byte sequence, move it to conv_rest[]
2016 * and try to read the rest of it, unless we've
2017 * already done so. */
2018 if (p > ptr)
2019 {
2020 conv_restlen = todo;
2021 mch_memmove(conv_rest, p, conv_restlen);
2022 size -= conv_restlen;
2023 break;
2024 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002026 if (l == 1 || l > todo)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002027 {
2028 /* Illegal byte. If we can try another encoding
Bram Moolenaarf453d352008-06-04 17:37:34 +00002029 * do that, unless at EOF where a truncated
2030 * file is more likely than a conversion error. */
2031 if (can_retry && !incomplete_tail)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002032 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01002033#ifdef USE_ICONV
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002034 /* When we did a conversion report an error. */
2035 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
2036 conv_error = readfile_linenr(linecnt, ptr, p);
Bram Moolenaar13505972019-01-24 15:04:48 +01002037#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00002038 /* Remember the first linenr with an illegal byte */
2039 if (conv_error == 0 && illegal_byte == 0)
2040 illegal_byte = readfile_linenr(linecnt, ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002041
2042 /* Drop, keep or replace the bad byte. */
2043 if (bad_char_behavior == BAD_DROP)
2044 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002045 mch_memmove(p, p + 1, todo - 1);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002046 --p;
2047 --size;
2048 }
2049 else if (bad_char_behavior != BAD_KEEP)
2050 *p = bad_char_behavior;
2051 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002052 else
2053 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054 }
2055 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002056 if (p < ptr + size && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 {
2058 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002060 /* Retry reading with another conversion. */
Bram Moolenaar13505972019-01-24 15:04:48 +01002061#if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002062 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
2063 /* iconv() failed, try 'charconvert' */
2064 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002066#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002067 /* use next item from 'fileencodings' */
2068 advance_fenc = TRUE;
2069 file_rewind = TRUE;
2070 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071 }
2072 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073
2074 /* count the number of characters (after conversion!) */
2075 filesize += size;
2076
2077 /*
2078 * when reading the first part of a file: guess EOL type
2079 */
2080 if (fileformat == EOL_UNKNOWN)
2081 {
2082 /* First try finding a NL, for Dos and Unix */
2083 if (try_dos || try_unix)
2084 {
Bram Moolenaarc6b72172015-02-27 17:48:09 +01002085 /* Reset the carriage return counter. */
2086 if (try_mac)
2087 try_mac = 1;
2088
Bram Moolenaar071d4272004-06-13 20:20:40 +00002089 for (p = ptr; p < ptr + size; ++p)
2090 {
2091 if (*p == NL)
2092 {
2093 if (!try_unix
2094 || (try_dos && p > ptr && p[-1] == CAR))
2095 fileformat = EOL_DOS;
2096 else
2097 fileformat = EOL_UNIX;
2098 break;
2099 }
Bram Moolenaar05eb6122015-02-17 14:15:19 +01002100 else if (*p == CAR && try_mac)
2101 try_mac++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102 }
2103
2104 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
2105 if (fileformat == EOL_UNIX && try_mac)
2106 {
2107 /* Need to reset the counters when retrying fenc. */
2108 try_mac = 1;
2109 try_unix = 1;
2110 for (; p >= ptr && *p != CAR; p--)
2111 ;
2112 if (p >= ptr)
2113 {
2114 for (p = ptr; p < ptr + size; ++p)
2115 {
2116 if (*p == NL)
2117 try_unix++;
2118 else if (*p == CAR)
2119 try_mac++;
2120 }
2121 if (try_mac > try_unix)
2122 fileformat = EOL_MAC;
2123 }
2124 }
Bram Moolenaar05eb6122015-02-17 14:15:19 +01002125 else if (fileformat == EOL_UNKNOWN && try_mac == 1)
2126 /* Looking for CR but found no end-of-line markers at
2127 * all: use the default format. */
2128 fileformat = default_fileformat();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 }
2130
2131 /* No NL found: may use Mac format */
2132 if (fileformat == EOL_UNKNOWN && try_mac)
2133 fileformat = EOL_MAC;
2134
2135 /* Still nothing found? Use first format in 'ffs' */
2136 if (fileformat == EOL_UNKNOWN)
2137 fileformat = default_fileformat();
2138
2139 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002140 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141 set_fileformat(fileformat, OPT_LOCAL);
2142 }
2143 }
2144
2145 /*
2146 * This loop is executed once for every character read.
2147 * Keep it fast!
2148 */
2149 if (fileformat == EOL_MAC)
2150 {
2151 --ptr;
2152 while (++ptr, --size >= 0)
2153 {
2154 /* catch most common case first */
2155 if ((c = *ptr) != NUL && c != CAR && c != NL)
2156 continue;
2157 if (c == NUL)
2158 *ptr = NL; /* NULs are replaced by newlines! */
2159 else if (c == NL)
2160 *ptr = CAR; /* NLs are replaced by CRs! */
2161 else
2162 {
2163 if (skip_count == 0)
2164 {
2165 *ptr = NUL; /* end of line */
2166 len = (colnr_T) (ptr - line_start + 1);
2167 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2168 {
2169 error = TRUE;
2170 break;
2171 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002172#ifdef FEAT_PERSISTENT_UNDO
2173 if (read_undo_file)
2174 sha256_update(&sha_ctx, line_start, len);
2175#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 ++lnum;
2177 if (--read_count == 0)
2178 {
2179 error = TRUE; /* break loop */
2180 line_start = ptr; /* nothing left to write */
2181 break;
2182 }
2183 }
2184 else
2185 --skip_count;
2186 line_start = ptr + 1;
2187 }
2188 }
2189 }
2190 else
2191 {
2192 --ptr;
2193 while (++ptr, --size >= 0)
2194 {
2195 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2196 continue;
2197 if (c == NUL)
2198 *ptr = NL; /* NULs are replaced by newlines! */
2199 else
2200 {
2201 if (skip_count == 0)
2202 {
2203 *ptr = NUL; /* end of line */
2204 len = (colnr_T)(ptr - line_start + 1);
2205 if (fileformat == EOL_DOS)
2206 {
Bram Moolenaar2aa5f692017-01-24 15:46:48 +01002207 if (ptr > line_start && ptr[-1] == CAR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 {
Bram Moolenaar2aa5f692017-01-24 15:46:48 +01002209 /* remove CR before NL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002210 ptr[-1] = NUL;
2211 --len;
2212 }
2213 /*
2214 * Reading in Dos format, but no CR-LF found!
2215 * When 'fileformats' includes "unix", delete all
2216 * the lines read so far and start all over again.
2217 * Otherwise give an error message later.
2218 */
2219 else if (ff_error != EOL_DOS)
2220 {
2221 if ( try_unix
2222 && !read_stdin
2223 && (read_buffer
Bram Moolenaar8767f522016-07-01 17:17:39 +02002224 || vim_lseek(fd, (off_T)0L, SEEK_SET)
2225 == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 {
2227 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002228 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 set_fileformat(EOL_UNIX, OPT_LOCAL);
2230 file_rewind = TRUE;
2231 keep_fileformat = TRUE;
2232 goto retry;
2233 }
2234 ff_error = EOL_DOS;
2235 }
2236 }
2237 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2238 {
2239 error = TRUE;
2240 break;
2241 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002242#ifdef FEAT_PERSISTENT_UNDO
2243 if (read_undo_file)
2244 sha256_update(&sha_ctx, line_start, len);
2245#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 ++lnum;
2247 if (--read_count == 0)
2248 {
2249 error = TRUE; /* break loop */
2250 line_start = ptr; /* nothing left to write */
2251 break;
2252 }
2253 }
2254 else
2255 --skip_count;
2256 line_start = ptr + 1;
2257 }
2258 }
2259 }
2260 linerest = (long)(ptr - line_start);
2261 ui_breakcheck();
2262 }
2263
2264failed:
2265 /* not an error, max. number of lines reached */
2266 if (error && read_count == 0)
2267 error = FALSE;
2268
2269 /*
2270 * If we get EOF in the middle of a line, note the fact and
2271 * complete the line ourselves.
2272 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2273 */
2274 if (!error
2275 && !got_int
2276 && linerest != 0
2277 && !(!curbuf->b_p_bin
2278 && fileformat == EOL_DOS
2279 && *line_start == Ctrl_Z
2280 && ptr == line_start + 1))
2281 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002282 /* remember for when writing */
2283 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 curbuf->b_p_eol = FALSE;
2285 *ptr = NUL;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002286 len = (colnr_T)(ptr - line_start + 1);
2287 if (ml_append(lnum, line_start, len, newfile) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 error = TRUE;
2289 else
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002290 {
2291#ifdef FEAT_PERSISTENT_UNDO
2292 if (read_undo_file)
2293 sha256_update(&sha_ctx, line_start, len);
2294#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 read_no_eol_lnum = ++lnum;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002296 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 }
2298
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002299 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 save_file_ff(curbuf); /* remember the current file format */
2301
2302#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002303 if (curbuf->b_cryptstate != NULL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002304 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002305 crypt_free_state(curbuf->b_cryptstate);
2306 curbuf->b_cryptstate = NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002307 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002308 if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
2309 crypt_free_key(cryptkey);
2310 /* Don't set cryptkey to NULL, it's used below as a flag that
2311 * encryption was used. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312#endif
2313
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002314 /* If editing a new file: set 'fenc' for the current buffer.
2315 * Also for ":read ++edit file". */
2316 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002318 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 if (fenc_alloced)
2320 vim_free(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01002321#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 if (iconv_fd != (iconv_t)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 iconv_close(iconv_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324#endif
2325
2326 if (!read_buffer && !read_stdin)
2327 close(fd); /* errors are ignored */
Bram Moolenaarf05da212009-11-17 16:13:15 +00002328#ifdef HAVE_FD_CLOEXEC
2329 else
2330 {
2331 int fdflags = fcntl(fd, F_GETFD);
2332 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01002333 (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaarf05da212009-11-17 16:13:15 +00002334 }
2335#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 vim_free(buffer);
2337
2338#ifdef HAVE_DUP
2339 if (read_stdin)
2340 {
2341 /* Use stderr for stdin, makes shell commands work. */
2342 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02002343 vim_ignored = dup(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344 }
2345#endif
2346
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347 if (tmpname != NULL)
2348 {
2349 mch_remove(tmpname); /* delete converted file */
2350 vim_free(tmpname);
2351 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 --no_wait_return; /* may wait for return now */
2353
2354 /*
2355 * In recovery mode everything but autocommands is skipped.
2356 */
2357 if (!recoverymode)
2358 {
2359 /* need to delete the last line, which comes from the empty buffer */
2360 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2361 {
2362#ifdef FEAT_NETBEANS_INTG
2363 netbeansFireChanges = 0;
2364#endif
2365 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2366#ifdef FEAT_NETBEANS_INTG
2367 netbeansFireChanges = 1;
2368#endif
2369 --linecnt;
2370 }
2371 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2372 if (filesize == 0)
2373 linecnt = 0;
2374 if (newfile || read_buffer)
Bram Moolenaar7263a772007-05-10 17:35:54 +00002375 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 redraw_curbuf_later(NOT_VALID);
Bram Moolenaar7263a772007-05-10 17:35:54 +00002377#ifdef FEAT_DIFF
2378 /* After reading the text into the buffer the diff info needs to
2379 * be updated. */
2380 diff_invalidate(curbuf);
2381#endif
2382#ifdef FEAT_FOLDING
2383 /* All folds in the window are invalid now. Mark them for update
2384 * before triggering autocommands. */
2385 foldUpdateAll(curwin);
2386#endif
2387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 else if (linecnt) /* appended at least one line */
2389 appended_lines_mark(from, linecnt);
2390
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391#ifndef ALWAYS_USE_GUI
2392 /*
2393 * If we were reading from the same terminal as where messages go,
2394 * the screen will have been messed up.
2395 * Switch on raw mode now and clear the screen.
2396 */
2397 if (read_stdin)
2398 {
2399 settmode(TMODE_RAW); /* set to raw mode */
2400 starttermcap();
2401 screenclear();
2402 }
2403#endif
2404
2405 if (got_int)
2406 {
2407 if (!(flags & READ_DUMMY))
2408 {
2409 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2410 if (newfile)
2411 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2412 }
2413 msg_scroll = msg_save;
2414#ifdef FEAT_VIMINFO
2415 check_marks_read();
2416#endif
2417 return OK; /* an interrupt isn't really an error */
2418 }
2419
2420 if (!filtering && !(flags & READ_DUMMY))
2421 {
2422 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2423 c = FALSE;
2424
2425#ifdef UNIX
Bram Moolenaard569bb02018-08-11 13:57:20 +02002426 if (S_ISFIFO(perm)) /* fifo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427 {
2428 STRCAT(IObuff, _("[fifo]"));
2429 c = TRUE;
2430 }
Bram Moolenaard569bb02018-08-11 13:57:20 +02002431 if (S_ISSOCK(perm)) /* or socket */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 {
2433 STRCAT(IObuff, _("[socket]"));
2434 c = TRUE;
2435 }
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002436# ifdef OPEN_CHR_FILES
2437 if (S_ISCHR(perm)) /* or character special */
2438 {
2439 STRCAT(IObuff, _("[character special]"));
2440 c = TRUE;
2441 }
2442# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443#endif
2444 if (curbuf->b_p_ro)
2445 {
2446 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2447 c = TRUE;
2448 }
2449 if (read_no_eol_lnum)
2450 {
2451 msg_add_eol();
2452 c = TRUE;
2453 }
2454 if (ff_error == EOL_DOS)
2455 {
2456 STRCAT(IObuff, _("[CR missing]"));
2457 c = TRUE;
2458 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 if (split)
2460 {
2461 STRCAT(IObuff, _("[long lines split]"));
2462 c = TRUE;
2463 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 if (notconverted)
2465 {
2466 STRCAT(IObuff, _("[NOT converted]"));
2467 c = TRUE;
2468 }
2469 else if (converted)
2470 {
2471 STRCAT(IObuff, _("[converted]"));
2472 c = TRUE;
2473 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474#ifdef FEAT_CRYPT
2475 if (cryptkey != NULL)
2476 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002477 crypt_append_msg(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 c = TRUE;
2479 }
2480#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002481 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002483 sprintf((char *)IObuff + STRLEN(IObuff),
2484 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485 c = TRUE;
2486 }
2487 else if (illegal_byte > 0)
2488 {
2489 sprintf((char *)IObuff + STRLEN(IObuff),
2490 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2491 c = TRUE;
2492 }
Bram Moolenaar13505972019-01-24 15:04:48 +01002493 else if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 {
2495 STRCAT(IObuff, _("[READ ERRORS]"));
2496 c = TRUE;
2497 }
2498 if (msg_add_fileformat(fileformat))
2499 c = TRUE;
2500#ifdef FEAT_CRYPT
2501 if (cryptkey != NULL)
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002502 msg_add_lines(c, (long)linecnt, filesize
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002503 - crypt_get_header_len(crypt_get_method_nr(curbuf)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 else
2505#endif
2506 msg_add_lines(c, (long)linecnt, filesize);
2507
Bram Moolenaard23a8232018-02-10 18:45:26 +01002508 VIM_CLEAR(keep_msg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 msg_scrolled_ign = TRUE;
2510#ifdef ALWAYS_USE_GUI
2511 /* Don't show the message when reading stdin, it would end up in a
2512 * message box (which might be shown when exiting!) */
2513 if (read_stdin || read_buffer)
2514 p = msg_may_trunc(FALSE, IObuff);
2515 else
2516#endif
Bram Moolenaar32526b32019-01-19 17:43:09 +01002517 p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002519 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 /* Need to repeat the message after redrawing when:
2521 * - When reading from stdin (the screen will be cleared next).
2522 * - When restart_edit is set (otherwise there will be a delay
2523 * before redrawing).
2524 * - When the screen was scrolled but there is no wait-return
2525 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002526 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 msg_scrolled_ign = FALSE;
2528 }
2529
2530 /* with errors writing the file requires ":w!" */
2531 if (newfile && (error
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002532 || conv_error != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01002533 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 curbuf->b_p_ro = TRUE;
2535
2536 u_clearline(); /* cannot use "U" command after adding lines */
2537
2538 /*
2539 * In Ex mode: cursor at last new line.
2540 * Otherwise: cursor at first new line.
2541 */
2542 if (exmode_active)
2543 curwin->w_cursor.lnum = from + linecnt;
2544 else
2545 curwin->w_cursor.lnum = from + 1;
2546 check_cursor_lnum();
2547 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2548
2549 /*
2550 * Set '[ and '] marks to the newly read lines.
2551 */
2552 curbuf->b_op_start.lnum = from + 1;
2553 curbuf->b_op_start.col = 0;
2554 curbuf->b_op_end.lnum = from + linecnt;
2555 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002556
Bram Moolenaar4f974752019-02-17 17:44:42 +01002557#ifdef MSWIN
Bram Moolenaar03f48552006-02-28 23:52:23 +00002558 /*
2559 * Work around a weird problem: When a file has two links (only
2560 * possible on NTFS) and we write through one link, then stat() it
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00002561 * through the other link, the timestamp information may be wrong.
Bram Moolenaar03f48552006-02-28 23:52:23 +00002562 * It's correct again after reading the file, thus reset the timestamp
2563 * here.
2564 */
2565 if (newfile && !read_stdin && !read_buffer
2566 && mch_stat((char *)fname, &st) >= 0)
2567 {
2568 buf_store_time(curbuf, &st, fname);
2569 curbuf->b_mtime_read = curbuf->b_mtime;
2570 }
2571#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 }
2573 msg_scroll = msg_save;
2574
2575#ifdef FEAT_VIMINFO
2576 /*
2577 * Get the marks before executing autocommands, so they can be used there.
2578 */
2579 check_marks_read();
2580#endif
2581
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 /*
Bram Moolenaar34d72d42015-07-17 14:18:08 +02002583 * We remember if the last line of the read didn't have
2584 * an eol even when 'binary' is off, to support turning 'fixeol' off,
2585 * or writing the read again with 'binary' on. The latter is required
2586 * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002588 curbuf->b_no_eol_lnum = read_no_eol_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02002590 /* When reloading a buffer put the cursor at the first line that is
2591 * different. */
2592 if (flags & READ_KEEP_UNDO)
2593 u_find_first_changed();
2594
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002595#ifdef FEAT_PERSISTENT_UNDO
2596 /*
2597 * When opening a new file locate undo info and read it.
2598 */
2599 if (read_undo_file)
2600 {
2601 char_u hash[UNDO_HASH_SIZE];
2602
2603 sha256_finish(&sha_ctx, hash);
Bram Moolenaar6ed8ed82010-05-30 20:40:11 +02002604 u_read_undo(NULL, hash, fname);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002605 }
2606#endif
2607
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02002608 if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609 {
2610 int m = msg_scroll;
2611 int n = msg_scrolled;
2612
2613 /* Save the fileformat now, otherwise the buffer will be considered
2614 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002615 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 save_file_ff(curbuf);
2617
2618 /*
2619 * The output from the autocommands should not overwrite anything and
2620 * should not be overwritten: Set msg_scroll, restore its value if no
2621 * output was done.
2622 */
2623 msg_scroll = TRUE;
2624 if (filtering)
2625 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2626 FALSE, curbuf, eap);
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02002627 else if (newfile || (read_buffer && sfname != NULL))
Bram Moolenaarc3691332016-04-20 12:49:49 +02002628 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2630 FALSE, curbuf, eap);
Bram Moolenaarc3691332016-04-20 12:49:49 +02002631 if (!au_did_filetype && *curbuf->b_p_ft != NUL)
2632 /*
2633 * EVENT_FILETYPE was not triggered but the buffer already has a
2634 * filetype. Trigger EVENT_FILETYPE using the existing filetype.
2635 */
2636 apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
2637 TRUE, curbuf);
2638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639 else
2640 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2641 FALSE, NULL, eap);
2642 if (msg_scrolled == n)
2643 msg_scroll = m;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002644# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 if (aborting()) /* autocmds may abort script processing */
2646 return FAIL;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002647# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649
2650 if (recoverymode && error)
2651 return FAIL;
2652 return OK;
2653}
2654
Bram Moolenaarf04507d2016-08-20 15:05:39 +02002655#if defined(OPEN_CHR_FILES) || defined(PROTO)
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002656/*
2657 * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
2658 * which is the name of files used for process substitution output by
2659 * some shells on some operating systems, e.g., bash on SunOS.
2660 * Do not accept "/dev/fd/[012]", opening these may hang Vim.
2661 */
Bram Moolenaarf04507d2016-08-20 15:05:39 +02002662 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002663is_dev_fd_file(char_u *fname)
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002664{
2665 return (STRNCMP(fname, "/dev/fd/", 8) == 0
2666 && VIM_ISDIGIT(fname[8])
2667 && *skipdigits(fname + 9) == NUL
2668 && (fname[9] != NUL
2669 || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
2670}
2671#endif
2672
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002673/*
2674 * From the current line count and characters read after that, estimate the
2675 * line number where we are now.
2676 * Used for error messages that include a line number.
2677 */
2678 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002679readfile_linenr(
2680 linenr_T linecnt, /* line count before reading more bytes */
2681 char_u *p, /* start of more bytes read */
2682 char_u *endp) /* end of more bytes read */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002683{
2684 char_u *s;
2685 linenr_T lnum;
2686
2687 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2688 for (s = p; s < endp; ++s)
2689 if (*s == '\n')
2690 ++lnum;
2691 return lnum;
2692}
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002693
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002695 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2696 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697 * Returns OK or FAIL.
2698 */
2699 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002700prep_exarg(exarg_T *eap, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701{
Bram Moolenaar13505972019-01-24 15:04:48 +01002702 eap->cmd = alloc(15 + (unsigned)STRLEN(buf->b_p_fenc));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 if (eap->cmd == NULL)
2704 return FAIL;
2705
Bram Moolenaar333b80a2018-04-04 22:57:29 +02002706 sprintf((char *)eap->cmd, "e ++enc=%s", buf->b_p_fenc);
2707 eap->force_enc = 8;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002708 eap->bad_char = buf->b_bad_char;
Bram Moolenaar333b80a2018-04-04 22:57:29 +02002709 eap->force_ff = *buf->b_p_ff;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002710
2711 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002712 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002713 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 return OK;
2715}
2716
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002717/*
2718 * Set default or forced 'fileformat' and 'binary'.
2719 */
2720 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002721set_file_options(int set_options, exarg_T *eap)
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002722{
2723 /* set default 'fileformat' */
2724 if (set_options)
2725 {
2726 if (eap != NULL && eap->force_ff != 0)
2727 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
2728 else if (*p_ffs != NUL)
2729 set_fileformat(default_fileformat(), OPT_LOCAL);
2730 }
2731
2732 /* set or reset 'binary' */
2733 if (eap != NULL && eap->force_bin != 0)
2734 {
2735 int oldval = curbuf->b_p_bin;
2736
2737 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
2738 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
2739 }
2740}
2741
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002742/*
2743 * Set forced 'fileencoding'.
2744 */
2745 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002746set_forced_fenc(exarg_T *eap)
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002747{
2748 if (eap->force_enc != 0)
2749 {
2750 char_u *fenc = enc_canonize(eap->cmd + eap->force_enc);
2751
2752 if (fenc != NULL)
2753 set_string_option_direct((char_u *)"fenc", -1,
2754 fenc, OPT_FREE|OPT_LOCAL, 0);
2755 vim_free(fenc);
2756 }
2757}
2758
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759/*
2760 * Find next fileencoding to use from 'fileencodings'.
2761 * "pp" points to fenc_next. It's advanced to the next item.
2762 * When there are no more items, an empty string is returned and *pp is set to
2763 * NULL.
2764 * When *pp is not set to NULL, the result is in allocated memory.
2765 */
2766 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002767next_fenc(char_u **pp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768{
2769 char_u *p;
2770 char_u *r;
2771
2772 if (**pp == NUL)
2773 {
2774 *pp = NULL;
2775 return (char_u *)"";
2776 }
2777 p = vim_strchr(*pp, ',');
2778 if (p == NULL)
2779 {
2780 r = enc_canonize(*pp);
2781 *pp += STRLEN(*pp);
2782 }
2783 else
2784 {
2785 r = vim_strnsave(*pp, (int)(p - *pp));
2786 *pp = p + 1;
2787 if (r != NULL)
2788 {
2789 p = enc_canonize(r);
2790 vim_free(r);
2791 r = p;
2792 }
2793 }
2794 if (r == NULL) /* out of memory */
2795 {
2796 r = (char_u *)"";
2797 *pp = NULL;
2798 }
2799 return r;
2800}
2801
Bram Moolenaar13505972019-01-24 15:04:48 +01002802#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803/*
2804 * Convert a file with the 'charconvert' expression.
2805 * This closes the file which is to be read, converts it and opens the
2806 * resulting file for reading.
2807 * Returns name of the resulting converted file (the caller should delete it
2808 * after reading it).
2809 * Returns NULL if the conversion failed ("*fdp" is not set) .
2810 */
2811 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002812readfile_charconvert(
2813 char_u *fname, /* name of input file */
2814 char_u *fenc, /* converted from */
2815 int *fdp) /* in/out: file descriptor of file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816{
2817 char_u *tmpname;
Bram Moolenaar32526b32019-01-19 17:43:09 +01002818 char *errmsg = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819
Bram Moolenaare5c421c2015-03-31 13:33:08 +02002820 tmpname = vim_tempname('r', FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821 if (tmpname == NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002822 errmsg = _("Can't find temp file for conversion");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002823 else
2824 {
2825 close(*fdp); /* close the input file, ignore errors */
2826 *fdp = -1;
2827 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2828 fname, tmpname) == FAIL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002829 errmsg = _("Conversion with 'charconvert' failed");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2831 O_RDONLY | O_EXTRA, 0)) < 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002832 errmsg = _("can't read output of 'charconvert'");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 }
2834
2835 if (errmsg != NULL)
2836 {
2837 /* Don't use emsg(), it breaks mappings, the retry with
2838 * another type of conversion might still work. */
Bram Moolenaar32526b32019-01-19 17:43:09 +01002839 msg(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 if (tmpname != NULL)
2841 {
2842 mch_remove(tmpname); /* delete converted file */
Bram Moolenaard23a8232018-02-10 18:45:26 +01002843 VIM_CLEAR(tmpname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 }
2845 }
2846
2847 /* If the input file is closed, open it (caller should check for error). */
2848 if (*fdp < 0)
2849 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2850
2851 return tmpname;
2852}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853#endif
2854
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002855#if defined(FEAT_CRYPT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856/*
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002857 * Check for magic number used for encryption. Applies to the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2859 * *filesizep are updated.
2860 * Return the (new) encryption key, NULL for no encryption.
2861 */
2862 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002863check_for_cryptkey(
2864 char_u *cryptkey, /* previous encryption key or NULL */
2865 char_u *ptr, /* pointer to read bytes */
2866 long *sizep, /* length of read bytes */
Bram Moolenaar8767f522016-07-01 17:17:39 +02002867 off_T *filesizep, /* nr of bytes used from file */
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002868 int newfile, /* editing a new buffer */
2869 char_u *fname, /* file name to display */
2870 int *did_ask) /* flag: whether already asked for key */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871{
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002872 int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002873 int b_p_ro = curbuf->b_p_ro;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002874
2875 if (method >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 {
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002877 /* Mark the buffer as read-only until the decryption has taken place.
2878 * Avoids accidentally overwriting the file with garbage. */
2879 curbuf->b_p_ro = TRUE;
2880
Bram Moolenaar2be79502014-08-13 21:58:28 +02002881 /* Set the cryptmethod local to the buffer. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002882 crypt_set_cm_option(curbuf, method);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002883 if (cryptkey == NULL && !*did_ask)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884 {
2885 if (*curbuf->b_p_key)
2886 cryptkey = curbuf->b_p_key;
2887 else
2888 {
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002889 /* When newfile is TRUE, store the typed key in the 'key'
2890 * option and don't free it. bf needs hash of the key saved.
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002891 * Don't ask for the key again when first time Enter was hit.
2892 * Happens when retrying to detect encoding. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002893 smsg(_(need_key_msg), fname);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002894 msg_scroll = TRUE;
Bram Moolenaar3a0c9082014-11-12 15:15:42 +01002895 crypt_check_method(method);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002896 cryptkey = crypt_get_key(newfile, FALSE);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002897 *did_ask = TRUE;
2898
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899 /* check if empty key entered */
2900 if (cryptkey != NULL && *cryptkey == NUL)
2901 {
2902 if (cryptkey != curbuf->b_p_key)
2903 vim_free(cryptkey);
2904 cryptkey = NULL;
2905 }
2906 }
2907 }
2908
2909 if (cryptkey != NULL)
2910 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002911 int header_len;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002912
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002913 curbuf->b_cryptstate = crypt_create_from_header(
2914 method, cryptkey, ptr);
2915 crypt_set_cm_option(curbuf, method);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002917 /* Remove cryptmethod specific header from the text. */
2918 header_len = crypt_get_header_len(method);
Bram Moolenaar680e0152016-09-25 20:54:11 +02002919 if (*sizep <= header_len)
2920 /* invalid header, buffer can't be encrypted */
2921 return NULL;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002922 *filesizep += header_len;
2923 *sizep -= header_len;
2924 mch_memmove(ptr, ptr + header_len, (size_t)*sizep);
2925
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002926 /* Restore the read-only flag. */
2927 curbuf->b_p_ro = b_p_ro;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 }
2929 }
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002930 /* When starting to edit a new file which does not have encryption, clear
2931 * the 'key' option, except when starting up (called with -x argument) */
Bram Moolenaarfa0ff9a2010-07-25 16:05:19 +02002932 else if (newfile && *curbuf->b_p_key != NUL && !starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2934
2935 return cryptkey;
2936}
Bram Moolenaar80794b12010-06-13 05:20:42 +02002937#endif /* FEAT_CRYPT */
2938
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939#ifdef UNIX
2940 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002941set_file_time(
2942 char_u *fname,
2943 time_t atime, /* access time */
2944 time_t mtime) /* modification time */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945{
2946# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2947 struct utimbuf buf;
2948
2949 buf.actime = atime;
2950 buf.modtime = mtime;
2951 (void)utime((char *)fname, &buf);
2952# else
2953# if defined(HAVE_UTIMES)
2954 struct timeval tvp[2];
2955
2956 tvp[0].tv_sec = atime;
2957 tvp[0].tv_usec = 0;
2958 tvp[1].tv_sec = mtime;
2959 tvp[1].tv_usec = 0;
2960# ifdef NeXT
2961 (void)utimes((char *)fname, tvp);
2962# else
2963 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2964# endif
2965# endif
2966# endif
2967}
2968#endif /* UNIX */
2969
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002970#if defined(VMS) && !defined(MIN)
2971/* Older DECC compiler for VAX doesn't define MIN() */
2972# define MIN(a, b) ((a) < (b) ? (a) : (b))
2973#endif
2974
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00002976 * Return TRUE if a file appears to be read-only from the file permissions.
2977 */
2978 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002979check_file_readonly(
2980 char_u *fname, /* full path to file */
2981 int perm) /* known permissions on file */
Bram Moolenaar5386a122007-06-28 20:02:32 +00002982{
2983#ifndef USE_MCH_ACCESS
2984 int fd = 0;
2985#endif
2986
2987 return (
2988#ifdef USE_MCH_ACCESS
2989# ifdef UNIX
2990 (perm & 0222) == 0 ||
2991# endif
2992 mch_access((char *)fname, W_OK)
2993#else
2994 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
2995 ? TRUE : (close(fd), FALSE)
2996#endif
2997 );
2998}
2999
3000
3001/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00003002 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 *
3004 * We do our own buffering here because fwrite() is so slow.
3005 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00003006 * If "forceit" is true, we don't care for errors when attempting backups.
3007 * In case of an error everything possible is done to restore the original
Bram Moolenaare37d50a2008-08-06 17:06:04 +00003008 * file. But when "forceit" is TRUE, we risk losing it.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003009 *
3010 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
3011 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012 *
3013 * This function must NOT use NameBuff (because it's called by autowrite()).
3014 *
3015 * return FAIL for failure, OK otherwise
3016 */
3017 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003018buf_write(
3019 buf_T *buf,
3020 char_u *fname,
3021 char_u *sfname,
3022 linenr_T start,
3023 linenr_T end,
3024 exarg_T *eap, /* for forced 'ff' and 'fenc', can be
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 NULL! */
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003026 int append, /* append to the file */
3027 int forceit,
3028 int reset_changed,
3029 int filtering)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030{
3031 int fd;
3032 char_u *backup = NULL;
3033 int backup_copy = FALSE; /* copy the original file? */
3034 int dobackup;
3035 char_u *ffname;
3036 char_u *wfname = NULL; /* name of file to write to */
3037 char_u *s;
3038 char_u *ptr;
3039 char_u c;
3040 int len;
3041 linenr_T lnum;
3042 long nchars;
3043 char_u *errmsg = NULL;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003044 int errmsg_allocated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045 char_u *errnum = NULL;
3046 char_u *buffer;
3047 char_u smallbuf[SMBUFSIZE];
3048 char_u *backup_ext;
3049 int bufsize;
3050 long perm; /* file permissions */
3051 int retval = OK;
3052 int newfile = FALSE; /* TRUE if file doesn't exist yet */
3053 int msg_save = msg_scroll;
3054 int overwriting; /* TRUE if writing over original */
3055 int no_eol = FALSE; /* no end-of-line written */
3056 int device = FALSE; /* writing to a device */
Bram Moolenaar8767f522016-07-01 17:17:39 +02003057 stat_T st_old;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 int prev_got_int = got_int;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02003059 int checking_conversion;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060 int file_readonly = FALSE; /* overwritten file is read-only */
3061 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
Bram Moolenaara06ecab2016-07-16 14:47:36 +02003062#if defined(UNIX) /*XXX fix me sometime? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063 int made_writable = FALSE; /* 'w' bit has been set */
3064#endif
3065 /* writing everything */
3066 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 linenr_T old_line_count = buf->b_ml.ml_line_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 int attr;
3069 int fileformat;
3070 int write_bin;
3071 struct bw_info write_info; /* info for buf_write_bytes() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 int converted = FALSE;
3073 int notconverted = FALSE;
3074 char_u *fenc; /* effective 'fileencoding' */
3075 char_u *fenc_tofree = NULL; /* allocated "fenc" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076#ifdef HAS_BW_FLAGS
3077 int wb_flags = 0;
3078#endif
3079#ifdef HAVE_ACL
3080 vim_acl_T acl = NULL; /* ACL copied from original file to
3081 backup or new file */
3082#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003083#ifdef FEAT_PERSISTENT_UNDO
3084 int write_undo_file = FALSE;
3085 context_sha256_T sha_ctx;
3086#endif
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003087 unsigned int bkc = get_bkc_value(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088
3089 if (fname == NULL || *fname == NUL) /* safety check */
3090 return FAIL;
Bram Moolenaar70d60e92009-12-31 13:53:33 +00003091 if (buf->b_ml.ml_mfp == NULL)
3092 {
3093 /* This can happen during startup when there is a stray "w" in the
3094 * vimrc file. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003095 emsg(_(e_emptybuf));
Bram Moolenaar70d60e92009-12-31 13:53:33 +00003096 return FAIL;
3097 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098
3099 /*
3100 * Disallow writing from .exrc and .vimrc in current directory for
3101 * security reasons.
3102 */
3103 if (check_secure())
3104 return FAIL;
3105
3106 /* Avoid a crash for a long name. */
3107 if (STRLEN(fname) >= MAXPATHL)
3108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003109 emsg(_(e_longname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110 return FAIL;
3111 }
3112
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
3114 write_info.bw_conv_buf = NULL;
3115 write_info.bw_conv_error = FALSE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003116 write_info.bw_conv_error_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117 write_info.bw_restlen = 0;
Bram Moolenaar13505972019-01-24 15:04:48 +01003118#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 write_info.bw_iconv_fd = (iconv_t)-1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02003121#ifdef FEAT_CRYPT
3122 write_info.bw_buffer = buf;
3123#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124
Bram Moolenaardf177f62005-02-22 08:39:57 +00003125 /* After writing a file changedtick changes but we don't want to display
3126 * the line. */
3127 ex_no_reprint = TRUE;
3128
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 /*
3130 * If there is no file name yet, use the one for the written file.
3131 * BF_NOTEDITED is set to reflect this (in case the write fails).
3132 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003133 * Don't do this when appending.
3134 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003136 if (buf->b_ffname == NULL
3137 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 && whole
3139 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003140#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003141 && !bt_nofilename(buf)
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003142#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00003144 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
3146 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003147 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003149 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 }
3151
3152 if (sfname == NULL)
3153 sfname = fname;
3154 /*
3155 * For Unix: Use the short file name whenever possible.
3156 * Avoids problems with networks and when directory names are changed.
3157 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
3158 * another directory, which we don't detect
3159 */
3160 ffname = fname; /* remember full fname */
3161#ifdef UNIX
3162 fname = sfname;
3163#endif
3164
3165 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
3166 overwriting = TRUE;
3167 else
3168 overwriting = FALSE;
3169
3170 if (exiting)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003171 settmode(TMODE_COOK); /* when exiting allow typeahead now */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172
3173 ++no_wait_return; /* don't wait for return yet */
3174
3175 /*
3176 * Set '[ and '] marks to the lines to be written.
3177 */
3178 buf->b_op_start.lnum = start;
3179 buf->b_op_start.col = 0;
3180 buf->b_op_end.lnum = end;
3181 buf->b_op_end.col = 0;
3182
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183 {
3184 aco_save_T aco;
3185 int buf_ffname = FALSE;
3186 int buf_sfname = FALSE;
3187 int buf_fname_f = FALSE;
3188 int buf_fname_s = FALSE;
3189 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003190 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003191 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003192 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193
3194 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003195 * Apply PRE autocommands.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 * Set curbuf to the buffer to be written.
3197 * Careful: The autocommands may call buf_write() recursively!
3198 */
3199 if (ffname == buf->b_ffname)
3200 buf_ffname = TRUE;
3201 if (sfname == buf->b_sfname)
3202 buf_sfname = TRUE;
3203 if (fname == buf->b_ffname)
3204 buf_fname_f = TRUE;
3205 if (fname == buf->b_sfname)
3206 buf_fname_s = TRUE;
3207
3208 /* set curwin/curbuf to buf and save a few things */
3209 aucmd_prepbuf(&aco, buf);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003210 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211
3212 if (append)
3213 {
3214 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
3215 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003216 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003217#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003218 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003219 nofile_err = TRUE;
3220 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003221#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003222 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 }
3226 else if (filtering)
3227 {
3228 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
3229 NULL, sfname, FALSE, curbuf, eap);
3230 }
3231 else if (reset_changed && whole)
3232 {
Bram Moolenaar39fc42e2011-09-02 11:56:20 +02003233 int was_changed = curbufIsChanged();
3234
3235 did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
3236 sfname, sfname, FALSE, curbuf, eap);
3237 if (did_cmd)
3238 {
3239 if (was_changed && !curbufIsChanged())
3240 {
3241 /* Written everything correctly and BufWriteCmd has reset
3242 * 'modified': Correct the undo information so that an
3243 * undo now sets 'modified'. */
3244 u_unchanged(curbuf);
3245 u_update_save_nr(curbuf);
3246 }
3247 }
3248 else
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003249 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003250#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003251 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003252 nofile_err = TRUE;
3253 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003254#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003255 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003257 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 }
3259 else
3260 {
3261 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
3262 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003263 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003264#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003265 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003266 nofile_err = TRUE;
3267 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003268#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003269 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003271 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 }
3273
3274 /* restore curwin/curbuf and a few other things */
3275 aucmd_restbuf(&aco);
3276
3277 /*
3278 * In three situations we return here and don't write the file:
3279 * 1. the autocommands deleted or unloaded the buffer.
3280 * 2. The autocommands abort script processing.
3281 * 3. If one of the "Cmd" autocommands was executed.
3282 */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003283 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003285 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00003286 || did_cmd || nofile_err
3287#ifdef FEAT_EVAL
3288 || aborting()
3289#endif
3290 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 {
3292 --no_wait_return;
3293 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003294 if (nofile_err)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003295 emsg(_("E676: No matching autocommands for acwrite buffer"));
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003296
Bram Moolenaar1e015462005-09-25 22:16:38 +00003297 if (nofile_err
3298#ifdef FEAT_EVAL
3299 || aborting()
3300#endif
3301 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 /* An aborting error, interrupt or exception in the
3303 * autocommands. */
3304 return FAIL;
3305 if (did_cmd)
3306 {
3307 if (buf == NULL)
3308 /* The buffer was deleted. We assume it was written
3309 * (can't retry anyway). */
3310 return OK;
3311 if (overwriting)
3312 {
3313 /* Assume the buffer was written, update the timestamp. */
3314 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003315 if (append)
3316 buf->b_flags &= ~BF_NEW;
3317 else
3318 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003320 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003321 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 /* Buffer still changed, the autocommands didn't work
3323 * properly. */
3324 return FAIL;
3325 return OK;
3326 }
3327#ifdef FEAT_EVAL
3328 if (!aborting())
3329#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003330 emsg(_("E203: Autocommands deleted or unloaded buffer to be written"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 return FAIL;
3332 }
3333
3334 /*
3335 * The autocommands may have changed the number of lines in the file.
3336 * When writing the whole file, adjust the end.
3337 * When writing part of the file, assume that the autocommands only
3338 * changed the number of lines that are to be written (tricky!).
3339 */
3340 if (buf->b_ml.ml_line_count != old_line_count)
3341 {
3342 if (whole) /* write all */
3343 end = buf->b_ml.ml_line_count;
3344 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3345 end += buf->b_ml.ml_line_count - old_line_count;
3346 else /* less lines */
3347 {
3348 end -= old_line_count - buf->b_ml.ml_line_count;
3349 if (end < start)
3350 {
3351 --no_wait_return;
3352 msg_scroll = msg_save;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003353 emsg(_("E204: Autocommand changed number of lines in unexpected way"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 return FAIL;
3355 }
3356 }
3357 }
3358
3359 /*
3360 * The autocommands may have changed the name of the buffer, which may
3361 * be kept in fname, ffname and sfname.
3362 */
3363 if (buf_ffname)
3364 ffname = buf->b_ffname;
3365 if (buf_sfname)
3366 sfname = buf->b_sfname;
3367 if (buf_fname_f)
3368 fname = buf->b_ffname;
3369 if (buf_fname_s)
3370 fname = buf->b_sfname;
3371 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372
3373#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003374 if (netbeans_active() && isNetbeansBuffer(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 {
3376 if (whole)
3377 {
3378 /*
3379 * b_changed can be 0 after an undo, but we still need to write
3380 * the buffer to NetBeans.
3381 */
3382 if (buf->b_changed || isNetbeansModified(buf))
3383 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003384 --no_wait_return; /* may wait for return now */
3385 msg_scroll = msg_save;
3386 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 return retval;
3388 }
3389 else
3390 {
3391 errnum = (char_u *)"E656: ";
Bram Moolenaared0e7452008-06-27 19:17:34 +00003392 errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 buffer = NULL;
3394 goto fail;
3395 }
3396 }
3397 else
3398 {
3399 errnum = (char_u *)"E657: ";
3400 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3401 buffer = NULL;
3402 goto fail;
3403 }
3404 }
3405#endif
3406
3407 if (shortmess(SHM_OVER) && !exiting)
3408 msg_scroll = FALSE; /* overwrite previous file message */
3409 else
3410 msg_scroll = TRUE; /* don't overwrite previous file message */
3411 if (!filtering)
3412 filemess(buf,
3413#ifndef UNIX
3414 sfname,
3415#else
3416 fname,
3417#endif
3418 (char_u *)"", 0); /* show that we are busy */
3419 msg_scroll = FALSE; /* always overwrite the file message now */
3420
3421 buffer = alloc(BUFSIZE);
3422 if (buffer == NULL) /* can't allocate big buffer, use small
3423 * one (to be able to write when out of
3424 * memory) */
3425 {
3426 buffer = smallbuf;
3427 bufsize = SMBUFSIZE;
3428 }
3429 else
3430 bufsize = BUFSIZE;
3431
3432 /*
3433 * Get information about original file (if there is one).
3434 */
Bram Moolenaar53076832015-12-31 19:53:21 +01003435#if defined(UNIX)
Bram Moolenaar6f192452007-11-08 19:49:02 +00003436 st_old.st_dev = 0;
3437 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 perm = -1;
3439 if (mch_stat((char *)fname, &st_old) < 0)
3440 newfile = TRUE;
3441 else
3442 {
3443 perm = st_old.st_mode;
3444 if (!S_ISREG(st_old.st_mode)) /* not a file */
3445 {
3446 if (S_ISDIR(st_old.st_mode))
3447 {
3448 errnum = (char_u *)"E502: ";
3449 errmsg = (char_u *)_("is a directory");
3450 goto fail;
3451 }
3452 if (mch_nodetype(fname) != NODE_WRITABLE)
3453 {
3454 errnum = (char_u *)"E503: ";
3455 errmsg = (char_u *)_("is not a file or writable device");
3456 goto fail;
3457 }
3458 /* It's a device of some kind (or a fifo) which we can write to
3459 * but for which we can't make a backup. */
3460 device = TRUE;
3461 newfile = TRUE;
3462 perm = -1;
3463 }
3464 }
3465#else /* !UNIX */
3466 /*
3467 * Check for a writable device name.
3468 */
3469 c = mch_nodetype(fname);
3470 if (c == NODE_OTHER)
3471 {
3472 errnum = (char_u *)"E503: ";
3473 errmsg = (char_u *)_("is not a file or writable device");
3474 goto fail;
3475 }
3476 if (c == NODE_WRITABLE)
3477 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003478# if defined(MSWIN)
Bram Moolenaar043545e2006-10-10 16:44:07 +00003479 /* MS-Windows allows opening a device, but we will probably get stuck
3480 * trying to write to it. */
3481 if (!p_odev)
3482 {
3483 errnum = (char_u *)"E796: ";
3484 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
3485 goto fail;
3486 }
3487# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488 device = TRUE;
3489 newfile = TRUE;
3490 perm = -1;
3491 }
3492 else
3493 {
3494 perm = mch_getperm(fname);
3495 if (perm < 0)
3496 newfile = TRUE;
3497 else if (mch_isdir(fname))
3498 {
3499 errnum = (char_u *)"E502: ";
3500 errmsg = (char_u *)_("is a directory");
3501 goto fail;
3502 }
3503 if (overwriting)
3504 (void)mch_stat((char *)fname, &st_old);
3505 }
3506#endif /* !UNIX */
3507
3508 if (!device && !newfile)
3509 {
3510 /*
3511 * Check if the file is really writable (when renaming the file to
3512 * make a backup we won't discover it later).
3513 */
Bram Moolenaar5386a122007-06-28 20:02:32 +00003514 file_readonly = check_file_readonly(fname, (int)perm);
3515
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516 if (!forceit && file_readonly)
3517 {
3518 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3519 {
3520 errnum = (char_u *)"E504: ";
3521 errmsg = (char_u *)_(err_readonly);
3522 }
3523 else
3524 {
3525 errnum = (char_u *)"E505: ";
3526 errmsg = (char_u *)_("is read-only (add ! to override)");
3527 }
3528 goto fail;
3529 }
3530
3531 /*
3532 * Check if the timestamp hasn't changed since reading the file.
3533 */
3534 if (overwriting)
3535 {
3536 retval = check_mtime(buf, &st_old);
3537 if (retval == FAIL)
3538 goto fail;
3539 }
3540 }
3541
3542#ifdef HAVE_ACL
3543 /*
3544 * For systems that support ACL: get the ACL from the original file.
3545 */
3546 if (!newfile)
3547 acl = mch_get_acl(fname);
3548#endif
3549
3550 /*
3551 * If 'backupskip' is not empty, don't make a backup for some files.
3552 */
3553 dobackup = (p_wb || p_bk || *p_pm != NUL);
3554#ifdef FEAT_WILDIGN
3555 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3556 dobackup = FALSE;
3557#endif
3558
3559 /*
3560 * Save the value of got_int and reset it. We don't want a previous
3561 * interruption cancel writing, only hitting CTRL-C while writing should
3562 * abort it.
3563 */
3564 prev_got_int = got_int;
3565 got_int = FALSE;
3566
3567 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3568 buf->b_saving = TRUE;
3569
3570 /*
3571 * If we are not appending or filtering, the file exists, and the
3572 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3573 * When 'patchmode' is set also make a backup when appending.
3574 *
3575 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3576 * off. This helps when editing large files on almost-full disks.
3577 */
3578 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3579 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01003580#if defined(UNIX) || defined(MSWIN)
Bram Moolenaar8767f522016-07-01 17:17:39 +02003581 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582#endif
3583
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003584 if ((bkc & BKC_YES) || append) /* "yes" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585 backup_copy = TRUE;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003586#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003587 else if ((bkc & BKC_AUTO)) /* "auto" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 {
3589 int i;
3590
3591# ifdef UNIX
3592 /*
3593 * Don't rename the file when:
3594 * - it's a hard link
3595 * - it's a symbolic link
3596 * - we don't have write permission in the directory
3597 * - we can't set the owner/group of the new file
3598 */
3599 if (st_old.st_nlink > 1
3600 || mch_lstat((char *)fname, &st) < 0
3601 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003602 || st.st_ino != st_old.st_ino
3603# ifndef HAVE_FCHOWN
3604 || st.st_uid != st_old.st_uid
3605 || st.st_gid != st_old.st_gid
3606# endif
3607 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 backup_copy = TRUE;
3609 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003610# else
Bram Moolenaar4f974752019-02-17 17:44:42 +01003611# ifdef MSWIN
Bram Moolenaar03f48552006-02-28 23:52:23 +00003612 /* On NTFS file systems hard links are possible. */
3613 if (mch_is_linked(fname))
3614 backup_copy = TRUE;
3615 else
3616# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617# endif
3618 {
3619 /*
3620 * Check if we can create a file and set the owner/group to
3621 * the ones from the original file.
3622 * First find a file name that doesn't exist yet (use some
3623 * arbitrary numbers).
3624 */
3625 STRCPY(IObuff, fname);
3626 for (i = 4913; ; i += 123)
3627 {
3628 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003629 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 break;
3631 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003632 fd = mch_open((char *)IObuff,
3633 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 if (fd < 0) /* can't write in directory */
3635 backup_copy = TRUE;
3636 else
3637 {
3638# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003639# ifdef HAVE_FCHOWN
Bram Moolenaar42335f52018-09-13 15:33:43 +02003640 vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003641# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642 if (mch_stat((char *)IObuff, &st) < 0
3643 || st.st_uid != st_old.st_uid
3644 || st.st_gid != st_old.st_gid
Bram Moolenaar78a15312009-05-15 19:33:18 +00003645 || (long)st.st_mode != perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 backup_copy = TRUE;
3647# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003648 /* Close the file before removing it, on MS-Windows we
3649 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003650 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003651 mch_remove(IObuff);
Bram Moolenaar3479c5d2010-08-08 18:46:06 +02003652# ifdef MSWIN
3653 /* MS-Windows may trigger a virus scanner to open the
3654 * file, we can't delete it then. Keep trying for half a
3655 * second. */
3656 {
3657 int try;
3658
3659 for (try = 0; try < 10; ++try)
3660 {
3661 if (mch_lstat((char *)IObuff, &st) < 0)
3662 break;
3663 ui_delay(50L, TRUE); /* wait 50 msec */
3664 mch_remove(IObuff);
3665 }
3666 }
3667# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 }
3669 }
3670 }
3671
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 /*
3673 * Break symlinks and/or hardlinks if we've been asked to.
3674 */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003675 if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 {
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003677# ifdef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 int lstat_res;
3679
3680 lstat_res = mch_lstat((char *)fname, &st);
3681
3682 /* Symlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003683 if ((bkc & BKC_BREAKSYMLINK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 && lstat_res == 0
3685 && st.st_ino != st_old.st_ino)
3686 backup_copy = FALSE;
3687
3688 /* Hardlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003689 if ((bkc & BKC_BREAKHARDLINK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 && st_old.st_nlink > 1
3691 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3692 backup_copy = FALSE;
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003693# else
Bram Moolenaar4f974752019-02-17 17:44:42 +01003694# if defined(MSWIN)
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003695 /* Symlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003696 if ((bkc & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname))
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003697 backup_copy = FALSE;
3698
3699 /* Hardlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003700 if ((bkc & BKC_BREAKHARDLINK) && mch_is_hard_link(fname))
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003701 backup_copy = FALSE;
3702# endif
3703# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705
3706#endif
3707
3708 /* make sure we have a valid backup extension to use */
3709 if (*p_bex == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 backup_ext = (char_u *)".bak";
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 else
3712 backup_ext = p_bex;
3713
3714 if (backup_copy
3715 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3716 {
3717 int bfd;
3718 char_u *copybuf, *wp;
3719 int some_error = FALSE;
Bram Moolenaar8767f522016-07-01 17:17:39 +02003720 stat_T st_new;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 char_u *dirp;
3722 char_u *rootname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003723#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003724 char_u *p;
3725#endif
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003726#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727 int did_set_shortname;
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003728 mode_t umask_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729#endif
3730
3731 copybuf = alloc(BUFSIZE + 1);
3732 if (copybuf == NULL)
3733 {
3734 some_error = TRUE; /* out of memory */
3735 goto nobackup;
3736 }
3737
3738 /*
3739 * Try to make the backup in each directory in the 'bdir' option.
3740 *
3741 * Unix semantics has it, that we may have a writable file,
3742 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3743 * - the directory is not writable,
3744 * - the file may be a symbolic link,
3745 * - the file may belong to another user/group, etc.
3746 *
3747 * For these reasons, the existing writable file must be truncated
3748 * and reused. Creation of a backup COPY will be attempted.
3749 */
3750 dirp = p_bdir;
3751 while (*dirp)
3752 {
3753#ifdef UNIX
3754 st_new.st_ino = 0;
3755 st_new.st_dev = 0;
3756 st_new.st_gid = 0;
3757#endif
3758
3759 /*
3760 * Isolate one directory name, using an entry in 'bdir'.
3761 */
3762 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003763
Bram Moolenaar4f974752019-02-17 17:44:42 +01003764#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003765 p = copybuf + STRLEN(copybuf);
3766 if (after_pathsep(copybuf, p) && p[-1] == p[-2])
3767 // Ends with '//', use full path
3768 if ((p = make_percent_swname(copybuf, fname)) != NULL)
3769 {
3770 backup = modname(p, backup_ext, FALSE);
3771 vim_free(p);
3772 }
3773#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 rootname = get_file_in_dir(fname, copybuf);
3775 if (rootname == NULL)
3776 {
3777 some_error = TRUE; /* out of memory */
3778 goto nobackup;
3779 }
3780
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003781#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782 did_set_shortname = FALSE;
3783#endif
3784
3785 /*
3786 * May try twice if 'shortname' not set.
3787 */
3788 for (;;)
3789 {
3790 /*
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003791 * Make the backup file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792 */
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003793 if (backup == NULL)
3794 backup = buf_modname((buf->b_p_sn || buf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 rootname, backup_ext, FALSE);
3796 if (backup == NULL)
3797 {
3798 vim_free(rootname);
3799 some_error = TRUE; /* out of memory */
3800 goto nobackup;
3801 }
3802
3803 /*
3804 * Check if backup file already exists.
3805 */
3806 if (mch_stat((char *)backup, &st_new) >= 0)
3807 {
3808#ifdef UNIX
3809 /*
3810 * Check if backup file is same as original file.
3811 * May happen when modname() gave the same file back.
3812 * E.g. silly link, or file name-length reached.
3813 * If we don't check here, we either ruin the file
3814 * when copying or erase it after writing. jw.
3815 */
3816 if (st_new.st_dev == st_old.st_dev
3817 && st_new.st_ino == st_old.st_ino)
3818 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01003819 VIM_CLEAR(backup); /* no backup file to delete */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 /*
3821 * may try again with 'shortname' set
3822 */
3823 if (!(buf->b_shortname || buf->b_p_sn))
3824 {
3825 buf->b_shortname = TRUE;
3826 did_set_shortname = TRUE;
3827 continue;
3828 }
3829 /* setting shortname didn't help */
3830 if (did_set_shortname)
3831 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 break;
3833 }
3834#endif
3835
3836 /*
3837 * If we are not going to keep the backup file, don't
3838 * delete an existing one, try to use another name.
3839 * Change one character, just before the extension.
3840 */
3841 if (!p_bk)
3842 {
3843 wp = backup + STRLEN(backup) - 1
3844 - STRLEN(backup_ext);
3845 if (wp < backup) /* empty file name ??? */
3846 wp = backup;
3847 *wp = 'z';
3848 while (*wp > 'a'
3849 && mch_stat((char *)backup, &st_new) >= 0)
3850 --*wp;
3851 /* They all exist??? Must be something wrong. */
3852 if (*wp == 'a')
Bram Moolenaard23a8232018-02-10 18:45:26 +01003853 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 }
3855 }
3856 break;
3857 }
3858 vim_free(rootname);
3859
3860 /*
3861 * Try to create the backup file
3862 */
3863 if (backup != NULL)
3864 {
3865 /* remove old backup, if present */
3866 mch_remove(backup);
3867 /* Open with O_EXCL to avoid the file being created while
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003868 * we were sleeping (symlink hacker attack?). Reset umask
3869 * if possible to avoid mch_setperm() below. */
3870#ifdef UNIX
3871 umask_save = umask(0);
3872#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003874 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3875 perm & 0777);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003876#ifdef UNIX
3877 (void)umask(umask_save);
3878#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879 if (bfd < 0)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003880 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 else
3882 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003883 /* Set file protection same as original file, but
3884 * strip s-bit. Only needed if umask() wasn't used
3885 * above. */
3886#ifndef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887 (void)mch_setperm(backup, perm & 0777);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003888#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889 /*
3890 * Try to set the group of the backup same as the
3891 * original file. If this fails, set the protection
3892 * bits for the group same as the protection bits for
3893 * others.
3894 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003895 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003897 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898# endif
3899 )
3900 mch_setperm(backup,
3901 (perm & 0707) | ((perm & 07) << 3));
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003902# if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003903 mch_copy_sec(fname, backup);
3904# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905#endif
3906
3907 /*
3908 * copy the file.
3909 */
3910 write_info.bw_fd = bfd;
3911 write_info.bw_buf = copybuf;
3912#ifdef HAS_BW_FLAGS
3913 write_info.bw_flags = FIO_NOCONVERT;
3914#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01003915 while ((write_info.bw_len = read_eintr(fd, copybuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003916 BUFSIZE)) > 0)
3917 {
3918 if (buf_write_bytes(&write_info) == FAIL)
3919 {
3920 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3921 break;
3922 }
3923 ui_breakcheck();
3924 if (got_int)
3925 {
3926 errmsg = (char_u *)_(e_interr);
3927 break;
3928 }
3929 }
3930
3931 if (close(bfd) < 0 && errmsg == NULL)
3932 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3933 if (write_info.bw_len < 0)
3934 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3935#ifdef UNIX
3936 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3937#endif
3938#ifdef HAVE_ACL
3939 mch_set_acl(backup, acl);
3940#endif
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003941#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003942 mch_copy_sec(fname, backup);
3943#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 break;
3945 }
3946 }
3947 }
3948 nobackup:
3949 close(fd); /* ignore errors for closing read file */
3950 vim_free(copybuf);
3951
3952 if (backup == NULL && errmsg == NULL)
3953 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3954 /* ignore errors when forceit is TRUE */
3955 if ((some_error || errmsg != NULL) && !forceit)
3956 {
3957 retval = FAIL;
3958 goto fail;
3959 }
3960 errmsg = NULL;
3961 }
3962 else
3963 {
3964 char_u *dirp;
3965 char_u *p;
3966 char_u *rootname;
3967
3968 /*
3969 * Make a backup by renaming the original file.
3970 */
3971 /*
3972 * If 'cpoptions' includes the "W" flag, we don't want to
3973 * overwrite a read-only file. But rename may be possible
3974 * anyway, thus we need an extra check here.
3975 */
3976 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3977 {
3978 errnum = (char_u *)"E504: ";
3979 errmsg = (char_u *)_(err_readonly);
3980 goto fail;
3981 }
3982
3983 /*
3984 *
3985 * Form the backup file name - change path/fo.o.h to
3986 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3987 * that works is used.
3988 */
3989 dirp = p_bdir;
3990 while (*dirp)
3991 {
3992 /*
3993 * Isolate one directory name and make the backup file name.
3994 */
3995 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003996
Bram Moolenaar4f974752019-02-17 17:44:42 +01003997#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003998 p = IObuff + STRLEN(IObuff);
3999 if (after_pathsep(IObuff, p) && p[-1] == p[-2])
4000 // path ends with '//', use full path
4001 if ((p = make_percent_swname(IObuff, fname)) != NULL)
4002 {
4003 backup = modname(p, backup_ext, FALSE);
4004 vim_free(p);
4005 }
4006#endif
4007 if (backup == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 {
Bram Moolenaarb782ba42018-08-07 21:39:28 +02004009 rootname = get_file_in_dir(fname, IObuff);
4010 if (rootname == NULL)
4011 backup = NULL;
4012 else
4013 {
4014 backup = buf_modname(
4015 (buf->b_p_sn || buf->b_shortname),
4016 rootname, backup_ext, FALSE);
4017 vim_free(rootname);
4018 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019 }
4020
4021 if (backup != NULL)
4022 {
4023 /*
4024 * If we are not going to keep the backup file, don't
4025 * delete an existing one, try to use another name.
4026 * Change one character, just before the extension.
4027 */
4028 if (!p_bk && mch_getperm(backup) >= 0)
4029 {
4030 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
4031 if (p < backup) /* empty file name ??? */
4032 p = backup;
4033 *p = 'z';
4034 while (*p > 'a' && mch_getperm(backup) >= 0)
4035 --*p;
4036 /* They all exist??? Must be something wrong! */
4037 if (*p == 'a')
Bram Moolenaard23a8232018-02-10 18:45:26 +01004038 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 }
4040 }
4041 if (backup != NULL)
4042 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00004044 * Delete any existing backup and move the current version
4045 * to the backup. For safety, we don't remove the backup
4046 * until the write has finished successfully. And if the
4047 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048 */
4049 /*
4050 * If the renaming of the original file to the backup file
4051 * works, quit here.
4052 */
4053 if (vim_rename(fname, backup) == 0)
4054 break;
4055
Bram Moolenaard23a8232018-02-10 18:45:26 +01004056 VIM_CLEAR(backup); /* don't do the rename below */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 }
4058 }
4059 if (backup == NULL && !forceit)
4060 {
4061 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
4062 goto fail;
4063 }
4064 }
4065 }
4066
Bram Moolenaar53076832015-12-31 19:53:21 +01004067#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 /* When using ":w!" and the file was read-only: make it writable */
4069 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
4070 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
4071 {
4072 perm |= 0200;
4073 (void)mch_setperm(fname, perm);
4074 made_writable = TRUE;
4075 }
4076#endif
4077
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004078 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004079 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
4080 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004081 {
4082 buf->b_p_ro = FALSE;
4083#ifdef FEAT_TITLE
4084 need_maketitle = TRUE; /* set window title later */
4085#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086 status_redraw_all(); /* redraw status lines later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 }
4088
4089 if (end > buf->b_ml.ml_line_count)
4090 end = buf->b_ml.ml_line_count;
4091 if (buf->b_ml.ml_flags & ML_EMPTY)
4092 start = end + 1;
4093
4094 /*
4095 * If the original file is being overwritten, there is a small chance that
4096 * we crash in the middle of writing. Therefore the file is preserved now.
4097 * This makes all block numbers positive so that recovery does not need
4098 * the original file.
4099 * Don't do this if there is a backup file and we are exiting.
4100 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004101 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 && !(exiting && backup != NULL))
4103 {
4104 ml_preserve(buf, FALSE);
4105 if (got_int)
4106 {
4107 errmsg = (char_u *)_(e_interr);
4108 goto restore_backup;
4109 }
4110 }
4111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112#ifdef VMS
4113 vms_remove_version(fname); /* remove version */
4114#endif
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00004115 /* Default: write the file directly. May write to a temp file for
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 * multi-byte conversion. */
4117 wfname = fname;
4118
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 /* Check for forced 'fileencoding' from "++opt=val" argument. */
4120 if (eap != NULL && eap->force_enc != 0)
4121 {
4122 fenc = eap->cmd + eap->force_enc;
4123 fenc = enc_canonize(fenc);
4124 fenc_tofree = fenc;
4125 }
4126 else
4127 fenc = buf->b_p_fenc;
4128
4129 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004130 * Check if the file needs to be converted.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131 */
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004132 converted = need_conversion(fenc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133
4134 /*
4135 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
4136 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
4137 * Prepare the flags for it and allocate bw_conv_buf when needed.
4138 */
4139 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
4140 {
4141 wb_flags = get_fio_flags(fenc);
4142 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
4143 {
4144 /* Need to allocate a buffer to translate into. */
4145 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
4146 write_info.bw_conv_buflen = bufsize * 2;
4147 else /* FIO_UCS4 */
4148 write_info.bw_conv_buflen = bufsize * 4;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004149 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 if (write_info.bw_conv_buf == NULL)
4151 end = 0;
4152 }
4153 }
4154
Bram Moolenaar4f974752019-02-17 17:44:42 +01004155#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
4157 {
4158 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
4159 write_info.bw_conv_buflen = bufsize * 4;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004160 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 if (write_info.bw_conv_buf == NULL)
4162 end = 0;
4163 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004164#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165
Bram Moolenaar13505972019-01-24 15:04:48 +01004166#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
4168 {
4169 write_info.bw_conv_buflen = bufsize * 3;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004170 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 if (write_info.bw_conv_buf == NULL)
4172 end = 0;
4173 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004174#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175
Bram Moolenaar13505972019-01-24 15:04:48 +01004176#if defined(FEAT_EVAL) || defined(USE_ICONV)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 if (converted && wb_flags == 0)
4178 {
Bram Moolenaar13505972019-01-24 15:04:48 +01004179# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180 /*
4181 * Use iconv() conversion when conversion is needed and it's not done
4182 * internally.
4183 */
4184 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
4185 enc_utf8 ? (char_u *)"utf-8" : p_enc);
4186 if (write_info.bw_iconv_fd != (iconv_t)-1)
4187 {
4188 /* We're going to use iconv(), allocate a buffer to convert in. */
4189 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004190 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 if (write_info.bw_conv_buf == NULL)
4192 end = 0;
4193 write_info.bw_first = TRUE;
4194 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195# ifdef FEAT_EVAL
Bram Moolenaar13505972019-01-24 15:04:48 +01004196 else
4197# endif
4198# endif
4199
4200# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 /*
4202 * When the file needs to be converted with 'charconvert' after
4203 * writing, write to a temp file instead and let the conversion
4204 * overwrite the original file.
4205 */
4206 if (*p_ccv != NUL)
4207 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +02004208 wfname = vim_tempname('w', FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209 if (wfname == NULL) /* Can't write without a tempfile! */
4210 {
4211 errmsg = (char_u *)_("E214: Can't find temp file for writing");
4212 goto restore_backup;
4213 }
4214 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215# endif
Bram Moolenaar13505972019-01-24 15:04:48 +01004216 }
4217#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004218 if (converted && wb_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01004219#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 && write_info.bw_iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01004221# endif
4222# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 && wfname == fname
Bram Moolenaar13505972019-01-24 15:04:48 +01004224# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 )
4226 {
4227 if (!forceit)
4228 {
4229 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
4230 goto restore_backup;
4231 }
4232 notconverted = TRUE;
4233 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234
4235 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004236 * If conversion is taking place, we may first pretend to write and check
4237 * for conversion errors. Then loop again to write for real.
4238 * When not doing conversion this writes for real right away.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004240 for (checking_conversion = TRUE; ; checking_conversion = FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 {
4242 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004243 * There is no need to check conversion when:
4244 * - there is no conversion
4245 * - we make a backup file, that can be restored in case of conversion
4246 * failure.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004248 if (!converted || dobackup)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004249 checking_conversion = FALSE;
4250
4251 if (checking_conversion)
4252 {
4253 /* Make sure we don't write anything. */
4254 fd = -1;
4255 write_info.bw_fd = fd;
4256 }
4257 else
4258 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004259#ifdef HAVE_FTRUNCATE
4260# define TRUNC_ON_OPEN 0
4261#else
4262# define TRUNC_ON_OPEN O_TRUNC
4263#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004264 /*
4265 * Open the file "wfname" for writing.
4266 * We may try to open the file twice: If we can't write to the file
4267 * and forceit is TRUE we delete the existing file and try to
4268 * create a new one. If this still fails we may have lost the
4269 * original file! (this may happen when the user reached his
4270 * quotum for number of files).
4271 * Appending will fail if the file does not exist and forceit is
4272 * FALSE.
4273 */
4274 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
4275 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004276 : (O_CREAT | TRUNC_ON_OPEN))
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004277 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004279 /*
4280 * A forced write will try to create a new file if the old one
4281 * is still readonly. This may also happen when the directory
4282 * is read-only. In that case the mch_remove() will fail.
4283 */
4284 if (errmsg == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 {
4286#ifdef UNIX
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004287 stat_T st;
4288
4289 /* Don't delete the file when it's a hard or symbolic link.
4290 */
4291 if ((!newfile && st_old.st_nlink > 1)
4292 || (mch_lstat((char *)fname, &st) == 0
4293 && (st.st_dev != st_old.st_dev
4294 || st.st_ino != st_old.st_ino)))
4295 errmsg = (char_u *)_("E166: Can't open linked file for writing");
4296 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004297#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004298 {
4299 errmsg = (char_u *)_("E212: Can't open file for writing");
4300 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
4301 && perm >= 0)
4302 {
4303#ifdef UNIX
4304 /* we write to the file, thus it should be marked
4305 writable after all */
4306 if (!(perm & 0200))
4307 made_writable = TRUE;
4308 perm |= 0200;
4309 if (st_old.st_uid != getuid()
4310 || st_old.st_gid != getgid())
4311 perm &= 0777;
4312#endif
4313 if (!append) /* don't remove when appending */
4314 mch_remove(wfname);
4315 continue;
4316 }
4317 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319
4320restore_backup:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004322 stat_T st;
4323
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004325 * If we failed to open the file, we don't need a backup.
4326 * Throw it away. If we moved or removed the original file
4327 * try to put the backup in its place.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004329 if (backup != NULL && wfname == fname)
4330 {
4331 if (backup_copy)
4332 {
4333 /*
4334 * There is a small chance that we removed the
4335 * original, try to move the copy in its place.
4336 * This may not work if the vim_rename() fails.
4337 * In that case we leave the copy around.
4338 */
4339 /* If file does not exist, put the copy in its
4340 * place */
4341 if (mch_stat((char *)fname, &st) < 0)
4342 vim_rename(backup, fname);
4343 /* if original file does exist throw away the copy
4344 */
4345 if (mch_stat((char *)fname, &st) >= 0)
4346 mch_remove(backup);
4347 }
4348 else
4349 {
4350 /* try to put the original file back */
4351 vim_rename(backup, fname);
4352 }
4353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004355 /* if original file no longer exists give an extra warning
4356 */
4357 if (!newfile && mch_stat((char *)fname, &st) < 0)
4358 end = 0;
4359 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004361 if (wfname != fname)
4362 vim_free(wfname);
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004363 goto fail;
4364 }
4365 write_info.bw_fd = fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004367#if defined(UNIX)
4368 {
4369 stat_T st;
4370
4371 /* Double check we are writing the intended file before making
4372 * any changes. */
4373 if (overwriting
4374 && (!dobackup || backup_copy)
4375 && fname == wfname
4376 && perm >= 0
4377 && mch_fstat(fd, &st) == 0
4378 && st.st_ino != st_old.st_ino)
4379 {
4380 close(fd);
4381 errmsg = (char_u *)_("E949: File changed while writing");
4382 goto fail;
4383 }
4384 }
4385#endif
4386#ifdef HAVE_FTRUNCATE
4387 if (!append)
Bram Moolenaar42335f52018-09-13 15:33:43 +02004388 vim_ignored = ftruncate(fd, (off_t)0);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004389#endif
4390
Bram Moolenaar4f974752019-02-17 17:44:42 +01004391#if defined(MSWIN)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004392 if (backup != NULL && overwriting && !append)
4393 {
4394 if (backup_copy)
4395 (void)mch_copy_file_attribute(wfname, backup);
4396 else
4397 (void)mch_copy_file_attribute(backup, wfname);
4398 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004400 if (!overwriting && !append)
4401 {
4402 if (buf->b_ffname != NULL)
4403 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
4404 /* Should copy resource fork */
4405 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406#endif
4407
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408#ifdef FEAT_CRYPT
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004409 if (*buf->b_p_key != NUL && !filtering)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004411 char_u *header;
4412 int header_len;
4413
4414 buf->b_cryptstate = crypt_create_for_writing(
4415 crypt_get_method_nr(buf),
4416 buf->b_p_key, &header, &header_len);
4417 if (buf->b_cryptstate == NULL || header == NULL)
4418 end = 0;
4419 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004421 /* Write magic number, so that Vim knows how this file is
4422 * encrypted when reading it back. */
4423 write_info.bw_buf = header;
4424 write_info.bw_len = header_len;
4425 write_info.bw_flags = FIO_NOCONVERT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 if (buf_write_bytes(&write_info) == FAIL)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004427 end = 0;
4428 wb_flags |= FIO_ENCRYPTED;
4429 vim_free(header);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004432#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004434 errmsg = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004436 write_info.bw_buf = buffer;
4437 nchars = 0;
4438
4439 /* use "++bin", "++nobin" or 'binary' */
4440 if (eap != NULL && eap->force_bin != 0)
4441 write_bin = (eap->force_bin == FORCE_BIN);
4442 else
4443 write_bin = buf->b_p_bin;
4444
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004446 * The BOM is written just after the encryption magic number.
4447 * Skip it when appending and the file already existed, the BOM only
4448 * makes sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004450 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004451 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004452 write_info.bw_len = make_bom(buffer, fenc);
4453 if (write_info.bw_len > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004455 /* don't convert, do encryption */
4456 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4457 if (buf_write_bytes(&write_info) == FAIL)
4458 end = 0;
4459 else
4460 nchars += write_info.bw_len;
4461 }
4462 }
4463 write_info.bw_start_lnum = start;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004464
4465#ifdef FEAT_PERSISTENT_UNDO
4466 write_undo_file = (buf->b_p_udf
4467 && overwriting
4468 && !append
4469 && !filtering
4470 && reset_changed
4471 && !checking_conversion);
4472 if (write_undo_file)
4473 /* Prepare for computing the hash value of the text. */
4474 sha256_start(&sha_ctx);
4475#endif
4476
4477 write_info.bw_len = bufsize;
4478#ifdef HAS_BW_FLAGS
4479 write_info.bw_flags = wb_flags;
4480#endif
4481 fileformat = get_fileformat_force(buf, eap);
4482 s = buffer;
4483 len = 0;
4484 for (lnum = start; lnum <= end; ++lnum)
4485 {
4486 /*
4487 * The next while loop is done once for each character written.
4488 * Keep it fast!
4489 */
4490 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4491#ifdef FEAT_PERSISTENT_UNDO
4492 if (write_undo_file)
4493 sha256_update(&sha_ctx, ptr + 1,
4494 (UINT32_T)(STRLEN(ptr + 1) + 1));
4495#endif
4496 while ((c = *++ptr) != NUL)
4497 {
4498 if (c == NL)
4499 *s = NUL; /* replace newlines with NULs */
4500 else if (c == CAR && fileformat == EOL_MAC)
4501 *s = NL; /* Mac: replace CRs with NLs */
4502 else
4503 *s = c;
4504 ++s;
4505 if (++len != bufsize)
4506 continue;
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004507 if (buf_write_bytes(&write_info) == FAIL)
4508 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004509 end = 0; /* write error: break loop */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004510 break;
4511 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004512 nchars += bufsize;
4513 s = buffer;
4514 len = 0;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004515 write_info.bw_start_lnum = lnum;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004516 }
4517 /* write failed or last line has no EOL: stop here */
4518 if (end == 0
4519 || (lnum == end
4520 && (write_bin || !buf->b_p_fixeol)
4521 && (lnum == buf->b_no_eol_lnum
4522 || (lnum == buf->b_ml.ml_line_count
4523 && !buf->b_p_eol))))
4524 {
4525 ++lnum; /* written the line, count it */
4526 no_eol = TRUE;
4527 break;
4528 }
4529 if (fileformat == EOL_UNIX)
4530 *s++ = NL;
4531 else
4532 {
4533 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4534 if (fileformat == EOL_DOS) /* write CR-NL */
4535 {
4536 if (++len == bufsize)
4537 {
4538 if (buf_write_bytes(&write_info) == FAIL)
4539 {
4540 end = 0; /* write error: break loop */
4541 break;
4542 }
4543 nchars += bufsize;
4544 s = buffer;
4545 len = 0;
4546 }
4547 *s++ = NL;
4548 }
4549 }
4550 if (++len == bufsize && end)
4551 {
4552 if (buf_write_bytes(&write_info) == FAIL)
4553 {
4554 end = 0; /* write error: break loop */
4555 break;
4556 }
4557 nchars += bufsize;
4558 s = buffer;
4559 len = 0;
4560
4561 ui_breakcheck();
4562 if (got_int)
4563 {
4564 end = 0; /* Interrupted, break loop */
4565 break;
4566 }
4567 }
4568#ifdef VMS
4569 /*
4570 * On VMS there is a problem: newlines get added when writing
4571 * blocks at a time. Fix it by writing a line at a time.
4572 * This is much slower!
4573 * Explanation: VAX/DECC RTL insists that records in some RMS
4574 * structures end with a newline (carriage return) character, and
4575 * if they don't it adds one.
4576 * With other RMS structures it works perfect without this fix.
4577 */
4578 if (buf->b_fab_rfm == FAB$C_VFC
4579 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4580 {
4581 int b2write;
4582
4583 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4584 ? MIN(4096, bufsize)
4585 : MIN(buf->b_fab_mrs, bufsize));
4586
4587 b2write = len;
4588 while (b2write > 0)
4589 {
4590 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4591 if (buf_write_bytes(&write_info) == FAIL)
4592 {
4593 end = 0;
4594 break;
4595 }
4596 b2write -= MIN(b2write, buf->b_fab_mrs);
4597 }
4598 write_info.bw_len = bufsize;
4599 nchars += len;
4600 s = buffer;
4601 len = 0;
4602 }
4603#endif
4604 }
4605 if (len > 0 && end > 0)
4606 {
4607 write_info.bw_len = len;
4608 if (buf_write_bytes(&write_info) == FAIL)
4609 end = 0; /* write error */
4610 nchars += len;
4611 }
4612
4613 /* Stop when writing done or an error was encountered. */
4614 if (!checking_conversion || end == 0)
4615 break;
4616
4617 /* If no error happened until now, writing should be ok, so loop to
4618 * really write the buffer. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 }
4620
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004621 /* If we started writing, finish writing. Also when an error was
4622 * encountered. */
4623 if (!checking_conversion)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004625#if defined(UNIX) && defined(HAVE_FSYNC)
4626 /*
4627 * On many journalling file systems there is a bug that causes both the
4628 * original and the backup file to be lost when halting the system
4629 * right after writing the file. That's because only the meta-data is
4630 * journalled. Syncing the file slows down the system, but assures it
4631 * has been written to disk and we don't lose it.
4632 * For a device do try the fsync() but don't complain if it does not
4633 * work (could be a pipe).
4634 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
4635 */
Bram Moolenaara7870192019-02-14 12:56:36 +01004636 if (p_fs && vim_fsync(fd) != 0 && !device)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004637 {
Bram Moolenaar7567d0b2017-11-16 23:04:15 +01004638 errmsg = (char_u *)_(e_fsync);
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004639 end = 0;
4640 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641#endif
4642
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02004643#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004644 /* Probably need to set the security context. */
4645 if (!backup_copy)
4646 mch_copy_sec(backup, wfname);
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004647#endif
4648
Bram Moolenaara5792f52005-11-23 21:25:05 +00004649#ifdef UNIX
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004650 /* When creating a new file, set its owner/group to that of the
4651 * original file. Get the new device and inode number. */
4652 if (backup != NULL && !backup_copy)
Bram Moolenaara5792f52005-11-23 21:25:05 +00004653 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004654# ifdef HAVE_FCHOWN
4655 stat_T st;
4656
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004657 /* Don't change the owner when it's already OK, some systems remove
4658 * permission or ACL stuff. */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004659 if (mch_stat((char *)wfname, &st) < 0
4660 || st.st_uid != st_old.st_uid
4661 || st.st_gid != st_old.st_gid)
4662 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004663 /* changing owner might not be possible */
Bram Moolenaar42335f52018-09-13 15:33:43 +02004664 vim_ignored = fchown(fd, st_old.st_uid, -1);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004665 /* if changing group fails clear the group permissions */
4666 if (fchown(fd, -1, st_old.st_gid) == -1 && perm > 0)
4667 perm &= ~070;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004668 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00004669# endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004670 buf_setino(buf);
4671 }
4672 else if (!buf->b_dev_valid)
4673 /* Set the inode when creating a new file. */
4674 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004675#endif
4676
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004677#ifdef UNIX
4678 if (made_writable)
4679 perm &= ~0200; /* reset 'w' bit for security reasons */
4680#endif
4681#ifdef HAVE_FCHMOD
4682 /* set permission of new file same as old file */
4683 if (perm >= 0)
4684 (void)mch_fsetperm(fd, perm);
4685#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004686 if (close(fd) != 0)
4687 {
4688 errmsg = (char_u *)_("E512: Close failed");
4689 end = 0;
4690 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004692#ifndef HAVE_FCHMOD
4693 /* set permission of new file same as old file */
4694 if (perm >= 0)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004695 (void)mch_setperm(wfname, perm);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004696#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697#ifdef HAVE_ACL
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004698 /*
4699 * Probably need to set the ACL before changing the user (can't set the
4700 * ACL on a file the user doesn't own).
4701 * On Solaris, with ZFS and the aclmode property set to "discard" (the
4702 * default), chmod() discards all part of a file's ACL that don't
4703 * represent the mode of the file. It's non-trivial for us to discover
4704 * whether we're in that situation, so we simply always re-set the ACL.
4705 */
Bram Moolenaarda412772016-07-14 20:37:07 +02004706# ifndef HAVE_SOLARIS_ZFS_ACL
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004707 if (!backup_copy)
Bram Moolenaarda412772016-07-14 20:37:07 +02004708# endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004709 mch_set_acl(wfname, acl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004711#ifdef FEAT_CRYPT
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004712 if (buf->b_cryptstate != NULL)
4713 {
4714 crypt_free_state(buf->b_cryptstate);
4715 buf->b_cryptstate = NULL;
4716 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004717#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718
Bram Moolenaar13505972019-01-24 15:04:48 +01004719#if defined(FEAT_EVAL)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004720 if (wfname != fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004722 /*
4723 * The file was written to a temp file, now it needs to be
4724 * converted with 'charconvert' to (overwrite) the output file.
4725 */
4726 if (end != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004728 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
4729 fenc, wfname, fname) == FAIL)
4730 {
4731 write_info.bw_conv_error = TRUE;
4732 end = 0;
4733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004735 mch_remove(wfname);
4736 vim_free(wfname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004739 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740
4741 if (end == 0)
4742 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004743 /*
4744 * Error encountered.
4745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746 if (errmsg == NULL)
4747 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 if (write_info.bw_conv_error)
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004749 {
4750 if (write_info.bw_conv_error_lnum == 0)
4751 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
4752 else
4753 {
4754 errmsg_allocated = TRUE;
4755 errmsg = alloc(300);
4756 vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"),
4757 (long)write_info.bw_conv_error_lnum);
4758 }
4759 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004760 else if (got_int)
4761 errmsg = (char_u *)_(e_interr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762 else
Bram Moolenaar13505972019-01-24 15:04:48 +01004763 errmsg = (char_u *)_("E514: write error (file system full?)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 }
4765
4766 /*
4767 * If we have a backup file, try to put it in place of the new file,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004768 * because the new file is probably corrupt. This avoids losing the
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769 * original file when trying to make a backup when writing the file a
4770 * second time.
4771 * When "backup_copy" is set we need to copy the backup over the new
4772 * file. Otherwise rename the backup file.
4773 * If this is OK, don't give the extra warning message.
4774 */
4775 if (backup != NULL)
4776 {
4777 if (backup_copy)
4778 {
4779 /* This may take a while, if we were interrupted let the user
4780 * know we got the message. */
4781 if (got_int)
4782 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004783 msg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784 out_flush();
4785 }
4786 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4787 {
4788 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004789 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4790 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 {
4792 /* copy the file. */
4793 write_info.bw_buf = smallbuf;
4794#ifdef HAS_BW_FLAGS
4795 write_info.bw_flags = FIO_NOCONVERT;
4796#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004797 while ((write_info.bw_len = read_eintr(fd, smallbuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798 SMBUFSIZE)) > 0)
4799 if (buf_write_bytes(&write_info) == FAIL)
4800 break;
4801
4802 if (close(write_info.bw_fd) >= 0
4803 && write_info.bw_len == 0)
4804 end = 1; /* success */
4805 }
4806 close(fd); /* ignore errors for closing read file */
4807 }
4808 }
4809 else
4810 {
4811 if (vim_rename(backup, fname) == 0)
4812 end = 1;
4813 }
4814 }
4815 goto fail;
4816 }
4817
4818 lnum -= start; /* compute number of written lines */
4819 --no_wait_return; /* may wait for return now */
4820
4821#if !(defined(UNIX) || defined(VMS))
4822 fname = sfname; /* use shortname now, for the messages */
4823#endif
4824 if (!filtering)
4825 {
4826 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4827 c = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 if (write_info.bw_conv_error)
4829 {
4830 STRCAT(IObuff, _(" CONVERSION ERROR"));
4831 c = TRUE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004832 if (write_info.bw_conv_error_lnum != 0)
Bram Moolenaara800b422010-06-27 01:15:55 +02004833 vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"),
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004834 (long)write_info.bw_conv_error_lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835 }
4836 else if (notconverted)
4837 {
4838 STRCAT(IObuff, _("[NOT converted]"));
4839 c = TRUE;
4840 }
4841 else if (converted)
4842 {
4843 STRCAT(IObuff, _("[converted]"));
4844 c = TRUE;
4845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 if (device)
4847 {
4848 STRCAT(IObuff, _("[Device]"));
4849 c = TRUE;
4850 }
4851 else if (newfile)
4852 {
4853 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4854 c = TRUE;
4855 }
4856 if (no_eol)
4857 {
4858 msg_add_eol();
4859 c = TRUE;
4860 }
4861 /* may add [unix/dos/mac] */
4862 if (msg_add_fileformat(fileformat))
4863 c = TRUE;
4864#ifdef FEAT_CRYPT
4865 if (wb_flags & FIO_ENCRYPTED)
4866 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004867 crypt_append_msg(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 c = TRUE;
4869 }
4870#endif
4871 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4872 if (!shortmess(SHM_WRITE))
4873 {
4874 if (append)
4875 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4876 else
4877 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4878 }
4879
Bram Moolenaar32526b32019-01-19 17:43:09 +01004880 set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881 }
4882
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004883 /* When written everything correctly: reset 'modified'. Unless not
4884 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004885 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886 && !write_info.bw_conv_error
Bram Moolenaar13505972019-01-24 15:04:48 +01004887 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888 {
Bram Moolenaarc024b462019-06-08 18:07:21 +02004889 unchanged(buf, TRUE, FALSE);
4890 /* b:changedtick is may be incremented in unchanged() but that
Bram Moolenaar086329d2014-10-31 19:51:36 +01004891 * should not trigger a TextChanged event. */
Bram Moolenaar5a093432018-02-10 18:15:19 +01004892 if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf))
4893 buf->b_last_changedtick = CHANGEDTICK(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894 u_unchanged(buf);
Bram Moolenaar730cde92010-06-27 05:18:54 +02004895 u_update_save_nr(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896 }
4897
4898 /*
4899 * If written to the current file, update the timestamp of the swap file
4900 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4901 */
4902 if (overwriting)
4903 {
4904 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004905 if (append)
4906 buf->b_flags &= ~BF_NEW;
4907 else
4908 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 }
4910
4911 /*
4912 * If we kept a backup until now, and we are in patch mode, then we make
4913 * the backup file our 'original' file.
4914 */
4915 if (*p_pm && dobackup)
4916 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004917 char *org = (char *)buf_modname((buf->b_p_sn || buf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 fname, p_pm, FALSE);
4919
4920 if (backup != NULL)
4921 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02004922 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923
4924 /*
4925 * If the original file does not exist yet
4926 * the current backup file becomes the original file
4927 */
4928 if (org == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004929 emsg(_("E205: Patchmode: can't save original file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930 else if (mch_stat(org, &st) < 0)
4931 {
4932 vim_rename(backup, (char_u *)org);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004933 VIM_CLEAR(backup); /* don't delete the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934#ifdef UNIX
4935 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4936#endif
4937 }
4938 }
4939 /*
4940 * If there is no backup file, remember that a (new) file was
4941 * created.
4942 */
4943 else
4944 {
4945 int empty_fd;
4946
4947 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004948 || (empty_fd = mch_open(org,
4949 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004950 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004951 emsg(_("E206: patchmode: can't touch empty original file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 else
4953 close(empty_fd);
4954 }
4955 if (org != NULL)
4956 {
4957 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4958 vim_free(org);
4959 }
4960 }
4961
Bram Moolenaarcf0bfd92019-05-18 18:52:04 +02004962 // Remove the backup unless 'backup' option is set or there was a
4963 // conversion error.
4964 if (!p_bk && backup != NULL && !write_info.bw_conv_error
4965 && mch_remove(backup) != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004966 emsg(_("E207: Can't delete backup file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967
Bram Moolenaar071d4272004-06-13 20:20:40 +00004968 goto nofail;
4969
4970 /*
4971 * Finish up. We get here either after failure or success.
4972 */
4973fail:
4974 --no_wait_return; /* may wait for return now */
4975nofail:
4976
4977 /* Done saving, we accept changed buffer warnings again */
4978 buf->b_saving = FALSE;
4979
4980 vim_free(backup);
4981 if (buffer != smallbuf)
4982 vim_free(buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004983 vim_free(fenc_tofree);
4984 vim_free(write_info.bw_conv_buf);
Bram Moolenaar13505972019-01-24 15:04:48 +01004985#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004986 if (write_info.bw_iconv_fd != (iconv_t)-1)
4987 {
4988 iconv_close(write_info.bw_iconv_fd);
4989 write_info.bw_iconv_fd = (iconv_t)-1;
4990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991#endif
4992#ifdef HAVE_ACL
4993 mch_free_acl(acl);
4994#endif
4995
4996 if (errmsg != NULL)
4997 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004998 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999
Bram Moolenaar8820b482017-03-16 17:23:31 +01005000 attr = HL_ATTR(HLF_E); /* set highlight for error messages */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 msg_add_fname(buf,
5002#ifndef UNIX
5003 sfname
5004#else
5005 fname
5006#endif
5007 ); /* put file name in IObuff with quotes */
5008 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
5009 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
5010 /* If the error message has the form "is ...", put the error number in
5011 * front of the file name. */
5012 if (errnum != NULL)
5013 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005014 STRMOVE(IObuff + numlen, IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015 mch_memmove(IObuff, errnum, (size_t)numlen);
5016 }
5017 STRCAT(IObuff, errmsg);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005018 emsg((char *)IObuff);
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005019 if (errmsg_allocated)
5020 vim_free(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005021
5022 retval = FAIL;
5023 if (end == 0)
5024 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005025 msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005026 attr | MSG_HIST);
Bram Moolenaar32526b32019-01-19 17:43:09 +01005027 msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005028 attr | MSG_HIST);
5029
5030 /* Update the timestamp to avoid an "overwrite changed file"
5031 * prompt when writing again. */
5032 if (mch_stat((char *)fname, &st_old) >= 0)
5033 {
5034 buf_store_time(buf, &st_old, fname);
5035 buf->b_mtime_read = buf->b_mtime;
5036 }
5037 }
5038 }
5039 msg_scroll = msg_save;
5040
Bram Moolenaar55debbe2010-05-23 23:34:36 +02005041#ifdef FEAT_PERSISTENT_UNDO
5042 /*
5043 * When writing the whole file and 'undofile' is set, also write the undo
5044 * file.
5045 */
5046 if (retval == OK && write_undo_file)
5047 {
5048 char_u hash[UNDO_HASH_SIZE];
5049
5050 sha256_finish(&sha_ctx, hash);
5051 u_write_undo(NULL, FALSE, buf, hash);
5052 }
5053#endif
5054
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055#ifdef FEAT_EVAL
5056 if (!should_abort(retval))
5057#else
5058 if (!got_int)
5059#endif
5060 {
5061 aco_save_T aco;
5062
Bram Moolenaar68a33fc2012-04-25 16:50:48 +02005063 curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
5064
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065 /*
5066 * Apply POST autocommands.
5067 * Careful: The autocommands may call buf_write() recursively!
5068 */
5069 aucmd_prepbuf(&aco, buf);
5070
5071 if (append)
5072 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
5073 FALSE, curbuf, eap);
5074 else if (filtering)
5075 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
5076 FALSE, curbuf, eap);
5077 else if (reset_changed && whole)
5078 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
5079 FALSE, curbuf, eap);
5080 else
5081 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
5082 FALSE, curbuf, eap);
5083
5084 /* restore curwin/curbuf and a few other things */
5085 aucmd_restbuf(&aco);
5086
5087#ifdef FEAT_EVAL
5088 if (aborting()) /* autocmds may abort script processing */
5089 retval = FALSE;
5090#endif
5091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092
5093 got_int |= prev_got_int;
5094
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095 return retval;
5096}
5097
Bram Moolenaara7870192019-02-14 12:56:36 +01005098#if defined(HAVE_FSYNC) || defined(PROTO)
5099/*
5100 * Call fsync() with Mac-specific exception.
5101 * Return fsync() result: zero for success.
5102 */
5103 int
5104vim_fsync(int fd)
5105{
5106 int r;
5107
5108# ifdef MACOS_X
5109 r = fcntl(fd, F_FULLFSYNC);
Bram Moolenaar91668382019-02-21 12:16:12 +01005110 if (r != 0) // F_FULLFSYNC not working or not supported
Bram Moolenaara7870192019-02-14 12:56:36 +01005111# endif
5112 r = fsync(fd);
5113 return r;
5114}
5115#endif
5116
Bram Moolenaar071d4272004-06-13 20:20:40 +00005117/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005118 * Set the name of the current buffer. Use when the buffer doesn't have a
5119 * name and a ":r" or ":w" command with a file name is used.
5120 */
5121 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005122set_rw_fname(char_u *fname, char_u *sfname)
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005123{
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005124 buf_T *buf = curbuf;
5125
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005126 /* It's like the unnamed buffer is deleted.... */
5127 if (curbuf->b_p_bl)
5128 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
5129 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005130#ifdef FEAT_EVAL
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005131 if (aborting()) /* autocmds may abort script processing */
5132 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005133#endif
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005134 if (curbuf != buf)
5135 {
5136 /* We are in another buffer now, don't do the renaming. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005137 emsg(_(e_auchangedbuf));
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005138 return FAIL;
5139 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005140
5141 if (setfname(curbuf, fname, sfname, FALSE) == OK)
5142 curbuf->b_flags |= BF_NOTEDITED;
5143
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005144 /* ....and a new named one is created */
5145 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
5146 if (curbuf->b_p_bl)
5147 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005148#ifdef FEAT_EVAL
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005149 if (aborting()) /* autocmds may abort script processing */
5150 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005151#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005152
5153 /* Do filetype detection now if 'filetype' is empty. */
5154 if (*curbuf->b_p_ft == NUL)
5155 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005156 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar1610d052016-06-09 22:53:01 +02005157 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE, NULL);
Bram Moolenaara3227e22006-03-08 21:32:40 +00005158 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005159 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005160
5161 return OK;
5162}
5163
5164/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005165 * Put file name into IObuff with quotes.
5166 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005167 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005168msg_add_fname(buf_T *buf, char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169{
5170 if (fname == NULL)
5171 fname = (char_u *)"-stdin-";
5172 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
5173 IObuff[0] = '"';
5174 STRCAT(IObuff, "\" ");
5175}
5176
5177/*
5178 * Append message for text mode to IObuff.
5179 * Return TRUE if something appended.
5180 */
5181 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005182msg_add_fileformat(int eol_type)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183{
5184#ifndef USE_CRNL
5185 if (eol_type == EOL_DOS)
5186 {
5187 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
5188 return TRUE;
5189 }
5190#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005191 if (eol_type == EOL_MAC)
5192 {
5193 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
5194 return TRUE;
5195 }
Bram Moolenaar00590742019-02-15 21:06:09 +01005196#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005197 if (eol_type == EOL_UNIX)
5198 {
5199 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
5200 return TRUE;
5201 }
5202#endif
5203 return FALSE;
5204}
5205
5206/*
5207 * Append line and character count to IObuff.
5208 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005209 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005210msg_add_lines(
5211 int insert_space,
5212 long lnum,
Bram Moolenaar8767f522016-07-01 17:17:39 +02005213 off_T nchars)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214{
5215 char_u *p;
5216
5217 p = IObuff + STRLEN(IObuff);
5218
5219 if (insert_space)
5220 *p++ = ' ';
5221 if (shortmess(SHM_LINES))
Bram Moolenaarbde98102016-07-01 20:03:42 +02005222 vim_snprintf((char *)p, IOSIZE - (p - IObuff),
Bram Moolenaar88c86eb2019-01-17 17:13:30 +01005223 "%ldL, %lldC", lnum, (long_long_T)nchars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005224 else
5225 {
Bram Moolenaarda6e8912018-08-21 15:12:14 +02005226 sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227 p += STRLEN(p);
Bram Moolenaarda6e8912018-08-21 15:12:14 +02005228 vim_snprintf((char *)p, IOSIZE - (p - IObuff),
5229 NGETTEXT("%lld character", "%lld characters", nchars),
Bram Moolenaar88c86eb2019-01-17 17:13:30 +01005230 (long_long_T)nchars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005231 }
5232}
5233
5234/*
5235 * Append message for missing line separator to IObuff.
5236 */
5237 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005238msg_add_eol(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239{
5240 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
5241}
5242
5243/*
5244 * Check modification time of file, before writing to it.
5245 * The size isn't checked, because using a tool like "gzip" takes care of
5246 * using the same timestamp but can't set the size.
5247 */
5248 static int
Bram Moolenaar8767f522016-07-01 17:17:39 +02005249check_mtime(buf_T *buf, stat_T *st)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250{
5251 if (buf->b_mtime_read != 0
5252 && time_differs((long)st->st_mtime, buf->b_mtime_read))
5253 {
5254 msg_scroll = TRUE; /* don't overwrite messages here */
5255 msg_silent = 0; /* must give this prompt */
5256 /* don't use emsg() here, don't want to flush the buffers */
Bram Moolenaar32526b32019-01-19 17:43:09 +01005257 msg_attr(_("WARNING: The file has been changed since reading it!!!"),
Bram Moolenaar8820b482017-03-16 17:23:31 +01005258 HL_ATTR(HLF_E));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005259 if (ask_yesno((char_u *)_("Do you really want to write to it"),
5260 TRUE) == 'n')
5261 return FAIL;
5262 msg_scroll = FALSE; /* always overwrite the file message now */
5263 }
5264 return OK;
5265}
5266
5267 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005268time_differs(long t1, long t2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005269{
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005270#if defined(__linux__) || defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
5272 * the seconds. Since the roundoff is done when flushing the inode, the
5273 * time may change unexpectedly by one second!!! */
5274 return (t1 - t2 > 1 || t2 - t1 > 1);
5275#else
5276 return (t1 != t2);
5277#endif
5278}
5279
5280/*
5281 * Call write() to write a number of bytes to the file.
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005282 * Handles encryption and 'encoding' conversion.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283 *
5284 * Return FAIL for failure, OK otherwise.
5285 */
5286 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005287buf_write_bytes(struct bw_info *ip)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288{
5289 int wlen;
5290 char_u *buf = ip->bw_buf; /* data to write */
5291 int len = ip->bw_len; /* length of data */
5292#ifdef HAS_BW_FLAGS
5293 int flags = ip->bw_flags; /* extra flags */
5294#endif
5295
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296 /*
5297 * Skip conversion when writing the crypt magic number or the BOM.
5298 */
5299 if (!(flags & FIO_NOCONVERT))
5300 {
5301 char_u *p;
5302 unsigned c;
5303 int n;
5304
5305 if (flags & FIO_UTF8)
5306 {
5307 /*
5308 * Convert latin1 in the buffer to UTF-8 in the file.
5309 */
5310 p = ip->bw_conv_buf; /* translate to buffer */
5311 for (wlen = 0; wlen < len; ++wlen)
5312 p += utf_char2bytes(buf[wlen], p);
5313 buf = ip->bw_conv_buf;
5314 len = (int)(p - ip->bw_conv_buf);
5315 }
5316 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
5317 {
5318 /*
5319 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
5320 * Latin1 chars in the file.
5321 */
5322 if (flags & FIO_LATIN1)
5323 p = buf; /* translate in-place (can only get shorter) */
5324 else
5325 p = ip->bw_conv_buf; /* translate to buffer */
5326 for (wlen = 0; wlen < len; wlen += n)
5327 {
5328 if (wlen == 0 && ip->bw_restlen != 0)
5329 {
5330 int l;
5331
5332 /* Use remainder of previous call. Append the start of
5333 * buf[] to get a full sequence. Might still be too
5334 * short! */
5335 l = CONV_RESTLEN - ip->bw_restlen;
5336 if (l > len)
5337 l = len;
5338 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005339 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340 if (n > ip->bw_restlen + len)
5341 {
5342 /* We have an incomplete byte sequence at the end to
5343 * be written. We can't convert it without the
5344 * remaining bytes. Keep them for the next call. */
5345 if (ip->bw_restlen + len > CONV_RESTLEN)
5346 return FAIL;
5347 ip->bw_restlen += len;
5348 break;
5349 }
5350 if (n > 1)
5351 c = utf_ptr2char(ip->bw_rest);
5352 else
5353 c = ip->bw_rest[0];
5354 if (n >= ip->bw_restlen)
5355 {
5356 n -= ip->bw_restlen;
5357 ip->bw_restlen = 0;
5358 }
5359 else
5360 {
5361 ip->bw_restlen -= n;
5362 mch_memmove(ip->bw_rest, ip->bw_rest + n,
5363 (size_t)ip->bw_restlen);
5364 n = 0;
5365 }
5366 }
5367 else
5368 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005369 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005370 if (n > len - wlen)
5371 {
5372 /* We have an incomplete byte sequence at the end to
5373 * be written. We can't convert it without the
5374 * remaining bytes. Keep them for the next call. */
5375 if (len - wlen > CONV_RESTLEN)
5376 return FAIL;
5377 ip->bw_restlen = len - wlen;
5378 mch_memmove(ip->bw_rest, buf + wlen,
5379 (size_t)ip->bw_restlen);
5380 break;
5381 }
5382 if (n > 1)
5383 c = utf_ptr2char(buf + wlen);
5384 else
5385 c = buf[wlen];
5386 }
5387
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005388 if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error)
5389 {
5390 ip->bw_conv_error = TRUE;
5391 ip->bw_conv_error_lnum = ip->bw_start_lnum;
5392 }
5393 if (c == NL)
5394 ++ip->bw_start_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005395 }
5396 if (flags & FIO_LATIN1)
5397 len = (int)(p - buf);
5398 else
5399 {
5400 buf = ip->bw_conv_buf;
5401 len = (int)(p - ip->bw_conv_buf);
5402 }
5403 }
5404
Bram Moolenaar4f974752019-02-17 17:44:42 +01005405#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005406 else if (flags & FIO_CODEPAGE)
5407 {
5408 /*
5409 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
5410 * codepage.
5411 */
5412 char_u *from;
5413 size_t fromlen;
5414 char_u *to;
5415 int u8c;
5416 BOOL bad = FALSE;
5417 int needed;
5418
5419 if (ip->bw_restlen > 0)
5420 {
5421 /* Need to concatenate the remainder of the previous call and
5422 * the bytes of the current call. Use the end of the
5423 * conversion buffer for this. */
5424 fromlen = len + ip->bw_restlen;
5425 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5426 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5427 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5428 }
5429 else
5430 {
5431 from = buf;
5432 fromlen = len;
5433 }
5434
5435 to = ip->bw_conv_buf;
5436 if (enc_utf8)
5437 {
5438 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
5439 * The buffer has been allocated to be big enough. */
5440 while (fromlen > 0)
5441 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005442 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005443 if (n > (int)fromlen) /* incomplete byte sequence */
5444 break;
5445 u8c = utf_ptr2char(from);
5446 *to++ = (u8c & 0xff);
5447 *to++ = (u8c >> 8);
5448 fromlen -= n;
5449 from += n;
5450 }
5451
5452 /* Copy remainder to ip->bw_rest[] to be used for the next
5453 * call. */
5454 if (fromlen > CONV_RESTLEN)
5455 {
5456 /* weird overlong sequence */
5457 ip->bw_conv_error = TRUE;
5458 return FAIL;
5459 }
5460 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005461 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005462 }
5463 else
5464 {
5465 /* Convert from enc_codepage to UCS-2, to the start of the
5466 * buffer. The buffer has been allocated to be big enough. */
5467 ip->bw_restlen = 0;
5468 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005469 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470 NULL, 0);
5471 if (needed == 0)
5472 {
5473 /* When conversion fails there may be a trailing byte. */
5474 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005475 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005476 NULL, 0);
5477 if (needed == 0)
5478 {
5479 /* Conversion doesn't work. */
5480 ip->bw_conv_error = TRUE;
5481 return FAIL;
5482 }
5483 /* Save the trailing byte for the next call. */
5484 ip->bw_rest[0] = from[fromlen - 1];
5485 ip->bw_restlen = 1;
5486 }
5487 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005488 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 (LPWSTR)to, needed);
5490 if (needed == 0)
5491 {
5492 /* Safety check: Conversion doesn't work. */
5493 ip->bw_conv_error = TRUE;
5494 return FAIL;
5495 }
5496 to += needed * 2;
5497 }
5498
5499 fromlen = to - ip->bw_conv_buf;
5500 buf = to;
Bram Moolenaar13505972019-01-24 15:04:48 +01005501# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005502 if (FIO_GET_CP(flags) == CP_UTF8)
5503 {
5504 /* Convert from UCS-2 to UTF-8, using the remainder of the
5505 * conversion buffer. Fails when out of space. */
5506 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5507 {
5508 u8c = *from++;
5509 u8c += (*from++ << 8);
5510 to += utf_char2bytes(u8c, to);
5511 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5512 {
5513 ip->bw_conv_error = TRUE;
5514 return FAIL;
5515 }
5516 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005517 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518 }
5519 else
Bram Moolenaar13505972019-01-24 15:04:48 +01005520# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 {
5522 /* Convert from UCS-2 to the codepage, using the remainder of
5523 * the conversion buffer. If the conversion uses the default
5524 * character "0", the data doesn't fit in this encoding, so
5525 * fail. */
5526 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5527 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005528 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
5529 &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005530 if (bad)
5531 {
5532 ip->bw_conv_error = TRUE;
5533 return FAIL;
5534 }
5535 }
5536 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005537#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005538
Bram Moolenaar13505972019-01-24 15:04:48 +01005539#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005540 else if (flags & FIO_MACROMAN)
5541 {
5542 /*
5543 * Convert UTF-8 or latin1 to Apple MacRoman.
5544 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545 char_u *from;
5546 size_t fromlen;
5547
5548 if (ip->bw_restlen > 0)
5549 {
5550 /* Need to concatenate the remainder of the previous call and
5551 * the bytes of the current call. Use the end of the
5552 * conversion buffer for this. */
5553 fromlen = len + ip->bw_restlen;
5554 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5555 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5556 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5557 }
5558 else
5559 {
5560 from = buf;
5561 fromlen = len;
5562 }
5563
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005564 if (enc2macroman(from, fromlen,
5565 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5566 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005567 {
5568 ip->bw_conv_error = TRUE;
5569 return FAIL;
5570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005572 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005573#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574
Bram Moolenaar13505972019-01-24 15:04:48 +01005575#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576 if (ip->bw_iconv_fd != (iconv_t)-1)
5577 {
5578 const char *from;
5579 size_t fromlen;
5580 char *to;
5581 size_t tolen;
5582
5583 /* Convert with iconv(). */
5584 if (ip->bw_restlen > 0)
5585 {
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005586 char *fp;
5587
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588 /* Need to concatenate the remainder of the previous call and
5589 * the bytes of the current call. Use the end of the
5590 * conversion buffer for this. */
5591 fromlen = len + ip->bw_restlen;
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005592 fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5593 mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
5594 mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
5595 from = fp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596 tolen = ip->bw_conv_buflen - fromlen;
5597 }
5598 else
5599 {
5600 from = (const char *)buf;
5601 fromlen = len;
5602 tolen = ip->bw_conv_buflen;
5603 }
5604 to = (char *)ip->bw_conv_buf;
5605
5606 if (ip->bw_first)
5607 {
5608 size_t save_len = tolen;
5609
5610 /* output the initial shift state sequence */
5611 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5612
5613 /* There is a bug in iconv() on Linux (which appears to be
5614 * wide-spread) which sets "to" to NULL and messes up "tolen".
5615 */
5616 if (to == NULL)
5617 {
5618 to = (char *)ip->bw_conv_buf;
5619 tolen = save_len;
5620 }
5621 ip->bw_first = FALSE;
5622 }
5623
5624 /*
5625 * If iconv() has an error or there is not enough room, fail.
5626 */
5627 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5628 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5629 || fromlen > CONV_RESTLEN)
5630 {
5631 ip->bw_conv_error = TRUE;
5632 return FAIL;
5633 }
5634
5635 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5636 if (fromlen > 0)
5637 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5638 ip->bw_restlen = (int)fromlen;
5639
5640 buf = ip->bw_conv_buf;
5641 len = (int)((char_u *)to - ip->bw_conv_buf);
5642 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005643#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645
Bram Moolenaare6bf6552017-06-27 22:11:51 +02005646 if (ip->bw_fd < 0)
5647 /* Only checking conversion, which is OK if we get here. */
5648 return OK;
5649
Bram Moolenaar071d4272004-06-13 20:20:40 +00005650#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005651 if (flags & FIO_ENCRYPTED)
5652 {
5653 /* Encrypt the data. Do it in-place if possible, otherwise use an
5654 * allocated buffer. */
Bram Moolenaar987411d2019-01-18 22:48:34 +01005655# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005656 if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
5657 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01005658# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005659 crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
Bram Moolenaar987411d2019-01-18 22:48:34 +01005660# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005661 }
5662 else
5663 {
5664 char_u *outbuf;
5665
5666 len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
5667 if (len == 0)
5668 return OK; /* Crypt layer is buffering, will flush later. */
5669 wlen = write_eintr(ip->bw_fd, outbuf, len);
5670 vim_free(outbuf);
5671 return (wlen < len) ? FAIL : OK;
5672 }
Bram Moolenaar987411d2019-01-18 22:48:34 +01005673# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005674 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005675#endif
5676
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005677 wlen = write_eintr(ip->bw_fd, buf, len);
5678 return (wlen < len) ? FAIL : OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005679}
5680
Bram Moolenaar071d4272004-06-13 20:20:40 +00005681/*
5682 * Convert a Unicode character to bytes.
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005683 * Return TRUE for an error, FALSE when it's OK.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684 */
5685 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005686ucs2bytes(
5687 unsigned c, /* in: character */
5688 char_u **pp, /* in/out: pointer to result */
5689 int flags) /* FIO_ flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005690{
5691 char_u *p = *pp;
5692 int error = FALSE;
5693 int cc;
5694
5695
5696 if (flags & FIO_UCS4)
5697 {
5698 if (flags & FIO_ENDIAN_L)
5699 {
5700 *p++ = c;
5701 *p++ = (c >> 8);
5702 *p++ = (c >> 16);
5703 *p++ = (c >> 24);
5704 }
5705 else
5706 {
5707 *p++ = (c >> 24);
5708 *p++ = (c >> 16);
5709 *p++ = (c >> 8);
5710 *p++ = c;
5711 }
5712 }
5713 else if (flags & (FIO_UCS2 | FIO_UTF16))
5714 {
5715 if (c >= 0x10000)
5716 {
5717 if (flags & FIO_UTF16)
5718 {
5719 /* Make two words, ten bits of the character in each. First
5720 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5721 c -= 0x10000;
5722 if (c >= 0x100000)
5723 error = TRUE;
5724 cc = ((c >> 10) & 0x3ff) + 0xd800;
5725 if (flags & FIO_ENDIAN_L)
5726 {
5727 *p++ = cc;
5728 *p++ = ((unsigned)cc >> 8);
5729 }
5730 else
5731 {
5732 *p++ = ((unsigned)cc >> 8);
5733 *p++ = cc;
5734 }
5735 c = (c & 0x3ff) + 0xdc00;
5736 }
5737 else
5738 error = TRUE;
5739 }
5740 if (flags & FIO_ENDIAN_L)
5741 {
5742 *p++ = c;
5743 *p++ = (c >> 8);
5744 }
5745 else
5746 {
5747 *p++ = (c >> 8);
5748 *p++ = c;
5749 }
5750 }
5751 else /* Latin1 */
5752 {
5753 if (c >= 0x100)
5754 {
5755 error = TRUE;
5756 *p++ = 0xBF;
5757 }
5758 else
5759 *p++ = c;
5760 }
5761
5762 *pp = p;
5763 return error;
5764}
5765
5766/*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005767 * Return TRUE if file encoding "fenc" requires conversion from or to
5768 * 'encoding'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005769 */
5770 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005771need_conversion(char_u *fenc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005772{
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005773 int same_encoding;
5774 int enc_flags;
5775 int fenc_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005777 if (*fenc == NUL || STRCMP(p_enc, fenc) == 0)
Bram Moolenaar442b4222010-05-24 21:34:22 +02005778 {
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005779 same_encoding = TRUE;
Bram Moolenaar442b4222010-05-24 21:34:22 +02005780 fenc_flags = 0;
5781 }
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005782 else
5783 {
5784 /* Ignore difference between "ansi" and "latin1", "ucs-4" and
5785 * "ucs-4be", etc. */
5786 enc_flags = get_fio_flags(p_enc);
5787 fenc_flags = get_fio_flags(fenc);
5788 same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
5789 }
5790 if (same_encoding)
5791 {
5792 /* Specified encoding matches with 'encoding'. This requires
5793 * conversion when 'encoding' is Unicode but not UTF-8. */
5794 return enc_unicode != 0;
5795 }
5796
5797 /* Encodings differ. However, conversion is not needed when 'enc' is any
5798 * Unicode encoding and the file is UTF-8. */
5799 return !(enc_utf8 && fenc_flags == FIO_UTF8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005800}
5801
5802/*
5803 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5804 * internal conversion.
5805 * if "ptr" is an empty string, use 'encoding'.
5806 */
5807 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005808get_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809{
5810 int prop;
5811
5812 if (*ptr == NUL)
5813 ptr = p_enc;
5814
5815 prop = enc_canon_props(ptr);
5816 if (prop & ENC_UNICODE)
5817 {
5818 if (prop & ENC_2BYTE)
5819 {
5820 if (prop & ENC_ENDIAN_L)
5821 return FIO_UCS2 | FIO_ENDIAN_L;
5822 return FIO_UCS2;
5823 }
5824 if (prop & ENC_4BYTE)
5825 {
5826 if (prop & ENC_ENDIAN_L)
5827 return FIO_UCS4 | FIO_ENDIAN_L;
5828 return FIO_UCS4;
5829 }
5830 if (prop & ENC_2WORD)
5831 {
5832 if (prop & ENC_ENDIAN_L)
5833 return FIO_UTF16 | FIO_ENDIAN_L;
5834 return FIO_UTF16;
5835 }
5836 return FIO_UTF8;
5837 }
5838 if (prop & ENC_LATIN1)
5839 return FIO_LATIN1;
5840 /* must be ENC_DBCS, requires iconv() */
5841 return 0;
5842}
5843
Bram Moolenaar4f974752019-02-17 17:44:42 +01005844#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845/*
5846 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5847 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5848 * Used for conversion between 'encoding' and 'fileencoding'.
5849 */
5850 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005851get_win_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852{
5853 int cp;
5854
5855 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5856 if (!enc_utf8 && enc_codepage <= 0)
5857 return 0;
5858
5859 cp = encname2codepage(ptr);
5860 if (cp == 0)
5861 {
5862# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5863 if (STRCMP(ptr, "utf-8") == 0)
5864 cp = CP_UTF8;
5865 else
5866# endif
5867 return 0;
5868 }
5869 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5870}
5871#endif
5872
Bram Moolenaard0573012017-10-28 21:11:06 +02005873#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874/*
5875 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5876 * needed for the internal conversion to/from utf-8 or latin1.
5877 */
5878 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005879get_mac_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880{
5881 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5882 && (enc_canon_props(ptr) & ENC_MACROMAN))
5883 return FIO_MACROMAN;
5884 return 0;
5885}
5886#endif
5887
5888/*
5889 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5890 * "size" must be at least 2.
5891 * Return the name of the encoding and set "*lenp" to the length.
5892 * Returns NULL when no BOM found.
5893 */
5894 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005895check_for_bom(
5896 char_u *p,
5897 long size,
5898 int *lenp,
5899 int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005900{
5901 char *name = NULL;
5902 int len = 2;
5903
5904 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
Bram Moolenaaree0f5a62008-07-24 20:09:16 +00005905 && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005906 {
5907 name = "utf-8"; /* EF BB BF */
5908 len = 3;
5909 }
5910 else if (p[0] == 0xff && p[1] == 0xfe)
5911 {
5912 if (size >= 4 && p[2] == 0 && p[3] == 0
5913 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5914 {
5915 name = "ucs-4le"; /* FF FE 00 00 */
5916 len = 4;
5917 }
Bram Moolenaar223a1892008-11-11 20:57:11 +00005918 else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 name = "ucs-2le"; /* FF FE */
Bram Moolenaar223a1892008-11-11 20:57:11 +00005920 else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
5921 /* utf-16le is preferred, it also works for ucs-2le text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922 name = "utf-16le"; /* FF FE */
5923 }
5924 else if (p[0] == 0xfe && p[1] == 0xff
5925 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5926 {
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005927 /* Default to utf-16, it works also for ucs-2 text. */
5928 if (flags == FIO_UCS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 name = "ucs-2"; /* FE FF */
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005930 else
5931 name = "utf-16"; /* FE FF */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932 }
5933 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5934 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5935 {
5936 name = "ucs-4"; /* 00 00 FE FF */
5937 len = 4;
5938 }
5939
5940 *lenp = len;
5941 return (char_u *)name;
5942}
5943
5944/*
5945 * Generate a BOM in "buf[4]" for encoding "name".
5946 * Return the length of the BOM (zero when no BOM).
5947 */
5948 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005949make_bom(char_u *buf, char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950{
5951 int flags;
5952 char_u *p;
5953
5954 flags = get_fio_flags(name);
5955
5956 /* Can't put a BOM in a non-Unicode file. */
5957 if (flags == FIO_LATIN1 || flags == 0)
5958 return 0;
5959
5960 if (flags == FIO_UTF8) /* UTF-8 */
5961 {
5962 buf[0] = 0xef;
5963 buf[1] = 0xbb;
5964 buf[2] = 0xbf;
5965 return 3;
5966 }
5967 p = buf;
5968 (void)ucs2bytes(0xfeff, &p, flags);
5969 return (int)(p - buf);
5970}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005971
5972/*
5973 * Try to find a shortname by comparing the fullname with the current
5974 * directory.
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005975 * Returns "full_path" or pointer into "full_path" if shortened.
5976 */
5977 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005978shorten_fname1(char_u *full_path)
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005979{
Bram Moolenaard9462e32011-04-11 21:35:11 +02005980 char_u *dirname;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005981 char_u *p = full_path;
5982
Bram Moolenaard9462e32011-04-11 21:35:11 +02005983 dirname = alloc(MAXPATHL);
5984 if (dirname == NULL)
5985 return full_path;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005986 if (mch_dirname(dirname, MAXPATHL) == OK)
5987 {
5988 p = shorten_fname(full_path, dirname);
5989 if (p == NULL || *p == NUL)
5990 p = full_path;
5991 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02005992 vim_free(dirname);
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005993 return p;
5994}
5995
5996/*
5997 * Try to find a shortname by comparing the fullname with the current
5998 * directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005999 * Returns NULL if not shorter name possible, pointer into "full_path"
6000 * otherwise.
6001 */
6002 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006003shorten_fname(char_u *full_path, char_u *dir_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006004{
6005 int len;
6006 char_u *p;
6007
6008 if (full_path == NULL)
6009 return NULL;
6010 len = (int)STRLEN(dir_name);
6011 if (fnamencmp(dir_name, full_path, len) == 0)
6012 {
6013 p = full_path + len;
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006014#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015 /*
Bram Moolenaar4f974752019-02-17 17:44:42 +01006016 * MS-Windows: when a file is in the root directory, dir_name will end
6017 * in a slash, since C: by itself does not define a specific dir. In
6018 * this case p may already be correct. <negri>
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019 */
6020 if (!((len > 2) && (*(p - 2) == ':')))
6021#endif
6022 {
6023 if (vim_ispathsep(*p))
6024 ++p;
6025#ifndef VMS /* the path separator is always part of the path */
6026 else
6027 p = NULL;
6028#endif
6029 }
6030 }
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006031#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 /*
6033 * When using a file in the current drive, remove the drive name:
6034 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
6035 * a floppy from "A:\dir" to "B:\dir".
6036 */
6037 else if (len > 3
6038 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
6039 && full_path[1] == ':'
6040 && vim_ispathsep(full_path[2]))
6041 p = full_path + 2;
6042#endif
6043 else
6044 p = NULL;
6045 return p;
6046}
6047
6048/*
Bram Moolenaara796d462018-05-01 14:30:36 +02006049 * Shorten filename of a buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050 * When "force" is TRUE: Use full path from now on for files currently being
6051 * edited, both for file name and swap file name. Try to shorten the file
6052 * names a bit, if safe to do so.
6053 * When "force" is FALSE: Only try to shorten absolute file names.
6054 * For buffers that have buftype "nofile" or "scratch": never change the file
6055 * name.
6056 */
6057 void
Bram Moolenaara796d462018-05-01 14:30:36 +02006058shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
6059{
6060 char_u *p;
6061
6062 if (buf->b_fname != NULL
6063#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02006064 && !bt_nofilename(buf)
Bram Moolenaara796d462018-05-01 14:30:36 +02006065#endif
6066 && !path_with_url(buf->b_fname)
6067 && (force
6068 || buf->b_sfname == NULL
6069 || mch_isFullName(buf->b_sfname)))
6070 {
Bram Moolenaar3d6014f2018-10-11 19:27:47 +02006071 if (buf->b_sfname != buf->b_ffname)
6072 VIM_CLEAR(buf->b_sfname);
Bram Moolenaara796d462018-05-01 14:30:36 +02006073 p = shorten_fname(buf->b_ffname, dirname);
6074 if (p != NULL)
6075 {
6076 buf->b_sfname = vim_strsave(p);
6077 buf->b_fname = buf->b_sfname;
6078 }
6079 if (p == NULL || buf->b_fname == NULL)
6080 buf->b_fname = buf->b_ffname;
6081 }
6082}
6083
6084/*
6085 * Shorten filenames for all buffers.
6086 */
6087 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006088shorten_fnames(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006089{
6090 char_u dirname[MAXPATHL];
6091 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092
6093 mch_dirname(dirname, MAXPATHL);
Bram Moolenaar29323592016-07-24 22:04:11 +02006094 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006095 {
Bram Moolenaara796d462018-05-01 14:30:36 +02006096 shorten_buf_fname(buf, dirname, force);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006097
6098 /* Always make the swap file name a full path, a "nofile" buffer may
6099 * also have a swap file. */
6100 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006103 redraw_tabline = TRUE;
Bram Moolenaar90f3e7a2019-08-01 22:40:44 +02006104#ifdef FEAT_TEXT_PROP
6105 popup_update_preview_title();
6106#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107}
6108
6109#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
6110 || defined(FEAT_GUI_MSWIN) \
6111 || defined(FEAT_GUI_MAC) \
6112 || defined(PROTO)
6113/*
6114 * Shorten all filenames in "fnames[count]" by current directory.
6115 */
6116 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006117shorten_filenames(char_u **fnames, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118{
6119 int i;
6120 char_u dirname[MAXPATHL];
6121 char_u *p;
6122
6123 if (fnames == NULL || count < 1)
6124 return;
6125 mch_dirname(dirname, sizeof(dirname));
6126 for (i = 0; i < count; ++i)
6127 {
6128 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
6129 {
6130 /* shorten_fname() returns pointer in given "fnames[i]". If free
6131 * "fnames[i]" first, "p" becomes invalid. So we need to copy
6132 * "p" first then free fnames[i]. */
6133 p = vim_strsave(p);
6134 vim_free(fnames[i]);
6135 fnames[i] = p;
6136 }
6137 }
6138}
6139#endif
6140
6141/*
Bram Moolenaarb782ba42018-08-07 21:39:28 +02006142 * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
Bram Moolenaar071d4272004-06-13 20:20:40 +00006143 * fo_o_h.ext for MSDOS or when shortname option set.
6144 *
6145 * Assumed that fname is a valid name found in the filesystem we assure that
6146 * the return value is a different name and ends in 'ext'.
6147 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
6148 * characters otherwise.
6149 * Space for the returned name is allocated, must be freed later.
6150 * Returns NULL when out of memory.
6151 */
6152 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006153modname(
6154 char_u *fname,
6155 char_u *ext,
6156 int prepend_dot) /* may prepend a '.' to file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006157{
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006158 return buf_modname((curbuf->b_p_sn || curbuf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00006159 fname, ext, prepend_dot);
6160}
6161
6162 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006163buf_modname(
6164 int shortname, /* use 8.3 file name */
6165 char_u *fname,
6166 char_u *ext,
6167 int prepend_dot) /* may prepend a '.' to file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006168{
6169 char_u *retval;
6170 char_u *s;
6171 char_u *e;
6172 char_u *ptr;
6173 int fnamelen, extlen;
6174
6175 extlen = (int)STRLEN(ext);
6176
6177 /*
6178 * If there is no file name we must get the name of the current directory
6179 * (we need the full path in case :cd is used).
6180 */
6181 if (fname == NULL || *fname == NUL)
6182 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02006183 retval = alloc(MAXPATHL + extlen + 3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184 if (retval == NULL)
6185 return NULL;
6186 if (mch_dirname(retval, MAXPATHL) == FAIL ||
6187 (fnamelen = (int)STRLEN(retval)) == 0)
6188 {
6189 vim_free(retval);
6190 return NULL;
6191 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006192 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 {
6194 retval[fnamelen++] = PATHSEP;
6195 retval[fnamelen] = NUL;
6196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006197 prepend_dot = FALSE; /* nothing to prepend a dot to */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198 }
6199 else
6200 {
6201 fnamelen = (int)STRLEN(fname);
Bram Moolenaar964b3742019-05-24 18:54:09 +02006202 retval = alloc(fnamelen + extlen + 3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203 if (retval == NULL)
6204 return NULL;
6205 STRCPY(retval, fname);
6206#ifdef VMS
6207 vms_remove_version(retval); /* we do not need versions here */
6208#endif
6209 }
6210
6211 /*
6212 * search backwards until we hit a '/', '\' or ':' replacing all '.'
6213 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
6214 * Then truncate what is after the '/', '\' or ':' to 8 characters for
6215 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
6216 */
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006217 for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006218 {
Bram Moolenaar00f148d2019-02-12 22:37:27 +01006219 if (*ext == '.' && shortname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006220 if (*ptr == '.') /* replace '.' by '_' */
6221 *ptr = '_';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006222 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006223 {
6224 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006226 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006228
6229 /* the file name has at most BASENAMELEN characters. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
6231 ptr[BASENAMELEN] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006232
6233 s = ptr + STRLEN(ptr);
6234
6235 /*
6236 * For 8.3 file names we may have to reduce the length.
6237 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238 if (shortname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239 {
6240 /*
6241 * If there is no file name, or the file name ends in '/', and the
6242 * extension starts with '.', put a '_' before the dot, because just
6243 * ".ext" is invalid.
6244 */
6245 if (fname == NULL || *fname == NUL
6246 || vim_ispathsep(fname[STRLEN(fname) - 1]))
6247 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248 if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 *s++ = '_';
6250 }
6251 /*
6252 * If the extension starts with '.', truncate the base name at 8
6253 * characters
6254 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006255 else if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256 {
Bram Moolenaar78a15312009-05-15 19:33:18 +00006257 if ((size_t)(s - ptr) > (size_t)8)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258 {
6259 s = ptr + 8;
6260 *s = '\0';
6261 }
6262 }
6263 /*
6264 * If the extension doesn't start with '.', and the file name
6265 * doesn't have an extension yet, append a '.'
6266 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006267 else if ((e = vim_strchr(ptr, '.')) == NULL)
6268 *s++ = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006269 /*
6270 * If the extension doesn't start with '.', and there already is an
Bram Moolenaar7263a772007-05-10 17:35:54 +00006271 * extension, it may need to be truncated
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272 */
6273 else if ((int)STRLEN(e) + extlen > 4)
6274 s = e + 4 - extlen;
6275 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006276#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277 /*
6278 * If there is no file name, and the extension starts with '.', put a
6279 * '_' before the dot, because just ".ext" may be invalid if it's on a
6280 * FAT partition, and on HPFS it doesn't matter.
6281 */
6282 else if ((fname == NULL || *fname == NUL) && *ext == '.')
6283 *s++ = '_';
6284#endif
6285
6286 /*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006287 * Append the extension.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006288 * ext can start with '.' and cannot exceed 3 more characters.
6289 */
6290 STRCPY(s, ext);
6291
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 /*
6293 * Prepend the dot.
6294 */
Bram Moolenaar00f148d2019-02-12 22:37:27 +01006295 if (prepend_dot && !shortname && *(e = gettail(retval)) != '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006297 STRMOVE(e + 1, e);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298 *e = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300
6301 /*
6302 * Check that, after appending the extension, the file name is really
6303 * different.
6304 */
6305 if (fname != NULL && STRCMP(fname, retval) == 0)
6306 {
6307 /* we search for a character that can be replaced by '_' */
6308 while (--s >= ptr)
6309 {
6310 if (*s != '_')
6311 {
6312 *s = '_';
6313 break;
6314 }
6315 }
6316 if (s < ptr) /* fname was "________.<ext>", how tricky! */
6317 *ptr = 'v';
6318 }
6319 return retval;
6320}
6321
6322/*
6323 * Like fgets(), but if the file line is too long, it is truncated and the
6324 * rest of the line is thrown away. Returns TRUE for end-of-file.
Bram Moolenaar7e1652c2017-12-16 18:27:02 +01006325 * If the line is truncated then buf[size - 2] will not be NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006326 */
6327 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006328vim_fgets(char_u *buf, int size, FILE *fp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329{
6330 char *eof;
6331#define FGETS_SIZE 200
6332 char tbuf[FGETS_SIZE];
6333
6334 buf[size - 2] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335 eof = fgets((char *)buf, size, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006336 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
6337 {
6338 buf[size - 1] = NUL; /* Truncate the line */
6339
6340 /* Now throw away the rest of the line: */
6341 do
6342 {
6343 tbuf[FGETS_SIZE - 2] = NUL;
Bram Moolenaar42335f52018-09-13 15:33:43 +02006344 vim_ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006345 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
6346 }
6347 return (eof == NULL);
6348}
6349
Bram Moolenaar071d4272004-06-13 20:20:40 +00006350/*
6351 * rename() only works if both files are on the same file system, this
6352 * function will (attempts to?) copy the file across if rename fails -- webb
6353 * Return -1 for failure, 0 for success.
6354 */
6355 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006356vim_rename(char_u *from, char_u *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006357{
6358 int fd_in;
6359 int fd_out;
6360 int n;
6361 char *errmsg = NULL;
6362 char *buffer;
6363#ifdef AMIGA
6364 BPTR flock;
6365#endif
Bram Moolenaar8767f522016-07-01 17:17:39 +02006366 stat_T st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006367 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006368#ifdef HAVE_ACL
6369 vim_acl_T acl; /* ACL from original file */
6370#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006371 int use_tmp_file = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006372
6373 /*
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006374 * When the names are identical, there is nothing to do. When they refer
6375 * to the same file (ignoring case and slash/backslash differences) but
6376 * the file name differs we need to go through a temp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006377 */
6378 if (fnamecmp(from, to) == 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006379 {
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01006380 if (p_fic && STRCMP(gettail(from), gettail(to)) != 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006381 use_tmp_file = TRUE;
6382 else
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006383 return 0;
6384 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006385
6386 /*
6387 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
6388 */
6389 if (mch_stat((char *)from, &st) < 0)
6390 return -1;
6391
Bram Moolenaar3576da72008-12-30 15:15:57 +00006392#ifdef UNIX
6393 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02006394 stat_T st_to;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006395
6396 /* It's possible for the source and destination to be the same file.
6397 * This happens when "from" and "to" differ in case and are on a FAT32
6398 * filesystem. In that case go through a temp file name. */
6399 if (mch_stat((char *)to, &st_to) >= 0
6400 && st.st_dev == st_to.st_dev
6401 && st.st_ino == st_to.st_ino)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006402 use_tmp_file = TRUE;
6403 }
6404#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006405#ifdef MSWIN
Bram Moolenaar1c32dff2011-05-05 16:41:24 +02006406 {
6407 BY_HANDLE_FILE_INFORMATION info1, info2;
6408
6409 /* It's possible for the source and destination to be the same file.
6410 * In that case go through a temp file name. This makes rename("foo",
6411 * "./foo") a no-op (in a complicated way). */
6412 if (win32_fileinfo(from, &info1) == FILEINFO_OK
6413 && win32_fileinfo(to, &info2) == FILEINFO_OK
6414 && info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
6415 && info1.nFileIndexHigh == info2.nFileIndexHigh
6416 && info1.nFileIndexLow == info2.nFileIndexLow)
6417 use_tmp_file = TRUE;
6418 }
6419#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006420
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006421 if (use_tmp_file)
6422 {
6423 char tempname[MAXPATHL + 1];
6424
6425 /*
6426 * Find a name that doesn't exist and is in the same directory.
6427 * Rename "from" to "tempname" and then rename "tempname" to "to".
6428 */
6429 if (STRLEN(from) >= MAXPATHL - 5)
6430 return -1;
6431 STRCPY(tempname, from);
6432 for (n = 123; n < 99999; ++n)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006433 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006434 sprintf((char *)gettail((char_u *)tempname), "%d", n);
6435 if (mch_stat(tempname, &st) < 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006436 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006437 if (mch_rename((char *)from, tempname) == 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006438 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006439 if (mch_rename(tempname, (char *)to) == 0)
6440 return 0;
6441 /* Strange, the second step failed. Try moving the
6442 * file back and return failure. */
6443 mch_rename(tempname, (char *)from);
Bram Moolenaar3576da72008-12-30 15:15:57 +00006444 return -1;
6445 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006446 /* If it fails for one temp name it will most likely fail
6447 * for any temp name, give up. */
6448 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006449 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006450 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006451 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006452 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006453
Bram Moolenaar071d4272004-06-13 20:20:40 +00006454 /*
6455 * Delete the "to" file, this is required on some systems to make the
6456 * mch_rename() work, on other systems it makes sure that we don't have
6457 * two files when the mch_rename() fails.
6458 */
6459
6460#ifdef AMIGA
6461 /*
6462 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
6463 * that the name of the "to" file is the same as the "from" file, even
Bram Moolenaar7263a772007-05-10 17:35:54 +00006464 * though the names are different. To avoid the chance of accidentally
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465 * deleting the "from" file (horror!) we lock it during the remove.
6466 *
6467 * When used for making a backup before writing the file: This should not
6468 * happen with ":w", because startscript() should detect this problem and
6469 * set buf->b_shortname, causing modname() to return a correct ".bak" file
6470 * name. This problem does exist with ":w filename", but then the
6471 * original file will be somewhere else so the backup isn't really
6472 * important. If autoscripting is off the rename may fail.
6473 */
6474 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
6475#endif
6476 mch_remove(to);
6477#ifdef AMIGA
6478 if (flock)
6479 UnLock(flock);
6480#endif
6481
6482 /*
6483 * First try a normal rename, return if it works.
6484 */
6485 if (mch_rename((char *)from, (char *)to) == 0)
6486 return 0;
6487
6488 /*
6489 * Rename() failed, try copying the file.
6490 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006491 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006492#ifdef HAVE_ACL
6493 /* For systems that support ACL: get the ACL from the original file. */
6494 acl = mch_get_acl(from);
6495#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006496 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6497 if (fd_in == -1)
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006498 {
6499#ifdef HAVE_ACL
6500 mch_free_acl(acl);
6501#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502 return -1;
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006503 }
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006504
6505 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006506 fd_out = mch_open((char *)to,
6507 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006508 if (fd_out == -1)
6509 {
6510 close(fd_in);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006511#ifdef HAVE_ACL
6512 mch_free_acl(acl);
6513#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514 return -1;
6515 }
6516
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006517 buffer = alloc(BUFSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006518 if (buffer == NULL)
6519 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006520 close(fd_out);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006521 close(fd_in);
6522#ifdef HAVE_ACL
6523 mch_free_acl(acl);
6524#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525 return -1;
6526 }
6527
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01006528 while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0)
6529 if (write_eintr(fd_out, buffer, n) != n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006530 {
6531 errmsg = _("E208: Error writing to \"%s\"");
6532 break;
6533 }
6534
6535 vim_free(buffer);
6536 close(fd_in);
6537 if (close(fd_out) < 0)
6538 errmsg = _("E209: Error closing \"%s\"");
6539 if (n < 0)
6540 {
6541 errmsg = _("E210: Error reading \"%s\"");
6542 to = from;
6543 }
Bram Moolenaar7263a772007-05-10 17:35:54 +00006544#ifndef UNIX /* for Unix mch_open() already set the permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006545 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006546#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006547#ifdef HAVE_ACL
6548 mch_set_acl(to, acl);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006549 mch_free_acl(acl);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006550#endif
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02006551#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaare8747442013-11-12 18:09:29 +01006552 mch_copy_sec(from, to);
Bram Moolenaar0671de32013-11-12 05:12:03 +01006553#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006554 if (errmsg != NULL)
6555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006556 semsg(errmsg, to);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006557 return -1;
6558 }
6559 mch_remove(from);
6560 return 0;
6561}
6562
6563static int already_warned = FALSE;
6564
6565/*
6566 * Check if any not hidden buffer has been changed.
6567 * Postpone the check if there are characters in the stuff buffer, a global
6568 * command is being executed, a mapping is being executed or an autocommand is
6569 * busy.
6570 * Returns TRUE if some message was written (screen should be redrawn and
6571 * cursor positioned).
6572 */
6573 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006574check_timestamps(
6575 int focus) /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576{
6577 buf_T *buf;
6578 int didit = 0;
6579 int n;
6580
6581 /* Don't check timestamps while system() or another low-level function may
6582 * cause us to lose and gain focus. */
6583 if (no_check_timestamps > 0)
6584 return FALSE;
6585
6586 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6587 * event and we would keep on checking if the file is steadily growing.
6588 * Do check again after typing something. */
6589 if (focus && did_check_timestamps)
6590 {
6591 need_check_timestamps = TRUE;
6592 return FALSE;
6593 }
6594
6595 if (!stuff_empty() || global_busy || !typebuf_typed()
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006596 || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006597 need_check_timestamps = TRUE; /* check later */
6598 else
6599 {
6600 ++no_wait_return;
6601 did_check_timestamps = TRUE;
6602 already_warned = FALSE;
Bram Moolenaar29323592016-07-24 22:04:11 +02006603 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006604 {
6605 /* Only check buffers in a window. */
6606 if (buf->b_nwindows > 0)
6607 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006608 bufref_T bufref;
6609
6610 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006611 n = buf_check_timestamp(buf, focus);
6612 if (didit < n)
6613 didit = n;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006614 if (n > 0 && !bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006615 {
6616 /* Autocommands have removed the buffer, start at the
6617 * first one again. */
6618 buf = firstbuf;
6619 continue;
6620 }
6621 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006622 }
6623 --no_wait_return;
6624 need_check_timestamps = FALSE;
6625 if (need_wait_return && didit == 2)
6626 {
6627 /* make sure msg isn't overwritten */
Bram Moolenaar32526b32019-01-19 17:43:09 +01006628 msg_puts("\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006629 out_flush();
6630 }
6631 }
6632 return didit;
6633}
6634
6635/*
6636 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6637 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6638 * empty.
6639 */
6640 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006641move_lines(buf_T *frombuf, buf_T *tobuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006642{
6643 buf_T *tbuf = curbuf;
6644 int retval = OK;
6645 linenr_T lnum;
6646 char_u *p;
6647
6648 /* Copy the lines in "frombuf" to "tobuf". */
6649 curbuf = tobuf;
6650 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6651 {
6652 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6653 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6654 {
6655 vim_free(p);
6656 retval = FAIL;
6657 break;
6658 }
6659 vim_free(p);
6660 }
6661
6662 /* Delete all the lines in "frombuf". */
6663 if (retval != FAIL)
6664 {
6665 curbuf = frombuf;
Bram Moolenaar9460b9d2007-01-09 14:37:01 +00006666 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
6667 if (ml_delete(lnum, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006668 {
6669 /* Oops! We could try putting back the saved lines, but that
6670 * might fail again... */
6671 retval = FAIL;
6672 break;
6673 }
6674 }
6675
6676 curbuf = tbuf;
6677 return retval;
6678}
6679
6680/*
6681 * Check if buffer "buf" has been changed.
6682 * Also check if the file for a new buffer unexpectedly appeared.
6683 * return 1 if a changed buffer was found.
6684 * return 2 if a message has been displayed.
6685 * return 0 otherwise.
6686 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006687 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006688buf_check_timestamp(
6689 buf_T *buf,
6690 int focus UNUSED) /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006691{
Bram Moolenaar8767f522016-07-01 17:17:39 +02006692 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006693 int stat_res;
6694 int retval = 0;
6695 char_u *path;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006696 char *tbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006697 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006698 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006699 int helpmesg = FALSE;
6700 int reload = FALSE;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006701 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006702#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6703 int can_reload = FALSE;
6704#endif
Bram Moolenaar8767f522016-07-01 17:17:39 +02006705 off_T orig_size = buf->b_orig_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006706 int orig_mode = buf->b_orig_mode;
6707#ifdef FEAT_GUI
6708 int save_mouse_correct = need_mouse_correct;
6709#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006710 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006711 int n;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006712#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006713 char_u *s;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006714#endif
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006715 bufref_T bufref;
6716
6717 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006718
6719 /* If there is no file name, the buffer is not loaded, 'buftype' is
6720 * set, we are in the middle of a save or being called recursively: ignore
6721 * this buffer. */
6722 if (buf->b_ffname == NULL
6723 || buf->b_ml.ml_mfp == NULL
Bram Moolenaar91335e52018-08-01 17:53:12 +02006724 || !bt_normal(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006725 || buf->b_saving
Bram Moolenaar071d4272004-06-13 20:20:40 +00006726 || busy
Bram Moolenaar009b2592004-10-24 19:18:58 +00006727#ifdef FEAT_NETBEANS_INTG
6728 || isNetbeansBuffer(buf)
6729#endif
Bram Moolenaar8cad9302017-08-12 14:32:32 +02006730#ifdef FEAT_TERMINAL
6731 || buf->b_term != NULL
6732#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006733 )
6734 return 0;
6735
6736 if ( !(buf->b_flags & BF_NOTEDITED)
6737 && buf->b_mtime != 0
6738 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6739 || time_differs((long)st.st_mtime, buf->b_mtime)
Bram Moolenaara7611f62014-05-02 15:46:14 +02006740 || st.st_size != buf->b_orig_size
Bram Moolenaar071d4272004-06-13 20:20:40 +00006741#ifdef HAVE_ST_MODE
6742 || (int)st.st_mode != buf->b_orig_mode
6743#else
6744 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6745#endif
6746 ))
6747 {
Bram Moolenaar674e2bd2019-07-31 20:21:01 +02006748 long prev_b_mtime = buf->b_mtime;
6749
Bram Moolenaar071d4272004-06-13 20:20:40 +00006750 retval = 1;
6751
Bram Moolenaar386bc822018-07-07 18:34:12 +02006752 // set b_mtime to stop further warnings (e.g., when executing
6753 // FileChangedShell autocmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754 if (stat_res < 0)
6755 {
Bram Moolenaar8239c622019-05-24 16:46:01 +02006756 // Check the file again later to see if it re-appears.
6757 buf->b_mtime = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006758 buf->b_orig_size = 0;
6759 buf->b_orig_mode = 0;
6760 }
6761 else
6762 buf_store_time(buf, &st, buf->b_ffname);
6763
6764 /* Don't do anything for a directory. Might contain the file
6765 * explorer. */
6766 if (mch_isdir(buf->b_fname))
6767 ;
6768
6769 /*
6770 * If 'autoread' is set, the buffer has no changes and the file still
6771 * exists, reload the buffer. Use the buffer-local option value if it
6772 * was set, the global option value otherwise.
6773 */
6774 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6775 && !bufIsChanged(buf) && stat_res >= 0)
6776 reload = TRUE;
6777 else
6778 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006779 if (stat_res < 0)
6780 reason = "deleted";
6781 else if (bufIsChanged(buf))
6782 reason = "conflict";
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01006783 /*
6784 * Check if the file contents really changed to avoid giving a
6785 * warning when only the timestamp was set (e.g., checked out of
6786 * CVS). Always warn when the buffer was changed.
6787 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006788 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6789 reason = "changed";
6790 else if (orig_mode != buf->b_orig_mode)
6791 reason = "mode";
6792 else
6793 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006794
6795 /*
6796 * Only give the warning if there are no FileChangedShell
6797 * autocommands.
6798 * Avoid being called recursively by setting "busy".
6799 */
6800 busy = TRUE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006801#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006802 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6803 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006804#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006805 ++allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006806 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6807 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006808 --allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 busy = FALSE;
6810 if (n)
6811 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006812 if (!bufref_valid(&bufref))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006813 emsg(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006814#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006815 s = get_vim_var_str(VV_FCS_CHOICE);
6816 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6817 reload = TRUE;
6818 else if (STRCMP(s, "ask") == 0)
6819 n = FALSE;
6820 else
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006821#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006822 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006824 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006825 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006826 if (*reason == 'd')
Bram Moolenaar674e2bd2019-07-31 20:21:01 +02006827 {
6828 // Only give the message once.
6829 if (prev_b_mtime != -1)
6830 mesg = _("E211: File \"%s\" no longer available");
6831 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006832 else
6833 {
6834 helpmesg = TRUE;
6835#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6836 can_reload = TRUE;
6837#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006838 if (reason[2] == 'n')
6839 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006840 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006841 mesg2 = _("See \":help W12\" for more info.");
6842 }
6843 else if (reason[1] == 'h')
6844 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006845 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006846 mesg2 = _("See \":help W11\" for more info.");
6847 }
6848 else if (*reason == 'm')
6849 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006850 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006851 mesg2 = _("See \":help W16\" for more info.");
6852 }
Bram Moolenaar85388b52009-06-24 09:58:32 +00006853 else
6854 /* Only timestamp changed, store it to avoid a warning
6855 * in check_mtime() later. */
6856 buf->b_mtime_read = buf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006857 }
6858 }
6859 }
6860
6861 }
6862 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6863 && vim_fexists(buf->b_ffname))
6864 {
6865 retval = 1;
6866 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6867 buf->b_flags |= BF_NEW_W;
6868#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6869 can_reload = TRUE;
6870#endif
6871 }
6872
6873 if (mesg != NULL)
6874 {
6875 path = home_replace_save(buf, buf->b_fname);
6876 if (path != NULL)
6877 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006878 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006879 mesg2 = "";
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006880 tbuf = alloc(STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006881 sprintf(tbuf, mesg, path);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006882#ifdef FEAT_EVAL
6883 /* Set warningmsg here, before the unimportant and output-specific
6884 * mesg2 has been appended. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006885 set_vim_var_string(VV_WARNINGMSG, (char_u *)tbuf, -1);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006886#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006887#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6888 if (can_reload)
6889 {
6890 if (*mesg2 != NUL)
6891 {
6892 STRCAT(tbuf, "\n");
6893 STRCAT(tbuf, mesg2);
6894 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006895 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"),
6896 (char_u *)tbuf,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01006897 (char_u *)_("&OK\n&Load File"), 1, NULL, TRUE) == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006898 reload = TRUE;
6899 }
6900 else
6901#endif
6902 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6903 {
6904 if (*mesg2 != NUL)
6905 {
6906 STRCAT(tbuf, "; ");
6907 STRCAT(tbuf, mesg2);
6908 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006909 emsg(tbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 retval = 2;
6911 }
6912 else
6913 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006914 if (!autocmd_busy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006915 {
6916 msg_start();
Bram Moolenaar32526b32019-01-19 17:43:09 +01006917 msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006918 if (*mesg2 != NUL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006919 msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006920 msg_clr_eos();
6921 (void)msg_end();
6922 if (emsg_silent == 0)
6923 {
6924 out_flush();
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006925#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 if (!focus)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006927#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 /* give the user some time to think about it */
6929 ui_delay(1000L, TRUE);
6930
6931 /* don't redraw and erase the message */
6932 redraw_cmdline = FALSE;
6933 }
6934 }
6935 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006936 }
6937
6938 vim_free(path);
6939 vim_free(tbuf);
6940 }
6941 }
6942
6943 if (reload)
Bram Moolenaar465748e2012-08-29 18:50:54 +02006944 {
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006945 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006946 buf_reload(buf, orig_mode);
Bram Moolenaar465748e2012-08-29 18:50:54 +02006947#ifdef FEAT_PERSISTENT_UNDO
6948 if (buf->b_p_udf && buf->b_ffname != NULL)
6949 {
6950 char_u hash[UNDO_HASH_SIZE];
6951 buf_T *save_curbuf = curbuf;
6952
6953 /* Any existing undo file is unusable, write it now. */
6954 curbuf = buf;
6955 u_compute_hash(hash);
6956 u_write_undo(NULL, FALSE, buf, hash);
6957 curbuf = save_curbuf;
6958 }
6959#endif
6960 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006962 /* Trigger FileChangedShell when the file was changed in any way. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006963 if (bufref_valid(&bufref) && retval != 0)
Bram Moolenaar56718732006-03-15 22:53:57 +00006964 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6965 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006966#ifdef FEAT_GUI
6967 /* restore this in case an autocommand has set it; it would break
6968 * 'mousefocus' */
6969 need_mouse_correct = save_mouse_correct;
6970#endif
6971
6972 return retval;
6973}
6974
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006975/*
6976 * Reload a buffer that is already loaded.
6977 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006978 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6979 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006980 */
6981 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006982buf_reload(buf_T *buf, int orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006983{
6984 exarg_T ea;
6985 pos_T old_cursor;
6986 linenr_T old_topline;
6987 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006988 buf_T *savebuf;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006989 bufref_T bufref;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006990 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006991 aco_save_T aco;
Bram Moolenaar59f931e2010-07-24 20:27:03 +02006992 int flags = READ_NEW;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006993
6994 /* set curwin/curbuf for "buf" and save some things */
6995 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006996
6997 /* We only want to read the text from the file, not reset the syntax
6998 * highlighting, clear marks, diff status, etc. Force the fileformat
6999 * and encoding to be the same. */
7000 if (prep_exarg(&ea, buf) == OK)
7001 {
7002 old_cursor = curwin->w_cursor;
7003 old_topline = curwin->w_topline;
7004
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007005 if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007006 {
7007 /* Save all the text, so that the reload can be undone.
7008 * Sync first so that this is a separate undo-able action. */
7009 u_sync(FALSE);
7010 saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
7011 flags |= READ_KEEP_UNDO;
7012 }
7013
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007014 /*
7015 * To behave like when a new file is edited (matters for
7016 * BufReadPost autocommands) we first need to delete the current
7017 * buffer contents. But if reading the file fails we should keep
7018 * the old contents. Can't use memory only, the file might be
7019 * too big. Use a hidden buffer to move the buffer contents to.
7020 */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007021 if (BUFEMPTY() || saved == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007022 savebuf = NULL;
7023 else
7024 {
7025 /* Allocate a buffer without putting it in the buffer list. */
7026 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007027 set_bufref(&bufref, savebuf);
Bram Moolenaar8424a622006-04-19 21:23:36 +00007028 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007029 {
7030 /* Open the memline. */
7031 curbuf = savebuf;
7032 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00007033 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007034 curbuf = buf;
7035 curwin->w_buffer = buf;
7036 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00007037 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007038 || move_lines(buf, savebuf) == FAIL)
7039 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007040 semsg(_("E462: Could not prepare for reloading \"%s\""),
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007041 buf->b_fname);
7042 saved = FAIL;
7043 }
7044 }
7045
7046 if (saved == OK)
7047 {
7048 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007049 keep_filetype = TRUE; /* don't detect 'filetype' */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007050 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
7051 (linenr_T)0,
Bram Moolenaare13b9af2017-01-13 22:01:02 +01007052 (linenr_T)MAXLNUM, &ea, flags) != OK)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007053 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01007054#if defined(FEAT_EVAL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007055 if (!aborting())
7056#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007057 semsg(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007058 if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007059 {
7060 /* Put the text back from the save buffer. First
7061 * delete any lines that readfile() added. */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007062 while (!BUFEMPTY())
Bram Moolenaar8424a622006-04-19 21:23:36 +00007063 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007064 break;
7065 (void)move_lines(savebuf, buf);
7066 }
7067 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007068 else if (buf == curbuf) /* "buf" still valid */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007069 {
7070 /* Mark the buffer as unmodified and free undo info. */
Bram Moolenaarc024b462019-06-08 18:07:21 +02007071 unchanged(buf, TRUE, TRUE);
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007072 if ((flags & READ_KEEP_UNDO) == 0)
7073 {
7074 u_blockfree(buf);
7075 u_clearall(buf);
7076 }
7077 else
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007078 {
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007079 /* Mark all undo states as changed. */
7080 u_unchanged(curbuf);
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007081 }
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007082 }
7083 }
7084 vim_free(ea.cmd);
7085
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007086 if (savebuf != NULL && bufref_valid(&bufref))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007087 wipe_buffer(savebuf, FALSE);
7088
7089#ifdef FEAT_DIFF
7090 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00007091 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007092#endif
7093
7094 /* Restore the topline and cursor position and check it (lines may
7095 * have been removed). */
7096 if (old_topline > curbuf->b_ml.ml_line_count)
7097 curwin->w_topline = curbuf->b_ml.ml_line_count;
7098 else
7099 curwin->w_topline = old_topline;
7100 curwin->w_cursor = old_cursor;
7101 check_cursor();
7102 update_topline();
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007103 keep_filetype = FALSE;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007104#ifdef FEAT_FOLDING
7105 {
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007106 win_T *wp;
7107 tabpage_T *tp;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007108
7109 /* Update folds unless they are defined manually. */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007110 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007111 if (wp->w_buffer == curwin->w_buffer
7112 && !foldmethodIsManual(wp))
7113 foldUpdateAll(wp);
7114 }
7115#endif
7116 /* If the mode didn't change and 'readonly' was set, keep the old
7117 * value; the user probably used the ":view" command. But don't
7118 * reset it, might have had a read error. */
7119 if (orig_mode == curbuf->b_orig_mode)
7120 curbuf->b_p_ro |= old_ro;
Bram Moolenaar52f85b72013-01-30 14:13:56 +01007121
7122 /* Modelines must override settings done by autocommands. */
7123 do_modelines(0);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007124 }
7125
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007126 /* restore curwin/curbuf and a few other things */
7127 aucmd_restbuf(&aco);
7128 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007129}
7130
Bram Moolenaar071d4272004-06-13 20:20:40 +00007131 void
Bram Moolenaar8767f522016-07-01 17:17:39 +02007132buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007133{
7134 buf->b_mtime = (long)st->st_mtime;
Bram Moolenaar914703b2010-05-31 21:59:46 +02007135 buf->b_orig_size = st->st_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007136#ifdef HAVE_ST_MODE
7137 buf->b_orig_mode = (int)st->st_mode;
7138#else
7139 buf->b_orig_mode = mch_getperm(fname);
7140#endif
7141}
7142
7143/*
7144 * Adjust the line with missing eol, used for the next write.
7145 * Used for do_filter(), when the input lines for the filter are deleted.
7146 */
7147 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007148write_lnum_adjust(linenr_T offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007149{
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01007150 if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */
7151 curbuf->b_no_eol_lnum += offset;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152}
7153
Bram Moolenaarda440d22016-01-16 21:27:23 +01007154#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
7155/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007156 * Core part of "readdir()" function.
7157 * Retrieve the list of files/directories of "path" into "gap".
7158 * Return OK for success, FAIL for failure.
7159 */
7160 int
7161readdir_core(
7162 garray_T *gap,
7163 char_u *path,
7164 void *context,
7165 int (*checkitem)(void *context, char_u *name))
7166{
7167 int failed = FALSE;
7168#ifdef MSWIN
7169 char_u *buf, *p;
7170 int ok;
7171 HANDLE hFind = INVALID_HANDLE_VALUE;
7172 WIN32_FIND_DATAW wfb;
7173 WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
7174#endif
7175
7176 ga_init2(gap, (int)sizeof(char *), 20);
7177
7178#ifdef MSWIN
Bram Moolenaar51e14382019-05-25 20:21:28 +02007179 buf = alloc(MAXPATHL);
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007180 if (buf == NULL)
7181 return FAIL;
7182 STRNCPY(buf, path, MAXPATHL-5);
Bram Moolenaar71de7202019-05-24 19:04:29 +02007183 p = buf + STRLEN(buf);
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007184 MB_PTR_BACK(buf, p);
7185 if (*p == '\\' || *p == '/')
7186 *p = NUL;
7187 STRCAT(buf, "\\*");
7188
7189 wn = enc_to_utf16(buf, NULL);
7190 if (wn != NULL)
7191 hFind = FindFirstFileW(wn, &wfb);
7192 ok = (hFind != INVALID_HANDLE_VALUE);
7193 if (!ok)
7194 {
7195 failed = TRUE;
7196 smsg(_(e_notopen), path);
7197 }
7198 else
7199 {
7200 while (ok)
7201 {
7202 int ignore;
7203
7204 p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here
7205 if (p == NULL)
7206 break; // out of memory
7207
7208 ignore = p[0] == '.' && (p[1] == NUL
7209 || (p[1] == '.' && p[2] == NUL));
7210 if (!ignore && checkitem != NULL)
7211 {
7212 int r = checkitem(context, p);
7213
7214 if (r < 0)
7215 {
7216 vim_free(p);
7217 break;
7218 }
7219 if (r == 0)
7220 ignore = TRUE;
7221 }
7222
7223 if (!ignore)
7224 {
7225 if (ga_grow(gap, 1) == OK)
7226 ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
7227 else
7228 {
7229 failed = TRUE;
7230 vim_free(p);
7231 break;
7232 }
7233 }
7234
7235 vim_free(p);
7236 ok = FindNextFileW(hFind, &wfb);
7237 }
7238 FindClose(hFind);
7239 }
7240
7241 vim_free(buf);
7242 vim_free(wn);
7243#else
7244 DIR *dirp;
7245 struct dirent *dp;
7246 char_u *p;
7247
7248 dirp = opendir((char *)path);
7249 if (dirp == NULL)
7250 {
7251 failed = TRUE;
7252 smsg(_(e_notopen), path);
7253 }
7254 else
7255 {
7256 for (;;)
7257 {
7258 int ignore;
7259
7260 dp = readdir(dirp);
7261 if (dp == NULL)
7262 break;
7263 p = (char_u *)dp->d_name;
7264
7265 ignore = p[0] == '.' &&
7266 (p[1] == NUL ||
7267 (p[1] == '.' && p[2] == NUL));
7268 if (!ignore && checkitem != NULL)
7269 {
7270 int r = checkitem(context, p);
7271
7272 if (r < 0)
7273 break;
7274 if (r == 0)
7275 ignore = TRUE;
7276 }
7277
7278 if (!ignore)
7279 {
7280 if (ga_grow(gap, 1) == OK)
7281 ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
7282 else
7283 {
7284 failed = TRUE;
7285 break;
7286 }
7287 }
7288 }
7289
7290 closedir(dirp);
7291 }
7292#endif
7293
7294 if (!failed && gap->ga_len > 0)
7295 sort_strings((char_u **)gap->ga_data, gap->ga_len);
7296
7297 return failed ? FAIL : OK;
7298}
7299
7300/*
Bram Moolenaarda440d22016-01-16 21:27:23 +01007301 * Delete "name" and everything in it, recursively.
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007302 * return 0 for success, -1 if some file was not deleted.
Bram Moolenaarda440d22016-01-16 21:27:23 +01007303 */
7304 int
7305delete_recursive(char_u *name)
7306{
7307 int result = 0;
Bram Moolenaarda440d22016-01-16 21:27:23 +01007308 int i;
7309 char_u *exp;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007310 garray_T ga;
Bram Moolenaarda440d22016-01-16 21:27:23 +01007311
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007312 // A symbolic link to a directory itself is deleted, not the directory it
7313 // points to.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007314 if (
Bram Moolenaar4f974752019-02-17 17:44:42 +01007315# if defined(UNIX) || defined(MSWIN)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007316 mch_isrealdir(name)
Bram Moolenaar203258c2016-01-17 22:15:16 +01007317# else
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007318 mch_isdir(name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007319# endif
7320 )
Bram Moolenaarda440d22016-01-16 21:27:23 +01007321 {
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007322 exp = vim_strsave(name);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007323 if (exp == NULL)
7324 return -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007325 if (readdir_core(&ga, exp, NULL, NULL) == OK)
Bram Moolenaarda440d22016-01-16 21:27:23 +01007326 {
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007327 for (i = 0; i < ga.ga_len; ++i)
7328 {
7329 vim_snprintf((char *)NameBuff, MAXPATHL, "%s/%s", exp,
7330 ((char_u **)ga.ga_data)[i]);
7331 if (delete_recursive(NameBuff) != 0)
Bram Moolenaarda440d22016-01-16 21:27:23 +01007332 result = -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007333 }
7334 ga_clear_strings(&ga);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007335 }
7336 else
7337 result = -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007338 (void)mch_rmdir(exp);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007339 vim_free(exp);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007340 }
7341 else
7342 result = mch_remove(name) == 0 ? 0 : -1;
7343
7344 return result;
7345}
7346#endif
7347
Bram Moolenaar071d4272004-06-13 20:20:40 +00007348#if defined(TEMPDIRNAMES) || defined(PROTO)
7349static long temp_count = 0; /* Temp filename counter. */
7350
7351/*
7352 * Delete the temp directory and all files it contains.
7353 */
7354 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007355vim_deltempdir(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007356{
Bram Moolenaar071d4272004-06-13 20:20:40 +00007357 if (vim_tempdir != NULL)
7358 {
Bram Moolenaarda440d22016-01-16 21:27:23 +01007359 /* remove the trailing path separator */
7360 gettail(vim_tempdir)[-1] = NUL;
7361 delete_recursive(vim_tempdir);
Bram Moolenaard23a8232018-02-10 18:45:26 +01007362 VIM_CLEAR(vim_tempdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007363 }
7364}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365
7366/*
Bram Moolenaareaf03392009-11-17 11:08:52 +00007367 * Directory "tempdir" was created. Expand this name to a full path and put
7368 * it in "vim_tempdir". This avoids that using ":cd" would confuse us.
7369 * "tempdir" must be no longer than MAXPATHL.
7370 */
7371 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007372vim_settempdir(char_u *tempdir)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007373{
7374 char_u *buf;
7375
Bram Moolenaar964b3742019-05-24 18:54:09 +02007376 buf = alloc(MAXPATHL + 2);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007377 if (buf != NULL)
7378 {
7379 if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
7380 STRCPY(buf, tempdir);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02007381 add_pathsep(buf);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007382 vim_tempdir = vim_strsave(buf);
7383 vim_free(buf);
7384 }
7385}
Bram Moolenaar4592dee2009-11-18 19:11:58 +00007386#endif
Bram Moolenaareaf03392009-11-17 11:08:52 +00007387
7388/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007389 * vim_tempname(): Return a unique name that can be used for a temp file.
7390 *
Bram Moolenaar76ae22f2016-06-13 20:00:29 +02007391 * The temp file is NOT guaranteed to be created. If "keep" is FALSE it is
7392 * guaranteed to NOT be created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007393 *
7394 * The returned pointer is to allocated memory.
7395 * The returned pointer is NULL if no valid name was found.
7396 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007398vim_tempname(
7399 int extra_char UNUSED, /* char to use in the name instead of '?' */
7400 int keep UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007401{
7402#ifdef USE_TMPNAM
7403 char_u itmp[L_tmpnam]; /* use tmpnam() */
Bram Moolenaar4f974752019-02-17 17:44:42 +01007404#elif defined(MSWIN)
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007405 WCHAR itmp[TEMPNAMELEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007406#else
7407 char_u itmp[TEMPNAMELEN];
7408#endif
7409
7410#ifdef TEMPDIRNAMES
7411 static char *(tempdirs[]) = {TEMPDIRNAMES};
7412 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007413# ifndef EEXIST
Bram Moolenaar8767f522016-07-01 17:17:39 +02007414 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007415# endif
7416
7417 /*
7418 * This will create a directory for private use by this instance of Vim.
7419 * This is done once, and the same directory is used for all temp files.
7420 * This method avoids security problems because of symlink attacks et al.
7421 * It's also a bit faster, because we only need to check for an existing
7422 * file when creating the directory and not for each temp file.
7423 */
7424 if (vim_tempdir == NULL)
7425 {
7426 /*
7427 * Try the entries in TEMPDIRNAMES to create the temp directory.
7428 */
Bram Moolenaar78a15312009-05-15 19:33:18 +00007429 for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007430 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007431# ifndef HAVE_MKDTEMP
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007432 size_t itmplen;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007433 long nr;
7434 long off;
7435# endif
7436
Bram Moolenaare1a61992015-12-03 21:02:27 +01007437 /* Expand $TMP, leave room for "/v1100000/999999999".
7438 * Skip the directory check if the expansion fails. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007439 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
Bram Moolenaare1a61992015-12-03 21:02:27 +01007440 if (itmp[0] != '$' && mch_isdir(itmp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007441 {
Bram Moolenaare1a61992015-12-03 21:02:27 +01007442 /* directory exists */
Bram Moolenaara06ecab2016-07-16 14:47:36 +02007443 add_pathsep(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007444
Bram Moolenaareaf03392009-11-17 11:08:52 +00007445# ifdef HAVE_MKDTEMP
Bram Moolenaar35d88f42016-06-04 14:52:00 +02007446 {
7447# if defined(UNIX) || defined(VMS)
7448 /* Make sure the umask doesn't remove the executable bit.
7449 * "repl" has been reported to use "177". */
7450 mode_t umask_save = umask(077);
7451# endif
7452 /* Leave room for filename */
7453 STRCAT(itmp, "vXXXXXX");
7454 if (mkdtemp((char *)itmp) != NULL)
7455 vim_settempdir(itmp);
7456# if defined(UNIX) || defined(VMS)
7457 (void)umask(umask_save);
7458# endif
7459 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007460# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007461 /* Get an arbitrary number of up to 6 digits. When it's
7462 * unlikely that it already exists it will be faster,
7463 * otherwise it doesn't matter. The use of mkdir() avoids any
7464 * security problems because of the predictable number. */
7465 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007466 itmplen = STRLEN(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007467
7468 /* Try up to 10000 different values until we find a name that
7469 * doesn't exist. */
7470 for (off = 0; off < 10000L; ++off)
7471 {
7472 int r;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007473# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007474 mode_t umask_save;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007475# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007476
Bram Moolenaareaf03392009-11-17 11:08:52 +00007477 sprintf((char *)itmp + itmplen, "v%ld", nr + off);
7478# ifndef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007479 /* If mkdir() does not set errno to EEXIST, check for
7480 * existing file here. There is a race condition then,
7481 * although it's fail-safe. */
7482 if (mch_stat((char *)itmp, &st) >= 0)
7483 continue;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007484# endif
7485# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007486 /* Make sure the umask doesn't remove the executable bit.
7487 * "repl" has been reported to use "177". */
7488 umask_save = umask(077);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007489# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007490 r = vim_mkdir(itmp, 0700);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007491# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007492 (void)umask(umask_save);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007493# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007494 if (r == 0)
7495 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007496 vim_settempdir(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007497 break;
7498 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007499# ifdef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007500 /* If the mkdir() didn't fail because the file/dir exists,
7501 * we probably can't create any dir here, try another
7502 * place. */
7503 if (errno != EEXIST)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007504# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007505 break;
7506 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007507# endif /* HAVE_MKDTEMP */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007508 if (vim_tempdir != NULL)
7509 break;
7510 }
7511 }
7512 }
7513
7514 if (vim_tempdir != NULL)
7515 {
7516 /* There is no need to check if the file exists, because we own the
7517 * directory and nobody else creates a file in it. */
7518 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
7519 return vim_strsave(itmp);
7520 }
7521
7522 return NULL;
7523
7524#else /* TEMPDIRNAMES */
7525
Bram Moolenaar4f974752019-02-17 17:44:42 +01007526# ifdef MSWIN
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007527 WCHAR wszTempFile[_MAX_PATH + 1];
7528 WCHAR buf4[4];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007529 char_u *retval;
7530 char_u *p;
7531
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007532 wcscpy(itmp, L"");
7533 if (GetTempPathW(_MAX_PATH, wszTempFile) == 0)
Bram Moolenaarb1891912011-02-09 14:47:03 +01007534 {
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007535 wszTempFile[0] = L'.'; // GetTempPathW() failed, use current dir
7536 wszTempFile[1] = NUL;
Bram Moolenaarb1891912011-02-09 14:47:03 +01007537 }
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007538 wcscpy(buf4, L"VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00007539 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007540 if (GetTempFileNameW(wszTempFile, buf4, 0, itmp) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007541 return NULL;
Bram Moolenaare5c421c2015-03-31 13:33:08 +02007542 if (!keep)
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007543 // GetTempFileName() will create the file, we don't want that
7544 (void)DeleteFileW(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007545
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007546 // Backslashes in a temp file name cause problems when filtering with
7547 // "sh". NOTE: This also checks 'shellcmdflag' to help those people who
7548 // didn't set 'shellslash'.
7549 retval = utf16_to_enc(itmp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007550 if (*p_shcf == '-' || p_ssl)
7551 for (p = retval; *p; ++p)
7552 if (*p == '\\')
7553 *p = '/';
7554 return retval;
7555
Bram Moolenaar4f974752019-02-17 17:44:42 +01007556# else // MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007557
7558# ifdef USE_TMPNAM
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007559 char_u *p;
7560
Bram Moolenaar071d4272004-06-13 20:20:40 +00007561 /* tmpnam() will make its own name */
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007562 p = tmpnam((char *)itmp);
7563 if (p == NULL || *p == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564 return NULL;
7565# else
7566 char_u *p;
7567
7568# ifdef VMS_TEMPNAM
7569 /* mktemp() is not working on VMS. It seems to be
7570 * a do-nothing function. Therefore we use tempnam().
7571 */
7572 sprintf((char *)itmp, "VIM%c", extra_char);
7573 p = (char_u *)tempnam("tmp:", (char *)itmp);
7574 if (p != NULL)
7575 {
Bram Moolenaar206f0112014-03-12 16:51:55 +01007576 /* VMS will use '.LIS' if we don't explicitly specify an extension,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007577 * and VIM will then be unable to find the file later */
7578 STRCPY(itmp, p);
7579 STRCAT(itmp, ".txt");
7580 free(p);
7581 }
7582 else
7583 return NULL;
7584# else
7585 STRCPY(itmp, TEMPNAME);
7586 if ((p = vim_strchr(itmp, '?')) != NULL)
7587 *p = extra_char;
7588 if (mktemp((char *)itmp) == NULL)
7589 return NULL;
7590# endif
7591# endif
7592
7593 return vim_strsave(itmp);
Bram Moolenaar4f974752019-02-17 17:44:42 +01007594# endif // MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007595#endif /* TEMPDIRNAMES */
7596}
7597
7598#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
7599/*
Bram Moolenaarb4f6a462015-10-13 19:43:17 +02007600 * Convert all backslashes in fname to forward slashes in-place, unless when
7601 * it looks like a URL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007602 */
7603 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007604forward_slash(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007605{
7606 char_u *p;
7607
Bram Moolenaarb4f6a462015-10-13 19:43:17 +02007608 if (path_with_url(fname))
7609 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007610 for (p = fname; *p != NUL; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007611 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007612 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007613 ++p;
Bram Moolenaar13505972019-01-24 15:04:48 +01007614 else if (*p == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00007615 *p = '/';
7616}
7617#endif
7618
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00007619/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00007620 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
7621 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
7622 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007623 * Used for autocommands and 'wildignore'.
7624 * Returns TRUE if there is a match, FALSE otherwise.
7625 */
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01007626 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007627match_file_pat(
7628 char_u *pattern, /* pattern to match with */
7629 regprog_T **prog, /* pre-compiled regprog or NULL */
7630 char_u *fname, /* full path of file name */
7631 char_u *sfname, /* short file name or NULL */
7632 char_u *tail, /* tail of path */
7633 int allow_dirs) /* allow matching with dir */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007634{
7635 regmatch_T regmatch;
7636 int result = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007637
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01007638 regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007639 if (prog != NULL)
7640 regmatch.regprog = *prog;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007641 else
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007642 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007643
7644 /*
7645 * Try for a match with the pattern with:
7646 * 1. the full file name, when the pattern has a '/'.
7647 * 2. the short file name, when the pattern has a '/'.
7648 * 3. the tail of the file name, when the pattern has no '/'.
7649 */
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007650 if (regmatch.regprog != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007651 && ((allow_dirs
7652 && (vim_regexec(&regmatch, fname, (colnr_T)0)
7653 || (sfname != NULL
7654 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007655 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007656 result = TRUE;
7657
Bram Moolenaardffa5b82014-11-19 16:38:07 +01007658 if (prog != NULL)
7659 *prog = regmatch.regprog;
7660 else
Bram Moolenaar473de612013-06-08 18:19:48 +02007661 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007662 return result;
7663}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007664
7665#if defined(FEAT_WILDIGN) || defined(PROTO)
7666/*
7667 * Return TRUE if a file matches with a pattern in "list".
7668 * "list" is a comma-separated list of patterns, like 'wildignore'.
7669 * "sfname" is the short file name or NULL, "ffname" the long file name.
7670 */
7671 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007672match_file_list(char_u *list, char_u *sfname, char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007673{
7674 char_u buf[100];
7675 char_u *tail;
7676 char_u *regpat;
7677 char allow_dirs;
7678 int match;
7679 char_u *p;
7680
7681 tail = gettail(sfname);
7682
7683 /* try all patterns in 'wildignore' */
7684 p = list;
7685 while (*p)
7686 {
7687 copy_option_part(&p, buf, 100, ",");
7688 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
7689 if (regpat == NULL)
7690 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007691 match = match_file_pat(regpat, NULL, ffname, sfname,
7692 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693 vim_free(regpat);
7694 if (match)
7695 return TRUE;
7696 }
7697 return FALSE;
7698}
7699#endif
7700
7701/*
7702 * Convert the given pattern "pat" which has shell style wildcards in it, into
7703 * a regular expression, and return the result in allocated memory. If there
7704 * is a directory path separator to be matched, then TRUE is put in
7705 * allow_dirs, otherwise FALSE is put there -- webb.
7706 * Handle backslashes before special characters, like "\*" and "\ ".
7707 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00007708 * Returns NULL when out of memory.
7709 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007710 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007711file_pat_to_reg_pat(
7712 char_u *pat,
7713 char_u *pat_end, /* first char after pattern or NULL */
7714 char *allow_dirs, /* Result passed back out in here */
7715 int no_bslash UNUSED) /* Don't use a backward slash as pathsep */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007716{
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007717 int size = 2; /* '^' at start, '$' at end */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007718 char_u *endp;
7719 char_u *reg_pat;
7720 char_u *p;
7721 int i;
7722 int nested = 0;
7723 int add_dollar = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007724
7725 if (allow_dirs != NULL)
7726 *allow_dirs = FALSE;
7727 if (pat_end == NULL)
7728 pat_end = pat + STRLEN(pat);
7729
Bram Moolenaar071d4272004-06-13 20:20:40 +00007730 for (p = pat; p < pat_end; p++)
7731 {
7732 switch (*p)
7733 {
7734 case '*':
7735 case '.':
7736 case ',':
7737 case '{':
7738 case '}':
7739 case '~':
7740 size += 2; /* extra backslash */
7741 break;
7742#ifdef BACKSLASH_IN_FILENAME
7743 case '\\':
7744 case '/':
7745 size += 4; /* could become "[\/]" */
7746 break;
7747#endif
7748 default:
7749 size++;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007750 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007751 {
7752 ++p;
7753 ++size;
7754 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007755 break;
7756 }
7757 }
7758 reg_pat = alloc(size + 1);
7759 if (reg_pat == NULL)
7760 return NULL;
7761
Bram Moolenaar071d4272004-06-13 20:20:40 +00007762 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007763
7764 if (pat[0] == '*')
7765 while (pat[0] == '*' && pat < pat_end - 1)
7766 pat++;
7767 else
7768 reg_pat[i++] = '^';
7769 endp = pat_end - 1;
Bram Moolenaar8fee8782015-08-11 18:45:48 +02007770 if (endp >= pat && *endp == '*')
Bram Moolenaar071d4272004-06-13 20:20:40 +00007771 {
7772 while (endp - pat > 0 && *endp == '*')
7773 endp--;
7774 add_dollar = FALSE;
7775 }
7776 for (p = pat; *p && nested >= 0 && p <= endp; p++)
7777 {
7778 switch (*p)
7779 {
7780 case '*':
7781 reg_pat[i++] = '.';
7782 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00007783 while (p[1] == '*') /* "**" matches like "*" */
7784 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007785 break;
7786 case '.':
Bram Moolenaar071d4272004-06-13 20:20:40 +00007787 case '~':
7788 reg_pat[i++] = '\\';
7789 reg_pat[i++] = *p;
7790 break;
7791 case '?':
Bram Moolenaar071d4272004-06-13 20:20:40 +00007792 reg_pat[i++] = '.';
7793 break;
7794 case '\\':
7795 if (p[1] == NUL)
7796 break;
7797#ifdef BACKSLASH_IN_FILENAME
7798 if (!no_bslash)
7799 {
7800 /* translate:
7801 * "\x" to "\\x" e.g., "dir\file"
7802 * "\*" to "\\.*" e.g., "dir\*.c"
7803 * "\?" to "\\." e.g., "dir\??.c"
7804 * "\+" to "\+" e.g., "fileX\+.c"
7805 */
7806 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
7807 && p[1] != '+')
7808 {
7809 reg_pat[i++] = '[';
7810 reg_pat[i++] = '\\';
7811 reg_pat[i++] = '/';
7812 reg_pat[i++] = ']';
7813 if (allow_dirs != NULL)
7814 *allow_dirs = TRUE;
7815 break;
7816 }
7817 }
7818#endif
Bram Moolenaar8cd213c2010-06-01 21:57:09 +02007819 /* Undo escaping from ExpandEscape():
7820 * foo\?bar -> foo?bar
7821 * foo\%bar -> foo%bar
7822 * foo\,bar -> foo,bar
7823 * foo\ bar -> foo bar
7824 * Don't unescape \, * and others that are also special in a
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007825 * regexp.
7826 * An escaped { must be unescaped since we use magic not
Bram Moolenaara946afe2013-08-02 15:22:39 +02007827 * verymagic. Use "\\\{n,m\}"" to get "\{n,m}".
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007828 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007829 if (*++p == '?'
7830#ifdef BACKSLASH_IN_FILENAME
7831 && no_bslash
7832#endif
7833 )
7834 reg_pat[i++] = '?';
7835 else
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007836 if (*p == ',' || *p == '%' || *p == '#'
Bram Moolenaar2288afe2015-08-11 16:20:05 +02007837 || vim_isspace(*p) || *p == '{' || *p == '}')
Bram Moolenaar8cd213c2010-06-01 21:57:09 +02007838 reg_pat[i++] = *p;
Bram Moolenaara946afe2013-08-02 15:22:39 +02007839 else if (*p == '\\' && p[1] == '\\' && p[2] == '{')
7840 {
7841 reg_pat[i++] = '\\';
7842 reg_pat[i++] = '{';
7843 p += 2;
7844 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007845 else
7846 {
7847 if (allow_dirs != NULL && vim_ispathsep(*p)
7848#ifdef BACKSLASH_IN_FILENAME
7849 && (!no_bslash || *p != '\\')
7850#endif
7851 )
7852 *allow_dirs = TRUE;
7853 reg_pat[i++] = '\\';
7854 reg_pat[i++] = *p;
7855 }
7856 break;
7857#ifdef BACKSLASH_IN_FILENAME
7858 case '/':
7859 reg_pat[i++] = '[';
7860 reg_pat[i++] = '\\';
7861 reg_pat[i++] = '/';
7862 reg_pat[i++] = ']';
7863 if (allow_dirs != NULL)
7864 *allow_dirs = TRUE;
7865 break;
7866#endif
7867 case '{':
7868 reg_pat[i++] = '\\';
7869 reg_pat[i++] = '(';
7870 nested++;
7871 break;
7872 case '}':
7873 reg_pat[i++] = '\\';
7874 reg_pat[i++] = ')';
7875 --nested;
7876 break;
7877 case ',':
7878 if (nested)
7879 {
7880 reg_pat[i++] = '\\';
7881 reg_pat[i++] = '|';
7882 }
7883 else
7884 reg_pat[i++] = ',';
7885 break;
7886 default:
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007887 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007888 reg_pat[i++] = *p++;
Bram Moolenaar13505972019-01-24 15:04:48 +01007889 else if (allow_dirs != NULL && vim_ispathsep(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007890 *allow_dirs = TRUE;
7891 reg_pat[i++] = *p;
7892 break;
7893 }
7894 }
7895 if (add_dollar)
7896 reg_pat[i++] = '$';
7897 reg_pat[i] = NUL;
7898 if (nested != 0)
7899 {
7900 if (nested < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007901 emsg(_("E219: Missing {."));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007902 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007903 emsg(_("E220: Missing }."));
Bram Moolenaard23a8232018-02-10 18:45:26 +01007904 VIM_CLEAR(reg_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007905 }
7906 return reg_pat;
7907}
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007908
7909#if defined(EINTR) || defined(PROTO)
7910/*
7911 * Version of read() that retries when interrupted by EINTR (possibly
7912 * by a SIGWINCH).
7913 */
7914 long
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007915read_eintr(int fd, void *buf, size_t bufsize)
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007916{
7917 long ret;
7918
7919 for (;;)
7920 {
7921 ret = vim_read(fd, buf, bufsize);
7922 if (ret >= 0 || errno != EINTR)
7923 break;
7924 }
7925 return ret;
7926}
7927
7928/*
7929 * Version of write() that retries when interrupted by EINTR (possibly
7930 * by a SIGWINCH).
7931 */
7932 long
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007933write_eintr(int fd, void *buf, size_t bufsize)
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007934{
7935 long ret = 0;
7936 long wlen;
7937
7938 /* Repeat the write() so long it didn't fail, other than being interrupted
7939 * by a signal. */
7940 while (ret < (long)bufsize)
7941 {
Bram Moolenaar9c263032010-12-17 18:06:06 +01007942 wlen = vim_write(fd, (char *)buf + ret, bufsize - ret);
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007943 if (wlen < 0)
7944 {
7945 if (errno != EINTR)
7946 break;
7947 }
7948 else
7949 ret += wlen;
7950 }
7951 return ret;
7952}
7953#endif