blob: e0226f8c8c1fe23a76f49418b3cf1ef66bfd7c93 [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 Moolenaarf077db22019-08-13 00:18:24 +020030static char_u *next_fenc(char_u **pp, int *alloced);
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 Moolenaar5843f5f2019-08-20 20:13:45 +0200114 static 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' */
Bram Moolenaarf077db22019-08-13 00:18:24 +0200893 fenc = next_fenc(&fenc_next, &fenc_alloced);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895
896 /*
897 * Jump back here to retry reading the file in different ways.
898 * Reasons to retry:
899 * - encoding conversion failed: try another one from "fenc_next"
900 * - BOM detected and fenc was set, need to setup conversion
901 * - "fileformat" check failed: try another
902 *
903 * Variables set for special retry actions:
904 * "file_rewind" Rewind the file to start reading it again.
905 * "advance_fenc" Advance "fenc" using "fenc_next".
906 * "skip_read" Re-use already read bytes (BOM detected).
907 * "did_iconv" iconv() conversion failed, try 'charconvert'.
908 * "keep_fileformat" Don't reset "fileformat".
909 *
910 * Other status indicators:
911 * "tmpname" When != NULL did conversion with 'charconvert'.
912 * Output file has to be deleted afterwards.
913 * "iconv_fd" When != -1 did conversion with iconv().
914 */
915retry:
916
917 if (file_rewind)
918 {
919 if (read_buffer)
920 {
921 read_buf_lnum = 1;
922 read_buf_col = 0;
923 }
Bram Moolenaar8767f522016-07-01 17:17:39 +0200924 else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925 {
926 /* Can't rewind the file, give up. */
927 error = TRUE;
928 goto failed;
929 }
930 /* Delete the previously read lines. */
931 while (lnum > from)
932 ml_delete(lnum--, FALSE);
933 file_rewind = FALSE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000934 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000935 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 curbuf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000937 curbuf->b_start_bomb = FALSE;
938 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000939 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000940 }
941
942 /*
943 * When retrying with another "fenc" and the first time "fileformat"
944 * will be reset.
945 */
946 if (keep_fileformat)
947 keep_fileformat = FALSE;
948 else
949 {
950 if (eap != NULL && eap->force_ff != 0)
Bram Moolenaar1c860362008-11-12 15:05:21 +0000951 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 fileformat = get_fileformat_force(curbuf, eap);
Bram Moolenaar1c860362008-11-12 15:05:21 +0000953 try_unix = try_dos = try_mac = FALSE;
954 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 else if (curbuf->b_p_bin)
956 fileformat = EOL_UNIX; /* binary: use Unix format */
957 else if (*p_ffs == NUL)
958 fileformat = get_fileformat(curbuf);/* use format from buffer */
959 else
960 fileformat = EOL_UNKNOWN; /* detect from file */
961 }
962
Bram Moolenaar13505972019-01-24 15:04:48 +0100963#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 if (iconv_fd != (iconv_t)-1)
965 {
966 /* aborted conversion with iconv(), close the descriptor */
967 iconv_close(iconv_fd);
968 iconv_fd = (iconv_t)-1;
969 }
Bram Moolenaar13505972019-01-24 15:04:48 +0100970#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971
972 if (advance_fenc)
973 {
974 /*
975 * Try the next entry in 'fileencodings'.
976 */
977 advance_fenc = FALSE;
978
979 if (eap != NULL && eap->force_enc != 0)
980 {
981 /* Conversion given with "++cc=" wasn't possible, read
982 * without conversion. */
983 notconverted = TRUE;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +0000984 conv_error = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985 if (fenc_alloced)
986 vim_free(fenc);
987 fenc = (char_u *)"";
988 fenc_alloced = FALSE;
989 }
990 else
991 {
992 if (fenc_alloced)
993 vim_free(fenc);
994 if (fenc_next != NULL)
995 {
Bram Moolenaarf077db22019-08-13 00:18:24 +0200996 fenc = next_fenc(&fenc_next, &fenc_alloced);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997 }
998 else
999 {
1000 fenc = (char_u *)"";
1001 fenc_alloced = FALSE;
1002 }
1003 }
1004 if (tmpname != NULL)
1005 {
1006 mch_remove(tmpname); /* delete converted file */
Bram Moolenaard23a8232018-02-10 18:45:26 +01001007 VIM_CLEAR(tmpname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 }
1009 }
1010
1011 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001012 * Conversion may be required when the encoding of the file is different
1013 * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 */
1015 fio_flags = 0;
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00001016 converted = need_conversion(fenc);
1017 if (converted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 {
1019
1020 /* "ucs-bom" means we need to check the first bytes of the file
1021 * for a BOM. */
1022 if (STRCMP(fenc, ENC_UCSBOM) == 0)
1023 fio_flags = FIO_UCSBOM;
1024
1025 /*
1026 * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
1027 * done. This is handled below after read(). Prepare the
1028 * fio_flags to avoid having to parse the string each time.
1029 * Also check for Unicode to Latin1 conversion, because iconv()
1030 * appears not to handle this correctly. This works just like
1031 * conversion to UTF-8 except how the resulting character is put in
1032 * the buffer.
1033 */
1034 else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
1035 fio_flags = get_fio_flags(fenc);
1036
Bram Moolenaar4f974752019-02-17 17:44:42 +01001037#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 /*
1039 * Conversion from an MS-Windows codepage to UTF-8 or another codepage
1040 * is handled with MultiByteToWideChar().
1041 */
1042 if (fio_flags == 0)
1043 fio_flags = get_win_fio_flags(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001044#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045
Bram Moolenaar13505972019-01-24 15:04:48 +01001046#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047 /* Conversion from Apple MacRoman to latin1 or UTF-8 */
1048 if (fio_flags == 0)
1049 fio_flags = get_mac_fio_flags(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001050#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051
Bram Moolenaar13505972019-01-24 15:04:48 +01001052#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 /*
1054 * Try using iconv() if we can't convert internally.
1055 */
1056 if (fio_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001057# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 && !did_iconv
Bram Moolenaar13505972019-01-24 15:04:48 +01001059# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 )
1061 iconv_fd = (iconv_t)my_iconv_open(
1062 enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01001063#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064
Bram Moolenaar13505972019-01-24 15:04:48 +01001065#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 /*
1067 * Use the 'charconvert' expression when conversion is required
1068 * and we can't do it internally or with iconv().
1069 */
1070 if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001071 && !read_fifo
Bram Moolenaar13505972019-01-24 15:04:48 +01001072# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073 && iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001074# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 )
1076 {
Bram Moolenaar13505972019-01-24 15:04:48 +01001077# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 did_iconv = FALSE;
Bram Moolenaar13505972019-01-24 15:04:48 +01001079# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080 /* Skip conversion when it's already done (retry for wrong
1081 * "fileformat"). */
1082 if (tmpname == NULL)
1083 {
1084 tmpname = readfile_charconvert(fname, fenc, &fd);
1085 if (tmpname == NULL)
1086 {
1087 /* Conversion failed. Try another one. */
1088 advance_fenc = TRUE;
1089 if (fd < 0)
1090 {
1091 /* Re-opening the original file failed! */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001092 emsg(_("E202: Conversion made file unreadable!"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 error = TRUE;
1094 goto failed;
1095 }
1096 goto retry;
1097 }
1098 }
1099 }
1100 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001101#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 {
1103 if (fio_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001104#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 && iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001106#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 )
1108 {
1109 /* Conversion wanted but we can't.
1110 * Try the next conversion in 'fileencodings' */
1111 advance_fenc = TRUE;
1112 goto retry;
1113 }
1114 }
1115 }
1116
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001117 /* Set "can_retry" when it's possible to rewind the file and try with
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 * another "fenc" value. It's FALSE when no other "fenc" to try, reading
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001119 * stdin or fixed at a specific encoding. */
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001120 can_retry = (*fenc != NUL && !read_stdin && !read_fifo && !keep_dest_enc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121
1122 if (!skip_read)
1123 {
1124 linerest = 0;
1125 filesize = 0;
1126 skip_count = lines_to_skip;
1127 read_count = lines_to_read;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 conv_restlen = 0;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001129#ifdef FEAT_PERSISTENT_UNDO
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001130 read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0
1131 && curbuf->b_ffname != NULL
1132 && curbuf->b_p_udf
1133 && !filtering
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02001134 && !read_fifo
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001135 && !read_stdin
1136 && !read_buffer);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02001137 if (read_undo_file)
1138 sha256_start(&sha_ctx);
1139#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001140#ifdef FEAT_CRYPT
1141 if (curbuf->b_cryptstate != NULL)
1142 {
1143 /* Need to free the state, but keep the key, don't want to ask for
1144 * it again. */
1145 crypt_free_state(curbuf->b_cryptstate);
1146 curbuf->b_cryptstate = NULL;
1147 }
1148#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149 }
1150
1151 while (!error && !got_int)
1152 {
1153 /*
1154 * We allocate as much space for the file as we can get, plus
1155 * space for the old line plus room for one terminating NUL.
1156 * The amount is limited by the fact that read() only can read
1157 * upto max_unsigned characters (and other things).
1158 */
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001159 if (!skip_read)
1160 {
Bram Moolenaar30276f22019-01-24 17:59:39 +01001161#if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001162 size = SSIZE_MAX; /* use max I/O size, 52K */
Bram Moolenaar30276f22019-01-24 17:59:39 +01001163#else
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001164 /* Use buffer >= 64K. Add linerest to double the size if the
1165 * line gets very long, to avoid a lot of copying. But don't
1166 * read more than 1 Mbyte at a time, so we can be interrupted.
1167 */
1168 size = 0x10000L + linerest;
1169 if (size > 0x100000L)
1170 size = 0x100000L;
Bram Moolenaar13d3b052018-04-29 13:34:47 +02001171#endif
1172 }
1173
1174 /* Protect against the argument of lalloc() going negative. */
Bram Moolenaar30276f22019-01-24 17:59:39 +01001175 if (size < 0 || size + linerest + 1 < 0 || linerest >= MAXCOL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 {
1177 ++split;
1178 *ptr = NL; /* split line by inserting a NL */
1179 size = 1;
1180 }
1181 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182 {
1183 if (!skip_read)
1184 {
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001185 for ( ; size >= 10; size = (long)((long_u)size >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 {
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02001187 if ((new_buffer = lalloc(size + linerest + 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 FALSE)) != NULL)
1189 break;
1190 }
1191 if (new_buffer == NULL)
1192 {
1193 do_outofmem_msg((long_u)(size * 2 + linerest + 1));
1194 error = TRUE;
1195 break;
1196 }
1197 if (linerest) /* copy characters from the previous buffer */
1198 mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
1199 vim_free(buffer);
1200 buffer = new_buffer;
1201 ptr = buffer + linerest;
1202 line_start = buffer;
1203
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 /* May need room to translate into.
1205 * For iconv() we don't really know the required space, use a
1206 * factor ICONV_MULT.
1207 * latin1 to utf-8: 1 byte becomes up to 2 bytes
1208 * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
1209 * become up to 4 bytes, size must be multiple of 2
1210 * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
1211 * multiple of 2
1212 * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
1213 * multiple of 4 */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001214 real_size = (int)size;
Bram Moolenaar13505972019-01-24 15:04:48 +01001215#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216 if (iconv_fd != (iconv_t)-1)
1217 size = size / ICONV_MULT;
1218 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001219#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 if (fio_flags & FIO_LATIN1)
1221 size = size / 2;
1222 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1223 size = (size * 2 / 3) & ~1;
1224 else if (fio_flags & FIO_UCS4)
1225 size = (size * 2 / 3) & ~3;
1226 else if (fio_flags == FIO_UCSBOM)
1227 size = size / ICONV_MULT; /* worst case */
Bram Moolenaar4f974752019-02-17 17:44:42 +01001228#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 else if (fio_flags & FIO_CODEPAGE)
1230 size = size / ICONV_MULT; /* also worst case */
Bram Moolenaar13505972019-01-24 15:04:48 +01001231#endif
1232#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 else if (fio_flags & FIO_MACROMAN)
1234 size = size / ICONV_MULT; /* also worst case */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235#endif
1236
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 if (conv_restlen > 0)
1238 {
1239 /* Insert unconverted bytes from previous line. */
1240 mch_memmove(ptr, conv_rest, conv_restlen);
1241 ptr += conv_restlen;
1242 size -= conv_restlen;
1243 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244
1245 if (read_buffer)
1246 {
1247 /*
1248 * Read bytes from curbuf. Used for converting text read
1249 * from stdin.
1250 */
1251 if (read_buf_lnum > from)
1252 size = 0;
1253 else
1254 {
1255 int n, ni;
1256 long tlen;
1257
1258 tlen = 0;
1259 for (;;)
1260 {
1261 p = ml_get(read_buf_lnum) + read_buf_col;
1262 n = (int)STRLEN(p);
1263 if ((int)tlen + n + 1 > size)
1264 {
1265 /* Filled up to "size", append partial line.
1266 * Change NL to NUL to reverse the effect done
1267 * below. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001268 n = (int)(size - tlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 for (ni = 0; ni < n; ++ni)
1270 {
1271 if (p[ni] == NL)
1272 ptr[tlen++] = NUL;
1273 else
1274 ptr[tlen++] = p[ni];
1275 }
1276 read_buf_col += n;
1277 break;
1278 }
1279 else
1280 {
1281 /* Append whole line and new-line. Change NL
1282 * to NUL to reverse the effect done below. */
1283 for (ni = 0; ni < n; ++ni)
1284 {
1285 if (p[ni] == NL)
1286 ptr[tlen++] = NUL;
1287 else
1288 ptr[tlen++] = p[ni];
1289 }
1290 ptr[tlen++] = NL;
1291 read_buf_col = 0;
1292 if (++read_buf_lnum > from)
1293 {
1294 /* When the last line didn't have an
1295 * end-of-line don't add it now either. */
1296 if (!curbuf->b_p_eol)
1297 --tlen;
1298 size = tlen;
1299 break;
1300 }
1301 }
1302 }
1303 }
1304 }
1305 else
1306 {
1307 /*
1308 * Read bytes from the file.
1309 */
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01001310 size = read_eintr(fd, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 }
1312
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001313#ifdef FEAT_CRYPT
1314 /*
1315 * At start of file: Check for magic number of encryption.
1316 */
1317 if (filesize == 0 && size > 0)
1318 cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1319 &filesize, newfile, sfname,
1320 &did_ask_for_key);
1321 /*
1322 * Decrypt the read bytes. This is done before checking for
1323 * EOF because the crypt layer may be buffering.
1324 */
Bram Moolenaar829aa642017-08-23 22:32:35 +02001325 if (cryptkey != NULL && curbuf->b_cryptstate != NULL
1326 && size > 0)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001327 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01001328# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001329 if (crypt_works_inplace(curbuf->b_cryptstate))
1330 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01001331# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001332 crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
Bram Moolenaar987411d2019-01-18 22:48:34 +01001333# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001334 }
1335 else
1336 {
1337 char_u *newptr = NULL;
1338 int decrypted_size;
1339
1340 decrypted_size = crypt_decode_alloc(
1341 curbuf->b_cryptstate, ptr, size, &newptr);
1342
1343 /* If the crypt layer is buffering, not producing
1344 * anything yet, need to read more. */
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +02001345 if (decrypted_size == 0)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001346 continue;
1347
1348 if (linerest == 0)
1349 {
1350 /* Simple case: reuse returned buffer (may be
1351 * NULL, checked later). */
1352 new_buffer = newptr;
1353 }
1354 else
1355 {
1356 long_u new_size;
1357
1358 /* Need new buffer to add bytes carried over. */
1359 new_size = (long_u)(decrypted_size + linerest + 1);
1360 new_buffer = lalloc(new_size, FALSE);
1361 if (new_buffer == NULL)
1362 {
1363 do_outofmem_msg(new_size);
1364 error = TRUE;
1365 break;
1366 }
1367
1368 mch_memmove(new_buffer, buffer, linerest);
1369 if (newptr != NULL)
1370 mch_memmove(new_buffer + linerest, newptr,
1371 decrypted_size);
1372 }
1373
1374 if (new_buffer != NULL)
1375 {
1376 vim_free(buffer);
1377 buffer = new_buffer;
1378 new_buffer = NULL;
1379 line_start = buffer;
1380 ptr = buffer + linerest;
1381 }
1382 size = decrypted_size;
1383 }
Bram Moolenaar987411d2019-01-18 22:48:34 +01001384# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001385 }
1386#endif
1387
Bram Moolenaar071d4272004-06-13 20:20:40 +00001388 if (size <= 0)
1389 {
1390 if (size < 0) /* read error */
1391 error = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001392 else if (conv_restlen > 0)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001393 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001394 /*
1395 * Reached end-of-file but some trailing bytes could
1396 * not be converted. Truncated file?
1397 */
1398
1399 /* When we did a conversion report an error. */
1400 if (fio_flags != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001401#ifdef USE_ICONV
Bram Moolenaarf453d352008-06-04 17:37:34 +00001402 || iconv_fd != (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001403#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00001404 )
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001405 {
Bram Moolenaare8d95302013-04-24 16:34:02 +02001406 if (can_retry)
1407 goto rewind_retry;
Bram Moolenaarf453d352008-06-04 17:37:34 +00001408 if (conv_error == 0)
1409 conv_error = curbuf->b_ml.ml_line_count
1410 - linecnt + 1;
1411 }
1412 /* Remember the first linenr with an illegal byte */
1413 else if (illegal_byte == 0)
1414 illegal_byte = curbuf->b_ml.ml_line_count
1415 - linecnt + 1;
1416 if (bad_char_behavior == BAD_DROP)
1417 {
1418 *(ptr - conv_restlen) = NUL;
1419 conv_restlen = 0;
1420 }
1421 else
1422 {
1423 /* Replace the trailing bytes with the replacement
1424 * character if we were converting; if we weren't,
1425 * leave the UTF8 checking code to do it, as it
1426 * works slightly differently. */
1427 if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001428#ifdef USE_ICONV
Bram Moolenaarf453d352008-06-04 17:37:34 +00001429 || iconv_fd != (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01001430#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00001431 ))
1432 {
1433 while (conv_restlen > 0)
1434 {
1435 *(--ptr) = bad_char_behavior;
1436 --conv_restlen;
1437 }
1438 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001439 fio_flags = 0; /* don't convert this */
Bram Moolenaar13505972019-01-24 15:04:48 +01001440#ifdef USE_ICONV
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001441 if (iconv_fd != (iconv_t)-1)
1442 {
1443 iconv_close(iconv_fd);
1444 iconv_fd = (iconv_t)-1;
1445 }
Bram Moolenaar13505972019-01-24 15:04:48 +01001446#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001447 }
1448 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 }
1451 skip_read = FALSE;
1452
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453 /*
1454 * At start of file (or after crypt magic number): Check for BOM.
1455 * Also check for a BOM for other Unicode encodings, but not after
1456 * converting with 'charconvert' or when a BOM has already been
1457 * found.
1458 */
1459 if ((filesize == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01001460#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001461 || (cryptkey != NULL
1462 && filesize == crypt_get_header_len(
1463 crypt_get_method_nr(curbuf)))
Bram Moolenaar13505972019-01-24 15:04:48 +01001464#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 )
1466 && (fio_flags == FIO_UCSBOM
1467 || (!curbuf->b_p_bomb
1468 && tmpname == NULL
1469 && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
1470 {
1471 char_u *ccname;
1472 int blen;
1473
1474 /* no BOM detection in a short file or in binary mode */
1475 if (size < 2 || curbuf->b_p_bin)
1476 ccname = NULL;
1477 else
1478 ccname = check_for_bom(ptr, size, &blen,
1479 fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
1480 if (ccname != NULL)
1481 {
1482 /* Remove BOM from the text */
1483 filesize += blen;
1484 size -= blen;
1485 mch_memmove(ptr, ptr + blen, (size_t)size);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001486 if (set_options)
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001487 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 curbuf->b_p_bomb = TRUE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +00001489 curbuf->b_start_bomb = TRUE;
1490 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491 }
1492
1493 if (fio_flags == FIO_UCSBOM)
1494 {
1495 if (ccname == NULL)
1496 {
1497 /* No BOM detected: retry with next encoding. */
1498 advance_fenc = TRUE;
1499 }
1500 else
1501 {
1502 /* BOM detected: set "fenc" and jump back */
1503 if (fenc_alloced)
1504 vim_free(fenc);
1505 fenc = ccname;
1506 fenc_alloced = FALSE;
1507 }
1508 /* retry reading without getting new bytes or rewinding */
1509 skip_read = TRUE;
1510 goto retry;
1511 }
1512 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001513
1514 /* Include not converted bytes. */
1515 ptr -= conv_restlen;
1516 size += conv_restlen;
1517 conv_restlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001518 /*
1519 * Break here for a read error or end-of-file.
1520 */
1521 if (size <= 0)
1522 break;
1523
Bram Moolenaar071d4272004-06-13 20:20:40 +00001524
Bram Moolenaar13505972019-01-24 15:04:48 +01001525#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 if (iconv_fd != (iconv_t)-1)
1527 {
1528 /*
1529 * Attempt conversion of the read bytes to 'encoding' using
1530 * iconv().
1531 */
1532 const char *fromp;
1533 char *top;
1534 size_t from_size;
1535 size_t to_size;
1536
1537 fromp = (char *)ptr;
1538 from_size = size;
1539 ptr += size;
1540 top = (char *)ptr;
1541 to_size = real_size - size;
1542
1543 /*
1544 * If there is conversion error or not enough room try using
Bram Moolenaar19a09a12005-03-04 23:39:37 +00001545 * another conversion. Except for when there is no
1546 * alternative (help files).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001548 while ((iconv(iconv_fd, (void *)&fromp, &from_size,
1549 &top, &to_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
1551 || from_size > CONV_RESTLEN)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001552 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001553 if (can_retry)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001554 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001555 if (conv_error == 0)
1556 conv_error = readfile_linenr(linecnt,
1557 ptr, (char_u *)top);
Bram Moolenaar42eeac32005-06-29 22:40:58 +00001558
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001559 /* Deal with a bad byte and continue with the next. */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001560 ++fromp;
1561 --from_size;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001562 if (bad_char_behavior == BAD_KEEP)
1563 {
1564 *top++ = *(fromp - 1);
1565 --to_size;
1566 }
1567 else if (bad_char_behavior != BAD_DROP)
1568 {
1569 *top++ = bad_char_behavior;
1570 --to_size;
1571 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001572 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573
1574 if (from_size > 0)
1575 {
1576 /* Some remaining characters, keep them for the next
1577 * round. */
1578 mch_memmove(conv_rest, (char_u *)fromp, from_size);
1579 conv_restlen = (int)from_size;
1580 }
1581
1582 /* move the linerest to before the converted characters */
1583 line_start = ptr - linerest;
1584 mch_memmove(line_start, buffer, (size_t)linerest);
1585 size = (long)((char_u *)top - ptr);
1586 }
Bram Moolenaar13505972019-01-24 15:04:48 +01001587#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588
Bram Moolenaar4f974752019-02-17 17:44:42 +01001589#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 if (fio_flags & FIO_CODEPAGE)
1591 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001592 char_u *src, *dst;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001593 WCHAR ucs2buf[3];
1594 int ucs2len;
1595 int codepage = FIO_GET_CP(fio_flags);
1596 int bytelen;
1597 int found_bad;
1598 char replstr[2];
1599
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 /*
1601 * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001602 * a codepage, using standard MS-Windows functions. This
1603 * requires two steps:
1604 * 1. convert from 'fileencoding' to ucs-2
1605 * 2. convert from ucs-2 to 'encoding'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 *
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001607 * Because there may be illegal bytes AND an incomplete byte
1608 * sequence at the end, we may have to do the conversion one
1609 * character at a time to get it right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001612 /* Replacement string for WideCharToMultiByte(). */
1613 if (bad_char_behavior > 0)
1614 replstr[0] = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 else
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001616 replstr[0] = '?';
1617 replstr[1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618
1619 /*
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001620 * Move the bytes to the end of the buffer, so that we have
1621 * room to put the result at the start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622 */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001623 src = ptr + real_size - size;
1624 mch_memmove(src, ptr, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001626 /*
1627 * Do the conversion.
1628 */
1629 dst = ptr;
1630 size = size;
1631 while (size > 0)
1632 {
1633 found_bad = FALSE;
1634
1635# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
1636 if (codepage == CP_UTF8)
1637 {
1638 /* Handle CP_UTF8 input ourselves to be able to handle
1639 * trailing bytes properly.
1640 * Get one UTF-8 character from src. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001641 bytelen = (int)utf_ptr2len_len(src, size);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001642 if (bytelen > size)
1643 {
1644 /* Only got some bytes of a character. Normally
1645 * it's put in "conv_rest", but if it's too long
1646 * deal with it as if they were illegal bytes. */
1647 if (bytelen <= CONV_RESTLEN)
1648 break;
1649
1650 /* weird overlong byte sequence */
1651 bytelen = size;
1652 found_bad = TRUE;
1653 }
1654 else
1655 {
Bram Moolenaarc01140a2006-03-24 22:21:52 +00001656 int u8c = utf_ptr2char(src);
1657
Bram Moolenaar86e01082005-12-29 22:45:34 +00001658 if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001659 found_bad = TRUE;
1660 ucs2buf[0] = u8c;
1661 ucs2len = 1;
1662 }
1663 }
1664 else
1665# endif
1666 {
1667 /* We don't know how long the byte sequence is, try
1668 * from one to three bytes. */
1669 for (bytelen = 1; bytelen <= size && bytelen <= 3;
1670 ++bytelen)
1671 {
1672 ucs2len = MultiByteToWideChar(codepage,
1673 MB_ERR_INVALID_CHARS,
1674 (LPCSTR)src, bytelen,
1675 ucs2buf, 3);
1676 if (ucs2len > 0)
1677 break;
1678 }
1679 if (ucs2len == 0)
1680 {
1681 /* If we have only one byte then it's probably an
1682 * incomplete byte sequence. Otherwise discard
1683 * one byte as a bad character. */
1684 if (size == 1)
1685 break;
1686 found_bad = TRUE;
1687 bytelen = 1;
1688 }
1689 }
1690
1691 if (!found_bad)
1692 {
1693 int i;
1694
1695 /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
1696 if (enc_utf8)
1697 {
1698 /* From UCS-2 to UTF-8. Cannot fail. */
1699 for (i = 0; i < ucs2len; ++i)
1700 dst += utf_char2bytes(ucs2buf[i], dst);
1701 }
1702 else
1703 {
1704 BOOL bad = FALSE;
1705 int dstlen;
1706
1707 /* From UCS-2 to "enc_codepage". If the
1708 * conversion uses the default character "?",
1709 * the data doesn't fit in this encoding. */
1710 dstlen = WideCharToMultiByte(enc_codepage, 0,
1711 (LPCWSTR)ucs2buf, ucs2len,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001712 (LPSTR)dst, (int)(src - dst),
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001713 replstr, &bad);
1714 if (bad)
1715 found_bad = TRUE;
1716 else
1717 dst += dstlen;
1718 }
1719 }
1720
1721 if (found_bad)
1722 {
1723 /* Deal with bytes we can't convert. */
1724 if (can_retry)
1725 goto rewind_retry;
1726 if (conv_error == 0)
1727 conv_error = readfile_linenr(linecnt, ptr, dst);
1728 if (bad_char_behavior != BAD_DROP)
1729 {
1730 if (bad_char_behavior == BAD_KEEP)
1731 {
1732 mch_memmove(dst, src, bytelen);
1733 dst += bytelen;
1734 }
1735 else
1736 *dst++ = bad_char_behavior;
1737 }
1738 }
1739
1740 src += bytelen;
1741 size -= bytelen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001743
1744 if (size > 0)
1745 {
1746 /* An incomplete byte sequence remaining. */
1747 mch_memmove(conv_rest, src, size);
1748 conv_restlen = size;
1749 }
1750
1751 /* The new size is equal to how much "dst" was advanced. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001752 size = (long)(dst - ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753 }
1754 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001755#endif
1756#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 if (fio_flags & FIO_MACROMAN)
1758 {
1759 /*
1760 * Conversion from Apple MacRoman char encoding to UTF-8 or
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001761 * latin1. This is in os_mac_conv.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 */
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001763 if (macroman2enc(ptr, &size, real_size) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 goto rewind_retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 }
1766 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001767#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 if (fio_flags != 0)
1769 {
1770 int u8c;
1771 char_u *dest;
1772 char_u *tail = NULL;
1773
1774 /*
1775 * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
1776 * "enc_utf8" not set: Convert Unicode to Latin1.
1777 * Go from end to start through the buffer, because the number
1778 * of bytes may increase.
1779 * "dest" points to after where the UTF-8 bytes go, "p" points
1780 * to after the next character to convert.
1781 */
1782 dest = ptr + real_size;
1783 if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
1784 {
1785 p = ptr + size;
1786 if (fio_flags == FIO_UTF8)
1787 {
1788 /* Check for a trailing incomplete UTF-8 sequence */
1789 tail = ptr + size - 1;
1790 while (tail > ptr && (*tail & 0xc0) == 0x80)
1791 --tail;
1792 if (tail + utf_byte2len(*tail) <= ptr + size)
1793 tail = NULL;
1794 else
1795 p = tail;
1796 }
1797 }
1798 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1799 {
1800 /* Check for a trailing byte */
1801 p = ptr + (size & ~1);
1802 if (size & 1)
1803 tail = p;
1804 if ((fio_flags & FIO_UTF16) && p > ptr)
1805 {
1806 /* Check for a trailing leading word */
1807 if (fio_flags & FIO_ENDIAN_L)
1808 {
1809 u8c = (*--p << 8);
1810 u8c += *--p;
1811 }
1812 else
1813 {
1814 u8c = *--p;
1815 u8c += (*--p << 8);
1816 }
1817 if (u8c >= 0xd800 && u8c <= 0xdbff)
1818 tail = p;
1819 else
1820 p += 2;
1821 }
1822 }
1823 else /* FIO_UCS4 */
1824 {
1825 /* Check for trailing 1, 2 or 3 bytes */
1826 p = ptr + (size & ~3);
1827 if (size & 3)
1828 tail = p;
1829 }
1830
1831 /* If there is a trailing incomplete sequence move it to
1832 * conv_rest[]. */
1833 if (tail != NULL)
1834 {
1835 conv_restlen = (int)((ptr + size) - tail);
1836 mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
1837 size -= conv_restlen;
1838 }
1839
1840
1841 while (p > ptr)
1842 {
1843 if (fio_flags & FIO_LATIN1)
1844 u8c = *--p;
1845 else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
1846 {
1847 if (fio_flags & FIO_ENDIAN_L)
1848 {
1849 u8c = (*--p << 8);
1850 u8c += *--p;
1851 }
1852 else
1853 {
1854 u8c = *--p;
1855 u8c += (*--p << 8);
1856 }
1857 if ((fio_flags & FIO_UTF16)
1858 && u8c >= 0xdc00 && u8c <= 0xdfff)
1859 {
1860 int u16c;
1861
1862 if (p == ptr)
1863 {
1864 /* Missing leading word. */
1865 if (can_retry)
1866 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001867 if (conv_error == 0)
1868 conv_error = readfile_linenr(linecnt,
1869 ptr, p);
1870 if (bad_char_behavior == BAD_DROP)
1871 continue;
1872 if (bad_char_behavior != BAD_KEEP)
1873 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 }
1875
1876 /* found second word of double-word, get the first
1877 * word and compute the resulting character */
1878 if (fio_flags & FIO_ENDIAN_L)
1879 {
1880 u16c = (*--p << 8);
1881 u16c += *--p;
1882 }
1883 else
1884 {
1885 u16c = *--p;
1886 u16c += (*--p << 8);
1887 }
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001888 u8c = 0x10000 + ((u16c & 0x3ff) << 10)
1889 + (u8c & 0x3ff);
1890
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 /* Check if the word is indeed a leading word. */
1892 if (u16c < 0xd800 || u16c > 0xdbff)
1893 {
1894 if (can_retry)
1895 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001896 if (conv_error == 0)
1897 conv_error = readfile_linenr(linecnt,
1898 ptr, p);
1899 if (bad_char_behavior == BAD_DROP)
1900 continue;
1901 if (bad_char_behavior != BAD_KEEP)
1902 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 }
1905 }
1906 else if (fio_flags & FIO_UCS4)
1907 {
1908 if (fio_flags & FIO_ENDIAN_L)
1909 {
Bram Moolenaardc1c9812017-10-27 22:15:24 +02001910 u8c = (unsigned)*--p << 24;
1911 u8c += (unsigned)*--p << 16;
1912 u8c += (unsigned)*--p << 8;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 u8c += *--p;
1914 }
1915 else /* big endian */
1916 {
1917 u8c = *--p;
Bram Moolenaardc1c9812017-10-27 22:15:24 +02001918 u8c += (unsigned)*--p << 8;
1919 u8c += (unsigned)*--p << 16;
1920 u8c += (unsigned)*--p << 24;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
1922 }
1923 else /* UTF-8 */
1924 {
1925 if (*--p < 0x80)
1926 u8c = *p;
1927 else
1928 {
1929 len = utf_head_off(ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001930 p -= len;
1931 u8c = utf_ptr2char(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 if (len == 0)
1933 {
1934 /* Not a valid UTF-8 character, retry with
1935 * another fenc when possible, otherwise just
1936 * report the error. */
1937 if (can_retry)
1938 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001939 if (conv_error == 0)
1940 conv_error = readfile_linenr(linecnt,
1941 ptr, p);
1942 if (bad_char_behavior == BAD_DROP)
1943 continue;
1944 if (bad_char_behavior != BAD_KEEP)
1945 u8c = bad_char_behavior;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 }
1948 }
1949 if (enc_utf8) /* produce UTF-8 */
1950 {
1951 dest -= utf_char2len(u8c);
1952 (void)utf_char2bytes(u8c, dest);
1953 }
1954 else /* produce Latin1 */
1955 {
1956 --dest;
1957 if (u8c >= 0x100)
1958 {
1959 /* character doesn't fit in latin1, retry with
1960 * another fenc when possible, otherwise just
1961 * report the error. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001962 if (can_retry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 goto rewind_retry;
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001964 if (conv_error == 0)
1965 conv_error = readfile_linenr(linecnt, ptr, p);
1966 if (bad_char_behavior == BAD_DROP)
1967 ++dest;
1968 else if (bad_char_behavior == BAD_KEEP)
1969 *dest = u8c;
1970 else if (eap != NULL && eap->bad_char != 0)
1971 *dest = bad_char_behavior;
1972 else
1973 *dest = 0xBF;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974 }
1975 else
1976 *dest = u8c;
1977 }
1978 }
1979
1980 /* move the linerest to before the converted characters */
1981 line_start = dest - linerest;
1982 mch_memmove(line_start, buffer, (size_t)linerest);
1983 size = (long)((ptr + real_size) - dest);
1984 ptr = dest;
1985 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00001986 else if (enc_utf8 && !curbuf->b_p_bin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00001988 int incomplete_tail = FALSE;
1989
1990 /* Reading UTF-8: Check if the bytes are valid UTF-8. */
1991 for (p = ptr; ; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001993 int todo = (int)((ptr + size) - p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00001994 int l;
1995
1996 if (todo <= 0)
1997 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998 if (*p >= 0x80)
1999 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 /* A length of 1 means it's an illegal byte. Accept
2001 * an incomplete character at the end though, the next
2002 * read() will get the next bytes, we'll check it
2003 * then. */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002004 l = utf_ptr2len_len(p, todo);
Bram Moolenaarf453d352008-06-04 17:37:34 +00002005 if (l > todo && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002007 /* Avoid retrying with a different encoding when
2008 * a truncated file is more likely, or attempting
2009 * to read the rest of an incomplete sequence when
2010 * we have already done so. */
2011 if (p > ptr || filesize > 0)
2012 incomplete_tail = TRUE;
2013 /* Incomplete byte sequence, move it to conv_rest[]
2014 * and try to read the rest of it, unless we've
2015 * already done so. */
2016 if (p > ptr)
2017 {
2018 conv_restlen = todo;
2019 mch_memmove(conv_rest, p, conv_restlen);
2020 size -= conv_restlen;
2021 break;
2022 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002024 if (l == 1 || l > todo)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002025 {
2026 /* Illegal byte. If we can try another encoding
Bram Moolenaarf453d352008-06-04 17:37:34 +00002027 * do that, unless at EOF where a truncated
2028 * file is more likely than a conversion error. */
2029 if (can_retry && !incomplete_tail)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002030 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01002031#ifdef USE_ICONV
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002032 /* When we did a conversion report an error. */
2033 if (iconv_fd != (iconv_t)-1 && conv_error == 0)
2034 conv_error = readfile_linenr(linecnt, ptr, p);
Bram Moolenaar13505972019-01-24 15:04:48 +01002035#endif
Bram Moolenaarf453d352008-06-04 17:37:34 +00002036 /* Remember the first linenr with an illegal byte */
2037 if (conv_error == 0 && illegal_byte == 0)
2038 illegal_byte = readfile_linenr(linecnt, ptr, p);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002039
2040 /* Drop, keep or replace the bad byte. */
2041 if (bad_char_behavior == BAD_DROP)
2042 {
Bram Moolenaarf453d352008-06-04 17:37:34 +00002043 mch_memmove(p, p + 1, todo - 1);
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002044 --p;
2045 --size;
2046 }
2047 else if (bad_char_behavior != BAD_KEEP)
2048 *p = bad_char_behavior;
2049 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002050 else
2051 p += l - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052 }
2053 }
Bram Moolenaarf453d352008-06-04 17:37:34 +00002054 if (p < ptr + size && !incomplete_tail)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 {
2056 /* Detected a UTF-8 error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057rewind_retry:
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002058 /* Retry reading with another conversion. */
Bram Moolenaar13505972019-01-24 15:04:48 +01002059#if defined(FEAT_EVAL) && defined(USE_ICONV)
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002060 if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
2061 /* iconv() failed, try 'charconvert' */
2062 did_iconv = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002064#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002065 /* use next item from 'fileencodings' */
2066 advance_fenc = TRUE;
2067 file_rewind = TRUE;
2068 goto retry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069 }
2070 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071
2072 /* count the number of characters (after conversion!) */
2073 filesize += size;
2074
2075 /*
2076 * when reading the first part of a file: guess EOL type
2077 */
2078 if (fileformat == EOL_UNKNOWN)
2079 {
2080 /* First try finding a NL, for Dos and Unix */
2081 if (try_dos || try_unix)
2082 {
Bram Moolenaarc6b72172015-02-27 17:48:09 +01002083 /* Reset the carriage return counter. */
2084 if (try_mac)
2085 try_mac = 1;
2086
Bram Moolenaar071d4272004-06-13 20:20:40 +00002087 for (p = ptr; p < ptr + size; ++p)
2088 {
2089 if (*p == NL)
2090 {
2091 if (!try_unix
2092 || (try_dos && p > ptr && p[-1] == CAR))
2093 fileformat = EOL_DOS;
2094 else
2095 fileformat = EOL_UNIX;
2096 break;
2097 }
Bram Moolenaar05eb6122015-02-17 14:15:19 +01002098 else if (*p == CAR && try_mac)
2099 try_mac++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 }
2101
2102 /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
2103 if (fileformat == EOL_UNIX && try_mac)
2104 {
2105 /* Need to reset the counters when retrying fenc. */
2106 try_mac = 1;
2107 try_unix = 1;
2108 for (; p >= ptr && *p != CAR; p--)
2109 ;
2110 if (p >= ptr)
2111 {
2112 for (p = ptr; p < ptr + size; ++p)
2113 {
2114 if (*p == NL)
2115 try_unix++;
2116 else if (*p == CAR)
2117 try_mac++;
2118 }
2119 if (try_mac > try_unix)
2120 fileformat = EOL_MAC;
2121 }
2122 }
Bram Moolenaar05eb6122015-02-17 14:15:19 +01002123 else if (fileformat == EOL_UNKNOWN && try_mac == 1)
2124 /* Looking for CR but found no end-of-line markers at
2125 * all: use the default format. */
2126 fileformat = default_fileformat();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 }
2128
2129 /* No NL found: may use Mac format */
2130 if (fileformat == EOL_UNKNOWN && try_mac)
2131 fileformat = EOL_MAC;
2132
2133 /* Still nothing found? Use first format in 'ffs' */
2134 if (fileformat == EOL_UNKNOWN)
2135 fileformat = default_fileformat();
2136
2137 /* if editing a new file: may set p_tx and p_ff */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002138 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 set_fileformat(fileformat, OPT_LOCAL);
2140 }
2141 }
2142
2143 /*
2144 * This loop is executed once for every character read.
2145 * Keep it fast!
2146 */
2147 if (fileformat == EOL_MAC)
2148 {
2149 --ptr;
2150 while (++ptr, --size >= 0)
2151 {
2152 /* catch most common case first */
2153 if ((c = *ptr) != NUL && c != CAR && c != NL)
2154 continue;
2155 if (c == NUL)
2156 *ptr = NL; /* NULs are replaced by newlines! */
2157 else if (c == NL)
2158 *ptr = CAR; /* NLs are replaced by CRs! */
2159 else
2160 {
2161 if (skip_count == 0)
2162 {
2163 *ptr = NUL; /* end of line */
2164 len = (colnr_T) (ptr - line_start + 1);
2165 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2166 {
2167 error = TRUE;
2168 break;
2169 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002170#ifdef FEAT_PERSISTENT_UNDO
2171 if (read_undo_file)
2172 sha256_update(&sha_ctx, line_start, len);
2173#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174 ++lnum;
2175 if (--read_count == 0)
2176 {
2177 error = TRUE; /* break loop */
2178 line_start = ptr; /* nothing left to write */
2179 break;
2180 }
2181 }
2182 else
2183 --skip_count;
2184 line_start = ptr + 1;
2185 }
2186 }
2187 }
2188 else
2189 {
2190 --ptr;
2191 while (++ptr, --size >= 0)
2192 {
2193 if ((c = *ptr) != NUL && c != NL) /* catch most common case */
2194 continue;
2195 if (c == NUL)
2196 *ptr = NL; /* NULs are replaced by newlines! */
2197 else
2198 {
2199 if (skip_count == 0)
2200 {
2201 *ptr = NUL; /* end of line */
2202 len = (colnr_T)(ptr - line_start + 1);
2203 if (fileformat == EOL_DOS)
2204 {
Bram Moolenaar2aa5f692017-01-24 15:46:48 +01002205 if (ptr > line_start && ptr[-1] == CAR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 {
Bram Moolenaar2aa5f692017-01-24 15:46:48 +01002207 /* remove CR before NL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 ptr[-1] = NUL;
2209 --len;
2210 }
2211 /*
2212 * Reading in Dos format, but no CR-LF found!
2213 * When 'fileformats' includes "unix", delete all
2214 * the lines read so far and start all over again.
2215 * Otherwise give an error message later.
2216 */
2217 else if (ff_error != EOL_DOS)
2218 {
2219 if ( try_unix
2220 && !read_stdin
2221 && (read_buffer
Bram Moolenaar8767f522016-07-01 17:17:39 +02002222 || vim_lseek(fd, (off_T)0L, SEEK_SET)
2223 == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 {
2225 fileformat = EOL_UNIX;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002226 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 set_fileformat(EOL_UNIX, OPT_LOCAL);
2228 file_rewind = TRUE;
2229 keep_fileformat = TRUE;
2230 goto retry;
2231 }
2232 ff_error = EOL_DOS;
2233 }
2234 }
2235 if (ml_append(lnum, line_start, len, newfile) == FAIL)
2236 {
2237 error = TRUE;
2238 break;
2239 }
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002240#ifdef FEAT_PERSISTENT_UNDO
2241 if (read_undo_file)
2242 sha256_update(&sha_ctx, line_start, len);
2243#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 ++lnum;
2245 if (--read_count == 0)
2246 {
2247 error = TRUE; /* break loop */
2248 line_start = ptr; /* nothing left to write */
2249 break;
2250 }
2251 }
2252 else
2253 --skip_count;
2254 line_start = ptr + 1;
2255 }
2256 }
2257 }
2258 linerest = (long)(ptr - line_start);
2259 ui_breakcheck();
2260 }
2261
2262failed:
2263 /* not an error, max. number of lines reached */
2264 if (error && read_count == 0)
2265 error = FALSE;
2266
2267 /*
2268 * If we get EOF in the middle of a line, note the fact and
2269 * complete the line ourselves.
2270 * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
2271 */
2272 if (!error
2273 && !got_int
2274 && linerest != 0
2275 && !(!curbuf->b_p_bin
2276 && fileformat == EOL_DOS
2277 && *line_start == Ctrl_Z
2278 && ptr == line_start + 1))
2279 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002280 /* remember for when writing */
2281 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 curbuf->b_p_eol = FALSE;
2283 *ptr = NUL;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002284 len = (colnr_T)(ptr - line_start + 1);
2285 if (ml_append(lnum, line_start, len, newfile) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 error = TRUE;
2287 else
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002288 {
2289#ifdef FEAT_PERSISTENT_UNDO
2290 if (read_undo_file)
2291 sha256_update(&sha_ctx, line_start, len);
2292#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 read_no_eol_lnum = ++lnum;
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002294 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 }
2296
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002297 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 save_file_ff(curbuf); /* remember the current file format */
2299
2300#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002301 if (curbuf->b_cryptstate != NULL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002302 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002303 crypt_free_state(curbuf->b_cryptstate);
2304 curbuf->b_cryptstate = NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002305 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002306 if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
2307 crypt_free_key(cryptkey);
2308 /* Don't set cryptkey to NULL, it's used below as a flag that
2309 * encryption was used. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310#endif
2311
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002312 /* If editing a new file: set 'fenc' for the current buffer.
2313 * Also for ":read ++edit file". */
2314 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 set_string_option_direct((char_u *)"fenc", -1, fenc,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00002316 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 if (fenc_alloced)
2318 vim_free(fenc);
Bram Moolenaar13505972019-01-24 15:04:48 +01002319#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (iconv_fd != (iconv_t)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 iconv_close(iconv_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322#endif
2323
2324 if (!read_buffer && !read_stdin)
2325 close(fd); /* errors are ignored */
Bram Moolenaarf05da212009-11-17 16:13:15 +00002326#ifdef HAVE_FD_CLOEXEC
2327 else
2328 {
2329 int fdflags = fcntl(fd, F_GETFD);
2330 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +01002331 (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaarf05da212009-11-17 16:13:15 +00002332 }
2333#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334 vim_free(buffer);
2335
2336#ifdef HAVE_DUP
2337 if (read_stdin)
2338 {
2339 /* Use stderr for stdin, makes shell commands work. */
2340 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02002341 vim_ignored = dup(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 }
2343#endif
2344
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 if (tmpname != NULL)
2346 {
2347 mch_remove(tmpname); /* delete converted file */
2348 vim_free(tmpname);
2349 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 --no_wait_return; /* may wait for return now */
2351
2352 /*
2353 * In recovery mode everything but autocommands is skipped.
2354 */
2355 if (!recoverymode)
2356 {
2357 /* need to delete the last line, which comes from the empty buffer */
2358 if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
2359 {
2360#ifdef FEAT_NETBEANS_INTG
2361 netbeansFireChanges = 0;
2362#endif
2363 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
2364#ifdef FEAT_NETBEANS_INTG
2365 netbeansFireChanges = 1;
2366#endif
2367 --linecnt;
2368 }
2369 linecnt = curbuf->b_ml.ml_line_count - linecnt;
2370 if (filesize == 0)
2371 linecnt = 0;
2372 if (newfile || read_buffer)
Bram Moolenaar7263a772007-05-10 17:35:54 +00002373 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 redraw_curbuf_later(NOT_VALID);
Bram Moolenaar7263a772007-05-10 17:35:54 +00002375#ifdef FEAT_DIFF
2376 /* After reading the text into the buffer the diff info needs to
2377 * be updated. */
2378 diff_invalidate(curbuf);
2379#endif
2380#ifdef FEAT_FOLDING
2381 /* All folds in the window are invalid now. Mark them for update
2382 * before triggering autocommands. */
2383 foldUpdateAll(curwin);
2384#endif
2385 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 else if (linecnt) /* appended at least one line */
2387 appended_lines_mark(from, linecnt);
2388
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389#ifndef ALWAYS_USE_GUI
2390 /*
2391 * If we were reading from the same terminal as where messages go,
2392 * the screen will have been messed up.
2393 * Switch on raw mode now and clear the screen.
2394 */
2395 if (read_stdin)
2396 {
2397 settmode(TMODE_RAW); /* set to raw mode */
2398 starttermcap();
2399 screenclear();
2400 }
2401#endif
2402
2403 if (got_int)
2404 {
2405 if (!(flags & READ_DUMMY))
2406 {
2407 filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
2408 if (newfile)
2409 curbuf->b_p_ro = TRUE; /* must use "w!" now */
2410 }
2411 msg_scroll = msg_save;
2412#ifdef FEAT_VIMINFO
2413 check_marks_read();
2414#endif
2415 return OK; /* an interrupt isn't really an error */
2416 }
2417
2418 if (!filtering && !(flags & READ_DUMMY))
2419 {
2420 msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
2421 c = FALSE;
2422
2423#ifdef UNIX
Bram Moolenaard569bb02018-08-11 13:57:20 +02002424 if (S_ISFIFO(perm)) /* fifo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 {
2426 STRCAT(IObuff, _("[fifo]"));
2427 c = TRUE;
2428 }
Bram Moolenaard569bb02018-08-11 13:57:20 +02002429 if (S_ISSOCK(perm)) /* or socket */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 {
2431 STRCAT(IObuff, _("[socket]"));
2432 c = TRUE;
2433 }
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002434# ifdef OPEN_CHR_FILES
2435 if (S_ISCHR(perm)) /* or character special */
2436 {
2437 STRCAT(IObuff, _("[character special]"));
2438 c = TRUE;
2439 }
2440# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441#endif
2442 if (curbuf->b_p_ro)
2443 {
2444 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
2445 c = TRUE;
2446 }
2447 if (read_no_eol_lnum)
2448 {
2449 msg_add_eol();
2450 c = TRUE;
2451 }
2452 if (ff_error == EOL_DOS)
2453 {
2454 STRCAT(IObuff, _("[CR missing]"));
2455 c = TRUE;
2456 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 if (split)
2458 {
2459 STRCAT(IObuff, _("[long lines split]"));
2460 c = TRUE;
2461 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 if (notconverted)
2463 {
2464 STRCAT(IObuff, _("[NOT converted]"));
2465 c = TRUE;
2466 }
2467 else if (converted)
2468 {
2469 STRCAT(IObuff, _("[converted]"));
2470 c = TRUE;
2471 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472#ifdef FEAT_CRYPT
2473 if (cryptkey != NULL)
2474 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002475 crypt_append_msg(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 c = TRUE;
2477 }
2478#endif
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002479 if (conv_error != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 {
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002481 sprintf((char *)IObuff + STRLEN(IObuff),
2482 _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483 c = TRUE;
2484 }
2485 else if (illegal_byte > 0)
2486 {
2487 sprintf((char *)IObuff + STRLEN(IObuff),
2488 _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
2489 c = TRUE;
2490 }
Bram Moolenaar13505972019-01-24 15:04:48 +01002491 else if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 {
2493 STRCAT(IObuff, _("[READ ERRORS]"));
2494 c = TRUE;
2495 }
2496 if (msg_add_fileformat(fileformat))
2497 c = TRUE;
2498#ifdef FEAT_CRYPT
2499 if (cryptkey != NULL)
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002500 msg_add_lines(c, (long)linecnt, filesize
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002501 - crypt_get_header_len(crypt_get_method_nr(curbuf)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 else
2503#endif
2504 msg_add_lines(c, (long)linecnt, filesize);
2505
Bram Moolenaard23a8232018-02-10 18:45:26 +01002506 VIM_CLEAR(keep_msg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 msg_scrolled_ign = TRUE;
2508#ifdef ALWAYS_USE_GUI
2509 /* Don't show the message when reading stdin, it would end up in a
2510 * message box (which might be shown when exiting!) */
2511 if (read_stdin || read_buffer)
2512 p = msg_may_trunc(FALSE, IObuff);
2513 else
2514#endif
Bram Moolenaar32526b32019-01-19 17:43:09 +01002515 p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 if (read_stdin || read_buffer || restart_edit != 0
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002517 || (msg_scrolled != 0 && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 /* Need to repeat the message after redrawing when:
2519 * - When reading from stdin (the screen will be cleared next).
2520 * - When restart_edit is set (otherwise there will be a delay
2521 * before redrawing).
2522 * - When the screen was scrolled but there is no wait-return
2523 * prompt. */
Bram Moolenaar8f7fd652006-02-21 22:04:51 +00002524 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 msg_scrolled_ign = FALSE;
2526 }
2527
2528 /* with errors writing the file requires ":w!" */
2529 if (newfile && (error
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002530 || conv_error != 0
Bram Moolenaar13505972019-01-24 15:04:48 +01002531 || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 curbuf->b_p_ro = TRUE;
2533
2534 u_clearline(); /* cannot use "U" command after adding lines */
2535
2536 /*
2537 * In Ex mode: cursor at last new line.
2538 * Otherwise: cursor at first new line.
2539 */
2540 if (exmode_active)
2541 curwin->w_cursor.lnum = from + linecnt;
2542 else
2543 curwin->w_cursor.lnum = from + 1;
2544 check_cursor_lnum();
2545 beginline(BL_WHITE | BL_FIX); /* on first non-blank */
2546
2547 /*
2548 * Set '[ and '] marks to the newly read lines.
2549 */
2550 curbuf->b_op_start.lnum = from + 1;
2551 curbuf->b_op_start.col = 0;
2552 curbuf->b_op_end.lnum = from + linecnt;
2553 curbuf->b_op_end.col = 0;
Bram Moolenaar03f48552006-02-28 23:52:23 +00002554
Bram Moolenaar4f974752019-02-17 17:44:42 +01002555#ifdef MSWIN
Bram Moolenaar03f48552006-02-28 23:52:23 +00002556 /*
2557 * Work around a weird problem: When a file has two links (only
2558 * possible on NTFS) and we write through one link, then stat() it
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00002559 * through the other link, the timestamp information may be wrong.
Bram Moolenaar03f48552006-02-28 23:52:23 +00002560 * It's correct again after reading the file, thus reset the timestamp
2561 * here.
2562 */
2563 if (newfile && !read_stdin && !read_buffer
2564 && mch_stat((char *)fname, &st) >= 0)
2565 {
2566 buf_store_time(curbuf, &st, fname);
2567 curbuf->b_mtime_read = curbuf->b_mtime;
2568 }
2569#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 }
2571 msg_scroll = msg_save;
2572
2573#ifdef FEAT_VIMINFO
2574 /*
2575 * Get the marks before executing autocommands, so they can be used there.
2576 */
2577 check_marks_read();
2578#endif
2579
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 /*
Bram Moolenaar34d72d42015-07-17 14:18:08 +02002581 * We remember if the last line of the read didn't have
2582 * an eol even when 'binary' is off, to support turning 'fixeol' off,
2583 * or writing the read again with 'binary' on. The latter is required
2584 * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002586 curbuf->b_no_eol_lnum = read_no_eol_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02002588 /* When reloading a buffer put the cursor at the first line that is
2589 * different. */
2590 if (flags & READ_KEEP_UNDO)
2591 u_find_first_changed();
2592
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002593#ifdef FEAT_PERSISTENT_UNDO
2594 /*
2595 * When opening a new file locate undo info and read it.
2596 */
2597 if (read_undo_file)
2598 {
2599 char_u hash[UNDO_HASH_SIZE];
2600
2601 sha256_finish(&sha_ctx, hash);
Bram Moolenaar6ed8ed82010-05-30 20:40:11 +02002602 u_read_undo(NULL, hash, fname);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02002603 }
2604#endif
2605
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02002606 if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 {
2608 int m = msg_scroll;
2609 int n = msg_scrolled;
2610
2611 /* Save the fileformat now, otherwise the buffer will be considered
2612 * modified if the format/encoding was automatically detected. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002613 if (set_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 save_file_ff(curbuf);
2615
2616 /*
2617 * The output from the autocommands should not overwrite anything and
2618 * should not be overwritten: Set msg_scroll, restore its value if no
2619 * output was done.
2620 */
2621 msg_scroll = TRUE;
2622 if (filtering)
2623 apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
2624 FALSE, curbuf, eap);
Bram Moolenaarf71d7b92016-08-09 22:14:05 +02002625 else if (newfile || (read_buffer && sfname != NULL))
Bram Moolenaarc3691332016-04-20 12:49:49 +02002626 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
2628 FALSE, curbuf, eap);
Bram Moolenaarc3691332016-04-20 12:49:49 +02002629 if (!au_did_filetype && *curbuf->b_p_ft != NUL)
2630 /*
2631 * EVENT_FILETYPE was not triggered but the buffer already has a
2632 * filetype. Trigger EVENT_FILETYPE using the existing filetype.
2633 */
2634 apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
2635 TRUE, curbuf);
2636 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 else
2638 apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
2639 FALSE, NULL, eap);
2640 if (msg_scrolled == n)
2641 msg_scroll = m;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002642# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 if (aborting()) /* autocmds may abort script processing */
2644 return FAIL;
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01002645# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647
2648 if (recoverymode && error)
2649 return FAIL;
2650 return OK;
2651}
2652
Bram Moolenaarf04507d2016-08-20 15:05:39 +02002653#if defined(OPEN_CHR_FILES) || defined(PROTO)
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002654/*
2655 * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
2656 * which is the name of files used for process substitution output by
2657 * some shells on some operating systems, e.g., bash on SunOS.
2658 * Do not accept "/dev/fd/[012]", opening these may hang Vim.
2659 */
Bram Moolenaarf04507d2016-08-20 15:05:39 +02002660 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002661is_dev_fd_file(char_u *fname)
Bram Moolenaarfe1c56d2007-07-10 15:10:54 +00002662{
2663 return (STRNCMP(fname, "/dev/fd/", 8) == 0
2664 && VIM_ISDIGIT(fname[8])
2665 && *skipdigits(fname + 9) == NUL
2666 && (fname[9] != NUL
2667 || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
2668}
2669#endif
2670
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002671/*
2672 * From the current line count and characters read after that, estimate the
2673 * line number where we are now.
2674 * Used for error messages that include a line number.
2675 */
2676 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002677readfile_linenr(
2678 linenr_T linecnt, /* line count before reading more bytes */
2679 char_u *p, /* start of more bytes read */
2680 char_u *endp) /* end of more bytes read */
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002681{
2682 char_u *s;
2683 linenr_T lnum;
2684
2685 lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
2686 for (s = p; s < endp; ++s)
2687 if (*s == '\n')
2688 ++lnum;
2689 return lnum;
2690}
Bram Moolenaarb0bf8582005-12-13 20:02:15 +00002691
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692/*
Bram Moolenaar195d6352005-12-19 22:08:24 +00002693 * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
2694 * equal to the buffer "buf". Used for calling readfile().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 * Returns OK or FAIL.
2696 */
2697 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002698prep_exarg(exarg_T *eap, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699{
Bram Moolenaar13505972019-01-24 15:04:48 +01002700 eap->cmd = alloc(15 + (unsigned)STRLEN(buf->b_p_fenc));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 if (eap->cmd == NULL)
2702 return FAIL;
2703
Bram Moolenaar333b80a2018-04-04 22:57:29 +02002704 sprintf((char *)eap->cmd, "e ++enc=%s", buf->b_p_fenc);
2705 eap->force_enc = 8;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002706 eap->bad_char = buf->b_bad_char;
Bram Moolenaar333b80a2018-04-04 22:57:29 +02002707 eap->force_ff = *buf->b_p_ff;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002708
2709 eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002710 eap->read_edit = FALSE;
Bram Moolenaar195d6352005-12-19 22:08:24 +00002711 eap->forceit = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 return OK;
2713}
2714
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002715/*
2716 * Set default or forced 'fileformat' and 'binary'.
2717 */
2718 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002719set_file_options(int set_options, exarg_T *eap)
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002720{
2721 /* set default 'fileformat' */
2722 if (set_options)
2723 {
2724 if (eap != NULL && eap->force_ff != 0)
2725 set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
2726 else if (*p_ffs != NUL)
2727 set_fileformat(default_fileformat(), OPT_LOCAL);
2728 }
2729
2730 /* set or reset 'binary' */
2731 if (eap != NULL && eap->force_bin != 0)
2732 {
2733 int oldval = curbuf->b_p_bin;
2734
2735 curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
2736 set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
2737 }
2738}
2739
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002740/*
2741 * Set forced 'fileencoding'.
2742 */
2743 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002744set_forced_fenc(exarg_T *eap)
Bram Moolenaarad875fb2013-07-24 15:02:03 +02002745{
2746 if (eap->force_enc != 0)
2747 {
2748 char_u *fenc = enc_canonize(eap->cmd + eap->force_enc);
2749
2750 if (fenc != NULL)
2751 set_string_option_direct((char_u *)"fenc", -1,
2752 fenc, OPT_FREE|OPT_LOCAL, 0);
2753 vim_free(fenc);
2754 }
2755}
2756
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757/*
2758 * Find next fileencoding to use from 'fileencodings'.
2759 * "pp" points to fenc_next. It's advanced to the next item.
2760 * When there are no more items, an empty string is returned and *pp is set to
2761 * NULL.
Bram Moolenaarf077db22019-08-13 00:18:24 +02002762 * When *pp is not set to NULL, the result is in allocated memory and "alloced"
2763 * is set to TRUE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 */
2765 static char_u *
Bram Moolenaarf077db22019-08-13 00:18:24 +02002766next_fenc(char_u **pp, int *alloced)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767{
2768 char_u *p;
2769 char_u *r;
2770
Bram Moolenaarf077db22019-08-13 00:18:24 +02002771 *alloced = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772 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 }
Bram Moolenaarf077db22019-08-13 00:18:24 +02002794 if (r != NULL)
2795 *alloced = TRUE;
2796 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797 {
Bram Moolenaarf077db22019-08-13 00:18:24 +02002798 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 r = (char_u *)"";
2800 *pp = NULL;
2801 }
2802 return r;
2803}
2804
Bram Moolenaar13505972019-01-24 15:04:48 +01002805#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806/*
2807 * Convert a file with the 'charconvert' expression.
2808 * This closes the file which is to be read, converts it and opens the
2809 * resulting file for reading.
2810 * Returns name of the resulting converted file (the caller should delete it
2811 * after reading it).
2812 * Returns NULL if the conversion failed ("*fdp" is not set) .
2813 */
2814 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002815readfile_charconvert(
2816 char_u *fname, /* name of input file */
2817 char_u *fenc, /* converted from */
2818 int *fdp) /* in/out: file descriptor of file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819{
2820 char_u *tmpname;
Bram Moolenaar32526b32019-01-19 17:43:09 +01002821 char *errmsg = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822
Bram Moolenaare5c421c2015-03-31 13:33:08 +02002823 tmpname = vim_tempname('r', FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 if (tmpname == NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002825 errmsg = _("Can't find temp file for conversion");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 else
2827 {
2828 close(*fdp); /* close the input file, ignore errors */
2829 *fdp = -1;
2830 if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
2831 fname, tmpname) == FAIL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002832 errmsg = _("Conversion with 'charconvert' failed");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
2834 O_RDONLY | O_EXTRA, 0)) < 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01002835 errmsg = _("can't read output of 'charconvert'");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836 }
2837
2838 if (errmsg != NULL)
2839 {
2840 /* Don't use emsg(), it breaks mappings, the retry with
2841 * another type of conversion might still work. */
Bram Moolenaar32526b32019-01-19 17:43:09 +01002842 msg(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 if (tmpname != NULL)
2844 {
2845 mch_remove(tmpname); /* delete converted file */
Bram Moolenaard23a8232018-02-10 18:45:26 +01002846 VIM_CLEAR(tmpname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 }
2848 }
2849
2850 /* If the input file is closed, open it (caller should check for error). */
2851 if (*fdp < 0)
2852 *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2853
2854 return tmpname;
2855}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856#endif
2857
Bram Moolenaara3ff49f2010-05-30 22:48:02 +02002858#if defined(FEAT_CRYPT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859/*
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002860 * Check for magic number used for encryption. Applies to the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 * If found, the magic number is removed from ptr[*sizep] and *sizep and
2862 * *filesizep are updated.
2863 * Return the (new) encryption key, NULL for no encryption.
2864 */
2865 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002866check_for_cryptkey(
2867 char_u *cryptkey, /* previous encryption key or NULL */
2868 char_u *ptr, /* pointer to read bytes */
2869 long *sizep, /* length of read bytes */
Bram Moolenaar8767f522016-07-01 17:17:39 +02002870 off_T *filesizep, /* nr of bytes used from file */
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002871 int newfile, /* editing a new buffer */
2872 char_u *fname, /* file name to display */
2873 int *did_ask) /* flag: whether already asked for key */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874{
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002875 int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002876 int b_p_ro = curbuf->b_p_ro;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002877
2878 if (method >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 {
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002880 /* Mark the buffer as read-only until the decryption has taken place.
2881 * Avoids accidentally overwriting the file with garbage. */
2882 curbuf->b_p_ro = TRUE;
2883
Bram Moolenaar2be79502014-08-13 21:58:28 +02002884 /* Set the cryptmethod local to the buffer. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002885 crypt_set_cm_option(curbuf, method);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002886 if (cryptkey == NULL && !*did_ask)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 {
2888 if (*curbuf->b_p_key)
2889 cryptkey = curbuf->b_p_key;
2890 else
2891 {
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002892 /* When newfile is TRUE, store the typed key in the 'key'
2893 * option and don't free it. bf needs hash of the key saved.
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002894 * Don't ask for the key again when first time Enter was hit.
2895 * Happens when retrying to detect encoding. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002896 smsg(_(need_key_msg), fname);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002897 msg_scroll = TRUE;
Bram Moolenaar3a0c9082014-11-12 15:15:42 +01002898 crypt_check_method(method);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002899 cryptkey = crypt_get_key(newfile, FALSE);
Bram Moolenaarf50a2532010-05-21 15:36:08 +02002900 *did_ask = TRUE;
2901
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 /* check if empty key entered */
2903 if (cryptkey != NULL && *cryptkey == NUL)
2904 {
2905 if (cryptkey != curbuf->b_p_key)
2906 vim_free(cryptkey);
2907 cryptkey = NULL;
2908 }
2909 }
2910 }
2911
2912 if (cryptkey != NULL)
2913 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002914 int header_len;
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002915
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002916 curbuf->b_cryptstate = crypt_create_from_header(
2917 method, cryptkey, ptr);
2918 crypt_set_cm_option(curbuf, method);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002920 /* Remove cryptmethod specific header from the text. */
2921 header_len = crypt_get_header_len(method);
Bram Moolenaar680e0152016-09-25 20:54:11 +02002922 if (*sizep <= header_len)
2923 /* invalid header, buffer can't be encrypted */
2924 return NULL;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002925 *filesizep += header_len;
2926 *sizep -= header_len;
2927 mch_memmove(ptr, ptr + header_len, (size_t)*sizep);
2928
Bram Moolenaarcf81aef2013-08-25 17:46:08 +02002929 /* Restore the read-only flag. */
2930 curbuf->b_p_ro = b_p_ro;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 }
2932 }
Bram Moolenaar40e6a712010-05-16 22:32:54 +02002933 /* When starting to edit a new file which does not have encryption, clear
2934 * the 'key' option, except when starting up (called with -x argument) */
Bram Moolenaarfa0ff9a2010-07-25 16:05:19 +02002935 else if (newfile && *curbuf->b_p_key != NUL && !starting)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
2937
2938 return cryptkey;
2939}
Bram Moolenaar80794b12010-06-13 05:20:42 +02002940#endif /* FEAT_CRYPT */
2941
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942#ifdef UNIX
2943 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002944set_file_time(
2945 char_u *fname,
2946 time_t atime, /* access time */
2947 time_t mtime) /* modification time */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948{
2949# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
2950 struct utimbuf buf;
2951
2952 buf.actime = atime;
2953 buf.modtime = mtime;
2954 (void)utime((char *)fname, &buf);
2955# else
2956# if defined(HAVE_UTIMES)
2957 struct timeval tvp[2];
2958
2959 tvp[0].tv_sec = atime;
2960 tvp[0].tv_usec = 0;
2961 tvp[1].tv_sec = mtime;
2962 tvp[1].tv_usec = 0;
2963# ifdef NeXT
2964 (void)utimes((char *)fname, tvp);
2965# else
2966 (void)utimes((char *)fname, (const struct timeval *)&tvp);
2967# endif
2968# endif
2969# endif
2970}
2971#endif /* UNIX */
2972
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002973#if defined(VMS) && !defined(MIN)
2974/* Older DECC compiler for VAX doesn't define MIN() */
2975# define MIN(a, b) ((a) < (b) ? (a) : (b))
2976#endif
2977
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00002979 * Return TRUE if a file appears to be read-only from the file permissions.
2980 */
2981 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002982check_file_readonly(
2983 char_u *fname, /* full path to file */
Bram Moolenaarbd67aac2019-09-21 23:09:04 +02002984 int perm UNUSED) /* known permissions on file */
Bram Moolenaar5386a122007-06-28 20:02:32 +00002985{
2986#ifndef USE_MCH_ACCESS
2987 int fd = 0;
2988#endif
2989
2990 return (
2991#ifdef USE_MCH_ACCESS
2992# ifdef UNIX
2993 (perm & 0222) == 0 ||
2994# endif
2995 mch_access((char *)fname, W_OK)
2996#else
2997 (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
2998 ? TRUE : (close(fd), FALSE)
2999#endif
3000 );
3001}
3002
3003
3004/*
Bram Moolenaar292ad192005-12-11 21:29:51 +00003005 * buf_write() - write to file "fname" lines "start" through "end"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 *
3007 * We do our own buffering here because fwrite() is so slow.
3008 *
Bram Moolenaar292ad192005-12-11 21:29:51 +00003009 * If "forceit" is true, we don't care for errors when attempting backups.
3010 * In case of an error everything possible is done to restore the original
Bram Moolenaare37d50a2008-08-06 17:06:04 +00003011 * file. But when "forceit" is TRUE, we risk losing it.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003012 *
3013 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
3014 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 *
3016 * This function must NOT use NameBuff (because it's called by autowrite()).
3017 *
3018 * return FAIL for failure, OK otherwise
3019 */
3020 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003021buf_write(
3022 buf_T *buf,
3023 char_u *fname,
3024 char_u *sfname,
3025 linenr_T start,
3026 linenr_T end,
3027 exarg_T *eap, /* for forced 'ff' and 'fenc', can be
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 NULL! */
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003029 int append, /* append to the file */
3030 int forceit,
3031 int reset_changed,
3032 int filtering)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033{
3034 int fd;
3035 char_u *backup = NULL;
3036 int backup_copy = FALSE; /* copy the original file? */
3037 int dobackup;
3038 char_u *ffname;
3039 char_u *wfname = NULL; /* name of file to write to */
3040 char_u *s;
3041 char_u *ptr;
3042 char_u c;
3043 int len;
3044 linenr_T lnum;
3045 long nchars;
3046 char_u *errmsg = NULL;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003047 int errmsg_allocated = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048 char_u *errnum = NULL;
3049 char_u *buffer;
3050 char_u smallbuf[SMBUFSIZE];
3051 char_u *backup_ext;
3052 int bufsize;
3053 long perm; /* file permissions */
3054 int retval = OK;
3055 int newfile = FALSE; /* TRUE if file doesn't exist yet */
3056 int msg_save = msg_scroll;
3057 int overwriting; /* TRUE if writing over original */
3058 int no_eol = FALSE; /* no end-of-line written */
3059 int device = FALSE; /* writing to a device */
Bram Moolenaar8767f522016-07-01 17:17:39 +02003060 stat_T st_old;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 int prev_got_int = got_int;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02003062 int checking_conversion;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063 int file_readonly = FALSE; /* overwritten file is read-only */
3064 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
Bram Moolenaara06ecab2016-07-16 14:47:36 +02003065#if defined(UNIX) /*XXX fix me sometime? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 int made_writable = FALSE; /* 'w' bit has been set */
3067#endif
3068 /* writing everything */
3069 int whole = (start == 1 && end == buf->b_ml.ml_line_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 linenr_T old_line_count = buf->b_ml.ml_line_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 int attr;
3072 int fileformat;
3073 int write_bin;
3074 struct bw_info write_info; /* info for buf_write_bytes() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 int converted = FALSE;
3076 int notconverted = FALSE;
3077 char_u *fenc; /* effective 'fileencoding' */
3078 char_u *fenc_tofree = NULL; /* allocated "fenc" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079#ifdef HAS_BW_FLAGS
3080 int wb_flags = 0;
3081#endif
3082#ifdef HAVE_ACL
3083 vim_acl_T acl = NULL; /* ACL copied from original file to
3084 backup or new file */
3085#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003086#ifdef FEAT_PERSISTENT_UNDO
3087 int write_undo_file = FALSE;
3088 context_sha256_T sha_ctx;
3089#endif
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003090 unsigned int bkc = get_bkc_value(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091
3092 if (fname == NULL || *fname == NUL) /* safety check */
3093 return FAIL;
Bram Moolenaar70d60e92009-12-31 13:53:33 +00003094 if (buf->b_ml.ml_mfp == NULL)
3095 {
3096 /* This can happen during startup when there is a stray "w" in the
3097 * vimrc file. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003098 emsg(_(e_emptybuf));
Bram Moolenaar70d60e92009-12-31 13:53:33 +00003099 return FAIL;
3100 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101
3102 /*
3103 * Disallow writing from .exrc and .vimrc in current directory for
3104 * security reasons.
3105 */
3106 if (check_secure())
3107 return FAIL;
3108
3109 /* Avoid a crash for a long name. */
3110 if (STRLEN(fname) >= MAXPATHL)
3111 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003112 emsg(_(e_longname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113 return FAIL;
3114 }
3115
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
3117 write_info.bw_conv_buf = NULL;
3118 write_info.bw_conv_error = FALSE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00003119 write_info.bw_conv_error_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 write_info.bw_restlen = 0;
Bram Moolenaar13505972019-01-24 15:04:48 +01003121#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 write_info.bw_iconv_fd = (iconv_t)-1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02003124#ifdef FEAT_CRYPT
3125 write_info.bw_buffer = buf;
3126#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127
Bram Moolenaardf177f62005-02-22 08:39:57 +00003128 /* After writing a file changedtick changes but we don't want to display
3129 * the line. */
3130 ex_no_reprint = TRUE;
3131
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 /*
3133 * If there is no file name yet, use the one for the written file.
3134 * BF_NOTEDITED is set to reflect this (in case the write fails).
3135 * Don't do this when the write is for a filter command.
Bram Moolenaar292ad192005-12-11 21:29:51 +00003136 * Don't do this when appending.
3137 * Only do this when 'cpoptions' contains the 'F' flag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 */
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003139 if (buf->b_ffname == NULL
3140 && reset_changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 && whole
3142 && buf == curbuf
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003143#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003144 && !bt_nofilename(buf)
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00003145#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 && !filtering
Bram Moolenaar292ad192005-12-11 21:29:51 +00003147 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
3149 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003150 if (set_rw_fname(fname, sfname) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151 return FAIL;
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003152 buf = curbuf; /* just in case autocmds made "buf" invalid */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 }
3154
3155 if (sfname == NULL)
3156 sfname = fname;
3157 /*
3158 * For Unix: Use the short file name whenever possible.
3159 * Avoids problems with networks and when directory names are changed.
3160 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
3161 * another directory, which we don't detect
3162 */
3163 ffname = fname; /* remember full fname */
3164#ifdef UNIX
3165 fname = sfname;
3166#endif
3167
3168 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
3169 overwriting = TRUE;
3170 else
3171 overwriting = FALSE;
3172
3173 if (exiting)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003174 settmode(TMODE_COOK); /* when exiting allow typeahead now */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175
3176 ++no_wait_return; /* don't wait for return yet */
3177
3178 /*
3179 * Set '[ and '] marks to the lines to be written.
3180 */
3181 buf->b_op_start.lnum = start;
3182 buf->b_op_start.col = 0;
3183 buf->b_op_end.lnum = end;
3184 buf->b_op_end.col = 0;
3185
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 {
3187 aco_save_T aco;
3188 int buf_ffname = FALSE;
3189 int buf_sfname = FALSE;
3190 int buf_fname_f = FALSE;
3191 int buf_fname_s = FALSE;
3192 int did_cmd = FALSE;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003193 int nofile_err = FALSE;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003194 int empty_memline = (buf->b_ml.ml_mfp == NULL);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003195 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196
3197 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003198 * Apply PRE autocommands.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 * Set curbuf to the buffer to be written.
3200 * Careful: The autocommands may call buf_write() recursively!
3201 */
3202 if (ffname == buf->b_ffname)
3203 buf_ffname = TRUE;
3204 if (sfname == buf->b_sfname)
3205 buf_sfname = TRUE;
3206 if (fname == buf->b_ffname)
3207 buf_fname_f = TRUE;
3208 if (fname == buf->b_sfname)
3209 buf_fname_s = TRUE;
3210
3211 /* set curwin/curbuf to buf and save a few things */
3212 aucmd_prepbuf(&aco, buf);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003213 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214
3215 if (append)
3216 {
3217 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
3218 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003219 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003220#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003221 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003222 nofile_err = TRUE;
3223 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003224#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003225 apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 }
3229 else if (filtering)
3230 {
3231 apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
3232 NULL, sfname, FALSE, curbuf, eap);
3233 }
3234 else if (reset_changed && whole)
3235 {
Bram Moolenaar39fc42e2011-09-02 11:56:20 +02003236 int was_changed = curbufIsChanged();
3237
3238 did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
3239 sfname, sfname, FALSE, curbuf, eap);
3240 if (did_cmd)
3241 {
3242 if (was_changed && !curbufIsChanged())
3243 {
3244 /* Written everything correctly and BufWriteCmd has reset
3245 * 'modified': Correct the undo information so that an
3246 * undo now sets 'modified'. */
3247 u_unchanged(curbuf);
3248 u_update_save_nr(curbuf);
3249 }
3250 }
3251 else
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003252 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003253#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003254 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003255 nofile_err = TRUE;
3256 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003257#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003258 apply_autocmds_exarg(EVENT_BUFWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003260 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 }
3262 else
3263 {
3264 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
3265 sfname, sfname, FALSE, curbuf, eap)))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003266 {
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003267#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02003268 if (overwriting && bt_nofilename(curbuf))
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003269 nofile_err = TRUE;
3270 else
Bram Moolenaarb1b715d2006-01-21 22:09:43 +00003271#endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003272 apply_autocmds_exarg(EVENT_FILEWRITEPRE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273 sfname, sfname, FALSE, curbuf, eap);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003274 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275 }
3276
3277 /* restore curwin/curbuf and a few other things */
3278 aucmd_restbuf(&aco);
3279
3280 /*
3281 * In three situations we return here and don't write the file:
3282 * 1. the autocommands deleted or unloaded the buffer.
3283 * 2. The autocommands abort script processing.
3284 * 3. If one of the "Cmd" autocommands was executed.
3285 */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02003286 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 buf = NULL;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003288 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
Bram Moolenaar1e015462005-09-25 22:16:38 +00003289 || did_cmd || nofile_err
3290#ifdef FEAT_EVAL
3291 || aborting()
3292#endif
3293 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 {
3295 --no_wait_return;
3296 msg_scroll = msg_save;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003297 if (nofile_err)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003298 emsg(_("E676: No matching autocommands for acwrite buffer"));
Bram Moolenaar21cf8232004-07-16 20:18:37 +00003299
Bram Moolenaar1e015462005-09-25 22:16:38 +00003300 if (nofile_err
3301#ifdef FEAT_EVAL
3302 || aborting()
3303#endif
3304 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305 /* An aborting error, interrupt or exception in the
3306 * autocommands. */
3307 return FAIL;
3308 if (did_cmd)
3309 {
3310 if (buf == NULL)
3311 /* The buffer was deleted. We assume it was written
3312 * (can't retry anyway). */
3313 return OK;
3314 if (overwriting)
3315 {
3316 /* Assume the buffer was written, update the timestamp. */
3317 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00003318 if (append)
3319 buf->b_flags &= ~BF_NEW;
3320 else
3321 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 }
Bram Moolenaar292ad192005-12-11 21:29:51 +00003323 if (reset_changed && buf->b_changed && !append
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003324 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 /* Buffer still changed, the autocommands didn't work
3326 * properly. */
3327 return FAIL;
3328 return OK;
3329 }
3330#ifdef FEAT_EVAL
3331 if (!aborting())
3332#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003333 emsg(_("E203: Autocommands deleted or unloaded buffer to be written"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 return FAIL;
3335 }
3336
3337 /*
3338 * The autocommands may have changed the number of lines in the file.
3339 * When writing the whole file, adjust the end.
3340 * When writing part of the file, assume that the autocommands only
3341 * changed the number of lines that are to be written (tricky!).
3342 */
3343 if (buf->b_ml.ml_line_count != old_line_count)
3344 {
3345 if (whole) /* write all */
3346 end = buf->b_ml.ml_line_count;
3347 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
3348 end += buf->b_ml.ml_line_count - old_line_count;
3349 else /* less lines */
3350 {
3351 end -= old_line_count - buf->b_ml.ml_line_count;
3352 if (end < start)
3353 {
3354 --no_wait_return;
3355 msg_scroll = msg_save;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003356 emsg(_("E204: Autocommand changed number of lines in unexpected way"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357 return FAIL;
3358 }
3359 }
3360 }
3361
3362 /*
3363 * The autocommands may have changed the name of the buffer, which may
3364 * be kept in fname, ffname and sfname.
3365 */
3366 if (buf_ffname)
3367 ffname = buf->b_ffname;
3368 if (buf_sfname)
3369 sfname = buf->b_sfname;
3370 if (buf_fname_f)
3371 fname = buf->b_ffname;
3372 if (buf_fname_s)
3373 fname = buf->b_sfname;
3374 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375
3376#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003377 if (netbeans_active() && isNetbeansBuffer(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 {
3379 if (whole)
3380 {
3381 /*
3382 * b_changed can be 0 after an undo, but we still need to write
3383 * the buffer to NetBeans.
3384 */
3385 if (buf->b_changed || isNetbeansModified(buf))
3386 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003387 --no_wait_return; /* may wait for return now */
3388 msg_scroll = msg_save;
3389 netbeans_save_buffer(buf); /* no error checking... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390 return retval;
3391 }
3392 else
3393 {
3394 errnum = (char_u *)"E656: ";
Bram Moolenaared0e7452008-06-27 19:17:34 +00003395 errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 buffer = NULL;
3397 goto fail;
3398 }
3399 }
3400 else
3401 {
3402 errnum = (char_u *)"E657: ";
3403 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
3404 buffer = NULL;
3405 goto fail;
3406 }
3407 }
3408#endif
3409
3410 if (shortmess(SHM_OVER) && !exiting)
3411 msg_scroll = FALSE; /* overwrite previous file message */
3412 else
3413 msg_scroll = TRUE; /* don't overwrite previous file message */
3414 if (!filtering)
3415 filemess(buf,
3416#ifndef UNIX
3417 sfname,
3418#else
3419 fname,
3420#endif
3421 (char_u *)"", 0); /* show that we are busy */
3422 msg_scroll = FALSE; /* always overwrite the file message now */
3423
3424 buffer = alloc(BUFSIZE);
3425 if (buffer == NULL) /* can't allocate big buffer, use small
3426 * one (to be able to write when out of
3427 * memory) */
3428 {
3429 buffer = smallbuf;
3430 bufsize = SMBUFSIZE;
3431 }
3432 else
3433 bufsize = BUFSIZE;
3434
3435 /*
3436 * Get information about original file (if there is one).
3437 */
Bram Moolenaar53076832015-12-31 19:53:21 +01003438#if defined(UNIX)
Bram Moolenaar6f192452007-11-08 19:49:02 +00003439 st_old.st_dev = 0;
3440 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441 perm = -1;
3442 if (mch_stat((char *)fname, &st_old) < 0)
3443 newfile = TRUE;
3444 else
3445 {
3446 perm = st_old.st_mode;
3447 if (!S_ISREG(st_old.st_mode)) /* not a file */
3448 {
3449 if (S_ISDIR(st_old.st_mode))
3450 {
3451 errnum = (char_u *)"E502: ";
3452 errmsg = (char_u *)_("is a directory");
3453 goto fail;
3454 }
3455 if (mch_nodetype(fname) != NODE_WRITABLE)
3456 {
3457 errnum = (char_u *)"E503: ";
3458 errmsg = (char_u *)_("is not a file or writable device");
3459 goto fail;
3460 }
3461 /* It's a device of some kind (or a fifo) which we can write to
3462 * but for which we can't make a backup. */
3463 device = TRUE;
3464 newfile = TRUE;
3465 perm = -1;
3466 }
3467 }
3468#else /* !UNIX */
3469 /*
3470 * Check for a writable device name.
3471 */
3472 c = mch_nodetype(fname);
3473 if (c == NODE_OTHER)
3474 {
3475 errnum = (char_u *)"E503: ";
3476 errmsg = (char_u *)_("is not a file or writable device");
3477 goto fail;
3478 }
3479 if (c == NODE_WRITABLE)
3480 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003481# if defined(MSWIN)
Bram Moolenaar043545e2006-10-10 16:44:07 +00003482 /* MS-Windows allows opening a device, but we will probably get stuck
3483 * trying to write to it. */
3484 if (!p_odev)
3485 {
3486 errnum = (char_u *)"E796: ";
3487 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
3488 goto fail;
3489 }
3490# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 device = TRUE;
3492 newfile = TRUE;
3493 perm = -1;
3494 }
3495 else
3496 {
3497 perm = mch_getperm(fname);
3498 if (perm < 0)
3499 newfile = TRUE;
3500 else if (mch_isdir(fname))
3501 {
3502 errnum = (char_u *)"E502: ";
3503 errmsg = (char_u *)_("is a directory");
3504 goto fail;
3505 }
3506 if (overwriting)
3507 (void)mch_stat((char *)fname, &st_old);
3508 }
3509#endif /* !UNIX */
3510
3511 if (!device && !newfile)
3512 {
3513 /*
3514 * Check if the file is really writable (when renaming the file to
3515 * make a backup we won't discover it later).
3516 */
Bram Moolenaar5386a122007-06-28 20:02:32 +00003517 file_readonly = check_file_readonly(fname, (int)perm);
3518
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 if (!forceit && file_readonly)
3520 {
3521 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3522 {
3523 errnum = (char_u *)"E504: ";
3524 errmsg = (char_u *)_(err_readonly);
3525 }
3526 else
3527 {
3528 errnum = (char_u *)"E505: ";
3529 errmsg = (char_u *)_("is read-only (add ! to override)");
3530 }
3531 goto fail;
3532 }
3533
3534 /*
3535 * Check if the timestamp hasn't changed since reading the file.
3536 */
3537 if (overwriting)
3538 {
3539 retval = check_mtime(buf, &st_old);
3540 if (retval == FAIL)
3541 goto fail;
3542 }
3543 }
3544
3545#ifdef HAVE_ACL
3546 /*
3547 * For systems that support ACL: get the ACL from the original file.
3548 */
3549 if (!newfile)
3550 acl = mch_get_acl(fname);
3551#endif
3552
3553 /*
3554 * If 'backupskip' is not empty, don't make a backup for some files.
3555 */
3556 dobackup = (p_wb || p_bk || *p_pm != NUL);
3557#ifdef FEAT_WILDIGN
3558 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
3559 dobackup = FALSE;
3560#endif
3561
3562 /*
3563 * Save the value of got_int and reset it. We don't want a previous
3564 * interruption cancel writing, only hitting CTRL-C while writing should
3565 * abort it.
3566 */
3567 prev_got_int = got_int;
3568 got_int = FALSE;
3569
3570 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
3571 buf->b_saving = TRUE;
3572
3573 /*
3574 * If we are not appending or filtering, the file exists, and the
3575 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
3576 * When 'patchmode' is set also make a backup when appending.
3577 *
3578 * Do not make any backup, if 'writebackup' and 'backup' are both switched
3579 * off. This helps when editing large files on almost-full disks.
3580 */
3581 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
3582 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01003583#if defined(UNIX) || defined(MSWIN)
Bram Moolenaar8767f522016-07-01 17:17:39 +02003584 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585#endif
3586
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003587 if ((bkc & BKC_YES) || append) /* "yes" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 backup_copy = TRUE;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003589#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003590 else if ((bkc & BKC_AUTO)) /* "auto" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 {
3592 int i;
3593
3594# ifdef UNIX
3595 /*
3596 * Don't rename the file when:
3597 * - it's a hard link
3598 * - it's a symbolic link
3599 * - we don't have write permission in the directory
3600 * - we can't set the owner/group of the new file
3601 */
3602 if (st_old.st_nlink > 1
3603 || mch_lstat((char *)fname, &st) < 0
3604 || st.st_dev != st_old.st_dev
Bram Moolenaara5792f52005-11-23 21:25:05 +00003605 || st.st_ino != st_old.st_ino
3606# ifndef HAVE_FCHOWN
3607 || st.st_uid != st_old.st_uid
3608 || st.st_gid != st_old.st_gid
3609# endif
3610 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 backup_copy = TRUE;
3612 else
Bram Moolenaar03f48552006-02-28 23:52:23 +00003613# else
Bram Moolenaar4f974752019-02-17 17:44:42 +01003614# ifdef MSWIN
Bram Moolenaar03f48552006-02-28 23:52:23 +00003615 /* On NTFS file systems hard links are possible. */
3616 if (mch_is_linked(fname))
3617 backup_copy = TRUE;
3618 else
3619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620# endif
3621 {
3622 /*
3623 * Check if we can create a file and set the owner/group to
3624 * the ones from the original file.
3625 * First find a file name that doesn't exist yet (use some
3626 * arbitrary numbers).
3627 */
3628 STRCPY(IObuff, fname);
3629 for (i = 4913; ; i += 123)
3630 {
3631 sprintf((char *)gettail(IObuff), "%d", i);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003632 if (mch_lstat((char *)IObuff, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633 break;
3634 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00003635 fd = mch_open((char *)IObuff,
3636 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 if (fd < 0) /* can't write in directory */
3638 backup_copy = TRUE;
3639 else
3640 {
3641# ifdef UNIX
Bram Moolenaara5792f52005-11-23 21:25:05 +00003642# ifdef HAVE_FCHOWN
Bram Moolenaar42335f52018-09-13 15:33:43 +02003643 vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003644# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645 if (mch_stat((char *)IObuff, &st) < 0
3646 || st.st_uid != st_old.st_uid
3647 || st.st_gid != st_old.st_gid
Bram Moolenaar78a15312009-05-15 19:33:18 +00003648 || (long)st.st_mode != perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649 backup_copy = TRUE;
3650# endif
Bram Moolenaar98358622005-11-28 22:58:23 +00003651 /* Close the file before removing it, on MS-Windows we
3652 * can't delete an open file. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003653 close(fd);
Bram Moolenaar98358622005-11-28 22:58:23 +00003654 mch_remove(IObuff);
Bram Moolenaar3479c5d2010-08-08 18:46:06 +02003655# ifdef MSWIN
3656 /* MS-Windows may trigger a virus scanner to open the
3657 * file, we can't delete it then. Keep trying for half a
3658 * second. */
3659 {
3660 int try;
3661
3662 for (try = 0; try < 10; ++try)
3663 {
3664 if (mch_lstat((char *)IObuff, &st) < 0)
3665 break;
3666 ui_delay(50L, TRUE); /* wait 50 msec */
3667 mch_remove(IObuff);
3668 }
3669 }
3670# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 }
3672 }
3673 }
3674
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675 /*
3676 * Break symlinks and/or hardlinks if we've been asked to.
3677 */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003678 if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 {
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003680# ifdef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 int lstat_res;
3682
3683 lstat_res = mch_lstat((char *)fname, &st);
3684
3685 /* Symlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003686 if ((bkc & BKC_BREAKSYMLINK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 && lstat_res == 0
3688 && st.st_ino != st_old.st_ino)
3689 backup_copy = FALSE;
3690
3691 /* Hardlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003692 if ((bkc & BKC_BREAKHARDLINK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 && st_old.st_nlink > 1
3694 && (lstat_res != 0 || st.st_ino == st_old.st_ino))
3695 backup_copy = FALSE;
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003696# else
Bram Moolenaar4f974752019-02-17 17:44:42 +01003697# if defined(MSWIN)
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003698 /* Symlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003699 if ((bkc & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname))
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003700 backup_copy = FALSE;
3701
3702 /* Hardlinks. */
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02003703 if ((bkc & BKC_BREAKHARDLINK) && mch_is_hard_link(fname))
Bram Moolenaar12b559e2013-06-12 22:41:37 +02003704 backup_copy = FALSE;
3705# endif
3706# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708
3709#endif
3710
3711 /* make sure we have a valid backup extension to use */
3712 if (*p_bex == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 backup_ext = (char_u *)".bak";
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 else
3715 backup_ext = p_bex;
3716
3717 if (backup_copy
3718 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
3719 {
3720 int bfd;
3721 char_u *copybuf, *wp;
3722 int some_error = FALSE;
Bram Moolenaar8767f522016-07-01 17:17:39 +02003723 stat_T st_new;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 char_u *dirp;
3725 char_u *rootname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003726#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003727 char_u *p;
3728#endif
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003729#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 int did_set_shortname;
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003731 mode_t umask_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732#endif
3733
3734 copybuf = alloc(BUFSIZE + 1);
3735 if (copybuf == NULL)
3736 {
3737 some_error = TRUE; /* out of memory */
3738 goto nobackup;
3739 }
3740
3741 /*
3742 * Try to make the backup in each directory in the 'bdir' option.
3743 *
3744 * Unix semantics has it, that we may have a writable file,
3745 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
3746 * - the directory is not writable,
3747 * - the file may be a symbolic link,
3748 * - the file may belong to another user/group, etc.
3749 *
3750 * For these reasons, the existing writable file must be truncated
3751 * and reused. Creation of a backup COPY will be attempted.
3752 */
3753 dirp = p_bdir;
3754 while (*dirp)
3755 {
3756#ifdef UNIX
3757 st_new.st_ino = 0;
3758 st_new.st_dev = 0;
3759 st_new.st_gid = 0;
3760#endif
3761
3762 /*
3763 * Isolate one directory name, using an entry in 'bdir'.
3764 */
3765 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003766
Bram Moolenaar4f974752019-02-17 17:44:42 +01003767#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003768 p = copybuf + STRLEN(copybuf);
3769 if (after_pathsep(copybuf, p) && p[-1] == p[-2])
3770 // Ends with '//', use full path
3771 if ((p = make_percent_swname(copybuf, fname)) != NULL)
3772 {
3773 backup = modname(p, backup_ext, FALSE);
3774 vim_free(p);
3775 }
3776#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 rootname = get_file_in_dir(fname, copybuf);
3778 if (rootname == NULL)
3779 {
3780 some_error = TRUE; /* out of memory */
3781 goto nobackup;
3782 }
3783
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003784#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 did_set_shortname = FALSE;
3786#endif
3787
3788 /*
3789 * May try twice if 'shortname' not set.
3790 */
3791 for (;;)
3792 {
3793 /*
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003794 * Make the backup file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 */
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003796 if (backup == NULL)
3797 backup = buf_modname((buf->b_p_sn || buf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 rootname, backup_ext, FALSE);
3799 if (backup == NULL)
3800 {
3801 vim_free(rootname);
3802 some_error = TRUE; /* out of memory */
3803 goto nobackup;
3804 }
3805
3806 /*
3807 * Check if backup file already exists.
3808 */
3809 if (mch_stat((char *)backup, &st_new) >= 0)
3810 {
3811#ifdef UNIX
3812 /*
3813 * Check if backup file is same as original file.
3814 * May happen when modname() gave the same file back.
3815 * E.g. silly link, or file name-length reached.
3816 * If we don't check here, we either ruin the file
3817 * when copying or erase it after writing. jw.
3818 */
3819 if (st_new.st_dev == st_old.st_dev
3820 && st_new.st_ino == st_old.st_ino)
3821 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01003822 VIM_CLEAR(backup); /* no backup file to delete */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 /*
3824 * may try again with 'shortname' set
3825 */
3826 if (!(buf->b_shortname || buf->b_p_sn))
3827 {
3828 buf->b_shortname = TRUE;
3829 did_set_shortname = TRUE;
3830 continue;
3831 }
3832 /* setting shortname didn't help */
3833 if (did_set_shortname)
3834 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 break;
3836 }
3837#endif
3838
3839 /*
3840 * If we are not going to keep the backup file, don't
3841 * delete an existing one, try to use another name.
3842 * Change one character, just before the extension.
3843 */
3844 if (!p_bk)
3845 {
3846 wp = backup + STRLEN(backup) - 1
3847 - STRLEN(backup_ext);
3848 if (wp < backup) /* empty file name ??? */
3849 wp = backup;
3850 *wp = 'z';
3851 while (*wp > 'a'
3852 && mch_stat((char *)backup, &st_new) >= 0)
3853 --*wp;
3854 /* They all exist??? Must be something wrong. */
3855 if (*wp == 'a')
Bram Moolenaard23a8232018-02-10 18:45:26 +01003856 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857 }
3858 }
3859 break;
3860 }
3861 vim_free(rootname);
3862
3863 /*
3864 * Try to create the backup file
3865 */
3866 if (backup != NULL)
3867 {
3868 /* remove old backup, if present */
3869 mch_remove(backup);
3870 /* Open with O_EXCL to avoid the file being created while
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003871 * we were sleeping (symlink hacker attack?). Reset umask
3872 * if possible to avoid mch_setperm() below. */
3873#ifdef UNIX
3874 umask_save = umask(0);
3875#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876 bfd = mch_open((char *)backup,
Bram Moolenaara5792f52005-11-23 21:25:05 +00003877 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
3878 perm & 0777);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003879#ifdef UNIX
3880 (void)umask(umask_save);
3881#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882 if (bfd < 0)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003883 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 else
3885 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003886 /* Set file protection same as original file, but
3887 * strip s-bit. Only needed if umask() wasn't used
3888 * above. */
3889#ifndef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 (void)mch_setperm(backup, perm & 0777);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01003891#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892 /*
3893 * Try to set the group of the backup same as the
3894 * original file. If this fails, set the protection
3895 * bits for the group same as the protection bits for
3896 * others.
3897 */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003898 if (st_new.st_gid != st_old.st_gid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
Bram Moolenaara5792f52005-11-23 21:25:05 +00003900 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901# endif
3902 )
3903 mch_setperm(backup,
3904 (perm & 0707) | ((perm & 07) << 3));
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003905# if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003906 mch_copy_sec(fname, backup);
3907# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908#endif
3909
3910 /*
3911 * copy the file.
3912 */
3913 write_info.bw_fd = bfd;
3914 write_info.bw_buf = copybuf;
3915#ifdef HAS_BW_FLAGS
3916 write_info.bw_flags = FIO_NOCONVERT;
3917#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01003918 while ((write_info.bw_len = read_eintr(fd, copybuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 BUFSIZE)) > 0)
3920 {
3921 if (buf_write_bytes(&write_info) == FAIL)
3922 {
3923 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
3924 break;
3925 }
3926 ui_breakcheck();
3927 if (got_int)
3928 {
3929 errmsg = (char_u *)_(e_interr);
3930 break;
3931 }
3932 }
3933
3934 if (close(bfd) < 0 && errmsg == NULL)
3935 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
3936 if (write_info.bw_len < 0)
3937 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
3938#ifdef UNIX
3939 set_file_time(backup, st_old.st_atime, st_old.st_mtime);
3940#endif
3941#ifdef HAVE_ACL
3942 mch_set_acl(backup, acl);
3943#endif
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003944#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00003945 mch_copy_sec(fname, backup);
3946#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 break;
3948 }
3949 }
3950 }
3951 nobackup:
3952 close(fd); /* ignore errors for closing read file */
3953 vim_free(copybuf);
3954
3955 if (backup == NULL && errmsg == NULL)
3956 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
3957 /* ignore errors when forceit is TRUE */
3958 if ((some_error || errmsg != NULL) && !forceit)
3959 {
3960 retval = FAIL;
3961 goto fail;
3962 }
3963 errmsg = NULL;
3964 }
3965 else
3966 {
3967 char_u *dirp;
3968 char_u *p;
3969 char_u *rootname;
3970
3971 /*
3972 * Make a backup by renaming the original file.
3973 */
3974 /*
3975 * If 'cpoptions' includes the "W" flag, we don't want to
3976 * overwrite a read-only file. But rename may be possible
3977 * anyway, thus we need an extra check here.
3978 */
3979 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
3980 {
3981 errnum = (char_u *)"E504: ";
3982 errmsg = (char_u *)_(err_readonly);
3983 goto fail;
3984 }
3985
3986 /*
3987 *
3988 * Form the backup file name - change path/fo.o.h to
3989 * path/fo.o.h.bak Try all directories in 'backupdir', first one
3990 * that works is used.
3991 */
3992 dirp = p_bdir;
3993 while (*dirp)
3994 {
3995 /*
3996 * Isolate one directory name and make the backup file name.
3997 */
3998 (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
Bram Moolenaarb782ba42018-08-07 21:39:28 +02003999
Bram Moolenaar4f974752019-02-17 17:44:42 +01004000#if defined(UNIX) || defined(MSWIN)
Bram Moolenaarb782ba42018-08-07 21:39:28 +02004001 p = IObuff + STRLEN(IObuff);
4002 if (after_pathsep(IObuff, p) && p[-1] == p[-2])
4003 // path ends with '//', use full path
4004 if ((p = make_percent_swname(IObuff, fname)) != NULL)
4005 {
4006 backup = modname(p, backup_ext, FALSE);
4007 vim_free(p);
4008 }
4009#endif
4010 if (backup == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011 {
Bram Moolenaarb782ba42018-08-07 21:39:28 +02004012 rootname = get_file_in_dir(fname, IObuff);
4013 if (rootname == NULL)
4014 backup = NULL;
4015 else
4016 {
4017 backup = buf_modname(
4018 (buf->b_p_sn || buf->b_shortname),
4019 rootname, backup_ext, FALSE);
4020 vim_free(rootname);
4021 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 }
4023
4024 if (backup != NULL)
4025 {
4026 /*
4027 * If we are not going to keep the backup file, don't
4028 * delete an existing one, try to use another name.
4029 * Change one character, just before the extension.
4030 */
4031 if (!p_bk && mch_getperm(backup) >= 0)
4032 {
4033 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
4034 if (p < backup) /* empty file name ??? */
4035 p = backup;
4036 *p = 'z';
4037 while (*p > 'a' && mch_getperm(backup) >= 0)
4038 --*p;
4039 /* They all exist??? Must be something wrong! */
4040 if (*p == 'a')
Bram Moolenaard23a8232018-02-10 18:45:26 +01004041 VIM_CLEAR(backup);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 }
4043 }
4044 if (backup != NULL)
4045 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 /*
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00004047 * Delete any existing backup and move the current version
4048 * to the backup. For safety, we don't remove the backup
4049 * until the write has finished successfully. And if the
4050 * 'backup' option is set, leave it around.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051 */
4052 /*
4053 * If the renaming of the original file to the backup file
4054 * works, quit here.
4055 */
4056 if (vim_rename(fname, backup) == 0)
4057 break;
4058
Bram Moolenaard23a8232018-02-10 18:45:26 +01004059 VIM_CLEAR(backup); /* don't do the rename below */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060 }
4061 }
4062 if (backup == NULL && !forceit)
4063 {
4064 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
4065 goto fail;
4066 }
4067 }
4068 }
4069
Bram Moolenaar53076832015-12-31 19:53:21 +01004070#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071 /* When using ":w!" and the file was read-only: make it writable */
4072 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
4073 && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
4074 {
4075 perm |= 0200;
4076 (void)mch_setperm(fname, perm);
4077 made_writable = TRUE;
4078 }
4079#endif
4080
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004081 /* When using ":w!" and writing to the current file, 'readonly' makes no
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004082 * sense, reset it, unless 'Z' appears in 'cpoptions'. */
4083 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084 {
4085 buf->b_p_ro = FALSE;
4086#ifdef FEAT_TITLE
4087 need_maketitle = TRUE; /* set window title later */
4088#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 status_redraw_all(); /* redraw status lines later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090 }
4091
4092 if (end > buf->b_ml.ml_line_count)
4093 end = buf->b_ml.ml_line_count;
4094 if (buf->b_ml.ml_flags & ML_EMPTY)
4095 start = end + 1;
4096
4097 /*
4098 * If the original file is being overwritten, there is a small chance that
4099 * we crash in the middle of writing. Therefore the file is preserved now.
4100 * This makes all block numbers positive so that recovery does not need
4101 * the original file.
4102 * Don't do this if there is a backup file and we are exiting.
4103 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004104 if (reset_changed && !newfile && overwriting
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105 && !(exiting && backup != NULL))
4106 {
4107 ml_preserve(buf, FALSE);
4108 if (got_int)
4109 {
4110 errmsg = (char_u *)_(e_interr);
4111 goto restore_backup;
4112 }
4113 }
4114
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115#ifdef VMS
4116 vms_remove_version(fname); /* remove version */
4117#endif
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00004118 /* Default: write the file directly. May write to a temp file for
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 * multi-byte conversion. */
4120 wfname = fname;
4121
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 /* Check for forced 'fileencoding' from "++opt=val" argument. */
4123 if (eap != NULL && eap->force_enc != 0)
4124 {
4125 fenc = eap->cmd + eap->force_enc;
4126 fenc = enc_canonize(fenc);
4127 fenc_tofree = fenc;
4128 }
4129 else
4130 fenc = buf->b_p_fenc;
4131
4132 /*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004133 * Check if the file needs to be converted.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 */
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00004135 converted = need_conversion(fenc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136
4137 /*
4138 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
4139 * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
4140 * Prepare the flags for it and allocate bw_conv_buf when needed.
4141 */
4142 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
4143 {
4144 wb_flags = get_fio_flags(fenc);
4145 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
4146 {
4147 /* Need to allocate a buffer to translate into. */
4148 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
4149 write_info.bw_conv_buflen = bufsize * 2;
4150 else /* FIO_UCS4 */
4151 write_info.bw_conv_buflen = bufsize * 4;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004152 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153 if (write_info.bw_conv_buf == NULL)
4154 end = 0;
4155 }
4156 }
4157
Bram Moolenaar4f974752019-02-17 17:44:42 +01004158#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
4160 {
4161 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
4162 write_info.bw_conv_buflen = bufsize * 4;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004163 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164 if (write_info.bw_conv_buf == NULL)
4165 end = 0;
4166 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004167#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168
Bram Moolenaar13505972019-01-24 15:04:48 +01004169#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
4171 {
4172 write_info.bw_conv_buflen = bufsize * 3;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004173 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 if (write_info.bw_conv_buf == NULL)
4175 end = 0;
4176 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004177#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178
Bram Moolenaar13505972019-01-24 15:04:48 +01004179#if defined(FEAT_EVAL) || defined(USE_ICONV)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180 if (converted && wb_flags == 0)
4181 {
Bram Moolenaar13505972019-01-24 15:04:48 +01004182# ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 /*
4184 * Use iconv() conversion when conversion is needed and it's not done
4185 * internally.
4186 */
4187 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
4188 enc_utf8 ? (char_u *)"utf-8" : p_enc);
4189 if (write_info.bw_iconv_fd != (iconv_t)-1)
4190 {
4191 /* We're going to use iconv(), allocate a buffer to convert in. */
4192 write_info.bw_conv_buflen = bufsize * ICONV_MULT;
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004193 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194 if (write_info.bw_conv_buf == NULL)
4195 end = 0;
4196 write_info.bw_first = TRUE;
4197 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198# ifdef FEAT_EVAL
Bram Moolenaar13505972019-01-24 15:04:48 +01004199 else
4200# endif
4201# endif
4202
4203# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204 /*
4205 * When the file needs to be converted with 'charconvert' after
4206 * writing, write to a temp file instead and let the conversion
4207 * overwrite the original file.
4208 */
4209 if (*p_ccv != NUL)
4210 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +02004211 wfname = vim_tempname('w', FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212 if (wfname == NULL) /* Can't write without a tempfile! */
4213 {
4214 errmsg = (char_u *)_("E214: Can't find temp file for writing");
4215 goto restore_backup;
4216 }
4217 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004218# endif
Bram Moolenaar13505972019-01-24 15:04:48 +01004219 }
4220#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 if (converted && wb_flags == 0
Bram Moolenaar13505972019-01-24 15:04:48 +01004222#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 && write_info.bw_iconv_fd == (iconv_t)-1
Bram Moolenaar13505972019-01-24 15:04:48 +01004224# endif
4225# ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 && wfname == fname
Bram Moolenaar13505972019-01-24 15:04:48 +01004227# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 )
4229 {
4230 if (!forceit)
4231 {
4232 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
4233 goto restore_backup;
4234 }
4235 notconverted = TRUE;
4236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237
4238 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004239 * If conversion is taking place, we may first pretend to write and check
4240 * for conversion errors. Then loop again to write for real.
4241 * When not doing conversion this writes for real right away.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004243 for (checking_conversion = TRUE; ; checking_conversion = FALSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244 {
4245 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004246 * There is no need to check conversion when:
4247 * - there is no conversion
4248 * - we make a backup file, that can be restored in case of conversion
4249 * failure.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004251 if (!converted || dobackup)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004252 checking_conversion = FALSE;
4253
4254 if (checking_conversion)
4255 {
4256 /* Make sure we don't write anything. */
4257 fd = -1;
4258 write_info.bw_fd = fd;
4259 }
4260 else
4261 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004262#ifdef HAVE_FTRUNCATE
4263# define TRUNC_ON_OPEN 0
4264#else
4265# define TRUNC_ON_OPEN O_TRUNC
4266#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004267 /*
4268 * Open the file "wfname" for writing.
4269 * We may try to open the file twice: If we can't write to the file
4270 * and forceit is TRUE we delete the existing file and try to
4271 * create a new one. If this still fails we may have lost the
4272 * original file! (this may happen when the user reached his
4273 * quotum for number of files).
4274 * Appending will fail if the file does not exist and forceit is
4275 * FALSE.
4276 */
4277 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
4278 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004279 : (O_CREAT | TRUNC_ON_OPEN))
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004280 , perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004282 /*
4283 * A forced write will try to create a new file if the old one
4284 * is still readonly. This may also happen when the directory
4285 * is read-only. In that case the mch_remove() will fail.
4286 */
4287 if (errmsg == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 {
4289#ifdef UNIX
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004290 stat_T st;
4291
4292 /* Don't delete the file when it's a hard or symbolic link.
4293 */
4294 if ((!newfile && st_old.st_nlink > 1)
4295 || (mch_lstat((char *)fname, &st) == 0
4296 && (st.st_dev != st_old.st_dev
4297 || st.st_ino != st_old.st_ino)))
4298 errmsg = (char_u *)_("E166: Can't open linked file for writing");
4299 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004300#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004301 {
4302 errmsg = (char_u *)_("E212: Can't open file for writing");
4303 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
4304 && perm >= 0)
4305 {
4306#ifdef UNIX
4307 /* we write to the file, thus it should be marked
4308 writable after all */
4309 if (!(perm & 0200))
4310 made_writable = TRUE;
4311 perm |= 0200;
4312 if (st_old.st_uid != getuid()
4313 || st_old.st_gid != getgid())
4314 perm &= 0777;
4315#endif
4316 if (!append) /* don't remove when appending */
4317 mch_remove(wfname);
4318 continue;
4319 }
4320 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322
4323restore_backup:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004325 stat_T st;
4326
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004328 * If we failed to open the file, we don't need a backup.
4329 * Throw it away. If we moved or removed the original file
4330 * try to put the backup in its place.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004332 if (backup != NULL && wfname == fname)
4333 {
4334 if (backup_copy)
4335 {
4336 /*
4337 * There is a small chance that we removed the
4338 * original, try to move the copy in its place.
4339 * This may not work if the vim_rename() fails.
4340 * In that case we leave the copy around.
4341 */
4342 /* If file does not exist, put the copy in its
4343 * place */
4344 if (mch_stat((char *)fname, &st) < 0)
4345 vim_rename(backup, fname);
4346 /* if original file does exist throw away the copy
4347 */
4348 if (mch_stat((char *)fname, &st) >= 0)
4349 mch_remove(backup);
4350 }
4351 else
4352 {
4353 /* try to put the original file back */
4354 vim_rename(backup, fname);
4355 }
4356 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004358 /* if original file no longer exists give an extra warning
4359 */
4360 if (!newfile && mch_stat((char *)fname, &st) < 0)
4361 end = 0;
4362 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004364 if (wfname != fname)
4365 vim_free(wfname);
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004366 goto fail;
4367 }
4368 write_info.bw_fd = fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004370#if defined(UNIX)
4371 {
4372 stat_T st;
4373
4374 /* Double check we are writing the intended file before making
4375 * any changes. */
4376 if (overwriting
4377 && (!dobackup || backup_copy)
4378 && fname == wfname
4379 && perm >= 0
4380 && mch_fstat(fd, &st) == 0
4381 && st.st_ino != st_old.st_ino)
4382 {
4383 close(fd);
4384 errmsg = (char_u *)_("E949: File changed while writing");
4385 goto fail;
4386 }
4387 }
4388#endif
4389#ifdef HAVE_FTRUNCATE
4390 if (!append)
Bram Moolenaar42335f52018-09-13 15:33:43 +02004391 vim_ignored = ftruncate(fd, (off_t)0);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004392#endif
4393
Bram Moolenaar4f974752019-02-17 17:44:42 +01004394#if defined(MSWIN)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004395 if (backup != NULL && overwriting && !append)
4396 {
4397 if (backup_copy)
4398 (void)mch_copy_file_attribute(wfname, backup);
4399 else
4400 (void)mch_copy_file_attribute(backup, wfname);
4401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004403 if (!overwriting && !append)
4404 {
4405 if (buf->b_ffname != NULL)
4406 (void)mch_copy_file_attribute(buf->b_ffname, wfname);
4407 /* Should copy resource fork */
4408 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409#endif
4410
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411#ifdef FEAT_CRYPT
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004412 if (*buf->b_p_key != NUL && !filtering)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004414 char_u *header;
4415 int header_len;
4416
4417 buf->b_cryptstate = crypt_create_for_writing(
4418 crypt_get_method_nr(buf),
4419 buf->b_p_key, &header, &header_len);
4420 if (buf->b_cryptstate == NULL || header == NULL)
4421 end = 0;
4422 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004424 /* Write magic number, so that Vim knows how this file is
4425 * encrypted when reading it back. */
4426 write_info.bw_buf = header;
4427 write_info.bw_len = header_len;
4428 write_info.bw_flags = FIO_NOCONVERT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 if (buf_write_bytes(&write_info) == FAIL)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004430 end = 0;
4431 wb_flags |= FIO_ENCRYPTED;
4432 vim_free(header);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004435#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004437 errmsg = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004439 write_info.bw_buf = buffer;
4440 nchars = 0;
4441
4442 /* use "++bin", "++nobin" or 'binary' */
4443 if (eap != NULL && eap->force_bin != 0)
4444 write_bin = (eap->force_bin == FORCE_BIN);
4445 else
4446 write_bin = buf->b_p_bin;
4447
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448 /*
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004449 * The BOM is written just after the encryption magic number.
4450 * Skip it when appending and the file already existed, the BOM only
4451 * makes sense at the start of the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452 */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004453 if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004455 write_info.bw_len = make_bom(buffer, fenc);
4456 if (write_info.bw_len > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004458 /* don't convert, do encryption */
4459 write_info.bw_flags = FIO_NOCONVERT | wb_flags;
4460 if (buf_write_bytes(&write_info) == FAIL)
4461 end = 0;
4462 else
4463 nchars += write_info.bw_len;
4464 }
4465 }
4466 write_info.bw_start_lnum = start;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004467
4468#ifdef FEAT_PERSISTENT_UNDO
4469 write_undo_file = (buf->b_p_udf
4470 && overwriting
4471 && !append
4472 && !filtering
4473 && reset_changed
4474 && !checking_conversion);
4475 if (write_undo_file)
4476 /* Prepare for computing the hash value of the text. */
4477 sha256_start(&sha_ctx);
4478#endif
4479
4480 write_info.bw_len = bufsize;
4481#ifdef HAS_BW_FLAGS
4482 write_info.bw_flags = wb_flags;
4483#endif
4484 fileformat = get_fileformat_force(buf, eap);
4485 s = buffer;
4486 len = 0;
4487 for (lnum = start; lnum <= end; ++lnum)
4488 {
4489 /*
4490 * The next while loop is done once for each character written.
4491 * Keep it fast!
4492 */
4493 ptr = ml_get_buf(buf, lnum, FALSE) - 1;
4494#ifdef FEAT_PERSISTENT_UNDO
4495 if (write_undo_file)
4496 sha256_update(&sha_ctx, ptr + 1,
4497 (UINT32_T)(STRLEN(ptr + 1) + 1));
4498#endif
4499 while ((c = *++ptr) != NUL)
4500 {
4501 if (c == NL)
4502 *s = NUL; /* replace newlines with NULs */
4503 else if (c == CAR && fileformat == EOL_MAC)
4504 *s = NL; /* Mac: replace CRs with NLs */
4505 else
4506 *s = c;
4507 ++s;
4508 if (++len != bufsize)
4509 continue;
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004510 if (buf_write_bytes(&write_info) == FAIL)
4511 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004512 end = 0; /* write error: break loop */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004513 break;
4514 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004515 nchars += bufsize;
4516 s = buffer;
4517 len = 0;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004518 write_info.bw_start_lnum = lnum;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004519 }
4520 /* write failed or last line has no EOL: stop here */
4521 if (end == 0
4522 || (lnum == end
4523 && (write_bin || !buf->b_p_fixeol)
4524 && (lnum == buf->b_no_eol_lnum
4525 || (lnum == buf->b_ml.ml_line_count
4526 && !buf->b_p_eol))))
4527 {
4528 ++lnum; /* written the line, count it */
4529 no_eol = TRUE;
4530 break;
4531 }
4532 if (fileformat == EOL_UNIX)
4533 *s++ = NL;
4534 else
4535 {
4536 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
4537 if (fileformat == EOL_DOS) /* write CR-NL */
4538 {
4539 if (++len == bufsize)
4540 {
4541 if (buf_write_bytes(&write_info) == FAIL)
4542 {
4543 end = 0; /* write error: break loop */
4544 break;
4545 }
4546 nchars += bufsize;
4547 s = buffer;
4548 len = 0;
4549 }
4550 *s++ = NL;
4551 }
4552 }
4553 if (++len == bufsize && end)
4554 {
4555 if (buf_write_bytes(&write_info) == FAIL)
4556 {
4557 end = 0; /* write error: break loop */
4558 break;
4559 }
4560 nchars += bufsize;
4561 s = buffer;
4562 len = 0;
4563
4564 ui_breakcheck();
4565 if (got_int)
4566 {
4567 end = 0; /* Interrupted, break loop */
4568 break;
4569 }
4570 }
4571#ifdef VMS
4572 /*
4573 * On VMS there is a problem: newlines get added when writing
4574 * blocks at a time. Fix it by writing a line at a time.
4575 * This is much slower!
4576 * Explanation: VAX/DECC RTL insists that records in some RMS
4577 * structures end with a newline (carriage return) character, and
4578 * if they don't it adds one.
4579 * With other RMS structures it works perfect without this fix.
4580 */
4581 if (buf->b_fab_rfm == FAB$C_VFC
4582 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4583 {
4584 int b2write;
4585
4586 buf->b_fab_mrs = (buf->b_fab_mrs == 0
4587 ? MIN(4096, bufsize)
4588 : MIN(buf->b_fab_mrs, bufsize));
4589
4590 b2write = len;
4591 while (b2write > 0)
4592 {
4593 write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
4594 if (buf_write_bytes(&write_info) == FAIL)
4595 {
4596 end = 0;
4597 break;
4598 }
4599 b2write -= MIN(b2write, buf->b_fab_mrs);
4600 }
4601 write_info.bw_len = bufsize;
4602 nchars += len;
4603 s = buffer;
4604 len = 0;
4605 }
4606#endif
4607 }
4608 if (len > 0 && end > 0)
4609 {
4610 write_info.bw_len = len;
4611 if (buf_write_bytes(&write_info) == FAIL)
4612 end = 0; /* write error */
4613 nchars += len;
4614 }
4615
4616 /* Stop when writing done or an error was encountered. */
4617 if (!checking_conversion || end == 0)
4618 break;
4619
4620 /* If no error happened until now, writing should be ok, so loop to
4621 * really write the buffer. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 }
4623
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004624 /* If we started writing, finish writing. Also when an error was
4625 * encountered. */
4626 if (!checking_conversion)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004628#if defined(UNIX) && defined(HAVE_FSYNC)
4629 /*
4630 * On many journalling file systems there is a bug that causes both the
4631 * original and the backup file to be lost when halting the system
4632 * right after writing the file. That's because only the meta-data is
4633 * journalled. Syncing the file slows down the system, but assures it
4634 * has been written to disk and we don't lose it.
4635 * For a device do try the fsync() but don't complain if it does not
4636 * work (could be a pipe).
4637 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
4638 */
Bram Moolenaara7870192019-02-14 12:56:36 +01004639 if (p_fs && vim_fsync(fd) != 0 && !device)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004640 {
Bram Moolenaar7567d0b2017-11-16 23:04:15 +01004641 errmsg = (char_u *)_(e_fsync);
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004642 end = 0;
4643 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644#endif
4645
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02004646#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004647 /* Probably need to set the security context. */
4648 if (!backup_copy)
4649 mch_copy_sec(backup, wfname);
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00004650#endif
4651
Bram Moolenaara5792f52005-11-23 21:25:05 +00004652#ifdef UNIX
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004653 /* When creating a new file, set its owner/group to that of the
4654 * original file. Get the new device and inode number. */
4655 if (backup != NULL && !backup_copy)
Bram Moolenaara5792f52005-11-23 21:25:05 +00004656 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004657# ifdef HAVE_FCHOWN
4658 stat_T st;
4659
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004660 /* Don't change the owner when it's already OK, some systems remove
4661 * permission or ACL stuff. */
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004662 if (mch_stat((char *)wfname, &st) < 0
4663 || st.st_uid != st_old.st_uid
4664 || st.st_gid != st_old.st_gid)
4665 {
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004666 /* changing owner might not be possible */
Bram Moolenaar42335f52018-09-13 15:33:43 +02004667 vim_ignored = fchown(fd, st_old.st_uid, -1);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004668 /* if changing group fails clear the group permissions */
4669 if (fchown(fd, -1, st_old.st_gid) == -1 && perm > 0)
4670 perm &= ~070;
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004671 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00004672# endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004673 buf_setino(buf);
4674 }
4675 else if (!buf->b_dev_valid)
4676 /* Set the inode when creating a new file. */
4677 buf_setino(buf);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004678#endif
4679
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004680#ifdef UNIX
4681 if (made_writable)
4682 perm &= ~0200; /* reset 'w' bit for security reasons */
4683#endif
4684#ifdef HAVE_FCHMOD
4685 /* set permission of new file same as old file */
4686 if (perm >= 0)
4687 (void)mch_fsetperm(fd, perm);
4688#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004689 if (close(fd) != 0)
4690 {
4691 errmsg = (char_u *)_("E512: Close failed");
4692 end = 0;
4693 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004695#ifndef HAVE_FCHMOD
4696 /* set permission of new file same as old file */
4697 if (perm >= 0)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004698 (void)mch_setperm(wfname, perm);
Bram Moolenaarcd142e32017-11-16 17:03:45 +01004699#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700#ifdef HAVE_ACL
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004701 /*
4702 * Probably need to set the ACL before changing the user (can't set the
4703 * ACL on a file the user doesn't own).
4704 * On Solaris, with ZFS and the aclmode property set to "discard" (the
4705 * default), chmod() discards all part of a file's ACL that don't
4706 * represent the mode of the file. It's non-trivial for us to discover
4707 * whether we're in that situation, so we simply always re-set the ACL.
4708 */
Bram Moolenaarda412772016-07-14 20:37:07 +02004709# ifndef HAVE_SOLARIS_ZFS_ACL
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004710 if (!backup_copy)
Bram Moolenaarda412772016-07-14 20:37:07 +02004711# endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004712 mch_set_acl(wfname, acl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004714#ifdef FEAT_CRYPT
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004715 if (buf->b_cryptstate != NULL)
4716 {
4717 crypt_free_state(buf->b_cryptstate);
4718 buf->b_cryptstate = NULL;
4719 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004720#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721
Bram Moolenaar13505972019-01-24 15:04:48 +01004722#if defined(FEAT_EVAL)
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004723 if (wfname != fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004725 /*
4726 * The file was written to a temp file, now it needs to be
4727 * converted with 'charconvert' to (overwrite) the output file.
4728 */
4729 if (end != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004731 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
4732 fenc, wfname, fname) == FAIL)
4733 {
4734 write_info.bw_conv_error = TRUE;
4735 end = 0;
4736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737 }
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004738 mch_remove(wfname);
4739 vim_free(wfname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741#endif
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004742 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743
4744 if (end == 0)
4745 {
Bram Moolenaare6bf6552017-06-27 22:11:51 +02004746 /*
4747 * Error encountered.
4748 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749 if (errmsg == NULL)
4750 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 if (write_info.bw_conv_error)
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004752 {
4753 if (write_info.bw_conv_error_lnum == 0)
4754 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
4755 else
4756 {
4757 errmsg_allocated = TRUE;
4758 errmsg = alloc(300);
4759 vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"),
4760 (long)write_info.bw_conv_error_lnum);
4761 }
4762 }
Bram Moolenaar13505972019-01-24 15:04:48 +01004763 else if (got_int)
4764 errmsg = (char_u *)_(e_interr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765 else
Bram Moolenaar13505972019-01-24 15:04:48 +01004766 errmsg = (char_u *)_("E514: write error (file system full?)");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767 }
4768
4769 /*
4770 * If we have a backup file, try to put it in place of the new file,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004771 * because the new file is probably corrupt. This avoids losing the
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 * original file when trying to make a backup when writing the file a
4773 * second time.
4774 * When "backup_copy" is set we need to copy the backup over the new
4775 * file. Otherwise rename the backup file.
4776 * If this is OK, don't give the extra warning message.
4777 */
4778 if (backup != NULL)
4779 {
4780 if (backup_copy)
4781 {
4782 /* This may take a while, if we were interrupted let the user
4783 * know we got the message. */
4784 if (got_int)
4785 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004786 msg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 out_flush();
4788 }
4789 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
4790 {
4791 if ((write_info.bw_fd = mch_open((char *)fname,
Bram Moolenaar9be038d2005-03-08 22:34:32 +00004792 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
4793 perm & 0777)) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 {
4795 /* copy the file. */
4796 write_info.bw_buf = smallbuf;
4797#ifdef HAS_BW_FLAGS
4798 write_info.bw_flags = FIO_NOCONVERT;
4799#endif
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004800 while ((write_info.bw_len = read_eintr(fd, smallbuf,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801 SMBUFSIZE)) > 0)
4802 if (buf_write_bytes(&write_info) == FAIL)
4803 break;
4804
4805 if (close(write_info.bw_fd) >= 0
4806 && write_info.bw_len == 0)
4807 end = 1; /* success */
4808 }
4809 close(fd); /* ignore errors for closing read file */
4810 }
4811 }
4812 else
4813 {
4814 if (vim_rename(backup, fname) == 0)
4815 end = 1;
4816 }
4817 }
4818 goto fail;
4819 }
4820
4821 lnum -= start; /* compute number of written lines */
4822 --no_wait_return; /* may wait for return now */
4823
4824#if !(defined(UNIX) || defined(VMS))
4825 fname = sfname; /* use shortname now, for the messages */
4826#endif
4827 if (!filtering)
4828 {
4829 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
4830 c = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831 if (write_info.bw_conv_error)
4832 {
4833 STRCAT(IObuff, _(" CONVERSION ERROR"));
4834 c = TRUE;
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004835 if (write_info.bw_conv_error_lnum != 0)
Bram Moolenaara800b422010-06-27 01:15:55 +02004836 vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"),
Bram Moolenaar32b485f2009-07-29 16:06:27 +00004837 (long)write_info.bw_conv_error_lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 }
4839 else if (notconverted)
4840 {
4841 STRCAT(IObuff, _("[NOT converted]"));
4842 c = TRUE;
4843 }
4844 else if (converted)
4845 {
4846 STRCAT(IObuff, _("[converted]"));
4847 c = TRUE;
4848 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849 if (device)
4850 {
4851 STRCAT(IObuff, _("[Device]"));
4852 c = TRUE;
4853 }
4854 else if (newfile)
4855 {
4856 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
4857 c = TRUE;
4858 }
4859 if (no_eol)
4860 {
4861 msg_add_eol();
4862 c = TRUE;
4863 }
4864 /* may add [unix/dos/mac] */
4865 if (msg_add_fileformat(fileformat))
4866 c = TRUE;
4867#ifdef FEAT_CRYPT
4868 if (wb_flags & FIO_ENCRYPTED)
4869 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004870 crypt_append_msg(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 c = TRUE;
4872 }
4873#endif
4874 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
4875 if (!shortmess(SHM_WRITE))
4876 {
4877 if (append)
4878 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
4879 else
4880 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
4881 }
4882
Bram Moolenaar32526b32019-01-19 17:43:09 +01004883 set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 }
4885
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004886 /* When written everything correctly: reset 'modified'. Unless not
4887 * writing to the original file and '+' is not in 'cpoptions'. */
Bram Moolenaar292ad192005-12-11 21:29:51 +00004888 if (reset_changed && whole && !append
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 && !write_info.bw_conv_error
Bram Moolenaar13505972019-01-24 15:04:48 +01004890 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891 {
Bram Moolenaarc024b462019-06-08 18:07:21 +02004892 unchanged(buf, TRUE, FALSE);
4893 /* b:changedtick is may be incremented in unchanged() but that
Bram Moolenaar086329d2014-10-31 19:51:36 +01004894 * should not trigger a TextChanged event. */
Bram Moolenaar5a093432018-02-10 18:15:19 +01004895 if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf))
4896 buf->b_last_changedtick = CHANGEDTICK(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 u_unchanged(buf);
Bram Moolenaar730cde92010-06-27 05:18:54 +02004898 u_update_save_nr(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004899 }
4900
4901 /*
4902 * If written to the current file, update the timestamp of the swap file
4903 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
4904 */
4905 if (overwriting)
4906 {
4907 ml_timestamp(buf);
Bram Moolenaar292ad192005-12-11 21:29:51 +00004908 if (append)
4909 buf->b_flags &= ~BF_NEW;
4910 else
4911 buf->b_flags &= ~BF_WRITE_MASK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912 }
4913
4914 /*
4915 * If we kept a backup until now, and we are in patch mode, then we make
4916 * the backup file our 'original' file.
4917 */
4918 if (*p_pm && dobackup)
4919 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004920 char *org = (char *)buf_modname((buf->b_p_sn || buf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921 fname, p_pm, FALSE);
4922
4923 if (backup != NULL)
4924 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02004925 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926
4927 /*
4928 * If the original file does not exist yet
4929 * the current backup file becomes the original file
4930 */
4931 if (org == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004932 emsg(_("E205: Patchmode: can't save original file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 else if (mch_stat(org, &st) < 0)
4934 {
4935 vim_rename(backup, (char_u *)org);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004936 VIM_CLEAR(backup); /* don't delete the file */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937#ifdef UNIX
4938 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
4939#endif
4940 }
4941 }
4942 /*
4943 * If there is no backup file, remember that a (new) file was
4944 * created.
4945 */
4946 else
4947 {
4948 int empty_fd;
4949
4950 if (org == NULL
Bram Moolenaara5792f52005-11-23 21:25:05 +00004951 || (empty_fd = mch_open(org,
4952 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00004953 perm < 0 ? 0666 : (perm & 0777))) < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004954 emsg(_("E206: patchmode: can't touch empty original file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 else
4956 close(empty_fd);
4957 }
4958 if (org != NULL)
4959 {
4960 mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
4961 vim_free(org);
4962 }
4963 }
4964
Bram Moolenaarcf0bfd92019-05-18 18:52:04 +02004965 // Remove the backup unless 'backup' option is set or there was a
4966 // conversion error.
4967 if (!p_bk && backup != NULL && !write_info.bw_conv_error
4968 && mch_remove(backup) != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004969 emsg(_("E207: Can't delete backup file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004970
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971 goto nofail;
4972
4973 /*
4974 * Finish up. We get here either after failure or success.
4975 */
4976fail:
4977 --no_wait_return; /* may wait for return now */
4978nofail:
4979
4980 /* Done saving, we accept changed buffer warnings again */
4981 buf->b_saving = FALSE;
4982
4983 vim_free(backup);
4984 if (buffer != smallbuf)
4985 vim_free(buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004986 vim_free(fenc_tofree);
4987 vim_free(write_info.bw_conv_buf);
Bram Moolenaar13505972019-01-24 15:04:48 +01004988#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989 if (write_info.bw_iconv_fd != (iconv_t)-1)
4990 {
4991 iconv_close(write_info.bw_iconv_fd);
4992 write_info.bw_iconv_fd = (iconv_t)-1;
4993 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994#endif
4995#ifdef HAVE_ACL
4996 mch_free_acl(acl);
4997#endif
4998
4999 if (errmsg != NULL)
5000 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005001 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005002
Bram Moolenaar8820b482017-03-16 17:23:31 +01005003 attr = HL_ATTR(HLF_E); /* set highlight for error messages */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004 msg_add_fname(buf,
5005#ifndef UNIX
5006 sfname
5007#else
5008 fname
5009#endif
5010 ); /* put file name in IObuff with quotes */
5011 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
5012 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
5013 /* If the error message has the form "is ...", put the error number in
5014 * front of the file name. */
5015 if (errnum != NULL)
5016 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005017 STRMOVE(IObuff + numlen, IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 mch_memmove(IObuff, errnum, (size_t)numlen);
5019 }
5020 STRCAT(IObuff, errmsg);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005021 emsg((char *)IObuff);
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005022 if (errmsg_allocated)
5023 vim_free(errmsg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024
5025 retval = FAIL;
5026 if (end == 0)
5027 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005028 msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029 attr | MSG_HIST);
Bram Moolenaar32526b32019-01-19 17:43:09 +01005030 msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005031 attr | MSG_HIST);
5032
5033 /* Update the timestamp to avoid an "overwrite changed file"
5034 * prompt when writing again. */
5035 if (mch_stat((char *)fname, &st_old) >= 0)
5036 {
5037 buf_store_time(buf, &st_old, fname);
5038 buf->b_mtime_read = buf->b_mtime;
5039 }
5040 }
5041 }
5042 msg_scroll = msg_save;
5043
Bram Moolenaar55debbe2010-05-23 23:34:36 +02005044#ifdef FEAT_PERSISTENT_UNDO
5045 /*
5046 * When writing the whole file and 'undofile' is set, also write the undo
5047 * file.
5048 */
5049 if (retval == OK && write_undo_file)
5050 {
5051 char_u hash[UNDO_HASH_SIZE];
5052
5053 sha256_finish(&sha_ctx, hash);
5054 u_write_undo(NULL, FALSE, buf, hash);
5055 }
5056#endif
5057
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058#ifdef FEAT_EVAL
5059 if (!should_abort(retval))
5060#else
5061 if (!got_int)
5062#endif
5063 {
5064 aco_save_T aco;
5065
Bram Moolenaar68a33fc2012-04-25 16:50:48 +02005066 curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
5067
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068 /*
5069 * Apply POST autocommands.
5070 * Careful: The autocommands may call buf_write() recursively!
5071 */
5072 aucmd_prepbuf(&aco, buf);
5073
5074 if (append)
5075 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
5076 FALSE, curbuf, eap);
5077 else if (filtering)
5078 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
5079 FALSE, curbuf, eap);
5080 else if (reset_changed && whole)
5081 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
5082 FALSE, curbuf, eap);
5083 else
5084 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
5085 FALSE, curbuf, eap);
5086
5087 /* restore curwin/curbuf and a few other things */
5088 aucmd_restbuf(&aco);
5089
5090#ifdef FEAT_EVAL
5091 if (aborting()) /* autocmds may abort script processing */
5092 retval = FALSE;
5093#endif
5094 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095
5096 got_int |= prev_got_int;
5097
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 return retval;
5099}
5100
Bram Moolenaara7870192019-02-14 12:56:36 +01005101#if defined(HAVE_FSYNC) || defined(PROTO)
5102/*
5103 * Call fsync() with Mac-specific exception.
5104 * Return fsync() result: zero for success.
5105 */
5106 int
5107vim_fsync(int fd)
5108{
5109 int r;
5110
5111# ifdef MACOS_X
5112 r = fcntl(fd, F_FULLFSYNC);
Bram Moolenaar91668382019-02-21 12:16:12 +01005113 if (r != 0) // F_FULLFSYNC not working or not supported
Bram Moolenaara7870192019-02-14 12:56:36 +01005114# endif
5115 r = fsync(fd);
5116 return r;
5117}
5118#endif
5119
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120/*
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005121 * Set the name of the current buffer. Use when the buffer doesn't have a
5122 * name and a ":r" or ":w" command with a file name is used.
5123 */
5124 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005125set_rw_fname(char_u *fname, char_u *sfname)
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005126{
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005127 buf_T *buf = curbuf;
5128
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005129 /* It's like the unnamed buffer is deleted.... */
5130 if (curbuf->b_p_bl)
5131 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
5132 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005133#ifdef FEAT_EVAL
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005134 if (aborting()) /* autocmds may abort script processing */
5135 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005136#endif
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005137 if (curbuf != buf)
5138 {
5139 /* We are in another buffer now, don't do the renaming. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005140 emsg(_(e_auchangedbuf));
Bram Moolenaar8b38e242009-06-16 13:35:20 +00005141 return FAIL;
5142 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005143
5144 if (setfname(curbuf, fname, sfname, FALSE) == OK)
5145 curbuf->b_flags |= BF_NOTEDITED;
5146
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005147 /* ....and a new named one is created */
5148 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
5149 if (curbuf->b_p_bl)
5150 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005151#ifdef FEAT_EVAL
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005152 if (aborting()) /* autocmds may abort script processing */
5153 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005154#endif
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005155
5156 /* Do filetype detection now if 'filetype' is empty. */
5157 if (*curbuf->b_p_ft == NUL)
5158 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005159 if (au_has_group((char_u *)"filetypedetect"))
Bram Moolenaar1610d052016-06-09 22:53:01 +02005160 (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE, NULL);
Bram Moolenaara3227e22006-03-08 21:32:40 +00005161 do_modelines(0);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005162 }
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005163
5164 return OK;
5165}
5166
5167/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005168 * Put file name into IObuff with quotes.
5169 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005170 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005171msg_add_fname(buf_T *buf, char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172{
5173 if (fname == NULL)
5174 fname = (char_u *)"-stdin-";
5175 home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
5176 IObuff[0] = '"';
5177 STRCAT(IObuff, "\" ");
5178}
5179
5180/*
5181 * Append message for text mode to IObuff.
5182 * Return TRUE if something appended.
5183 */
5184 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005185msg_add_fileformat(int eol_type)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005186{
5187#ifndef USE_CRNL
5188 if (eol_type == EOL_DOS)
5189 {
5190 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
5191 return TRUE;
5192 }
5193#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194 if (eol_type == EOL_MAC)
5195 {
5196 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
5197 return TRUE;
5198 }
Bram Moolenaar00590742019-02-15 21:06:09 +01005199#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 if (eol_type == EOL_UNIX)
5201 {
5202 STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
5203 return TRUE;
5204 }
5205#endif
5206 return FALSE;
5207}
5208
5209/*
5210 * Append line and character count to IObuff.
5211 */
Bram Moolenaar009b2592004-10-24 19:18:58 +00005212 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005213msg_add_lines(
5214 int insert_space,
5215 long lnum,
Bram Moolenaar8767f522016-07-01 17:17:39 +02005216 off_T nchars)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217{
5218 char_u *p;
5219
5220 p = IObuff + STRLEN(IObuff);
5221
5222 if (insert_space)
5223 *p++ = ' ';
5224 if (shortmess(SHM_LINES))
Bram Moolenaarbde98102016-07-01 20:03:42 +02005225 vim_snprintf((char *)p, IOSIZE - (p - IObuff),
Bram Moolenaar88c86eb2019-01-17 17:13:30 +01005226 "%ldL, %lldC", lnum, (long_long_T)nchars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227 else
5228 {
Bram Moolenaarda6e8912018-08-21 15:12:14 +02005229 sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 p += STRLEN(p);
Bram Moolenaarda6e8912018-08-21 15:12:14 +02005231 vim_snprintf((char *)p, IOSIZE - (p - IObuff),
5232 NGETTEXT("%lld character", "%lld characters", nchars),
Bram Moolenaar88c86eb2019-01-17 17:13:30 +01005233 (long_long_T)nchars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234 }
5235}
5236
5237/*
5238 * Append message for missing line separator to IObuff.
5239 */
5240 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005241msg_add_eol(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242{
5243 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
5244}
5245
5246/*
5247 * Check modification time of file, before writing to it.
5248 * The size isn't checked, because using a tool like "gzip" takes care of
5249 * using the same timestamp but can't set the size.
5250 */
5251 static int
Bram Moolenaar8767f522016-07-01 17:17:39 +02005252check_mtime(buf_T *buf, stat_T *st)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253{
5254 if (buf->b_mtime_read != 0
5255 && time_differs((long)st->st_mtime, buf->b_mtime_read))
5256 {
5257 msg_scroll = TRUE; /* don't overwrite messages here */
5258 msg_silent = 0; /* must give this prompt */
5259 /* don't use emsg() here, don't want to flush the buffers */
Bram Moolenaar32526b32019-01-19 17:43:09 +01005260 msg_attr(_("WARNING: The file has been changed since reading it!!!"),
Bram Moolenaar8820b482017-03-16 17:23:31 +01005261 HL_ATTR(HLF_E));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005262 if (ask_yesno((char_u *)_("Do you really want to write to it"),
5263 TRUE) == 'n')
5264 return FAIL;
5265 msg_scroll = FALSE; /* always overwrite the file message now */
5266 }
5267 return OK;
5268}
5269
5270 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005271time_differs(long t1, long t2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272{
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005273#if defined(__linux__) || defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
5275 * the seconds. Since the roundoff is done when flushing the inode, the
5276 * time may change unexpectedly by one second!!! */
5277 return (t1 - t2 > 1 || t2 - t1 > 1);
5278#else
5279 return (t1 != t2);
5280#endif
5281}
5282
5283/*
5284 * Call write() to write a number of bytes to the file.
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005285 * Handles encryption and 'encoding' conversion.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005286 *
5287 * Return FAIL for failure, OK otherwise.
5288 */
5289 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005290buf_write_bytes(struct bw_info *ip)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291{
5292 int wlen;
5293 char_u *buf = ip->bw_buf; /* data to write */
5294 int len = ip->bw_len; /* length of data */
5295#ifdef HAS_BW_FLAGS
5296 int flags = ip->bw_flags; /* extra flags */
5297#endif
5298
Bram Moolenaar071d4272004-06-13 20:20:40 +00005299 /*
5300 * Skip conversion when writing the crypt magic number or the BOM.
5301 */
5302 if (!(flags & FIO_NOCONVERT))
5303 {
5304 char_u *p;
5305 unsigned c;
5306 int n;
5307
5308 if (flags & FIO_UTF8)
5309 {
5310 /*
5311 * Convert latin1 in the buffer to UTF-8 in the file.
5312 */
5313 p = ip->bw_conv_buf; /* translate to buffer */
5314 for (wlen = 0; wlen < len; ++wlen)
5315 p += utf_char2bytes(buf[wlen], p);
5316 buf = ip->bw_conv_buf;
5317 len = (int)(p - ip->bw_conv_buf);
5318 }
5319 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
5320 {
5321 /*
5322 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
5323 * Latin1 chars in the file.
5324 */
5325 if (flags & FIO_LATIN1)
5326 p = buf; /* translate in-place (can only get shorter) */
5327 else
5328 p = ip->bw_conv_buf; /* translate to buffer */
5329 for (wlen = 0; wlen < len; wlen += n)
5330 {
5331 if (wlen == 0 && ip->bw_restlen != 0)
5332 {
5333 int l;
5334
5335 /* Use remainder of previous call. Append the start of
5336 * buf[] to get a full sequence. Might still be too
5337 * short! */
5338 l = CONV_RESTLEN - ip->bw_restlen;
5339 if (l > len)
5340 l = len;
5341 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005342 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005343 if (n > ip->bw_restlen + len)
5344 {
5345 /* We have an incomplete byte sequence at the end to
5346 * be written. We can't convert it without the
5347 * remaining bytes. Keep them for the next call. */
5348 if (ip->bw_restlen + len > CONV_RESTLEN)
5349 return FAIL;
5350 ip->bw_restlen += len;
5351 break;
5352 }
5353 if (n > 1)
5354 c = utf_ptr2char(ip->bw_rest);
5355 else
5356 c = ip->bw_rest[0];
5357 if (n >= ip->bw_restlen)
5358 {
5359 n -= ip->bw_restlen;
5360 ip->bw_restlen = 0;
5361 }
5362 else
5363 {
5364 ip->bw_restlen -= n;
5365 mch_memmove(ip->bw_rest, ip->bw_rest + n,
5366 (size_t)ip->bw_restlen);
5367 n = 0;
5368 }
5369 }
5370 else
5371 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005372 n = utf_ptr2len_len(buf + wlen, len - wlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373 if (n > len - wlen)
5374 {
5375 /* We have an incomplete byte sequence at the end to
5376 * be written. We can't convert it without the
5377 * remaining bytes. Keep them for the next call. */
5378 if (len - wlen > CONV_RESTLEN)
5379 return FAIL;
5380 ip->bw_restlen = len - wlen;
5381 mch_memmove(ip->bw_rest, buf + wlen,
5382 (size_t)ip->bw_restlen);
5383 break;
5384 }
5385 if (n > 1)
5386 c = utf_ptr2char(buf + wlen);
5387 else
5388 c = buf[wlen];
5389 }
5390
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005391 if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error)
5392 {
5393 ip->bw_conv_error = TRUE;
5394 ip->bw_conv_error_lnum = ip->bw_start_lnum;
5395 }
5396 if (c == NL)
5397 ++ip->bw_start_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398 }
5399 if (flags & FIO_LATIN1)
5400 len = (int)(p - buf);
5401 else
5402 {
5403 buf = ip->bw_conv_buf;
5404 len = (int)(p - ip->bw_conv_buf);
5405 }
5406 }
5407
Bram Moolenaar4f974752019-02-17 17:44:42 +01005408#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005409 else if (flags & FIO_CODEPAGE)
5410 {
5411 /*
5412 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
5413 * codepage.
5414 */
5415 char_u *from;
5416 size_t fromlen;
5417 char_u *to;
5418 int u8c;
5419 BOOL bad = FALSE;
5420 int needed;
5421
5422 if (ip->bw_restlen > 0)
5423 {
5424 /* Need to concatenate the remainder of the previous call and
5425 * the bytes of the current call. Use the end of the
5426 * conversion buffer for this. */
5427 fromlen = len + ip->bw_restlen;
5428 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5429 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5430 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5431 }
5432 else
5433 {
5434 from = buf;
5435 fromlen = len;
5436 }
5437
5438 to = ip->bw_conv_buf;
5439 if (enc_utf8)
5440 {
5441 /* Convert from UTF-8 to UCS-2, to the start of the buffer.
5442 * The buffer has been allocated to be big enough. */
5443 while (fromlen > 0)
5444 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005445 n = (int)utf_ptr2len_len(from, (int)fromlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 if (n > (int)fromlen) /* incomplete byte sequence */
5447 break;
5448 u8c = utf_ptr2char(from);
5449 *to++ = (u8c & 0xff);
5450 *to++ = (u8c >> 8);
5451 fromlen -= n;
5452 from += n;
5453 }
5454
5455 /* Copy remainder to ip->bw_rest[] to be used for the next
5456 * call. */
5457 if (fromlen > CONV_RESTLEN)
5458 {
5459 /* weird overlong sequence */
5460 ip->bw_conv_error = TRUE;
5461 return FAIL;
5462 }
5463 mch_memmove(ip->bw_rest, from, fromlen);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005464 ip->bw_restlen = (int)fromlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 }
5466 else
5467 {
5468 /* Convert from enc_codepage to UCS-2, to the start of the
5469 * buffer. The buffer has been allocated to be big enough. */
5470 ip->bw_restlen = 0;
5471 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005472 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473 NULL, 0);
5474 if (needed == 0)
5475 {
5476 /* When conversion fails there may be a trailing byte. */
5477 needed = MultiByteToWideChar(enc_codepage,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005478 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479 NULL, 0);
5480 if (needed == 0)
5481 {
5482 /* Conversion doesn't work. */
5483 ip->bw_conv_error = TRUE;
5484 return FAIL;
5485 }
5486 /* Save the trailing byte for the next call. */
5487 ip->bw_rest[0] = from[fromlen - 1];
5488 ip->bw_restlen = 1;
5489 }
5490 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005491 (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005492 (LPWSTR)to, needed);
5493 if (needed == 0)
5494 {
5495 /* Safety check: Conversion doesn't work. */
5496 ip->bw_conv_error = TRUE;
5497 return FAIL;
5498 }
5499 to += needed * 2;
5500 }
5501
5502 fromlen = to - ip->bw_conv_buf;
5503 buf = to;
Bram Moolenaar13505972019-01-24 15:04:48 +01005504# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005505 if (FIO_GET_CP(flags) == CP_UTF8)
5506 {
5507 /* Convert from UCS-2 to UTF-8, using the remainder of the
5508 * conversion buffer. Fails when out of space. */
5509 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
5510 {
5511 u8c = *from++;
5512 u8c += (*from++ << 8);
5513 to += utf_char2bytes(u8c, to);
5514 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
5515 {
5516 ip->bw_conv_error = TRUE;
5517 return FAIL;
5518 }
5519 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005520 len = (int)(to - buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 }
5522 else
Bram Moolenaar13505972019-01-24 15:04:48 +01005523# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005524 {
5525 /* Convert from UCS-2 to the codepage, using the remainder of
5526 * the conversion buffer. If the conversion uses the default
5527 * character "0", the data doesn't fit in this encoding, so
5528 * fail. */
5529 len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
5530 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
Bram Moolenaar36f5ac02007-05-06 12:40:34 +00005531 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
5532 &bad);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005533 if (bad)
5534 {
5535 ip->bw_conv_error = TRUE;
5536 return FAIL;
5537 }
5538 }
5539 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005540#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005541
Bram Moolenaar13505972019-01-24 15:04:48 +01005542#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005543 else if (flags & FIO_MACROMAN)
5544 {
5545 /*
5546 * Convert UTF-8 or latin1 to Apple MacRoman.
5547 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548 char_u *from;
5549 size_t fromlen;
5550
5551 if (ip->bw_restlen > 0)
5552 {
5553 /* Need to concatenate the remainder of the previous call and
5554 * the bytes of the current call. Use the end of the
5555 * conversion buffer for this. */
5556 fromlen = len + ip->bw_restlen;
5557 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5558 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
5559 mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
5560 }
5561 else
5562 {
5563 from = buf;
5564 fromlen = len;
5565 }
5566
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00005567 if (enc2macroman(from, fromlen,
5568 ip->bw_conv_buf, &len, ip->bw_conv_buflen,
5569 ip->bw_rest, &ip->bw_restlen) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570 {
5571 ip->bw_conv_error = TRUE;
5572 return FAIL;
5573 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 buf = ip->bw_conv_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005575 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005576#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005577
Bram Moolenaar13505972019-01-24 15:04:48 +01005578#ifdef USE_ICONV
Bram Moolenaar071d4272004-06-13 20:20:40 +00005579 if (ip->bw_iconv_fd != (iconv_t)-1)
5580 {
5581 const char *from;
5582 size_t fromlen;
5583 char *to;
5584 size_t tolen;
5585
5586 /* Convert with iconv(). */
5587 if (ip->bw_restlen > 0)
5588 {
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005589 char *fp;
5590
Bram Moolenaar071d4272004-06-13 20:20:40 +00005591 /* Need to concatenate the remainder of the previous call and
5592 * the bytes of the current call. Use the end of the
5593 * conversion buffer for this. */
5594 fromlen = len + ip->bw_restlen;
Bram Moolenaar5d294d12009-03-11 12:11:02 +00005595 fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
5596 mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
5597 mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
5598 from = fp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 tolen = ip->bw_conv_buflen - fromlen;
5600 }
5601 else
5602 {
5603 from = (const char *)buf;
5604 fromlen = len;
5605 tolen = ip->bw_conv_buflen;
5606 }
5607 to = (char *)ip->bw_conv_buf;
5608
5609 if (ip->bw_first)
5610 {
5611 size_t save_len = tolen;
5612
5613 /* output the initial shift state sequence */
5614 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
5615
5616 /* There is a bug in iconv() on Linux (which appears to be
5617 * wide-spread) which sets "to" to NULL and messes up "tolen".
5618 */
5619 if (to == NULL)
5620 {
5621 to = (char *)ip->bw_conv_buf;
5622 tolen = save_len;
5623 }
5624 ip->bw_first = FALSE;
5625 }
5626
5627 /*
5628 * If iconv() has an error or there is not enough room, fail.
5629 */
5630 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
5631 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
5632 || fromlen > CONV_RESTLEN)
5633 {
5634 ip->bw_conv_error = TRUE;
5635 return FAIL;
5636 }
5637
5638 /* copy remainder to ip->bw_rest[] to be used for the next call. */
5639 if (fromlen > 0)
5640 mch_memmove(ip->bw_rest, (void *)from, fromlen);
5641 ip->bw_restlen = (int)fromlen;
5642
5643 buf = ip->bw_conv_buf;
5644 len = (int)((char_u *)to - ip->bw_conv_buf);
5645 }
Bram Moolenaar13505972019-01-24 15:04:48 +01005646#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005648
Bram Moolenaare6bf6552017-06-27 22:11:51 +02005649 if (ip->bw_fd < 0)
5650 /* Only checking conversion, which is OK if we get here. */
5651 return OK;
5652
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005654 if (flags & FIO_ENCRYPTED)
5655 {
5656 /* Encrypt the data. Do it in-place if possible, otherwise use an
5657 * allocated buffer. */
Bram Moolenaar987411d2019-01-18 22:48:34 +01005658# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005659 if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
5660 {
Bram Moolenaar987411d2019-01-18 22:48:34 +01005661# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005662 crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
Bram Moolenaar987411d2019-01-18 22:48:34 +01005663# ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005664 }
5665 else
5666 {
5667 char_u *outbuf;
5668
5669 len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
5670 if (len == 0)
5671 return OK; /* Crypt layer is buffering, will flush later. */
5672 wlen = write_eintr(ip->bw_fd, outbuf, len);
5673 vim_free(outbuf);
5674 return (wlen < len) ? FAIL : OK;
5675 }
Bram Moolenaar987411d2019-01-18 22:48:34 +01005676# endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02005677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005678#endif
5679
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005680 wlen = write_eintr(ip->bw_fd, buf, len);
5681 return (wlen < len) ? FAIL : OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682}
5683
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684/*
5685 * Convert a Unicode character to bytes.
Bram Moolenaar32b485f2009-07-29 16:06:27 +00005686 * Return TRUE for an error, FALSE when it's OK.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005687 */
5688 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005689ucs2bytes(
5690 unsigned c, /* in: character */
5691 char_u **pp, /* in/out: pointer to result */
5692 int flags) /* FIO_ flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005693{
5694 char_u *p = *pp;
5695 int error = FALSE;
5696 int cc;
5697
5698
5699 if (flags & FIO_UCS4)
5700 {
5701 if (flags & FIO_ENDIAN_L)
5702 {
5703 *p++ = c;
5704 *p++ = (c >> 8);
5705 *p++ = (c >> 16);
5706 *p++ = (c >> 24);
5707 }
5708 else
5709 {
5710 *p++ = (c >> 24);
5711 *p++ = (c >> 16);
5712 *p++ = (c >> 8);
5713 *p++ = c;
5714 }
5715 }
5716 else if (flags & (FIO_UCS2 | FIO_UTF16))
5717 {
5718 if (c >= 0x10000)
5719 {
5720 if (flags & FIO_UTF16)
5721 {
5722 /* Make two words, ten bits of the character in each. First
5723 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
5724 c -= 0x10000;
5725 if (c >= 0x100000)
5726 error = TRUE;
5727 cc = ((c >> 10) & 0x3ff) + 0xd800;
5728 if (flags & FIO_ENDIAN_L)
5729 {
5730 *p++ = cc;
5731 *p++ = ((unsigned)cc >> 8);
5732 }
5733 else
5734 {
5735 *p++ = ((unsigned)cc >> 8);
5736 *p++ = cc;
5737 }
5738 c = (c & 0x3ff) + 0xdc00;
5739 }
5740 else
5741 error = TRUE;
5742 }
5743 if (flags & FIO_ENDIAN_L)
5744 {
5745 *p++ = c;
5746 *p++ = (c >> 8);
5747 }
5748 else
5749 {
5750 *p++ = (c >> 8);
5751 *p++ = c;
5752 }
5753 }
5754 else /* Latin1 */
5755 {
5756 if (c >= 0x100)
5757 {
5758 error = TRUE;
5759 *p++ = 0xBF;
5760 }
5761 else
5762 *p++ = c;
5763 }
5764
5765 *pp = p;
5766 return error;
5767}
5768
5769/*
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005770 * Return TRUE if file encoding "fenc" requires conversion from or to
5771 * 'encoding'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005772 */
5773 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005774need_conversion(char_u *fenc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775{
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005776 int same_encoding;
5777 int enc_flags;
5778 int fenc_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005780 if (*fenc == NUL || STRCMP(p_enc, fenc) == 0)
Bram Moolenaar442b4222010-05-24 21:34:22 +02005781 {
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005782 same_encoding = TRUE;
Bram Moolenaar442b4222010-05-24 21:34:22 +02005783 fenc_flags = 0;
5784 }
Bram Moolenaarb5cdf2e2009-07-29 16:25:31 +00005785 else
5786 {
5787 /* Ignore difference between "ansi" and "latin1", "ucs-4" and
5788 * "ucs-4be", etc. */
5789 enc_flags = get_fio_flags(p_enc);
5790 fenc_flags = get_fio_flags(fenc);
5791 same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
5792 }
5793 if (same_encoding)
5794 {
5795 /* Specified encoding matches with 'encoding'. This requires
5796 * conversion when 'encoding' is Unicode but not UTF-8. */
5797 return enc_unicode != 0;
5798 }
5799
5800 /* Encodings differ. However, conversion is not needed when 'enc' is any
5801 * Unicode encoding and the file is UTF-8. */
5802 return !(enc_utf8 && fenc_flags == FIO_UTF8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005803}
5804
5805/*
5806 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
5807 * internal conversion.
5808 * if "ptr" is an empty string, use 'encoding'.
5809 */
5810 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005811get_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005812{
5813 int prop;
5814
5815 if (*ptr == NUL)
5816 ptr = p_enc;
5817
5818 prop = enc_canon_props(ptr);
5819 if (prop & ENC_UNICODE)
5820 {
5821 if (prop & ENC_2BYTE)
5822 {
5823 if (prop & ENC_ENDIAN_L)
5824 return FIO_UCS2 | FIO_ENDIAN_L;
5825 return FIO_UCS2;
5826 }
5827 if (prop & ENC_4BYTE)
5828 {
5829 if (prop & ENC_ENDIAN_L)
5830 return FIO_UCS4 | FIO_ENDIAN_L;
5831 return FIO_UCS4;
5832 }
5833 if (prop & ENC_2WORD)
5834 {
5835 if (prop & ENC_ENDIAN_L)
5836 return FIO_UTF16 | FIO_ENDIAN_L;
5837 return FIO_UTF16;
5838 }
5839 return FIO_UTF8;
5840 }
5841 if (prop & ENC_LATIN1)
5842 return FIO_LATIN1;
5843 /* must be ENC_DBCS, requires iconv() */
5844 return 0;
5845}
5846
Bram Moolenaar4f974752019-02-17 17:44:42 +01005847#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00005848/*
5849 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
5850 * for the conversion MS-Windows can do for us. Also accept "utf-8".
5851 * Used for conversion between 'encoding' and 'fileencoding'.
5852 */
5853 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005854get_win_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855{
5856 int cp;
5857
5858 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
5859 if (!enc_utf8 && enc_codepage <= 0)
5860 return 0;
5861
5862 cp = encname2codepage(ptr);
5863 if (cp == 0)
5864 {
5865# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
5866 if (STRCMP(ptr, "utf-8") == 0)
5867 cp = CP_UTF8;
5868 else
5869# endif
5870 return 0;
5871 }
5872 return FIO_PUT_CP(cp) | FIO_CODEPAGE;
5873}
5874#endif
5875
Bram Moolenaard0573012017-10-28 21:11:06 +02005876#ifdef MACOS_CONVERT
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877/*
5878 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
5879 * needed for the internal conversion to/from utf-8 or latin1.
5880 */
5881 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005882get_mac_fio_flags(char_u *ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883{
5884 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
5885 && (enc_canon_props(ptr) & ENC_MACROMAN))
5886 return FIO_MACROMAN;
5887 return 0;
5888}
5889#endif
5890
5891/*
5892 * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
5893 * "size" must be at least 2.
5894 * Return the name of the encoding and set "*lenp" to the length.
5895 * Returns NULL when no BOM found.
5896 */
5897 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005898check_for_bom(
5899 char_u *p,
5900 long size,
5901 int *lenp,
5902 int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903{
5904 char *name = NULL;
5905 int len = 2;
5906
5907 if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
Bram Moolenaaree0f5a62008-07-24 20:09:16 +00005908 && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005909 {
5910 name = "utf-8"; /* EF BB BF */
5911 len = 3;
5912 }
5913 else if (p[0] == 0xff && p[1] == 0xfe)
5914 {
5915 if (size >= 4 && p[2] == 0 && p[3] == 0
5916 && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
5917 {
5918 name = "ucs-4le"; /* FF FE 00 00 */
5919 len = 4;
5920 }
Bram Moolenaar223a1892008-11-11 20:57:11 +00005921 else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922 name = "ucs-2le"; /* FF FE */
Bram Moolenaar223a1892008-11-11 20:57:11 +00005923 else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
5924 /* utf-16le is preferred, it also works for ucs-2le text */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005925 name = "utf-16le"; /* FF FE */
5926 }
5927 else if (p[0] == 0xfe && p[1] == 0xff
5928 && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
5929 {
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005930 /* Default to utf-16, it works also for ucs-2 text. */
5931 if (flags == FIO_UCS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932 name = "ucs-2"; /* FE FF */
Bram Moolenaarffd82c52008-02-20 17:15:26 +00005933 else
5934 name = "utf-16"; /* FE FF */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005935 }
5936 else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
5937 && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
5938 {
5939 name = "ucs-4"; /* 00 00 FE FF */
5940 len = 4;
5941 }
5942
5943 *lenp = len;
5944 return (char_u *)name;
5945}
5946
5947/*
5948 * Generate a BOM in "buf[4]" for encoding "name".
5949 * Return the length of the BOM (zero when no BOM).
5950 */
5951 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005952make_bom(char_u *buf, char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953{
5954 int flags;
5955 char_u *p;
5956
5957 flags = get_fio_flags(name);
5958
5959 /* Can't put a BOM in a non-Unicode file. */
5960 if (flags == FIO_LATIN1 || flags == 0)
5961 return 0;
5962
5963 if (flags == FIO_UTF8) /* UTF-8 */
5964 {
5965 buf[0] = 0xef;
5966 buf[1] = 0xbb;
5967 buf[2] = 0xbf;
5968 return 3;
5969 }
5970 p = buf;
5971 (void)ucs2bytes(0xfeff, &p, flags);
5972 return (int)(p - buf);
5973}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974
5975/*
5976 * Try to find a shortname by comparing the fullname with the current
5977 * directory.
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005978 * Returns "full_path" or pointer into "full_path" if shortened.
5979 */
5980 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005981shorten_fname1(char_u *full_path)
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005982{
Bram Moolenaard9462e32011-04-11 21:35:11 +02005983 char_u *dirname;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005984 char_u *p = full_path;
5985
Bram Moolenaard9462e32011-04-11 21:35:11 +02005986 dirname = alloc(MAXPATHL);
5987 if (dirname == NULL)
5988 return full_path;
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005989 if (mch_dirname(dirname, MAXPATHL) == OK)
5990 {
5991 p = shorten_fname(full_path, dirname);
5992 if (p == NULL || *p == NUL)
5993 p = full_path;
5994 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02005995 vim_free(dirname);
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005996 return p;
5997}
5998
5999/*
6000 * Try to find a shortname by comparing the fullname with the current
6001 * directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006002 * Returns NULL if not shorter name possible, pointer into "full_path"
6003 * otherwise.
6004 */
6005 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006006shorten_fname(char_u *full_path, char_u *dir_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006007{
6008 int len;
6009 char_u *p;
6010
6011 if (full_path == NULL)
6012 return NULL;
6013 len = (int)STRLEN(dir_name);
6014 if (fnamencmp(dir_name, full_path, len) == 0)
6015 {
6016 p = full_path + len;
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006017#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006018 /*
Bram Moolenaar4f974752019-02-17 17:44:42 +01006019 * MS-Windows: when a file is in the root directory, dir_name will end
6020 * in a slash, since C: by itself does not define a specific dir. In
6021 * this case p may already be correct. <negri>
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022 */
6023 if (!((len > 2) && (*(p - 2) == ':')))
6024#endif
6025 {
6026 if (vim_ispathsep(*p))
6027 ++p;
6028#ifndef VMS /* the path separator is always part of the path */
6029 else
6030 p = NULL;
6031#endif
6032 }
6033 }
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006034#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035 /*
6036 * When using a file in the current drive, remove the drive name:
6037 * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
6038 * a floppy from "A:\dir" to "B:\dir".
6039 */
6040 else if (len > 3
6041 && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
6042 && full_path[1] == ':'
6043 && vim_ispathsep(full_path[2]))
6044 p = full_path + 2;
6045#endif
6046 else
6047 p = NULL;
6048 return p;
6049}
6050
6051/*
Bram Moolenaara796d462018-05-01 14:30:36 +02006052 * Shorten filename of a buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006053 * When "force" is TRUE: Use full path from now on for files currently being
6054 * edited, both for file name and swap file name. Try to shorten the file
6055 * names a bit, if safe to do so.
6056 * When "force" is FALSE: Only try to shorten absolute file names.
6057 * For buffers that have buftype "nofile" or "scratch": never change the file
6058 * name.
6059 */
6060 void
Bram Moolenaara796d462018-05-01 14:30:36 +02006061shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
6062{
6063 char_u *p;
6064
6065 if (buf->b_fname != NULL
6066#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02006067 && !bt_nofilename(buf)
Bram Moolenaara796d462018-05-01 14:30:36 +02006068#endif
6069 && !path_with_url(buf->b_fname)
6070 && (force
6071 || buf->b_sfname == NULL
6072 || mch_isFullName(buf->b_sfname)))
6073 {
Bram Moolenaar3d6014f2018-10-11 19:27:47 +02006074 if (buf->b_sfname != buf->b_ffname)
6075 VIM_CLEAR(buf->b_sfname);
Bram Moolenaara796d462018-05-01 14:30:36 +02006076 p = shorten_fname(buf->b_ffname, dirname);
6077 if (p != NULL)
6078 {
6079 buf->b_sfname = vim_strsave(p);
6080 buf->b_fname = buf->b_sfname;
6081 }
6082 if (p == NULL || buf->b_fname == NULL)
6083 buf->b_fname = buf->b_ffname;
6084 }
6085}
6086
6087/*
6088 * Shorten filenames for all buffers.
6089 */
6090 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006091shorten_fnames(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092{
6093 char_u dirname[MAXPATHL];
6094 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006095
6096 mch_dirname(dirname, MAXPATHL);
Bram Moolenaar29323592016-07-24 22:04:11 +02006097 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 {
Bram Moolenaara796d462018-05-01 14:30:36 +02006099 shorten_buf_fname(buf, dirname, force);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006100
6101 /* Always make the swap file name a full path, a "nofile" buffer may
6102 * also have a swap file. */
6103 mf_fullname(buf->b_ml.ml_mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006105 status_redraw_all();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006106 redraw_tabline = TRUE;
Bram Moolenaar90f3e7a2019-08-01 22:40:44 +02006107#ifdef FEAT_TEXT_PROP
6108 popup_update_preview_title();
6109#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006110}
6111
6112#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
6113 || defined(FEAT_GUI_MSWIN) \
6114 || defined(FEAT_GUI_MAC) \
6115 || defined(PROTO)
6116/*
6117 * Shorten all filenames in "fnames[count]" by current directory.
6118 */
6119 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006120shorten_filenames(char_u **fnames, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121{
6122 int i;
6123 char_u dirname[MAXPATHL];
6124 char_u *p;
6125
6126 if (fnames == NULL || count < 1)
6127 return;
6128 mch_dirname(dirname, sizeof(dirname));
6129 for (i = 0; i < count; ++i)
6130 {
6131 if ((p = shorten_fname(fnames[i], dirname)) != NULL)
6132 {
6133 /* shorten_fname() returns pointer in given "fnames[i]". If free
6134 * "fnames[i]" first, "p" becomes invalid. So we need to copy
6135 * "p" first then free fnames[i]. */
6136 p = vim_strsave(p);
6137 vim_free(fnames[i]);
6138 fnames[i] = p;
6139 }
6140 }
6141}
6142#endif
6143
6144/*
Bram Moolenaarb782ba42018-08-07 21:39:28 +02006145 * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
Bram Moolenaar071d4272004-06-13 20:20:40 +00006146 * fo_o_h.ext for MSDOS or when shortname option set.
6147 *
6148 * Assumed that fname is a valid name found in the filesystem we assure that
6149 * the return value is a different name and ends in 'ext'.
6150 * "ext" MUST be at most 4 characters long if it starts with a dot, 3
6151 * characters otherwise.
6152 * Space for the returned name is allocated, must be freed later.
6153 * Returns NULL when out of memory.
6154 */
6155 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006156modname(
6157 char_u *fname,
6158 char_u *ext,
6159 int prepend_dot) /* may prepend a '.' to file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160{
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006161 return buf_modname((curbuf->b_p_sn || curbuf->b_shortname),
Bram Moolenaar071d4272004-06-13 20:20:40 +00006162 fname, ext, prepend_dot);
6163}
6164
6165 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006166buf_modname(
6167 int shortname, /* use 8.3 file name */
6168 char_u *fname,
6169 char_u *ext,
6170 int prepend_dot) /* may prepend a '.' to file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171{
6172 char_u *retval;
6173 char_u *s;
6174 char_u *e;
6175 char_u *ptr;
6176 int fnamelen, extlen;
6177
6178 extlen = (int)STRLEN(ext);
6179
6180 /*
6181 * If there is no file name we must get the name of the current directory
6182 * (we need the full path in case :cd is used).
6183 */
6184 if (fname == NULL || *fname == NUL)
6185 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02006186 retval = alloc(MAXPATHL + extlen + 3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187 if (retval == NULL)
6188 return NULL;
6189 if (mch_dirname(retval, MAXPATHL) == FAIL ||
6190 (fnamelen = (int)STRLEN(retval)) == 0)
6191 {
6192 vim_free(retval);
6193 return NULL;
6194 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006195 if (!after_pathsep(retval, retval + fnamelen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196 {
6197 retval[fnamelen++] = PATHSEP;
6198 retval[fnamelen] = NUL;
6199 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200 prepend_dot = FALSE; /* nothing to prepend a dot to */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006201 }
6202 else
6203 {
6204 fnamelen = (int)STRLEN(fname);
Bram Moolenaar964b3742019-05-24 18:54:09 +02006205 retval = alloc(fnamelen + extlen + 3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006206 if (retval == NULL)
6207 return NULL;
6208 STRCPY(retval, fname);
6209#ifdef VMS
6210 vms_remove_version(retval); /* we do not need versions here */
6211#endif
6212 }
6213
6214 /*
6215 * search backwards until we hit a '/', '\' or ':' replacing all '.'
6216 * by '_' for MSDOS or when shortname option set and ext starts with a dot.
6217 * Then truncate what is after the '/', '\' or ':' to 8 characters for
6218 * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
6219 */
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006220 for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006221 {
Bram Moolenaar00f148d2019-02-12 22:37:27 +01006222 if (*ext == '.' && shortname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223 if (*ptr == '.') /* replace '.' by '_' */
6224 *ptr = '_';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225 if (vim_ispathsep(*ptr))
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006226 {
6227 ++ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006228 break;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00006229 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006231
6232 /* the file name has at most BASENAMELEN characters. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006233 if (STRLEN(ptr) > (unsigned)BASENAMELEN)
6234 ptr[BASENAMELEN] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235
6236 s = ptr + STRLEN(ptr);
6237
6238 /*
6239 * For 8.3 file names we may have to reduce the length.
6240 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006241 if (shortname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 {
6243 /*
6244 * If there is no file name, or the file name ends in '/', and the
6245 * extension starts with '.', put a '_' before the dot, because just
6246 * ".ext" is invalid.
6247 */
6248 if (fname == NULL || *fname == NUL
6249 || vim_ispathsep(fname[STRLEN(fname) - 1]))
6250 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251 if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006252 *s++ = '_';
6253 }
6254 /*
6255 * If the extension starts with '.', truncate the base name at 8
6256 * characters
6257 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258 else if (*ext == '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006259 {
Bram Moolenaar78a15312009-05-15 19:33:18 +00006260 if ((size_t)(s - ptr) > (size_t)8)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006261 {
6262 s = ptr + 8;
6263 *s = '\0';
6264 }
6265 }
6266 /*
6267 * If the extension doesn't start with '.', and the file name
6268 * doesn't have an extension yet, append a '.'
6269 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006270 else if ((e = vim_strchr(ptr, '.')) == NULL)
6271 *s++ = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272 /*
6273 * If the extension doesn't start with '.', and there already is an
Bram Moolenaar7263a772007-05-10 17:35:54 +00006274 * extension, it may need to be truncated
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275 */
6276 else if ((int)STRLEN(e) + extlen > 4)
6277 s = e + 4 - extlen;
6278 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006279#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00006280 /*
6281 * If there is no file name, and the extension starts with '.', put a
6282 * '_' before the dot, because just ".ext" may be invalid if it's on a
6283 * FAT partition, and on HPFS it doesn't matter.
6284 */
6285 else if ((fname == NULL || *fname == NUL) && *ext == '.')
6286 *s++ = '_';
6287#endif
6288
6289 /*
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006290 * Append the extension.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 * ext can start with '.' and cannot exceed 3 more characters.
6292 */
6293 STRCPY(s, ext);
6294
Bram Moolenaar071d4272004-06-13 20:20:40 +00006295 /*
6296 * Prepend the dot.
6297 */
Bram Moolenaar00f148d2019-02-12 22:37:27 +01006298 if (prepend_dot && !shortname && *(e = gettail(retval)) != '.')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 {
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006300 STRMOVE(e + 1, e);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006301 *e = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00006302 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006303
6304 /*
6305 * Check that, after appending the extension, the file name is really
6306 * different.
6307 */
6308 if (fname != NULL && STRCMP(fname, retval) == 0)
6309 {
6310 /* we search for a character that can be replaced by '_' */
6311 while (--s >= ptr)
6312 {
6313 if (*s != '_')
6314 {
6315 *s = '_';
6316 break;
6317 }
6318 }
6319 if (s < ptr) /* fname was "________.<ext>", how tricky! */
6320 *ptr = 'v';
6321 }
6322 return retval;
6323}
6324
6325/*
6326 * Like fgets(), but if the file line is too long, it is truncated and the
6327 * rest of the line is thrown away. Returns TRUE for end-of-file.
Bram Moolenaar7e1652c2017-12-16 18:27:02 +01006328 * If the line is truncated then buf[size - 2] will not be NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329 */
6330 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006331vim_fgets(char_u *buf, int size, FILE *fp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006332{
6333 char *eof;
6334#define FGETS_SIZE 200
6335 char tbuf[FGETS_SIZE];
6336
6337 buf[size - 2] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006338 eof = fgets((char *)buf, size, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006339 if (buf[size - 2] != NUL && buf[size - 2] != '\n')
6340 {
6341 buf[size - 1] = NUL; /* Truncate the line */
6342
6343 /* Now throw away the rest of the line: */
6344 do
6345 {
6346 tbuf[FGETS_SIZE - 2] = NUL;
Bram Moolenaar42335f52018-09-13 15:33:43 +02006347 vim_ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006348 } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
6349 }
6350 return (eof == NULL);
6351}
6352
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353/*
6354 * rename() only works if both files are on the same file system, this
6355 * function will (attempts to?) copy the file across if rename fails -- webb
6356 * Return -1 for failure, 0 for success.
6357 */
6358 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006359vim_rename(char_u *from, char_u *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006360{
6361 int fd_in;
6362 int fd_out;
6363 int n;
6364 char *errmsg = NULL;
6365 char *buffer;
6366#ifdef AMIGA
6367 BPTR flock;
6368#endif
Bram Moolenaar8767f522016-07-01 17:17:39 +02006369 stat_T st;
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006370 long perm;
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006371#ifdef HAVE_ACL
6372 vim_acl_T acl; /* ACL from original file */
6373#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006374 int use_tmp_file = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006375
6376 /*
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006377 * When the names are identical, there is nothing to do. When they refer
6378 * to the same file (ignoring case and slash/backslash differences) but
6379 * the file name differs we need to go through a temp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006380 */
6381 if (fnamecmp(from, to) == 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006382 {
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01006383 if (p_fic && STRCMP(gettail(from), gettail(to)) != 0)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006384 use_tmp_file = TRUE;
6385 else
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006386 return 0;
6387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006388
6389 /*
6390 * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
6391 */
6392 if (mch_stat((char *)from, &st) < 0)
6393 return -1;
6394
Bram Moolenaar3576da72008-12-30 15:15:57 +00006395#ifdef UNIX
6396 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02006397 stat_T st_to;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006398
6399 /* It's possible for the source and destination to be the same file.
6400 * This happens when "from" and "to" differ in case and are on a FAT32
6401 * filesystem. In that case go through a temp file name. */
6402 if (mch_stat((char *)to, &st_to) >= 0
6403 && st.st_dev == st_to.st_dev
6404 && st.st_ino == st_to.st_ino)
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006405 use_tmp_file = TRUE;
6406 }
6407#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006408#ifdef MSWIN
Bram Moolenaar1c32dff2011-05-05 16:41:24 +02006409 {
6410 BY_HANDLE_FILE_INFORMATION info1, info2;
6411
6412 /* It's possible for the source and destination to be the same file.
6413 * In that case go through a temp file name. This makes rename("foo",
6414 * "./foo") a no-op (in a complicated way). */
6415 if (win32_fileinfo(from, &info1) == FILEINFO_OK
6416 && win32_fileinfo(to, &info2) == FILEINFO_OK
6417 && info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
6418 && info1.nFileIndexHigh == info2.nFileIndexHigh
6419 && info1.nFileIndexLow == info2.nFileIndexLow)
6420 use_tmp_file = TRUE;
6421 }
6422#endif
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006423
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006424 if (use_tmp_file)
6425 {
6426 char tempname[MAXPATHL + 1];
6427
6428 /*
6429 * Find a name that doesn't exist and is in the same directory.
6430 * Rename "from" to "tempname" and then rename "tempname" to "to".
6431 */
6432 if (STRLEN(from) >= MAXPATHL - 5)
6433 return -1;
6434 STRCPY(tempname, from);
6435 for (n = 123; n < 99999; ++n)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006436 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006437 sprintf((char *)gettail((char_u *)tempname), "%d", n);
6438 if (mch_stat(tempname, &st) < 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006439 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006440 if (mch_rename((char *)from, tempname) == 0)
Bram Moolenaar3576da72008-12-30 15:15:57 +00006441 {
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006442 if (mch_rename(tempname, (char *)to) == 0)
6443 return 0;
6444 /* Strange, the second step failed. Try moving the
6445 * file back and return failure. */
6446 mch_rename(tempname, (char *)from);
Bram Moolenaar3576da72008-12-30 15:15:57 +00006447 return -1;
6448 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006449 /* If it fails for one temp name it will most likely fail
6450 * for any temp name, give up. */
6451 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006452 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006453 }
Bram Moolenaare0e6f992008-12-31 15:21:32 +00006454 return -1;
Bram Moolenaar3576da72008-12-30 15:15:57 +00006455 }
Bram Moolenaar3576da72008-12-30 15:15:57 +00006456
Bram Moolenaar071d4272004-06-13 20:20:40 +00006457 /*
6458 * Delete the "to" file, this is required on some systems to make the
6459 * mch_rename() work, on other systems it makes sure that we don't have
6460 * two files when the mch_rename() fails.
6461 */
6462
6463#ifdef AMIGA
6464 /*
6465 * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
6466 * that the name of the "to" file is the same as the "from" file, even
Bram Moolenaar7263a772007-05-10 17:35:54 +00006467 * though the names are different. To avoid the chance of accidentally
Bram Moolenaar071d4272004-06-13 20:20:40 +00006468 * deleting the "from" file (horror!) we lock it during the remove.
6469 *
6470 * When used for making a backup before writing the file: This should not
6471 * happen with ":w", because startscript() should detect this problem and
6472 * set buf->b_shortname, causing modname() to return a correct ".bak" file
6473 * name. This problem does exist with ":w filename", but then the
6474 * original file will be somewhere else so the backup isn't really
6475 * important. If autoscripting is off the rename may fail.
6476 */
6477 flock = Lock((UBYTE *)from, (long)ACCESS_READ);
6478#endif
6479 mch_remove(to);
6480#ifdef AMIGA
6481 if (flock)
6482 UnLock(flock);
6483#endif
6484
6485 /*
6486 * First try a normal rename, return if it works.
6487 */
6488 if (mch_rename((char *)from, (char *)to) == 0)
6489 return 0;
6490
6491 /*
6492 * Rename() failed, try copying the file.
6493 */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006494 perm = mch_getperm(from);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006495#ifdef HAVE_ACL
6496 /* For systems that support ACL: get the ACL from the original file. */
6497 acl = mch_get_acl(from);
6498#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006499 fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
6500 if (fd_in == -1)
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006501 {
6502#ifdef HAVE_ACL
6503 mch_free_acl(acl);
6504#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006505 return -1;
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006506 }
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006507
6508 /* Create the new file with same permissions as the original. */
Bram Moolenaara5792f52005-11-23 21:25:05 +00006509 fd_out = mch_open((char *)to,
6510 O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006511 if (fd_out == -1)
6512 {
6513 close(fd_in);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006514#ifdef HAVE_ACL
6515 mch_free_acl(acl);
6516#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517 return -1;
6518 }
6519
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006520 buffer = alloc(BUFSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006521 if (buffer == NULL)
6522 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006523 close(fd_out);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006524 close(fd_in);
6525#ifdef HAVE_ACL
6526 mch_free_acl(acl);
6527#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006528 return -1;
6529 }
6530
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01006531 while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0)
6532 if (write_eintr(fd_out, buffer, n) != n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 {
6534 errmsg = _("E208: Error writing to \"%s\"");
6535 break;
6536 }
6537
6538 vim_free(buffer);
6539 close(fd_in);
6540 if (close(fd_out) < 0)
6541 errmsg = _("E209: Error closing \"%s\"");
6542 if (n < 0)
6543 {
6544 errmsg = _("E210: Error reading \"%s\"");
6545 to = from;
6546 }
Bram Moolenaar7263a772007-05-10 17:35:54 +00006547#ifndef UNIX /* for Unix mch_open() already set the permission */
Bram Moolenaar9be038d2005-03-08 22:34:32 +00006548 mch_setperm(to, perm);
Bram Moolenaarc6039d82005-12-02 00:44:04 +00006549#endif
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006550#ifdef HAVE_ACL
6551 mch_set_acl(to, acl);
Bram Moolenaarb23a7e82008-06-27 18:42:32 +00006552 mch_free_acl(acl);
Bram Moolenaarcd71fa32005-03-11 22:46:48 +00006553#endif
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02006554#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
Bram Moolenaare8747442013-11-12 18:09:29 +01006555 mch_copy_sec(from, to);
Bram Moolenaar0671de32013-11-12 05:12:03 +01006556#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006557 if (errmsg != NULL)
6558 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006559 semsg(errmsg, to);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560 return -1;
6561 }
6562 mch_remove(from);
6563 return 0;
6564}
6565
6566static int already_warned = FALSE;
6567
6568/*
6569 * Check if any not hidden buffer has been changed.
6570 * Postpone the check if there are characters in the stuff buffer, a global
6571 * command is being executed, a mapping is being executed or an autocommand is
6572 * busy.
6573 * Returns TRUE if some message was written (screen should be redrawn and
6574 * cursor positioned).
6575 */
6576 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006577check_timestamps(
6578 int focus) /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006579{
6580 buf_T *buf;
6581 int didit = 0;
6582 int n;
6583
6584 /* Don't check timestamps while system() or another low-level function may
6585 * cause us to lose and gain focus. */
6586 if (no_check_timestamps > 0)
6587 return FALSE;
6588
6589 /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
6590 * event and we would keep on checking if the file is steadily growing.
6591 * Do check again after typing something. */
6592 if (focus && did_check_timestamps)
6593 {
6594 need_check_timestamps = TRUE;
6595 return FALSE;
6596 }
6597
6598 if (!stuff_empty() || global_busy || !typebuf_typed()
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006599 || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006600 need_check_timestamps = TRUE; /* check later */
6601 else
6602 {
6603 ++no_wait_return;
6604 did_check_timestamps = TRUE;
6605 already_warned = FALSE;
Bram Moolenaar29323592016-07-24 22:04:11 +02006606 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006607 {
6608 /* Only check buffers in a window. */
6609 if (buf->b_nwindows > 0)
6610 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006611 bufref_T bufref;
6612
6613 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006614 n = buf_check_timestamp(buf, focus);
6615 if (didit < n)
6616 didit = n;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006617 if (n > 0 && !bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006618 {
6619 /* Autocommands have removed the buffer, start at the
6620 * first one again. */
6621 buf = firstbuf;
6622 continue;
6623 }
6624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006625 }
6626 --no_wait_return;
6627 need_check_timestamps = FALSE;
6628 if (need_wait_return && didit == 2)
6629 {
6630 /* make sure msg isn't overwritten */
Bram Moolenaar32526b32019-01-19 17:43:09 +01006631 msg_puts("\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006632 out_flush();
6633 }
6634 }
6635 return didit;
6636}
6637
6638/*
6639 * Move all the lines from buffer "frombuf" to buffer "tobuf".
6640 * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
6641 * empty.
6642 */
6643 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006644move_lines(buf_T *frombuf, buf_T *tobuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006645{
6646 buf_T *tbuf = curbuf;
6647 int retval = OK;
6648 linenr_T lnum;
6649 char_u *p;
6650
6651 /* Copy the lines in "frombuf" to "tobuf". */
6652 curbuf = tobuf;
6653 for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
6654 {
6655 p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
6656 if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
6657 {
6658 vim_free(p);
6659 retval = FAIL;
6660 break;
6661 }
6662 vim_free(p);
6663 }
6664
6665 /* Delete all the lines in "frombuf". */
6666 if (retval != FAIL)
6667 {
6668 curbuf = frombuf;
Bram Moolenaar9460b9d2007-01-09 14:37:01 +00006669 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
6670 if (ml_delete(lnum, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006671 {
6672 /* Oops! We could try putting back the saved lines, but that
6673 * might fail again... */
6674 retval = FAIL;
6675 break;
6676 }
6677 }
6678
6679 curbuf = tbuf;
6680 return retval;
6681}
6682
6683/*
6684 * Check if buffer "buf" has been changed.
6685 * Also check if the file for a new buffer unexpectedly appeared.
6686 * return 1 if a changed buffer was found.
6687 * return 2 if a message has been displayed.
6688 * return 0 otherwise.
6689 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006691buf_check_timestamp(
6692 buf_T *buf,
6693 int focus UNUSED) /* called for GUI focus event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006694{
Bram Moolenaar8767f522016-07-01 17:17:39 +02006695 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006696 int stat_res;
6697 int retval = 0;
6698 char_u *path;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006699 char *tbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006700 char *mesg = NULL;
Bram Moolenaar44ecf652005-03-07 23:09:59 +00006701 char *mesg2 = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006702 int helpmesg = FALSE;
6703 int reload = FALSE;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006704 char *reason;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006705#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6706 int can_reload = FALSE;
6707#endif
Bram Moolenaar8767f522016-07-01 17:17:39 +02006708 off_T orig_size = buf->b_orig_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006709 int orig_mode = buf->b_orig_mode;
6710#ifdef FEAT_GUI
6711 int save_mouse_correct = need_mouse_correct;
6712#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006713 static int busy = FALSE;
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006714 int n;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006715#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006716 char_u *s;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006717#endif
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006718 bufref_T bufref;
6719
6720 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006721
6722 /* If there is no file name, the buffer is not loaded, 'buftype' is
6723 * set, we are in the middle of a save or being called recursively: ignore
6724 * this buffer. */
6725 if (buf->b_ffname == NULL
6726 || buf->b_ml.ml_mfp == NULL
Bram Moolenaar91335e52018-08-01 17:53:12 +02006727 || !bt_normal(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006728 || buf->b_saving
Bram Moolenaar071d4272004-06-13 20:20:40 +00006729 || busy
Bram Moolenaar009b2592004-10-24 19:18:58 +00006730#ifdef FEAT_NETBEANS_INTG
6731 || isNetbeansBuffer(buf)
6732#endif
Bram Moolenaar8cad9302017-08-12 14:32:32 +02006733#ifdef FEAT_TERMINAL
6734 || buf->b_term != NULL
6735#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006736 )
6737 return 0;
6738
6739 if ( !(buf->b_flags & BF_NOTEDITED)
6740 && buf->b_mtime != 0
6741 && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
6742 || time_differs((long)st.st_mtime, buf->b_mtime)
Bram Moolenaara7611f62014-05-02 15:46:14 +02006743 || st.st_size != buf->b_orig_size
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744#ifdef HAVE_ST_MODE
6745 || (int)st.st_mode != buf->b_orig_mode
6746#else
6747 || mch_getperm(buf->b_ffname) != buf->b_orig_mode
6748#endif
6749 ))
6750 {
Bram Moolenaar674e2bd2019-07-31 20:21:01 +02006751 long prev_b_mtime = buf->b_mtime;
6752
Bram Moolenaar071d4272004-06-13 20:20:40 +00006753 retval = 1;
6754
Bram Moolenaar386bc822018-07-07 18:34:12 +02006755 // set b_mtime to stop further warnings (e.g., when executing
6756 // FileChangedShell autocmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006757 if (stat_res < 0)
6758 {
Bram Moolenaar8239c622019-05-24 16:46:01 +02006759 // Check the file again later to see if it re-appears.
6760 buf->b_mtime = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006761 buf->b_orig_size = 0;
6762 buf->b_orig_mode = 0;
6763 }
6764 else
6765 buf_store_time(buf, &st, buf->b_ffname);
6766
6767 /* Don't do anything for a directory. Might contain the file
6768 * explorer. */
6769 if (mch_isdir(buf->b_fname))
6770 ;
6771
6772 /*
6773 * If 'autoread' is set, the buffer has no changes and the file still
6774 * exists, reload the buffer. Use the buffer-local option value if it
6775 * was set, the global option value otherwise.
6776 */
6777 else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
6778 && !bufIsChanged(buf) && stat_res >= 0)
6779 reload = TRUE;
6780 else
6781 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006782 if (stat_res < 0)
6783 reason = "deleted";
6784 else if (bufIsChanged(buf))
6785 reason = "conflict";
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01006786 /*
6787 * Check if the file contents really changed to avoid giving a
6788 * warning when only the timestamp was set (e.g., checked out of
6789 * CVS). Always warn when the buffer was changed.
6790 */
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006791 else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
6792 reason = "changed";
6793 else if (orig_mode != buf->b_orig_mode)
6794 reason = "mode";
6795 else
6796 reason = "time";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006797
6798 /*
6799 * Only give the warning if there are no FileChangedShell
6800 * autocommands.
6801 * Avoid being called recursively by setting "busy".
6802 */
6803 busy = TRUE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006804#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006805 set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
6806 set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006807#endif
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006808 ++allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 n = apply_autocmds(EVENT_FILECHANGEDSHELL,
6810 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00006811 --allbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006812 busy = FALSE;
6813 if (n)
6814 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006815 if (!bufref_valid(&bufref))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006816 emsg(_("E246: FileChangedShell autocommand deleted buffer"));
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006817#ifdef FEAT_EVAL
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006818 s = get_vim_var_str(VV_FCS_CHOICE);
6819 if (STRCMP(s, "reload") == 0 && *reason != 'd')
6820 reload = TRUE;
6821 else if (STRCMP(s, "ask") == 0)
6822 n = FALSE;
6823 else
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006824#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006825 return 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 }
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006827 if (!n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006828 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006829 if (*reason == 'd')
Bram Moolenaar674e2bd2019-07-31 20:21:01 +02006830 {
6831 // Only give the message once.
6832 if (prev_b_mtime != -1)
6833 mesg = _("E211: File \"%s\" no longer available");
6834 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006835 else
6836 {
6837 helpmesg = TRUE;
6838#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6839 can_reload = TRUE;
6840#endif
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006841 if (reason[2] == 'n')
6842 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006843 mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006844 mesg2 = _("See \":help W12\" for more info.");
6845 }
6846 else if (reason[1] == 'h')
6847 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 mesg = _("W11: Warning: File \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006849 mesg2 = _("See \":help W11\" for more info.");
6850 }
6851 else if (*reason == 'm')
6852 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006853 mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006854 mesg2 = _("See \":help W16\" for more info.");
6855 }
Bram Moolenaar85388b52009-06-24 09:58:32 +00006856 else
6857 /* Only timestamp changed, store it to avoid a warning
6858 * in check_mtime() later. */
6859 buf->b_mtime_read = buf->b_mtime;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 }
6861 }
6862 }
6863
6864 }
6865 else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
6866 && vim_fexists(buf->b_ffname))
6867 {
6868 retval = 1;
6869 mesg = _("W13: Warning: File \"%s\" has been created after editing started");
6870 buf->b_flags |= BF_NEW_W;
6871#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6872 can_reload = TRUE;
6873#endif
6874 }
6875
6876 if (mesg != NULL)
6877 {
6878 path = home_replace_save(buf, buf->b_fname);
6879 if (path != NULL)
6880 {
Bram Moolenaar19a09a12005-03-04 23:39:37 +00006881 if (!helpmesg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006882 mesg2 = "";
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006883 tbuf = alloc(STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006884 sprintf(tbuf, mesg, path);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006885#ifdef FEAT_EVAL
6886 /* Set warningmsg here, before the unimportant and output-specific
6887 * mesg2 has been appended. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006888 set_vim_var_string(VV_WARNINGMSG, (char_u *)tbuf, -1);
Bram Moolenaar496c5262009-03-18 14:42:00 +00006889#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006890#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
6891 if (can_reload)
6892 {
6893 if (*mesg2 != NUL)
6894 {
6895 STRCAT(tbuf, "\n");
6896 STRCAT(tbuf, mesg2);
6897 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006898 if (do_dialog(VIM_WARNING, (char_u *)_("Warning"),
6899 (char_u *)tbuf,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01006900 (char_u *)_("&OK\n&Load File"), 1, NULL, TRUE) == 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006901 reload = TRUE;
6902 }
6903 else
6904#endif
6905 if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
6906 {
6907 if (*mesg2 != NUL)
6908 {
6909 STRCAT(tbuf, "; ");
6910 STRCAT(tbuf, mesg2);
6911 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006912 emsg(tbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 retval = 2;
6914 }
6915 else
6916 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006917 if (!autocmd_busy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006918 {
6919 msg_start();
Bram Moolenaar32526b32019-01-19 17:43:09 +01006920 msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921 if (*mesg2 != NUL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006922 msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006923 msg_clr_eos();
6924 (void)msg_end();
6925 if (emsg_silent == 0)
6926 {
6927 out_flush();
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006928#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00006929 if (!focus)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006930#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006931 /* give the user some time to think about it */
6932 ui_delay(1000L, TRUE);
6933
6934 /* don't redraw and erase the message */
6935 redraw_cmdline = FALSE;
6936 }
6937 }
6938 already_warned = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006939 }
6940
6941 vim_free(path);
6942 vim_free(tbuf);
6943 }
6944 }
6945
6946 if (reload)
Bram Moolenaar465748e2012-08-29 18:50:54 +02006947 {
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006948 /* Reload the buffer. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006949 buf_reload(buf, orig_mode);
Bram Moolenaar465748e2012-08-29 18:50:54 +02006950#ifdef FEAT_PERSISTENT_UNDO
6951 if (buf->b_p_udf && buf->b_ffname != NULL)
6952 {
6953 char_u hash[UNDO_HASH_SIZE];
6954 buf_T *save_curbuf = curbuf;
6955
6956 /* Any existing undo file is unusable, write it now. */
6957 curbuf = buf;
6958 u_compute_hash(hash);
6959 u_write_undo(NULL, FALSE, buf, hash);
6960 curbuf = save_curbuf;
6961 }
6962#endif
6963 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006964
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006965 /* Trigger FileChangedShell when the file was changed in any way. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006966 if (bufref_valid(&bufref) && retval != 0)
Bram Moolenaar56718732006-03-15 22:53:57 +00006967 (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
6968 buf->b_fname, buf->b_fname, FALSE, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006969#ifdef FEAT_GUI
6970 /* restore this in case an autocommand has set it; it would break
6971 * 'mousefocus' */
6972 need_mouse_correct = save_mouse_correct;
6973#endif
6974
6975 return retval;
6976}
6977
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006978/*
6979 * Reload a buffer that is already loaded.
6980 * Used when the file was changed outside of Vim.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006981 * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
6982 * buf->b_orig_mode may have been reset already.
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006983 */
6984 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01006985buf_reload(buf_T *buf, int orig_mode)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006986{
6987 exarg_T ea;
6988 pos_T old_cursor;
6989 linenr_T old_topline;
6990 int old_ro = buf->b_p_ro;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006991 buf_T *savebuf;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006992 bufref_T bufref;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006993 int saved = OK;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006994 aco_save_T aco;
Bram Moolenaar59f931e2010-07-24 20:27:03 +02006995 int flags = READ_NEW;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006996
6997 /* set curwin/curbuf for "buf" and save some things */
6998 aucmd_prepbuf(&aco, buf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00006999
7000 /* We only want to read the text from the file, not reset the syntax
7001 * highlighting, clear marks, diff status, etc. Force the fileformat
7002 * and encoding to be the same. */
7003 if (prep_exarg(&ea, buf) == OK)
7004 {
7005 old_cursor = curwin->w_cursor;
7006 old_topline = curwin->w_topline;
7007
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007008 if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007009 {
7010 /* Save all the text, so that the reload can be undone.
7011 * Sync first so that this is a separate undo-able action. */
7012 u_sync(FALSE);
7013 saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
7014 flags |= READ_KEEP_UNDO;
7015 }
7016
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007017 /*
7018 * To behave like when a new file is edited (matters for
7019 * BufReadPost autocommands) we first need to delete the current
7020 * buffer contents. But if reading the file fails we should keep
7021 * the old contents. Can't use memory only, the file might be
7022 * too big. Use a hidden buffer to move the buffer contents to.
7023 */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007024 if (BUFEMPTY() || saved == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007025 savebuf = NULL;
7026 else
7027 {
7028 /* Allocate a buffer without putting it in the buffer list. */
7029 savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007030 set_bufref(&bufref, savebuf);
Bram Moolenaar8424a622006-04-19 21:23:36 +00007031 if (savebuf != NULL && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007032 {
7033 /* Open the memline. */
7034 curbuf = savebuf;
7035 curwin->w_buffer = savebuf;
Bram Moolenaar4770d092006-01-12 23:22:24 +00007036 saved = ml_open(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007037 curbuf = buf;
7038 curwin->w_buffer = buf;
7039 }
Bram Moolenaar8424a622006-04-19 21:23:36 +00007040 if (savebuf == NULL || saved == FAIL || buf != curbuf
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007041 || move_lines(buf, savebuf) == FAIL)
7042 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007043 semsg(_("E462: Could not prepare for reloading \"%s\""),
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007044 buf->b_fname);
7045 saved = FAIL;
7046 }
7047 }
7048
7049 if (saved == OK)
7050 {
7051 curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007052 keep_filetype = TRUE; /* don't detect 'filetype' */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007053 if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
7054 (linenr_T)0,
Bram Moolenaare13b9af2017-01-13 22:01:02 +01007055 (linenr_T)MAXLNUM, &ea, flags) != OK)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007056 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01007057#if defined(FEAT_EVAL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007058 if (!aborting())
7059#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007060 semsg(_("E321: Could not reload \"%s\""), buf->b_fname);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007061 if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007062 {
7063 /* Put the text back from the save buffer. First
7064 * delete any lines that readfile() added. */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007065 while (!BUFEMPTY())
Bram Moolenaar8424a622006-04-19 21:23:36 +00007066 if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007067 break;
7068 (void)move_lines(savebuf, buf);
7069 }
7070 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007071 else if (buf == curbuf) /* "buf" still valid */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007072 {
7073 /* Mark the buffer as unmodified and free undo info. */
Bram Moolenaarc024b462019-06-08 18:07:21 +02007074 unchanged(buf, TRUE, TRUE);
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007075 if ((flags & READ_KEEP_UNDO) == 0)
7076 {
7077 u_blockfree(buf);
7078 u_clearall(buf);
7079 }
7080 else
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007081 {
Bram Moolenaar59f931e2010-07-24 20:27:03 +02007082 /* Mark all undo states as changed. */
7083 u_unchanged(curbuf);
Bram Moolenaarf9bb7342010-08-04 14:29:54 +02007084 }
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007085 }
7086 }
7087 vim_free(ea.cmd);
7088
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02007089 if (savebuf != NULL && bufref_valid(&bufref))
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007090 wipe_buffer(savebuf, FALSE);
7091
7092#ifdef FEAT_DIFF
7093 /* Invalidate diff info if necessary. */
Bram Moolenaar8424a622006-04-19 21:23:36 +00007094 diff_invalidate(curbuf);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007095#endif
7096
7097 /* Restore the topline and cursor position and check it (lines may
7098 * have been removed). */
7099 if (old_topline > curbuf->b_ml.ml_line_count)
7100 curwin->w_topline = curbuf->b_ml.ml_line_count;
7101 else
7102 curwin->w_topline = old_topline;
7103 curwin->w_cursor = old_cursor;
7104 check_cursor();
7105 update_topline();
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007106 keep_filetype = FALSE;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007107#ifdef FEAT_FOLDING
7108 {
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007109 win_T *wp;
7110 tabpage_T *tp;
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007111
7112 /* Update folds unless they are defined manually. */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00007113 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007114 if (wp->w_buffer == curwin->w_buffer
7115 && !foldmethodIsManual(wp))
7116 foldUpdateAll(wp);
7117 }
7118#endif
7119 /* If the mode didn't change and 'readonly' was set, keep the old
7120 * value; the user probably used the ":view" command. But don't
7121 * reset it, might have had a read error. */
7122 if (orig_mode == curbuf->b_orig_mode)
7123 curbuf->b_p_ro |= old_ro;
Bram Moolenaar52f85b72013-01-30 14:13:56 +01007124
7125 /* Modelines must override settings done by autocommands. */
7126 do_modelines(0);
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007127 }
7128
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007129 /* restore curwin/curbuf and a few other things */
7130 aucmd_restbuf(&aco);
7131 /* Careful: autocommands may have made "buf" invalid! */
Bram Moolenaar631d6f62005-06-07 21:02:10 +00007132}
7133
Bram Moolenaar071d4272004-06-13 20:20:40 +00007134 void
Bram Moolenaar8767f522016-07-01 17:17:39 +02007135buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007136{
7137 buf->b_mtime = (long)st->st_mtime;
Bram Moolenaar914703b2010-05-31 21:59:46 +02007138 buf->b_orig_size = st->st_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007139#ifdef HAVE_ST_MODE
7140 buf->b_orig_mode = (int)st->st_mode;
7141#else
7142 buf->b_orig_mode = mch_getperm(fname);
7143#endif
7144}
7145
7146/*
7147 * Adjust the line with missing eol, used for the next write.
7148 * Used for do_filter(), when the input lines for the filter are deleted.
7149 */
7150 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007151write_lnum_adjust(linenr_T offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152{
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01007153 if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */
7154 curbuf->b_no_eol_lnum += offset;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007155}
7156
Bram Moolenaarda440d22016-01-16 21:27:23 +01007157#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
7158/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007159 * Core part of "readdir()" function.
7160 * Retrieve the list of files/directories of "path" into "gap".
7161 * Return OK for success, FAIL for failure.
7162 */
7163 int
7164readdir_core(
7165 garray_T *gap,
7166 char_u *path,
7167 void *context,
7168 int (*checkitem)(void *context, char_u *name))
7169{
7170 int failed = FALSE;
7171#ifdef MSWIN
7172 char_u *buf, *p;
7173 int ok;
7174 HANDLE hFind = INVALID_HANDLE_VALUE;
7175 WIN32_FIND_DATAW wfb;
7176 WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
7177#endif
7178
7179 ga_init2(gap, (int)sizeof(char *), 20);
7180
7181#ifdef MSWIN
Bram Moolenaar51e14382019-05-25 20:21:28 +02007182 buf = alloc(MAXPATHL);
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007183 if (buf == NULL)
7184 return FAIL;
7185 STRNCPY(buf, path, MAXPATHL-5);
Bram Moolenaar71de7202019-05-24 19:04:29 +02007186 p = buf + STRLEN(buf);
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007187 MB_PTR_BACK(buf, p);
7188 if (*p == '\\' || *p == '/')
7189 *p = NUL;
7190 STRCAT(buf, "\\*");
7191
7192 wn = enc_to_utf16(buf, NULL);
7193 if (wn != NULL)
7194 hFind = FindFirstFileW(wn, &wfb);
7195 ok = (hFind != INVALID_HANDLE_VALUE);
7196 if (!ok)
7197 {
7198 failed = TRUE;
7199 smsg(_(e_notopen), path);
7200 }
7201 else
7202 {
7203 while (ok)
7204 {
7205 int ignore;
7206
7207 p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here
7208 if (p == NULL)
7209 break; // out of memory
7210
7211 ignore = p[0] == '.' && (p[1] == NUL
7212 || (p[1] == '.' && p[2] == NUL));
7213 if (!ignore && checkitem != NULL)
7214 {
7215 int r = checkitem(context, p);
7216
7217 if (r < 0)
7218 {
7219 vim_free(p);
7220 break;
7221 }
7222 if (r == 0)
7223 ignore = TRUE;
7224 }
7225
7226 if (!ignore)
7227 {
7228 if (ga_grow(gap, 1) == OK)
7229 ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
7230 else
7231 {
7232 failed = TRUE;
7233 vim_free(p);
7234 break;
7235 }
7236 }
7237
7238 vim_free(p);
7239 ok = FindNextFileW(hFind, &wfb);
7240 }
7241 FindClose(hFind);
7242 }
7243
7244 vim_free(buf);
7245 vim_free(wn);
7246#else
7247 DIR *dirp;
7248 struct dirent *dp;
7249 char_u *p;
7250
7251 dirp = opendir((char *)path);
7252 if (dirp == NULL)
7253 {
7254 failed = TRUE;
7255 smsg(_(e_notopen), path);
7256 }
7257 else
7258 {
7259 for (;;)
7260 {
7261 int ignore;
7262
7263 dp = readdir(dirp);
7264 if (dp == NULL)
7265 break;
7266 p = (char_u *)dp->d_name;
7267
7268 ignore = p[0] == '.' &&
7269 (p[1] == NUL ||
7270 (p[1] == '.' && p[2] == NUL));
7271 if (!ignore && checkitem != NULL)
7272 {
7273 int r = checkitem(context, p);
7274
7275 if (r < 0)
7276 break;
7277 if (r == 0)
7278 ignore = TRUE;
7279 }
7280
7281 if (!ignore)
7282 {
7283 if (ga_grow(gap, 1) == OK)
7284 ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
7285 else
7286 {
7287 failed = TRUE;
7288 break;
7289 }
7290 }
7291 }
7292
7293 closedir(dirp);
7294 }
7295#endif
7296
7297 if (!failed && gap->ga_len > 0)
7298 sort_strings((char_u **)gap->ga_data, gap->ga_len);
7299
7300 return failed ? FAIL : OK;
7301}
7302
7303/*
Bram Moolenaarda440d22016-01-16 21:27:23 +01007304 * Delete "name" and everything in it, recursively.
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007305 * return 0 for success, -1 if some file was not deleted.
Bram Moolenaarda440d22016-01-16 21:27:23 +01007306 */
7307 int
7308delete_recursive(char_u *name)
7309{
7310 int result = 0;
Bram Moolenaarda440d22016-01-16 21:27:23 +01007311 int i;
7312 char_u *exp;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007313 garray_T ga;
Bram Moolenaarda440d22016-01-16 21:27:23 +01007314
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007315 // A symbolic link to a directory itself is deleted, not the directory it
7316 // points to.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007317 if (
Bram Moolenaar4f974752019-02-17 17:44:42 +01007318# if defined(UNIX) || defined(MSWIN)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007319 mch_isrealdir(name)
Bram Moolenaar203258c2016-01-17 22:15:16 +01007320# else
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007321 mch_isdir(name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01007322# endif
7323 )
Bram Moolenaarda440d22016-01-16 21:27:23 +01007324 {
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007325 exp = vim_strsave(name);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007326 if (exp == NULL)
7327 return -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007328 if (readdir_core(&ga, exp, NULL, NULL) == OK)
Bram Moolenaarda440d22016-01-16 21:27:23 +01007329 {
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007330 for (i = 0; i < ga.ga_len; ++i)
7331 {
7332 vim_snprintf((char *)NameBuff, MAXPATHL, "%s/%s", exp,
7333 ((char_u **)ga.ga_data)[i]);
7334 if (delete_recursive(NameBuff) != 0)
Bram Moolenaarda440d22016-01-16 21:27:23 +01007335 result = -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007336 }
7337 ga_clear_strings(&ga);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007338 }
7339 else
7340 result = -1;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007341 (void)mch_rmdir(exp);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007342 vim_free(exp);
Bram Moolenaarda440d22016-01-16 21:27:23 +01007343 }
7344 else
7345 result = mch_remove(name) == 0 ? 0 : -1;
7346
7347 return result;
7348}
7349#endif
7350
Bram Moolenaar071d4272004-06-13 20:20:40 +00007351#if defined(TEMPDIRNAMES) || defined(PROTO)
7352static long temp_count = 0; /* Temp filename counter. */
7353
7354/*
7355 * Delete the temp directory and all files it contains.
7356 */
7357 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007358vim_deltempdir(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007359{
Bram Moolenaar071d4272004-06-13 20:20:40 +00007360 if (vim_tempdir != NULL)
7361 {
Bram Moolenaarda440d22016-01-16 21:27:23 +01007362 /* remove the trailing path separator */
7363 gettail(vim_tempdir)[-1] = NUL;
7364 delete_recursive(vim_tempdir);
Bram Moolenaard23a8232018-02-10 18:45:26 +01007365 VIM_CLEAR(vim_tempdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007366 }
7367}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007368
7369/*
Bram Moolenaareaf03392009-11-17 11:08:52 +00007370 * Directory "tempdir" was created. Expand this name to a full path and put
7371 * it in "vim_tempdir". This avoids that using ":cd" would confuse us.
7372 * "tempdir" must be no longer than MAXPATHL.
7373 */
7374 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007375vim_settempdir(char_u *tempdir)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007376{
7377 char_u *buf;
7378
Bram Moolenaar964b3742019-05-24 18:54:09 +02007379 buf = alloc(MAXPATHL + 2);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007380 if (buf != NULL)
7381 {
7382 if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
7383 STRCPY(buf, tempdir);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02007384 add_pathsep(buf);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007385 vim_tempdir = vim_strsave(buf);
7386 vim_free(buf);
7387 }
7388}
Bram Moolenaar4592dee2009-11-18 19:11:58 +00007389#endif
Bram Moolenaareaf03392009-11-17 11:08:52 +00007390
7391/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007392 * vim_tempname(): Return a unique name that can be used for a temp file.
7393 *
Bram Moolenaar76ae22f2016-06-13 20:00:29 +02007394 * The temp file is NOT guaranteed to be created. If "keep" is FALSE it is
7395 * guaranteed to NOT be created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007396 *
7397 * The returned pointer is to allocated memory.
7398 * The returned pointer is NULL if no valid name was found.
7399 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007400 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007401vim_tempname(
7402 int extra_char UNUSED, /* char to use in the name instead of '?' */
7403 int keep UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007404{
7405#ifdef USE_TMPNAM
7406 char_u itmp[L_tmpnam]; /* use tmpnam() */
Bram Moolenaar4f974752019-02-17 17:44:42 +01007407#elif defined(MSWIN)
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007408 WCHAR itmp[TEMPNAMELEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007409#else
7410 char_u itmp[TEMPNAMELEN];
7411#endif
7412
7413#ifdef TEMPDIRNAMES
7414 static char *(tempdirs[]) = {TEMPDIRNAMES};
7415 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007416# ifndef EEXIST
Bram Moolenaar8767f522016-07-01 17:17:39 +02007417 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007418# endif
7419
7420 /*
7421 * This will create a directory for private use by this instance of Vim.
7422 * This is done once, and the same directory is used for all temp files.
7423 * This method avoids security problems because of symlink attacks et al.
7424 * It's also a bit faster, because we only need to check for an existing
7425 * file when creating the directory and not for each temp file.
7426 */
7427 if (vim_tempdir == NULL)
7428 {
7429 /*
7430 * Try the entries in TEMPDIRNAMES to create the temp directory.
7431 */
Bram Moolenaar78a15312009-05-15 19:33:18 +00007432 for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007433 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007434# ifndef HAVE_MKDTEMP
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007435 size_t itmplen;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007436 long nr;
7437 long off;
7438# endif
7439
Bram Moolenaare1a61992015-12-03 21:02:27 +01007440 /* Expand $TMP, leave room for "/v1100000/999999999".
7441 * Skip the directory check if the expansion fails. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007442 expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
Bram Moolenaare1a61992015-12-03 21:02:27 +01007443 if (itmp[0] != '$' && mch_isdir(itmp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007444 {
Bram Moolenaare1a61992015-12-03 21:02:27 +01007445 /* directory exists */
Bram Moolenaara06ecab2016-07-16 14:47:36 +02007446 add_pathsep(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007447
Bram Moolenaareaf03392009-11-17 11:08:52 +00007448# ifdef HAVE_MKDTEMP
Bram Moolenaar35d88f42016-06-04 14:52:00 +02007449 {
7450# if defined(UNIX) || defined(VMS)
7451 /* Make sure the umask doesn't remove the executable bit.
7452 * "repl" has been reported to use "177". */
7453 mode_t umask_save = umask(077);
7454# endif
7455 /* Leave room for filename */
7456 STRCAT(itmp, "vXXXXXX");
7457 if (mkdtemp((char *)itmp) != NULL)
7458 vim_settempdir(itmp);
7459# if defined(UNIX) || defined(VMS)
7460 (void)umask(umask_save);
7461# endif
7462 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007463# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007464 /* Get an arbitrary number of up to 6 digits. When it's
7465 * unlikely that it already exists it will be faster,
7466 * otherwise it doesn't matter. The use of mkdir() avoids any
7467 * security problems because of the predictable number. */
7468 nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01007469 itmplen = STRLEN(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007470
7471 /* Try up to 10000 different values until we find a name that
7472 * doesn't exist. */
7473 for (off = 0; off < 10000L; ++off)
7474 {
7475 int r;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007476# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007477 mode_t umask_save;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007478# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007479
Bram Moolenaareaf03392009-11-17 11:08:52 +00007480 sprintf((char *)itmp + itmplen, "v%ld", nr + off);
7481# ifndef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007482 /* If mkdir() does not set errno to EEXIST, check for
7483 * existing file here. There is a race condition then,
7484 * although it's fail-safe. */
7485 if (mch_stat((char *)itmp, &st) >= 0)
7486 continue;
Bram Moolenaareaf03392009-11-17 11:08:52 +00007487# endif
7488# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007489 /* Make sure the umask doesn't remove the executable bit.
7490 * "repl" has been reported to use "177". */
7491 umask_save = umask(077);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007492# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007493 r = vim_mkdir(itmp, 0700);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007494# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007495 (void)umask(umask_save);
Bram Moolenaareaf03392009-11-17 11:08:52 +00007496# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007497 if (r == 0)
7498 {
Bram Moolenaareaf03392009-11-17 11:08:52 +00007499 vim_settempdir(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007500 break;
7501 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007502# ifdef EEXIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00007503 /* If the mkdir() didn't fail because the file/dir exists,
7504 * we probably can't create any dir here, try another
7505 * place. */
7506 if (errno != EEXIST)
Bram Moolenaareaf03392009-11-17 11:08:52 +00007507# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007508 break;
7509 }
Bram Moolenaareaf03392009-11-17 11:08:52 +00007510# endif /* HAVE_MKDTEMP */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007511 if (vim_tempdir != NULL)
7512 break;
7513 }
7514 }
7515 }
7516
7517 if (vim_tempdir != NULL)
7518 {
7519 /* There is no need to check if the file exists, because we own the
7520 * directory and nobody else creates a file in it. */
7521 sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
7522 return vim_strsave(itmp);
7523 }
7524
7525 return NULL;
7526
7527#else /* TEMPDIRNAMES */
7528
Bram Moolenaar4f974752019-02-17 17:44:42 +01007529# ifdef MSWIN
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007530 WCHAR wszTempFile[_MAX_PATH + 1];
7531 WCHAR buf4[4];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007532 char_u *retval;
7533 char_u *p;
7534
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007535 wcscpy(itmp, L"");
7536 if (GetTempPathW(_MAX_PATH, wszTempFile) == 0)
Bram Moolenaarb1891912011-02-09 14:47:03 +01007537 {
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007538 wszTempFile[0] = L'.'; // GetTempPathW() failed, use current dir
7539 wszTempFile[1] = NUL;
Bram Moolenaarb1891912011-02-09 14:47:03 +01007540 }
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007541 wcscpy(buf4, L"VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00007542 buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007543 if (GetTempFileNameW(wszTempFile, buf4, 0, itmp) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007544 return NULL;
Bram Moolenaare5c421c2015-03-31 13:33:08 +02007545 if (!keep)
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007546 // GetTempFileName() will create the file, we don't want that
7547 (void)DeleteFileW(itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007548
Bram Moolenaarec0f50a2019-02-10 23:26:13 +01007549 // Backslashes in a temp file name cause problems when filtering with
7550 // "sh". NOTE: This also checks 'shellcmdflag' to help those people who
7551 // didn't set 'shellslash'.
7552 retval = utf16_to_enc(itmp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007553 if (*p_shcf == '-' || p_ssl)
7554 for (p = retval; *p; ++p)
7555 if (*p == '\\')
7556 *p = '/';
7557 return retval;
7558
Bram Moolenaar4f974752019-02-17 17:44:42 +01007559# else // MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007560
7561# ifdef USE_TMPNAM
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007562 char_u *p;
7563
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564 /* tmpnam() will make its own name */
Bram Moolenaar95474ca2011-02-09 16:44:51 +01007565 p = tmpnam((char *)itmp);
7566 if (p == NULL || *p == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007567 return NULL;
7568# else
7569 char_u *p;
7570
7571# ifdef VMS_TEMPNAM
7572 /* mktemp() is not working on VMS. It seems to be
7573 * a do-nothing function. Therefore we use tempnam().
7574 */
7575 sprintf((char *)itmp, "VIM%c", extra_char);
7576 p = (char_u *)tempnam("tmp:", (char *)itmp);
7577 if (p != NULL)
7578 {
Bram Moolenaar206f0112014-03-12 16:51:55 +01007579 /* VMS will use '.LIS' if we don't explicitly specify an extension,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007580 * and VIM will then be unable to find the file later */
7581 STRCPY(itmp, p);
7582 STRCAT(itmp, ".txt");
7583 free(p);
7584 }
7585 else
7586 return NULL;
7587# else
7588 STRCPY(itmp, TEMPNAME);
7589 if ((p = vim_strchr(itmp, '?')) != NULL)
7590 *p = extra_char;
7591 if (mktemp((char *)itmp) == NULL)
7592 return NULL;
7593# endif
7594# endif
7595
7596 return vim_strsave(itmp);
Bram Moolenaar4f974752019-02-17 17:44:42 +01007597# endif // MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00007598#endif /* TEMPDIRNAMES */
7599}
7600
7601#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
7602/*
Bram Moolenaarb4f6a462015-10-13 19:43:17 +02007603 * Convert all backslashes in fname to forward slashes in-place, unless when
7604 * it looks like a URL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007605 */
7606 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007607forward_slash(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007608{
7609 char_u *p;
7610
Bram Moolenaarb4f6a462015-10-13 19:43:17 +02007611 if (path_with_url(fname))
7612 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007613 for (p = fname; *p != NUL; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007614 /* The Big5 encoding can have '\' in the trail byte. */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007615 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007616 ++p;
Bram Moolenaar13505972019-01-24 15:04:48 +01007617 else if (*p == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00007618 *p = '/';
7619}
7620#endif
7621
Bram Moolenaarf30e74c2006-08-16 17:35:00 +00007622/*
Bram Moolenaar748bf032005-02-02 23:04:36 +00007623 * Try matching a filename with a "pattern" ("prog" is NULL), or use the
7624 * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
7625 * vim_regcomp() often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007626 * Used for autocommands and 'wildignore'.
7627 * Returns TRUE if there is a match, FALSE otherwise.
7628 */
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01007629 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007630match_file_pat(
7631 char_u *pattern, /* pattern to match with */
7632 regprog_T **prog, /* pre-compiled regprog or NULL */
7633 char_u *fname, /* full path of file name */
7634 char_u *sfname, /* short file name or NULL */
7635 char_u *tail, /* tail of path */
7636 int allow_dirs) /* allow matching with dir */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007637{
7638 regmatch_T regmatch;
7639 int result = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01007641 regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007642 if (prog != NULL)
7643 regmatch.regprog = *prog;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007644 else
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007645 regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007646
7647 /*
7648 * Try for a match with the pattern with:
7649 * 1. the full file name, when the pattern has a '/'.
7650 * 2. the short file name, when the pattern has a '/'.
7651 * 3. the tail of the file name, when the pattern has no '/'.
7652 */
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007653 if (regmatch.regprog != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007654 && ((allow_dirs
7655 && (vim_regexec(&regmatch, fname, (colnr_T)0)
7656 || (sfname != NULL
7657 && vim_regexec(&regmatch, sfname, (colnr_T)0))))
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007658 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007659 result = TRUE;
7660
Bram Moolenaardffa5b82014-11-19 16:38:07 +01007661 if (prog != NULL)
7662 *prog = regmatch.regprog;
7663 else
Bram Moolenaar473de612013-06-08 18:19:48 +02007664 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007665 return result;
7666}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007667
7668#if defined(FEAT_WILDIGN) || defined(PROTO)
7669/*
7670 * Return TRUE if a file matches with a pattern in "list".
7671 * "list" is a comma-separated list of patterns, like 'wildignore'.
7672 * "sfname" is the short file name or NULL, "ffname" the long file name.
7673 */
7674 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007675match_file_list(char_u *list, char_u *sfname, char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007676{
7677 char_u buf[100];
7678 char_u *tail;
7679 char_u *regpat;
7680 char allow_dirs;
7681 int match;
7682 char_u *p;
7683
7684 tail = gettail(sfname);
7685
7686 /* try all patterns in 'wildignore' */
7687 p = list;
7688 while (*p)
7689 {
7690 copy_option_part(&p, buf, 100, ",");
7691 regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
7692 if (regpat == NULL)
7693 break;
Bram Moolenaar748bf032005-02-02 23:04:36 +00007694 match = match_file_pat(regpat, NULL, ffname, sfname,
7695 tail, (int)allow_dirs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007696 vim_free(regpat);
7697 if (match)
7698 return TRUE;
7699 }
7700 return FALSE;
7701}
7702#endif
7703
7704/*
7705 * Convert the given pattern "pat" which has shell style wildcards in it, into
7706 * a regular expression, and return the result in allocated memory. If there
7707 * is a directory path separator to be matched, then TRUE is put in
7708 * allow_dirs, otherwise FALSE is put there -- webb.
7709 * Handle backslashes before special characters, like "\*" and "\ ".
7710 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00007711 * Returns NULL when out of memory.
7712 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007713 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007714file_pat_to_reg_pat(
7715 char_u *pat,
7716 char_u *pat_end, /* first char after pattern or NULL */
7717 char *allow_dirs, /* Result passed back out in here */
7718 int no_bslash UNUSED) /* Don't use a backward slash as pathsep */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007719{
Bram Moolenaar49a6ed82015-01-07 14:43:39 +01007720 int size = 2; /* '^' at start, '$' at end */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007721 char_u *endp;
7722 char_u *reg_pat;
7723 char_u *p;
7724 int i;
7725 int nested = 0;
7726 int add_dollar = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007727
7728 if (allow_dirs != NULL)
7729 *allow_dirs = FALSE;
7730 if (pat_end == NULL)
7731 pat_end = pat + STRLEN(pat);
7732
Bram Moolenaar071d4272004-06-13 20:20:40 +00007733 for (p = pat; p < pat_end; p++)
7734 {
7735 switch (*p)
7736 {
7737 case '*':
7738 case '.':
7739 case ',':
7740 case '{':
7741 case '}':
7742 case '~':
7743 size += 2; /* extra backslash */
7744 break;
7745#ifdef BACKSLASH_IN_FILENAME
7746 case '\\':
7747 case '/':
7748 size += 4; /* could become "[\/]" */
7749 break;
7750#endif
7751 default:
7752 size++;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007753 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007754 {
7755 ++p;
7756 ++size;
7757 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007758 break;
7759 }
7760 }
7761 reg_pat = alloc(size + 1);
7762 if (reg_pat == NULL)
7763 return NULL;
7764
Bram Moolenaar071d4272004-06-13 20:20:40 +00007765 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007766
7767 if (pat[0] == '*')
7768 while (pat[0] == '*' && pat < pat_end - 1)
7769 pat++;
7770 else
7771 reg_pat[i++] = '^';
7772 endp = pat_end - 1;
Bram Moolenaar8fee8782015-08-11 18:45:48 +02007773 if (endp >= pat && *endp == '*')
Bram Moolenaar071d4272004-06-13 20:20:40 +00007774 {
7775 while (endp - pat > 0 && *endp == '*')
7776 endp--;
7777 add_dollar = FALSE;
7778 }
7779 for (p = pat; *p && nested >= 0 && p <= endp; p++)
7780 {
7781 switch (*p)
7782 {
7783 case '*':
7784 reg_pat[i++] = '.';
7785 reg_pat[i++] = '*';
Bram Moolenaar02743632005-07-25 20:42:36 +00007786 while (p[1] == '*') /* "**" matches like "*" */
7787 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007788 break;
7789 case '.':
Bram Moolenaar071d4272004-06-13 20:20:40 +00007790 case '~':
7791 reg_pat[i++] = '\\';
7792 reg_pat[i++] = *p;
7793 break;
7794 case '?':
Bram Moolenaar071d4272004-06-13 20:20:40 +00007795 reg_pat[i++] = '.';
7796 break;
7797 case '\\':
7798 if (p[1] == NUL)
7799 break;
7800#ifdef BACKSLASH_IN_FILENAME
7801 if (!no_bslash)
7802 {
7803 /* translate:
7804 * "\x" to "\\x" e.g., "dir\file"
7805 * "\*" to "\\.*" e.g., "dir\*.c"
7806 * "\?" to "\\." e.g., "dir\??.c"
7807 * "\+" to "\+" e.g., "fileX\+.c"
7808 */
7809 if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
7810 && p[1] != '+')
7811 {
7812 reg_pat[i++] = '[';
7813 reg_pat[i++] = '\\';
7814 reg_pat[i++] = '/';
7815 reg_pat[i++] = ']';
7816 if (allow_dirs != NULL)
7817 *allow_dirs = TRUE;
7818 break;
7819 }
7820 }
7821#endif
Bram Moolenaar8cd213c2010-06-01 21:57:09 +02007822 /* Undo escaping from ExpandEscape():
7823 * foo\?bar -> foo?bar
7824 * foo\%bar -> foo%bar
7825 * foo\,bar -> foo,bar
7826 * foo\ bar -> foo bar
7827 * Don't unescape \, * and others that are also special in a
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007828 * regexp.
7829 * An escaped { must be unescaped since we use magic not
Bram Moolenaara946afe2013-08-02 15:22:39 +02007830 * verymagic. Use "\\\{n,m\}"" to get "\{n,m}".
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007831 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007832 if (*++p == '?'
7833#ifdef BACKSLASH_IN_FILENAME
7834 && no_bslash
7835#endif
7836 )
7837 reg_pat[i++] = '?';
7838 else
Bram Moolenaarf4e11432013-07-03 16:53:03 +02007839 if (*p == ',' || *p == '%' || *p == '#'
Bram Moolenaar2288afe2015-08-11 16:20:05 +02007840 || vim_isspace(*p) || *p == '{' || *p == '}')
Bram Moolenaar8cd213c2010-06-01 21:57:09 +02007841 reg_pat[i++] = *p;
Bram Moolenaara946afe2013-08-02 15:22:39 +02007842 else if (*p == '\\' && p[1] == '\\' && p[2] == '{')
7843 {
7844 reg_pat[i++] = '\\';
7845 reg_pat[i++] = '{';
7846 p += 2;
7847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007848 else
7849 {
7850 if (allow_dirs != NULL && vim_ispathsep(*p)
7851#ifdef BACKSLASH_IN_FILENAME
7852 && (!no_bslash || *p != '\\')
7853#endif
7854 )
7855 *allow_dirs = TRUE;
7856 reg_pat[i++] = '\\';
7857 reg_pat[i++] = *p;
7858 }
7859 break;
7860#ifdef BACKSLASH_IN_FILENAME
7861 case '/':
7862 reg_pat[i++] = '[';
7863 reg_pat[i++] = '\\';
7864 reg_pat[i++] = '/';
7865 reg_pat[i++] = ']';
7866 if (allow_dirs != NULL)
7867 *allow_dirs = TRUE;
7868 break;
7869#endif
7870 case '{':
7871 reg_pat[i++] = '\\';
7872 reg_pat[i++] = '(';
7873 nested++;
7874 break;
7875 case '}':
7876 reg_pat[i++] = '\\';
7877 reg_pat[i++] = ')';
7878 --nested;
7879 break;
7880 case ',':
7881 if (nested)
7882 {
7883 reg_pat[i++] = '\\';
7884 reg_pat[i++] = '|';
7885 }
7886 else
7887 reg_pat[i++] = ',';
7888 break;
7889 default:
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00007890 if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007891 reg_pat[i++] = *p++;
Bram Moolenaar13505972019-01-24 15:04:48 +01007892 else if (allow_dirs != NULL && vim_ispathsep(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007893 *allow_dirs = TRUE;
7894 reg_pat[i++] = *p;
7895 break;
7896 }
7897 }
7898 if (add_dollar)
7899 reg_pat[i++] = '$';
7900 reg_pat[i] = NUL;
7901 if (nested != 0)
7902 {
7903 if (nested < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007904 emsg(_("E219: Missing {."));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007905 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007906 emsg(_("E220: Missing }."));
Bram Moolenaard23a8232018-02-10 18:45:26 +01007907 VIM_CLEAR(reg_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007908 }
7909 return reg_pat;
7910}
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007911
7912#if defined(EINTR) || defined(PROTO)
7913/*
7914 * Version of read() that retries when interrupted by EINTR (possibly
7915 * by a SIGWINCH).
7916 */
7917 long
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007918read_eintr(int fd, void *buf, size_t bufsize)
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007919{
7920 long ret;
7921
7922 for (;;)
7923 {
7924 ret = vim_read(fd, buf, bufsize);
7925 if (ret >= 0 || errno != EINTR)
7926 break;
7927 }
7928 return ret;
7929}
7930
7931/*
7932 * Version of write() that retries when interrupted by EINTR (possibly
7933 * by a SIGWINCH).
7934 */
7935 long
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01007936write_eintr(int fd, void *buf, size_t bufsize)
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007937{
7938 long ret = 0;
7939 long wlen;
7940
7941 /* Repeat the write() so long it didn't fail, other than being interrupted
7942 * by a signal. */
7943 while (ret < (long)bufsize)
7944 {
Bram Moolenaar9c263032010-12-17 18:06:06 +01007945 wlen = vim_write(fd, (char *)buf + ret, bufsize - ret);
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01007946 if (wlen < 0)
7947 {
7948 if (errno != EINTR)
7949 break;
7950 }
7951 else
7952 ret += wlen;
7953 }
7954 return ret;
7955}
7956#endif