119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: ex_bang.c,v 10.36 2001/06/25 15:19:14 skimo Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <errno.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter#include <unistd.h> 2719304Speter 2819304Speter#include "../common/common.h" 2919304Speter#include "../vi/vi.h" 3019304Speter 3119304Speter/* 3219304Speter * ex_bang -- :[line [,line]] ! command 3319304Speter * 3419304Speter * Pass the rest of the line after the ! character to the program named by 3519304Speter * the O_SHELL option. 3619304Speter * 3719304Speter * Historical vi did NOT do shell expansion on the arguments before passing 3819304Speter * them, only file name expansion. This means that the O_SHELL program got 3919304Speter * "$t" as an argument if that is what the user entered. Also, there's a 4019304Speter * special expansion done for the bang command. Any exclamation points in 4119304Speter * the user's argument are replaced by the last, expanded ! command. 4219304Speter * 4319304Speter * There's some fairly amazing slop in this routine to make the different 4419304Speter * ways of getting here display the right things. It took a long time to 4519304Speter * get it right (wrong?), so be careful. 4619304Speter * 4719304Speter * PUBLIC: int ex_bang __P((SCR *, EXCMD *)); 4819304Speter */ 4919304Speterint 50254225Speterex_bang(SCR *sp, EXCMD *cmdp) 5119304Speter{ 5219304Speter enum filtertype ftype; 5319304Speter ARGS *ap; 5419304Speter EX_PRIVATE *exp; 5519304Speter MARK rm; 5619304Speter recno_t lno; 5719304Speter int rval; 5819304Speter const char *msg; 59254225Speter char *np; 60254225Speter size_t nlen; 6119304Speter 6219304Speter ap = cmdp->argv[0]; 6319304Speter if (ap->len == 0) { 6419304Speter ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); 6519304Speter return (1); 6619304Speter } 6719304Speter 6819304Speter /* Set the "last bang command" remembered value. */ 6919304Speter exp = EXP(sp); 7019304Speter if (exp->lastbcomm != NULL) 7119304Speter free(exp->lastbcomm); 72254225Speter if ((exp->lastbcomm = v_wstrdup(sp, ap->bp, ap->len)) == NULL) { 7319304Speter msgq(sp, M_SYSERR, NULL); 7419304Speter return (1); 7519304Speter } 7619304Speter 7719304Speter /* 7819304Speter * If the command was modified by the expansion, it was historically 7919304Speter * redisplayed. 8019304Speter */ 8119304Speter if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { 8219304Speter /* 8319304Speter * Display the command if modified. Historic ex/vi displayed 8419304Speter * the command if it was modified due to file name and/or bang 8519304Speter * expansion. If piping lines in vi, it would be immediately 8619304Speter * overwritten by any error or line change reporting. 8719304Speter */ 8819304Speter if (F_ISSET(sp, SC_VI)) 8919304Speter vs_update(sp, "!", ap->bp); 9019304Speter else { 91254225Speter (void)ex_printf(sp, "!"WS"\n", ap->bp); 9219304Speter (void)ex_fflush(sp); 9319304Speter } 9419304Speter } 9519304Speter 9619304Speter /* 9719304Speter * If no addresses were specified, run the command. If there's an 9819304Speter * underlying file, it's been modified and autowrite is set, write 9919304Speter * the file back. If the file has been modified, autowrite is not 10019304Speter * set and the warn option is set, tell the user about the file. 10119304Speter */ 10219304Speter if (cmdp->addrcnt == 0) { 10319304Speter msg = NULL; 10419304Speter if (sp->ep != NULL && F_ISSET(sp->ep, F_MODIFIED)) 10519304Speter if (O_ISSET(sp, O_AUTOWRITE)) { 10619304Speter if (file_aw(sp, FS_ALL)) 10719304Speter return (0); 10819304Speter } else if (O_ISSET(sp, O_WARN) && 10919304Speter !F_ISSET(sp, SC_EX_SILENT)) 11019304Speter msg = msg_cat(sp, 11119304Speter "303|File modified since last write.", 11219304Speter NULL); 11319304Speter 11419304Speter /* If we're still in a vi screen, move out explicitly. */ 115254225Speter INT2CHAR(sp, ap->bp, ap->len+1, np, nlen); 11619304Speter (void)ex_exec_proc(sp, 117254225Speter cmdp, np, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); 11819304Speter } 11919304Speter 12019304Speter /* 12119304Speter * If addresses were specified, pipe lines from the file through the 12219304Speter * command. 12319304Speter * 12419304Speter * Historically, vi lines were replaced by both the stdout and stderr 12519304Speter * lines of the command, but ex lines by only the stdout lines. This 12619304Speter * makes no sense to me, so nvi makes it consistent for both, and 12719304Speter * matches vi's historic behavior. 12819304Speter */ 12919304Speter else { 13019304Speter NEEDFILE(sp, cmdp); 13119304Speter 13219304Speter /* Autoprint is set historically, even if the command fails. */ 13319304Speter F_SET(cmdp, E_AUTOPRINT); 13419304Speter 13519304Speter /* 13619304Speter * !!! 13719304Speter * Historical vi permitted "!!" in an empty file. When this 13819304Speter * happens, we arrive here with two addresses of 1,1 and a 13919304Speter * bad attitude. The simple solution is to turn it into a 14019304Speter * FILTER_READ operation, with the exception that stdin isn't 14119304Speter * opened for the utility, and the cursor position isn't the 14219304Speter * same. The only historic glitch (I think) is that we don't 14319304Speter * put an empty line into the default cut buffer, as historic 14419304Speter * vi did. Imagine, if you can, my disappointment. 14519304Speter */ 14619304Speter ftype = FILTER_BANG; 14719304Speter if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { 14819304Speter if (db_last(sp, &lno)) 14919304Speter return (1); 15019304Speter if (lno == 0) { 15119304Speter cmdp->addr1.lno = cmdp->addr2.lno = 0; 15219304Speter ftype = FILTER_RBANG; 15319304Speter } 15419304Speter } 15519304Speter rval = ex_filter(sp, cmdp, 15619304Speter &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); 15719304Speter 15819304Speter /* 15919304Speter * If in vi mode, move to the first nonblank. 16019304Speter * 16119304Speter * !!! 16219304Speter * Historic vi wasn't consistent in this area -- if you used 16319304Speter * a forward motion it moved to the first nonblank, but if you 16419304Speter * did a backward motion it didn't. And, if you followed a 16519304Speter * backward motion with a forward motion, it wouldn't move to 16619304Speter * the nonblank for either. Going to the nonblank generally 16719304Speter * seems more useful and consistent, so we do it. 16819304Speter */ 16919304Speter sp->lno = rm.lno; 17019304Speter if (F_ISSET(sp, SC_VI)) { 17119304Speter sp->cno = 0; 17219304Speter (void)nonblank(sp, sp->lno, &sp->cno); 17319304Speter } else 17419304Speter sp->cno = rm.cno; 17519304Speter } 17619304Speter 17719304Speter /* Ex terminates with a bang, even if the command fails. */ 17819304Speter if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) 17919304Speter (void)ex_puts(sp, "!\n"); 18019304Speter 18119304Speter /* 18219304Speter * XXX 18319304Speter * The ! commands never return an error, so that autoprint always 18419304Speter * happens in the ex parser. 18519304Speter */ 18619304Speter return (0); 18719304Speter} 188