home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / text_ed / elv16b2 / st / blk.c < prev    next >
C/C++ Source or Header  |  1992-05-12  |  9KB  |  473 lines

  1. /* blk.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  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. }
  473.