1b8ba871bSPeter Wemm /*-
2b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994
3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved.
4b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994, 1995, 1996
5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved.
6b8ba871bSPeter Wemm *
7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information.
8b8ba871bSPeter Wemm */
9b8ba871bSPeter Wemm
10b8ba871bSPeter Wemm #include "config.h"
11b8ba871bSPeter Wemm
12b8ba871bSPeter Wemm #include <sys/types.h>
13b8ba871bSPeter Wemm #include <sys/queue.h>
14b8ba871bSPeter Wemm #include <sys/time.h>
15b8ba871bSPeter Wemm
16b8ba871bSPeter Wemm #include <bitstring.h>
17b8ba871bSPeter Wemm #include <limits.h>
18b8ba871bSPeter Wemm #include <stdio.h>
19b8ba871bSPeter Wemm #include <stdlib.h>
20b8ba871bSPeter Wemm #include <string.h>
21b8ba871bSPeter Wemm #include <unistd.h>
22b8ba871bSPeter Wemm
23b8ba871bSPeter Wemm #include "../common/common.h"
24b8ba871bSPeter Wemm #include "vi.h"
25b8ba871bSPeter Wemm
26b8ba871bSPeter Wemm static int v_ecl(SCR *);
27b8ba871bSPeter Wemm static int v_ecl_init(SCR *);
28b8ba871bSPeter Wemm static int v_ecl_log(SCR *, TEXT *);
29b8ba871bSPeter Wemm static int v_ex_done(SCR *, VICMD *);
30b8ba871bSPeter Wemm static int v_exec_ex(SCR *, VICMD *, EXCMD *);
31b8ba871bSPeter Wemm
32b8ba871bSPeter Wemm /*
33b8ba871bSPeter Wemm * v_again -- &
34b8ba871bSPeter Wemm * Repeat the previous substitution.
35b8ba871bSPeter Wemm *
36b8ba871bSPeter Wemm * PUBLIC: int v_again(SCR *, VICMD *);
37b8ba871bSPeter Wemm */
38b8ba871bSPeter Wemm int
v_again(SCR * sp,VICMD * vp)39b8ba871bSPeter Wemm v_again(SCR *sp, VICMD *vp)
40b8ba871bSPeter Wemm {
41b8ba871bSPeter Wemm EXCMD cmd;
42b8ba871bSPeter Wemm
43b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1);
44b8ba871bSPeter Wemm argv_exp0(sp, &cmd, L(""), 1);
45b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
46b8ba871bSPeter Wemm }
47b8ba871bSPeter Wemm
48b8ba871bSPeter Wemm /*
49b8ba871bSPeter Wemm * v_exmode -- Q
50b8ba871bSPeter Wemm * Switch the editor into EX mode.
51b8ba871bSPeter Wemm *
52b8ba871bSPeter Wemm * PUBLIC: int v_exmode(SCR *, VICMD *);
53b8ba871bSPeter Wemm */
54b8ba871bSPeter Wemm int
v_exmode(SCR * sp,VICMD * vp)55b8ba871bSPeter Wemm v_exmode(SCR *sp, VICMD *vp)
56b8ba871bSPeter Wemm {
57b8ba871bSPeter Wemm GS *gp;
58b8ba871bSPeter Wemm
59b8ba871bSPeter Wemm gp = sp->gp;
60b8ba871bSPeter Wemm
61b8ba871bSPeter Wemm /* Try and switch screens -- the screen may not permit it. */
62b8ba871bSPeter Wemm if (gp->scr_screen(sp, SC_EX)) {
63b8ba871bSPeter Wemm msgq(sp, M_ERR,
64b8ba871bSPeter Wemm "207|The Q command requires the ex terminal interface");
65b8ba871bSPeter Wemm return (1);
66b8ba871bSPeter Wemm }
67b8ba871bSPeter Wemm (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
68b8ba871bSPeter Wemm
69b8ba871bSPeter Wemm /* Save the current cursor position. */
70b8ba871bSPeter Wemm sp->frp->lno = sp->lno;
71b8ba871bSPeter Wemm sp->frp->cno = sp->cno;
72b8ba871bSPeter Wemm F_SET(sp->frp, FR_CURSORSET);
73b8ba871bSPeter Wemm
74b8ba871bSPeter Wemm /* Switch to ex mode. */
75b8ba871bSPeter Wemm F_CLR(sp, SC_VI | SC_SCR_VI);
76b8ba871bSPeter Wemm F_SET(sp, SC_EX);
77b8ba871bSPeter Wemm
78b8ba871bSPeter Wemm /* Move out of the vi screen. */
79b8ba871bSPeter Wemm (void)ex_puts(sp, "\n");
80b8ba871bSPeter Wemm
81b8ba871bSPeter Wemm return (0);
82b8ba871bSPeter Wemm }
83b8ba871bSPeter Wemm
84b8ba871bSPeter Wemm /*
85b8ba871bSPeter Wemm * v_join -- [count]J
86b8ba871bSPeter Wemm * Join lines together.
87b8ba871bSPeter Wemm *
88b8ba871bSPeter Wemm * PUBLIC: int v_join(SCR *, VICMD *);
89b8ba871bSPeter Wemm */
90b8ba871bSPeter Wemm int
v_join(SCR * sp,VICMD * vp)91b8ba871bSPeter Wemm v_join(SCR *sp, VICMD *vp)
92b8ba871bSPeter Wemm {
93b8ba871bSPeter Wemm EXCMD cmd;
94b8ba871bSPeter Wemm int lno;
95b8ba871bSPeter Wemm
96b8ba871bSPeter Wemm /*
97b8ba871bSPeter Wemm * YASC.
98b8ba871bSPeter Wemm * The general rule is that '#J' joins # lines, counting the current
99b8ba871bSPeter Wemm * line. However, 'J' and '1J' are the same as '2J', i.e. join the
100b8ba871bSPeter Wemm * current and next lines. This doesn't map well into the ex command
101b8ba871bSPeter Wemm * (which takes two line numbers), so we handle it here. Note that
102b8ba871bSPeter Wemm * we never test for EOF -- historically going past the end of file
103b8ba871bSPeter Wemm * worked just fine.
104b8ba871bSPeter Wemm */
105b8ba871bSPeter Wemm lno = vp->m_start.lno + 1;
106b8ba871bSPeter Wemm if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
107b8ba871bSPeter Wemm lno = vp->m_start.lno + (vp->count - 1);
108b8ba871bSPeter Wemm
109b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_JOIN, 2, vp->m_start.lno, lno, 0);
110b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
111b8ba871bSPeter Wemm }
112b8ba871bSPeter Wemm
113b8ba871bSPeter Wemm /*
114b8ba871bSPeter Wemm * v_shiftl -- [count]<motion
115b8ba871bSPeter Wemm * Shift lines left.
116b8ba871bSPeter Wemm *
117b8ba871bSPeter Wemm * PUBLIC: int v_shiftl(SCR *, VICMD *);
118b8ba871bSPeter Wemm */
119b8ba871bSPeter Wemm int
v_shiftl(SCR * sp,VICMD * vp)120b8ba871bSPeter Wemm v_shiftl(SCR *sp, VICMD *vp)
121b8ba871bSPeter Wemm {
122b8ba871bSPeter Wemm EXCMD cmd;
123b8ba871bSPeter Wemm
124b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0);
125b8ba871bSPeter Wemm argv_exp0(sp, &cmd, L("<"), 2);
126b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
127b8ba871bSPeter Wemm }
128b8ba871bSPeter Wemm
129b8ba871bSPeter Wemm /*
130b8ba871bSPeter Wemm * v_shiftr -- [count]>motion
131b8ba871bSPeter Wemm * Shift lines right.
132b8ba871bSPeter Wemm *
133b8ba871bSPeter Wemm * PUBLIC: int v_shiftr(SCR *, VICMD *);
134b8ba871bSPeter Wemm */
135b8ba871bSPeter Wemm int
v_shiftr(SCR * sp,VICMD * vp)136b8ba871bSPeter Wemm v_shiftr(SCR *sp, VICMD *vp)
137b8ba871bSPeter Wemm {
138b8ba871bSPeter Wemm EXCMD cmd;
139b8ba871bSPeter Wemm
140b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0);
141b8ba871bSPeter Wemm argv_exp0(sp, &cmd, L(">"), 2);
142b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
143b8ba871bSPeter Wemm }
144b8ba871bSPeter Wemm
145b8ba871bSPeter Wemm /*
146b8ba871bSPeter Wemm * v_suspend -- ^Z
147b8ba871bSPeter Wemm * Suspend vi.
148b8ba871bSPeter Wemm *
149b8ba871bSPeter Wemm * PUBLIC: int v_suspend(SCR *, VICMD *);
150b8ba871bSPeter Wemm */
151b8ba871bSPeter Wemm int
v_suspend(SCR * sp,VICMD * vp)152b8ba871bSPeter Wemm v_suspend(SCR *sp, VICMD *vp)
153b8ba871bSPeter Wemm {
154b8ba871bSPeter Wemm EXCMD cmd;
155b8ba871bSPeter Wemm
156b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_STOP, 0, OOBLNO, OOBLNO, 0);
157b8ba871bSPeter Wemm argv_exp0(sp, &cmd, L("suspend"), SIZE(L("suspend")));
158b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
159b8ba871bSPeter Wemm }
160b8ba871bSPeter Wemm
161b8ba871bSPeter Wemm /*
162b8ba871bSPeter Wemm * v_switch -- ^^
163b8ba871bSPeter Wemm * Switch to the previous file.
164b8ba871bSPeter Wemm *
165b8ba871bSPeter Wemm * PUBLIC: int v_switch(SCR *, VICMD *);
166b8ba871bSPeter Wemm */
167b8ba871bSPeter Wemm int
v_switch(SCR * sp,VICMD * vp)168b8ba871bSPeter Wemm v_switch(SCR *sp, VICMD *vp)
169b8ba871bSPeter Wemm {
170b8ba871bSPeter Wemm EXCMD cmd;
171b8ba871bSPeter Wemm char *name;
172b8ba871bSPeter Wemm CHAR_T *wp;
173b8ba871bSPeter Wemm size_t wlen;
174b8ba871bSPeter Wemm
175b8ba871bSPeter Wemm /*
176b8ba871bSPeter Wemm * Try the alternate file name, then the previous file
177b8ba871bSPeter Wemm * name. Use the real name, not the user's current name.
178b8ba871bSPeter Wemm */
179b8ba871bSPeter Wemm if ((name = sp->alt_name) == NULL) {
180b8ba871bSPeter Wemm msgq(sp, M_ERR, "180|No previous file to edit");
181b8ba871bSPeter Wemm return (1);
182b8ba871bSPeter Wemm }
183b8ba871bSPeter Wemm
184b8ba871bSPeter Wemm /* If autowrite is set, write out the file. */
185b8ba871bSPeter Wemm if (file_m1(sp, 0, FS_ALL))
186b8ba871bSPeter Wemm return (1);
187b8ba871bSPeter Wemm
188b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
189b8ba871bSPeter Wemm CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
190b8ba871bSPeter Wemm argv_exp0(sp, &cmd, wp, wlen);
191b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
192b8ba871bSPeter Wemm }
193b8ba871bSPeter Wemm
194b8ba871bSPeter Wemm /*
195b8ba871bSPeter Wemm * v_tagpush -- ^[
196b8ba871bSPeter Wemm * Do a tag search on the cursor keyword.
197b8ba871bSPeter Wemm *
198b8ba871bSPeter Wemm * PUBLIC: int v_tagpush(SCR *, VICMD *);
199b8ba871bSPeter Wemm */
200b8ba871bSPeter Wemm int
v_tagpush(SCR * sp,VICMD * vp)201b8ba871bSPeter Wemm v_tagpush(SCR *sp, VICMD *vp)
202b8ba871bSPeter Wemm {
203b8ba871bSPeter Wemm EXCMD cmd;
204b8ba871bSPeter Wemm
205b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, 0, 0);
206b8ba871bSPeter Wemm argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw) + 1);
207b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
208b8ba871bSPeter Wemm }
209b8ba871bSPeter Wemm
210b8ba871bSPeter Wemm /*
211b8ba871bSPeter Wemm * v_tagpop -- ^T
212b8ba871bSPeter Wemm * Pop the tags stack.
213b8ba871bSPeter Wemm *
214b8ba871bSPeter Wemm * PUBLIC: int v_tagpop(SCR *, VICMD *);
215b8ba871bSPeter Wemm */
216b8ba871bSPeter Wemm int
v_tagpop(SCR * sp,VICMD * vp)217b8ba871bSPeter Wemm v_tagpop(SCR *sp, VICMD *vp)
218b8ba871bSPeter Wemm {
219b8ba871bSPeter Wemm EXCMD cmd;
220b8ba871bSPeter Wemm
221b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_TAGPOP, 0, OOBLNO, 0, 0);
222b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
223b8ba871bSPeter Wemm }
224b8ba871bSPeter Wemm
225b8ba871bSPeter Wemm /*
226b8ba871bSPeter Wemm * v_filter -- [count]!motion command(s)
227b8ba871bSPeter Wemm * Run range through shell commands, replacing text.
228b8ba871bSPeter Wemm *
229e56a7205SJordan K. Hubbard * PUBLIC: int v_filter(SCR *, VICMD *);
230e56a7205SJordan K. Hubbard */
231e56a7205SJordan K. Hubbard int
v_filter(SCR * sp,VICMD * vp)232e56a7205SJordan K. Hubbard v_filter(SCR *sp, VICMD *vp)
233e56a7205SJordan K. Hubbard {
234b8ba871bSPeter Wemm EXCMD cmd;
235b8ba871bSPeter Wemm TEXT *tp;
236b8ba871bSPeter Wemm
237b8ba871bSPeter Wemm /*
238b8ba871bSPeter Wemm * !!!
239b8ba871bSPeter Wemm * Historical vi permitted "!!" in an empty file, and it's handled
240b8ba871bSPeter Wemm * as a special case in the ex_bang routine. Don't modify this setup
241b8ba871bSPeter Wemm * without understanding that one. In particular, note that we're
242b8ba871bSPeter Wemm * manipulating the ex argument structures behind ex's back.
243b8ba871bSPeter Wemm *
244b8ba871bSPeter Wemm * !!!
245b8ba871bSPeter Wemm * Historical vi did not permit the '!' command to be associated with
246b8ba871bSPeter Wemm * a non-line oriented motion command, in general, although it did
247b8ba871bSPeter Wemm * with search commands. So, !f; and !w would fail, but !/;<CR>
248b8ba871bSPeter Wemm * would succeed, even if they all moved to the same location in the
249b8ba871bSPeter Wemm * current line. I don't see any reason to disallow '!' using any of
250b8ba871bSPeter Wemm * the possible motion commands.
251b8ba871bSPeter Wemm *
252b8ba871bSPeter Wemm * !!!
253b8ba871bSPeter Wemm * Historical vi ran the last bang command if N or n was used as the
254b8ba871bSPeter Wemm * search motion.
255b8ba871bSPeter Wemm */
256b8ba871bSPeter Wemm if (F_ISSET(vp, VC_ISDOT) ||
257b8ba871bSPeter Wemm ISCMD(vp->rkp, 'N') || ISCMD(vp->rkp, 'n')) {
258b8ba871bSPeter Wemm ex_cinit(sp,
259b8ba871bSPeter Wemm &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0);
260b8ba871bSPeter Wemm EXP(sp)->argsoff = 0; /* XXX */
261b8ba871bSPeter Wemm
262b8ba871bSPeter Wemm if (argv_exp1(sp, &cmd, L("!"), 1, 1))
263b8ba871bSPeter Wemm return (1);
264b8ba871bSPeter Wemm cmd.argc = EXP(sp)->argsoff; /* XXX */
265b8ba871bSPeter Wemm cmd.argv = EXP(sp)->args; /* XXX */
266b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
267b8ba871bSPeter Wemm }
268b8ba871bSPeter Wemm
269b8ba871bSPeter Wemm /* Get the command from the user. */
270b8ba871bSPeter Wemm if (v_tcmd(sp, vp,
271b8ba871bSPeter Wemm '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_FILEC | TXT_PROMPT))
272b8ba871bSPeter Wemm return (1);
273b8ba871bSPeter Wemm
274b8ba871bSPeter Wemm /*
275b8ba871bSPeter Wemm * Check to see if the user changed their mind.
276b8ba871bSPeter Wemm *
277b8ba871bSPeter Wemm * !!!
278b8ba871bSPeter Wemm * Entering <escape> on an empty line was historically an error,
279b8ba871bSPeter Wemm * this implementation doesn't bother.
280b8ba871bSPeter Wemm */
281b8ba871bSPeter Wemm tp = TAILQ_FIRST(sp->tiq);
282b8ba871bSPeter Wemm if (tp->term != TERM_OK) {
283b8ba871bSPeter Wemm vp->m_final.lno = sp->lno;
284b8ba871bSPeter Wemm vp->m_final.cno = sp->cno;
285b8ba871bSPeter Wemm return (0);
286b8ba871bSPeter Wemm }
287b8ba871bSPeter Wemm
288b8ba871bSPeter Wemm /* Home the cursor. */
289b8ba871bSPeter Wemm vs_home(sp);
290b8ba871bSPeter Wemm
291b8ba871bSPeter Wemm ex_cinit(sp, &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0);
292b8ba871bSPeter Wemm EXP(sp)->argsoff = 0; /* XXX */
293b8ba871bSPeter Wemm
294b8ba871bSPeter Wemm if (argv_exp1(sp, &cmd, tp->lb + 1, tp->len - 1, 1))
295b8ba871bSPeter Wemm return (1);
296b8ba871bSPeter Wemm cmd.argc = EXP(sp)->argsoff; /* XXX */
297b8ba871bSPeter Wemm cmd.argv = EXP(sp)->args; /* XXX */
298b8ba871bSPeter Wemm return (v_exec_ex(sp, vp, &cmd));
299b8ba871bSPeter Wemm }
300b8ba871bSPeter Wemm
301b8ba871bSPeter Wemm /*
302b8ba871bSPeter Wemm * v_exec_ex --
303b8ba871bSPeter Wemm * Execute an ex command.
304b8ba871bSPeter Wemm */
305b8ba871bSPeter Wemm static int
v_exec_ex(SCR * sp,VICMD * vp,EXCMD * exp)306b8ba871bSPeter Wemm v_exec_ex(SCR *sp, VICMD *vp, EXCMD *exp)
307b8ba871bSPeter Wemm {
308b8ba871bSPeter Wemm int rval;
309b8ba871bSPeter Wemm
310b8ba871bSPeter Wemm rval = exp->cmd->fn(sp, exp);
311b8ba871bSPeter Wemm return (v_ex_done(sp, vp) || rval);
312b8ba871bSPeter Wemm }
313b8ba871bSPeter Wemm
314b8ba871bSPeter Wemm /*
315b8ba871bSPeter Wemm * v_ex -- :
316b8ba871bSPeter Wemm * Execute a colon command line.
317b8ba871bSPeter Wemm *
318b8ba871bSPeter Wemm * PUBLIC: int v_ex(SCR *, VICMD *);
319b8ba871bSPeter Wemm */
320b8ba871bSPeter Wemm int
v_ex(SCR * sp,VICMD * vp)321b8ba871bSPeter Wemm v_ex(SCR *sp, VICMD *vp)
322b8ba871bSPeter Wemm {
323b8ba871bSPeter Wemm GS *gp;
324b8ba871bSPeter Wemm TEXT *tp;
325b8ba871bSPeter Wemm int do_cedit, do_resolution, ifcontinue;
326b8ba871bSPeter Wemm
327b8ba871bSPeter Wemm gp = sp->gp;
328b8ba871bSPeter Wemm
329b8ba871bSPeter Wemm /*
330b8ba871bSPeter Wemm * !!!
331b8ba871bSPeter Wemm * If we put out more than a single line of messages, or ex trashes
332b8ba871bSPeter Wemm * the screen, the user may continue entering ex commands. We find
333b8ba871bSPeter Wemm * this out when we do the screen/message resolution. We can't enter
334b8ba871bSPeter Wemm * completely into ex mode however, because the user can elect to
335b8ba871bSPeter Wemm * return into vi mode by entering any key, i.e. we have to be in raw
336b8ba871bSPeter Wemm * mode.
337b8ba871bSPeter Wemm */
338b8ba871bSPeter Wemm for (do_cedit = do_resolution = 0;;) {
339b8ba871bSPeter Wemm /*
340b8ba871bSPeter Wemm * !!!
341b8ba871bSPeter Wemm * There may already be an ex command waiting to run. If
342b8ba871bSPeter Wemm * so, we continue with it.
343b8ba871bSPeter Wemm */
344b8ba871bSPeter Wemm if (!EXCMD_RUNNING(gp)) {
345b8ba871bSPeter Wemm /* Get a command. */
346b8ba871bSPeter Wemm if (v_tcmd(sp, vp, ':',
347b8ba871bSPeter Wemm TXT_BS | TXT_CEDIT | TXT_FILEC | TXT_PROMPT))
348b8ba871bSPeter Wemm return (1);
349b8ba871bSPeter Wemm tp = TAILQ_FIRST(sp->tiq);
350b8ba871bSPeter Wemm
351b8ba871bSPeter Wemm /*
352b8ba871bSPeter Wemm * If the user entered a single <esc>, they want to
353b8ba871bSPeter Wemm * edit their colon command history. If they already
354b8ba871bSPeter Wemm * entered some text, move it into the edit history.
355b8ba871bSPeter Wemm */
356b8ba871bSPeter Wemm if (tp->term == TERM_CEDIT) {
357b8ba871bSPeter Wemm if (tp->len > 1 && v_ecl_log(sp, tp))
358b8ba871bSPeter Wemm return (1);
359b8ba871bSPeter Wemm do_cedit = 1;
360b8ba871bSPeter Wemm break;
361b8ba871bSPeter Wemm }
362b8ba871bSPeter Wemm
363b8ba871bSPeter Wemm /* If the user didn't enter anything, return. */
364b8ba871bSPeter Wemm if (tp->term == TERM_BS)
365b8ba871bSPeter Wemm break;
366b8ba871bSPeter Wemm
367b8ba871bSPeter Wemm /* If the user changed their mind, return. */
368b8ba871bSPeter Wemm if (tp->term != TERM_OK)
369b8ba871bSPeter Wemm break;
370b8ba871bSPeter Wemm
371b8ba871bSPeter Wemm /* Log the command. */
372b8ba871bSPeter Wemm if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp))
373b8ba871bSPeter Wemm return (1);
374b8ba871bSPeter Wemm
375b8ba871bSPeter Wemm /* Push a command on the command stack. */
376b8ba871bSPeter Wemm if (ex_run_str(sp, NULL, tp->lb, tp->len, 0, 1))
377b8ba871bSPeter Wemm return (1);
378b8ba871bSPeter Wemm }
379b8ba871bSPeter Wemm
380b8ba871bSPeter Wemm /* Home the cursor. */
381b8ba871bSPeter Wemm vs_home(sp);
382b8ba871bSPeter Wemm
383b8ba871bSPeter Wemm /*
384b8ba871bSPeter Wemm * !!!
385b8ba871bSPeter Wemm * If the editor wrote the screen behind curses back, put out
386b8ba871bSPeter Wemm * a <newline> so that we don't overwrite the user's command
387b8ba871bSPeter Wemm * with its output or the next want-to-continue? message. This
388b8ba871bSPeter Wemm * doesn't belong here, but I can't find another place to put
389b8ba871bSPeter Wemm * it. See, we resolved the output from the last ex command,
390b8ba871bSPeter Wemm * and the user entered another one. This is the only place
391b8ba871bSPeter Wemm * where we have control before the ex command writes output.
392b8ba871bSPeter Wemm * We could get control in vs_msg(), but we have no way to know
393b8ba871bSPeter Wemm * if command didn't put out any output when we try and resolve
394b8ba871bSPeter Wemm * this command. This fixes a bug where combinations of ex
395b8ba871bSPeter Wemm * commands, e.g. ":set<CR>:!date<CR>:set" didn't look right.
396b8ba871bSPeter Wemm */
397b8ba871bSPeter Wemm if (F_ISSET(sp, SC_SCR_EXWROTE))
398b8ba871bSPeter Wemm (void)putchar('\n');
399b8ba871bSPeter Wemm
400b8ba871bSPeter Wemm /* Call the ex parser. */
401b8ba871bSPeter Wemm (void)ex_cmd(sp);
402b8ba871bSPeter Wemm
403b8ba871bSPeter Wemm /* Flush ex messages. */
404b8ba871bSPeter Wemm (void)ex_fflush(sp);
405b8ba871bSPeter Wemm
406b8ba871bSPeter Wemm /* Resolve any messages. */
407b8ba871bSPeter Wemm if (vs_ex_resolve(sp, &ifcontinue))
408b8ba871bSPeter Wemm return (1);
409b8ba871bSPeter Wemm
410b8ba871bSPeter Wemm /*
411b8ba871bSPeter Wemm * Continue or return. If continuing, make sure that we
412b8ba871bSPeter Wemm * eventually do resolution.
413b8ba871bSPeter Wemm */
414b8ba871bSPeter Wemm if (!ifcontinue)
415b8ba871bSPeter Wemm break;
416b8ba871bSPeter Wemm do_resolution = 1;
417b8ba871bSPeter Wemm
418b8ba871bSPeter Wemm /* If we're continuing, it's a new command. */
419b8ba871bSPeter Wemm ++sp->ccnt;
420b8ba871bSPeter Wemm }
421b8ba871bSPeter Wemm
422b8ba871bSPeter Wemm /*
423b8ba871bSPeter Wemm * If the user previously continued an ex command, we have to do
424b8ba871bSPeter Wemm * resolution to clean up the screen. Don't wait, we already did
425b8ba871bSPeter Wemm * that.
426b8ba871bSPeter Wemm */
427b8ba871bSPeter Wemm if (do_resolution) {
428b8ba871bSPeter Wemm F_SET(sp, SC_EX_WAIT_NO);
429b8ba871bSPeter Wemm if (vs_ex_resolve(sp, &ifcontinue))
430b8ba871bSPeter Wemm return (1);
431725f5cdbSJaakko Heinonen }
432725f5cdbSJaakko Heinonen
433725f5cdbSJaakko Heinonen /* Cleanup from the ex command. */
434725f5cdbSJaakko Heinonen if (v_ex_done(sp, vp))
435b8ba871bSPeter Wemm return (1);
436b8ba871bSPeter Wemm
437b8ba871bSPeter Wemm /* The user may want to edit their colon command history. */
438b8ba871bSPeter Wemm if (do_cedit)
439b8ba871bSPeter Wemm return (v_ecl(sp));
440b8ba871bSPeter Wemm
441b8ba871bSPeter Wemm return (0);
442b8ba871bSPeter Wemm }
443b8ba871bSPeter Wemm
444b8ba871bSPeter Wemm /*
445b8ba871bSPeter Wemm * v_ex_done --
446b8ba871bSPeter Wemm * Cleanup from an ex command.
447b8ba871bSPeter Wemm */
448b8ba871bSPeter Wemm static int
v_ex_done(SCR * sp,VICMD * vp)449b8ba871bSPeter Wemm v_ex_done(SCR *sp, VICMD *vp)
450b8ba871bSPeter Wemm {
451b8ba871bSPeter Wemm size_t len;
452b8ba871bSPeter Wemm
453b8ba871bSPeter Wemm /*
454b8ba871bSPeter Wemm * The only cursor modifications are real, however, the underlying
455b8ba871bSPeter Wemm * line may have changed; don't trust anything. This code has been
456b8ba871bSPeter Wemm * a remarkably fertile place for bugs. Do a reality check on a
457b8ba871bSPeter Wemm * cursor value, and make sure it's okay. If necessary, change it.
458b8ba871bSPeter Wemm * Ex keeps track of the line number, but it cares less about the
459b8ba871bSPeter Wemm * column and it may have disappeared.
460b8ba871bSPeter Wemm *
461b8ba871bSPeter Wemm * Don't trust ANYTHING.
462b8ba871bSPeter Wemm *
463b8ba871bSPeter Wemm * XXX
464b8ba871bSPeter Wemm * Ex will soon have to start handling the column correctly; see
465b8ba871bSPeter Wemm * the POSIX 1003.2 standard.
466b8ba871bSPeter Wemm */
467b8ba871bSPeter Wemm if (db_eget(sp, sp->lno, NULL, &len, NULL)) {
468b8ba871bSPeter Wemm sp->lno = 1;
469b8ba871bSPeter Wemm sp->cno = 0;
470b8ba871bSPeter Wemm } else if (sp->cno >= len)
471b8ba871bSPeter Wemm sp->cno = len ? len - 1 : 0;
472b8ba871bSPeter Wemm
473b8ba871bSPeter Wemm vp->m_final.lno = sp->lno;
474b8ba871bSPeter Wemm vp->m_final.cno = sp->cno;
475b8ba871bSPeter Wemm
476b8ba871bSPeter Wemm /*
477b8ba871bSPeter Wemm * Don't re-adjust the cursor after executing an ex command,
478b8ba871bSPeter Wemm * and ex movements are permanent.
479b8ba871bSPeter Wemm */
480b8ba871bSPeter Wemm F_CLR(vp, VM_RCM_MASK);
481b8ba871bSPeter Wemm F_SET(vp, VM_RCM_SET);
482b8ba871bSPeter Wemm
483b8ba871bSPeter Wemm return (0);
484b8ba871bSPeter Wemm }
485b8ba871bSPeter Wemm
486b8ba871bSPeter Wemm /*
487b8ba871bSPeter Wemm * v_ecl --
488b8ba871bSPeter Wemm * Start an edit window on the colon command-line commands.
489b8ba871bSPeter Wemm */
490b8ba871bSPeter Wemm static int
v_ecl(SCR * sp)491b8ba871bSPeter Wemm v_ecl(SCR *sp)
492b8ba871bSPeter Wemm {
493b8ba871bSPeter Wemm GS *gp;
494b8ba871bSPeter Wemm SCR *new;
495b8ba871bSPeter Wemm
496b8ba871bSPeter Wemm /* Initialize the screen, if necessary. */
497b8ba871bSPeter Wemm gp = sp->gp;
498b8ba871bSPeter Wemm if (gp->ccl_sp == NULL && v_ecl_init(sp))
499b8ba871bSPeter Wemm return (1);
500b8ba871bSPeter Wemm
501b8ba871bSPeter Wemm /* Get a new screen. */
502b8ba871bSPeter Wemm if (screen_init(gp, sp, &new))
503b8ba871bSPeter Wemm return (1);
504b8ba871bSPeter Wemm if (vs_split(sp, new, 1)) {
505b8ba871bSPeter Wemm (void)screen_end(new);
506b8ba871bSPeter Wemm return (1);
507b8ba871bSPeter Wemm }
508b8ba871bSPeter Wemm
509b8ba871bSPeter Wemm /* Attach to the screen. */
510b8ba871bSPeter Wemm new->ep = gp->ccl_sp->ep;
511b8ba871bSPeter Wemm ++new->ep->refcnt;
512b8ba871bSPeter Wemm
513b8ba871bSPeter Wemm new->frp = gp->ccl_sp->frp;
514b8ba871bSPeter Wemm new->frp->flags = sp->frp->flags;
515b8ba871bSPeter Wemm
516b8ba871bSPeter Wemm /* Move the cursor to the end. */
517b8ba871bSPeter Wemm (void)db_last(new, &new->lno);
518b8ba871bSPeter Wemm if (new->lno == 0)
519b8ba871bSPeter Wemm new->lno = 1;
520b8ba871bSPeter Wemm
521b8ba871bSPeter Wemm /* Remember the originating window. */
522b8ba871bSPeter Wemm sp->ccl_parent = sp;
523b8ba871bSPeter Wemm
524b8ba871bSPeter Wemm /* It's a special window. */
525b8ba871bSPeter Wemm F_SET(new, SC_COMEDIT);
526b8ba871bSPeter Wemm
527b8ba871bSPeter Wemm #if defined(USE_WIDECHAR) && defined(USE_ICONV)
528b8ba871bSPeter Wemm /* Bypass iconv on writing to DB. */
529b8ba871bSPeter Wemm o_set(new, O_FILEENCODING, OS_STRDUP, codeset(), 0);
530b8ba871bSPeter Wemm #endif
531b8ba871bSPeter Wemm
532b8ba871bSPeter Wemm /* Set up the switch. */
533b8ba871bSPeter Wemm sp->nextdisp = new;
534b8ba871bSPeter Wemm F_SET(sp, SC_SSWITCH);
535b8ba871bSPeter Wemm return (0);
536b8ba871bSPeter Wemm }
537b8ba871bSPeter Wemm
538b8ba871bSPeter Wemm /*
539b8ba871bSPeter Wemm * v_ecl_exec --
540b8ba871bSPeter Wemm * Execute a command from a colon command-line window.
541b8ba871bSPeter Wemm *
542b8ba871bSPeter Wemm * PUBLIC: int v_ecl_exec(SCR *);
543b8ba871bSPeter Wemm */
544b8ba871bSPeter Wemm int
v_ecl_exec(SCR * sp)545b8ba871bSPeter Wemm v_ecl_exec(SCR *sp)
546b8ba871bSPeter Wemm {
547b8ba871bSPeter Wemm size_t len;
548b8ba871bSPeter Wemm CHAR_T *p;
549b8ba871bSPeter Wemm
550b8ba871bSPeter Wemm if (db_get(sp, sp->lno, 0, &p, &len) && sp->lno == 1) {
551b8ba871bSPeter Wemm v_emsg(sp, NULL, VIM_EMPTY);
552b8ba871bSPeter Wemm return (1);
553b8ba871bSPeter Wemm }
554b8ba871bSPeter Wemm if (len == 0) {
555b8ba871bSPeter Wemm msgq(sp, M_BERR, "307|No ex command to execute");
556b8ba871bSPeter Wemm return (1);
557b8ba871bSPeter Wemm }
558b8ba871bSPeter Wemm
559b8ba871bSPeter Wemm /* Push the command on the command stack. */
560b8ba871bSPeter Wemm if (ex_run_str(sp, NULL, p, len, 0, 0))
561b8ba871bSPeter Wemm return (1);
562b8ba871bSPeter Wemm
563b8ba871bSPeter Wemm /* Set up the switch. */
564b8ba871bSPeter Wemm sp->nextdisp = sp->ccl_parent;
565b8ba871bSPeter Wemm F_SET(sp, SC_EXIT);
566b8ba871bSPeter Wemm return (0);
567b8ba871bSPeter Wemm }
568b8ba871bSPeter Wemm
569b8ba871bSPeter Wemm /*
570b8ba871bSPeter Wemm * v_ecl_log --
571b8ba871bSPeter Wemm * Log a command into the colon command-line log file.
572b8ba871bSPeter Wemm */
573b8ba871bSPeter Wemm static int
v_ecl_log(SCR * sp,TEXT * tp)574b8ba871bSPeter Wemm v_ecl_log(SCR *sp, TEXT *tp)
575b8ba871bSPeter Wemm {
576b8ba871bSPeter Wemm recno_t lno;
577b8ba871bSPeter Wemm int rval;
578b8ba871bSPeter Wemm CHAR_T *p;
579b8ba871bSPeter Wemm size_t len;
580b8ba871bSPeter Wemm SCR *ccl_sp;
581b8ba871bSPeter Wemm
582b8ba871bSPeter Wemm /* Initialize the screen, if necessary. */
583b8ba871bSPeter Wemm if (sp->gp->ccl_sp == NULL && v_ecl_init(sp))
584b8ba871bSPeter Wemm return (1);
585b8ba871bSPeter Wemm
586b8ba871bSPeter Wemm ccl_sp = sp->gp->ccl_sp;
587b8ba871bSPeter Wemm
588b8ba871bSPeter Wemm /*
589b8ba871bSPeter Wemm * Don't log colon command window commands into the colon command
590b8ba871bSPeter Wemm * window...
591b8ba871bSPeter Wemm */
592b8ba871bSPeter Wemm if (sp->ep == ccl_sp->ep)
593b8ba871bSPeter Wemm return (0);
594b8ba871bSPeter Wemm
595b8ba871bSPeter Wemm if (db_last(ccl_sp, &lno)) {
596b8ba871bSPeter Wemm return (1);
597b8ba871bSPeter Wemm }
598b8ba871bSPeter Wemm /* Don't log line that is identical to previous one */
599b8ba871bSPeter Wemm if (lno > 0 &&
600b8ba871bSPeter Wemm !db_get(ccl_sp, lno, 0, &p, &len) &&
601b8ba871bSPeter Wemm len == tp->len &&
602b8ba871bSPeter Wemm !MEMCMP(tp->lb, p, len))
603b8ba871bSPeter Wemm rval = 0;
604b8ba871bSPeter Wemm else {
605b8ba871bSPeter Wemm rval = db_append(ccl_sp, 0, lno, tp->lb, tp->len);
606b8ba871bSPeter Wemm /* XXXX end "transaction" on ccl */
607b8ba871bSPeter Wemm /* Is this still necessary now that we no longer hijack sp ? */
608b8ba871bSPeter Wemm log_cursor(ccl_sp);
609b8ba871bSPeter Wemm }
610b8ba871bSPeter Wemm
611b8ba871bSPeter Wemm return (rval);
612b8ba871bSPeter Wemm }
613b8ba871bSPeter Wemm
614b8ba871bSPeter Wemm /*
615b8ba871bSPeter Wemm * v_ecl_init --
616b8ba871bSPeter Wemm * Initialize the colon command-line log file.
617b8ba871bSPeter Wemm */
618b8ba871bSPeter Wemm static int
v_ecl_init(SCR * sp)619b8ba871bSPeter Wemm v_ecl_init(SCR *sp)
620b8ba871bSPeter Wemm {
621b8ba871bSPeter Wemm FREF *frp;
622b8ba871bSPeter Wemm GS *gp;
623b8ba871bSPeter Wemm
624b8ba871bSPeter Wemm gp = sp->gp;
625b8ba871bSPeter Wemm
626b8ba871bSPeter Wemm /* Get a temporary file. */
627b8ba871bSPeter Wemm if ((frp = file_add(sp, NULL)) == NULL)
628b8ba871bSPeter Wemm return (1);
629b8ba871bSPeter Wemm
630b8ba871bSPeter Wemm /*
631b8ba871bSPeter Wemm * XXX
632b8ba871bSPeter Wemm * Create a screen -- the file initialization code wants one.
633b8ba871bSPeter Wemm */
634b8ba871bSPeter Wemm if (screen_init(gp, sp, &gp->ccl_sp))
635b8ba871bSPeter Wemm return (1);
636b8ba871bSPeter Wemm if (file_init(gp->ccl_sp, frp, NULL, 0)) {
637b8ba871bSPeter Wemm (void)screen_end(gp->ccl_sp);
638b8ba871bSPeter Wemm gp->ccl_sp = NULL;
639b8ba871bSPeter Wemm return (1);
640b8ba871bSPeter Wemm }
641b8ba871bSPeter Wemm
642b8ba871bSPeter Wemm /* The underlying file isn't recoverable. */
643b8ba871bSPeter Wemm F_CLR(gp->ccl_sp->ep, F_RCV_ON);
644b8ba871bSPeter Wemm
645b8ba871bSPeter Wemm return (0);
646b8ba871bSPeter Wemm }
647b8ba871bSPeter Wemm