[BACK]Return to compat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/compat.c, Revision 1.1

1.1     ! deraadt     1: /*     $NetBSD: compat.c,v 1.11 1995/09/27 18:44:38 jtc Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
        !             5:  * Copyright (c) 1988, 1989 by Adam de Boor
        !             6:  * Copyright (c) 1989 by Berkeley Softworks
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * This code is derived from software contributed to Berkeley by
        !            10:  * Adam de Boor.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *     This product includes software developed by the University of
        !            23:  *     California, Berkeley and its contributors.
        !            24:  * 4. Neither the name of the University nor the names of its contributors
        !            25:  *    may be used to endorse or promote products derived from this software
        !            26:  *    without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            29:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            31:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            32:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            33:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            34:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            35:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            36:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            37:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            38:  * SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: #ifndef lint
        !            42: #if 0
        !            43: static char sccsid[] = "@(#)compat.c   5.7 (Berkeley) 3/1/91";
        !            44: #else
        !            45: static char rcsid[] = "$NetBSD: compat.c,v 1.11 1995/09/27 18:44:38 jtc Exp $";
        !            46: #endif
        !            47: #endif /* not lint */
        !            48:
        !            49: /*-
        !            50:  * compat.c --
        !            51:  *     The routines in this file implement the full-compatibility
        !            52:  *     mode of PMake. Most of the special functionality of PMake
        !            53:  *     is available in this mode. Things not supported:
        !            54:  *         - different shells.
        !            55:  *         - friendly variable substitution.
        !            56:  *
        !            57:  * Interface:
        !            58:  *     Compat_Run          Initialize things for this module and recreate
        !            59:  *                         thems as need creatin'
        !            60:  */
        !            61:
        !            62: #include    <stdio.h>
        !            63: #include    <sys/types.h>
        !            64: #include    <sys/stat.h>
        !            65: #include    <sys/wait.h>
        !            66: #include    <ctype.h>
        !            67: #include    <errno.h>
        !            68: #include    <signal.h>
        !            69: #include    "make.h"
        !            70: #include    "hash.h"
        !            71: #include    "dir.h"
        !            72: #include    "job.h"
        !            73: extern int errno;
        !            74:
        !            75: /*
        !            76:  * The following array is used to make a fast determination of which
        !            77:  * characters are interpreted specially by the shell.  If a command
        !            78:  * contains any of these characters, it is executed by the shell, not
        !            79:  * directly by us.
        !            80:  */
        !            81:
        !            82: static char        meta[256];
        !            83:
        !            84: static GNode       *curTarg = NILGNODE;
        !            85: static GNode       *ENDNode;
        !            86: static void CompatInterrupt __P((int));
        !            87: static int CompatRunCommand __P((ClientData, ClientData));
        !            88: static int CompatMake __P((ClientData, ClientData));
        !            89:
        !            90: /*-
        !            91:  *-----------------------------------------------------------------------
        !            92:  * CompatInterrupt --
        !            93:  *     Interrupt the creation of the current target and remove it if
        !            94:  *     it ain't precious.
        !            95:  *
        !            96:  * Results:
        !            97:  *     None.
        !            98:  *
        !            99:  * Side Effects:
        !           100:  *     The target is removed and the process exits. If .INTERRUPT exists,
        !           101:  *     its commands are run first WITH INTERRUPTS IGNORED..
        !           102:  *
        !           103:  *-----------------------------------------------------------------------
        !           104:  */
        !           105: static void
        !           106: CompatInterrupt (signo)
        !           107:     int            signo;
        !           108: {
        !           109:     GNode   *gn;
        !           110:
        !           111:     if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {
        !           112:        char      *p1;
        !           113:        char      *file = Var_Value (TARGET, curTarg, &p1);
        !           114:        struct stat st;
        !           115:
        !           116:        if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) &&
        !           117:            unlink(file) != -1) {
        !           118:            printf ("*** %s removed\n", file);
        !           119:        }
        !           120:        if (p1)
        !           121:            free(p1);
        !           122:
        !           123:        /*
        !           124:         * Run .INTERRUPT only if hit with interrupt signal
        !           125:         */
        !           126:        if (signo == SIGINT) {
        !           127:            gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
        !           128:            if (gn != NILGNODE) {
        !           129:                Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
        !           130:            }
        !           131:        }
        !           132:
        !           133:     }
        !           134:     exit (signo);
        !           135: }
        !           136: 
        !           137: /*-
        !           138:  *-----------------------------------------------------------------------
        !           139:  * CompatRunCommand --
        !           140:  *     Execute the next command for a target. If the command returns an
        !           141:  *     error, the node's made field is set to ERROR and creation stops.
        !           142:  *
        !           143:  * Results:
        !           144:  *     0 if the command succeeded, 1 if an error occurred.
        !           145:  *
        !           146:  * Side Effects:
        !           147:  *     The node's 'made' field may be set to ERROR.
        !           148:  *
        !           149:  *-----------------------------------------------------------------------
        !           150:  */
        !           151: static int
        !           152: CompatRunCommand (cmdp, gnp)
        !           153:     ClientData    cmdp;                /* Command to execute */
        !           154:     ClientData    gnp;         /* Node from which the command came */
        !           155: {
        !           156:     char         *cmdStart;    /* Start of expanded command */
        !           157:     register char *cp;
        !           158:     Boolean      silent,       /* Don't print command */
        !           159:                  errCheck;     /* Check errors */
        !           160:     union wait           reason;       /* Reason for child's death */
        !           161:     int                  status;       /* Description of child's death */
        !           162:     int                  cpid;         /* Child actually found */
        !           163:     ReturnStatus  stat;                /* Status of fork */
        !           164:     LstNode      cmdNode;      /* Node where current command is located */
        !           165:     char         **av;         /* Argument vector for thing to exec */
        !           166:     int                  argc;         /* Number of arguments in av or 0 if not
        !           167:                                 * dynamically allocated */
        !           168:     Boolean      local;        /* TRUE if command should be executed
        !           169:                                 * locally */
        !           170:     char         *cmd = (char *) cmdp;
        !           171:     GNode        *gn = (GNode *) gnp;
        !           172:
        !           173:     /*
        !           174:      * Avoid clobbered variable warnings by forcing the compiler
        !           175:      * to ``unregister'' variables
        !           176:      */
        !           177: #if __GNUC__
        !           178:     (void) &av;
        !           179:     (void) &errCheck;
        !           180: #endif
        !           181:     silent = gn->type & OP_SILENT;
        !           182:     errCheck = !(gn->type & OP_IGNORE);
        !           183:
        !           184:     cmdNode = Lst_Member (gn->commands, (ClientData)cmd);
        !           185:     cmdStart = Var_Subst (NULL, cmd, gn, FALSE);
        !           186:
        !           187:     /*
        !           188:      * brk_string will return an argv with a NULL in av[1], thus causing
        !           189:      * execvp to choke and die horribly. Besides, how can we execute a null
        !           190:      * command? In any case, we warn the user that the command expanded to
        !           191:      * nothing (is this the right thing to do?).
        !           192:      */
        !           193:
        !           194:     if (*cmdStart == '\0') {
        !           195:        free(cmdStart);
        !           196:        Error("%s expands to empty string", cmd);
        !           197:        return(0);
        !           198:     } else {
        !           199:        cmd = cmdStart;
        !           200:     }
        !           201:     Lst_Replace (cmdNode, (ClientData)cmdStart);
        !           202:
        !           203:     if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
        !           204:        (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
        !           205:        return(0);
        !           206:     } else if (strcmp(cmdStart, "...") == 0) {
        !           207:        gn->type |= OP_SAVE_CMDS;
        !           208:        return(0);
        !           209:     }
        !           210:
        !           211:     while ((*cmd == '@') || (*cmd == '-')) {
        !           212:        if (*cmd == '@') {
        !           213:            silent = TRUE;
        !           214:        } else {
        !           215:            errCheck = FALSE;
        !           216:        }
        !           217:        cmd++;
        !           218:     }
        !           219:
        !           220:     while (isspace((unsigned char)*cmd))
        !           221:        cmd++;
        !           222:
        !           223:     /*
        !           224:      * Search for meta characters in the command. If there are no meta
        !           225:      * characters, there's no need to execute a shell to execute the
        !           226:      * command.
        !           227:      */
        !           228:     for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
        !           229:        continue;
        !           230:     }
        !           231:
        !           232:     /*
        !           233:      * Print the command before echoing if we're not supposed to be quiet for
        !           234:      * this one. We also print the command if -n given.
        !           235:      */
        !           236:     if (!silent || noExecute) {
        !           237:        printf ("%s\n", cmd);
        !           238:        fflush(stdout);
        !           239:     }
        !           240:
        !           241:     /*
        !           242:      * If we're not supposed to execute any commands, this is as far as
        !           243:      * we go...
        !           244:      */
        !           245:     if (noExecute) {
        !           246:        return (0);
        !           247:     }
        !           248:
        !           249:     if (*cp != '\0') {
        !           250:        /*
        !           251:         * If *cp isn't the null character, we hit a "meta" character and
        !           252:         * need to pass the command off to the shell. We give the shell the
        !           253:         * -e flag as well as -c if it's supposed to exit when it hits an
        !           254:         * error.
        !           255:         */
        !           256:        static char     *shargv[4] = { "/bin/sh" };
        !           257:
        !           258:        shargv[1] = (errCheck ? "-ec" : "-c");
        !           259:        shargv[2] = cmd;
        !           260:        shargv[3] = (char *)NULL;
        !           261:        av = shargv;
        !           262:        argc = 0;
        !           263:     } else {
        !           264:        /*
        !           265:         * No meta-characters, so no need to exec a shell. Break the command
        !           266:         * into words to form an argument vector we can execute.
        !           267:         * brk_string sticks our name in av[0], so we have to
        !           268:         * skip over it...
        !           269:         */
        !           270:        av = brk_string(cmd, &argc, TRUE);
        !           271:        av += 1;
        !           272:     }
        !           273:
        !           274:     local = TRUE;
        !           275:
        !           276:     /*
        !           277:      * Fork and execute the single command. If the fork fails, we abort.
        !           278:      */
        !           279:     cpid = vfork();
        !           280:     if (cpid < 0) {
        !           281:        Fatal("Could not fork");
        !           282:     }
        !           283:     if (cpid == 0) {
        !           284:        if (local) {
        !           285:            execvp(av[0], av);
        !           286:            (void) write (2, av[0], strlen (av[0]));
        !           287:            (void) write (2, ": not found\n", sizeof(": not found"));
        !           288:        } else {
        !           289:            (void)execv(av[0], av);
        !           290:        }
        !           291:        exit(1);
        !           292:     }
        !           293:     free(cmdStart);
        !           294:     Lst_Replace (cmdNode, (ClientData) NULL);
        !           295:
        !           296:     /*
        !           297:      * The child is off and running. Now all we can do is wait...
        !           298:      */
        !           299:     while (1) {
        !           300:
        !           301:        while ((stat = wait((int *)&reason)) != cpid) {
        !           302:            if (stat == -1 && errno != EINTR) {
        !           303:                break;
        !           304:            }
        !           305:        }
        !           306:
        !           307:        if (stat > -1) {
        !           308:            if (WIFSTOPPED(reason)) {
        !           309:                status = reason.w_stopval;              /* stopped */
        !           310:            } else if (WIFEXITED(reason)) {
        !           311:                status = reason.w_retcode;              /* exited */
        !           312:                if (status != 0) {
        !           313:                    printf ("*** Error code %d", status);
        !           314:                }
        !           315:            } else {
        !           316:                status = reason.w_termsig;              /* signaled */
        !           317:                printf ("*** Signal %d", status);
        !           318:            }
        !           319:
        !           320:
        !           321:            if (!WIFEXITED(reason) || (status != 0)) {
        !           322:                if (errCheck) {
        !           323:                    gn->made = ERROR;
        !           324:                    if (keepgoing) {
        !           325:                        /*
        !           326:                         * Abort the current target, but let others
        !           327:                         * continue.
        !           328:                         */
        !           329:                        printf (" (continuing)\n");
        !           330:                    }
        !           331:                } else {
        !           332:                    /*
        !           333:                     * Continue executing commands for this target.
        !           334:                     * If we return 0, this will happen...
        !           335:                     */
        !           336:                    printf (" (ignored)\n");
        !           337:                    status = 0;
        !           338:                }
        !           339:            }
        !           340:            break;
        !           341:        } else {
        !           342:            Fatal ("error in wait: %d", stat);
        !           343:            /*NOTREACHED*/
        !           344:        }
        !           345:     }
        !           346:
        !           347:     return (status);
        !           348: }
        !           349: 
        !           350: /*-
        !           351:  *-----------------------------------------------------------------------
        !           352:  * CompatMake --
        !           353:  *     Make a target.
        !           354:  *
        !           355:  * Results:
        !           356:  *     0
        !           357:  *
        !           358:  * Side Effects:
        !           359:  *     If an error is detected and not being ignored, the process exits.
        !           360:  *
        !           361:  *-----------------------------------------------------------------------
        !           362:  */
        !           363: static int
        !           364: CompatMake (gnp, pgnp)
        !           365:     ClientData gnp;        /* The node to make */
        !           366:     ClientData  pgnp;      /* Parent to abort if necessary */
        !           367: {
        !           368:     GNode *gn = (GNode *) gnp;
        !           369:     GNode *pgn = (GNode *) pgnp;
        !           370:     if (gn->type & OP_USE) {
        !           371:        Make_HandleUse(gn, pgn);
        !           372:     } else if (gn->made == UNMADE) {
        !           373:        /*
        !           374:         * First mark ourselves to be made, then apply whatever transformations
        !           375:         * the suffix module thinks are necessary. Once that's done, we can
        !           376:         * descend and make all our children. If any of them has an error
        !           377:         * but the -k flag was given, our 'make' field will be set FALSE again.
        !           378:         * This is our signal to not attempt to do anything but abort our
        !           379:         * parent as well.
        !           380:         */
        !           381:        gn->make = TRUE;
        !           382:        gn->made = BEINGMADE;
        !           383:        Suff_FindDeps (gn);
        !           384:        Lst_ForEach (gn->children, CompatMake, (ClientData)gn);
        !           385:        if (!gn->make) {
        !           386:            gn->made = ABORTED;
        !           387:            pgn->make = FALSE;
        !           388:            return (0);
        !           389:        }
        !           390:
        !           391:        if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
        !           392:            char *p1;
        !           393:            Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
        !           394:            if (p1)
        !           395:                free(p1);
        !           396:        }
        !           397:
        !           398:        /*
        !           399:         * All the children were made ok. Now cmtime contains the modification
        !           400:         * time of the newest child, we need to find out if we exist and when
        !           401:         * we were modified last. The criteria for datedness are defined by the
        !           402:         * Make_OODate function.
        !           403:         */
        !           404:        if (DEBUG(MAKE)) {
        !           405:            printf("Examining %s...", gn->name);
        !           406:        }
        !           407:        if (! Make_OODate(gn)) {
        !           408:            gn->made = UPTODATE;
        !           409:            if (DEBUG(MAKE)) {
        !           410:                printf("up-to-date.\n");
        !           411:            }
        !           412:            return (0);
        !           413:        } else if (DEBUG(MAKE)) {
        !           414:            printf("out-of-date.\n");
        !           415:        }
        !           416:
        !           417:        /*
        !           418:         * If the user is just seeing if something is out-of-date, exit now
        !           419:         * to tell him/her "yes".
        !           420:         */
        !           421:        if (queryFlag) {
        !           422:            exit (-1);
        !           423:        }
        !           424:
        !           425:        /*
        !           426:         * We need to be re-made. We also have to make sure we've got a $?
        !           427:         * variable. To be nice, we also define the $> variable using
        !           428:         * Make_DoAllVar().
        !           429:         */
        !           430:        Make_DoAllVar(gn);
        !           431:
        !           432:        /*
        !           433:         * Alter our type to tell if errors should be ignored or things
        !           434:         * should not be printed so CompatRunCommand knows what to do.
        !           435:         */
        !           436:        if (Targ_Ignore (gn)) {
        !           437:            gn->type |= OP_IGNORE;
        !           438:        }
        !           439:        if (Targ_Silent (gn)) {
        !           440:            gn->type |= OP_SILENT;
        !           441:        }
        !           442:
        !           443:        if (Job_CheckCommands (gn, Fatal)) {
        !           444:            /*
        !           445:             * Our commands are ok, but we still have to worry about the -t
        !           446:             * flag...
        !           447:             */
        !           448:            if (!touchFlag) {
        !           449:                curTarg = gn;
        !           450:                Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn);
        !           451:                curTarg = NILGNODE;
        !           452:            } else {
        !           453:                Job_Touch (gn, gn->type & OP_SILENT);
        !           454:            }
        !           455:        } else {
        !           456:            gn->made = ERROR;
        !           457:        }
        !           458:
        !           459:        if (gn->made != ERROR) {
        !           460:            /*
        !           461:             * If the node was made successfully, mark it so, update
        !           462:             * its modification time and timestamp all its parents. Note
        !           463:             * that for .ZEROTIME targets, the timestamping isn't done.
        !           464:             * This is to keep its state from affecting that of its parent.
        !           465:             */
        !           466:            gn->made = MADE;
        !           467: #ifndef RECHECK
        !           468:            /*
        !           469:             * We can't re-stat the thing, but we can at least take care of
        !           470:             * rules where a target depends on a source that actually creates
        !           471:             * the target, but only if it has changed, e.g.
        !           472:             *
        !           473:             * parse.h : parse.o
        !           474:             *
        !           475:             * parse.o : parse.y
        !           476:             *          yacc -d parse.y
        !           477:             *          cc -c y.tab.c
        !           478:             *          mv y.tab.o parse.o
        !           479:             *          cmp -s y.tab.h parse.h || mv y.tab.h parse.h
        !           480:             *
        !           481:             * In this case, if the definitions produced by yacc haven't
        !           482:             * changed from before, parse.h won't have been updated and
        !           483:             * gn->mtime will reflect the current modification time for
        !           484:             * parse.h. This is something of a kludge, I admit, but it's a
        !           485:             * useful one..
        !           486:             *
        !           487:             * XXX: People like to use a rule like
        !           488:             *
        !           489:             * FRC:
        !           490:             *
        !           491:             * To force things that depend on FRC to be made, so we have to
        !           492:             * check for gn->children being empty as well...
        !           493:             */
        !           494:            if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
        !           495:                gn->mtime = now;
        !           496:            }
        !           497: #else
        !           498:            /*
        !           499:             * This is what Make does and it's actually a good thing, as it
        !           500:             * allows rules like
        !           501:             *
        !           502:             *  cmp -s y.tab.h parse.h || cp y.tab.h parse.h
        !           503:             *
        !           504:             * to function as intended. Unfortunately, thanks to the stateless
        !           505:             * nature of NFS (and the speed of this program), there are times
        !           506:             * when the modification time of a file created on a remote
        !           507:             * machine will not be modified before the stat() implied by
        !           508:             * the Dir_MTime occurs, thus leading us to believe that the file
        !           509:             * is unchanged, wreaking havoc with files that depend on this one.
        !           510:             *
        !           511:             * I have decided it is better to make too much than to make too
        !           512:             * little, so this stuff is commented out unless you're sure it's
        !           513:             * ok.
        !           514:             * -- ardeb 1/12/88
        !           515:             */
        !           516:            if (noExecute || Dir_MTime(gn) == 0) {
        !           517:                gn->mtime = now;
        !           518:            }
        !           519:            if (gn->cmtime > gn->mtime)
        !           520:                gn->mtime = gn->cmtime;
        !           521:            if (DEBUG(MAKE)) {
        !           522:                printf("update time: %s\n", Targ_FmtTime(gn->mtime));
        !           523:            }
        !           524: #endif
        !           525:            if (!(gn->type & OP_EXEC)) {
        !           526:                pgn->childMade = TRUE;
        !           527:                Make_TimeStamp(pgn, gn);
        !           528:            }
        !           529:        } else if (keepgoing) {
        !           530:            pgn->make = FALSE;
        !           531:        } else {
        !           532:            printf ("\n\nStop.\n");
        !           533:            exit (1);
        !           534:        }
        !           535:     } else if (gn->made == ERROR) {
        !           536:        /*
        !           537:         * Already had an error when making this beastie. Tell the parent
        !           538:         * to abort.
        !           539:         */
        !           540:        pgn->make = FALSE;
        !           541:     } else {
        !           542:        if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
        !           543:            char *p1;
        !           544:            Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
        !           545:            if (p1)
        !           546:                free(p1);
        !           547:        }
        !           548:        switch(gn->made) {
        !           549:            case BEINGMADE:
        !           550:                Error("Graph cycles through %s\n", gn->name);
        !           551:                gn->made = ERROR;
        !           552:                pgn->make = FALSE;
        !           553:                break;
        !           554:            case MADE:
        !           555:                if ((gn->type & OP_EXEC) == 0) {
        !           556:                    pgn->childMade = TRUE;
        !           557:                    Make_TimeStamp(pgn, gn);
        !           558:                }
        !           559:                break;
        !           560:            case UPTODATE:
        !           561:                if ((gn->type & OP_EXEC) == 0) {
        !           562:                    Make_TimeStamp(pgn, gn);
        !           563:                }
        !           564:                break;
        !           565:            default:
        !           566:                break;
        !           567:        }
        !           568:     }
        !           569:
        !           570:     return (0);
        !           571: }
        !           572: 
        !           573: /*-
        !           574:  *-----------------------------------------------------------------------
        !           575:  * Compat_Run --
        !           576:  *     Initialize this mode and start making.
        !           577:  *
        !           578:  * Results:
        !           579:  *     None.
        !           580:  *
        !           581:  * Side Effects:
        !           582:  *     Guess what?
        !           583:  *
        !           584:  *-----------------------------------------------------------------------
        !           585:  */
        !           586: void
        !           587: Compat_Run(targs)
        !           588:     Lst                  targs;    /* List of target nodes to re-create */
        !           589: {
        !           590:     char         *cp;      /* Pointer to string of shell meta-characters */
        !           591:     GNode        *gn = NULL;/* Current root target */
        !           592:     int                  errors;   /* Number of targets not remade due to errors */
        !           593:
        !           594:     if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
        !           595:        signal(SIGINT, CompatInterrupt);
        !           596:     }
        !           597:     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
        !           598:        signal(SIGTERM, CompatInterrupt);
        !           599:     }
        !           600:     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
        !           601:        signal(SIGHUP, CompatInterrupt);
        !           602:     }
        !           603:     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
        !           604:        signal(SIGQUIT, CompatInterrupt);
        !           605:     }
        !           606:
        !           607:     for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
        !           608:        meta[(unsigned char) *cp] = 1;
        !           609:     }
        !           610:     /*
        !           611:      * The null character serves as a sentinel in the string.
        !           612:      */
        !           613:     meta[0] = 1;
        !           614:
        !           615:     ENDNode = Targ_FindNode(".END", TARG_CREATE);
        !           616:     /*
        !           617:      * If the user has defined a .BEGIN target, execute the commands attached
        !           618:      * to it.
        !           619:      */
        !           620:     if (!queryFlag) {
        !           621:        gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
        !           622:        if (gn != NILGNODE) {
        !           623:            Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
        !           624:        }
        !           625:     }
        !           626:
        !           627:     /*
        !           628:      * For each entry in the list of targets to create, call CompatMake on
        !           629:      * it to create the thing. CompatMake will leave the 'made' field of gn
        !           630:      * in one of several states:
        !           631:      *     UPTODATE        gn was already up-to-date
        !           632:      *     MADE            gn was recreated successfully
        !           633:      *     ERROR           An error occurred while gn was being created
        !           634:      *     ABORTED         gn was not remade because one of its inferiors
        !           635:      *                     could not be made due to errors.
        !           636:      */
        !           637:     errors = 0;
        !           638:     while (!Lst_IsEmpty (targs)) {
        !           639:        gn = (GNode *) Lst_DeQueue (targs);
        !           640:        CompatMake (gn, gn);
        !           641:
        !           642:        if (gn->made == UPTODATE) {
        !           643:            printf ("`%s' is up to date.\n", gn->name);
        !           644:        } else if (gn->made == ABORTED) {
        !           645:            printf ("`%s' not remade because of errors.\n", gn->name);
        !           646:            errors += 1;
        !           647:        }
        !           648:     }
        !           649:
        !           650:     /*
        !           651:      * If the user has defined a .END target, run its commands.
        !           652:      */
        !           653:     if (errors == 0) {
        !           654:        Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn);
        !           655:     }
        !           656: }