home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / pico / line.c < prev    next >
C/C++ Source or Header  |  1998-04-02  |  18KB  |  760 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: line.c,v 4.20 1998/04/02 05:59:44 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Line management routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1998 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  */
  30. /*
  31.  * The functions in this file are a general set of line management utilities.
  32.  * They are the only routines that touch the text. They also touch the buffer
  33.  * and window structures, to make sure that the necessary updating gets done.
  34.  * There are routines in this file that handle the kill buffer too. It isn't
  35.  * here for any good reason.
  36.  *
  37.  * Note that this code only updates the dot and mark values in the window list.
  38.  * Since all the code acts on the current window, the buffer that we are
  39.  * editing must be being displayed, which means that "b_nwnd" is non zero,
  40.  * which means that the dot and mark values in the buffer headers are nonsense.
  41.  */
  42.  
  43. #include    "headers.h"
  44.  
  45. #define NBLOCK    16                      /* Line block chunk size        */
  46. #define KBLOCK  1024                    /* Kill buffer block size       */
  47.  
  48.  
  49. /*
  50.  * Struct to manage the kill and justify buffers
  51.  */
  52. struct pkchunk {
  53.     short        used;        /* # of bytes used in this buffer*/
  54.     char        bufp[KBLOCK];    /* buffer containing text        */
  55.     struct pkchunk *next;        /* pointer to next chunk     */
  56. };
  57.  
  58. static struct pkbuf {
  59.     long        total;        /* # of bytes used in buffer     */
  60.     struct pkchunk *first;        /* first one of these in the chain */
  61.     struct pkchunk *last;        /* last one of these in the chain */
  62. } *kbufp, *fbufp;
  63.  
  64.  
  65. #ifdef    ANSI
  66.     int insspace(int, int);
  67.     int ldelnewline(void);
  68.     int pkbufdel(struct pkbuf **);
  69.     void pkchunkdel(struct pkchunk **);
  70.     int pkbufinsert(int, struct pkbuf **);
  71.     int pkbufremove(int, struct pkbuf *);
  72. #else
  73.     int insspace();
  74.     int ldelnewline();
  75.     int pkbufdel();
  76.     void pkchunkdel();
  77.     int pkbufinsert();
  78.     int pkbufremove();
  79. #endif
  80.  
  81.  
  82. /*
  83.  * This routine allocates a block of memory large enough to hold a LINE
  84.  * containing "used" characters. The block is always rounded up a bit. Return
  85.  * a pointer to the new block, or NULL if there isn't any memory left. Print a
  86.  * message in the message line if no space.
  87.  */
  88. LINE    *
  89. lalloc(used)
  90. register int    used;
  91. {
  92.     register LINE   *lp;
  93.     register int    size;
  94.  
  95.     size = (used+NBLOCK-1) & ~(NBLOCK-1);
  96.     if (size == 0)                          /* Assume that an empty */
  97.       size = NBLOCK;                  /* line is for type-in. */
  98.  
  99.     if ((lp = (LINE *) malloc(sizeof(LINE)+(size*sizeof(CELL)))) == NULL) {
  100.     emlwrite("Cannot allocate %d bytes", (void *)size);
  101.     return (NULL);
  102.     }
  103.  
  104.     lp->l_size = size;
  105.     lp->l_used = used;
  106.     return (lp);
  107. }
  108.  
  109. /*
  110.  * Delete line "lp". Fix all of the links that might point at it (they are
  111.  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  112.  * might be in. Release the memory. The buffers are updated too; the magic
  113.  * conditions described in the above comments don't hold here.
  114.  */
  115. lfree(lp)
  116. register LINE   *lp;
  117. {
  118.     register BUFFER *bp;
  119.     register WINDOW *wp;
  120.  
  121.     wp = wheadp;
  122.     while (wp != NULL) {
  123.     if (wp->w_linep == lp)
  124.       wp->w_linep = lp->l_fp;
  125.  
  126.     if (wp->w_dotp  == lp) {
  127.         wp->w_dotp  = lp->l_fp;
  128.         wp->w_doto  = 0;
  129.     }
  130.  
  131.     if (wp->w_markp == lp) {
  132.         wp->w_markp = lp->l_fp;
  133.         wp->w_marko = 0;
  134.     }
  135.  
  136.     wp = wp->w_wndp;
  137.     }
  138.  
  139.     bp = bheadp;
  140.     while (bp != NULL) {
  141.     if (bp->b_nwnd == 0) {
  142.         if (bp->b_dotp  == lp) {
  143.         bp->b_dotp = lp->l_fp;
  144.         bp->b_doto = 0;
  145.         }
  146.  
  147.         if (bp->b_markp == lp) {
  148.         bp->b_markp = lp->l_fp;
  149.         bp->b_marko = 0;
  150.         }
  151.     }
  152.  
  153.     bp = bp->b_bufp;
  154.     }
  155.  
  156.     lp->l_bp->l_fp = lp->l_fp;
  157.     lp->l_fp->l_bp = lp->l_bp;
  158.     free((char *) lp);
  159. }
  160.  
  161.  
  162. /*
  163.  * This routine gets called when a character is changed in place in the current
  164.  * buffer. It updates all of the required flags in the buffer and window
  165.  * system. The flag used is passed as an argument; if the buffer is being
  166.  * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  167.  * mode line needs to be updated (the "*" has to be set).
  168.  */
  169. lchange(flag)
  170. register int    flag;
  171. {
  172.     register WINDOW *wp;
  173.  
  174.     if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  175.       flag = WFHARD;
  176.  
  177.     if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  178.     if(Pmaster == NULL)
  179.       flag |= WFMODE;                 /* update mode lines.   */
  180.     curbp->b_flag |= BFCHG;
  181.     }
  182.  
  183.     wp = wheadp;
  184.     while (wp != NULL) {
  185.     if (wp->w_bufp == curbp)
  186.       wp->w_flag |= flag;
  187.     wp = wp->w_wndp;
  188.     }
  189. }
  190.  
  191.  
  192. /*
  193.  * insert spaces forward into text
  194.  * default flag and numeric argument 
  195.  */
  196. insspace(f, n)    
  197. int f, n;
  198. {
  199.     linsert(n, ' ');
  200.     backchar(f, n);
  201. }
  202.  
  203. /*
  204.  * Insert "n" copies of the character "c" at the current location of dot. In
  205.  * the easy case all that happens is the text is stored in the line. In the
  206.  * hard case, the line has to be reallocated. When the window list is updated,
  207.  * take special care; I screwed it up once. You always update dot in the
  208.  * current window. You update mark, and a dot in another window, if it is
  209.  * greater than the place where you did the insert. Return TRUE if all is
  210.  * well, and FALSE on errors.
  211.  */
  212. linsert(n, c)
  213. int n, c;
  214. {
  215.     register LINE   *dotp;
  216.     register int     doto;
  217.     register WINDOW *wp;
  218.  
  219.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  220.       return(rdonly());    /* we are in read only mode    */
  221.  
  222.     dotp = curwp->w_dotp;
  223.     doto = curwp->w_doto;
  224.     lchange(WFEDIT);
  225.  
  226.     if(!geninsert(&(curwp->w_dotp), &(curwp->w_doto), curbp->b_linep,
  227.                   c, (curwp->w_markp) ? 1 : 0, n, &curbp->b_linecnt))
  228.       return(FALSE);
  229.  
  230.     wp = wheadp;                /* Update windows       */
  231.     while (wp != NULL) {
  232.     if (wp->w_linep == dotp)
  233.       wp->w_linep = wp->w_dotp;
  234.  
  235.     if (wp->w_imarkp == dotp) {        /* added for internal mark */
  236.         wp->w_imarkp = wp->w_dotp;
  237.         if (wp->w_imarko > doto)
  238.           wp->w_imarko += n;
  239.     }
  240.  
  241.     if (wp->w_markp == dotp) {
  242.         wp->w_markp = dotp;
  243.         if (wp->w_marko > doto)
  244.           wp->w_marko += n;
  245.     }
  246.     wp = wp->w_wndp;
  247.     }
  248.  
  249.     return (TRUE);
  250. }
  251.  
  252.  
  253. /*
  254.  * geninsert - do the actual work of inserting a character into
  255.  *             the list of lines.
  256.  */
  257. int
  258. geninsert(dotp, doto, linep, c, attb, n, lines)
  259. LINE **dotp, *linep;
  260. int   *doto;
  261. int    c, attb, n;
  262. long  *lines;
  263. {
  264.     register LINE  *lp1;
  265.     register LINE  *lp2;
  266.     register CELL  *cp1;
  267.     register CELL  *cp2;
  268.     CELL ac;
  269.  
  270.     ac.a = attb;
  271.     if (*dotp == linep) {            /* At the end: special  */
  272.     if (*doto != 0) {
  273.         emlwrite("Programmer botch: geninsert", NULL);
  274.         return (FALSE);
  275.     }
  276.  
  277.     if ((lp1=lalloc(n)) == NULL)        /* Allocate new line    */
  278.       return (FALSE);
  279.  
  280.     lp2 = (*dotp)->l_bp;                /* Previous line        */
  281.     lp2->l_fp = lp1;                /* Link in              */
  282.     lp1->l_fp = *dotp;
  283.     (*dotp)->l_bp = lp1;
  284.     lp1->l_bp = lp2;
  285.     *doto = n;
  286.     *dotp = lp1;
  287.     ac.c  = ((char)c & 0xff);
  288.     cp1   = &(*dotp)->l_text[0];
  289.         while(n--)
  290.       *cp1++ = ac;
  291.  
  292.     if(lines)
  293.       (*lines)++;
  294.  
  295.     return (TRUE);
  296.     }
  297.  
  298.     if ((*dotp)->l_used+n > (*dotp)->l_size) {      /* Hard: reallocate     */
  299.     if ((lp1=lalloc((*dotp)->l_used+n)) == NULL)
  300.       return (FALSE);
  301.  
  302.     cp1 = &(*dotp)->l_text[0];
  303.     cp2 = &lp1->l_text[0];
  304.     while (cp1 != &(*dotp)->l_text[*doto])
  305.       *cp2++ = *cp1++;
  306.  
  307.     cp2 += n;
  308.     while (cp1 != &(*dotp)->l_text[(*dotp)->l_used])
  309.       *cp2++ = *cp1++;
  310.  
  311.     (*dotp)->l_bp->l_fp = lp1;
  312.     lp1->l_fp = (*dotp)->l_fp;
  313.     (*dotp)->l_fp->l_bp = lp1;
  314.     lp1->l_bp = (*dotp)->l_bp;
  315.  
  316.     /* global may be keeping track of mark/imark */
  317.     if(wheadp){
  318.         if (wheadp->w_imarkp == *dotp)
  319.           wheadp->w_imarkp = lp1;
  320.  
  321.         if (wheadp->w_markp == *dotp)
  322.           wheadp->w_markp = lp1;
  323.     }
  324.  
  325.     free((char *) (*dotp));
  326.     *dotp = lp1;
  327.     } else {                                /* Easy: in place       */
  328.     (*dotp)->l_used += n;
  329.     cp2 = &(*dotp)->l_text[(*dotp)->l_used];
  330.     cp1 = cp2-n;
  331.     while (cp1 != &(*dotp)->l_text[*doto])
  332.       *--cp2 = *--cp1;
  333.     }
  334.  
  335.     ac.c = ((char)c & 0xff);
  336.     while(n--)                    /* add the chars */
  337.       (*dotp)->l_text[(*doto)++] = ac;
  338.  
  339.     return(TRUE);
  340. }
  341.  
  342.  
  343. /*
  344.  * Insert a newline into the buffer at the current location of dot in the
  345.  * current window. The funny ass-backwards way it does things is not a botch;
  346.  * it just makes the last line in the file not a special case. Return TRUE if
  347.  * everything works out and FALSE on error (memory allocation failure). The
  348.  * update of dot and mark is a bit easier than in the above case, because the
  349.  * split forces more updating.
  350.  */
  351. lnewline()
  352. {
  353.     register CELL   *cp1;
  354.     register CELL   *cp2;
  355.     register LINE   *lp1;
  356.     register LINE   *lp2;
  357.     register int    doto;
  358.     register WINDOW *wp;
  359.  
  360.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  361.       return(rdonly());    /* we are in read only mode    */
  362.  
  363.     lchange(WFHARD);
  364.     lp1  = curwp->w_dotp;                   /* Get the address and  */
  365.     doto = curwp->w_doto;                   /* offset of "."        */
  366.     if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  367.       return (FALSE);
  368.  
  369.     cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  370.     cp2 = &lp2->l_text[0];
  371.     while (cp1 != &lp1->l_text[doto])
  372.       *cp2++ = *cp1++;
  373.  
  374.     cp2 = &lp1->l_text[0];
  375.     while (cp1 != &lp1->l_text[lp1->l_used])
  376.       *cp2++ = *cp1++;
  377.  
  378.     lp1->l_used -= doto;
  379.     lp2->l_bp = lp1->l_bp;
  380.     lp1->l_bp = lp2;
  381.     lp2->l_bp->l_fp = lp2;
  382.     lp2->l_fp = lp1;
  383.     wp = wheadp;                            /* Windows              */
  384.     while (wp != NULL) {
  385.     if (wp->w_linep == lp1)
  386.       wp->w_linep = lp2;
  387.  
  388.     if (wp->w_dotp == lp1) {
  389.         if (wp->w_doto < doto)
  390.           wp->w_dotp = lp2;
  391.         else
  392.           wp->w_doto -= doto;
  393.     }
  394.  
  395.     if (wp->w_imarkp == lp1) {          /* ADDED for internal mark */
  396.         if (wp->w_imarko < doto)
  397.           wp->w_imarkp = lp2;
  398.         else
  399.           wp->w_imarko -= doto;
  400.     }
  401.  
  402.     if (wp->w_markp == lp1) {
  403.         if (wp->w_marko < doto)
  404.           wp->w_markp = lp2;
  405.         else
  406.           wp->w_marko -= doto;
  407.     }
  408.     wp = wp->w_wndp;
  409.     }
  410.  
  411.     /*
  412.      * Keep track of the number of lines in the buffer.
  413.      */
  414.     ++curbp->b_linecnt;
  415.     return (TRUE);
  416. }
  417.  
  418.  
  419. /*
  420.  * This function deletes "n" bytes, starting at dot. It understands how do deal
  421.  * with end of lines, etc. It returns TRUE if all of the characters were
  422.  * deleted, and FALSE if they were not (because dot ran into the end of the
  423.  * buffer. The "preserve" function is used to save what was deleted.
  424.  */
  425. ldelete(n, preserve)
  426. long n;
  427. int (*preserve) PROTO((int));
  428. {
  429.     register CELL   *cp1;
  430.     register CELL   *cp2;
  431.     register LINE   *dotp;
  432.     register int    doto;
  433.     register int    chunk;
  434.     register WINDOW *wp;
  435.  
  436.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  437.       return(rdonly());    /* we are in read only mode    */
  438.  
  439.     while (n != 0) {
  440.     dotp = curwp->w_dotp;
  441.     doto = curwp->w_doto;
  442.     if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  443.       return (FALSE);
  444.     chunk = dotp->l_used-doto;      /* Size of chunk.       */
  445.     if (chunk > n)
  446.       chunk = n;
  447.     if (chunk == 0) {               /* End of line, merge.  */
  448.         lchange(WFHARD);
  449.         if (ldelnewline() == FALSE
  450.         || (preserve ? (*preserve)('\n') == FALSE : 0))
  451.           return (FALSE);
  452.         --n;
  453.         continue;
  454.     }
  455.  
  456.     lchange(WFEDIT);
  457.     cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  458.     cp2 = cp1 + chunk;
  459.     if (preserve) {           /* Kill?                */
  460.         while (cp1 != cp2) {
  461.         if ((*preserve)(cp1->c) == FALSE)
  462.           return (FALSE);
  463.         ++cp1;
  464.         }
  465.         cp1 = &dotp->l_text[doto];
  466.     }
  467.  
  468.     while (cp2 != &dotp->l_text[dotp->l_used])
  469.       *cp1++ = *cp2++;
  470.  
  471.     dotp->l_used -= chunk;
  472.     wp = wheadp;                    /* Fix windows          */
  473.     while (wp != NULL) {
  474.         if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  475.         wp->w_doto -= chunk;
  476.         if (wp->w_doto < doto)
  477.           wp->w_doto = doto;
  478.         }
  479.  
  480.         if (wp->w_markp==dotp && wp->w_marko>=doto) {
  481.         wp->w_marko -= chunk;
  482.         if (wp->w_marko < doto)
  483.           wp->w_marko = doto;
  484.         }
  485.  
  486.         if (wp->w_imarkp==dotp && wp->w_imarko>=doto) {
  487.         wp->w_imarko -= chunk;
  488.         if (wp->w_imarko < doto)
  489.           wp->w_imarko = doto;
  490.         }
  491.  
  492.         wp = wp->w_wndp;
  493.     }
  494.     n -= chunk;
  495.     }
  496.  
  497. #ifdef _WINDOWS
  498.     if (preserve == kinsert && ksize() > 0)
  499.       mswin_killbuftoclip (kremove);
  500. #endif
  501.  
  502.     return (TRUE);
  503. }
  504.  
  505. /*
  506.  * Delete a newline. Join the current line with the next line. If the next line
  507.  * is the magic header line always return TRUE; merging the last line with the
  508.  * header line can be thought of as always being a successful operation, even
  509.  * if nothing is done, and this makes the kill buffer work "right". Easy cases
  510.  * can be done by shuffling data around. Hard cases require that lines be moved
  511.  * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  512.  * "ldelete" only.
  513.  */
  514. ldelnewline()
  515. {
  516.     register CELL   *cp1;
  517.     register CELL   *cp2;
  518.     register LINE   *lp1;
  519.     register LINE   *lp2;
  520.     register LINE   *lp3;
  521.     register WINDOW *wp;
  522.  
  523.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  524.       return(rdonly());    /* we are in read only mode    */
  525.  
  526.     lp1 = curwp->w_dotp;
  527.     lp2 = lp1->l_fp;
  528.     if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  529.     if (lp1->l_used == 0) {             /* Blank line.          */
  530.         lfree(lp1);
  531.         --curbp->b_linecnt;
  532.     }
  533.  
  534.     return (TRUE);
  535.     }
  536.  
  537.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  538.     cp1 = &lp1->l_text[lp1->l_used];
  539.     cp2 = &lp2->l_text[0];
  540.     while (cp2 != &lp2->l_text[lp2->l_used])
  541.       *cp1++ = *cp2++;
  542.  
  543.     wp = wheadp;
  544.     while (wp != NULL) {
  545.         if (wp->w_linep == lp2)
  546.           wp->w_linep = lp1;
  547.         if (wp->w_dotp == lp2) {
  548.         wp->w_dotp  = lp1;
  549.         wp->w_doto += lp1->l_used;
  550.         }
  551.         if (wp->w_markp == lp2) {
  552.         wp->w_markp  = lp1;
  553.         wp->w_marko += lp1->l_used;
  554.         }
  555.         wp = wp->w_wndp;
  556.     }
  557.     lp1->l_used += lp2->l_used;
  558.     lp1->l_fp = lp2->l_fp;
  559.     lp2->l_fp->l_bp = lp1;
  560.     free((char *) lp2);
  561.     --curbp->b_linecnt;
  562.     return (TRUE);
  563.     }
  564.  
  565.     if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  566.       return (FALSE);
  567.  
  568.     cp1 = &lp1->l_text[0];
  569.     cp2 = &lp3->l_text[0];
  570.     while (cp1 != &lp1->l_text[lp1->l_used])
  571.       *cp2++ = *cp1++;
  572.  
  573.     cp1 = &lp2->l_text[0];
  574.     while (cp1 != &lp2->l_text[lp2->l_used])
  575.       *cp2++ = *cp1++;
  576.  
  577.     lp1->l_bp->l_fp = lp3;
  578.     lp3->l_fp = lp2->l_fp;
  579.     lp2->l_fp->l_bp = lp3;
  580.     lp3->l_bp = lp1->l_bp;
  581.     wp = wheadp;
  582.     while (wp != NULL) {
  583.     if (wp->w_linep==lp1 || wp->w_linep==lp2)
  584.       wp->w_linep = lp3;
  585.     if (wp->w_dotp == lp1)
  586.       wp->w_dotp  = lp3;
  587.     else if (wp->w_dotp == lp2) {
  588.         wp->w_dotp  = lp3;
  589.         wp->w_doto += lp1->l_used;
  590.     }
  591.     if (wp->w_markp == lp1)
  592.       wp->w_markp  = lp3;
  593.     else if (wp->w_markp == lp2) {
  594.         wp->w_markp  = lp3;
  595.         wp->w_marko += lp1->l_used;
  596.     }
  597.     wp = wp->w_wndp;
  598.     }
  599.  
  600.     free((char *) lp1);
  601.     free((char *) lp2);
  602.     --curbp->b_linecnt;
  603.     return (TRUE);
  604. }
  605.  
  606.  
  607. /*
  608.  * Tell the caller if the given line is blank or not.
  609.  */
  610. lisblank(line)
  611.     LINE *line;
  612. {
  613.     int n = 0;
  614.  
  615.     n = (Pmaster && Pmaster->quote_str && quote_match(Pmaster->quote_str,line))
  616.       ? strlen(Pmaster->quote_str) : 0;
  617.  
  618.     for(; n < llength(line); n++)
  619.       if(!isspace((unsigned char) lgetc(line, n).c))
  620.     return(FALSE);
  621.  
  622.     return(TRUE);
  623. }
  624.  
  625.  
  626. /*
  627.  * Delete all of the text saved in the kill buffer. Called by commands when a
  628.  * new kill context is being created. The kill buffer array is released, just
  629.  * in case the buffer has grown to immense size. No errors.
  630.  */
  631. kdelete()
  632. {
  633.     return(pkbufdel(&kbufp));
  634. }
  635.  
  636. fdelete()
  637. {
  638.     return(pkbufdel(&fbufp));
  639. }
  640.  
  641. pkbufdel(buf)
  642.     struct pkbuf **buf;
  643. {
  644.     if (*buf) {
  645.     pkchunkdel(&(*buf)->first);
  646.     free((char *) *buf);
  647.     *buf = NULL;
  648.     }
  649. }
  650.  
  651.  
  652. void
  653. pkchunkdel(chunk)
  654.     struct pkchunk **chunk;
  655. {
  656.     if(chunk){
  657.     if((*chunk)->next)
  658.       pkchunkdel(&(*chunk)->next);
  659.  
  660.     free((char *) *chunk);
  661.     *chunk = NULL;
  662.     }
  663. }
  664.  
  665.  
  666. /*
  667.  * Insert a character to the kill buffer, enlarging the buffer if there isn't
  668.  * any room. Always grow the buffer in chunks, on the assumption that if you
  669.  * put something in the kill buffer you are going to put more stuff there too
  670.  * later. Return TRUE if all is well, and FALSE on errors.
  671.  */
  672. kinsert(c)
  673.     int c;
  674. {
  675.     return(pkbufinsert(c, &kbufp));
  676. }
  677.  
  678. finsert(c)
  679.     int c;
  680. {
  681.     return(pkbufinsert(c, &fbufp));
  682. }
  683.  
  684. pkbufinsert(c, buf)
  685.     int c;
  686.     struct pkbuf **buf;
  687. {
  688.     register char *nbufp;
  689.  
  690.     if(!*buf){
  691.     if(*buf = (struct pkbuf *) malloc(sizeof(struct pkbuf)))
  692.       memset(*buf, 0, sizeof(struct pkbuf));
  693.     else
  694.       return(FALSE);
  695.     }
  696.  
  697.     if((*buf)->total % KBLOCK == 0){
  698.     struct pkchunk *p = (*buf)->last;
  699.     if((*buf)->last = (struct pkchunk *) malloc(sizeof(struct pkchunk))){
  700.         memset((*buf)->last, 0, sizeof(struct pkchunk));
  701.         if(p)
  702.           p->next = (*buf)->last;
  703.         else
  704.           (*buf)->first = (*buf)->last;
  705.     }
  706.     else
  707.       return(FALSE);
  708.     }
  709.  
  710.     (*buf)->last->bufp[(*buf)->last->used++] = c;
  711.     (*buf)->total++;
  712.     return (TRUE);
  713. }
  714.  
  715.  
  716. /*
  717.  * These functions get characters from the requested buffer. If the
  718.  * character index "n" is off the end, it returns "-1". This lets the
  719.  * caller just scan along until it gets a "-1" back.
  720.  */
  721. kremove(n)
  722.     int n;
  723. {
  724.     return(pkbufremove(n, kbufp));
  725. }
  726.  
  727. fremove(n)
  728.     int n;
  729. {
  730.     return(pkbufremove(n, fbufp));
  731. }
  732.  
  733.  
  734. pkbufremove(n, buf)
  735.     int n;
  736.     struct pkbuf *buf;
  737. {
  738.     if(n >= 0 && buf && n < buf->total){
  739.     register struct pkchunk *p = buf->first;
  740.     int             block = n / KBLOCK;
  741.  
  742.     while(block--)
  743.       if(!(p = p->next))
  744.         return(-1);
  745.  
  746.     return(p->bufp[n % KBLOCK] & 0xff);
  747.     }
  748.     else
  749.       return(-1);
  750. }
  751.  
  752.  
  753. /*
  754.  * This function just returns the current size of the kill buffer
  755.  */
  756. ksize()
  757. {
  758.     return(kbufp ? (int) kbufp->total : 0);
  759. }
  760.