xref: /openbsd/usr.bin/vi/ex/ex_append.c (revision 721c3ea3)
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
ex_append(SCR * sp,EXCMD * cmdp)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
ex_change(SCR * sp,EXCMD * cmdp)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
ex_insert(SCR * sp,EXCMD * cmdp)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
ex_aci(SCR * sp,EXCMD * cmdp,enum which cmd)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 }
267