home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1707 / modify.c next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  8.4 KB  |  431 lines

  1. /* modify.c */
  2.  
  3. /* This file contains the low-level file modification functions:
  4.  *    delete(frommark, tomark)    - removes line or portions of lines
  5.  *    add(frommark, text)        - inserts new text
  6.  *    change(frommark, tomark, text)    - delete, then add
  7.  */
  8.  
  9. #include "config.h"
  10. #include "vi.h"
  11.  
  12.  
  13. /* delete a range of text from the file */
  14. delete(frommark, tomark)
  15.     MARK        frommark;    /* first char to be deleted */
  16.     MARK        tomark;        /* AFTER last char to be deleted */
  17. {
  18.     int        i;        /* used to move thru logical blocks */
  19.     register char    *scan;        /* used to scan thru text of the blk */
  20.     register char    *cpy;        /* used when copying chars */
  21.     BLK        *blk;        /* a text block */
  22.     long        l;        /* a line number */
  23.     MARK        m;        /* a traveling version of frommark */
  24.  
  25.     /* if not deleting anything, quit now */
  26.     if (frommark == tomark)
  27.     {
  28.         return;
  29.     }
  30.  
  31.     /* This is a change */
  32.     changes++;
  33.  
  34.     /* if this is a multi-line change, then we'll have to redraw */
  35.     if (markline(frommark) != markline(tomark))
  36.     {
  37.         mustredraw = TRUE;
  38.         redrawrange(markline(frommark), markline(tomark), markline(frommark));
  39.     }
  40.  
  41.     /* adjust marks 'a through 'z and '' as needed */
  42.     l = markline(tomark);
  43.     for (i = 0; i < NMARKS; i++)
  44.     {
  45.         if (mark[i] < frommark)
  46.         {
  47.             continue;
  48.         }
  49.         else if (mark[i] < tomark)
  50.         {
  51.             mark[i] = MARK_UNSET;
  52.         }
  53.         else if (markline(mark[i]) == l)
  54.         {
  55.             if (markline(frommark) == l)
  56.             {
  57.                 mark[i] -= markidx(tomark) - markidx(frommark);
  58.             }
  59.             else
  60.             {
  61.                 mark[i] -= markidx(tomark);
  62.             }
  63.         }
  64.         else
  65.         {
  66.             mark[i] -= MARK_AT_LINE(l - markline(frommark));
  67.         }
  68.     }
  69.  
  70.     /* Reporting... */
  71.     if (markidx(frommark) == 0 && markidx(tomark) == 0)
  72.     {
  73.         rptlines = markline(tomark) - markline(frommark);
  74.         rptlabel = "deleted";
  75.     }
  76.  
  77.     /* find the block containing frommark */
  78.     l = markline(frommark);
  79.     for (i = 1; lnum[i] < l; i++)
  80.     {
  81.     }
  82.  
  83.     /* process each affected block... */
  84.     for (m = frommark;
  85.          m < tomark && lnum[i] < INFINITY;
  86.          m = MARK_AT_LINE(lnum[i - 1] + 1))
  87.     {
  88.         /* fetch the block */
  89.         blk = blkget(i);
  90.  
  91.         /* find the mark in the block */
  92.         scan = blk->c;
  93.         for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
  94.         {
  95.             while (*scan++ != '\n')
  96.             {
  97.             }
  98.         }
  99.         scan += markidx(m);
  100.  
  101.         /* figure out where the changes to this block end */
  102.         if (markline(tomark) > lnum[i])
  103.         {
  104.             cpy = blk->c + BLKSIZE;
  105.         }
  106.         else if (markline(tomark) == markline(m))
  107.         {
  108.             cpy = scan - markidx(m) + markidx(tomark);
  109.         }
  110.         else
  111.         {
  112.             cpy = scan;
  113.             for (l = markline(tomark) - markline(m);
  114.                  l > 0;
  115.                  l--)
  116.             {
  117.                 while (*cpy++ != '\n')
  118.                 {
  119.                 }
  120.             }
  121.             cpy += markidx(tomark);
  122.         }
  123.  
  124.         /* delete the stuff by moving chars within this block */
  125.         while (cpy < blk->c + BLKSIZE)
  126.         {
  127.             *scan++ = *cpy++;
  128.         }
  129.         while (scan < blk->c + BLKSIZE)
  130.         {
  131.             *scan++ = '\0';
  132.         }
  133.  
  134.         /* adjust tomark to allow for lines deleted from this block */
  135.         tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
  136.  
  137.         /* if this block isn't empty now, then advance i */
  138.         if (*blk->c)
  139.         {
  140.             i++;
  141.         }
  142.  
  143.         /* the buffer has changed.  Update hdr and lnum. */
  144.         blkdirty(blk);
  145.     }
  146.  
  147.     /* must have at least 1 line */
  148.     if (nlines == 0)
  149.     {
  150.         blk = blkadd(1);
  151.         blk->c[0] = '\n';
  152.         blkdirty(blk);
  153.         cursor = MARK_FIRST;
  154.     }
  155. }
  156.  
  157.  
  158. /* add some text at a specific place in the file */
  159. add(atmark, newtext)
  160.     MARK        atmark;        /* where to insert the new text */
  161.     char        *newtext;    /* NUL-terminated string to insert */
  162. {
  163.     register char    *scan;        /* used to move through string */
  164.     register char    *build;        /* used while copying chars */
  165.     int        addlines;    /* number of lines we're adding */
  166.     int        lastpart;    /* size of last partial line */
  167.     BLK        *blk;        /* the block to be modified */
  168.     int        blkno;        /* the logical block# of (*blk) */
  169.     register char    *newptr;    /* where new text starts in blk */
  170.     BLK        buf;        /* holds chars from orig blk */
  171.     BLK        linebuf;    /* holds part of line that didn't fit */
  172.     BLK        *following;    /* the BLK following the last BLK */
  173.     int        i;
  174.     long        l;
  175.  
  176.     /* if not adding anything, return now */
  177.     if (!*newtext)
  178.     {
  179.         return;
  180.     }
  181.  
  182.     /* This is a change */
  183.     changes++;
  184.  
  185.     /* count the number of lines in the new text */
  186.     for (scan = newtext, lastpart = addlines = 0; *scan; )
  187.     {
  188.         if (*scan++ == '\n')
  189.         {
  190.             addlines++;
  191.             lastpart = 0;
  192.         }
  193.         else
  194.         {
  195.             lastpart++;
  196.         }
  197.     }
  198.  
  199.     /* Reporting... */
  200.     if (lastpart == 0 && markidx(atmark) == 0)
  201.     {
  202.         rptlines = addlines;
  203.         rptlabel = "added";
  204.     }
  205.  
  206.     /* extract the line# from atmark */
  207.     l = markline(atmark);
  208.  
  209.     /* if more than 0 lines, then we'll have to redraw the screen */
  210.     if (addlines > 0)
  211.     {
  212.         mustredraw = TRUE;
  213.         if (markidx(atmark) == 0)
  214.         {
  215.             redrawrange(l, l, l + addlines);
  216.         }
  217.         else
  218.         {
  219.             /* make sure the last line gets redrawn -- it was
  220.              * split, so its appearance has changed
  221.              */
  222.             redrawrange(l, l + 1L, l + addlines + 1L);
  223.         }
  224.     }
  225.  
  226.     /* adjust marks 'a through 'z and '' as needed */
  227.     for (i = 0; i < NMARKS; i++)
  228.     {
  229.         if (mark[i] < atmark)
  230.         {
  231.             continue;
  232.         }
  233.         else if (markline(mark[i]) > l)
  234.         {
  235.             mark[i] += MARK_AT_LINE(addlines);
  236.         }
  237.         else
  238.         {
  239.             mark[i] += MARK_AT_LINE(addlines) + lastpart;
  240.         }
  241.     }
  242.  
  243.     /* get the block to be modified */
  244.     for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
  245.     {
  246.     }
  247.     blk = blkget(blkno);
  248.     buf = *blk;
  249.  
  250.     /* figure out where the new text starts */
  251.     for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
  252.          l > 0;
  253.          l--)
  254.     {
  255.         while (*newptr++ != '\n')
  256.         {
  257.         }
  258.     }
  259.     newptr += markidx(atmark);
  260.  
  261.     /* keep start of old block */
  262.     build = blk->c + (newptr - buf.c);
  263.  
  264.     /* fill this block (or blocks) from the newtext string */
  265.     while (*newtext)
  266.     {
  267.         while (*newtext && build < blk->c + BLKSIZE - 1)
  268.         {
  269.             *build++ = *newtext++;
  270.         }
  271.         if (*newtext)
  272.         {
  273.             /* save the excess */
  274.             for (scan = linebuf.c + BLKSIZE;
  275.                  build > blk->c && build[-1] != '\n';
  276.                  )
  277.             {
  278.                 *--scan = *--build;
  279.             }
  280.  
  281.             /* write the block */
  282.             while (build < blk->c + BLKSIZE)
  283.             {
  284.                 *build++ = '\0';
  285.             }
  286.             blkdirty(blk);
  287.  
  288.             /* add another block */
  289.             blkno++;
  290.             blk = blkadd(blkno);
  291.  
  292.             /* copy in the excess from last time */
  293.             for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  294.             {
  295.                 *build++ = *scan++;
  296.             }
  297.         }
  298.     }
  299.  
  300.     /* fill this block(s) from remainder of orig block */
  301.     while (newptr < buf.c + BLKSIZE && *newptr)
  302.     {
  303.         while (newptr < buf.c + BLKSIZE
  304.             && *newptr
  305.             && build < blk->c + BLKSIZE - 1)
  306.         {
  307.             *build++ = *newptr++;
  308.         }
  309.         if (newptr < buf.c + BLKSIZE && *newptr)
  310.         {
  311.             /* save the excess */
  312.             for (scan = linebuf.c + BLKSIZE;
  313.                  build > blk->c && build[-1] != '\n';
  314.                  )
  315.             {
  316.                 *--scan = *--build;
  317.             }
  318.  
  319.             /* write the block */
  320.             while (build < blk->c + BLKSIZE)
  321.             {
  322.                 *build++ = '\0';
  323.             }
  324.             blkdirty(blk);
  325.  
  326.             /* add another block */
  327.             blkno++;
  328.             blk = blkadd(blkno);
  329.  
  330.             /* copy in the excess from last time */
  331.             for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  332.             {
  333.                 *build++ = *scan++;
  334.             }
  335.         }
  336.     }
  337.  
  338.     /* see if we can combine our last block with the following block */
  339.     if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
  340.     {
  341.         /* hey, we probably can!  Get the following block & see... */
  342.         following = blkget(blkno + 1);
  343.         if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
  344.         {
  345.             /* we can!  Copy text from following to blk */
  346.             for (scan = following->c; *scan; )
  347.             {
  348.                 *build++ = *scan++;
  349.             }
  350.             while (build < blk->c + BLKSIZE)
  351.             {
  352.                 *build++ = '\0';
  353.             }
  354.             blkdirty(blk);
  355.  
  356.             /* pretend the following was the last blk */
  357.             blk = following;
  358.             build = blk->c;
  359.         }
  360.     }
  361.  
  362.     /* that last block is dirty by now */
  363.     while (build < blk->c + BLKSIZE)
  364.     {
  365.         *build++ = '\0';
  366.     }
  367.     blkdirty(blk);
  368. }
  369.  
  370.  
  371. /* change the text of a file */
  372. change(frommark, tomark, newtext)
  373.     MARK    frommark, tomark;
  374.     char    *newtext;
  375. {
  376.     int    i;
  377.     long    l;
  378.     char    *text;
  379.     BLK    *blk;
  380.  
  381.     /* optimize for single-character replacement */
  382.     if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
  383.     {
  384.         /* find the block containing frommark */
  385.         l = markline(frommark);
  386.         for (i = 1; lnum[i] < l; i++)
  387.         {
  388.         }
  389.  
  390.         /* get the block */
  391.         blk = blkget(i);
  392.  
  393.         /* find the line within the block */
  394.         for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
  395.         {
  396.             if (*text == '\n')
  397.             {
  398.                 i--;
  399.             }
  400.         }
  401.  
  402.         /* replace the char */
  403.         text += markidx(frommark);
  404.         if (*text == newtext[0])
  405.         {
  406.             /* no change was needed - same char */
  407.             return;
  408.         }
  409.         else if (*text != '\n')
  410.         {
  411.             /* This is a change */
  412.             changes++;
  413.             ChangeText
  414.             {
  415.                 *text = newtext[0];
  416.                 blkdirty(blk);
  417.             }
  418.             return;
  419.         }
  420.         /* else it is a complex change involving newline... */
  421.     }
  422.  
  423.     /* couldn't optimize, so do delete & add */
  424.     ChangeText
  425.     {
  426.         delete(frommark, tomark);
  427.         add(frommark, newtext);
  428.         rptlabel = "changed";
  429.     }
  430. }
  431.