📄 memfile.c
字号:
/*
* release as many blocks as possible
* Used in case of out of memory
*
* return TRUE if any memory was released
*/
int
mf_release_all()
{
BUF *buf;
MEMFILE *mfp;
BHDR *hp;
int retval = FALSE;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
mfp = buf->b_ml.ml_mfp;
/* only if there is a memfile with a file */
if (mfp != NULL && mfp->mf_fd >= 0)
for (hp = mfp->mf_used_last; hp != NULL; )
{
if (!(hp->bh_flags & BH_LOCKED) && (!(hp->bh_flags & BH_DIRTY)
|| mf_write(mfp, hp) != FAIL))
{
mf_rem_used(mfp, hp);
mf_rem_hash(mfp, hp);
mf_free_bhdr(hp);
hp = mfp->mf_used_last; /* re-start, list was changed */
retval = TRUE;
}
else
hp = hp->bh_prev;
}
}
return retval;
}
/*
* Allocate a block header and a block of memory for it
*/
static BHDR *
mf_alloc_bhdr(mfp, page_count)
MEMFILE *mfp;
int page_count;
{
BHDR *hp;
if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
{
if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
== NULL)
{
vim_free(hp); /* not enough memory */
return NULL;
}
hp->bh_page_count = page_count;
}
return hp;
}
/*
* Free a block header and the block of memory for it
*/
static void
mf_free_bhdr(hp)
BHDR *hp;
{
vim_free(hp->bh_data);
vim_free(hp);
}
/*
* insert entry *hp in the free list
*/
static void
mf_ins_free(mfp, hp)
MEMFILE *mfp;
BHDR *hp;
{
hp->bh_next = mfp->mf_free_first;
mfp->mf_free_first = hp;
}
/*
* remove the first entry from the free list and return a pointer to it
* Note: caller must check that mfp->mf_free_first is not NULL!
*/
static BHDR *
mf_rem_free(mfp)
MEMFILE *mfp;
{
BHDR *hp;
hp = mfp->mf_free_first;
mfp->mf_free_first = hp->bh_next;
return hp;
}
/*
* read a block from disk
*
* Return FAIL for failure, OK otherwise
*/
static int
mf_read(mfp, hp)
MEMFILE *mfp;
BHDR *hp;
{
off_t offset;
unsigned page_size;
unsigned size;
if (mfp->mf_fd < 0) /* there is no file, can't read */
return FAIL;
page_size = mfp->mf_page_size;
offset = page_size * hp->bh_bnum;
size = page_size * hp->bh_page_count;
if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
{
EMSG("Seek error in swap file read");
return FAIL;
}
if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
{
EMSG("Read error in swap file");
return FAIL;
}
return OK;
}
/*
* write a block to disk
*
* Return FAIL for failure, OK otherwise
*/
static int
mf_write(mfp, hp)
MEMFILE *mfp;
BHDR *hp;
{
off_t offset; /* offset in the file */
blocknr_t nr; /* block nr which is being written */
BHDR *hp2;
unsigned page_size; /* number of bytes in a page */
unsigned page_count; /* number of pages written */
unsigned size; /* number of bytes written */
if (mfp->mf_fd < 0) /* there is no file, can't write */
return FAIL;
if (hp->bh_bnum < 0) /* must assign file block number */
if (mf_trans_add(mfp, hp) == FAIL)
return FAIL;
page_size = mfp->mf_page_size;
/*
* We don't want gaps in the file. Write the blocks in front of *hp
* to extend the file.
* If block 'mf_infile_count' is not in the hash list, it has been
* freed. Fill the space in the file with data from the current block.
*/
for (;;)
{
nr = hp->bh_bnum;
if (nr > mfp->mf_infile_count) /* beyond end of file */
{
nr = mfp->mf_infile_count;
hp2 = mf_find_hash(mfp, nr); /* NULL catched below */
}
else
hp2 = hp;
offset = page_size * nr;
if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
{
EMSG("Seek error in swap file write");
return FAIL;
}
if (hp2 == NULL) /* freed block, fill with dummy data */
page_count = 1;
else
page_count = hp2->bh_page_count;
size = page_size * page_count;
if ((unsigned)write(mfp->mf_fd,
(char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
{
/*
* Avoid repeating the error message, this mostly happens when the
* disk is full. We give the message again only after a succesful
* write or when hitting a key. We keep on trying, in case some
* space becomes available.
*/
if (!did_swapwrite_msg)
EMSG("Write error in swap file");
did_swapwrite_msg = TRUE;
return FAIL;
}
did_swapwrite_msg = FALSE;
if (hp2 != NULL) /* written a non-dummy block */
hp2->bh_flags &= ~BH_DIRTY;
/* appended to the file */
if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
mfp->mf_infile_count = nr + page_count;
if (nr == hp->bh_bnum) /* written the desired block */
break;
}
return OK;
}
/*
* Make block number for *hp positive and add it to the translation list
*
* Return FAIL for failure, OK otherwise
*/
static int
mf_trans_add(mfp, hp)
MEMFILE *mfp;
BHDR *hp;
{
BHDR *freep;
blocknr_t new_bnum;
int hash;
NR_TRANS *np;
int page_count;
if (hp->bh_bnum >= 0) /* it's already positive */
return OK;
if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
return FAIL;
/*
* get a new number for the block.
* If the first item in the free list has sufficient pages, use its number
* Otherwise use mf_blocknr_max.
*/
freep = mfp->mf_free_first;
page_count = hp->bh_page_count;
if (freep != NULL && freep->bh_page_count >= page_count)
{
new_bnum = freep->bh_bnum;
/*
* If the page count of the free block was larger, recude it.
* If the page count matches, remove the block from the free list
*/
if (freep->bh_page_count > page_count)
{
freep->bh_bnum += page_count;
freep->bh_page_count -= page_count;
}
else
{
freep = mf_rem_free(mfp);
vim_free(freep);
}
}
else
{
new_bnum = mfp->mf_blocknr_max;
mfp->mf_blocknr_max += page_count;
}
np->nt_old_bnum = hp->bh_bnum; /* adjust number */
np->nt_new_bnum = new_bnum;
mf_rem_hash(mfp, hp); /* remove from old hash list */
hp->bh_bnum = new_bnum;
mf_ins_hash(mfp, hp); /* insert in new hash list */
hash = MEMHASH(np->nt_old_bnum); /* insert in trans list */
np->nt_next = mfp->mf_trans[hash];
mfp->mf_trans[hash] = np;
if (np->nt_next != NULL)
np->nt_next->nt_prev = np;
np->nt_prev = NULL;
return OK;
}
/*
* Lookup a tranlation from the trans lists and delete the entry
*
* Return the positive new number when found, the old number when not found
*/
blocknr_t
mf_trans_del(mfp, old_nr)
MEMFILE *mfp;
blocknr_t old_nr;
{
int hash;
NR_TRANS *np;
blocknr_t new_bnum;
hash = MEMHASH(old_nr);
for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
if (np->nt_old_bnum == old_nr)
break;
if (np == NULL) /* not found */
return old_nr;
mfp->mf_neg_count--;
new_bnum = np->nt_new_bnum;
if (np->nt_prev != NULL) /* remove entry from the trans list */
np->nt_prev->nt_next = np->nt_next;
else
mfp->mf_trans[hash] = np->nt_next;
if (np->nt_next != NULL)
np->nt_next->nt_prev = np->nt_prev;
vim_free(np);
return new_bnum;
}
/*
* Set mfp->mf_ffname according to mfp->mf_fname and some other things.
* Only called when creating or renaming the swapfile. Either way it's a new
* name so we must work out the full path name.
*/
void
mf_set_ffname(mfp)
MEMFILE *mfp;
{
mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE);
}
/*
* Make the name of the file used for the memfile a full path.
* Used before doing a :cd
*/
void
mf_fullname(mfp)
MEMFILE *mfp;
{
if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL)
{
vim_free(mfp->mf_fname);
mfp->mf_fname = mfp->mf_ffname;
mfp->mf_ffname = NULL;
}
}
/*
* return TRUE if there are any translations pending for 'mfp'
*/
int
mf_need_trans(mfp)
MEMFILE *mfp;
{
return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
}
/*
* Open a swap file for a memfile.
* The "fname" must be in allocated memory, and is consumed (also when an
* error occurs).
*/
static void
mf_do_open(mfp, fname, trunc_file)
MEMFILE *mfp;
char_u *fname;
int trunc_file;
{
mfp->mf_fname = fname;
/*
* Get the full path name before the open, because this is
* not possible after the open on the Amiga.
* fname cannot be NameBuff, because it must have been allocated.
*/
mf_set_ffname(mfp);
#if defined(MSDOS) || defined(WIN32) || defined(RISCOS)
/*
* A ":!cd e:xxx" may change the directory without us knowning, use the
* full pathname always. Careful: This frees fname!
*/
mf_fullname(mfp);
#endif
/*
* try to open the file
*/
mfp->mf_fd = open((char *)mfp->mf_fname,
(trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
#if defined(UNIX) || defined(RISCOS) /* open in rw------- mode */
, (mode_t)0600
#endif
#if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
, S_IREAD | S_IWRITE /* open read/write */
#endif
#ifdef VMS /* open in rw------- mode */
, 0600
#endif
);
/*
* If the file cannot be opened, use memory only
*/
if (mfp->mf_fd < 0)
{
vim_free(mfp->mf_fname);
vim_free(mfp->mf_ffname);
mfp->mf_fname = NULL;
mfp->mf_ffname = NULL;
}
else
mch_hide(mfp->mf_fname); /* try setting the 'hidden' flag */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -