match_file_pat(
    char_u	*pattern,		/* pattern to match with */
    regprog_T	**prog,			/* pre-compiled regprog or NULL */
    char_u	*fname,			/* full path of file name */
    char_u	*sfname,		/* short file name or NULL */
    char_u	*tail,			/* tail of path */
    int		allow_dirs)		/* allow matching with dir */
{
    regmatch_T	regmatch;
    int		result = FALSE;

    regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */
    if (prog != NULL)
	regmatch.regprog = *prog;
    else
	regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);

    /*
     * Try for a match with the pattern with:
     * 1. the full file name, when the pattern has a '/'.
     * 2. the short file name, when the pattern has a '/'.
     * 3. the tail of the file name, when the pattern has no '/'.
     */
    if (regmatch.regprog != NULL
	     && ((allow_dirs
		     && (vim_regexec(&regmatch, fname, (colnr_T)0)
			 || (sfname != NULL
			     && vim_regexec(&regmatch, sfname, (colnr_T)0))))
		 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0))))
	result = TRUE;

    if (prog != NULL)
	*prog = regmatch.regprog;
    else
	vim_regfree(regmatch.regprog);
    return result;
}

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

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


check_mtime(buf_T *buf, stat_T *st)
{
    if (buf->b_mtime_read != 0
	    && time_differs((long)st->st_mtime, buf->b_mtime_read))
    {
	msg_scroll = TRUE;	    /* don't overwrite messages here */
	msg_silent = 0;		    /* must give this prompt */
	/* don't use emsg() here, don't want to flush the buffers */
	MSG_ATTR(_("WARNING: The file has been changed since reading it!!!"),
						       HL_ATTR(HLF_E));
	if (ask_yesno((char_u *)_("Do you really want to write to it"),
								 TRUE) == 'n')
	    return FAIL;
	msg_scroll = FALSE;	    /* always overwrite the file message now */
    }
    return OK;
}

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.

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

char_u	c;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

long	size = 0;

char_u	*p;

int		skip_read = FALSE;

char_u	*cryptkey = NULL;

int		did_ask_for_key = FALSE;

int		read_undo_file = FALSE;


check_file_readonly(
    char_u	*fname,		/* full path to file */
    int		perm)		/* known permissions on file */
{
#ifndef USE_MCH_ACCESS
    int	    fd = 0;
#endif

    return (
#ifdef USE_MCH_ACCESS
# ifdef UNIX
	(perm & 0222) == 0 ||
# endif
	mch_access((char *)fname, W_OK)
#else
	(fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
					? TRUE : (close(fd), FALSE)
#endif
	);
}

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


write_lnum_adjust(linenr_T offset)
{
    if (curbuf->b_no_eol_lnum != 0)	/* only if there is a missing eol */
	curbuf->b_no_eol_lnum += offset;
}

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

linenr_T	read_buf_lnum = 1;

linenr_T	lnum = from;

linenr_T	linecnt;

linenr_T	skip_count = 0;

linenr_T	read_count = 0;

linenr_T	read_no_eol_lnum = 0;

linenr_T	conv_error = 0;

linenr_T	illegal_byte = 0;

linenr_T	    lnum;

static char	    *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";

linenr_T	    old_line_count = buf->b_ml.ml_line_count;


au_get_grouparg(char_u **argp)
{
    char_u	*group_name;
    char_u	*p;
    char_u	*arg = *argp;
    int		group = AUGROUP_ALL;

    for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
	;
    if (p > arg)
    {
	group_name = vim_strnsave(arg, (int)(p - arg));
	if (group_name == NULL)		/* out of memory */
	    return AUGROUP_ERROR;
	group = au_find_group(group_name);
	if (group == AUGROUP_ERROR)
	    group = AUGROUP_ALL;	/* no match, use all groups */
	else
	    *argp = skipwhite(p);	/* match, skip over group name */
	vim_free(group_name);
    }
    return group;
}

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

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


block_autocmds(void)
{
# ifdef FEAT_EVAL
    /* Remember the value of v:termresponse. */
    if (autocmd_blocked == 0)
	old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
# endif
    ++autocmd_blocked;
}

static void check_marks_read(void);

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

static void msg_add_eol(void);

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 void vim_settempdir(char_u *tempdir);

sfname
#else
		fname
#endif
		     );

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;

static void show_autocmd(AutoPat *ap, event_T event);

static void au_remove_pat(AutoPat *ap);

static void au_remove_cmds(AutoPat *ap);

static void au_cleanup(void);

static void au_del_group(char_u *name);

static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);

static int	autocmd_blocked = 0;

static char_u	*old_termresponse = NULL;


au_cleanup(void)
{
    AutoPat	*ap, **prev_ap;
    AutoCmd	*ac, **prev_ac;
    event_T	event;

    if (autocmd_busy || !au_need_clean)
	return;

    /* loop over all events */
    for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
					    event = (event_T)((int)event + 1))
    {
	/* loop over all autocommand patterns */
	prev_ap = &(first_autopat[(int)event]);
	for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
	{
	    /* loop over all commands for this pattern */
	    prev_ac = &(ap->cmds);
	    for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
	    {
		/* remove the command if the pattern is to be deleted or when
		 * the command has been marked for deletion */
		if (ap->pat == NULL || ac->cmd == NULL)
		{
		    *prev_ac = ac->next;
		    vim_free(ac->cmd);
		    vim_free(ac);
		}
		else
		    prev_ac = &(ac->next);
	    }

	    /* remove the pattern if it has been marked for deletion */
	    if (ap->pat == NULL)
	    {
		*prev_ap = ap->next;
		vim_regfree(ap->reg_prog);
		vim_free(ap);
	    }
	    else
		prev_ap = &(ap->next);
	}
    }

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

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

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;


next_fenc(char_u **pp)
{
    char_u	*p;
    char_u	*r;

    if (**pp == NUL)
    {
	*pp = NULL;
	return (char_u *)"";
    }
    p = vim_strchr(*pp, ',');
    if (p == NULL)
    {
	r = enc_canonize(*pp);
	*pp += STRLEN(*pp);
    }
    else
    {
	r = vim_strnsave(*pp, (int)(p - *pp));
	*pp = p + 1;
	if (r != NULL)
	{
	    p = enc_canonize(r);
	    vim_free(r);
	    r = p;
	}
    }
    if (r == NULL)	/* out of memory */
    {
	r = (char_u *)"";
	*pp = NULL;
    }
    return r;
}

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

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

char_u	c;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

int		wasempty;

char_u	*p;

int		skip_read = FALSE;


au_event_disable(char *what)
{
    char_u	*new_ei;
    char_u	*save_ei;

    save_ei = vim_strsave(p_ei);
    if (save_ei != NULL)
    {
	new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
	if (new_ei != NULL)
	{
	    if (*what == ',' && *p_ei == NUL)
		STRCPY(new_ei, what + 1);
	    else
		STRCAT(new_ei, what);
	    set_string_option_direct((char_u *)"ei", -1, new_ei,
							  OPT_FREE, SID_NONE);
	    vim_free(new_ei);
	}
    }
    return save_ei;
}

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

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;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;


aucmd_prepbuf(
    aco_save_T	*aco,		/* structure to save values in */
    buf_T	*buf)		/* new curbuf */
{
    aco->save_curbuf = curbuf;
    --curbuf->b_nwindows;
    curbuf = buf;
    curwin->w_buffer = buf;
    ++curbuf->b_nwindows;
}

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

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 make_bom(char_u *buf, char_u *name);

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

buf_T	*old_curbuf;

int		    whole = (start == 1 && end == buf->b_ml.ml_line_count);

linenr_T	    old_line_count = buf->b_ml.ml_line_count;

unsigned int    bkc = get_bkc_value(buf);

typedef struct AutoPatCmd
{
    AutoPat	*curpat;	/* next AutoPat to examine */
    AutoCmd	*nextcmd;	/* next AutoCmd to execute */
    int		group;		/* group being used */
    char_u	*fname;		/* fname to match with */
    char_u	*sfname;	/* sfname to match with */
    char_u	*tail;		/* tail of fname */
    event_T	event;		/* current event */
    int		arg_bufnr;	/* initially equal to <abuf>, set to zero when
				   buf is deleted */
    struct AutoPatCmd   *next;	/* chain of active apc-s for auto-invalidation*/
} AutoPatCmd;

static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);


msg_add_eol(void)
{
    STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
}

static void check_marks_read(void);

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

static void msg_add_eol(void);

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 void vim_settempdir(char_u *tempdir);

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;

static void show_autocmd(AutoPat *ap, event_T event);

static void au_remove_pat(AutoPat *ap);

static void au_remove_cmds(AutoPat *ap);

static void au_cleanup(void);

static void au_del_group(char_u *name);

static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);


get_augroup_name(expand_T *xp UNUSED, int idx)
{
    if (idx == augroups.ga_len)		/* add "END" add the end */
	return (char_u *)"END";
    if (idx >= augroups.ga_len)		/* end of list */
	return NULL;
    if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
	/* skip deleted entries */
	return (char_u *)"";
    return AUGROUP_NAME(idx);		/* return a name */
}

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

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;

char_u	*ptr = NULL;


get_event_name(expand_T *xp UNUSED, int idx)
{
    if (idx < augroups.ga_len)		/* First list group names, if wanted */
    {
	if (!include_groups || AUGROUP_NAME(idx) == NULL
				 || AUGROUP_NAME(idx) == get_deleted_augroup())
	    return (char_u *)"";	/* skip deleted entries */
	return AUGROUP_NAME(idx);	/* return a name */
    }
    return (char_u *)event_names[idx - augroups.ga_len].name;
}

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

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


is_dev_fd_file(char_u *fname)
{
    return (STRNCMP(fname, "/dev/fd/", 8) == 0
	    && VIM_ISDIGIT(fname[8])
	    && *skipdigits(fname + 9) == NUL
	    && (fname[9] != NUL
		|| (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
}

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 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 void vim_settempdir(char_u *tempdir);

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;

char_u	    *errnum = NULL;

char_u	    *buffer;

char_u	    smallbuf[SMBUFSIZE];

char_u	    *backup_ext;

char_u	    *fenc;

char_u	    *fenc_tofree = NULL;

sfname
#else
		fname
#endif
		     );


unblock_autocmds(void)
{
    --autocmd_blocked;

# ifdef FEAT_EVAL
    /* When v:termresponse was set while autocommands were blocked, trigger
     * the autocommands now.  Esp. useful when executing a shell command
     * during startup (vimdiff). */
    if (autocmd_blocked == 0
		      && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
	apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
# endif
}

static void check_marks_read(void);

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

static void msg_add_eol(void);

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 void vim_settempdir(char_u *tempdir);

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;

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;

int		file_rewind = FALSE;

int		keep_dest_enc = FALSE;

char_u	*tmpname = NULL;

char_u	*fenc_next = NULL;

int		advance_fenc = FALSE;

int		did_iconv = FALSE;

int		converted = FALSE;

int		notconverted = FALSE;

char_u	    *backup = NULL;

int		    backup_copy = FALSE;

char_u	    *wfname = NULL;

char_u	    *errmsg = NULL;

int		    errmsg_allocated = FALSE;

char_u	    *errnum = NULL;

int		    newfile = FALSE;

int		    no_eol = FALSE;

int		    device = FALSE;

int		    file_readonly = FALSE;

int		    made_writable = FALSE;

int		    converted = FALSE;

int		    notconverted = FALSE;

char_u	    *fenc_tofree = NULL;

vim_acl_T	    acl = NULL;

int		    write_undo_file = FALSE;

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

sfname
#else
		fname
#endif
		     );

static int already_warned = FALSE;

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;


free_all_autocmds(void)
{
    int		i;
    char_u	*s;

    for (current_augroup = -1; current_augroup < augroups.ga_len;
							    ++current_augroup)
	do_autocmd((char_u *)"", TRUE);

    for (i = 0; i < augroups.ga_len; ++i)
    {
	s = ((char_u **)(augroups.ga_data))[i];
	if (s != get_deleted_augroup())
	    vim_free(s);
    }
    ga_clear(&augroups);
}

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

char_u	*ptr = NULL;


buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
{
    buf->b_mtime = (long)st->st_mtime;
    buf->b_orig_size = st->st_size;
#ifdef HAVE_ST_MODE
    buf->b_orig_mode = (int)st->st_mode;
#else
    buf->b_orig_mode = mch_getperm(fname);
#endif
}

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

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

char_u	c;

char_u	*ptr = NULL;

char_u	*buffer = NULL;

char_u	*new_buffer = NULL;

char_u	*line_start = NULL;

int		wasempty;

long	size = 0;

char_u	*p;


aucmd_prepbuf(
    aco_save_T	*aco,		/* structure to save values in */
    buf_T	*buf)		/* new curbuf */
{
    win_T	*win;
    int		save_ea;
#ifdef FEAT_AUTOCHDIR
    int		save_acd;
#endif

    /* Find a window that is for the new buffer */
    if (buf == curbuf)		/* be quick when buf is curbuf */
	win = curwin;
    else
	FOR_ALL_WINDOWS(win)
	    if (win->w_buffer == buf)
		break;

    /* Allocate "aucmd_win" when needed.  If this fails (out of memory) fall
     * back to using the current window. */
    if (win == NULL && aucmd_win == NULL)
    {
	win_alloc_aucmd_win();
	if (aucmd_win == NULL)
	    win = curwin;
    }
    if (win == NULL && aucmd_win_used)
	/* Strange recursive autocommand, fall back to using the current
	 * window.  Expect a few side effects... */
	win = curwin;

    aco->save_curwin = curwin;
    aco->save_curbuf = curbuf;
    if (win != NULL)
    {
	/* There is a window for "buf" in the current tab page, make it the
	 * curwin.  This is preferred, it has the least side effects (esp. if
	 * "buf" is curbuf). */
	aco->use_aucmd_win = FALSE;
	curwin = win;
    }
    else
    {
	/* There is no window for "buf", use "aucmd_win".  To minimize the side
	 * effects, insert it in the current tab page.
	 * Anything related to a window (e.g., setting folds) may have
	 * unexpected results. */
	aco->use_aucmd_win = TRUE;
	aucmd_win_used = TRUE;
	aucmd_win->w_buffer = buf;
	aucmd_win->w_s = &buf->b_s;
	++buf->b_nwindows;
	win_init_empty(aucmd_win); /* set cursor and topline to safe values */

	/* Make sure w_localdir and globaldir are NULL to avoid a chdir() in
	 * win_enter_ext(). */
	vim_free(aucmd_win->w_localdir);
	aucmd_win->w_localdir = NULL;
	aco->globaldir = globaldir;
	globaldir = NULL;

	/* Split the current window, put the aucmd_win in the upper half.
	 * We don't want the BufEnter or WinEnter autocommands. */
	block_autocmds();
	make_snapshot(SNAP_AUCMD_IDX);
	save_ea = p_ea;
	p_ea = FALSE;

#ifdef FEAT_AUTOCHDIR
	/* Prevent chdir() call in win_enter_ext(), through do_autochdir(). */
	save_acd = p_acd;
	p_acd = FALSE;
#endif

	(void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
	(void)win_comp_pos();   /* recompute window positions */
	p_ea = save_ea;
#ifdef FEAT_AUTOCHDIR
	p_acd = save_acd;
#endif
	unblock_autocmds();
	curwin = aucmd_win;
    }
    curbuf = buf;
    aco->new_curwin = curwin;
    set_bufref(&aco->new_curbuf, curbuf);
}

#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 FIO_PUT_CP(x) (((x) & 0xffff) << 16)	/* put codepage in top word */

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


getnextac(int c UNUSED, void *cookie, int indent UNUSED)
{
    AutoPatCmd	    *acp = (AutoPatCmd *)cookie;
    char_u	    *retval;
    AutoCmd	    *ac;

    /* Can be called again after returning the last line. */
    if (acp->curpat == NULL)
	return NULL;

    /* repeat until we find an autocommand to execute */
    for (;;)
    {
	/* skip removed commands */
	while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
	    if (acp->nextcmd->last)
		acp->nextcmd = NULL;
	    else
		acp->nextcmd = acp->nextcmd->next;

	if (acp->nextcmd != NULL)
	    break;

	/* at end of commands, find next pattern that matches */
	if (acp->curpat->last)
	    acp->curpat = NULL;
	else
	    acp->curpat = acp->curpat->next;
	if (acp->curpat != NULL)
	    auto_next_pat(acp, TRUE);
	if (acp->curpat == NULL)
	    return NULL;
    }

    ac = acp->nextcmd;

    if (p_verbose >= 9)
    {
	verbose_enter_scroll();
	smsg((char_u *)_("autocommand %s"), ac->cmd);
	msg_puts((char_u *)"\n");   /* don't overwrite this either */
	verbose_leave_scroll();
    }
    retval = vim_strsave(ac->cmd);
    autocmd_nested = ac->nested;
#ifdef FEAT_EVAL
    current_SID = ac->scriptID;
#endif
    if (ac->last)
	acp->nextcmd = NULL;
    else
	acp->nextcmd = ac->next;
    return retval;
}

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


apply_autocmds_group(
    event_T	event,
    char_u	*fname,	    /* NULL or empty means use actual file name */
    char_u	*fname_io,  /* fname to use for <afile> on cmdline, NULL means
			       use fname */
    int		force,	    /* when TRUE, ignore autocmd_busy */
    int		group,	    /* group ID, or AUGROUP_ALL */
    buf_T	*buf,	    /* buffer for <abuf> */
    exarg_T	*eap)	    /* command arguments */
{
    char_u	*sfname = NULL;	/* short file name */
    char_u	*tail;
    int		save_changed;
    buf_T	*old_curbuf;
    int		retval = FALSE;
    char_u	*save_sourcing_name;
    linenr_T	save_sourcing_lnum;
    char_u	*save_autocmd_fname;
    int		save_autocmd_fname_full;
    int		save_autocmd_bufnr;
    char_u	*save_autocmd_match;
    int		save_autocmd_busy;
    int		save_autocmd_nested;
    static int	nesting = 0;
    AutoPatCmd	patcmd;
    AutoPat	*ap;
#ifdef FEAT_EVAL
    scid_T	save_current_SID;
    void	*save_funccalp;
    char_u	*save_cmdarg;
    long	save_cmdbang;
#endif
    static int	filechangeshell_busy = FALSE;
#ifdef FEAT_PROFILE
    proftime_T	wait_time;
#endif
    int		did_save_redobuff = FALSE;
    save_redo_T	save_redo;

    /*
     * Quickly return if there are no autocommands for this event or
     * autocommands are blocked.
     */
    if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
	    || autocmd_blocked > 0)
	goto BYPASS_AU;

    /*
     * When autocommands are busy, new autocommands are only executed when
     * explicitly enabled with the "nested" flag.
     */
    if (autocmd_busy && !(force || autocmd_nested))
	goto BYPASS_AU;

#ifdef FEAT_EVAL
    /*
     * Quickly return when immediately aborting on error, or when an interrupt
     * occurred or an exception was thrown but not caught.
     */
    if (aborting())
	goto BYPASS_AU;
#endif

    /*
     * FileChangedShell never nests, because it can create an endless loop.
     */
    if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
				      || event == EVENT_FILECHANGEDSHELLPOST))
	goto BYPASS_AU;

    /*
     * Ignore events in 'eventignore'.
     */
    if (event_ignored(event))
	goto BYPASS_AU;

    /*
     * Allow nesting of autocommands, but restrict the depth, because it's
     * possible to create an endless loop.
     */
    if (nesting == 10)
    {
	EMSG(_("E218: autocommand nesting too deep"));
	goto BYPASS_AU;
    }

    /*
     * Check if these autocommands are disabled.  Used when doing ":all" or
     * ":ball".
     */
    if (       (autocmd_no_enter
		&& (event == EVENT_WINENTER || event == EVENT_BUFENTER))
	    || (autocmd_no_leave
		&& (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
	goto BYPASS_AU;

    /*
     * Save the autocmd_* variables and info about the current buffer.
     */
    save_autocmd_fname = autocmd_fname;
    save_autocmd_fname_full = autocmd_fname_full;
    save_autocmd_bufnr = autocmd_bufnr;
    save_autocmd_match = autocmd_match;
    save_autocmd_busy = autocmd_busy;
    save_autocmd_nested = autocmd_nested;
    save_changed = curbuf->b_changed;
    old_curbuf = curbuf;

    /*
     * Set the file name to be used for <afile>.
     * Make a copy to avoid that changing a buffer name or directory makes it
     * invalid.
     */
    if (fname_io == NULL)
    {
	if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET)
	    autocmd_fname = NULL;
	else if (fname != NULL && !ends_excmd(*fname))
	    autocmd_fname = fname;
	else if (buf != NULL)
	    autocmd_fname = buf->b_ffname;
	else
	    autocmd_fname = NULL;
    }
    else
	autocmd_fname = fname_io;
    if (autocmd_fname != NULL)
	autocmd_fname = vim_strsave(autocmd_fname);
    autocmd_fname_full = FALSE; /* call FullName_save() later */

    /*
     * Set the buffer number to be used for <abuf>.
     */
    if (buf == NULL)
	autocmd_bufnr = 0;
    else
	autocmd_bufnr = buf->b_fnum;

    /*
     * When the file name is NULL or empty, use the file name of buffer "buf".
     * Always use the full path of the file name to match with, in case
     * "allow_dirs" is set.
     */
    if (fname == NULL || *fname == NUL)
    {
	if (buf == NULL)
	    fname = NULL;
	else
	{
#ifdef FEAT_SYN_HL
	    if (event == EVENT_SYNTAX)
		fname = buf->b_p_syn;
	    else
#endif
		if (event == EVENT_FILETYPE)
		    fname = buf->b_p_ft;
		else
		{
		    if (buf->b_sfname != NULL)
			sfname = vim_strsave(buf->b_sfname);
		    fname = buf->b_ffname;
		}
	}
	if (fname == NULL)
	    fname = (char_u *)"";
	fname = vim_strsave(fname);	/* make a copy, so we can change it */
    }
    else
    {
	sfname = vim_strsave(fname);
	/* Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
	 * ColorScheme or QuickFixCmd* */
	if (event == EVENT_FILETYPE
		|| event == EVENT_SYNTAX
		|| event == EVENT_FUNCUNDEFINED
		|| event == EVENT_REMOTEREPLY
		|| event == EVENT_SPELLFILEMISSING
		|| event == EVENT_QUICKFIXCMDPRE
		|| event == EVENT_COLORSCHEME
		|| event == EVENT_OPTIONSET
		|| event == EVENT_QUICKFIXCMDPOST)
	    fname = vim_strsave(fname);
	else
	    fname = FullName_save(fname, FALSE);
    }
    if (fname == NULL)	    /* out of memory */
    {
	vim_free(sfname);
	retval = FALSE;
	goto BYPASS_AU;
    }

#ifdef BACKSLASH_IN_FILENAME
    /*
     * Replace all backslashes with forward slashes.  This makes the
     * autocommand patterns portable between Unix and MS-DOS.
     */
    if (sfname != NULL)
	forward_slash(sfname);
    forward_slash(fname);
#endif

#ifdef VMS
    /* remove version for correct match */
    if (sfname != NULL)
	vms_remove_version(sfname);
    vms_remove_version(fname);
#endif

    /*
     * Set the name to be used for <amatch>.
     */
    autocmd_match = fname;

    /* Don't redraw while doing auto commands. */
    ++RedrawingDisabled;
    save_sourcing_name = sourcing_name;
    sourcing_name = NULL;	/* don't free this one */
    save_sourcing_lnum = sourcing_lnum;
    sourcing_lnum = 0;		/* no line number here */

#ifdef FEAT_EVAL
    save_current_SID = current_SID;

# ifdef FEAT_PROFILE
    if (do_profiling == PROF_YES)
	prof_child_enter(&wait_time); /* doesn't count for the caller itself */
# endif

    /* Don't use local function variables, if called from a function */
    save_funccalp = save_funccal();
#endif

    /*
     * When starting to execute autocommands, save the search patterns.
     */
    if (!autocmd_busy)
    {
	save_search_patterns();
#ifdef FEAT_INS_EXPAND
	if (!ins_compl_active())
#endif
	{
	    saveRedobuff(&save_redo);
	    did_save_redobuff = TRUE;
	}
	did_filetype = keep_filetype;
    }

    /*
     * Note that we are applying autocmds.  Some commands need to know.
     */
    autocmd_busy = TRUE;
    filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
    ++nesting;		/* see matching decrement below */

    /* Remember that FileType was triggered.  Used for did_filetype(). */
    if (event == EVENT_FILETYPE)
	did_filetype = TRUE;

    tail = gettail(fname);

    /* Find first autocommand that matches */
    patcmd.curpat = first_autopat[(int)event];
    patcmd.nextcmd = NULL;
    patcmd.group = group;
    patcmd.fname = fname;
    patcmd.sfname = sfname;
    patcmd.tail = tail;
    patcmd.event = event;
    patcmd.arg_bufnr = autocmd_bufnr;
    patcmd.next = NULL;
    auto_next_pat(&patcmd, FALSE);

    /* found one, start executing the autocommands */
    if (patcmd.curpat != NULL)
    {
	/* add to active_apc_list */
	patcmd.next = active_apc_list;
	active_apc_list = &patcmd;

#ifdef FEAT_EVAL
	/* set v:cmdarg (only when there is a matching pattern) */
	save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
	if (eap != NULL)
	{
	    save_cmdarg = set_cmdarg(eap, NULL);
	    set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
	}
	else
	    save_cmdarg = NULL;	/* avoid gcc warning */
#endif
	retval = TRUE;
	/* mark the last pattern, to avoid an endless loop when more patterns
	 * are added when executing autocommands */
	for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
	    ap->last = FALSE;
	ap->last = TRUE;
	check_lnums(TRUE);	/* make sure cursor and topline are valid */
	do_cmdline(NULL, getnextac, (void *)&patcmd,
				     DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
#ifdef FEAT_EVAL
	if (eap != NULL)
	{
	    (void)set_cmdarg(NULL, save_cmdarg);
	    set_vim_var_nr(VV_CMDBANG, save_cmdbang);
	}
#endif
	/* delete from active_apc_list */
	if (active_apc_list == &patcmd)	    /* just in case */
	    active_apc_list = patcmd.next;
    }

    --RedrawingDisabled;
    autocmd_busy = save_autocmd_busy;
    filechangeshell_busy = FALSE;
    autocmd_nested = save_autocmd_nested;
    vim_free(sourcing_name);
    sourcing_name = save_sourcing_name;
    sourcing_lnum = save_sourcing_lnum;
    vim_free(autocmd_fname);
    autocmd_fname = save_autocmd_fname;
    autocmd_fname_full = save_autocmd_fname_full;
    autocmd_bufnr = save_autocmd_bufnr;
    autocmd_match = save_autocmd_match;
#ifdef FEAT_EVAL
    current_SID = save_current_SID;
    restore_funccal(save_funccalp);
# ifdef FEAT_PROFILE
    if (do_profiling == PROF_YES)
	prof_child_exit(&wait_time);
# endif
#endif
    vim_free(fname);
    vim_free(sfname);
    --nesting;		/* see matching increment above */

    /*
     * When stopping to execute autocommands, restore the search patterns and
     * the redo buffer.  Free any buffers in the au_pending_free_buf list and
     * free any windows in the au_pending_free_win list.
     */
    if (!autocmd_busy)
    {
	restore_search_patterns();
	if (did_save_redobuff)
	    restoreRedobuff(&save_redo);
	did_filetype = FALSE;
	while (au_pending_free_buf != NULL)
	{
	    buf_T *b = au_pending_free_buf->b_next;
	    vim_free(au_pending_free_buf);
	    au_pending_free_buf = b;
	}
	while (au_pending_free_win != NULL)
	{
	    win_T *w = au_pending_free_win->w_next;
	    vim_free(au_pending_free_win);
	    au_pending_free_win = w;
	}
    }

    /*
     * Some events don't set or reset the Changed flag.
     * Check if still in the same buffer!
     */
    if (curbuf == old_curbuf
	    && (event == EVENT_BUFREADPOST
		|| event == EVENT_BUFWRITEPOST
		|| event == EVENT_FILEAPPENDPOST
		|| event == EVENT_VIMLEAVE
		|| event == EVENT_VIMLEAVEPRE))
    {
#ifdef FEAT_TITLE
	if (curbuf->b_changed != save_changed)
	    need_maketitle = TRUE;
#endif
	curbuf->b_changed = save_changed;
    }

    au_cleanup();	/* may really delete removed patterns/commands now */

BYPASS_AU:
    /* When wiping out a buffer make sure all its buffer-local autocommands
     * are deleted. */
    if (event == EVENT_BUFWIPEOUT && buf != NULL)
	aubuflocal_remove(buf);

    if (retval == OK && event == EVENT_FILETYPE)
	au_did_filetype = TRUE;

    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 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_DEFAULT    -1	    /* default autocmd group */

# define AUGROUP_ERROR	    -2	    /* erroneous autocmd group */

# define AUGROUP_ALL	    -3	    /* all autocmd groups */

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


do_doautocmd(
    char_u	*arg,
    int		do_msg,	    /* give message for no matching autocmds? */
    int		*did_something)
{
    char_u	*fname;
    int		nothing_done = TRUE;
    int		group;

    if (did_something != NULL)
	*did_something = FALSE;

    /*
     * Check for a legal group name.  If not, use AUGROUP_ALL.
     */
    group = au_get_grouparg(&arg);
    if (arg == NULL)	    /* out of memory */
	return FAIL;

    if (*arg == '*')
    {
	EMSG(_("E217: Can't execute autocommands for ALL events"));
	return FAIL;
    }

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

    fname = skipwhite(fname);

    /*
     * Loop over the events.
     */
    while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
	if (apply_autocmds_group(event_name2nr(arg, &arg),
				      fname, NULL, TRUE, group, curbuf, NULL))
	    nothing_done = FALSE;

    if (nothing_done && do_msg)
	MSG(_("No matching autocommands"));
    if (did_something != NULL)
	*did_something = !nothing_done;

#ifdef FEAT_EVAL
    return aborting() ? FAIL : OK;
#else
    return OK;
#endif
}

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;

int		filtering = (flags & READ_FILTER);

int		read_stdin = (flags & READ_STDIN);


vim_settempdir(char_u *tempdir)
{
    char_u	*buf;

    buf = alloc((unsigned)MAXPATHL + 2);
    if (buf != NULL)
    {
	if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
	    STRCPY(buf, tempdir);
	add_pathsep(buf);
	vim_tempdir = vim_strsave(buf);
	vim_free(buf);
    }
}

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 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 void vim_settempdir(char_u *tempdir);

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;

int		file_rewind = FALSE;

int		keep_dest_enc = FALSE;

char_u	*tmpname = NULL;

char_u	*fenc;

char_u	*fenc_next = NULL;

int		advance_fenc = FALSE;

int		did_iconv = FALSE;

int		converted = FALSE;

int		notconverted = FALSE;

char_u	conv_rest[CONV_RESTLEN];

char_u	*old_b_ffname;


shorten_fname1(char_u *full_path)
{
    char_u	*dirname;
    char_u	*p = full_path;

    dirname = alloc(MAXPATHL);
    if (dirname == NULL)
	return full_path;
    if (mch_dirname(dirname, MAXPATHL) == OK)
    {
	p = shorten_fname(full_path, dirname);
	if (p == NULL || *p == NUL)
	    p = full_path;
    }
    vim_free(dirname);
    return p;
}

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 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 void vim_settempdir(char_u *tempdir);

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;

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;

char_u	    *errnum = NULL;

char_u	    *buffer;

char_u	    smallbuf[SMBUFSIZE];

char_u	    *backup_ext;

char_u	    *fenc;


write_eintr(int fd, void *buf, size_t bufsize)
{
    long    ret = 0;
    long    wlen;

    /* Repeat the write() so long it didn't fail, other than being interrupted
     * by a signal. */
    while (ret < (long)bufsize)
    {
	wlen = vim_write(fd, (char *)buf + ret, bufsize - ret);
	if (wlen < 0)
	{
	    if (errno != EINTR)
		break;
	}
	else
	    ret += wlen;
    }
    return ret;
}

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

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

int		wasempty;

long	size = 0;

int		skip_read = FALSE;


show_autocmd(AutoPat *ap, event_T event)
{
    AutoCmd *ac;

    /* Check for "got_int" (here and at various places below), which is set
     * when "q" has been hit for the "--more--" prompt */
    if (got_int)
	return;
    if (ap->pat == NULL)		/* pattern has been removed */
	return;

    msg_putchar('\n');
    if (got_int)
	return;
    if (event != last_event || ap->group != last_group)
    {
	if (ap->group != AUGROUP_DEFAULT)
	{
	    if (AUGROUP_NAME(ap->group) == NULL)
		msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E));
	    else
		msg_puts_attr(AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
	    msg_puts((char_u *)"  ");
	}
	msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T));
	last_event = event;
	last_group = ap->group;
	msg_putchar('\n');
	if (got_int)
	    return;
    }
    msg_col = 4;
    msg_outtrans(ap->pat);

    for (ac = ap->cmds; ac != NULL; ac = ac->next)
    {
	if (ac->cmd != NULL)		/* skip removed commands */
	{
	    if (msg_col >= 14)
		msg_putchar('\n');
	    msg_col = 14;
	    if (got_int)
		return;
	    msg_outtrans(ac->cmd);
#ifdef FEAT_EVAL
	    if (p_verbose > 0)
		last_set_msg(ac->scriptID);
#endif
	    if (got_int)
		return;
	    if (ac->next != NULL)
	    {
		msg_putchar('\n');
		if (got_int)
		    return;
	    }
	}
    }
}

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

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;

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;


set_forced_fenc(exarg_T *eap)
{
    if (eap->force_enc != 0)
    {
	char_u *fenc = enc_canonize(eap->cmd + eap->force_enc);

	if (fenc != NULL)
	    set_string_option_direct((char_u *)"fenc", -1,
				 fenc, OPT_FREE|OPT_LOCAL, 0);
	vim_free(fenc);
    }
}


get_mac_fio_flags(char_u *ptr)
{
    if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
				     && (enc_canon_props(ptr) & ENC_MACROMAN))
	return FIO_MACROMAN;
    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 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_MACROMAN	0x20	/* convert MacRoman */

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 void vim_settempdir(char_u *tempdir);

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;

char_u	    *errnum = NULL;

char_u	    *buffer;

char_u	    smallbuf[SMBUFSIZE];

char_u	    *backup_ext;

char_u	    *fenc;

char_u	    *fenc_tofree = NULL;


vim_deltempdir(void)
{
    if (vim_tempdir != NULL)
    {
	/* remove the trailing path separator */
	gettail(vim_tempdir)[-1] = NUL;
	delete_recursive(vim_tempdir);
	vim_free(vim_tempdir);
	vim_tempdir = NULL;
    }
}

static void check_marks_read(void);

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

static void msg_add_eol(void);

static void vim_settempdir(char_u *tempdir);

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;


make_bom(char_u *buf, char_u *name)
{
    int		flags;
    char_u	*p;

    flags = get_fio_flags(name);

    /* Can't put a BOM in a non-Unicode file. */
    if (flags == FIO_LATIN1 || flags == 0)
	return 0;

    if (flags == FIO_UTF8)	/* UTF-8 */
    {
	buf[0] = 0xef;
	buf[1] = 0xbb;
	buf[2] = 0xbf;
	return 3;
    }
    p = buf;
    (void)ucs2bytes(0xfeff, &p, flags);
    return (int)(p - buf);
}

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 FIO_LATIN1	0x01	/* convert Latin1 */

# define FIO_UTF8	0x02	/* convert UTF-8 */

# define FIO_UTF16	0x10	/* convert UTF-16 */

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

# 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


tag_fgets(char_u *buf, int size, FILE *fp)
{
    int		i = 0;
    int		c;
    int		eof = FALSE;

    for (;;)
    {
	c = fgetc(fp);
	if (c == EOF)
	{
	    eof = TRUE;
	    break;
	}
	if (c == '\r')
	{
	    /* Always store a NL for end-of-line. */
	    if (i < size - 1)
		buf[i++] = '\n';
	    c = fgetc(fp);
	    if (c != '\n')	/* Macintosh format: single CR. */
		ungetc(c, fp);
	    break;
	}
	if (i < size - 1)
	    buf[i++] = c;
	if (c == '\n')
	    break;
    }
    buf[i] = NUL;
    return eof;
}

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