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

1780 lines
34 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:misc.c 1.36.1.2"
#include "defs"
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h> /* struct stat */
#include <stdarg.h>
#include <pfmt.h>
#include <locale.h>
#define HASHSIZE 1609
/* The gothead and gotf structures are used to remember
* the names of the files `make' automatically gets so
* `make' can remove them upon exit. See get() and rmgots().
*/
typedef struct gotf { /* a node in a list of files */
struct gotf *gnextp;
CHARSTAR gnamep;
} *GOTF;
typedef struct gothead { /* head node of list of files */
struct gotf *gnextp;
CHARSTAR gnamep;
GOTF endp;
} *GOTHEAD;
extern int errno;
extern char touch_t[], /* from doname.c */
archmem[]; /* files.c */
extern VARBLOCK firstvar; /* from main.c */
extern int yyparse(); /* gram.y */
extern time_t maxtime; /* maximum time sen */
typedef struct hashentry {
NAMEBLOCK contents;
struct hashentry *next;
} *HASHENTRY;
HASHENTRY hashtab[HASHSIZE];
/*
** Declare local functions and make LINT happy.
*/
static CHARSTAR colontrans();
static CHARSTAR do_colon();
int getword();
static CHARSTAR dftrans();
static CHARSTAR do_df();
static CHARSTAR straightrans();
static void rm_gots();
static time_t lookarch();
static int sstat();
static void insert_ar();
int prereq(), is_on(), is_off();
NAMEBLOCK
hashfind(s) /* given string, return its NAMEBLOCK or NULL */
register CHARSTAR s;
{
register int hashval = 0;
register CHARSTAR t;
HASHENTRY p;
for (t = s; *t != CNULL; ++t)
hashval += (unsigned char) *t;
hashval %= HASHSIZE;
for (p = hashtab[hashval]; p; p = p->next) {
if (STREQ(s, p->contents->namep)) {
return(p->contents);
}
}
return(NULL);
}
NAMEBLOCK
hashput(b) /* given NAMEBLOCK, put into hash table */
NAMEBLOCK b;
{
register int hashval = 0;
register CHARSTAR t;
HASHENTRY p;
for (t = b->namep; *t != CNULL; ++t)
hashval += (unsigned char) *t;
hashval %= HASHSIZE;
for (p = hashtab[hashval]; p; p = p->next)
if (STREQ(b->namep, p->contents->namep)) {
return(p->contents);
}
p = ALLOC (hashentry);
p->next = hashtab[hashval];
p->contents = b;
hashtab[hashval] = p;
return(p->contents);
}
NAMEBLOCK
makename(s) /* make a name entry; `s' is assumed previously saved */
register CHARSTAR s;
{
register NAMEBLOCK p;
NAMEBLOCK hashput();
p = ALLOC(nameblock);
p->nextname = firstname;
p->backname = NULL;
p->namep = s;
p->linep = NULL;
p->done = D_INIT;
p->septype = 0;
p->rundep = 0;
p->modtime = 0L;
p->shenvp = NULL;
p->tbfp = NULL;
(void) hashput( p );
firstname = p;
return( p );
}
#define SHASHSIZE 73
FSTATIC struct string {
struct string *str_p;
char *str_s;
} *strtab[SHASHSIZE];
CHARSTAR
copys(s)
register char *s;
{
register char *t;
register int len, hashval = 0;
register struct string *p;
for (len = 0, t = s; *t != CNULL; len++, t++)
hashval += (unsigned char) *t;
len++;
hashval %= SHASHSIZE;
for (p = strtab[hashval]; p; p = p->str_p)
if (STREQ(s, p->str_s))
return(p->str_s);
if ( !(p = ALLOC(string)) )
fat: fatal(":130:cannot alloc memory");
if ( !(p->str_s = (CHARSTAR) calloc((unsigned) len, sizeof(*p->str_s))) )
goto fat;
p->str_p = strtab[hashval];
strtab[hashval] = p;
t = p->str_s;
while (*t++ = *s++)
;
return(p->str_s);
}
CHARSTAR
concat(a, b, c) /* c = concatenation of a and b */
register CHARSTAR a, b;
CHARSTAR c;
{
register CHARSTAR t = c;
while (*t = *a++)
t++;
while (*t++ = *b++)
;
return(c);
}
int
suffix(a, b, p) /* if b is the suffix of a, set p = prefix */
register CHARSTAR a, b, p;
{
if (! (a && b) )
return(0);
else {
CHARSTAR a0 = a,
b0 = b;
while (*a++) ;
while (*b++) ;
if ( (a - a0) < (b - b0) )
return(0);
while (b > b0)
if (*--a != *--b)
return(0);
while (a0 < a)
*p++ = *a0++;
*p = CNULL;
return(1);
}
}
int *
intalloc(n)
int n;
{
int *p;
if ( p = (int *) calloc(1, (unsigned) n) )
return(p);
fatal(":131:out of memory");
/*NOTREACHED*/
}
CHARSTAR
subst(a, b, subflg) /* copy string a into b, substituting for arguments */
/* If subflg set, doing a variable within a variable */
register CHARSTAR a, b;
{
register CHARSTAR s;
static depth = 0;
char *vname;
int amatch();
char *avname = NULL;
char svname[64];
char closer[100];
int vlen = 0, mlen = 64;
char *sva = a;
vname = svname;
if (++depth > 100)
fatal1(_SGI_MMX_make_recurse ":infinitely recursive macro? - %s", a);
if (a) {
while (*a) {
if (*a != DOLLAR)
*b++ = *a++;
else if (*++a == CNULL || *a == DOLLAR)
*b++ = *a++;
else {
s = vname;
vlen = 0;
if ( *a == LPAREN || *a == LCURLY ) {
closer[0] = (*a == LPAREN ? RPAREN : RCURLY);
++a;
while (*a == BLANK)
++a;
while ((*a != BLANK) &&
(*a != closer[0]) &&
(*a != CNULL)) {
/* >= so we always have room for NULL */
if (++vlen >= mlen) {
mlen *= 2;
vname = realloc(avname, mlen);
if (vname == NULL)
fatal(":133:cannot alloc mem");
if (avname == NULL)
strncpy(vname, svname, vlen - 1);
avname = vname;
s = vname + vlen - 1;
}
if(*a == DOLLAR) {
int cnt;
int closer_cnt = 1;
char *dol,*subclose;
char *n = a+1;
s = subst(a,s,1);
while( closer_cnt != -1 && *n != CNULL){
switch(*n){
case LPAREN:
closer[closer_cnt] = RPAREN;
break;
case LCURLY:
closer[closer_cnt] = RCURLY;
break;
case RPAREN:
case RCURLY:
if(closer[closer_cnt] == *n)
--closer_cnt;
break;
case DOLLAR:
++closer_cnt;
break;
}
++n;
}
if(closer_cnt != -1 && *n == CNULL){
fatal1(":170:Unmatched closing curly braces or parenthesis in line containing:\n\t%s",sva);
}
a += (n-a-1);
}
else *s++ = *a++;
}
while (*a != closer[0] && *a != CNULL)
++a;
if (*a == closer[0])
++a;
} else {
/* >= so we always have room for NULL */
if (++vlen >= mlen) {
mlen *= 2;
vname = realloc(avname, mlen);
if (vname == NULL)
fatal(":133:cannot alloc mem");
if (avname == NULL)
strncpy(vname, svname, vlen - 1);
avname = vname;
s = vname + vlen - 1;
}
*s++ = *a++;
}
*s = CNULL;
if (amatch(&vname[0], "*:*=*"))
b = colontrans(b, vname);
else if (ANY("@*<%?", vname[0]) && vname[1])
b = dftrans(b, vname);
else
b = straightrans(b, vname);
/* XXXjwag eh? what good does this do??
s++;
*/
}
if(subflg)
goto done;
}
}
done:
*b = CNULL;
--depth;
if (avname)
free(avname);
return(b);
}
static CHARSTAR
colontrans(b, vname) /* Translate the $(name:*=*) type things. */
register CHARSTAR b;
char vname[];
{
char evalbuf[30000];
char *ev = evalbuf;
char *aev = NULL;
register CHARSTAR p, q = 0;
char dftype = 0;
CHARSTAR pcolon;
VARBLOCK vbp, srchvar();
/* Mark off the name (up to colon),
* the from expression (up to '='),
* and the to expresion (up to CNULL). */
for (p = &vname[0]; *p && *p != KOLON; p++)
;
pcolon = p;
*pcolon = CNULL;
if (ANY("@*<%?", vname[0])) {
dftype = vname[1];
vname[1] = CNULL;
}
if ( !(vbp = srchvar(vname)) )
return(b);
p = vbp->varval.charstar;
if (dftype) {
if ( !(q = (CHARSTAR) calloc((unsigned) (strlen(p) + 2), 1)) )
fatal(":133:cannot alloc mem");
/* pass dftype so $(@D:=.d) works since vname[1] gets trounced */
(void)do_df(q, p, dftype); /*D/F trans gets smaller*/
p = q;
} else {
/* eval any macros inside := this makes things like
* CFILES= ${RULES}.c
* OBJECTS= ${CFILES:.c=.o}
* work
*/
/*
* a hack - evalbuf really needs to be as large as outmax
* but we hate to malloc each time - so as of 5/17/94
* ncargs == outmax was around 20000. SO we pre-alloc a buffer
* biggier than that. If someone has raised it, we force them
* to malloc each time.
*/
if (outmax > 30000) {
aev = ck_malloc(outmax);
ev = aev;
}
(void) subst(p, ev, 0);
p = ev;
}
if (p && *p)
b = do_colon(b, p, pcolon + 1);
*pcolon = KOLON;
if (dftype)
vname[1] = dftype;
if (q)
free(q);
if (aev)
free(aev);
return(b);
}
static char *subStringOccurs(string, subStr)
char *string, *subStr;
{
int len = strlen(subStr);
while(*string){
if(strncmp(string, subStr, len)==0)
return string;
string++;
}
return 0;
}
static CHARSTAR
do_colon(to, from, trans) /* Translate $(name:*=*) type things. */
register CHARSTAR to, from;
CHARSTAR trans;
{
register int i = 0, leftlen;
register CHARSTAR p;
CHARSTAR pbuf, trysccs(), strshift(), sdot();
char left[30], right[70], buf[PATH_MAX];
int lwig = 0, rwig = 0, len;
int sindex();
/* Mark off the name (up to colon), the from expression ( up to '=')
* and the to expression (up to CNULL)
*/
while (*trans != EQUALS)
left[i++] = *trans++;
if (i && left[i-1] == WIGGLE) {
lwig++;
--i;
}
left[i] = CNULL;
leftlen = i;
i = 0;
while (*++trans)
right[i++] = *trans;
if (right[i-1] == WIGGLE) {
rwig++;
--i;
}
right[i] = CNULL;
/* Now, translate. */
for (; len = getword(from, buf); from += len) {
pbuf = buf;
/*
* use rsindex so:
* CFILES=goo.c.c
* $(CFILES:.c=.o) works
*/
if ((i = rsindex(pbuf, left)) >= 0 &&
/* is found 'left' a suffix */
(pbuf[i+leftlen] == CNULL) &&
(lwig ? ((p = sdot(pbuf)) != NULL) : 1)) {
pbuf[i] = CNULL;
if (!lwig && rwig)
(void)trysccs(pbuf);
else if (lwig && !rwig)
(void)strshift(p, -2);
to = copstr(to, pbuf);
to = copstr(to, right);
} else if (pbuf[0] != BLANK && pbuf[0] != TAB && leftlen == 0) {
/*
* append right
* gets $(CFILES:=.d) to work
*/
to = copstr(to, pbuf);
to = copstr(to, right);
} else
to = copstr(to, pbuf);
}
#ifdef NEVER
/* XXXjwag this is ESMP code */
for (; len = getword(from, buf); from += len) {
char *occurence;
pbuf = buf;
while(occurence=subStringOccurs(pbuf,left)){
char saveC = *occurence;
*occurence = CNULL;
to = copstr(to, pbuf);
to = copstr(to, right);
*occurence = saveC;
/* Jump over the substituted string */
pbuf = occurence+leftlen;
}
/* copy the rest of trailing stuff */
to = copstr(to,pbuf);
}
#endif
return(to);
}
int
getword(from, buf)
register CHARSTAR from, buf;
{
register int i = 0;
if (*from == TAB || *from == BLANK)
while (*from == TAB || *from == BLANK) {
*buf++ = *from++;
++i;
}
else
while (*from && *from != TAB && *from != BLANK) {
*buf++ = *from++;
++i;
}
*buf = CNULL;
return(i);
}
static CHARSTAR
dftrans(b, vname) /* Do the $(@D) type translations. */
register CHARSTAR b;
CHARSTAR vname;
{
register VARBLOCK vbp;
VARBLOCK srchvar();
char c1 = vname[1];
vname[1] = CNULL;
vbp = srchvar(vname);
vname[1] = c1;
if (vbp && *vbp->varval.charstar)
b = do_df(b, vbp->varval.charstar, c1);
return(b);
}
static CHARSTAR
do_df(b, str, type)
register CHARSTAR b;
char str[], type;
{
register int i;
register CHARSTAR p;
char buf[PATH_MAX];
#define LASTSLASH(a) strrchr(a, SLASH)
*b = CNULL;
for (; i = getword(str, buf); str += i) {
if (buf[0] == BLANK || buf[0] == TAB) {
b = copstr(b, buf);
continue;
}
if (p = LASTSLASH(buf)) {
*p = CNULL;
b = copstr(b, type == 'D' ? (buf[0] == CNULL ? "/" : buf):
p + 1);
*p = SLASH;
} else {
if(IS_ON(POSIX))
b = copstr(b, type == 'D' ? "." : buf);
/* XXXjwag ESMP added '/' */
else b = copstr(b, type == 'D' ? "./" : buf);
}
}
return(b);
}
static CHARSTAR
straightrans(b, vname) /* Standard trnaslation, nothing fancy. */
register CHARSTAR b;
char vname[];
{
register CHAIN pchain;
register NAMEBLOCK pn;
register VARBLOCK vbp;
VARBLOCK srchvar();
if ( vbp = srchvar(vname) ) {
if (vbp->v_aflg && vbp->varval.chain) {
pchain = (vbp->varval.chain);
for (; pchain; pchain = pchain->nextchain) {
pn = pchain->datap.nameblock;
if (pn->alias)
b = copstr(b, pn->alias);
#ifdef OLDVPATH
else if (pn->valias)
b = copstr(b, pn->valias);
#endif
else
b = copstr(b, pn->namep);
*b++ = BLANK;
}
vbp->used = YES;
} else if (*vbp->varval.charstar)
b = subst(vbp->varval.charstar, b, 0);
vbp->used = YES;
}
return(b);
}
/* copy s into t, return the location of the next free character in s */
CHARSTAR
copstr(s, t)
register CHARSTAR s, t;
{
if ( !t )
return(s);
while (*t)
*s++ = *t++;
*s = CNULL;
return(s);
}
void
setvar(v, s)
register CHARSTAR v, s;
{
VARBLOCK srchvar();
register VARBLOCK p = srchvar(v);
if ( !p )
p = varptr(v);
else {
if (IS_ON(INARGS))
p->noreset = NO;
}
if ( !s )
s = Nullstr;
if ( !(p->noreset) ) {
if (IS_ON(EXPORT))
p->envflg = YES;
p->varval.charstar = s;
if (IS_ON(INARGS) || IS_ON(ENVOVER))
p->noreset = YES;
else
p->noreset = NO;
#ifdef MKDEBUG
if (IS_ON(DBUG)) {
printf("setvar: %s = %s, noreset = %d envflg = %d Mflags = 0%o\n",
v, p->varval.charstar, p->noreset, p->envflg, Mflags);
}
if (p->used && !amatch(v, "[@*<?!%]") ){
if(IS_OFF(WARN))
pfmt(stderr, MM_WARNING,
":122:%s changed after being used\n",
v);
}
#endif
}
}
VARBLOCK
varptr(v)
register CHARSTAR v;
{
VARBLOCK srchvar();
register VARBLOCK vp = srchvar(v);
if ( vp )
return(vp);
vp = ALLOC(varblock);
vp->nextvar = firstvar;
firstvar = vp;
vp->varname = copys(v);
/* assign Nullstr rather than NULL so don't access 0 */
vp->varval.charstar = Nullstr;
return(vp);
}
VARBLOCK
srchvar(vname)
register CHARSTAR vname;
{
register VARBLOCK vp = firstvar;
for (; vp; vp = vp->nextvar)
if (STREQ(vname, vp->varname))
return(vp);
return( NULL );
}
void
fatal1(CHARSTAR s, ...)
{
va_list ap;
fflush(stdout);
va_start(ap, s);
vpfmt(stderr, MM_ERROR, s, ap);
va_end(ap);
fprintf(stderr, ".\n");
mkexit(1);
}
void
fatal(s)
CHARSTAR s;
{
fflush(stdout);
if (s){
pfmt(stderr, MM_ERROR, s);
fprintf(stderr, ".\n");
}
mkexit(1);
}
yyerror(s) /* called when yyparse encounters an error */
CHARSTAR s;
{
extern int yylineno;
extern char yyfilename[];
pfmt(stderr, MM_ERROR, _SGI_MMX_make_yprint ":%s: file `%s' line %d: ",
"make", yyfilename, yylineno);
/* yacc has already run gettxt on the error message */
fprintf(stderr, "%s\n", s);
fatal(NULL);
/* NOTREACHED */
}
void
yprintf(FILE *f, ...)
{
va_list ap;
char *fmt;
extern int yylineno;
extern char yyfilename[];
va_start(ap, f);
pfmt(f, MM_ERROR, _SGI_MMX_make_yprint ":%s: file `%s' line %d: ",
"make", yyfilename, yylineno);
fmt = va_arg(ap, char *);
vpfmt(f, MM_NOSTD, fmt, ap);
return;
}
/*
* Search for tail already existing on queue.
* This can occur when both implicit and explicit dependencies occur and
* we are appending to $?
*/
void
appendq(head, tail)
register CHAIN head;
CHARSTAR tail;
{
register CHAIN p, q;
/* whew! appendq really gets a CHAIN*
* that really only points to a single word
*/
for (q = head->nextchain; q; head = q, q = q->nextchain)
if (q->datap.charstar && STREQ(q->datap.charstar, tail))
return;
p = ALLOC(chain);
p->datap.charstar = tail;
head->nextchain = p;
}
CHARSTAR
mkqlist(p)
register CHAIN p;
{
static char *qbuf = NULL;
register CHARSTAR s, qbufp = qbuf;
static int qblen = 0;
int curslen;
int curqblen = 0;
for ( ; p; p = p->nextchain) {
s = p->datap.charstar;
if ((curslen = strlen(s)) + curqblen > (qblen - 3)) {
char *oqbuf = qbuf;
qblen += 4096;
if ((qbuf = realloc(qbuf, qblen)) == NULL)
fatal(":131:out of memory");
qbufp = (qbufp - oqbuf) + qbuf;
}
if (qbufp != qbuf) {
*qbufp++ = BLANK;
curqblen++;
}
memcpy(qbufp, s, curslen);
qbufp += curslen;
curqblen += curslen;
#ifdef NEVER
/* ESMP code.. */
if (qbufp + strlen(s) > qp) {
pfmt(stderr, MM_ERROR, ":124:$? (bu35)\n");
break;
}
while (*s)
*qbufp++ = *s++;
#endif
}
if (qbuf == NULL) {
qblen += 4096;
if ((qbuf = realloc(qbuf, qblen)) == NULL)
fatal(":131:out of memory");
qbufp = qbuf;
}
*qbufp = CNULL;
return(qbuf);
}
/*
* Find first occurrence of string s2 within string s1.
* Returns index of such occurrence or -1 if none.
*/
int
sindex(s1, s2)
CHARSTAR s1, s2;
{
register CHARSTAR p1 = &s1[0],
p2 = &s2[0];
register int ii = 0, flag = -1;
for (; ; ii++) {
while (*p1 == *p2) {
if (flag < 0)
flag = ii;
if (*p1++ == CNULL)
return(flag);
p2++;
}
if (*p2 == CNULL)
return(flag);
if (flag >= 0) {
flag = -1;
p2 = &s2[0];
}
if (*s1++ == CNULL)
return(flag);
p1 = s1;
}
}
/*
* Find last occurrence of string s2 within string s1.
* Returns index of such occurrence or -1 if none.
*/
rsindex(s1,s2)
CHARSTAR s1;
CHARSTAR s2;
{
register CHARSTAR p1;
register CHARSTAR p2;
register int ii, len;
ii = strlen(s1) - 1; /* index of last character in s1 */
if (ii < 0)
return(-1);
p1 = &s1[ii];
p2 = &s2[0];
len = strlen(p2);
for ( ; ii >= 0 ; ii--, p1--)
if (strncmp(p1, p2, len) == 0)
return(ii);
return(-1);
}
CHARSTAR
trysccs(str) /* change xx to s.xx or /x/y/z to /x/y/s.z */
register CHARSTAR str;
{
CHARSTAR sstr = str;
register int i = 2;
for (; *str; str++)
;
str[2] = CNULL;
str--;
for (; str >= sstr; str--) {
if ((*str == SLASH) && (i == 2)) {
i = 0;
*(str + 2) = DOT;
*(str + 1) = 's';
}
*(str + i) = *str;
}
if (i == 2) {
*(str + 2) = DOT;
*(str + 1) = 's';
}
return(sstr);
}
CHARSTAR
trySCCS(str) /* change xx to SCCS/s.xx or /x/y/z to /x/y/SCCS/s.z */
register CHARSTAR str;
{
CHARSTAR sstr = str;
register int i = 7;
for (; *str; str++)
;
str[7] = CNULL;
str--;
for (; str >= sstr; str--) {
if ((*str == SLASH) && (i == 7)) {
i = 0;
strncpy(str+1,"SCCS/s.",7);
}
*(str + i) = *str;
}
if (i == 7) {
strncpy(str+1,"SCCS/s.",7);
}
return(sstr);
}
int
is_sccs(filename)
register CHARSTAR filename;
{
register CHARSTAR p = filename;
for (; *p; p++)
if ((*p == 's') &&
((p == filename && p[1] == DOT) ||
(p[-1] == SLASH && p[1] == DOT)))
return(YES);
return(NO);
}
CHARSTAR
sdot(p)
register CHARSTAR p;
{
register CHARSTAR ps = p;
for (; *p; p++)
if ((*p == 's') &&
((p == ps && p[1] == DOT) ||
(p[-1] == SLASH && p[1] == DOT)))
return(p);
return(NULL);
}
CHARSTAR
addstars(pfx) /* change pfx to /xxx/yy/\*zz.* or *zz.* */
register CHARSTAR pfx;
{
register CHARSTAR p1 = pfx, p2;
for (; *p1; p1++)
;
p2 = p1 + 3; /* 3 characters, '*', '.', and '*'. */
p1--;
*p2-- = CNULL;
*p2-- = STAR;
*p2-- = DOT;
while (p1 >= pfx) {
if (*p1 == SLASH) {
*p2 = STAR;
return(pfx);
}
*p2-- = *p1--;
}
*p2 = STAR;
return(p2);
}
/*
* NOTE: this is only called in the forked child, so memory leakage
* isn't a problem.
*/
#define NENV 5000
void
setenv() /* set up the environment */
{
register CHARSTAR *ea, p;
register int nenv;
register VARBLOCK vp;
CHARSTAR *es;
if ( !firstvar )
return;
if ( !(es = ea = (CHARSTAR *)calloc(NENV, sizeof * ea)) )
m_error: fatal(":133:cannot alloc mem");
nenv = 0;
for (vp = firstvar; vp; vp = vp->nextvar)
if (vp->envflg) {
/*
* ESMP added subst for env variables
* 1/16/95 - this seems wrong and breaks
* some makefiles - it also appears to
* violate POSIX 1003.2.
* For example if someone has the following
* set in their env:
* OPT='$(FOO)'
* Then when we invoke a command from make,
* subst() will have converted it to:
* OPT=<value_of_FOO> rather than passing the
* environment variable intact which is what
* previous versions of make/smake and POSIX
* imply one should do.
*/
if (++nenv >= NENV)
fatal(":134:too many env parameters.");
if ( !(*ea = (CHARSTAR) calloc( (unsigned) (strlen(vp->varname) +
strlen(vp->varval.charstar) + 2),
sizeof **ea)) )
goto m_error;
p = copstr(*ea++, vp->varname);
p = copstr(p, "=");
p = copstr(p, vp->varval.charstar);
}
*ea = 0;
if (nenv > 0)
environ = es;
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("nenv = %d\n", nenv);
#endif
}
/*
* Shift a string `pstr' count places. negative is left, pos is right
* Negative shifts cause char's at front to be lost.
* Positive shifts assume enough space!
*/
CHARSTAR
strshift(pstr, count)
register CHARSTAR pstr;
register int count;
{
register CHARSTAR sstr = pstr;
if (count < 0) {
for (count = -count; *pstr = pstr[count]; pstr++)
;
*pstr = 0;
return(sstr);
}
for (; *pstr; pstr++)
;
do
pstr[count] = *pstr;
while (pstr--, count--);
return(sstr);
}
/*
* get() does an SCCS get on the file ssfile.
* For the get command, get() uses the value of the variable "GET".
* If the rlse string variable is set, get() uses it in the
* get command sequence.
* Thus a possible sequence is:
* set -x;
* get -r2.3.4.5 s.stdio.h
*
*/
GOTHEAD gotfiles;
get(ssfile, rlse, tarp)
register CHARSTAR ssfile;
CHARSTAR rlse;
NAMEBLOCK tarp;
{
register CHARSTAR pr, pr1;
CHARSTAR trysccs(), sdot(), rmsdot();
char gbuf[PATH_MAX+128], sfile[PATH_MAX], dfile[PATH_MAX];
int retval, access();
GOTF gf;
(void)copstr(sfile, ssfile);
if (!sdot(sfile)) {
(void)trysccs(sfile);
if(access(sfile, 4) &&
strcmp(ssfile,"makefile") == 0 || strcmp(ssfile,"Makefile") == 0) {
(void)copstr(sfile, ssfile);
(void)trySCCS(sfile);
}
}
if (access(sfile, 4) && IS_OFF(GET))
return(NO);
pr = gbuf;
if (is_off(SIL,tarp))
pr = copstr(pr, "set -x;\n");
pr = copstr(pr, varptr("GET")->varval.charstar);
pr = copstr(pr, " ");
pr = copstr(pr, varptr("GFLAGS")->varval.charstar);
pr = copstr(pr, " ");
if ((pr1 = rlse) && pr1[0] != CNULL) {
if (pr1[0] != MINUS) /* RELEASE doesn't have '-r' */
pr = copstr(pr, "-r");
pr = copstr(pr, pr1);
pr = copstr(pr, " ");
}
pr = copstr(pr, sfile);
/*
* exit codes are opposite of error codes so do the following:
*/
if ( retval = !system(gbuf) ? YES : NO ) {
if ( !gotfiles ) {
gotfiles = ALLOC(gothead);
gf = (GOTF)gotfiles;
gotfiles->gnextp = NULL;
gotfiles->endp = (GOTF)gotfiles;
} else {
gf = gotfiles->endp;
gf->gnextp = ALLOC(gotf);
gf = gf->gnextp;
gf->gnextp = NULL;
}
/* set the name of the file to dest directory, plus the *
* file name without the source path or the "s." stuff */
(void) cat(dfile, rmsdot(sfile), 0);
gf->gnamep = copys(dfile);
gotfiles->endp = gf;
}
return(retval);
}
/* rmsdot(sccsname) returns a pointer to the portion of an sccs file
* name that is beyond the directory specifications and the
* "s." prefix of the sccs file name.
*/
CHARSTAR
rmsdot(sccsname)
CHARSTAR sccsname; /* pointer to the name string to fix */
{
register CHARSTAR p = sccsname;
for (; *p != '\0'; p++)
; /* skip to end of full pathname */
for (; *p != '/' && p >= sccsname; p--)
; /* back up to beginning of name part */
return(p + 3); /* skip the "/s." characters */
}
static void
rm_gots() /* remove gotten files. */
{
int unlink();
if (IS_ON(GF_KEEP))
return;
else {
register GOTF gf = (GOTF)gotfiles;
for ( ; gf; gf = gf->gnextp)
if (gf->gnamep) {
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("rm_got: %s\n", gf->gnamep);
#endif
(void)unlink(gf->gnamep);
}
}
}
int
isprecious(p)
CHARSTAR p;
{
register NAMEBLOCK np;
if (np = SRCHNAME(".PRECIOUS")) {
register LINEBLOCK lp = np->linep;
register DEPBLOCK dp;
for ( ; lp; lp = lp->nextline)
for (dp = lp->depp; dp; dp = dp->nextdep)
if (STREQ(p, dp->depname->namep))
return(YES);
}
return(NO);
}
int
isdir(filnam)
char *filnam;
{
struct stat statbuf;
if (stat(filnam, &statbuf) == -1)
return(2); /* can't stat, don't remove */
if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
return(1);
return(0);
}
/* for notations a(b) and a((b)), look inside archives
* a(b) is file member b in archive a
* a((b)) is entry point b in object archive a
*/
static time_t
lookarch(filename)
register CHARSTAR filename;
{
register int i;
register CHARSTAR p;
CHARSTAR q, Q, sname();
CHARSTAR sfname;
time_t ret_la, la();
char *s;
int objarch = NO;
#ifdef MKDEBUG
if (IS_ON(DBUG))
printf("lookarch(%s)\n", filename);
#endif
if (filename[0] == CNULL)
f_error: fatal1(":135:null archive name `%s'", filename);
s = (char *)malloc(strlen(filename));
for (p = filename; *p != LPAREN ; ++p)
;
Q = p++;
sfname = sname(filename);
if ((i = Q - sfname) == 0)
fatal1(":135:null archive name `%s'", sfname);
if (*p == LPAREN) {
objarch = YES;
++p;
if ( !(q = strchr(p, RPAREN)) )
q = p + strlen(p);
(void)strncpy(s, p, (size_t) (q - p) );
s[q-p] = CNULL;
} else {
if ( !(q = strchr(p, RPAREN)) )
q = p + strlen(p);
i = q - p;
(void)strncpy(archmem, p, (size_t) i);
archmem[i] = CNULL;
if (archmem[0] == CNULL)
goto f_error;
if (q = strrchr(archmem, SLASH))
++q;
else
q = archmem;
(void)strcpy(s, q);
}
*Q = CNULL;
ret_la = la(filename, s, objarch);
insert_ar(sname(filename));
*Q = LPAREN;
return( ret_la );
}
#define RETURN(x) { ret_value = (x); goto return_here; }
static int
sstat(pname, buffer)
NAMEBLOCK pname;
struct stat *buffer;
{
register char *s;
register int nonfile = NO;
char temp[PATH_MAX];
int ret_value;
CHARSTAR filename = pname->namep;
archmem[0] = CNULL;
if (ANY(filename, LPAREN)) {
nonfile = YES;
strcpy(temp,filename);
(void)compath(temp);
for (s = temp; !(*s == CNULL || *s == LPAREN); s++)
;
*s = CNULL;
pname->alias = copys(temp);
}
strcpy(temp,filename);
(void)compath(temp);
if ((nonfile && (buffer->st_mtime = lookarch(temp))) ||
(!(stat(temp, buffer) || nonfile))){
RETURN(1);
}
#ifdef OLDVPATH
{
extern CHARSTAR findfl(CHARSTAR, CHARSTAR);
CHARSTAR s = findfl(filename, "VPATH");
if (s != (CHARSTAR )-1) {
#ifdef MKDEBUG
if (IS_ON(DBUG))
fprintf(stdout, "VPATH file = %s\n", s);
#endif
pname->valias = copys(s);
if (stat(pname->valias, buffer) == 0)
RETURN(1);
}
}
#endif
RETURN(-1)
return_here:
/*
* maintain maximum time for all files ever seen
*/
if (ret_value >= 0) {
if (buffer->st_mtime > maxtime)
maxtime = buffer->st_mtime;
}
return ret_value;
}
time_t
exists(pname)
NAMEBLOCK pname;
{
struct stat buf;
if (pname == NULL)
return(-1L);
if ( sstat(pname, &buf) < 0 ) {
return(-1L);
} else {
#ifdef MKDEBUG
if (IS_ON(DBUG))
fprintf(stdout, "time = %ld\n", buf.st_mtime);
#endif
return(buf.st_mtime);
}
}
void
mkexit(arg) /* remove files make automatically got */
{
void kill_run();
void exit();
(void)signal(SIGINT, SIG_IGN); /* ignore signals */
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGTERM, SIG_IGN);
if (IS_ON(TOUCH)) /* remove `touch' temporary file */
(void)unlink(touch_t);
rm_gots();
if(IS_ON(PAR) && nproc)
kill_run();
#ifdef __BTOOL__
btool_writelog("makeblog");
#endif
if(arg==0 && IS_ON(POSIX) && IS_ON(KEEPGO) && k_error)
arg = IS_ON(QUEST)?2:1;
exit(arg < 0 ? arg + 256 : arg);
}
/* dname(), sname(), and cat() were stolen from libPW */
/*
dname() returns directory name containing a file (by
modifying its argument).
Returns "." if current directory; handles root correctly.
Returns its argument.
Bugs: doesn't handle null strings correctly.
*/
char *dname(p)
char *p;
{
register char *c;
register int s = strlen(p) + 1;
for(c = p+s-2; c > p; c--)
if(*c == '/') {
*c = '\0';
return(p);
}
if (p[0] != '/')
p[0] = '.';
p[1] = 0;
return(p);
}
/*
sname() returns pointer to "simple" name of path name; that
is, pointer to first character after last "/". If no
slashes, returns pointer to first char of arg.
If the string ends in a slash, returns a pointer to the first
character after the preceeding slash, or the first character.
*/
char *sname(s)
char *s;
{
register char *p;
register int j;
register int n = strlen(s);
--n;
if (s[n] == '/')
for (j=n; j >= 0; --j)
if (s[j] != '/') {
s[++j] = '\0';
break;
}
for(p=s; *p; p++)
if(*p == '/')
s = p + 1;
return(s);
}
/*
Concatenate strings.
cat(destination,source1,source2,...,sourcen,0);
*/
/*VARARGS*/
void
cat(CHARSTAR d, ...)
{
register char *s;
va_list ap;
va_start(ap, d);
while (s = va_arg(ap, CHARSTAR)) {
while (*d++ = *s++) ;
d--;
}
}
/*
* compath(pathname)
*
* This compresses pathnames. All strings of multiple slashes are
* changed to a single slash. All occurrences of "./" are removed.
* Whenever possible, strings of "/.." are removed together with
* the directory names that they follow.
*
* WARNING: since pathname is altered by this function, it should
* be located in a temporary buffer. This avoids the problem
* of accidently changing strings obtained from makefiles
* and stored in global structures.
*/
char *
compath(pathname)
register char *pathname;
{
register char *nextchar, *lastchar, *sofar;
char *pnend;
int pnlen;
/* return if the path has no "/" */
if ( !strchr(pathname, '/') )
return(pathname);
/* find all strings consisting of more than one '/' */
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((*lastchar == '/') && (*(lastchar - 1) == '/')) {
/* find the character after the last slash */
nextchar = lastchar;
while (*++lastchar == '/')
;
/* eliminate the extra slashes by copying
* everything after the slashes over the slashes
*/
sofar = nextchar;
while ((*nextchar++ = *lastchar++) != '\0')
;
lastchar = sofar;
}
/* find all strings of "./" */
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((*lastchar == '/') &&
(*(lastchar - 1) == '.') &&
((lastchar - 1 == pathname) ||
(*(lastchar - 2) == '/'))) {
/* copy everything after the "./" over the "./" */
nextchar = lastchar - 1;
sofar = nextchar;
while ((*nextchar++ = *++lastchar) != '\0')
;
lastchar = sofar;
}
/* find each occurrence of "/.." */
for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++)
if ((lastchar != pathname) && (*lastchar == '/') &&
(*(lastchar+1) == '.') &&
(*(lastchar+2) == '.') &&
((*(lastchar+3) == '/') || (*(lastchar+3) == '\0'))) {
/* find the directory name preceding the "/.." */
nextchar = lastchar - 1;
while ((nextchar != pathname) &&
(*(nextchar - 1) != '/'))
--nextchar;
/* make sure the preceding directory's name
* is not "." or ".."
*/
if (!((*nextchar == '.') &&
(*(nextchar + 1) == '/') ||
((*(nextchar + 1) == '.') &&
(*(nextchar + 2) == '/')))) {
/* prepare to eliminate either *
* "dir_name/../" or "dir_name/.." */
if (*(lastchar + 3) == '/')
lastchar += 4;
else
lastchar += 3;
/* copy everything after the "/.." to *
* before the preceding directory name */
sofar = nextchar - 1;
while ((*nextchar++ = *lastchar++) != '\0')
;
lastchar = sofar;
/* if (the character before what was
* taken out is '/'),
* set up to check
* if the slash is part of "/.."
*/
if ((sofar + 1 != pathname) && (*sofar == '/'))
--lastchar;
}
}
/* if the string is more than a character long and ends in '/'
* eliminate the '/'.
*/
pnend = strchr(pathname, '\0') - 1;
if (((pnlen = strlen(pathname)) > 1) && (*pnend == '/')) {
*pnend-- = '\0';
pnlen--;
}
/* if the string has more than two characters and ends in "/.",
* remove the "/.".
*/
if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.'))
*--pnend = '\0';
/*
* if all characters were deleted, return ".";
* otherwise return pathname
*/
if (*pathname == '\0')
(void)strcpy(pathname, ".");
return(pathname);
}
typedef struct ar_node {
char *name;
struct ar_node *next;
} ar_node;
ar_node *ar_set = (ar_node *)NULL; /* linked list of archive names */
static void
insert_ar(name) /* save an archive's name */
char *name;
{
if (! member_ar(name) ) {
register ar_node *temp = (ar_node *)ck_malloc(sizeof(ar_node));
temp -> name = ck_malloc((unsigned) (strlen(name) + 1));
strcpy(temp -> name, name);
strcat(temp -> name, "\0");
if (ar_set == (ar_node *)NULL)
temp -> next = (ar_node *)NULL;
else
temp -> next = ar_set;
ar_set = temp;
}
}
int
member_ar(name) /* archive name previously saved? */
register char *name;
{
register ar_node *p = ar_set;
for (; p; p = p -> next)
if (!strcmp(p -> name, name))
return(1);
return(0);
}
char *
ck_malloc(len)
int len;
{
char *p;
if((p= malloc(len)) == NULL)
fatal1(":140:couldn't malloc len=%d", len);
return(p);
}
/*
* If flag is on globally - return 1
* If target matches prerequisites for flag macro - return 1
* Else - return 0
*/
int is_on(flag,tarp)
register int flag;
NAMEBLOCK tarp;
{
CHARSTAR f;
switch(flag)
{
case IGNERR: f = ".IGNORE"; break;
default: return(0);
}
if (IS_ON(flag))
return(1);
else if (IS_ON(POSIX) && tarp && prereq(SRCHNAME(f),tarp->namep))
return(1);
else return(0);
}
/*
* If flag is on globally - return 0
* If target matches prerequisites for flag macro - return 0
* Else - return 1
*/
int is_off(flag,tarp)
register int flag;
NAMEBLOCK tarp;
{
CHARSTAR f;
switch(flag)
{
case SIL: f = ".SILENT"; break;
default: return(1);
}
if(IS_ON(flag))
return(0);
else if(IS_ON(POSIX) && tarp && prereq(SRCHNAME(f),tarp->namep))
return(0);
else return(1);
}
/*
* prereq() Search for any prerequisites of the NAMEBLOCK(p)
* If target is null, search for any.
* Else search for specified target.
*/
int
prereq(p,target)
register NAMEBLOCK p;
CHARSTAR target;
{
register DEPBLOCK dp;
register LINEBLOCK lp;
if(!p) return(0);
for (lp = p->linep; lp; lp = lp->nextline) {
if ( dp = lp->depp ) {
for (; dp; dp = dp->nextdep)
if ( dp->depname) {
if(!target || strcmp(target,dp->depname->namep)==0)
return(1);
}
}
}
return(0);
}