]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Initial revision
authorRoland McGrath <roland@redhat.com>
Fri, 13 Sep 1991 23:39:37 +0000 (23:39 +0000)
committerRoland McGrath <roland@redhat.com>
Fri, 13 Sep 1991 23:39:37 +0000 (23:39 +0000)
expand.c [new file with mode: 0644]

diff --git a/expand.c b/expand.c
new file mode 100644 (file)
index 0000000..81796d5
--- /dev/null
+++ b/expand.c
@@ -0,0 +1,342 @@
+/* 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;
+}
+\f
+/* 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 ();
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}