ex_bang.c revision 281373
1142425Snectar/*- 2160814Ssimon * Copyright (c) 1992, 1993, 1994 3142425Snectar * The Regents of the University of California. All rights reserved. 4142425Snectar * Copyright (c) 1992, 1993, 1994, 1995, 1996 5142425Snectar * Keith Bostic. All rights reserved. 6142425Snectar * 7142425Snectar * See the LICENSE file for redistribution information. 8142425Snectar */ 9142425Snectar 10142425Snectar#include "config.h" 11142425Snectar 12142425Snectar#ifndef lint 13142425Snectarstatic const char sccsid[] = "$Id: ex_bang.c,v 10.36 2001/06/25 15:19:14 skimo Exp $"; 14142425Snectar#endif /* not lint */ 15142425Snectar 16142425Snectar#include <sys/types.h> 17142425Snectar#include <sys/queue.h> 18142425Snectar#include <sys/time.h> 19142425Snectar 20160814Ssimon#include <bitstring.h> 21142425Snectar#include <errno.h> 22142425Snectar#include <limits.h> 23142425Snectar#include <stdio.h> 24142425Snectar#include <stdlib.h> 25142425Snectar#include <string.h> 26142425Snectar#include <unistd.h> 27142425Snectar 28142425Snectar#include "../common/common.h" 29142425Snectar#include "../vi/vi.h" 30142425Snectar 31142425Snectar/* 32142425Snectar * ex_bang -- :[line [,line]] ! command 33142425Snectar * 34142425Snectar * Pass the rest of the line after the ! character to the program named by 35142425Snectar * the O_SHELL option. 36142425Snectar * 37142425Snectar * Historical vi did NOT do shell expansion on the arguments before passing 38142425Snectar * them, only file name expansion. This means that the O_SHELL program got 39142425Snectar * "$t" as an argument if that is what the user entered. Also, there's a 40142425Snectar * special expansion done for the bang command. Any exclamation points in 41142425Snectar * the user's argument are replaced by the last, expanded ! command. 42142425Snectar * 43142425Snectar * There's some fairly amazing slop in this routine to make the different 44142425Snectar * ways of getting here display the right things. It took a long time to 45142425Snectar * get it right (wrong?), so be careful. 46142425Snectar * 47160814Ssimon * PUBLIC: int ex_bang(SCR *, EXCMD *); 48160814Ssimon */ 49160814Ssimonint 50160814Ssimonex_bang(SCR *sp, EXCMD *cmdp) 51160814Ssimon{ 52160814Ssimon enum filtertype ftype; 53142425Snectar ARGS *ap; 54160814Ssimon EX_PRIVATE *exp; 55160814Ssimon MARK rm; 56142425Snectar recno_t lno; 57142425Snectar int rval; 58142425Snectar const char *msg; 59142425Snectar char *np; 60142425Snectar size_t nlen; 61142425Snectar 62142425Snectar ap = cmdp->argv[0]; 63142425Snectar if (ap->len == 0) { 64142425Snectar ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); 65142425Snectar return (1); 66160814Ssimon } 67160814Ssimon 68142425Snectar /* Set the "last bang command" remembered value. */ 69142425Snectar exp = EXP(sp); 70142425Snectar if (exp->lastbcomm != NULL) 71142425Snectar free(exp->lastbcomm); 72142425Snectar if ((exp->lastbcomm = v_wstrdup(sp, ap->bp, ap->len)) == NULL) { 73142425Snectar msgq(sp, M_SYSERR, NULL); 74142425Snectar return (1); 75142425Snectar } 76142425Snectar 77142425Snectar /* 78142425Snectar * If the command was modified by the expansion, it was historically 79142425Snectar * redisplayed. 80142425Snectar */ 81142425Snectar if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { 82160814Ssimon /* 83142425Snectar * Display the command if modified. Historic ex/vi displayed 84142425Snectar * the command if it was modified due to file name and/or bang 85142425Snectar * expansion. If piping lines in vi, it would be immediately 86142425Snectar * overwritten by any error or line change reporting. 87142425Snectar */ 88142425Snectar if (F_ISSET(sp, SC_VI)) 89142425Snectar vs_update(sp, "!", ap->bp); 90160814Ssimon else { 91142425Snectar (void)ex_printf(sp, "!"WS"\n", ap->bp); 92142425Snectar (void)ex_fflush(sp); 93142425Snectar } 94160814Ssimon } 95160814Ssimon 96160814Ssimon /* 97160814Ssimon * If no addresses were specified, run the command. If there's an 98160814Ssimon * underlying file, it's been modified and autowrite is set, write 99160814Ssimon * the file back. If the file has been modified, autowrite is not 100160814Ssimon * set and the warn option is set, tell the user about the file. 101160814Ssimon */ 102160814Ssimon if (cmdp->addrcnt == 0) { 103160814Ssimon 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 INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); 116 (void)ex_exec_proc(sp, 117 cmdp, np, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); 118 } 119 120 /* 121 * If addresses were specified, pipe lines from the file through the 122 * command. 123 * 124 * Historically, vi lines were replaced by both the stdout and stderr 125 * lines of the command, but ex lines by only the stdout lines. This 126 * makes no sense to me, so nvi makes it consistent for both, and 127 * matches vi's historic behavior. 128 */ 129 else { 130 NEEDFILE(sp, cmdp); 131 132 /* Autoprint is set historically, even if the command fails. */ 133 F_SET(cmdp, E_AUTOPRINT); 134 135 /* 136 * !!! 137 * Historical vi permitted "!!" in an empty file. When this 138 * happens, we arrive here with two addresses of 1,1 and a 139 * bad attitude. The simple solution is to turn it into a 140 * FILTER_READ operation, with the exception that stdin isn't 141 * opened for the utility, and the cursor position isn't the 142 * same. The only historic glitch (I think) is that we don't 143 * put an empty line into the default cut buffer, as historic 144 * vi did. Imagine, if you can, my disappointment. 145 */ 146 ftype = FILTER_BANG; 147 if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { 148 if (db_last(sp, &lno)) 149 return (1); 150 if (lno == 0) { 151 cmdp->addr1.lno = cmdp->addr2.lno = 0; 152 ftype = FILTER_RBANG; 153 } 154 } 155 rval = ex_filter(sp, cmdp, 156 &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); 157 158 /* 159 * If in vi mode, move to the first nonblank. 160 * 161 * !!! 162 * Historic vi wasn't consistent in this area -- if you used 163 * a forward motion it moved to the first nonblank, but if you 164 * did a backward motion it didn't. And, if you followed a 165 * backward motion with a forward motion, it wouldn't move to 166 * the nonblank for either. Going to the nonblank generally 167 * seems more useful and consistent, so we do it. 168 */ 169 sp->lno = rm.lno; 170 if (F_ISSET(sp, SC_VI)) { 171 sp->cno = 0; 172 (void)nonblank(sp, sp->lno, &sp->cno); 173 } else 174 sp->cno = rm.cno; 175 } 176 177 /* Ex terminates with a bang, even if the command fails. */ 178 if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) 179 (void)ex_puts(sp, "!\n"); 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