m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

branch-1_4 and frozen files


From: Eric Blake
Subject: branch-1_4 and frozen files
Date: Thu, 22 Jun 2006 22:42:37 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

This patch does two things: It tightens the allowable syntax of frozen files, 
as mentioned here:
http://www.nabble.com/frozen-files-format-2-p4992582.html

And it makes it possible to avoid warnings when loading a frozen file created 
by another version of m4 with more builtins, as mentioned here:
http://www.nabble.com/Re%3A-m4-1.4.4b-problems-p4994425.html

Instead, the warning occurs on use (direct expansion, via indir, or via defn).  
In the common case where a macro present only in the freezing m4 is not later 
used in the remaining input of the reloading m4 (ie. since autoconf doesn't try 
to use the symbols builtin of m4-1.4o or the changeword builtin of m4-1.4.x), 
this allows reloading to operate warning free in spite of the unknown builtin.  
Tested by installing m4 with changeword turned on, installing autoconf (which 
freezes files with changeword in them), then reconfiguring m4 to not use 
changeword, then rebootstrapping using the changed m4.  Before my patch, the 
bootstrap failed because m4sugar treats the warning about changeword being 
unknown as fatal; after the patch the bootstrap worked just fine, especially 
nice since m4's configure.ac does an ifdef test on changeword.  Also tested by 
manually editing a frozen file to experiment with intentional mention of a bad 
builtin name.

Patch is generated with -b, because of the amount of reindentation in freeze.c.

2006-06-22  Eric Blake  <address@hidden>

        Robustify frozen file format.
        * src/freeze.c (reload_frozen_state): Add GET_DIRECTIVE helper
        macro.  Require V first, and only accept it once.  For F, use
        placeholder if builtin is not found, rather than warning.
        * src/m4.h (m4_placeholder): New prototype.
        * src/builtin.c: Unify error message style.
        (m4_placeholder): New function, warn if invoked.
        (builtin_tab): Add m4_placeholder.
        (m4_defn): Warn if placeholder is encountered.
        (find_builtin_by_addr): Handle placeholder.
        (find_builtin_by_name): Return placeholder on failure.
        (m4_builtin): Treat placeholder as undefined.
        * doc/m4.texinfo (Frozen files): Document changes in V and F.
        * NEWS: Document this change.
        Reported by Bruno Haible.

Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.23
diff -u -b -r1.1.1.1.2.23 NEWS
--- NEWS        22 Jun 2006 14:55:48 -0000      1.1.1.1.2.23
+++ NEWS        22 Jun 2006 22:34:37 -0000
@@ -8,6 +8,13 @@
   in the low-order byte.
 * The maketemp macro is no longer subject to platform limitations (such as
   26 or 32 max files from a given template).
+* Frozen files now require that the first directive be V (version), to
+  better diagnose version mismatch.  Additionally, if the F directive
+  (builtin function) names an unknown builtin that existed in the m4 that
+  froze the file but not in the current m4 (for example, changeword), the
+  warning is deferred until an attempt is made to actually use the builtin.
+  This allows downgrading from beta m4-1.4o to m4-1.4.5 without breaking
+  autoconf.
 
 Version 1.4.4b - 17 June 2006, by Eric Blake  (CVS version 1.4.4a)
 
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.22
diff -u -b -r1.1.1.1.2.22 m4.texinfo
--- doc/m4.texinfo      22 Jun 2006 17:49:18 -0000      1.1.1.1.2.22
+++ doc/m4.texinfo      22 Jun 2006 22:34:37 -0000
@@ -3418,7 +3418,10 @@
 
 @table @code
 @item V @var{number} @key{NL}
-Confirms the format of the file.  @var{number} should be 1.
+Confirms the format of the file.  @code{m4} @value{VERSION} only creates
+and understands frozen files where @var{number} is 1.  This directive
+must be the first non-comment in the file, and may not appear more than
+once.
 
 @item C @var{length1} , @var{length2} @key{NL} @var{string1} @var{string2} @key
{NL}
 Uses @var{string1} and @var{string2} as the beginning comment and
@@ -3430,7 +3433,12 @@
 
 @item F @var{length1} , @var{length2} @key{NL} @var{string1} @var{string2} @key
{NL}
 Defines, through @code{pushdef}, a definition for @var{string1}
-expanding to the function whose builtin name is @var{string2}.
+expanding to the function whose builtin name is @var{string2}.  If the
+builtin does not exist (for example, if the frozen file was produced by
+a copy of @code{m4} compiled with changeword support, but the version
+of @code{m4} reloading was compiled without it), the reload is silent,
+but any subsequent use of the definition of @var{string1} will result in
+a warning.
 
 @item T @var{length1} , @var{length2} @key{NL} @var{string1} @var{string2} @key
{NL}
 Defines, though @code{pushdef}, a definition for @var{string1}
Index: src/builtin.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/builtin.c,v
retrieving revision 1.1.1.1.2.12
diff -u -b -r1.1.1.1.2.12 builtin.c
--- src/builtin.c       18 Jun 2006 21:31:56 -0000      1.1.1.1.2.12
+++ src/builtin.c       22 Jun 2006 22:34:37 -0000
@@ -138,6 +138,11 @@
   { "undivert",                FALSE,  FALSE,  FALSE,  m4_undivert },
 
   { 0,                 FALSE,  FALSE,  FALSE,  0 },
+
+  /* placeholder is intentionally stuck after the table end delimiter,
+     so that we can easily find it, while not treating it as a real
+     builtin.  */
+  { "placeholder",     TRUE,   FALSE,  FALSE,  m4_placeholder },
 };
 
 static predefined const
@@ -161,12 +166,15 @@
   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
     if (bp->func == func)
       return bp;
+  if (func == m4_placeholder)
+    return bp + 1;
   return NULL;
 }
 
-/*-----------------------------------.
-| Find the builtin, which has NAME.  |
-`-----------------------------------*/
+/*----------------------------------------------------------.
+| Find the builtin, which has NAME.  On failure, return the |
+| placeholder builtin.                                      |
+`----------------------------------------------------------*/
 
 const builtin *
 find_builtin_by_name (const char *name)
@@ -176,7 +184,7 @@
   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
     if (strcmp (bp->name, name) == 0)
       return bp;
-  return NULL;
+  return bp + 1;
 }
 
 /*-------------------------------------------------------------------------.
@@ -272,13 +280,13 @@
     {
       if (!suppress_warnings)
        M4ERROR ((warning_status, 0,
-                 "Warning: Too few arguments to builtin `%s'",
+                 "Warning: too few arguments to builtin `%s'",
                  TOKEN_DATA_TEXT (name)));
       isbad = TRUE;
     }
   else if (max > 0 && argc > max && !suppress_warnings)
     M4ERROR ((warning_status, 0,
-             "Warning: Excess arguments to builtin `%s' ignored",
+             "Warning: excess arguments to builtin `%s' ignored",
              TOKEN_DATA_TEXT (name)));
 
   return isbad;
@@ -298,7 +306,7 @@
   if (*arg == 0 || (*valuep = strtol (arg, &endp, 10), *endp != 0))
     {
       M4ERROR ((warning_status, 0,
-               "Non-numeric argument to builtin `%s'",
+               "non-numeric argument to builtin `%s'",
                TOKEN_DATA_TEXT (macro)));
       return FALSE;
     }
@@ -438,7 +446,7 @@
 
     default:
       M4ERROR ((warning_status, 0,
-               "INTERNAL ERROR: Bad token data type in define_macro ()"));
+               "INTERNAL ERROR: bad token data type in define_macro ()"));
       abort ();
     }
   return;
@@ -608,7 +616,7 @@
            dump_symbol (s, &data);
          else
            M4ERROR ((warning_status, 0,
-                     "Undefined name %s", TOKEN_DATA_TEXT (argv[i])));
+                     "undefined macro `%s'", TOKEN_DATA_TEXT (argv[i])));
        }
     }
 
@@ -637,7 +645,7 @@
          if (bp == NULL)
            {
              M4ERROR ((warning_status, 0, "\
-INTERNAL ERROR: Builtin not found in builtin table!"));
+INTERNAL ERROR: builtin not found in builtin table"));
              abort ();
            }
          DEBUG_PRINT1 ("<%s>\n", bp->name);
@@ -645,7 +653,7 @@
 
        default:
          M4ERROR ((warning_status, 0,
-                   "INTERNAL ERROR: Bad token data type in m4_dumpdef ()"));
+                   "INTERNAL ERROR: bad token data type in m4_dumpdef ()"));
          abort ();
          break;
        }
@@ -669,9 +677,9 @@
     return;
 
   bp = find_builtin_by_name (name);
-  if (bp == NULL)
+  if (bp->func == m4_placeholder)
     M4ERROR ((warning_status, 0,
-             "Undefined name %s", name));
+             "undefined builtin `%s'", name));
   else
     (*bp->func) (obs, argc - 1, argv + 1);
 }
@@ -695,7 +703,7 @@
   s = lookup_symbol (name, SYMBOL_LOOKUP);
   if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
     M4ERROR ((warning_status, 0,
-             "Undefined macro `%s'", name));
+             "undefined macro `%s'", name));
   else
     call_macro (s, argc - 1, argv + 1, obs);
 }
@@ -710,6 +718,7 @@
 m4_defn (struct obstack *obs, int argc, token_data **argv)
 {
   symbol *s;
+  builtin_func *b;
 
   if (bad_argc (argv[0], argc, 2, 2))
     return;
@@ -727,7 +736,12 @@
       break;
 
     case TOKEN_FUNC:
-      push_macro (SYMBOL_FUNC (s));
+      b = SYMBOL_FUNC (s);
+      if (b == m4_placeholder)
+        M4ERROR ((warning_status, 0, "\
+builtin `%s' requested by frozen file is not supported", ARG (1)));
+      else
+        push_macro (b);
       break;
 
     case TOKEN_VOID:
@@ -735,7 +749,7 @@
 
     default:
       M4ERROR ((warning_status, 0,
-               "INTERNAL ERROR: Bad symbol type in m4_defn ()"));
+               "INTERNAL ERROR: bad symbol type in m4_defn ()"));
       abort ();
     }
 }
@@ -777,7 +791,7 @@
   if (pin == NULL)
     {
       M4ERROR ((warning_status, errno,
-               "Cannot open pipe to command \"%s\"", ARG (1)));
+               "cannot open pipe to command \"%s\"", ARG (1)));
       sysval = 0xffff;
     }
   else
@@ -816,7 +830,8 @@
   if (radix <= 1 || radix > (int) strlen (digits))
     {
       M4ERROR ((warning_status, 0,
-               "Radix in eval out of range (radix = %d)", radix));
+               "radix in builtin `%s' out of range (radix = %d)",
+                ARG (0), radix));
       return;
     }
 
@@ -825,7 +840,7 @@
   if  (min <= 0)
     {
       M4ERROR ((warning_status, 0,
-               "Negative width to eval"));
+               "negative width to builtin `%s'", ARG (0)));
       return;
     }
 
@@ -930,7 +945,7 @@
          insert_diversion (file);
        else if (no_gnu_extensions)
          M4ERROR ((warning_status, 0,
-                   "Non-numeric argument to %s", TOKEN_DATA_TEXT (argv[0])));
+                   "non-numeric argument to builtin `%s'", ARG (0)));
        else
          {
            fp = path_search (ARG (i));
@@ -941,7 +956,7 @@
              }
            else
              M4ERROR ((warning_status, errno,
-                       "Cannot undivert %s", ARG (i)));
+                       "cannot undivert `%s'", ARG (i)));
          }
       }
 }
@@ -1047,7 +1062,7 @@
     {
       if (!silent)
        M4ERROR ((warning_status, errno,
-                 "Cannot open %s", ARG (1)));
+                 "cannot open `%s'", ARG (1)));
       return;
     }
 
@@ -1090,7 +1105,8 @@
   errno = 0;
   if ((fd = mkstemp (ARG (1))) < 0)
     {
-      M4ERROR ((warning_status, errno, "Cannot create tempfile %s", ARG (1)));
+      M4ERROR ((warning_status, errno, "cannot create tempfile `%s'",
+                ARG (1)));
       return;
     }
   close(fd);
@@ -1291,7 +1307,7 @@
     debug_set_output (NULL);
   else if (!debug_set_output (ARG (1)))
     M4ERROR ((warning_status, errno,
-             "Cannot set error file: %s", ARG (1)));
+             "cannot set error file: `%s'", ARG (1)));
 }
 
 /* This section contains text processing macros: "len", "index",
@@ -1573,7 +1589,7 @@
   if (msg != NULL)
     {
       M4ERROR ((warning_status, 0,
-               "Bad regular expression: `%s': %s", regexp, msg));
+               "bad regular expression: `%s': %s", regexp, msg));
       return;
     }
 
@@ -1584,7 +1600,7 @@
   if (startpos  == -2)
     {
       M4ERROR ((warning_status, 0,
-               "Error matching regular expression \"%s\"", regexp));
+               "error matching regular expression \"%s\"", regexp));
       return;
     }
 
@@ -1633,7 +1649,7 @@
   if (msg != NULL)
     {
       M4ERROR ((warning_status, 0,
-               "Bad regular expression `%s': %s", regexp, msg));
+               "bad regular expression `%s': %s", regexp, msg));
       if (buf.buffer != NULL)
        xfree (buf.buffer);
       return;
@@ -1657,7 +1673,7 @@
 
          if (matchpos == -2)
            M4ERROR ((warning_status, 0,
-                     "Error matching regular expression \"%s\"", regexp));
+                     "error matching regular expression \"%s\"", regexp));
          else if (offset < length)
            obstack_grow (obs, victim + offset, length - offset);
          break;
@@ -1686,6 +1702,28 @@
   return;
 }
 
+/* Finally, a placeholder builtin.  This builtin is not installed by
+   default, but when reading back frozen files, this is associated
+   with any builtin we don't recognize (for example, if the frozen
+   file was created with a changeword capable m4, but is then loaded
+   by a different m4 that does not support changeword).  This way, we
+   can keep 'm4 -R' quiet in the common case that the user did not
+   know or care about the builtin when the frozen file was created,
+   while still flagging it as a potential error if an attempt is made
+   to actually use the builtin.  */
+
+/*--------------------------------------------------------------------.
+| Issue a warning that this macro is a placeholder for an unsupported |
+| builtin that was requested while reloading a frozen file.           |
+`--------------------------------------------------------------------*/
+
+void
+m4_placeholder (struct obstack *obs, int argc, token_data **argv)
+{
+  M4ERROR ((warning_status, 0, "\
+builtin `%s' requested by frozen file is not supported", ARG (0)));
+}
+
 /*-------------------------------------------------------------------------.
 | This function handles all expansion of user defined and predefined      |
 | macros.  It is called with an obstack OBS, where the macros expansion
           |
Index: src/freeze.c
===================================================================
RCS file: /sources/m4/m4/src/freeze.c,v
retrieving revision 1.1.1.1.2.5
diff -u -b -r1.1.1.1.2.5 freeze.c
--- src/freeze.c        15 Jun 2006 21:29:16 -0000      1.1.1.1.2.5
+++ src/freeze.c        22 Jun 2006 22:34:37 -0000
@@ -211,6 +211,22 @@
     }                                                          \
   while (0)
 
+  /* Skip comments (`#' at beginning of line) and blank lines, setting
+     character to the next directive or to EOF.  */
+
+#define GET_DIRECTIVE \
+  do                                                            \
+    {                                                           \
+      GET_CHARACTER;                                            \
+      if (character == '#')                                     \
+        {                                                       \
+          while (character != EOF && character != '\n')         \
+            GET_CHARACTER;                                      \
+          VALIDATE ('\n');                                      \
+        }                                                       \
+    }                                                           \
+  while (character == '\n')
+
   file = path_search (name);
   if (file == NULL)
     M4ERROR ((EXIT_FAILURE, errno, "Cannot open %s", name));
@@ -220,28 +236,22 @@
   allocated[1] = 100;
   string[1] = xmalloc ((size_t) allocated[1]);
 
-  while (GET_CHARACTER, character != EOF)
+  /* Validate format version.  Only `1' is acceptable for now.  */
+  GET_DIRECTIVE;
+  VALIDATE ('V');
+  GET_CHARACTER;
+  VALIDATE ('1');
+  GET_CHARACTER;
+  VALIDATE ('\n');
+
+  GET_DIRECTIVE;
+  while (character != EOF)
+    {
     switch (character)
       {
       default:
        M4ERROR ((EXIT_FAILURE, 0, "Ill-formed frozen file"));
 
-      case '\n':
-
-       /* Skip empty lines.  */
-
-       break;
-
-      case '#':
-
-       /* Comments are introduced by `#' at beginning of line, and are
-          ignored.  */
-
-       while (character != EOF && character != '\n')
-         GET_CHARACTER;
-       VALIDATE ('\n');
-       break;
-
       case 'C':
       case 'D':
       case 'F':
@@ -326,12 +336,7 @@
            /* Enter a macro having a builtin function as a definition.  */
 
            bp = find_builtin_by_name (string[1]);
-           if (bp)
              define_builtin (string[0], bp, SYMBOL_PUSHDEF);
-           else
-             M4ERROR ((warning_status, 0, "\
-`%s' from frozen file not found in builtin table!",
-                       string[0]));
            break;
 
          case 'T':
@@ -356,16 +361,8 @@
          }
        break;
 
-      case 'V':
-
-       /* Validate format version.  Only `1' is acceptable for now.  */
-
-       GET_CHARACTER;
-       VALIDATE ('1');
-       GET_CHARACTER;
-       VALIDATE ('\n');
-       break;
-
+        }
+      GET_DIRECTIVE;
       }
 
   free (string[0]);
@@ -373,6 +370,7 @@
   fclose (file);
 
 #undef GET_CHARACTER
+#undef GET_DIRECTIVE
 #undef GET_NUMBER
 #undef VALIDATE
 }
Index: src/m4.h
===================================================================
RCS file: /sources/m4/m4/src/m4.h,v
retrieving revision 1.1.1.1.2.11
diff -u -b -r1.1.1.1.2.11 m4.h
--- src/m4.h    22 Jun 2006 17:43:05 -0000      1.1.1.1.2.11
+++ src/m4.h    22 Jun 2006 22:34:37 -0000
@@ -439,6 +439,7 @@
 void define_user_macro _((const char *, const char *, symbol_lookup));
 void undivert_all _((void));
 void expand_user_macro _((struct obstack *, symbol *, int, token_data **));
+void m4_placeholder _((struct obstack *, int, token_data **));
 
 const builtin *find_builtin_by_addr _((builtin_func *));
 const builtin *find_builtin_by_name _((const char *));






reply via email to

[Prev in Thread] Current Thread [Next in Thread]