Annotation of coherent/g/usr/bin/vi/blk.c, revision 1.1.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.