home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / common / put.c < prev    next >
C/C++ Source or Header  |  1996-09-23  |  6KB  |  232 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)put.c    10.11 (Berkeley) 9/23/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <ctype.h>
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "common.h"
  27.  
  28. /*
  29.  * put --
  30.  *    Put text buffer contents into the file.
  31.  *
  32.  * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int));
  33.  */
  34. int
  35. put(sp, cbp, namep, cp, rp, append)
  36.     SCR *sp;
  37.     CB *cbp;
  38.     CHAR_T *namep;
  39.     MARK *cp, *rp;
  40.     int append;
  41. {
  42.     CHAR_T name;
  43.     TEXT *ltp, *tp;
  44.     recno_t lno;
  45.     size_t blen, clen, len;
  46.     int rval;
  47.     char *bp, *p, *t;
  48.  
  49.     if (cbp == NULL)
  50.         if (namep == NULL) {
  51.             cbp = sp->gp->dcbp;
  52.             if (cbp == NULL) {
  53.                 msgq(sp, M_ERR,
  54.                     "053|The default buffer is empty");
  55.                 return (1);
  56.             }
  57.         } else {
  58.             name = *namep;
  59.             CBNAME(sp, cbp, name);
  60.             if (cbp == NULL) {
  61.                 msgq(sp, M_ERR, "054|Buffer %s is empty",
  62.                     KEY_NAME(sp, name));
  63.                 return (1);
  64.             }
  65.         }
  66.     tp = cbp->textq.cqh_first;
  67.  
  68.     /*
  69.      * It's possible to do a put into an empty file, meaning that the cut
  70.      * buffer simply becomes the file.  It's a special case so that we can
  71.      * ignore it in general.
  72.      *
  73.      * !!!
  74.      * Historically, pasting into a file with no lines in vi would preserve
  75.      * the single blank line.  This is surely a result of the fact that the
  76.      * historic vi couldn't deal with a file that had no lines in it.  This
  77.      * implementation treats that as a bug, and does not retain the blank
  78.      * line.
  79.      *
  80.      * Historical practice is that the cursor ends at the first character
  81.      * in the file.
  82.      */
  83.     if (cp->lno == 1) {
  84.         if (db_last(sp, &lno))
  85.             return (1);
  86.         if (lno == 0) {
  87.             for (; tp != (void *)&cbp->textq;
  88.                 ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
  89.                 if (db_append(sp, 1, lno, tp->lb, tp->len))
  90.                     return (1);
  91.             rp->lno = 1;
  92.             rp->cno = 0;
  93.             return (0);
  94.         }
  95.     }
  96.  
  97.     /* If a line mode buffer, append each new line into the file. */
  98.     if (F_ISSET(cbp, CB_LMODE)) {
  99.         lno = append ? cp->lno : cp->lno - 1;
  100.         rp->lno = lno + 1;
  101.         for (; tp != (void *)&cbp->textq;
  102.             ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
  103.             if (db_append(sp, 1, lno, tp->lb, tp->len))
  104.                 return (1);
  105.         rp->cno = 0;
  106.         (void)nonblank(sp, rp->lno, &rp->cno);
  107.         return (0);
  108.     }
  109.  
  110.     /*
  111.      * If buffer was cut in character mode, replace the current line with
  112.      * one built from the portion of the first line to the left of the
  113.      * split plus the first line in the CB.  Append each intermediate line
  114.      * in the CB.  Append a line built from the portion of the first line
  115.      * to the right of the split plus the last line in the CB.
  116.      *
  117.      * Get the first line.
  118.      */
  119.     lno = cp->lno;
  120.     if (db_get(sp, lno, DBG_FATAL, &p, &len))
  121.         return (1);
  122.  
  123.     GET_SPACE_RET(sp, bp, blen, tp->len + len + 1);
  124.     t = bp;
  125.  
  126.     /* Original line, left of the split. */
  127.     if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) {
  128.         memcpy(bp, p, clen);
  129.         p += clen;
  130.         t += clen;
  131.     }
  132.  
  133.     /* First line from the CB. */
  134.     if (tp->len != 0) {
  135.         memcpy(t, tp->lb, tp->len);
  136.         t += tp->len;
  137.     }
  138.  
  139.     /* Calculate length left in the original line. */
  140.     clen = len == 0 ? 0 : len - (cp->cno + (append ? 1 : 0));
  141.  
  142.     /*
  143.      * !!!
  144.      * In the historical 4BSD version of vi, character mode puts within
  145.      * a single line have two cursor behaviors: if the put is from the
  146.      * unnamed buffer, the cursor moves to the character inserted which
  147.      * appears last in the file.  If the put is from a named buffer,
  148.      * the cursor moves to the character inserted which appears first
  149.      * in the file.  In System III/V, it was changed at some point and
  150.      * the cursor always moves to the first character.  In both versions
  151.      * of vi, character mode puts that cross line boundaries leave the
  152.      * cursor on the first character.  Nvi implements the System III/V
  153.      * behavior, and expect POSIX.2 to do so as well.
  154.      */
  155.     rp->lno = lno;
  156.     rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0);
  157.  
  158.     /*
  159.      * If no more lines in the CB, append the rest of the original
  160.      * line and quit.  Otherwise, build the last line before doing
  161.      * the intermediate lines, because the line changes will lose
  162.      * the cached line.
  163.      */
  164.     if (tp->q.cqe_next == (void *)&cbp->textq) {
  165.         if (clen > 0) {
  166.             memcpy(t, p, clen);
  167.             t += clen;
  168.         }
  169.         if (db_set(sp, lno, bp, t - bp))
  170.             goto err;
  171.         if (sp->rptlchange != lno) {
  172.             sp->rptlchange = lno;
  173.             ++sp->rptlines[L_CHANGED];
  174.         }
  175.     } else {
  176.         /*
  177.          * Have to build both the first and last lines of the
  178.          * put before doing any sets or we'll lose the cached
  179.          * line.  Build both the first and last lines in the
  180.          * same buffer, so we don't have to have another buffer
  181.          * floating around.
  182.          *
  183.          * Last part of original line; check for space, reset
  184.          * the pointer into the buffer.
  185.          */
  186.         ltp = cbp->textq.cqh_last;
  187.         len = t - bp;
  188.         ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
  189.         t = bp + len;
  190.  
  191.         /* Add in last part of the CB. */
  192.         memcpy(t, ltp->lb, ltp->len);
  193.         if (clen)
  194.             memcpy(t + ltp->len, p, clen);
  195.         clen += ltp->len;
  196.  
  197.         /*
  198.          * Now: bp points to the first character of the first
  199.          * line, t points to the last character of the last
  200.          * line, t - bp is the length of the first line, and
  201.          * clen is the length of the last.  Just figured you'd
  202.          * want to know.
  203.          *
  204.          * Output the line replacing the original line.
  205.          */
  206.         if (db_set(sp, lno, bp, t - bp))
  207.             goto err;
  208.         if (sp->rptlchange != lno) {
  209.             sp->rptlchange = lno;
  210.             ++sp->rptlines[L_CHANGED];
  211.         }
  212.  
  213.         /* Output any intermediate lines in the CB. */
  214.         for (tp = tp->q.cqe_next;
  215.             tp->q.cqe_next != (void *)&cbp->textq;
  216.             ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next)
  217.             if (db_append(sp, 1, lno, tp->lb, tp->len))
  218.                 goto err;
  219.  
  220.         if (db_append(sp, 1, lno, t, clen))
  221.             goto err;
  222.         ++sp->rptlines[L_ADDED];
  223.     }
  224.     rval = 0;
  225.  
  226.     if (0)
  227. err:        rval = 1;
  228.  
  229.     FREE_SPACE(sp, bp, blen);
  230.     return (rval);
  231. }
  232.