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 #include <sys/types.h>
13 #include <sys/queue.h>
14 #include <sys/time.h>
15
16 #include <bitstring.h>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include "../common/common.h"
23
24 enum which {APPEND, CHANGE, INSERT};
25
26 static int ex_aci(SCR *, EXCMD *, enum which);
27
28 /*
29 * ex_append -- :[line] a[ppend][!]
30 * Append one or more lines of new text after the specified line,
31 * or the current line if no address is specified.
32 *
33 * PUBLIC: int ex_append(SCR *, EXCMD *);
34 */
35 int
ex_append(SCR * sp,EXCMD * cmdp)36 ex_append(SCR *sp, EXCMD *cmdp)
37 {
38 return (ex_aci(sp, cmdp, APPEND));
39 }
40
41 /*
42 * ex_change -- :[line[,line]] c[hange][!] [count]
43 * Change one or more lines to the input text.
44 *
45 * PUBLIC: int ex_change(SCR *, EXCMD *);
46 */
47 int
ex_change(SCR * sp,EXCMD * cmdp)48 ex_change(SCR *sp, EXCMD *cmdp)
49 {
50 return (ex_aci(sp, cmdp, CHANGE));
51 }
52
53 /*
54 * ex_insert -- :[line] i[nsert][!]
55 * Insert one or more lines of new text before the specified line,
56 * or the current line if no address is specified.
57 *
58 * PUBLIC: int ex_insert(SCR *, EXCMD *);
59 */
60 int
ex_insert(SCR * sp,EXCMD * cmdp)61 ex_insert(SCR *sp, EXCMD *cmdp)
62 {
63 return (ex_aci(sp, cmdp, INSERT));
64 }
65
66 /*
67 * ex_aci --
68 * Append, change, insert in ex.
69 */
70 static int
ex_aci(SCR * sp,EXCMD * cmdp,enum which cmd)71 ex_aci(SCR *sp, EXCMD *cmdp, enum which cmd)
72 {
73 CHAR_T *p, *t;
74 GS *gp;
75 TEXT *tp;
76 TEXTH tiq[] = {{ 0 }};
77 recno_t cnt = 0, lno;
78 size_t len;
79 u_int32_t flags;
80 int need_newline;
81
82 gp = sp->gp;
83 NEEDFILE(sp, cmdp);
84
85 /*
86 * If doing a change, replace lines for as long as possible. Then,
87 * append more lines or delete remaining lines. Changes to an empty
88 * file are appends, inserts are the same as appends to the previous
89 * line.
90 *
91 * !!!
92 * Set the address to which we'll append. We set sp->lno to this
93 * address as well so that autoindent works correctly when get text
94 * from the user.
95 */
96 lno = cmdp->addr1.lno;
97 sp->lno = lno;
98 if ((cmd == CHANGE || cmd == INSERT) && lno != 0)
99 --lno;
100
101 /*
102 * !!!
103 * If the file isn't empty, cut changes into the unnamed buffer.
104 */
105 if (cmd == CHANGE && cmdp->addr1.lno != 0 &&
106 (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) ||
107 del(sp, &cmdp->addr1, &cmdp->addr2, 1)))
108 return (1);
109
110 /*
111 * !!!
112 * Anything that was left after the command separator becomes part
113 * of the inserted text. Apparently, it was common usage to enter:
114 *
115 * :g/pattern/append|stuff1
116 *
117 * and append the line of text "stuff1" to the lines containing the
118 * pattern. It was also historically legal to enter:
119 *
120 * :append|stuff1
121 * stuff2
122 * .
123 *
124 * and the text on the ex command line would be appended as well as
125 * the text inserted after it. There was an historic bug however,
126 * that the user had to enter *two* terminating lines (the '.' lines)
127 * to terminate text input mode, in this case. This whole thing
128 * could be taken too far, however. Entering:
129 *
130 * :append|stuff1\
131 * stuff2
132 * stuff3
133 * .
134 *
135 * i.e. mixing and matching the forms confused the historic vi, and,
136 * not only did it take two terminating lines to terminate text input
137 * mode, but the trailing backslashes were retained on the input. We
138 * match historic practice except that we discard the backslashes.
139 *
140 * Input lines specified on the ex command line lines are separated by
141 * <newline>s. If there is a trailing delimiter an empty line was
142 * inserted. There may also be a leading delimiter, which is ignored
143 * unless it's also a trailing delimiter. It is possible to encounter
144 * a termination line, i.e. a single '.', in a global command, but not
145 * necessary if the text insert command was the last of the global
146 * commands.
147 */
148 if (cmdp->save_cmdlen != 0) {
149 for (p = cmdp->save_cmd,
150 len = cmdp->save_cmdlen; len > 0; p = t) {
151 for (t = p; len > 0 && t[0] != '\n'; ++t, --len);
152 if (F_ISSET(sp, SC_EX_GLOBAL) &&
153 t - p == 1 && p[0] == '.') {
154 ++t;
155 if (len > 0)
156 --len;
157 break;
158 }
159 if (db_append(sp, 1, lno++, p, t - p))
160 return (1);
161 if (len != 0) {
162 ++t;
163 if (--len == 0 &&
164 db_append(sp, 1, lno++, NULL, 0))
165 return (1);
166 }
167 }
168 /*
169 * If there's any remaining text, we're in a global, and
170 * there's more command to parse.
171 *
172 * !!!
173 * We depend on the fact that non-global commands will eat the
174 * rest of the command line as text input, and before getting
175 * any text input from the user. Otherwise, we'd have to save
176 * off the command text before or during the call to the text
177 * input function below.
178 */
179 if (len != 0)
180 cmdp->save_cmd = t;
181 cmdp->save_cmdlen = len;
182 } else if (cmdp->trailing) {
183 if (db_append(sp, 1, lno++, NULL, 0))
184 return 1;
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_wemsg(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,
222 msg_cat(sp, "273|Entering ex input mode.", NULL));
223 (void)ex_puts(sp, "\n");
224 (void)ex_fflush(sp);
225 }
226
227 /*
228 * Set input flags; the ! flag turns off autoindent for append,
229 * change and insert.
230 */
231 LF_INIT(TXT_DOTTERM | TXT_NUMBER);
232 if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT))
233 LF_SET(TXT_AUTOINDENT);
234 if (O_ISSET(sp, O_BEAUTIFY))
235 LF_SET(TXT_BEAUTIFY);
236
237 /*
238 * This code can't use the common screen TEXTH structure (sp->tiq),
239 * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail
240 * as we are only halfway through the text when the append code fires.
241 * Use a local structure instead. (The ex code would have to use a
242 * local structure except that we're guaranteed to finish remaining
243 * characters in the common TEXTH structure when they were inserted
244 * into the file, above.)
245 */
246 TAILQ_INIT(tiq);
247
248 if (ex_txt(sp, tiq, 0, flags))
249 return (1);
250
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