| /* Variable expansion functions for GNU Make. |
| Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. |
| This file is part of GNU Make. |
| |
| GNU Make is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Make is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Make; see the file COPYING. If not, write to |
| the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
| |
| #include "make.h" |
| #include "commands.h" |
| #include "file.h" |
| #include "variable.h" |
| |
| |
| /* Recursively expand V. The returned string is malloc'd. */ |
| |
| static char * |
| recursively_expand (v) |
| register struct variable *v; |
| { |
| char *value; |
| |
| if (v->expanding) |
| { |
| /* Expanding V causes infinite recursion. Lose. */ |
| if (reading_filename == 0) |
| fatal ("Recursive variable `%s' references itself (eventually)", |
| v->name); |
| else |
| makefile_fatal |
| (reading_filename, *reading_lineno_ptr, |
| "Recursive variable `%s' references itself (eventually)", |
| v->name); |
| } |
| |
| v->expanding = 1; |
| value = allocated_variable_expand (v->value); |
| v->expanding = 0; |
| |
| return value; |
| } |
| |
| /* Scan LINE for variable references and expansion-function calls. |
| Build in `variable_buffer' the result of expanding the references and calls. |
| Return the address of the resulting string, which is null-terminated |
| and is valid only until the next time this function is called. */ |
| |
| char * |
| variable_expand (line) |
| register char *line; |
| { |
| register struct variable *v; |
| register char *p, *o, *p1; |
| |
| p = line; |
| o = initialize_variable_output (); |
| |
| while (1) |
| { |
| /* Copy all following uninteresting chars all at once to the |
| variable output buffer, and skip them. Uninteresting chars end |
| at the next $ or the end of the input. */ |
| |
| p1 = index (p, '$'); |
| |
| o = variable_buffer_output (o, p, p1 != 0 ? p1 - p : strlen (p) + 1); |
| |
| if (p1 == 0) |
| break; |
| p = p1 + 1; |
| |
| /* Dispatch on the char that follows the $. */ |
| |
| switch (*p) |
| { |
| case '$': |
| /* $$ seen means output one $ to the variable output buffer. */ |
| o = variable_buffer_output (o, p, 1); |
| break; |
| |
| case '(': |
| case '{': |
| /* $(...) or ${...} is the general case of substitution. */ |
| { |
| char openparen = *p; |
| char closeparen = (openparen == '(') ? ')' : '}'; |
| register char *beg = p + 1; |
| char *op, *begp; |
| char *end; |
| |
| op = o; |
| begp = p; |
| if (handle_function (&op, &begp)) |
| { |
| o = op; |
| p = begp; |
| break; |
| } |
| |
| /* Is there a variable reference inside the parens or braces? |
| If so, expand it before expanding the entire reference. */ |
| |
| p1 = index (beg, closeparen); |
| if (p1 != 0) |
| p1 = lindex (beg, p1, '$'); |
| if (p1 != 0) |
| { |
| /* BEG now points past the opening paren or brace. |
| Count parens or braces until it is matched. */ |
| int count = 0; |
| for (p = beg; *p != '\0'; ++p) |
| { |
| if (*p == openparen) |
| ++count; |
| else if (*p == closeparen && --count < 0) |
| break; |
| } |
| /* If count is >= 0, there were unmatched opening parens |
| or braces, so we go to the simple case of a variable name |
| such as `$($(a)'. */ |
| if (count < 0) |
| { |
| char *name = expand_argument (beg, p); |
| static char start[3] = { '$', }, end[2]; |
| start[1] = openparen; |
| end[0] = closeparen; |
| p1 = concat (start, name, end); |
| free (name); |
| name = allocated_variable_expand (p1); |
| o = variable_buffer_output (o, name, strlen (name)); |
| free (name); |
| break; |
| } |
| } |
| |
| /* This is not a reference to a built-in function and |
| it does not contain any variable references inside. |
| There are several things it could be. */ |
| |
| p = index (beg, ':'); |
| if (p != 0 && lindex (beg, p, closeparen) == 0) |
| { |
| /* This is a substitution reference: $(FOO:A=B). */ |
| int count; |
| char *subst_beg, *replace_beg; |
| unsigned int subst_len, replace_len; |
| |
| v = lookup_variable (beg, p - beg); |
| |
| subst_beg = p + 1; |
| count = 0; |
| for (p = subst_beg; *p != '\0'; ++p) |
| { |
| if (*p == openparen) |
| ++count; |
| else if (*p == closeparen) |
| --count; |
| else if (*p == '=' && count <= 0) |
| break; |
| } |
| if (count > 0) |
| /* There were unmatched opening parens. */ |
| return initialize_variable_output (); |
| subst_len = p - subst_beg; |
| |
| 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_len = p - replace_beg; |
| |
| if (v != 0 && *v->value != '\0') |
| { |
| char *value = (v->recursive ? recursively_expand (v) |
| : v->value); |
| if (lindex (subst_beg, subst_beg + subst_len, '%') != 0) |
| { |
| p = savestring (subst_beg, subst_len); |
| p1 = savestring (replace_beg, replace_len); |
| o = patsubst_expand (o, value, p, p1, |
| index (p, '%'), index (p1, '%')); |
| free (p); |
| free (p1); |
| } |
| else |
| o = subst_expand (o, value, subst_beg, replace_beg, |
| subst_len, replace_len, 0, 1); |
| if (v->recursive) |
| free (value); |
| } |
| } |
| |
| /* No, this must be an ordinary variable reference. */ |
| else |
| { |
| /* Look up the value of the variable. */ |
| end = index (beg, closeparen); |
| if (end == 0) |
| return initialize_variable_output (); |
| v = lookup_variable (beg, end - beg); |
| |
| if (v != 0 && *v->value != '\0') |
| { |
| char *value = (v->recursive ? recursively_expand (v) |
| : v->value); |
| o = variable_buffer_output (o, value, strlen (value)); |
| if (v->recursive) |
| free (value); |
| } |
| } |
| |
| /* Advance p past the variable reference to resume scan. */ |
| p = end; |
| } |
| break; |
| |
| case '\0': |
| break; |
| |
| default: |
| if (isblank (p[-1])) |
| break; |
| |
| /* A $ followed by a random char is a variable reference: |
| $a is equivalent to $(a). */ |
| { |
| /* We could do the expanding here, but this way |
| avoids code repetition at a small performance cost. */ |
| char name[5]; |
| name[0] = '$'; |
| name[1] = '('; |
| name[2] = *p; |
| name[3] = ')'; |
| name[4] = '\0'; |
| p1 = allocated_variable_expand (name); |
| o = variable_buffer_output (o, p1, strlen (p1)); |
| free (p1); |
| } |
| |
| break; |
| } |
| |
| if (*p == '\0') |
| break; |
| else |
| ++p; |
| } |
| |
| (void) variable_buffer_output (o, "", 1); |
| return initialize_variable_output (); |
| } |
| |
| /* Expand an argument for an expansion function. |
| The text starting at STR and ending at END is variable-expanded |
| into a null-terminated string that is returned as the value. |
| This is done without clobbering `variable_buffer' or the current |
| variable-expansion that is in progress. */ |
| |
| char * |
| expand_argument (str, end) |
| char *str, *end; |
| { |
| char *tmp = savestring (str, end - str); |
| char *value = allocated_variable_expand (tmp); |
| |
| free (tmp); |
| |
| return value; |
| } |
| |
| /* Expand LINE for FILE. Error messages refer to the file and line where |
| FILE's commands were found. Expansion uses FILE's variable set list. */ |
| |
| char * |
| variable_expand_for_file (line, file) |
| char *line; |
| register struct file *file; |
| { |
| char *result; |
| struct variable_set_list *save; |
| |
| if (file == 0) |
| return variable_expand (line); |
| |
| save = current_variable_set_list; |
| current_variable_set_list = file->variables; |
| reading_filename = file->cmds->filename; |
| reading_lineno_ptr = &file->cmds->lineno; |
| result = variable_expand (line); |
| current_variable_set_list = save; |
| reading_filename = 0; |
| reading_lineno_ptr = 0; |
| |
| return result; |
| } |
| |
| /* Like variable_expand, but the returned string is malloc'd. */ |
| char * |
| allocated_variable_expand (line) |
| char *line; |
| { |
| return allocated_variable_expand_for_file (line, (struct file *) 0); |
| } |
| |
| /* Like variable_expand_for_file, but the returned string is malloc'd. */ |
| |
| char * |
| allocated_variable_expand_for_file (line, file) |
| char *line; |
| struct file *file; |
| { |
| char *save; |
| char *value; |
| |
| save = save_variable_output (); |
| |
| value = variable_expand_for_file (line, file); |
| value = savestring (value, strlen (value)); |
| |
| restore_variable_output (save); |
| |
| return value; |
| } |