]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libcpp/mkdeps.c
Daily bump.
[thirdparty/gcc.git] / libcpp / mkdeps.c
index 8aa96c529e3371065eb0b9bb730dbe21b414ce9f..96cc49b9cc1720544c56e38210d48c78136011a2 100644 (file)
@@ -1,10 +1,10 @@
 /* Dependency generator for Makefile fragments.
-   Copyright (C) 2000, 2001, 2003, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2000-2019 Free Software Foundation, Inc.
    Contributed by Zack Weinberg, Mar 2000
 
 This program 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
+Free Software Foundation; either version 3, or (at your option) any
 later version.
 
 This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@ 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 this program; if not, write to the Free Software
-Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+along with this program; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.
 
  In other words, you are welcome to use, share and improve this program.
  You are forbidden to forbid anyone else to use, share and improve
@@ -24,120 +24,184 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 #include "system.h"
 #include "mkdeps.h"
 
+/* Not set up to just include std::vector et al, here's a simple
+   implementation.  */
+
 /* Keep this structure local to this file, so clients don't find it
    easy to start making assumptions.  */
-struct deps
+struct mkdeps
 {
-  const char **targetv;
-  unsigned int ntargets;       /* number of slots actually occupied */
-  unsigned int targets_size;   /* amt of allocated space - in words */
-
-  const char **depv;
-  unsigned int ndeps;
-  unsigned int deps_size;
-
-  const char **vpathv;
-  size_t *vpathlv;
-  unsigned int nvpaths;
-  unsigned int vpaths_size;
-};
-
-static const char *munge (const char *);
-
-/* Given a filename, quote characters in that filename which are
-   significant to Make.  Note that it's not possible to quote all such
-   characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
-   not properly handled.  It isn't possible to get this right in any
-   current version of Make.  (??? Still true?  Old comment referred to
-   3.76.1.)  */
-
-static const char *
-munge (const char *filename)
-{
-  int len;
-  const char *p, *q;
-  char *dst, *buffer;
-
-  for (p = filename, len = 0; *p; p++, len++)
+public:
+  /* T has trivial cctor & dtor.  */
+  template <typename T>
+  class vec
+  {
+  private:
+    T *ary;
+    unsigned num;
+    unsigned alloc;
+
+  public:
+    vec ()
+      : ary (NULL), num (0), alloc (0)
+      {}
+    ~vec ()
+      {
+       XDELETEVEC (ary);
+      }
+
+  public:
+    unsigned size () const
     {
-      switch (*p)
-       {
-       case ' ':
-       case '\t':
-         /* GNU make uses a weird quoting scheme for white space.
-            A space or tab preceded by 2N+1 backslashes represents
-            N backslashes followed by space; a space or tab
-            preceded by 2N backslashes represents N backslashes at
-            the end of a file name; and backslashes in other
-            contexts should not be doubled.  */
-         for (q = p - 1; filename <= q && *q == '\\';  q--)
-           len++;
-         len++;
-         break;
-
-       case '$':
-         /* '$' is quoted by doubling it.  */
-         len++;
-         break;
-       }
+      return num;
     }
-
-  /* Now we know how big to make the buffer.  */
-  buffer = XNEWVEC (char, len + 1);
-
-  for (p = filename, dst = buffer; *p; p++, dst++)
+    const T &operator[] (unsigned ix) const
+    {
+      return ary[ix];
+    }
+    void push (const T &elt)
     {
-      switch (*p)
+      if (num == alloc)
        {
-       case ' ':
-       case '\t':
-         for (q = p - 1; filename <= q && *q == '\\';  q--)
-           *dst++ = '\\';
-         *dst++ = '\\';
-         break;
-
-       case '$':
-         *dst++ = '$';
-         break;
-
-       default:
-         /* nothing */;
+         alloc = alloc ? alloc * 2 : 16;
+         ary = XRESIZEVEC (T, ary, alloc);
        }
-      *dst = *p;
+      ary[num++] = elt;
     }
+  };
+  struct velt
+  {
+    const char *str;
+    size_t len;
+  };
+
+  mkdeps ()
+    : quote_lwm (0)
+  {
+  }
+  ~mkdeps ()
+  {
+    unsigned int i;
+
+    for (i = targets.size (); i--;)
+      free (const_cast <char *> (targets[i]));
+    for (i = deps.size (); i--;)
+      free (const_cast <char *> (deps[i]));
+    for (i = vpath.size (); i--;)
+      XDELETEVEC (vpath[i].str);
+  }
+
+public:
+  vec<const char *> targets;
+  vec<const char *> deps;
+  vec<velt> vpath;
+
+public:
+  unsigned short quote_lwm;
+};
 
-  *dst = '\0';
-  return buffer;
-}
+/* Apply Make quoting to STR, TRAIL etc.  Note that it's not possible
+   to quote all such characters - e.g. \n, %, *, ?, [, \ (in some
+   contexts), and ~ are not properly handled.  It isn't possible to
+   get this right in any current version of Make.  (??? Still true?
+   Old comment referred to 3.76.1.)  */
 
-/* If T begins with any of the partial pathnames listed in d->vpathv,
-   then advance T to point beyond that pathname.  */
 static const char *
-apply_vpath (struct deps *d, const char *t)
+munge (const char *str, const char *trail = NULL, ...)
 {
-  if (d->vpathv)
+  static unsigned alloc;
+  static char *buf;
+  unsigned dst = 0;
+  va_list args;
+  if (trail)
+    va_start (args, trail);
+
+  for (bool first = true; str; first = false)
     {
-      unsigned int i;
-      for (i = 0; i < d->nvpaths; i++)
+      unsigned slashes = 0;
+      char c;
+      for (const char *probe = str; (c = *probe++);)
        {
-         if (!strncmp (d->vpathv[i], t, d->vpathlv[i]))
+         if (alloc < dst + 4 + slashes)
            {
-             const char *p = t + d->vpathlv[i];
-             if (!IS_DIR_SEPARATOR (*p))
-               goto not_this_one;
+             alloc = alloc * 2 + 32;
+             buf = XRESIZEVEC (char, buf, alloc);
+           }
 
-             /* Do not simplify $(vpath)/../whatever.  ??? Might not
-                be necessary. */
-             if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
-               goto not_this_one;
+         switch (c)
+           {
+           case '\\':
+             slashes++;
+             break;
 
-             /* found a match */
-             t = t + d->vpathlv[i] + 1;
+           case '$':
+             buf[dst++] = '$';
+             goto def;
+
+           case ' ':
+           case '\t':
+             /* GNU make uses a weird quoting scheme for white space.
+                A space or tab preceded by 2N+1 backslashes
+                represents N backslashes followed by space; a space
+                or tab preceded by 2N backslashes represents N
+                backslashes at the end of a file name; and
+                backslashes in other contexts should not be
+                doubled.  */
+             while (slashes--)
+               buf[dst++] = '\\';
+             /* FALLTHROUGH  */
+
+           case '#':
+           case ':':
+             buf[dst++] = '\\';
+             /* FALLTHROUGH  */
+
+           default:
+           def:
+             slashes = 0;
              break;
            }
-       not_this_one:;
+
+         buf[dst++] = c;
        }
+
+      if (first)
+       str = trail;
+      else
+       str = va_arg (args, const char *);
     }
+  if (trail)
+    va_end (args);
+
+  buf[dst] = 0;
+  return buf;
+}
+
+/* If T begins with any of the partial pathnames listed in d->vpathv,
+   then advance T to point beyond that pathname.  */
+static const char *
+apply_vpath (struct mkdeps *d, const char *t)
+{
+  if (unsigned len = d->vpath.size ())
+    for (unsigned i = len; i--;)
+      {
+       if (!filename_ncmp (d->vpath[i].str, t, d->vpath[i].len))
+         {
+           const char *p = t + d->vpath[i].len;
+           if (!IS_DIR_SEPARATOR (*p))
+             goto not_this_one;
+
+           /* Do not simplify $(vpath)/../whatever.  ??? Might not
+              be necessary. */
+           if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
+             goto not_this_one;
+
+           /* found a match */
+           t = t + d->vpath[i].len + 1;
+           break;
+         }
+      not_this_one:;
+      }
 
   /* Remove leading ./ in any case.  */
   while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
@@ -154,70 +218,41 @@ apply_vpath (struct deps *d, const char *t)
 
 /* Public routines.  */
 
-struct deps *
+struct mkdeps *
 deps_init (void)
 {
-  return XCNEW (struct deps);
+  return new mkdeps ();
 }
 
 void
-deps_free (struct deps *d)
+deps_free (struct mkdeps *d)
 {
-  unsigned int i;
-
-  if (d->targetv)
-    {
-      for (i = 0; i < d->ntargets; i++)
-       free ((void *) d->targetv[i]);
-      free (d->targetv);
-    }
-
-  if (d->depv)
-    {
-      for (i = 0; i < d->ndeps; i++)
-       free ((void *) d->depv[i]);
-      free (d->depv);
-    }
-
-  if (d->vpathv)
-    {
-      for (i = 0; i < d->nvpaths; i++)
-       free ((void *) d->vpathv[i]);
-      free (d->vpathv);
-      free (d->vpathlv);
-    }
-
-  free (d);
+  delete d;
 }
 
 /* Adds a target T.  We make a copy, so it need not be a permanent
    string.  QUOTE is true if the string should be quoted.  */
 void
-deps_add_target (struct deps *d, const char *t, int quote)
+deps_add_target (struct mkdeps *d, const char *t, int quote)
 {
-  if (d->ntargets == d->targets_size)
+  t = apply_vpath (d, t);
+  if (!quote)
     {
-      d->targets_size = d->targets_size * 2 + 4;
-      d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
+      gcc_assert (d->quote_lwm == d->targets.size ());
+      d->quote_lwm++;
     }
 
-  t = apply_vpath (d, t);
-  if (quote)
-    t = munge (t);  /* Also makes permanent copy.  */
-  else
-    t = xstrdup (t);
-
-  d->targetv[d->ntargets++] = t;
+  d->targets.push (xstrdup (t));
 }
 
 /* Sets the default target if none has been given already.  An empty
    string as the default target in interpreted as stdin.  The string
    is quoted for MAKE.  */
 void
-deps_add_default_target (struct deps *d, const char *tgt)
+deps_add_default_target (struct mkdeps *d, const char *tgt)
 {
   /* Only if we have no targets.  */
-  if (d->ntargets)
+  if (d->targets.size ())
     return;
 
   if (tgt[0] == '\0')
@@ -244,175 +279,181 @@ deps_add_default_target (struct deps *d, const char *tgt)
 }
 
 void
-deps_add_dep (struct deps *d, const char *t)
+deps_add_dep (struct mkdeps *d, const char *t)
 {
-  t = munge (apply_vpath (d, t));  /* Also makes permanent copy.  */
+  gcc_assert (*t);
 
-  if (d->ndeps == d->deps_size)
-    {
-      d->deps_size = d->deps_size * 2 + 8;
-      d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
-    }
-  d->depv[d->ndeps++] = t;
+  t = apply_vpath (d, t);
+
+  d->deps.push (xstrdup (t));
 }
 
 void
-deps_add_vpath (struct deps *d, const char *vpath)
+deps_add_vpath (struct mkdeps *d, const char *vpath)
 {
   const char *elem, *p;
-  char *copy;
-  size_t len;
 
   for (elem = vpath; *elem; elem = p)
     {
-      for (p = elem; *p && *p != ':'; p++);
-      len = p - elem;
-      copy = XNEWVEC (char, len + 1);
-      memcpy (copy, elem, len);
-      copy[len] = '\0';
+      for (p = elem; *p && *p != ':'; p++)
+       continue;
+      mkdeps::velt elt;
+      elt.len = p - elem;
+      char *str = XNEWVEC (char, elt.len + 1);
+      elt.str = str;
+      memcpy (str, elem, elt.len);
+      str[elt.len] = '\0';
       if (*p == ':')
        p++;
 
-      if (d->nvpaths == d->vpaths_size)
-       {
-         d->vpaths_size = d->vpaths_size * 2 + 8;
-         d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
-         d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
-       }
-      d->vpathv[d->nvpaths] = copy;
-      d->vpathlv[d->nvpaths] = len;
-      d->nvpaths++;
+      d->vpath.push (elt);
     }
 }
 
-void
-deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
-{
-  unsigned int size, i, column;
+/* Write NAME, with a leading space to FP, a Makefile.  Advance COL as
+   appropriate, wrap at COLMAX, returning new column number.  Iff
+   QUOTE apply quoting.  Append TRAIL.  */
 
-  column = 0;
-  if (colmax && colmax < 34)
-    colmax = 34;
+static unsigned
+make_write_name (const char *name, FILE *fp, unsigned col, unsigned colmax,
+                bool quote = true, const char *trail = NULL)
+{
+  if (quote)
+    name = munge (name, trail, NULL);
+  unsigned size = strlen (name);
 
-  for (i = 0; i < d->ntargets; i++)
+  if (col)
     {
-      size = strlen (d->targetv[i]);
-      column += size;
-      if (colmax && column > colmax)
+      if (colmax && col + size> colmax)
        {
-         fputs (" \\\n ", fp);
-         column = 1 + size;
+         fputs (" \\\n", fp);
+         col = 0;
        }
-      if (i)
-       {
-         putc (' ', fp);
-         column++;
-       }
-      fputs (d->targetv[i], fp);
+      col++;
+      fputs (" ", fp);
     }
 
-  putc (':', fp);
-  putc (' ', fp);
-  column += 2;
+  col += size;
+  fputs (name, fp);
 
-  for (i = 0; i < d->ndeps; i++)
-    {
-      size = strlen (d->depv[i]);
-      column += size;
-      if (colmax && column > colmax)
-       {
-         fputs (" \\\n ", fp);
-         column = 1 + size;
-       }
-      if (i)
-       {
-         putc (' ', fp);
-         column++;
-       }
-      fputs (d->depv[i], fp);
-    }
-  putc ('\n', fp);
+  return col;
 }
 
-void
-deps_phony_targets (const struct deps *d, FILE *fp)
+/* Write all the names in VEC via make_write_name.  */
+
+static unsigned
+make_write_vec (const mkdeps::vec<const char *> &vec, FILE *fp,
+               unsigned col, unsigned colmax, unsigned quote_lwm = 0,
+               const char *trail = NULL)
 {
-  unsigned int i;
+  for (unsigned ix = 0; ix != vec.size (); ix++)
+    col = make_write_name (vec[ix], fp, col, colmax, ix >= quote_lwm, trail);
+  return col;
+}
+
+/* Write the dependencies to a Makefile.  If PHONY is true, add
+   .PHONY targets for all the dependencies too.  */
 
-  for (i = 1; i < d->ndeps; i++)
+static void
+make_write (const struct mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
+{
+  unsigned column = 0;
+  if (colmax && colmax < 34)
+    colmax = 34;
+
+  if (d->deps.size ())
     {
-      putc ('\n', fp);
-      fputs (d->depv[i], fp);
-      putc (':', fp);
-      putc ('\n', fp);
+      column = make_write_vec (d->targets, fp, 0, colmax, d->quote_lwm);
+      fputs (":", fp);
+      column++;
+      column = make_write_vec (d->deps, fp, column, colmax);
+      fputs ("\n", fp);
+      if (phony)
+       for (unsigned i = 1; i < d->deps.size (); i++)
+         fprintf (fp, "%s:\n", munge (d->deps[i]));
     }
 }
 
+/* Write out dependencies according to the selected format (which is
+   only Make at the moment).  */
+
+void
+deps_write (const struct mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
+{
+  make_write (d, fp, phony, colmax);
+}
+
 /* Write out a deps buffer to a file, in a form that can be read back
    with deps_restore.  Returns nonzero on error, in which case the
    error number will be in errno.  */
 
 int
-deps_save (struct deps *deps, FILE *f)
+deps_save (struct mkdeps *deps, FILE *f)
 {
   unsigned int i;
+  size_t size;
 
   /* The cppreader structure contains makefile dependences.  Write out this
      structure.  */
 
   /* The number of dependences.  */
-  if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
-      return -1;
+  size = deps->deps.size ();
+  if (fwrite (&size, sizeof (size), 1, f) != 1)
+    return -1;
+
   /* The length of each dependence followed by the string.  */
-  for (i = 0; i < deps->ndeps; i++)
+  for (i = 0; i < deps->deps.size (); i++)
     {
-      size_t num_to_write = strlen (deps->depv[i]);
-      if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
-          return -1;
-      if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
-          return -1;
+      size = strlen (deps->deps[i]);
+      if (fwrite (&size, sizeof (size), 1, f) != 1)
+       return -1;
+      if (fwrite (deps->deps[i], size, 1, f) != 1)
+       return -1;
     }
 
   return 0;
 }
 
 /* Read back dependency information written with deps_save into
-   the deps buffer.  The third argument may be NULL, in which case
+   the deps sizefer.  The third argument may be NULL, in which case
    the dependency information is just skipped, or it may be a filename,
    in which case that filename is skipped.  */
 
 int
-deps_restore (struct deps *deps, FILE *fd, const char *self)
+deps_restore (struct mkdeps *deps, FILE *fd, const char *self)
 {
-  unsigned int i, count;
-  size_t num_to_read;
-  size_t buf_size = 512;
-  char *buf = XNEWVEC (char, buf_size);
+  size_t size;
+  char *buf = NULL;
+  size_t buf_size = 0;
 
   /* Number of dependences.  */
-  if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
+  if (fread (&size, sizeof (size), 1, fd) != 1)
     return -1;
 
   /* The length of each dependence string, followed by the string.  */
-  for (i = 0; i < count; i++)
+  for (unsigned i = size; i--;)
     {
       /* Read in # bytes in string.  */
-      if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
+      if (fread (&size, sizeof (size), 1, fd) != 1)
        return -1;
-      if (buf_size < num_to_read + 1)
+
+      if (size >= buf_size)
        {
-         buf_size = num_to_read + 1 + 127;
+         buf_size = size + 512;
          buf = XRESIZEVEC (char, buf, buf_size);
        }
-      if (fread (buf, 1, num_to_read, fd) != num_to_read)
-       return -1;
-      buf[num_to_read] = '\0';
+      if (fread (buf, 1, size, fd) != size)
+       {
+         XDELETEVEC (buf);
+         return -1;
+       }
+      buf[size] = 0;
 
       /* Generate makefile dependencies from .pch if -nopch-deps.  */
-      if (self != NULL && strcmp (buf, self) != 0)
+      if (self != NULL && filename_cmp (buf, self) != 0)
         deps_add_dep (deps, buf);
     }
 
-  free (buf);
+  XDELETEVEC (buf);
   return 0;
 }