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