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

📄 memfile.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (nr < 0 || nr >= mfp->mf_infile_count)   /* can't be in the file */
	    return NULL;

	/* could check here if the block is in the free list */

	/*
	 * Check if we need to flush an existing block.
	 * If so, use that block.
	 * If not, allocate a new block.
	 */
	hp = mf_release(mfp, page_count);
	if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
	    return NULL;

	hp->bh_bnum = nr;
	hp->bh_flags = 0;
	hp->bh_page_count = page_count;
	if (mf_read(mfp, hp) == FAIL)	    /* cannot read the block! */
	{
	    mf_free_bhdr(hp);
	    return NULL;
	}
    }
    else
    {
	mf_rem_used(mfp, hp);	/* remove from list, insert in front below */
	mf_rem_hash(mfp, hp);
    }

    hp->bh_flags |= BH_LOCKED;
    mf_ins_used(mfp, hp);	/* put in front of used list */
    mf_ins_hash(mfp, hp);	/* put in front of hash list */

    return hp;
}

/*
 * release the block *hp
 *
 *   dirty: Block must be written to file later
 *   infile: Block should be in file (needed for recovery)
 *
 *  no return value, function cannot fail
 */
    void
mf_put(mfp, hp, dirty, infile)
    MEMFILE *mfp;
    BHDR    *hp;
    int	    dirty;
    int	    infile;
{
    int	    flags;

    flags = hp->bh_flags;

    if ((flags & BH_LOCKED) == 0)
	EMSG("block was not locked");
    flags &= ~BH_LOCKED;
    if (dirty)
    {
	flags |= BH_DIRTY;
	mfp->mf_dirty = TRUE;
    }
    hp->bh_flags = flags;
    if (infile)
	mf_trans_add(mfp, hp);	    /* may translate negative in positive nr */
}

/*
 * block *hp is no longer in used, may put it in the free list of memfile *mfp
 */
    void
mf_free(mfp, hp)
    MEMFILE *mfp;
    BHDR    *hp;
{
    vim_free(hp->bh_data);	/* free the memory */
    mf_rem_hash(mfp, hp);	/* get *hp out of the hash list */
    mf_rem_used(mfp, hp);	/* get *hp out of the used list */
    if (hp->bh_bnum < 0)
    {
	vim_free(hp);		/* don't want negative numbers in free list */
	mfp->mf_neg_count--;
    }
    else
	mf_ins_free(mfp, hp);	/* put *hp in the free list */
}

/*
 * Sync the memory file *mfp to disk.
 * Flags:
 *  MFS_ALL	If not given, blocks with negative numbers are not synced,
 *		even when they are dirty!
 *  MFS_STOP	Stop syncing when a character becomes available, but sync at
 *		least one block.
 *  MFS_FLUSH	Make sure buffers are flushed to disk, so they will survive a
 *		system crash.
 *  MFS_ZERO	Only write block 0.
 *
 * Return FAIL for failure, OK otherwise
 */
    int
mf_sync(mfp, flags)
    MEMFILE *mfp;
    int	    flags;
{
    int	    status;
    BHDR    *hp;
#ifdef SYNC_DUP_CLOSE
    int	    fd;
#endif

    if (mfp->mf_fd < 0)	    /* there is no file, nothing to do */
    {
	mfp->mf_dirty = FALSE;
	return FAIL;
    }

    /*
     * sync from last to first (may reduce the probability of an inconsistent
     * file) If a write fails, it is very likely caused by a full filesystem.
     * Then we only try to write blocks within the existing file. If that also
     * fails then we give up.
     */
    status = OK;
    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
	if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
		&& (hp->bh_flags & BH_DIRTY)
		&& (status == OK || (hp->bh_bnum >= 0
		    && hp->bh_bnum < mfp->mf_infile_count)))
	{
	    if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
		continue;
	    if (mf_write(mfp, hp) == FAIL)
	    {
		if (status == FAIL)	/* double error: quit syncing */
		    break;
		status = FAIL;
	    }
	    /* Stop when char available now */
	    if ((flags & MFS_STOP) && ui_char_avail())
		break;
	}

    /*
     * If the whole list is flushed, the memfile is not dirty anymore.
     * In case of an error this flag is also set, to avoid trying all the time.
     */
    if (hp == NULL || status == FAIL)
	mfp->mf_dirty = FALSE;

    if ((flags & MFS_FLUSH) && *p_sws != NUL)
    {
#if defined(UNIX)
# ifdef HAVE_FSYNC
	/*
	 * most Unixes have the very useful fsync() function, just what we need.
	 * However, with OS/2 and EMX it is also available, but there are
	 * reports of bad problems with it (a bug in HPFS.IFS).
	 * So we disable use of it here in case someone tries to be smart
	 * and changes os_os2_cfg.h... (even though there is no __EMX__ test
	 * in the #if, as __EMX__ does not have sync(); we hope for a timely
	 * sync from the system itself).
	 */
#  if defined(__EMX__)
   error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
#  endif
	if (STRCMP(p_sws, "fsync") == 0)
	{
	    if (fsync(mfp->mf_fd))
		status = FAIL;
	}
	else
# endif
# ifdef __OPENNT
	    fflush(NULL);	/* OpenNT is strictly POSIX (Benzinger) */
# else
	    sync();
# endif
#endif
#ifdef VMS
	if (STRCMP(p_sws, "fsync") == 0)
	{
	    if (fsync(mfp->mf_fd))
		status = FAIL;
	}
#endif
#ifdef MSDOS
	if (_dos_commit(mfp->mf_fd))
	    status = FAIL;
#else
# ifdef SYNC_DUP_CLOSE
	/*
	 * Win32 is a bit more work: Duplicate the file handle and close it.
	 * This should flush the file to disk.
	 */
	if ((fd = dup(mfp->mf_fd)) >= 0)
	    close(fd);
# endif
#endif
#ifdef AMIGA
	/*
	 * Flush() only exists for AmigaDos 2.0.
	 * For 1.3 it should be done with close() + open(), but then the risk
	 * is that the open() may fail and lose the file....
	 */
# ifndef NO_ARP
	if (dos2)
# endif
# ifdef SASC
	{
	    struct UFB *fp = chkufb(mfp->mf_fd);

	    if (fp != NULL)
		Flush(fp->ufbfh);
	}
# else
#  ifdef _DCC
	{
	    BPTR fh = (BPTR)fdtofh(mfp->mf_fd);

	    if (fh != 0)
		Flush(fh);
	    }
#  else /* assume Manx */
	    Flush(_devtab[mfp->mf_fd].fd);
#  endif
# endif
#endif /* AMIGA */
    }

    return status;
}

/*
 * insert block *hp in front of hashlist of memfile *mfp
 */
    static void
mf_ins_hash(mfp, hp)
    MEMFILE *mfp;
    BHDR    *hp;
{
    BHDR    *hhp;
    int	    hash;

    hash = MEMHASH(hp->bh_bnum);
    hhp = mfp->mf_hash[hash];
    hp->bh_hash_next = hhp;
    hp->bh_hash_prev = NULL;
    if (hhp != NULL)
	hhp->bh_hash_prev = hp;
    mfp->mf_hash[hash] = hp;
}

/*
 * remove block *hp from hashlist of memfile list *mfp
 */
    static void
mf_rem_hash(mfp, hp)
    MEMFILE *mfp;
    BHDR    *hp;
{
    if (hp->bh_hash_prev == NULL)
	mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
    else
	hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;

    if (hp->bh_hash_next)
	hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
}

/*
 * look in hash lists of memfile *mfp for block header with number 'nr'
 */
    static BHDR *
mf_find_hash(mfp, nr)
    MEMFILE	*mfp;
    blocknr_t	nr;
{
    BHDR	*hp;

    for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
	if (hp->bh_bnum == nr)
	    break;
    return hp;
}

/*
 * insert block *hp in front of used list of memfile *mfp
 */
    static void
mf_ins_used(mfp, hp)
    MEMFILE *mfp;
    BHDR    *hp;
{
    hp->bh_next = mfp->mf_used_first;
    mfp->mf_used_first = hp;
    hp->bh_prev = NULL;
    if (hp->bh_next == NULL)	    /* list was empty, adjust last pointer */
	mfp->mf_used_last = hp;
    else
	hp->bh_next->bh_prev = hp;
    mfp->mf_used_count += hp->bh_page_count;
    total_mem_used += hp->bh_page_count * mfp->mf_page_size;
}

/*
 * remove block *hp from used list of memfile *mfp
 */
    static void
mf_rem_used(mfp, hp)
    MEMFILE *mfp;
    BHDR    *hp;
{
    if (hp->bh_next == NULL)	    /* last block in used list */
	mfp->mf_used_last = hp->bh_prev;
    else
	hp->bh_next->bh_prev = hp->bh_prev;
    if (hp->bh_prev == NULL)	    /* first block in used list */
	mfp->mf_used_first = hp->bh_next;
    else
	hp->bh_prev->bh_next = hp->bh_next;
    mfp->mf_used_count -= hp->bh_page_count;
    total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
}

/*
 * Release the least recently used block from the used list if the number
 * of used memory blocks gets to big.
 *
 * Return the block header to the caller, including the memory block, so
 * it can be re-used. Make sure the page_count is right.
 */
    static BHDR *
mf_release(mfp, page_count)
    MEMFILE	*mfp;
    int		page_count;
{
    BHDR	*hp;
    int		need_release;
    BUF		*buf;

    /* don't release while in mf_close_file() */
    if (dont_release)
	return NULL;

    /*
     * Need to release a block if the number of blocks for this memfile is
     * higher than the maximum or total memory used is over 'maxmemtot'
     */
    need_release = ((mfp->mf_used_count >= mfp->mf_used_count_max)
				  || (total_mem_used >> 10) >= (long_u)p_mmt);

    /*
     * Try to create a swap file if the amount of memory used is getting too
     * high.
     */
    if (mfp->mf_fd < 0 && need_release && p_uc)
    {
	/* find for which buffer this memfile is */
	for (buf = firstbuf; buf != NULL; buf = buf->b_next)
	    if (buf->b_ml.ml_mfp == mfp)
		break;
	if (buf != NULL && buf->b_may_swap)
	    ml_open_file(buf);
    }

    /*
     * don't release a block if
     *	there is no file for this memfile
     * or
     *	the number of blocks for this memfile is lower than the maximum
     *	  and
     *	total memory used is not up to 'maxmemtot'
     */
    if (mfp->mf_fd < 0 || !need_release)
	return NULL;

    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
	if (!(hp->bh_flags & BH_LOCKED))
	    break;
    if (hp == NULL)	/* not a single one that can be released */
	return NULL;

    /*
     * If the block is dirty, write it.
     * If the write fails we don't free it.
     */
    if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
	return NULL;

    mf_rem_used(mfp, hp);
    mf_rem_hash(mfp, hp);

    /*
     * If a BHDR is returned, make sure that the page_count of bh_data is right
     */
    if (hp->bh_page_count != page_count)
    {
	vim_free(hp->bh_data);
	if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
	{
	    vim_free(hp);
	    return NULL;
	}
	hp->bh_page_count = page_count;
    }
    return hp;
}

⌨️ 快捷键说明

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