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

📄 fileio.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:

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