Annotation of coherent/g/usr/bin/vi/blk.c, revision 1.1

1.1     ! root        1: /* blk.c */
        !             2: 
        !             3: /* Author:
        !             4:  *     Steve Kirkendall
        !             5:  *     14407 SW Teal Blvd. #C
        !             6:  *     Beaverton, OR 97005
        !             7:  *     [email protected]
        !             8:  */
        !             9: 
        !            10: 
        !            11: /* This file contains the functions that get/put blocks from the temp file.
        !            12:  * It also contains the "do" and "undo" functions.
        !            13:  */
        !            14: 
        !            15: #include "config.h"
        !            16: #include "vi.h"
        !            17: 
        !            18: #ifndef NBUFS
        !            19: # define NBUFS 5               /* must be at least 3 -- more is better */
        !            20: #endif
        !            21: 
        !            22: 
        !            23: /*------------------------------------------------------------------------*/
        !            24: 
        !            25: BLK            hdr;            /* buffer for the header block */
        !            26: 
        !            27: static int     b4cnt;          /* used to count context of beforedo/afterdo */
        !            28: static struct _blkbuf
        !            29: {
        !            30:        BLK             buf;            /* contents of a text block */
        !            31:        unsigned short  logical;        /* logical block number */
        !            32:        int             dirty;          /* must the buffer be rewritten? */
        !            33: }
        !            34:                blk[NBUFS],     /* buffers for text[?] blocks */
        !            35:                *toonew,        /* buffer which shouldn't be recycled yet */
        !            36:                *newtoo,        /* another buffer which should be recycled */
        !            37:                *recycle = blk; /* next block to be recycled */
        !            38: 
        !            39: 
        !            40: 
        !            41: void blkflush P_((REG struct _blkbuf *this));
        !            42: 
        !            43: 
        !            44: 
        !            45: 
        !            46: /* This function wipes out all buffers */
        !            47: void blkinit()
        !            48: {
        !            49:        int     i;
        !            50: 
        !            51:        for (i = 0; i < NBUFS; i++)
        !            52:        {
        !            53:                blk[i].logical = 0;
        !            54:                blk[i].dirty = FALSE;
        !            55:        }
        !            56:        for (i = 0; i < MAXBLKS; i++)
        !            57:        {
        !            58:                hdr.n[i] = 0;
        !            59:        }
        !            60: }
        !            61: 
        !            62: /* This function allocates a buffer and fills it with a given block's text */
        !            63: BLK *blkget(logical)
        !            64:        int     logical;        /* logical block number to fetch */
        !            65: {
        !            66:        REG struct _blkbuf      *this;  /* used to step through blk[] */
        !            67:        REG int i;
        !            68: 
        !            69:        /* if logical is 0, just return the hdr buffer */
        !            70:        if (logical == 0)
        !            71:        {
        !            72:                return &hdr;
        !            73:        }
        !            74: 
        !            75:        /* see if we have that block in mem already */
        !            76:        for (this = blk; this < &blk[NBUFS]; this++)
        !            77:        {
        !            78:                if (this->logical == logical)
        !            79:                {
        !            80:                        newtoo = toonew;
        !            81:                        toonew = this;
        !            82:                        return &this->buf;
        !            83:                }
        !            84:        }
        !            85: 
        !            86:        /* choose a block to be recycled */
        !            87:        do
        !            88:        {
        !            89:                this = recycle++;
        !            90:                if (recycle == &blk[NBUFS])
        !            91:                {
        !            92:                        recycle = blk;
        !            93:                }
        !            94:        } while (this == toonew || this == newtoo);
        !            95: 
        !            96:        /* if it contains a block, flush that block */
        !            97:        blkflush(this);
        !            98: 
        !            99:        /* fill this buffer with the desired block */
        !           100:        this->logical = logical;
        !           101:        if (hdr.n[logical])
        !           102:        {
        !           103:                /* it has been used before - fill it from tmp file */
        !           104:                lseek(tmpfd, (long)hdr.n[logical] * (long)BLKSIZE, 0);
        !           105:                if (read(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
        !           106:                {
        !           107:                        msg("Error reading back from tmp file!");
        !           108:                }
        !           109:        }
        !           110:        else
        !           111:        {
        !           112:                /* it is new - zero it */
        !           113:                for (i = 0; i < BLKSIZE; i++)
        !           114:                {
        !           115:                        this->buf.c[i] = 0;
        !           116:                }
        !           117:        }
        !           118: 
        !           119:        /* This isn't really a change, but it does potentially invalidate
        !           120:         * the kinds of shortcuts that the "changes" variable is supposed
        !           121:         * to protect us from... so count it as a change.
        !           122:         */
        !           123:        changes++;
        !           124: 
        !           125:        /* mark it as being "not dirty" */
        !           126:        this->dirty = 0;
        !           127: 
        !           128:        /* return it */
        !           129:        newtoo = toonew;
        !           130:        toonew = this;
        !           131:        return &this->buf;
        !           132: }
        !           133: 
        !           134: 
        !           135: 
        !           136: /* This function writes a block out to the temporary file */
        !           137: void blkflush(this)
        !           138:        REG struct _blkbuf      *this;  /* the buffer to flush */
        !           139: {
        !           140:        long            seekpos;        /* seek position of the new block */
        !           141:        unsigned short  physical;       /* physical block number */
        !           142: 
        !           143:        /* if its empty (an orphan blkadd() maybe?) then make it dirty */
        !           144:        if (this->logical && !*this->buf.c)
        !           145:        {
        !           146:                blkdirty(&this->buf);
        !           147:        }
        !           148: 
        !           149:        /* if it's an empty buffer or a clean version is on disk, quit */
        !           150:        if (!this->logical || hdr.n[this->logical] && !this->dirty)
        !           151:        {
        !           152:                return;
        !           153:        }
        !           154: 
        !           155:        /* find a free place in the file */
        !           156: #ifndef NO_RECYCLE
        !           157:        seekpos = allocate();
        !           158:        lseek(tmpfd, seekpos, 0);
        !           159: #else
        !           160:        seekpos = lseek(tmpfd, 0L, 2);
        !           161: #endif
        !           162:        physical = seekpos / BLKSIZE;
        !           163: 
        !           164:        /* put the block there */
        !           165:        if (write(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
        !           166:        {
        !           167:                msg("Trouble writing to tmp file");
        !           168:        }
        !           169:        this->dirty = FALSE;
        !           170: 
        !           171:        /* update the header so it knows we put it there */
        !           172:        hdr.n[this->logical] = physical;
        !           173: }
        !           174: 
        !           175: 
        !           176: /* This function sets a block's "dirty" flag or deletes empty blocks */
        !           177: void blkdirty(bp)
        !           178:        BLK     *bp;    /* buffer returned by blkget() */
        !           179: {
        !           180:        REG int         i, j;
        !           181:        REG char        *scan;
        !           182:        REG int         k;
        !           183: 
        !           184:        /* find the buffer */
        !           185:        for (i = 0; i < NBUFS && bp != &blk[i].buf; i++)
        !           186:        {
        !           187:        }
        !           188: #ifdef DEBUG
        !           189:        if (i >= NBUFS)
        !           190:        {
        !           191:                msg("blkdirty() called with unknown buffer at 0x%lx", bp);
        !           192:                return;
        !           193:        }
        !           194:        if (blk[i].logical == 0)
        !           195:        {
        !           196:                msg("blkdirty called with freed buffer");
        !           197:                return;
        !           198:        }
        !           199: #endif
        !           200: 
        !           201:        /* if this block ends with line# INFINITY, then it must have been
        !           202:         * allocated unnecessarily during tmpstart().  Forget it.
        !           203:         */
        !           204:        if (lnum[blk[i].logical] == INFINITY)
        !           205:        {
        !           206: #ifdef DEBUG
        !           207:                if (blk[i].buf.c[0])
        !           208:                {
        !           209:                        msg("bkldirty called with non-empty extra BLK");
        !           210:                }
        !           211: #endif
        !           212:                blk[i].logical = 0;
        !           213:                blk[i].dirty = FALSE;
        !           214:                return;
        !           215:        }
        !           216: 
        !           217:        /* count lines in this block */
        !           218:        for (j = 0, scan = bp->c; *scan && scan < bp->c + BLKSIZE; scan++)
        !           219:        {
        !           220:                if (*scan == '\n')
        !           221:                {
        !           222:                        j++;
        !           223:                }
        !           224:        }
        !           225: 
        !           226:        /* adjust lnum, if necessary */
        !           227:        k = blk[i].logical;
        !           228:        j += (lnum[k - 1] - lnum[k]);
        !           229:        if (j != 0)
        !           230:        {
        !           231:                nlines += j;
        !           232:                while (k < MAXBLKS && lnum[k] != INFINITY)
        !           233:                {
        !           234:                        lnum[k++] += j;
        !           235:                }
        !           236:        }
        !           237: 
        !           238:        /* if it still has text, mark it as dirty */
        !           239:        if (*bp->c)
        !           240:        {
        !           241:                blk[i].dirty = TRUE;
        !           242:        }
        !           243:        else /* empty block, so delete it */
        !           244:        {
        !           245:                /* adjust the cache */
        !           246:                k = blk[i].logical;
        !           247:                for (j = 0; j < NBUFS; j++)
        !           248:                {
        !           249:                        if (blk[j].logical >= k)
        !           250:                        {
        !           251:                                blk[j].logical--;
        !           252:                        }
        !           253:                }
        !           254: 
        !           255:                /* delete it from hdr.n[] and lnum[] */
        !           256:                blk[i].logical = 0;
        !           257:                blk[i].dirty = FALSE;
        !           258:                while (k < MAXBLKS - 1)
        !           259:                {
        !           260:                        hdr.n[k] = hdr.n[k + 1];
        !           261:                        lnum[k] = lnum[k + 1];
        !           262:                        k++;
        !           263:                }
        !           264:                hdr.n[MAXBLKS - 1] = 0;
        !           265:                lnum[MAXBLKS - 1] = INFINITY;
        !           266:        }
        !           267: }
        !           268: 
        !           269: 
        !           270: /* insert a new block into hdr, and adjust the cache */
        !           271: BLK *blkadd(logical)
        !           272:        int     logical;        /* where to insert the new block */
        !           273: {
        !           274:        REG int i;
        !           275: 
        !           276:        /* adjust hdr and lnum[] */
        !           277:        for (i = MAXBLKS - 1; i > logical; i--)
        !           278:        {
        !           279:                hdr.n[i] = hdr.n[i - 1];
        !           280:                lnum[i] = lnum[i - 1];
        !           281:        }
        !           282:        hdr.n[logical] = 0;
        !           283:        lnum[logical] = lnum[logical - 1];
        !           284: 
        !           285:        /* adjust the cache */
        !           286:        for (i = 0; i < NBUFS; i++)
        !           287:        {
        !           288:                if (blk[i].logical >= logical)
        !           289:                {
        !           290:                        blk[i].logical++;
        !           291:                }
        !           292:        }
        !           293: 
        !           294:        /* return the new block, via blkget() */
        !           295:        return blkget(logical);
        !           296: }
        !           297: 
        !           298: 
        !           299: /* This function forces all dirty blocks out to disk */
        !           300: void blksync()
        !           301: {
        !           302:        int     i;
        !           303: 
        !           304:        for (i = 0; i < NBUFS; i++)
        !           305:        {
        !           306:                /* blk[i].dirty = TRUE; */
        !           307:                blkflush(&blk[i]);
        !           308:        }
        !           309:        if (*o_sync)
        !           310:        {
        !           311:                sync();
        !           312:        }
        !           313: }
        !           314: 
        !           315: /*------------------------------------------------------------------------*/
        !           316: 
        !           317: static MARK    undocurs;       /* where the cursor should go if undone */
        !           318: static long    oldnlines;
        !           319: static long    oldlnum[MAXBLKS];
        !           320: 
        !           321: 
        !           322: /* This function should be called before each command that changes the text.
        !           323:  * It defines the state that undo() will reset the file to.
        !           324:  */
        !           325: void beforedo(forundo)
        !           326:        int             forundo;        /* boolean: is this for an undo? */
        !           327: {
        !           328:        REG int         i;
        !           329:        REG long        l;
        !           330: 
        !           331:        /* if this is a nested call to beforedo, quit! Use larger context */
        !           332:        if (b4cnt++ > 0)
        !           333:        {
        !           334:                return;
        !           335:        }
        !           336: 
        !           337:        /* force all block buffers to disk */
        !           338:        blksync();
        !           339: 
        !           340: #ifndef NO_RECYCLE
        !           341:        /* perform garbage collection on blocks from tmp file */
        !           342:        garbage();
        !           343: #endif
        !           344: 
        !           345:        /* force the header out to disk */
        !           346:        lseek(tmpfd, 0L, 0);
        !           347:        if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) != BLKSIZE)
        !           348:        {
        !           349:                msg("Trouble writing header to tmp file ");
        !           350:        }
        !           351: 
        !           352:        /* copy or swap oldnlines <--> nlines, oldlnum <--> lnum */
        !           353:        if (forundo)
        !           354:        {
        !           355:                for (i = 0; i < MAXBLKS; i++)
        !           356:                {
        !           357:                        l = lnum[i];
        !           358:                        lnum[i] = oldlnum[i];
        !           359:                        oldlnum[i] = l;
        !           360:                }
        !           361:                l = nlines;
        !           362:                nlines = oldnlines;
        !           363:                oldnlines = l;
        !           364:        }
        !           365:        else
        !           366:        {
        !           367:                for (i = 0; i < MAXBLKS; i++)
        !           368:                {
        !           369:                        oldlnum[i] = lnum[i];
        !           370:                }
        !           371:                oldnlines = nlines;
        !           372:        }
        !           373: 
        !           374:        /* save the cursor position */
        !           375:        undocurs = cursor;
        !           376: 
        !           377:        /* upon return, the calling function continues and makes changes... */
        !           378: }
        !           379: 
        !           380: /* This function marks the end of a (nested?) change to the file */
        !           381: void afterdo()
        !           382: {
        !           383:        if (--b4cnt)
        !           384:        {
        !           385:                /* after abortdo(), b4cnt may decribe nested beforedo/afterdo
        !           386:                 * pairs incorrectly.  If it is decremented to often, then
        !           387:                 * keep b4cnt sane but don't do anything else.
        !           388:                 */
        !           389:                if (b4cnt < 0)
        !           390:                        b4cnt = 0;
        !           391: 
        !           392:                return;
        !           393:        }
        !           394: 
        !           395:        /* make sure the cursor wasn't left stranded in deleted text */
        !           396:        if (markline(cursor) > nlines)
        !           397:        {
        !           398:                cursor = MARK_LAST;
        !           399:        }
        !           400:        /* NOTE: it is still possible that markidx(cursor) is after the
        !           401:         * end of a line, so the Vi mode will have to take care of that
        !           402:         * itself */
        !           403: 
        !           404:        /* if a significant change has been made to this file, then set the
        !           405:         * MODIFIED flag.
        !           406:         */
        !           407:        if (significant)
        !           408:        {
        !           409:                setflag(file, MODIFIED);
        !           410:                setflag(file, UNDOABLE);
        !           411:        }       
        !           412: }
        !           413: 
        !           414: /* This function cuts short the current set of changes.  It is called after
        !           415:  * a SIGINT.
        !           416:  */
        !           417: void abortdo()
        !           418: {
        !           419:        /* finish the operation immediately. */
        !           420:        if (b4cnt > 0)
        !           421:        {
        !           422:                b4cnt = 1;
        !           423:                afterdo();
        !           424:        }
        !           425: 
        !           426:        /* in visual mode, the screen is probably screwed up */
        !           427:        if (mode == MODE_COLON)
        !           428:        {
        !           429:                mode = MODE_VI;
        !           430:        }
        !           431:        if (mode == MODE_VI)
        !           432:        {
        !           433:                redraw(MARK_UNSET, FALSE);
        !           434:        }
        !           435: }
        !           436: 
        !           437: /* This function discards all changes made since the last call to beforedo() */
        !           438: int undo()
        !           439: {
        !           440:        BLK             oldhdr;
        !           441: 
        !           442:        /* if beforedo() has never been run, fail */
        !           443:        if (!tstflag(file, UNDOABLE))
        !           444:        {
        !           445:                msg("You haven't modified this file yet.");
        !           446:                return FALSE;
        !           447:        }
        !           448: 
        !           449:        /* read the old header form the tmp file */
        !           450:        lseek(tmpfd, 0L, 0);
        !           451:        if (read(tmpfd, oldhdr.c, (unsigned)BLKSIZE) != BLKSIZE)
        !           452:        {
        !           453:                msg("Trouble rereading the old header from tmp file");
        !           454:        }
        !           455: 
        !           456:        /* "do" the changed version, so we can undo the "undo" */
        !           457:        cursor = undocurs;
        !           458:        beforedo(TRUE);
        !           459:        afterdo();
        !           460: 
        !           461:        /* wipe out the block buffers - we can't assume they're correct */
        !           462:        blkinit();
        !           463: 
        !           464:        /* use the old header -- and therefore the old text blocks */
        !           465:        hdr = oldhdr;
        !           466: 
        !           467:        /* This is a change */
        !           468:        significant = TRUE;
        !           469:        changes++;
        !           470: 
        !           471:        return TRUE;
        !           472: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.