home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bsd / src / make / make-amiga / compat.c < prev    next >
C/C++ Source or Header  |  1993-09-23  |  17KB  |  617 lines

  1. /*
  2.  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  3.  * Copyright (c) 1988, 1989 by Adam de Boor
  4.  * Copyright (c) 1989 by Berkeley Softworks
  5.  * All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Adam de Boor.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #ifndef lint
  40. static char sccsid[] = "@(#)compat.c    5.7 (Berkeley) 3/1/91";
  41. #endif /* not lint */
  42.  
  43. /*-
  44.  * compat.c --
  45.  *    The routines in this file implement the full-compatibility
  46.  *    mode of PMake. Most of the special functionality of PMake
  47.  *    is available in this mode. Things not supported:
  48.  *        - different shells.
  49.  *        - friendly variable substitution.
  50.  *
  51.  * Interface:
  52.  *    Compat_Run        Initialize things for this module and recreate
  53.  *                      thems as need creatin'
  54.  */
  55.  
  56. #include    <stdio.h>
  57. #include    <sys/types.h>
  58. #include    <sys/signal.h>
  59. #include    <sys/wait.h>
  60. #include    <sys/errno.h>
  61. #include    <ctype.h>
  62. #include    "make.h"
  63. extern int errno;
  64.  
  65. /*
  66.  * The following array is used to make a fast determination of which
  67.  * characters are interpreted specially by the shell.  If a command
  68.  * contains any of these characters, it is executed by the shell, not
  69.  * directly by us.
  70.  */
  71.  
  72. static char         meta[256];
  73.  
  74. static GNode        *curTarg = NILGNODE;
  75. static GNode        *ENDNode;
  76. static int          CompatRunCommand();
  77.  
  78. /*-
  79.  *-----------------------------------------------------------------------
  80.  * CompatInterrupt --
  81.  *    Interrupt the creation of the current target and remove it if
  82.  *    it ain't precious.
  83.  *
  84.  * Results:
  85.  *    None.
  86.  *
  87.  * Side Effects:
  88.  *    The target is removed and the process exits. If .INTERRUPT exists,
  89.  *    its commands are run first WITH INTERRUPTS IGNORED..
  90.  *
  91.  *-----------------------------------------------------------------------
  92.  */
  93. static void
  94. CompatInterrupt (signo)
  95.     int        signo;
  96. {
  97.     GNode   *gn;
  98.     
  99.     if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {
  100.     char       *file = Var_Value (TARGET, curTarg);
  101.  
  102.     if (unlink (file) == SUCCESS) {
  103.         printf ("*** %s removed\n", file);
  104.     }
  105.  
  106.     /*
  107.      * Run .INTERRUPT only if hit with interrupt signal
  108.      */
  109.     if (signo == SIGINT) {
  110.         gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
  111.         if (gn != NILGNODE) {
  112.         Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
  113.         }
  114.     }
  115.     }
  116.     exit (0);
  117. }
  118.  
  119. /*-
  120.  *-----------------------------------------------------------------------
  121.  * CompatRunCommand --
  122.  *    Execute the next command for a target. If the command returns an
  123.  *    error, the node's made field is set to ERROR and creation stops.
  124.  *
  125.  * Results:
  126.  *    0 if the command succeeded, 1 if an error occurred.
  127.  *
  128.  * Side Effects:
  129.  *    The node's 'made' field may be set to ERROR.
  130.  *
  131.  *-----------------------------------------------------------------------
  132.  */
  133. static int
  134. CompatRunCommand (cmd, gn)
  135.     char          *cmd;            /* Command to execute */
  136.     GNode         *gn;        /* Node from which the command came */
  137. {
  138.     char          *cmdStart;    /* Start of expanded command */
  139.     register char *cp;
  140.     Boolean       silent,       /* Don't print command */
  141.           errCheck;     /* Check errors */
  142.     union wait       reason;       /* Reason for child's death */
  143.     int              status;       /* Description of child's death */
  144.     int              cpid;            /* Child actually found */
  145.     int              numWritten;    /* Number of bytes written for error message */
  146.     ReturnStatus  stat;            /* Status of fork */
  147.     LstNode       cmdNode;      /* Node where current command is located */
  148.     char          **av;            /* Argument vector for thing to exec */
  149.     int              argc;            /* Number of arguments in av or 0 if not
  150.                  * dynamically allocated */
  151.     Boolean       local;        /* TRUE if command should be executed
  152.                  * locally */
  153.  
  154.     silent = gn->type & OP_SILENT;
  155.     errCheck = !(gn->type & OP_IGNORE);
  156.  
  157.     cmdNode = Lst_Member (gn->commands, (ClientData)cmd);
  158.     cmdStart = Var_Subst (cmd, gn, FALSE);
  159.  
  160.     /*
  161.      * brk_string will return an argv with a NULL in av[1], thus causing
  162.      * execvp to choke and die horribly. Besides, how can we execute a null
  163.      * command? In any case, we warn the user that the command expanded to
  164.      * nothing (is this the right thing to do?).
  165.      */
  166.      
  167.     if (*cmdStart == '\0') {
  168.     Error("%s expands to empty string", cmd);
  169.     return(0);
  170.     } else {
  171.     cmd = cmdStart;
  172.     }
  173.     Lst_Replace (cmdNode, (ClientData)cmdStart);
  174.  
  175.     if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
  176.     (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
  177.     return(0);
  178.     } else if (strcmp(cmdStart, "...") == 0) {
  179.     gn->type |= OP_SAVE_CMDS;
  180.     return(0);
  181.     }
  182.  
  183.     while ((*cmd == '@') || (*cmd == '-')) {
  184.     if (*cmd == '@') {
  185.         silent = TRUE;
  186.     } else {
  187.         errCheck = FALSE;
  188.     }
  189.     cmd++;
  190.     }
  191.     
  192.     /*
  193.      * Search for meta characters in the command. If there are no meta
  194.      * characters, there's no need to execute a shell to execute the
  195.      * command.
  196.      */
  197.     for (cp = cmd; !meta[*cp]; cp++) {
  198.     continue;
  199.     }
  200.  
  201.     /*
  202.      * Print the command before echoing if we're not supposed to be quiet for
  203.      * this one. We also print the command if -n given.
  204.      */
  205.     if (!silent || noExecute) {
  206.     printf ("%s\n", cmd);
  207.     fflush(stdout);
  208.     }
  209.  
  210.     /*
  211.      * If we're not supposed to execute any commands, this is as far as
  212.      * we go...
  213.      */
  214.     if (noExecute) {
  215.     return (0);
  216.     }
  217.     
  218.     if (*cp != '\0') {
  219.     /*
  220.      * If *cp isn't the null character, we hit a "meta" character and
  221.      * need to pass the command off to the shell. We give the shell the
  222.      * -e flag as well as -c if it's supposed to exit when it hits an
  223.      * error.
  224.      */
  225.     static char    *shargv[4] = { "/bin/sh" };
  226.  
  227.     shargv[1] = (errCheck ? "-ec" : "-c");
  228.     shargv[2] = cmd;
  229.     shargv[3] = (char *)NULL;
  230.     av = shargv;
  231.     argc = 0;
  232.     } else {
  233.     /*
  234.      * No meta-characters, so no need to exec a shell. Break the command
  235.      * into words to form an argument vector we can execute.
  236.      * brk_string sticks our name in av[0], so we have to
  237.      * skip over it...
  238.      */
  239.     av = brk_string(cmd, &argc);
  240.     av += 1;
  241.     }
  242.     
  243.     local = TRUE;
  244.  
  245.     /*
  246.      * Fork and execute the single command. If the fork fails, we abort.
  247.      */
  248.     cpid = vfork();
  249.     if (cpid < 0) {
  250.     Fatal("Could not fork");
  251.     }
  252.     if (cpid == 0) {
  253.     if (local) {
  254.         execvp(av[0], av);
  255.         numWritten = write (2, av[0], strlen (av[0]));
  256.         numWritten = write (2, ": not found\n", sizeof(": not found"));
  257.     } else {
  258.         (void)execv(av[0], av);
  259.     }
  260.     exit(1);
  261.     }
  262.     
  263.     /*
  264.      * The child is off and running. Now all we can do is wait...
  265.      */
  266.