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