2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: ex_bang.c,v 8.21 1993/12/09 19:42:38 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:42:38 $";
12 #include <sys/types.h>
21 #include "sex/sex_screen.h"
24 * ex_bang -- :[line [,line]] ! command
26 * Pass the rest of the line after the ! character to the program named by
29 * Historical vi did NOT do shell expansion on the arguments before passing
30 * them, only file name expansion. This means that the O_SHELL program got
31 * "$t" as an argument if that is what the user entered. Also, there's a
32 * special expansion done for the bang command. Any exclamation points in
33 * the user's argument are replaced by the last, expanded ! command.
35 * There's some fairly amazing slop in this routine to make the different
36 * ways of getting here display the right things. It took a long time to
37 * get it right (wrong?), so be careful.
45 enum filtertype ftype
;
57 msgq(sp
, M_ERR
, "Usage: %s", cmdp
->cmd
->usage
);
63 if (exp
->lastbcomm
!= NULL
)
64 FREE(exp
->lastbcomm
, strlen(exp
->lastbcomm
) + 1);
65 if ((exp
->lastbcomm
= strdup(ap
->bp
)) == NULL
) {
66 msgq(sp
, M_SYSERR
, NULL
);
71 * If the command was modified by the expansion, we redisplay it.
72 * Redisplaying it in vi mode is tricky, and handled separately
73 * in each case below. If we're in ex mode, it's easy, so we just
77 if (F_ISSET(cmdp
, E_MODIFY
)) {
79 (void)ex_printf(EXCOOKIE
, "!%s\n", ap
->bp
);
80 (void)ex_fflush(EXCOOKIE
);
83 * Vi: Display the command if modified. Historic vi displayed
84 * the command if it was modified due to file name and/or bang
85 * expansion. If piping lines, it was immediately overwritten
86 * by any error or line change reporting. We don't the user to
87 * have to page through the responses, so we only post it until
88 * it's erased by something else. Otherwise, pass it on to the
89 * ex_exec_proc routine to display after the screen has been
93 GET_SPACE_RET(sp
, bp
, blen
, ap
->len
+ 2);
95 memmove(bp
+ 1, ap
->bp
, ap
->len
+ 1);
100 * If addresses were specified, pipe lines from the file through
103 if (cmdp
->addrcnt
!= 0) {
105 (void)sp
->s_busy(sp
, bp
);
106 FREE_SPACE(sp
, bp
, blen
);
110 * Historical vi permitted "!!" in an empty file. When it
111 * happens, we get called with two addresses of 1,1 and a
115 if (cmdp
->addr1
.lno
== 1 && cmdp
->addr2
.lno
== 1) {
116 if (file_lline(sp
, ep
, &lno
))
119 cmdp
->addr1
.lno
= cmdp
->addr2
.lno
= 0;
123 if (filtercmd(sp
, ep
,
124 &cmdp
->addr1
, &cmdp
->addr2
, &rm
, ap
->bp
, ftype
))
127 F_SET(sp
, S_AUTOPRINT
);
132 * If no addresses were specified, run the command. If the file
133 * has been modified and autowrite is set, write the file back.
134 * If the file has been modified, autowrite is not set and the
135 * warn option is set, tell the user about the file.
138 if (F_ISSET(ep
, F_MODIFIED
))
139 if (O_ISSET(sp
, O_AUTOWRITE
)) {
140 if (file_write(sp
, ep
, NULL
, NULL
, NULL
, FS_ALL
)) {
144 } else if (O_ISSET(sp
, O_WARN
))
145 if (IN_VI_MODE(sp
) && F_ISSET(cmdp
, E_MODIFY
))
146 msg
= "\nFile modified since last write.\n";
148 msg
= "File modified since last write.\n";
150 /* Run the command. */
151 rval
= ex_exec_proc(sp
, ap
->bp
, bp
, msg
);
153 /* Ex terminates with a bang. */
155 (void)write(STDOUT_FILENO
, "!\n", 2);
157 /* Vi requires user permission to continue. */
159 F_SET(sp
, S_CONTINUE
);
161 /* Free the extra space. */
163 FREE_SPACE(sp
, bp
, blen
);