home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / newemacs / line.c < prev    next >
Text File  |  1979-12-31  |  15KB  |  573 lines

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