autoconf-patches
[Top][All Lists]
Advanced

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

Re: how to do "$@"?


From: Paul Eggert
Subject: Re: how to do "$@"?
Date: Wed, 17 Apr 2002 14:51:42 -0700 (PDT)

> Date: Wed, 17 Apr 2002 11:41:25 -0600 (MDT)
> From: "Nelson H. F. Beebe" <address@hidden>
>
> The problem seems to arise from manipulations of "$@" that cause
> quoting of arguments containing blanks to be lost.

I think the main problem is dealing with the case where there are no
positional arguments.  In that case, the Unix Version 7 shell treats
"$@" like "", whereas POSIX requires that it should treat "$@" as if
it were absent.  For example:

  set x
  shift
  cat "$@" /dev/null

In Unix Version 7, this fails and outputs something like this:

  cat: : No such file or directory

whereas in a POSIX shell, it outputs nothing.

> I suspect that most scripts only require the simpler use, and thus,
> that "$@" should be preferred over the ${1+"$@"} form

But this won't work on older versions of Digital Unix.

How about the following (untested) patch instead?  It avoids the
problem entirely, by removing all instances of "$@" in cases where
there might be zero positional arguments.

2002-04-17  Paul Eggert  <address@hidden>

        Stop using "$@" when there might be zero positional arguments
        in cases where this matters, as it's not portable to Zsh and
        Mac OS X uses Zsh as /bin/sh.

        * bin/autoconf.as: Ensure at least one positional arg before
        using "$@", in cases where it's important to preserve argument count.
        Do not use ${1+"$@"}, to avoid Zsh compatibility problem.
        * bin/autoconf.in: Likewise.
        * bin/autoheader.in: Likewise.
        * bin/auto4mte.in: Likewise.
        * bin/autoreconf.in: Likewise.
        * bin/autoscan.in: Likewise.
        * bin/autoupdate.in: Likewise.
        * bin/ifnames.in: Likewise.
        * config/missing: Likewise.
        * lib/autoconf/programs.m4: Likewise.
        * lib/autoconf/status.m4: Likewise.
        * lib/autotest/general.m4: Likewise.
        * lib/m4sugar/m4sh.m4: Likewise.
        * tests/atgeneral.m4: Likewise.
        * tests/autoreconf.in: Likewise.
        * tests/c.at: Likewise.
        * tests/wrappl.as: Likewise.
        * tests/wrapsh.as: Likewise.

        * bin/autoconf.in: Remove Zsh workaround; no longer needed.
        * lib/m4sugar.m4sh.m4: Likewise.

        * doc/autoconf.texi (Shell Substitutions): Document the problem.

Index: bin/autoconf.as
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoconf.as,v
retrieving revision 1.1
diff -p -u -r1.1 autoconf.as
--- bin/autoconf.as     10 Apr 2002 15:58:19 -0000      1.1
+++ bin/autoconf.as     17 Apr 2002 21:47:49 -0000
@@ -185,7 +185,7 @@ test -z "$outfile" && outfile=-
 # Running autom4te.
 run_autom4te="$AUTOM4TE --language=autoconf --output=$outfile"
 # Autom4te expansion.
-eval set dummy "$traces"
+eval set dummy "$traces" \$infile
 shift
-$verbose "$me: running $run_autom4te "${1+"$@"}" $infile" >&2
-exec $run_autom4te ${1+"$@"} $infile
+$verbose "$me: running $run_autom4te $*" >&2
+exec $run_autom4te "$@"
Index: bin/autoconf.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoconf.in,v
retrieving revision 1.146
diff -p -u -r1.146 autoconf.in
--- bin/autoconf.in     10 Apr 2002 17:32:35 -0000      1.146
+++ bin/autoconf.in     17 Apr 2002 21:47:49 -0000
@@ -7,9 +7,6 @@
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
-  # Zsh performs word splitting on ${1+"$@"}, which is contrary to
-  # our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
 elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
   set -o posix
 fi
@@ -281,7 +278,7 @@ test -z "$outfile" && outfile=-
 # Running autom4te.
 run_autom4te="$AUTOM4TE --language=autoconf --output=$outfile"
 # Autom4te expansion.
-eval set dummy "$traces"
+eval set dummy "$traces" \$infile
 shift
-$verbose "$me: running $run_autom4te "${1+"$@"}" $infile" >&2
-exec $run_autom4te ${1+"$@"} $infile
+$verbose "$me: running $run_autom4te $*" >&2
+exec $run_autom4te "$@"
Index: bin/autoheader.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoheader.in,v
retrieving revision 1.115
diff -p -u -r1.115 autoheader.in
--- bin/autoheader.in   8 Mar 2002 11:46:31 -0000       1.115
+++ bin/autoheader.in   17 Apr 2002 21:47:49 -0000
@@ -2,7 +2,7 @@
 # -*- Perl -*-
 # @configure_input@
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 # autoheader -- create `config.h.in' from `configure.ac'
Index: bin/autom4te.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autom4te.in,v
retrieving revision 1.59
diff -p -u -r1.59 autom4te.in
--- bin/autom4te.in     8 Mar 2002 12:01:23 -0000       1.59
+++ bin/autom4te.in     17 Apr 2002 21:47:49 -0000
@@ -2,7 +2,7 @@
 # -*- perl -*-
 # @configure_input@
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 # autom4te - Wrapper around M4 libraries.
Index: bin/autoreconf.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoreconf.in,v
retrieving revision 1.92
diff -p -u -r1.92 autoreconf.in
--- bin/autoreconf.in   5 Apr 2002 09:42:49 -0000       1.92
+++ bin/autoreconf.in   17 Apr 2002 21:47:50 -0000
@@ -2,7 +2,7 @@
 # -*- perl -*-
 # @configure_input@
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 # autoreconf - install the GNU Build System in a directory tree
Index: bin/autoscan.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoscan.in,v
retrieving revision 1.76
diff -p -u -r1.76 autoscan.in
--- bin/autoscan.in     19 Mar 2002 15:25:26 -0000      1.76
+++ bin/autoscan.in     17 Apr 2002 21:47:50 -0000
@@ -20,7 +20,7 @@
 
 # Written by David MacKenzie <address@hidden>.
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 BEGIN
Index: bin/autoupdate.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/autoupdate.in,v
retrieving revision 1.31
diff -p -u -r1.31 autoupdate.in
--- bin/autoupdate.in   8 Mar 2002 11:46:31 -0000       1.31
+++ bin/autoupdate.in   17 Apr 2002 21:47:50 -0000
@@ -21,7 +21,7 @@
 # Originally written by David MacKenzie <address@hidden>.
 # Rewritten by Akim Demaille <address@hidden>.
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 BEGIN
Index: bin/ifnames.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/bin/ifnames.in,v
retrieving revision 1.25
diff -p -u -r1.25 ifnames.in
--- bin/ifnames.in      8 Mar 2002 11:46:31 -0000       1.25
+++ bin/ifnames.in      17 Apr 2002 21:47:50 -0000
@@ -2,7 +2,7 @@
 # -*- perl -*-
 # @configure_input@
 
-eval 'exec @PERL@ -S $0 ${1+"$@"}'
+eval 'case $# in 0) exec @PERL@ -S $0;; *) exec @PERL@ -S $0 "$@";; esac'
     if 0;
 
 # ifnames - print the identifiers used in C preprocessor conditionals
Index: config/missing
===================================================================
RCS file: /cvsroot/autoconf/autoconf/config/missing,v
retrieving revision 1.6
diff -p -u -r1.6 missing
--- config/missing      24 Jan 2002 17:42:05 -0000      1.6
+++ config/missing      17 Apr 2002 21:47:50 -0000
@@ -293,23 +293,23 @@ WARNING: \`$1' is missing on your system
     # Look for gnutar/gtar before invocation to avoid ugly error
     # messages.
     if (gnutar --version > /dev/null 2>&1); then
-       gnutar ${1+"$@"} && exit 0
+       gnutar "$@" && exit 0
     fi
     if (gtar --version > /dev/null 2>&1); then
-       gtar ${1+"$@"} && exit 0
+       gtar "$@" && exit 0
     fi
     firstarg="$1"
     if shift; then
        case "$firstarg" in
        *o*)
            firstarg=`echo "$firstarg" | sed s/o//`
-           tar "$firstarg" ${1+"$@"} && exit 0
+           tar "$firstarg" "$@" && exit 0
            ;;
        esac
        case "$firstarg" in
        *h*)
            firstarg=`echo "$firstarg" | sed s/h//`
-           tar "$firstarg" ${1+"$@"} && exit 0
+           tar "$firstarg" "$@" && exit 0
            ;;
        esac
     fi
Index: doc/autoconf.texi
===================================================================
RCS file: /cvsroot/autoconf/autoconf/doc/autoconf.texi,v
retrieving revision 1.610
diff -p -u -r1.610 autoconf.texi
--- doc/autoconf.texi   11 Apr 2002 10:24:22 -0000      1.610
+++ doc/autoconf.texi   17 Apr 2002 21:47:54 -0000
@@ -8458,13 +8458,16 @@ strings inside double-quoted backquoted 
 @item $@@
 @cindex @samp{"$@@"}
 One of the most famous shell-portability issues is related to
address@hidden"$@@"}: when there are no positional arguments, it is supposed to
-be equivalent to nothing.  But some shells, for instance under Digital
-Unix 4.0 and 5.0, will then replace it with an empty argument.  To be
-portable, use @address@hidden"$@@"@}}.
-
-But that's not the end of the story.  Zsh (3.x and 4.x), when emulating
-the Bourne shell, does perform word splitting on @address@hidden"$@@"@}}...
address@hidden"$@@"}: when there are no positional arguments, @sc{posix} says
+that it is supposed to be equivalent to nothing.  But the original
+Unix Version 7 Bourne shell treated it as equivalent to @samp{""}
+instead, and this behavior survives in some more modern
+implementations, for instance under Digital Unix 5.0.
+
+The traditional way to work around this portability problem is to use
address@hidden@{1+"$@@"@}}.  Unfortunately this method does not work with
+Zsh (3.x and 4.x), which is used on Mac OS X.  When emulating
+the Bourne shell, Zsh performs word splitting on @address@hidden"$@@"@}}:
 
 @example
 zsh $ @kbd{emulate sh}
@@ -8478,19 +8481,25 @@ World
 @end example
 
 @noindent
-It is not clear whether this is a violation of the Bourne shell
-standard, nevertheless, in this regard Zsh is different from all the
-other shells.  Of course Zsh handles @samp{"$@@"} properly, but we can't
-use it portably...
-
-Fortunately, there is a workaround which relies on Zsh's ``global
-aliases'': let it convert @address@hidden"$@@"@}} into @samp{"$@@"} by
-itself:
+Zsh handles plain @samp{"$@@"} properly, but we can't use plain
address@hidden"$@@"} because of the portability problems mentioned above.
+
+The most portable workaround is to avoid @samp{"$@@"} if it is possible
+that there may be no positional arguments.  For example, instead of:
 
 @example
-test -n "address@hidden@}" = set && alias -g 'address@hidden"$@@"@}'='"$@@"'
+# Not portable if there are no positional arguments.
+cat conftest.c "$@@"
 @end example
 
+you should use this instead:
+
address@hidden
+case $# in
+0) cat conftest.c;;
+*) cat conftest.c "$@@";;
+esac
address@hidden example
 
 @item address@hidden@var{var}:address@hidden@}
 @c Info cannot handle `:' in index entries.
Index: lib/autoconf/programs.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/programs.m4,v
retrieving revision 1.9
diff -p -u -r1.9 programs.m4
--- lib/autoconf/programs.m4    2 Mar 2002 15:19:48 -0000       1.9
+++ lib/autoconf/programs.m4    17 Apr 2002 21:47:54 -0000
@@ -92,7 +92,10 @@ m4_ifvaln([$6],
     # However, it has the same basename, so the bogon will be chosen
     # first if we set $1 to just the basename; use the full file name.
     shift
-    set dummy "$as_dir/$ac_word" ${1+"address@hidden"}
+    case address@hidden:@] in
+    0) set dummy "$as_dir/$ac_word";;
+    *) set dummy "$as_dir/$ac_word" "address@hidden";;
+    esac
     shift
     ac_cv_prog_$1="address@hidden"
 m4_if([$2], [$4],
Index: lib/autoconf/status.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/status.m4,v
retrieving revision 1.22
diff -p -u -r1.22 status.m4
--- lib/autoconf/status.m4      10 Apr 2002 15:58:20 -0000      1.22
+++ lib/autoconf/status.m4      17 Apr 2002 21:47:55 -0000
@@ -1383,7 +1383,10 @@ do
     ac_option=`expr "x$[1]" : 'x\([[^=]]*\)='`
     ac_optarg=`expr "x$[1]" : 'x[[^=]]*=\(.*\)'`
     shift
-    set dummy "$ac_option" "$ac_optarg" ${1+"address@hidden"}
+    case $[#] in
+    0) set dummy "$ac_option" "$ac_optarg";;
+    *) set dummy "$ac_option" "$ac_optarg" "address@hidden";;
+    esac
     shift
     ;;
   -*);;
Index: lib/autotest/general.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autotest/general.m4,v
retrieving revision 1.130
diff -p -u -r1.130 general.m4
--- lib/autotest/general.m4     10 Apr 2002 15:58:20 -0000      1.130
+++ lib/autotest/general.m4     17 Apr 2002 21:47:55 -0000
@@ -101,7 +101,7 @@ AS_PREPARE
 SHELL=${CONFIG_SHELL-/bin/sh}
 
 # How were we run?
-at_cli_args=${1+"address@hidden"}
+at_cli_args="address@hidden"
 
 # Load the config file.
 for at_file in atconfig atlocal
@@ -570,8 +570,12 @@ _ATEOF
             {
               echo "#! /bin/sh"
               echo "cd $at_dir"
-              echo 'exec ${CONFIG_SHELL-'"$SHELL"'}' "$[0]" \
-                   '-v -d' "$at_debug_args" "$at_group" '${1+"address@hidden"}'
+              echo 'case $[#] in'
+              echo '0) exec ${CONFIG_SHELL-'"$SHELL"'}' "$[0]" \
+                   '-v -d' "$at_debug_args" "$at_group;;"
+              echo '*) exec ${CONFIG_SHELL-'"$SHELL"'}' "$[0]" \
+                   '-v -d' "$at_debug_args" "$at_group" '"address@hidden";;'
+              echo 'esac'
               echo 'exit 1'
             } >$at_group_dir/run
             chmod +x $at_group_dir/run
Index: lib/m4sugar/m4sh.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/m4sugar/m4sh.m4,v
retrieving revision 1.83
diff -p -u -r1.83 m4sh.m4
--- lib/m4sugar/m4sh.m4 10 Apr 2002 17:36:45 -0000      1.83
+++ lib/m4sugar/m4sh.m4 17 Apr 2002 21:47:55 -0000
@@ -146,9 +146,6 @@ m4_defun([AS_SHELL_SANITIZE],
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
-  [#] Zsh 3.x and 4.x performs word splitting on ${1+"address@hidden"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"address@hidden"}'='"address@hidden"'
 elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
   set -o posix
 fi
@@ -555,7 +552,10 @@ _AS_LINENO_WORKS || {
             AS_UNSET(ENV)
             CONFIG_SHELL=$as_dir/$as_base
             export CONFIG_SHELL
-            exec "$CONFIG_SHELL" "$[0]" ${1+"address@hidden"}
+            case $[#] in
+            0) exec "$CONFIG_SHELL" "$[0]";;
+            *) exec "$CONFIG_SHELL" "$[0]" "address@hidden";;
+            esac
           fi;;
         esac
        done]);;
Index: tests/atgeneral.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/atgeneral.m4,v
retrieving revision 1.70
diff -p -u -r1.70 atgeneral.m4
--- tests/atgeneral.m4  25 Nov 2001 15:13:04 -0000      1.70
+++ tests/atgeneral.m4  17 Apr 2002 21:47:55 -0000
@@ -318,7 +318,10 @@ elif test $at_debug = false; then
   for at_group in $at_fail_list; do
     echo $at_n " $at_group$at_c"
     ( echo "#! /bin/sh"
-      echo 'exec ${CONFIG_SHELL-'"$SHELL"'} '"$[0]"' -v -d '"$at_group"' 
${1+"address@hidden"}'
+      echo 'case $[#] in'
+      echo '0) exec ${CONFIG_SHELL-'"$SHELL"'} '"$[0]"' -v -d '"$at_group"';;'
+      echo '*) exec ${CONFIG_SHELL-'"$SHELL"'} '"$[0]"' -v -d '"$at_group"' 
"address@hidden";;'
+      echo 'esac'
       echo 'exit 1'
     ) >debug-$at_group.sh
     chmod +x debug-$at_group.sh
Index: tests/autoreconf.in
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/autoreconf.in,v
retrieving revision 1.2
diff -p -u -r1.2 autoreconf.in
--- tests/autoreconf.in 14 Dec 2001 17:57:29 -0000      1.2
+++ tests/autoreconf.in 17 Apr 2002 21:47:55 -0000
@@ -3,4 +3,7 @@
 
 me=`echo "$0" | sed -e 's,.*[\\/],,'`
 
-exec @abs_top_builddir@/bin/$me --autoconf-dir @abs_top_builddir@/lib ${1+"$@"}
+case $# in
+0) exec @abs_top_builddir@/bin/$me --autoconf-dir @abs_top_builddir@/lib;;
+*) exec @abs_top_builddir@/bin/$me --autoconf-dir @abs_top_builddir@/lib "$@";;
+esac
Index: tests/c.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/c.at,v
retrieving revision 1.1
diff -p -u -r1.1 c.at
--- tests/c.at  27 Sep 2001 13:28:15 -0000      1.1
+++ tests/c.at  17 Apr 2002 21:47:55 -0000
@@ -113,7 +113,7 @@ AT_SETUP([AC_PROG_CPP with warnings])
 AT_DATA([mycpp],
 [[#! /bin/sh
 echo noise >&2
-exec ${1+"$@"}
+exec "$@"
 ]])
 
 chmod +x mycpp
@@ -146,7 +146,7 @@ AT_CHECK([/lib/cpp </dev/null || exit 77
 # A cpp which exit status is meaningless.
 AT_DATA([mycpp],
 [[#! /bin/sh
-/lib/cpp ${1+"$@"}
+/lib/cpp "$@"
 exit 0
 ]])
 
Index: tests/wrappl.as
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/wrappl.as,v
retrieving revision 1.3
diff -p -u -r1.3 wrappl.as
--- tests/wrappl.as     12 Apr 2002 10:10:10 -0000      1.3
+++ tests/wrappl.as     17 Apr 2002 21:47:55 -0000
@@ -9,7 +9,10 @@ export autom4te_perllibdir
 case $as_me in
   ifnames)
      # Does not have lib files.
-     exec @abs_top_builddir@/bin/$as_me ${1+"$@"}
+     case $# in
+     0) exec @abs_top_builddir@/bin/$as_me;;
+     *) exec @abs_top_builddir@/bin/$as_me "$@";;
+     esac
      ;;
 
   autom4te)
@@ -19,6 +22,11 @@ case $as_me in
 
 esac
 # We might need files from build (frozen files), in addition of src files.
-exec @abs_top_builddir@/bin/$as_me \
+case $# in
+0) exec @abs_top_builddir@/bin/$as_me \
        -I @abs_top_builddir@/lib \
-       -I @abs_top_srcdir@/lib ${1+"$@"}
+       -I @abs_top_srcdir@/lib;;
+*) exec @abs_top_builddir@/bin/$as_me \
+       -I @abs_top_builddir@/lib \
+       -I @abs_top_srcdir@/lib "$@";;
+esac
Index: tests/wrapsh.as
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/wrapsh.as,v
retrieving revision 1.2
diff -p -u -r1.2 wrapsh.as
--- tests/wrapsh.as     12 Apr 2002 09:56:11 -0000      1.2
+++ tests/wrapsh.as     17 Apr 2002 21:47:55 -0000
@@ -1,4 +1,7 @@
 AS_INIT[]dnl                                         -*- shell-script -*-
 # @configure_input@
 # Running `$0' as if it were installed.
-exec @abs_top_builddir@/bin/$as_me --include @abs_top_builddir@/lib ${1+"$@"}
+case $# in
+0) exec @abs_top_builddir@/bin/$as_me --include @abs_top_builddir@/lib;;
+*) exec @abs_top_builddir@/bin/$as_me --include @abs_top_builddir@/lib "$@";;
+esac



reply via email to

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