/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1984-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* make metarule routines
*/
#include "make.h"
/*
* return a pointer to the metarule that builds
* a file that matches the metarule pattern out from
* a file that matches the metarule pattern in
* force causes the rule to be created
*/
{
register Rule_t* r;
register char* s;
r = getrule(s);
if (force)
{
if (!r)
}
else
{
/*
* if in -> out is a secondary metrule then return primary
*/
{
if (r->prereqs)
{
}
else
r = 0;
}
r = 0;
}
return r;
}
/*
* metarule supplementary info
*
* type
*
* 'I' inputs
* 'N' nonterminal unconstrained inputs
* 'O' outputs
* 'P' primary output
* 'S' primary secondary outputs
* 'T' terminal unconstrained inputs
* 'X' unconstrained output exclusions
*/
{
register Rule_t* r;
sfprintf(internal.met, "%s.%c.%s%s%s", internal.metarule->name, type, s1 ? s1 : null, s2 ? ">" : null, s2 ? s2 : null);
{
r->property |= P_readonly;
}
return r;
}
#if _WINIX
/*
* yes, metarules are affected by the case insensitive filesystem botch
* we do case insensitive metarule pattern matching for all patterns that
* do not match `[-+]*'
*/
static int
metaccmp(register char* p, register int a, register int b)
{
return a == b || *p != '-' && *p != '+' && (isupper(a) ? tolower(a) : a) == (isupper(b) ? tolower(b) : b);
}
#else
#define metaccmp(p,a,b) ((a)==(b))
#endif
/*
* match s against metarule pattern
* leading unmatched directories before % are ignored
* returns 0 if no match
* otherwise if stem!=0 then non-dir part of matched stem is copied there
*/
int
{
register char* p;
register char* t;
register char* x;
register char* y;
char* b;
register int targetprefix;
b = s;
p = pattern;
while (*p != '%')
{
if (!*s)
return 0;
{
do
{
if (*s == '/')
{
while (*++s == '/');
break;
}
else if (*s == targetprefix)
{
x = state.targetprefix;
y = s;
while (*++x == *++y && *x);
if (!*x)
{
s = y;
break;
}
}
} while (*++s);
if (!*(b = s))
return 0;
p = pattern;
}
else if (!*p++)
{
if (p = stem)
{
s = b;
while (*p++ = *s++);
}
return 1;
}
else
s++;
}
t = s;
while (*s)
s++;
while (*p)
p++;
while (*--p != '%')
return 0;
if (stem)
{
if ((p = strrchr(t, '/')) && p < s)
t = p + 1;
if (state.targetprefix)
{
b = t;
while ((p = strchr(b, targetprefix)) && p < s)
{
x = state.targetprefix;
y = p;
while (*++x == *++y && *x);
if (!*x)
b = t = y;
else
b++;
}
}
p = stem;
while (t < s)
*p++ = *t++;
*p = 0;
}
return 1;
}
/*
* expand the metarule pattern p into sp using stem
*/
void
{
register int c;
while ((c = *p++) != '%')
{
if (!c)
return;
}
}
/*
* update the metarule closure graph
*
* NOTE: c==0 (PREREQ_APPEND alias) is used to cut off part of the closure recursion
*/
void
{
char* s;
Rule_t* x;
Rule_t* y;
Rule_t* z;
List_t* p;
List_t* q;
#if DEBUG
static int eloop = 0;
#endif
#if DEBUG
if (eloop++ > 64)
{
eloop--;
return;
}
#endif
return;
{
{
{
{
if (c == PREREQ_DELETE)
s = 0;
else
{
{
x->mark |= M_metarule;
x->mark &= ~M_metarule;
}
}
x->uname = s;
x->dynamic &= ~D_compiled;
}
}
}
if (c != PREREQ_DELETE && metamatch(stem, q->rule->name, in->name) && !streq(stem, "%") && (x = metainfo('I', q->rule->name, NiL, 0)))
{
{
{
if (!(x->mark & M_metarule))
{
x->mark |= M_metarule;
x->mark &= ~M_metarule;
}
x->dynamic &= ~D_compiled;
}
}
}
}
{
{
if (!(x->mark & M_metarule))
{
x->mark |= M_metarule;
x->mark &= ~M_metarule;
}
if (!x->uname)
{
x->dynamic &= ~D_compiled;
}
}
}
#if DEBUG
eloop--;
#endif
}
/*
* return the primary metarule source that generates r
* *meta is the matching metarule
*/
{
register List_t* p;
register List_t* q;
register List_t* v;
Rule_t* m;
Rule_t* s;
Rule_t* x;
Rule_t* y;
char* b;
char* u;
char* t;
Flags_t f;
int matched;
u = unbound(r);
prereqs = 0;
if (active)
{
do
{
{
break;
}
break;
else
} while (active);
}
else
f = 0;
if (prereqs)
{
/*
* check explicit constrained prereqs -- easy
*/
matched = 0;
if (metamatch(stem, u, p->rule->name) && (x = metainfo('I', p->rule->name, NiL, 0)) && (matched = 1, x->prereqs))
if (metamatch(t, unbound(q->rule), v->rule->name) && streq(t, stem) && (m = metarule(v->rule->name, p->rule->name, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)))
{
s = q->rule;
goto primary;
}
}
else
matched = 1;
if (b = strrchr(u, '/'))
b++;
else
b = u;
if (matched)
{
/*
* check implicit constrained prereqs -- a little harder
*/
matched = 0;
if ((m = metarule(q->rule->name, p->rule->name, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)) && !(m->property & f))
{
if (!tmp)
if (b != u && *u != '/' && *q->rule->name && ((state.questionable & 0x00000008) || !strchr(q->rule->name, '/')))
{
char* x = u;
for (;;)
{
{
if (!buf)
}
if ((s = bindfile(NiL, t, 0)) && s->status != UPDATE && (s->time || (s->property & P_target)) || !(state.questionable & 0x08000000) && m->action && !*m->action && (s = makerule(t)))
{
if (buf)
goto primary;
}
if (!(x = strchr(x, '/')))
break;
x++;
}
}
else
{
{
if (!buf)
}
goto primary;
if ((s = bindfile(NiL, t, 0)) && s->status != UPDATE && (s->time || (s->property & P_target)) || !(state.questionable & 0x08000000) && m->action && !*m->action && (s = makerule(t)))
{
if (buf)
goto primary;
}
}
/*
* check terminal unconstrained metarules
*/
{
if (!buf)
{
s = makerule(t);
goto primary;
}
}
}
if (buf)
if (tmp)
}
/*
* unconstrained metarules ignored on recursive calls
*/
if (!meta)
return 0;
/*
* check terminal unconstrained metarules
*/
if (prereqs)
{
/*
* check explicit terminal unconstrained prereqs
*/
if (metamatch(t, q->rule->name, p->rule->name) && streq(t, b) && (s = bindfile(q->rule, NiL, 0)) && s->time)
{
goto unconstrained;
}
}
/*
* check implicit terminal unconstrained prereqs
*/
if ((m = metarule(p->rule->name, NiL, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)) && !(m->property & f))
{
{
goto unconstrained;
}
}
/*
* check nonterminal unconstrained metarules
* nonterminals skipped if r matched any constrained metarule target
*/
{
/*
* don't try to match excluded patterns
*/
{
matched = 1;
break;
}
if (!matched)
{
if (prereqs)
{
/*
* check explicit prereqs -- easy
*/
{
s = q->rule;
goto unconstrained;
}
}
/*
* check implicit prereqs -- hardest
*/
{
s = getrule(t);
if (isstatevar(t))
{
goto unconstrained;
}
{
/*
* use s if it exists
*/
goto unconstrained;
/*
* use s if it can be generated
*/
goto unconstrained;
}
}
}
}
/*
* no metarule match
*/
return 0;
/*
* unconstrained match
*/
/*
* primary match
*/
if (meta)
{
if (m->uname)
{
/*
* metarule intermediate prerequisite
*/
{
x = 0;
{
if (!x->uname)
break;
x = 0;
}
}
if (x)
{
{
*meta = x;
s = y;
goto found;
}
}
}
*meta = m;
}
if (m->property & P_terminal)
s->property |= P_terminal;
{
return 0;
}
{
*t = 0;
{
}
{
sfsprintf(stem, MAXNAME - 1, "%s%s%s", u, state.targetprefix ? state.targetprefix : "/", sfstruse(internal.met));
}
*t = '/';
}
return s;
}