home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / elvis / Source / c / blk < prev    next >
Encoding:
Text File  |  1989-12-31  |  8.3 KB  |  425 lines

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