[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     ! 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: }