aboutsummaryrefslogtreecommitdiff
path: root/src/fileio.c
diff options
context:
space:
mode:
authorEliseo Martínez <eliseomarmol@gmail.com>2014-05-12 02:25:17 +0200
committerEliseo Martínez <eliseomarmol@gmail.com>2014-05-15 20:46:01 +0200
commitda51dc9cf202772f60bd2da975dbef257bd9237c (patch)
tree5c16b93238a153f55634e9323077f30c8133970c /src/fileio.c
parentffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff)
downloadrneovim-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.c8148
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