119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: put.c,v 10.19 04/07/11 17:00:24 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 18254225Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <ctype.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter 2719304Speter#include "common.h" 2819304Speter 2919304Speter/* 3019304Speter * put -- 3119304Speter * Put text buffer contents into the file. 3219304Speter * 3319304Speter * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int)); 3419304Speter */ 3519304Speterint 36254225Speterput( 37254225Speter SCR *sp, 38254225Speter CB *cbp, 39254225Speter CHAR_T *namep, 40254225Speter MARK *cp, 41254225Speter MARK *rp, 42254225Speter int append) 4319304Speter{ 4419304Speter CHAR_T name; 4519304Speter TEXT *ltp, *tp; 4619304Speter recno_t lno; 4719304Speter size_t blen, clen, len; 4819304Speter int rval; 49254225Speter CHAR_T *bp, *t; 50254225Speter CHAR_T *p; 5119304Speter 5219304Speter if (cbp == NULL) 5319304Speter if (namep == NULL) { 5419304Speter cbp = sp->gp->dcbp; 5519304Speter if (cbp == NULL) { 5619304Speter msgq(sp, M_ERR, 5719304Speter "053|The default buffer is empty"); 5819304Speter return (1); 5919304Speter } 6019304Speter } else { 6119304Speter name = *namep; 6219304Speter CBNAME(sp, cbp, name); 6319304Speter if (cbp == NULL) { 6419304Speter msgq(sp, M_ERR, "054|Buffer %s is empty", 6519304Speter KEY_NAME(sp, name)); 6619304Speter return (1); 6719304Speter } 6819304Speter } 69254225Speter tp = TAILQ_FIRST(cbp->textq); 7019304Speter 7119304Speter /* 7219304Speter * It's possible to do a put into an empty file, meaning that the cut 7319304Speter * buffer simply becomes the file. It's a special case so that we can 7419304Speter * ignore it in general. 7519304Speter * 7619304Speter * !!! 7719304Speter * Historically, pasting into a file with no lines in vi would preserve 7819304Speter * the single blank line. This is surely a result of the fact that the 7919304Speter * historic vi couldn't deal with a file that had no lines in it. This 8019304Speter * implementation treats that as a bug, and does not retain the blank 8119304Speter * line. 8219304Speter * 8319304Speter * Historical practice is that the cursor ends at the first character 8419304Speter * in the file. 8519304Speter */ 8619304Speter if (cp->lno == 1) { 8719304Speter if (db_last(sp, &lno)) 8819304Speter return (1); 8919304Speter if (lno == 0) { 90254225Speter for (; tp != NULL; 91254225Speter ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 9219304Speter if (db_append(sp, 1, lno, tp->lb, tp->len)) 9319304Speter return (1); 9419304Speter rp->lno = 1; 9519304Speter rp->cno = 0; 9619304Speter return (0); 9719304Speter } 9819304Speter } 9919304Speter 10019304Speter /* If a line mode buffer, append each new line into the file. */ 10119304Speter if (F_ISSET(cbp, CB_LMODE)) { 10219304Speter lno = append ? cp->lno : cp->lno - 1; 10319304Speter rp->lno = lno + 1; 104254225Speter for (; tp != NULL; 105254225Speter ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 10619304Speter if (db_append(sp, 1, lno, tp->lb, tp->len)) 10719304Speter return (1); 10819304Speter rp->cno = 0; 10919304Speter (void)nonblank(sp, rp->lno, &rp->cno); 11019304Speter return (0); 11119304Speter } 11219304Speter 11319304Speter /* 11419304Speter * If buffer was cut in character mode, replace the current line with 11519304Speter * one built from the portion of the first line to the left of the 11619304Speter * split plus the first line in the CB. Append each intermediate line 11719304Speter * in the CB. Append a line built from the portion of the first line 11819304Speter * to the right of the split plus the last line in the CB. 11919304Speter * 12019304Speter * Get the first line. 12119304Speter */ 12219304Speter lno = cp->lno; 12319304Speter if (db_get(sp, lno, DBG_FATAL, &p, &len)) 12419304Speter return (1); 12519304Speter 126254225Speter GET_SPACE_RETW(sp, bp, blen, tp->len + len + 1); 12719304Speter t = bp; 12819304Speter 12919304Speter /* Original line, left of the split. */ 13019304Speter if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) { 131254225Speter MEMCPY(bp, p, clen); 13219304Speter p += clen; 13319304Speter t += clen; 13419304Speter } 13519304Speter 13619304Speter /* First line from the CB. */ 13719304Speter if (tp->len != 0) { 138254225Speter MEMCPY(t, tp->lb, tp->len); 13919304Speter t += tp->len; 14019304Speter } 14119304Speter 14219304Speter /* Calculate length left in the original line. */ 14319304Speter clen = len == 0 ? 0 : len - (cp->cno + (append ? 1 : 0)); 14419304Speter 14519304Speter /* 14619304Speter * !!! 14719304Speter * In the historical 4BSD version of vi, character mode puts within 14819304Speter * a single line have two cursor behaviors: if the put is from the 14919304Speter * unnamed buffer, the cursor moves to the character inserted which 15019304Speter * appears last in the file. If the put is from a named buffer, 15119304Speter * the cursor moves to the character inserted which appears first 15219304Speter * in the file. In System III/V, it was changed at some point and 15319304Speter * the cursor always moves to the first character. In both versions 15419304Speter * of vi, character mode puts that cross line boundaries leave the 15519304Speter * cursor on the first character. Nvi implements the System III/V 15619304Speter * behavior, and expect POSIX.2 to do so as well. 15719304Speter */ 15819304Speter rp->lno = lno; 15919304Speter rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0); 16019304Speter 16119304Speter /* 16219304Speter * If no more lines in the CB, append the rest of the original 16319304Speter * line and quit. Otherwise, build the last line before doing 16419304Speter * the intermediate lines, because the line changes will lose 16519304Speter * the cached line. 16619304Speter */ 167254225Speter if (TAILQ_NEXT(tp, q) == NULL) { 16819304Speter if (clen > 0) { 169254225Speter MEMCPY(t, p, clen); 17019304Speter t += clen; 17119304Speter } 17219304Speter if (db_set(sp, lno, bp, t - bp)) 17319304Speter goto err; 17419304Speter if (sp->rptlchange != lno) { 17519304Speter sp->rptlchange = lno; 17619304Speter ++sp->rptlines[L_CHANGED]; 17719304Speter } 17819304Speter } else { 17919304Speter /* 18019304Speter * Have to build both the first and last lines of the 18119304Speter * put before doing any sets or we'll lose the cached 18219304Speter * line. Build both the first and last lines in the 18319304Speter * same buffer, so we don't have to have another buffer 18419304Speter * floating around. 18519304Speter * 18619304Speter * Last part of original line; check for space, reset 18719304Speter * the pointer into the buffer. 18819304Speter */ 189254225Speter ltp = TAILQ_LAST(cbp->textq, _texth); 19019304Speter len = t - bp; 191254225Speter ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen); 19219304Speter t = bp + len; 19319304Speter 19419304Speter /* Add in last part of the CB. */ 195254225Speter MEMCPY(t, ltp->lb, ltp->len); 19619304Speter if (clen) 197254225Speter MEMCPY(t + ltp->len, p, clen); 19819304Speter clen += ltp->len; 19919304Speter 20019304Speter /* 20119304Speter * Now: bp points to the first character of the first 20219304Speter * line, t points to the last character of the last 20319304Speter * line, t - bp is the length of the first line, and 20419304Speter * clen is the length of the last. Just figured you'd 20519304Speter * want to know. 20619304Speter * 20719304Speter * Output the line replacing the original line. 20819304Speter */ 20919304Speter if (db_set(sp, lno, bp, t - bp)) 21019304Speter goto err; 21119304Speter if (sp->rptlchange != lno) { 21219304Speter sp->rptlchange = lno; 21319304Speter ++sp->rptlines[L_CHANGED]; 21419304Speter } 21519304Speter 21619304Speter /* Output any intermediate lines in the CB. */ 217254225Speter for (tp = TAILQ_NEXT(tp, q); TAILQ_NEXT(tp, q) != NULL; 218254225Speter ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 21919304Speter if (db_append(sp, 1, lno, tp->lb, tp->len)) 22019304Speter goto err; 22119304Speter 22219304Speter if (db_append(sp, 1, lno, t, clen)) 22319304Speter goto err; 22419304Speter ++sp->rptlines[L_ADDED]; 22519304Speter } 22619304Speter rval = 0; 22719304Speter 22819304Speter if (0) 22919304Spetererr: rval = 1; 23019304Speter 231254225Speter FREE_SPACEW(sp, bp, blen); 23219304Speter return (rval); 23319304Speter} 234