m4-patches
[Top][All Lists]
Advanced

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

Re: rfc: new __program__ macro


From: Eric Blake
Subject: Re: rfc: new __program__ macro
Date: Fri, 04 Aug 2006 07:18:45 -0600
User-agent: Thunderbird 1.5.0.5 (Windows/20060719)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Gary,

According to Gary V. Vaughan on 8/4/2006 2:50 AM:
> Hi Eric,
> 
> Eric Blake wrote:
>> Would it be worth adding __program__ macro, to go along with __file__ and
>> __line__, which expands to argv[0] in the same manner that error messages
>> do?  That way, if a user invokes m4 via a symlink or absolute path, rather
>> than through their PATH, they can match internal m4 messages.  They can
>> also use that information to invoke a sub-m4 in syscmd using the same
>> version of m4 currently running, rather than picking up an arbitrary m4
>> from PATH.
> 
> Yes, I think that is an excellent idea.

With that recommendation, branch-1_4 now follows GNU Coding Standards in
its error messages.

Man, I wish I could get glibc to provide a va_list variant of
error/error_at_line (I'm in the process of proposing that, trying to bring
gnulib and glibc back in sync and fix other bugs in the error.c module).
Without it, and due to the fact that error_print_progname takes no
arguments, I have to use the relatively gross hack of another global
variable that tells the callback whether it was invoked from error or
error_at_line.

2006-08-04  Eric Blake  <address@hidden>

        * src/m4.h (program_name): Declare.
        (suppress_line): New variable.
        (M4ERROR_AT_LINE): New macro.
        * src/m4.c (reference_error, main): Follow GNU Coding Standards
        for error message format.
        * src/input.c (skip_line, next_token): Use M4ERROR_AT_LINE.
        * src/macro.c (expand_argument): Likewise.
        * checks/check-them (examples): Adjust to new message format.
        * src/builtin.c (m4___program__): New builtin.
        * doc/m4.texinfo (Location): Split from Errprint into new node,
        and document __program__.
        (Builtin, Ifdef, Ifelse, Dumpdef, Trace, Debug Output, Dnl)
        (Include, Regexp, Patsubst, Incr, Eval): Adjust error message
        format.
        (Extensions): Document __program__.
        * NEWS: Document this change.

- --
Life is short - so eat dessert first!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFE00k084KuGfSFAYARAhNmAJ48td8V2S9nfJ0D8YTdsQn0vwzUzACg1JsV
AS9v4xjFMxJ+JN3Ej8fgroI=
=Ylh0
-----END PGP SIGNATURE-----
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.48
diff -u -p -r1.1.1.1.2.48 NEWS
--- NEWS        3 Aug 2006 13:31:40 -0000       1.1.1.1.2.48
+++ NEWS        4 Aug 2006 13:16:26 -0000
@@ -25,6 +25,9 @@ Version 1.4.6 - ?? 2006, by ??  (CVS ver
 * The changequote and changecom macros now work with 8-bit characters, and
   quotes and strings that begin with `(' are properly recognized following
   a word.
+* The new macro __program__ is added, which allows the input file to issue
+  an error message that resembles messages from m4.  Warning and error
+  messages have been reformatted to comply with GNU Coding Standards.
 
 Version 1.4.5 - 15 July 2006, by Eric Blake  (CVS version 1.4.4c)
 
Index: checks/check-them
===================================================================
RCS file: /sources/m4/m4/checks/Attic/check-them,v
retrieving revision 1.1.1.1.2.9
diff -u -p -r1.1.1.1.2.9 check-them
--- checks/check-them   30 Jul 2006 21:46:10 -0000      1.1.1.1.2.9
+++ checks/check-them   4 Aug 2006 13:16:26 -0000
@@ -66,7 +66,7 @@ do
     diff $xout $out
   fi
 
-  sed -e '/^dnl @error{}/!d' -e 's///' -e "s| m4:| $m4:|" "$file" > $xerr
+  sed -e '/^dnl @error{}/!d' -e 's///' -e "s|^m4:|$m4:|" "$file" > $xerr
 
   if cmp -s $err $xerr; then
     :
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.60
diff -u -p -r1.1.1.1.2.60 m4.texinfo
--- doc/m4.texinfo      3 Aug 2006 13:31:40 -0000       1.1.1.1.2.60
+++ doc/m4.texinfo      4 Aug 2006 13:16:27 -0000
@@ -234,6 +234,7 @@ Running shell commands
 Miscellaneous builtin macros
 
 * Errprint::                    Printing error messages
+* Location::                    Printing current location
 * M4exit::                      Exiting from m4
 
 Fast loading of frozen state
@@ -1680,13 +1681,13 @@ provoke a warning, and result in a void 
 builtin
 @result{}builtin
 builtin()
address@hidden:2: m4: undefined builtin `'
address@hidden:stdin:2: undefined builtin `'
 @result{}
 builtin(`builtin')
address@hidden:3: m4: Warning: too few arguments to builtin `builtin'
address@hidden:stdin:3: Warning: too few arguments to builtin `builtin'
 @result{}
 builtin(`builtin',)
address@hidden:4: m4: undefined builtin `'
address@hidden:stdin:4: undefined builtin `'
 @result{}
 @end example
 
@@ -1729,7 +1730,7 @@ define(`foo', `')
 ifdef(`foo', ``foo' is defined', ``foo' is not defined')
 @result{}foo is defined
 ifdef(`no_such_macro', `yes', `no', `extra argument')
address@hidden:4: m4: Warning: excess arguments to builtin `ifdef' ignored
address@hidden:stdin:4: Warning: excess arguments to builtin `ifdef' ignored
 @result{}no
 @end example
 
@@ -1770,7 +1771,7 @@ case, the warning about missing argument
 ifelse(`some comments')
 @result{}
 ifelse(`foo', `bar')
address@hidden:2: m4: Warning: too few arguments to builtin `ifelse'
address@hidden:stdin:2: Warning: too few arguments to builtin `ifelse'
 @result{}
 @end example
 
@@ -2005,7 +2006,7 @@ f(popdef(`f')dumpdef(`f'))
 @error{}f:@tabchar{}``$0'1'
 @result{}f2
 f(popdef(`f')dumpdef(`f'))
address@hidden:3: m4: undefined macro `f'
address@hidden:stdin:3: undefined macro `f'
 @result{}f1
 @end example
 
@@ -2078,7 +2079,7 @@ undefine(`foo')
 ifdef(`foo', `yes', `no')
 @result{}no
 indir(`foo')
address@hidden:8: m4: undefined macro `foo'
address@hidden:stdin:8: undefined macro `foo'
 @result{}
 define(`foo', `blah')
 @result{}
@@ -2235,13 +2236,13 @@ The expansion of @code{debugfile} is voi
 traceon(`divnum')
 @result{}
 divnum(`extra')
address@hidden:2: m4: Warning: excess arguments to builtin `divnum' ignored
address@hidden:stdin:2: Warning: excess arguments to builtin `divnum' ignored
 @error{}m4trace: -1- divnum(`extra') -> `0'
 @result{}0
 debugfile()
 @result{}
 divnum(`extra')
address@hidden:4: m4: Warning: excess arguments to builtin `divnum' ignored
address@hidden:stdin:4: Warning: excess arguments to builtin `divnum' ignored
 @result{}0
 debugfile
 @result{}
@@ -2301,7 +2302,7 @@ next newline, on whatever line containin
 @example
 dnl(`args are ignored, but side effects occur',
 define(`foo', `like this')) while this text is ignored: undefine(`foo')
address@hidden:2: m4: Warning: excess arguments to builtin `dnl' ignored
address@hidden:stdin:2: Warning: excess arguments to builtin `dnl' ignored
 See how `foo' was defined, foo?
 @result{}See how foo was defined, like this?
 @end example
@@ -2879,10 +2880,10 @@ parameters.
 @example
 include(`none')
 @result{}
address@hidden:1: m4: cannot open `none': No such file or directory
address@hidden:stdin:1: cannot open `none': No such file or directory
 include()
 @result{}
address@hidden:2: m4: cannot open `': No such file or directory
address@hidden:stdin:2: cannot open `': No such file or directory
 sinclude(`none')
 @result{}
 sinclude()
@@ -3333,8 +3334,8 @@ Here are some more examples on the handl
 regexp(`abc', `\(b\)', `\\\10\a')
 @result{}\b0a
 regexp(`abc', `b', `\1\')
address@hidden:2: m4: Warning: sub-expression 1 not present
address@hidden:2: m4: Warning: trailing \ ignored in replacement
address@hidden:stdin:2: Warning: sub-expression 1 not present
address@hidden:stdin:2: Warning: trailing \ ignored in replacement
 @result{}
 @end example
 
@@ -3455,7 +3456,7 @@ patsubst(`GNUs not Unix', `\w+', `(\&)')
 patsubst(`GNUs not Unix', `[A-Z][a-z]+')
 @result{}GN not @comment
 patsubst(`GNUs not Unix', `not', `NOT\')
address@hidden:6: m4: Warning: trailing \ ignored in replacement
address@hidden:stdin:6: Warning: trailing \ ignored in replacement
 @result{}GNUs NOT Unix
 @end example
 
@@ -3603,10 +3604,10 @@ incr(`4')
 decr(`7')
 @result{}6
 incr()
address@hidden:3: m4: empty string treated as 0 in builtin `incr'
address@hidden:stdin:3: empty string treated as 0 in builtin `incr'
 @result{}1
 decr()
address@hidden:4: m4: empty string treated as 0 in builtin `decr'
address@hidden:stdin:4: empty string treated as 0 in builtin `decr'
 @result{}-1
 @end example
 
@@ -3705,7 +3706,7 @@ square(square(`5')`+1')
 define(`foo', `666')
 @result{}
 eval(`foo/6')
address@hidden:8: m4: bad expression in eval: foo/6
address@hidden:stdin:8: bad expression in eval: foo/6
 @result{}
 eval(foo/6)
 @result{}111
@@ -4047,6 +4048,7 @@ any of the previous chapters.
 
 @menu
 * Errprint::                    Printing error messages
+* Location::                    Printing current location
 * M4exit::                      Exiting from m4
 @end menu
 
@@ -4078,17 +4080,22 @@ implementations of @code{m4} do append a
 @code{errprint} call, while some other implementations only print the
 first argument.
 
-To make it possible to specify the location of the error, two
address@hidden Location
address@hidden Printing current location
+
+To make it possible to specify the location of an error, three
 utility builtins exist:
 
 @deffn Builtin __file__
 @deffnx Builtin __line__
-Expand to the quoted name of the current input file, and the
-current input line number in that file.
address@hidden Builtin __program__
+Expand to the quoted name of the current input file, the
+current input line number in that file, and the quoted name of the
+current invocation of @code{m4}.
 @end deffn
 
 @example
-errprint(`m4:'__file__:__line__: `input error
+errprint(__program__:__file__:__line__: `input error
 ')
 @error{}m4:stdin:1: input error
 @result{}
@@ -4119,6 +4126,16 @@ as though it came from line 0 of the fil
 future release of @code{m4} can overcome this limitation and remember
 which file invoked the call to @code{m4wrap}.
 
+The @code{__program__} macro behaves like @samp{$0} in shell
+terminology.  If you invoke @code{m4} through an absolute path or a link
+with a different spelling, rather than by relying on a @env{PATH} search
+for plain @samp{m4}, it will affect how @code{__program__} expands.  The
+intent is that you can use it to produce error messages with the same
+formatting that @code{m4} produces internally.  It can also be used
+within @code{syscmd} (@pxref{Syscmd}) to pick the same version of
address@hidden that is currently running, rather than whatever version of
address@hidden happens to be first in @env{PATH}.
+
 @node M4exit
 @section Exiting from @code{m4}
 
@@ -4144,7 +4161,7 @@ resulting string to standard error.
 
 @example
 define(`fatal_error',
-       `errprint(`m4:'__file__:__line__`: fatal error: $*
+       `errprint(__program__:__file__:__line__`: fatal error: $*
 ')m4exit(`1')')
 @result{}
 fatal_error(`this is a BAD one, buster')
@@ -4450,9 +4467,9 @@ There is indirect access to any builtin 
 Macros can be called indirectly through @code{indir} (@pxref{Indir}).
 
 @item
-The name of the current input file and the current input line number are
-accessible through the builtins @code{__file__} and @code{__line__}
-(@pxref{Errprint}).
+The name of the program, the current input file, and the current input
+line number are accessible through the builtins @code{__program__},
address@hidden, and @code{__line__} (@pxref{Location}).
 
 @item
 The format of the output from @code{dumpdef} and macro tracing can be
Index: src/builtin.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/builtin.c,v
retrieving revision 1.1.1.1.2.30
diff -u -p -r1.1.1.1.2.30 builtin.c
--- src/builtin.c       30 Jul 2006 23:46:51 -0000      1.1.1.1.2.30
+++ src/builtin.c       4 Aug 2006 13:16:27 -0000
@@ -43,6 +43,7 @@ extern FILE *popen ();
 
 DECLARE (m4___file__);
 DECLARE (m4___line__);
+DECLARE (m4___program__);
 DECLARE (m4_builtin);
 DECLARE (m4_changecom);
 DECLARE (m4_changequote);
@@ -97,6 +98,7 @@ builtin_tab[] =
 
   { "__file__",                TRUE,   FALSE,  FALSE,  m4___file__ },
   { "__line__",                TRUE,   FALSE,  FALSE,  m4___line__ },
+  { "__program__",     TRUE,   FALSE,  FALSE,  m4___program__ },
   { "builtin",         TRUE,   FALSE,  TRUE,   m4_builtin },
   { "changecom",       FALSE,  FALSE,  FALSE,  m4_changecom },
   { "changequote",     FALSE,  FALSE,  FALSE,  m4_changequote },
@@ -1192,8 +1194,8 @@ m4_sinclude (struct obstack *obs, int ar
   include (argc, argv, TRUE);
 }
 
-/* More miscellaneous builtins -- "maketemp", "errprint", "__file__" and
-   "__line__".  The last two are GNU specific.  */
+/* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
+   "__line__", and "__program__".  The last three are GNU specific.  */
 
 /*------------------------------------------------------------------.
 | Use the first argument as at template for a temporary file name.  |
@@ -1246,6 +1248,16 @@ m4___line__ (struct obstack *obs, int ar
     return;
   shipout_int (obs, current_line);
 }
+
+static void
+m4___program__ (struct obstack *obs, int argc, token_data **argv)
+{
+  if (bad_argc (argv[0], argc, 1, 1))
+    return;
+  obstack_grow (obs, lquote.string, lquote.length);
+  obstack_grow (obs, program_name, strlen (program_name));
+  obstack_grow (obs, rquote.string, rquote.length);
+}
 
 /* This section contains various macros for exiting, saving input until
    EOF is seen, and tracing macro calls.  That is: "m4exit", "m4wrap",
Index: src/input.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/input.c,v
retrieving revision 1.1.1.1.2.17
diff -u -p -r1.1.1.1.2.17 input.c
--- src/input.c 3 Aug 2006 13:31:40 -0000       1.1.1.1.2.17
+++ src/input.c 4 Aug 2006 13:16:27 -0000
@@ -537,8 +537,8 @@ skip_line (void)
   if (ch == CHAR_EOF)
     /* current_file changed to "NONE" if we see CHAR_EOF, use the
        previous value we stored earlier.  */
-    error_at_line (warning_status, 0, file, line,
-                  "Warning: end of file treated as newline");
+    M4ERROR_AT_LINE ((warning_status, 0, file, line,
+                     "Warning: end of file treated as newline"));
 }
 
 
@@ -808,8 +808,8 @@ next_token (token_data *td)
       else
        /* current_file changed to "NONE" if we see CHAR_EOF, use the
           previous value we stored earlier.  */
-       error_at_line (EXIT_FAILURE, 0, file, line,
-                      "ERROR: end of file in comment");
+       M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, line,
+                         "ERROR: end of file in comment"));
 
       type = TOKEN_STRING;
     }
@@ -890,8 +890,8 @@ next_token (token_data *td)
          if (ch == CHAR_EOF)
            /* current_file changed to "NONE" if we see CHAR_EOF, use
               the previous value we stored earlier.  */
-           error_at_line (EXIT_FAILURE, 0, file, line,
-                          "ERROR: end of file in string");
+           M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, line,
+                             "ERROR: end of file in string"));
 
          if (MATCH (ch, rquote.string, TRUE))
            {
Index: src/m4.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/m4.c,v
retrieving revision 1.1.1.1.2.24
diff -u -p -r1.1.1.1.2.24 m4.c
--- src/m4.c    30 Jul 2006 23:46:51 -0000      1.1.1.1.2.24
+++ src/m4.c    4 Aug 2006 13:16:27 -0000
@@ -86,18 +86,27 @@ typedef struct macro_definition macro_de
 
 /* Error handling functions.  */
 
-/*-------------------------------------------------------------------------.
-| Print source and line reference on standard error, as a prefix for error |
-| messages.  Flush standard output first.                                 |
-`-------------------------------------------------------------------------*/
+/* TRUE if error_at_line was called.  Too bad the error module doesn't
+   let us pass a parameter to the callback, or take a va_list
+   argument.  */
+boolean suppress_line;
+
+/*---------------------------------------------------------------.
+| Callback used by error to print program name, source, and line |
+| reference.                                                    |
+`---------------------------------------------------------------*/
 
 void
 reference_error (void)
 {
-  int e = errno;
-  fflush (stdout);
-  fprintf (stderr, "%s:%d: ", current_file, current_line);
-  errno = e;
+  /* error already flushed stdout before calling us.  */
+  if (suppress_line)
+    {
+      fprintf (stderr, "%s:", program_name);
+      suppress_line = FALSE;
+    }
+  else
+    fprintf (stderr, "%s:%s:%d: ", program_name, current_file, current_line);
 }
 
 #ifdef USE_STACKOVF
@@ -269,6 +278,7 @@ main (int argc, char *const *argv, char 
   FILE *fp;
 
   program_name = argv[0];
+  error_print_progname = reference_error;
   retcode = EXIT_SUCCESS;
 
   include_init ();
Index: src/m4.h
===================================================================
RCS file: /sources/m4/m4/src/m4.h,v
retrieving revision 1.1.1.1.2.24
diff -u -p -r1.1.1.1.2.24 m4.h
--- src/m4.h    3 Aug 2006 13:31:40 -0000       1.1.1.1.2.24
+++ src/m4.h    4 Aug 2006 13:16:27 -0000
@@ -90,6 +90,18 @@ typedef struct string STRING;
 /* Those must come first.  */
 typedef struct token_data token_data;
 typedef void builtin_func (struct obstack *, int, token_data **);
+
+/* Take advantage of GNU C compiler source level optimization hints,
+   using portable macros.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
+#  define M4_GNUC_ATTRIBUTE(args)      __attribute__(args)
+#else
+#  define M4_GNUC_ATTRIBUTE(args)
+#endif  /* __GNUC__ */
+
+#define M4_GNUC_UNUSED         M4_GNUC_ATTRIBUTE((__unused__))
+#define M4_GNUC_PRINTF(fmt, arg)                       \
+  M4_GNUC_ATTRIBUTE((__format__ (__printf__, fmt, arg)))
 
 /* File: m4.c  --- global definitions.  */
 
@@ -109,9 +121,32 @@ extern const char *user_word_regexp;       /* 
 
 /* Error handling.  */
 extern int retcode;
-#define M4ERROR(Arglist) \
-  (reference_error (), error Arglist)
+extern const char *program_name;
+
+/* It would be so much nicer if the gnulib error module provided a
+   va_list version of error, so that we wouldn't need to use macros
+   and a global hook variable.  Oh well.  */
+#if 0
+void m4_error (int, int, const char *, ...) M4_GNUC_PRINTF(3, 4);
+/* Would be implemented as:
+void
+m4_error (int status, int errnum, const char *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  verror_at_line (status, errnum, current_file, current_line, format, args);
+}
+*/
+#endif
 
+#define M4ERROR(Arglist) (error Arglist)
+#define M4ERROR_AT_LINE(Arglist) do {          \
+    suppress_line = TRUE;                      \
+    (error_at_line Arglist);                   \
+  } while (0)
+
+
+extern boolean suppress_line;
 void reference_error (void);
 
 #ifdef USE_STACKOVF
@@ -441,13 +476,3 @@ void reload_frozen_state (const char *);
    a bit safer than casting to unsigned char, since it catches some type
    errors that the cast doesn't.  */
 static inline unsigned char to_uchar (char ch) { return ch; }
-
-/* Take advantage of GNU C compiler source level optimization hints,
-   using portable macros.  */
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
-#  define M4_GNUC_ATTRIBUTE(args)      __attribute__(args)
-#else
-#  define M4_GNUC_ATTRIBUTE(args)
-#endif  /* __GNUC__ */
-
-#define M4_GNUC_UNUSED         M4_GNUC_ATTRIBUTE((unused))
Index: src/macro.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/macro.c,v
retrieving revision 1.1.1.1.2.9
diff -u -p -r1.1.1.1.2.9 macro.c
--- src/macro.c 3 Aug 2006 13:31:40 -0000       1.1.1.1.2.9
+++ src/macro.c 4 Aug 2006 13:16:27 -0000
@@ -167,8 +167,8 @@ expand_argument (struct obstack *obs, to
        case TOKEN_EOF:
          /* current_file changed to "NONE" if we see TOKEN_EOF, use the
             previous value we stored earlier.  */
-         error_at_line (EXIT_FAILURE, 0, file, line,
-                        "ERROR: end of file in argument list");
+         M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, line,
+                           "ERROR: end of file in argument list"));
          break;
 
        case TOKEN_WORD:

reply via email to

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