GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../ex/ex_append.c Lines: 0 63 0.0 %
Date: 2017-11-07 Branches: 0 76 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ex_append.c,v 1.14 2016/05/27 09:18:12 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 <limits.h>
19
#include <stdio.h>
20
#include <string.h>
21
#include <unistd.h>
22
23
#include "../common/common.h"
24
25
enum which {APPEND, CHANGE, INSERT};
26
27
static int ex_aci(SCR *, EXCMD *, enum which);
28
29
/*
30
 * ex_append -- :[line] a[ppend][!]
31
 *	Append one or more lines of new text after the specified line,
32
 *	or the current line if no address is specified.
33
 *
34
 * PUBLIC: int ex_append(SCR *, EXCMD *);
35
 */
36
int
37
ex_append(SCR *sp, EXCMD *cmdp)
38
{
39
	return (ex_aci(sp, cmdp, APPEND));
40
}
41
42
/*
43
 * ex_change -- :[line[,line]] c[hange][!] [count]
44
 *	Change one or more lines to the input text.
45
 *
46
 * PUBLIC: int ex_change(SCR *, EXCMD *);
47
 */
48
int
49
ex_change(SCR *sp, EXCMD *cmdp)
50
{
51
	return (ex_aci(sp, cmdp, CHANGE));
52
}
53
54
/*
55
 * ex_insert -- :[line] i[nsert][!]
56
 *	Insert one or more lines of new text before the specified line,
57
 *	or the current line if no address is specified.
58
 *
59
 * PUBLIC: int ex_insert(SCR *, EXCMD *);
60
 */
61
int
62
ex_insert(SCR *sp, EXCMD *cmdp)
63
{
64
	return (ex_aci(sp, cmdp, INSERT));
65
}
66
67
/*
68
 * ex_aci --
69
 *	Append, change, insert in ex.
70
 */
71
static int
72
ex_aci(SCR *sp, EXCMD *cmdp, enum which cmd)
73
{
74
	CHAR_T *p, *t;
75
	GS *gp;
76
	TEXT *tp;
77
	TEXTH tiq;
78
	recno_t cnt, lno;
79
	size_t len;
80
	u_int32_t flags;
81
	int need_newline;
82
83
	gp = sp->gp;
84
	NEEDFILE(sp, cmdp);
85
86
	/*
87
	 * If doing a change, replace lines for as long as possible.  Then,
88
	 * append more lines or delete remaining lines.  Changes to an empty
89
	 * file are appends, inserts are the same as appends to the previous
90
	 * line.
91
	 *
92
	 * !!!
93
	 * Set the address to which we'll append.  We set sp->lno to this
94
	 * address as well so that autoindent works correctly when get text
95
	 * from the user.
96
	 */
97
	lno = cmdp->addr1.lno;
98
	sp->lno = lno;
99
	if ((cmd == CHANGE || cmd == INSERT) && lno != 0)
100
		--lno;
101
102
	/*
103
	 * !!!
104
	 * If the file isn't empty, cut changes into the unnamed buffer.
105
	 */
106
	if (cmd == CHANGE && cmdp->addr1.lno != 0 &&
107
	    (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) ||
108
	    del(sp, &cmdp->addr1, &cmdp->addr2, 1)))
109
		return (1);
110
111
	/*
112
	 * !!!
113
	 * Anything that was left after the command separator becomes part
114
	 * of the inserted text.  Apparently, it was common usage to enter:
115
	 *
116
	 *	:g/pattern/append|stuff1
117
	 *
118
	 * and append the line of text "stuff1" to the lines containing the
119
	 * pattern.  It was also historically legal to enter:
120
	 *
121
	 *	:append|stuff1
122
	 *	stuff2
123
	 *	.
124
	 *
125
	 * and the text on the ex command line would be appended as well as
126
	 * the text inserted after it.  There was an historic bug however,
127
	 * that the user had to enter *two* terminating lines (the '.' lines)
128
	 * to terminate text input mode, in this case.  This whole thing
129
	 * could be taken too far, however.  Entering:
130
	 *
131
	 *	:append|stuff1\
132
	 *	stuff2
133
	 *	stuff3
134
	 *	.
135
	 *
136
	 * i.e. mixing and matching the forms confused the historic vi, and,
137
	 * not only did it take two terminating lines to terminate text input
138
	 * mode, but the trailing backslashes were retained on the input.  We
139
	 * match historic practice except that we discard the backslashes.
140
	 *
141
	 * Input lines specified on the ex command line lines are separated by
142
	 * <newline>s.  If there is a trailing delimiter an empty line was
143
	 * inserted.  There may also be a leading delimiter, which is ignored
144
	 * unless it's also a trailing delimiter.  It is possible to encounter
145
	 * a termination line, i.e. a single '.', in a global command, but not
146
	 * necessary if the text insert command was the last of the global
147
	 * commands.
148
	 */
149
	if (cmdp->save_cmdlen != 0) {
150
		for (p = cmdp->save_cmd,
151
		    len = cmdp->save_cmdlen; len > 0; p = t) {
152
			for (t = p; len > 0 && t[0] != '\n'; ++t, --len);
153
			if (t != p || len == 0) {
154
				if (F_ISSET(sp, SC_EX_GLOBAL) &&
155
				    t - p == 1 && p[0] == '.') {
156
					++t;
157
					if (len > 0)
158
						--len;
159
					break;
160
				}
161
				if (db_append(sp, 1, lno++, p, t - p))
162
					return (1);
163
			}
164
			if (len != 0) {
165
				++t;
166
				if (--len == 0 &&
167
				    db_append(sp, 1, lno++, "", 0))
168
					return (1);
169
			}
170
		}
171
		/*
172
		 * If there's any remaining text, we're in a global, and
173
		 * there's more command to parse.
174
		 *
175
		 * !!!
176
		 * We depend on the fact that non-global commands will eat the
177
		 * rest of the command line as text input, and before getting
178
		 * any text input from the user.  Otherwise, we'd have to save
179
		 * off the command text before or during the call to the text
180
		 * input function below.
181
		 */
182
		if (len != 0)
183
			cmdp->save_cmd = t;
184
		cmdp->save_cmdlen = len;
185
	}
186
187
	if (F_ISSET(sp, SC_EX_GLOBAL)) {
188
		if ((sp->lno = lno) == 0 && db_exist(sp, 1))
189
			sp->lno = 1;
190
		return (0);
191
	}
192
193
	/*
194
	 * If not in a global command, read from the terminal.
195
	 *
196
	 * If this code is called by vi, we want to reset the terminal and use
197
	 * ex's line get routine.  It actually works fine if we use vi's get
198
	 * routine, but it doesn't look as nice.  Maybe if we had a separate
199
	 * window or something, but getting a line at a time looks awkward.
200
	 * However, depending on the screen that we're using, that may not
201
	 * be possible.
202
	 */
203
	if (F_ISSET(sp, SC_VI)) {
204
		if (gp->scr_screen(sp, SC_EX)) {
205
			ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
206
			return (1);
207
		}
208
209
		/* If we're still in the vi screen, move out explicitly. */
210
		need_newline = !F_ISSET(sp, SC_SCR_EXWROTE);
211
		F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
212
		if (need_newline)
213
			(void)ex_puts(sp, "\n");
214
215
		/*
216
		 * !!!
217
		 * Users of historical versions of vi sometimes get confused
218
		 * when they enter append mode, and can't seem to get out of
219
		 * it.  Give them an informational message.
220
		 */
221
		(void)ex_puts(sp, "Entering ex input mode.\n");
222
		(void)ex_fflush(sp);
223
	}
224
225
	/*
226
	 * Set input flags; the ! flag turns off autoindent for append,
227
	 * change and insert.
228
	 */
229
	LF_INIT(TXT_DOTTERM | TXT_NUMBER);
230
	if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT))
231
		LF_SET(TXT_AUTOINDENT);
232
	if (O_ISSET(sp, O_BEAUTIFY))
233
		LF_SET(TXT_BEAUTIFY);
234
235
	/*
236
	 * This code can't use the common screen TEXTH structure (sp->tiq),
237
	 * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail
238
	 * as we are only halfway through the text when the append code fires.
239
	 * Use a local structure instead.  (The ex code would have to use a
240
	 * local structure except that we're guaranteed to finish remaining
241
	 * characters in the common TEXTH structure when they were inserted
242
	 * into the file, above.)
243
	 */
244
	memset(&tiq, 0, sizeof(TEXTH));
245
	TAILQ_INIT(&tiq);
246
247
	if (ex_txt(sp, &tiq, 0, flags))
248
		return (1);
249
250
	cnt = 0;
251
	TAILQ_FOREACH(tp, &tiq, q) {
252
		if (db_append(sp, 1, lno++, tp->lb, tp->len))
253
			return (1);
254
		cnt++;
255
	}
256
257
	/*
258
	 * Set sp->lno to the final line number value (correcting for a
259
	 * possible 0 value) as that's historically correct for the final
260
	 * line value, whether or not the user entered any text.
261
	 */
262
	if ((sp->lno = lno) == 0 && db_exist(sp, 1))
263
		sp->lno = 1;
264
265
	return (0);
266
}