diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/fileio.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/fileio.c')
| -rw-r--r-- | src/fileio.c | 8148 |
1 files changed, 0 insertions, 8148 deletions
diff --git a/src/fileio.c b/src/fileio.c deleted file mode 100644 index 4fc73d8ebf..0000000000 --- a/src/fileio.c +++ /dev/null @@ -1,8148 +0,0 @@ -/* - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * fileio.c: read from and write to a file - */ - -#include <string.h> - -#include "vim.h" -#include "fileio.h" -#include "blowfish.h" -#include "buffer.h" -#include "charset.h" -#include "diff.h" -#include "edit.h" -#include "eval.h" -#include "ex_cmds.h" -#include "ex_docmd.h" -#include "ex_eval.h" -#include "fold.h" -#include "getchar.h" -#include "hashtab.h" -#include "mbyte.h" -#include "memfile.h" -#include "memline.h" -#include "memory.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "crypt.h" -#include "garray.h" -#include "move.h" -#include "normal.h" -#include "option.h" -#include "os_unix.h" -#include "path.h" -#include "quickfix.h" -#include "regexp.h" -#include "screen.h" -#include "search.h" -#include "sha256.h" -#include "term.h" -#include "ui.h" -#include "undo.h" -#include "window.h" -#include "os/os.h" - - -#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) -# include <utime.h> /* for struct utimbuf */ -#endif - -#define BUFSIZE 8192 /* size of normal write buffer */ -#define SMBUFSIZE 256 /* size of emergency write buffer */ - -/* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */ -static char *crypt_magic[] = {"VimCrypt~01!", "VimCrypt~02!"}; -static char crypt_magic_head[] = "VimCrypt~"; -# define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */ - -/* For blowfish, after the magic header, we store 8 bytes of salt and then 8 - * bytes of seed (initialisation vector). */ -static int crypt_salt_len[] = {0, 8}; -static int crypt_seed_len[] = {0, 8}; -#define CRYPT_SALT_LEN_MAX 8 -#define CRYPT_SEED_LEN_MAX 8 - -static char_u *next_fenc(char_u **pp); -static char_u *readfile_charconvert(char_u *fname, char_u *fenc, - int *fdp); -static void check_marks_read(void); -static int crypt_method_from_magic(char *ptr, int len); -static char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, - long *sizep, off_t *filesizep, - int newfile, char_u *fname, - int *did_ask); -#ifdef UNIX -static void set_file_time(char_u *fname, time_t atime, time_t mtime); -#endif -static int set_rw_fname(char_u *fname, char_u *sfname); -static int msg_add_fileformat(int eol_type); -static void msg_add_eol(void); -static int check_mtime(buf_T *buf, FileInfo *file_info); -static int time_differs(long t1, long t2); -static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, - int force, buf_T *buf, - exarg_T *eap); -static int au_find_group(char_u *name); - -# define AUGROUP_DEFAULT -1 /* default autocmd group */ -# define AUGROUP_ERROR -2 /* erroneous autocmd group */ -# define AUGROUP_ALL -3 /* all autocmd groups */ - -# define HAS_BW_FLAGS -# define FIO_LATIN1 0x01 /* convert Latin1 */ -# define FIO_UTF8 0x02 /* convert UTF-8 */ -# define FIO_UCS2 0x04 /* convert UCS-2 */ -# define FIO_UCS4 0x08 /* convert UCS-4 */ -# define FIO_UTF16 0x10 /* convert UTF-16 */ -# define FIO_ENDIAN_L 0x80 /* little endian */ -# define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */ -# define FIO_NOCONVERT 0x2000 /* skip encoding conversion */ -# define FIO_UCSBOM 0x4000 /* check for BOM at start of file */ -# define FIO_ALL -1 /* allow all formats */ - -/* When converting, a read() or write() may leave some bytes to be converted - * for the next call. The value is guessed... */ -#define CONV_RESTLEN 30 - -/* We have to guess how much a sequence of bytes may expand when converting - * with iconv() to be able to allocate a buffer. */ -#define ICONV_MULT 8 - -/* - * Structure to pass arguments from buf_write() to buf_write_bytes(). - */ -struct bw_info { - int bw_fd; /* file descriptor */ - char_u *bw_buf; /* buffer with data to be written */ - int bw_len; /* length of data */ -#ifdef HAS_BW_FLAGS - int bw_flags; /* FIO_ flags */ -#endif - char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */ - int bw_restlen; /* nr of bytes in bw_rest[] */ - int bw_first; /* first write call */ - char_u *bw_conv_buf; /* buffer for writing converted chars */ - int bw_conv_buflen; /* size of bw_conv_buf */ - int bw_conv_error; /* set for conversion error */ - linenr_T bw_conv_error_lnum; /* first line with error or zero */ - linenr_T bw_start_lnum; /* line number at start of buffer */ -# ifdef USE_ICONV - iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */ -# endif -}; - -static int buf_write_bytes(struct bw_info *ip); - -static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, - char_u *endp); -static int ucs2bytes(unsigned c, char_u **pp, int flags); -static int need_conversion(char_u *fenc); -static int get_fio_flags(char_u *ptr); -static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags); -static int make_bom(char_u *buf, char_u *name); -static int move_lines(buf_T *frombuf, buf_T *tobuf); -#ifdef TEMPDIRNAMES -static void vim_settempdir(char_u *tempdir); -#endif -static char *e_auchangedbuf = N_( - "E812: Autocommands changed buffer or buffer name"); - -void filemess(buf_T *buf, char_u *name, char_u *s, int attr) -{ - int msg_scroll_save; - - if (msg_silent != 0) - return; - msg_add_fname(buf, name); /* put file name in IObuff with quotes */ - /* If it's extremely long, truncate it. */ - if (STRLEN(IObuff) > IOSIZE - 80) - IObuff[IOSIZE - 80] = NUL; - STRCAT(IObuff, s); - /* - * For the first message may have to start a new line. - * For further ones overwrite the previous one, reset msg_scroll before - * calling filemess(). - */ - msg_scroll_save = msg_scroll; - if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) - msg_scroll = FALSE; - if (!msg_scroll) /* wait a bit when overwriting an error msg */ - check_for_delay(FALSE); - msg_start(); - msg_scroll = msg_scroll_save; - msg_scrolled_ign = TRUE; - /* may truncate the message to avoid a hit-return prompt */ - msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr); - msg_clr_eos(); - out_flush(); - msg_scrolled_ign = FALSE; -} - -/* - * Read lines from file "fname" into the buffer after line "from". - * - * 1. We allocate blocks with try_malloc, as big as possible. - * 2. Each block is filled with characters from the file with a single read(). - * 3. The lines are inserted in the buffer with ml_append(). - * - * (caller must check that fname != NULL, unless READ_STDIN is used) - * - * "lines_to_skip" is the number of lines that must be skipped - * "lines_to_read" is the number of lines that are appended - * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM. - * - * flags: - * READ_NEW starting to edit a new buffer - * READ_FILTER reading filter output - * READ_STDIN read from stdin instead of a file - * READ_BUFFER read from curbuf instead of a file (converting after reading - * stdin) - * READ_DUMMY read into a dummy buffer (to check if file contents changed) - * READ_KEEP_UNDO don't clear undo info or read it from a file - * - * return FAIL for failure, OK otherwise - */ -int -readfile ( - char_u *fname, - char_u *sfname, - linenr_T from, - linenr_T lines_to_skip, - linenr_T lines_to_read, - exarg_T *eap, /* can be NULL! */ - int flags -) -{ - int fd = 0; - int newfile = (flags & READ_NEW); - int check_readonly; - int filtering = (flags & READ_FILTER); - int read_stdin = (flags & READ_STDIN); - int read_buffer = (flags & READ_BUFFER); - int set_options = newfile || read_buffer - || (eap != NULL && eap->read_edit); - linenr_T read_buf_lnum = 1; /* next line to read from curbuf */ - colnr_T read_buf_col = 0; /* next char to read from this line */ - char_u c; - linenr_T lnum = from; - char_u *ptr = NULL; /* pointer into read buffer */ - char_u *buffer = NULL; /* read buffer */ - char_u *new_buffer = NULL; /* init to shut up gcc */ - char_u *line_start = NULL; /* init to shut up gcc */ - int wasempty; /* buffer was empty before reading */ - colnr_T len; - long size = 0; - char_u *p; - off_t filesize = 0; - int skip_read = FALSE; - char_u *cryptkey = NULL; - int did_ask_for_key = FALSE; - int crypt_method_used; - context_sha256_T sha_ctx; - int read_undo_file = FALSE; - int split = 0; /* number of split lines */ - linenr_T linecnt; - int error = FALSE; /* errors encountered */ - int ff_error = EOL_UNKNOWN; /* file format with errors */ - long linerest = 0; /* remaining chars in line */ -#ifdef UNIX - int perm = 0; - int swap_mode = -1; /* protection bits for swap file */ -#else - int perm; -#endif - int fileformat = 0; /* end-of-line format */ - int keep_fileformat = FALSE; - int file_readonly; - linenr_T skip_count = 0; - linenr_T read_count = 0; - int msg_save = msg_scroll; - linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of - * last read was missing the eol */ - int try_mac = (vim_strchr(p_ffs, 'm') != NULL); - int try_dos = (vim_strchr(p_ffs, 'd') != NULL); - int try_unix = (vim_strchr(p_ffs, 'x') != NULL); - int file_rewind = FALSE; - int can_retry; - linenr_T conv_error = 0; /* line nr with conversion error */ - linenr_T illegal_byte = 0; /* line nr with illegal byte */ - int keep_dest_enc = FALSE; /* don't retry when char doesn't fit - in destination encoding */ - int bad_char_behavior = BAD_REPLACE; - /* BAD_KEEP, BAD_DROP or character to - * replace with */ - char_u *tmpname = NULL; /* name of 'charconvert' output file */ - int fio_flags = 0; - char_u *fenc; /* fileencoding to use */ - int fenc_alloced; /* fenc_next is in allocated memory */ - char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */ - int advance_fenc = FALSE; - long real_size = 0; -# ifdef USE_ICONV - iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */ - int did_iconv = FALSE; /* TRUE when iconv() failed and trying - 'charconvert' next */ -# endif - int converted = FALSE; /* TRUE if conversion done */ - int notconverted = FALSE; /* TRUE if conversion wanted but it - wasn't possible */ - char_u conv_rest[CONV_RESTLEN]; - int conv_restlen = 0; /* nr of bytes in conv_rest[] */ - buf_T *old_curbuf; - char_u *old_b_ffname; - char_u *old_b_fname; - int using_b_ffname; - int using_b_fname; - - curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */ - - /* - * If there is no file name yet, use the one for the read file. - * BF_NOTEDITED is set to reflect this. - * Don't do this for a read from a filter. - * Only do this when 'cpoptions' contains the 'f' flag. - */ - if (curbuf->b_ffname == NULL - && !filtering - && fname != NULL - && vim_strchr(p_cpo, CPO_FNAMER) != NULL - && !(flags & READ_DUMMY)) { - if (set_rw_fname(fname, sfname) == FAIL) - return FAIL; - } - - /* Remember the initial values of curbuf, curbuf->b_ffname and - * curbuf->b_fname to detect whether they are altered as a result of - * executing nasty autocommands. Also check if "fname" and "sfname" - * point to one of these values. */ - old_curbuf = curbuf; - old_b_ffname = curbuf->b_ffname; - old_b_fname = curbuf->b_fname; - using_b_ffname = (fname == curbuf->b_ffname) - || (sfname == curbuf->b_ffname); - using_b_fname = (fname == curbuf->b_fname) || (sfname == curbuf->b_fname); - - /* After reading a file the cursor line changes but we don't want to - * display the line. */ - ex_no_reprint = TRUE; - - /* don't display the file info for another buffer now */ - need_fileinfo = FALSE; - - /* - * For Unix: Use the short file name whenever possible. - * Avoids problems with networks and when directory names are changed. - * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to - * another directory, which we don't detect. - */ - if (sfname == NULL) - sfname = fname; -#if defined(UNIX) - fname = sfname; -#endif - - /* - * The BufReadCmd and FileReadCmd events intercept the reading process by - * executing the associated commands instead. - */ - if (!filtering && !read_stdin && !read_buffer) { - pos_T pos; - - pos = curbuf->b_op_start; - - /* Set '[ mark to the line above where the lines go (line 1 if zero). */ - curbuf->b_op_start.lnum = ((from == 0) ? 1 : from); - curbuf->b_op_start.col = 0; - - if (newfile) { - if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, - FALSE, curbuf, eap)) - return aborting() ? FAIL : OK; - } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, - FALSE, NULL, eap)) - return aborting() ? FAIL : OK; - - curbuf->b_op_start = pos; - } - - if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) - msg_scroll = FALSE; /* overwrite previous file message */ - else - msg_scroll = TRUE; /* don't overwrite previous file message */ - - /* - * If the name ends in a path separator, we can't open it. Check here, - * because reading the file may actually work, but then creating the swap - * file may destroy it! Reported on MS-DOS and Win 95. - * If the name is too long we might crash further on, quit here. - */ - if (fname != NULL && *fname != NUL) { - p = fname + STRLEN(fname); - if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL) { - filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0); - msg_end(); - msg_scroll = msg_save; - return FAIL; - } - } - - if (!read_stdin && !read_buffer) { -#ifdef UNIX - /* - * On Unix it is possible to read a directory, so we have to - * check for it before the mch_open(). - */ - perm = os_getperm(fname); - if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */ -# ifdef S_ISFIFO - && !S_ISFIFO(perm) /* ... or fifo */ -# endif -# ifdef S_ISSOCK - && !S_ISSOCK(perm) /* ... or socket */ -# endif -# ifdef OPEN_CHR_FILES - && !(S_ISCHR(perm) && is_dev_fd_file(fname)) - /* ... or a character special file named /dev/fd/<n> */ -# endif - ) { - if (S_ISDIR(perm)) - filemess(curbuf, fname, (char_u *)_("is a directory"), 0); - else - filemess(curbuf, fname, (char_u *)_("is not a file"), 0); - msg_end(); - msg_scroll = msg_save; - return FAIL; - } -#endif - } - - /* Set default or forced 'fileformat' and 'binary'. */ - set_file_options(set_options, eap); - - /* - * When opening a new file we take the readonly flag from the file. - * Default is r/w, can be set to r/o below. - * Don't reset it when in readonly mode - * Only set/reset b_p_ro when BF_CHECK_RO is set. - */ - check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO)); - if (check_readonly && !readonlymode) - curbuf->b_p_ro = FALSE; - - if (newfile && !read_stdin && !read_buffer) { - /* Remember time of file. */ - FileInfo file_info; - if (os_get_file_info((char *)fname, &file_info)) { - buf_store_file_info(curbuf, &file_info); - curbuf->b_mtime_read = curbuf->b_mtime; -#ifdef UNIX - /* - * Use the protection bits of the original file for the swap file. - * This makes it possible for others to read the name of the - * edited file from the swapfile, but only if they can read the - * edited file. - * Remove the "write" and "execute" bits for group and others - * (they must not write the swapfile). - * Add the "read" and "write" bits for the user, otherwise we may - * not be able to write to the file ourselves. - * Setting the bits is done below, after creating the swap file. - */ - swap_mode = (file_info.stat.st_mode & 0644) | 0600; -#endif - } else { - curbuf->b_mtime = 0; - curbuf->b_mtime_read = 0; - curbuf->b_orig_size = 0; - curbuf->b_orig_mode = 0; - } - - /* Reset the "new file" flag. It will be set again below when the - * file doesn't exist. */ - curbuf->b_flags &= ~(BF_NEW | BF_NEW_W); - } - - /* - * Check readonly by trying to open the file for writing. - * If this fails, we know that the file is readonly. - */ - file_readonly = FALSE; - if (!read_buffer && !read_stdin) { - if (!newfile || readonlymode) { - file_readonly = TRUE; - } else if ((fd = mch_open((char *)fname, O_RDWR, 0)) < 0) { - // opening in readwrite mode failed => file is readonly - file_readonly = TRUE; - } - if (file_readonly == TRUE) { - // try to open readonly - fd = mch_open((char *)fname, O_RDONLY, 0); - } - } - - if (fd < 0) { /* cannot open at all */ - msg_scroll = msg_save; -#ifndef UNIX - /* - * On non-unix systems we can't open a directory, check here. - */ - perm = os_getperm(fname); /* check if the file exists */ - if (os_isdir(fname)) { - filemess(curbuf, sfname, (char_u *)_("is a directory"), 0); - curbuf->b_p_ro = TRUE; /* must use "w!" now */ - } else -#endif - if (newfile) { - if (perm < 0 -#ifdef ENOENT - && errno == ENOENT -#endif - ) { - /* - * Set the 'new-file' flag, so that when the file has - * been created by someone else, a ":w" will complain. - */ - curbuf->b_flags |= BF_NEW; - - /* Create a swap file now, so that other Vims are warned - * that we are editing this file. Don't do this for a - * "nofile" or "nowrite" buffer type. */ - if (!bt_dontwrite(curbuf)) { - check_need_swap(newfile); - /* SwapExists autocommand may mess things up */ - if (curbuf != old_curbuf - || (using_b_ffname - && (old_b_ffname != curbuf->b_ffname)) - || (using_b_fname - && (old_b_fname != curbuf->b_fname))) { - EMSG(_(e_auchangedbuf)); - return FAIL; - } - } - if (dir_of_file_exists(fname)) - filemess(curbuf, sfname, (char_u *)_("[New File]"), 0); - else - filemess(curbuf, sfname, - (char_u *)_("[New DIRECTORY]"), 0); - /* Even though this is a new file, it might have been - * edited before and deleted. Get the old marks. */ - check_marks_read(); - /* Set forced 'fileencoding'. */ - if (eap != NULL) - set_forced_fenc(eap); - apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname, - FALSE, curbuf, eap); - /* remember the current fileformat */ - save_file_ff(curbuf); - - if (aborting()) /* autocmds may abort script processing */ - return FAIL; - return OK; /* a new file is not an error */ - } else { - filemess(curbuf, sfname, (char_u *)( -# ifdef EFBIG - (errno == EFBIG) ? _("[File too big]") : -# endif -# ifdef EOVERFLOW - (errno == EOVERFLOW) ? _("[File too big]") : -# endif - _("[Permission Denied]")), 0); - curbuf->b_p_ro = TRUE; /* must use "w!" now */ - } - } - - return FAIL; - } - - /* - * Only set the 'ro' flag for readonly files the first time they are - * loaded. Help files always get readonly mode - */ - if ((check_readonly && file_readonly) || curbuf->b_help) - curbuf->b_p_ro = TRUE; - - if (set_options) { - /* Don't change 'eol' if reading from buffer as it will already be - * correctly set when reading stdin. */ - if (!read_buffer) { - curbuf->b_p_eol = TRUE; - curbuf->b_start_eol = TRUE; - } - curbuf->b_p_bomb = FALSE; - curbuf->b_start_bomb = FALSE; - } - - /* Create a swap file now, so that other Vims are warned that we are - * editing this file. - * Don't do this for a "nofile" or "nowrite" buffer type. */ - if (!bt_dontwrite(curbuf)) { - check_need_swap(newfile); - if (!read_stdin && (curbuf != old_curbuf - || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) - || (using_b_fname && - (old_b_fname != curbuf->b_fname)))) { - EMSG(_(e_auchangedbuf)); - if (!read_buffer) - close(fd); - return FAIL; - } -#ifdef UNIX - /* Set swap file protection bits after creating it. */ - if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL - && curbuf->b_ml.ml_mfp->mf_fname != NULL) - (void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode); -#endif - } - -#if defined(HAS_SWAP_EXISTS_ACTION) - /* If "Quit" selected at ATTENTION dialog, don't load the file */ - if (swap_exists_action == SEA_QUIT) { - if (!read_buffer && !read_stdin) - close(fd); - return FAIL; - } -#endif - - ++no_wait_return; /* don't wait for return yet */ - - /* - * Set '[ mark to the line above where the lines go (line 1 if zero). - */ - curbuf->b_op_start.lnum = ((from == 0) ? 1 : from); - curbuf->b_op_start.col = 0; - - if (!read_buffer) { - int m = msg_scroll; - int n = msg_scrolled; - - /* - * The file must be closed again, the autocommands may want to change - * the file before reading it. - */ - if (!read_stdin) - close(fd); /* ignore errors */ - - /* - * The output from the autocommands should not overwrite anything and - * should not be overwritten: Set msg_scroll, restore its value if no - * output was done. - */ - msg_scroll = TRUE; - if (filtering) - apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname, - FALSE, curbuf, eap); - else if (read_stdin) - apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname, - FALSE, curbuf, eap); - else if (newfile) - apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname, - FALSE, curbuf, eap); - else - apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname, - FALSE, NULL, eap); - if (msg_scrolled == n) - msg_scroll = m; - - if (aborting()) { /* autocmds may abort script processing */ - --no_wait_return; - msg_scroll = msg_save; - curbuf->b_p_ro = TRUE; /* must use "w!" now */ - return FAIL; - } - /* - * Don't allow the autocommands to change the current buffer. - * Try to re-open the file. - * - * Don't allow the autocommands to change the buffer name either - * (cd for example) if it invalidates fname or sfname. - */ - if (!read_stdin && (curbuf != old_curbuf - || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) - || (using_b_fname && (old_b_fname != curbuf->b_fname)) - || (fd = - mch_open((char *)fname, O_RDONLY, - 0)) < 0)) { - --no_wait_return; - msg_scroll = msg_save; - if (fd < 0) - EMSG(_("E200: *ReadPre autocommands made the file unreadable")); - else - EMSG(_("E201: *ReadPre autocommands must not change current buffer")); - curbuf->b_p_ro = TRUE; /* must use "w!" now */ - return FAIL; - } - } - - /* Autocommands may add lines to the file, need to check if it is empty */ - wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY); - - if (!recoverymode && !filtering && !(flags & READ_DUMMY)) { - /* - * Show the user that we are busy reading the input. Sometimes this - * may take a while. When reading from stdin another program may - * still be running, don't move the cursor to the last line, unless - * always using the GUI. - */ - if (read_stdin) { - mch_msg(_("Vim: Reading from stdin...\n")); - } else if (!read_buffer) - filemess(curbuf, sfname, (char_u *)"", 0); - } - - msg_scroll = FALSE; /* overwrite the file message */ - - /* - * Set linecnt now, before the "retry" caused by a wrong guess for - * fileformat, and after the autocommands, which may change them. - */ - linecnt = curbuf->b_ml.ml_line_count; - - /* "++bad=" argument. */ - if (eap != NULL && eap->bad_char != 0) { - bad_char_behavior = eap->bad_char; - if (set_options) - curbuf->b_bad_char = eap->bad_char; - } else - curbuf->b_bad_char = 0; - - /* - * Decide which 'encoding' to use or use first. - */ - if (eap != NULL && eap->force_enc != 0) { - fenc = enc_canonize(eap->cmd + eap->force_enc); - fenc_alloced = TRUE; - keep_dest_enc = TRUE; - } else if (curbuf->b_p_bin) { - fenc = (char_u *)""; /* binary: don't convert */ - fenc_alloced = FALSE; - } else if (curbuf->b_help) { - char_u firstline[80]; - int fc; - - /* Help files are either utf-8 or latin1. Try utf-8 first, if this - * fails it must be latin1. - * Always do this when 'encoding' is "utf-8". Otherwise only do - * this when needed to avoid [converted] remarks all the time. - * It is needed when the first line contains non-ASCII characters. - * That is only in *.??x files. */ - fenc = (char_u *)"latin1"; - c = enc_utf8; - if (!c && !read_stdin) { - fc = fname[STRLEN(fname) - 1]; - if (TOLOWER_ASC(fc) == 'x') { - /* Read the first line (and a bit more). Immediately rewind to - * the start of the file. If the read() fails "len" is -1. */ - len = read_eintr(fd, firstline, 80); - lseek(fd, (off_t)0L, SEEK_SET); - for (p = firstline; p < firstline + len; ++p) - if (*p >= 0x80) { - c = TRUE; - break; - } - } - } - - if (c) { - fenc_next = fenc; - fenc = (char_u *)"utf-8"; - - /* When the file is utf-8 but a character doesn't fit in - * 'encoding' don't retry. In help text editing utf-8 bytes - * doesn't make sense. */ - if (!enc_utf8) - keep_dest_enc = TRUE; - } - fenc_alloced = FALSE; - } else if (*p_fencs == NUL) { - fenc = curbuf->b_p_fenc; /* use format from buffer */ - fenc_alloced = FALSE; - } else { - fenc_next = p_fencs; /* try items in 'fileencodings' */ - fenc = next_fenc(&fenc_next); - fenc_alloced = TRUE; - } - - /* - * Jump back here to retry reading the file in different ways. - * Reasons to retry: - * - encoding conversion failed: try another one from "fenc_next" - * - BOM detected and fenc was set, need to setup conversion - * - "fileformat" check failed: try another - * - * Variables set for special retry actions: - * "file_rewind" Rewind the file to start reading it again. - * "advance_fenc" Advance "fenc" using "fenc_next". - * "skip_read" Re-use already read bytes (BOM detected). - * "did_iconv" iconv() conversion failed, try 'charconvert'. - * "keep_fileformat" Don't reset "fileformat". - * - * Other status indicators: - * "tmpname" When != NULL did conversion with 'charconvert'. - * Output file has to be deleted afterwards. - * "iconv_fd" When != -1 did conversion with iconv(). - */ -retry: - - if (file_rewind) { - if (read_buffer) { - read_buf_lnum = 1; - read_buf_col = 0; - } else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0) { - /* Can't rewind the file, give up. */ - error = TRUE; - goto failed; - } - /* Delete the previously read lines. */ - while (lnum > from) - ml_delete(lnum--, FALSE); - file_rewind = FALSE; - if (set_options) { - curbuf->b_p_bomb = FALSE; - curbuf->b_start_bomb = FALSE; - } - conv_error = 0; - } - - if (cryptkey != NULL) - /* Need to reset the state, but keep the key, don't want to ask for it - * again. */ - crypt_pop_state(); - - /* - * When retrying with another "fenc" and the first time "fileformat" - * will be reset. - */ - if (keep_fileformat) - keep_fileformat = FALSE; - else { - if (eap != NULL && eap->force_ff != 0) { - fileformat = get_fileformat_force(curbuf, eap); - try_unix = try_dos = try_mac = FALSE; - } else if (curbuf->b_p_bin) - fileformat = EOL_UNIX; /* binary: use Unix format */ - else if (*p_ffs == NUL) - fileformat = get_fileformat(curbuf); /* use format from buffer */ - else - fileformat = EOL_UNKNOWN; /* detect from file */ - } - -# ifdef USE_ICONV - if (iconv_fd != (iconv_t)-1) { - /* aborted conversion with iconv(), close the descriptor */ - iconv_close(iconv_fd); - iconv_fd = (iconv_t)-1; - } -# endif - - if (advance_fenc) { - /* - * Try the next entry in 'fileencodings'. - */ - advance_fenc = FALSE; - - if (eap != NULL && eap->force_enc != 0) { - /* Conversion given with "++cc=" wasn't possible, read - * without conversion. */ - notconverted = TRUE; - conv_error = 0; - if (fenc_alloced) - free(fenc); - fenc = (char_u *)""; - fenc_alloced = FALSE; - } else { - if (fenc_alloced) - free(fenc); - if (fenc_next != NULL) { - fenc = next_fenc(&fenc_next); - fenc_alloced = (fenc_next != NULL); - } else { - fenc = (char_u *)""; - fenc_alloced = FALSE; - } - } - if (tmpname != NULL) { - os_remove((char *)tmpname); // delete converted file - free(tmpname); - tmpname = NULL; - } - } - - /* - * Conversion may be required when the encoding of the file is different - * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. - */ - fio_flags = 0; - converted = need_conversion(fenc); - if (converted) { - - /* "ucs-bom" means we need to check the first bytes of the file - * for a BOM. */ - if (STRCMP(fenc, ENC_UCSBOM) == 0) - fio_flags = FIO_UCSBOM; - - /* - * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be - * done. This is handled below after read(). Prepare the - * fio_flags to avoid having to parse the string each time. - * Also check for Unicode to Latin1 conversion, because iconv() - * appears not to handle this correctly. This works just like - * conversion to UTF-8 except how the resulting character is put in - * the buffer. - */ - else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0) - fio_flags = get_fio_flags(fenc); - - - -# ifdef USE_ICONV - /* - * Try using iconv() if we can't convert internally. - */ - if (fio_flags == 0 - && !did_iconv - ) - iconv_fd = (iconv_t)my_iconv_open( - enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc); -# endif - - /* - * Use the 'charconvert' expression when conversion is required - * and we can't do it internally or with iconv(). - */ - if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL -# ifdef USE_ICONV - && iconv_fd == (iconv_t)-1 -# endif - ) { -# ifdef USE_ICONV - did_iconv = FALSE; -# endif - /* Skip conversion when it's already done (retry for wrong - * "fileformat"). */ - if (tmpname == NULL) { - tmpname = readfile_charconvert(fname, fenc, &fd); - if (tmpname == NULL) { - /* Conversion failed. Try another one. */ - advance_fenc = TRUE; - if (fd < 0) { - /* Re-opening the original file failed! */ - EMSG(_("E202: Conversion made file unreadable!")); - error = TRUE; - goto failed; - } - goto retry; - } - } - } else { - if (fio_flags == 0 -# ifdef USE_ICONV - && iconv_fd == (iconv_t)-1 -# endif - ) { - /* Conversion wanted but we can't. - * Try the next conversion in 'fileencodings' */ - advance_fenc = TRUE; - goto retry; - } - } - } - - /* Set "can_retry" when it's possible to rewind the file and try with - * another "fenc" value. It's FALSE when no other "fenc" to try, reading - * stdin or fixed at a specific encoding. */ - can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc); - - if (!skip_read) { - linerest = 0; - filesize = 0; - skip_count = lines_to_skip; - read_count = lines_to_read; - conv_restlen = 0; - read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0 - && curbuf->b_ffname != NULL - && curbuf->b_p_udf - && !filtering - && !read_stdin - && !read_buffer); - if (read_undo_file) - sha256_start(&sha_ctx); - } - - while (!error && !got_int) { - /* - * We allocate as much space for the file as we can get, plus - * space for the old line plus room for one terminating NUL. - * The amount is limited by the fact that read() only can read - * upto max_unsigned characters (and other things). - */ - { - if (!skip_read) { - size = 0x10000L; /* use buffer >= 64K */ - - for (; size >= 10; size /= 2) { - new_buffer = verbose_try_malloc((size_t)size + (size_t)linerest + 1); - if (new_buffer) { - break; - } - } - if (new_buffer == NULL) { - error = TRUE; - break; - } - if (linerest) /* copy characters from the previous buffer */ - memmove(new_buffer, ptr - l |