Merge from vendor branch LIBPCAP:
[dragonfly.git] / contrib / nvi / ex / ex_append.c
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
13 static 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
27 enum which {APPEND, CHANGE, INSERT};
28
29 static 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  */
38 int
39 ex_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  */
52 int
53 ex_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  */
67 int
68 ex_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  */
79 static int
80 ex_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 }