504 lines
7 KiB
C
504 lines
7 KiB
C
#include "defs.h"
|
||
|
||
static int hasslash(char *);
|
||
static int haspercent(char *);
|
||
static void rehash(void);
|
||
|
||
/* simple linear hash. hash function is sum of
|
||
characters mod hash table size.
|
||
*/
|
||
static int
|
||
hashloc(char *s)
|
||
{
|
||
int i;
|
||
int hashval;
|
||
char *t;
|
||
|
||
hashval = 0;
|
||
|
||
for(t=s; *t!='\0' ; ++t)
|
||
hashval += *t;
|
||
|
||
hashval %= hashsize;
|
||
|
||
for(i=hashval;
|
||
hashtab[i]!=0 && !equal(s,hashtab[i]->namep);
|
||
i = i >= hashsize-1 ? 0 : i+1) ;
|
||
|
||
return i;
|
||
}
|
||
|
||
|
||
nameblkp
|
||
srchname(char *s)
|
||
{
|
||
return hashtab[hashloc(s)] ;
|
||
}
|
||
|
||
|
||
|
||
nameblkp
|
||
makename(char *s)
|
||
{
|
||
nameblkp p;
|
||
|
||
if(nhashed > hashthresh)
|
||
rehash();
|
||
|
||
++nhashed;
|
||
hashtab[hashloc(s)] = p = ALLOC(nameblock);
|
||
p->nxtnameblock = firstname;
|
||
p->namep = copys(s); /* make a fresh copy of the string s */
|
||
/* p->linep = 0; p->done = 0; p->septype = 0; p->modtime = 0; */
|
||
|
||
firstname = p;
|
||
if(mainname==NULL && !haspercent(s) && (*s!='.' || hasslash(s)) )
|
||
mainname = p;
|
||
|
||
return p;
|
||
}
|
||
|
||
|
||
static int
|
||
hasslash(char *s)
|
||
{
|
||
for( ; *s ; ++s)
|
||
if(*s == '/')
|
||
return YES;
|
||
return NO;
|
||
}
|
||
|
||
static int
|
||
haspercent(char *s)
|
||
{
|
||
for( ; *s ; ++s)
|
||
if(*s == '%')
|
||
return YES;
|
||
return NO;
|
||
}
|
||
|
||
int
|
||
hasparen(char *s)
|
||
{
|
||
for( ; *s ; ++s)
|
||
if(*s == '(')
|
||
return YES;
|
||
return NO;
|
||
}
|
||
|
||
static void
|
||
rehash(void)
|
||
{
|
||
nameblkp *ohash;
|
||
nameblkp p, *hp, *endohash;
|
||
hp = ohash = hashtab;
|
||
endohash = hashtab + hashsize;
|
||
|
||
newhash(2*hashsize);
|
||
|
||
while( hp<endohash )
|
||
if(p = *hp++)
|
||
hashtab[hashloc(p->namep)] = p;
|
||
|
||
free( (char *) ohash);
|
||
}
|
||
|
||
|
||
void
|
||
newhash(int newsize)
|
||
{
|
||
hashsize = newsize;
|
||
hashtab = (nameblkp *) ckalloc(hashsize * sizeof(nameblkp));
|
||
hashthresh = (2*hashsize)/3;
|
||
}
|
||
|
||
|
||
|
||
nameblkp chkname(char *s)
|
||
{
|
||
nameblkp p;
|
||
time_t k;
|
||
/*TEMP NEW */
|
||
if(hasparen(s))
|
||
{
|
||
k = lookarch(s);
|
||
/*TEMP fprintf(stderr, "chkname(%s): look=%d\n", s, k); */
|
||
if(k == 0)
|
||
return NULL;
|
||
}
|
||
if(p = srchname(s))
|
||
return p;
|
||
dirsrch(s);
|
||
return srchname(s);
|
||
}
|
||
|
||
|
||
|
||
char *
|
||
copys(char *s)
|
||
{
|
||
char *t;
|
||
|
||
if( (t = malloc( strlen(s)+1 ) ) == NULL)
|
||
fatal("out of memory");
|
||
strcpy(t, s);
|
||
return t;
|
||
}
|
||
|
||
|
||
|
||
char *
|
||
concat(char *a, char *b, char *c) /* c = concatenation of a and b */
|
||
{
|
||
char *t;
|
||
t = c;
|
||
|
||
while(*t = *a++) t++;
|
||
while(*t++ = *b++);
|
||
return c;
|
||
}
|
||
|
||
|
||
int
|
||
suffix(char *a, char *b, char *p) /* is b the suffix of a? if so, set p = prefix */
|
||
{
|
||
char *a0,*b0;
|
||
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 = '\0';
|
||
|
||
return 1;
|
||
}
|
||
|
||
int *
|
||
ckalloc(int n)
|
||
{
|
||
int *p;
|
||
|
||
if( p = (int *) calloc(1,n) )
|
||
return p;
|
||
|
||
fatal("out of memory");
|
||
return 0;/* NOTREACHED */
|
||
}
|
||
|
||
/* copy string a into b, substituting for arguments */
|
||
char *
|
||
subst(char *a, char *b)
|
||
{
|
||
static depth = 0;
|
||
char *s;
|
||
char vname[100];
|
||
struct varblock *vbp;
|
||
char closer;
|
||
|
||
if(++depth > 100)
|
||
fatal("infinitely recursive macro?");
|
||
if(a) while(*a)
|
||
{
|
||
if(*a!='$' || a[1]=='\0' || *++a=='$')
|
||
/* if a non-macro character copy it. if $$ or $\0, copy $ */
|
||
*b++ = *a++;
|
||
else {
|
||
s = vname;
|
||
if( *a=='(' || *a=='{' )
|
||
{
|
||
closer = ( *a=='(' ? ')' : '}');
|
||
++a;
|
||
while(*a == ' ') ++a;
|
||
while(*a!=' ' && *a!=closer && *a!='\0') *s++ = *a++;
|
||
while(*a!=closer && *a!='\0') ++a;
|
||
if(*a == closer) ++a;
|
||
}
|
||
else *s++ = *a++;
|
||
|
||
*s = '\0';
|
||
if( (vbp = varptr(vname)) ->varval != 0)
|
||
{
|
||
b = subst(vbp->varval, b);
|
||
vbp->used = YES;
|
||
}
|
||
}
|
||
}
|
||
|
||
*b = '\0';
|
||
--depth;
|
||
return b;
|
||
}
|
||
|
||
void
|
||
setvar(char *v, char *s, int dyn)
|
||
{
|
||
struct varblock *p;
|
||
|
||
p = varptr(v);
|
||
if( ! p->noreset )
|
||
{
|
||
p->varval = s;
|
||
p->noreset = inarglist;
|
||
if(p->used && !dyn)
|
||
fprintf(stderr, "Warning: %s changed after being used\n",v);
|
||
if(p->export)
|
||
{
|
||
/* change string pointed to by environment to new v=s */
|
||
char *t;
|
||
int lenv;
|
||
lenv = strlen(v);
|
||
*(p->export) = t = (char *) ckalloc(lenv + strlen(s) + 2);
|
||
strcpy(t,v);
|
||
t[lenv] = '=';
|
||
strcpy(t+lenv+1, s);
|
||
}
|
||
else
|
||
p->export = envpp;
|
||
}
|
||
}
|
||
|
||
|
||
/* for setting Bradford's *D and *F family of macros whens setting * etc */
|
||
void
|
||
set3var(char *macro, char *value)
|
||
{
|
||
char *s;
|
||
char macjunk[8], *lastslash, *dirpart, *filepart;
|
||
|
||
setvar(macro, value, YES);
|
||
if(value == CHNULL)
|
||
dirpart = filepart = CHNULL;
|
||
else
|
||
{
|
||
lastslash = CHNULL;
|
||
for(s = value; *s; ++s)
|
||
if(*s == '/')
|
||
lastslash = s;
|
||
if(lastslash)
|
||
{
|
||
dirpart = copys(value);
|
||
filepart = dirpart + (lastslash-value);
|
||
filepart[-1] = '\0';
|
||
}
|
||
else
|
||
{
|
||
dirpart = "";
|
||
filepart = value;
|
||
}
|
||
}
|
||
setvar(concat(macro, "D", macjunk), dirpart, YES);
|
||
setvar(concat(macro, "F", macjunk), filepart, YES);
|
||
}
|
||
|
||
|
||
int
|
||
eqsign(char *a) /*look for arguments with equal signs but not colons */
|
||
{
|
||
char *s, *t;
|
||
char c;
|
||
|
||
while(*a == ' ') ++a;
|
||
for(s=a ; *s!='\0' && *s!=':' ; ++s)
|
||
if(*s == '=')
|
||
{
|
||
for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ; ++t );
|
||
c = *t;
|
||
*t = '\0';
|
||
|
||
for(++s; *s==' ' || *s=='\t' ; ++s);
|
||
setvar(a, copys(s), NO);
|
||
*t = c;
|
||
return YES;
|
||
}
|
||
|
||
return NO;
|
||
}
|
||
|
||
struct varblock *
|
||
varptr(char *v)
|
||
{
|
||
struct varblock *vp;
|
||
|
||
/* for compatibility, $(TGS) = $^ */
|
||
if(equal(v, "TGS") )
|
||
v = "^";
|
||
for(vp = firstvar; vp ; vp = vp->nxtvarblock)
|
||
if(equal(v , vp->varname))
|
||
return vp;
|
||
|
||
vp = ALLOC(varblock);
|
||
vp->nxtvarblock = firstvar;
|
||
firstvar = vp;
|
||
vp->varname = copys(v);
|
||
vp->varval = 0;
|
||
return vp;
|
||
}
|
||
|
||
int
|
||
dynmacro(char *line)
|
||
{
|
||
char *s;
|
||
char endc, *endp;
|
||
if(!isalpha(line[0]))
|
||
return NO;
|
||
for(s=line+1 ; *s && (isalpha(*s) | isdigit(*s)) ; ++s)
|
||
;
|
||
endp = s;
|
||
while( isspace(*s) )
|
||
++s;
|
||
if(s[0]!=':' || s[1]!='=')
|
||
return NO;
|
||
|
||
endc = *endp;
|
||
*endp = '\0';
|
||
setvar(line, copys(s+2), YES);
|
||
*endp = endc;
|
||
|
||
return YES;
|
||
}
|
||
|
||
|
||
void
|
||
fatal1(char *s, char *t)
|
||
{
|
||
char buf[100];
|
||
sprintf(buf, s, t);
|
||
fatal(buf);
|
||
}
|
||
|
||
|
||
void
|
||
fatal(char *s)
|
||
{
|
||
fflush(stdout);
|
||
if(s)
|
||
fprintf(stderr, "Make: %s. Stop.\n", s);
|
||
else
|
||
fprintf(stderr, "\nStop.\n");
|
||
|
||
waitstack(0);
|
||
exit(1);
|
||
}
|
||
|
||
|
||
|
||
/* appends to the chain for $? and $^ */
|
||
chainp
|
||
appendq(chainp head, char *tail)
|
||
{
|
||
chainp p, q;
|
||
|
||
p = ALLOC(chain);
|
||
p->datap = tail;
|
||
|
||
if(head)
|
||
{
|
||
for(q = head ; q->nextp ; q = q->nextp)
|
||
;
|
||
q->nextp = p;
|
||
return head;
|
||
}
|
||
else
|
||
return p;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/* builds the value for $? and $^ */
|
||
char *
|
||
mkqlist(chainp p, char *qbuf)
|
||
{
|
||
char *qbufp, *s;
|
||
|
||
if(p == NULL)
|
||
return "";
|
||
|
||
qbufp = qbuf;
|
||
|
||
for( ; p ; p = p->nextp)
|
||
{
|
||
s = p->datap;
|
||
if(qbufp+strlen(s) > &qbuf[QBUFMAX-3])
|
||
{
|
||
fprintf(stderr, "$? list too long\n");
|
||
break;
|
||
}
|
||
while (*s)
|
||
*qbufp++ = *s++;
|
||
*qbufp++ = ' ';
|
||
}
|
||
*--qbufp = '\0';
|
||
return qbuf;
|
||
}
|
||
|
||
wildp
|
||
iswild(char *name)
|
||
{
|
||
char *s;
|
||
wildp p;
|
||
|
||
for(s=name; *s; ++s)
|
||
if(*s == '%')
|
||
{
|
||
p = ALLOC(wild);
|
||
*s = '\0';
|
||
p->left = copys(name);
|
||
*s = '%';
|
||
p->right = copys(s+1);
|
||
p->llen = strlen(p->left);
|
||
p->rlen = strlen(p->right);
|
||
p->totlen = p->llen + p->rlen;
|
||
return p;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
char *
|
||
wildmatch(wildp p, char *name, int len)
|
||
{
|
||
char *stem;
|
||
char *s;
|
||
char c;
|
||
|
||
if(len < p->totlen ||
|
||
strncmp(name, p->left, p->llen) ||
|
||
strncmp(s = name+len-p->rlen, p->right, p->rlen) )
|
||
return CHNULL;
|
||
|
||
/*TEMP fprintf(stderr, "wildmatch(%s)=%s%%%s)\n", name,p->left,p->right); */
|
||
c = *s;
|
||
*s = '\0';
|
||
stem = copys(name + p->llen);
|
||
*s = c;
|
||
return stem;
|
||
}
|
||
|
||
|
||
|
||
/* substitute stem for any % marks */
|
||
char *
|
||
wildsub(char *pat, char *stem)
|
||
{
|
||
static char temp[100];
|
||
char *s, *t;
|
||
|
||
s = temp;
|
||
for(; *pat; ++pat)
|
||
if(*pat == '%')
|
||
for(t = stem ; *t; )
|
||
*s++ = *t++;
|
||
else
|
||
*s++ = *pat;
|
||
*s = '\0';
|
||
return temp;
|
||
}
|