ex_bang.c revision 254225
1144966Svkashyap/*- 2169400Sscottl * Copyright (c) 1992, 1993, 1994 3144966Svkashyap * The Regents of the University of California. All rights reserved. 4144966Svkashyap * Copyright (c) 1992, 1993, 1994, 1995, 1996 5144966Svkashyap * Keith Bostic. All rights reserved. 6144966Svkashyap * 7144966Svkashyap * See the LICENSE file for redistribution information. 8144966Svkashyap */ 9144966Svkashyap 10144966Svkashyap#include "config.h" 11144966Svkashyap 12144966Svkashyap#ifndef lint 13144966Svkashyapstatic const char sccsid[] = "$Id: ex_bang.c,v 10.36 2001/06/25 15:19:14 skimo Exp $"; 14144966Svkashyap#endif /* not lint */ 15144966Svkashyap 16144966Svkashyap#include <sys/types.h> 17144966Svkashyap#include <sys/queue.h> 18144966Svkashyap#include <sys/time.h> 19144966Svkashyap 20144966Svkashyap#include <bitstring.h> 21144966Svkashyap#include <errno.h> 22144966Svkashyap#include <limits.h> 23144966Svkashyap#include <stdio.h> 24144966Svkashyap#include <stdlib.h> 25144966Svkashyap#include <string.h> 26144966Svkashyap#include <unistd.h> 27144966Svkashyap 28144966Svkashyap#include "../common/common.h" 29144966Svkashyap#include "../vi/vi.h" 30144966Svkashyap 31144966Svkashyap/* 32144966Svkashyap * ex_bang -- :[line [,line]] ! command 33144966Svkashyap * 34169400Sscottl * Pass the rest of the line after the ! character to the program named by 35172496Sscottl * the O_SHELL option. 36144966Svkashyap * 37144966Svkashyap * Historical vi did NOT do shell expansion on the arguments before passing 38144966Svkashyap * them, only file name expansion. This means that the O_SHELL program got 39144966Svkashyap * "$t" as an argument if that is what the user entered. Also, there's a 40144966Svkashyap * special expansion done for the bang command. Any exclamation points in 41144966Svkashyap * the user's argument are replaced by the last, expanded ! command. 42144966Svkashyap * 43144966Svkashyap * There's some fairly amazing slop in this routine to make the different 44144966Svkashyap * ways of getting here display the right things. It took a long time to 45144966Svkashyap * get it right (wrong?), so be careful. 46144966Svkashyap * 47144966Svkashyap * PUBLIC: int ex_bang __P((SCR *, EXCMD *)); 48144966Svkashyap */ 49144966Svkashyapint 50144966Svkashyapex_bang(SCR *sp, EXCMD *cmdp) 51144966Svkashyap{ 52144966Svkashyap enum filtertype ftype; 53144966Svkashyap ARGS *ap; 54144966Svkashyap EX_PRIVATE *exp; 55144966Svkashyap MARK rm; 56144966Svkashyap recno_t lno; 57144966Svkashyap int rval; 58144966Svkashyap const char *msg; 59144966Svkashyap char *np; 60144966Svkashyap size_t nlen; 61144966Svkashyap 62144966Svkashyap ap = cmdp->argv[0]; 63144966Svkashyap if (ap->len == 0) { 64144966Svkashyap ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); 65144966Svkashyap return (1); 66144966Svkashyap } 67144966Svkashyap 68144966Svkashyap /* Set the "last bang command" remembered value. */ 69152213Svkashyap exp = EXP(sp); 70152213Svkashyap if (exp->lastbcomm != NULL) 71152213Svkashyap free(exp->lastbcomm); 72144966Svkashyap if ((exp->lastbcomm = v_wstrdup(sp, ap->bp, ap->len)) == NULL) { 73144966Svkashyap msgq(sp, M_SYSERR, NULL); 74144966Svkashyap return (1); 75144966Svkashyap } 76144966Svkashyap 77144966Svkashyap /* 78144966Svkashyap * If the command was modified by the expansion, it was historically 79144966Svkashyap * redisplayed. 80144966Svkashyap */ 81144966Svkashyap if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { 82144966Svkashyap /* 83144966Svkashyap * Display the command if modified. Historic ex/vi displayed 84144966Svkashyap * the command if it was modified due to file name and/or bang 85144966Svkashyap * expansion. If piping lines in vi, it would be immediately 86212008Sdelphij * overwritten by any error or line change reporting. 87212008Sdelphij */ 88144966Svkashyap if (F_ISSET(sp, SC_VI)) 89144966Svkashyap vs_update(sp, "!", ap->bp); 90144966Svkashyap else { 91144966Svkashyap (void)ex_printf(sp, "!"WS"\n", ap->bp); 92144966Svkashyap (void)ex_fflush(sp); 93144966Svkashyap } 94144966Svkashyap } 95144966Svkashyap 96144966Svkashyap /* 97144966Svkashyap * If no addresses were specified, run the command. If there's an 98144966Svkashyap * underlying file, it's been modified and autowrite is set, write 99144966Svkashyap * the file back. If the file has been modified, autowrite is not 100144966Svkashyap * set and the warn option is set, tell the user about the file. 101212008Sdelphij */ 102212008Sdelphij if (cmdp->addrcnt == 0) { 103212008Sdelphij msg = NULL; 104144966Svkashyap if (sp->ep != NULL && F_ISSET(sp->ep, F_MODIFIED)) 105212008Sdelphij if (O_ISSET(sp, O_AUTOWRITE)) { 106212008Sdelphij if (file_aw(sp, FS_ALL)) 107212008Sdelphij return (0); 108144966Svkashyap } else if (O_ISSET(sp, O_WARN) && 109144966Svkashyap !F_ISSET(sp, SC_EX_SILENT)) 110212008Sdelphij msg = msg_cat(sp, 111212008Sdelphij "303|File modified since last write.", 112212008Sdelphij NULL); 113212008Sdelphij 114144966Svkashyap /* If we're still in a vi screen, move out explicitly. */ 115212008Sdelphij INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); 116144966Svkashyap (void)ex_exec_proc(sp, 117144966Svkashyap cmdp, np, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); 118144966Svkashyap } 119144966Svkashyap 120144966Svkashyap /* 121144966Svkashyap * If addresses were specified, pipe lines from the file through the 122144966Svkashyap * command. 123152213Svkashyap * 124152213Svkashyap * Historically, vi lines were replaced by both the stdout and stderr 125152213Svkashyap * lines of the command, but ex lines by only the stdout lines. This 126144966Svkashyap * makes no sense to me, so nvi makes it consistent for both, and 127144966Svkashyap * matches vi's historic behavior. 128144966Svkashyap */ 129144966Svkashyap else { 130144966Svkashyap NEEDFILE(sp, cmdp); 131144966Svkashyap 132144966Svkashyap /* Autoprint is set historically, even if the command fails. */ 133144966Svkashyap F_SET(cmdp, E_AUTOPRINT); 134144966Svkashyap 135144966Svkashyap /* 136144966Svkashyap * !!! 137144966Svkashyap * Historical vi permitted "!!" in an empty file. When this 138144966Svkashyap * happens, we arrive here with two addresses of 1,1 and a 139144966Svkashyap * bad attitude. The simple solution is to turn it into a 140212008Sdelphij * FILTER_READ operation, with the exception that stdin isn't 141212008Sdelphij * opened for the utility, and the cursor position isn't the 142144966Svkashyap * same. The only historic glitch (I think) is that we don't 143144966Svkashyap * put an empty line into the default cut buffer, as historic 144144966Svkashyap * vi did. Imagine, if you can, my disappointment. 145144966Svkashyap */ 146144966Svkashyap ftype = FILTER_BANG; 147144966Svkashyap if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { 148144966Svkashyap if (db_last(sp, &lno)) 149144966Svkashyap return (1); 150144966Svkashyap if (lno == 0) { 151144966Svkashyap cmdp->addr1.lno = cmdp->addr2.lno = 0; 152144966Svkashyap ftype = FILTER_RBANG; 153144966Svkashyap } 154144966Svkashyap } 155212008Sdelphij rval = ex_filter(sp, cmdp, 156212008Sdelphij &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); 157212008Sdelphij 158144966Svkashyap /* 159212008Sdelphij * If in vi mode, move to the first nonblank. 160212008Sdelphij * 161212008Sdelphij * !!! 162144966Svkashyap * Historic vi wasn't consistent in this area -- if you used 163144966Svkashyap * a forward motion it moved to the first nonblank, but if you 164212008Sdelphij * did a backward motion it didn't. And, if you followed a 165212008Sdelphij * backward motion with a forward motion, it wouldn't move to 166212008Sdelphij * the nonblank for either. Going to the nonblank generally 167212008Sdelphij * seems more useful and consistent, so we do it. 168144966Svkashyap */ 169212008Sdelphij sp->lno = rm.lno; 170144966Svkashyap if (F_ISSET(sp, SC_VI)) { 171144966Svkashyap sp->cno = 0; 172144966Svkashyap (void)nonblank(sp, sp->lno, &sp->cno); 173144966Svkashyap } else 174144966Svkashyap sp->cno = rm.cno; 175144966Svkashyap } 176144966Svkashyap 177152213Svkashyap /* Ex terminates with a bang, even if the command fails. */ 178152213Svkashyap if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) 179144966Svkashyap (void)ex_puts(sp, "!\n"); 180144966Svkashyap 181144966Svkashyap /* 182144966Svkashyap * XXX 183144966Svkashyap * The ! commands never return an error, so that autoprint always 184144966Svkashyap * happens in the ex parser. 185144966Svkashyap */ 186144966Svkashyap return (0); 187144966Svkashyap} 188144966Svkashyap