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[] = "@(#)ex_bang.c 10.33 (Berkeley) 9/23/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 <errno.h> 22 #include <limits.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "../common/common.h" 29 #include "../vi/vi.h" 30 31 /* 32 * ex_bang -- :[line [,line]] ! command 33 * 34 * Pass the rest of the line after the ! character to the program named by 35 * the O_SHELL option. 36 * 37 * Historical vi did NOT do shell expansion on the arguments before passing 38 * them, only file name expansion. This means that the O_SHELL program got 39 * "$t" as an argument if that is what the user entered. Also, there's a 40 * special expansion done for the bang command. Any exclamation points in 41 * the user's argument are replaced by the last, expanded ! command. 42 * 43 * There's some fairly amazing slop in this routine to make the different 44 * ways of getting here display the right things. It took a long time to 45 * get it right (wrong?), so be careful. 46 * 47 * PUBLIC: int ex_bang __P((SCR *, EXCMD *)); 48 */ 49 int 50 ex_bang(sp, cmdp) 51 SCR *sp; 52 EXCMD *cmdp; 53 { 54 enum filtertype ftype; 55 ARGS *ap; 56 EX_PRIVATE *exp; 57 MARK rm; 58 recno_t lno; 59 int rval; 60 const char *msg; 61 62 ap = cmdp->argv[0]; 63 if (ap->len == 0) { 64 ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); 65 return (1); 66 } 67 68 /* Set the "last bang command" remembered value. */ 69 exp = EXP(sp); 70 if (exp->lastbcomm != NULL) 71 free(exp->lastbcomm); 72 if ((exp->lastbcomm = strdup(ap->bp)) == NULL) { 73 msgq(sp, M_SYSERR, NULL); 74 return (1); 75 } 76 77 /* 78 * If the command was modified by the expansion, it was historically 79 * redisplayed. 80 */ 81 if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { 82 /* 83 * Display the command if modified. Historic ex/vi displayed 84 * the command if it was modified due to file name and/or bang 85 * expansion. If piping lines in vi, it would be immediately 86 * overwritten by any error or line change reporting. 87 */ 88 if (F_ISSET(sp, SC_VI)) 89 vs_update(sp, "!", ap->bp); 90 else { 91 (void)ex_printf(sp, "!%s\n", ap->bp); 92 (void)ex_fflush(sp); 93 } 94 } 95 96 /* 97 * If no addresses were specified, run the command. If there's an 98 * underlying file, it's been modified and autowrite is set, write 99 * the file back. If the file has been modified, autowrite is not 100 * set and the warn option is set, tell the user about the file. 101 */ 102 if (cmdp->addrcnt == 0) { 103 msg = NULL; 104 if (sp->ep != NULL && F_ISSET(sp->ep, F_MODIFIED)) 105 if (O_ISSET(sp, O_AUTOWRITE)) { 106 if (file_aw(sp, FS_ALL)) 107 return (0); 108 } else if (O_ISSET(sp, O_WARN) && 109 !F_ISSET(sp, SC_EX_SILENT)) 110 msg = msg_cat(sp, 111 "303|File modified since last write.", 112 NULL); 113 114 /* If we're still in a vi screen, move out explicitly. */ 115 (void)ex_exec_proc(sp, 116 cmdp, ap->bp, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); 117 } 118 119 /* 120 * If addresses were specified, pipe lines from the file through the 121 * command. 122 * 123 * Historically, vi lines were replaced by both the stdout and stderr 124 * lines of the command, but ex lines by only the stdout lines. This 125 * makes no sense to me, so nvi makes it consistent for both, and 126 * matches vi's historic behavior. 127 */ 128 else { 129 NEEDFILE(sp, cmdp); 130 131 /* Autoprint is set historically, even if the command fails. */ 132 F_SET(cmdp, E_AUTOPRINT); 133 134 /* 135 * !!! 136 * Historical vi permitted "!!" in an empty file. When this 137 * happens, we arrive here with two addresses of 1,1 and a 138 * bad attitude. The simple solution is to turn it into a 139 * FILTER_READ operation, with the exception that stdin isn't 140 * opened for the utility, and the cursor position isn't the 141 * same. The only historic glitch (I think) is that we don't 142 * put an empty line into the default cut buffer, as historic 143 * vi did. Imagine, if you can, my disappointment. 144 */ 145 ftype = FILTER_BANG; 146 if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { 147 if (db_last(sp, &lno)) 148 return (1); 149 if (lno == 0) { 150 cmdp->addr1.lno = cmdp->addr2.lno = 0; 151 ftype = FILTER_RBANG; 152 } 153 } 154 rval = ex_filter(sp, cmdp, 155 &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); 156 157 /* 158 * If in vi mode, move to the first nonblank. 159 * 160 * !!! 161 * Historic vi wasn't consistent in this area -- if you used 162 * a forward motion it moved to the first nonblank, but if you 163 * did a backward motion it didn't. And, if you followed a 164 * backward motion with a forward motion, it wouldn't move to 165 * the nonblank for either. Going to the nonblank generally 166 * seems more useful and consistent, so we do it. 167 */ 168 sp->lno = rm.lno; 169 if (F_ISSET(sp, SC_VI)) { 170 sp->cno = 0; 171 (void)nonblank(sp, sp->lno, &sp->cno); 172 } else 173 sp->cno = rm.cno; 174 } 175 176 /* Ex terminates with a bang, even if the command fails. */ 177 if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) 178 (void)ex_puts(sp, "!\n"); 179 180 /* 181 * XXX 182 * The ! commands never return an error, so that autoprint always 183 * happens in the ex parser. 184 */ 185 return (0); 186 } 187