GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../common/put.c Lines: 0 79 0.0 %
Date: 2017-11-07 Branches: 0 112 0.0 %

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