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