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