#include "make.h"
#include "rule.h"
#include "dep.h"
#include "filedef.h"
#include "debug.h"
static int pattern_search PARAMS ((struct file *file, int archive, unsigned int depth,
unsigned int recursions));
int
try_implicit_rule (file, depth)
struct file *file;
unsigned int depth;
{
DBF (DB_IMPLICIT, _("Looking for an implicit rule for `%s'.\n"));
if (pattern_search (file, 0, depth, 0))
return 1;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
DBF (DB_IMPLICIT,
_("Looking for archive-member implicit rule for `%s'.\n"));
if (pattern_search (file, 1, depth, 0))
return 1;
}
#endif
return 0;
}
static int
pattern_search (file, archive, depth, recursions)
struct file *file;
int archive;
unsigned int depth;
unsigned int recursions;
{
char *filename = archive ? strchr (file->name, '(') : file->name;
unsigned int namelen = strlen (filename);
char *lastslash;
struct file *intermediate_file = 0;
struct file **intermediate_files
= (struct file **) alloca (max_pattern_deps * sizeof (struct file *));
char **intermediate_patterns
= (char **) alloca (max_pattern_deps * sizeof (char *));
char **found_files = (char **) alloca (max_pattern_deps * sizeof (char *));
unsigned int deps_found = 0;
register char *depname = (char *) alloca (namelen + max_pattern_dep_length);
register char *stem = 0;
register unsigned int stemlen = 0;
struct rule **tryrules
= (struct rule **) alloca (num_pattern_rules * max_pattern_targets
* sizeof (struct rule *));
unsigned int nrules;
unsigned int *matches
= (unsigned int *) alloca (num_pattern_rules * sizeof (unsigned int));
char *checked_lastslash
= (char *) alloca (num_pattern_rules * sizeof (char));
unsigned int foundrule;
int intermed_ok;
int specific_rule_matched = 0;
register unsigned int i = 0;
register struct rule *rule;
register struct dep *dep;
char *p, *vp;
#ifndef NO_ARCHIVES
if (archive || ar_name (filename))
lastslash = 0;
else
#endif
{
#ifdef VMS
lastslash = strrchr (filename, ']');
if (lastslash == 0)
lastslash = strrchr (filename, ':');
#else
lastslash = strrchr (filename, '/');
#if defined(__MSDOS__) || defined(WINDOWS32)
{
char *bslash = strrchr (filename, '\\');
if (lastslash == 0 || bslash > lastslash)
lastslash = bslash;
if (lastslash == 0 && filename[0] && filename[1] == ':')
lastslash = filename + 1;
}
#endif
#endif
if (lastslash != 0 && lastslash[1] == '\0')
lastslash = 0;
}
nrules = 0;
for (rule = pattern_rules; rule != 0; rule = rule->next)
{
if (rule->deps != 0 && rule->cmds == 0)
continue;
if (rule->in_use)
{
DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n")));
continue;
}
for (i = 0; rule->targets[i] != 0; ++i)
{
char *target = rule->targets[i];
char *suffix = rule->suffixes[i];
int check_lastslash;
if (recursions > 0 && target[1] == '\0' && !rule->terminal)
continue;
if (rule->lens[i] > namelen)
continue;
stem = filename + (suffix - target - 1);
stemlen = namelen - rule->lens[i] + 1;
#ifdef VMS
check_lastslash = lastslash != 0
&& ((strchr (target, ']') == 0)
&& (strchr (target, ':') == 0));
#else
check_lastslash = lastslash != 0 && strchr (target, '/') == 0;
#endif
if (check_lastslash)
{
unsigned int difference = lastslash - filename + 1;
if (difference > stemlen)
continue;
stemlen -= difference;
stem += difference;
}
if (check_lastslash)
{
if (stem > (lastslash + 1)
&& !strneq (target, lastslash + 1, stem - lastslash - 1))
continue;
}
else if (stem > filename
&& !strneq (target, filename, stem - filename))
continue;
if (*suffix != stem[stemlen]
|| (*suffix != '\0' && !streq (&suffix[1], &stem[stemlen + 1])))
continue;
if (target[1] != '\0')
specific_rule_matched = 1;
if (rule->deps == 0 && rule->cmds == 0)
continue;
tryrules[nrules] = rule;
matches[nrules] = i;
checked_lastslash[nrules] = check_lastslash;
++nrules;
}
}
if (specific_rule_matched)
for (i = 0; i < nrules; ++i)
if (!tryrules[i]->terminal)
{
register unsigned int j;
for (j = 0; tryrules[i]->targets[j] != 0; ++j)
if (tryrules[i]->targets[j][1] == '\0')
break;
if (tryrules[i]->targets[j] != 0)
tryrules[i] = 0;
}
for (intermed_ok = 0; intermed_ok == !!intermed_ok; ++intermed_ok)
{
for (i = 0; i < nrules; i++)
{
int check_lastslash;
rule = tryrules[i];
if (rule == 0)
continue;
if (intermed_ok && rule->terminal)
continue;
rule->in_use = 1;
stem = filename
+ (rule->suffixes[matches[i]] - rule->targets[matches[i]]) - 1;
stemlen = namelen - rule->lens[matches[i]] + 1;
check_lastslash = checked_lastslash[i];
if (check_lastslash)
{
stem += lastslash - filename + 1;
stemlen -= (lastslash - filename) + 1;
}
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem `%.*s'.\n"),
(int) stemlen, stem));
deps_found = 0;
for (dep = rule->deps; dep != 0; dep = dep->next)
{
p = strchr (dep_name (dep), '%');
if (p != 0)
{
register unsigned int i;
if (check_lastslash)
{
i = lastslash - filename + 1;
bcopy (filename, depname, i);
}
else
i = 0;
bcopy (dep_name (dep), depname + i, p - dep_name (dep));
i += p - dep_name (dep);
bcopy (stem, depname + i, stemlen);
i += stemlen;
strcpy (depname + i, p + 1);
p = depname;
}
else
p = dep_name (dep);
if (file_impossible_p (p))
{
DBS (DB_IMPLICIT,
(p == depname
? _("Rejecting impossible implicit prerequisite `%s'.\n")
: _("Rejecting impossible rule prerequisite `%s'.\n"),
p));
tryrules[i] = 0;
break;
}
intermediate_files[deps_found] = 0;
DBS (DB_IMPLICIT,
(p == depname
? _("Trying implicit prerequisite `%s'.\n")
: _("Trying rule prerequisite `%s'.\n"), p));
if ((!dep->changed || check_lastslash)
&& (lookup_file (p) != 0 || file_exists_p (p)))
{
found_files[deps_found++] = xstrdup (p);
continue;
}
vp = p;
if (vpath_search (&vp, (FILE_TIMESTAMP *) 0))
{
DBS (DB_IMPLICIT,
(_("Found prerequisite `%s' as VPATH `%s'\n"), p, vp));
strcpy (vp, p);
found_files[deps_found++] = vp;
continue;
}
if (intermed_ok)
{
if (intermediate_file == 0)
intermediate_file
= (struct file *) alloca (sizeof (struct file));
DBS (DB_IMPLICIT,
(_("Looking for a rule with intermediate file `%s'.\n"),
p));
bzero ((char *) intermediate_file, sizeof (struct file));
intermediate_file->name = p;
if (pattern_search (intermediate_file, 0, depth + 1,
recursions + 1))
{
p = xstrdup (p);
intermediate_patterns[deps_found]
= intermediate_file->name;
intermediate_file->name = p;
intermediate_files[deps_found] = intermediate_file;
intermediate_file = 0;
found_files[deps_found] = xstrdup (p);
++deps_found;
continue;
}
file_impossible (p);
}
break;
}
rule->in_use = 0;
if (dep != 0)
{
while (deps_found-- > 0)
{
register struct file *f = intermediate_files[deps_found];
free (found_files[deps_found]);
if (f != 0
&& (f->stem < f->name
|| f->stem > f->name + strlen (f->name)))
free (f->stem);
}
}
else
break;
}
if (i < nrules)
break;
rule = 0;
}
#if defined(__APPLE__) || defined(NeXT) || defined(NeXT_PDO)
if (rule == 0) {
if ((next_flag & NEXT_VPATH_FLAG) && file->old_name != 0) {
int v;
char *save_name = file->name;
file->name = file->old_name;
file->old_name = 0;
v = pattern_search(file, archive, depth, recursions);
file->old_name = file->name;
file->name = save_name;
return v;
}
return 0;
}
#else
if (rule == 0)
return 0;
#endif
foundrule = i;
if (recursions > 0)
file->name = rule->targets[matches[foundrule]];
while (deps_found-- > 0)
{
register char *s;
if (intermediate_files[deps_found] != 0)
{
struct file *imf = intermediate_files[deps_found];
register struct file *f = enter_file (imf->name);
f->deps = imf->deps;
f->cmds = imf->cmds;
f->stem = imf->stem;
f->also_make = imf->also_make;
imf = lookup_file (intermediate_patterns[deps_found]);
if (imf != 0 && imf->precious)
f->precious = 1;
f->intermediate = 1;
f->tried_implicit = 1;
for (dep = f->deps; dep != 0; dep = dep->next)
{
dep->file = enter_file (dep->name);
if (dep->name != dep->file->name)
free (dep->name);
dep->name = 0;
dep->file->tried_implicit |= dep->changed;
}
num_intermediates++;
}
dep = (struct dep *) xmalloc (sizeof (struct dep));
s = found_files[deps_found];
if (recursions == 0)
{
dep->name = 0;
dep->file = lookup_file (s);
if (dep->file == 0)
dep->file = enter_file (s);
else
free (s);
}
else
{
dep->name = s;
dep->file = 0;
dep->changed = 0;
}
if (intermediate_files[deps_found] == 0 && tryrules[foundrule]->terminal)
{
if (dep->file == 0)
dep->changed = 1;
else
dep->file->tried_implicit = 1;
}
dep->next = file->deps;
file->deps = dep;
}
if (!checked_lastslash[foundrule])
file->stem = savestring (stem, stemlen);
else
{
file->stem = (char *) xmalloc (((lastslash + 1) - filename)
+ stemlen + 1);
bcopy (filename, file->stem, (lastslash + 1) - filename);
bcopy (stem, file->stem + ((lastslash + 1) - filename), stemlen);
file->stem[((lastslash + 1) - filename) + stemlen] = '\0';
}
file->cmds = rule->cmds;
if (rule->targets[1] != 0)
for (i = 0; rule->targets[i] != 0; ++i)
if (i != matches[foundrule])
{
struct dep *new = (struct dep *) xmalloc (sizeof (struct dep));
new->name = p = (char *) xmalloc (rule->lens[i] + stemlen + 1);
bcopy (rule->targets[i], p,
rule->suffixes[i] - rule->targets[i] - 1);
p += rule->suffixes[i] - rule->targets[i] - 1;
bcopy (stem, p, stemlen);
p += stemlen;
bcopy (rule->suffixes[i], p,
rule->lens[i] - (rule->suffixes[i] - rule->targets[i]) + 1);
new->file = enter_file (new->name);
new->next = file->also_make;
file->also_make = new;
}
return 1;
}