home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_bang.c < prev    next >
C/C++ Source or Header  |  1996-09-23  |  5KB  |  187 lines

  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.