[BACK]Return to memfile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/memfile.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved       by Bram Moolenaar
                      5:  *
                      6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      7:  * Do ":help credits" in Vim to see a list of people who contributed.
                      8:  */
                      9:
                     10: /* for debugging */
                     11: #define CHECK(c, s)    if (c) printf(s)
                     12:
                     13: /*
                     14:  * memfile.c: Contains the functions for handling blocks of memory which can
                     15:  * be stored in a file. This is the implementation of a sort of virtual memory.
                     16:  *
                     17:  * A memfile consists of a sequence of blocks. The blocks numbered from 0
                     18:  * upwards have been assigned a place in the actual file. The block number
                     19:  * is equal to the page number in the file. The
                     20:  * blocks with negative numbers are currently in memory only. They can be
                     21:  * assigned a place in the file when too much memory is being used. At that
                     22:  * moment they get a new, positive, number. A list is used for translation of
                     23:  * negative to positive numbers.
                     24:  *
                     25:  * The size of a block is a multiple of a page size, normally the page size of
                     26:  * the device the file is on. Most blocks are 1 page long. A Block of multiple
                     27:  * pages is used for a line that does not fit in a single page.
                     28:  *
                     29:  * Each block can be in memory and/or in a file. The block stays in memory
                     30:  * as long as it is locked. If it is no longer locked it can be swapped out to
                     31:  * the file. It is only written to the file if it has been changed.
                     32:  *
                     33:  * Under normal operation the file is created when opening the memory file and
                     34:  * deleted when closing the memory file. Only with recovery an existing memory
                     35:  * file is opened.
                     36:  */
                     37:
                     38: #if defined MSDOS  ||  defined WIN32
                     39: # include <io.h>       /* for lseek(), must be before vim.h */
                     40: #endif
                     41:
                     42: #include "vim.h"
                     43: #include "globals.h"
                     44: #include "proto.h"
                     45: #include "option.h"
                     46: #ifdef HAVE_FCNTL_H
                     47: # include <fcntl.h>
                     48: #endif
                     49:
                     50: /*
                     51:  * Some systems have the page size in statfs, some in stat
                     52:  */
                     53: #ifdef HAVE_SYS_STATFS_H
                     54: # include <sys/statfs.h>
                     55: # define STATFS statfs
                     56: # define F_BSIZE f_bsize
                     57: # ifdef MINT
                     58: #  define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
                     59: # endif
                     60: #else
                     61: # define STATFS stat
                     62: # define F_BSIZE st_blksize
                     63: # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
                     64: #endif
                     65:
                     66: /*
                     67:  * for Amiga Dos 2.0x we use Flush
                     68:  */
                     69: #ifdef AMIGA
                     70: # ifndef NO_ARP
                     71: extern int dos2;                       /* this is in amiga.c */
                     72: # endif
                     73: # ifdef SASC
                     74: #  include <proto/dos.h>
                     75: #  include <ios1.h>                        /* for chkufb() */
                     76: # endif
                     77: #endif
                     78:
                     79: #define MEMFILE_PAGE_SIZE 4096         /* default page size */
                     80:
                     81: static long total_mem_used = 0;            /* total memory used for memfiles */
                     82:
                     83: static void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
                     84: static void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
                     85: static BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
                     86: static void mf_ins_used __ARGS((MEMFILE *, BHDR *));
                     87: static void mf_rem_used __ARGS((MEMFILE *, BHDR *));
                     88: static BHDR *mf_release __ARGS((MEMFILE *, int));
                     89: static BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
                     90: static void mf_free_bhdr __ARGS((BHDR *));
                     91: static void mf_ins_free __ARGS((MEMFILE *, BHDR *));
                     92: static BHDR *mf_rem_free __ARGS((MEMFILE *));
                     93: static int mf_read __ARGS((MEMFILE *, BHDR *));
                     94: static int mf_write __ARGS((MEMFILE *, BHDR *));
                     95: static int mf_trans_add __ARGS((MEMFILE *, BHDR *));
                     96: static void mf_do_open __ARGS((MEMFILE *, char_u *, int));
                     97:
                     98: /*
                     99:  * The functions for using a memfile:
                    100:  *
                    101:  * mf_open()       open a new or existing memfile
                    102:  * mf_open_file()  open a swap file for an existing memfile
                    103:  * mf_close()      close (and delete) a memfile
                    104:  * mf_new()            create a new block in a memfile and lock it
                    105:  * mf_get()            get an existing block and lock it
                    106:  * mf_put()            unlock a block, may be marked for writing
                    107:  * mf_free()       remove a block
                    108:  * mf_sync()       sync changed parts of memfile to disk
                    109:  * mf_release_all()    release as much memory as possible
                    110:  * mf_trans_del()  may translate negative to positive block number
                    111:  * mf_fullname()   make file name full path (use before first :cd)
                    112:  */
                    113:
                    114: /*
                    115:  * mf_open: open an existing or new memory block file
                    116:  *
                    117:  * fname:      name of file to use (NULL means no file at all)
                    118:  *             Note: fname must have been allocated, it is not copied!
                    119:  *                     If opening the file fails, fname is NOT freed.
                    120:  *  trunc_file:        if TRUE: file should be truncated when opening
                    121:  *
                    122:  *  If fname != NULL and file cannot be opened, fail.
                    123:  *
                    124:  * return value: identifier for this memory block file.
                    125:  */
                    126:    MEMFILE *
                    127: mf_open(fname, trunc_file)
                    128:    char_u  *fname;
                    129:    int     trunc_file;
                    130: {
                    131:    MEMFILE         *mfp;
                    132:    int             i;
                    133:    long            size;
                    134: #ifdef UNIX
                    135:    struct STATFS   stf;
                    136: #endif
                    137:
                    138:    if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
                    139:        return NULL;
                    140:
                    141:    if (fname == NULL)      /* no file for this memfile, use memory only */
                    142:    {
                    143:        mfp->mf_fname = NULL;
                    144:        mfp->mf_xfname = NULL;
                    145:        mfp->mf_fd = -1;
                    146:    }
                    147:    else
                    148:    {
                    149:        mf_do_open(mfp, fname, trunc_file);     /* try to open the file */
                    150:
                    151:        /* if the file cannot be opened, return here */
                    152:        if (mfp->mf_fd < 0)
                    153:        {
                    154:            vim_free(mfp);
                    155:            return NULL;
                    156:        }
                    157:    }
                    158:
                    159:    mfp->mf_free_first = NULL;          /* free list is empty */
                    160:    mfp->mf_used_first = NULL;          /* used list is empty */
                    161:    mfp->mf_used_last = NULL;
                    162:    mfp->mf_dirty = FALSE;
                    163:    mfp->mf_used_count = 0;
                    164:    for (i = 0; i < MEMHASHSIZE; ++i)
                    165:    {
                    166:        mfp->mf_hash[i] = NULL;         /* hash lists are empty */
                    167:        mfp->mf_trans[i] = NULL;        /* trans lists are empty */
                    168:    }
                    169:    mfp->mf_page_size = MEMFILE_PAGE_SIZE;
                    170:
                    171: #ifdef UNIX
                    172:    /*
                    173:     * Try to set the page size equal to the block size of the device.
                    174:     * Speeds up I/O a lot.
                    175:     * NOTE: minimal block size depends on size of block 0 data! It's not done
                    176:     * with a sizeof(), because block 0 is defined in memline.c (Sorry).
                    177:     * The maximal block size is arbitrary.
                    178:     */
                    179:    if (mfp->mf_fd >= 0 &&
                    180:                    fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
                    181:                    stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
                    182:        mfp->mf_page_size = stf.F_BSIZE;
                    183: #endif
                    184:
                    185:    if (mfp->mf_fd < 0 || trunc_file ||
                    186:                                (size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
                    187:        mfp->mf_blocknr_max = 0;        /* no file or empty file */
                    188:    else
                    189:        mfp->mf_blocknr_max = size / mfp->mf_page_size;
                    190:    mfp->mf_blocknr_min = -1;
                    191:    mfp->mf_neg_count = 0;
                    192:    mfp->mf_infile_count = mfp->mf_blocknr_max;
                    193:    if (mfp->mf_fd < 0)
                    194:        mfp->mf_used_count_max = 0;         /* no limit */
                    195:    else
                    196:        mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
                    197:
                    198:    return mfp;
                    199: }
                    200:
                    201: /*
                    202:  * mf_open_file: open a file for an existing memfile. Used when updatecount
                    203:  *              set from 0 to some value.
                    204:  *
                    205:  * fname:      name of file to use (NULL means no file at all)
                    206:  *             Note: fname must have been allocated, it is not copied!
                    207:  *                     If opening the file fails, fname is NOT freed.
                    208:  *
                    209:  * return value: FAIL if file could not be opened, OK otherwise
                    210:  */
                    211:    int
                    212: mf_open_file(mfp, fname)
                    213:    MEMFILE     *mfp;
                    214:    char_u      *fname;
                    215: {
                    216:    mf_do_open(mfp, fname, TRUE);               /* try to open the file */
                    217:
                    218:    if (mfp->mf_fd < 0)
                    219:        return FAIL;
                    220:
                    221:    mfp->mf_dirty = TRUE;
                    222:    return OK;
                    223: }
                    224:
                    225: /*
                    226:  * close a memory file and delete the associated file if 'del_file' is TRUE
                    227:  */
                    228:    void
                    229: mf_close(mfp, del_file)
                    230:    MEMFILE *mfp;
                    231:    int     del_file;
                    232: {
                    233:    BHDR        *hp, *nextp;
                    234:    NR_TRANS    *tp, *tpnext;
                    235:    int         i;
                    236:
                    237:    if (mfp == NULL)                /* safety check */
                    238:        return;
                    239:    if (mfp->mf_fd >= 0)
                    240:    {
                    241:        if (close(mfp->mf_fd) < 0)
                    242:            EMSG("Close error on swap file");
                    243:    }
                    244:    if (del_file && mfp->mf_fname != NULL)
                    245:        vim_remove(mfp->mf_fname);
                    246:                                            /* free entries in used list */
                    247:    for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
                    248:    {
                    249:        total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
                    250:        nextp = hp->bh_next;
                    251:        mf_free_bhdr(hp);
                    252:    }
                    253:    while (mfp->mf_free_first != NULL)      /* free entries in free list */
                    254:        vim_free(mf_rem_free(mfp));
                    255:    for (i = 0; i < MEMHASHSIZE; ++i)       /* free entries in trans lists */
                    256:        for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
                    257:        {
                    258:            tpnext = tp->nt_next;
                    259:            vim_free(tp);
                    260:        }
                    261:    vim_free(mfp->mf_fname);
                    262:    vim_free(mfp->mf_xfname);
                    263:    vim_free(mfp);
                    264: }
                    265:
                    266: /*
                    267:  * get a new block
                    268:  *
                    269:  *   negative: TRUE if negative block number desired (data block)
                    270:  */
                    271:    BHDR *
                    272: mf_new(mfp, negative, page_count)
                    273:    MEMFILE     *mfp;
                    274:    int         negative;
                    275:    int         page_count;
                    276: {
                    277:    BHDR    *hp;            /* new BHDR */
                    278:    BHDR    *freep;         /* first block in free list */
                    279:    char_u  *p;
                    280:
                    281:    /*
                    282:     * If we reached the maximum size for the used memory blocks, release one
                    283:     * If a BHDR is returned, use it and adjust the page_count if necessary.
                    284:     */
                    285:    hp = mf_release(mfp, page_count);
                    286:
                    287: /*
                    288:  * Decide on the number to use:
                    289:  * If there is a free block, use its number.
                    290:  * Otherwise use mf_block_min for a negative number, mf_block_max for
                    291:  * a positive number.
                    292:  */
                    293:    freep = mfp->mf_free_first;
                    294:    if (!negative && freep != NULL && freep->bh_page_count >= page_count)
                    295:    {
                    296:        /*
                    297:         * If the block in the free list has more pages, take only the number
                    298:         * of pages needed and allocate a new BHDR with data
                    299:         *
                    300:         * If the number of pages matches and mf_release did not return a BHDR,
                    301:         * use the BHDR from the free list and allocate the data
                    302:         *
                    303:         * If the number of pages matches and mf_release returned a BHDR,
                    304:         * just use the number and free the BHDR from the free list
                    305:         */
                    306:        if (freep->bh_page_count > page_count)
                    307:        {
                    308:            if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
                    309:                return NULL;
                    310:            hp->bh_bnum = freep->bh_bnum;
                    311:            freep->bh_bnum += page_count;
                    312:            freep->bh_page_count -= page_count;
                    313:        }
                    314:        else if (hp == NULL)        /* need to allocate memory for this block */
                    315:        {
                    316:            if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
                    317:                return NULL;
                    318:            hp = mf_rem_free(mfp);
                    319:            hp->bh_data = p;
                    320:        }
                    321:        else                /* use the number, remove entry from free list */
                    322:        {
                    323:            freep = mf_rem_free(mfp);
                    324:            hp->bh_bnum = freep->bh_bnum;
                    325:            vim_free(freep);
                    326:        }
                    327:    }
                    328:    else        /* get a new number */
                    329:    {
                    330:        if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
                    331:            return NULL;
                    332:        if (negative)
                    333:        {
                    334:            hp->bh_bnum = mfp->mf_blocknr_min--;
                    335:            mfp->mf_neg_count++;
                    336:        }
                    337:        else
                    338:        {
                    339:            hp->bh_bnum = mfp->mf_blocknr_max;
                    340:            mfp->mf_blocknr_max += page_count;
                    341:        }
                    342:    }
                    343:    hp->bh_flags = BH_LOCKED | BH_DIRTY;        /* new block is always dirty */
                    344:    mfp->mf_dirty = TRUE;
                    345:    hp->bh_page_count = page_count;
                    346:    mf_ins_used(mfp, hp);
                    347:    mf_ins_hash(mfp, hp);
                    348:
                    349:    return hp;
                    350: }
                    351:
                    352: /*
                    353:  * get existing block 'nr' with 'page_count' pages
                    354:  *
                    355:  * Note: The caller should first check a negative nr with mf_trans_del()
                    356:  */
                    357:    BHDR *
                    358: mf_get(mfp, nr, page_count)
                    359:    MEMFILE     *mfp;
                    360:    blocknr_t   nr;
                    361:    int         page_count;
                    362: {
                    363:    BHDR    *hp;
                    364:                                                /* doesn't exist */
                    365:    if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
                    366:        return NULL;
                    367:
                    368:    /*
                    369:     * see if it is in the cache
                    370:     */
                    371:    hp = mf_find_hash(mfp, nr);
                    372:    if (hp == NULL)     /* not in the hash list */
                    373:    {
                    374:        if (nr < 0 || nr >= mfp->mf_infile_count)   /* can't be in the file */
                    375:            return NULL;
                    376:
                    377:        /* could check here if the block is in the free list */
                    378:
                    379:        /*
                    380:         * Check if we need to flush an existing block.
                    381:         * If so, use that block.
                    382:         * If not, allocate a new block.
                    383:         */
                    384:        hp = mf_release(mfp, page_count);
                    385:        if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
                    386:            return NULL;
                    387:
                    388:        hp->bh_bnum = nr;
                    389:        hp->bh_flags = 0;
                    390:        hp->bh_page_count = page_count;
                    391:        if (mf_read(mfp, hp) == FAIL)       /* cannot read the block! */
                    392:        {
                    393:            mf_free_bhdr(hp);
                    394:            return NULL;
                    395:        }
                    396:    }
                    397:    else
                    398:    {
                    399:        mf_rem_used(mfp, hp);   /* remove from list, insert in front below */
                    400:        mf_rem_hash(mfp, hp);
                    401:    }
                    402:
                    403:    hp->bh_flags |= BH_LOCKED;
                    404:    mf_ins_used(mfp, hp);       /* put in front of used list */
                    405:    mf_ins_hash(mfp, hp);       /* put in front of hash list */
                    406:
                    407:    return hp;
                    408: }
                    409:
                    410: /*
                    411:  * release the block *hp
                    412:  *
                    413:  *   dirty: Block must be written to file later
                    414:  *  infile: Block should be in file (needed for recovery)
                    415:  *
                    416:  *  no return value, function cannot fail
                    417:  */
                    418:    void
                    419: mf_put(mfp, hp, dirty, infile)
                    420:    MEMFILE *mfp;
                    421:    BHDR    *hp;
                    422:    int     dirty;
                    423:    int     infile;
                    424: {
                    425:    int     flags;
                    426:
                    427:    flags = hp->bh_flags;
                    428:    CHECK((flags & BH_LOCKED) == 0, "block was not locked");
                    429:    flags &= ~BH_LOCKED;
                    430:    if (dirty)
                    431:    {
                    432:        flags |= BH_DIRTY;
                    433:        mfp->mf_dirty = TRUE;
                    434:    }
                    435:    hp->bh_flags = flags;
                    436:    if (infile)
                    437:        mf_trans_add(mfp, hp);      /* may translate negative in positive nr */
                    438: }
                    439:
                    440: /*
                    441:  * block *hp is no longer in used, may put it in the free list of memfile *mfp
                    442:  */
                    443:    void
                    444: mf_free(mfp, hp)
                    445:    MEMFILE *mfp;
                    446:    BHDR    *hp;
                    447: {
                    448:    vim_free(hp->bh_data);      /* free the memory */
                    449:    mf_rem_hash(mfp, hp);       /* get *hp out of the hash list */
                    450:    mf_rem_used(mfp, hp);       /* get *hp out of the used list */
                    451:    if (hp->bh_bnum < 0)
                    452:    {
                    453:        vim_free(hp);           /* don't want negative numbers in free list */
                    454:        mfp->mf_neg_count--;
                    455:    }
                    456:    else
                    457:        mf_ins_free(mfp, hp);   /* put *hp in the free list */
                    458: }
                    459:
                    460: /*
                    461:  * sync the memory file *mfp to disk
                    462:  * if 'all' is FALSE blocks with negative numbers are not synced, even when
                    463:  *  they are dirty!
                    464:  *  if 'check_char' is TRUE, stop syncing when a character becomes available,
                    465:  *  but sync at least one block.
                    466:  *  if 'do_fsync' is TRUE make sure buffers are flushed to disk, so they will
                    467:  *  survive a system crash.
                    468:  *
                    469:  * Return FAIL for failure, OK otherwise
                    470:  */
                    471:    int
                    472: mf_sync(mfp, all, check_char, do_fsync)
                    473:    MEMFILE *mfp;
                    474:    int     all;
                    475:    int     check_char;
                    476:    int     do_fsync;
                    477: {
                    478:    int     status;
                    479:    BHDR    *hp;
                    480: #ifdef SYNC_DUP_CLOSE
                    481:    int     fd;
                    482: #endif
                    483:
                    484:    if (mfp->mf_fd < 0)     /* there is no file, nothing to do */
                    485:    {
                    486:        mfp->mf_dirty = FALSE;
                    487:        return FAIL;
                    488:    }
                    489:
                    490:    /*
                    491:     * sync from last to first (may reduce the probability of an inconsistent
                    492:     * file) If a write fails, it is very likely caused by a full filesystem.
                    493:     * Then we only try to write blocks within the existing file. If that also
                    494:     * fails then we give up.
                    495:     */
                    496:    status = OK;
                    497:    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
                    498:        if ((all || hp->bh_bnum >= 0) && (hp->bh_flags & BH_DIRTY) &&
                    499:                    (status == OK || (hp->bh_bnum >= 0 &&
                    500:                        hp->bh_bnum < mfp->mf_infile_count)))
                    501:        {
                    502:            if (mf_write(mfp, hp) == FAIL)
                    503:            {
                    504:                if (status == FAIL)     /* double error: quit syncing */
                    505:                    break;
                    506:                status = FAIL;
                    507:            }
                    508:            if (check_char && mch_char_avail()) /* char available now */
                    509:                break;
                    510:        }
                    511:
                    512:    /*
                    513:     * If the whole list is flushed, the memfile is not dirty anymore.
                    514:     * In case of an error this flag is also set, to avoid trying all the time.
                    515:     */
                    516:    if (hp == NULL || status == FAIL)
                    517:        mfp->mf_dirty = FALSE;
                    518:
                    519:    if (do_fsync && *p_sws != NUL)
                    520:    {
                    521: #if defined(UNIX)
                    522: # ifdef HAVE_FSYNC
                    523:        /*
                    524:         * most Unixes have the very useful fsync() function, just what we need.
                    525:         * However, with OS/2 and EMX it is also available, but there are
                    526:         * reports of bad problems with it (a bug in HPFS.IFS).
                    527:         * So we disable use of it here in case someone tries to be smart
                    528:         * and changes conf_os2.h... (even though there is no __EMX__ test
                    529:         * in the #if, as __EMX__ does not have sync(); we hope for a timely
                    530:         * sync from the system itself).
                    531:         */
                    532: #  if defined(__EMX__)
                    533:    error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
                    534: #  endif
                    535:        if (STRCMP(p_sws, "fsync") == 0)
                    536:        {
                    537:            if (fsync(mfp->mf_fd))
                    538:                status = FAIL;
                    539:        }
                    540:        else
                    541: # endif
                    542:             sync();
                    543: #endif
                    544: #ifdef DJGPP
                    545:        if (_dos_commit(mfp->mf_fd))
                    546:            status = FAIL;
                    547: #else
                    548: # ifdef SYNC_DUP_CLOSE
                    549:        /*
                    550:         * MSdos is a bit more work: Duplicate the file handle and close it.
                    551:         * This should flush the file to disk.
                    552:         */
                    553:        if ((fd = dup(mfp->mf_fd)) >= 0)
                    554:            close(fd);
                    555: # endif
                    556: #endif
                    557: #ifdef AMIGA
                    558:        /*
                    559:         * Flush() only exists for AmigaDos 2.0.
                    560:         * For 1.3 it should be done with close() + open(), but then the risk
                    561:         * is that the open() may fail and lose the file....
                    562:         */
                    563: # ifndef NO_ARP
                    564:        if (dos2)
                    565: # endif
                    566: # ifdef SASC
                    567:        {
                    568:            struct UFB *fp = chkufb(mfp->mf_fd);
                    569:
                    570:            if (fp != NULL)
                    571:                Flush(fp->ufbfh);
                    572:        }
                    573: # else
                    574: #  ifdef _DCC
                    575:        {
                    576:            BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
                    577:
                    578:            if (fh != 0)
                    579:                Flush(fh);
                    580:            }
                    581: #  else /* assume Manx */
                    582:            Flush(_devtab[mfp->mf_fd].fd);
                    583: #  endif
                    584: # endif
                    585: #endif /* AMIGA */
                    586:    }
                    587:
                    588:    return status;
                    589: }
                    590:
                    591: /*
                    592:  * insert block *hp in front of hashlist of memfile *mfp
                    593:  */
                    594:    static void
                    595: mf_ins_hash(mfp, hp)
                    596:    MEMFILE *mfp;
                    597:    BHDR    *hp;
                    598: {
                    599:    BHDR    *hhp;
                    600:    int     hash;
                    601:
                    602:    hash = MEMHASH(hp->bh_bnum);
                    603:    hhp = mfp->mf_hash[hash];
                    604:    hp->bh_hash_next = hhp;
                    605:    hp->bh_hash_prev = NULL;
                    606:    if (hhp != NULL)
                    607:        hhp->bh_hash_prev = hp;
                    608:    mfp->mf_hash[hash] = hp;
                    609: }
                    610:
                    611: /*
                    612:  * remove block *hp from hashlist of memfile list *mfp
                    613:  */
                    614:    static void
                    615: mf_rem_hash(mfp, hp)
                    616:    MEMFILE *mfp;
                    617:    BHDR    *hp;
                    618: {
                    619:    if (hp->bh_hash_prev == NULL)
                    620:        mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
                    621:    else
                    622:        hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
                    623:
                    624:    if (hp->bh_hash_next)
                    625:        hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
                    626: }
                    627:
                    628: /*
                    629:  * look in hash lists of memfile *mfp for block header with number 'nr'
                    630:  */
                    631:    static BHDR *
                    632: mf_find_hash(mfp, nr)
                    633:    MEMFILE     *mfp;
                    634:    blocknr_t   nr;
                    635: {
                    636:    BHDR        *hp;
                    637:
                    638:    for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
                    639:        if (hp->bh_bnum == nr)
                    640:            break;
                    641:    return hp;
                    642: }
                    643:
                    644: /*
                    645:  * insert block *hp in front of used list of memfile *mfp
                    646:  */
                    647:    static void
                    648: mf_ins_used(mfp, hp)
                    649:    MEMFILE *mfp;
                    650:    BHDR    *hp;
                    651: {
                    652:    hp->bh_next = mfp->mf_used_first;
                    653:    mfp->mf_used_first = hp;
                    654:    hp->bh_prev = NULL;
                    655:    if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
                    656:        mfp->mf_used_last = hp;
                    657:    else
                    658:        hp->bh_next->bh_prev = hp;
                    659:    mfp->mf_used_count += hp->bh_page_count;
                    660:    total_mem_used += hp->bh_page_count * mfp->mf_page_size;
                    661: }
                    662:
                    663: /*
                    664:  * remove block *hp from used list of memfile *mfp
                    665:  */
                    666:    static void
                    667: mf_rem_used(mfp, hp)
                    668:    MEMFILE *mfp;
                    669:    BHDR    *hp;
                    670: {
                    671:    if (hp->bh_next == NULL)        /* last block in used list */
                    672:        mfp->mf_used_last = hp->bh_prev;
                    673:    else
                    674:        hp->bh_next->bh_prev = hp->bh_prev;
                    675:    if (hp->bh_prev == NULL)        /* first block in used list */
                    676:        mfp->mf_used_first = hp->bh_next;
                    677:    else
                    678:        hp->bh_prev->bh_next = hp->bh_next;
                    679:    mfp->mf_used_count -= hp->bh_page_count;
                    680:    total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
                    681: }
                    682:
                    683: /*
                    684:  * Release the least recently used block from the used list if the number
                    685:  * of used memory blocks gets to big.
                    686:  *
                    687:  * Return the block header to the caller, including the memory block, so
                    688:  * it can be re-used. Make sure the page_count is right.
                    689:  */
                    690:    static BHDR *
                    691: mf_release(mfp, page_count)
                    692:    MEMFILE     *mfp;
                    693:    int         page_count;
                    694: {
                    695:    BHDR        *hp;
                    696:
                    697:        /*
                    698:         * don't release a block if
                    699:         *      there is no file for this memfile
                    700:         * or
                    701:         *      there is no limit to the number of blocks for this memfile or
                    702:         *      the maximum is not reached yet
                    703:         *    and
                    704:         *      total memory used is not up to 'maxmemtot'
                    705:         */
                    706:    if (mfp->mf_fd < 0 || ((mfp->mf_used_count < mfp->mf_used_count_max ||
                    707:                        mfp->mf_used_count_max == 0) &&
                    708:                        (total_mem_used >> 10) < p_mmt))
                    709:        return NULL;
                    710:
                    711:    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
                    712:        if (!(hp->bh_flags & BH_LOCKED))
                    713:            break;
                    714:    if (hp == NULL)     /* not a single one that can be released */
                    715:        return NULL;
                    716:
                    717:        /*
                    718:         * If the block is dirty, write it.
                    719:         * If the write fails we don't free it.
                    720:         */
                    721:    if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
                    722:        return NULL;
                    723:
                    724:    mf_rem_used(mfp, hp);
                    725:    mf_rem_hash(mfp, hp);
                    726:
                    727: /*
                    728:  * If a BHDR is returned, make sure that the page_count of bh_data is right
                    729:  */
                    730:    if (hp->bh_page_count != page_count)
                    731:    {
                    732:        vim_free(hp->bh_data);
                    733:        if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
                    734:        {
                    735:            vim_free(hp);
                    736:            return NULL;
                    737:        }
                    738:        hp->bh_page_count = page_count;
                    739:    }
                    740:    return hp;
                    741: }
                    742:
                    743: /*
                    744:  * release as many blocks as possible
                    745:  * Used in case of out of memory
                    746:  *
                    747:  * return TRUE if any memory was released
                    748:  */
                    749:    int
                    750: mf_release_all()
                    751: {
                    752:    BUF         *buf;
                    753:    MEMFILE     *mfp;
                    754:    BHDR        *hp;
                    755:    int         retval = FALSE;
                    756:
                    757:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    758:    {
                    759:        mfp = buf->b_ml.ml_mfp;
                    760:        if (mfp != NULL && mfp->mf_fd >= 0)     /* only if there is a memfile with a file */
                    761:            for (hp = mfp->mf_used_last; hp != NULL; )
                    762:            {
                    763:                if (!(hp->bh_flags & BH_LOCKED) &&
                    764:                        (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL))
                    765:                {
                    766:                    mf_rem_used(mfp, hp);
                    767:                    mf_rem_hash(mfp, hp);
                    768:                    mf_free_bhdr(hp);
                    769:                    hp = mfp->mf_used_last;     /* re-start, list was changed */
                    770:                    retval = TRUE;
                    771:                }
                    772:                else
                    773:                    hp = hp->bh_prev;
                    774:            }
                    775:    }
                    776:    return retval;
                    777: }
                    778:
                    779: /*
                    780:  * Allocate a block header and a block of memory for it
                    781:  */
                    782:    static BHDR *
                    783: mf_alloc_bhdr(mfp, page_count)
                    784:    MEMFILE     *mfp;
                    785:    int         page_count;
                    786: {
                    787:    BHDR    *hp;
                    788:
                    789:    if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
                    790:    {
                    791:        if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
                    792:                                                                      == NULL)
                    793:        {
                    794:            vim_free(hp);           /* not enough memory */
                    795:            return NULL;
                    796:        }
                    797:        hp->bh_page_count = page_count;
                    798:    }
                    799:    return hp;
                    800: }
                    801:
                    802: /*
                    803:  * Free a block header and the block of memory for it
                    804:  */
                    805:    static void
                    806: mf_free_bhdr(hp)
                    807:    BHDR        *hp;
                    808: {
                    809:    vim_free(hp->bh_data);
                    810:    vim_free(hp);
                    811: }
                    812:
                    813: /*
                    814:  * insert entry *hp in the free list
                    815:  */
                    816:    static void
                    817: mf_ins_free(mfp, hp)
                    818:    MEMFILE *mfp;
                    819:    BHDR    *hp;
                    820: {
                    821:    hp->bh_next = mfp->mf_free_first;
                    822:    mfp->mf_free_first = hp;
                    823: }
                    824:
                    825: /*
                    826:  * remove the first entry from the free list and return a pointer to it
                    827:  * Note: caller must check that mfp->mf_free_first is not NULL!
                    828:  */
                    829:    static BHDR *
                    830: mf_rem_free(mfp)
                    831:    MEMFILE *mfp;
                    832: {
                    833:    BHDR    *hp;
                    834:
                    835:    hp = mfp->mf_free_first;
                    836:    mfp->mf_free_first = hp->bh_next;
                    837:    return hp;
                    838: }
                    839:
                    840: /*
                    841:  * read a block from disk
                    842:  *
                    843:  * Return FAIL for failure, OK otherwise
                    844:  */
                    845:    static int
                    846: mf_read(mfp, hp)
                    847:    MEMFILE     *mfp;
                    848:    BHDR        *hp;
                    849: {
                    850:    long_u      offset;
                    851:    unsigned    page_size;
                    852:    unsigned    size;
                    853:
                    854:    if (mfp->mf_fd < 0)     /* there is no file, can't read */
                    855:        return FAIL;
                    856:
                    857:    page_size = mfp->mf_page_size;
                    858:    offset = page_size * hp->bh_bnum;
                    859:    size = page_size * hp->bh_page_count;
                    860:    if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
                    861:    {
                    862:        EMSG("Seek error in swap file read");
                    863:        return FAIL;
                    864:    }
                    865:    if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
                    866:    {
                    867:        EMSG("Read error in swap file");
                    868:        return FAIL;
                    869:    }
                    870:    return OK;
                    871: }
                    872:
                    873: /*
                    874:  * write a block to disk
                    875:  *
                    876:  * Return FAIL for failure, OK otherwise
                    877:  */
                    878:    static int
                    879: mf_write(mfp, hp)
                    880:    MEMFILE     *mfp;
                    881:    BHDR        *hp;
                    882: {
                    883:    long_u      offset;     /* offset in the file */
                    884:    blocknr_t   nr;         /* block nr which is being written */
                    885:    BHDR        *hp2;
                    886:    unsigned    page_size;  /* number of bytes in a page */
                    887:    unsigned    page_count; /* number of pages written */
                    888:    unsigned    size;       /* number of bytes written */
                    889:
                    890:    if (mfp->mf_fd < 0)     /* there is no file, can't write */
                    891:        return FAIL;
                    892:
                    893:    if (hp->bh_bnum < 0)        /* must assign file block number */
                    894:        if (mf_trans_add(mfp, hp) == FAIL)
                    895:            return FAIL;
                    896:
                    897:    page_size = mfp->mf_page_size;
                    898:
                    899:    /*
                    900:     * We don't want gaps in the file. Write the blocks in front of *hp
                    901:     * to extend the file.
                    902:     * If block 'mf_infile_count' is not in the hash list, it has been
                    903:     * freed. Fill the space in the file with data from the current block.
                    904:     */
                    905:    for (;;)
                    906:    {
                    907:        nr = hp->bh_bnum;
                    908:        if (nr > mfp->mf_infile_count)          /* beyond end of file */
                    909:        {
                    910:            nr = mfp->mf_infile_count;
                    911:            hp2 = mf_find_hash(mfp, nr);        /* NULL catched below */
                    912:        }
                    913:        else
                    914:            hp2 = hp;
                    915:
                    916:        offset = page_size * nr;
                    917:        if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
                    918:        {
                    919:            EMSG("Seek error in swap file write");
                    920:            return FAIL;
                    921:        }
                    922:        if (hp2 == NULL)            /* freed block, fill with dummy data */
                    923:            page_count = 1;
                    924:        else
                    925:            page_count = hp2->bh_page_count;
                    926:        size = page_size * page_count;
                    927:        if ((unsigned)write(mfp->mf_fd,
                    928:             (char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
                    929:        {
                    930:            /*
                    931:             * Avoid repeating the error message, this mostly happens when the
                    932:             * disk is full. We give the message again only after a succesful
                    933:             * write or when hitting a key. We keep on trying, in case some
                    934:             * space becomes available.
                    935:             */
                    936:            if (!did_swapwrite_msg)
                    937:                EMSG("Write error in swap file");
                    938:            did_swapwrite_msg = TRUE;
                    939:            return FAIL;
                    940:        }
                    941:        did_swapwrite_msg = FALSE;
                    942:        if (hp2 != NULL)                    /* written a non-dummy block */
                    943:            hp2->bh_flags &= ~BH_DIRTY;
                    944:                                            /* appended to the file */
                    945:        if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
                    946:            mfp->mf_infile_count = nr + page_count;
                    947:        if (nr == hp->bh_bnum)              /* written the desired block */
                    948:            break;
                    949:    }
                    950:    return OK;
                    951: }
                    952:
                    953: /*
                    954:  * Make block number for *hp positive and add it to the translation list
                    955:  *
                    956:  * Return FAIL for failure, OK otherwise
                    957:  */
                    958:    static int
                    959: mf_trans_add(mfp, hp)
                    960:    MEMFILE *mfp;
                    961:    BHDR    *hp;
                    962: {
                    963:    BHDR        *freep;
                    964:    blocknr_t   new_bnum;
                    965:    int         hash;
                    966:    NR_TRANS    *np;
                    967:    int         page_count;
                    968:
                    969:    if (hp->bh_bnum >= 0)                   /* it's already positive */
                    970:        return OK;
                    971:
                    972:    if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
                    973:        return FAIL;
                    974:
                    975: /*
                    976:  * get a new number for the block.
                    977:  * If the first item in the free list has sufficient pages, use its number
                    978:  * Otherwise use mf_blocknr_max.
                    979:  */
                    980:    freep = mfp->mf_free_first;
                    981:    page_count = hp->bh_page_count;
                    982:    if (freep != NULL && freep->bh_page_count >= page_count)
                    983:    {
                    984:        new_bnum = freep->bh_bnum;
                    985:        /*
                    986:         * If the page count of the free block was larger, recude it.
                    987:         * If the page count matches, remove the block from the free list
                    988:         */
                    989:        if (freep->bh_page_count > page_count)
                    990:        {
                    991:            freep->bh_bnum += page_count;
                    992:            freep->bh_page_count -= page_count;
                    993:        }
                    994:        else
                    995:        {
                    996:            freep = mf_rem_free(mfp);
                    997:            vim_free(freep);
                    998:        }
                    999:    }
                   1000:    else
                   1001:    {
                   1002:        new_bnum = mfp->mf_blocknr_max;
                   1003:        mfp->mf_blocknr_max += page_count;
                   1004:    }
                   1005:
                   1006:    np->nt_old_bnum = hp->bh_bnum;          /* adjust number */
                   1007:    np->nt_new_bnum = new_bnum;
                   1008:
                   1009:    mf_rem_hash(mfp, hp);                   /* remove from old hash list */
                   1010:    hp->bh_bnum = new_bnum;
                   1011:    mf_ins_hash(mfp, hp);                   /* insert in new hash list */
                   1012:
                   1013:    hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
                   1014:    np->nt_next = mfp->mf_trans[hash];
                   1015:    mfp->mf_trans[hash] = np;
                   1016:    if (np->nt_next != NULL)
                   1017:        np->nt_next->nt_prev = np;
                   1018:    np->nt_prev = NULL;
                   1019:
                   1020:    return OK;
                   1021: }
                   1022:
                   1023: /*
                   1024:  * Lookup a tranlation from the trans lists and delete the entry
                   1025:  *
                   1026:  * Return the positive new number when found, the old number when not found
                   1027:  */
                   1028:    blocknr_t
                   1029: mf_trans_del(mfp, old_nr)
                   1030:    MEMFILE     *mfp;
                   1031:    blocknr_t   old_nr;
                   1032: {
                   1033:    int         hash;
                   1034:    NR_TRANS    *np;
                   1035:    blocknr_t   new_bnum;
                   1036:
                   1037:    hash = MEMHASH(old_nr);
                   1038:    for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
                   1039:        if (np->nt_old_bnum == old_nr)
                   1040:            break;
                   1041:    if (np == NULL)             /* not found */
                   1042:        return old_nr;
                   1043:
                   1044:    mfp->mf_neg_count--;
                   1045:    new_bnum = np->nt_new_bnum;
                   1046:    if (np->nt_prev != NULL)            /* remove entry from the trans list */
                   1047:        np->nt_prev->nt_next = np->nt_next;
                   1048:    else
                   1049:        mfp->mf_trans[hash] = np->nt_next;
                   1050:    if (np->nt_next != NULL)
                   1051:        np->nt_next->nt_prev = np->nt_prev;
                   1052:    vim_free(np);
                   1053:
                   1054:    return new_bnum;
                   1055: }
                   1056:
                   1057: /*
                   1058:  * Set mfp->mf_xfname according to mfp->mf_fname and some other things.
                   1059:  * Don't get the full path name if did_cd is TRUE, then fname should
                   1060:  * already be a full path name.
                   1061:  */
                   1062:    void
                   1063: mf_set_xfname(mfp)
                   1064:    MEMFILE     *mfp;
                   1065: {
                   1066:    mfp->mf_xfname = NULL;
                   1067:    if (!did_cd)
                   1068:        mfp->mf_xfname = FullName_save(mfp->mf_fname);
                   1069: }
                   1070:
                   1071: /*
                   1072:  * Make the name of the file used for the memfile a full path.
                   1073:  * Used before doing a :cd
                   1074:  */
                   1075:    void
                   1076: mf_fullname(mfp)
                   1077:    MEMFILE     *mfp;
                   1078: {
                   1079:    if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_xfname != NULL)
                   1080:    {
                   1081:        vim_free(mfp->mf_fname);
                   1082:        mfp->mf_fname = mfp->mf_xfname;
                   1083:        mfp->mf_xfname = NULL;
                   1084:    }
                   1085: }
                   1086:
                   1087: /*
                   1088:  * return TRUE if there are any translations pending for 'mfp'
                   1089:  */
                   1090:    int
                   1091: mf_need_trans(mfp)
                   1092:    MEMFILE     *mfp;
                   1093: {
                   1094:    return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
                   1095: }
                   1096:
                   1097: #if 1          /* included for beta release, TODO: remove later */
                   1098: /*
                   1099:  * print statistics for a memfile (for debugging)
                   1100:  */
                   1101:    void
                   1102: mf_statistics()
                   1103: {
                   1104:    MEMFILE     *mfp;
                   1105:    BHDR        *hp;
                   1106:    int         used = 0;
                   1107:    int         locked = 0;
                   1108:    int         dirty = 0;
                   1109:    int         nfree = 0;
                   1110:    int         negative = 0;
                   1111:
                   1112:    mfp = curbuf->b_ml.ml_mfp;
                   1113:    if (mfp == NULL)
                   1114:        MSG("No memfile");
                   1115:    else
                   1116:    {
                   1117:        for (hp = mfp->mf_used_first; hp != NULL; hp = hp->bh_next)
                   1118:        {
                   1119:            ++used;
                   1120:            if (hp->bh_flags & BH_LOCKED)
                   1121:                ++locked;
                   1122:            if (hp->bh_flags & BH_DIRTY)
                   1123:                ++dirty;
                   1124:            if (hp->bh_bnum < 0)
                   1125:                ++negative;
                   1126:        }
                   1127:        for (hp = mfp->mf_free_first; hp != NULL; hp = hp->bh_next)
                   1128:            ++nfree;
                   1129:        sprintf((char *)IObuff, "%d used (%d locked, %d dirty, %d (%d) negative), %d free",
                   1130:                        used, locked, dirty, negative, (int)mfp->mf_neg_count, nfree);
                   1131:        msg(IObuff);
                   1132:        sprintf((char *)IObuff, "Total mem used is %ld bytes", total_mem_used);
                   1133:        msg(IObuff);
                   1134:    }
                   1135: }
                   1136: #endif
                   1137:
                   1138: /*
                   1139:  * open a swap file for a memfile
                   1140:  */
                   1141:    static void
                   1142: mf_do_open(mfp, fname, trunc_file)
                   1143:    MEMFILE     *mfp;
                   1144:    char_u      *fname;
                   1145:    int         trunc_file;
                   1146: {
                   1147:    mfp->mf_fname = fname;
                   1148:    /*
                   1149:     * Get the full path name before the open, because this is
                   1150:     * not possible after the open on the Amiga.
                   1151:     * fname cannot be NameBuff, because it must have been allocated.
                   1152:     */
                   1153:    mf_set_xfname(mfp);
                   1154:
                   1155:    /*
                   1156:     * try to open the file
                   1157:     */
                   1158:    mfp->mf_fd = open((char *)fname,
                   1159:            (trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
                   1160:
                   1161: #ifdef AMIGA               /* Amiga has no mode argument */
                   1162:                    );
                   1163: #endif
                   1164: #ifdef UNIX                    /* open in rw------- mode */
                   1165:                    , (mode_t)0600);
                   1166: #endif
                   1167: #if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
                   1168:                    , S_IREAD | S_IWRITE);         /* open read/write */
                   1169: #endif
                   1170: #ifdef VMS                 /* open in rw------- mode */
                   1171:                    , 0600);
                   1172: #endif
                   1173:
                   1174:    /*
                   1175:     * If the file cannot be opened, use memory only
                   1176:     */
                   1177:    if (mfp->mf_fd < 0)
                   1178:    {
                   1179:        vim_free(mfp->mf_xfname);
                   1180:        mfp->mf_fname = NULL;
                   1181:        mfp->mf_xfname = NULL;
                   1182:    }
                   1183: }