(variable_expand): Rewrote computed variable name and substitution

reference handling to be simpler.  First expand the entire text between the
parens if it contains any $s, then examine the result of that for
subtitution references and do no further expansion while parsing them.
This commit is contained in:
Roland McGrath 1995-01-15 15:32:37 +00:00
parent 7879457545
commit e167e0a3c2

206
expand.c
View file

@ -1,5 +1,5 @@
/* Variable expansion functions for GNU Make. /* Variable expansion functions for GNU Make.
Copyright (C) 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. Copyright (C) 1988, 89, 91, 92, 93, 95 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify GNU Make is free software; you can redistribute it and/or modify
@ -197,9 +197,9 @@ variable_expand (line)
char openparen = *p; char openparen = *p;
char closeparen = (openparen == '(') ? ')' : '}'; char closeparen = (openparen == '(') ? ')' : '}';
register char *beg = p + 1; register char *beg = p + 1;
int free_beg = 0;
char *op, *begp; char *op, *begp;
char *end; char *end, *colon;
char *colon = 0;
op = o; op = o;
begp = p; begp = p;
@ -213,10 +213,18 @@ variable_expand (line)
/* Is there a variable reference inside the parens or braces? /* Is there a variable reference inside the parens or braces?
If so, expand it before expanding the entire reference. */ If so, expand it before expanding the entire reference. */
p1 = index (beg, closeparen); end = index (beg, closeparen);
if (end == 0)
{
/* Unterminated variable reference. */
if (reading_filename != 0)
makefile_fatal (reading_filename, *reading_lineno_ptr,
"unterminated variable reference");
else
fatal ("unterminated variable reference");
}
p1 = lindex (beg, end, '$');
if (p1 != 0) if (p1 != 0)
p1 = lindex (beg, p1, '$');
if (p1 != 0 && lindex (beg, p1, ':') == 0)
{ {
/* BEG now points past the opening paren or brace. /* BEG now points past the opening paren or brace.
Count parens or braces until it is matched. */ Count parens or braces until it is matched. */
@ -227,133 +235,107 @@ variable_expand (line)
++count; ++count;
else if (*p == closeparen && --count < 0) else if (*p == closeparen && --count < 0)
break; break;
else if (colon == 0 && count == 0 && *p == ':')
/* Record where we found a colon, which
indicates a substitution reference.
We want to expand the text before the
reference only. */
colon = p;
} }
/* If COUNT is >= 0, there were unmatched opening parens /* If COUNT is >= 0, there were unmatched opening parens
or braces, so we go to the simple case of a variable name or braces, so we go to the simple case of a variable name
such as `$($(a)'. */ such as `$($(a)'. */
if (count < 0) if (count < 0)
{ {
char *name = expand_argument (beg, colon == 0 ? p : colon); beg = expand_argument (beg, p); /* Expand the name. */
unsigned int namelen = strlen (name); free_beg = 1; /* Remember to free BEG when finished. */
if (colon == 0) end = index (beg, '\0');
{
/* This is a simple reference to the expanded name. */
o = reference_variable (o, name, namelen);
free (name);
break;
}
else
{
/* This is a substitution reference to the expanded
name. We replace the pending text with a copy
containing the expanded name in place of the
original name, and then fall through to
the normal substitution reference code below. */
unsigned int restlen = strlen (colon) + 1;
beg = (char *) alloca (namelen + restlen);
bcopy (name, beg, namelen);
bcopy (colon, &beg[namelen], restlen);
/* Point COLON into the new copy. */
colon = &beg[namelen];
}
} }
} }
else
/* Advance P to the end of this reference. After we are
finished expanding this one, P will be incremented to
continue the scan. */
p = end;
/* This is not a reference to a built-in function and /* This is not a reference to a built-in function and
it does not contain any variable references inside. any variable references inside are now expanded.
There are several things it could be. */ Is the resultant text a substitution reference? */
if (colon == 0) colon = index (beg, ':');
colon = index (beg, ':'); if (colon != 0)
if (colon != 0 && lindex (beg, colon, closeparen) == 0)
{ {
/* This is a substitution reference: $(FOO:A=B). */ /* This looks like a substitution reference: $(FOO:A=B). */
int count;
char *subst_beg, *subst_end, *replace_beg, *replace_end; char *subst_beg, *subst_end, *replace_beg, *replace_end;
v = lookup_variable (beg, colon - beg);
if (v == 0)
warn_undefined (beg, colon - beg);
subst_beg = colon + 1; subst_beg = colon + 1;
count = 0; subst_end = index (subst_beg, '=');
for (p = subst_beg; *p != '\0'; ++p) if (subst_end == 0)
/* There is no = in sight. Punt on the substitution
reference and treat this as a variable name containing
a colon, in the code below. */
colon = 0;
else
{ {
if (*p == openparen) replace_beg = subst_end + 1;
++count; replace_end = end;
else if (*p == closeparen)
--count; /* Extract the variable name before the colon
else if (*p == '=' && count <= 0) and look up that variable. */
break; v = lookup_variable (beg, colon - beg);
if (v == 0)
warn_undefined (beg, colon - beg);
if (v != 0 && *v->value != '\0')
{
char *value = (v->recursive ? recursively_expand (v)
: v->value);
char *pattern, *percent;
if (free_beg)
{
*subst_end = '\0';
pattern = subst_beg;
}
else
{
pattern = alloca (subst_end - subst_beg + 1);
bcopy (subst_beg, pattern, subst_end - subst_beg);
pattern[subst_end - subst_beg] = '\0';
}
percent = find_percent (pattern);
if (percent != 0)
{
char *replace;
if (free_beg)
{
*replace_end = '\0';
replace = replace_beg;
}
else
{
replace = alloca (replace_end - replace_beg
+ 1);
bcopy (replace_beg, replace,
replace_end - replace_beg);
replace[replace_end - replace_beg] = '\0';
}
o = patsubst_expand (o, value, pattern, replace,
percent, (char *) 0);
}
else
o = subst_expand (o, value,
pattern, replace_beg,
strlen (pattern),
end - replace_beg,
0, 1);
if (v->recursive)
free (value);
}
} }
if (count > 0)
/* There were unmatched opening parens. */
return initialize_variable_output ();
subst_end = p;
replace_beg = p + 1;
count = 0;
for (p = replace_beg; *p != '\0'; ++p)
{
if (*p == openparen)
++count;
else if (*p == closeparen && --count < 0)
break;
}
if (count > 0)
/* There were unmatched opening parens. */
return initialize_variable_output ();
end = p;
replace_end = p;
p = expand_argument (subst_beg, subst_end);
p1 = expand_argument (replace_beg, replace_end);
if (v != 0 && *v->value != '\0')
{
char *value = (v->recursive ? recursively_expand (v)
: v->value);
char *percent = find_percent (p);
if (percent != 0)
o = patsubst_expand (o, value, p, p1,
percent, (char *) 0);
else
o = subst_expand (o, value,
p, p1, strlen (p), strlen (p1),
0, 1);
if (v->recursive)
free (value);
}
free (p);
free (p1);
} }
/* No, this must be an ordinary variable reference. */ if (colon == 0)
else /* This is an ordinary variable reference.
{ Look up the value of the variable. */
/* Look up the value of the variable. */
end = index (beg, closeparen);
if (end == 0)
{
/* Unterminated variable reference. */
if (reading_filename != 0)
makefile_fatal (reading_filename, *reading_lineno_ptr,
"unterminated variable reference");
else
fatal ("unterminated variable reference");
}
o = reference_variable (o, beg, end - beg); o = reference_variable (o, beg, end - beg);
}
/* Advance p past the variable reference to resume scan. */ if (free_beg)
p = end; free (beg);
} }
break; break;