autoconf-patches
[Top][All Lists]
Advanced

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

Re: AS_MESSAGE_FD


From: Eric Blake
Subject: Re: AS_MESSAGE_FD
Date: Sat, 22 Nov 2008 00:06:59 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> > +AT_SETUP([AS@&t <at> _INIT_GENERATED])
> > +
> > +AT_DATA_M4SH([script.as], [[dnl
> > +m4_define([AS_MESSAGE_FD], [1])
> 
> By the way, this test points out another m4sh flaw that needs fixing - we 
> should consider providing default values for AS_MESSAGE_FD (1) and 
> AS_MESSAGE_LOG_FD (empty), which can be changed by clients, so that 
AS_MESSAGE 
> works if the client doesn't touch these macros.  The manual documents that 
they 
> exist, but is silent on whether the users may/must redefine them (and 
> AS_INIT_GENERATED currently doesn't work if the user does not redefine 
them).  

What do you think of this patch?


From: Eric Blake <address@hidden>
Date: Fri, 21 Nov 2008 15:50:37 -0700
Subject: [PATCH] Clean up AS_MESSAGE_LOG_FD usage.

* lib/m4sugar/m4sh.m4 (AS_MESSAGE_FD, AS_MESSAGE_LOG_FD)
(AS_ORIGINAL_STDIN_FD): Provide default M4sh values.
(_AS_ECHO_LOG, AS_MESSAGE, _AS_ERROR_PREPARE, AS_ERROR): Simplify
usage.
(AS_INIT_GENERATED): Don't shuffle an unchanged AS_MESSAGE_FD.
* tests/m4sh.at (AS@&address@hidden): Update test.
(AS@&address@hidden): New test.
* doc/autoconf.texi (Initialization Macros) <AS_INIT_GENERATED>:
Give more details about fd manipulation.
(File Descriptor Macros): Describe M4sh defaults for the fds.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog           |   14 ++++++++
 doc/autoconf.texi   |   35 +++++++++++++++------
 lib/m4sugar/m4sh.m4 |   46 +++++++++++++++++++++-------
 tests/m4sh.at       |   84 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 157 insertions(+), 22 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ec79176..d72ad1f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2008-11-21  Eric Blake  <address@hidden>
 
+       Clean up AS_MESSAGE_LOG_FD usage.
+       * lib/m4sugar/m4sh.m4 (AS_MESSAGE_FD, AS_MESSAGE_LOG_FD)
+       (AS_ORIGINAL_STDIN_FD): Provide default M4sh values.
+       (_AS_ECHO_LOG, AS_MESSAGE, _AS_ERROR_PREPARE, AS_ERROR): Simplify
+       usage.
+       (AS_INIT_GENERATED): Don't shuffle an unchanged AS_MESSAGE_FD.
+       * tests/m4sh.at (AS@&address@hidden): Update test.
+       (AS@&address@hidden): New test.
+       * doc/autoconf.texi (Initialization Macros) <AS_INIT_GENERATED>:
+       Give more details about fd manipulation.
+       (File Descriptor Macros): Describe M4sh defaults for the fds.
+
+2008-11-21  Eric Blake  <address@hidden>
+
        Use shell function for AS_ERROR.
        * lib/m4sugar/m4sh.m4 (_AS_ERROR_PREPARE): New macro, defining a
        new shell function.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index e8cab41..957b8be 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -12500,15 +12500,21 @@ Initialization Macros
 (thus, the emitted code is equivalent in effect, but more efficient,
 than the code output by @code{AS_INIT}, @code{AS_BOURNE_COMPATIBLE}, and
 @code{AS_SHELL_SANITIZE}).  If present, @var{comment} is output near the
-beginning of the child, prior to the shell initialization code.  The
+beginning of the child, prior to the shell initialization code, and is
+subject to parameter expansion, command substitution, and backslash
+quote removal.  The
 parent script should check the exit status after this macro, in case
 @var{file} could not be properly created (for example, if the disk was
 full).  If successfully created, the parent script can then proceed to
 append additional M4sh constructs into the child script.
 
-Note that the child script starts life without a log file open, so you
+Note that the child script starts life without a log file open, so if
+the parent script uses logging (@pxref{AS_MESSAGE_LOG_FD}), you
 must temporarily disable any attempts to use the log file until after
-emitting code to open a log within the child.  Currently, the suggested
+emitting code to open a log within the child.  On the other hand, if the
+parent script has @code{AS_MESSAGE_FD} redirected somewhere besides
address@hidden, then the child script already has code that copies stdout to
+that descriptor.  Currently, the suggested
 idiom for writing a M4sh shell script from within another script is:
 
 @example
@@ -12583,27 +12589,36 @@ File Descriptor Macros
 @defmac AS_MESSAGE_FD
 @asindex{MESSAGE_FD}
 The file descriptor for @samp{checking for...}  messages and results.
-Normally this directs messages to the standard output, however when
address@hidden is run with the @option{-q} option, messages sent to
address@hidden are discarded.
+By default, @code{AS_INIT} sets this to @samp{1} for standalone M4sh
+clients.  However, @code{AC_INIT} shuffles things around to another file
+descriptor, in order to allow the @option{-q} option of
address@hidden to choose whether messages should go to the script's
+standard output or be discarded.
 
 If you want to display some messages, consider using one of the printing
 macros (@pxref{Printing Messages}) instead.  Copies of messages output
 via these macros are also recorded in @file{config.log}.
 @end defmac
 
address@hidden
 @defmac AS_MESSAGE_LOG_FD
 @asindex{MESSAGE_LOG_FD}
-
-The file descriptor for messages logged to @file{config.log}.  Macros
-that run tools, like @code{AC_COMPILE_IFELSE} (@pxref{Running the
+This must either be empty, or expand to a file descriptor for log
+messages.  By default, @code{AS_INIT} sets this macro to the empty
+string for standalone M4sh clients, thus disabling logging.  However,
address@hidden shuffles things around so that both @command{configure}
+and @command{config.status} use @file{config.log} for log messages.
+Macros that run tools, like @code{AC_COMPILE_IFELSE} (@pxref{Running the
 Compiler}), redirect all output to this descriptor.  You may want to do
 so if you develop such a low-level macro.
 @end defmac
 
 @defmac AS_ORIGINAL_STDIN_FD
 @asindex{ORIGINAL_STDIN_FD}
-The file descriptor for the original standard input.
+This must expand to a file descriptor for the original standard input.
+By default, @code{AS_INIT} sets this macro to @samp{0} for standalone
+M4sh clients.  However, @code{AC_INIT} shuffles things around for
+safety.
 
 When @command{configure} runs, it may accidentally execute an
 interactive command that has the same name as the non-interactive meant
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index f3dc4ac..67eb9ff 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -658,8 +658,30 @@ m4_defun([AS_UNSET],
 ## 3. Error and warnings at the shell level.  ##
 ## ------------------------------------------ ##
 
-# If AS_MESSAGE_LOG_FD is defined, shell messages are duplicated there
-# too.
+
+# AS_MESSAGE_FD
+# -------------
+# Must expand to the fd where messages will be sent.  Defaults to 1,
+# although a script may reassign this value and use exec to either
+# copy stdout to the new fd, or open the new fd on /dev/null.
+m4_define([AS_MESSAGE_FD], [1])
+
+# AS_MESSAGE_LOG_FD
+# -----------------
+# Must expand to either the empty string (when no logging is
+# performed), or to the fd of a log file.  Defaults to empty, although
+# a script may reassign this value and use exec to open a log.  When
+# not empty, messages to AS_MESSAGE_FD are duplicated to the log,
+# along with a LINENO reference.
+m4_define([AS_MESSAGE_LOG_FD])
+
+
+# AS_ORIGINAL_STDIN_FD
+# --------------------
+# Must expand to the fd of the script's original stdin.  Defaults to
+# 0, although the script may reassign this value and use exec to
+# shuffle fd's.
+m4_define([AS_ORIGINAL_STDIN_FD], [0])
 
 
 # AS_ESCAPE(STRING, [CHARS = $"`\])
@@ -730,7 +752,7 @@ m4_define([_AS_ECHO],
 # Log the string to AS_MESSAGE_LOG_FD.
 m4_defun_init([_AS_ECHO_LOG],
 [AS_REQUIRE([_AS_LINENO_PREPARE])],
-[_AS_ECHO([$as_me:${as_lineno-$LINENO}: $1], [AS_MESSAGE_LOG_FD])])
+[_AS_ECHO([$as_me:${as_lineno-$LINENO}: $1], AS_MESSAGE_LOG_FD)])
 
 
 # _AS_ECHO_N_PREPARE
@@ -765,10 +787,11 @@ m4_define([_AS_ECHO_N],
 
 # AS_MESSAGE(STRING, [FD = AS_MESSAGE_FD])
 # ----------------------------------------
-# Output "`basename $0`: "STRING to the open file FD.
+# Output "`basename $0`: STRING" to the open file FD, and if logging
+# is enabled, copy it to the log with a reference to LINENO.
 m4_defun_init([AS_MESSAGE],
 [AS_REQUIRE([_AS_ME_PREPARE])],
-[m4_ifset([AS_MESSAGE_LOG_FD],
+[m4_ifval(AS_MESSAGE_LOG_FD,
          [{ _AS_ECHO_LOG([$1])
 _AS_ECHO([$as_me: $1], [$2]);}],
          [_AS_ECHO([$as_me: $1], [$2])])[]])
@@ -792,15 +815,15 @@ m4_define([AS_WARN],
 # otherwise, assume the entire script does not do logging.
 m4_define([_AS_ERROR_PREPARE],
 [AS_REQUIRE_SHELL_FN([as_fn_error],
-  [AS_FUNCTION_DESCRIBE([as_fn_error], [ERROR]m4_ifset([AS_MESSAGE_LOG_FD],
+  [AS_FUNCTION_DESCRIBE([as_fn_error], [ERROR]m4_ifval(AS_MESSAGE_LOG_FD,
       [[ [[LINENO LOG_FD]]]]),
     [Output "`basename @S|@0`: error: ERROR" to stderr.]
-m4_ifset([AS_MESSAGE_LOG_FD],
+m4_ifval(AS_MESSAGE_LOG_FD,
     [[If LINENO and LOG_FD are provided, also output the error to LOG_FD,
       referencing LINENO.]])
     [Then exit the script with status $?, using 1 if that was 0.])],
 [  as_status=$?; test $as_status -eq 0 && as_status=1
-m4_ifset([AS_MESSAGE_LOG_FD],
+m4_ifval(AS_MESSAGE_LOG_FD,
 [m4_pushdef([AS_MESSAGE_LOG_FD], [$[3]])dnl
   if test "$[3]"; then
     AS_LINENO_PUSH([$[2]])
@@ -819,7 +842,7 @@ m4_defun_init([AS_ERROR],
 [m4_append_uniq([_AS_CLEANUP],
   [m4_divert_text([M4SH-INIT-FN], [_AS_ERROR_PREPARE[]])])],
 [m4_ifvaln([$2], [{ AS_SET_STATUS([$2])])]dnl
-[as_fn_error "_AS_QUOTE([$1])"m4_ifset([AS_MESSAGE_LOG_FD],
+[as_fn_error "_AS_QUOTE([$1])"m4_ifval([AS_MESSAGE_LOG_FD],
   [ "$LINENO" AS_MESSAGE_LOG_FD])[]m4_ifval([$2], [; }])])
 
 
@@ -1986,8 +2009,9 @@ _ASEOF
 cat >>$1 <<\_ASEOF || as_write_fail=1
 _AS_SHELL_SANITIZE
 _AS_PREPARE
-exec AS_MESSAGE_FD>&1
-m4_text_box([Main body of $1 script.])
+m4_if(AS_MESSAGE_FD, [1], [], [exec AS_MESSAGE_FD>&1
+])]dnl
+[m4_text_box([Main body of $1 script.])
 _ASEOF
 test $as_write_fail = 0 && chmod +x $1[]dnl
 _m4_popdef([AS_MESSAGE_LOG_FD])])# AS_INIT_GENERATED
diff --git a/tests/m4sh.at b/tests/m4sh.at
index e85aabe..0c575de 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -1259,9 +1259,10 @@ AT_CLEANUP
 ## ------------------- ##
 
 AT_SETUP([AS@&address@hidden)
+AT_KEYWORDS([AS@&address@hidden AS@&address@hidden)
 
+dnl First run, no logging, tests shell selection
 AT_DATA_M4SH([script.as], [[dnl
-m4_define([AS_MESSAGE_FD], [1])
 AS_INIT
 AS_INIT_GENERATED([child], [echo hello from child])
 cat >>child <<\EOF
@@ -1286,4 +1287,85 @@ AT_CHECK([grep 'SHELL=.' stdout], [0], [ignore])
 sed s/parent/child/ <stdout >expout
 AT_CHECK([./child], [0], [expout])
 
+
+dnl Second run, with logging from parent and child, tests fd handling
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+child=${1-child}
+m4_define([AS_MESSAGE_LOG_FD], [5])
+exec AS_MESSAGE_LOG_FD>log
+AS_INIT_GENERATED([$child], [echo hello1 from $child]) || AS_EXIT([1])
+cat >>$child <<\EOF
+m4_pushdef([AS_MESSAGE_LOG_FD])
+AS_MESSAGE([hello2 from ${child}child])
+m4_popdef([AS_MESSAGE_LOG_FD])
+exec AS_MESSAGE_LOG_FD>>log
+AS_MESSAGE([hello3 from child])
+EOF
+AS_MESSAGE([hello from parent])
+dnl close log in parent before spawning child, for mingw
+exec AS_MESSAGE_LOG_FD>-
+./$child
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script], [0], [[script: hello from parent
+hello1 from child
+child: hello2 from child
+child: hello3 from child
+]])
+AT_CHECK([[sed 's,:[0-9][0-9]*:,:0:,' log]], [0],
+[[script:0: hello from parent
+child:0: hello3 from child
+]])
+
+# Force write error creating a file on stdout
+if test -w /dev/full && test -c /dev/full; then
+  AT_CHECK([./script /dev/full], [1], [ignore], [ignore])
+fi
+
+AT_CLEANUP
+
+
+## --------------- ##
+## AS_MESSAGE_FD.  ##
+## --------------- ##
+
+AT_SETUP([AS@&address@hidden)
+AT_KEYWORDS([AS@&address@hidden AS@&address@hidden AS@&t_ORIGINAL_STDIN_FD])
+AT_KEYWORDS([AS@&address@hidden)
+
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+m4_define([AS_ORIGINAL_STDIN_FD], [5])
+m4_define([AS_MESSAGE_LOG_FD], [6])
+m4_define([AS_MESSAGE_FD], [7])
+exec AS_ORIGINAL_STDIN_FD<&0 </dev/null AS_MESSAGE_LOG_FD>log
+if test $[#] -gt 0; then
+  exec AS_MESSAGE_FD>/dev/null
+else
+  exec AS_MESSAGE_FD>&1
+fi
+AS_LINENO_PUSH([100])
+cat # tests that stdin is neutralized
+AS_MESSAGE([hello world])
+cat <&AS_ORIGINAL_STDIN_FD
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([echo goodbye | ./script], [0],
+[[script: hello world
+goodbye
+]])
+AT_CHECK([cat log], [0],
+[[script:100: hello world
+]])
+rm log
+AT_CHECK([echo goodbye | ./script silent], [0],
+[[goodbye
+]])
+AT_CHECK([cat log], [0],
+[[script:100: hello world
+]])
+
 AT_CLEANUP
-- 
1.6.0.4







reply via email to

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