1
0
Files
irix-657m-src/eoe/cmd/make/main.c
2022-09-29 17:59:04 +03:00

1398 lines
30 KiB
C

/* Copyright (c) 1993 UNIX System Laboratories, Inc. */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
/* Copyright (c) 1988, 1990 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)make:main.c 1.24.1.2"
#include "defs"
#include <signal.h>
#include <errno.h>
#include <ctype.h>
#include <pfmt.h>
#include <locale.h>
#include <paths.h>
/* NAME
** make - maintain, update and regenerate groups of programs.
**
** OPTIONS for make
** '-f' The description file is the next argument;
** (makefile is the default)
** '-p' Print out a complete set of macro definitions and target
** descriptions
** '-i' Ignore error codes returned by invoked commands
** '-S' stop after any command fails (normally do parallel work)
** '-s' Silent mode. Do not print command lines before invoking
** '-n' No execute mode. Print commands, but do not execute them.
** '-t' Touch the target files but don't issue command
** '-g' Turn on auto $(GET)
** '-q' Question. Check if object is up-to-date;
** returns exit code 0 if up-to-date, -1 if not
** '-u' unconditional flag. Ignore timestamps.
** '-e' environment variable override locals
** '-r' ignore built in rules
** '-d' Debug. No-op unless compiled with -DMKDEBUG
** prints nice debug tracking messages
** '-D' Debug alot.
** '-w' Set off warning msgs.
** '-P' Set on parallel.
** '-B' Block the target's output.
** Additional SGI options:
** '-N' turn on NULL suffix allowing dependencies option
** '-M' turn off NULL suffix ... option
** '-O' turn off -b'
** '-b' turn on MH DEFAULT handling (default)
*/
#ifndef MAKE_SHELL
#define MAKE_SHELL _PATH_BSHELL
#endif
static char makefile[] = "makefile",
Makefile[] = "Makefile",
Makeflags[] = "MAKEFLAGS",
RELEASE[] = "RELEASE";
char Nullstr[] = "",
funny[CHAR_LIST];
extern CHARSTAR builtin[];
CHARSTAR *linesptr = builtin;
int parallel = PARALLEL ; /* The max. no. of parallel proc. that make will fork */
char tmp_block[30];
char * cur_makefile;
char * cur_wd; /* Current working directory */
int nproc = 0 ; /* No. of process currently running */
int desc_start = NO;
FILE *fin;
struct nameblock pspace;
NAMEBLOCK curpname = &pspace,
mainname,
firstname;
LINEBLOCK sufflist;
VARBLOCK firstvar;
PATTERN firstpat ;
OPENDIR firstod;
void (*intstat) (),
(*quitstat) (),
(*hupstat) (),
(*termstat) ();
/*
** Declare local functions and make LINT happy.
*/
static int rddescf();
static int rdd1();
static void printdesc();
static void prname();
static void getmflgs();
static void setflags();
static int optswitch();
static void usage();
static void setmflgs();
static int chkmflgs();
static void setmmacs();
static int chkmmacs();
static void readenv();
static int eqsign();
static void callyacc();
void posix_env();
void convtmflgs();
static char temp_path[MAXPATHLEN]; /* max temp pathname */
int Mflags = MH_DEP;
int okdel = YES;
int k_error = 0; /* For -k option errors */
int mf_dashed = 0; /* If MAKEFLAGS is dashed format or not */
/*
* Save command line args for a possible alternate make -
* the arg parsing stuff trashes argv before we can determine
* that we need to switch makes
*/
CHARSTAR *sargv;
int sargc;
static CHARSTAR Cmd;
/*
* OUTMAX really needs to scale with ARG_MAX - we use outmax instead.
* Since quite a few routines (subst()) have no length checking
* we give ourselves some extra - its still easy to coredump make by
* having too long a command line, but at least we'll never core dump when
* we could have executed the command successfully.
*/
long outmax;
extern char yyfilename[];
extern int prereq();
main(argc, argv)
int argc;
CHARSTAR argv[];
{
void intrupt();
register NAMEBLOCK p;
register CHARSTAR s;
register VARBLOCK v;
register int i;
time_t tjunk;
char *getenv(), *sname(),
*m_getcwd(), *vptr;
void setvar(), enbint(), pwait();
int nfargs, chdir(), doname(), isdir(),
descset = 0;
char *args;
(void)setlocale(LC_ALL, "");
(void)setcat("uxepu");
(void)setlabel("UX:make");
for (s = "#|=^();&<>*?[]:$`'\"\\\n" ; *s ; ++s)
funny[(unsigned char)*s] |= META;
/* make '$' a terminal so yylex can interpret */
for (s = "\n\t :=;{}&>|$" ; *s ; ++s)
funny[(unsigned char)*s] |= TERMINAL;
funny[(unsigned char)'\0'] |= TERMINAL;
TURNON(INTRULE); /* Default internal rules, turned on */
init_lex();
builtin[1] = "MAKE=make";
/*
* WARNING - this is only useful for error messages, etc - we
* permit make to continue (and set this to ".") if the getcwd
* fails.
*/
cur_wd = m_getcwd();
outmax = sysconf(_SC_ARG_MAX) + 8000;
/* remember args since setflags trashes */
Cmd = argv[0];
sargv = malloc((argc+1-1) * sizeof(CHARSTAR));
for(i=1; i<argc; ++i)
sargv[i-1] = argv[i];
sargv[i-1] = NULL;
sargc = argc - 1;
v = varptr("SHELL");
v->varval.charstar = MAKE_SHELL;
v->envflg = YES;
v->noreset = NO;
TURNON(EXPORT); /* Export $(MAKEFLAGS) macros */
getmflgs(); /* Init $(MAKEFLAGS) variable */
TURNOFF(EXPORT);
setflags(argc, argv); /* Set command line flags */
setvar("$", "$");
/* Read command line "=" type args and make them readonly. */
TURNON(INARGS | EXPORT);
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("Reading \"=\" args on command line.\n");
#endif
args = ck_malloc(outmax);
strcpy(args,"MAKEARGS="); /* set to all command line macros */
/* set a yyfilename - eqsign calls yacc that may output an error */
strcpy(yyfilename, "Command line argruments");
for (i = 1; i < argc; ++i)
if ( argv[i] && argv[i][0] != MINUS &&
eqsign(argv[i]) ) {
strcat(args, " '");
strcat(args, argv[i]);
strcat(args, "'");
setmmacs(argv[i]); /* POSIX Add to MAKEFLAGS */
argv[i] = 0;
}
callyacc(args);
TURNOFF(INARGS | EXPORT);
if (IS_ON(INTRULE)) { /* Read internal definitions and rules. */
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("Reading internal rules.\n");
#endif
strcpy(yyfilename, "Internal Rules");
(void)rdd1((FILE *) NULL);
}
TURNOFF(INTRULE); /* Done with internal rules, now. */
/* Read environment args.
* Let file args which follow override, unless 'e'
* in MAKEFLAGS variable is set.
*/
if (chkmflgs('e')) /* New POSIX format but backward compat */
TURNON(ENVOVER);
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("Reading environment.\n");
#endif
TURNON(EXPORT);
strcpy(yyfilename, "Environment variables");
readenv();
TURNOFF(EXPORT | ENVOVER);
/* Get description file in the following order:
** - command line '-f' parameters
** - default names (makefile, Makefile, s.makefile, s.Makefile)
*/
desc_start = YES;
for (i = 1; i < argc; i++)
if ( argv[i] && (argv[i][0] == MINUS) &&
(argv[i][1] == 'f') && (argv[i][2] == CNULL)) {
argv[i] = 0;
if (i >= argc - 1 || argv[i+1] == 0)
fatal(":117:no description file after -f flag (bu1)");
if ( rddescf(argv[++i], YES) )
fatal1(":118:cannot open %s", argv[i]);
argv[i] = 0;
++descset;
}
if ( !descset ) {
if ( rddescf(makefile, NO))
if ( rddescf(Makefile, NO) )
if ( rddescf(makefile, YES))
(void)rddescf(Makefile, YES);
}
/* Set the POSIX default for ARFLAGS */
if(IS_ON(POSIX) && !getenv("ARFLAGS") ) {
setvar("ARFLAGS","-rv");
}
if (IS_ON(PRTR))
printdesc(NO);
if ( p = SRCHNAME(".IGNORE") ) {
/* POSIX: Turn on globally only if no prerequisites */
if(IS_ON(POSIX)) {
if(!prereq(p,(CHARSTAR) 0))
TURNON(IGNERR);
}
else TURNON(IGNERR);
}
if ( p = SRCHNAME(".SILENT") ) {
/* POSIX: Turn on globally only if no prerequisites */
if(IS_ON(POSIX)) {
if(!prereq(p,(CHARSTAR) 0))
TURNON(SIL);
}
else TURNON(SIL);
}
/*
* Permit flags to be turned on from within a Makefile
* We don't use .MAKEFLAGS since smake already uses that
*/
if (p = SRCHNAME(".MAKEOPTS")) {
DEPBLOCK d;
LINEBLOCK lp;
for (lp = p->linep; lp; lp = lp->nextline) {
for (d = lp->depp; d; d = d->nextdep)
if (d->depname->namep[0] == '-')
optswitch(d->depname->namep[1]);
}
}
/* perform sanity checking for parallel (after MAKEOPTS) */
if(IS_ON(PAR) && IS_ON(NOEX))
TURNOFF(PAR);
if (IS_ON(PAR)) {
if(IS_ON(BLOCK))
sprintf(tmp_block,"/var/tmp/make%d", getpid());
if ((vptr = getenv("PARALLEL")) && !(STREQ(vptr, "")))
if((parallel = atoi(vptr)) <= 0 )
parallel = 1;
} else
TURNOFF(BLOCK);
if (p = SRCHNAME(".SUFFIXES"))
sufflist = p->linep;
intstat = (void(*)()) signal(SIGINT, SIG_IGN);
quitstat = (void(*)()) signal(SIGQUIT, SIG_IGN);
hupstat = (void(*)()) signal(SIGHUP, SIG_IGN);
termstat = (void(*)()) signal(SIGTERM, SIG_IGN);
enbint(intrupt);
nfargs = 0;
for (i = 1; i < argc; ++i)
if ( s = argv[i] ) {
if ( !(p = SRCHNAME(s)) )
p = makename(s);
++nfargs;
(void)doname(p, 0, &tjunk );
if(IS_ON(PAR)){
#ifdef MKDEBUG
if (IS_ON(DBUG))
printdesc(YES);
#endif
pwait(0);
}
#ifdef MKDEBUG
if (IS_ON(DBUG))
printdesc(YES);
#endif
}
/*
* If no file arguments have been encountered, make the first
* name encountered that doesn't start with a dot
*/
if ( !nfargs )
if ( !mainname )
fatal(":119:no arguments or description file (bu7)");
else {
(void)doname(mainname, 0, &tjunk);
if(IS_ON(PAR)){
#ifdef MKDEBUG
if (IS_ON(DBUG))
printdesc(YES);
#endif
pwait(0);
}
#ifdef MKDEBUG
if (IS_ON(DBUG))
printdesc(YES);
#endif
}
mkexit(0); /* make succeeded; no fatal errors */
/*NOTREACHED*/
}
void
intrupt()
{
time_t exists();
int isprecious(), member_ar(), unlink();
void mkexit();
int lev, ret_isdir;
CHARSTAR p;
NAMEBLOCK lookup_name();
/*
* wait for all children to finish so they can get any
* errors out
*/
while (wait(NULL) != -1 && errno != ECHILD)
;
if (okdel && IS_OFF(NOEX) && IS_OFF(TOUCH) &&
(p = (varptr("@")->varval.charstar)) &&
(exists( lookup_name(p), &lev) != -1) &&
(!isprecious(p)) &&
(!member_ar(p))) /* don't remove archives generated during make */
{
if ((ret_isdir = isdir(p)) == 1)
pfmt(stderr, MM_NOSTD,
":102:\n*** %s NOT removed.\n", p);
else if ( !( ( ret_isdir == 2 ) || unlink(p) ) )
pfmt(stderr, MM_NOSTD,
":103:\n*** %s removed.\n", p);
}
fprintf(stderr, "\n");
mkexit(2);
/*NOTREACHED*/
}
void
enbint(onintr)
void (*onintr)();
{
if (intstat == (void(*)())SIG_DFL)
(void)sigset(SIGINT, onintr);
if (quitstat == (void(*)())SIG_DFL)
(void)sigset(SIGQUIT, onintr);
if (hupstat == (void(*)())SIG_DFL)
(void)sigset(SIGHUP, onintr);
if (termstat == (void(*)())SIG_DFL)
(void)sigset(SIGTERM, onintr);
}
static int
rddescf(descfile, sflg) /* read and parse description file */
CHARSTAR descfile;
int sflg; /* if YES try s.descfile */
{
void setvar();
FILE *k;
setvar("MAKEFILE", descfile);
strcpy(yyfilename, descfile);
if (STREQ(descfile, "-")) {
cur_makefile = descfile;
return( rdd1(stdin) );
}
retry:
strcpy(yyfilename, descfile);
if (k = fopen(descfile, "r")) {
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("Reading %s\n", descfile);
#endif
cur_makefile = descfile;
return( rdd1(k) );
}
if ( !sflg || !get(descfile, varptr(RELEASE)->varval.charstar,0) )
return(1);
sflg = NO;
goto retry;
}
/** used by yyparse **/
extern int yylineno;
extern CHARSTAR zznextc;
static int
rdd1(k)
FILE *k;
{
int yyparse();
void fatal();
fin = k;
yylineno = 0;
zznextc = 0;
if ( yyparse() )
fatal(":120:description file error (bu9)");
if ( ! (fin == NULL || fin == stdin) )
(void)fclose(fin);
return(0);
}
static void
printdesc(prntflag)
int prntflag;
{
register NAMEBLOCK p;
register VARBLOCK vp;
register CHAIN pch;
FILE *op;
if (prntflag)
op = stderr;
else
op = stdout;
fflush(stdout);
fflush(stderr);
if (prntflag) {
register OPENDIR od;
pfmt(op, MM_NOSTD, ":104:Open directories:\n");
for (od = firstod; od; od = od->nextopendir)
fprintf(op, "\t%s\n", od->dirn);
}
if (firstvar)
pfmt(op, MM_NOSTD, ":105:Macros:\n");
for (vp = firstvar; vp; vp = vp->nextvar)
if ( !(vp->v_aflg) )
fprintf(op, "%s = %s\n", vp->varname,
((vp->varval.charstar) == NULL? " ":vp->varval.charstar));
else {
pfmt(op, MM_NOSTD,
":106:Lookup chain: %s\n\t", vp->varname);
for (pch = (vp->varval.chain); pch; pch = pch->nextchain)
fprintf(op, " %s", (pch->datap.nameblock)->namep);
fprintf(op, "\n");
}
for (p = firstname; p; p = p->nextname)
prname(p, prntflag);
fprintf(op, "\n");
(void)fflush(op);
}
#include "termio.h"
static void
prname(p, prntflag)
register NAMEBLOCK p;
{
register DEPBLOCK dp;
register SHBLOCK sp;
register LINEBLOCK lp;
FILE *op;
static int cols = -1;
register int deplen;
if (prntflag)
op = stderr;
else
op = stdout;
if (cols < 0) {
/* determine # columns on screen */
struct winsize w;
if (ioctl(fileno(op), TIOCGWINSZ, &w) < 0)
cols = 80;
else
cols = w.ws_col;
}
fprintf(op, "\nTARGET:%s:", p->namep);
if (prntflag)
fprintf(op, " done=%d", p->done);
if (p == mainname)
pfmt(op, MM_NOSTD, ":107:(MAIN NAME)");
for (lp = p->linep; lp; lp = lp->nextline) {
if ( dp = lp->depp ) {
pfmt(op, MM_NOSTD, ":108:\n depends on:");
for (; dp; dp = dp->nextdep)
if ( dp->depname) {
register ilen;
ilen = strlen(dp->depname->namep) + 1;
if (ilen + deplen >= cols) {
deplen = 12;
fprintf(op, "\n\t ");
}
deplen += ilen;
fprintf(op, "%s ", dp->depname->namep);
}
}
if (sp = lp->shp) {
fprintf(op, "\n");
pfmt(op, MM_NOSTD, ":109:commands:\n");
for ( ; sp; sp = sp->nextsh)
fprintf(op, "\t%s\n", sp->shbp);
}
}
}
/*
* POSIX: $(MAKEFLAGS) now contains options and command line and user
* defined macros.
* Options can be "abcd" or "-a -b -c -d"
* Macros are white space seperated with no spaces around '=' char.
*/
static void
getmflgs() /* export command line flags for future invocation */
{
void setvar();
int sindex();
register CHARSTAR m, args, mf, eq;
register VARBLOCK vpr = varptr(Makeflags);
args = ck_malloc(outmax);
setvar(Makeflags, args);
vpr->varval.charstar[0] = CNULL;
vpr->envflg = YES;
vpr->noreset = YES;
/*optswitch('b');*/
if(!(mf = getenv("MAKEFLAGS")))
return;
m = mf;
while(m=strchr(m,'=')){
if(isspace(*(m-1))) {
printf("Environment MAKEFLAGS: No white space before '=' char");
mkexit(1);
}
++m;
}
while(*mf) {
char *mac;
int len;
switch(*mf) {
case '-': /* Handle single letter dashed option */
++mf_dashed;
++mf;
optswitch(*mf);
if(*mf == 'f') { /* Skip past possible f option arg */
while(isspace(*mf))++mf;
while(*mf && !isspace(*mf)) ++mf;
}
else ++mf;
break;
case ' ':
case '\t':
++mf;
break;
case '\'':
case '\"':
++mf; /* Skip user imbedded chars */
break;
default: /* Handle undashed options or macros */
m=mf;
if(!strchr(mf,'=')) { /* No macros - just options */
optswitch(*mf++);
break;
}
eq = strchr(mf,'=');
while(*m && !isspace(*m))++m; /* Past starting chars */
if(m < eq) {
optswitch(*mf++); /* Options */
break;
}
/* Macros */
m=mf;
while(*m && !isspace(*m)) ++m;
mac = ck_malloc(m-mf+1);
strncpy(mac,mf,m-mf);
mac[m-mf] = CNULL;
callyacc(mac);
setmmacs(mac);
free(mac);
mf = m;
break;
}
}
}
static void
setflags(ac, av)
register int ac;
CHARSTAR *av;
{
register int i, j;
register char c;
int flflg = 0; /* flag to note '-f' option. */
for (i = 1; i < ac; ++i) {
if (flflg ) {
flflg = 0;
continue;
}
if (av[i] && av[i][0] == MINUS) {
if (ANY(av[i], 'f'))
flflg++;
for (j = 1 ; (c = av[i][j]) != CNULL ; ++j)
if(optswitch(c))
break;
if (flflg)
av[i] = "-f";
else
av[i] = 0;
}
}
}
static int
optswitch(c) /* Handle a single character option */
char c;
{
switch (c) {
case 's': /* silent flag */
TURNON(SIL);
setmflgs(c);
return(0);
case 'n': /* do not exec any commands, just print */
TURNON(NOEX);
setmflgs(c);
return(0);
case 'e': /* environment override flag */
setmflgs(c);
return(0);
case 'p': /* print description */
TURNON(PRTR);
return(0);
case 'i': /* ignore errors */
TURNON(IGNERR);
setmflgs(c);
return(0);
case 'S':
TURNOFF(KEEPGO);
setmflgs(c);
return(0);
case 'k':
TURNON(KEEPGO);
setmflgs(c);
return(0);
case 'r': /* turn off internal rules */
TURNOFF(INTRULE);
return(0);
case 't': /* touch flag */
TURNON(TOUCH);
setmflgs(c);
return(0);
case 'q': /* question flag */
TURNON(QUEST);
setmflgs(c);
return(0);
case 'g': /* turn default $(GET) of files not found */
TURNON(GET);
setmflgs(c);
return(0);
case 'b': /* use MH version of test for whether cmd exists */
TURNON(MH_DEP);
setmflgs(c);
return(0);
/* turn off -b flag */
case 'O':
TURNOFF(MH_DEP);
setmflgs(c);
return(0);
case 'd': /* debug flag */
case 'D':
#ifdef MKDEBUG
if (c == 'd')
TURNON(DBUG2);
else
TURNON(DBUG);
setmflgs(c);
setlinebuf(stdout);
setlinebuf(stderr);
#endif
return(0);
case 'm': /* print memory map is not supported any more */
return(0);
case 'f': /* named makefile: handled by setflags() */
return(0);
case 'u': /* unconditional build indicator */
TURNON(UCBLD);
setmflgs(c);
return(0);
case 'w': /* Set off warning msgs */
TURNON(WARN);
setmflgs(c);
return(0);
case 'P': /* Set on parallel */
TURNON(PAR);
setmflgs(c);
return(0);
case 'B': /* Set on target's output blocking */
TURNON(BLOCK);
setmflgs(c);
return(0);
case 'M': /* deny explicit null suffix dependencies */
TURNOFF(NULLSFX);
setmflgs(c);
return(0);
case 'N': /* permit explicit null suffix dependencies */
TURNON(NULLSFX);
setmflgs(c);
return(0);
case '-':
return(1);
}
usage(c);
/* NOTREACHED */
}
static void
usage(c)
char c;
{
pfmt(stderr, MM_ACTION, _SGI_MMX_make_usage
":Usage: make [-f makefile] [-p] [-i] [-k] [-s] [-r] [-n] [-u]\n\t");
#ifdef MKDEBUG
fprintf(stderr, "[-d] [-D] ");
#endif
fprintf(stderr, "[-S] [-g] [-w] [-P] [-B] [-b] [-O] [-e] [-t] [-q] [-M] [-N] [names]\n");
mkexit(1);
}
/* Called from parser to reconvert MAKEFLAGS variable back to original
* format, that is, without macros and single letter dashed options.
*/
void
convtmflgs()
{
register CHARSTAR m = (varptr(Makeflags))->varval.charstar;
register CHARSTAR s, args;
void setvar();
int off = 0;
if(s = strchr(m,'=')){ /* Macros */
/* Search backwards for start of macro */
--s;
while(s > m && !isspace(*s)) --s;
*s = CNULL;
}
args = ck_malloc(29); /* Old style was 29 'Z' letters */
args[off] = CNULL;
s = m;
while(*s) {
if(*s != '-' && !isspace(*s))
args[off++] = *s;
++s;
}
args[off] = CNULL;
free(m);
(varptr(Makeflags))->noreset = NO;
setvar(Makeflags, args);
(varptr(Makeflags))->noreset = YES;
}
/* Called from parser to establish POSIX environment */
void
posix_env()
{
VARBLOCK srchvar();
void setvar();
register VARBLOCK mp,sp;
if(mp = srchvar("MAKEFLAGS_POSIX")){
strcpy((srchvar(Makeflags))->varval.charstar,mp->varval.charstar);
free(mp->varval.charstar);
mp->varval.charstar = "";
}
if(sp = srchvar("SHELL_POSIX")){
strcpy((srchvar("SHELL"))->varval.charstar,sp->varval.charstar);
free(sp->varval.charstar);
sp->varval.charstar = "";
}
(srchvar(Makeflags))->noreset = NO;
}
/*
* POSIX: Called from readenv() to prevent overwriting the MAKEFLAGS and SHELL
* variables and to prevent overwriting any macros included in the MAKEFLAGS variable.
* We only know if we are in a POSIX environment after the makefile is parsed.
* Save the "MAKEFLAGS" and "SHELL" variables and restore from the parser when
* we know we are POSIX. See posix_env().
*/
static int
chkmmacs(mac)
register char *mac;
{
register CHARSTAR m = (varptr(Makeflags))->varval.charstar;
register CHARSTAR s = (varptr("SHELL"))->varval.charstar;
register CHARSTAR a,l,mp,sp;
register int mlen;
void setvar();
/* Insure new invocations do not inherit these flags */
if(strncmp(mac,"MAKEFLAGS_POSIX=",16)==0 || strncmp(mac,"SHELL_POSIX=",12)==0)
return(0);
if(strncmp(mac,"MAKEFLAGS=",10)==0) {
mp = ck_malloc(outmax);
strcpy(mp,m);
setvar("MAKEFLAGS_POSIX",mp); /* Save and allow to be overwritten */
return(1);
}
if(strncmp(mac,"SHELL=",6)==0 ) {
sp = ck_malloc(strlen(s)+1);
strcpy(sp,s);
setvar("SHELL_POSIX",sp); /* Save and allow to be overwritten */
return(0);
}
a = m;
mlen = (strchr(mac,'=') - mac);
while(a = strchr(a,'=')) {
l = a;
while(!isspace(*a) && a > m)--a; /* Beginning of macro */
if(isspace(*a)) ++a;
if(strncmp(a,mac,mlen)==0)
return(0);
a = l+1;
}
return(1);
}
static void
setmmacs(mac) /* POSIX: Add macro to $(MAKEFLAGS) */
register char *mac;
{
register CHARSTAR p = (varptr(Makeflags))->varval.charstar;
register CHARSTAR s;
register int mlen = 0;
s = mac;
while(*s) {
if(!isspace(*s))
++mlen;
++s;
}
if((mlen + strlen(p) + 2) > outmax) {
fatal(":169:MAKEFLAGS buffer overrun");
}
s = p + strlen(p);
if(s != p)
*s++ = ' ';
while(*mac){
if(!isspace(*mac)) /* Trim out spaces */
*s++ = *mac;
++mac;
}
*s = CNULL;
}
static int
chkmflgs(c) /* Check $(MAKEFLAGS) for option */
register char c;
{
register CHARSTAR p = (varptr(Makeflags))->varval.charstar;
register CHARSTAR mac,o;
if(mac = strchr(p,'='))
while(!isspace(*mac) && mac > p)--mac;
if((!mac && *p) || (mac && mac > p)) { /* We have options */
if(*p == '-') {
for(o=p;o = strchr(o,'-');)
if(c == *++o)
return(1); /* Duplicate */
return(0);
} else {
for (; *p && !isspace(*p); p++)
if (*p == c)
return(1); /* Duplicate */
return(0);
}
}
return(0);
}
/* Add the option to $(MAKEFLAGS) */
static void
setmflgs(c) /* set up the cmd line input flags for EXPORT. */
register char c;
{
register CHARSTAR p = (varptr(Makeflags))->varval.charstar;
register int mlen = strlen(p);
register CHARSTAR mac, sv, o;
if((mlen+(mf_dashed?3:1)) > outmax) { /* Overrun */
fatal(":169:MAKEFLAGS buffer overrun");
}
/* If macros exist, save and append them after option insertion */
if(mac = strchr(p,'=')) {
while(!isspace(*mac) && mac > p)--mac;
if(isspace(*mac)) {
*mac = CNULL;
++mac;
sv = ck_malloc(strlen(mac)+1);
strcpy(sv,mac);
}
else {
sv = ck_malloc(strlen(mac)+1);
strcpy(sv,mac);
*p = CNULL;
}
}
if(*p) { /* Existing options */
char opt[4];
if(*p == '-') {
for(o=p;o = strchr(o,'-');)
if(c == *++o)
return; /* Duplicate */
sprintf(opt," -%c",c); /* Append */
strcat(p,opt);
} else {
for (; *p && !isspace(*p); p++)
if (*p == c)
return; /* Duplicate */
sprintf(opt,"%c",c); /* Append */
strcat(p,opt);
}
} else { /* No options */
if(mf_dashed) {
*p++ = '-';
*p++ = c;
*p = CNULL;
} else {
*p++ = c;
*p = CNULL;
}
}
if(mac) {
strcat(p," ");
strcat(p,sv);
free(sv);
}
}
/*
* If a string like "CC=" occurs then CC is not put in environment.
* This is because there is no good way to remove a variable
* from the environment within the shell.
* Note: POSIX wants these empty variables, so in setenv(), don't
* export them if in non-POSIX environment.
*/
static void
readenv()
{
register CHARSTAR *ea, p;
ea = environ;
for (; *ea; ea++) {
for (p = *ea; *p && *p != EQUALS; p++)
;
/* if ((*p == EQUALS) && *(p + 1)) */
if (*p == EQUALS) { /* POSIX */
if(chkmmacs(*ea)) /* POSIX Don't overwrite certain var or macros */
(void)eqsign(*ea);
}
}
}
static int
eqsign(a)
register CHARSTAR a;
{
register CHARSTAR p;
/* allow most anything in a macro name - this begins to help
* porting from VMS etc where file names have strange chars
*/
for (p = "="; *p; p++)
if (ANY(a, *p)) {
callyacc(a);
return(YES);
}
return(NO);
}
static void
callyacc(str)
register CHARSTAR str;
{
CHARSTAR lines[2];
FILE *finsave = fin;
CHARSTAR *lpsave = linesptr;
char fnsave[PATH_MAX];
strcpy(fnsave, yyfilename);
fin = 0;
lines[0] = str;
lines[1] = 0;
linesptr = lines;
(void)yyparse();
fin = finsave;
linesptr = lpsave;
strcpy(yyfilename, fnsave);
}
NAMEBLOCK
lookup_name(namep)
CHARSTAR namep;
{
NAMEBLOCK p;
for (p = firstname; p; p = p->nextname) {
if (STREQ(namep, p->namep))
return (p);
}
return ( NULL );
}
char *
m_getcwd()
{
char *getcwd();
char *p;
/*
* SGI - this is ONLY used for printing error messages in
* parallel mode - but some customers like to run make in
* an area they can't do a pwd in :-) so we make this optional
*/
if(getcwd(temp_path, MAXPATHLEN) == NULL)
strcpy(temp_path, ".");
p = ck_malloc(strlen(temp_path) + 1);
strcpy(p, temp_path);
return(p);
}
#include "sys/stat.h"
CHARSTAR findfl(CHARSTAR, CHARSTAR);
CHARSTAR execat(CHARSTAR, CHARSTAR, CHARSTAR);
static char *sstr(char *);
/*
* donmake - handle #! on 1st line of makefile
*/
void
donmake(line)
char *line;
{
int len;
char *from = line;
char buf[128];
char *ncmd, *nCmd;
char **nargs;
char **nnargs, **pnnargs;
int i, ncargs;
int havefflag = 0;
int fflgloc;
struct stat sc, sn;
/* grab additional options on #! line */
nargs = malloc(sizeof(char *));
nargs[0] = NULL;
ncargs = 0;
for(; len=getword(from,buf); from += len) {
if (buf[0] == TAB || buf[0] == BLANK)
continue;
/*
* If a makefile is suitable to be run as a shell
* script it may have a line like:
* #!/bin/make -kf
* where exec will add the name of the makefile AFTER
* the f... this is incompatible from the way we do
* things.
* Also, it would be nice if it were possible that
* in makes #! line one could specify an alternate
* makefile:
* #!smake -f smakefile
*
* So: if we find a lone f option - we squash it
* if we find an f option with an argument - we squash
* any command line f options
*/
if (buf[0] == '-' && ANY(&buf[1], 'f')) {
havefflag = 1;
fflgloc = ncargs;
} else if (havefflag == 1) {
/* have a -f flag and now an argument - set
* flag so that we squash any original -f arg
*/
havefflag = 2;
}
nargs = realloc(nargs, (ncargs+1)*sizeof(char *));
nargs[ncargs++] = sstr(buf);
}
/* if we had a lone -f option then havefflag will be 1 -
* we need to go back and erase it
*/
if (havefflag == 1) {
char *floc;
if (nargs[fflgloc][1] == 'f') {
/* lone flag */
nargs[fflgloc] = NULL;
} else {
floc = strchr(nargs[fflgloc], 'f');
*floc = '\0';
}
}
/* now have all args */
if (nargs[0] == NULL ||
((ncmd = findfl(nargs[0], "PATH")) == (CHARSTAR) -1) ||
(stat(ncmd, &sn) != 0)) {
/* if fail - just proceed */
free(nargs);
if(IS_ON(DBUG) || IS_ON(DBUG2))
pfmt(stdout, MM_NOSTD, _SGI_MMX_make_noaltmake
":Cannot find alternate make:%s\n", nargs[0]);
return;
}
ncmd = sstr(ncmd); /* findfl overwrites */
nCmd = Cmd;
if (*Cmd == '/' || (nCmd = findfl(Cmd, "PATH")) != (CHARSTAR) -1) {
/* do a stab at making sure we don't exec ourselves */
if (stat(nCmd, &sc) == 0 && stat(ncmd, &sn) == 0) {
if (sc.st_dev == sn.st_dev &&
sc.st_ino == sn.st_ino) {
if(IS_ON(DBUG))
pfmt(stdout, MM_NOSTD, _SGI_MMX_make_ignaltmake
":Ignoring alternate make; its me!:%s\n",
ncmd);
return;
}
}
}
/* now insert all #! args before command line args */
nnargs = malloc((ncargs+sargc+1) * sizeof (char*));
pnnargs = nnargs;
for (i = 0; i < ncargs; i++)
if (nargs[i])
*pnnargs++ = nargs[i];
for (i = 0; i < sargc; i++) {
if (havefflag == 2 && sargv[i][0] == '-' &&
ANY(&sargv[i][1], 'f')) {
/* remove -f and next arg
* note that 'f' MUST be last
*/
if (sargv[i][1] == 'f')
/* skip sargv[i] & sargv[i+1] */
i++;
else {
char *floc;
/* remove f and sargv[i+1] */
*pnnargs = sstr(sargv[i]);
floc = strchr(*pnnargs, 'f');
*floc = '\0';
pnnargs++;
i++;
}
continue;
}
*pnnargs++ = sargv[i];
}
*pnnargs = NULL;
if (IS_ON(DBUG) || IS_ON(DBUG2)) {
pfmt(stdout, MM_NOSTD, _SGI_MMX_make_swaltmake
":Switching to alternate make:%s\nargs:", ncmd);
for (pnnargs = nnargs; *pnnargs; pnnargs++)
printf("%s ", *pnnargs);
printf("\n");
}
execv(ncmd, nnargs);
/* if fail - just proceed */
free(nnargs);
free(nargs);
}
static char *
sstr(s)
char *s;
{
char *r;
r = ck_malloc(strlen(s) + 1);
strcpy(r, s);
return(r);
}
/*
* findfl(name) (like execvp, but does path search and finds files)
*/
static char fname[PATH_MAX];
CHARSTAR
findfl(name, varnm)
register CHARSTAR name;
CHARSTAR varnm; /* variable containing path information */
{
register CHARSTAR p;
register VARBLOCK cp;
char tempbuf[PATH_MAX];
char *tempval = tempbuf;
size_t len;
if(name[0] == SLASH)
return(name);
cp = varptr(varnm);
if(*cp->varval.charstar == 0)
p = ":";
else
p = cp->varval.charstar;
/* Since subst() doesn't take into account the length of the
* variable, if input path is greater than PATH_MAX then
* fail-over to dynamic allocation.
*/
if ((len = strlen(p)) >= PATH_MAX) {
tempval = ck_malloc(len + 1);
}
subst(p, tempval, 0);
p = tempval;
do
{
p = execat(p, name, fname);
if(access(fname, 4) == 0) {
if (tempval != tempbuf)
free(tempval);
return(fname);
}
} while (p);
if (tempval != tempbuf)
free(tempval);
return((CHARSTAR )-1);
}
CHARSTAR
execat(s1, s2, si)
register CHARSTAR s1, s2;
CHARSTAR si;
{
register CHARSTAR s;
s = si;
while (*s1 && *s1 != KOLON)
*s++ = *s1++;
if (si != s)
*s++ = SLASH;
while (*s2)
*s++ = *s2++;
*s = CNULL;
return(*s1? ++s1: 0);
}