autoconf-patches
[Top][All Lists]
Advanced

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

Re: AS_DIRNAME and expr


From: Akim Demaille
Subject: Re: AS_DIRNAME and expr
Date: 29 Nov 2000 16:53:01 +0100
User-agent: Gnus/5.0807 (Gnus v5.8.7) XEmacs/21.1 (Channel Islands)

Here is my proposal for fixing and documenting our expr problems.  I'm
applying it now so that David may run the test suite and check the
issue is indeed fixed, but of course any request for modification will
be honored.

I'm happy to (hopefully) close this thread, it was getting obscure :)

Index: ChangeLog
from  Akim Demaille  <address@hidden>
        QNX 4.2.5's expr always exits 1 when `:' is used with parens.

        * doc/autoconf.texi (Limitations of Usual Tools) <expr>: More
        information, thanks to Paul Berrevoets, Paul Eggert and David
        Morgan.
        * sh.m4 (_AS_EXPR_PREPARE): New.
        (AS_DIRNAME): Use it.

Index: THANKS
===================================================================
RCS file: /cvs/autoconf/THANKS,v
retrieving revision 1.44
diff -u -u -r1.44 THANKS
--- THANKS 2000/11/10 12:10:13 1.44
+++ THANKS 2000/11/29 15:45:10
@@ -28,6 +28,7 @@
 Cort Dougan            address@hidden
 Dave Adams             address@hidden
 Dave Love              address@hidden
+David Morgan           address@hidden
 Didier Desseaux                address@hidden
 Didier Verna           address@hidden
 Dietmar P. Schindler   address@hidden
@@ -98,6 +99,7 @@
 Noah Friedman          address@hidden
 Ossama Othman          address@hidden
 Patrick Tullmann       address@hidden
+Paul Berrevoets                address@hidden
 Paul Eggert            address@hidden
 Paul Gampe             address@hidden
 Paul Martinolich       address@hidden
Index: m4sh.m4
===================================================================
RCS file: /cvs/autoconf/m4sh.m4,v
retrieving revision 1.12
diff -u -u -r1.12 m4sh.m4
--- m4sh.m4 2000/11/29 10:09:44 1.12
+++ m4sh.m4 2000/11/29 15:45:16
@@ -66,6 +66,7 @@
   set -o posix
 fi
 
+_AS_EXPR_PREPARE
 _AS_UNSET_PREPARE
 
 # NLS nuisances.
@@ -242,29 +245,13 @@
 
 
 
-## ------------------------------------------- ##
-## 4. Portable versions of common file utils.  ##
-## ------------------------------------------- ##
+## -------------------------------------- ##
+## 4. Portable versions of common tools.  ##
+## -------------------------------------- ##
 
 # This section is lexicographically sorted.
 
 
 # AS_DIRNAME(PATHNAME)
 # --------------------
 # Simulate running `dirname(1)' on PATHNAME, not all systems have it.
@@ -276,14 +263,20 @@
 # a silly length limit that causes expr to fail if the matched
 # substring is longer than 120 bytes.  So fall back on echo|sed if
 # expr fails.
-m4_define([AS_DIRNAME_EXPR],
-[expr X[]$1 : 'X\(.*[[^/]]\)//*[[^/][^/]]*/*$' \| \
-      X[]$1 : 'X\(//\)[[^/]]' \| \
-      X[]$1 : 'X\(//\)$' \| \
-      X[]$1 : 'X\(/\)' \| \
-      .     : '\(.\)'])
+#
+# FIXME: Please note the following m4_require is quite wrong: if the first
+# occurrence of AS_DIRNAME_EXPR is in a backquoted expression, the
+# shell will be lost.  We might have to introduce diversions for
+# setting up an M4sh script: required macros will them be expanded there.
+m4_defun([AS_DIRNAME_EXPR],
+[m4_require([_AS_EXPR_PREPARE])dnl
+$as_expr X[]$1 : 'X\(.*[[^/]]\)//*[[^/][^/]]*/*$' \| \
+         X[]$1 : 'X\(//\)[[^/]]' \| \
+         X[]$1 : 'X\(//\)$' \| \
+         X[]$1 : 'X\(/\)' \| \
+         .     : '\(.\)'])
 
-m4_define([AS_DIRNAME_SED],
+m4_defun([AS_DIRNAME_SED],
 [echo X[]$1 |
     sed ['/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
          /^X\(\/\/\)[^/].*/{ s//\1/; q; }
@@ -291,9 +284,39 @@
          /^X\(\/\).*/{ s//\1/; q; }
          s/.*/./; q']])
 
-m4_define([AS_DIRNAME],
+m4_defun([AS_DIRNAME],
 [AS_DIRNAME_EXPR([$1]) 2>/dev/null ||
 AS_DIRNAME_SED([$1])])
+
+
+# _AS_EXPR_PREPARE
+# ----------------
+# Some expr work properly (i.e. compute and issue the right result),
+# but exit with failure.  When a fall back to expr (as in AS_DIRNAME)
+# is provided, you get twice the result.  Prevent this.
+m4_defun([_AS_EXPR_PREPARE],
+[as_expr=`expr a : '\(a\)'`
+case $as_expr,$? in
+  a,0) as_expr=expr;;
+    *) as_expr=false;;
+esac[]dnl
+])# _AS_EXPR_PREPARE
+
 
 
 
Index: doc/autoconf.texi
===================================================================
RCS file: /cvs/autoconf/doc/autoconf.texi,v
retrieving revision 1.394
diff -u -u -r1.394 autoconf.texi
--- doc/autoconf.texi 2000/11/28 18:58:16 1.394
+++ doc/autoconf.texi 2000/11/29 15:46:17
@@ -5825,42 +5825,95 @@
 @item @command{expr}
 @cindex @command{expr}
 No @command{expr} keyword starts with @samp{x}, so use @samp{expr
-x"@var{word}" : '@var{regex}'} to keep @command{expr} from
+x"@var{word}" : 'address@hidden'} to keep @command{expr} from
 misinterpreting @var{word}.
 
-You can use @samp{|}.  There is one portability problem occuring when
-you @samp{|} together the empty string (or zero) with the empty string.
-For example:
+Don't use @code{length}, @code{substr}, @code{match} and @code{index}.
+
address@hidden @command{expr} (@samp{|})
address@hidden @command{expr} (@samp{|})
+You can use @samp{|}.  Although @sc{posix} does require that @samp{expr
+''} return the empty string, it does not specify the result when you
address@hidden|} together the empty string (or zero) with the empty string.  For
+example:
 
 @example
 expr '' \| ''
 @end example
 
address@hidden/Linux and @sc{posix.2} return the empty string for this case,
-but traditional Unix returns @samp{0}.  In the latest @sc{posix} draft,
-the specification has been changed to match traditional Unix's behavior
-(which is bizarre, but it's too late to fix this).
address@hidden/Linux and @sc{posix.2-1992} return the empty string for this
+case, but traditional Unix returns @samp{0} (Solaris is one such
+example).  In the latest @sc{posix} draft, the specification has been
+changed to match traditional Unix's behavior (which is bizarre, but it's
+too late to fix this).  Please note that the same problem does arise
+when the empty string results from a computation, as in:
 
-Avoid this portability problem by avoiding the empty string.
address@hidden
+expr bar : foo \| foo : bar
address@hidden example
 
-Don't use @code{length}, @code{substr}, @code{match} and @code{index}.
address@hidden
+Avoid this portability problem by avoiding the empty string.
 
 @item @command{expr} (@samp{:})
 @cindex @command{expr}
 Don't use @samp{\?}, @samp{\+} and @samp{\|} in patterns, they are
 not supported on Solaris.
+
+The @sc{posix.2-1992} standard is ambiguous as to whether @samp{expr a :
+b} (and @samp{expr 'a' : '\(b\)'}) output @samp{0} or the empty string.
+In practice, it outputs the empty string on most platforms, but portable
+scripts should not assume this.  For instance, the @sc{qnx} 4.2.5 native
address@hidden returns @samp{0}.
+
+You may believe that one means to get a uniform behavior would be to use
+the empty string as a default value:
+
address@hidden
+expr a : b \| ''
address@hidden example
 
-The @sc{posix}.2-1996 standard is ambiguous as to whether @samp{expr 'a'
-: '\(b\)'} outputs @samp{0} or the empty string.  In practice, it
-outputs the empty string on most platforms, but portable scripts should
-not assume this.  For instance, the @sc{qnx} 4.2.5 native @command{expr}
-returns @samp{0}.
address@hidden
+unfortunately this behaves exactly as the original expression, see the
address@hidden@command{expr} (@samp{:})} entry for more information.
 
 Older @command{expr} implementations (e.g. SunOS 4 @command{expr} and
 Solaris 8 @command{/usr/ucb/expr}) have a silly length limit that causes
 @command{expr} to fail if the matched substring is longer than 120
 bytes.  In this case, you might want to fall back on @samp{echo|sed} if
 @command{expr} fails.
+
+Don't leave, there is some more!
+
+The @sc{qnx} 4.2.5 @command{expr}, in addition of preferring @samp{0} to
+the empty string, has a funny behavior wrt exit status: it's always 1
+when the parenthesis are used!
+
address@hidden
+$ val=`expr 'a' : 'a'`; echo "$?: $val"
+0: 1
+$ val=`expr 'a' : 'b'`; echo "$?: $val"
+1: 0
+
+$ val=`expr 'a' : '\(a\)'`; echo "?: $val"
+1: a
+$ val=`expr 'a' : '\(b\)'`; echo "?: $val"
+1: 0
address@hidden example
+
address@hidden
+In practice this can be a big problem if you are ready to catch failures
+of @command{expr} programs with some other method (such as using
address@hidden), since you may get twice the result.  For instance
+
address@hidden
+$ expr 'a' : '\(a\)' || echo 'a' | sed 's/^\(a\)$/\1/'
address@hidden example
+
address@hidden
+will output @samp{a} on most hosts, but @samp{aa} on @sc{qnx} 4.2.5.  A
+simple work around consists in testing @command{expr} and use a variable
+set to @command{expr} or to @command{false} according to the result.
 
 
 @item @command{grep}
Index: tests/m4sh.at
===================================================================
RCS file: /cvs/autoconf/tests/m4sh.at,v
retrieving revision 1.9
diff -u -u -r1.9 m4sh.at
--- tests/m4sh.at 2000/11/29 10:12:05 1.9
+++ tests/m4sh.at 2000/11/29 15:46:17
@@ -12,7 +12,9 @@
 AT_SETUP([[AS_DIRNAME & AS_DIRNAME_SED]])
 
 AT_DATA(configure.in,
-[[define([AS_DIRNAME_TEST],
+[[_AS_EXPR_PREPARE
+
+define([AS_DIRNAME_TEST],
 [dir=`AS_DIRNAME([$1])`
 test "$dir" = "$2" ||
   echo "dirname($1) = $dir instead of $2" >&2



reply via email to

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