⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fileio.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
     * a new one. If this still fails we may have lost the original file!
     * (this may happen when the user reached his quotum for number of files).
     * Appending will fail if the file does not exist and forceit is FALSE.
     */
#ifdef VMS
    STRCPY(nfname, fname);
    if (cp = vim_strchr(nfname, ';')) /* remove version */
	*cp = '\0';
#endif

    while ((fd = open((char *)
#ifdef VMS
		    nfname,
#else
		    fname,
#endif
			  O_WRONLY | O_EXTRA | (append ?
		    (forceit ? (O_APPEND | O_CREAT) : O_APPEND) :
		    (O_CREAT | O_TRUNC))
#ifndef macintosh
			, 0666
#endif
				)) < 0)
    {
	/*
	 * A forced write will try to create a new file if the old one is
	 * still readonly. This may also happen when the directory is
	 * read-only. In that case the mch_remove() will fail.
	 */
	if (!errmsg)
	{
	    errmsg = (char_u *)"Can't open file for writing";
	    if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
	    {
#ifdef UNIX
		/* we write to the file, thus it should be marked
						    writable after all */
		if (!(perm & 0200))
		    made_writable = TRUE;
		perm |= 0200;
		if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
		    perm &= 0777;
#endif
		if (!append)	    /* don't remove when appending */
		    mch_remove(fname);
		continue;
	    }
	}
/*
 * If we failed to open the file, we don't need a backup. Throw it away.
 * If we moved or removed the original file try to put the backup in its place.
 */
	if (backup != NULL)
	{
#ifdef UNIX
	    struct stat st;

	    /*
	     * There is a small chance that we removed the original, try
	     * to move the copy in its place.
	     * This may not work if the vim_rename() fails.
	     * In that case we leave the copy around.
	     */
					/* file does not exist */
	    if (stat((char *)fname, &st) < 0)
					/* put the copy in its place */
		vim_rename(backup, fname);
					/* original file does exist */
	    if (stat((char *)fname, &st) >= 0)
		mch_remove(backup); /* throw away the copy */
#else
					/* try to put the original file back */
	    vim_rename(backup, fname);
#endif
	}
	goto fail;
    }
    errmsg = NULL;

    if (end > buf->b_ml.ml_line_count)
	end = buf->b_ml.ml_line_count;
    len = 0;
    s = buffer;
    nchars = 0;
    if (buf->b_ml.ml_flags & ML_EMPTY)
	start = end + 1;
    for (lnum = start; lnum <= end; ++lnum)
    {
	/*
	 * The next while loop is done once for each character written.
	 * Keep it fast!
	 */
	ptr = ml_get_buf(buf, lnum, FALSE) - 1;
	while ((c = *++ptr) != NUL)
	{
	    if (c == NL)
		*s = NUL;		/* replace newlines with NULs */
	    else
		*s = c;
	    ++s;
	    if (++len != bufsize)
		continue;
	    if (write_buf(fd, buffer, bufsize) == FAIL)
	    {
		end = 0;		/* write error: break loop */
		break;
	    }
	    nchars += bufsize;
	    s = buffer;
	    len = 0;
	}
	/* write failed or last line has no EOL: stop here */
	if (end == 0 || (lnum == end && buf->b_p_bin &&
						(lnum == write_no_eol_lnum ||
			 (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
	{
	    ++lnum;			/* written the line, count it */
	    no_eol = TRUE;
	    break;
	}
	if (fileformat == EOL_UNIX)
	    *s++ = NL;
	else
	{
	    *s++ = CR;			/* EOL_MAC or EOL_DOS: write CR */
	    if (fileformat == EOL_DOS)	/* write CR-NL */
	    {
		if (++len == bufsize)
		{
		    if (write_buf(fd, buffer, bufsize) == FAIL)
		    {
			end = 0;	/* write error: break loop */
			break;
		    }
		    nchars += bufsize;
		    s = buffer;
		    len = 0;
		}
		*s++ = NL;
	    }
	}
	if (++len == bufsize && end)
	{
	    if (write_buf(fd, buffer, bufsize) == FAIL)
	    {
		end = 0;		/* write error: break loop */
		break;
	    }
	    nchars += bufsize;
	    s = buffer;
	    len = 0;
	}
    }
    if (len && end)
    {
	if (write_buf(fd, buffer, len) == FAIL)
	    end = 0;		    /* write error */
	nchars += len;
    }

    if (close(fd) != 0)
    {
	errmsg = (char_u *)"Close failed";
	goto fail;
    }
#ifdef UNIX
    if (made_writable)
	perm &= ~0200;		/* reset 'w' bit for security reasons */
#endif
    if (perm >= 0)		/* set perm. of new file same as old file */
	(void)mch_setperm(fname, perm);
#ifdef RISCOS
    if (!append && !filtering)
	/* Set the filetype after writing the file. */
	ro_set_filetype(fname, buf->b_p_ft);
#endif

    if (end == 0)
    {
	errmsg = (char_u *)"write error (file system full?)";
	/*
	 * If we have a backup file, try to put it in place of the new file,
	 * because it is probably corrupt. This avoids loosing the original
	 * file when trying to make a backup when writing the file a second
	 * time.
	 * For unix this means copying the backup over the new file.
	 * For others this means renaming the backup file.
	 * If this is OK, don't give the extra warning message.
	 */
	if (backup != NULL)
	{
#ifdef UNIX
	    char_u	copybuf[BUFSIZE + 1];
	    int		bfd, buflen;

	    if ((bfd = open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
	    {
		if ((fd = open((char *)fname,
			  O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA, 0666)) >= 0)
		{
		    /* copy the file. */
		    while ((buflen = read(bfd, (char *)copybuf, BUFSIZE)) > 0)
			if (write_buf(fd, copybuf, buflen) == FAIL)
			    break;
		    if (close(fd) >= 0 && buflen == 0)	/* success */
			end = 1;
		}
		close(bfd);	/* ignore errors for closing read file */
	    }
#else
	    if (vim_rename(backup, fname) == 0)
		end = 1;
#endif
	}
	goto fail;
    }

    lnum -= start;	    /* compute number of written lines */
    --no_wait_return;	    /* may wait for return now */

#ifndef UNIX
    fname = sfname;	    /* use shortname now, for the messages */
#endif
    if (!filtering)
    {
	msg_add_fname(buf, fname);	/* put fname in IObuff with quotes */
	c = FALSE;
	if (newfile)
	{
	    STRCAT(IObuff, shortmess(SHM_NEW) ? "[New]" : "[New File]");
	    c = TRUE;
	}
	if (no_eol)
	{
	    msg_add_eol();
	    c = TRUE;
	}
	/* may add [unix/dos/mac] */
	if (msg_add_fileformat(fileformat))
	    c = TRUE;
	msg_add_lines(c, (long)lnum, nchars);	/* add line/char count */
	if (!shortmess(SHM_WRITE))
	    STRCAT(IObuff, shortmess(SHM_WRI) ? " [w]" : " written");

	keep_msg = msg_trunc_attr(IObuff, FALSE, 0);
	keep_msg_attr = 0;
    }

    if (reset_changed && whole)		/* when written everything */
    {
	unchanged(buf, TRUE);
	u_unchanged(buf);
    }

    /*
     * If written to the current file, update the timestamp of the swap file
     * and reset the 'notedited' flag. Also sets buf->b_mtime.
     */
    if (!exiting && overwriting)
    {
	ml_timestamp(buf);
	buf->b_notedited = FALSE;
    }

    /*
     * If we kept a backup until now, and we are in patch mode, then we make
     * the backup file our 'original' file.
     */
    if (*p_pm)
    {
	char *org = (char *)buf_modname(
#ifdef SHORT_FNAME
					TRUE,
#else
					(buf->b_p_sn || buf->b_shortname),
#endif
							  fname, p_pm, FALSE);

	if (backup != NULL)
	{
	    struct stat st;

	    /*
	     * If the original file does not exist yet
	     * the current backup file becomes the original file
	     */
	    if (org == NULL)
		EMSG("patchmode: can't save original file");
	    else if (stat(org, &st) < 0)
	    {
		vim_rename(backup, (char_u *)org);
		vim_free(backup);	    /* don't delete the file */
		backup = NULL;
#ifdef UNIX
		set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
#endif
	    }
	}
	/*
	 * If there is no backup file, remember that a (new) file was
	 * created.
	 */
	else
	{
	    int empty_fd;

	    if (org == NULL || (empty_fd = open(org, O_CREAT | O_EXTRA
#ifndef macintosh
				, 0666
#endif
					)) < 0)
	      EMSG("patchmode: can't touch empty original file");
	    else
	      close(empty_fd);
	}
	if (org != NULL)
	{
	    mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
	    vim_free(org);
	}
    }

    /*
     * Remove the backup unless 'backup' option is set
     */
    if (!p_bk && backup != NULL && mch_remove(backup) != 0)
	EMSG("Can't delete backup file");

    goto nofail;

fail:
    --no_wait_return;		/* may wait for return now */
nofail:

    vim_free(backup);
    if (buffer != smallbuf)
	vim_free(buffer);

    if (errmsg != NULL)
    {
	attr = hl_attr(HLF_E);	/* set highlight for error messages */
	msg_add_fname(buf,
#ifndef UNIX
		sfname
#else
		fname
#endif
		     );		/* put file name in IObuff with quotes */
	STRCAT(IObuff, errmsg);
	emsg(IObuff);

	retval = FAIL;
	if (end == 0)
	{
	    MSG_PUTS_ATTR("\nWARNING: Original file may be lost or damaged\n",
		    attr);
	    MSG_PUTS_ATTR("don't quit the editor until the file is successfully written!",
		    attr);
	}
    }
    msg_scroll = msg_save;

#ifdef AUTOCMD
    write_no_eol_lnum = 0;	/* in case it was set by the previous read */

    /*
     * Apply POST autocommands.
     * Careful: The autocommands may call buf_write() recursively!
     */
    save_buf = curbuf;
    curbuf = buf;
    curwin->w_buffer = buf;
    if (append)
	apply_autocmds(EVENT_FILEAPPENDPOST, fname, fname, FALSE, curbuf);
    else if (filtering)
	apply_autocmds(EVENT_FILTERWRITEPOST, NULL, fname, FALSE, curbuf);
    else if (reset_changed && whole)
	apply_autocmds(EVENT_BUFWRITEPOST, fname, fname, FALSE, curbuf);
    else
	apply_autocmds(EVENT_FILEWRITEPOST, fname, fname, FALSE, curbuf);
    /*
     * If the autocommands didn't change the current buffer, go back to the
     * original current buffer, if it still exists.
     */
    if (curbuf == buf && buf_valid(save_buf))
    {
	curbuf = save_buf;
	curwin->w_buffer = save_buf;
    }
#endif

    return retval;
}

/*
 * Put file name into IObuff with quotes.
 */
    static void
msg_add_fname(buf, fname)
    BUF	    *buf;
    char_u  *fname;
{
    if (fname == NULL)
	fname = (char_u *)"-stdin-";
    home_replace(buf, fname, IObuff + 1, IOSIZE - 1, TRUE);
    IObuff[0] = '"';
    STRCAT(IObuff, "\" ");
}

/*
 * Append message for text mode to IObuff.
 * Return TRUE if something appended.
 */
    static int
msg_add_fileformat(eol_type)
    int	    eol_type;
{
#ifndef USE_CRNL
    if (eol_type == EOL_DOS)
    {
	STRCAT(IObuff, shortmess(SHM_TEXT) ? "[dos]" : "[dos format]");
	return TRUE;
    }
#endif
#ifndef USE_CR
    if (eol_type == EOL_MAC)
    {
	STRCAT(IObuff, shortmess(SHM_TEXT) ? "[mac]" : "[mac format]");
	return TRUE;
    }
#endif
#if defined(USE_CRNL) || defined(USE_CR)
    if (eol_type == EOL_UNIX)
    {
	STRCAT(IObuff, shortmess(SHM_TEXT) ? "[unix]" : "[unix format]");
	return TRUE;
    }
#endif
    return FALSE;
}

/*
 * Append line and character count to IObuff.
 */
    static void
msg_add_lines(insert_space, lnum, nchars)
    int	    insert_space;
    long    lnum;
    long    nchars;
{
    char_u  *p;

    p = IObuff + STRLEN(IObuff);

    if (insert_space)
	*p++ = ' ';
    if (shortmess(SHM_LINES))
	sprintf((char *)p, "%ldL, %ldC", lnum, nchars);
    else
	sprintf((char *)p, "%ld line%s, %ld character%s",
	    lnum, plural(lnum),
	    nchars, plural(nchars));
}

/*
 * Append message for missing line separator to IObuff.
 */
    static void
msg_add_eol()
{
    STRCAT(IObuff, shortmess(SHM_LAST) ? "[noeol]" : "[Incomplete last line]");
}

/*
 * Check modification time of file, before writing to it.
 */
    static int
check_mtime(buf, st)
    BUF			*buf;
    struct stat		*st;
{
    if (buf->b_mtime_read != 0
#ifdef __linux__
	    /* In Linux, on a FAT filesystem, there are only 5 bits to store
	     * the seconds.  Since the roundoff is done when flushing the
	     * inode, the time may change unexpectedly by one second!!! */
	    && st->st_mtime - buf->b_mtime_read > 1
#else
	    && buf->b_mtime_read != st->st_mtime
#endif
	    )
    {
	msg_scroll = TRUE;	    /* don't overwrite messages here */
	/* 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;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -