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