home *** CD-ROM | disk | FTP | other *** search
- /* Variable expansion functions for GNU Make.
- Copyright (C) 1988, 1989 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 1, 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. */
-
- /*
- * MS-DOS port (c) 1990 by Thorsten Ohl <ohl@gnu.ai.mit.edu>
- *
- * To this port, the same copying conditions apply as to the
- * original release.
- *
- * IMPORTANT:
- * This file is not identical to the original GNU release!
- * You should have received this code as patch to the official
- * GNU release.
- *
- * MORE IMPORTANT:
- * This port comes with ABSOLUTELY NO WARRANTY.
- *
- * $Header: e:/gnu/make/RCS/expand.c'v 3.58.0.1 90/07/17 00:59:05 tho Exp $
- */
-
- #include "make.h"
- #include "commands.h"
- #include "file.h"
- #include "variable.h"
-
- #ifdef MSDOS
- static char *recursively_expand (struct variable *v);
- #endif /* MSDOS */
-
- /* Recursively expand V. The returned string is malloc'd. */
-
- static char *
- recursively_expand (v)
- register struct variable *v;
- {
- char *value;
-
- if (v->expanding)
- fatal ("%s:%u: Recursive variable `%s' references itself (eventually)",
- reading_filename, *reading_lineno_ptr, 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':
- case '\t':
- case ' ':
- break;
-
- default:
- /* 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;
- {
- #ifdef MSDOS
- return allocated_var_exp_for_file (line, (struct file *) 0);
- #else
- return allocated_variable_expand_for_file (line, (struct file *) 0);
- #endif /* MSDOS */
-
- }
-
- /* Like variable_expand_for_file, but the returned string is malloc'd. */
-
- char *
- #ifdef MSDOS
- allocated_var_exp_for_file (line, file)
- #else
- allocated_variable_expand_for_file (line, file)
- #endif /* MSDOS */
- 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;
- }
-