home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / pico / line.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-06  |  20.4 KB  |  810 lines

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