home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / ce331src.arj / LINE.C < prev    next >
C/C++ Source or Header  |  1991-03-10  |  19KB  |  850 lines

  1. /*
  2.  *    L I N E . C
  3.  *
  4.  *    purpose:
  5.  *        The functions in this file are a general set of line management
  6.  *        utilities. They are the only routines that touch the text. They
  7.  *        also touch the buffer and window structures, to make sure that the
  8.  *        necessary updating gets done. There are routines in this file that
  9.  *        handle the kill buffer too (but aren't here for any specific reason).
  10.  *
  11.  *        Note that this code only updates the dot and mark values in the window
  12.  *        list. Since all the code acts on the current window, the buffer that we
  13.  *        are editing must be currently displayed, which means that "b_nwnd" is
  14.  *        non-zero, which means that the dot and mark values in the buffer
  15.  *        headers are nonsense.
  16.  */
  17.  
  18. #include <stdio.h>            /* Turbo C++ verison 1.0 */
  19. #include <alloc.h>
  20. #include <dos.h>
  21.  
  22. #include <pdefs.h>            /* PforCe version 1.05 (includes jwg.h) */
  23. #include <pf_ansi.h>
  24.  
  25. #include "struct.h"
  26. #include "def.h"
  27. #include "protos.h"
  28.  
  29. #define    BSIZE(a)    (a+NBLOCK-1)&(~(NBLOCK-1))
  30.  
  31. /*
  32.  * local function prototypes
  33.  */
  34.  
  35. static int near        ldelnewline(void);
  36. static int near        lowrite(char);
  37.  
  38. /*
  39.  * local (module global) variable declarations
  40.  */
  41.  
  42. static KILL            *ykbuf;    /* ptr to current kill buffer chunk being yanked */
  43. static int             ykboff; /* offset into that chunk */
  44.  
  45. /**
  46.  * This routine allocates a block of memory large enough to hold a LINE
  47.  * containing "used" characters. Return a pointer to the new block, or
  48.  * NULL if there isn't any memory left.
  49.  */
  50. LINE * LAlloc(used)
  51.   int    used;
  52. {
  53.   LINE    *lp;
  54.  
  55.     if ((lp = (LINE *)malloc(sizeof(LINE) + used)) == NULLLPTR)
  56.     {
  57.         OutOfMem();
  58.         return(NULLLPTR);
  59.     }
  60.     lp->l_size = used;
  61.     lp->l_used = used;
  62.     return(lp);
  63. }
  64.  
  65. /**
  66.  * Delete line "lp". Fix all of the links that might point to it (they are
  67.  * moved to offset 0 of the next line). Unlink the line from whatever buffer
  68.  * it might be in. Release the memory. Update the buffers.
  69.  */
  70. int LFree(lp)
  71.   LINE        *lp;
  72. {
  73.   WINDOW    *wp;
  74.   BUFFER    *bp;
  75. #if BMARKS
  76.   int        bmark;
  77. #endif
  78.  
  79.     wp = wheadp;
  80.     while (wp != NULLWPTR)
  81.     {
  82.         if (wp->w_linep == lp)
  83.             wp->w_linep = lp->l_fp;
  84.         if (wp->w_dotp == lp)
  85.         {
  86.             wp->w_dotp = lp->l_fp;
  87.             wp->w_doto = 0;
  88.         }
  89.         if (wp->w_markp == lp)
  90.         {
  91.             wp->w_markp = lp->l_fp;
  92.             wp->w_marko = 0;
  93.         }
  94.         if (wp->w_anchorp == lp)
  95.         {
  96.             wp->w_anchorp = lp->l_fp;
  97.             wp->w_anchoro = 0;
  98.         }
  99. #if BMARKS
  100.         for (bmark = 0; bmark < NBMARKS; bmark++)
  101.         {
  102.             if (wp->w_bmarkp[bmark] == lp)
  103.             {
  104.                 wp->w_bmarkp[bmark] = lp->l_fp;
  105.                 wp->w_bmarko[bmark] = 0;
  106.             }
  107.         }
  108. #endif
  109.         wp = wp->w_wndp;
  110.     }
  111.  
  112.     bp = bheadp;
  113.     while (bp != NULLBPTR)
  114.     {
  115.         if (bp->b_nwnd == 0)
  116.         {
  117.             if (bp->b_dotp == lp)
  118.             {
  119.                 bp->b_dotp = lp->l_fp;
  120.                 bp->b_doto = 0;
  121.             }
  122.             if (bp->b_markp == lp)
  123.             {
  124.                 bp->b_markp = lp->l_fp;
  125.                 bp->b_marko = 0;
  126.             }
  127.             if (bp->b_anchorp == lp)
  128.             {
  129.                 bp->b_anchorp = lp->l_fp;
  130.                 bp->b_anchoro = 0;
  131.             }
  132. #if BMARKS
  133.             for (bmark = 0; bmark < NBMARKS; bmark++)
  134.             {
  135.                 if (bp->b_bmarkp[bmark] == lp)
  136.                 {
  137.                     bp->b_bmarkp[bmark] = lp->l_fp;
  138.                     bp->b_bmarko[bmark] = 0;
  139.                 }
  140.             }
  141. #endif
  142.         }
  143.         bp = bp->b_fp;
  144.     }
  145.  
  146.     lp->l_bp->l_fp = lp->l_fp;
  147.     lp->l_fp->l_bp = lp->l_bp;
  148.     free((char *)lp);
  149.     return(TRUE);
  150. }
  151.  
  152. /**
  153.  * This routine gets called when a character is changed in place in the
  154.  * current buffer. It updates all of the required flags in the buffer and
  155.  * window system. The flag used is passed as an argument; if the buffer is
  156.  * being displayed in more than 1 window, we change EDIT to HARD. Set MODE
  157.  * if the mode line needs to be updated (the "*" has to be set).
  158.  */
  159. int LChange(flag)
  160.   int        flag;
  161. {
  162.   WINDOW    *wp;
  163.  
  164.     if (curbp->b_nwnd != 1)             /* ensure hard */
  165.         flag = WFHARD;
  166.     if ((curbp->b_flag & BFCHG) == 0)     /* first change, so */
  167.     {
  168.         flag |= WFMODE;                 /* Update mode lines */
  169.         curbp->b_flag |= BFCHG;
  170.     }
  171.     wp = wheadp;
  172.     while (wp != NULLWPTR)
  173.     {
  174.         if (wp->w_bufp == curbp)
  175.             wp->w_flag |= flag;
  176.         wp = wp->w_wndp;
  177.     }
  178.     return(TRUE);
  179. }
  180.  
  181. /**
  182.  * Insert spaces forward into text
  183.  */
  184. int InsSpace(f, n)
  185.   int    f, n;
  186. {
  187.     LInsert(n, ' ');
  188.     BackChar(f, n);
  189.     return(TRUE);
  190. }
  191.  
  192. /**
  193.  * Insert a string at the current point
  194.  */
  195. int LInstr(instr)
  196.   char    *instr;
  197. {
  198.   int    status = TRUE;
  199.   char    tmpc;
  200.  
  201.     if (instr != NULLCPTR)
  202.     {
  203.         while (((tmpc = *instr) != NULL) && status == TRUE)
  204.         {
  205.             status = (tmpc == '\n' ? LNewline() : LInsert(1, tmpc));
  206.  
  207.             /* insertion error? */
  208.             if (status != TRUE)
  209.             {
  210.                 OutOfMem();
  211.                 break;
  212.             }
  213.             instr++;
  214.         }
  215.     }
  216.     return(status);
  217. }
  218.  
  219. /**
  220.  * Insert "n" copies of the character "c" at the current location of dot. In
  221.  * the easy case all that happens is the text is stored in the line. In the
  222.  * hard case, the line has to be reallocated. When the window list is updated,
  223.  * take special care. You always Update dot in the current window. You Update
  224.  * mark and dot in another window, if it is greater than the place where you
  225.  * did the insert. Return TRUE if all is well, and FALSE on errors.
  226.  */
  227. int LInsert(n, c)
  228.   int        n;
  229.   int        c;
  230. {
  231.   char        *cp1;
  232.   char        *cp2;
  233.   LINE        *lp1;
  234.   LINE        *lp2;
  235.   LINE        *lp3;
  236.   short        doto;
  237.   int        i;
  238.   WINDOW    *wp;
  239. #if BMARKS
  240.   int        bmark;
  241. #endif
  242.  
  243.     if (curbp->b_mode & MDVIEW)         /* don't allow this command if */
  244.         return(ReadOnly());                /* we are in read only mode */
  245.     LChange(WFEDIT);
  246.     lp1 = curwp->w_dotp;                /* current line */
  247.     if (lp1 == curbp->b_linep)            /* at the end (special) */
  248.     {
  249.         if (curwp->w_doto != 0)
  250.             return(FALSE);
  251.         if ((lp2 = LAlloc(BSIZE(n))) == NULLLPTR)    /* allocate new line */
  252.             return(FALSE);
  253.         lp2->l_used = n;
  254.         lp3 = lp1->l_bp;                /* previous line */
  255.         lp3->l_fp = lp2;                /* link in */
  256.         lp2->l_fp = lp1;
  257.         lp1->l_bp = lp2;
  258.         lp2->l_bp = lp3;
  259.         for (i = 0; i < n; ++i)
  260.             lp2->l_text[i] = (char)c;
  261.         curwp->w_dotp = lp2;
  262.         curwp->w_doto = n;
  263.         return(TRUE);
  264.     }
  265.     doto = curwp->w_doto;                /* save for later */
  266.     if (lp1->l_used + n > lp1->l_size)    /* hard: reallocate */
  267.     {
  268.         if ((lp2 = LAlloc(BSIZE(lp1->l_used + n))) == NULLLPTR)
  269.             return(FALSE);
  270.         lp2->l_used = lp1->l_used + n;
  271.         cp1 = &lp1->l_text[0];
  272.         cp2 = &lp2->l_text[0];
  273.         while (cp1 != &lp1->l_text[doto])
  274.             *cp2++ = *cp1++;
  275.         cp2 += n;
  276.         while (cp1 != &lp1->l_text[lp1->l_used])
  277.             *cp2++ = *cp1++;
  278.         lp1->l_bp->l_fp = lp2;
  279.         lp2->l_fp = lp1->l_fp;
  280.         lp1->l_fp->l_bp = lp2;
  281.         lp2->l_bp = lp1->l_bp;
  282.         free((char *)lp1);
  283.     }
  284.     else
  285.     {                                     /* easy: in place */
  286.         lp2 = lp1;                        /* pretend new line */
  287.         lp2->l_used += n;
  288.         cp2 = &lp1->l_text[lp1->l_used];
  289.         cp1 = cp2 - n;
  290.         while (cp1 != &lp1->l_text[doto])
  291.             *--cp2 = *--cp1;
  292.     }
  293.     for (i = 0; i < n; ++i)             /* add the characters */
  294.         lp2->l_text[doto + i] = (char)c;
  295.     wp = wheadp;                        /* Update windows */
  296.     while (wp != NULLWPTR)
  297.     {
  298.         if (wp->w_linep == lp1)
  299.             wp->w_linep = lp2;
  300.         if (wp->w_dotp == lp1)
  301.         {
  302.             wp->w_dotp = lp2;
  303.             if (wp == curwp || wp->w_doto > doto)
  304.                 wp->w_doto += n;
  305.         }
  306.         if (wp->w_markp == lp1)
  307.         {
  308.             wp->w_markp = lp2;
  309.             if (wp->w_marko > doto)
  310.                 wp->w_marko += n;
  311.         }
  312.         if (wp->w_anchorp == lp1)
  313.         {
  314.             wp->w_anchorp = lp2;
  315.             if (wp->w_anchoro > doto)
  316.                 wp->w_anchoro += n;
  317.         }
  318. #if BMARKS
  319.         for (bmark = 0; bmark < NBMARKS; bmark++)
  320.         {
  321.             if (wp->w_bmarkp[bmark] == lp1)
  322.             {
  323.                 wp->w_bmarkp[bmark] = lp2;
  324.                 if (wp->w_bmarko[bmark] > doto)
  325.                     wp->w_bmarko[bmark] += n;
  326.             }
  327.         }
  328. #endif
  329.         wp = wp->w_wndp;
  330.     }
  331.     return(TRUE);
  332. }
  333.  
  334. /**
  335.  * Overwrite a character in the current line at the current position
  336.  */
  337. static int near lowrite(c)
  338.   char    c;            /* character to overwrite */
  339. {
  340.     if    (
  341.                 curwp->w_doto < curwp->w_dotp->l_used
  342.             &&
  343.                 (
  344.                         lgetc(curwp->w_dotp, curwp->w_doto) != '\t'
  345.                     ||
  346.                         curwp->w_doto % tabsize == tabsize - 1
  347.                 )
  348.         )
  349.         LDelete(1L, FALSE);
  350.     return(LInsert(1, c));
  351. }
  352.  
  353. /**
  354.  * Overwrite a string at the current point
  355.  */
  356. int LOver(ostr)
  357.   char    *ostr;
  358. {
  359.   int    status = TRUE;
  360.   char    tmpc;
  361.  
  362.     if (ostr != NULLCPTR)
  363.     {
  364.         while (((tmpc = *ostr) != NULL) && status == TRUE)
  365.         {
  366.             status = (tmpc == '\n' ? LNewline() : lowrite(tmpc));
  367.  
  368.             /* insertion error? */
  369.             if (status != TRUE)
  370.             {
  371.                 OutOfMem();
  372.                 break;
  373.             }
  374.             ostr++;
  375.         }
  376.     }
  377.     return(status);
  378. }
  379.  
  380. /**
  381.  * Insert a NewLine into the buffer at the current location of dot in the
  382.  * current window. The funny ass-backwards way it does things is not a botch;
  383.  * it just makes the last line in the file not a special case. Return TRUE if
  384.  * everything works out and FALSE on errors (memory allocation failure). The
  385.  * Update of dot and mark is a bit easier then in the above case, because the
  386.  * split forces more updating.
  387.  */
  388. int LNewline()
  389. {
  390.   char        *cp1;
  391.   char        *cp2;
  392.   LINE        *lp1;
  393.   LINE        *lp2;
  394.   short        doto;
  395.   WINDOW    *wp;
  396. #if BMARKS
  397.   int        bmark;
  398. #endif
  399.  
  400.     if (curbp->b_mode & MDVIEW)     /* don't allow this command if */
  401.         return(ReadOnly());            /* we are in read only mode */
  402.     LChange(WFHARD);
  403.     lp1 = curwp->w_dotp;            /* get the address and */
  404.     doto = curwp->w_doto;            /* offset of "." */
  405.     if ((lp2 = LAlloc(doto)) == NULLLPTR)    /* new first half line */
  406.         return(FALSE);
  407.     cp1 = &lp1->l_text[0];            /* shuffle text around */
  408.     cp2 = &lp2->l_text[0];
  409.     while (cp1 != &lp1->l_text[doto])
  410.         *cp2++ = *cp1++;
  411.     cp2 = &lp1->l_text[0];
  412.     while (cp1 != &lp1->l_text[lp1->l_used])
  413.         *cp2++ = *cp1++;
  414.     lp1->l_used -= doto;
  415.     lp2->l_bp = lp1->l_bp;
  416.     lp1->l_bp = lp2;
  417.     lp2->l_bp->l_fp = lp2;
  418.     lp2->l_fp = lp1;
  419.     wp = wheadp;                    /* windows */
  420.     while (wp != NULLWPTR)
  421.     {
  422.         if (wp->w_linep == lp1)
  423.             wp->w_linep = lp2;
  424.         if (wp->w_dotp == lp1)
  425.         {
  426.             if (wp->w_doto < doto)
  427.                 wp->w_dotp = lp2;
  428.             else
  429.                 wp->w_doto -= doto;
  430.         }
  431.         if (wp->w_markp == lp1)
  432.         {
  433.             if (wp->w_marko < doto)
  434.                 wp->w_markp = lp2;
  435.             else
  436.                 wp->w_marko -= doto;
  437.         }
  438.         if (wp->w_anchorp == lp1)
  439.         {
  440.             if (wp->w_anchoro < doto)
  441.                 wp->w_anchorp = lp2;
  442.             else
  443.                 wp->w_anchoro -= doto;
  444.         }
  445. #if BMARKS
  446.         for (bmark = 0; bmark < NBMARKS; bmark++)
  447.         {
  448.             if (wp->w_bmarkp[bmark] == lp1)
  449.             {
  450.                 if (wp->w_bmarko[bmark] < doto)
  451.                     wp->w_bmarkp[bmark] = lp2;
  452.                 else
  453.                     wp->w_bmarko[bmark] -= doto;
  454.             }
  455.         }
  456. #endif
  457.         wp = wp->w_wndp;
  458.     }
  459.     return(TRUE);
  460. }
  461.  
  462. /**
  463.  * This function deletes "n" bytes, starting at dot. It understands how to deal
  464.  * with end of lines, etc. It returns TRUE if all of the characters were
  465.  * deleted, and FALSE if they were not (because dot ran into the end of the
  466.  * buffer). The "kflag" is TRUE if the text should be put in the kill buffer.
  467.  */
  468. int LDelete(n, kflag)
  469.   long        n;            /* # of chars to delete */
  470.   int        kflag;        /* put killed text in kill buffer flag */
  471. {
  472.   char        *cp1;
  473.   char        *cp2;
  474.   LINE        *dotp;
  475.   short        doto;
  476.   int        chunk;
  477.   WINDOW    *wp;
  478. #if BMARKS
  479.   int        bmark;
  480. #endif
  481.  
  482.     if (curbp->b_mode & MDVIEW)         /* don't allow this command if */
  483.         return(ReadOnly());                /* we are in read only mode */
  484.     while (n != 0L)
  485.     {
  486.         dotp = curwp->w_dotp;
  487.         doto = curwp->w_doto;
  488.         if (dotp == curbp->b_linep)     /* hit end of buffer */
  489.             return(FALSE);
  490.         chunk = dotp->l_used - doto;    /* size of chunk */
  491.         if ((long)chunk > n)
  492.             chunk = (int)n;
  493.         if (chunk == 0)                 /* end of line, merge */
  494.         {
  495.             LChange(WFHARD);
  496.             if    (
  497.                         ldelnewline() == FALSE
  498.                     ||
  499.                         (
  500.                                 kflag != FALSE
  501.                             &&
  502.                                 KInsert('\n') == FALSE
  503.                         )
  504.                 )
  505.                 return(FALSE);
  506.             --n;
  507.             continue;
  508.         }
  509.         LChange(WFEDIT);
  510.         cp1 = &dotp->l_text[doto];        /* scrunch text */
  511.         cp2 = cp1 + chunk;
  512.         if (kflag != FALSE)             /* kill? */
  513.         {
  514.             while (cp1 != cp2)
  515.             {
  516.                 if (KInsert(*cp1) == FALSE)
  517.                     return(FALSE);
  518.                 ++cp1;
  519.             }
  520.             cp1 = &dotp->l_text[doto];
  521.         }
  522.         while (cp2 != &dotp->l_text[dotp->l_used])
  523.             *cp1++ = *cp2++;
  524.         dotp->l_used -= chunk;
  525.         wp = wheadp;                    /* fix windows */
  526.         while (wp != NULLWPTR)
  527.         {
  528.             if (wp->w_dotp == dotp && wp->w_doto >= doto)
  529.             {
  530.                 wp->w_doto -= chunk;
  531.                 if (wp->w_doto < doto)
  532.                     wp->w_doto = doto;
  533.             }
  534.             if (wp->w_markp == dotp && wp->w_marko >= doto)
  535.             {
  536.                 wp->w_marko -= chunk;
  537.                 if (wp->w_marko < doto)
  538.                     wp->w_marko = doto;
  539.             }
  540.             if (wp->w_anchorp == dotp && wp->w_anchoro >= doto)
  541.             {
  542.                 wp->w_anchoro -= chunk;
  543.                 if (wp->w_anchoro < doto)
  544.                     wp->w_anchoro = doto;
  545.             }
  546. #if BMARKS
  547.             for (bmark = 0; bmark < NBMARKS; bmark++)
  548.             {
  549.                 if (wp->w_bmarkp[bmark] == dotp && wp->w_bmarko[bmark] >= doto)
  550.                 {
  551.                     wp->w_bmarko[bmark] -= chunk;
  552.                     if (wp->w_bmarko[bmark] < doto)
  553.                         wp->w_bmarko[bmark] = doto;
  554.                 }
  555.             }
  556. #endif
  557.             wp = wp->w_wndp;
  558.         }
  559.         n -= (long)chunk;
  560.     }
  561.     return(TRUE);
  562. }
  563.  
  564. /**
  565.  * Grab and return a string with the text of the current line
  566.  */
  567. char * GetCText()
  568. {
  569.   LINE    *lp;             /* line to copy */
  570.   int    size;            /* length of line to return */
  571.   char    *sp;             /* string pointer into line */
  572.   char    *dp;             /* string pointer into returned line */
  573.  
  574.   static char    rline[NSTRING]; /* line to return */
  575.  
  576.     /* find the contents of the current line and its length */
  577.     lp = curwp->w_dotp;
  578.     sp = lp->l_text;
  579.     size = lp->l_used;
  580.     if (size >= NSTRING)
  581.         size = NSTRING - 1;
  582.  
  583.     /* copy it across */
  584.     dp = rline;
  585.     while (size--)
  586.         *dp++ = *sp++;
  587.     *dp = 0;
  588.     return(rline);
  589. }
  590.  
  591. /**
  592.  * Replace the current line with the passed text
  593.  */
  594. int PutCText(iline)
  595.   char    *iline;                /* contents of new line */
  596. {
  597.   int    status;
  598.  
  599.     /* delete the current line (from the beginning) */
  600.     curwp->w_doto = 0;
  601.     if (!KillText(TRUE, 1))
  602.         return(FALSE);
  603.  
  604.     /* insert the new line */
  605.     if (!LInstr(iline))
  606.         return(FALSE);
  607.  
  608.     status = LNewline();
  609.     BackLine(TRUE, 1);
  610.     return(status);
  611. }
  612.  
  613. /**
  614.  * Delete a NewLine. Join the current line with the next line. If the next line
  615.  * is the magic header line always return TRUE; merging the last line with the
  616.  * header line can be thought of as always being a successful operation, even
  617.  * if nothing is done, and this makes the kill buffer work "right". Easy cases
  618.  * can be done by shuffling data around. Hard cases require that lines be moved
  619.  * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  620.  * "LDelete" only, so we don't need to check for MDVIEW.
  621.  */
  622. static int near ldelnewline()
  623. {
  624.   char        *cp1;
  625.   char        *cp2;
  626.   LINE        *lp1;
  627.   LINE        *lp2;
  628.   LINE        *lp3;
  629.   WINDOW    *wp;
  630. #if BMARKS
  631.   int        bmark;
  632. #endif
  633.  
  634.     lp1 = curwp->w_dotp;
  635.     lp2 = lp1->l_fp;
  636.     if (lp2 == curbp->b_linep)    /* at the buffer end */
  637.     {
  638.         if (lp1->l_used == 0)    /* blank line */
  639.             LFree(lp1);
  640.         return(TRUE);
  641.     }
  642.     if (lp2->l_used <= lp1->l_size - lp1->l_used)
  643.     {
  644.         cp1 = &lp1->l_text[lp1->l_used];
  645.         cp2 = &lp2->l_text[0];
  646.         while (cp2 != &lp2->l_text[lp2->l_used])
  647.             *cp1++ = *cp2++;
  648.         wp = wheadp;
  649.         while (wp != NULLWPTR)
  650.         {
  651.             if (wp->w_linep == lp2)
  652.                 wp->w_linep = lp1;
  653.             if (wp->w_dotp == lp2)
  654.             {
  655.                 wp->w_dotp = lp1;
  656.                 wp->w_doto += lp1->l_used;
  657.             }
  658.             if (wp->w_markp == lp2)
  659.             {
  660.                 wp->w_markp = lp1;
  661.                 wp->w_marko += lp1->l_used;
  662.             }
  663.             if (wp->w_anchorp == lp2)
  664.             {
  665.                 wp->w_anchorp = lp1;
  666.                 wp->w_anchoro += lp1->l_used;
  667.             }
  668. #if BMARKS
  669.             for (bmark = 0; bmark < NBMARKS; bmark++)
  670.             {
  671.                 if (wp->w_bmarkp[bmark] == lp2)
  672.                 {
  673.                     wp->w_bmarkp[bmark] = lp1;
  674.                     wp->w_bmarko[bmark] += lp1->l_used;
  675.                 }
  676.             }
  677. #endif
  678.             wp = wp->w_wndp;
  679.         }
  680.         lp1->l_used += lp2->l_used;
  681.         lp1->l_fp = lp2->l_fp;
  682.         lp2->l_fp->l_bp = lp1;
  683.         free((char *)lp2);
  684.         return(TRUE);
  685.     }
  686.     if ((lp3 = LAlloc(lp1->l_used + lp2->l_used)) == NULLLPTR)
  687.         return(FALSE);
  688.     cp1 = &lp1->l_text[0];
  689.     cp2 = &lp3->l_text[0];
  690.     while (cp1 != &lp1->l_text[lp1->l_used])
  691.         *cp2++ = *cp1++;
  692.     cp1 = &lp2->l_text[0];
  693.     while (cp1 != &lp2->l_text[lp2->l_used])
  694.         *cp2++ = *cp1++;
  695.     lp1->l_bp->l_fp = lp3;
  696.     lp3->l_fp = lp2->l_fp;
  697.     lp2->l_fp->l_bp = lp3;
  698.     lp3->l_bp = lp1->l_bp;
  699.     wp = wheadp;
  700.     while (wp != NULLWPTR)
  701.     {
  702.         if (wp->w_linep == lp1 || wp->w_linep == lp2)
  703.             wp->w_linep = lp3;
  704.         if (wp->w_dotp == lp1)
  705.             wp->w_dotp = lp3;
  706.         else if (wp->w_dotp == lp2)
  707.         {
  708.             wp->w_dotp = lp3;
  709.             wp->w_doto += lp1->l_used;
  710.         }
  711.         if (wp->w_markp == lp1)
  712.             wp->w_markp = lp3;
  713.         else if (wp->w_markp == lp2)
  714.         {
  715.             wp->w_markp = lp3;
  716.             wp->w_marko += lp1->l_used;
  717.         }
  718.         if (wp->w_anchorp == lp1)
  719.             wp->w_anchorp = lp3;
  720.         else if (wp->w_anchorp == lp2)
  721.         {
  722.             wp->w_anchorp = lp3;
  723.             wp->w_anchoro += lp1->l_used;
  724.         }
  725. #if BMARKS
  726.         for (bmark = 0; bmark < NBMARKS; bmark++)
  727.         {
  728.             if (wp->w_bmarkp[bmark] == lp1)
  729.                 wp->w_bmarkp[bmark] = lp3;
  730.             else if (wp->w_bmarkp[bmark] == lp2)
  731.             {
  732.                 wp->w_bmarkp[bmark] = lp3;
  733.                 wp->w_bmarko[bmark] += lp1->l_used;
  734.             }
  735.         }
  736. #endif
  737.         wp = wp->w_wndp;
  738.     }
  739.     free((char *)lp1);
  740.     free((char *)lp2);
  741.     return(TRUE);
  742. }
  743.  
  744. /**
  745.  * Delete all of the text saved in the kill buffer. Called by commands when a
  746.  * new kill context is being created. The kill buffer array is released, just
  747.  * in case the buffer has grown to immense size. No errors.
  748.  */
  749. int KDelete()
  750. {
  751.   KILL    *kp;         /* ptr to scan kill buffer chunk list */
  752.  
  753.     if (kbufh != NULLKPTR)
  754.     {
  755.         /* first, delete all the chunks */
  756.         kbufp = kbufh;
  757.         while (kbufp != NULLKPTR)
  758.         {
  759.             kp = kbufp->d_next;
  760.             free(kbufp);
  761.             kbufp = kp;
  762.         }
  763.  
  764.         /* and reset all the kill buffer pointers */
  765.         kbufh = kbufp = NULLKPTR;
  766.         kused = KBLOCK;                 /* force malloc of new KILL block */
  767.     }
  768.     return(TRUE);
  769. }
  770.  
  771. /**
  772.  * Insert a character to the kill buffer, allocating new chunks as needed.
  773.  * Return TRUE if all is well, and FALSE on errors.
  774.  */
  775. int KInsert(c)
  776.   int    c;            /* character to insert in the kill buffer */
  777. {
  778.   KILL    *nchunk;     /* ptr to newly malloc'd chunk */
  779.  
  780.     /* check to see if we need a new chunk */
  781.     if (kused >= KBLOCK)
  782.     {
  783.         if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULLKPTR)
  784.             return(FALSE);
  785.         if (kbufh == NULLKPTR)        /* set head ptr if first time */
  786.             kbufh = nchunk;
  787.         if (kbufp != NULLKPTR)        /* point the current to this new one */
  788.             kbufp->d_next = nchunk;
  789.         kbufp = nchunk;
  790.         kbufp->d_next = NULLKPTR;
  791.         kused = 0;
  792.     }
  793.  
  794.     /* and now insert the character */
  795.     kbufp->d_chunk[kused++] = (char)c;
  796.     return(TRUE);
  797. }
  798.  
  799. /**
  800.  * Yank text back from the kill buffer. This is really easy. All of the work
  801.  * is done by the standard insert routines. All you do is run the loop, and
  802.  * check for errors.
  803.  */
  804. int Yank(f, n)
  805.   int    f;
  806.   int    n;
  807. {
  808.   int    c;
  809.   int    i;
  810.   char    *sp;             /* pointer into string to insert */
  811.   KILL    *kp;             /* pointer into kill buffer */
  812.  
  813.     if (curbp->b_mode & MDVIEW) /* don't allow this command if */
  814.         return(ReadOnly());        /* we are in read only mode */
  815.     if (n < 0)
  816.         return(FALSE);
  817.     /* make sure there is something to Yank */
  818.     if (kbufh == NULLKPTR)
  819.         return(TRUE);            /* not an error, just nothing */
  820.  
  821.     /* for each time */
  822.     while (n--)
  823.     {
  824.         kp = kbufh;
  825.         while (kp != NULLKPTR)
  826.         {
  827.             if (kp->d_next == NULLKPTR)
  828.                 i = kused;        /* last KILL block, so only 'kused' full */
  829.             else
  830.                 i = KBLOCK;        /* not the last, so it must be full */
  831.             sp = kp->d_chunk;
  832.             while (i--)
  833.             {
  834.                 if ((c = *sp++) == '\n')
  835.                 {
  836.                     if (LNewline() == FALSE)
  837.                         return(FALSE);
  838.                 }
  839.                 else
  840.                 {
  841.                     if (LInsert(1, c) == FALSE)
  842.                         return(FALSE);
  843.                 }
  844.             }
  845.             kp = kp->d_next;
  846.         }
  847.     }
  848.     return(TRUE);
  849. }
  850.