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