rework initial error handling -- since we check for any screens on
[nvi.git] / ex / ex_bang.c
blobfc8d7b0d69fb72655256c142f724a33f2427c7d6
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: ex_bang.c,v 8.22 1993/12/29 09:50:48 bostic Exp $ (Berkeley) $Date: 1993/12/29 09:50:48 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
19 #include "vi.h"
20 #include "excmd.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
27 * the O_SHELL option.
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.
39 int
40 ex_bang(sp, ep, cmdp)
41 SCR *sp;
42 EXF *ep;
43 EXCMDARG *cmdp;
45 enum filtertype ftype;
46 ARGS *ap;
47 EX_PRIVATE *exp;
48 MARK rm;
49 recno_t lno;
50 size_t blen;
51 int rval;
52 char *bp, *msg;
55 ap = cmdp->argv[0];
56 if (ap->len == 0) {
57 msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
58 return (1);
61 /* Swap commands. */
62 exp = EXP(sp);
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);
67 return (1);
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
74 * do it here.
76 bp = NULL;
77 if (F_ISSET(cmdp, E_MODIFY)) {
78 if (IN_EX_MODE(sp)) {
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
90 * cleaned up.
92 if (IN_VI_MODE(sp)) {
93 GET_SPACE_RET(sp, bp, blen, ap->len + 2);
94 bp[0] = '!';
95 memmove(bp + 1, ap->bp, ap->len + 1);
100 * If addresses were specified, pipe lines from the file through
101 * the command.
103 if (cmdp->addrcnt != 0) {
104 if (bp != NULL) {
105 (void)sp->s_busy(sp, bp);
106 FREE_SPACE(sp, bp, blen);
109 * !!!
110 * Historical vi permitted "!!" in an empty file. When it
111 * happens, we get called with two addresses of 1,1 and a
112 * bad attitude.
114 ftype = FILTER;
115 if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) {
116 if (file_lline(sp, ep, &lno))
117 return (1);
118 if (lno == 0) {
119 cmdp->addr1.lno = cmdp->addr2.lno = 0;
120 ftype = FILTER_READ;
123 if (filtercmd(sp, ep,
124 &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype))
125 return (1);
126 sp->lno = rm.lno;
127 F_SET(exp, EX_AUTOPRINT);
128 return (0);
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.
137 msg = "\n";
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)) {
141 rval = 1;
142 goto ret;
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";
147 else
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. */
154 if (IN_EX_MODE(sp))
155 (void)write(STDOUT_FILENO, "!\n", 2);
157 /* Vi requires user permission to continue. */
158 if (IN_VI_MODE(sp))
159 F_SET(sp, S_CONTINUE);
161 /* Free the extra space. */
162 ret: if (bp != NULL)
163 FREE_SPACE(sp, bp, blen);
165 return (rval);