1 | // This is an open source non-commercial project. Dear PVS-Studio, please check |
2 | // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
3 | |
4 | // fileio.c: read from and write to a file |
5 | |
6 | #include <assert.h> |
7 | #include <errno.h> |
8 | #include <stdbool.h> |
9 | #include <string.h> |
10 | #include <inttypes.h> |
11 | #include <fcntl.h> |
12 | |
13 | #include "nvim/vim.h" |
14 | #include "nvim/api/private/handle.h" |
15 | #include "nvim/ascii.h" |
16 | #include "nvim/fileio.h" |
17 | #include "nvim/buffer.h" |
18 | #include "nvim/change.h" |
19 | #include "nvim/charset.h" |
20 | #include "nvim/cursor.h" |
21 | #include "nvim/diff.h" |
22 | #include "nvim/edit.h" |
23 | #include "nvim/eval.h" |
24 | #include "nvim/ex_cmds.h" |
25 | #include "nvim/ex_docmd.h" |
26 | #include "nvim/ex_eval.h" |
27 | #include "nvim/fold.h" |
28 | #include "nvim/func_attr.h" |
29 | #include "nvim/getchar.h" |
30 | #include "nvim/hashtab.h" |
31 | #include "nvim/iconv.h" |
32 | #include "nvim/mbyte.h" |
33 | #include "nvim/memfile.h" |
34 | #include "nvim/memline.h" |
35 | #include "nvim/memory.h" |
36 | #include "nvim/message.h" |
37 | #include "nvim/misc1.h" |
38 | #include "nvim/garray.h" |
39 | #include "nvim/move.h" |
40 | #include "nvim/normal.h" |
41 | #include "nvim/option.h" |
42 | #include "nvim/os_unix.h" |
43 | #include "nvim/path.h" |
44 | #include "nvim/quickfix.h" |
45 | #include "nvim/regexp.h" |
46 | #include "nvim/screen.h" |
47 | #include "nvim/search.h" |
48 | #include "nvim/sha256.h" |
49 | #include "nvim/state.h" |
50 | #include "nvim/strings.h" |
51 | #include "nvim/ui.h" |
52 | #include "nvim/ui_compositor.h" |
53 | #include "nvim/types.h" |
54 | #include "nvim/undo.h" |
55 | #include "nvim/window.h" |
56 | #include "nvim/shada.h" |
57 | #include "nvim/os/os.h" |
58 | #include "nvim/os/os_defs.h" |
59 | #include "nvim/os/time.h" |
60 | #include "nvim/os/input.h" |
61 | |
62 | #define BUFSIZE 8192 /* size of normal write buffer */ |
63 | #define SMBUFSIZE 256 /* size of emergency write buffer */ |
64 | |
65 | // |
66 | // The autocommands are stored in a list for each event. |
67 | // Autocommands for the same pattern, that are consecutive, are joined |
68 | // together, to avoid having to match the pattern too often. |
69 | // The result is an array of Autopat lists, which point to AutoCmd lists: |
70 | // |
71 | // last_autopat[0] -----------------------------+ |
72 | // V |
73 | // first_autopat[0] --> Autopat.next --> Autopat.next --> NULL |
74 | // Autopat.cmds Autopat.cmds |
75 | // | | |
76 | // V V |
77 | // AutoCmd.next AutoCmd.next |
78 | // | | |
79 | // V V |
80 | // AutoCmd.next NULL |
81 | // | |
82 | // V |
83 | // NULL |
84 | // |
85 | // last_autopat[1] --------+ |
86 | // V |
87 | // first_autopat[1] --> Autopat.next --> NULL |
88 | // Autopat.cmds |
89 | // | |
90 | // V |
91 | // AutoCmd.next |
92 | // | |
93 | // V |
94 | // NULL |
95 | // etc. |
96 | // |
97 | // The order of AutoCmds is important, this is the order in which they were |
98 | // defined and will have to be executed. |
99 | // |
100 | typedef struct AutoCmd { |
101 | char_u *cmd; // Command to be executed (NULL when |
102 | // command has been removed) |
103 | bool once; // "One shot": removed after execution |
104 | char nested; // If autocommands nest here |
105 | char last; // last command in list |
106 | sctx_T script_ctx; // script context where defined |
107 | struct AutoCmd *next; // Next AutoCmd in list |
108 | } AutoCmd; |
109 | |
110 | typedef struct AutoPat { |
111 | struct AutoPat *next; // next AutoPat in AutoPat list; MUST |
112 | // be the first entry |
113 | char_u *pat; // pattern as typed (NULL when pattern |
114 | // has been removed) |
115 | regprog_T *reg_prog; // compiled regprog for pattern |
116 | AutoCmd *cmds; // list of commands to do |
117 | int group; // group ID |
118 | int patlen; // strlen() of pat |
119 | int buflocal_nr; // !=0 for buffer-local AutoPat |
120 | char allow_dirs; // Pattern may match whole path |
121 | char last; // last pattern for apply_autocmds() |
122 | } AutoPat; |
123 | |
124 | /// |
125 | /// Struct used to keep status while executing autocommands for an event. |
126 | /// |
127 | typedef struct AutoPatCmd { |
128 | AutoPat *curpat; // next AutoPat to examine |
129 | AutoCmd *nextcmd; // next AutoCmd to execute |
130 | int group; // group being used |
131 | char_u *fname; // fname to match with |
132 | char_u *sfname; // sfname to match with |
133 | char_u *tail; // tail of fname |
134 | event_T event; // current event |
135 | int arg_bufnr; // initially equal to <abuf>, set to zero when |
136 | // buf is deleted |
137 | struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation |
138 | } AutoPatCmd; |
139 | |
140 | #define AUGROUP_DEFAULT -1 /* default autocmd group */ |
141 | #define AUGROUP_ERROR -2 /* erroneous autocmd group */ |
142 | #define AUGROUP_ALL -3 /* all autocmd groups */ |
143 | |
144 | #define HAS_BW_FLAGS |
145 | #define FIO_LATIN1 0x01 /* convert Latin1 */ |
146 | #define FIO_UTF8 0x02 /* convert UTF-8 */ |
147 | #define FIO_UCS2 0x04 /* convert UCS-2 */ |
148 | #define FIO_UCS4 0x08 /* convert UCS-4 */ |
149 | #define FIO_UTF16 0x10 /* convert UTF-16 */ |
150 | #define FIO_ENDIAN_L 0x80 /* little endian */ |
151 | #define FIO_NOCONVERT 0x2000 /* skip encoding conversion */ |
152 | #define FIO_UCSBOM 0x4000 /* check for BOM at start of file */ |
153 | #define FIO_ALL -1 /* allow all formats */ |
154 | |
155 | /* When converting, a read() or write() may leave some bytes to be converted |
156 | * for the next call. The value is guessed... */ |
157 | #define CONV_RESTLEN 30 |
158 | |
159 | /* We have to guess how much a sequence of bytes may expand when converting |
160 | * with iconv() to be able to allocate a buffer. */ |
161 | #define ICONV_MULT 8 |
162 | |
163 | /* |
164 | * Structure to pass arguments from buf_write() to buf_write_bytes(). |
165 | */ |
166 | struct bw_info { |
167 | int bw_fd; // file descriptor |
168 | char_u *bw_buf; // buffer with data to be written |
169 | int bw_len; // length of data |
170 | #ifdef HAS_BW_FLAGS |
171 | int bw_flags; // FIO_ flags |
172 | #endif |
173 | char_u bw_rest[CONV_RESTLEN]; // not converted bytes |
174 | int bw_restlen; // nr of bytes in bw_rest[] |
175 | int bw_first; // first write call |
176 | char_u *bw_conv_buf; // buffer for writing converted chars |
177 | int bw_conv_buflen; // size of bw_conv_buf |
178 | int bw_conv_error; // set for conversion error |
179 | linenr_T bw_conv_error_lnum; // first line with error or zero |
180 | linenr_T bw_start_lnum; // line number at start of buffer |
181 | # ifdef HAVE_ICONV |
182 | iconv_t bw_iconv_fd; // descriptor for iconv() or -1 |
183 | # endif |
184 | }; |
185 | |
186 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
187 | # include "fileio.c.generated.h" |
188 | #endif |
189 | |
190 | static char *e_auchangedbuf = N_( |
191 | "E812: Autocommands changed buffer or buffer name" ); |
192 | |
193 | // Set by the apply_autocmds_group function if the given event is equal to |
194 | // EVENT_FILETYPE. Used by the readfile function in order to determine if |
195 | // EVENT_BUFREADPOST triggered the EVENT_FILETYPE. |
196 | // |
197 | // Relying on this value requires one to reset it prior calling |
198 | // apply_autocmds_group. |
199 | static bool au_did_filetype INIT(= false); |
200 | |
201 | void filemess(buf_T *buf, char_u *name, char_u *s, int attr) |
202 | { |
203 | int msg_scroll_save; |
204 | |
205 | if (msg_silent != 0) { |
206 | return; |
207 | } |
208 | add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name); |
209 | xstrlcat((char *)IObuff, (const char *)s, IOSIZE); |
210 | // For the first message may have to start a new line. |
211 | // For further ones overwrite the previous one, reset msg_scroll before |
212 | // calling filemess(). |
213 | msg_scroll_save = msg_scroll; |
214 | if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) |
215 | msg_scroll = FALSE; |
216 | if (!msg_scroll) /* wait a bit when overwriting an error msg */ |
217 | check_for_delay(FALSE); |
218 | msg_start(); |
219 | msg_scroll = msg_scroll_save; |
220 | msg_scrolled_ign = TRUE; |
221 | /* may truncate the message to avoid a hit-return prompt */ |
222 | msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr); |
223 | msg_clr_eos(); |
224 | ui_flush(); |
225 | msg_scrolled_ign = FALSE; |
226 | } |
227 | |
228 | static AutoPat *last_autopat[NUM_EVENTS] = { |
229 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
230 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
231 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
232 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
233 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
234 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
235 | }; |
236 | |
237 | /* |
238 | * Read lines from file "fname" into the buffer after line "from". |
239 | * |
240 | * 1. We allocate blocks with try_malloc, as big as possible. |
241 | * 2. Each block is filled with characters from the file with a single read(). |
242 | * 3. The lines are inserted in the buffer with ml_append(). |
243 | * |
244 | * (caller must check that fname != NULL, unless READ_STDIN is used) |
245 | * |
246 | * "lines_to_skip" is the number of lines that must be skipped |
247 | * "lines_to_read" is the number of lines that are appended |
248 | * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM. |
249 | * |
250 | * flags: |
251 | * READ_NEW starting to edit a new buffer |
252 | * READ_FILTER reading filter output |
253 | * READ_STDIN read from stdin instead of a file |
254 | * READ_BUFFER read from curbuf instead of a file (converting after reading |
255 | * stdin) |
256 | * READ_DUMMY read into a dummy buffer (to check if file contents changed) |
257 | * READ_KEEP_UNDO don't clear undo info or read it from a file |
258 | * READ_FIFO read from fifo/socket instead of a file |
259 | * |
260 | * return FAIL for failure, NOTDONE for directory (failure), or OK |
261 | */ |
262 | int |
263 | readfile( |
264 | char_u *fname, |
265 | char_u *sfname, |
266 | linenr_T from, |
267 | linenr_T lines_to_skip, |
268 | linenr_T lines_to_read, |
269 | exarg_T *eap, // can be NULL! |
270 | int flags |
271 | ) |
272 | { |
273 | int fd = 0; |
274 | int newfile = (flags & READ_NEW); |
275 | int check_readonly; |
276 | int filtering = (flags & READ_FILTER); |
277 | int read_stdin = (flags & READ_STDIN); |
278 | int read_buffer = (flags & READ_BUFFER); |
279 | int read_fifo = (flags & READ_FIFO); |
280 | int set_options = newfile || read_buffer |
281 | || (eap != NULL && eap->read_edit); |
282 | linenr_T read_buf_lnum = 1; /* next line to read from curbuf */ |
283 | colnr_T read_buf_col = 0; /* next char to read from this line */ |
284 | char_u c; |
285 | linenr_T lnum = from; |
286 | char_u *ptr = NULL; /* pointer into read buffer */ |
287 | char_u *buffer = NULL; /* read buffer */ |
288 | char_u *new_buffer = NULL; /* init to shut up gcc */ |
289 | char_u *line_start = NULL; /* init to shut up gcc */ |
290 | int wasempty; /* buffer was empty before reading */ |
291 | colnr_T len; |
292 | long size = 0; |
293 | uint8_t *p = NULL; |
294 | off_T filesize = 0; |
295 | int skip_read = false; |
296 | context_sha256_T sha_ctx; |
297 | int read_undo_file = false; |
298 | linenr_T linecnt; |
299 | int error = FALSE; /* errors encountered */ |
300 | int ff_error = EOL_UNKNOWN; /* file format with errors */ |
301 | long linerest = 0; /* remaining chars in line */ |
302 | int perm = 0; |
303 | #ifdef UNIX |
304 | int swap_mode = -1; /* protection bits for swap file */ |
305 | #endif |
306 | int fileformat = 0; // end-of-line format |
307 | bool keep_fileformat = false; |
308 | FileInfo file_info; |
309 | int file_readonly; |
310 | linenr_T skip_count = 0; |
311 | linenr_T read_count = 0; |
312 | int msg_save = msg_scroll; |
313 | linenr_T read_no_eol_lnum = 0; // non-zero lnum when last line of |
314 | // last read was missing the eol |
315 | bool file_rewind = false; |
316 | int can_retry; |
317 | linenr_T conv_error = 0; // line nr with conversion error |
318 | linenr_T illegal_byte = 0; // line nr with illegal byte |
319 | bool keep_dest_enc = false; // don't retry when char doesn't fit |
320 | // in destination encoding |
321 | int bad_char_behavior = BAD_REPLACE; |
322 | /* BAD_KEEP, BAD_DROP or character to |
323 | * replace with */ |
324 | char_u *tmpname = NULL; /* name of 'charconvert' output file */ |
325 | int fio_flags = 0; |
326 | char_u *fenc; // fileencoding to use |
327 | bool fenc_alloced; // fenc_next is in allocated memory |
328 | char_u *fenc_next = NULL; // next item in 'fencs' or NULL |
329 | bool advance_fenc = false; |
330 | long real_size = 0; |
331 | # ifdef HAVE_ICONV |
332 | iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 |
333 | int did_iconv = false; // TRUE when iconv() failed and trying |
334 | // 'charconvert' next |
335 | # endif |
336 | int converted = FALSE; /* TRUE if conversion done */ |
337 | int notconverted = FALSE; /* TRUE if conversion wanted but it |
338 | wasn't possible */ |
339 | char_u conv_rest[CONV_RESTLEN]; |
340 | int conv_restlen = 0; /* nr of bytes in conv_rest[] */ |
341 | buf_T *old_curbuf; |
342 | char_u *old_b_ffname; |
343 | char_u *old_b_fname; |
344 | int using_b_ffname; |
345 | int using_b_fname; |
346 | |
347 | au_did_filetype = false; // reset before triggering any autocommands |
348 | |
349 | curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */ |
350 | |
351 | /* |
352 | * If there is no file name yet, use the one for the read file. |
353 | * BF_NOTEDITED is set to reflect this. |
354 | * Don't do this for a read from a filter. |
355 | * Only do this when 'cpoptions' contains the 'f' flag. |
356 | */ |
357 | if (curbuf->b_ffname == NULL |
358 | && !filtering |
359 | && fname != NULL |
360 | && vim_strchr(p_cpo, CPO_FNAMER) != NULL |
361 | && !(flags & READ_DUMMY)) { |
362 | if (set_rw_fname(fname, sfname) == FAIL) |
363 | return FAIL; |
364 | } |
365 | |
366 | /* Remember the initial values of curbuf, curbuf->b_ffname and |
367 | * curbuf->b_fname to detect whether they are altered as a result of |
368 | * executing nasty autocommands. Also check if "fname" and "sfname" |
369 | * point to one of these values. */ |
370 | old_curbuf = curbuf; |
371 | old_b_ffname = curbuf->b_ffname; |
372 | old_b_fname = curbuf->b_fname; |
373 | using_b_ffname = (fname == curbuf->b_ffname) |
374 | || (sfname == curbuf->b_ffname); |
375 | using_b_fname = (fname == curbuf->b_fname) || (sfname == curbuf->b_fname); |
376 | |
377 | /* After reading a file the cursor line changes but we don't want to |
378 | * display the line. */ |
379 | ex_no_reprint = TRUE; |
380 | |
381 | /* don't display the file info for another buffer now */ |
382 | need_fileinfo = FALSE; |
383 | |
384 | // For Unix: Use the short file name whenever possible. |
385 | // Avoids problems with networks and when directory names are changed. |
386 | // Don't do this for Windows, a "cd" in a sub-shell may have moved us to |
387 | // another directory, which we don't detect. |
388 | if (sfname == NULL) { |
389 | sfname = fname; |
390 | } |
391 | #if defined(UNIX) |
392 | fname = sfname; |
393 | #endif |
394 | |
395 | /* |
396 | * The BufReadCmd and FileReadCmd events intercept the reading process by |
397 | * executing the associated commands instead. |
398 | */ |
399 | if (!filtering && !read_stdin && !read_buffer) { |
400 | pos_T pos; |
401 | |
402 | pos = curbuf->b_op_start; |
403 | |
404 | /* Set '[ mark to the line above where the lines go (line 1 if zero). */ |
405 | curbuf->b_op_start.lnum = ((from == 0) ? 1 : from); |
406 | curbuf->b_op_start.col = 0; |
407 | |
408 | if (newfile) { |
409 | if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, |
410 | FALSE, curbuf, eap)) |
411 | return aborting() ? FAIL : OK; |
412 | } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, |
413 | FALSE, NULL, eap)) |
414 | return aborting() ? FAIL : OK; |
415 | |
416 | curbuf->b_op_start = pos; |
417 | } |
418 | |
419 | if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) |
420 | msg_scroll = FALSE; /* overwrite previous file message */ |
421 | else |
422 | msg_scroll = TRUE; /* don't overwrite previous file message */ |
423 | |
424 | /* |
425 | * If the name is too long we might crash further on, quit here. |
426 | */ |
427 | if (fname != NULL && *fname != NUL) { |
428 | if (STRLEN(fname) >= MAXPATHL) { |
429 | filemess(curbuf, fname, (char_u *)_("Illegal file name" ), 0); |
430 | msg_end(); |
431 | msg_scroll = msg_save; |
432 | return FAIL; |
433 | } |
434 | } |
435 | |
436 | if (!read_buffer && !read_stdin && !read_fifo) { |
437 | perm = os_getperm((const char *)fname); |
438 | #ifdef UNIX |
439 | // On Unix it is possible to read a directory, so we have to |
440 | // check for it before os_open(). |
441 | if (perm >= 0 && !S_ISREG(perm) // not a regular file ... |
442 | # ifdef S_ISFIFO |
443 | && !S_ISFIFO(perm) // ... or fifo |
444 | # endif |
445 | # ifdef S_ISSOCK |
446 | && !S_ISSOCK(perm) // ... or socket |
447 | # endif |
448 | # ifdef OPEN_CHR_FILES |
449 | && !(S_ISCHR(perm) && is_dev_fd_file(fname)) |
450 | // ... or a character special file named /dev/fd/<n> |
451 | # endif |
452 | ) { |
453 | if (S_ISDIR(perm)) { |
454 | filemess(curbuf, fname, (char_u *)_("is a directory" ), 0); |
455 | } else { |
456 | filemess(curbuf, fname, (char_u *)_("is not a file" ), 0); |
457 | } |
458 | msg_end(); |
459 | msg_scroll = msg_save; |
460 | return S_ISDIR(perm) ? NOTDONE : FAIL; |
461 | } |
462 | #endif |
463 | } |
464 | |
465 | /* Set default or forced 'fileformat' and 'binary'. */ |
466 | set_file_options(set_options, eap); |
467 | |
468 | /* |
469 | * When opening a new file we take the readonly flag from the file. |
470 | * Default is r/w, can be set to r/o below. |
471 | * Don't reset it when in readonly mode |
472 | * Only set/reset b_p_ro when BF_CHECK_RO is set. |
473 | */ |
474 | check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO)); |
475 | if (check_readonly && !readonlymode) |
476 | curbuf->b_p_ro = FALSE; |
477 | |
478 | if (newfile && !read_stdin && !read_buffer && !read_fifo) { |
479 | // Remember time of file. |
480 | if (os_fileinfo((char *)fname, &file_info)) { |
481 | buf_store_file_info(curbuf, &file_info); |
482 | curbuf->b_mtime_read = curbuf->b_mtime; |
483 | #ifdef UNIX |
484 | /* |
485 | * Use the protection bits of the original file for the swap file. |
486 | * This makes it possible for others to read the name of the |
487 | * edited file from the swapfile, but only if they can read the |
488 | * edited file. |
489 | * Remove the "write" and "execute" bits for group and others |
490 | * (they must not write the swapfile). |
491 | * Add the "read" and "write" bits for the user, otherwise we may |
492 | * not be able to write to the file ourselves. |
493 | * Setting the bits is done below, after creating the swap file. |
494 | */ |
495 | swap_mode = (file_info.stat.st_mode & 0644) | 0600; |
496 | #endif |
497 | } else { |
498 | curbuf->b_mtime = 0; |
499 | curbuf->b_mtime_read = 0; |
500 | curbuf->b_orig_size = 0; |
501 | curbuf->b_orig_mode = 0; |
502 | } |
503 | |
504 | /* Reset the "new file" flag. It will be set again below when the |
505 | * file doesn't exist. */ |
506 | curbuf->b_flags &= ~(BF_NEW | BF_NEW_W); |
507 | } |
508 | |
509 | // Check readonly. |
510 | file_readonly = false; |
511 | if (!read_buffer && !read_stdin) { |
512 | if (!newfile || readonlymode || !(perm & 0222) |
513 | || !os_file_is_writable((char *)fname)) { |
514 | file_readonly = true; |
515 | } |
516 | fd = os_open((char *)fname, O_RDONLY, 0); |
517 | } |
518 | |
519 | if (fd < 0) { // cannot open at all |
520 | msg_scroll = msg_save; |
521 | #ifndef UNIX |
522 | // On non-unix systems we can't open a directory, check here. |
523 | if (os_isdir(fname)) { |
524 | filemess(curbuf, sfname, (char_u *)_("is a directory" ), 0); |
525 | curbuf->b_p_ro = true; // must use "w!" now |
526 | } else { |
527 | #endif |
528 | if (!newfile) { |
529 | return FAIL; |
530 | } |
531 | if (perm == UV_ENOENT) { // check if the file exists |
532 | // Set the 'new-file' flag, so that when the file has |
533 | // been created by someone else, a ":w" will complain. |
534 | curbuf->b_flags |= BF_NEW; |
535 | |
536 | /* Create a swap file now, so that other Vims are warned |
537 | * that we are editing this file. Don't do this for a |
538 | * "nofile" or "nowrite" buffer type. */ |
539 | if (!bt_dontwrite(curbuf)) { |
540 | check_need_swap(newfile); |
541 | /* SwapExists autocommand may mess things up */ |
542 | if (curbuf != old_curbuf |
543 | || (using_b_ffname |
544 | && (old_b_ffname != curbuf->b_ffname)) |
545 | || (using_b_fname |
546 | && (old_b_fname != curbuf->b_fname))) { |
547 | EMSG(_(e_auchangedbuf)); |
548 | return FAIL; |
549 | } |
550 | } |
551 | if (dir_of_file_exists(fname)) |
552 | filemess(curbuf, sfname, (char_u *)_("[New File]" ), 0); |
553 | else |
554 | filemess(curbuf, sfname, |
555 | (char_u *)_("[New DIRECTORY]" ), 0); |
556 | /* Even though this is a new file, it might have been |
557 | * edited before and deleted. Get the old marks. */ |
558 | check_marks_read(); |
559 | /* Set forced 'fileencoding'. */ |
560 | if (eap != NULL) |
561 | set_forced_fenc(eap); |
562 | apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname, |
563 | FALSE, curbuf, eap); |
564 | /* remember the current fileformat */ |
565 | save_file_ff(curbuf); |
566 | |
567 | if (aborting()) /* autocmds may abort script processing */ |
568 | return FAIL; |
569 | return OK; /* a new file is not an error */ |
570 | } else { |
571 | filemess(curbuf, sfname, (char_u *)( |
572 | (fd == UV_EFBIG) ? _("[File too big]" ) : |
573 | # if defined(UNIX) && defined(EOVERFLOW) |
574 | // libuv only returns -errno in Unix and in Windows open() does not |
575 | // set EOVERFLOW |
576 | (fd == -EOVERFLOW) ? _("[File too big]" ) : |
577 | # endif |
578 | _("[Permission Denied]" )), 0); |
579 | curbuf->b_p_ro = TRUE; /* must use "w!" now */ |
580 | } |
581 | |
582 | return FAIL; |
583 | } |
584 | #ifndef UNIX |
585 | } |
586 | #endif |
587 | |
588 | /* |
589 | * Only set the 'ro' flag for readonly files the first time they are |
590 | * loaded. Help files always get readonly mode |
591 | */ |
592 | if ((check_readonly && file_readonly) || curbuf->b_help) |
593 | curbuf->b_p_ro = TRUE; |
594 | |
595 | if (set_options) { |
596 | /* Don't change 'eol' if reading from buffer as it will already be |
597 | * correctly set when reading stdin. */ |
598 | if (!read_buffer) { |
599 | curbuf->b_p_eol = TRUE; |
600 | curbuf->b_start_eol = TRUE; |
601 | } |
602 | curbuf->b_p_bomb = FALSE; |
603 | curbuf->b_start_bomb = FALSE; |
604 | } |
605 | |
606 | /* Create a swap file now, so that other Vims are warned that we are |
607 | * editing this file. |
608 | * Don't do this for a "nofile" or "nowrite" buffer type. */ |
609 | if (!bt_dontwrite(curbuf)) { |
610 | check_need_swap(newfile); |
611 | if (!read_stdin |
612 | && (curbuf != old_curbuf |
613 | || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) |
614 | || (using_b_fname && (old_b_fname != curbuf->b_fname)))) { |
615 | EMSG(_(e_auchangedbuf)); |
616 | if (!read_buffer) { |
617 | close(fd); |
618 | } |
619 | return FAIL; |
620 | } |
621 | #ifdef UNIX |
622 | // Set swap file protection bits after creating it. |
623 | if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL |
624 | && curbuf->b_ml.ml_mfp->mf_fname != NULL) { |
625 | const char *swap_fname = (const char *)curbuf->b_ml.ml_mfp->mf_fname; |
626 | |
627 | // If the group-read bit is set but not the world-read bit, then |
628 | // the group must be equal to the group of the original file. If |
629 | // we can't make that happen then reset the group-read bit. This |
630 | // avoids making the swap file readable to more users when the |
631 | // primary group of the user is too permissive. |
632 | if ((swap_mode & 044) == 040) { |
633 | FileInfo swap_info; |
634 | |
635 | if (os_fileinfo(swap_fname, &swap_info) |
636 | && file_info.stat.st_gid != swap_info.stat.st_gid |
637 | && os_fchown(curbuf->b_ml.ml_mfp->mf_fd, -1, file_info.stat.st_gid) |
638 | == -1) { |
639 | swap_mode &= 0600; |
640 | } |
641 | } |
642 | |
643 | (void)os_setperm(swap_fname, swap_mode); |
644 | } |
645 | #endif |
646 | } |
647 | |
648 | // If "Quit" selected at ATTENTION dialog, don't load the file. |
649 | if (swap_exists_action == SEA_QUIT) { |
650 | if (!read_buffer && !read_stdin) |
651 | close(fd); |
652 | return FAIL; |
653 | } |
654 | |
655 | ++no_wait_return; /* don't wait for return yet */ |
656 | |
657 | /* |
658 | * Set '[ mark to the line above where the lines go (line 1 if zero). |
659 | */ |
660 | curbuf->b_op_start.lnum = ((from == 0) ? 1 : from); |
661 | curbuf->b_op_start.col = 0; |
662 | |
663 | int try_mac = (vim_strchr(p_ffs, 'm') != NULL); |
664 | int try_dos = (vim_strchr(p_ffs, 'd') != NULL); |
665 | int try_unix = (vim_strchr(p_ffs, 'x') != NULL); |
666 | |
667 | if (!read_buffer) { |
668 | int m = msg_scroll; |
669 | int n = msg_scrolled; |
670 | |
671 | // The file must be closed again, the autocommands may want to change |
672 | // the file before reading it. |
673 | if (!read_stdin) { |
674 | close(fd); // ignore errors |
675 | } |
676 | |
677 | // The output from the autocommands should not overwrite anything and |
678 | // should not be overwritten: Set msg_scroll, restore its value if no |
679 | // output was done. |
680 | msg_scroll = true; |
681 | if (filtering) { |
682 | apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname, |
683 | false, curbuf, eap); |
684 | } else if (read_stdin) { |
685 | apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname, |
686 | false, curbuf, eap); |
687 | } else if (newfile) { |
688 | apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname, |
689 | false, curbuf, eap); |
690 | } else { |
691 | apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname, |
692 | false, NULL, eap); |
693 | } |
694 | |
695 | // autocommands may have changed it |
696 | try_mac = (vim_strchr(p_ffs, 'm') != NULL); |
697 | try_dos = (vim_strchr(p_ffs, 'd') != NULL); |
698 | try_unix = (vim_strchr(p_ffs, 'x') != NULL); |
699 | |
700 | if (msg_scrolled == n) { |
701 | msg_scroll = m; |
702 | } |
703 | |
704 | if (aborting()) { /* autocmds may abort script processing */ |
705 | --no_wait_return; |
706 | msg_scroll = msg_save; |
707 | curbuf->b_p_ro = TRUE; /* must use "w!" now */ |
708 | return FAIL; |
709 | } |
710 | /* |
711 | * Don't allow the autocommands to change the current buffer. |
712 | * Try to re-open the file. |
713 | * |
714 | * Don't allow the autocommands to change the buffer name either |
715 | * (cd for example) if it invalidates fname or sfname. |
716 | */ |
717 | if (!read_stdin && (curbuf != old_curbuf |
718 | || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) |
719 | || (using_b_fname && (old_b_fname != curbuf->b_fname)) |
720 | || (fd = os_open((char *)fname, O_RDONLY, 0)) < 0)) { |
721 | --no_wait_return; |
722 | msg_scroll = msg_save; |
723 | if (fd < 0) |
724 | EMSG(_("E200: *ReadPre autocommands made the file unreadable" )); |
725 | else |
726 | EMSG(_("E201: *ReadPre autocommands must not change current buffer" )); |
727 | curbuf->b_p_ro = TRUE; /* must use "w!" now */ |
728 | return FAIL; |
729 | } |
730 | } |
731 | |
732 | /* Autocommands may add lines to the file, need to check if it is empty */ |
733 | wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY); |
734 | |
735 | if (!recoverymode && !filtering && !(flags & READ_DUMMY)) { |
736 | if (!read_stdin && !read_buffer) { |
737 | filemess(curbuf, sfname, (char_u *)"" , 0); |
738 | } |
739 | } |
740 | |
741 | msg_scroll = FALSE; /* overwrite the file message */ |
742 | |
743 | /* |
744 | * Set linecnt now, before the "retry" caused by a wrong guess for |
745 | * fileformat, and after the autocommands, which may change them. |
746 | */ |
747 | linecnt = curbuf->b_ml.ml_line_count; |
748 | |
749 | /* "++bad=" argument. */ |
750 | if (eap != NULL && eap->bad_char != 0) { |
751 | bad_char_behavior = eap->bad_char; |
752 | if (set_options) |
753 | curbuf->b_bad_char = eap->bad_char; |
754 | } else |
755 | curbuf->b_bad_char = 0; |
756 | |
757 | /* |
758 | * Decide which 'encoding' to use or use first. |
759 | */ |
760 | if (eap != NULL && eap->force_enc != 0) { |
761 | fenc = enc_canonize(eap->cmd + eap->force_enc); |
762 | fenc_alloced = true; |
763 | keep_dest_enc = true; |
764 | } else if (curbuf->b_p_bin) { |
765 | fenc = (char_u *)"" ; // binary: don't convert |
766 | fenc_alloced = false; |
767 | } else if (curbuf->b_help) { |
768 | // Help files are either utf-8 or latin1. Try utf-8 first, if this |
769 | // fails it must be latin1. |
770 | // It is needed when the first line contains non-ASCII characters. |
771 | // That is only in *.??x files. |
772 | fenc_next = (char_u *)"latin1" ; |
773 | fenc = (char_u *)"utf-8" ; |
774 | |
775 | fenc_alloced = false; |
776 | } else if (*p_fencs == NUL) { |
777 | fenc = curbuf->b_p_fenc; // use format from buffer |
778 | fenc_alloced = false; |
779 | } else { |
780 | fenc_next = p_fencs; // try items in 'fileencodings' |
781 | fenc = next_fenc(&fenc_next, &fenc_alloced); |
782 | } |
783 | |
784 | /* |
785 | * Jump back here to retry reading the file in different ways. |
786 | * Reasons to retry: |
787 | * - encoding conversion failed: try another one from "fenc_next" |
788 | * - BOM detected and fenc was set, need to setup conversion |
789 | * - "fileformat" check failed: try another |
790 | * |
791 | * Variables set for special retry actions: |
792 | * "file_rewind" Rewind the file to start reading it again. |
793 | * "advance_fenc" Advance "fenc" using "fenc_next". |
794 | * "skip_read" Re-use already read bytes (BOM detected). |
795 | * "did_iconv" iconv() conversion failed, try 'charconvert'. |
796 | * "keep_fileformat" Don't reset "fileformat". |
797 | * |
798 | * Other status indicators: |
799 | * "tmpname" When != NULL did conversion with 'charconvert'. |
800 | * Output file has to be deleted afterwards. |
801 | * "iconv_fd" When != -1 did conversion with iconv(). |
802 | */ |
803 | retry: |
804 | |
805 | if (file_rewind) { |
806 | if (read_buffer) { |
807 | read_buf_lnum = 1; |
808 | read_buf_col = 0; |
809 | } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) { |
810 | // Can't rewind the file, give up. |
811 | error = true; |
812 | goto failed; |
813 | } |
814 | // Delete the previously read lines. |
815 | while (lnum > from) { |
816 | ml_delete(lnum--, false); |
817 | } |
818 | file_rewind = false; |
819 | if (set_options) { |
820 | curbuf->b_p_bomb = FALSE; |
821 | curbuf->b_start_bomb = FALSE; |
822 | } |
823 | conv_error = 0; |
824 | } |
825 | |
826 | /* |
827 | * When retrying with another "fenc" and the first time "fileformat" |
828 | * will be reset. |
829 | */ |
830 | if (keep_fileformat) { |
831 | keep_fileformat = false; |
832 | } else { |
833 | if (eap != NULL && eap->force_ff != 0) { |
834 | fileformat = get_fileformat_force(curbuf, eap); |
835 | try_unix = try_dos = try_mac = FALSE; |
836 | } else if (curbuf->b_p_bin) |
837 | fileformat = EOL_UNIX; /* binary: use Unix format */ |
838 | else if (*p_ffs == NUL) |
839 | fileformat = get_fileformat(curbuf); /* use format from buffer */ |
840 | else |
841 | fileformat = EOL_UNKNOWN; /* detect from file */ |
842 | } |
843 | |
844 | # ifdef HAVE_ICONV |
845 | if (iconv_fd != (iconv_t)-1) { |
846 | /* aborted conversion with iconv(), close the descriptor */ |
847 | iconv_close(iconv_fd); |
848 | iconv_fd = (iconv_t)-1; |
849 | } |
850 | # endif |
851 | |
852 | if (advance_fenc) { |
853 | /* |
854 | * Try the next entry in 'fileencodings'. |
855 | */ |
856 | advance_fenc = false; |
857 | |
858 | if (eap != NULL && eap->force_enc != 0) { |
859 | /* Conversion given with "++cc=" wasn't possible, read |
860 | * without conversion. */ |
861 | notconverted = TRUE; |
862 | conv_error = 0; |
863 | if (fenc_alloced) |
864 | xfree(fenc); |
865 | fenc = (char_u *)"" ; |
866 | fenc_alloced = false; |
867 | } else { |
868 | if (fenc_alloced) |
869 | xfree(fenc); |
870 | if (fenc_next != NULL) { |
871 | fenc = next_fenc(&fenc_next, &fenc_alloced); |
872 | } else { |
873 | fenc = (char_u *)"" ; |
874 | fenc_alloced = false; |
875 | } |
876 | } |
877 | if (tmpname != NULL) { |
878 | os_remove((char *)tmpname); // delete converted file |
879 | XFREE_CLEAR(tmpname); |
880 | } |
881 | } |
882 | |
883 | /* |
884 | * Conversion may be required when the encoding of the file is different |
885 | * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. |
886 | */ |
887 | fio_flags = 0; |
888 | converted = need_conversion(fenc); |
889 | if (converted) { |
890 | |
891 | /* "ucs-bom" means we need to check the first bytes of the file |
892 | * for a BOM. */ |
893 | if (STRCMP(fenc, ENC_UCSBOM) == 0) |
894 | fio_flags = FIO_UCSBOM; |
895 | |
896 | /* |
897 | * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be |
898 | * done. This is handled below after read(). Prepare the |
899 | * fio_flags to avoid having to parse the string each time. |
900 | * Also check for Unicode to Latin1 conversion, because iconv() |
901 | * appears not to handle this correctly. This works just like |
902 | * conversion to UTF-8 except how the resulting character is put in |
903 | * the buffer. |
904 | */ |
905 | else if (enc_utf8 || STRCMP(p_enc, "latin1" ) == 0) |
906 | fio_flags = get_fio_flags(fenc); |
907 | |
908 | |
909 | |
910 | # ifdef HAVE_ICONV |
911 | // Try using iconv() if we can't convert internally. |
912 | if (fio_flags == 0 |
913 | && !did_iconv |
914 | ) { |
915 | iconv_fd = (iconv_t)my_iconv_open( |
916 | enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc); |
917 | } |
918 | # endif |
919 | |
920 | /* |
921 | * Use the 'charconvert' expression when conversion is required |
922 | * and we can't do it internally or with iconv(). |
923 | */ |
924 | if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL |
925 | && !read_fifo |
926 | # ifdef HAVE_ICONV |
927 | && iconv_fd == (iconv_t)-1 |
928 | # endif |
929 | ) { |
930 | # ifdef HAVE_ICONV |
931 | did_iconv = false; |
932 | # endif |
933 | /* Skip conversion when it's already done (retry for wrong |
934 | * "fileformat"). */ |
935 | if (tmpname == NULL) { |
936 | tmpname = readfile_charconvert(fname, fenc, &fd); |
937 | if (tmpname == NULL) { |
938 | // Conversion failed. Try another one. |
939 | advance_fenc = true; |
940 | if (fd < 0) { |
941 | /* Re-opening the original file failed! */ |
942 | EMSG(_("E202: Conversion made file unreadable!" )); |
943 | error = TRUE; |
944 | goto failed; |
945 | } |
946 | goto retry; |
947 | } |
948 | } |
949 | } else { |
950 | if (fio_flags == 0 |
951 | # ifdef HAVE_ICONV |
952 | && iconv_fd == (iconv_t)-1 |
953 | # endif |
954 | ) { |
955 | /* Conversion wanted but we can't. |
956 | * Try the next conversion in 'fileencodings' */ |
957 | advance_fenc = true; |
958 | goto retry; |
959 | } |
960 | } |
961 | } |
962 | |
963 | /* Set "can_retry" when it's possible to rewind the file and try with |
964 | * another "fenc" value. It's FALSE when no other "fenc" to try, reading |
965 | * stdin or fixed at a specific encoding. */ |
966 | can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc && !read_fifo); |
967 | |
968 | if (!skip_read) { |
969 | linerest = 0; |
970 | filesize = 0; |
971 | skip_count = lines_to_skip; |
972 | read_count = lines_to_read; |
973 | conv_restlen = 0; |
974 | read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0 |
975 | && curbuf->b_ffname != NULL |
976 | && curbuf->b_p_udf |
977 | && !filtering |
978 | && !read_fifo |
979 | && !read_stdin |
980 | && !read_buffer); |
981 | if (read_undo_file) |
982 | sha256_start(&sha_ctx); |
983 | } |
984 | |
985 | while (!error && !got_int) { |
986 | /* |
987 | * We allocate as much space for the file as we can get, plus |
988 | * space for the old line plus room for one terminating NUL. |
989 | * The amount is limited by the fact that read() only can read |
990 | * up to max_unsigned characters (and other things). |
991 | */ |
992 | { |
993 | if (!skip_read) { |
994 | size = 0x10000L; /* use buffer >= 64K */ |
995 | |
996 | for (; size >= 10; size /= 2) { |
997 | new_buffer = verbose_try_malloc((size_t)size + (size_t)linerest + 1); |
998 | if (new_buffer) { |
999 | break; |
1000 | } |
1001 | } |
1002 | if (new_buffer == NULL) { |
1003 | error = TRUE; |
1004 | break; |
1005 | } |
1006 | if (linerest) /* copy characters from the previous buffer */ |
1007 | memmove(new_buffer, ptr - linerest, (size_t)linerest); |
1008 | xfree(buffer); |
1009 | buffer = new_buffer; |
1010 | ptr = buffer + linerest; |
1011 | line_start = buffer; |
1012 | |
1013 | /* May need room to translate into. |
1014 | * For iconv() we don't really know the required space, use a |
1015 | * factor ICONV_MULT. |
1016 | * latin1 to utf-8: 1 byte becomes up to 2 bytes |
1017 | * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes |
1018 | * become up to 4 bytes, size must be multiple of 2 |
1019 | * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be |
1020 | * multiple of 2 |
1021 | * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be |
1022 | * multiple of 4 */ |
1023 | real_size = (int)size; |
1024 | # ifdef HAVE_ICONV |
1025 | if (iconv_fd != (iconv_t)-1) { |
1026 | size = size / ICONV_MULT; |
1027 | } else { |
1028 | # endif |
1029 | if (fio_flags & FIO_LATIN1) { |
1030 | size = size / 2; |
1031 | } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { |
1032 | size = (size * 2 / 3) & ~1; |
1033 | } else if (fio_flags & FIO_UCS4) { |
1034 | size = (size * 2 / 3) & ~3; |
1035 | } else if (fio_flags == FIO_UCSBOM) { |
1036 | size = size / ICONV_MULT; // worst case |
1037 | } |
1038 | # ifdef HAVE_ICONV |
1039 | } |
1040 | # endif |
1041 | if (conv_restlen > 0) { |
1042 | // Insert unconverted bytes from previous line. |
1043 | memmove(ptr, conv_rest, conv_restlen); // -V614 |
1044 | ptr += conv_restlen; |
1045 | size -= conv_restlen; |
1046 | } |
1047 | |
1048 | if (read_buffer) { |
1049 | /* |
1050 | * Read bytes from curbuf. Used for converting text read |
1051 | * from stdin. |
1052 | */ |
1053 | if (read_buf_lnum > from) |
1054 | size = 0; |
1055 | else { |
1056 | int n, ni; |
1057 | long tlen; |
1058 | |
1059 | tlen = 0; |
1060 | for (;; ) { |
1061 | p = ml_get(read_buf_lnum) + read_buf_col; |
1062 | n = (int)STRLEN(p); |
1063 | if ((int)tlen + n + 1 > size) { |
1064 | /* Filled up to "size", append partial line. |
1065 | * Change NL to NUL to reverse the effect done |
1066 | * below. */ |
1067 | n = (int)(size - tlen); |
1068 | for (ni = 0; ni < n; ++ni) { |
1069 | if (p[ni] == NL) |
1070 | ptr[tlen++] = NUL; |
1071 | else |
1072 | ptr[tlen++] = p[ni]; |
1073 | } |
1074 | read_buf_col += n; |
1075 | break; |
1076 | } else { |
1077 | /* Append whole line and new-line. Change NL |
1078 | * to NUL to reverse the effect done below. */ |
1079 | for (ni = 0; ni < n; ++ni) { |
1080 | if (p[ni] == NL) |
1081 | ptr[tlen++] = NUL; |
1082 | else |
1083 | ptr[tlen++] = p[ni]; |
1084 | } |
1085 | ptr[tlen++] = NL; |
1086 | read_buf_col = 0; |
1087 | if (++read_buf_lnum > from) { |
1088 | /* When the last line didn't have an |
1089 | * end-of-line don't add it now either. */ |
1090 | if (!curbuf->b_p_eol) |
1091 | --tlen; |
1092 | size = tlen; |
1093 | break; |
1094 | } |
1095 | } |
1096 | } |
1097 | } |
1098 | } else { |
1099 | /* |
1100 | * Read bytes from the file. |
1101 | */ |
1102 | size = read_eintr(fd, ptr, size); |
1103 | } |
1104 | |
1105 | if (size <= 0) { |
1106 | if (size < 0) /* read error */ |
1107 | error = TRUE; |
1108 | else if (conv_restlen > 0) { |
1109 | /* |
1110 | * Reached end-of-file but some trailing bytes could |
1111 | * not be converted. Truncated file? |
1112 | */ |
1113 | |
1114 | /* When we did a conversion report an error. */ |
1115 | if (fio_flags != 0 |
1116 | # ifdef HAVE_ICONV |
1117 | || iconv_fd != (iconv_t)-1 |
1118 | # endif |
1119 | ) { |
1120 | if (can_retry) |
1121 | goto rewind_retry; |
1122 | if (conv_error == 0) |
1123 | conv_error = curbuf->b_ml.ml_line_count |
1124 | - linecnt + 1; |
1125 | } |
1126 | /* Remember the first linenr with an illegal byte */ |
1127 | else if (illegal_byte == 0) |
1128 | illegal_byte = curbuf->b_ml.ml_line_count |
1129 | - linecnt + 1; |
1130 | if (bad_char_behavior == BAD_DROP) { |
1131 | *(ptr - conv_restlen) = NUL; |
1132 | conv_restlen = 0; |
1133 | } else { |
1134 | /* Replace the trailing bytes with the replacement |
1135 | * character if we were converting; if we weren't, |
1136 | * leave the UTF8 checking code to do it, as it |
1137 | * works slightly differently. */ |
1138 | if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 |
1139 | # ifdef HAVE_ICONV |
1140 | || iconv_fd != (iconv_t)-1 |
1141 | # endif |
1142 | )) { |
1143 | while (conv_restlen > 0) { |
1144 | *(--ptr) = bad_char_behavior; |
1145 | --conv_restlen; |
1146 | } |
1147 | } |
1148 | fio_flags = 0; // don't convert this |
1149 | # ifdef HAVE_ICONV |
1150 | if (iconv_fd != (iconv_t)-1) { |
1151 | iconv_close(iconv_fd); |
1152 | iconv_fd = (iconv_t)-1; |
1153 | } |
1154 | # endif |
1155 | } |
1156 | } |
1157 | } |
1158 | } |
1159 | |
1160 | skip_read = FALSE; |
1161 | |
1162 | /* |
1163 | * At start of file: Check for BOM. |
1164 | * Also check for a BOM for other Unicode encodings, but not after |
1165 | * converting with 'charconvert' or when a BOM has already been |
1166 | * found. |
1167 | */ |
1168 | if ((filesize == 0) |
1169 | && (fio_flags == FIO_UCSBOM |
1170 | || (!curbuf->b_p_bomb |
1171 | && tmpname == NULL |
1172 | && (*fenc == 'u' || (*fenc == NUL && enc_utf8))))) { |
1173 | char_u *ccname; |
1174 | int blen; |
1175 | |
1176 | /* no BOM detection in a short file or in binary mode */ |
1177 | if (size < 2 || curbuf->b_p_bin) |
1178 | ccname = NULL; |
1179 | else |
1180 | ccname = check_for_bom(ptr, size, &blen, |
1181 | fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); |
1182 | if (ccname != NULL) { |
1183 | /* Remove BOM from the text */ |
1184 | filesize += blen; |
1185 | size -= blen; |
1186 | memmove(ptr, ptr + blen, (size_t)size); |
1187 | if (set_options) { |
1188 | curbuf->b_p_bomb = TRUE; |
1189 | curbuf->b_start_bomb = TRUE; |
1190 | } |
1191 | } |
1192 | |
1193 | if (fio_flags == FIO_UCSBOM) { |
1194 | if (ccname == NULL) { |
1195 | // No BOM detected: retry with next encoding. |
1196 | advance_fenc = true; |
1197 | } else { |
1198 | /* BOM detected: set "fenc" and jump back */ |
1199 | if (fenc_alloced) |
1200 | xfree(fenc); |
1201 | fenc = ccname; |
1202 | fenc_alloced = false; |
1203 | } |
1204 | /* retry reading without getting new bytes or rewinding */ |
1205 | skip_read = TRUE; |
1206 | goto retry; |
1207 | } |
1208 | } |
1209 | |
1210 | /* Include not converted bytes. */ |
1211 | ptr -= conv_restlen; |
1212 | size += conv_restlen; |
1213 | conv_restlen = 0; |
1214 | /* |
1215 | * Break here for a read error or end-of-file. |
1216 | */ |
1217 | if (size <= 0) |
1218 | break; |
1219 | |
1220 | # ifdef HAVE_ICONV |
1221 | if (iconv_fd != (iconv_t)-1) { |
1222 | /* |
1223 | * Attempt conversion of the read bytes to 'encoding' using |
1224 | * iconv(). |
1225 | */ |
1226 | const char *fromp; |
1227 | char *top; |
1228 | size_t from_size; |
1229 | size_t to_size; |
1230 | |
1231 | fromp = (char *)ptr; |
1232 | from_size = size; |
1233 | ptr += size; |
1234 | top = (char *)ptr; |
1235 | to_size = real_size - size; |
1236 | |
1237 | /* |
1238 | * If there is conversion error or not enough room try using |
1239 | * another conversion. Except for when there is no |
1240 | * alternative (help files). |
1241 | */ |
1242 | while ((iconv(iconv_fd, (void *)&fromp, &from_size, |
1243 | &top, &to_size) |
1244 | == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) |
1245 | || from_size > CONV_RESTLEN) { |
1246 | if (can_retry) |
1247 | goto rewind_retry; |
1248 | if (conv_error == 0) |
1249 | conv_error = readfile_linenr(linecnt, |
1250 | ptr, (char_u *)top); |
1251 | |
1252 | /* Deal with a bad byte and continue with the next. */ |
1253 | ++fromp; |
1254 | --from_size; |
1255 | if (bad_char_behavior == BAD_KEEP) { |
1256 | *top++ = *(fromp - 1); |
1257 | --to_size; |
1258 | } else if (bad_char_behavior != BAD_DROP) { |
1259 | *top++ = bad_char_behavior; |
1260 | --to_size; |
1261 | } |
1262 | } |
1263 | |
1264 | if (from_size > 0) { |
1265 | /* Some remaining characters, keep them for the next |
1266 | * round. */ |
1267 | memmove(conv_rest, (char_u *)fromp, from_size); |
1268 | conv_restlen = (int)from_size; |
1269 | } |
1270 | |
1271 | /* move the linerest to before the converted characters */ |
1272 | line_start = ptr - linerest; |
1273 | memmove(line_start, buffer, (size_t)linerest); |
1274 | size = (long)((char_u *)top - ptr); |
1275 | } |
1276 | # endif |
1277 | |
1278 | if (fio_flags != 0) { |
1279 | unsigned int u8c; |
1280 | char_u *dest; |
1281 | char_u *tail = NULL; |
1282 | |
1283 | /* |
1284 | * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8. |
1285 | * "enc_utf8" not set: Convert Unicode to Latin1. |
1286 | * Go from end to start through the buffer, because the number |
1287 | * of bytes may increase. |
1288 | * "dest" points to after where the UTF-8 bytes go, "p" points |
1289 | * to after the next character to convert. |
1290 | */ |
1291 | dest = ptr + real_size; |
1292 | if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8) { |
1293 | p = ptr + size; |
1294 | if (fio_flags == FIO_UTF8) { |
1295 | /* Check for a trailing incomplete UTF-8 sequence */ |
1296 | tail = ptr + size - 1; |
1297 | while (tail > ptr && (*tail & 0xc0) == 0x80) |
1298 | --tail; |
1299 | if (tail + utf_byte2len(*tail) <= ptr + size) |
1300 | tail = NULL; |
1301 | else |
1302 | p = tail; |
1303 | } |
1304 | } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { |
1305 | /* Check for a trailing byte */ |
1306 | p = ptr + (size & ~1); |
1307 | if (size & 1) |
1308 | tail = p; |
1309 | if ((fio_flags & FIO_UTF16) && p > ptr) { |
1310 | /* Check for a trailing leading word */ |
1311 | if (fio_flags & FIO_ENDIAN_L) { |
1312 | u8c = (*--p << 8); |
1313 | u8c += *--p; |
1314 | } else { |
1315 | u8c = *--p; |
1316 | u8c += (*--p << 8); |
1317 | } |
1318 | if (u8c >= 0xd800 && u8c <= 0xdbff) |
1319 | tail = p; |
1320 | else |
1321 | p += 2; |
1322 | } |
1323 | } else { /* FIO_UCS4 */ |
1324 | /* Check for trailing 1, 2 or 3 bytes */ |
1325 | p = ptr + (size & ~3); |
1326 | if (size & 3) |
1327 | tail = p; |
1328 | } |
1329 | |
1330 | /* If there is a trailing incomplete sequence move it to |
1331 | * conv_rest[]. */ |
1332 | if (tail != NULL) { |
1333 | conv_restlen = (int)((ptr + size) - tail); |
1334 | memmove(conv_rest, tail, conv_restlen); |
1335 | size -= conv_restlen; |
1336 | } |
1337 | |
1338 | |
1339 | while (p > ptr) { |
1340 | if (fio_flags & FIO_LATIN1) |
1341 | u8c = *--p; |
1342 | else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { |
1343 | if (fio_flags & FIO_ENDIAN_L) { |
1344 | u8c = (*--p << 8); |
1345 | u8c += *--p; |
1346 | } else { |
1347 | u8c = *--p; |
1348 | u8c += (*--p << 8); |
1349 | } |
1350 | if ((fio_flags & FIO_UTF16) |
1351 | && u8c >= 0xdc00 && u8c <= 0xdfff) { |
1352 | int u16c; |
1353 | |
1354 | if (p == ptr) { |
1355 | /* Missing leading word. */ |
1356 | if (can_retry) |
1357 | goto rewind_retry; |
1358 | if (conv_error == 0) |
1359 | conv_error = readfile_linenr(linecnt, |
1360 | ptr, p); |
1361 | if (bad_char_behavior == BAD_DROP) |
1362 | continue; |
1363 | if (bad_char_behavior != BAD_KEEP) |
1364 | u8c = bad_char_behavior; |
1365 | } |
1366 | |
1367 | /* found second word of double-word, get the first |
1368 | * word and compute the resulting character */ |
1369 | if (fio_flags & FIO_ENDIAN_L) { |
1370 | u16c = (*--p << 8); |
1371 | u16c += *--p; |
1372 | } else { |
1373 | u16c = *--p; |
1374 | u16c += (*--p << 8); |
1375 | } |
1376 | u8c = 0x10000 + ((u16c & 0x3ff) << 10) |
1377 | + (u8c & 0x3ff); |
1378 | |
1379 | /* Check if the word is indeed a leading word. */ |
1380 | if (u16c < 0xd800 || u16c > 0xdbff) { |
1381 | if (can_retry) |
1382 | goto rewind_retry; |
1383 | if (conv_error == 0) |
1384 | conv_error = readfile_linenr(linecnt, |
1385 | ptr, p); |
1386 | if (bad_char_behavior == BAD_DROP) |
1387 | continue; |
1388 | if (bad_char_behavior != BAD_KEEP) |
1389 | u8c = bad_char_behavior; |
1390 | } |
1391 | } |
1392 | } else if (fio_flags & FIO_UCS4) { |
1393 | if (fio_flags & FIO_ENDIAN_L) { |
1394 | u8c = (unsigned)(*--p) << 24; |
1395 | u8c += (unsigned)(*--p) << 16; |
1396 | u8c += (unsigned)(*--p) << 8; |
1397 | u8c += *--p; |
1398 | } else { /* big endian */ |
1399 | u8c = *--p; |
1400 | u8c += (unsigned)(*--p) << 8; |
1401 | u8c += (unsigned)(*--p) << 16; |
1402 | u8c += (unsigned)(*--p) << 24; |
1403 | } |
1404 | } else { /* UTF-8 */ |
1405 | if (*--p < 0x80) |
1406 | u8c = *p; |
1407 | else { |
1408 | len = utf_head_off(ptr, p); |
1409 | p -= len; |
1410 | u8c = utf_ptr2char(p); |
1411 | if (len == 0) { |
1412 | /* Not a valid UTF-8 character, retry with |
1413 | * another fenc when possible, otherwise just |
1414 | * report the error. */ |
1415 | if (can_retry) |
1416 | goto rewind_retry; |
1417 | if (conv_error == 0) |
1418 | conv_error = readfile_linenr(linecnt, |
1419 | ptr, p); |
1420 | if (bad_char_behavior == BAD_DROP) |
1421 | continue; |
1422 | if (bad_char_behavior != BAD_KEEP) |
1423 | u8c = bad_char_behavior; |
1424 | } |
1425 | } |
1426 | } |
1427 | assert(u8c <= INT_MAX); |
1428 | // produce UTF-8 |
1429 | dest -= utf_char2len((int)u8c); |
1430 | (void)utf_char2bytes((int)u8c, dest); |
1431 | } |
1432 | |
1433 | // move the linerest to before the converted characters |
1434 | line_start = dest - linerest; |
1435 | memmove(line_start, buffer, (size_t)linerest); |
1436 | size = (long)((ptr + real_size) - dest); |
1437 | ptr = dest; |
1438 | } else if (enc_utf8 && !curbuf->b_p_bin) { |
1439 | int incomplete_tail = FALSE; |
1440 | |
1441 | // Reading UTF-8: Check if the bytes are valid UTF-8. |
1442 | for (p = ptr;; p++) { |
1443 | int todo = (int)((ptr + size) - p); |
1444 | int l; |
1445 | |
1446 | if (todo <= 0) { |
1447 | break; |
1448 | } |
1449 | if (*p >= 0x80) { |
1450 | // A length of 1 means it's an illegal byte. Accept |
1451 | // an incomplete character at the end though, the next |
1452 | // read() will get the next bytes, we'll check it |
1453 | // then. |
1454 | l = utf_ptr2len_len(p, todo); |
1455 | if (l > todo && !incomplete_tail) { |
1456 | /* Avoid retrying with a different encoding when |
1457 | * a truncated file is more likely, or attempting |
1458 | * to read the rest of an incomplete sequence when |
1459 | * we have already done so. */ |
1460 | if (p > ptr || filesize > 0) |
1461 | incomplete_tail = TRUE; |
1462 | /* Incomplete byte sequence, move it to conv_rest[] |
1463 | * and try to read the rest of it, unless we've |
1464 | * already done so. */ |
1465 | if (p > ptr) { |
1466 | conv_restlen = todo; |
1467 | memmove(conv_rest, p, conv_restlen); |
1468 | size -= conv_restlen; |
1469 | break; |
1470 | } |
1471 | } |
1472 | if (l == 1 || l > todo) { |
1473 | /* Illegal byte. If we can try another encoding |
1474 | * do that, unless at EOF where a truncated |
1475 | * file is more likely than a conversion error. */ |
1476 | if (can_retry && !incomplete_tail) |
1477 | break; |
1478 | # ifdef HAVE_ICONV |
1479 | // When we did a conversion report an error. |
1480 | if (iconv_fd != (iconv_t)-1 && conv_error == 0) { |
1481 | conv_error = readfile_linenr(linecnt, ptr, p); |
1482 | } |
1483 | # endif |
1484 | /* Remember the first linenr with an illegal byte */ |
1485 | if (conv_error == 0 && illegal_byte == 0) |
1486 | illegal_byte = readfile_linenr(linecnt, ptr, p); |
1487 | |
1488 | /* Drop, keep or replace the bad byte. */ |
1489 | if (bad_char_behavior == BAD_DROP) { |
1490 | memmove(p, p + 1, todo - 1); |
1491 | --p; |
1492 | --size; |
1493 | } else if (bad_char_behavior != BAD_KEEP) |
1494 | *p = bad_char_behavior; |
1495 | } else |
1496 | p += l - 1; |
1497 | } |
1498 | } |
1499 | if (p < ptr + size && !incomplete_tail) { |
1500 | /* Detected a UTF-8 error. */ |
1501 | rewind_retry: |
1502 | // Retry reading with another conversion. |
1503 | # ifdef HAVE_ICONV |
1504 | if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) { |
1505 | // iconv() failed, try 'charconvert' |
1506 | did_iconv = true; |
1507 | } else { |
1508 | # endif |
1509 | // use next item from 'fileencodings' |
1510 | advance_fenc = true; |
1511 | # ifdef HAVE_ICONV |
1512 | } |
1513 | # endif |
1514 | file_rewind = true; |
1515 | goto retry; |
1516 | } |
1517 | } |
1518 | |
1519 | /* count the number of characters (after conversion!) */ |
1520 | filesize += size; |
1521 | |
1522 | /* |
1523 | * when reading the first part of a file: guess EOL type |
1524 | */ |
1525 | if (fileformat == EOL_UNKNOWN) { |
1526 | /* First try finding a NL, for Dos and Unix */ |
1527 | if (try_dos || try_unix) { |
1528 | // Reset the carriage return counter. |
1529 | if (try_mac) { |
1530 | try_mac = 1; |
1531 | } |
1532 | |
1533 | for (p = ptr; p < ptr + size; ++p) { |
1534 | if (*p == NL) { |
1535 | if (!try_unix |
1536 | || (try_dos && p > ptr && p[-1] == CAR)) |
1537 | fileformat = EOL_DOS; |
1538 | else |
1539 | fileformat = EOL_UNIX; |
1540 | break; |
1541 | } else if (*p == CAR && try_mac) { |
1542 | try_mac++; |
1543 | } |
1544 | } |
1545 | |
1546 | /* Don't give in to EOL_UNIX if EOL_MAC is more likely */ |
1547 | if (fileformat == EOL_UNIX && try_mac) { |
1548 | /* Need to reset the counters when retrying fenc. */ |
1549 | try_mac = 1; |
1550 | try_unix = 1; |
1551 | for (; p >= ptr && *p != CAR; p--) |
1552 | ; |
1553 | if (p >= ptr) { |
1554 | for (p = ptr; p < ptr + size; ++p) { |
1555 | if (*p == NL) |
1556 | try_unix++; |
1557 | else if (*p == CAR) |
1558 | try_mac++; |
1559 | } |
1560 | if (try_mac > try_unix) |
1561 | fileformat = EOL_MAC; |
1562 | } |
1563 | } else if (fileformat == EOL_UNKNOWN && try_mac == 1) { |
1564 | // Looking for CR but found no end-of-line markers at all: |
1565 | // use the default format. |
1566 | fileformat = default_fileformat(); |
1567 | } |
1568 | } |
1569 | |
1570 | /* No NL found: may use Mac format */ |
1571 | if (fileformat == EOL_UNKNOWN && try_mac) |
1572 | fileformat = EOL_MAC; |
1573 | |
1574 | /* Still nothing found? Use first format in 'ffs' */ |
1575 | if (fileformat == EOL_UNKNOWN) |
1576 | fileformat = default_fileformat(); |
1577 | |
1578 | // May set 'p_ff' if editing a new file. |
1579 | if (set_options) { |
1580 | set_fileformat(fileformat, OPT_LOCAL); |
1581 | } |
1582 | } |
1583 | } |
1584 | |
1585 | /* |
1586 | * This loop is executed once for every character read. |
1587 | * Keep it fast! |
1588 | */ |
1589 | if (fileformat == EOL_MAC) { |
1590 | --ptr; |
1591 | while (++ptr, --size >= 0) { |
1592 | /* catch most common case first */ |
1593 | if ((c = *ptr) != NUL && c != CAR && c != NL) |
1594 | continue; |
1595 | if (c == NUL) |
1596 | *ptr = NL; /* NULs are replaced by newlines! */ |
1597 | else if (c == NL) |
1598 | *ptr = CAR; /* NLs are replaced by CRs! */ |
1599 | else { |
1600 | if (skip_count == 0) { |
1601 | *ptr = NUL; /* end of line */ |
1602 | len = (colnr_T) (ptr - line_start + 1); |
1603 | if (ml_append(lnum, line_start, len, newfile) == FAIL) { |
1604 | error = TRUE; |
1605 | break; |
1606 | } |
1607 | if (read_undo_file) |
1608 | sha256_update(&sha_ctx, line_start, len); |
1609 | ++lnum; |
1610 | if (--read_count == 0) { |
1611 | error = TRUE; /* break loop */ |
1612 | line_start = ptr; /* nothing left to write */ |
1613 | break; |
1614 | } |
1615 | } else |
1616 | --skip_count; |
1617 | line_start = ptr + 1; |
1618 | } |
1619 | } |
1620 | } else { |
1621 | --ptr; |
1622 | while (++ptr, --size >= 0) { |
1623 | if ((c = *ptr) != NUL && c != NL) /* catch most common case */ |
1624 | continue; |
1625 | if (c == NUL) |
1626 | *ptr = NL; /* NULs are replaced by newlines! */ |
1627 | else { |
1628 | if (skip_count == 0) { |
1629 | *ptr = NUL; /* end of line */ |
1630 | len = (colnr_T)(ptr - line_start + 1); |
1631 | if (fileformat == EOL_DOS) { |
1632 | if (ptr > line_start && ptr[-1] == CAR) { |
1633 | // remove CR before NL |
1634 | ptr[-1] = NUL; |
1635 | len--; |
1636 | } else if (ff_error != EOL_DOS) { |
1637 | // Reading in Dos format, but no CR-LF found! |
1638 | // When 'fileformats' includes "unix", delete all |
1639 | // the lines read so far and start all over again. |
1640 | // Otherwise give an error message later. |
1641 | if (try_unix |
1642 | && !read_stdin |
1643 | && (read_buffer |
1644 | || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { |
1645 | fileformat = EOL_UNIX; |
1646 | if (set_options) |
1647 | set_fileformat(EOL_UNIX, OPT_LOCAL); |
1648 | file_rewind = true; |
1649 | keep_fileformat = true; |
1650 | goto retry; |
1651 | } |
1652 | ff_error = EOL_DOS; |
1653 | } |
1654 | } |
1655 | if (ml_append(lnum, line_start, len, newfile) == FAIL) { |
1656 | error = TRUE; |
1657 | break; |
1658 | } |
1659 | if (read_undo_file) |
1660 | sha256_update(&sha_ctx, line_start, len); |
1661 | ++lnum; |
1662 | if (--read_count == 0) { |
1663 | error = TRUE; /* break loop */ |
1664 | line_start = ptr; /* nothing left to write */ |
1665 | break; |
1666 | } |
1667 | } else |
1668 | --skip_count; |
1669 | line_start = ptr + 1; |
1670 | } |
1671 | } |
1672 | } |
1673 | linerest = (long)(ptr - line_start); |
1674 | os_breakcheck(); |
1675 | } |
1676 | |
1677 | failed: |
1678 | /* not an error, max. number of lines reached */ |
1679 | if (error && read_count == 0) |
1680 | error = FALSE; |
1681 | |
1682 | /* |
1683 | * If we get EOF in the middle of a line, note the fact and |
1684 | * complete the line ourselves. |
1685 | * In Dos format ignore a trailing CTRL-Z, unless 'binary' set. |
1686 | */ |
1687 | if (!error |
1688 | && !got_int |
1689 | && linerest != 0 |
1690 | && !(!curbuf->b_p_bin |
1691 | && fileformat == EOL_DOS |
1692 | && *line_start == Ctrl_Z |
1693 | && ptr == line_start + 1)) { |
1694 | /* remember for when writing */ |
1695 | if (set_options) |
1696 | curbuf->b_p_eol = FALSE; |
1697 | *ptr = NUL; |
1698 | len = (colnr_T)(ptr - line_start + 1); |
1699 | if (ml_append(lnum, line_start, len, newfile) == FAIL) |
1700 | error = TRUE; |
1701 | else { |
1702 | if (read_undo_file) |
1703 | sha256_update(&sha_ctx, line_start, len); |
1704 | read_no_eol_lnum = ++lnum; |
1705 | } |
1706 | } |
1707 | |
1708 | if (set_options) { |
1709 | // Remember the current file format. |
1710 | save_file_ff(curbuf); |
1711 | // If editing a new file: set 'fenc' for the current buffer. |
1712 | // Also for ":read ++edit file". |
1713 | set_string_option_direct((char_u *)"fenc" , -1, fenc, |
1714 | OPT_FREE | OPT_LOCAL, 0); |
1715 | } |
1716 | if (fenc_alloced) |
1717 | xfree(fenc); |
1718 | # ifdef HAVE_ICONV |
1719 | if (iconv_fd != (iconv_t)-1) { |
1720 | iconv_close(iconv_fd); |
1721 | # ifndef __clang_analyzer__ |
1722 | iconv_fd = (iconv_t)-1; |
1723 | # endif |
1724 | } |
1725 | # endif |
1726 | |
1727 | if (!read_buffer && !read_stdin) { |
1728 | close(fd); // errors are ignored |
1729 | } else { |
1730 | (void)os_set_cloexec(fd); |
1731 | } |
1732 | xfree(buffer); |
1733 | |
1734 | if (read_stdin) { |
1735 | close(0); |
1736 | #ifndef WIN32 |
1737 | // On Unix, use stderr for stdin, makes shell commands work. |
1738 | vim_ignored = dup(2); |
1739 | #else |
1740 | // On Windows, use the console input handle for stdin. |
1741 | HANDLE conin = CreateFile("CONIN$" , GENERIC_READ | GENERIC_WRITE, |
1742 | FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, |
1743 | OPEN_EXISTING, 0, (HANDLE)NULL); |
1744 | vim_ignored = _open_osfhandle(conin, _O_RDONLY); |
1745 | #endif |
1746 | } |
1747 | |
1748 | if (tmpname != NULL) { |
1749 | os_remove((char *)tmpname); // delete converted file |
1750 | xfree(tmpname); |
1751 | } |
1752 | --no_wait_return; /* may wait for return now */ |
1753 | |
1754 | /* |
1755 | * In recovery mode everything but autocommands is skipped. |
1756 | */ |
1757 | if (!recoverymode) { |
1758 | /* need to delete the last line, which comes from the empty buffer */ |
1759 | if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { |
1760 | ml_delete(curbuf->b_ml.ml_line_count, false); |
1761 | linecnt--; |
1762 | } |
1763 | curbuf->deleted_bytes = 0; |
1764 | curbuf->deleted_codepoints = 0; |
1765 | curbuf->deleted_codeunits = 0; |
1766 | linecnt = curbuf->b_ml.ml_line_count - linecnt; |
1767 | if (filesize == 0) |
1768 | linecnt = 0; |
1769 | if (newfile || read_buffer) { |
1770 | redraw_curbuf_later(NOT_VALID); |
1771 | /* After reading the text into the buffer the diff info needs to |
1772 | * be updated. */ |
1773 | diff_invalidate(curbuf); |
1774 | /* All folds in the window are invalid now. Mark them for update |
1775 | * before triggering autocommands. */ |
1776 | foldUpdateAll(curwin); |
1777 | } else if (linecnt) /* appended at least one line */ |
1778 | appended_lines_mark(from, linecnt); |
1779 | |
1780 | /* |
1781 | * If we were reading from the same terminal as where messages go, |
1782 | * the screen will have been messed up. |
1783 | * Switch on raw mode now and clear the screen. |
1784 | */ |
1785 | if (read_stdin) { |
1786 | screenclear(); |
1787 | } |
1788 | |
1789 | if (got_int) { |
1790 | if (!(flags & READ_DUMMY)) { |
1791 | filemess(curbuf, sfname, (char_u *)_(e_interr), 0); |
1792 | if (newfile) |
1793 | curbuf->b_p_ro = TRUE; /* must use "w!" now */ |
1794 | } |
1795 | msg_scroll = msg_save; |
1796 | check_marks_read(); |
1797 | return OK; /* an interrupt isn't really an error */ |
1798 | } |
1799 | |
1800 | if (!filtering && !(flags & READ_DUMMY)) { |
1801 | add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname); |
1802 | c = false; |
1803 | |
1804 | #ifdef UNIX |
1805 | # ifdef S_ISFIFO |
1806 | if (S_ISFIFO(perm)) { /* fifo or socket */ |
1807 | STRCAT(IObuff, _("[fifo/socket]" )); |
1808 | c = TRUE; |
1809 | } |
1810 | # else |
1811 | # ifdef S_IFIFO |
1812 | if ((perm & S_IFMT) == S_IFIFO) { /* fifo */ |
1813 | STRCAT(IObuff, _("[fifo]" )); |
1814 | c = TRUE; |
1815 | } |
1816 | # endif |
1817 | # ifdef S_IFSOCK |
1818 | if ((perm & S_IFMT) == S_IFSOCK) { /* or socket */ |
1819 | STRCAT(IObuff, _("[socket]" )); |
1820 | c = TRUE; |
1821 | } |
1822 | # endif |
1823 | # endif |
1824 | # ifdef OPEN_CHR_FILES |
1825 | if (S_ISCHR(perm)) { /* or character special */ |
1826 | STRCAT(IObuff, _("[character special]" )); |
1827 | c = TRUE; |
1828 | } |
1829 | # endif |
1830 | #endif |
1831 | if (curbuf->b_p_ro) { |
1832 | STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]" ) : _("[readonly]" )); |
1833 | c = TRUE; |
1834 | } |
1835 | if (read_no_eol_lnum) { |
1836 | msg_add_eol(); |
1837 | c = TRUE; |
1838 | } |
1839 | if (ff_error == EOL_DOS) { |
1840 | STRCAT(IObuff, _("[CR missing]" )); |
1841 | c = TRUE; |
1842 | } |
1843 | if (notconverted) { |
1844 | STRCAT(IObuff, _("[NOT converted]" )); |
1845 | c = TRUE; |
1846 | } else if (converted) { |
1847 | STRCAT(IObuff, _("[converted]" )); |
1848 | c = TRUE; |
1849 | } |
1850 | if (conv_error != 0) { |
1851 | sprintf((char *)IObuff + STRLEN(IObuff), |
1852 | _("[CONVERSION ERROR in line %" PRId64 "]" ), (int64_t)conv_error); |
1853 | c = TRUE; |
1854 | } else if (illegal_byte > 0) { |
1855 | sprintf((char *)IObuff + STRLEN(IObuff), |
1856 | _("[ILLEGAL BYTE in line %" PRId64 "]" ), (int64_t)illegal_byte); |
1857 | c = TRUE; |
1858 | } else if (error) { |
1859 | STRCAT(IObuff, _("[READ ERRORS]" )); |
1860 | c = TRUE; |
1861 | } |
1862 | if (msg_add_fileformat(fileformat)) |
1863 | c = TRUE; |
1864 | |
1865 | msg_add_lines(c, (long)linecnt, filesize); |
1866 | |
1867 | XFREE_CLEAR(keep_msg); |
1868 | p = NULL; |
1869 | msg_scrolled_ign = TRUE; |
1870 | |
1871 | if (!read_stdin && !read_buffer) { |
1872 | p = msg_trunc_attr(IObuff, FALSE, 0); |
1873 | } |
1874 | |
1875 | if (read_stdin || read_buffer || restart_edit != 0 |
1876 | || (msg_scrolled != 0 && !need_wait_return)) { |
1877 | // Need to repeat the message after redrawing when: |
1878 | // - When reading from stdin (the screen will be cleared next). |
1879 | // - When restart_edit is set (otherwise there will be a delay before |
1880 | // redrawing). |
1881 | // - When the screen was scrolled but there is no wait-return prompt. |
1882 | set_keep_msg(p, 0); |
1883 | } |
1884 | msg_scrolled_ign = FALSE; |
1885 | } |
1886 | |
1887 | /* with errors writing the file requires ":w!" */ |
1888 | if (newfile && (error |
1889 | || conv_error != 0 |
1890 | || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP) |
1891 | )) |
1892 | curbuf->b_p_ro = TRUE; |
1893 | |
1894 | u_clearline(); /* cannot use "U" command after adding lines */ |
1895 | |
1896 | /* |
1897 | * In Ex mode: cursor at last new line. |
1898 | * Otherwise: cursor at first new line. |
1899 | */ |
1900 | if (exmode_active) |
1901 | curwin->w_cursor.lnum = from + linecnt; |
1902 | else |
1903 | curwin->w_cursor.lnum = from + 1; |
1904 | check_cursor_lnum(); |
1905 | beginline(BL_WHITE | BL_FIX); /* on first non-blank */ |
1906 | |
1907 | /* |
1908 | * Set '[ and '] marks to the newly read lines. |
1909 | */ |
1910 | curbuf->b_op_start.lnum = from + 1; |
1911 | curbuf->b_op_start.col = 0; |
1912 | curbuf->b_op_end.lnum = from + linecnt; |
1913 | curbuf->b_op_end.col = 0; |
1914 | |
1915 | } |
1916 | msg_scroll = msg_save; |
1917 | |
1918 | /* |
1919 | * Get the marks before executing autocommands, so they can be used there. |
1920 | */ |
1921 | check_marks_read(); |
1922 | |
1923 | /* |
1924 | * We remember if the last line of the read didn't have |
1925 | * an eol even when 'binary' is off, to support turning 'fixeol' off, |
1926 | * or writing the read again with 'binary' on. The latter is required |
1927 | * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. |
1928 | */ |
1929 | curbuf->b_no_eol_lnum = read_no_eol_lnum; |
1930 | |
1931 | /* When reloading a buffer put the cursor at the first line that is |
1932 | * different. */ |
1933 | if (flags & READ_KEEP_UNDO) |
1934 | u_find_first_changed(); |
1935 | |
1936 | /* |
1937 | * When opening a new file locate undo info and read it. |
1938 | */ |
1939 | if (read_undo_file) { |
1940 | char_u hash[UNDO_HASH_SIZE]; |
1941 | |
1942 | sha256_finish(&sha_ctx, hash); |
1943 | u_read_undo(NULL, hash, fname); |
1944 | } |
1945 | |
1946 | if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) { |
1947 | int m = msg_scroll; |
1948 | int n = msg_scrolled; |
1949 | |
1950 | /* Save the fileformat now, otherwise the buffer will be considered |
1951 | * modified if the format/encoding was automatically detected. */ |
1952 | if (set_options) |
1953 | save_file_ff(curbuf); |
1954 | |
1955 | /* |
1956 | * The output from the autocommands should not overwrite anything and |
1957 | * should not be overwritten: Set msg_scroll, restore its value if no |
1958 | * output was done. |
1959 | */ |
1960 | msg_scroll = true; |
1961 | if (filtering) { |
1962 | apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname, |
1963 | false, curbuf, eap); |
1964 | } else if (newfile || (read_buffer && sfname != NULL)) { |
1965 | apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname, |
1966 | false, curbuf, eap); |
1967 | if (!au_did_filetype && *curbuf->b_p_ft != NUL) { |
1968 | // EVENT_FILETYPE was not triggered but the buffer already has a |
1969 | // filetype. Trigger EVENT_FILETYPE using the existing filetype. |
1970 | apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, |
1971 | true, curbuf); |
1972 | } |
1973 | } else { |
1974 | apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname, |
1975 | false, NULL, eap); |
1976 | } |
1977 | if (msg_scrolled == n) { |
1978 | msg_scroll = m; |
1979 | } |
1980 | if (aborting()) { // autocmds may abort script processing |
1981 | return FAIL; |
1982 | } |
1983 | } |
1984 | |
1985 | if (recoverymode && error) |
1986 | return FAIL; |
1987 | return OK; |
1988 | } |
1989 | |
1990 | #ifdef OPEN_CHR_FILES |
1991 | /// Returns true if the file name argument is of the form "/dev/fd/\d\+", |
1992 | /// which is the name of files used for process substitution output by |
1993 | /// some shells on some operating systems, e.g., bash on SunOS. |
1994 | /// Do not accept "/dev/fd/[012]", opening these may hang Vim. |
1995 | /// |
1996 | /// @param fname file name to check |
1997 | bool is_dev_fd_file(char_u *fname) |
1998 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT |
1999 | { |
2000 | return STRNCMP(fname, "/dev/fd/" , 8) == 0 |
2001 | && ascii_isdigit(fname[8]) |
2002 | && *skipdigits(fname + 9) == NUL |
2003 | && (fname[9] != NUL |
2004 | || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')); |
2005 | } |
2006 | #endif |
2007 | |
2008 | |
2009 | /* |
2010 | * From the current line count and characters read after that, estimate the |
2011 | * line number where we are now. |
2012 | * Used for error messages that include a line number. |
2013 | */ |
2014 | static linenr_T |
2015 | readfile_linenr( |
2016 | linenr_T linecnt, // line count before reading more bytes |
2017 | char_u *p, // start of more bytes read |
2018 | char_u *endp // end of more bytes read |
2019 | ) |
2020 | { |
2021 | char_u *s; |
2022 | linenr_T lnum; |
2023 | |
2024 | lnum = curbuf->b_ml.ml_line_count - linecnt + 1; |
2025 | for (s = p; s < endp; ++s) |
2026 | if (*s == '\n') |
2027 | ++lnum; |
2028 | return lnum; |
2029 | } |
2030 | |
2031 | /* |
2032 | * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be |
2033 | * equal to the buffer "buf". Used for calling readfile(). |
2034 | */ |
2035 | void prep_exarg(exarg_T *eap, buf_T *buf) |
2036 | { |
2037 | eap->cmd = xmalloc(STRLEN(buf->b_p_ff) + STRLEN(buf->b_p_fenc) + 15); |
2038 | |
2039 | sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s" , buf->b_p_ff, buf->b_p_fenc); |
2040 | eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff); |
2041 | eap->bad_char = buf->b_bad_char; |
2042 | eap->force_ff = 7; |
2043 | |
2044 | eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN; |
2045 | eap->read_edit = FALSE; |
2046 | eap->forceit = FALSE; |
2047 | } |
2048 | |
2049 | /* |
2050 | * Set default or forced 'fileformat' and 'binary'. |
2051 | */ |
2052 | void set_file_options(int set_options, exarg_T *eap) |
2053 | { |
2054 | /* set default 'fileformat' */ |
2055 | if (set_options) { |
2056 | if (eap != NULL && eap->force_ff != 0) |
2057 | set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL); |
2058 | else if (*p_ffs != NUL) |
2059 | set_fileformat(default_fileformat(), OPT_LOCAL); |
2060 | } |
2061 | |
2062 | /* set or reset 'binary' */ |
2063 | if (eap != NULL && eap->force_bin != 0) { |
2064 | int oldval = curbuf->b_p_bin; |
2065 | |
2066 | curbuf->b_p_bin = (eap->force_bin == FORCE_BIN); |
2067 | set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL); |
2068 | } |
2069 | } |
2070 | |
2071 | /* |
2072 | * Set forced 'fileencoding'. |
2073 | */ |
2074 | void set_forced_fenc(exarg_T *eap) |
2075 | { |
2076 | if (eap->force_enc != 0) { |
2077 | char_u *fenc = enc_canonize(eap->cmd + eap->force_enc); |
2078 | set_string_option_direct((char_u *)"fenc" , -1, fenc, OPT_FREE|OPT_LOCAL, 0); |
2079 | xfree(fenc); |
2080 | } |
2081 | } |
2082 | |
2083 | // Find next fileencoding to use from 'fileencodings'. |
2084 | // "pp" points to fenc_next. It's advanced to the next item. |
2085 | // When there are no more items, an empty string is returned and *pp is set to |
2086 | // NULL. |
2087 | // When *pp is not set to NULL, the result is in allocated memory and "alloced" |
2088 | // is set to true. |
2089 | static char_u *next_fenc(char_u **pp, bool *alloced) |
2090 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET |
2091 | { |
2092 | char_u *p; |
2093 | char_u *r; |
2094 | |
2095 | *alloced = false; |
2096 | if (**pp == NUL) { |
2097 | *pp = NULL; |
2098 | return (char_u *)"" ; |
2099 | } |
2100 | p = vim_strchr(*pp, ','); |
2101 | if (p == NULL) { |
2102 | r = enc_canonize(*pp); |
2103 | *pp += STRLEN(*pp); |
2104 | } else { |
2105 | r = vim_strnsave(*pp, (int)(p - *pp)); |
2106 | *pp = p + 1; |
2107 | p = enc_canonize(r); |
2108 | xfree(r); |
2109 | r = p; |
2110 | } |
2111 | *alloced = true; |
2112 | return r; |
2113 | } |
2114 | |
2115 | /* |
2116 | * Convert a file with the 'charconvert' expression. |
2117 | * This closes the file which is to be read, converts it and opens the |
2118 | * resulting file for reading. |
2119 | * Returns name of the resulting converted file (the caller should delete it |
2120 | * after reading it). |
2121 | * Returns NULL if the conversion failed ("*fdp" is not set) . |
2122 | */ |
2123 | static char_u * |
2124 | readfile_charconvert ( |
2125 | char_u *fname, /* name of input file */ |
2126 | char_u *fenc, /* converted from */ |
2127 | int *fdp /* in/out: file descriptor of file */ |
2128 | ) |
2129 | { |
2130 | char_u *tmpname; |
2131 | char_u *errmsg = NULL; |
2132 | |
2133 | tmpname = vim_tempname(); |
2134 | if (tmpname == NULL) |
2135 | errmsg = (char_u *)_("Can't find temp file for conversion" ); |
2136 | else { |
2137 | close(*fdp); /* close the input file, ignore errors */ |
2138 | *fdp = -1; |
2139 | if (eval_charconvert((char *) fenc, enc_utf8 ? "utf-8" : (char *) p_enc, |
2140 | (char *) fname, (char *) tmpname) == FAIL) { |
2141 | errmsg = (char_u *)_("Conversion with 'charconvert' failed" ); |
2142 | } |
2143 | if (errmsg == NULL && (*fdp = os_open((char *)tmpname, O_RDONLY, 0)) < 0) { |
2144 | errmsg = (char_u *)_("can't read output of 'charconvert'" ); |
2145 | } |
2146 | } |
2147 | |
2148 | if (errmsg != NULL) { |
2149 | /* Don't use emsg(), it breaks mappings, the retry with |
2150 | * another type of conversion might still work. */ |
2151 | MSG(errmsg); |
2152 | if (tmpname != NULL) { |
2153 | os_remove((char *)tmpname); // delete converted file |
2154 | XFREE_CLEAR(tmpname); |
2155 | } |
2156 | } |
2157 | |
2158 | /* If the input file is closed, open it (caller should check for error). */ |
2159 | if (*fdp < 0) { |
2160 | *fdp = os_open((char *)fname, O_RDONLY, 0); |
2161 | } |
2162 | |
2163 | return tmpname; |
2164 | } |
2165 | |
2166 | |
2167 | /* |
2168 | * Read marks for the current buffer from the ShaDa file, when we support |
2169 | * buffer marks and the buffer has a name. |
2170 | */ |
2171 | static void check_marks_read(void) |
2172 | { |
2173 | if (!curbuf->b_marks_read && get_shada_parameter('\'') > 0 |
2174 | && curbuf->b_ffname != NULL) { |
2175 | shada_read_marks(); |
2176 | } |
2177 | |
2178 | /* Always set b_marks_read; needed when 'shada' is changed to include |
2179 | * the ' parameter after opening a buffer. */ |
2180 | curbuf->b_marks_read = true; |
2181 | } |
2182 | |
2183 | /* |
2184 | * buf_write() - write to file "fname" lines "start" through "end" |
2185 | * |
2186 | * We do our own buffering here because fwrite() is so slow. |
2187 | * |
2188 | * If "forceit" is true, we don't care for errors when attempting backups. |
2189 | * In case of an error everything possible is done to restore the original |
2190 | * file. But when "forceit" is TRUE, we risk losing it. |
2191 | * |
2192 | * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and |
2193 | * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. |
2194 | * |
2195 | * This function must NOT use NameBuff (because it's called by autowrite()). |
2196 | * |
2197 | * return FAIL for failure, OK otherwise |
2198 | */ |
2199 | int |
2200 | buf_write( |
2201 | buf_T *buf, |
2202 | char_u *fname, |
2203 | char_u *sfname, |
2204 | linenr_T start, |
2205 | linenr_T end, |
2206 | exarg_T *eap, /* for forced 'ff' and 'fenc', can be |
2207 | NULL! */ |
2208 | int append, /* append to the file */ |
2209 | int forceit, |
2210 | int reset_changed, |
2211 | int filtering |
2212 | ) |
2213 | { |
2214 | int fd; |
2215 | char_u *backup = NULL; |
2216 | int backup_copy = FALSE; /* copy the original file? */ |
2217 | int dobackup; |
2218 | char_u *ffname; |
2219 | char_u *wfname = NULL; /* name of file to write to */ |
2220 | char_u *s; |
2221 | char_u *ptr; |
2222 | char_u c; |
2223 | int len; |
2224 | linenr_T lnum; |
2225 | long nchars; |
2226 | #define SET_ERRMSG_NUM(num, msg) \ |
2227 | errnum = num, errmsg = msg, errmsgarg = 0 |
2228 | #define SET_ERRMSG_ARG(msg, error) \ |
2229 | errnum = NULL, errmsg = msg, errmsgarg = error |
2230 | #define SET_ERRMSG(msg) \ |
2231 | errnum = NULL, errmsg = msg, errmsgarg = 0 |
2232 | const char *errnum = NULL; |
2233 | char *errmsg = NULL; |
2234 | int errmsgarg = 0; |
2235 | bool errmsg_allocated = false; |
2236 | char_u *buffer; |
2237 | char_u smallbuf[SMBUFSIZE]; |
2238 | char_u *backup_ext; |
2239 | int bufsize; |
2240 | long perm; // file permissions |
2241 | int retval = OK; |
2242 | int newfile = false; // TRUE if file doesn't exist yet |
2243 | int msg_save = msg_scroll; |
2244 | int overwriting; // TRUE if writing over original |
2245 | int no_eol = false; // no end-of-line written |
2246 | int device = false; // writing to a device |
2247 | int prev_got_int = got_int; |
2248 | int checking_conversion; |
2249 | bool file_readonly = false; // overwritten file is read-only |
2250 | static char *err_readonly = |
2251 | "is read-only (cannot override: \"W\" in 'cpoptions')" ; |
2252 | #if defined(UNIX) |
2253 | int made_writable = FALSE; /* 'w' bit has been set */ |
2254 | #endif |
2255 | /* writing everything */ |
2256 | int whole = (start == 1 && end == buf->b_ml.ml_line_count); |
2257 | linenr_T old_line_count = buf->b_ml.ml_line_count; |
2258 | int fileformat; |
2259 | int write_bin; |
2260 | struct bw_info write_info; /* info for buf_write_bytes() */ |
2261 | int converted = FALSE; |
2262 | int notconverted = FALSE; |
2263 | char_u *fenc; /* effective 'fileencoding' */ |
2264 | char_u *fenc_tofree = NULL; /* allocated "fenc" */ |
2265 | #ifdef HAS_BW_FLAGS |
2266 | int wb_flags = 0; |
2267 | #endif |
2268 | #ifdef HAVE_ACL |
2269 | vim_acl_T acl = NULL; /* ACL copied from original file to |
2270 | backup or new file */ |
2271 | #endif |
2272 | int write_undo_file = FALSE; |
2273 | context_sha256_T sha_ctx; |
2274 | unsigned int bkc = get_bkc_value(buf); |
2275 | |
2276 | if (fname == NULL || *fname == NUL) /* safety check */ |
2277 | return FAIL; |
2278 | if (buf->b_ml.ml_mfp == NULL) { |
2279 | /* This can happen during startup when there is a stray "w" in the |
2280 | * vimrc file. */ |
2281 | EMSG(_(e_emptybuf)); |
2282 | return FAIL; |
2283 | } |
2284 | |
2285 | /* |
2286 | * Disallow writing from .exrc and .vimrc in current directory for |
2287 | * security reasons. |
2288 | */ |
2289 | if (check_secure()) |
2290 | return FAIL; |
2291 | |
2292 | /* Avoid a crash for a long name. */ |
2293 | if (STRLEN(fname) >= MAXPATHL) { |
2294 | EMSG(_(e_longname)); |
2295 | return FAIL; |
2296 | } |
2297 | |
2298 | /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */ |
2299 | write_info.bw_conv_buf = NULL; |
2300 | write_info.bw_conv_error = FALSE; |
2301 | write_info.bw_conv_error_lnum = 0; |
2302 | write_info.bw_restlen = 0; |
2303 | # ifdef HAVE_ICONV |
2304 | write_info.bw_iconv_fd = (iconv_t)-1; |
2305 | # endif |
2306 | |
2307 | /* After writing a file changedtick changes but we don't want to display |
2308 | * the line. */ |
2309 | ex_no_reprint = TRUE; |
2310 | |
2311 | /* |
2312 | * If there is no file name yet, use the one for the written file. |
2313 | * BF_NOTEDITED is set to reflect this (in case the write fails). |
2314 | * Don't do this when the write is for a filter command. |
2315 | * Don't do this when appending. |
2316 | * Only do this when 'cpoptions' contains the 'F' flag. |
2317 | */ |
2318 | if (buf->b_ffname == NULL |
2319 | && reset_changed |
2320 | && whole |
2321 | && buf == curbuf |
2322 | && !bt_nofile(buf) |
2323 | && !filtering |
2324 | && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) |
2325 | && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { |
2326 | if (set_rw_fname(fname, sfname) == FAIL) |
2327 | return FAIL; |
2328 | buf = curbuf; /* just in case autocmds made "buf" invalid */ |
2329 | } |
2330 | |
2331 | if (sfname == NULL) |
2332 | sfname = fname; |
2333 | |
2334 | // For Unix: Use the short file name whenever possible. |
2335 | // Avoids problems with networks and when directory names are changed. |
2336 | // Don't do this for Windows, a "cd" in a sub-shell may have moved us to |
2337 | // another directory, which we don't detect. |
2338 | ffname = fname; // remember full fname |
2339 | #ifdef UNIX |
2340 | fname = sfname; |
2341 | #endif |
2342 | |
2343 | if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0) |
2344 | overwriting = TRUE; |
2345 | else |
2346 | overwriting = FALSE; |
2347 | |
2348 | ++no_wait_return; /* don't wait for return yet */ |
2349 | |
2350 | /* |
2351 | * Set '[ and '] marks to the lines to be written. |
2352 | */ |
2353 | buf->b_op_start.lnum = start; |
2354 | buf->b_op_start.col = 0; |
2355 | buf->b_op_end.lnum = end; |
2356 | buf->b_op_end.col = 0; |
2357 | |
2358 | { |
2359 | aco_save_T aco; |
2360 | int buf_ffname = FALSE; |
2361 | int buf_sfname = FALSE; |
2362 | int buf_fname_f = FALSE; |
2363 | int buf_fname_s = FALSE; |
2364 | int did_cmd = FALSE; |
2365 | int nofile_err = FALSE; |
2366 | int empty_memline = (buf->b_ml.ml_mfp == NULL); |
2367 | bufref_T bufref; |
2368 | |
2369 | /* |
2370 | * Apply PRE autocommands. |
2371 | * Set curbuf to the buffer to be written. |
2372 | * Careful: The autocommands may call buf_write() recursively! |
2373 | */ |
2374 | if (ffname == buf->b_ffname) |
2375 | buf_ffname = TRUE; |
2376 | if (sfname == buf->b_sfname) |
2377 | buf_sfname = TRUE; |
2378 | if (fname == buf->b_ffname) |
2379 | buf_fname_f = TRUE; |
2380 | if (fname == buf->b_sfname) |
2381 | buf_fname_s = TRUE; |
2382 | |
2383 | // Set curwin/curbuf to buf and save a few things. |
2384 | aucmd_prepbuf(&aco, buf); |
2385 | set_bufref(&bufref, buf); |
2386 | |
2387 | if (append) { |
2388 | if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, |
2389 | sfname, sfname, FALSE, curbuf, eap))) { |
2390 | if (overwriting && bt_nofile(curbuf)) |
2391 | nofile_err = TRUE; |
2392 | else |
2393 | apply_autocmds_exarg(EVENT_FILEAPPENDPRE, |
2394 | sfname, sfname, FALSE, curbuf, eap); |
2395 | } |
2396 | } else if (filtering) { |
2397 | apply_autocmds_exarg(EVENT_FILTERWRITEPRE, |
2398 | NULL, sfname, FALSE, curbuf, eap); |
2399 | } else if (reset_changed && whole) { |
2400 | int was_changed = curbufIsChanged(); |
2401 | |
2402 | did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, |
2403 | sfname, sfname, FALSE, curbuf, eap); |
2404 | if (did_cmd) { |
2405 | if (was_changed && !curbufIsChanged()) { |
2406 | /* Written everything correctly and BufWriteCmd has reset |
2407 | * 'modified': Correct the undo information so that an |
2408 | * undo now sets 'modified'. */ |
2409 | u_unchanged(curbuf); |
2410 | u_update_save_nr(curbuf); |
2411 | } |
2412 | } else { |
2413 | if (overwriting && bt_nofile(curbuf)) |
2414 | nofile_err = TRUE; |
2415 | else |
2416 | apply_autocmds_exarg(EVENT_BUFWRITEPRE, |
2417 | sfname, sfname, FALSE, curbuf, eap); |
2418 | } |
2419 | } else { |
2420 | if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, |
2421 | sfname, sfname, FALSE, curbuf, eap))) { |
2422 | if (overwriting && bt_nofile(curbuf)) |
2423 | nofile_err = TRUE; |
2424 | else |
2425 | apply_autocmds_exarg(EVENT_FILEWRITEPRE, |
2426 | sfname, sfname, FALSE, curbuf, eap); |
2427 | } |
2428 | } |
2429 | |
2430 | /* restore curwin/curbuf and a few other things */ |
2431 | aucmd_restbuf(&aco); |
2432 | |
2433 | // In three situations we return here and don't write the file: |
2434 | // 1. the autocommands deleted or unloaded the buffer. |
2435 | // 2. The autocommands abort script processing. |
2436 | // 3. If one of the "Cmd" autocommands was executed. |
2437 | if (!bufref_valid(&bufref)) { |
2438 | buf = NULL; |
2439 | } |
2440 | if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) |
2441 | || did_cmd || nofile_err |
2442 | || aborting() |
2443 | ) { |
2444 | --no_wait_return; |
2445 | msg_scroll = msg_save; |
2446 | if (nofile_err) |
2447 | EMSG(_("E676: No matching autocommands for acwrite buffer" )); |
2448 | |
2449 | if (nofile_err |
2450 | || aborting() |
2451 | ) |
2452 | /* An aborting error, interrupt or exception in the |
2453 | * autocommands. */ |
2454 | return FAIL; |
2455 | if (did_cmd) { |
2456 | if (buf == NULL) |
2457 | /* The buffer was deleted. We assume it was written |
2458 | * (can't retry anyway). */ |
2459 | return OK; |
2460 | if (overwriting) { |
2461 | /* Assume the buffer was written, update the timestamp. */ |
2462 | ml_timestamp(buf); |
2463 | if (append) |
2464 | buf->b_flags &= ~BF_NEW; |
2465 | else |
2466 | buf->b_flags &= ~BF_WRITE_MASK; |
2467 | } |
2468 | if (reset_changed && buf->b_changed && !append |
2469 | && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) |
2470 | /* Buffer still changed, the autocommands didn't work |
2471 | * properly. */ |
2472 | return FAIL; |
2473 | return OK; |
2474 | } |
2475 | if (!aborting()) |
2476 | EMSG(_("E203: Autocommands deleted or unloaded buffer to be written" )); |
2477 | return FAIL; |
2478 | } |
2479 | |
2480 | /* |
2481 | * The autocommands may have changed the number of lines in the file. |
2482 | * When writing the whole file, adjust the end. |
2483 | * When writing part of the file, assume that the autocommands only |
2484 | * changed the number of lines that are to be written (tricky!). |
2485 | */ |
2486 | if (buf->b_ml.ml_line_count != old_line_count) { |
2487 | if (whole) /* write all */ |
2488 | end = buf->b_ml.ml_line_count; |
2489 | else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */ |
2490 | end += buf->b_ml.ml_line_count - old_line_count; |
2491 | else { /* less lines */ |
2492 | end -= old_line_count - buf->b_ml.ml_line_count; |
2493 | if (end < start) { |
2494 | --no_wait_return; |
2495 | msg_scroll = msg_save; |
2496 | EMSG(_("E204: Autocommand changed number of lines in unexpected way" )); |
2497 | return FAIL; |
2498 | } |
2499 | } |
2500 | } |
2501 | |
2502 | /* |
2503 | * The autocommands may have changed the name of the buffer, which may |
2504 | * be kept in fname, ffname and sfname. |
2505 | */ |
2506 | if (buf_ffname) |
2507 | ffname = buf->b_ffname; |
2508 | if (buf_sfname) |
2509 | sfname = buf->b_sfname; |
2510 | if (buf_fname_f) |
2511 | fname = buf->b_ffname; |
2512 | if (buf_fname_s) |
2513 | fname = buf->b_sfname; |
2514 | } |
2515 | |
2516 | |
2517 | if (shortmess(SHM_OVER) && !exiting) |
2518 | msg_scroll = FALSE; /* overwrite previous file message */ |
2519 | else |
2520 | msg_scroll = TRUE; /* don't overwrite previous file message */ |
2521 | if (!filtering) |
2522 | filemess(buf, |
2523 | #ifndef UNIX |
2524 | sfname, |
2525 | #else |
2526 | fname, |
2527 | #endif |
2528 | (char_u *)"" , 0); /* show that we are busy */ |
2529 | msg_scroll = FALSE; /* always overwrite the file message now */ |
2530 | |
2531 | buffer = verbose_try_malloc(BUFSIZE); |
2532 | // can't allocate big buffer, use small one (to be able to write when out of |
2533 | // memory) |
2534 | if (buffer == NULL) { |
2535 | buffer = smallbuf; |
2536 | bufsize = SMBUFSIZE; |
2537 | } else |
2538 | bufsize = BUFSIZE; |
2539 | |
2540 | /* |
2541 | * Get information about original file (if there is one). |
2542 | */ |
2543 | FileInfo file_info_old; |
2544 | #if defined(UNIX) |
2545 | perm = -1; |
2546 | if (!os_fileinfo((char *)fname, &file_info_old)) { |
2547 | newfile = TRUE; |
2548 | } else { |
2549 | perm = file_info_old.stat.st_mode; |
2550 | if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */ |
2551 | if (S_ISDIR(file_info_old.stat.st_mode)) { |
2552 | SET_ERRMSG_NUM("E502" , _("is a directory" )); |
2553 | goto fail; |
2554 | } |
2555 | if (os_nodetype((char *)fname) != NODE_WRITABLE) { |
2556 | SET_ERRMSG_NUM("E503" , _("is not a file or writable device" )); |
2557 | goto fail; |
2558 | } |
2559 | /* It's a device of some kind (or a fifo) which we can write to |
2560 | * but for which we can't make a backup. */ |
2561 | device = TRUE; |
2562 | newfile = TRUE; |
2563 | perm = -1; |
2564 | } |
2565 | } |
2566 | #else // win32 |
2567 | // Check for a writable device name. |
2568 | c = fname == NULL ? NODE_OTHER : os_nodetype((char *)fname); |
2569 | if (c == NODE_OTHER) { |
2570 | SET_ERRMSG_NUM("E503" , _("is not a file or writable device" )); |
2571 | goto fail; |
2572 | } |
2573 | if (c == NODE_WRITABLE) { |
2574 | device = TRUE; |
2575 | newfile = TRUE; |
2576 | perm = -1; |
2577 | } else { |
2578 | perm = os_getperm((const char *)fname); |
2579 | if (perm < 0) { |
2580 | newfile = true; |
2581 | } else if (os_isdir(fname)) { |
2582 | SET_ERRMSG_NUM("E502" , _("is a directory" )); |
2583 | goto fail; |
2584 | } |
2585 | if (overwriting) { |
2586 | os_fileinfo((char *)fname, &file_info_old); |
2587 | } |
2588 | } |
2589 | #endif // !UNIX |
2590 | |
2591 | if (!device && !newfile) { |
2592 | /* |
2593 | * Check if the file is really writable (when renaming the file to |
2594 | * make a backup we won't discover it later). |
2595 | */ |
2596 | file_readonly = !os_file_is_writable((char *)fname); |
2597 | |
2598 | if (!forceit && file_readonly) { |
2599 | if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { |
2600 | SET_ERRMSG_NUM("E504" , _(err_readonly)); |
2601 | } else { |
2602 | SET_ERRMSG_NUM("E505" , _("is read-only (add ! to override)" )); |
2603 | } |
2604 | goto fail; |
2605 | } |
2606 | |
2607 | /* |
2608 | * Check if the timestamp hasn't changed since reading the file. |
2609 | */ |
2610 | if (overwriting) { |
2611 | retval = check_mtime(buf, &file_info_old); |
2612 | if (retval == FAIL) |
2613 | goto fail; |
2614 | } |
2615 | } |
2616 | |
2617 | #ifdef HAVE_ACL |
2618 | /* |
2619 | * For systems that support ACL: get the ACL from the original file. |
2620 | */ |
2621 | if (!newfile) |
2622 | acl = mch_get_acl(fname); |
2623 | #endif |
2624 | |
2625 | /* |
2626 | * If 'backupskip' is not empty, don't make a backup for some files. |
2627 | */ |
2628 | dobackup = (p_wb || p_bk || *p_pm != NUL); |
2629 | if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) |
2630 | dobackup = FALSE; |
2631 | |
2632 | /* |
2633 | * Save the value of got_int and reset it. We don't want a previous |
2634 | * interruption cancel writing, only hitting CTRL-C while writing should |
2635 | * abort it. |
2636 | */ |
2637 | prev_got_int = got_int; |
2638 | got_int = FALSE; |
2639 | |
2640 | /* Mark the buffer as 'being saved' to prevent changed buffer warnings */ |
2641 | buf->b_saving = true; |
2642 | |
2643 | /* |
2644 | * If we are not appending or filtering, the file exists, and the |
2645 | * 'writebackup', 'backup' or 'patchmode' option is set, need a backup. |
2646 | * When 'patchmode' is set also make a backup when appending. |
2647 | * |
2648 | * Do not make any backup, if 'writebackup' and 'backup' are both switched |
2649 | * off. This helps when editing large files on almost-full disks. |
2650 | */ |
2651 | if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { |
2652 | FileInfo file_info; |
2653 | |
2654 | if ((bkc & BKC_YES) || append) { /* "yes" */ |
2655 | backup_copy = TRUE; |
2656 | } else if ((bkc & BKC_AUTO)) { /* "auto" */ |
2657 | int i; |
2658 | |
2659 | /* |
2660 | * Don't rename the file when: |
2661 | * - it's a hard link |
2662 | * - it's a symbolic link |
2663 | * - we don't have write permission in the directory |
2664 | */ |
2665 | if (os_fileinfo_hardlinks(&file_info_old) > 1 |
2666 | || !os_fileinfo_link((char *)fname, &file_info) |
2667 | || !os_fileinfo_id_equal(&file_info, &file_info_old)) { |
2668 | backup_copy = TRUE; |
2669 | } else { |
2670 | /* |
2671 | * Check if we can create a file and set the owner/group to |
2672 | * the ones from the original file. |
2673 | * First find a file name that doesn't exist yet (use some |
2674 | * arbitrary numbers). |
2675 | */ |
2676 | STRCPY(IObuff, fname); |
2677 | for (i = 4913;; i += 123) { |
2678 | sprintf((char *)path_tail(IObuff), "%d" , i); |
2679 | if (!os_fileinfo_link((char *)IObuff, &file_info)) { |
2680 | break; |
2681 | } |
2682 | } |
2683 | fd = os_open((char *)IObuff, |
2684 | O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); |
2685 | if (fd < 0) /* can't write in directory */ |
2686 | backup_copy = TRUE; |
2687 | else { |
2688 | # ifdef UNIX |
2689 | os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); |
2690 | if (!os_fileinfo((char *)IObuff, &file_info) |
2691 | || file_info.stat.st_uid != file_info_old.stat.st_uid |
2692 | || file_info.stat.st_gid != file_info_old.stat.st_gid |
2693 | || (long)file_info.stat.st_mode != perm) { |
2694 | backup_copy = TRUE; |
2695 | } |
2696 | # endif |
2697 | /* Close the file before removing it, on MS-Windows we |
2698 | * can't delete an open file. */ |
2699 | close(fd); |
2700 | os_remove((char *)IObuff); |
2701 | } |
2702 | } |
2703 | } |
2704 | |
2705 | /* |
2706 | * Break symlinks and/or hardlinks if we've been asked to. |
2707 | */ |
2708 | if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) { |
2709 | # ifdef UNIX |
2710 | bool file_info_link_ok = os_fileinfo_link((char *)fname, &file_info); |
2711 | |
2712 | /* Symlinks. */ |
2713 | if ((bkc & BKC_BREAKSYMLINK) |
2714 | && file_info_link_ok |
2715 | && !os_fileinfo_id_equal(&file_info, &file_info_old)) { |
2716 | backup_copy = FALSE; |
2717 | } |
2718 | |
2719 | /* Hardlinks. */ |
2720 | if ((bkc & BKC_BREAKHARDLINK) |
2721 | && os_fileinfo_hardlinks(&file_info_old) > 1 |
2722 | && (!file_info_link_ok |
2723 | || os_fileinfo_id_equal(&file_info, &file_info_old))) { |
2724 | backup_copy = FALSE; |
2725 | } |
2726 | # endif |
2727 | } |
2728 | |
2729 | /* make sure we have a valid backup extension to use */ |
2730 | if (*p_bex == NUL) |
2731 | backup_ext = (char_u *)".bak" ; |
2732 | else |
2733 | backup_ext = p_bex; |
2734 | |
2735 | if (backup_copy) { |
2736 | char_u *wp; |
2737 | int some_error = false; |
2738 | char_u *dirp; |
2739 | char_u *rootname; |
2740 | |
2741 | /* |
2742 | * Try to make the backup in each directory in the 'bdir' option. |
2743 | * |
2744 | * Unix semantics has it, that we may have a writable file, |
2745 | * that cannot be recreated with a simple open(..., O_CREAT, ) e.g: |
2746 | * - the directory is not writable, |
2747 | * - the file may be a symbolic link, |
2748 | * - the file may belong to another user/group, etc. |
2749 | * |
2750 | * For these reasons, the existing writable file must be truncated |
2751 | * and reused. Creation of a backup COPY will be attempted. |
2752 | */ |
2753 | dirp = p_bdir; |
2754 | while (*dirp) { |
2755 | /* |
2756 | * Isolate one directory name, using an entry in 'bdir'. |
2757 | */ |
2758 | (void)copy_option_part(&dirp, IObuff, IOSIZE, "," ); |
2759 | rootname = get_file_in_dir(fname, IObuff); |
2760 | if (rootname == NULL) { |
2761 | some_error = TRUE; /* out of memory */ |
2762 | goto nobackup; |
2763 | } |
2764 | |
2765 | FileInfo file_info_new; |
2766 | { |
2767 | /* |
2768 | * Make backup file name. |
2769 | */ |
2770 | backup = (char_u *)modname((char *)rootname, (char *)backup_ext, FALSE); |
2771 | if (backup == NULL) { |
2772 | xfree(rootname); |
2773 | some_error = TRUE; /* out of memory */ |
2774 | goto nobackup; |
2775 | } |
2776 | |
2777 | /* |
2778 | * Check if backup file already exists. |
2779 | */ |
2780 | if (os_fileinfo((char *)backup, &file_info_new)) { |
2781 | if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { |
2782 | // |
2783 | // Backup file is same as original file. |
2784 | // May happen when modname() gave the same file back (e.g. silly |
2785 | // link). If we don't check here, we either ruin the file when |
2786 | // copying or erase it after writing. |
2787 | // |
2788 | XFREE_CLEAR(backup); // no backup file to delete |
2789 | } else if (!p_bk) { |
2790 | // We are not going to keep the backup file, so don't |
2791 | // delete an existing one, and try to use another name instead. |
2792 | // Change one character, just before the extension. |
2793 | // |
2794 | wp = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); |
2795 | if (wp < backup) { // empty file name ??? |
2796 | wp = backup; |
2797 | } |
2798 | *wp = 'z'; |
2799 | while (*wp > 'a' |
2800 | && os_fileinfo((char *)backup, &file_info_new)) { |
2801 | --*wp; |
2802 | } |
2803 | // They all exist??? Must be something wrong. |
2804 | if (*wp == 'a') { |
2805 | XFREE_CLEAR(backup); |
2806 | } |
2807 | } |
2808 | } |
2809 | } |
2810 | xfree(rootname); |
2811 | |
2812 | /* |
2813 | * Try to create the backup file |
2814 | */ |
2815 | if (backup != NULL) { |
2816 | /* remove old backup, if present */ |
2817 | os_remove((char *)backup); |
2818 | |
2819 | // set file protection same as original file, but |
2820 | // strip s-bit. |
2821 | (void)os_setperm((const char *)backup, perm & 0777); |
2822 | |
2823 | #ifdef UNIX |
2824 | // |
2825 | // Try to set the group of the backup same as the original file. If |
2826 | // this fails, set the protection bits for the group same as the |
2827 | // protection bits for others. |
2828 | // |
2829 | if (file_info_new.stat.st_gid != file_info_old.stat.st_gid |
2830 | && os_chown((char *)backup, -1, file_info_old.stat.st_gid) != 0) { |
2831 | os_setperm((const char *)backup, |
2832 | (perm & 0707) | ((perm & 07) << 3)); |
2833 | } |
2834 | #endif |
2835 | |
2836 | // copy the file |
2837 | if (os_copy((char *)fname, (char *)backup, UV_FS_COPYFILE_FICLONE) |
2838 | != 0) { |
2839 | SET_ERRMSG(_("E506: Can't write to backup file " |
2840 | "(add ! to override)" )); |
2841 | } |
2842 | |
2843 | #ifdef UNIX |
2844 | os_file_settime((char *)backup, |
2845 | file_info_old.stat.st_atim.tv_sec, |
2846 | file_info_old.stat.st_mtim.tv_sec); |
2847 | #endif |
2848 | #ifdef HAVE_ACL |
2849 | mch_set_acl(backup, acl); |
2850 | #endif |
2851 | break; |
2852 | } |
2853 | } |
2854 | |
2855 | nobackup: |
2856 | if (backup == NULL && errmsg == NULL) { |
2857 | SET_ERRMSG(_( |
2858 | "E509: Cannot create backup file (add ! to override)" )); |
2859 | } |
2860 | // Ignore errors when forceit is TRUE. |
2861 | if ((some_error || errmsg != NULL) && !forceit) { |
2862 | retval = FAIL; |
2863 | goto fail; |
2864 | } |
2865 | SET_ERRMSG(NULL); |
2866 | } else { |
2867 | char_u *dirp; |
2868 | char_u *p; |
2869 | char_u *rootname; |
2870 | |
2871 | /* |
2872 | * Make a backup by renaming the original file. |
2873 | */ |
2874 | /* |
2875 | * If 'cpoptions' includes the "W" flag, we don't want to |
2876 | * overwrite a read-only file. But rename may be possible |
2877 | * anyway, thus we need an extra check here. |
2878 | */ |
2879 | if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { |
2880 | SET_ERRMSG_NUM("E504" , _(err_readonly)); |
2881 | goto fail; |
2882 | } |
2883 | |
2884 | /* |
2885 | * |
2886 | * Form the backup file name - change path/fo.o.h to |
2887 | * path/fo.o.h.bak Try all directories in 'backupdir', first one |
2888 | * that works is used. |
2889 | */ |
2890 | dirp = p_bdir; |
2891 | while (*dirp) { |
2892 | /* |
2893 | * Isolate one directory name and make the backup file name. |
2894 | */ |
2895 | (void)copy_option_part(&dirp, IObuff, IOSIZE, "," ); |
2896 | rootname = get_file_in_dir(fname, IObuff); |
2897 | if (rootname == NULL) |
2898 | backup = NULL; |
2899 | else { |
2900 | backup = (char_u *)modname((char *)rootname, (char *)backup_ext, FALSE); |
2901 | xfree(rootname); |
2902 | } |
2903 | |
2904 | if (backup != NULL) { |
2905 | /* |
2906 | * If we are not going to keep the backup file, don't |
2907 | * delete an existing one, try to use another name. |
2908 | * Change one character, just before the extension. |
2909 | */ |
2910 | if (!p_bk && os_path_exists(backup)) { |
2911 | p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); |
2912 | if (p < backup) /* empty file name ??? */ |
2913 | p = backup; |
2914 | *p = 'z'; |
2915 | while (*p > 'a' && os_path_exists(backup)) { |
2916 | (*p)--; |
2917 | } |
2918 | // They all exist??? Must be something wrong! |
2919 | if (*p == 'a') { |
2920 | XFREE_CLEAR(backup); |
2921 | } |
2922 | } |
2923 | } |
2924 | if (backup != NULL) { |
2925 | // Delete any existing backup and move the current version |
2926 | // to the backup. For safety, we don't remove the backup |
2927 | // until the write has finished successfully. And if the |
2928 | // 'backup' option is set, leave it around. |
2929 | |
2930 | // If the renaming of the original file to the backup file |
2931 | // works, quit here. |
2932 | /// |
2933 | if (vim_rename(fname, backup) == 0) { |
2934 | break; |
2935 | } |
2936 | |
2937 | XFREE_CLEAR(backup); // don't do the rename below |
2938 | } |
2939 | } |
2940 | if (backup == NULL && !forceit) { |
2941 | SET_ERRMSG(_("E510: Can't make backup file (add ! to override)" )); |
2942 | goto fail; |
2943 | } |
2944 | } |
2945 | } |
2946 | |
2947 | #if defined(UNIX) |
2948 | // When using ":w!" and the file was read-only: make it writable |
2949 | if (forceit && perm >= 0 && !(perm & 0200) |
2950 | && file_info_old.stat.st_uid == getuid() |
2951 | && vim_strchr(p_cpo, CPO_FWRITE) == NULL) { |
2952 | perm |= 0200; |
2953 | (void)os_setperm((const char *)fname, perm); |
2954 | made_writable = true; |
2955 | } |
2956 | #endif |
2957 | |
2958 | // When using ":w!" and writing to the current file, 'readonly' makes no |
2959 | // sense, reset it, unless 'Z' appears in 'cpoptions'. |
2960 | if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) { |
2961 | buf->b_p_ro = false; |
2962 | need_maketitle = true; // set window title later |
2963 | status_redraw_all(); // redraw status lines later |
2964 | } |
2965 | |
2966 | if (end > buf->b_ml.ml_line_count) |
2967 | end = buf->b_ml.ml_line_count; |
2968 | if (buf->b_ml.ml_flags & ML_EMPTY) |
2969 | start = end + 1; |
2970 | |
2971 | // If the original file is being overwritten, there is a small chance that |
2972 | // we crash in the middle of writing. Therefore the file is preserved now. |
2973 | // This makes all block numbers positive so that recovery does not need |
2974 | // the original file. |
2975 | // Don't do this if there is a backup file and we are exiting. |
2976 | if (reset_changed && !newfile && overwriting |
2977 | && !(exiting && backup != NULL)) { |
2978 | ml_preserve(buf, false, !!p_fs); |
2979 | if (got_int) { |
2980 | SET_ERRMSG(_(e_interr)); |
2981 | goto restore_backup; |
2982 | } |
2983 | } |
2984 | |
2985 | |
2986 | // Default: write the file directly. May write to a temp file for |
2987 | // multi-byte conversion. |
2988 | wfname = fname; |
2989 | |
2990 | // Check for forced 'fileencoding' from "++opt=val" argument. |
2991 | if (eap != NULL && eap->force_enc != 0) { |
2992 | fenc = eap->cmd + eap->force_enc; |
2993 | fenc = enc_canonize(fenc); |
2994 | fenc_tofree = fenc; |
2995 | } else { |
2996 | fenc = buf->b_p_fenc; |
2997 | } |
2998 | |
2999 | // Check if the file needs to be converted. |
3000 | converted = need_conversion(fenc); |
3001 | |
3002 | // Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or |
3003 | // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). |
3004 | // Prepare the flags for it and allocate bw_conv_buf when needed. |
3005 | if (converted && (enc_utf8 || STRCMP(p_enc, "latin1" ) == 0)) { |
3006 | wb_flags = get_fio_flags(fenc); |
3007 | if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) { |
3008 | // Need to allocate a buffer to translate into. |
3009 | if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) { |
3010 | write_info.bw_conv_buflen = bufsize * 2; |
3011 | } else { // FIO_UCS4 |
3012 | write_info.bw_conv_buflen = bufsize * 4; |
3013 | } |
3014 | write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen); |
3015 | if (!write_info.bw_conv_buf) { |
3016 | end = 0; |
3017 | } |
3018 | } |
3019 | } |
3020 | |
3021 | |
3022 | |
3023 | if (converted && wb_flags == 0) { |
3024 | # ifdef HAVE_ICONV |
3025 | // Use iconv() conversion when conversion is needed and it's not done |
3026 | // internally. |
3027 | write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, |
3028 | enc_utf8 ? (char_u *)"utf-8" : p_enc); |
3029 | if (write_info.bw_iconv_fd != (iconv_t)-1) { |
3030 | /* We're going to use iconv(), allocate a buffer to convert in. */ |
3031 | write_info.bw_conv_buflen = bufsize * ICONV_MULT; |
3032 | write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen); |
3033 | if (!write_info.bw_conv_buf) { |
3034 | end = 0; |
3035 | } |
3036 | write_info.bw_first = TRUE; |
3037 | } else |
3038 | # endif |
3039 | |
3040 | /* |
3041 | * When the file needs to be converted with 'charconvert' after |
3042 | * writing, write to a temp file instead and let the conversion |
3043 | * overwrite the original file. |
3044 | */ |
3045 | if (*p_ccv != NUL) { |
3046 | wfname = vim_tempname(); |
3047 | if (wfname == NULL) { // Can't write without a tempfile! |
3048 | SET_ERRMSG(_("E214: Can't find temp file for writing" )); |
3049 | goto restore_backup; |
3050 | } |
3051 | } |
3052 | } |
3053 | if (converted && wb_flags == 0 |
3054 | # ifdef HAVE_ICONV |
3055 | && write_info.bw_iconv_fd == (iconv_t)-1 |
3056 | # endif |
3057 | && wfname == fname |
3058 | ) { |
3059 | if (!forceit) { |
3060 | SET_ERRMSG(_( |
3061 | "E213: Cannot convert (add ! to write without conversion)" )); |
3062 | goto restore_backup; |
3063 | } |
3064 | notconverted = TRUE; |
3065 | } |
3066 | |
3067 | // If conversion is taking place, we may first pretend to write and check |
3068 | // for conversion errors. Then loop again to write for real. |
3069 | // When not doing conversion this writes for real right away. |
3070 | for (checking_conversion = true; ; checking_conversion = false) { |
3071 | // There is no need to check conversion when: |
3072 | // - there is no conversion |
3073 | // - we make a backup file, that can be restored in case of conversion |
3074 | // failure. |
3075 | if (!converted || dobackup) { |
3076 | checking_conversion = false; |
3077 | } |
3078 | |
3079 | if (checking_conversion) { |
3080 | // Make sure we don't write anything. |
3081 | fd = -1; |
3082 | write_info.bw_fd = fd; |
3083 | } else { |
3084 | // Open the file "wfname" for writing. |
3085 | // We may try to open the file twice: If we can't write to the file |
3086 | // and forceit is TRUE we delete the existing file and try to |
3087 | // create a new one. If this still fails we may have lost the |
3088 | // original file! (this may happen when the user reached his |
3089 | // quotum for number of files). |
3090 | // Appending will fail if the file does not exist and forceit is |
3091 | // FALSE. |
3092 | while ((fd = os_open((char *)wfname, |
3093 | O_WRONLY | |
3094 | (append ? |
3095 | (forceit ? (O_APPEND | O_CREAT) : O_APPEND) |
3096 | : (O_CREAT | O_TRUNC)) |
3097 | , perm < 0 ? 0666 : (perm & 0777))) < 0) { |
3098 | // A forced write will try to create a new file if the old one |
3099 | // is still readonly. This may also happen when the directory |
3100 | // is read-only. In that case the mch_remove() will fail. |
3101 | if (errmsg == NULL) { |
3102 | #ifdef UNIX |
3103 | FileInfo file_info; |
3104 | |
3105 | // Don't delete the file when it's a hard or symbolic link. |
3106 | if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1) |
3107 | || (os_fileinfo_link((char *)fname, &file_info) |
3108 | && !os_fileinfo_id_equal(&file_info, &file_info_old))) { |
3109 | SET_ERRMSG(_("E166: Can't open linked file for writing" )); |
3110 | } else { |
3111 | #endif |
3112 | SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s" ), fd); |
3113 | if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL |
3114 | && perm >= 0) { |
3115 | #ifdef UNIX |
3116 | // we write to the file, thus it should be marked |
3117 | // writable after all |
3118 | if (!(perm & 0200)) { |
3119 | made_writable = true; |
3120 | } |
3121 | perm |= 0200; |
3122 | if (file_info_old.stat.st_uid != getuid() |
3123 | || file_info_old.stat.st_gid != getgid()) { |
3124 | perm &= 0777; |
3125 | } |
3126 | #endif |
3127 | if (!append) { // don't remove when appending |
3128 | os_remove((char *)wfname); |
3129 | } |
3130 | continue; |
3131 | } |
3132 | #ifdef UNIX |
3133 | } |
3134 | #endif |
3135 | } |
3136 | |
3137 | restore_backup: |
3138 | { |
3139 | // If we failed to open the file, we don't need a backup. Throw it |
3140 | // away. If we moved or removed the original file try to put the |
3141 | // backup in its place. |
3142 | if (backup != NULL && wfname == fname) { |
3143 | if (backup_copy) { |
3144 | // There is a small chance that we removed the original, |
3145 | // try to move the copy in its place. |
3146 | // This may not work if the vim_rename() fails. |
3147 | // In that case we leave the copy around. |
3148 | // If file does not exist, put the copy in its place |
3149 | if (!os_path_exists(fname)) { |
3150 | vim_rename(backup, fname); |
3151 | } |
3152 | // if original file does exist throw away the copy |
3153 | if (os_path_exists(fname)) { |
3154 | os_remove((char *)backup); |
3155 | } |
3156 | } else { |
3157 | // try to put the original file back |
3158 | vim_rename(backup, fname); |
3159 | } |
3160 | } |
3161 | |
3162 | // if original file no longer exists give an extra warning |
3163 | if (!newfile && !os_path_exists(fname)) { |
3164 | end = 0; |
3165 | } |
3166 | } |
3167 | |
3168 | if (wfname != fname) { |
3169 | xfree(wfname); |
3170 | } |
3171 | goto fail; |
3172 | } |
3173 | write_info.bw_fd = fd; |
3174 | } |
3175 | SET_ERRMSG(NULL); |
3176 | |
3177 | write_info.bw_buf = buffer; |
3178 | nchars = 0; |
3179 | |
3180 | // use "++bin", "++nobin" or 'binary' |
3181 | if (eap != NULL && eap->force_bin != 0) { |
3182 | write_bin = (eap->force_bin == FORCE_BIN); |
3183 | } else { |
3184 | write_bin = buf->b_p_bin; |
3185 | } |
3186 | |
3187 | // Skip the BOM when appending and the file already existed, the BOM |
3188 | // only makes sense at the start of the file. |
3189 | if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) { |
3190 | write_info.bw_len = make_bom(buffer, fenc); |
3191 | if (write_info.bw_len > 0) { |
3192 | // don't convert |
3193 | write_info.bw_flags = FIO_NOCONVERT | wb_flags; |
3194 | if (buf_write_bytes(&write_info) == FAIL) { |
3195 | end = 0; |
3196 | } else { |
3197 | nchars += write_info.bw_len; |
3198 | } |
3199 | } |
3200 | } |
3201 | write_info.bw_start_lnum = start; |
3202 | |
3203 | write_undo_file = (buf->b_p_udf && overwriting && !append |
3204 | && !filtering && reset_changed && !checking_conversion); |
3205 | if (write_undo_file) { |
3206 | // Prepare for computing the hash value of the text. |
3207 | sha256_start(&sha_ctx); |
3208 | } |
3209 | |
3210 | write_info.bw_len = bufsize; |
3211 | #ifdef HAS_BW_FLAGS |
3212 | write_info.bw_flags = wb_flags; |
3213 | #endif |
3214 | fileformat = get_fileformat_force(buf, eap); |
3215 | s = buffer; |
3216 | len = 0; |
3217 | for (lnum = start; lnum <= end; lnum++) { |
3218 | // The next while loop is done once for each character written. |
3219 | // Keep it fast! |
3220 | ptr = ml_get_buf(buf, lnum, false) - 1; |
3221 | if (write_undo_file) { |
3222 | sha256_update(&sha_ctx, ptr + 1, (uint32_t)(STRLEN(ptr + 1) + 1)); |
3223 | } |
3224 | while ((c = *++ptr) != NUL) { |
3225 | if (c == NL) { |
3226 | *s = NUL; // replace newlines with NULs |
3227 | } else if (c == CAR && fileformat == EOL_MAC) { |
3228 | *s = NL; // Mac: replace CRs with NLs |
3229 | } else { |
3230 | *s = c; |
3231 | } |
3232 | s++; |
3233 | if (++len != bufsize) { |
3234 | continue; |
3235 | } |
3236 | if (buf_write_bytes(&write_info) == FAIL) { |
3237 | end = 0; // write error: break loop |
3238 | break; |
3239 | } |
3240 | nchars += bufsize; |
3241 | s = buffer; |
3242 | len = 0; |
3243 | write_info.bw_start_lnum = lnum; |
3244 | } |
3245 | // write failed or last line has no EOL: stop here |
3246 | if (end == 0 |
3247 | || (lnum == end |
3248 | && (write_bin || !buf->b_p_fixeol) |
3249 | && (lnum == buf->b_no_eol_lnum |
3250 | || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) { |
3251 | lnum++; // written the line, count it |
3252 | no_eol = true; |
3253 | break; |
3254 | } |
3255 | if (fileformat == EOL_UNIX) { |
3256 | *s++ = NL; |
3257 | } else { |
3258 | *s++ = CAR; // EOL_MAC or EOL_DOS: write CR |
3259 | if (fileformat == EOL_DOS) { // write CR-NL |
3260 | if (++len == bufsize) { |
3261 | if (buf_write_bytes(&write_info) == FAIL) { |
3262 | end = 0; // write error: break loop |
3263 | break; |
3264 | } |
3265 | nchars += bufsize; |
3266 | s = buffer; |
3267 | len = 0; |
3268 | } |
3269 | *s++ = NL; |
3270 | } |
3271 | } |
3272 | if (++len == bufsize) { |
3273 | if (buf_write_bytes(&write_info) == FAIL) { |
3274 | end = 0; // Write error: break loop. |
3275 | break; |
3276 | } |
3277 | nchars += bufsize; |
3278 | s = buffer; |
3279 | len = 0; |
3280 | |
3281 | os_breakcheck(); |
3282 | if (got_int) { |
3283 | end = 0; // Interrupted, break loop. |
3284 | break; |
3285 | } |
3286 | } |
3287 | } |
3288 | if (len > 0 && end > 0) { |
3289 | write_info.bw_len = len; |
3290 | if (buf_write_bytes(&write_info) == FAIL) { |
3291 | end = 0; // write error |
3292 | } |
3293 | nchars += len; |
3294 | } |
3295 | |
3296 | // Stop when writing done or an error was encountered. |
3297 | if (!checking_conversion || end == 0) { |
3298 | break; |
3299 | } |
3300 | |
3301 | // If no error happened until now, writing should be ok, so loop to |
3302 | // really write the buffer. |
3303 | } |
3304 | |
3305 | // If we started writing, finish writing. Also when an error was |
3306 | // encountered. |
3307 | if (!checking_conversion) { |
3308 | // On many journalling file systems there is a bug that causes both the |
3309 | // original and the backup file to be lost when halting the system right |
3310 | // after writing the file. That's because only the meta-data is |
3311 | // journalled. Syncing the file slows down the system, but assures it has |
3312 | // been written to disk and we don't lose it. |
3313 | // For a device do try the fsync() but don't complain if it does not work |
3314 | // (could be a pipe). |
3315 | // If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. |
3316 | int error; |
3317 | if (p_fs && (error = os_fsync(fd)) != 0 && !device |
3318 | // fsync not supported on this storage. |
3319 | && error != UV_ENOTSUP) { |
3320 | SET_ERRMSG_ARG(e_fsync, error); |
3321 | end = 0; |
3322 | } |
3323 | |
3324 | #ifdef UNIX |
3325 | // When creating a new file, set its owner/group to that of the original |
3326 | // file. Get the new device and inode number. |
3327 | if (backup != NULL && !backup_copy) { |
3328 | // don't change the owner when it's already OK, some systems remove |
3329 | // permission or ACL stuff |
3330 | FileInfo file_info; |
3331 | if (!os_fileinfo((char *)wfname, &file_info) |
3332 | || file_info.stat.st_uid != file_info_old.stat.st_uid |
3333 | || file_info.stat.st_gid != file_info_old.stat.st_gid) { |
3334 | os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); |
3335 | if (perm >= 0) { // Set permission again, may have changed. |
3336 | (void)os_setperm((const char *)wfname, perm); |
3337 | } |
3338 | } |
3339 | buf_set_file_id(buf); |
3340 | } else if (!buf->file_id_valid) { |
3341 | // Set the file_id when creating a new file. |
3342 | buf_set_file_id(buf); |
3343 | } |
3344 | #endif |
3345 | |
3346 | if ((error = os_close(fd)) != 0) { |
3347 | SET_ERRMSG_ARG(_("E512: Close failed: %s" ), error); |
3348 | end = 0; |
3349 | } |
3350 | |
3351 | #ifdef UNIX |
3352 | if (made_writable) { |
3353 | perm &= ~0200; // reset 'w' bit for security reasons |
3354 | } |
3355 | #endif |
3356 | if (perm >= 0) { // Set perm. of new file same as old file. |
3357 | (void)os_setperm((const char *)wfname, perm); |
3358 | } |
3359 | #ifdef HAVE_ACL |
3360 | // Probably need to set the ACL before changing the user (can't set the |
3361 | // ACL on a file the user doesn't own). |
3362 | if (!backup_copy) { |
3363 | mch_set_acl(wfname, acl); |
3364 | } |
3365 | #endif |
3366 | |
3367 | if (wfname != fname) { |
3368 | // The file was written to a temp file, now it needs to be converted |
3369 | // with 'charconvert' to (overwrite) the output file. |
3370 | if (end != 0) { |
3371 | if (eval_charconvert(enc_utf8 ? "utf-8" : (char *)p_enc, (char *)fenc, |
3372 | (char *)wfname, (char *)fname) == FAIL) { |
3373 | write_info.bw_conv_error = true; |
3374 | end = 0; |
3375 | } |
3376 | } |
3377 | os_remove((char *)wfname); |
3378 | xfree(wfname); |
3379 | } |
3380 | } |
3381 | |
3382 | if (end == 0) { |
3383 | // Error encountered. |
3384 | if (errmsg == NULL) { |
3385 | if (write_info.bw_conv_error) { |
3386 | if (write_info.bw_conv_error_lnum == 0) { |
3387 | SET_ERRMSG(_( |
3388 | "E513: write error, conversion failed " |
3389 | "(make 'fenc' empty to override)" )); |
3390 | } else { |
3391 | errmsg_allocated = true; |
3392 | SET_ERRMSG(xmalloc(300)); |
3393 | vim_snprintf( |
3394 | errmsg, 300, |
3395 | _("E513: write error, conversion failed in line %" PRIdLINENR |
3396 | " (make 'fenc' empty to override)" ), |
3397 | write_info.bw_conv_error_lnum); |
3398 | } |
3399 | } else if (got_int) { |
3400 | SET_ERRMSG(_(e_interr)); |
3401 | } else { |
3402 | SET_ERRMSG(_("E514: write error (file system full?)" )); |
3403 | } |
3404 | } |
3405 | |
3406 | // If we have a backup file, try to put it in place of the new file, |
3407 | // because the new file is probably corrupt. This avoids losing the |
3408 | // original file when trying to make a backup when writing the file a |
3409 | // second time. |
3410 | // When "backup_copy" is set we need to copy the backup over the new |
3411 | // file. Otherwise rename the backup file. |
3412 | // If this is OK, don't give the extra warning message. |
3413 | if (backup != NULL) { |
3414 | if (backup_copy) { |
3415 | // This may take a while, if we were interrupted let the user |
3416 | // know we got the message. |
3417 | if (got_int) { |
3418 | MSG(_(e_interr)); |
3419 | ui_flush(); |
3420 | } |
3421 | |
3422 | // copy the file. |
3423 | if (os_copy((char *)backup, (char *)fname, UV_FS_COPYFILE_FICLONE) |
3424 | == 0) { |
3425 | end = 1; // success |
3426 | } |
3427 | } else { |
3428 | if (vim_rename(backup, fname) == 0) { |
3429 | end = 1; |
3430 | } |
3431 | } |
3432 | } |
3433 | goto fail; |
3434 | } |
3435 | |
3436 | lnum -= start; /* compute number of written lines */ |
3437 | --no_wait_return; /* may wait for return now */ |
3438 | |
3439 | #if !defined(UNIX) |
3440 | fname = sfname; /* use shortname now, for the messages */ |
3441 | #endif |
3442 | if (!filtering) { |
3443 | add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname); |
3444 | c = false; |
3445 | if (write_info.bw_conv_error) { |
3446 | STRCAT(IObuff, _(" CONVERSION ERROR" )); |
3447 | c = TRUE; |
3448 | if (write_info.bw_conv_error_lnum != 0) |
3449 | vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %" PRId64 ";" ), |
3450 | (int64_t)write_info.bw_conv_error_lnum); |
3451 | } else if (notconverted) { |
3452 | STRCAT(IObuff, _("[NOT converted]" )); |
3453 | c = TRUE; |
3454 | } else if (converted) { |
3455 | STRCAT(IObuff, _("[converted]" )); |
3456 | c = TRUE; |
3457 | } |
3458 | if (device) { |
3459 | STRCAT(IObuff, _("[Device]" )); |
3460 | c = TRUE; |
3461 | } else if (newfile) { |
3462 | STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]" ) : _("[New File]" )); |
3463 | c = TRUE; |
3464 | } |
3465 | if (no_eol) { |
3466 | msg_add_eol(); |
3467 | c = TRUE; |
3468 | } |
3469 | /* may add [unix/dos/mac] */ |
3470 | if (msg_add_fileformat(fileformat)) |
3471 | c = TRUE; |
3472 | msg_add_lines(c, (long)lnum, nchars); /* add line/char count */ |
3473 | if (!shortmess(SHM_WRITE)) { |
3474 | if (append) |
3475 | STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]" ) : _(" appended" )); |
3476 | else |
3477 | STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]" ) : _(" written" )); |
3478 | } |
3479 | |
3480 | set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0); |
3481 | } |
3482 | |
3483 | /* When written everything correctly: reset 'modified'. Unless not |
3484 | * writing to the original file and '+' is not in 'cpoptions'. */ |
3485 | if (reset_changed && whole && !append |
3486 | && !write_info.bw_conv_error |
3487 | && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { |
3488 | unchanged(buf, true, false); |
3489 | const varnumber_T changedtick = buf_get_changedtick(buf); |
3490 | if (buf->b_last_changedtick + 1 == changedtick) { |
3491 | // b:changedtick may be incremented in unchanged() but that |
3492 | // should not trigger a TextChanged event. |
3493 | buf->b_last_changedtick = changedtick; |
3494 | } |
3495 | u_unchanged(buf); |
3496 | u_update_save_nr(buf); |
3497 | } |
3498 | |
3499 | /* |
3500 | * If written to the current file, update the timestamp of the swap file |
3501 | * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. |
3502 | */ |
3503 | if (overwriting) { |
3504 | ml_timestamp(buf); |
3505 | if (append) |
3506 | buf->b_flags &= ~BF_NEW; |
3507 | else |
3508 | buf->b_flags &= ~BF_WRITE_MASK; |
3509 | } |
3510 | |
3511 | /* |
3512 | * If we kept a backup until now, and we are in patch mode, then we make |
3513 | * the backup file our 'original' file. |
3514 | */ |
3515 | if (*p_pm && dobackup) { |
3516 | char *org = modname((char *)fname, (char *)p_pm, FALSE); |
3517 | |
3518 | if (backup != NULL) { |
3519 | /* |
3520 | * If the original file does not exist yet |
3521 | * the current backup file becomes the original file |
3522 | */ |
3523 | if (org == NULL) { |
3524 | EMSG(_("E205: Patchmode: can't save original file" )); |
3525 | } else if (!os_path_exists((char_u *)org)) { |
3526 | vim_rename(backup, (char_u *)org); |
3527 | XFREE_CLEAR(backup); // don't delete the file |
3528 | #ifdef UNIX |
3529 | os_file_settime(org, |
3530 | file_info_old.stat.st_atim.tv_sec, |
3531 | file_info_old.stat.st_mtim.tv_sec); |
3532 | #endif |
3533 | } |
3534 | } |
3535 | /* |
3536 | * If there is no backup file, remember that a (new) file was |
3537 | * created. |
3538 | */ |
3539 | else { |
3540 | int empty_fd; |
3541 | |
3542 | if (org == NULL |
3543 | || (empty_fd = os_open(org, |
3544 | O_CREAT | O_EXCL | O_NOFOLLOW, |
3545 | perm < 0 ? 0666 : (perm & 0777))) < 0) |
3546 | EMSG(_("E206: patchmode: can't touch empty original file" )); |
3547 | else |
3548 | close(empty_fd); |
3549 | } |
3550 | if (org != NULL) { |
3551 | os_setperm(org, os_getperm((const char *)fname) & 0777); |
3552 | xfree(org); |
3553 | } |
3554 | } |
3555 | |
3556 | /* |
3557 | * Remove the backup unless 'backup' option is set |
3558 | */ |
3559 | if (!p_bk && backup != NULL |
3560 | && !write_info.bw_conv_error |
3561 | && os_remove((char *)backup) != 0) { |
3562 | EMSG(_("E207: Can't delete backup file" )); |
3563 | } |
3564 | |
3565 | goto nofail; |
3566 | |
3567 | /* |
3568 | * Finish up. We get here either after failure or success. |
3569 | */ |
3570 | fail: |
3571 | --no_wait_return; /* may wait for return now */ |
3572 | nofail: |
3573 | |
3574 | /* Done saving, we accept changed buffer warnings again */ |
3575 | buf->b_saving = false; |
3576 | |
3577 | xfree(backup); |
3578 | if (buffer != smallbuf) |
3579 | xfree(buffer); |
3580 | xfree(fenc_tofree); |
3581 | xfree(write_info.bw_conv_buf); |
3582 | # ifdef HAVE_ICONV |
3583 | if (write_info.bw_iconv_fd != (iconv_t)-1) { |
3584 | iconv_close(write_info.bw_iconv_fd); |
3585 | write_info.bw_iconv_fd = (iconv_t)-1; |
3586 | } |
3587 | # endif |
3588 | #ifdef HAVE_ACL |
3589 | mch_free_acl(acl); |
3590 | #endif |
3591 | |
3592 | if (errmsg != NULL) { |
3593 | // - 100 to save some space for further error message |
3594 | #ifndef UNIX |
3595 | add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname); |
3596 | #else |
3597 | add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname); |
3598 | #endif |
3599 | if (errnum != NULL) { |
3600 | if (errmsgarg != 0) { |
3601 | emsgf("%s: %s%s: %s" , errnum, IObuff, errmsg, os_strerror(errmsgarg)); |
3602 | } else { |
3603 | emsgf("%s: %s%s" , errnum, IObuff, errmsg); |
3604 | } |
3605 | } else if (errmsgarg != 0) { |
3606 | emsgf(errmsg, os_strerror(errmsgarg)); |
3607 | } else { |
3608 | EMSG(errmsg); |
3609 | } |
3610 | if (errmsg_allocated) { |
3611 | xfree(errmsg); |
3612 | } |
3613 | |
3614 | retval = FAIL; |
3615 | if (end == 0) { |
3616 | const int attr = HL_ATTR(HLF_E); // Set highlight for error messages. |
3617 | MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n" ), |
3618 | attr | MSG_HIST); |
3619 | MSG_PUTS_ATTR(_( |
3620 | "don't quit the editor until the file is successfully written!" ), |
3621 | attr | MSG_HIST); |
3622 | |
3623 | /* Update the timestamp to avoid an "overwrite changed file" |
3624 | * prompt when writing again. */ |
3625 | if (os_fileinfo((char *)fname, &file_info_old)) { |
3626 | buf_store_file_info(buf, &file_info_old); |
3627 | buf->b_mtime_read = buf->b_mtime; |
3628 | } |
3629 | } |
3630 | } |
3631 | msg_scroll = msg_save; |
3632 | |
3633 | /* |
3634 | * When writing the whole file and 'undofile' is set, also write the undo |
3635 | * file. |
3636 | */ |
3637 | if (retval == OK && write_undo_file) { |
3638 | char_u hash[UNDO_HASH_SIZE]; |
3639 | |
3640 | sha256_finish(&sha_ctx, hash); |
3641 | u_write_undo(NULL, FALSE, buf, hash); |
3642 | } |
3643 | |
3644 | if (!should_abort(retval)) { |
3645 | aco_save_T aco; |
3646 | |
3647 | curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */ |
3648 | |
3649 | /* |
3650 | * Apply POST autocommands. |
3651 | * Careful: The autocommands may call buf_write() recursively! |
3652 | */ |
3653 | aucmd_prepbuf(&aco, buf); |
3654 | |
3655 | if (append) |
3656 | apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, |
3657 | FALSE, curbuf, eap); |
3658 | else if (filtering) |
3659 | apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, |
3660 | FALSE, curbuf, eap); |
3661 | else if (reset_changed && whole) |
3662 | apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, |
3663 | FALSE, curbuf, eap); |
3664 | else |
3665 | apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, |
3666 | FALSE, curbuf, eap); |
3667 | |
3668 | /* restore curwin/curbuf and a few other things */ |
3669 | aucmd_restbuf(&aco); |
3670 | |
3671 | if (aborting()) /* autocmds may abort script processing */ |
3672 | retval = FALSE; |
3673 | } |
3674 | |
3675 | got_int |= prev_got_int; |
3676 | |
3677 | return retval; |
3678 | #undef SET_ERRMSG |
3679 | #undef SET_ERRMSG_ARG |
3680 | #undef SET_ERRMSG_NUM |
3681 | } |
3682 | |
3683 | /* |
3684 | * Set the name of the current buffer. Use when the buffer doesn't have a |
3685 | * name and a ":r" or ":w" command with a file name is used. |
3686 | */ |
3687 | static int set_rw_fname(char_u *fname, char_u *sfname) |
3688 | { |
3689 | buf_T *buf = curbuf; |
3690 | |
3691 | /* It's like the unnamed buffer is deleted.... */ |
3692 | if (curbuf->b_p_bl) |
3693 | apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf); |
3694 | apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf); |
3695 | if (aborting()) /* autocmds may abort script processing */ |
3696 | return FAIL; |
3697 | if (curbuf != buf) { |
3698 | /* We are in another buffer now, don't do the renaming. */ |
3699 | EMSG(_(e_auchangedbuf)); |
3700 | return FAIL; |
3701 | } |
3702 | |
3703 | if (setfname(curbuf, fname, sfname, FALSE) == OK) |
3704 | curbuf->b_flags |= BF_NOTEDITED; |
3705 | |
3706 | /* ....and a new named one is created */ |
3707 | apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf); |
3708 | if (curbuf->b_p_bl) |
3709 | apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf); |
3710 | if (aborting()) /* autocmds may abort script processing */ |
3711 | return FAIL; |
3712 | |
3713 | /* Do filetype detection now if 'filetype' is empty. */ |
3714 | if (*curbuf->b_p_ft == NUL) { |
3715 | if (au_has_group((char_u *)"filetypedetect" )) { |
3716 | (void)do_doautocmd((char_u *)"filetypedetect BufRead" , false, NULL); |
3717 | } |
3718 | do_modelines(0); |
3719 | } |
3720 | |
3721 | return OK; |
3722 | } |
3723 | |
3724 | /// Put file name into the specified buffer with quotes |
3725 | /// |
3726 | /// Replaces home directory at the start with `~`. |
3727 | /// |
3728 | /// @param[out] ret_buf Buffer to save results to. |
3729 | /// @param[in] buf_len ret_buf length. |
3730 | /// @param[in] buf buf_T file name is coming from. |
3731 | /// @param[in] fname File name to write. |
3732 | static void add_quoted_fname(char *const ret_buf, const size_t buf_len, |
3733 | const buf_T *const buf, const char *fname) |
3734 | FUNC_ATTR_NONNULL_ARG(1) |
3735 | { |
3736 | if (fname == NULL) { |
3737 | fname = "-stdin-" ; |
3738 | } |
3739 | ret_buf[0] = '"'; |
3740 | home_replace(buf, (const char_u *)fname, (char_u *)ret_buf + 1, |
3741 | (int)buf_len - 4, true); |
3742 | xstrlcat(ret_buf, "\" " , buf_len); |
3743 | } |
3744 | |
3745 | /// Append message for text mode to IObuff. |
3746 | /// |
3747 | /// @param eol_type line ending type |
3748 | /// |
3749 | /// @return true if something was appended. |
3750 | static bool msg_add_fileformat(int eol_type) |
3751 | { |
3752 | #ifndef USE_CRNL |
3753 | if (eol_type == EOL_DOS) { |
3754 | STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]" ) : _("[dos format]" )); |
3755 | return true; |
3756 | } |
3757 | #endif |
3758 | if (eol_type == EOL_MAC) { |
3759 | STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]" ) : _("[mac format]" )); |
3760 | return true; |
3761 | } |
3762 | #ifdef USE_CRNL |
3763 | if (eol_type == EOL_UNIX) { |
3764 | STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]" ) : _("[unix format]" )); |
3765 | return true; |
3766 | } |
3767 | #endif |
3768 | return false; |
3769 | } |
3770 | |
3771 | /* |
3772 | * Append line and character count to IObuff. |
3773 | */ |
3774 | void msg_add_lines(int insert_space, long lnum, off_T nchars) |
3775 | { |
3776 | char_u *p; |
3777 | |
3778 | p = IObuff + STRLEN(IObuff); |
3779 | |
3780 | if (insert_space) |
3781 | *p++ = ' '; |
3782 | if (shortmess(SHM_LINES)) { |
3783 | sprintf((char *)p, "%" PRId64 "L, %" PRId64 "C" , |
3784 | (int64_t)lnum, (int64_t)nchars); |
3785 | } |
3786 | else { |
3787 | if (lnum == 1) |
3788 | STRCPY(p, _("1 line, " )); |
3789 | else |
3790 | sprintf((char *)p, _("%" PRId64 " lines, " ), (int64_t)lnum); |
3791 | p += STRLEN(p); |
3792 | if (nchars == 1) |
3793 | STRCPY(p, _("1 character" )); |
3794 | else { |
3795 | sprintf((char *)p, _("%" PRId64 " characters" ), (int64_t)nchars); |
3796 | } |
3797 | } |
3798 | } |
3799 | |
3800 | /* |
3801 | * Append message for missing line separator to IObuff. |
3802 | */ |
3803 | static void msg_add_eol(void) |
3804 | { |
3805 | STRCAT(IObuff, |
3806 | shortmess(SHM_LAST) ? _("[noeol]" ) : _("[Incomplete last line]" )); |
3807 | } |
3808 | |
3809 | /* |
3810 | * Check modification time of file, before writing to it. |
3811 | * The size isn't checked, because using a tool like "gzip" takes care of |
3812 | * using the same timestamp but can't set the size. |
3813 | */ |
3814 | static int check_mtime(buf_T *buf, FileInfo *file_info) |
3815 | { |
3816 | if (buf->b_mtime_read != 0 |
3817 | && time_differs(file_info->stat.st_mtim.tv_sec, |
3818 | buf->b_mtime_read)) { |
3819 | msg_scroll = true; // Don't overwrite messages here. |
3820 | msg_silent = 0; // Must give this prompt. |
3821 | // Don't use emsg() here, don't want to flush the buffers. |
3822 | msg_attr(_("WARNING: The file has been changed since reading it!!!" ), |
3823 | HL_ATTR(HLF_E)); |
3824 | if (ask_yesno(_("Do you really want to write to it" ), true) == 'n') { |
3825 | return FAIL; |
3826 | } |
3827 | msg_scroll = false; // Always overwrite the file message now. |
3828 | } |
3829 | return OK; |
3830 | } |
3831 | |
3832 | /// Return true if the times differ |
3833 | /// |
3834 | /// @param t1 first time |
3835 | /// @param t2 second time |
3836 | static bool time_differs(long t1, long t2) FUNC_ATTR_CONST |
3837 | { |
3838 | #if defined(__linux__) || defined(MSWIN) |
3839 | /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store |
3840 | * the seconds. Since the roundoff is done when flushing the inode, the |
3841 | * time may change unexpectedly by one second!!! */ |
3842 | return t1 - t2 > 1 || t2 - t1 > 1; |
3843 | #else |
3844 | return t1 != t2; |
3845 | #endif |
3846 | } |
3847 | |
3848 | /* |
3849 | * Call write() to write a number of bytes to the file. |
3850 | * Handles 'encoding' conversion. |
3851 | * |
3852 | * Return FAIL for failure, OK otherwise. |
3853 | */ |
3854 | static int buf_write_bytes(struct bw_info *ip) |
3855 | { |
3856 | int wlen; |
3857 | char_u *buf = ip->bw_buf; /* data to write */ |
3858 | int len = ip->bw_len; /* length of data */ |
3859 | #ifdef HAS_BW_FLAGS |
3860 | int flags = ip->bw_flags; /* extra flags */ |
3861 | #endif |
3862 | |
3863 | /* |
3864 | * Skip conversion when writing the BOM. |
3865 | */ |
3866 | if (!(flags & FIO_NOCONVERT)) { |
3867 | char_u *p; |
3868 | unsigned c; |
3869 | int n; |
3870 | |
3871 | if (flags & FIO_UTF8) { |
3872 | /* |
3873 | * Convert latin1 in the buffer to UTF-8 in the file. |
3874 | */ |
3875 | p = ip->bw_conv_buf; /* translate to buffer */ |
3876 | for (wlen = 0; wlen < len; ++wlen) |
3877 | p += utf_char2bytes(buf[wlen], p); |
3878 | buf = ip->bw_conv_buf; |
3879 | len = (int)(p - ip->bw_conv_buf); |
3880 | } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { |
3881 | /* |
3882 | * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or |
3883 | * Latin1 chars in the file. |
3884 | */ |
3885 | if (flags & FIO_LATIN1) |
3886 | p = buf; /* translate in-place (can only get shorter) */ |
3887 | else |
3888 | p = ip->bw_conv_buf; /* translate to buffer */ |
3889 | for (wlen = 0; wlen < len; wlen += n) { |
3890 | if (wlen == 0 && ip->bw_restlen != 0) { |
3891 | int l; |
3892 | |
3893 | /* Use remainder of previous call. Append the start of |
3894 | * buf[] to get a full sequence. Might still be too |
3895 | * short! */ |
3896 | l = CONV_RESTLEN - ip->bw_restlen; |
3897 | if (l > len) |
3898 | l = len; |
3899 | memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); |
3900 | n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); |
3901 | if (n > ip->bw_restlen + len) { |
3902 | /* We have an incomplete byte sequence at the end to |
3903 | * be written. We can't convert it without the |
3904 | * remaining bytes. Keep them for the next call. */ |
3905 | if (ip->bw_restlen + len > CONV_RESTLEN) |
3906 | return FAIL; |
3907 | ip->bw_restlen += len; |
3908 | break; |
3909 | } |
3910 | if (n > 1) |
3911 | c = utf_ptr2char(ip->bw_rest); |
3912 | else |
3913 | c = ip->bw_rest[0]; |
3914 | if (n >= ip->bw_restlen) { |
3915 | n -= ip->bw_restlen; |
3916 | ip->bw_restlen = 0; |
3917 | } else { |
3918 | ip->bw_restlen -= n; |
3919 | memmove(ip->bw_rest, ip->bw_rest + n, |
3920 | (size_t)ip->bw_restlen); |
3921 | n = 0; |
3922 | } |
3923 | } else { |
3924 | n = utf_ptr2len_len(buf + wlen, len - wlen); |
3925 | if (n > len - wlen) { |
3926 | /* We have an incomplete byte sequence at the end to |
3927 | * be written. We can't convert it without the |
3928 | * remaining bytes. Keep them for the next call. */ |
3929 | if (len - wlen > CONV_RESTLEN) |
3930 | return FAIL; |
3931 | ip->bw_restlen = len - wlen; |
3932 | memmove(ip->bw_rest, buf + wlen, |
3933 | (size_t)ip->bw_restlen); |
3934 | break; |
3935 | } |
3936 | if (n > 1) |
3937 | c = utf_ptr2char(buf + wlen); |
3938 | else |
3939 | c = buf[wlen]; |
3940 | } |
3941 | |
3942 | if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { |
3943 | ip->bw_conv_error = TRUE; |
3944 | ip->bw_conv_error_lnum = ip->bw_start_lnum; |
3945 | } |
3946 | if (c == NL) |
3947 | ++ip->bw_start_lnum; |
3948 | } |
3949 | if (flags & FIO_LATIN1) |
3950 | len = (int)(p - buf); |
3951 | else { |
3952 | buf = ip->bw_conv_buf; |
3953 | len = (int)(p - ip->bw_conv_buf); |
3954 | } |
3955 | } |
3956 | |
3957 | # ifdef HAVE_ICONV |
3958 | if (ip->bw_iconv_fd != (iconv_t)-1) { |
3959 | const char *from; |
3960 | size_t fromlen; |
3961 | char *to; |
3962 | size_t tolen; |
3963 | |
3964 | /* Convert with iconv(). */ |
3965 | if (ip->bw_restlen > 0) { |
3966 | char *fp; |
3967 | |
3968 | /* Need to concatenate the remainder of the previous call and |
3969 | * the bytes of the current call. Use the end of the |
3970 | * conversion buffer for this. */ |
3971 | fromlen = len + ip->bw_restlen; |
3972 | fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; |
3973 | memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); |
3974 | memmove(fp + ip->bw_restlen, buf, (size_t)len); |
3975 | from = fp; |
3976 | tolen = ip->bw_conv_buflen - fromlen; |
3977 | } else { |
3978 | from = (const char *)buf; |
3979 | fromlen = len; |
3980 | tolen = ip->bw_conv_buflen; |
3981 | } |
3982 | to = (char *)ip->bw_conv_buf; |
3983 | |
3984 | if (ip->bw_first) { |
3985 | size_t save_len = tolen; |
3986 | |
3987 | /* output the initial shift state sequence */ |
3988 | (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen); |
3989 | |
3990 | /* There is a bug in iconv() on Linux (which appears to be |
3991 | * wide-spread) which sets "to" to NULL and messes up "tolen". |
3992 | */ |
3993 | if (to == NULL) { |
3994 | to = (char *)ip->bw_conv_buf; |
3995 | tolen = save_len; |
3996 | } |
3997 | ip->bw_first = FALSE; |
3998 | } |
3999 | |
4000 | /* |
4001 | * If iconv() has an error or there is not enough room, fail. |
4002 | */ |
4003 | if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen) |
4004 | == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) |
4005 | || fromlen > CONV_RESTLEN) { |
4006 | ip->bw_conv_error = TRUE; |
4007 | return FAIL; |
4008 | } |
4009 | |
4010 | /* copy remainder to ip->bw_rest[] to be used for the next call. */ |
4011 | if (fromlen > 0) |
4012 | memmove(ip->bw_rest, (void *)from, fromlen); |
4013 | ip->bw_restlen = (int)fromlen; |
4014 | |
4015 | buf = ip->bw_conv_buf; |
4016 | len = (int)((char_u *)to - ip->bw_conv_buf); |
4017 | } |
4018 | # endif |
4019 | } |
4020 | |
4021 | if (ip->bw_fd < 0) { |
4022 | // Only checking conversion, which is OK if we get here. |
4023 | return OK; |
4024 | } |
4025 | wlen = write_eintr(ip->bw_fd, buf, len); |
4026 | return (wlen < len) ? FAIL : OK; |
4027 | } |
4028 | |
4029 | /// Convert a Unicode character to bytes. |
4030 | /// |
4031 | /// @param c character to convert |
4032 | /// @param[in,out] pp pointer to store the result at |
4033 | /// @param flags FIO_ flags that specify which encoding to use |
4034 | /// |
4035 | /// @return true for an error, false when it's OK. |
4036 | static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL |
4037 | { |
4038 | char_u *p = *pp; |
4039 | bool error = false; |
4040 | int cc; |
4041 | |
4042 | |
4043 | if (flags & FIO_UCS4) { |
4044 | if (flags & FIO_ENDIAN_L) { |
4045 | *p++ = c; |
4046 | *p++ = (c >> 8); |
4047 | *p++ = (c >> 16); |
4048 | *p++ = (c >> 24); |
4049 | } else { |
4050 | *p++ = (c >> 24); |
4051 | *p++ = (c >> 16); |
4052 | *p++ = (c >> 8); |
4053 | *p++ = c; |
4054 | } |
4055 | } else if (flags & (FIO_UCS2 | FIO_UTF16)) { |
4056 | if (c >= 0x10000) { |
4057 | if (flags & FIO_UTF16) { |
4058 | /* Make two words, ten bits of the character in each. First |
4059 | * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */ |
4060 | c -= 0x10000; |
4061 | if (c >= 0x100000) { |
4062 | error = true; |
4063 | } |
4064 | cc = ((c >> 10) & 0x3ff) + 0xd800; |
4065 | if (flags & FIO_ENDIAN_L) { |
4066 | *p++ = cc; |
4067 | *p++ = ((unsigned)cc >> 8); |
4068 | } else { |
4069 | *p++ = ((unsigned)cc >> 8); |
4070 | *p++ = cc; |
4071 | } |
4072 | c = (c & 0x3ff) + 0xdc00; |
4073 | } else { |
4074 | error = true; |
4075 | } |
4076 | } |
4077 | if (flags & FIO_ENDIAN_L) { |
4078 | *p++ = c; |
4079 | *p++ = (c >> 8); |
4080 | } else { |
4081 | *p++ = (c >> 8); |
4082 | *p++ = c; |
4083 | } |
4084 | } else { /* Latin1 */ |
4085 | if (c >= 0x100) { |
4086 | error = true; |
4087 | *p++ = 0xBF; |
4088 | } else |
4089 | *p++ = c; |
4090 | } |
4091 | |
4092 | *pp = p; |
4093 | return error; |
4094 | } |
4095 | |
4096 | /// Return true if file encoding "fenc" requires conversion from or to |
4097 | /// 'encoding'. |
4098 | /// |
4099 | /// @param fenc file encoding to check |
4100 | /// |
4101 | /// @return true if conversion is required |
4102 | static bool need_conversion(const char_u *fenc) |
4103 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT |
4104 | { |
4105 | int same_encoding; |
4106 | int enc_flags; |
4107 | int fenc_flags; |
4108 | |
4109 | if (*fenc == NUL || STRCMP(p_enc, fenc) == 0) { |
4110 | same_encoding = TRUE; |
4111 | fenc_flags = 0; |
4112 | } else { |
4113 | /* Ignore difference between "ansi" and "latin1", "ucs-4" and |
4114 | * "ucs-4be", etc. */ |
4115 | enc_flags = get_fio_flags(p_enc); |
4116 | fenc_flags = get_fio_flags(fenc); |
4117 | same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); |
4118 | } |
4119 | if (same_encoding) { |
4120 | // Specified file encoding matches UTF-8. |
4121 | return false; |
4122 | } |
4123 | |
4124 | /* Encodings differ. However, conversion is not needed when 'enc' is any |
4125 | * Unicode encoding and the file is UTF-8. */ |
4126 | return !(enc_utf8 && fenc_flags == FIO_UTF8); |
4127 | } |
4128 | |
4129 | /// Return the FIO_ flags needed for the internal conversion if 'name' was |
4130 | /// unicode or latin1, otherwise 0. If "name" is an empty string, |
4131 | /// use 'encoding'. |
4132 | /// |
4133 | /// @param name string to check for encoding |
4134 | static int get_fio_flags(const char_u *name) |
4135 | { |
4136 | int prop; |
4137 | |
4138 | if (*name == NUL) { |
4139 | name = p_enc; |
4140 | } |
4141 | prop = enc_canon_props(name); |
4142 | if (prop & ENC_UNICODE) { |
4143 | if (prop & ENC_2BYTE) { |
4144 | if (prop & ENC_ENDIAN_L) |
4145 | return FIO_UCS2 | FIO_ENDIAN_L; |
4146 | return FIO_UCS2; |
4147 | } |
4148 | if (prop & ENC_4BYTE) { |
4149 | if (prop & ENC_ENDIAN_L) |
4150 | return FIO_UCS4 | FIO_ENDIAN_L; |
4151 | return FIO_UCS4; |
4152 | } |
4153 | if (prop & ENC_2WORD) { |
4154 | if (prop & ENC_ENDIAN_L) |
4155 | return FIO_UTF16 | FIO_ENDIAN_L; |
4156 | return FIO_UTF16; |
4157 | } |
4158 | return FIO_UTF8; |
4159 | } |
4160 | if (prop & ENC_LATIN1) |
4161 | return FIO_LATIN1; |
4162 | /* must be ENC_DBCS, requires iconv() */ |
4163 | return 0; |
4164 | } |
4165 | |
4166 | |
4167 | |
4168 | /* |
4169 | * Check for a Unicode BOM (Byte Order Mark) at the start of p[size]. |
4170 | * "size" must be at least 2. |
4171 | * Return the name of the encoding and set "*lenp" to the length. |
4172 | * Returns NULL when no BOM found. |
4173 | */ |
4174 | static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags) |
4175 | { |
4176 | char *name = NULL; |
4177 | int len = 2; |
4178 | |
4179 | if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf |
4180 | && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0)) { |
4181 | name = "utf-8" ; /* EF BB BF */ |
4182 | len = 3; |
4183 | } else if (p[0] == 0xff && p[1] == 0xfe) { |
4184 | if (size >= 4 && p[2] == 0 && p[3] == 0 |
4185 | && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L))) { |
4186 | name = "ucs-4le" ; /* FF FE 00 00 */ |
4187 | len = 4; |
4188 | } else if (flags == (FIO_UCS2 | FIO_ENDIAN_L)) |
4189 | name = "ucs-2le" ; /* FF FE */ |
4190 | else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L)) |
4191 | /* utf-16le is preferred, it also works for ucs-2le text */ |
4192 | name = "utf-16le" ; /* FF FE */ |
4193 | } else if (p[0] == 0xfe && p[1] == 0xff |
4194 | && (flags == FIO_ALL || flags == FIO_UCS2 || flags == |
4195 | FIO_UTF16)) { |
4196 | /* Default to utf-16, it works also for ucs-2 text. */ |
4197 | if (flags == FIO_UCS2) |
4198 | name = "ucs-2" ; /* FE FF */ |
4199 | else |
4200 | name = "utf-16" ; /* FE FF */ |
4201 | } else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe |
4202 | && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4)) { |
4203 | name = "ucs-4" ; /* 00 00 FE FF */ |
4204 | len = 4; |
4205 | } |
4206 | |
4207 | *lenp = len; |
4208 | return (char_u *)name; |
4209 | } |
4210 | |
4211 | /* |
4212 | * Generate a BOM in "buf[4]" for encoding "name". |
4213 | * Return the length of the BOM (zero when no BOM). |
4214 | */ |
4215 | static int make_bom(char_u *buf, char_u *name) |
4216 | { |
4217 | int flags; |
4218 | char_u *p; |
4219 | |
4220 | flags = get_fio_flags(name); |
4221 | |
4222 | /* Can't put a BOM in a non-Unicode file. */ |
4223 | if (flags == FIO_LATIN1 || flags == 0) |
4224 | return 0; |
4225 | |
4226 | if (flags == FIO_UTF8) { /* UTF-8 */ |
4227 | buf[0] = 0xef; |
4228 | buf[1] = 0xbb; |
4229 | buf[2] = 0xbf; |
4230 | return 3; |
4231 | } |
4232 | p = buf; |
4233 | (void)ucs2bytes(0xfeff, &p, flags); |
4234 | return (int)(p - buf); |
4235 | } |
4236 | |
4237 | /// Shorten filename of a buffer. |
4238 | /// When "force" is TRUE: Use full path from now on for files currently being |
4239 | /// edited, both for file name and swap file name. Try to shorten the file |
4240 | /// names a bit, if safe to do so. |
4241 | /// When "force" is FALSE: Only try to shorten absolute file names. |
4242 | /// For buffers that have buftype "nofile" or "scratch": never change the file |
4243 | /// name. |
4244 | void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) |
4245 | { |
4246 | char_u *p; |
4247 | |
4248 | if (buf->b_fname != NULL |
4249 | && !bt_nofile(buf) |
4250 | && !path_with_url((char *)buf->b_fname) |
4251 | && (force |
4252 | || buf->b_sfname == NULL |
4253 | || path_is_absolute(buf->b_sfname))) { |
4254 | XFREE_CLEAR(buf->b_sfname); |
4255 | p = path_shorten_fname(buf->b_ffname, dirname); |
4256 | if (p != NULL) { |
4257 | buf->b_sfname = vim_strsave(p); |
4258 | buf->b_fname = buf->b_sfname; |
4259 | } |
4260 | if (p == NULL) { |
4261 | buf->b_fname = buf->b_ffname; |
4262 | } |
4263 | } |
4264 | } |
4265 | |
4266 | /// Shorten filenames for all buffers. |
4267 | void shorten_fnames(int force) |
4268 | { |
4269 | char_u dirname[MAXPATHL]; |
4270 | |
4271 | os_dirname(dirname, MAXPATHL); |
4272 | FOR_ALL_BUFFERS(buf) { |
4273 | shorten_buf_fname(buf, dirname, force); |
4274 | |
4275 | // Always make the swap file name a full path, a "nofile" buffer may |
4276 | // also have a swap file. |
4277 | mf_fullname(buf->b_ml.ml_mfp); |
4278 | } |
4279 | status_redraw_all(); |
4280 | redraw_tabline = TRUE; |
4281 | } |
4282 | |
4283 | /// Get new filename ended by given extension. |
4284 | /// |
4285 | /// @param fname The original filename. |
4286 | /// If NULL, use current directory name and ext to |
4287 | /// compute new filename. |
4288 | /// @param ext The extension to add to the filename. |
4289 | /// 4 chars max if prefixed with a dot, 3 otherwise. |
4290 | /// @param prepend_dot If true, prefix ext with a dot. |
4291 | /// Does nothing if ext already starts with a dot, or |
4292 | /// if fname is NULL. |
4293 | /// |
4294 | /// @return [allocated] - A new filename, made up from: |
4295 | /// * fname + ext, if fname not NULL. |
4296 | /// * current dir + ext, if fname is NULL. |
4297 | /// Result is guaranteed to: |
4298 | /// * be ended by <ext>. |
4299 | /// * have a basename with at most BASENAMELEN chars: |
4300 | /// original basename is truncated if necessary. |
4301 | /// * be different than original: basename chars are |
4302 | /// replaced by "_" if necessary. If that can't be done |
4303 | /// because truncated value of original filename was |
4304 | /// made of all underscores, replace first "_" by "v". |
4305 | /// - NULL, if fname is NULL and there was a problem trying |
4306 | /// to get current directory. |
4307 | char *modname(const char *fname, const char *ext, bool prepend_dot) |
4308 | FUNC_ATTR_NONNULL_ARG(2) |
4309 | { |
4310 | char *retval; |
4311 | size_t fnamelen; |
4312 | size_t extlen = strlen(ext); |
4313 | |
4314 | // If there is no file name we must get the name of the current directory |
4315 | // (we need the full path in case :cd is used). |
4316 | if (fname == NULL || *fname == NUL) { |
4317 | retval = xmalloc(MAXPATHL + extlen + 3); // +3 for PATHSEP, "_" (Win), NUL |
4318 | if (os_dirname((char_u *)retval, MAXPATHL) == FAIL |
4319 | || (fnamelen = strlen(retval)) == 0) { |
4320 | xfree(retval); |
4321 | return NULL; |
4322 | } |
4323 | add_pathsep(retval); |
4324 | fnamelen = strlen(retval); |
4325 | prepend_dot = FALSE; // nothing to prepend a dot to |
4326 | } else { |
4327 | fnamelen = strlen(fname); |
4328 | retval = xmalloc(fnamelen + extlen + 3); |
4329 | strcpy(retval, fname); |
4330 | } |
4331 | |
4332 | // Search backwards until we hit a '/', '\' or ':'. |
4333 | // Then truncate what is after the '/', '\' or ':' to BASENAMELEN characters. |
4334 | char *ptr = NULL; |
4335 | for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr)) { |
4336 | if (vim_ispathsep(*ptr)) { |
4337 | ptr++; |
4338 | break; |
4339 | } |
4340 | } |
4341 | |
4342 | // the file name has at most BASENAMELEN characters. |
4343 | if (strlen(ptr) > BASENAMELEN) { |
4344 | ptr[BASENAMELEN] = '\0'; |
4345 | } |
4346 | |
4347 | char *s; |
4348 | s = ptr + strlen(ptr); |
4349 | |
4350 | // Append the extension. |
4351 | // ext can start with '.' and cannot exceed 3 more characters. |
4352 | strcpy(s, ext); |
4353 | |
4354 | char *e; |
4355 | // Prepend the dot if needed. |
4356 | if (prepend_dot && *(e = (char *)path_tail((char_u *)retval)) != '.') { |
4357 | STRMOVE(e + 1, e); |
4358 | *e = '.'; |
4359 | } |
4360 | |
4361 | // Check that, after appending the extension, the file name is really |
4362 | // different. |
4363 | if (fname != NULL && strcmp(fname, retval) == 0) { |
4364 | // we search for a character that can be replaced by '_' |
4365 | while (--s >= ptr) { |
4366 | if (*s != '_') { |
4367 | *s = '_'; |
4368 | break; |
4369 | } |
4370 | } |
4371 | if (s < ptr) { // fname was "________.<ext>", how tricky! |
4372 | *ptr = 'v'; |
4373 | } |
4374 | } |
4375 | return retval; |
4376 | } |
4377 | |
4378 | /// Like fgets(), but if the file line is too long, it is truncated and the |
4379 | /// rest of the line is thrown away. |
4380 | /// |
4381 | /// @param[out] buf buffer to fill |
4382 | /// @param size size of the buffer |
4383 | /// @param fp file to read from |
4384 | /// |
4385 | /// @return true for EOF or error |
4386 | bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL |
4387 | { |
4388 | char *retval; |
4389 | |
4390 | assert(size > 0); |
4391 | buf[size - 2] = NUL; |
4392 | |
4393 | do { |
4394 | errno = 0; |
4395 | retval = fgets((char *)buf, size, fp); |
4396 | } while (retval == NULL && errno == EINTR && ferror(fp)); |
4397 | |
4398 | if (buf[size - 2] != NUL && buf[size - 2] != '\n') { |
4399 | char tbuf[200]; |
4400 | |
4401 | buf[size - 1] = NUL; // Truncate the line. |
4402 | |
4403 | // Now throw away the rest of the line: |
4404 | do { |
4405 | tbuf[sizeof(tbuf) - 2] = NUL; |
4406 | errno = 0; |
4407 | retval = fgets((char *)tbuf, sizeof(tbuf), fp); |
4408 | if (retval == NULL && (feof(fp) || errno != EINTR)) { |
4409 | break; |
4410 | } |
4411 | } while (tbuf[sizeof(tbuf) - 2] != NUL && tbuf[sizeof(tbuf) - 2] != '\n'); |
4412 | } |
4413 | return retval == NULL; |
4414 | } |
4415 | |
4416 | /// Read 2 bytes from "fd" and turn them into an int, MSB first. |
4417 | /// Returns -1 when encountering EOF. |
4418 | int get2c(FILE *fd) |
4419 | { |
4420 | const int n = getc(fd); |
4421 | if (n == EOF) { |
4422 | return -1; |
4423 | } |
4424 | const int c = getc(fd); |
4425 | if (c == EOF) { |
4426 | return -1; |
4427 | } |
4428 | return (n << 8) + c; |
4429 | } |
4430 | |
4431 | /// Read 3 bytes from "fd" and turn them into an int, MSB first. |
4432 | /// Returns -1 when encountering EOF. |
4433 | int get3c(FILE *fd) |
4434 | { |
4435 | int n = getc(fd); |
4436 | if (n == EOF) { |
4437 | return -1; |
4438 | } |
4439 | int c = getc(fd); |
4440 | if (c == EOF) { |
4441 | return -1; |
4442 | } |
4443 | n = (n << 8) + c; |
4444 | c = getc(fd); |
4445 | if (c == EOF) { |
4446 | return -1; |
4447 | } |
4448 | return (n << 8) + c; |
4449 | } |
4450 | |
4451 | /// Read 4 bytes from "fd" and turn them into an int, MSB first. |
4452 | /// Returns -1 when encountering EOF. |
4453 | int get4c(FILE *fd) |
4454 | { |
4455 | // Use unsigned rather than int otherwise result is undefined |
4456 | // when left-shift sets the MSB. |
4457 | unsigned n; |
4458 | |
4459 | int c = getc(fd); |
4460 | if (c == EOF) { |
4461 | return -1; |
4462 | } |
4463 | n = (unsigned)c; |
4464 | c = getc(fd); |
4465 | if (c == EOF) { |
4466 | return -1; |
4467 | } |
4468 | n = (n << 8) + (unsigned)c; |
4469 | c = getc(fd); |
4470 | if (c == EOF) { |
4471 | return -1; |
4472 | } |
4473 | n = (n << 8) + (unsigned)c; |
4474 | c = getc(fd); |
4475 | if (c == EOF) { |
4476 | return -1; |
4477 | } |
4478 | n = (n << 8) + (unsigned)c; |
4479 | return (int)n; |
4480 | } |
4481 | |
4482 | /// Read 8 bytes from `fd` and turn them into a time_t, MSB first. |
4483 | /// Returns -1 when encountering EOF. |
4484 | time_t get8ctime(FILE *fd) |
4485 | { |
4486 | time_t n = 0; |
4487 | |
4488 | for (int i = 0; i < 8; i++) { |
4489 | const int c = getc(fd); |
4490 | if (c == EOF) { |
4491 | return -1; |
4492 | } |
4493 | n = (n << 8) + c; |
4494 | } |
4495 | return n; |
4496 | } |
4497 | |
4498 | /// Reads a string of length "cnt" from "fd" into allocated memory. |
4499 | /// @return pointer to the string or NULL when unable to read that many bytes. |
4500 | char *read_string(FILE *fd, size_t cnt) |
4501 | { |
4502 | char *str = xmallocz(cnt); |
4503 | for (size_t i = 0; i < cnt; i++) { |
4504 | int c = getc(fd); |
4505 | if (c == EOF) { |
4506 | xfree(str); |
4507 | return NULL; |
4508 | } |
4509 | str[i] = (char)c; |
4510 | } |
4511 | return str; |
4512 | } |
4513 | |
4514 | /// Writes a number to file "fd", most significant bit first, in "len" bytes. |
4515 | /// @returns false in case of an error. |
4516 | bool put_bytes(FILE *fd, uintmax_t number, size_t len) |
4517 | { |
4518 | assert(len > 0); |
4519 | for (size_t i = len - 1; i < len; i--) { |
4520 | if (putc((int)(number >> (i * 8)), fd) == EOF) { |
4521 | return false; |
4522 | } |
4523 | } |
4524 | return true; |
4525 | } |
4526 | |
4527 | /// Writes time_t to file "fd" in 8 bytes. |
4528 | /// @returns FAIL when the write failed. |
4529 | int put_time(FILE *fd, time_t time_) |
4530 | { |
4531 | uint8_t buf[8]; |
4532 | time_to_bytes(time_, buf); |
4533 | return fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd) == 1 ? OK : FAIL; |
4534 | } |
4535 | |
4536 | /// os_rename() only works if both files are on the same file system, this |
4537 | /// function will (attempts to?) copy the file across if rename fails -- webb |
4538 | /// |
4539 | /// @return -1 for failure, 0 for success |
4540 | int vim_rename(const char_u *from, const char_u *to) |
4541 | FUNC_ATTR_NONNULL_ALL |
4542 | { |
4543 | int fd_in; |
4544 | int fd_out; |
4545 | int n; |
4546 | char *errmsg = NULL; |
4547 | char *buffer; |
4548 | long perm; |
4549 | #ifdef HAVE_ACL |
4550 | vim_acl_T acl; /* ACL from original file */ |
4551 | #endif |
4552 | bool use_tmp_file = false; |
4553 | |
4554 | /* |
4555 | * When the names are identical, there is nothing to do. When they refer |
4556 | * to the same file (ignoring case and slash/backslash differences) but |
4557 | * the file name differs we need to go through a temp file. |
4558 | */ |
4559 | if (fnamecmp(from, to) == 0) { |
4560 | if (p_fic && (STRCMP(path_tail((char_u *)from), path_tail((char_u *)to)) |
4561 | != 0)) { |
4562 | use_tmp_file = true; |
4563 | } else { |
4564 | return 0; |
4565 | } |
4566 | } |
4567 | |
4568 | // Fail if the "from" file doesn't exist. Avoids that "to" is deleted. |
4569 | FileInfo from_info; |
4570 | if (!os_fileinfo((char *)from, &from_info)) { |
4571 | return -1; |
4572 | } |
4573 | |
4574 | // It's possible for the source and destination to be the same file. |
4575 | // This happens when "from" and "to" differ in case and are on a FAT32 |
4576 | // filesystem. In that case go through a temp file name. |
4577 | FileInfo to_info; |
4578 | if (os_fileinfo((char *)to, &to_info) |
4579 | && os_fileinfo_id_equal(&from_info, &to_info)) { |
4580 | use_tmp_file = true; |
4581 | } |
4582 | |
4583 | if (use_tmp_file) { |
4584 | char_u tempname[MAXPATHL + 1]; |
4585 | |
4586 | /* |
4587 | * Find a name that doesn't exist and is in the same directory. |
4588 | * Rename "from" to "tempname" and then rename "tempname" to "to". |
4589 | */ |
4590 | if (STRLEN(from) >= MAXPATHL - 5) |
4591 | return -1; |
4592 | STRCPY(tempname, from); |
4593 | for (n = 123; n < 99999; n++) { |
4594 | char * tail = (char *)path_tail(tempname); |
4595 | snprintf(tail, (MAXPATHL + 1) - (tail - (char *)tempname - 1), "%d" , n); |
4596 | |
4597 | if (!os_path_exists(tempname)) { |
4598 | if (os_rename(from, tempname) == OK) { |
4599 | if (os_rename(tempname, to) == OK) |
4600 | return 0; |
4601 | /* Strange, the second step failed. Try moving the |
4602 | * file back and return failure. */ |
4603 | os_rename(tempname, from); |
4604 | return -1; |
4605 | } |
4606 | /* If it fails for one temp name it will most likely fail |
4607 | * for any temp name, give up. */ |
4608 | return -1; |
4609 | } |
4610 | } |
4611 | return -1; |
4612 | } |
4613 | |
4614 | /* |
4615 | * Delete the "to" file, this is required on some systems to make the |
4616 | * os_rename() work, on other systems it makes sure that we don't have |
4617 | * two files when the os_rename() fails. |
4618 | */ |
4619 | |
4620 | os_remove((char *)to); |
4621 | |
4622 | /* |
4623 | * First try a normal rename, return if it works. |
4624 | */ |
4625 | if (os_rename(from, to) == OK) |
4626 | return 0; |
4627 | |
4628 | /* |
4629 | * Rename() failed, try copying the file. |
4630 | */ |
4631 | perm = os_getperm((const char *)from); |
4632 | #ifdef HAVE_ACL |
4633 | // For systems that support ACL: get the ACL from the original file. |
4634 | acl = mch_get_acl(from); |
4635 | #endif |
4636 | fd_in = os_open((char *)from, O_RDONLY, 0); |
4637 | if (fd_in < 0) { |
4638 | #ifdef HAVE_ACL |
4639 | mch_free_acl(acl); |
4640 | #endif |
4641 | return -1; |
4642 | } |
4643 | |
4644 | /* Create the new file with same permissions as the original. */ |
4645 | fd_out = os_open((char *)to, |
4646 | O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); |
4647 | if (fd_out < 0) { |
4648 | close(fd_in); |
4649 | #ifdef HAVE_ACL |
4650 | mch_free_acl(acl); |
4651 | #endif |
4652 | return -1; |
4653 | } |
4654 | |
4655 | // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim |
4656 | // is `preserve_exit()`ing. |
4657 | buffer = try_malloc(BUFSIZE); |
4658 | if (buffer == NULL) { |
4659 | close(fd_out); |
4660 | close(fd_in); |
4661 | #ifdef HAVE_ACL |
4662 | mch_free_acl(acl); |
4663 | #endif |
4664 | return -1; |
4665 | } |
4666 | |
4667 | while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0) |
4668 | if (write_eintr(fd_out, buffer, n) != n) { |
4669 | errmsg = _("E208: Error writing to \"%s\"" ); |
4670 | break; |
4671 | } |
4672 | |
4673 | xfree(buffer); |
4674 | close(fd_in); |
4675 | if (close(fd_out) < 0) |
4676 | errmsg = _("E209: Error closing \"%s\"" ); |
4677 | if (n < 0) { |
4678 | errmsg = _("E210: Error reading \"%s\"" ); |
4679 | to = from; |
4680 | } |
4681 | #ifndef UNIX // For Unix os_open() already set the permission. |
4682 | os_setperm((const char *)to, perm); |
4683 | #endif |
4684 | #ifdef HAVE_ACL |
4685 | mch_set_acl(to, acl); |
4686 | mch_free_acl(acl); |
4687 | #endif |
4688 | if (errmsg != NULL) { |
4689 | EMSG2(errmsg, to); |
4690 | return -1; |
4691 | } |
4692 | os_remove((char *)from); |
4693 | return 0; |
4694 | } |
4695 | |
4696 | static int already_warned = FALSE; |
4697 | |
4698 | // Check if any not hidden buffer has been changed. |
4699 | // Postpone the check if there are characters in the stuff buffer, a global |
4700 | // command is being executed, a mapping is being executed or an autocommand is |
4701 | // busy. |
4702 | // Returns TRUE if some message was written (screen should be redrawn and |
4703 | // cursor positioned). |
4704 | int |
4705 | check_timestamps( |
4706 | int focus // called for GUI focus event |
4707 | ) |
4708 | { |
4709 | int didit = 0; |
4710 | int n; |
4711 | |
4712 | /* Don't check timestamps while system() or another low-level function may |
4713 | * cause us to lose and gain focus. */ |
4714 | if (no_check_timestamps > 0) |
4715 | return FALSE; |
4716 | |
4717 | /* Avoid doing a check twice. The OK/Reload dialog can cause a focus |
4718 | * event and we would keep on checking if the file is steadily growing. |
4719 | * Do check again after typing something. */ |
4720 | if (focus && did_check_timestamps) { |
4721 | need_check_timestamps = TRUE; |
4722 | return FALSE; |
4723 | } |
4724 | |
4725 | if (!stuff_empty() || global_busy || !typebuf_typed() |
4726 | || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0 |
4727 | ) { |
4728 | need_check_timestamps = true; // check later |
4729 | } else { |
4730 | no_wait_return++; |
4731 | did_check_timestamps = true; |
4732 | already_warned = false; |
4733 | FOR_ALL_BUFFERS(buf) { |
4734 | // Only check buffers in a window. |
4735 | if (buf->b_nwindows > 0) { |
4736 | bufref_T bufref; |
4737 | set_bufref(&bufref, buf); |
4738 | n = buf_check_timestamp(buf, focus); |
4739 | if (didit < n) { |
4740 | didit = n; |
4741 | } |
4742 | if (n > 0 && !bufref_valid(&bufref)) { |
4743 | // Autocommands have removed the buffer, start at the first one again. |
4744 | buf = firstbuf; |
4745 | continue; |
4746 | } |
4747 | } |
4748 | } |
4749 | --no_wait_return; |
4750 | need_check_timestamps = FALSE; |
4751 | if (need_wait_return && didit == 2) { |
4752 | // make sure msg isn't overwritten |
4753 | msg_puts("\n" ); |
4754 | ui_flush(); |
4755 | } |
4756 | } |
4757 | return didit; |
4758 | } |
4759 | |
4760 | /* |
4761 | * Move all the lines from buffer "frombuf" to buffer "tobuf". |
4762 | * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not |
4763 | * empty. |
4764 | */ |
4765 | static int move_lines(buf_T *frombuf, buf_T *tobuf) |
4766 | { |
4767 | buf_T *tbuf = curbuf; |
4768 | int retval = OK; |
4769 | linenr_T lnum; |
4770 | char_u *p; |
4771 | |
4772 | /* Copy the lines in "frombuf" to "tobuf". */ |
4773 | curbuf = tobuf; |
4774 | for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { |
4775 | p = vim_strsave(ml_get_buf(frombuf, lnum, false)); |
4776 | if (ml_append(lnum - 1, p, 0, false) == FAIL) { |
4777 | xfree(p); |
4778 | retval = FAIL; |
4779 | break; |
4780 | } |
4781 | xfree(p); |
4782 | } |
4783 | |
4784 | /* Delete all the lines in "frombuf". */ |
4785 | if (retval != FAIL) { |
4786 | curbuf = frombuf; |
4787 | for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { |
4788 | if (ml_delete(lnum, false) == FAIL) { |
4789 | // Oops! We could try putting back the saved lines, but that |
4790 | // might fail again... |
4791 | retval = FAIL; |
4792 | break; |
4793 | } |
4794 | } |
4795 | } |
4796 | |
4797 | curbuf = tbuf; |
4798 | return retval; |
4799 | } |
4800 | |
4801 | /* |
4802 | * Check if buffer "buf" has been changed. |
4803 | * Also check if the file for a new buffer unexpectedly appeared. |
4804 | * return 1 if a changed buffer was found. |
4805 | * return 2 if a message has been displayed. |
4806 | * return 0 otherwise. |
4807 | */ |
4808 | int |
4809 | buf_check_timestamp( |
4810 | buf_T *buf, |
4811 | int focus /* called for GUI focus event */ |
4812 | ) |
4813 | FUNC_ATTR_NONNULL_ALL |
4814 | { |
4815 | int retval = 0; |
4816 | char_u *path; |
4817 | char *mesg = NULL; |
4818 | char *mesg2 = "" ; |
4819 | bool helpmesg = false; |
4820 | bool reload = false; |
4821 | bool can_reload = false; |
4822 | uint64_t orig_size = buf->b_orig_size; |
4823 | int orig_mode = buf->b_orig_mode; |
4824 | static bool busy = false; |
4825 | char_u *s; |
4826 | char *reason; |
4827 | |
4828 | bufref_T bufref; |
4829 | set_bufref(&bufref, buf); |
4830 | |
4831 | // If its a terminal, there is no file name, the buffer is not loaded, |
4832 | // 'buftype' is set, we are in the middle of a save or being called |
4833 | // recursively: ignore this buffer. |
4834 | if (buf->terminal |
4835 | || buf->b_ffname == NULL |
4836 | || buf->b_ml.ml_mfp == NULL |
4837 | || *buf->b_p_bt != NUL |
4838 | || buf->b_saving |
4839 | || busy |
4840 | ) |
4841 | return 0; |
4842 | |
4843 | FileInfo file_info; |
4844 | bool file_info_ok; |
4845 | if (!(buf->b_flags & BF_NOTEDITED) |
4846 | && buf->b_mtime != 0 |
4847 | && (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info)) |
4848 | || time_differs(file_info.stat.st_mtim.tv_sec, buf->b_mtime) |
4849 | || (int)file_info.stat.st_mode != buf->b_orig_mode)) { |
4850 | const long prev_b_mtime = buf->b_mtime; |
4851 | |
4852 | retval = 1; |
4853 | |
4854 | // set b_mtime to stop further warnings (e.g., when executing |
4855 | // FileChangedShell autocmd) |
4856 | if (!file_info_ok) { |
4857 | // Check the file again later to see if it re-appears. |
4858 | buf->b_mtime = -1; |
4859 | buf->b_orig_size = 0; |
4860 | buf->b_orig_mode = 0; |
4861 | } else { |
4862 | buf_store_file_info(buf, &file_info); |
4863 | } |
4864 | |
4865 | /* Don't do anything for a directory. Might contain the file |
4866 | * explorer. */ |
4867 | if (os_isdir(buf->b_fname)) { |
4868 | } else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar) |
4869 | && !bufIsChanged(buf) && file_info_ok) { |
4870 | // If 'autoread' is set, the buffer has no changes and the file still |
4871 | // exists, reload the buffer. Use the buffer-local option value if it |
4872 | // was set, the global option value otherwise. |
4873 | reload = true; |
4874 | } else { |
4875 | if (!file_info_ok) { |
4876 | reason = "deleted" ; |
4877 | } else if (bufIsChanged(buf)) { |
4878 | reason = "conflict" ; |
4879 | } else if (orig_size != buf->b_orig_size || buf_contents_changed(buf)) { |
4880 | reason = "changed" ; |
4881 | } else if (orig_mode != buf->b_orig_mode) { |
4882 | reason = "mode" ; |
4883 | } else { |
4884 | reason = "time" ; |
4885 | } |
4886 | |
4887 | // Only give the warning if there are no FileChangedShell |
4888 | // autocommands. |
4889 | // Avoid being called recursively by setting "busy". |
4890 | busy = true; |
4891 | set_vim_var_string(VV_FCS_REASON, reason, -1); |
4892 | set_vim_var_string(VV_FCS_CHOICE, "" , -1); |
4893 | allbuf_lock++; |
4894 | bool n = apply_autocmds(EVENT_FILECHANGEDSHELL, |
4895 | buf->b_fname, buf->b_fname, false, buf); |
4896 | allbuf_lock--; |
4897 | busy = false; |
4898 | if (n) { |
4899 | if (!bufref_valid(&bufref)) { |
4900 | EMSG(_("E246: FileChangedShell autocommand deleted buffer" )); |
4901 | } |
4902 | s = get_vim_var_str(VV_FCS_CHOICE); |
4903 | if (STRCMP(s, "reload" ) == 0 && *reason != 'd') { |
4904 | reload = true; |
4905 | } else if (STRCMP(s, "ask" ) == 0) { |
4906 | n = false; |
4907 | } else { |
4908 | return 2; |
4909 | } |
4910 | } |
4911 | if (!n) { |
4912 | if (*reason == 'd') { |
4913 | // Only give the message once. |
4914 | if (prev_b_mtime != -1) { |
4915 | mesg = _("E211: File \"%s\" no longer available" ); |
4916 | } |
4917 | } else { |
4918 | helpmesg = true; |
4919 | can_reload = true; |
4920 | |
4921 | // Check if the file contents really changed to avoid |
4922 | // giving a warning when only the timestamp was set (e.g., |
4923 | // checked out of CVS). Always warn when the buffer was |
4924 | // changed. |
4925 | if (reason[2] == 'n') { |
4926 | mesg = _( |
4927 | "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well" ); |
4928 | mesg2 = _("See \":help W12\" for more info." ); |
4929 | } else if (reason[1] == 'h') { |
4930 | mesg = _( |
4931 | "W11: Warning: File \"%s\" has changed since editing started" ); |
4932 | mesg2 = _("See \":help W11\" for more info." ); |
4933 | } else if (*reason == 'm') { |
4934 | mesg = _( |
4935 | "W16: Warning: Mode of file \"%s\" has changed since editing started" ); |
4936 | mesg2 = _("See \":help W16\" for more info." ); |
4937 | } else |
4938 | /* Only timestamp changed, store it to avoid a warning |
4939 | * in check_mtime() later. */ |
4940 | buf->b_mtime_read = buf->b_mtime; |
4941 | } |
4942 | } |
4943 | } |
4944 | |
4945 | } else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W) |
4946 | && os_path_exists(buf->b_ffname)) { |
4947 | retval = 1; |
4948 | mesg = _("W13: Warning: File \"%s\" has been created after editing started" ); |
4949 | buf->b_flags |= BF_NEW_W; |
4950 | can_reload = true; |
4951 | } |
4952 | |
4953 | if (mesg != NULL) { |
4954 | path = home_replace_save(buf, buf->b_fname); |
4955 | if (!helpmesg) { |
4956 | mesg2 = "" ; |
4957 | } |
4958 | const size_t tbuf_len = STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2; |
4959 | char *const tbuf = xmalloc(tbuf_len); |
4960 | snprintf(tbuf, tbuf_len, mesg, path); |
4961 | // Set warningmsg here, before the unimportant and output-specific |
4962 | // mesg2 has been appended. |
4963 | set_vim_var_string(VV_WARNINGMSG, tbuf, -1); |
4964 | if (can_reload) { |
4965 | if (*mesg2 != NUL) { |
4966 | xstrlcat(tbuf, "\n" , tbuf_len - 1); |
4967 | xstrlcat(tbuf, mesg2, tbuf_len - 1); |
4968 | } |
4969 | if (do_dialog(VIM_WARNING, (char_u *) _("Warning" ), (char_u *) tbuf, |
4970 | (char_u *) _("&OK\n&Load File" ), 1, NULL, true) == 2) { |
4971 | reload = true; |
4972 | } |
4973 | } else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) { |
4974 | if (*mesg2 != NUL) { |
4975 | xstrlcat(tbuf, "; " , tbuf_len - 1); |
4976 | xstrlcat(tbuf, mesg2, tbuf_len - 1); |
4977 | } |
4978 | EMSG(tbuf); |
4979 | retval = 2; |
4980 | } else { |
4981 | if (!autocmd_busy) { |
4982 | msg_start(); |
4983 | msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST); |
4984 | if (*mesg2 != NUL) { |
4985 | msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST); |
4986 | } |
4987 | msg_clr_eos(); |
4988 | (void)msg_end(); |
4989 | if (emsg_silent == 0) { |
4990 | ui_flush(); |
4991 | /* give the user some time to think about it */ |
4992 | os_delay(1000L, true); |
4993 | |
4994 | /* don't redraw and erase the message */ |
4995 | redraw_cmdline = FALSE; |
4996 | } |
4997 | } |
4998 | already_warned = TRUE; |
4999 | } |
5000 | |
5001 | xfree(path); |
5002 | xfree(tbuf); |
5003 | } |
5004 | |
5005 | if (reload) { |
5006 | /* Reload the buffer. */ |
5007 | buf_reload(buf, orig_mode); |
5008 | if (buf->b_p_udf && buf->b_ffname != NULL) { |
5009 | char_u hash[UNDO_HASH_SIZE]; |
5010 | buf_T *save_curbuf = curbuf; |
5011 | |
5012 | /* Any existing undo file is unusable, write it now. */ |
5013 | curbuf = buf; |
5014 | u_compute_hash(hash); |
5015 | u_write_undo(NULL, FALSE, buf, hash); |
5016 | curbuf = save_curbuf; |
5017 | } |
5018 | } |
5019 | |
5020 | // Trigger FileChangedShell when the file was changed in any way. |
5021 | if (bufref_valid(&bufref) && retval != 0) { |
5022 | (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST, buf->b_fname, buf->b_fname, |
5023 | false, buf); |
5024 | } |
5025 | return retval; |
5026 | } |
5027 | |
5028 | /* |
5029 | * Reload a buffer that is already loaded. |
5030 | * Used when the file was changed outside of Vim. |
5031 | * "orig_mode" is buf->b_orig_mode before the need for reloading was detected. |
5032 | * buf->b_orig_mode may have been reset already. |
5033 | */ |
5034 | void buf_reload(buf_T *buf, int orig_mode) |
5035 | { |
5036 | exarg_T ea; |
5037 | pos_T old_cursor; |
5038 | linenr_T old_topline; |
5039 | int old_ro = buf->b_p_ro; |
5040 | buf_T *savebuf; |
5041 | bufref_T bufref; |
5042 | int saved = OK; |
5043 | aco_save_T aco; |
5044 | int flags = READ_NEW; |
5045 | |
5046 | /* set curwin/curbuf for "buf" and save some things */ |
5047 | aucmd_prepbuf(&aco, buf); |
5048 | |
5049 | // We only want to read the text from the file, not reset the syntax |
5050 | // highlighting, clear marks, diff status, etc. Force the fileformat and |
5051 | // encoding to be the same. |
5052 | |
5053 | prep_exarg(&ea, buf); |
5054 | old_cursor = curwin->w_cursor; |
5055 | old_topline = curwin->w_topline; |
5056 | |
5057 | if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { |
5058 | /* Save all the text, so that the reload can be undone. |
5059 | * Sync first so that this is a separate undo-able action. */ |
5060 | u_sync(FALSE); |
5061 | saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE); |
5062 | flags |= READ_KEEP_UNDO; |
5063 | } |
5064 | |
5065 | // To behave like when a new file is edited (matters for |
5066 | // BufReadPost autocommands) we first need to delete the current |
5067 | // buffer contents. But if reading the file fails we should keep |
5068 | // the old contents. Can't use memory only, the file might be |
5069 | // too big. Use a hidden buffer to move the buffer contents to. |
5070 | if (BUFEMPTY() || saved == FAIL) { |
5071 | savebuf = NULL; |
5072 | } else { |
5073 | // Allocate a buffer without putting it in the buffer list. |
5074 | savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); |
5075 | set_bufref(&bufref, savebuf); |
5076 | if (savebuf != NULL && buf == curbuf) { |
5077 | /* Open the memline. */ |
5078 | curbuf = savebuf; |
5079 | curwin->w_buffer = savebuf; |
5080 | saved = ml_open(curbuf); |
5081 | curbuf = buf; |
5082 | curwin->w_buffer = buf; |
5083 | } |
5084 | if (savebuf == NULL || saved == FAIL || buf != curbuf |
5085 | || move_lines(buf, savebuf) == FAIL) { |
5086 | EMSG2(_("E462: Could not prepare for reloading \"%s\"" ), |
5087 | buf->b_fname); |
5088 | saved = FAIL; |
5089 | } |
5090 | } |
5091 | |
5092 | if (saved == OK) { |
5093 | curbuf->b_flags |= BF_CHECK_RO; // check for RO again |
5094 | keep_filetype = true; // don't detect 'filetype' |
5095 | if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0, (linenr_T)0, |
5096 | (linenr_T)MAXLNUM, &ea, flags) != OK) { |
5097 | if (!aborting()) { |
5098 | EMSG2(_("E321: Could not reload \"%s\"" ), buf->b_fname); |
5099 | } |
5100 | if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf) { |
5101 | // Put the text back from the save buffer. First |
5102 | // delete any lines that readfile() added. |
5103 | while (!BUFEMPTY()) { |
5104 | if (ml_delete(buf->b_ml.ml_line_count, false) == FAIL) { |
5105 | break; |
5106 | } |
5107 | } |
5108 | (void)move_lines(savebuf, buf); |
5109 | } |
5110 | } else if (buf == curbuf) { // "buf" still valid. |
5111 | // Mark the buffer as unmodified and free undo info. |
5112 | unchanged(buf, true, true); |
5113 | if ((flags & READ_KEEP_UNDO) == 0) { |
5114 | u_blockfree(buf); |
5115 | u_clearall(buf); |
5116 | } else { |
5117 | // Mark all undo states as changed. |
5118 | u_unchanged(curbuf); |
5119 | } |
5120 | } |
5121 | } |
5122 | xfree(ea.cmd); |
5123 | |
5124 | if (savebuf != NULL && bufref_valid(&bufref)) { |
5125 | wipe_buffer(savebuf, false); |
5126 | } |
5127 | |
5128 | /* Invalidate diff info if necessary. */ |
5129 | diff_invalidate(curbuf); |
5130 | |
5131 | /* Restore the topline and cursor position and check it (lines may |
5132 | * have been removed). */ |
5133 | if (old_topline > curbuf->b_ml.ml_line_count) |
5134 | curwin->w_topline = curbuf->b_ml.ml_line_count; |
5135 | else |
5136 | curwin->w_topline = old_topline; |
5137 | curwin->w_cursor = old_cursor; |
5138 | check_cursor(); |
5139 | update_topline(); |
5140 | keep_filetype = FALSE; |
5141 | |
5142 | /* Update folds unless they are defined manually. */ |
5143 | FOR_ALL_TAB_WINDOWS(tp, wp) { |
5144 | if (wp->w_buffer == curwin->w_buffer |
5145 | && !foldmethodIsManual(wp)) { |
5146 | foldUpdateAll(wp); |
5147 | } |
5148 | } |
5149 | |
5150 | /* If the mode didn't change and 'readonly' was set, keep the old |
5151 | * value; the user probably used the ":view" command. But don't |
5152 | * reset it, might have had a read error. */ |
5153 | if (orig_mode == curbuf->b_orig_mode) |
5154 | curbuf->b_p_ro |= old_ro; |
5155 | |
5156 | /* Modelines must override settings done by autocommands. */ |
5157 | do_modelines(0); |
5158 | |
5159 | /* restore curwin/curbuf and a few other things */ |
5160 | aucmd_restbuf(&aco); |
5161 | /* Careful: autocommands may have made "buf" invalid! */ |
5162 | } |
5163 | |
5164 | void buf_store_file_info(buf_T *buf, FileInfo *file_info) |
5165 | FUNC_ATTR_NONNULL_ALL |
5166 | { |
5167 | buf->b_mtime = file_info->stat.st_mtim.tv_sec; |
5168 | buf->b_orig_size = os_fileinfo_size(file_info); |
5169 | buf->b_orig_mode = (int)file_info->stat.st_mode; |
5170 | } |
5171 | |
5172 | /* |
5173 | * Adjust the line with missing eol, used for the next write. |
5174 | * Used for do_filter(), when the input lines for the filter are deleted. |
5175 | */ |
5176 | void write_lnum_adjust(linenr_T offset) |
5177 | { |
5178 | if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */ |
5179 | curbuf->b_no_eol_lnum += offset; |
5180 | } |
5181 | |
5182 | #if defined(BACKSLASH_IN_FILENAME) |
5183 | /// Convert all backslashes in fname to forward slashes in-place, |
5184 | /// unless when it looks like a URL. |
5185 | void forward_slash(char_u *fname) |
5186 | { |
5187 | char_u *p; |
5188 | |
5189 | if (path_with_url((const char *)fname)) { |
5190 | return; |
5191 | } |
5192 | for (p = fname; *p != NUL; p++) { |
5193 | // The Big5 encoding can have '\' in the trail byte. |
5194 | if (*p == '\\') { |
5195 | *p = '/'; |
5196 | } |
5197 | } |
5198 | } |
5199 | #endif |
5200 | |
5201 | /// Name of Vim's own temp dir. Ends in a slash. |
5202 | static char_u *vim_tempdir = NULL; |
5203 | |
5204 | /// Create a directory for private use by this instance of Neovim. |
5205 | /// This is done once, and the same directory is used for all temp files. |
5206 | /// This method avoids security problems because of symlink attacks et al. |
5207 | /// It's also a bit faster, because we only need to check for an existing |
5208 | /// file when creating the directory and not for each temp file. |
5209 | static void vim_maketempdir(void) |
5210 | { |
5211 | static const char *temp_dirs[] = TEMP_DIR_NAMES; |
5212 | // Try the entries in `TEMP_DIR_NAMES` to create the temp directory. |
5213 | char_u template[TEMP_FILE_PATH_MAXLEN]; |
5214 | char_u path[TEMP_FILE_PATH_MAXLEN]; |
5215 | |
5216 | // Make sure the umask doesn't remove the executable bit. |
5217 | // "repl" has been reported to use "0177". |
5218 | mode_t umask_save = umask(0077); |
5219 | for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); i++) { |
5220 | // Expand environment variables, leave room for "/nvimXXXXXX/999999999" |
5221 | expand_env((char_u *)temp_dirs[i], template, TEMP_FILE_PATH_MAXLEN - 22); |
5222 | if (!os_isdir(template)) { // directory doesn't exist |
5223 | continue; |
5224 | } |
5225 | |
5226 | add_pathsep((char *)template); |
5227 | // Concatenate with temporary directory name pattern |
5228 | STRCAT(template, "nvimXXXXXX" ); |
5229 | |
5230 | if (os_mkdtemp((const char *)template, (char *)path) != 0) { |
5231 | continue; |
5232 | } |
5233 | |
5234 | if (vim_settempdir((char *)path)) { |
5235 | // Successfully created and set temporary directory so stop trying. |
5236 | break; |
5237 | } else { |
5238 | // Couldn't set `vim_tempdir` to `path` so remove created directory. |
5239 | os_rmdir((char *)path); |
5240 | } |
5241 | } |
5242 | (void)umask(umask_save); |
5243 | } |
5244 | |
5245 | /// Delete "name" and everything in it, recursively. |
5246 | /// @param name The path which should be deleted. |
5247 | /// @return 0 for success, -1 if some file was not deleted. |
5248 | int delete_recursive(const char *name) |
5249 | { |
5250 | int result = 0; |
5251 | |
5252 | if (os_isrealdir(name)) { |
5253 | snprintf((char *)NameBuff, MAXPATHL, "%s/*" , name); // NOLINT |
5254 | |
5255 | char_u **files; |
5256 | int file_count; |
5257 | char_u *exp = vim_strsave(NameBuff); |
5258 | if (gen_expand_wildcards(1, &exp, &file_count, &files, |
5259 | EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS |
5260 | | EW_DODOT | EW_EMPTYOK) == OK) { |
5261 | for (int i = 0; i < file_count; i++) { |
5262 | if (delete_recursive((const char *)files[i]) != 0) { |
5263 | result = -1; |
5264 | } |
5265 | } |
5266 | FreeWild(file_count, files); |
5267 | } else { |
5268 | result = -1; |
5269 | } |
5270 | |
5271 | xfree(exp); |
5272 | os_rmdir(name); |
5273 | } else { |
5274 | result = os_remove(name) == 0 ? 0 : -1; |
5275 | } |
5276 | |
5277 | return result; |
5278 | } |
5279 | |
5280 | /// Delete the temp directory and all files it contains. |
5281 | void vim_deltempdir(void) |
5282 | { |
5283 | if (vim_tempdir != NULL) { |
5284 | // remove the trailing path separator |
5285 | path_tail(vim_tempdir)[-1] = NUL; |
5286 | delete_recursive((const char *)vim_tempdir); |
5287 | XFREE_CLEAR(vim_tempdir); |
5288 | } |
5289 | } |
5290 | |
5291 | /// Get the name of temp directory. This directory would be created on the first |
5292 | /// call to this function. |
5293 | char_u *vim_gettempdir(void) |
5294 | { |
5295 | if (vim_tempdir == NULL) { |
5296 | vim_maketempdir(); |
5297 | } |
5298 | |
5299 | return vim_tempdir; |
5300 | } |
5301 | |
5302 | /// Set Neovim own temporary directory name to `tempdir`. This directory should |
5303 | /// be already created. Expand this name to a full path and put it in |
5304 | /// `vim_tempdir`. This avoids that using `:cd` would confuse us. |
5305 | /// |
5306 | /// @param tempdir must be no longer than MAXPATHL. |
5307 | /// |
5308 | /// @return false if we run out of memory. |
5309 | static bool vim_settempdir(char *tempdir) |
5310 | { |
5311 | char *buf = verbose_try_malloc(MAXPATHL + 2); |
5312 | if (!buf) { |
5313 | return false; |
5314 | } |
5315 | vim_FullName(tempdir, buf, MAXPATHL, false); |
5316 | add_pathsep(buf); |
5317 | vim_tempdir = (char_u *)xstrdup(buf); |
5318 | xfree(buf); |
5319 | return true; |
5320 | } |
5321 | |
5322 | /// Return a unique name that can be used for a temp file. |
5323 | /// |
5324 | /// @note The temp file is NOT created. |
5325 | /// |
5326 | /// @return pointer to the temp file name or NULL if Neovim can't create |
5327 | /// temporary directory for its own temporary files. |
5328 | char_u *vim_tempname(void) |
5329 | { |
5330 | // Temp filename counter. |
5331 | static uint32_t temp_count; |
5332 | |
5333 | char_u *tempdir = vim_gettempdir(); |
5334 | if (!tempdir) { |
5335 | return NULL; |
5336 | } |
5337 | |
5338 | // There is no need to check if the file exists, because we own the directory |
5339 | // and nobody else creates a file in it. |
5340 | char_u template[TEMP_FILE_PATH_MAXLEN]; |
5341 | snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, |
5342 | "%s%" PRIu32, tempdir, temp_count++); |
5343 | return vim_strsave(template); |
5344 | } |
5345 | |
5346 | |
5347 | /* |
5348 | * Code for automatic commands. |
5349 | */ |
5350 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
5351 | # include "auevents_name_map.generated.h" |
5352 | #endif |
5353 | |
5354 | static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */ |
5355 | |
5356 | /// List of autocmd group names |
5357 | static garray_T augroups = { 0, 0, sizeof(char_u *), 10, NULL }; |
5358 | #define AUGROUP_NAME(i) (((char **)augroups.ga_data)[i]) |
5359 | |
5360 | /* |
5361 | * The ID of the current group. Group 0 is the default one. |
5362 | */ |
5363 | static int current_augroup = AUGROUP_DEFAULT; |
5364 | |
5365 | static int au_need_clean = FALSE; /* need to delete marked patterns */ |
5366 | |
5367 | |
5368 | |
5369 | static event_T last_event; |
5370 | static int last_group; |
5371 | static int autocmd_blocked = 0; /* block all autocmds */ |
5372 | |
5373 | // use get_deleted_augroup() to get this |
5374 | static const char *deleted_augroup = NULL; |
5375 | |
5376 | static inline const char *get_deleted_augroup(void) |
5377 | FUNC_ATTR_ALWAYS_INLINE |
5378 | { |
5379 | if (deleted_augroup == NULL) { |
5380 | deleted_augroup = _("--Deleted--" ); |
5381 | } |
5382 | return deleted_augroup; |
5383 | } |
5384 | |
5385 | /* |
5386 | * Show the autocommands for one AutoPat. |
5387 | */ |
5388 | static void show_autocmd(AutoPat *ap, event_T event) |
5389 | { |
5390 | AutoCmd *ac; |
5391 | |
5392 | /* Check for "got_int" (here and at various places below), which is set |
5393 | * when "q" has been hit for the "--more--" prompt */ |
5394 | if (got_int) |
5395 | return; |
5396 | if (ap->pat == NULL) /* pattern has been removed */ |
5397 | return; |
5398 | |
5399 | msg_putchar('\n'); |
5400 | if (got_int) |
5401 | return; |
5402 | if (event != last_event || ap->group != last_group) { |
5403 | if (ap->group != AUGROUP_DEFAULT) { |
5404 | if (AUGROUP_NAME(ap->group) == NULL) { |
5405 | msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E)); |
5406 | } else { |
5407 | msg_puts_attr(AUGROUP_NAME(ap->group), HL_ATTR(HLF_T)); |
5408 | } |
5409 | msg_puts(" " ); |
5410 | } |
5411 | msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T)); |
5412 | last_event = event; |
5413 | last_group = ap->group; |
5414 | msg_putchar('\n'); |
5415 | if (got_int) |
5416 | return; |
5417 | } |
5418 | msg_col = 4; |
5419 | msg_outtrans(ap->pat); |
5420 | |
5421 | for (ac = ap->cmds; ac != NULL; ac = ac->next) { |
5422 | if (ac->cmd == NULL) { /* skip removed commands */ |
5423 | continue; |
5424 | } |
5425 | if (msg_col >= 14) { |
5426 | msg_putchar('\n'); |
5427 | } |
5428 | msg_col = 14; |
5429 | if (got_int) { |
5430 | return; |
5431 | } |
5432 | msg_outtrans(ac->cmd); |
5433 | if (p_verbose > 0) { |
5434 | last_set_msg(ac->script_ctx); |
5435 | } |
5436 | if (got_int) { |
5437 | return; |
5438 | } |
5439 | if (ac->next != NULL) { |
5440 | msg_putchar('\n'); |
5441 | if (got_int) { |
5442 | return; |
5443 | } |
5444 | } |
5445 | } |
5446 | } |
5447 | |
5448 | // Mark an autocommand handler for deletion. |
5449 | static void au_remove_pat(AutoPat *ap) |
5450 | { |
5451 | XFREE_CLEAR(ap->pat); |
5452 | ap->buflocal_nr = -1; |
5453 | au_need_clean = true; |
5454 | } |
5455 | |
5456 | // Mark all commands for a pattern for deletion. |
5457 | static void au_remove_cmds(AutoPat *ap) |
5458 | { |
5459 | for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) { |
5460 | XFREE_CLEAR(ac->cmd); |
5461 | } |
5462 | au_need_clean = true; |
5463 | } |
5464 | |
5465 | // Delete one command from an autocmd pattern. |
5466 | static void au_del_cmd(AutoCmd *ac) |
5467 | { |
5468 | XFREE_CLEAR(ac->cmd); |
5469 | au_need_clean = true; |
5470 | } |
5471 | |
5472 | /// Cleanup autocommands and patterns that have been deleted. |
5473 | /// This is only done when not executing autocommands. |
5474 | static void au_cleanup(void) |
5475 | { |
5476 | AutoPat *ap, **prev_ap; |
5477 | AutoCmd *ac, **prev_ac; |
5478 | event_T event; |
5479 | |
5480 | if (autocmd_busy || !au_need_clean) { |
5481 | return; |
5482 | } |
5483 | |
5484 | // Loop over all events. |
5485 | for (event = (event_T)0; (int)event < (int)NUM_EVENTS; |
5486 | event = (event_T)((int)event + 1)) { |
5487 | // Loop over all autocommand patterns. |
5488 | prev_ap = &(first_autopat[(int)event]); |
5489 | for (ap = *prev_ap; ap != NULL; ap = *prev_ap) { |
5490 | // Loop over all commands for this pattern. |
5491 | prev_ac = &(ap->cmds); |
5492 | bool has_cmd = false; |
5493 | |
5494 | for (ac = *prev_ac; ac != NULL; ac = *prev_ac) { |
5495 | // Remove the command if the pattern is to be deleted or when |
5496 | // the command has been marked for deletion. |
5497 | if (ap->pat == NULL || ac->cmd == NULL) { |
5498 | *prev_ac = ac->next; |
5499 | xfree(ac->cmd); |
5500 | xfree(ac); |
5501 | } else { |
5502 | has_cmd = true; |
5503 | prev_ac = &(ac->next); |
5504 | } |
5505 | } |
5506 | |
5507 | if (ap->pat != NULL && !has_cmd) { |
5508 | // Pattern was not marked for deletion, but all of its commands were. |
5509 | // So mark the pattern for deletion. |
5510 | au_remove_pat(ap); |
5511 | } |
5512 | |
5513 | // Remove the pattern if it has been marked for deletion. |
5514 | if (ap->pat == NULL) { |
5515 | if (ap->next == NULL) { |
5516 | if (prev_ap == &(first_autopat[(int)event])) { |
5517 | last_autopat[(int)event] = NULL; |
5518 | } else { |
5519 | // this depends on the "next" field being the first in |
5520 | // the struct |
5521 | last_autopat[(int)event] = (AutoPat *)prev_ap; |
5522 | } |
5523 | } |
5524 | *prev_ap = ap->next; |
5525 | vim_regfree(ap->reg_prog); |
5526 | xfree(ap); |
5527 | } else { |
5528 | prev_ap = &(ap->next); |
5529 | } |
5530 | } |
5531 | } |
5532 | |
5533 | au_need_clean = false; |
5534 | } |
5535 | |
5536 | /* |
5537 | * Called when buffer is freed, to remove/invalidate related buffer-local |
5538 | * autocmds. |
5539 | */ |
5540 | void aubuflocal_remove(buf_T *buf) |
5541 | { |
5542 | AutoPat *ap; |
5543 | event_T event; |
5544 | AutoPatCmd *apc; |
5545 | |
5546 | /* invalidate currently executing autocommands */ |
5547 | for (apc = active_apc_list; apc; apc = apc->next) |
5548 | if (buf->b_fnum == apc->arg_bufnr) |
5549 | apc->arg_bufnr = 0; |
5550 | |
5551 | /* invalidate buflocals looping through events */ |
5552 | for (event = (event_T)0; (int)event < (int)NUM_EVENTS; |
5553 | event = (event_T)((int)event + 1)) |
5554 | /* loop over all autocommand patterns */ |
5555 | for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) |
5556 | if (ap->buflocal_nr == buf->b_fnum) { |
5557 | au_remove_pat(ap); |
5558 | if (p_verbose >= 6) { |
5559 | verbose_enter(); |
5560 | smsg(_("auto-removing autocommand: %s <buffer=%d>" ), |
5561 | event_nr2name(event), buf->b_fnum); |
5562 | verbose_leave(); |
5563 | } |
5564 | } |
5565 | au_cleanup(); |
5566 | } |
5567 | |
5568 | // Add an autocmd group name. |
5569 | // Return its ID. Returns AUGROUP_ERROR (< 0) for error. |
5570 | static int au_new_group(char_u *name) |
5571 | { |
5572 | int i = au_find_group(name); |
5573 | if (i == AUGROUP_ERROR) { // the group doesn't exist yet, add it. |
5574 | // First try using a free entry. |
5575 | for (i = 0; i < augroups.ga_len; i++) { |
5576 | if (AUGROUP_NAME(i) == NULL) { |
5577 | break; |
5578 | } |
5579 | } |
5580 | if (i == augroups.ga_len) { |
5581 | ga_grow(&augroups, 1); |
5582 | } |
5583 | |
5584 | AUGROUP_NAME(i) = xstrdup((char *)name); |
5585 | if (i == augroups.ga_len) { |
5586 | augroups.ga_len++; |
5587 | } |
5588 | } |
5589 | |
5590 | return i; |
5591 | } |
5592 | |
5593 | static void au_del_group(char_u *name) |
5594 | { |
5595 | int i = au_find_group(name); |
5596 | if (i == AUGROUP_ERROR) { // the group doesn't exist |
5597 | EMSG2(_("E367: No such group: \"%s\"" ), name); |
5598 | } else if (i == current_augroup) { |
5599 | EMSG(_("E936: Cannot delete the current group" )); |
5600 | } else { |
5601 | event_T event; |
5602 | AutoPat *ap; |
5603 | int in_use = false; |
5604 | |
5605 | for (event = (event_T)0; (int)event < (int)NUM_EVENTS; |
5606 | event = (event_T)((int)event + 1)) { |
5607 | for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) { |
5608 | if (ap->group == i && ap->pat != NULL) { |
5609 | give_warning((char_u *) |
5610 | _("W19: Deleting augroup that is still in use" ), true); |
5611 | in_use = true; |
5612 | event = NUM_EVENTS; |
5613 | break; |
5614 | } |
5615 | } |
5616 | } |
5617 | xfree(AUGROUP_NAME(i)); |
5618 | if (in_use) { |
5619 | AUGROUP_NAME(i) = (char *)get_deleted_augroup(); |
5620 | } else { |
5621 | AUGROUP_NAME(i) = NULL; |
5622 | } |
5623 | } |
5624 | } |
5625 | |
5626 | /// Find the ID of an autocmd group name. |
5627 | /// |
5628 | /// @param name augroup name |
5629 | /// |
5630 | /// @return the ID or AUGROUP_ERROR (< 0) for error. |
5631 | static int au_find_group(const char_u *name) |
5632 | FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
5633 | { |
5634 | for (int i = 0; i < augroups.ga_len; i++) { |
5635 | if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup() |
5636 | && STRCMP(AUGROUP_NAME(i), name) == 0) { |
5637 | return i; |
5638 | } |
5639 | } |
5640 | return AUGROUP_ERROR; |
5641 | } |
5642 | |
5643 | /// Return true if augroup "name" exists. |
5644 | /// |
5645 | /// @param name augroup name |
5646 | bool au_has_group(const char_u *name) |
5647 | FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
5648 | { |
5649 | return au_find_group(name) != AUGROUP_ERROR; |
5650 | } |
5651 | |
5652 | /// ":augroup {name}". |
5653 | void do_augroup(char_u *arg, int del_group) |
5654 | { |
5655 | if (del_group) { |
5656 | if (*arg == NUL) { |
5657 | EMSG(_(e_argreq)); |
5658 | } else { |
5659 | au_del_group(arg); |
5660 | } |
5661 | } else if (STRICMP(arg, "end" ) == 0) { // ":aug end": back to group 0 |
5662 | current_augroup = AUGROUP_DEFAULT; |
5663 | } else if (*arg) { // ":aug xxx": switch to group xxx |
5664 | int i = au_new_group(arg); |
5665 | if (i != AUGROUP_ERROR) |
5666 | current_augroup = i; |
5667 | } else { // ":aug": list the group names |
5668 | msg_start(); |
5669 | for (int i = 0; i < augroups.ga_len; ++i) { |
5670 | if (AUGROUP_NAME(i) != NULL) { |
5671 | msg_puts(AUGROUP_NAME(i)); |
5672 | msg_puts(" " ); |
5673 | } |
5674 | } |
5675 | msg_clr_eos(); |
5676 | msg_end(); |
5677 | } |
5678 | } |
5679 | |
5680 | #if defined(EXITFREE) |
5681 | void free_all_autocmds(void) |
5682 | { |
5683 | for (current_augroup = -1; current_augroup < augroups.ga_len; |
5684 | current_augroup++) { |
5685 | do_autocmd((char_u *)"" , true); |
5686 | } |
5687 | |
5688 | for (int i = 0; i < augroups.ga_len; i++) { |
5689 | char *const s = ((char **)(augroups.ga_data))[i]; |
5690 | if ((const char *)s != get_deleted_augroup()) { |
5691 | xfree(s); |
5692 | } |
5693 | } |
5694 | ga_clear(&augroups); |
5695 | } |
5696 | #endif |
5697 | |
5698 | /* |
5699 | * Return the event number for event name "start". |
5700 | * Return NUM_EVENTS if the event name was not found. |
5701 | * Return a pointer to the next event name in "end". |
5702 | */ |
5703 | static event_T event_name2nr(const char_u *start, char_u **end) |
5704 | { |
5705 | const char_u *p; |
5706 | int i; |
5707 | int len; |
5708 | |
5709 | // the event name ends with end of line, '|', a blank or a comma |
5710 | for (p = start; *p && !ascii_iswhite(*p) && *p != ',' && *p != '|'; p++) { |
5711 | } |
5712 | for (i = 0; event_names[i].name != NULL; i++) { |
5713 | len = (int)event_names[i].len; |
5714 | if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0) { |
5715 | break; |
5716 | } |
5717 | } |
5718 | if (*p == ',') { |
5719 | p++; |
5720 | } |
5721 | *end = (char_u *)p; |
5722 | if (event_names[i].name == NULL) { |
5723 | return NUM_EVENTS; |
5724 | } |
5725 | return event_names[i].event; |
5726 | } |
5727 | |
5728 | /// Return the name for event |
5729 | /// |
5730 | /// @param[in] event Event to return name for. |
5731 | /// |
5732 | /// @return Event name, static string. Returns "Unknown" for unknown events. |
5733 | static const char *event_nr2name(event_T event) |
5734 | FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_CONST |
5735 | { |
5736 | int i; |
5737 | |
5738 | for (i = 0; event_names[i].name != NULL; i++) { |
5739 | if (event_names[i].event == event) { |
5740 | return event_names[i].name; |
5741 | } |
5742 | } |
5743 | return "Unknown" ; |
5744 | } |
5745 | |
5746 | /* |
5747 | * Scan over the events. "*" stands for all events. |
5748 | */ |
5749 | static char_u * |
5750 | find_end_event ( |
5751 | char_u *arg, |
5752 | int have_group /* TRUE when group name was found */ |
5753 | ) |
5754 | { |
5755 | char_u *pat; |
5756 | char_u *p; |
5757 | |
5758 | if (*arg == '*') { |
5759 | if (arg[1] && !ascii_iswhite(arg[1])) { |
5760 | EMSG2(_("E215: Illegal character after *: %s" ), arg); |
5761 | return NULL; |
5762 | } |
5763 | pat = arg + 1; |
5764 | } else { |
5765 | for (pat = arg; *pat && *pat != '|' && !ascii_iswhite(*pat); pat = p) { |
5766 | if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS) { |
5767 | if (have_group) |
5768 | EMSG2(_("E216: No such event: %s" ), pat); |
5769 | else |
5770 | EMSG2(_("E216: No such group or event: %s" ), pat); |
5771 | return NULL; |
5772 | } |
5773 | } |
5774 | } |
5775 | return pat; |
5776 | } |
5777 | |
5778 | /// Return true if "event" is included in 'eventignore'. |
5779 | /// |
5780 | /// @param event event to check |
5781 | static bool event_ignored(event_T event) |
5782 | FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
5783 | { |
5784 | char_u *p = p_ei; |
5785 | |
5786 | while (*p != NUL) { |
5787 | if (STRNICMP(p, "all" , 3) == 0 && (p[3] == NUL || p[3] == ',')) { |
5788 | return true; |
5789 | } |
5790 | if (event_name2nr(p, &p) == event) { |
5791 | return true; |
5792 | } |
5793 | } |
5794 | |
5795 | return false; |
5796 | } |
5797 | |
5798 | /* |
5799 | * Return OK when the contents of p_ei is valid, FAIL otherwise. |
5800 | */ |
5801 | int check_ei(void) |
5802 | { |
5803 | char_u *p = p_ei; |
5804 | |
5805 | while (*p) { |
5806 | if (STRNICMP(p, "all" , 3) == 0 && (p[3] == NUL || p[3] == ',')) { |
5807 | p += 3; |
5808 | if (*p == ',') |
5809 | ++p; |
5810 | } else if (event_name2nr(p, &p) == NUM_EVENTS) |
5811 | return FAIL; |
5812 | } |
5813 | |
5814 | return OK; |
5815 | } |
5816 | |
5817 | /* |
5818 | * Add "what" to 'eventignore' to skip loading syntax highlighting for every |
5819 | * buffer loaded into the window. "what" must start with a comma. |
5820 | * Returns the old value of 'eventignore' in allocated memory. |
5821 | */ |
5822 | char_u *au_event_disable(char *what) |
5823 | { |
5824 | char_u *new_ei; |
5825 | char_u *save_ei; |
5826 | |
5827 | save_ei = vim_strsave(p_ei); |
5828 | new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what))); |
5829 | if (*what == ',' && *p_ei == NUL) |
5830 | STRCPY(new_ei, what + 1); |
5831 | else |
5832 | STRCAT(new_ei, what); |
5833 | set_string_option_direct((char_u *)"ei" , -1, new_ei, OPT_FREE, SID_NONE); |
5834 | xfree(new_ei); |
5835 | |
5836 | return save_ei; |
5837 | } |
5838 | |
5839 | void au_event_restore(char_u *old_ei) |
5840 | { |
5841 | if (old_ei != NULL) { |
5842 | set_string_option_direct((char_u *)"ei" , -1, old_ei, |
5843 | OPT_FREE, SID_NONE); |
5844 | xfree(old_ei); |
5845 | } |
5846 | } |
5847 | |
5848 | // Implements :autocmd. |
5849 | // Defines an autocmd (does not execute; cf. apply_autocmds_group). |
5850 | // |
5851 | // Can be used in the following ways: |
5852 | // |
5853 | // :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that |
5854 | // will be automatically executed for <event> |
5855 | // when editing a file matching <pat>, in |
5856 | // the current group. |
5857 | // :autocmd <event> <pat> Show the autocommands associated with |
5858 | // <event> and <pat>. |
5859 | // :autocmd <event> Show the autocommands associated with |
5860 | // <event>. |
5861 | // :autocmd Show all autocommands. |
5862 | // :autocmd! <event> <pat> <cmd> Remove all autocommands associated with |
5863 | // <event> and <pat>, and add the command |
5864 | // <cmd>, for the current group. |
5865 | // :autocmd! <event> <pat> Remove all autocommands associated with |
5866 | // <event> and <pat> for the current group. |
5867 | // :autocmd! <event> Remove all autocommands associated with |
5868 | // <event> for the current group. |
5869 | // :autocmd! Remove ALL autocommands for the current |
5870 | // group. |
5871 | // |
5872 | // Multiple events and patterns may be given separated by commas. Here are |
5873 | // some examples: |
5874 | // :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic |
5875 | // :autocmd bufleave * set tw=79 nosmartindent ic infercase |
5876 | // |
5877 | // :autocmd * *.c show all autocommands for *.c files. |
5878 | // |
5879 | // Mostly a {group} argument can optionally appear before <event>. |
5880 | void do_autocmd(char_u *arg_in, int forceit) |
5881 | { |
5882 | char_u *arg = arg_in; |
5883 | char_u *pat; |
5884 | char_u *envpat = NULL; |
5885 | char_u *cmd; |
5886 | int need_free = false; |
5887 | int nested = false; |
5888 | bool once = false; |
5889 | int group; |
5890 | |
5891 | if (*arg == '|') { |
5892 | arg = (char_u *)"" ; |
5893 | group = AUGROUP_ALL; // no argument, use all groups |
5894 | } else { |
5895 | // Check for a legal group name. If not, use AUGROUP_ALL. |
5896 | group = au_get_grouparg(&arg); |
5897 | } |
5898 | |
5899 | /* |
5900 | * Scan over the events. |
5901 | * If we find an illegal name, return here, don't do anything. |
5902 | */ |
5903 | pat = find_end_event(arg, group != AUGROUP_ALL); |
5904 | if (pat == NULL) |
5905 | return; |
5906 | |
5907 | pat = skipwhite(pat); |
5908 | if (*pat == '|') { |
5909 | pat = (char_u *)"" ; |
5910 | cmd = (char_u *)"" ; |
5911 | } else { |
5912 | // Scan over the pattern. Put a NUL at the end. |
5913 | cmd = pat; |
5914 | while (*cmd && (!ascii_iswhite(*cmd) || cmd[-1] == '\\')) { |
5915 | cmd++; |
5916 | } |
5917 | if (*cmd) { |
5918 | *cmd++ = NUL; |
5919 | } |
5920 | |
5921 | // Expand environment variables in the pattern. Set 'shellslash', we want |
5922 | // forward slashes here. |
5923 | if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL) { |
5924 | #ifdef BACKSLASH_IN_FILENAME |
5925 | int p_ssl_save = p_ssl; |
5926 | |
5927 | p_ssl = true; |
5928 | #endif |
5929 | envpat = expand_env_save(pat); |
5930 | #ifdef BACKSLASH_IN_FILENAME |
5931 | p_ssl = p_ssl_save; |
5932 | #endif |
5933 | if (envpat != NULL) { |
5934 | pat = envpat; |
5935 | } |
5936 | } |
5937 | |
5938 | cmd = skipwhite(cmd); |
5939 | for (size_t i = 0; i < 2; i++) { |
5940 | if (*cmd != NUL) { |
5941 | // Check for "++once" flag. |
5942 | if (STRNCMP(cmd, "++once" , 6) == 0 && ascii_iswhite(cmd[6])) { |
5943 | if (once) { |
5944 | EMSG2(_(e_duparg2), "++once" ); |
5945 | } |
5946 | once = true; |
5947 | cmd = skipwhite(cmd + 6); |
5948 | } |
5949 | |
5950 | // Check for "++nested" flag. |
5951 | if ((STRNCMP(cmd, "++nested" , 8) == 0 && ascii_iswhite(cmd[8]))) { |
5952 | if (nested) { |
5953 | EMSG2(_(e_duparg2), "++nested" ); |
5954 | } |
5955 | nested = true; |
5956 | cmd = skipwhite(cmd + 8); |
5957 | } |
5958 | |
5959 | // Check for the old (deprecated) "nested" flag. |
5960 | if (STRNCMP(cmd, "nested" , 6) == 0 && ascii_iswhite(cmd[6])) { |
5961 | if (nested) { |
5962 | EMSG2(_(e_duparg2), "nested" ); |
5963 | } |
5964 | nested = true; |
5965 | cmd = skipwhite(cmd + 6); |
5966 | } |
5967 | } |
5968 | } |
5969 | |
5970 | // Find the start of the commands. |
5971 | // Expand <sfile> in it. |
5972 | if (*cmd != NUL) { |
5973 | cmd = expand_sfile(cmd); |
5974 | if (cmd == NULL) { // some error |
5975 | return; |
5976 | } |
5977 | need_free = true; |
5978 | } |
5979 | } |
5980 | |
5981 | /* |
5982 | * Print header when showing autocommands. |
5983 | */ |
5984 | if (!forceit && *cmd == NUL) { |
5985 | // Highlight title |
5986 | MSG_PUTS_TITLE(_("\n--- Autocommands ---" )); |
5987 | } |
5988 | |
5989 | /* |
5990 | * Loop over the events. |
5991 | */ |
5992 | last_event = (event_T)-1; // for listing the event name |
5993 | last_group = AUGROUP_ERROR; // for listing the group name |
5994 | if (*arg == '*' || *arg == NUL || *arg == '|') { |
5995 | for (event_T event = (event_T)0; (int)event < (int)NUM_EVENTS; |
5996 | event = (event_T)((int)event + 1)) { |
5997 | if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group) |
5998 | == FAIL) { |
5999 | break; |
6000 | } |
6001 | } |
6002 | } else { |
6003 | while (*arg && *arg != '|' && !ascii_iswhite(*arg)) { |
6004 | event_T event = event_name2nr(arg, &arg); |
6005 | assert(event < NUM_EVENTS); |
6006 | if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group) |
6007 | == FAIL) { |
6008 | break; |
6009 | } |
6010 | } |
6011 | } |
6012 | |
6013 | if (need_free) |
6014 | xfree(cmd); |
6015 | xfree(envpat); |
6016 | } |
6017 | |
6018 | /* |
6019 | * Find the group ID in a ":autocmd" or ":doautocmd" argument. |
6020 | * The "argp" argument is advanced to the following argument. |
6021 | * |
6022 | * Returns the group ID or AUGROUP_ALL. |
6023 | */ |
6024 | static int au_get_grouparg(char_u **argp) |
6025 | { |
6026 | char_u *group_name; |
6027 | char_u *p; |
6028 | char_u *arg = *argp; |
6029 | int group = AUGROUP_ALL; |
6030 | |
6031 | for (p = arg; *p && !ascii_iswhite(*p) && *p != '|'; p++) { |
6032 | } |
6033 | if (p > arg) { |
6034 | group_name = vim_strnsave(arg, (int)(p - arg)); |
6035 | group = au_find_group(group_name); |
6036 | if (group == AUGROUP_ERROR) |
6037 | group = AUGROUP_ALL; /* no match, use all groups */ |
6038 | else |
6039 | *argp = skipwhite(p); /* match, skip over group name */ |
6040 | xfree(group_name); |
6041 | } |
6042 | return group; |
6043 | } |
6044 | |
6045 | // do_autocmd() for one event. |
6046 | // Defines an autocmd (does not execute; cf. apply_autocmds_group). |
6047 | // |
6048 | // If *pat == NUL: do for all patterns. |
6049 | // If *cmd == NUL: show entries. |
6050 | // If forceit == TRUE: delete entries. |
6051 | // If group is not AUGROUP_ALL: only use this group. |
6052 | static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, |
6053 | char_u *cmd, int forceit, int group) |
6054 | { |
6055 | AutoPat *ap; |
6056 | AutoPat **prev_ap; |
6057 | AutoCmd *ac; |
6058 | AutoCmd **prev_ac; |
6059 | int brace_level; |
6060 | char_u *endpat; |
6061 | int findgroup; |
6062 | int allgroups; |
6063 | int patlen; |
6064 | int is_buflocal; |
6065 | int buflocal_nr; |
6066 | char_u buflocal_pat[25]; /* for "<buffer=X>" */ |
6067 | |
6068 | if (group == AUGROUP_ALL) |
6069 | findgroup = current_augroup; |
6070 | else |
6071 | findgroup = group; |
6072 | allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL); |
6073 | |
6074 | /* |
6075 | * Show or delete all patterns for an event. |
6076 | */ |
6077 | if (*pat == NUL) { |
6078 | for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) { |
6079 | if (forceit) { /* delete the AutoPat, if it's in the current group */ |
6080 | if (ap->group == findgroup) |
6081 | au_remove_pat(ap); |
6082 | } else if (group == AUGROUP_ALL || ap->group == group) |
6083 | show_autocmd(ap, event); |
6084 | } |
6085 | } |
6086 | |
6087 | /* |
6088 | * Loop through all the specified patterns. |
6089 | */ |
6090 | for (; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) { |
6091 | /* |
6092 | * Find end of the pattern. |
6093 | * Watch out for a comma in braces, like "*.\{obj,o\}". |
6094 | */ |
6095 | endpat = pat; |
6096 | // ignore single comma |
6097 | if (*endpat == ',') { |
6098 | continue; |
6099 | } |
6100 | brace_level = 0; |
6101 | for (; *endpat && (*endpat != ',' || brace_level || endpat[-1] == '\\'); |
6102 | ++endpat) { |
6103 | if (*endpat == '{') |
6104 | brace_level++; |
6105 | else if (*endpat == '}') |
6106 | brace_level--; |
6107 | } |
6108 | patlen = (int)(endpat - pat); |
6109 | |
6110 | /* |
6111 | * detect special <buflocal[=X]> buffer-local patterns |
6112 | */ |
6113 | is_buflocal = FALSE; |
6114 | buflocal_nr = 0; |
6115 | |
6116 | if (patlen >= 8 && STRNCMP(pat, "<buffer" , 7) == 0 |
6117 | && pat[patlen - 1] == '>') { |
6118 | /* "<buffer...>": Error will be printed only for addition. |
6119 | * printing and removing will proceed silently. */ |
6120 | is_buflocal = TRUE; |
6121 | if (patlen == 8) |
6122 | /* "<buffer>" */ |
6123 | buflocal_nr = curbuf->b_fnum; |
6124 | else if (patlen > 9 && pat[7] == '=') { |
6125 | if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>" , 13) == 0) |
6126 | /* "<buffer=abuf>" */ |
6127 | buflocal_nr = autocmd_bufnr; |
6128 | else if (skipdigits(pat + 8) == pat + patlen - 1) |
6129 | /* "<buffer=123>" */ |
6130 | buflocal_nr = atoi((char *)pat + 8); |
6131 | } |
6132 | } |
6133 | |
6134 | if (is_buflocal) { |
6135 | /* normalize pat into standard "<buffer>#N" form */ |
6136 | sprintf((char *)buflocal_pat, "<buffer=%d>" , buflocal_nr); |
6137 | pat = buflocal_pat; /* can modify pat and patlen */ |
6138 | patlen = (int)STRLEN(buflocal_pat); /* but not endpat */ |
6139 | } |
6140 | |
6141 | // Find AutoPat entries with this pattern. When adding a command it |
6142 | // always goes at or after the last one, so start at the end. |
6143 | if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) { |
6144 | prev_ap = &last_autopat[(int)event]; |
6145 | } else { |
6146 | prev_ap = &first_autopat[(int)event]; |
6147 | } |
6148 | while ((ap = *prev_ap) != NULL) { |
6149 | if (ap->pat != NULL) { |
6150 | /* Accept a pattern when: |
6151 | * - a group was specified and it's that group, or a group was |
6152 | * not specified and it's the current group, or a group was |
6153 | * not specified and we are listing |
6154 | * - the length of the pattern matches |
6155 | * - the pattern matches. |
6156 | * For <buffer[=X]>, this condition works because we normalize |
6157 | * all buffer-local patterns. |
6158 | */ |
6159 | if ((allgroups || ap->group == findgroup) |
6160 | && ap->patlen == patlen |
6161 | && STRNCMP(pat, ap->pat, patlen) == 0) { |
6162 | /* |
6163 | * Remove existing autocommands. |
6164 | * If adding any new autocmd's for this AutoPat, don't |
6165 | * delete the pattern from the autopat list, append to |
6166 | * this list. |
6167 | */ |
6168 | if (forceit) { |
6169 | if (*cmd != NUL && ap->next == NULL) { |
6170 | au_remove_cmds(ap); |
6171 | break; |
6172 | } |
6173 | au_remove_pat(ap); |
6174 | } |
6175 | /* |
6176 | * Show autocmd's for this autopat, or buflocals <buffer=X> |
6177 | */ |
6178 | else if (*cmd == NUL) |
6179 | show_autocmd(ap, event); |
6180 | |
6181 | /* |
6182 | * Add autocmd to this autopat, if it's the last one. |
6183 | */ |
6184 | else if (ap->next == NULL) |
6185 | break; |
6186 | } |
6187 | } |
6188 | prev_ap = &ap->next; |
6189 | } |
6190 | |
6191 | /* |
6192 | * Add a new command. |
6193 | */ |
6194 | if (*cmd != NUL) { |
6195 | /* |
6196 | * If the pattern we want to add a command to does appear at the |
6197 | * end of the list (or not is not in the list at all), add the |
6198 | * pattern at the end of the list. |
6199 | */ |
6200 | if (ap == NULL) { |
6201 | /* refuse to add buffer-local ap if buffer number is invalid */ |
6202 | if (is_buflocal && (buflocal_nr == 0 |
6203 | || buflist_findnr(buflocal_nr) == NULL)) { |
6204 | emsgf(_("E680: <buffer=%d>: invalid buffer number " ), |
6205 | buflocal_nr); |
6206 | return FAIL; |
6207 | } |
6208 | |
6209 | ap = xmalloc(sizeof(AutoPat)); |
6210 | ap->pat = vim_strnsave(pat, patlen); |
6211 | ap->patlen = patlen; |
6212 | |
6213 | if (is_buflocal) { |
6214 | ap->buflocal_nr = buflocal_nr; |
6215 | ap->reg_prog = NULL; |
6216 | } else { |
6217 | char_u *reg_pat; |
6218 | |
6219 | ap->buflocal_nr = 0; |
6220 | reg_pat = file_pat_to_reg_pat(pat, endpat, |
6221 | &ap->allow_dirs, TRUE); |
6222 | if (reg_pat != NULL) |
6223 | ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC); |
6224 | xfree(reg_pat); |
6225 | if (reg_pat == NULL || ap->reg_prog == NULL) { |
6226 | xfree(ap->pat); |
6227 | xfree(ap); |
6228 | return FAIL; |
6229 | } |
6230 | } |
6231 | ap->cmds = NULL; |
6232 | *prev_ap = ap; |
6233 | last_autopat[(int)event] = ap; |
6234 | ap->next = NULL; |
6235 | if (group == AUGROUP_ALL) |
6236 | ap->group = current_augroup; |
6237 | else |
6238 | ap->group = group; |
6239 | } |
6240 | |
6241 | /* |
6242 | * Add the autocmd at the end of the AutoCmd list. |
6243 | */ |
6244 | prev_ac = &(ap->cmds); |
6245 | while ((ac = *prev_ac) != NULL) |
6246 | prev_ac = &ac->next; |
6247 | ac = xmalloc(sizeof(AutoCmd)); |
6248 | ac->cmd = vim_strsave(cmd); |
6249 | ac->script_ctx = current_sctx; |
6250 | ac->script_ctx.sc_lnum += sourcing_lnum; |
6251 | ac->next = NULL; |
6252 | *prev_ac = ac; |
6253 | ac->once = once; |
6254 | ac->nested = nested; |
6255 | } |
6256 | } |
6257 | |
6258 | au_cleanup(); /* may really delete removed patterns/commands now */ |
6259 | return OK; |
6260 | } |
6261 | |
6262 | // Implementation of ":doautocmd [group] event [fname]". |
6263 | // Return OK for success, FAIL for failure; |
6264 | int |
6265 | do_doautocmd( |
6266 | char_u *arg, |
6267 | int do_msg, // give message for no matching autocmds? |
6268 | bool *did_something |
6269 | ) |
6270 | { |
6271 | char_u *fname; |
6272 | int nothing_done = TRUE; |
6273 | int group; |
6274 | |
6275 | if (did_something != NULL) { |
6276 | *did_something = false; |
6277 | } |
6278 | |
6279 | /* |
6280 | * Check for a legal group name. If not, use AUGROUP_ALL. |
6281 | */ |
6282 | group = au_get_grouparg(&arg); |
6283 | |
6284 | if (*arg == '*') { |
6285 | EMSG(_("E217: Can't execute autocommands for ALL events" )); |
6286 | return FAIL; |
6287 | } |
6288 | |
6289 | /* |
6290 | * Scan over the events. |
6291 | * If we find an illegal name, return here, don't do anything. |
6292 | */ |
6293 | fname = find_end_event(arg, group != AUGROUP_ALL); |
6294 | if (fname == NULL) |
6295 | return FAIL; |
6296 | |
6297 | fname = skipwhite(fname); |
6298 | |
6299 | // Loop over the events. |
6300 | while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) { |
6301 | if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true, |
6302 | group, curbuf, NULL)) { |
6303 | nothing_done = false; |
6304 | } |
6305 | } |
6306 | |
6307 | if (nothing_done && do_msg) { |
6308 | MSG(_("No matching autocommands" )); |
6309 | } |
6310 | if (did_something != NULL) { |
6311 | *did_something = !nothing_done; |
6312 | } |
6313 | |
6314 | return aborting() ? FAIL : OK; |
6315 | } |
6316 | |
6317 | /* |
6318 | * ":doautoall": execute autocommands for each loaded buffer. |
6319 | */ |
6320 | void ex_doautoall(exarg_T *eap) |
6321 | { |
6322 | int retval; |
6323 | aco_save_T aco; |
6324 | char_u *arg = eap->arg; |
6325 | int call_do_modelines = check_nomodeline(&arg); |
6326 | bufref_T bufref; |
6327 | |
6328 | /* |
6329 | * This is a bit tricky: For some commands curwin->w_buffer needs to be |
6330 | * equal to curbuf, but for some buffers there may not be a window. |
6331 | * So we change the buffer for the current window for a moment. This |
6332 | * gives problems when the autocommands make changes to the list of |
6333 | * buffers or windows... |
6334 | */ |
6335 | FOR_ALL_BUFFERS(buf) { |
6336 | if (buf->b_ml.ml_mfp == NULL) { |
6337 | continue; |
6338 | } |
6339 | // Find a window for this buffer and save some values. |
6340 | aucmd_prepbuf(&aco, buf); |
6341 | set_bufref(&bufref, buf); |
6342 | |
6343 | bool did_aucmd; |
6344 | // execute the autocommands for this buffer |
6345 | retval = do_doautocmd(arg, false, &did_aucmd); |
6346 | |
6347 | if (call_do_modelines && did_aucmd) { |
6348 | // Execute the modeline settings, but don't set window-local |
6349 | // options if we are using the current window for another |
6350 | // buffer. |
6351 | do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0); |
6352 | } |
6353 | |
6354 | /* restore the current window */ |
6355 | aucmd_restbuf(&aco); |
6356 | |
6357 | // Stop if there is some error or buffer was deleted. |
6358 | if (retval == FAIL || !bufref_valid(&bufref)) { |
6359 | break; |
6360 | } |
6361 | } |
6362 | |
6363 | check_cursor(); /* just in case lines got deleted */ |
6364 | } |
6365 | |
6366 | /// Check *argp for <nomodeline>. When it is present return false, otherwise |
6367 | /// return true and advance *argp to after it. Thus do_modelines() should be |
6368 | /// called when true is returned. |
6369 | /// |
6370 | /// @param[in,out] argp argument string |
6371 | bool check_nomodeline(char_u **argp) |
6372 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT |
6373 | { |
6374 | if (STRNCMP(*argp, "<nomodeline>" , 12) == 0) { |
6375 | *argp = skipwhite(*argp + 12); |
6376 | return false; |
6377 | } |
6378 | return true; |
6379 | } |
6380 | |
6381 | /// Prepare for executing autocommands for (hidden) buffer `buf`. |
6382 | /// If the current buffer is not in any visible window, put it in a temporary |
6383 | /// floating window `aucmd_win`. |
6384 | /// Set `curbuf` and `curwin` to match `buf`. |
6385 | /// |
6386 | /// @param aco structure to save values in |
6387 | /// @param buf new curbuf |
6388 | void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) |
6389 | { |
6390 | win_T *win; |
6391 | bool need_append = true; // Append `aucmd_win` to the window list. |
6392 | |
6393 | /* Find a window that is for the new buffer */ |
6394 | if (buf == curbuf) { /* be quick when buf is curbuf */ |
6395 | win = curwin; |
6396 | } else { |
6397 | win = NULL; |
6398 | FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { |
6399 | if (wp->w_buffer == buf) { |
6400 | win = wp; |
6401 | break; |
6402 | } |
6403 | } |
6404 | } |
6405 | |
6406 | // Allocate the `aucmd_win` dummy floating window. |
6407 | if (win == NULL && aucmd_win == NULL) { |
6408 | win_alloc_aucmd_win(); |
6409 | need_append = false; |
6410 | } |
6411 | if (win == NULL && aucmd_win_used) |
6412 | /* Strange recursive autocommand, fall back to using the current |
6413 | * window. Expect a few side effects... */ |
6414 | win = curwin; |
6415 | |
6416 | aco->save_curwin = curwin; |
6417 | aco->save_prevwin = prevwin; |
6418 | aco->save_curbuf = curbuf; |
6419 | if (win != NULL) { |
6420 | /* There is a window for "buf" in the current tab page, make it the |
6421 | * curwin. This is preferred, it has the least side effects (esp. if |
6422 | * "buf" is curbuf). */ |
6423 | aco->use_aucmd_win = FALSE; |
6424 | curwin = win; |
6425 | } else { |
6426 | /* There is no window for "buf", use "aucmd_win". To minimize the side |
6427 | * effects, insert it in the current tab page. |
6428 | * Anything related to a window (e.g., setting folds) may have |
6429 | * unexpected results. */ |
6430 | aco->use_aucmd_win = TRUE; |
6431 | aucmd_win_used = TRUE; |
6432 | aucmd_win->w_buffer = buf; |
6433 | aucmd_win->w_s = &buf->b_s; |
6434 | ++buf->b_nwindows; |
6435 | win_init_empty(aucmd_win); /* set cursor and topline to safe values */ |
6436 | |
6437 | /* Make sure w_localdir and globaldir are NULL to avoid a chdir() in |
6438 | * win_enter_ext(). */ |
6439 | XFREE_CLEAR(aucmd_win->w_localdir); |
6440 | aco->globaldir = globaldir; |
6441 | globaldir = NULL; |
6442 | |
6443 | block_autocmds(); // We don't want BufEnter/WinEnter autocommands. |
6444 | if (need_append) { |
6445 | win_append(lastwin, aucmd_win); |
6446 | handle_register_window(aucmd_win); |
6447 | win_config_float(aucmd_win, aucmd_win->w_float_config); |
6448 | } |
6449 | // Prevent chdir() call in win_enter_ext(), through do_autochdir() |
6450 | int save_acd = p_acd; |
6451 | p_acd = false; |
6452 | win_enter(aucmd_win, false); |
6453 | p_acd = save_acd; |
6454 | unblock_autocmds(); |
6455 | curwin = aucmd_win; |
6456 | } |
6457 | curbuf = buf; |
6458 | aco->new_curwin = curwin; |
6459 | set_bufref(&aco->new_curbuf, curbuf); |
6460 | } |
6461 | |
6462 | /// Cleanup after executing autocommands for a (hidden) buffer. |
6463 | /// Restore the window as it was (if possible). |
6464 | /// |
6465 | /// @param aco structure holding saved values |
6466 | void aucmd_restbuf(aco_save_T *aco) |
6467 | { |
6468 | if (aco->use_aucmd_win) { |
6469 | curbuf->b_nwindows--; |
6470 | // Find "aucmd_win", it can't be closed, but it may be in another tab page. |
6471 | // Do not trigger autocommands here. |
6472 | block_autocmds(); |
6473 | if (curwin != aucmd_win) { |
6474 | FOR_ALL_TAB_WINDOWS(tp, wp) { |
6475 | if (wp == aucmd_win) { |
6476 | if (tp != curtab) { |
6477 | goto_tabpage_tp(tp, true, true); |
6478 | } |
6479 | win_goto(aucmd_win); |
6480 | goto win_found; |
6481 | } |
6482 | } |
6483 | } |
6484 | win_found: |
6485 | |
6486 | win_remove(curwin, NULL); |
6487 | handle_unregister_window(curwin); |
6488 | if (curwin->w_grid.chars != NULL) { |
6489 | ui_comp_remove_grid(&curwin->w_grid); |
6490 | ui_call_win_hide(curwin->w_grid.handle); |
6491 | grid_free(&curwin->w_grid); |
6492 | } |
6493 | |
6494 | aucmd_win_used = false; |
6495 | last_status(false); // may need to remove last status line |
6496 | |
6497 | if (!valid_tabpage_win(curtab)) { |
6498 | // no valid window in current tabpage |
6499 | close_tabpage(curtab); |
6500 | } |
6501 | |
6502 | unblock_autocmds(); |
6503 | |
6504 | if (win_valid(aco->save_curwin)) { |
6505 | curwin = aco->save_curwin; |
6506 | } else { |
6507 | // Hmm, original window disappeared. Just use the first one. |
6508 | curwin = firstwin; |
6509 | } |
6510 | prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin |
6511 | : firstwin; // window disappeared? |
6512 | vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables |
6513 | hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab |
6514 | curbuf = curwin->w_buffer; |
6515 | |
6516 | xfree(globaldir); |
6517 | globaldir = aco->globaldir; |
6518 | |
6519 | // the buffer contents may have changed |
6520 | check_cursor(); |
6521 | if (curwin->w_topline > curbuf->b_ml.ml_line_count) { |
6522 | curwin->w_topline = curbuf->b_ml.ml_line_count; |
6523 | curwin->w_topfill = 0; |
6524 | } |
6525 | } else { |
6526 | // restore curwin |
6527 | if (win_valid(aco->save_curwin)) { |
6528 | // Restore the buffer which was previously edited by curwin, if it was |
6529 | // changed, we are still the same window and the buffer is valid. |
6530 | if (curwin == aco->new_curwin |
6531 | && curbuf != aco->new_curbuf.br_buf |
6532 | && bufref_valid(&aco->new_curbuf) |
6533 | && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) { |
6534 | if (curwin->w_s == &curbuf->b_s) { |
6535 | curwin->w_s = &aco->new_curbuf.br_buf->b_s; |
6536 | } |
6537 | curbuf->b_nwindows--; |
6538 | curbuf = aco->new_curbuf.br_buf; |
6539 | curwin->w_buffer = curbuf; |
6540 | curbuf->b_nwindows++; |
6541 | } |
6542 | |
6543 | curwin = aco->save_curwin; |
6544 | prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin |
6545 | : firstwin; // window disappeared? |
6546 | curbuf = curwin->w_buffer; |
6547 | // In case the autocommand moves the cursor to a position that does not |
6548 | // exist in curbuf |
6549 | check_cursor(); |
6550 | } |
6551 | } |
6552 | } |
6553 | |
6554 | static int autocmd_nested = FALSE; |
6555 | |
6556 | /// Execute autocommands for "event" and file name "fname". |
6557 | /// |
6558 | /// @param event event that occured |
6559 | /// @param fname filename, NULL or empty means use actual file name |
6560 | /// @param fname_io filename to use for <afile> on cmdline |
6561 | /// @param force When true, ignore autocmd_busy |
6562 | /// @param buf Buffer for <abuf> |
6563 | /// |
6564 | /// @return true if some commands were executed. |
6565 | bool apply_autocmds(event_T event, char_u *fname, char_u *fname_io, bool force, |
6566 | buf_T *buf) |
6567 | { |
6568 | return apply_autocmds_group(event, fname, fname_io, force, |
6569 | AUGROUP_ALL, buf, NULL); |
6570 | } |
6571 | |
6572 | /// Like apply_autocmds(), but with extra "eap" argument. This takes care of |
6573 | /// setting v:filearg. |
6574 | /// |
6575 | /// @param event event that occured |
6576 | /// @param fname NULL or empty means use actual file name |
6577 | /// @param fname_io fname to use for <afile> on cmdline |
6578 | /// @param force When true, ignore autocmd_busy |
6579 | /// @param buf Buffer for <abuf> |
6580 | /// @param exarg Ex command arguments |
6581 | /// |
6582 | /// @return true if some commands were executed. |
6583 | static bool apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, |
6584 | bool force, buf_T *buf, exarg_T *eap) |
6585 | { |
6586 | return apply_autocmds_group(event, fname, fname_io, force, |
6587 | AUGROUP_ALL, buf, eap); |
6588 | } |
6589 | |
6590 | /// Like apply_autocmds(), but handles the caller's retval. If the script |
6591 | /// processing is being aborted or if retval is FAIL when inside a try |
6592 | /// conditional, no autocommands are executed. If otherwise the autocommands |
6593 | /// cause the script to be aborted, retval is set to FAIL. |
6594 | /// |
6595 | /// @param event event that occured |
6596 | /// @param fname NULL or empty means use actual file name |
6597 | /// @param fname_io fname to use for <afile> on cmdline |
6598 | /// @param force When true, ignore autocmd_busy |
6599 | /// @param buf Buffer for <abuf> |
6600 | /// @param[in,out] retval caller's retval |
6601 | /// |
6602 | /// @return true if some autocommands were executed |
6603 | bool apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, |
6604 | bool force, buf_T *buf, int *retval) |
6605 | { |
6606 | if (should_abort(*retval)) { |
6607 | return false; |
6608 | } |
6609 | |
6610 | bool did_cmd = apply_autocmds_group(event, fname, fname_io, force, |
6611 | AUGROUP_ALL, buf, NULL); |
6612 | if (did_cmd && aborting()) { |
6613 | *retval = FAIL; |
6614 | } |
6615 | return did_cmd; |
6616 | } |
6617 | |
6618 | /// Return true when there is a CursorHold/CursorHoldI autocommand defined for |
6619 | /// the current mode. |
6620 | bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
6621 | { |
6622 | return first_autopat[(int)(get_real_state() == NORMAL_BUSY |
6623 | ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL; |
6624 | } |
6625 | |
6626 | /// Return true if the CursorHold/CursorHoldI event can be triggered. |
6627 | bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
6628 | { |
6629 | int state; |
6630 | |
6631 | if (!did_cursorhold |
6632 | && has_cursorhold() |
6633 | && reg_recording == 0 |
6634 | && typebuf.tb_len == 0 |
6635 | && !ins_compl_active() |
6636 | ) { |
6637 | state = get_real_state(); |
6638 | if (state == NORMAL_BUSY || (state & INSERT) != 0) { |
6639 | return true; |
6640 | } |
6641 | } |
6642 | return false; |
6643 | } |
6644 | |
6645 | /// Return true if "event" autocommand is defined. |
6646 | /// |
6647 | /// @param event the autocommand to check |
6648 | bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
6649 | { |
6650 | return first_autopat[event] != NULL; |
6651 | } |
6652 | |
6653 | /// Execute autocommands for "event" and file name "fname". |
6654 | /// |
6655 | /// @param event event that occured |
6656 | /// @param fname filename, NULL or empty means use actual file name |
6657 | /// @param fname_io filename to use for <afile> on cmdline, |
6658 | /// NULL means use `fname`. |
6659 | /// @param force When true, ignore autocmd_busy |
6660 | /// @param group autocmd group ID or AUGROUP_ALL |
6661 | /// @param buf Buffer for <abuf> |
6662 | /// @param eap Ex command arguments |
6663 | /// |
6664 | /// @return true if some commands were executed. |
6665 | static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, |
6666 | bool force, int group, buf_T *buf, |
6667 | exarg_T *eap) |
6668 | { |
6669 | char_u *sfname = NULL; /* short file name */ |
6670 | char_u *tail; |
6671 | bool save_changed; |
6672 | buf_T *old_curbuf; |
6673 | bool retval = false; |
6674 | char_u *save_sourcing_name; |
6675 | linenr_T save_sourcing_lnum; |
6676 | char_u *save_autocmd_fname; |
6677 | int save_autocmd_bufnr; |
6678 | char_u *save_autocmd_match; |
6679 | int save_autocmd_busy; |
6680 | int save_autocmd_nested; |
6681 | static int nesting = 0; |
6682 | AutoPatCmd patcmd; |
6683 | AutoPat *ap; |
6684 | void *save_funccalp; |
6685 | char_u *save_cmdarg; |
6686 | long save_cmdbang; |
6687 | static int filechangeshell_busy = FALSE; |
6688 | proftime_T wait_time; |
6689 | bool did_save_redobuff = false; |
6690 | save_redo_T save_redo; |
6691 | const bool save_KeyTyped = KeyTyped; |
6692 | |
6693 | // Quickly return if there are no autocommands for this event or |
6694 | // autocommands are blocked. |
6695 | if (event == NUM_EVENTS || first_autopat[(int)event] == NULL |
6696 | || autocmd_blocked > 0) { |
6697 | goto BYPASS_AU; |
6698 | } |
6699 | |
6700 | /* |
6701 | * When autocommands are busy, new autocommands are only executed when |
6702 | * explicitly enabled with the "nested" flag. |
6703 | */ |
6704 | if (autocmd_busy && !(force || autocmd_nested)) |
6705 | goto BYPASS_AU; |
6706 | |
6707 | /* |
6708 | * Quickly return when immediately aborting on error, or when an interrupt |
6709 | * occurred or an exception was thrown but not caught. |
6710 | */ |
6711 | if (aborting()) |
6712 | goto BYPASS_AU; |
6713 | |
6714 | /* |
6715 | * FileChangedShell never nests, because it can create an endless loop. |
6716 | */ |
6717 | if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL |
6718 | || event == EVENT_FILECHANGEDSHELLPOST)) |
6719 | goto BYPASS_AU; |
6720 | |
6721 | /* |
6722 | * Ignore events in 'eventignore'. |
6723 | */ |
6724 | if (event_ignored(event)) |
6725 | goto BYPASS_AU; |
6726 | |
6727 | /* |
6728 | * Allow nesting of autocommands, but restrict the depth, because it's |
6729 | * possible to create an endless loop. |
6730 | */ |
6731 | if (nesting == 10) { |
6732 | EMSG(_("E218: autocommand nesting too deep" )); |
6733 | goto BYPASS_AU; |
6734 | } |
6735 | |
6736 | /* |
6737 | * Check if these autocommands are disabled. Used when doing ":all" or |
6738 | * ":ball". |
6739 | */ |
6740 | if ( (autocmd_no_enter |
6741 | && (event == EVENT_WINENTER || event == EVENT_BUFENTER)) |
6742 | || (autocmd_no_leave |
6743 | && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE))) |
6744 | goto BYPASS_AU; |
6745 | |
6746 | /* |
6747 | * Save the autocmd_* variables and info about the current buffer. |
6748 | */ |
6749 | save_autocmd_fname = autocmd_fname; |
6750 | save_autocmd_bufnr = autocmd_bufnr; |
6751 | save_autocmd_match = autocmd_match; |
6752 | save_autocmd_busy = autocmd_busy; |
6753 | save_autocmd_nested = autocmd_nested; |
6754 | save_changed = curbuf->b_changed; |
6755 | old_curbuf = curbuf; |
6756 | |
6757 | /* |
6758 | * Set the file name to be used for <afile>. |
6759 | * Make a copy to avoid that changing a buffer name or directory makes it |
6760 | * invalid. |
6761 | */ |
6762 | if (fname_io == NULL) { |
6763 | if (event == EVENT_COLORSCHEME |
6764 | || event == EVENT_COLORSCHEMEPRE |
6765 | || event == EVENT_OPTIONSET) { |
6766 | autocmd_fname = NULL; |
6767 | } else if (fname != NULL && !ends_excmd(*fname)) { |
6768 | autocmd_fname = fname; |
6769 | } else if (buf != NULL) { |
6770 | autocmd_fname = buf->b_ffname; |
6771 | } else { |
6772 | autocmd_fname = NULL; |
6773 | } |
6774 | } else { |
6775 | autocmd_fname = fname_io; |
6776 | } |
6777 | if (autocmd_fname != NULL) { |
6778 | // Allocate MAXPATHL for when eval_vars() resolves the fullpath. |
6779 | autocmd_fname = vim_strnsave(autocmd_fname, MAXPATHL); |
6780 | } |
6781 | |
6782 | /* |
6783 | * Set the buffer number to be used for <abuf>. |
6784 | */ |
6785 | if (buf == NULL) |
6786 | autocmd_bufnr = 0; |
6787 | else |
6788 | autocmd_bufnr = buf->b_fnum; |
6789 | |
6790 | /* |
6791 | * When the file name is NULL or empty, use the file name of buffer "buf". |
6792 | * Always use the full path of the file name to match with, in case |
6793 | * "allow_dirs" is set. |
6794 | */ |
6795 | if (fname == NULL || *fname == NUL) { |
6796 | if (buf == NULL) |
6797 | fname = NULL; |
6798 | else { |
6799 | if (event == EVENT_SYNTAX) |
6800 | fname = buf->b_p_syn; |
6801 | else if (event == EVENT_FILETYPE) |
6802 | fname = buf->b_p_ft; |
6803 | else { |
6804 | if (buf->b_sfname != NULL) |
6805 | sfname = vim_strsave(buf->b_sfname); |
6806 | fname = buf->b_ffname; |
6807 | } |
6808 | } |
6809 | if (fname == NULL) |
6810 | fname = (char_u *)"" ; |
6811 | fname = vim_strsave(fname); /* make a copy, so we can change it */ |
6812 | } else { |
6813 | sfname = vim_strsave(fname); |
6814 | // Don't try expanding the following events. |
6815 | if (event == EVENT_CMDLINECHANGED |
6816 | || event == EVENT_CMDLINEENTER |
6817 | || event == EVENT_CMDLINELEAVE |
6818 | || event == EVENT_CMDWINENTER |
6819 | || event == EVENT_CMDWINLEAVE |
6820 | || event == EVENT_CMDUNDEFINED |
6821 | || event == EVENT_COLORSCHEME |
6822 | || event == EVENT_COLORSCHEMEPRE |
6823 | || event == EVENT_DIRCHANGED |
6824 | || event == EVENT_FILETYPE |
6825 | || event == EVENT_FUNCUNDEFINED |
6826 | || event == EVENT_OPTIONSET |
6827 | || event == EVENT_QUICKFIXCMDPOST |
6828 | || event == EVENT_QUICKFIXCMDPRE |
6829 | || event == EVENT_REMOTEREPLY |
6830 | || event == EVENT_SPELLFILEMISSING |
6831 | || event == EVENT_SYNTAX |
6832 | || event == EVENT_SIGNAL |
6833 | || event == EVENT_TABCLOSED) { |
6834 | fname = vim_strsave(fname); |
6835 | } else { |
6836 | fname = (char_u *)FullName_save((char *)fname, false); |
6837 | } |
6838 | } |
6839 | if (fname == NULL) { /* out of memory */ |
6840 | xfree(sfname); |
6841 | retval = false; |
6842 | goto BYPASS_AU; |
6843 | } |
6844 | |
6845 | #ifdef BACKSLASH_IN_FILENAME |
6846 | // Replace all backslashes with forward slashes. This makes the |
6847 | // autocommand patterns portable between Unix and Windows. |
6848 | if (sfname != NULL) { |
6849 | forward_slash(sfname); |
6850 | } |
6851 | forward_slash(fname); |
6852 | #endif |
6853 | |
6854 | |
6855 | /* |
6856 | * Set the name to be used for <amatch>. |
6857 | */ |
6858 | autocmd_match = fname; |
6859 | |
6860 | |
6861 | // Don't redraw while doing autocommands. |
6862 | RedrawingDisabled++; |
6863 | save_sourcing_name = sourcing_name; |
6864 | sourcing_name = NULL; /* don't free this one */ |
6865 | save_sourcing_lnum = sourcing_lnum; |
6866 | sourcing_lnum = 0; /* no line number here */ |
6867 | |
6868 | const sctx_T save_current_sctx = current_sctx; |
6869 | |
6870 | if (do_profiling == PROF_YES) |
6871 | prof_child_enter(&wait_time); /* doesn't count for the caller itself */ |
6872 | |
6873 | /* Don't use local function variables, if called from a function */ |
6874 | save_funccalp = save_funccal(); |
6875 | |
6876 | /* |
6877 | * When starting to execute autocommands, save the search patterns. |
6878 | */ |
6879 | if (!autocmd_busy) { |
6880 | save_search_patterns(); |
6881 | if (!ins_compl_active()) { |
6882 | saveRedobuff(&save_redo); |
6883 | did_save_redobuff = true; |
6884 | } |
6885 | did_filetype = keep_filetype; |
6886 | } |
6887 | |
6888 | /* |
6889 | * Note that we are applying autocmds. Some commands need to know. |
6890 | */ |
6891 | autocmd_busy = TRUE; |
6892 | filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL); |
6893 | ++nesting; /* see matching decrement below */ |
6894 | |
6895 | /* Remember that FileType was triggered. Used for did_filetype(). */ |
6896 | if (event == EVENT_FILETYPE) |
6897 | did_filetype = TRUE; |
6898 | |
6899 | tail = path_tail(fname); |
6900 | |
6901 | /* Find first autocommand that matches */ |
6902 | patcmd.curpat = first_autopat[(int)event]; |
6903 | patcmd.nextcmd = NULL; |
6904 | patcmd.group = group; |
6905 | patcmd.fname = fname; |
6906 | patcmd.sfname = sfname; |
6907 | patcmd.tail = tail; |
6908 | patcmd.event = event; |
6909 | patcmd.arg_bufnr = autocmd_bufnr; |
6910 | patcmd.next = NULL; |
6911 | auto_next_pat(&patcmd, false); |
6912 | |
6913 | /* found one, start executing the autocommands */ |
6914 | if (patcmd.curpat != NULL) { |
6915 | /* add to active_apc_list */ |
6916 | patcmd.next = active_apc_list; |
6917 | active_apc_list = &patcmd; |
6918 | |
6919 | // set v:cmdarg (only when there is a matching pattern) |
6920 | save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG); |
6921 | if (eap != NULL) { |
6922 | save_cmdarg = set_cmdarg(eap, NULL); |
6923 | set_vim_var_nr(VV_CMDBANG, (long)eap->forceit); |
6924 | } else { |
6925 | save_cmdarg = NULL; // avoid gcc warning |
6926 | } |
6927 | retval = true; |
6928 | // mark the last pattern, to avoid an endless loop when more patterns |
6929 | // are added when executing autocommands |
6930 | for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) { |
6931 | ap->last = false; |
6932 | } |
6933 | ap->last = true; |
6934 | check_lnums(true); // make sure cursor and topline are valid |
6935 | |
6936 | // Execute the autocmd. The `getnextac` callback handles iteration. |
6937 | do_cmdline(NULL, getnextac, (void *)&patcmd, |
6938 | DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); |
6939 | |
6940 | reset_lnums(); // restore cursor and topline, unless they were changed |
6941 | |
6942 | if (eap != NULL) { |
6943 | (void)set_cmdarg(NULL, save_cmdarg); |
6944 | set_vim_var_nr(VV_CMDBANG, save_cmdbang); |
6945 | } |
6946 | /* delete from active_apc_list */ |
6947 | if (active_apc_list == &patcmd) /* just in case */ |
6948 | active_apc_list = patcmd.next; |
6949 | } |
6950 | |
6951 | --RedrawingDisabled; |
6952 | autocmd_busy = save_autocmd_busy; |
6953 | filechangeshell_busy = FALSE; |
6954 | autocmd_nested = save_autocmd_nested; |
6955 | xfree(sourcing_name); |
6956 | sourcing_name = save_sourcing_name; |
6957 | sourcing_lnum = save_sourcing_lnum; |
6958 | xfree(autocmd_fname); |
6959 | autocmd_fname = save_autocmd_fname; |
6960 | autocmd_bufnr = save_autocmd_bufnr; |
6961 | autocmd_match = save_autocmd_match; |
6962 | current_sctx = save_current_sctx; |
6963 | restore_funccal(save_funccalp); |
6964 | if (do_profiling == PROF_YES) |
6965 | prof_child_exit(&wait_time); |
6966 | KeyTyped = save_KeyTyped; |
6967 | xfree(fname); |
6968 | xfree(sfname); |
6969 | --nesting; /* see matching increment above */ |
6970 | |
6971 | // When stopping to execute autocommands, restore the search patterns and |
6972 | // the redo buffer. Free any buffers in the au_pending_free_buf list and |
6973 | // free any windows in the au_pending_free_win list. |
6974 | if (!autocmd_busy) { |
6975 | restore_search_patterns(); |
6976 | if (did_save_redobuff) { |
6977 | restoreRedobuff(&save_redo); |
6978 | } |
6979 | did_filetype = FALSE; |
6980 | while (au_pending_free_buf != NULL) { |
6981 | buf_T *b = au_pending_free_buf->b_next; |
6982 | xfree(au_pending_free_buf); |
6983 | au_pending_free_buf = b; |
6984 | } |
6985 | while (au_pending_free_win != NULL) { |
6986 | win_T *w = au_pending_free_win->w_next; |
6987 | xfree(au_pending_free_win); |
6988 | au_pending_free_win = w; |
6989 | } |
6990 | } |
6991 | |
6992 | /* |
6993 | * Some events don't set or reset the Changed flag. |
6994 | * Check if still in the same buffer! |
6995 | */ |
6996 | if (curbuf == old_curbuf |
6997 | && (event == EVENT_BUFREADPOST |
6998 | || event == EVENT_BUFWRITEPOST |
6999 | || event == EVENT_FILEAPPENDPOST |
7000 | || event == EVENT_VIMLEAVE |
7001 | || event == EVENT_VIMLEAVEPRE)) { |
7002 | if (curbuf->b_changed != save_changed) |
7003 | need_maketitle = TRUE; |
7004 | curbuf->b_changed = save_changed; |
7005 | } |
7006 | |
7007 | au_cleanup(); /* may really delete removed patterns/commands now */ |
7008 | |
7009 | BYPASS_AU: |
7010 | /* When wiping out a buffer make sure all its buffer-local autocommands |
7011 | * are deleted. */ |
7012 | if (event == EVENT_BUFWIPEOUT && buf != NULL) |
7013 | aubuflocal_remove(buf); |
7014 | |
7015 | if (retval == OK && event == EVENT_FILETYPE) { |
7016 | au_did_filetype = true; |
7017 | } |
7018 | |
7019 | return retval; |
7020 | } |
7021 | |
7022 | static char_u *old_termresponse = NULL; |
7023 | |
7024 | /* |
7025 | * Block triggering autocommands until unblock_autocmd() is called. |
7026 | * Can be used recursively, so long as it's symmetric. |
7027 | */ |
7028 | void block_autocmds(void) |
7029 | { |
7030 | /* Remember the value of v:termresponse. */ |
7031 | if (autocmd_blocked == 0) |
7032 | old_termresponse = get_vim_var_str(VV_TERMRESPONSE); |
7033 | ++autocmd_blocked; |
7034 | } |
7035 | |
7036 | void unblock_autocmds(void) |
7037 | { |
7038 | --autocmd_blocked; |
7039 | |
7040 | /* When v:termresponse was set while autocommands were blocked, trigger |
7041 | * the autocommands now. Esp. useful when executing a shell command |
7042 | * during startup (nvim -d). */ |
7043 | if (autocmd_blocked == 0 |
7044 | && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) |
7045 | apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); |
7046 | } |
7047 | |
7048 | // Find next autocommand pattern that matches. |
7049 | static void |
7050 | auto_next_pat( |
7051 | AutoPatCmd *apc, |
7052 | int stop_at_last /* stop when 'last' flag is set */ |
7053 | ) |
7054 | { |
7055 | AutoPat *ap; |
7056 | AutoCmd *cp; |
7057 | char *s; |
7058 | |
7059 | XFREE_CLEAR(sourcing_name); |
7060 | |
7061 | for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) { |
7062 | apc->curpat = NULL; |
7063 | |
7064 | /* Only use a pattern when it has not been removed, has commands and |
7065 | * the group matches. For buffer-local autocommands only check the |
7066 | * buffer number. */ |
7067 | if (ap->pat != NULL && ap->cmds != NULL |
7068 | && (apc->group == AUGROUP_ALL || apc->group == ap->group)) { |
7069 | /* execution-condition */ |
7070 | if (ap->buflocal_nr == 0 |
7071 | ? match_file_pat(NULL, &ap->reg_prog, apc->fname, apc->sfname, |
7072 | apc->tail, ap->allow_dirs) |
7073 | : ap->buflocal_nr == apc->arg_bufnr) { |
7074 | const char *const name = event_nr2name(apc->event); |
7075 | s = _("%s Autocommands for \"%s\"" ); |
7076 | const size_t sourcing_name_len = (STRLEN(s) + strlen(name) + ap->patlen |
7077 | + 1); |
7078 | sourcing_name = xmalloc(sourcing_name_len); |
7079 | snprintf((char *)sourcing_name, sourcing_name_len, s, name, |
7080 | (char *)ap->pat); |
7081 | if (p_verbose >= 8) { |
7082 | verbose_enter(); |
7083 | smsg(_("Executing %s" ), sourcing_name); |
7084 | verbose_leave(); |
7085 | } |
7086 | |
7087 | apc->curpat = ap; |
7088 | apc->nextcmd = ap->cmds; |
7089 | /* mark last command */ |
7090 | for (cp = ap->cmds; cp->next != NULL; cp = cp->next) |
7091 | cp->last = FALSE; |
7092 | cp->last = TRUE; |
7093 | } |
7094 | line_breakcheck(); |
7095 | if (apc->curpat != NULL) /* found a match */ |
7096 | break; |
7097 | } |
7098 | if (stop_at_last && ap->last) |
7099 | break; |
7100 | } |
7101 | } |
7102 | |
7103 | /* |
7104 | * Get next autocommand command. |
7105 | * Called by do_cmdline() to get the next line for ":if". |
7106 | * Returns allocated string, or NULL for end of autocommands. |
7107 | */ |
7108 | char_u *getnextac(int c, void *cookie, int indent) |
7109 | { |
7110 | AutoPatCmd *acp = (AutoPatCmd *)cookie; |
7111 | char_u *retval; |
7112 | AutoCmd *ac; |
7113 | |
7114 | /* Can be called again after returning the last line. */ |
7115 | if (acp->curpat == NULL) |
7116 | return NULL; |
7117 | |
7118 | /* repeat until we find an autocommand to execute */ |
7119 | for (;; ) { |
7120 | /* skip removed commands */ |
7121 | while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL) |
7122 | if (acp->nextcmd->last) |
7123 | acp->nextcmd = NULL; |
7124 | else |
7125 | acp->nextcmd = acp->nextcmd->next; |
7126 | |
7127 | if (acp->nextcmd != NULL) |
7128 | break; |
7129 | |
7130 | /* at end of commands, find next pattern that matches */ |
7131 | if (acp->curpat->last) |
7132 | acp->curpat = NULL; |
7133 | else |
7134 | acp->curpat = acp->curpat->next; |
7135 | if (acp->curpat != NULL) |
7136 | auto_next_pat(acp, TRUE); |
7137 | if (acp->curpat == NULL) |
7138 | return NULL; |
7139 | } |
7140 | |
7141 | ac = acp->nextcmd; |
7142 | |
7143 | if (p_verbose >= 9) { |
7144 | verbose_enter_scroll(); |
7145 | smsg(_("autocommand %s" ), ac->cmd); |
7146 | msg_puts("\n" ); // don't overwrite this either |
7147 | verbose_leave_scroll(); |
7148 | } |
7149 | retval = vim_strsave(ac->cmd); |
7150 | // Remove one-shot ("once") autocmd in anticipation of its execution. |
7151 | if (ac->once) { |
7152 | au_del_cmd(ac); |
7153 | } |
7154 | autocmd_nested = ac->nested; |
7155 | current_sctx = ac->script_ctx; |
7156 | if (ac->last) { |
7157 | acp->nextcmd = NULL; |
7158 | } else { |
7159 | acp->nextcmd = ac->next; |
7160 | } |
7161 | |
7162 | return retval; |
7163 | } |
7164 | |
7165 | /// Return true if there is a matching autocommand for "fname". |
7166 | /// To account for buffer-local autocommands, function needs to know |
7167 | /// in which buffer the file will be opened. |
7168 | /// |
7169 | /// @param event event that occured. |
7170 | /// @param sfname filename the event occured in. |
7171 | /// @param buf buffer the file is open in |
7172 | bool has_autocmd(event_T event, char_u *sfname, buf_T *buf) |
7173 | FUNC_ATTR_WARN_UNUSED_RESULT |
7174 | { |
7175 | AutoPat *ap; |
7176 | char_u *fname; |
7177 | char_u *tail = path_tail(sfname); |
7178 | bool retval = false; |
7179 | |
7180 | fname = (char_u *)FullName_save((char *)sfname, false); |
7181 | if (fname == NULL) { |
7182 | return false; |
7183 | } |
7184 | |
7185 | #ifdef BACKSLASH_IN_FILENAME |
7186 | // Replace all backslashes with forward slashes. This makes the |
7187 | // autocommand patterns portable between Unix and Windows. |
7188 | sfname = vim_strsave(sfname); |
7189 | forward_slash(sfname); |
7190 | forward_slash(fname); |
7191 | #endif |
7192 | |
7193 | for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) { |
7194 | if (ap->pat != NULL && ap->cmds != NULL |
7195 | && (ap->buflocal_nr == 0 |
7196 | ? match_file_pat(NULL, &ap->reg_prog, fname, sfname, tail, |
7197 | ap->allow_dirs) |
7198 | : buf != NULL && ap->buflocal_nr == buf->b_fnum)) { |
7199 | retval = true; |
7200 | break; |
7201 | } |
7202 | } |
7203 | |
7204 | xfree(fname); |
7205 | #ifdef BACKSLASH_IN_FILENAME |
7206 | xfree(sfname); |
7207 | #endif |
7208 | |
7209 | return retval; |
7210 | } |
7211 | |
7212 | /* |
7213 | * Function given to ExpandGeneric() to obtain the list of autocommand group |
7214 | * names. |
7215 | */ |
7216 | char_u *get_augroup_name(expand_T *xp, int idx) |
7217 | { |
7218 | if (idx == augroups.ga_len) { // add "END" add the end |
7219 | return (char_u *)"END" ; |
7220 | } |
7221 | if (idx >= augroups.ga_len) { // end of list |
7222 | return NULL; |
7223 | } |
7224 | if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) { |
7225 | // skip deleted entries |
7226 | return (char_u *)"" ; |
7227 | } |
7228 | return (char_u *)AUGROUP_NAME(idx); |
7229 | } |
7230 | |
7231 | static int include_groups = FALSE; |
7232 | |
7233 | char_u * |
7234 | set_context_in_autocmd ( |
7235 | expand_T *xp, |
7236 | char_u *arg, |
7237 | int doautocmd /* TRUE for :doauto*, FALSE for :autocmd */ |
7238 | ) |
7239 | { |
7240 | char_u *p; |
7241 | int group; |
7242 | |
7243 | /* check for a group name, skip it if present */ |
7244 | include_groups = FALSE; |
7245 | p = arg; |
7246 | group = au_get_grouparg(&arg); |
7247 | |
7248 | /* If there only is a group name that's what we expand. */ |
7249 | if (*arg == NUL && group != AUGROUP_ALL && !ascii_iswhite(arg[-1])) { |
7250 | arg = p; |
7251 | group = AUGROUP_ALL; |
7252 | } |
7253 | |
7254 | /* skip over event name */ |
7255 | for (p = arg; *p != NUL && !ascii_iswhite(*p); ++p) |
7256 | if (*p == ',') |
7257 | arg = p + 1; |
7258 | if (*p == NUL) { |
7259 | if (group == AUGROUP_ALL) |
7260 | include_groups = TRUE; |
7261 | xp->xp_context = EXPAND_EVENTS; /* expand event name */ |
7262 | xp->xp_pattern = arg; |
7263 | return NULL; |
7264 | } |
7265 | |
7266 | /* skip over pattern */ |
7267 | arg = skipwhite(p); |
7268 | while (*arg && (!ascii_iswhite(*arg) || arg[-1] == '\\')) |
7269 | arg++; |
7270 | if (*arg) |
7271 | return arg; /* expand (next) command */ |
7272 | |
7273 | if (doautocmd) |
7274 | xp->xp_context = EXPAND_FILES; /* expand file names */ |
7275 | else |
7276 | xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */ |
7277 | return NULL; |
7278 | } |
7279 | |
7280 | /* |
7281 | * Function given to ExpandGeneric() to obtain the list of event names. |
7282 | */ |
7283 | char_u *get_event_name(expand_T *xp, int idx) |
7284 | { |
7285 | if (idx < augroups.ga_len) { // First list group names, if wanted |
7286 | if (!include_groups || AUGROUP_NAME(idx) == NULL |
7287 | || AUGROUP_NAME(idx) == get_deleted_augroup()) { |
7288 | return (char_u *)"" ; // skip deleted entries |
7289 | } |
7290 | return (char_u *)AUGROUP_NAME(idx); |
7291 | } |
7292 | return (char_u *)event_names[idx - augroups.ga_len].name; |
7293 | } |
7294 | |
7295 | |
7296 | /// Check whether given autocommand is supported |
7297 | /// |
7298 | /// @param[in] event Event to check. |
7299 | /// |
7300 | /// @return True if it is, false otherwise. |
7301 | bool autocmd_supported(const char *const event) |
7302 | FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
7303 | { |
7304 | char_u *p; |
7305 | return event_name2nr((const char_u *)event, &p) != NUM_EVENTS; |
7306 | } |
7307 | |
7308 | /// Return true if an autocommand is defined for a group, event and |
7309 | /// pattern: The group can be omitted to accept any group. |
7310 | /// `event` and `pattern` can be omitted to accept any event and pattern. |
7311 | /// Buffer-local patterns <buffer> or <buffer=N> are accepted. |
7312 | /// Used for: |
7313 | /// exists("#Group") or |
7314 | /// exists("#Group#Event") or |
7315 | /// exists("#Group#Event#pat") or |
7316 | /// exists("#Event") or |
7317 | /// exists("#Event#pat") |
7318 | /// |
7319 | /// @param arg autocommand string |
7320 | bool au_exists(const char *const arg) FUNC_ATTR_WARN_UNUSED_RESULT |
7321 | { |
7322 | event_T event; |
7323 | AutoPat *ap; |
7324 | buf_T *buflocal_buf = NULL; |
7325 | int group; |
7326 | bool retval = false; |
7327 | |
7328 | // Make a copy so that we can change the '#' chars to a NUL. |
7329 | char *const arg_save = xstrdup(arg); |
7330 | char *p = strchr(arg_save, '#'); |
7331 | if (p != NULL) { |
7332 | *p++ = NUL; |
7333 | } |
7334 | |
7335 | // First, look for an autocmd group name. |
7336 | group = au_find_group((char_u *)arg_save); |
7337 | char *event_name; |
7338 | if (group == AUGROUP_ERROR) { |
7339 | /* Didn't match a group name, assume the first argument is an event. */ |
7340 | group = AUGROUP_ALL; |
7341 | event_name = arg_save; |
7342 | } else { |
7343 | if (p == NULL) { |
7344 | // "Group": group name is present and it's recognized |
7345 | retval = true; |
7346 | goto theend; |
7347 | } |
7348 | |
7349 | // Must be "Group#Event" or "Group#Event#pat". |
7350 | event_name = p; |
7351 | p = strchr(event_name, '#'); |
7352 | if (p != NULL) { |
7353 | *p++ = NUL; // "Group#Event#pat" |
7354 | } |
7355 | } |
7356 | |
7357 | char *pattern = p; // "pattern" is NULL when there is no pattern. |
7358 | |
7359 | // Find the index (enum) for the event name. |
7360 | event = event_name2nr((char_u *)event_name, (char_u **)&p); |
7361 | |
7362 | /* return FALSE if the event name is not recognized */ |
7363 | if (event == NUM_EVENTS) |
7364 | goto theend; |
7365 | |
7366 | /* Find the first autocommand for this event. |
7367 | * If there isn't any, return FALSE; |
7368 | * If there is one and no pattern given, return TRUE; */ |
7369 | ap = first_autopat[(int)event]; |
7370 | if (ap == NULL) |
7371 | goto theend; |
7372 | |
7373 | /* if pattern is "<buffer>", special handling is needed which uses curbuf */ |
7374 | /* for pattern "<buffer=N>, fnamecmp() will work fine */ |
7375 | if (pattern != NULL && STRICMP(pattern, "<buffer>" ) == 0) |
7376 | buflocal_buf = curbuf; |
7377 | |
7378 | /* Check if there is an autocommand with the given pattern. */ |
7379 | for (; ap != NULL; ap = ap->next) |
7380 | /* only use a pattern when it has not been removed and has commands. */ |
7381 | /* For buffer-local autocommands, fnamecmp() works fine. */ |
7382 | if (ap->pat != NULL && ap->cmds != NULL |
7383 | && (group == AUGROUP_ALL || ap->group == group) |
7384 | && (pattern == NULL |
7385 | || (buflocal_buf == NULL |
7386 | ? fnamecmp(ap->pat, (char_u *)pattern) == 0 |
7387 | : ap->buflocal_nr == buflocal_buf->b_fnum))) { |
7388 | retval = true; |
7389 | break; |
7390 | } |
7391 | |
7392 | theend: |
7393 | xfree(arg_save); |
7394 | return retval; |
7395 | } |
7396 | |
7397 | /// Tries matching a filename with a "pattern" ("prog" is NULL), or use the |
7398 | /// precompiled regprog "prog" ("pattern" is NULL). That avoids calling |
7399 | /// vim_regcomp() often. |
7400 | /// |
7401 | /// Used for autocommands and 'wildignore'. |
7402 | /// |
7403 | /// @param pattern pattern to match with |
7404 | /// @param prog pre-compiled regprog or NULL |
7405 | /// @param fname full path of the file name |
7406 | /// @param sfname short file name or NULL |
7407 | /// @param tail tail of the path |
7408 | /// @param allow_dirs Allow matching with dir |
7409 | /// |
7410 | /// @return true if there is a match, false otherwise |
7411 | static bool match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname, |
7412 | char_u *sfname, char_u *tail, int allow_dirs) |
7413 | { |
7414 | regmatch_T regmatch; |
7415 | bool result = false; |
7416 | |
7417 | regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */ |
7418 | { |
7419 | if (prog != NULL) |
7420 | regmatch.regprog = *prog; |
7421 | else |
7422 | regmatch.regprog = vim_regcomp(pattern, RE_MAGIC); |
7423 | } |
7424 | |
7425 | /* |
7426 | * Try for a match with the pattern with: |
7427 | * 1. the full file name, when the pattern has a '/'. |
7428 | * 2. the short file name, when the pattern has a '/'. |
7429 | * 3. the tail of the file name, when the pattern has no '/'. |
7430 | */ |
7431 | if (regmatch.regprog != NULL |
7432 | && ((allow_dirs |
7433 | && (vim_regexec(®match, fname, (colnr_T)0) |
7434 | || (sfname != NULL |
7435 | && vim_regexec(®match, sfname, (colnr_T)0)))) |
7436 | || (!allow_dirs && vim_regexec(®match, tail, (colnr_T)0)))) { |
7437 | result = true; |
7438 | } |
7439 | |
7440 | if (prog != NULL) { |
7441 | *prog = regmatch.regprog; |
7442 | } else { |
7443 | vim_regfree(regmatch.regprog); |
7444 | } |
7445 | return result; |
7446 | } |
7447 | |
7448 | /// Check if a file matches with a pattern in "list". |
7449 | /// "list" is a comma-separated list of patterns, like 'wildignore'. |
7450 | /// "sfname" is the short file name or NULL, "ffname" the long file name. |
7451 | /// |
7452 | /// @param list list of patterns to match |
7453 | /// @param sfname short file name |
7454 | /// @param ffname full file name |
7455 | /// |
7456 | /// @return true if there was a match |
7457 | bool match_file_list(char_u *list, char_u *sfname, char_u *ffname) |
7458 | FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) |
7459 | { |
7460 | char_u buf[100]; |
7461 | char_u *tail; |
7462 | char_u *regpat; |
7463 | char allow_dirs; |
7464 | bool match; |
7465 | char_u *p; |
7466 | |
7467 | tail = path_tail(sfname); |
7468 | |
7469 | // try all patterns in 'wildignore' |
7470 | p = list; |
7471 | while (*p) { |
7472 | copy_option_part(&p, buf, ARRAY_SIZE(buf), "," ); |
7473 | regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); |
7474 | if (regpat == NULL) { |
7475 | break; |
7476 | } |
7477 | match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); |
7478 | xfree(regpat); |
7479 | if (match) { |
7480 | return true; |
7481 | } |
7482 | } |
7483 | return false; |
7484 | } |
7485 | |
7486 | /// Convert the given pattern "pat" which has shell style wildcards in it, into |
7487 | /// a regular expression, and return the result in allocated memory. If there |
7488 | /// is a directory path separator to be matched, then TRUE is put in |
7489 | /// allow_dirs, otherwise FALSE is put there -- webb. |
7490 | /// Handle backslashes before special characters, like "\*" and "\ ". |
7491 | /// |
7492 | /// Returns NULL on failure. |
7493 | char_u * file_pat_to_reg_pat( |
7494 | const char_u *pat, |
7495 | const char_u *pat_end, // first char after pattern or NULL |
7496 | char *allow_dirs, // Result passed back out in here |
7497 | int no_bslash // Don't use a backward slash as pathsep |
7498 | ) |
7499 | FUNC_ATTR_NONNULL_ARG(1) |
7500 | { |
7501 | const char_u *endp; |
7502 | char_u *reg_pat; |
7503 | const char_u *p; |
7504 | int nested = 0; |
7505 | int add_dollar = TRUE; |
7506 | |
7507 | if (allow_dirs != NULL) |
7508 | *allow_dirs = FALSE; |
7509 | if (pat_end == NULL) |
7510 | pat_end = pat + STRLEN(pat); |
7511 | |
7512 | if (pat_end == pat) { |
7513 | return (char_u *)xstrdup("^$" ); |
7514 | } |
7515 | |
7516 | size_t size = 2; // '^' at start, '$' at end. |
7517 | |
7518 | for (p = pat; p < pat_end; p++) { |
7519 | switch (*p) { |
7520 | case '*': |
7521 | case '.': |
7522 | case ',': |
7523 | case '{': |
7524 | case '}': |
7525 | case '~': |
7526 | size += 2; /* extra backslash */ |
7527 | break; |
7528 | #ifdef BACKSLASH_IN_FILENAME |
7529 | case '\\': |
7530 | case '/': |
7531 | size += 4; /* could become "[\/]" */ |
7532 | break; |
7533 | #endif |
7534 | default: |
7535 | size++; |
7536 | break; |
7537 | } |
7538 | } |
7539 | reg_pat = xmalloc(size + 1); |
7540 | |
7541 | size_t i = 0; |
7542 | |
7543 | if (pat[0] == '*') |
7544 | while (pat[0] == '*' && pat < pat_end - 1) |
7545 | pat++; |
7546 | else |
7547 | reg_pat[i++] = '^'; |
7548 | endp = pat_end - 1; |
7549 | if (endp >= pat && *endp == '*') { |
7550 | while (endp - pat > 0 && *endp == '*') { |
7551 | endp--; |
7552 | } |
7553 | add_dollar = false; |
7554 | } |
7555 | for (p = pat; *p && nested >= 0 && p <= endp; p++) { |
7556 | switch (*p) { |
7557 | case '*': |
7558 | reg_pat[i++] = '.'; |
7559 | reg_pat[i++] = '*'; |
7560 | while (p[1] == '*') /* "**" matches like "*" */ |
7561 | ++p; |
7562 | break; |
7563 | case '.': |
7564 | case '~': |
7565 | reg_pat[i++] = '\\'; |
7566 | reg_pat[i++] = *p; |
7567 | break; |
7568 | case '?': |
7569 | reg_pat[i++] = '.'; |
7570 | break; |
7571 | case '\\': |
7572 | if (p[1] == NUL) |
7573 | break; |
7574 | #ifdef BACKSLASH_IN_FILENAME |
7575 | if (!no_bslash) { |
7576 | /* translate: |
7577 | * "\x" to "\\x" e.g., "dir\file" |
7578 | * "\*" to "\\.*" e.g., "dir\*.c" |
7579 | * "\?" to "\\." e.g., "dir\??.c" |
7580 | * "\+" to "\+" e.g., "fileX\+.c" |
7581 | */ |
7582 | if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?') |
7583 | && p[1] != '+') { |
7584 | reg_pat[i++] = '['; |
7585 | reg_pat[i++] = '\\'; |
7586 | reg_pat[i++] = '/'; |
7587 | reg_pat[i++] = ']'; |
7588 | if (allow_dirs != NULL) |
7589 | *allow_dirs = TRUE; |
7590 | break; |
7591 | } |
7592 | } |
7593 | #endif |
7594 | /* Undo escaping from ExpandEscape(): |
7595 | * foo\?bar -> foo?bar |
7596 | * foo\%bar -> foo%bar |
7597 | * foo\,bar -> foo,bar |
7598 | * foo\ bar -> foo bar |
7599 | * Don't unescape \, * and others that are also special in a |
7600 | * regexp. |
7601 | * An escaped { must be unescaped since we use magic not |
7602 | * verymagic. Use "\\\{n,m\}"" to get "\{n,m}". |
7603 | */ |
7604 | if (*++p == '?' |
7605 | #ifdef BACKSLASH_IN_FILENAME |
7606 | && no_bslash |
7607 | #endif |
7608 | ) { |
7609 | reg_pat[i++] = '?'; |
7610 | } else if (*p == ',' || *p == '%' || *p == '#' |
7611 | || ascii_isspace(*p) || *p == '{' || *p == '}') { |
7612 | reg_pat[i++] = *p; |
7613 | } else if (*p == '\\' && p[1] == '\\' && p[2] == '{') { |
7614 | reg_pat[i++] = '\\'; |
7615 | reg_pat[i++] = '{'; |
7616 | p += 2; |
7617 | } else { |
7618 | if (allow_dirs != NULL && vim_ispathsep(*p) |
7619 | #ifdef BACKSLASH_IN_FILENAME |
7620 | && (!no_bslash || *p != '\\') |
7621 | #endif |
7622 | ) |
7623 | *allow_dirs = TRUE; |
7624 | reg_pat[i++] = '\\'; |
7625 | reg_pat[i++] = *p; |
7626 | } |
7627 | break; |
7628 | #ifdef BACKSLASH_IN_FILENAME |
7629 | case '/': |
7630 | reg_pat[i++] = '['; |
7631 | reg_pat[i++] = '\\'; |
7632 | reg_pat[i++] = '/'; |
7633 | reg_pat[i++] = ']'; |
7634 | if (allow_dirs != NULL) |
7635 | *allow_dirs = TRUE; |
7636 | break; |
7637 | #endif |
7638 | case '{': |
7639 | reg_pat[i++] = '\\'; |
7640 | reg_pat[i++] = '('; |
7641 | nested++; |
7642 | break; |
7643 | case '}': |
7644 | reg_pat[i++] = '\\'; |
7645 | reg_pat[i++] = ')'; |
7646 | --nested; |
7647 | break; |
7648 | case ',': |
7649 | if (nested) { |
7650 | reg_pat[i++] = '\\'; |
7651 | reg_pat[i++] = '|'; |
7652 | } else |
7653 | reg_pat[i++] = ','; |
7654 | break; |
7655 | default: |
7656 | if (allow_dirs != NULL && vim_ispathsep(*p)) { |
7657 | *allow_dirs = true; |
7658 | } |
7659 | reg_pat[i++] = *p; |
7660 | break; |
7661 | } |
7662 | } |
7663 | if (add_dollar) |
7664 | reg_pat[i++] = '$'; |
7665 | reg_pat[i] = NUL; |
7666 | if (nested != 0) { |
7667 | if (nested < 0) { |
7668 | EMSG(_("E219: Missing {." )); |
7669 | } else { |
7670 | EMSG(_("E220: Missing }." )); |
7671 | } |
7672 | XFREE_CLEAR(reg_pat); |
7673 | } |
7674 | return reg_pat; |
7675 | } |
7676 | |
7677 | #if defined(EINTR) |
7678 | /* |
7679 | * Version of read() that retries when interrupted by EINTR (possibly |
7680 | * by a SIGWINCH). |
7681 | */ |
7682 | long read_eintr(int fd, void *buf, size_t bufsize) |
7683 | { |
7684 | long ret; |
7685 | |
7686 | for (;; ) { |
7687 | ret = read(fd, buf, bufsize); |
7688 | if (ret >= 0 || errno != EINTR) |
7689 | break; |
7690 | } |
7691 | return ret; |
7692 | } |
7693 | |
7694 | /* |
7695 | * Version of write() that retries when interrupted by EINTR (possibly |
7696 | * by a SIGWINCH). |
7697 | */ |
7698 | long write_eintr(int fd, void *buf, size_t bufsize) |
7699 | { |
7700 | long ret = 0; |
7701 | long wlen; |
7702 | |
7703 | /* Repeat the write() so long it didn't fail, other than being interrupted |
7704 | * by a signal. */ |
7705 | while (ret < (long)bufsize) { |
7706 | wlen = write(fd, (char *)buf + ret, bufsize - ret); |
7707 | if (wlen < 0) { |
7708 | if (errno != EINTR) |
7709 | break; |
7710 | } else |
7711 | ret += wlen; |
7712 | } |
7713 | return ret; |
7714 | } |
7715 | #endif |
7716 | |