11022Sache/*- 21533Sjoerg * Copyright (c) 1992, 1993, 1994 31022Sache * The Regents of the University of California. All rights reserved. 41022Sache * Copyright (c) 1992, 1993, 1994, 1995, 1996 51022Sache * Keith Bostic. All rights reserved. 61022Sache * 71022Sache * See the LICENSE file for redistribution information. 81022Sache */ 91022Sache 101022Sache#include "config.h" 111022Sache 121022Sache#ifndef lint 131022Sachestatic const char sccsid[] = "$Id: put.c,v 10.19 04/07/11 17:00:24 zy Exp $"; 141533Sjoerg#endif /* not lint */ 151533Sjoerg 161533Sjoerg#include <sys/types.h> 171533Sjoerg#include <sys/queue.h> 181533Sjoerg#include <sys/time.h> 191533Sjoerg 201533Sjoerg#include <bitstring.h> 211533Sjoerg#include <ctype.h> 221533Sjoerg#include <limits.h> 231533Sjoerg#include <stdio.h> 241533Sjoerg#include <stdlib.h> 2555541Skato#include <string.h> 2655541Skato 271022Sache#include "common.h" 281022Sache 291022Sache/* 301022Sache * put -- 311022Sache * Put text buffer contents into the file. 328857Srgrimes * 331022Sache * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int)); 341022Sache */ 351022Sacheint 361022Sacheput( 371022Sache SCR *sp, 381022Sache CB *cbp, 391022Sache CHAR_T *namep, 401022Sache MARK *cp, 411022Sache MARK *rp, 421022Sache int append) 4329531Scharnier{ 4429531Scharnier CHAR_T name; 4529531Scharnier TEXT *ltp, *tp; 461022Sache recno_t lno; 471022Sache size_t blen, clen, len; 4829531Scharnier int rval; 491022Sache CHAR_T *bp, *t; 501022Sache CHAR_T *p; 511022Sache 521022Sache if (cbp == NULL) 531022Sache if (namep == NULL) { 541022Sache cbp = sp->gp->dcbp; 551137Sache if (cbp == NULL) { 561022Sache msgq(sp, M_ERR, 571022Sache "053|The default buffer is empty"); 581137Sache return (1); 591138Sache } 601022Sache } else { 611137Sache name = *namep; 621137Sache CBNAME(sp, cbp, name); 631137Sache if (cbp == NULL) { 641137Sache msgq(sp, M_ERR, "054|Buffer %s is empty", 651137Sache KEY_NAME(sp, name)); 661137Sache return (1); 671137Sache } 681022Sache } 691022Sache tp = TAILQ_FIRST(cbp->textq); 701022Sache 711022Sache /* 721022Sache * It's possible to do a put into an empty file, meaning that the cut 731022Sache * buffer simply becomes the file. It's a special case so that we can 741022Sache * ignore it in general. 751022Sache * 761022Sache * !!! 771022Sache * Historically, pasting into a file with no lines in vi would preserve 781022Sache * the single blank line. This is surely a result of the fact that the 791022Sache * historic vi couldn't deal with a file that had no lines in it. This 801137Sache * implementation treats that as a bug, and does not retain the blank 811022Sache * line. 821022Sache * 8329531Scharnier * Historical practice is that the cursor ends at the first character 8429531Scharnier * in the file. 851022Sache */ 861022Sache if (cp->lno == 1) { 871022Sache if (db_last(sp, &lno)) 881022Sache return (1); 891022Sache if (lno == 0) { 901022Sache for (; tp != NULL; 911022Sache ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 921533Sjoerg if (db_append(sp, 1, lno, tp->lb, tp->len)) 931022Sache return (1); 941533Sjoerg rp->lno = 1; 9529531Scharnier rp->cno = 0; 961533Sjoerg return (0); 971533Sjoerg } 981533Sjoerg } 991533Sjoerg 1001533Sjoerg /* If a line mode buffer, append each new line into the file. */ 1018857Srgrimes if (F_ISSET(cbp, CB_LMODE)) { 1021022Sache lno = append ? cp->lno : cp->lno - 1; 1031022Sache rp->lno = lno + 1; 1041022Sache for (; tp != NULL; 1051022Sache ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 1061022Sache if (db_append(sp, 1, lno, tp->lb, tp->len)) 1071022Sache return (1); 1081022Sache rp->cno = 0; 1091022Sache (void)nonblank(sp, rp->lno, &rp->cno); 11029531Scharnier return (0); 11129531Scharnier } 1121022Sache 1131533Sjoerg /* 1141533Sjoerg * If buffer was cut in character mode, replace the current line with 1151533Sjoerg * one built from the portion of the first line to the left of the 1161533Sjoerg * split plus the first line in the CB. Append each intermediate line 1171533Sjoerg * in the CB. Append a line built from the portion of the first line 1181533Sjoerg * to the right of the split plus the last line in the CB. 1191533Sjoerg * 1201533Sjoerg * Get the first line. 1211022Sache */ 1221022Sache lno = cp->lno; 1231022Sache if (db_get(sp, lno, DBG_FATAL, &p, &len)) 1241022Sache return (1); 1251022Sache 12656447Sasmodai GET_SPACE_RETW(sp, bp, blen, tp->len + len + 1); 1271022Sache t = bp; 1281022Sache 1291022Sache /* Original line, left of the split. */ 1301022Sache if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) { 1311022Sache MEMCPY(bp, p, clen); 1321022Sache p += clen; 13356447Sasmodai t += clen; 1341022Sache } 1351022Sache 1361022Sache /* First line from the CB. */ 1371022Sache if (tp->len != 0) { 1381022Sache MEMCPY(t, tp->lb, tp->len); 1391022Sache t += tp->len; 1401533Sjoerg } 1411022Sache 14229531Scharnier /* Calculate length left in the original line. */ 14361154Sphk clen = len == 0 ? 0 : len - (cp->cno + (append ? 1 : 0)); 14429531Scharnier 1451022Sache /* 1461022Sache * !!! 1471022Sache * In the historical 4BSD version of vi, character mode puts within 1481022Sache * a single line have two cursor behaviors: if the put is from the 1491533Sjoerg * unnamed buffer, the cursor moves to the character inserted which 1501022Sache * appears last in the file. If the put is from a named buffer, 1511022Sache * the cursor moves to the character inserted which appears first 1521022Sache * in the file. In System III/V, it was changed at some point and 1531022Sache * the cursor always moves to the first character. In both versions 1541022Sache * of vi, character mode puts that cross line boundaries leave the 1551022Sache * cursor on the first character. Nvi implements the System III/V 1561022Sache * behavior, and expect POSIX.2 to do so as well. 1571022Sache */ 1581022Sache rp->lno = lno; 1591022Sache rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0); 1601022Sache 1611022Sache /* 1621022Sache * If no more lines in the CB, append the rest of the original 1631022Sache * line and quit. Otherwise, build the last line before doing 1641022Sache * the intermediate lines, because the line changes will lose 1651022Sache * the cached line. 1661022Sache */ 1671022Sache if (TAILQ_NEXT(tp, q) == NULL) { 1681022Sache if (clen > 0) { 1691022Sache MEMCPY(t, p, clen); 1701022Sache t += clen; 1711022Sache } 1721022Sache if (db_set(sp, lno, bp, t - bp)) 17361154Sphk goto err; 1741022Sache if (sp->rptlchange != lno) { 1751022Sache sp->rptlchange = lno; 1761022Sache ++sp->rptlines[L_CHANGED]; 1771022Sache } 17861154Sphk } else { 1791022Sache /* 1801022Sache * Have to build both the first and last lines of the 1811022Sache * put before doing any sets or we'll lose the cached 1821022Sache * line. Build both the first and last lines in the 1831022Sache * same buffer, so we don't have to have another buffer 1841022Sache * floating around. 1851022Sache * 1861022Sache * Last part of original line; check for space, reset 1871022Sache * the pointer into the buffer. 1881022Sache */ 1891022Sache ltp = TAILQ_LAST(cbp->textq, _texth); 1901022Sache len = t - bp; 1911022Sache ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen); 1921022Sache t = bp + len; 1931022Sache 1941022Sache /* Add in last part of the CB. */ 1951022Sache MEMCPY(t, ltp->lb, ltp->len); 1961022Sache if (clen) 1971022Sache MEMCPY(t + ltp->len, p, clen); 1981022Sache clen += ltp->len; 1991022Sache 2001022Sache /* 2011022Sache * Now: bp points to the first character of the first 2021022Sache * line, t points to the last character of the last 2031022Sache * line, t - bp is the length of the first line, and 2041022Sache * clen is the length of the last. Just figured you'd 2051022Sache * want to know. 2061022Sache * 2071022Sache * Output the line replacing the original line. 2081022Sache */ 2091022Sache if (db_set(sp, lno, bp, t - bp)) 2101022Sache goto err; 2111022Sache if (sp->rptlchange != lno) { 2121022Sache sp->rptlchange = lno; 2131022Sache ++sp->rptlines[L_CHANGED]; 2141022Sache } 2151022Sache 2161022Sache /* Output any intermediate lines in the CB. */ 2171022Sache for (tp = TAILQ_NEXT(tp, q); TAILQ_NEXT(tp, q) != NULL; 2181022Sache ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) 2191022Sache if (db_append(sp, 1, lno, tp->lb, tp->len)) 2201022Sache goto err; 2211022Sache 2221022Sache if (db_append(sp, 1, lno, t, clen)) 2231022Sache goto err; 22461154Sphk ++sp->rptlines[L_ADDED]; 22561154Sphk } 22661154Sphk rval = 0; 22761154Sphk 2281022Sache if (0) 2291022Sacheerr: rval = 1; 2301022Sache 2311022Sache FREE_SPACEW(sp, bp, blen); 2321022Sache return (rval); 2331022Sache} 2341022Sache