[Top][All Lists]
[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:
- Re: rfc: new __program__ macro,
Eric Blake <=