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