move_lines(buf_T *frombuf, buf_T *tobuf)
{
    buf_T	*tbuf = curbuf;
    int		retval = OK;
    linenr_T	lnum;
    char_u	*p;

    /* Copy the lines in "frombuf" to "tobuf". */
    curbuf = tobuf;
    for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
    {
	p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
	if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
	{
	    vim_free(p);
	    retval = FAIL;
	    break;
	}
	vim_free(p);
    }

    /* Delete all the lines in "frombuf". */
    if (retval != FAIL)
    {
	curbuf = frombuf;
	for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
	    if (ml_delete(lnum, FALSE) == FAIL)
	    {
		/* Oops!  We could try putting back the saved lines, but that
		 * might fail again... */
		retval = FAIL;
		break;
	    }
    }

    curbuf = tbuf;
    return retval;
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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_ALL	    -3	    /* all autocmd groups */

# define FIO_UCSBOM	0x4000	/* check for BOM at start of file */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static int au_did_filetype

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		read_fifo = (flags & READ_FIFO);

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);


set_context_in_autocmd(
    expand_T	*xp,
    char_u	*arg,
    int		doautocmd)	/* TRUE for :doauto*, FALSE for :autocmd */
{
    char_u	*p;
    int		group;

    /* check for a group name, skip it if present */
    include_groups = FALSE;
    p = arg;
    group = au_get_grouparg(&arg);
    if (group == AUGROUP_ERROR)
	return NULL;
    /* If there only is a group name that's what we expand. */
    if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
    {
	arg = p;
	group = AUGROUP_ALL;
    }

    /* skip over event name */
    for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
	if (*p == ',')
	    arg = p + 1;
    if (*p == NUL)
    {
	if (group == AUGROUP_ALL)
	    include_groups = TRUE;
	xp->xp_context = EXPAND_EVENTS;	    /* expand event name */
	xp->xp_pattern = arg;
	return NULL;
    }

    /* skip over pattern */
    arg = skipwhite(p);
    while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
	arg++;
    if (*arg)
	return arg;			    /* expand (next) command */

    if (doautocmd)
	xp->xp_context = EXPAND_FILES;	    /* expand file names */
    else
	xp->xp_context = EXPAND_NOTHING;    /* pattern is not expanded */
    return NULL;
}

patch 8.0.1263: others can read the swap file if a user is careless

Problem:    Others can read the swap file if a user is careless with his
            primary group.
Solution:   If the group permission allows for reading but the world
            permissions doesn't, make sure the group is right.

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_NOCONVERT	0x2000	/* skip encoding conversion */

# define FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

int		fd = 0;

int		newfile = (flags & READ_NEW);

int		check_readonly;

int		filtering = (flags & READ_FILTER);


modname(
    char_u *fname,
    char_u *ext,
    int	    prepend_dot)	/* may prepend a '.' to file name */
{
    return buf_modname((curbuf->b_p_sn || curbuf->b_shortname),
						     fname, ext, prepend_dot);
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

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		read_fifo = (flags & READ_FIFO);

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);

char_u	c;


trigger_cursorhold(void)
{
    int		state;

    if (!did_cursorhold
	    && has_cursorhold()
	    && !Recording
	    && typebuf.tb_len == 0
#ifdef FEAT_INS_EXPAND
	    && !ins_compl_active()
#endif
	    )
    {
	state = get_real_state();
	if (state == NORMAL_BUSY || (state & INSERT) != 0)
	    return TRUE;
    }
    return FALSE;
}

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

static void check_marks_read(void);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

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, stat_T *s);

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);

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#endif
}

static int  buf_write_bytes(struct bw_info *ip);

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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static int au_did_filetype

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		read_fifo = (flags & READ_FIFO);

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);

int		wasempty;

int		skip_read = FALSE;

int		did_ask_for_key = FALSE;

int		read_undo_file = FALSE;

int		split = 0;

int		error = FALSE;

int		ff_error = EOL_UNKNOWN;

int		perm = 0;

int		swap_mode = -1;

int		perm;


buf_reload(buf_T *buf, int orig_mode)
{
    exarg_T	ea;
    pos_T	old_cursor;
    linenr_T	old_topline;
    int		old_ro = buf->b_p_ro;
    buf_T	*savebuf;
    bufref_T	bufref;
    int		saved = OK;
    aco_save_T	aco;
    int		flags = READ_NEW;

    /* set curwin/curbuf for "buf" and save some things */
    aucmd_prepbuf(&aco, buf);

    /* We only want to read the text from the file, not reset the syntax
     * highlighting, clear marks, diff status, etc.  Force the fileformat
     * and encoding to be the same. */
    if (prep_exarg(&ea, buf) == OK)
    {
	old_cursor = curwin->w_cursor;
	old_topline = curwin->w_topline;

	if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
	{
	    /* Save all the text, so that the reload can be undone.
	     * Sync first so that this is a separate undo-able action. */
	    u_sync(FALSE);
	    saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
	    flags |= READ_KEEP_UNDO;
	}

	/*
	 * To behave like when a new file is edited (matters for
	 * BufReadPost autocommands) we first need to delete the current
	 * buffer contents.  But if reading the file fails we should keep
	 * the old contents.  Can't use memory only, the file might be
	 * too big.  Use a hidden buffer to move the buffer contents to.
	 */
	if (BUFEMPTY() || saved == FAIL)
	    savebuf = NULL;
	else
	{
	    /* Allocate a buffer without putting it in the buffer list. */
	    savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
	    set_bufref(&bufref, savebuf);
	    if (savebuf != NULL && buf == curbuf)
	    {
		/* Open the memline. */
		curbuf = savebuf;
		curwin->w_buffer = savebuf;
		saved = ml_open(curbuf);
		curbuf = buf;
		curwin->w_buffer = buf;
	    }
	    if (savebuf == NULL || saved == FAIL || buf != curbuf
				      || move_lines(buf, savebuf) == FAIL)
	    {
		EMSG2(_("E462: Could not prepare for reloading \"%s\""),
							    buf->b_fname);
		saved = FAIL;
	    }
	}

	if (saved == OK)
	{
	    curbuf->b_flags |= BF_CHECK_RO;	/* check for RO again */
#ifdef FEAT_AUTOCMD
	    keep_filetype = TRUE;		/* don't detect 'filetype' */
#endif
	    if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
			(linenr_T)0,
			(linenr_T)MAXLNUM, &ea, flags) != OK)
	    {
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
		if (!aborting())
#endif
		    EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
		if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf)
		{
		    /* Put the text back from the save buffer.  First
		     * delete any lines that readfile() added. */
		    while (!BUFEMPTY())
			if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
			    break;
		    (void)move_lines(savebuf, buf);
		}
	    }
	    else if (buf == curbuf)  /* "buf" still valid */
	    {
		/* Mark the buffer as unmodified and free undo info. */
		unchanged(buf, TRUE);
		if ((flags & READ_KEEP_UNDO) == 0)
		{
		    u_blockfree(buf);
		    u_clearall(buf);
		}
		else
		{
		    /* Mark all undo states as changed. */
		    u_unchanged(curbuf);
		}
	    }
	}
	vim_free(ea.cmd);

	if (savebuf != NULL && bufref_valid(&bufref))
	    wipe_buffer(savebuf, FALSE);

#ifdef FEAT_DIFF
	/* Invalidate diff info if necessary. */
	diff_invalidate(curbuf);
#endif

	/* Restore the topline and cursor position and check it (lines may
	 * have been removed). */
	if (old_topline > curbuf->b_ml.ml_line_count)
	    curwin->w_topline = curbuf->b_ml.ml_line_count;
	else
	    curwin->w_topline = old_topline;
	curwin->w_cursor = old_cursor;
	check_cursor();
	update_topline();
#ifdef FEAT_AUTOCMD
	keep_filetype = FALSE;
#endif
#ifdef FEAT_FOLDING
	{
	    win_T	*wp;
	    tabpage_T	*tp;

	    /* Update folds unless they are defined manually. */
	    FOR_ALL_TAB_WINDOWS(tp, wp)
		if (wp->w_buffer == curwin->w_buffer
			&& !foldmethodIsManual(wp))
		    foldUpdateAll(wp);
	}
#endif
	/* If the mode didn't change and 'readonly' was set, keep the old
	 * value; the user probably used the ":view" command.  But don't
	 * reset it, might have had a read error. */
	if (orig_mode == curbuf->b_orig_mode)
	    curbuf->b_p_ro |= old_ro;

	/* Modelines must override settings done by autocommands. */
	do_modelines(0);
    }

    /* restore curwin/curbuf and a few other things */
    aucmd_restbuf(&aco);
    /* Careful: autocommands may have made "buf" invalid! */
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

static void check_marks_read(void);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

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, stat_T *s);

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_ALL	    -3	    /* all autocmd groups */

#  define FIO_GET_CP(x)	(((x)>>16) & 0xffff)	/* get codepage from top word */

# 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 */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);


set_file_time(
    char_u  *fname,
    time_t  atime,	    /* access time */
    time_t  mtime)	    /* modification time */
{
# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
    struct utimbuf  buf;

    buf.actime	= atime;
    buf.modtime	= mtime;
    (void)utime((char *)fname, &buf);
# else
#  if defined(HAVE_UTIMES)
    struct timeval  tvp[2];

    tvp[0].tv_sec   = atime;
    tvp[0].tv_usec  = 0;
    tvp[1].tv_sec   = mtime;
    tvp[1].tv_usec  = 0;
#   ifdef NeXT
    (void)utimes((char *)fname, tvp);
#   else
    (void)utimes((char *)fname, (const struct timeval *)&tvp);
#   endif
#  endif
# endif
}

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 char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static void msg_add_eol(void);

static int check_mtime(buf_T *buf, stat_T *s);

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);

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

char_u	c;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

char_u	*p;

char_u	*cryptkey = NULL;

char_u	*tmpname = NULL;

char_u	*fenc;

char_u	*fenc_next = NULL;

char_u	conv_rest[CONV_RESTLEN];

char_u	*old_b_ffname;

char_u	*old_b_fname;

char_u	    *backup = NULL;

char_u	    *ffname;

char_u	    *wfname = NULL;

char_u	    *s;

char_u	    *ptr;

char_u	    c;

char_u	    *errmsg = NULL;


vim_fgets(char_u *buf, int size, FILE *fp)
{
    char	*eof;
#define FGETS_SIZE 200
    char	tbuf[FGETS_SIZE];

    buf[size - 2] = NUL;
#ifdef USE_CR
    eof = fgets_cr((char *)buf, size, fp);
#else
    eof = fgets((char *)buf, size, fp);
#endif
    if (buf[size - 2] != NUL && buf[size - 2] != '\n')
    {
	buf[size - 1] = NUL;	    /* Truncate the line */

	/* Now throw away the rest of the line: */
	do
	{
	    tbuf[FGETS_SIZE - 2] = NUL;
#ifdef USE_CR
	    ignoredp = fgets_cr((char *)tbuf, FGETS_SIZE, fp);
#else
	    ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
#endif
	} while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
    }
    return (eof == NULL);
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

#define USE_MCH_ACCESS

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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_CODEPAGE	0x20	/* convert MS-Windows codepage */

#  define FIO_PUT_CP(x) (((x) & 0xffff) << 16)	/* put codepage in top word */

#  define FIO_GET_CP(x)	(((x)>>16) & 0xffff)	/* get codepage from top word */

#  define FIO_MACROMAN	0x20	/* convert MacRoman */

# 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 */

#define CONV_RESTLEN 30

#define ICONV_MULT 8


aucmd_restbuf(
    aco_save_T	*aco)		/* structure holding saved values */
{
    --curbuf->b_nwindows;
    curbuf = aco->save_curbuf;
    curwin->w_buffer = curbuf;
    ++curbuf->b_nwindows;
}

char_u	c;

stat_T	st;

int		    fd;

int		    len;

int		    bufsize;

long	    perm;

int		    attr;

#define USE_MCH_ACCESS

colnr_T	len;

char_u	*p;

int		perm;

int		try_mac;

int		try_unix;

int		can_retry;

int		    dobackup;

char_u	    c;

long	    nchars;

int		    overwriting;

int		    checking_conversion;

int		    fileformat;

int		    write_bin;

static int	last_group;

# define HAS_BW_FLAGS

#define ICONV_MULT 8

int		check_readonly;

int		wasempty;

long	size = 0;

int		error = FALSE;

int		file_readonly;

int		try_dos;

char_u	*fenc;

int		using_b_fname;

char_u	    *s;

char_u	    *ptr;

char_u	    *buffer;

int		    retval = OK;

int		    device = FALSE;

stat_T	    st_old;

int		    converted = FALSE;

static void au_cleanup(void);

static event_T	last_event;

static void check_marks_read(void);

static int au_did_filetype

int		fd = 0;

linenr_T	linecnt;

int		fenc_alloced;

long	real_size = 0;

int		converted = FALSE;

int		notconverted = FALSE;

int		using_b_ffname;

int		    backup_copy = FALSE;

char_u	    *ffname;

int		    errmsg_allocated = FALSE;

char_u	    *backup_ext;

int		    newfile = FALSE;

struct bw_info  write_info;

int		    notconverted = FALSE;

char_u	    *fenc;

static int include_groups = FALSE;

static void msg_add_eol(void);

#define CONV_RESTLEN 30

char_u	*ptr = NULL;

char_u	*buffer = NULL;

off_T	filesize = 0;

int		skip_read = FALSE;

int		read_undo_file = FALSE;

int		split = 0;

long	linerest = 0;

int		perm = 0;

int		swap_mode = -1;

int		fileformat = 0;

int		msg_save = msg_scroll;

int		file_rewind = FALSE;

buf_T	*old_curbuf;

char_u	*old_b_fname;

char_u	    *backup = NULL;

linenr_T	    lnum;

char_u	    *errmsg = NULL;

int		    msg_save = msg_scroll;

int		    no_eol = FALSE;

int		    file_readonly = FALSE;

int		    made_writable = FALSE;

int		    wb_flags = 0;

vim_acl_T	    acl = NULL;

int		    write_undo_file = FALSE;

static int already_warned = FALSE;

static long	temp_count = 0;

static int au_need_clean = FALSE;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

char_u	*cryptkey = NULL;

context_sha256_T sha_ctx;

int		ff_error = EOL_UNKNOWN;

int		keep_fileformat = FALSE;

int		keep_dest_enc = FALSE;

char_u	*tmpname = NULL;

int		fio_flags = 0;

char_u	*fenc_next = NULL;

int		advance_fenc = FALSE;

int		did_iconv = FALSE;

char_u	*old_b_ffname;

char_u	    *wfname = NULL;

char_u	    *errnum = NULL;

static int event_ignored(event_T event);

static int au_find_group(char_u *name);

static int need_conversion(char_u *fenc);

colnr_T	read_buf_col = 0;

linenr_T	lnum = from;

int		did_ask_for_key = FALSE;

linenr_T	read_count = 0;

int		bad_char_behavior = BAD_REPLACE;

int		conv_restlen = 0;


vim_tempname(
    int	    extra_char UNUSED,  /* char to use in the name instead of '?' */
    int	    keep UNUSED)
{
#ifdef USE_TMPNAM
    char_u	itmp[L_tmpnam];	/* use tmpnam() */
#else
    char_u	itmp[TEMPNAMELEN];
#endif

#ifdef TEMPDIRNAMES
    static char	*(tempdirs[]) = {TEMPDIRNAMES};
    int		i;
# ifndef EEXIST
    stat_T	st;
# endif

    /*
     * This will create a directory for private use by this instance of Vim.
     * This is done once, and the same directory is used for all temp files.
     * This method avoids security problems because of symlink attacks et al.
     * It's also a bit faster, because we only need to check for an existing
     * file when creating the directory and not for each temp file.
     */
    if (vim_tempdir == NULL)
    {
	/*
	 * Try the entries in TEMPDIRNAMES to create the temp directory.
	 */
	for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
	{
# ifndef HAVE_MKDTEMP
	    size_t	itmplen;
	    long	nr;
	    long	off;
# endif

	    /* Expand $TMP, leave room for "/v1100000/999999999".
	     * Skip the directory check if the expansion fails. */
	    expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
	    if (itmp[0] != '$' && mch_isdir(itmp))
	    {
		/* directory exists */
		add_pathsep(itmp);

# ifdef HAVE_MKDTEMP
		{
#  if defined(UNIX) || defined(VMS)
		    /* Make sure the umask doesn't remove the executable bit.
		     * "repl" has been reported to use "177". */
		    mode_t	umask_save = umask(077);
#  endif
		    /* Leave room for filename */
		    STRCAT(itmp, "vXXXXXX");
		    if (mkdtemp((char *)itmp) != NULL)
			vim_settempdir(itmp);
#  if defined(UNIX) || defined(VMS)
		    (void)umask(umask_save);
#  endif
		}
# else
		/* Get an arbitrary number of up to 6 digits.  When it's
		 * unlikely that it already exists it will be faster,
		 * otherwise it doesn't matter.  The use of mkdir() avoids any
		 * security problems because of the predictable number. */
		nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
		itmplen = STRLEN(itmp);

		/* Try up to 10000 different values until we find a name that
		 * doesn't exist. */
		for (off = 0; off < 10000L; ++off)
		{
		    int		r;
#  if defined(UNIX) || defined(VMS)
		    mode_t	umask_save;
#  endif

		    sprintf((char *)itmp + itmplen, "v%ld", nr + off);
#  ifndef EEXIST
		    /* If mkdir() does not set errno to EEXIST, check for
		     * existing file here.  There is a race condition then,
		     * although it's fail-safe. */
		    if (mch_stat((char *)itmp, &st) >= 0)
			continue;
#  endif
#  if defined(UNIX) || defined(VMS)
		    /* Make sure the umask doesn't remove the executable bit.
		     * "repl" has been reported to use "177". */
		    umask_save = umask(077);
#  endif
		    r = vim_mkdir(itmp, 0700);
#  if defined(UNIX) || defined(VMS)
		    (void)umask(umask_save);
#  endif
		    if (r == 0)
		    {
			vim_settempdir(itmp);
			break;
		    }
#  ifdef EEXIST
		    /* If the mkdir() didn't fail because the file/dir exists,
		     * we probably can't create any dir here, try another
		     * place. */
		    if (errno != EEXIST)
#  endif
			break;
		}
# endif /* HAVE_MKDTEMP */
		if (vim_tempdir != NULL)
		    break;
	    }
	}
    }

    if (vim_tempdir != NULL)
    {
	/* There is no need to check if the file exists, because we own the
	 * directory and nobody else creates a file in it. */
	sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
	return vim_strsave(itmp);
    }

    return NULL;

#else /* TEMPDIRNAMES */

# ifdef WIN3264
    char	szTempFile[_MAX_PATH + 1];
    char	buf4[4];
    char_u	*retval;
    char_u	*p;

    STRCPY(itmp, "");
    if (GetTempPath(_MAX_PATH, szTempFile) == 0)
    {
	szTempFile[0] = '.';	/* GetTempPath() failed, use current dir */
	szTempFile[1] = NUL;
    }
    strcpy(buf4, "VIM");
    buf4[2] = extra_char;   /* make it "VIa", "VIb", etc. */
    if (GetTempFileName(szTempFile, buf4, 0, (LPSTR)itmp) == 0)
	return NULL;
    if (!keep)
	/* GetTempFileName() will create the file, we don't want that */
	(void)DeleteFile((LPSTR)itmp);

    /* Backslashes in a temp file name cause problems when filtering with
     * "sh".  NOTE: This also checks 'shellcmdflag' to help those people who
     * didn't set 'shellslash'. */
    retval = vim_strsave(itmp);
    if (*p_shcf == '-' || p_ssl)
	for (p = retval; *p; ++p)
	    if (*p == '\\')
		*p = '/';
    return retval;

# else /* WIN3264 */

#  ifdef USE_TMPNAM
    char_u	*p;

    /* tmpnam() will make its own name */
    p = tmpnam((char *)itmp);
    if (p == NULL || *p == NUL)
	return NULL;
#  else
    char_u	*p;

#   ifdef VMS_TEMPNAM
    /* mktemp() is not working on VMS.  It seems to be
     * a do-nothing function. Therefore we use tempnam().
     */
    sprintf((char *)itmp, "VIM%c", extra_char);
    p = (char_u *)tempnam("tmp:", (char *)itmp);
    if (p != NULL)
    {
	/* VMS will use '.LIS' if we don't explicitly specify an extension,
	 * and VIM will then be unable to find the file later */
	STRCPY(itmp, p);
	STRCAT(itmp, ".txt");
	free(p);
    }
    else
	return NULL;
#   else
    STRCPY(itmp, TEMPNAME);
    if ((p = vim_strchr(itmp, '?')) != NULL)
	*p = extra_char;
    if (mktemp((char *)itmp) == NULL)
	return NULL;
#   endif
#  endif

    return vim_strsave(itmp);
# endif /* WIN3264 */
#endif /* TEMPDIRNAMES */
}

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 char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

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, stat_T *s);

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_ALL	    -3	    /* all autocmd groups */

# define FIO_UCSBOM	0x4000	/* check for BOM at start of file */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

int		fd = 0;

int		newfile = (flags & READ_NEW);

int		check_readonly;

int		filtering = (flags & READ_FILTER);

int		read_stdin = (flags & READ_STDIN);


do_autocmd(char_u *arg_in, int forceit)
{
    char_u	*arg = arg_in;
    char_u	*pat;
    char_u	*envpat = NULL;
    char_u	*cmd;
    event_T	event;
    int		need_free = FALSE;
    int		nested = FALSE;
    int		group;

    if (*arg == '|')
    {
	arg = (char_u *)"";
	group = AUGROUP_ALL;	/* no argument, use all groups */
    }
    else
    {
	/*
	 * Check for a legal group name.  If not, use AUGROUP_ALL.
	 */
	group = au_get_grouparg(&arg);
	if (arg == NULL)	    /* out of memory */
	    return;
    }

    /*
     * Scan over the events.
     * If we find an illegal name, return here, don't do anything.
     */
    pat = find_end_event(arg, group != AUGROUP_ALL);
    if (pat == NULL)
	return;

    pat = skipwhite(pat);
    if (*pat == '|')
    {
	pat = (char_u *)"";
	cmd = (char_u *)"";
    }
    else
    {
	/*
	 * Scan over the pattern.  Put a NUL at the end.
	 */
	cmd = pat;
	while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
	    cmd++;
	if (*cmd)
	    *cmd++ = NUL;

	/* Expand environment variables in the pattern.  Set 'shellslash', we want
	 * forward slashes here. */
	if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
	{
#ifdef BACKSLASH_IN_FILENAME
	    int	p_ssl_save = p_ssl;

	    p_ssl = TRUE;
#endif
	    envpat = expand_env_save(pat);
#ifdef BACKSLASH_IN_FILENAME
	    p_ssl = p_ssl_save;
#endif
	    if (envpat != NULL)
		pat = envpat;
	}

	/*
	 * Check for "nested" flag.
	 */
	cmd = skipwhite(cmd);
	if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
	{
	    nested = TRUE;
	    cmd = skipwhite(cmd + 6);
	}

	/*
	 * Find the start of the commands.
	 * Expand <sfile> in it.
	 */
	if (*cmd != NUL)
	{
	    cmd = expand_sfile(cmd);
	    if (cmd == NULL)	    /* some error */
		return;
	    need_free = TRUE;
	}
    }

    /*
     * Print header when showing autocommands.
     */
    if (!forceit && *cmd == NUL)
    {
	/* Highlight title */
	MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
    }

    /*
     * Loop over the events.
     */
    last_event = (event_T)-1;		/* for listing the event name */
    last_group = AUGROUP_ERROR;		/* for listing the group name */
    if (*arg == '*' || *arg == NUL || *arg == '|')
    {
	for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
					    event = (event_T)((int)event + 1))
	    if (do_autocmd_event(event, pat,
					 nested, cmd, forceit, group) == FAIL)
		break;
    }
    else
    {
	while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
	    if (do_autocmd_event(event_name2nr(arg, &arg), pat,
					nested,	cmd, forceit, group) == FAIL)
		break;
    }

    if (need_free)
	vim_free(cmd);
    vim_free(envpat);
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_UCSBOM	0x4000	/* check for BOM at start of file */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

int		fd = 0;

int		newfile = (flags & READ_NEW);

int		check_readonly;

int		filtering = (flags & READ_FILTER);


au_exists(char_u *arg)
{
    char_u	*arg_save;
    char_u	*pattern = NULL;
    char_u	*event_name;
    char_u	*p;
    event_T	event;
    AutoPat	*ap;
    buf_T	*buflocal_buf = NULL;
    int		group;
    int		retval = FALSE;

    /* Make a copy so that we can change the '#' chars to a NUL. */
    arg_save = vim_strsave(arg);
    if (arg_save == NULL)
	return FALSE;
    p = vim_strchr(arg_save, '#');
    if (p != NULL)
	*p++ = NUL;

    /* First, look for an autocmd group name */
    group = au_find_group(arg_save);
    if (group == AUGROUP_ERROR)
    {
	/* Didn't match a group name, assume the first argument is an event. */
	group = AUGROUP_ALL;
	event_name = arg_save;
    }
    else
    {
	if (p == NULL)
	{
	    /* "Group": group name is present and it's recognized */
	    retval = TRUE;
	    goto theend;
	}

	/* Must be "Group#Event" or "Group#Event#pat". */
	event_name = p;
	p = vim_strchr(event_name, '#');
	if (p != NULL)
	    *p++ = NUL;	    /* "Group#Event#pat" */
    }

    pattern = p;	    /* "pattern" is NULL when there is no pattern */

    /* find the index (enum) for the event name */
    event = event_name2nr(event_name, &p);

    /* return FALSE if the event name is not recognized */
    if (event == NUM_EVENTS)
	goto theend;

    /* Find the first autocommand for this event.
     * If there isn't any, return FALSE;
     * If there is one and no pattern given, return TRUE; */
    ap = first_autopat[(int)event];
    if (ap == NULL)
	goto theend;

    /* if pattern is "<buffer>", special handling is needed which uses curbuf */
    /* for pattern "<buffer=N>, fnamecmp() will work fine */
    if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
	buflocal_buf = curbuf;

    /* Check if there is an autocommand with the given pattern. */
    for ( ; ap != NULL; ap = ap->next)
	/* only use a pattern when it has not been removed and has commands. */
	/* For buffer-local autocommands, fnamecmp() works fine. */
	if (ap->pat != NULL && ap->cmds != NULL
	    && (group == AUGROUP_ALL || ap->group == group)
	    && (pattern == NULL
		|| (buflocal_buf == NULL
		    ? fnamecmp(ap->pat, pattern) == 0
		    : ap->buflocal_nr == buflocal_buf->b_fnum)))
	{
	    retval = TRUE;
	    break;
	}

theend:
    vim_free(arg_save);
    return retval;
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

int		fd = 0;

int		newfile = (flags & READ_NEW);

int		check_readonly;


buf_modname(
    int	    shortname,		/* use 8.3 file name */
    char_u  *fname,
    char_u  *ext,
    int	    prepend_dot)	/* may prepend a '.' to file name */
{
    char_u	*retval;
    char_u	*s;
    char_u	*e;
    char_u	*ptr;
    int		fnamelen, extlen;

    extlen = (int)STRLEN(ext);

    /*
     * If there is no file name we must get the name of the current directory
     * (we need the full path in case :cd is used).
     */
    if (fname == NULL || *fname == NUL)
    {
	retval = alloc((unsigned)(MAXPATHL + extlen + 3));
	if (retval == NULL)
	    return NULL;
	if (mch_dirname(retval, MAXPATHL) == FAIL ||
				     (fnamelen = (int)STRLEN(retval)) == 0)
	{
	    vim_free(retval);
	    return NULL;
	}
	if (!after_pathsep(retval, retval + fnamelen))
	{
	    retval[fnamelen++] = PATHSEP;
	    retval[fnamelen] = NUL;
	}
	prepend_dot = FALSE;	    /* nothing to prepend a dot to */
    }
    else
    {
	fnamelen = (int)STRLEN(fname);
	retval = alloc((unsigned)(fnamelen + extlen + 3));
	if (retval == NULL)
	    return NULL;
	STRCPY(retval, fname);
#ifdef VMS
	vms_remove_version(retval); /* we do not need versions here */
#endif
    }

    /*
     * search backwards until we hit a '/', '\' or ':' replacing all '.'
     * by '_' for MSDOS or when shortname option set and ext starts with a dot.
     * Then truncate what is after the '/', '\' or ':' to 8 characters for
     * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
     */
    for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr))
    {
	if (*ext == '.'
#ifdef USE_LONG_FNAME
		    && (!USE_LONG_FNAME || shortname)
#else
		    && shortname
#endif
								)
	    if (*ptr == '.')	/* replace '.' by '_' */
		*ptr = '_';
	if (vim_ispathsep(*ptr))
	{
	    ++ptr;
	    break;
	}
    }

    /* the file name has at most BASENAMELEN characters. */
    if (STRLEN(ptr) > (unsigned)BASENAMELEN)
	ptr[BASENAMELEN] = '\0';

    s = ptr + STRLEN(ptr);

    /*
     * For 8.3 file names we may have to reduce the length.
     */
#ifdef USE_LONG_FNAME
    if (!USE_LONG_FNAME || shortname)
#else
    if (shortname)
#endif
    {
	/*
	 * If there is no file name, or the file name ends in '/', and the
	 * extension starts with '.', put a '_' before the dot, because just
	 * ".ext" is invalid.
	 */
	if (fname == NULL || *fname == NUL
				   || vim_ispathsep(fname[STRLEN(fname) - 1]))
	{
	    if (*ext == '.')
		*s++ = '_';
	}
	/*
	 * If the extension starts with '.', truncate the base name at 8
	 * characters
	 */
	else if (*ext == '.')
	{
	    if ((size_t)(s - ptr) > (size_t)8)
	    {
		s = ptr + 8;
		*s = '\0';
	    }
	}
	/*
	 * If the extension doesn't start with '.', and the file name
	 * doesn't have an extension yet, append a '.'
	 */
	else if ((e = vim_strchr(ptr, '.')) == NULL)
	    *s++ = '.';
	/*
	 * If the extension doesn't start with '.', and there already is an
	 * extension, it may need to be truncated
	 */
	else if ((int)STRLEN(e) + extlen > 4)
	    s = e + 4 - extlen;
    }
#if defined(USE_LONG_FNAME) || defined(WIN3264)
    /*
     * If there is no file name, and the extension starts with '.', put a
     * '_' before the dot, because just ".ext" may be invalid if it's on a
     * FAT partition, and on HPFS it doesn't matter.
     */
    else if ((fname == NULL || *fname == NUL) && *ext == '.')
	*s++ = '_';
#endif

    /*
     * Append the extension.
     * ext can start with '.' and cannot exceed 3 more characters.
     */
    STRCPY(s, ext);

    /*
     * Prepend the dot.
     */
    if (prepend_dot && !shortname && *(e = gettail(retval)) != '.'
#ifdef USE_LONG_FNAME
	    && USE_LONG_FNAME
#endif
				)
    {
	STRMOVE(e + 1, e);
	*e = '.';
    }

    /*
     * Check that, after appending the extension, the file name is really
     * different.
     */
    if (fname != NULL && STRCMP(fname, retval) == 0)
    {
	/* we search for a character that can be replaced by '_' */
	while (--s >= ptr)
	{
	    if (*s != '_')
	    {
		*s = '_';
		break;
	    }
	}
	if (s < ptr)	/* fname was "________.<ext>", how tricky! */
	    *ptr = 'v';
    }
    return retval;
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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_ALL	    -3	    /* all autocmd groups */

#  define FIO_PUT_CP(x) (((x) & 0xffff) << 16)	/* put codepage in top word */

#  define FIO_GET_CP(x)	(((x)>>16) & 0xffff)	/* get codepage from top word */

# define FIO_UCSBOM	0x4000	/* check for BOM at start of file */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

int		fd = 0;


au_remove_cmds(AutoPat *ap)
{
    AutoCmd *ac;

    for (ac = ap->cmds; ac != NULL; ac = ac->next)
    {
	vim_free(ac->cmd);
	ac->cmd = NULL;
    }
    au_need_clean = TRUE;
}

# define FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#endif
}

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

char_u	*cryptkey = NULL;

char_u	*tmpname = NULL;

char_u	*fenc_next = NULL;

char_u	    *backup = NULL;

char_u	    *wfname = NULL;

char_u	    *errmsg = NULL;

char_u	    *errnum = NULL;

char_u	    *fenc_tofree = NULL;

vim_acl_T	    acl = NULL;

int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;

typedef struct AutoCmd
{
    char_u	    *cmd;		/* The command to be executed (NULL
					   when command has been removed) */
    char	    nested;		/* If autocommands nest here */
    char	    last;		/* last command in list */
#ifdef FEAT_EVAL
    scid_T	    scriptID;		/* script ID where defined */
#endif
    struct AutoCmd  *next;		/* Next AutoCmd in list */
} AutoCmd;

typedef struct AutoPat
{
    char_u	    *pat;		/* pattern as typed (NULL when pattern
					   has been removed) */
    regprog_T	    *reg_prog;		/* compiled regprog for pattern */
    AutoCmd	    *cmds;		/* list of commands to do */
    struct AutoPat  *next;		/* next AutoPat in AutoPat list */
    int		    group;		/* group ID */
    int		    patlen;		/* strlen() of pat */
    int		    buflocal_nr;	/* !=0 for buffer-local AutoPat */
    char	    allow_dirs;		/* Pattern may match whole path */
    char	    last;		/* last pattern for apply_autocmds() */
} AutoPat;


au_del_group(char_u *name)
{
    int	    i;

    i = au_find_group(name);
    if (i == AUGROUP_ERROR)	/* the group doesn't exist */
	EMSG2(_("E367: No such group: \"%s\""), name);
    else if (i == current_augroup)
	EMSG(_("E936: Cannot delete the current group"));
    else
    {
	event_T	event;
	AutoPat	*ap;
	int	in_use = FALSE;

	for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
					    event = (event_T)((int)event + 1))
	{
	    for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
		if (ap->group == i && ap->pat != NULL)
		{
		    give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
		    in_use = TRUE;
		    event = NUM_EVENTS;
		    break;
		}
	}
	vim_free(AUGROUP_NAME(i));
	if (in_use)
	{
	    AUGROUP_NAME(i) = get_deleted_augroup();
	}
	else
	    AUGROUP_NAME(i) = NULL;
    }
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

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		read_fifo = (flags & READ_FIFO);


get_fio_flags(char_u *ptr)
{
    int		prop;

    if (*ptr == NUL)
	ptr = p_enc;

    prop = enc_canon_props(ptr);
    if (prop & ENC_UNICODE)
    {
	if (prop & ENC_2BYTE)
	{
	    if (prop & ENC_ENDIAN_L)
		return FIO_UCS2 | FIO_ENDIAN_L;
	    return FIO_UCS2;
	}
	if (prop & ENC_4BYTE)
	{
	    if (prop & ENC_ENDIAN_L)
		return FIO_UCS4 | FIO_ENDIAN_L;
	    return FIO_UCS4;
	}
	if (prop & ENC_2WORD)
	{
	    if (prop & ENC_ENDIAN_L)
		return FIO_UTF16 | FIO_ENDIAN_L;
	    return FIO_UTF16;
	}
	return FIO_UTF8;
    }
    if (prop & ENC_LATIN1)
	return FIO_LATIN1;
    /* must be ENC_DBCS, requires iconv() */
    return 0;
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 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 */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static int au_did_filetype

int		fd = 0;

int		newfile = (flags & READ_NEW);

int		check_readonly;

int		filtering = (flags & READ_FILTER);


shorten_fnames(int force)
{
    char_u	dirname[MAXPATHL];
    buf_T	*buf;
    char_u	*p;

    mch_dirname(dirname, MAXPATHL);
    FOR_ALL_BUFFERS(buf)
    {
	if (buf->b_fname != NULL
#ifdef FEAT_QUICKFIX
		&& !bt_nofile(buf)
#endif
		&& !path_with_url(buf->b_fname)
		&& (force
		    || buf->b_sfname == NULL
		    || mch_isFullName(buf->b_sfname)))
	{
	    vim_free(buf->b_sfname);
	    buf->b_sfname = NULL;
	    p = shorten_fname(buf->b_ffname, dirname);
	    if (p != NULL)
	    {
		buf->b_sfname = vim_strsave(p);
		buf->b_fname = buf->b_sfname;
	    }
	    if (p == NULL || buf->b_fname == NULL)
		buf->b_fname = buf->b_ffname;
	}

	/* Always make the swap file name a full path, a "nofile" buffer may
	 * also have a swap file. */
	mf_fullname(buf->b_ml.ml_mfp);
    }
    status_redraw_all();
    redraw_tabline = TRUE;
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 FIO_UCSBOM	0x4000	/* check for BOM at start of file */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

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);


au_new_group(char_u *name)
{
    int		i;

    i = au_find_group(name);
    if (i == AUGROUP_ERROR)	/* the group doesn't exist yet, add it */
    {
	/* First try using a free entry. */
	for (i = 0; i < augroups.ga_len; ++i)
	    if (AUGROUP_NAME(i) == NULL)
		break;
	if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
	    return AUGROUP_ERROR;

	AUGROUP_NAME(i) = vim_strsave(name);
	if (AUGROUP_NAME(i) == NULL)
	    return AUGROUP_ERROR;
	if (i == augroups.ga_len)
	    ++augroups.ga_len;
    }

    return i;
}


set_rw_fname(char_u *fname, char_u *sfname)
{
#ifdef FEAT_AUTOCMD
    buf_T	*buf = curbuf;

    /* It's like the unnamed buffer is deleted.... */
    if (curbuf->b_p_bl)
	apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
    apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
# ifdef FEAT_EVAL
    if (aborting())	    /* autocmds may abort script processing */
	return FAIL;
# endif
    if (curbuf != buf)
    {
	/* We are in another buffer now, don't do the renaming. */
	EMSG(_(e_auchangedbuf));
	return FAIL;
    }
#endif

    if (setfname(curbuf, fname, sfname, FALSE) == OK)
	curbuf->b_flags |= BF_NOTEDITED;

#ifdef FEAT_AUTOCMD
    /* ....and a new named one is created */
    apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
    if (curbuf->b_p_bl)
	apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
# ifdef FEAT_EVAL
    if (aborting())	    /* autocmds may abort script processing */
	return FAIL;
# endif

    /* Do filetype detection now if 'filetype' is empty. */
    if (*curbuf->b_p_ft == NUL)
    {
	if (au_has_group((char_u *)"filetypedetect"))
	    (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE, NULL);
	do_modelines(0);
    }
#endif

    return OK;
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

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 char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static void msg_add_eol(void);

static int check_mtime(buf_T *buf, stat_T *s);

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);

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#endif
}

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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);

char_u	c;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

char_u	*p;

int		skip_read = FALSE;

char_u	*cryptkey = NULL;

int		did_ask_for_key = FALSE;

int		read_undo_file = FALSE;

int		error = FALSE;

int		keep_fileformat = FALSE;


match_file_list(char_u *list, char_u *sfname, char_u *ffname)
{
    char_u	buf[100];
    char_u	*tail;
    char_u	*regpat;
    char	allow_dirs;
    int		match;
    char_u	*p;

    tail = gettail(sfname);

    /* try all patterns in 'wildignore' */
    p = list;
    while (*p)
    {
	copy_option_part(&p, buf, 100, ",");
	regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
	if (regpat == NULL)
	    break;
	match = match_file_pat(regpat, NULL, ffname, sfname,
						       tail, (int)allow_dirs);
	vim_free(regpat);
	if (match)
	    return TRUE;
    }
    return FALSE;
}

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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_ALL	    -3	    /* all autocmd groups */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);

static void vim_settempdir(char_u *tempdir);

static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");

static int au_did_filetype

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		read_fifo = (flags & READ_FIFO);

int		set_options = newfile || read_buffer
					   || (eap != NULL && eap->read_edit);


check_for_bom(
    char_u	*p,
    long	size,
    int		*lenp,
    int		flags)
{
    char	*name = NULL;
    int		len = 2;

    if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
	    && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
    {
	name = "utf-8";		/* EF BB BF */
	len = 3;
    }
    else if (p[0] == 0xff && p[1] == 0xfe)
    {
	if (size >= 4 && p[2] == 0 && p[3] == 0
	    && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
	{
	    name = "ucs-4le";	/* FF FE 00 00 */
	    len = 4;
	}
	else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
	    name = "ucs-2le";	/* FF FE */
	else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
	    /* utf-16le is preferred, it also works for ucs-2le text */
	    name = "utf-16le";	/* FF FE */
    }
    else if (p[0] == 0xfe && p[1] == 0xff
	    && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
    {
	/* Default to utf-16, it works also for ucs-2 text. */
	if (flags == FIO_UCS2)
	    name = "ucs-2";	/* FE FF */
	else
	    name = "utf-16";	/* FE FF */
    }
    else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
	    && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
    {
	name = "ucs-4";		/* 00 00 FE FF */
	len = 4;
    }

    *lenp = len;
    return (char_u *)name;
}

#define BUFSIZE		8192	/* size of normal write buffer */

#define SMBUFSIZE	256	/* size of emergency write buffer */

static char_u *next_fenc(char_u **pp);

static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);

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);

static void set_file_time(char_u *fname, time_t atime, time_t mtime);

static int set_rw_fname(char_u *fname, char_u *sfname);

static int msg_add_fileformat(int eol_type);

static int check_mtime(buf_T *buf, stat_T *s);

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 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_UCSBOM	0x4000	/* check for BOM at start of file */

# define FIO_ALL	-1	/* allow all formats */

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
#ifdef FEAT_CRYPT
    buf_T	*bw_buffer;	/* buffer being written */
#endif
#ifdef FEAT_MBYTE
    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
#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 get_win_fio_flags(char_u *ptr);

static int get_mac_fio_flags(char_u *ptr);

static int move_lines(buf_T *frombuf, buf_T *tobuf);