align CHAR_T string in log
[nvi.git] / ex / ex_append.c
blobffc0c121f4101c70e38495fe74efb99b3debceba
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: ex_append.c,v 10.32 2000/07/14 14:29:19 skimo Exp $ (Berkeley) $Date: 2000/07/14 14:29:19 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <bitstring.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "../common/common.h"
27 enum which {APPEND, CHANGE, INSERT};
29 static int ex_aci __P((SCR *, EXCMD *, enum which));
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.
36 * PUBLIC: int ex_append __P((SCR *, EXCMD *));
38 int
39 ex_append(sp, cmdp)
40 SCR *sp;
41 EXCMD *cmdp;
43 return (ex_aci(sp, cmdp, APPEND));
47 * ex_change -- :[line[,line]] c[hange][!] [count]
48 * Change one or more lines to the input text.
50 * PUBLIC: int ex_change __P((SCR *, EXCMD *));
52 int
53 ex_change(sp, cmdp)
54 SCR *sp;
55 EXCMD *cmdp;
57 return (ex_aci(sp, cmdp, CHANGE));
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.
65 * PUBLIC: int ex_insert __P((SCR *, EXCMD *));
67 int
68 ex_insert(sp, cmdp)
69 SCR *sp;
70 EXCMD *cmdp;
72 return (ex_aci(sp, cmdp, INSERT));
76 * ex_aci --
77 * Append, change, insert in ex.
79 static int
80 ex_aci(sp, cmdp, cmd)
81 SCR *sp;
82 EXCMD *cmdp;
83 enum which cmd;
85 CHAR_T *p, *t;
86 GS *gp;
87 TEXT *tp;
88 TEXTH tiq;
89 db_recno_t cnt, lno;
90 size_t len;
91 u_int32_t flags;
92 int need_newline;
94 gp = sp->gp;
95 NEEDFILE(sp, cmdp);
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.
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.
108 lno = cmdp->addr1.lno;
109 sp->lno = lno;
110 if ((cmd == CHANGE || cmd == INSERT) && lno != 0)
111 --lno;
114 * !!!
115 * If the file isn't empty, cut changes into the unnamed buffer.
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);
123 * !!!
124 * Anything that was left after the command separator becomes part
125 * of the inserted text. Apparently, it was common usage to enter:
127 * :g/pattern/append|stuff1
129 * and append the line of text "stuff1" to the lines containing the
130 * pattern. It was also historically legal to enter:
132 * :append|stuff1
133 * stuff2
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:
142 * :append|stuff1\
143 * stuff2
144 * stuff3
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.
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.
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;
172 if (db_append(sp, 1, lno++, p, t - p))
173 return (1);
175 if (len != 0) {
176 ++t;
177 if (--len == 0 &&
178 db_append(sp, 1, lno++, NULL, 0))
179 return (1);
183 * If there's any remaining text, we're in a global, and
184 * there's more command to parse.
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.
193 if (len != 0)
194 cmdp->save_cmd = t;
195 cmdp->save_cmdlen = len;
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);
205 * If not in a global command, read from the terminal.
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.
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);
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");
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.
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);
239 * Set input flags; the ! flag turns off autoindent for append,
240 * change and insert.
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);
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.)
257 memset(&tiq, 0, sizeof(TEXTH));
258 CIRCLEQ_INIT(&tiq);
260 if (ex_txt(sp, &tiq, 0, flags))
261 return (1);
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);
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.
273 if ((sp->lno = lno) == 0 && db_exist(sp, 1))
274 sp->lno = 1;
276 return (0);