📄 fileio.c
字号:
/*
* write_buf: call write() to write a buffer
*
* return FAIL for failure, OK otherwise
*/
static int
write_buf(fd, buf, len)
int fd;
char_u *buf;
int len;
{
int wlen;
while (len)
{
wlen = write(fd, (char *)buf, (size_t)len);
if (wlen <= 0) /* error! */
return FAIL;
len -= wlen;
buf += wlen;
}
return OK;
}
/*
* shorten_fname: Try to find a shortname by comparing the fullname with the
* current directory.
* Returns NULL if not shorter name possible, pointer into "full_path"
* otherwise.
*/
char_u *
shorten_fname(full_path, dir_name)
char_u *full_path;
char_u *dir_name;
{
int len;
char_u *p;
if (full_path == NULL)
return NULL;
len = STRLEN(dir_name);
if (fnamencmp(dir_name, full_path, len) == 0)
{
p = full_path + len;
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
/*
* MSDOS: when a file is in the root directory, dir_name will end in a
* slash, since C: by itself does not define a specific dir. In this
* case p may already be correct. <negri>
*/
if (!((len > 2) && (*(p - 2) == ':')))
#endif
if (vim_ispathsep(*p))
++p;
else
p = NULL;
}
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
/*
* When using a file in the current drive, remove the drive name:
* "A:\dir\file" -> "\dir\file". This helps when moving a session file on
* a floppy from "A:\dir" to "B:\dir".
*/
else if (len > 3
&& TO_UPPER(full_path[0]) == TO_UPPER(dir_name[0])
&& full_path[1] == ':'
&& vim_ispathsep(full_path[2]))
p = full_path + 2;
#endif
else
p = NULL;
return p;
}
/*
* Use full path from now on for files currently being edited, both for file
* name and swap file name. Try to shorten the file names a bit if safe to do
* so.
*/
void
shorten_fnames()
{
char_u dirname[MAXPATHL];
BUF *buf;
char_u *p;
mch_dirname(dirname, MAXPATHL);
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
if (buf->b_fname != NULL)
{
vim_free(buf->b_sfname);
buf->b_sfname = NULL;
p = shorten_fname(buf->b_ffname, dirname);
if (p != NULL)
{
buf->b_sfname = vim_strsave(p);
buf->b_fname = buf->b_sfname;
}
if (p == NULL || buf->b_fname == NULL)
buf->b_fname = buf->b_ffname;
mf_fullname(buf->b_ml.ml_mfp);
}
}
status_redraw_all();
}
/*
* add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
* fo_o_h.ext for MSDOS or when shortname option set.
*
* Assumed that fname is a valid name found in the filesystem we assure that
* the return value is a different name and ends in 'ext'.
* "ext" MUST be at most 4 characters long if it starts with a dot, 3
* characters otherwise.
* Space for the returned name is allocated, must be freed later.
* Returns NULL when out of memory.
*/
char_u *
modname(fname, ext, prepend_dot)
char_u *fname, *ext;
int prepend_dot; /* may prepend a '.' to file name */
{
return buf_modname(
#ifdef SHORT_FNAME
TRUE,
#else
(curbuf->b_p_sn || curbuf->b_shortname),
#endif
fname, ext, prepend_dot);
}
char_u *
buf_modname(shortname, fname, ext, prepend_dot)
int shortname; /* use 8.3 file name */
char_u *fname, *ext;
int prepend_dot; /* may prepend a '.' to file name (for Unix) */
{
char_u *retval;
char_u *s;
char_u *e;
char_u *ptr;
int fnamelen, extlen;
extlen = STRLEN(ext);
/*
* If there is no file name we must get the name of the current directory
* (we need the full path in case :cd is used).
*/
if (fname == NULL || *fname == NUL)
{
retval = alloc((unsigned)(MAXPATHL + extlen + 3));
if (retval == NULL)
return NULL;
if (mch_dirname(retval, MAXPATHL) == FAIL ||
(fnamelen = STRLEN(retval)) == 0)
{
vim_free(retval);
return NULL;
}
if (!vim_ispathsep(retval[fnamelen - 1]))
{
retval[fnamelen++] = PATHSEP;
retval[fnamelen] = NUL;
}
#ifndef SHORT_FNAME
prepend_dot = FALSE; /* nothing to prepend a dot to */
#endif
}
else
{
fnamelen = STRLEN(fname);
retval = alloc((unsigned)(fnamelen + extlen + 3));
if (retval == NULL)
return NULL;
STRCPY(retval, fname);
}
/*
* search backwards until we hit a '/', '\' or ':' replacing all '.'
* by '_' for MSDOS or when shortname option set and ext starts with a dot.
* Then truncate what is after the '/', '\' or ':' to 8 characters for
* MSDOS and 26 characters for AMIGA, a lot more for UNIX.
*/
for (ptr = retval + fnamelen; ptr >= retval; ptr--)
{
#ifndef RISCOS
if (*ext == '.'
#ifdef USE_LONG_FNAME
&& (!USE_LONG_FNAME || shortname)
#else
# ifndef SHORT_FNAME
&& shortname
# endif
#endif
)
if (*ptr == '.') /* replace '.' by '_' */
*ptr = '_';
#endif /* RISCOS */
if (vim_ispathsep(*ptr))
break;
}
ptr++;
/* the file name has at most BASENAMELEN characters. */
#ifndef SHORT_FNAME
if (STRLEN(ptr) > (unsigned)BASENAMELEN)
ptr[BASENAMELEN] = '\0';
#endif
s = ptr + STRLEN(ptr);
/*
* For 8.3 file names we may have to reduce the length.
*/
#ifdef USE_LONG_FNAME
if (!USE_LONG_FNAME || shortname)
#else
# ifndef SHORT_FNAME
if (shortname)
# endif
#endif
{
/*
* If there is no file name, or the file name ends in '/', and the
* extension starts with '.', put a '_' before the dot, because just
* ".ext" is invalid.
*/
if (fname == NULL || *fname == NUL
|| vim_ispathsep(fname[STRLEN(fname) - 1]))
{
#ifdef RISCOS
if (*ext == '/')
#else
if (*ext == '.')
#endif
*s++ = '_';
}
/*
* If the extension starts with '.', truncate the base name at 8
* characters
*/
#ifdef RISCOS
/* We normally use '/', but swap files are '_' */
else if (*ext == '/' || *ext == '_')
#else
else if (*ext == '.')
#endif
{
if (s - ptr > (size_t)8)
{
s = ptr + 8;
*s = '\0';
}
}
/*
* If the extension doesn't start with '.', and the file name
* doesn't have an extension yet, append a '.'
*/
#ifdef RISCOS
else if ((e = vim_strchr(ptr, '/')) == NULL)
*s++ = '/';
#else
else if ((e = vim_strchr(ptr, '.')) == NULL)
*s++ = '.';
#endif
/*
* If the extension doesn't start with '.', and there already is an
* extension, it may need to be tructated
*/
else if ((int)STRLEN(e) + extlen > 4)
s = e + 4 - extlen;
}
#if defined(OS2) || defined(USE_LONG_FNAME) || defined(WIN32)
/*
* If there is no file name, and the extension starts with '.', put a
* '_' before the dot, because just ".ext" may be invalid if it's on a
* FAT partition, and on HPFS it doesn't matter.
*/
else if ((fname == NULL || *fname == NUL) && *ext == '.')
*s++ = '_';
#endif
/*
* Append the extention.
* ext can start with '.' and cannot exceed 3 more characters.
*/
STRCPY(s, ext);
#ifndef SHORT_FNAME
/*
* Prepend the dot.
*/
if (prepend_dot && !shortname && *(e = gettail(retval)) !=
#ifdef RISCOS
'/'
#else
'.'
#endif
#ifdef USE_LONG_FNAME
&& USE_LONG_FNAME
#endif
)
{
mch_memmove(e + 1, e, STRLEN(e) + 1);
#ifdef RISCOS
*e = '/';
#else
*e = '.';
#endif
}
#endif
/*
* Check that, after appending the extension, the file name is really
* different.
*/
if (fname != NULL && STRCMP(fname, retval) == 0)
{
/* we search for a character that can be replaced by '_' */
while (--s >= ptr)
{
if (*s != '_')
{
*s = '_';
break;
}
}
if (s < ptr) /* fname was "________.<ext>" how tricky! */
*ptr = 'v';
}
return retval;
}
/* vim_fgets();
*
* Like fgets(), but if the file line is too long, it is truncated and the
* rest of the line is thrown away. Returns TRUE for end-of-file.
* Note: do not pass IObuff as the buffer since this is used to read and
* discard the extra part of any long lines.
*/
int
vim_fgets(buf, size, fp)
char_u *buf;
int size;
FILE *fp;
{
char *eof;
buf[size - 2] = NUL;
eof = fgets((char *)buf, size, fp);
if (buf[size - 2] != NUL && buf[size - 2] != '\n')
{
buf[size - 1] = NUL; /* Truncate the line */
/* Now throw away the rest of the line: */
do
{
IObuff[IOSIZE - 2] = NUL;
fgets((char *)IObuff, IOSIZE, fp);
} while (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != '\n');
}
return (eof == NULL);
}
/*
* rename() only works if both files are on the same file system, this
* function will (attempts to?) copy the file across if rename fails -- webb
* Return -1 for failure, 0 for success.
*/
int
vim_rename(from, to)
char_u *from;
char_u *to;
{
int fd_in;
int fd_out;
int n;
char *errmsg = NULL;
char *buffer;
/*
* First delete the "to" file, this is required on some systems to make
* the mch_rename() work, on other systems it makes sure that we don't
* have two files when the mch_rename() fails.
*/
mch_remove(to);
/*
* First try a normal rename, return if it works.
*/
if (mch_rename((char *)from, (char *)to) == 0)
return 0;
/*
* Rename() failed, try copying the file.
*/
fd_in = open((char *)from, O_RDONLY | O_EXTRA
#ifndef macintosh
, 0
#endif
);
if (fd_in == -1)
return -1;
fd_out = open((char *)to, O_CREAT | O_TRUNC | O_WRONLY | O_EXTRA
#ifndef macintosh
, 0666
#endif
);
if (fd_out == -1)
{
close(fd_in);
return -1;
}
buffer = (char *)alloc(BUFSIZE);
if (buffer == NULL)
{
close(fd_in);
close(fd_out);
return -1;
}
while ((n = read(fd_in, buffer, (size_t)BUFSIZE)) > 0)
if (write(fd_out, buffer, (size_t)n) != n)
{
errmsg = "writing to";
break;
}
vim_free(buffer);
close(fd_in);
if (close(fd_out) < 0)
errmsg = "closing";
if (n < 0)
{
errmsg = "reading";
to = from;
}
if (errmsg != NULL)
{
sprintf((char *)IObuff, "Error %s '%s'", errmsg, to);
emsg(IObuff);
return -1;
}
mch_remove(from);
return 0;
}
/*
* Check if any not hidden buffer has been changed.
* Postpone the check if there are characters in the stuff buffer, a global
* command is being executed, a mapping is being executed or an autocommand is
* busy.
*/
void
check_timestamps()
{
BUF *buf;
if (!stuff_empty() || global_busy || !typebuf_typed()
#ifdef AUTOCMD
|| autocmd_busy
#endif
)
need_check_timestamps = TRUE; /* check later */
else
{
++no_wait_return;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
buf_check_timestamp(buf);
--no_wait_return;
need_check_timestamps = FALSE;
if (need_wait_return) /* make sure the message isn't overwritten */
msg_puts((char_u *)"\n");
}
}
/*
* Check if buffer "buf" has been changed.
*/
void
buf_check_timestamp(buf)
BUF *buf;
{
struct stat st;
char_u *path;
if ( buf->b_ffname != NULL
&& buf->b_ml.ml_mfp != NULL
&& !buf->b_notedited
&& buf->b_mtime != 0
&& stat((char *)buf->b_ffname, &st) >= 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!!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -