[libcpp] Reimplement mkdeps data structures
authorNathan Sidwell <nathan@acm.org>
Tue, 7 May 2019 12:39:59 +0000 (12:39 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 7 May 2019 12:39:59 +0000 (12:39 +0000)
https://gcc.gnu.org/ml/gcc-patches/2019-05/msg00293.html
* include/mkdeps.h (deps_write): Add PHONY arg.
(deps_phony_targets): Delete.
* init.c (cpp_finish): Just call deps_write.
* mkdeps.c (struct mkdeps): Add local vector class.  Reimplement
vector handling.
(munge): Munge to static buffer.
(apply_vpath): Adjust vector handling.
(deps_init, deps_free): Use new, delete.
(deps_add_target): Do not munge here.  Record quoting low water mark.
(deps_add_dep): Do not munge here.
(deps_add_vpath): Adjust vector handling.
(make_write_name): New.  Munge on demand here.
(make_write_vec): New.
(deps_phony_targets): Delete.
(make_write): New.
(deps_write): Forward to deps_Write.
(deps_save, deps_restore): Adjust vector handling.

From-SVN: r270943

libcpp/ChangeLog
libcpp/include/mkdeps.h
libcpp/init.c
libcpp/mkdeps.c

index 0e3fc56bc02bf2f6ce4b9fa8090cb3de11ada248..df8da71f3297205bd592be8264c27951b77deea1 100644 (file)
@@ -1,3 +1,23 @@
+2019-05-07  Nathan Sidwell  <nathan@acm.org>
+
+       * include/mkdeps.h (deps_write): Add PHONY arg.
+       (deps_phony_targets): Delete.
+       * init.c (cpp_finish): Just call deps_write.
+       * mkdeps.c (struct mkdeps): Add local vector class.  Reimplement
+       vector handling.
+       (munge): Munge to static buffer.
+       (apply_vpath): Adjust vector handling.
+       (deps_init, deps_free): Use new, delete.
+       (deps_add_target): Do not munge here.  Record quoting low water mark.
+       (deps_add_dep): Do not munge here.
+       (deps_add_vpath): Adjust vector handling.
+       (make_write_name): New.  Munge on demand here.
+       (make_write_vec): New.
+       (deps_phony_targets): Delete.
+       (make_write): New.
+       (deps_write): Forward to deps_Write.
+       (deps_save, deps_restore): Adjust vector handling.
+
 2019-05-06  Nathan Sidwell  <nathan@acm.org>
 
        * include/mkdeps.h: Rename struct deps to struct mkdeps.
index b0e34728b5dc83b1b1d53b061bc88fabb5f98ac0..e0ac21f5d076d71694777432c1ec5b306137941a 100644 (file)
@@ -57,7 +57,7 @@ extern void deps_add_dep (struct mkdeps *, const char *);
 
 /* Write out a deps buffer to a specified file.  The third argument
    is the number of columns to word-wrap at (0 means don't wrap).  */
-extern void deps_write (const struct mkdeps *, FILE *, unsigned int);
+extern void deps_write (const struct mkdeps *, FILE *, bool, unsigned int);
 
 /* 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
@@ -70,10 +70,4 @@ extern int deps_save (struct mkdeps *, FILE *);
    in which case that filename is skipped.  */
 extern int deps_restore (struct mkdeps *, FILE *, const char *);
 
-/* For each dependency *except the first*, emit a dummy rule for that
-   file, causing it to depend on nothing.  This is used to work around
-   the intermediate-file deletion misfeature in Make, in some
-   automatic dependency schemes.  */
-extern void deps_phony_targets (const struct mkdeps *, FILE *);
-
 #endif /* ! LIBCPP_MKDEPS_H */
index 60d2588985720e3b68792c60969369d5ce1c183f..c0c9020fdb7fda9578409da518e3cdd6ddae5ff7 100644 (file)
@@ -764,14 +764,9 @@ cpp_finish (cpp_reader *pfile, FILE *deps_stream)
   while (pfile->buffer)
     _cpp_pop_buffer (pfile);
 
-  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE
-      && deps_stream)
-    {
-      deps_write (pfile->deps, deps_stream, 72);
-
-      if (CPP_OPTION (pfile, deps.phony_targets))
-       deps_phony_targets (pfile->deps, deps_stream);
-    }
+  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE && deps_stream)
+    deps_write (pfile->deps, deps_stream,
+               CPP_OPTION (pfile, deps.phony_targets), 72);
 
   /* Report on headers that could use multiple include guards.  */
   if (CPP_OPTION (pfile, print_include_names))
index 3cbd75640aa1747b5255ae62cc0c218c6a412ec5..a9a050cf110434a68bc0afb58a2307c283a9b3d5 100644 (file)
@@ -24,129 +24,184 @@ along with this program; see the file COPYING3.  If not see
 #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 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;
-
-       case '#':
-         /* '#' is quoted with a backslash.  */
-         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
     {
-      switch (*p)
+      return ary[ix];
+    }
+    void push (const T &elt)
+    {
+      if (num == alloc)
        {
-       case ' ':
-       case '\t':
-         for (q = p - 1; filename <= q && *q == '\\';  q--)
-           *dst++ = '\\';
-         *dst++ = '\\';
-         break;
-
-       case '$':
-         *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 mkdeps *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 (!filename_ncmp (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]))
@@ -166,37 +221,13 @@ apply_vpath (struct mkdeps *d, const char *t)
 struct mkdeps *
 deps_init (void)
 {
-  return XCNEW (struct mkdeps);
+  return new mkdeps ();
 }
 
 void
 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
@@ -204,19 +235,14 @@ deps_free (struct mkdeps *d)
 void
 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
@@ -226,7 +252,7 @@ void
 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')
@@ -255,110 +281,106 @@ deps_add_default_target (struct mkdeps *d, const char *tgt)
 void
 deps_add_dep (struct mkdeps *d, const char *t)
 {
-  t = munge (apply_vpath (d, t));  /* Also makes permanent copy.  */
+  t = apply_vpath (d, 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;
+  d->deps.push (xstrdup (t));
 }
 
 void
 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 mkdeps *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 (i)
+      if (colmax && col + size> colmax)
        {
-         if (colmax && column > colmax)
-           {
-             fputs (" \\\n ", fp);
-             column = 1 + size;
-           }
-         else
-           {
-             putc (' ', fp);
-             column++;
-           }
+         fputs (" \\\n", fp);
+         col = 0;
        }
-      fputs (d->targetv[i], fp);
+      col++;
+      fputs (" ", fp);
     }
 
-  putc (':', fp);
-  column++;
+  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;
-       }
-      else
-       {
-         putc (' ', fp);
-         column++;
-       }
-      fputs (d->depv[i], fp);
-    }
-  putc ('\n', fp);
+  return col;
 }
 
-void
-deps_phony_targets (const struct mkdeps *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;
+}
 
-  for (i = 1; i < d->ndeps; i++)
+/* Write the dependencies to a Makefile.  If PHONY is true, add
+   .PHONY targets for all the dependencies too.  */
+
+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.  */
@@ -367,71 +389,69 @@ int
 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 mkdeps *deps, FILE *fd, const char *self)
 {
-  unsigned int i, count;
-  size_t num_to_read;
-  size_t buf_size = 512;
-  char *buf;
+  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;
 
-  buf = XNEWVEC (char, buf_size);
-
   /* 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))
-       {
-         free (buf);
-         return -1;
-       }
-      if (buf_size < num_to_read + 1)
+      if (fread (&size, sizeof (size), 1, fd) != 1)
+       return -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)
+      if (fread (buf, 1, size, fd) != size)
        {
-         free (buf);
+         XDELETEVEC (buf);
          return -1;
        }
-      buf[num_to_read] = '\0';
+      buf[size] = 0;
 
       /* Generate makefile dependencies from .pch if -nopch-deps.  */
       if (self != NULL && filename_cmp (buf, self) != 0)
         deps_add_dep (deps, buf);
     }
 
-  free (buf);
+  XDELETEVEC (buf);
   return 0;
 }