home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d131 / mg1b.lha / Mg1b / Source / line.c < prev    next >
C/C++ Source or Header  |  1988-03-14  |  16KB  |  613 lines

  1. /*
  2.  *        Text line handling.
  3.  * The functions in this file
  4.  * are a general set of line management
  5.  * utilities. They are the only routines that
  6.  * touch the text. They also touch the buffer
  7.  * and window structures, to make sure that the
  8.  * necessary updating gets done. There are routines
  9.  * in this file that handle the kill buffer too.
  10.  * It isn't here for any good reason.
  11.  *
  12.  * Note that this code only updates the dot and
  13.  * mark values in the window list. Since all the code
  14.  * acts on the current window, the buffer that we
  15.  * are editing must be being displayed, which means
  16.  * that "b_nwnd" is non zero, which means that the
  17.  * dot and mark values in the buffer headers are
  18.  * nonsense.
  19.  */
  20. #include    "def.h"
  21.  
  22. #define    NBLOCK    16            /* Line block chunk size    */
  23.  
  24. #ifndef    KBLOCK
  25. #define    KBLOCK    256            /* Kill buffer block size.    */
  26. #endif
  27.  
  28. static char    *kbufp    = NULL;        /* Kill buffer data.        */
  29. static RSIZE    kused    = 0;        /* # of bytes used in KB.    */
  30. static RSIZE    ksize    = 0;        /* # of bytes allocated in KB.    */
  31. static RSIZE    kstart  = 0;        /* # of first used byte in KB.    */
  32. char    *malloc();
  33. /*
  34.  * This routine allocates a block
  35.  * of memory large enough to hold a LINE
  36.  * containing "used" characters. The block is
  37.  * always rounded up a bit. Return a pointer
  38.  * to the new block, or NULL if there isn't
  39.  * any memory left. Print a message in the
  40.  * message line if no space.
  41.  */
  42. LINE    *
  43. lalloc(used) register RSIZE used; {
  44.     register LINE    *lp;
  45.     register int    size;
  46.  
  47.     /*NOSTRICT*/
  48.     size = (NBLOCK-1+used) & ~(NBLOCK-1);
  49.     if (size == 0)                /* Assume that an empty    */
  50.         size = NBLOCK;            /* line is for type-in.    */
  51.     /*NOSTRICT*/
  52.     if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) {
  53.         ewprintf("Can't get %d bytes", sizeof(LINE) + size);
  54.         return (NULL);
  55.     }
  56.     lp->l_size = size;
  57.     /*NOSTRICT*/
  58.     lp->l_used = used;
  59.     return (lp);
  60. }
  61.  
  62. /*
  63.  * Delete line "lp". Fix all of the
  64.  * links that might point at it (they are
  65.  * moved to offset 0 of the next line.
  66.  * Unlink the line from whatever buffer it
  67.  * might be in. Release the memory. The
  68.  * buffers are updated too; the magic conditions
  69.  * described in the above comments don't hold
  70.  * here.
  71.  */
  72. VOID
  73. lfree(lp) register LINE *lp; {
  74.     register BUFFER    *bp;
  75.     register WINDOW    *wp;
  76.  
  77.     wp = wheadp;
  78.     while (wp != NULL) {
  79.         if (wp->w_linep == lp)
  80.             wp->w_linep = lp->l_fp;
  81.         if (wp->w_dotp  == lp) {
  82.             wp->w_dotp  = lp->l_fp;
  83.             wp->w_doto  = 0;
  84.         }
  85.         if (wp->w_markp == lp) {
  86.             wp->w_markp = lp->l_fp;
  87.             wp->w_marko = 0;
  88.         }
  89.         wp = wp->w_wndp;
  90.     }
  91.     bp = bheadp;
  92.     while (bp != NULL) {
  93.         if (bp->b_nwnd == 0) {
  94.             if (bp->b_dotp  == lp) {
  95.                 bp->b_dotp = lp->l_fp;
  96.                 bp->b_doto = 0;
  97.             }
  98.             if (bp->b_markp == lp) {
  99.                 bp->b_markp = lp->l_fp;
  100.                 bp->b_marko = 0;
  101.             }
  102.         }
  103.         bp = bp->b_bufp;
  104.     }
  105.     lp->l_bp->l_fp = lp->l_fp;
  106.     lp->l_fp->l_bp = lp->l_bp;
  107.     free((char *) lp);
  108. }
  109.  
  110. /*
  111.  * This routine gets called when
  112.  * a character is changed in place in the
  113.  * current buffer. It updates all of the required
  114.  * flags in the buffer and window system. The flag
  115.  * used is passed as an argument; if the buffer is being
  116.  * displayed in more than 1 window we change EDIT to
  117.  * HARD. Set MODE if the mode line needs to be
  118.  * updated (the "*" has to be set).
  119.  * Modified by Walter Bright to reduce update times.
  120.  */
  121. VOID
  122. lchange(flag) register int flag; {
  123.     register WINDOW    *wp;
  124.  
  125.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so     */
  126.         flag |= WFMODE;            /* update mode lines.    */
  127.         curbp->b_flag |= BFCHG;
  128.     }
  129.     wp = wheadp;
  130.     while (wp != NULL) {
  131.         if (wp->w_bufp == curbp) {
  132.             wp->w_flag |= flag;
  133.             if (wp != curwp) wp->w_flag |= WFHARD;
  134.             }
  135.         wp = wp->w_wndp;
  136.     }
  137. }
  138.  
  139. /*
  140.  * Insert "n" copies of the character "c"
  141.  * at the current location of dot. In the easy case
  142.  * all that happens is the text is stored in the line.
  143.  * In the hard case, the line has to be reallocated.
  144.  * When the window list is updated, take special
  145.  * care; I screwed it up once. You always update dot
  146.  * in the current window. You update mark, and a
  147.  * dot in another window, if it is greater than
  148.  * the place where you did the insert. Return TRUE
  149.  * if all is well, and FALSE on errors.
  150.  */
  151. linsert(n, c) RSIZE n; {
  152.     register char    *cp1;
  153.     register char    *cp2;
  154.     register LINE    *lp1;
  155.     LINE        *lp2;
  156.     LINE        *lp3;
  157.     register int    doto;
  158.     register RSIZE    i;
  159.     WINDOW        *wp;
  160.  
  161.     lchange(WFEDIT);
  162.     lp1 = curwp->w_dotp;            /* Current line        */
  163.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  164.         if (curwp->w_doto != 0) {
  165.             ewprintf("bug: linsert");
  166.             return (FALSE);
  167.         }
  168.         if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  169.             return (FALSE);
  170.         lp3 = lp1->l_bp;        /* Previous line    */
  171.         lp3->l_fp = lp2;        /* Link in        */
  172.         lp2->l_fp = lp1;
  173.         lp1->l_bp = lp2;
  174.         lp2->l_bp = lp3;
  175.         for (i=0; i<n; ++i)
  176.             lp2->l_text[i] = c;
  177.         wp = wheadp;            /* Update windows    */
  178.         while (wp != NULL) {
  179.             if (wp->w_linep == lp1)
  180.                 wp->w_linep = lp2;
  181.             if (wp->w_dotp == lp1)
  182.                 wp->w_dotp = lp2;
  183.             if (wp->w_markp == lp1)
  184.                 wp->w_markp = lp2;
  185.             wp = wp->w_wndp;
  186.         }
  187.         /*NOSTRICT*/
  188.         curwp->w_doto = n;
  189.         return (TRUE);
  190.     }
  191.     doto = curwp->w_doto;            /* Save for later.    */
  192.     /*NOSTRICT (2) */
  193.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  194.         if ((lp2=lalloc((RSIZE) (lp1->l_used+n))) == NULL)
  195.             return (FALSE);
  196.         cp1 = &lp1->l_text[0];
  197.         cp2 = &lp2->l_text[0];
  198.         while (cp1 != &lp1->l_text[doto])
  199.             *cp2++ = *cp1++;
  200.         /*NOSTRICT*/
  201.         cp2 += n;
  202.         while (cp1 != &lp1->l_text[lp1->l_used])
  203.             *cp2++ = *cp1++;
  204.         lp1->l_bp->l_fp = lp2;
  205.         lp2->l_fp = lp1->l_fp;
  206.         lp1->l_fp->l_bp = lp2;
  207.         lp2->l_bp = lp1->l_bp;
  208.         free((char *) lp1);
  209.     } else {                /* Easy: in place    */
  210.         lp2 = lp1;            /* Pretend new line    */
  211.         /*NOSTRICT*/
  212.         lp2->l_used += n;
  213.         cp2 = &lp1->l_text[lp1->l_used];
  214.  
  215.         cp1 = cp2-n;
  216.         while (cp1 != &lp1->l_text[doto])
  217.             *--cp2 = *--cp1;
  218.     }
  219.     for (i=0; i<n; ++i)            /* Add the characters    */
  220.         lp2->l_text[doto+i] = c;
  221.     wp = wheadp;                /* Update windows    */
  222.     while (wp != NULL) {
  223.         if (wp->w_linep == lp1)
  224.             wp->w_linep = lp2;
  225.         if (wp->w_dotp == lp1) {
  226.             wp->w_dotp = lp2;
  227.             if (wp==curwp || wp->w_doto>doto)
  228.                 /*NOSTRICT*/
  229.                 wp->w_doto += n;
  230.         }
  231.         if (wp->w_markp == lp1) {
  232.             wp->w_markp = lp2;
  233.             if (wp->w_marko > doto)
  234.                 /*NOSTRICT*/
  235.                 wp->w_marko += n;
  236.         }
  237.         wp = wp->w_wndp;
  238.     }
  239.     return (TRUE);
  240. }
  241.  
  242. /*
  243.  * Insert a newline into the buffer
  244.  * at the current location of dot in the current
  245.  * window. The funny ass-backwards way it does things
  246.  * is not a botch; it just makes the last line in
  247.  * the file not a special case. Return TRUE if everything
  248.  * works out and FALSE on error (memory allocation
  249.  * failure). The update of dot and mark is a bit
  250.  * easier then in the above case, because the split
  251.  * forces more updating.
  252.  */
  253. lnewline() {
  254.     register char    *cp1;
  255.     register char    *cp2;
  256.     register LINE    *lp1;
  257.     LINE        *lp2;
  258.     register int    doto;
  259.     WINDOW        *wp;
  260.  
  261.     lchange(WFHARD);
  262.     lp1  = curwp->w_dotp;            /* Get the address and    */
  263.     doto = curwp->w_doto;            /* offset of "."    */
  264.     if ((lp2=lalloc((RSIZE) doto)) == NULL)    /* New first half line    */
  265.         return (FALSE);
  266.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  267.     cp2 = &lp2->l_text[0];
  268.     while (cp1 != &lp1->l_text[doto])
  269.         *cp2++ = *cp1++;
  270.     cp2 = &lp1->l_text[0];
  271.     while (cp1 != &lp1->l_text[lp1->l_used])
  272.         *cp2++ = *cp1++;
  273.     lp1->l_used -= doto;
  274.     lp2->l_bp = lp1->l_bp;
  275.     lp1->l_bp = lp2;
  276.     lp2->l_bp->l_fp = lp2;
  277.     lp2->l_fp = lp1;
  278.     wp = wheadp;                /* Windows        */
  279.     while (wp != NULL) {
  280.         if (wp->w_linep == lp1)
  281.             wp->w_linep = lp2;
  282.         if (wp->w_dotp == lp1) {
  283.             if (wp->w_doto < doto)
  284.                 wp->w_dotp = lp2;
  285.             else
  286.                 wp->w_doto -= doto;
  287.         }
  288.         if (wp->w_markp == lp1) {
  289.             if (wp->w_marko < doto)
  290.                 wp->w_markp = lp2;
  291.             else
  292.                 wp->w_marko -= doto;
  293.         }
  294.         wp = wp->w_wndp;
  295.     }    
  296.     return (TRUE);
  297. }
  298.  
  299. /*
  300.  * This function deletes "n" bytes,
  301.  * starting at dot. It understands how do deal
  302.  * with end of lines, etc. It returns TRUE if all
  303.  * of the characters were deleted, and FALSE if
  304.  * they were not (because dot ran into the end of
  305.  * the buffer. The "kflag" indicates either no insertion,
  306.  * or direction of insertion into the kill buffer.
  307.  */
  308. ldelete(n, kflag) RSIZE n; {
  309.     register char    *cp1;
  310.     register char    *cp2;
  311.     register LINE    *dotp;
  312.     register int    doto;
  313.     register RSIZE    chunk;
  314.     WINDOW        *wp;
  315.  
  316.     /*
  317.      * HACK - doesn't matter, and fixes back-over-nl bug for empty
  318.      *    kill buffers.
  319.      */
  320.     if (kused == kstart) kflag = KFORW;
  321.  
  322.     while (n != 0) {
  323.         dotp = curwp->w_dotp;
  324.         doto = curwp->w_doto;
  325.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  326.             return (FALSE);
  327.         chunk = dotp->l_used-doto;    /* Size of chunk.    */
  328.         if (chunk > n)
  329.             chunk = n;
  330.         if (chunk == 0) {        /* End of line, merge.    */
  331.             lchange(WFHARD);
  332.             if (ldelnewline() == FALSE
  333.             || (kflag!=KNONE && kinsert('\n', kflag)==FALSE))
  334.                 return (FALSE);
  335.             --n;
  336.             continue;
  337.         }
  338.         lchange(WFEDIT);
  339.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  340.         cp2 = cp1 + chunk;
  341.         if (kflag == KFORW) {
  342.             while (ksize - kused < chunk)
  343.                 if (kgrow(FALSE) == FALSE) return FALSE;
  344.             bcopy(cp1, &(kbufp[kused]), (int) chunk);
  345.             kused += chunk;
  346.         } else if (kflag == KBACK) {
  347.             while (kstart < chunk)
  348.                 if (kgrow(TRUE) == FALSE) return FALSE;
  349.             bcopy(cp1, &(kbufp[kstart-chunk]), (int) chunk);
  350.             kstart -= chunk;
  351.         } else if (kflag != KNONE) panic("broken ldelete call");
  352.         while (cp2 != &dotp->l_text[dotp->l_used])
  353.             *cp1++ = *cp2++;
  354.         dotp->l_used -= (int) chunk;
  355.         wp = wheadp;            /* Fix windows        */
  356.         while (wp != NULL) {
  357.             if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  358.                 /*NOSTRICT*/
  359.                 wp->w_doto -= chunk;
  360.                 if (wp->w_doto < doto)
  361.                     wp->w_doto = doto;
  362.             }    
  363.             if (wp->w_markp==dotp && wp->w_marko>=doto) {
  364.                 /*NOSTRICT*/
  365.                 wp->w_marko -= chunk;
  366.                 if (wp->w_marko < doto)
  367.                     wp->w_marko = doto;
  368.             }
  369.             wp = wp->w_wndp;
  370.         }
  371.         n -= chunk;
  372.     }
  373.     return (TRUE);
  374. }
  375.  
  376. /*
  377.  * Delete a newline. Join the current line
  378.  * with the next line. If the next line is the magic
  379.  * header line always return TRUE; merging the last line
  380.  * with the header line can be thought of as always being a
  381.  * successful operation, even if nothing is done, and this makes
  382.  * the kill buffer work "right". Easy cases can be done by
  383.  * shuffling data around. Hard cases require that lines be moved
  384.  * about in memory. Return FALSE on error and TRUE if all
  385.  * looks ok.
  386.  */
  387. ldelnewline() {
  388.     register char    *cp1;
  389.     register char    *cp2;
  390.     register LINE    *lp1;
  391.     LINE        *lp2;
  392.     LINE        *lp3;
  393.     WINDOW        *wp;
  394.  
  395.     lp1 = curwp->w_dotp;
  396.     lp2 = lp1->l_fp;
  397.     if (lp2 == curbp->b_linep) {        /* At the buffer end.    */
  398.         if (lp1->l_used == 0)        /* Blank line.        */
  399.             lfree(lp1);
  400.         return (TRUE);
  401.     }
  402.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  403.         cp1 = &lp1->l_text[lp1->l_used];
  404.         cp2 = &lp2->l_text[0];
  405.         while (cp2 != &lp2->l_text[lp2->l_used])
  406.             *cp1++ = *cp2++;
  407.         wp = wheadp;
  408.         while (wp != NULL) {
  409.             if (wp->w_linep == lp2)
  410.                 wp->w_linep = lp1;
  411.             if (wp->w_dotp == lp2) {
  412.                 wp->w_dotp  = lp1;
  413.                 wp->w_doto += lp1->l_used;
  414.             }
  415.             if (wp->w_markp == lp2) {
  416.                 wp->w_markp  = lp1;
  417.                 wp->w_marko += lp1->l_used;
  418.             }
  419.             wp = wp->w_wndp;
  420.         }        
  421.         lp1->l_used += lp2->l_used;
  422.         lp1->l_fp = lp2->l_fp;
  423.         lp2->l_fp->l_bp = lp1;
  424.         free((char *) lp2);
  425.         return (TRUE);
  426.     }
  427.     if ((lp3=lalloc((RSIZE) (lp1->l_used+lp2->l_used))) == NULL)
  428.         return (FALSE);
  429.     cp1 = &lp1->l_text[0];
  430.     cp2 = &lp3->l_text[0];
  431.     while (cp1 != &lp1->l_text[lp1->l_used])
  432.         *cp2++ = *cp1++;
  433.     cp1 = &lp2->l_text[0];
  434.     while (cp1 != &lp2->l_text[lp2->l_used])
  435.         *cp2++ = *cp1++;
  436.     lp1->l_bp->l_fp = lp3;
  437.     lp3->l_fp = lp2->l_fp;
  438.     lp2->l_fp->l_bp = lp3;
  439.     lp3->l_bp = lp1->l_bp;
  440.     wp = wheadp;
  441.     while (wp != NULL) {
  442.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  443.             wp->w_linep = lp3;
  444.         if (wp->w_dotp == lp1)
  445.             wp->w_dotp  = lp3;
  446.         else if (wp->w_dotp == lp2) {
  447.             wp->w_dotp  = lp3;
  448.             wp->w_doto += lp1->l_used;
  449.         }
  450.         if (wp->w_markp == lp1)
  451.             wp->w_markp  = lp3;
  452.         else if (wp->w_markp == lp2) {
  453.             wp->w_markp  = lp3;
  454.             wp->w_marko += lp1->l_used;
  455.         }
  456.         wp = wp->w_wndp;
  457.     }
  458.     free((char *) lp1);
  459.     free((char *) lp2);
  460.     return (TRUE);
  461. }
  462.  
  463. /*
  464.  * Replace plen characters before dot with argument string.
  465.  * Control-J characters in st are interpreted as newlines.
  466.  * There is a casehack disable flag (normally it likes to match
  467.  * case of replacement to what was there).
  468.  */
  469. lreplace(plen, st, f)
  470. register RSIZE    plen;            /* length to remove        */
  471. char        *st;            /* replacement string        */
  472. int        f;            /* case hack disable        */
  473. {
  474.     register RSIZE    rlen;        /* replacement length        */
  475.     register int    rtype;        /* capitalization         */
  476.     register int    c;        /* used for random characters    */
  477.     register int    doto;        /* offset into line        */
  478.  
  479.     /*
  480.      * Find the capitalization of the word that was found.
  481.      * f says use exact case of replacement string (same thing that
  482.      * happens with lowercase found), so bypass check.
  483.      */
  484.     /*NOSTRICT*/
  485.     (VOID) backchar(TRUE, (int) plen, KRANDOM);
  486.     rtype = _L;
  487.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  488.     if (ISUPPER(c)!=FALSE  &&  f==FALSE) {
  489.         rtype = _U|_L;
  490.         if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
  491.             c = lgetc(curwp->w_dotp, curwp->w_doto+1);
  492.             if (ISUPPER(c) != FALSE) {
  493.                 rtype = _U;
  494.             }
  495.         }
  496.     }
  497.  
  498.     /*
  499.      * make the string lengths match (either pad the line
  500.      * so that it will fit, or scrunch out the excess).
  501.      * be careful with dot's offset.
  502.      */
  503.     rlen = strlen(st);
  504.     doto = curwp->w_doto;
  505.     if (plen > rlen)
  506.         (VOID) ldelete((RSIZE) (plen-rlen), KNONE);
  507.     else if (plen < rlen) {
  508.         if (linsert((RSIZE) (rlen-plen), ' ') == FALSE)
  509.             return (FALSE);
  510.     }
  511.     curwp->w_doto = doto;
  512.  
  513.     /*
  514.      * do the replacement:  If was capital, then place first 
  515.      * char as if upper, and subsequent chars as if lower.  
  516.      * If inserting upper, check replacement for case.
  517.      */
  518.     while ((c = *st++&0xff) != '\0') {
  519.         if ((rtype&_U)!=0  &&  ISLOWER(c)!=0)
  520.             c = TOUPPER(c);
  521.         if (rtype == (_U|_L))
  522.             rtype = _L;
  523.         if (c == SEOL) {
  524.             if (curwp->w_doto == llength(curwp->w_dotp))
  525.                 (VOID) forwchar(FALSE, 1, KRANDOM);
  526.             else {
  527.                 if (ldelete((RSIZE) 1, KNONE) != FALSE)
  528.                     (VOID) lnewline();
  529.             }
  530.         } else if (curwp->w_dotp == curbp->b_linep) {
  531.             (VOID) linsert((RSIZE) 1, c);
  532.         } else if (curwp->w_doto == llength(curwp->w_dotp)) {
  533.             if (ldelete((RSIZE) 1, KNONE) != FALSE)
  534.                 (VOID) linsert((RSIZE) 1, c);
  535.         } else
  536.             lputc(curwp->w_dotp, curwp->w_doto++, c);
  537.     }
  538.     lchange(WFHARD);
  539.     return (TRUE);
  540. }
  541.  
  542. /*
  543.  * Delete all of the text
  544.  * saved in the kill buffer. Called by commands
  545.  * when a new kill context is being created. The kill
  546.  * buffer array is released, just in case the buffer has
  547.  * grown to immense size. No errors.
  548.  */
  549. VOID
  550. kdelete() {
  551.     if (kbufp != NULL) {
  552.         free((char *) kbufp);
  553.         kbufp = NULL;
  554.         kstart = kused = ksize = 0;
  555.     }
  556. }
  557.  
  558. /*
  559.  * Insert a character to the kill buffer,
  560.  * enlarging the buffer if there isn't any room. Always
  561.  * grow the buffer in chunks, on the assumption that if you
  562.  * put something in the kill buffer you are going to put
  563.  * more stuff there too later. Return TRUE if all is
  564.  * well, and FALSE on errors. Print a message on
  565.  * errors. Dir says whether to put it at back or front.
  566.  */
  567. kinsert(c, dir) {
  568.  
  569.     if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
  570.         return FALSE;
  571.     if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
  572.         return FALSE;
  573.     if (dir == KFORW) kbufp[kused++] = c;
  574.     else if (dir == KBACK) kbufp[--kstart] = c;
  575.     else panic("broken kinsert call");        /* Oh shit! */
  576.     return (TRUE);
  577. }
  578.  
  579. /*
  580.  * kgrow - just get more kill buffer for the callee. back is true if
  581.  * we are trying to get space at the beginning of the kill buffer.
  582.  */
  583. kgrow(back) {
  584.     register int    nstart;
  585.     register char    *nbufp;
  586.  
  587.     if ((nbufp=malloc((int)(ksize+KBLOCK))) == NULL) {
  588.         ewprintf("Can't get %ld bytes", (long)(ksize+KBLOCK));
  589.         return (FALSE);
  590.     }
  591.     nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ;
  592.     bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int) (kused-kstart));
  593.     if (kbufp != NULL)
  594.         free((char *) kbufp);
  595.     kbufp  = nbufp;
  596.     ksize += KBLOCK;
  597.     kused = kused - kstart + nstart;
  598.     kstart = nstart;
  599.     return TRUE;
  600. }
  601.  
  602. /*
  603.  * This function gets characters from
  604.  * the kill buffer. If the character index "n" is
  605.  * off the end, it returns "-1". This lets the caller
  606.  * just scan along until it gets a "-1" back.
  607.  */
  608. kremove(n) {
  609.     if (n < 0 || n + kstart >= kused)
  610.         return (-1);
  611.     return (kbufp[n + kstart] & 0xFF);
  612. }
  613.