📄 fileio.c
字号:
* 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 + -