Annotation of coherent/d/usr/bin/elvis/blk.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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