chet@kiwi.INS.CWRU.Edu (Chet Ramey) (07/01/89)
There are a few problems with the test builtin as released with bash 1.01.
1. I claim that test handles the unary negation operator (`!') incorrectly.
Here is the test program I used:
if [ ! -d /usr -a ! -d /etc ] ; then
echo "Bogus"
else
echo "OK"
fi
I claim that "OK" should be echoed (on any Unix system). The following
Bourne-style shells agree with me:
4.3 BSD /bin/sh
SunOS 3.5 /bin/sh (s5r2-based)
Ultrix 3.0 /bin/sh (4.2 BSD +)
ksh version 06/03/86b
Ultrix 3.0 /bin/sh5 (s5r2 shell)
AIX 2.2.1 /bin/sh
s5r2 /bin/sh
s5r3.2 /bin/sh
ash (Kenneth Almquist's shell)
Vanilla Bash 1.01 echos "[: too many arguments". The problem is that
"!" is recognized and handled in expr(), not in term(). The fix is
simple.
2. The precendeces of -a and -o are switched. Fixes for this have already
been posted by andy@csvax.caltech.edu (<8906240223.AA27273@csvax.caltech.edu>);
I mention them only because they are also in the diffs.
3. I posted a fix for the test_syntax_error problem yesterday (6/28); that
patch is in here.
4. The problem with -w, as reported by Peter Su (hugo@GRIGGS.DARTMOUTH.EDU),
can be fixed by using access(). I changed -r to do so as well (-x already
did).
*** bash-1.01/test.c Fri Jun 23 00:43:13 1989
--- src-1.01/test.c Fri Jun 30 12:57:05 1989
***************
*** 33,39 ****
#include <sys/stat.h>
#include <sys/file.h>
! #ifndef X_OK
#define X_OK 1
! #endif
#ifndef lint
static char *rcsid="$Id: gtest.c,v 1.10 88/07/02 13:34:45 afb Exp Locker: afb $";
--- 33,42 ----
#include <sys/stat.h>
#include <sys/file.h>
! #ifndef R_OK
! #define R_OK 4
! #define W_OK 2
#define X_OK 1
! #define F_OK 0
! #endif /* R_OK */
#ifndef lint
static char *rcsid="$Id: gtest.c,v 1.10 88/07/02 13:34:45 afb Exp Locker: afb $";
***************
*** 67,71 ****
--- 70,78 ----
#endif /* STANDALONE */
+ #ifndef SYSV
int sys_v = 0;
+ #else
+ int sys_v = 1;
+ #endif
static int pos; /* position in list */
***************
*** 73,76 ****
--- 80,84 ----
static char **argv; /* the argument list */
+ #ifndef SYSV
static void
test_syntax_error (pchFmt, args)
***************
*** 84,87 ****
--- 92,110 ----
}
+ #else
+ #include <varargs.h>
+
+ static void
+ test_syntax_error(fmt, va)
+ char *fmt;
+ va_list va;
+ {
+ (void) fprintf(stderr,"%s: ", argv[0]);
+ (void) vfprintf(stderr, fmt, va);
+ (void) fflush(stderr); /* just in case */
+ test_exit(SHELL_BOOLEAN(FALSE));
+ }
+ #endif /* SYSV */
+
test_io_error (name)
char *name;
***************
*** 195,198 ****
--- 218,222 ----
*
* term ::=
+ * '!' term
* '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
* '-'('L'|'x') filename
***************
*** 217,221 ****
* expressions of the form '-l string'?
*/
! auto int value, fd;
if (pos >= argc)
--- 241,245 ----
* expressions of the form '-l string'?
*/
! auto int value;
if (pos >= argc)
***************
*** 222,225 ****
--- 246,262 ----
beyond();
+ if ('!' == argv[pos][0] && '\000' == argv[pos][1])
+ {
+ value = FALSE;
+
+ /* Deal with leading "not"s. */
+ while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
+ {
+ advance(1);
+ value ^= (TRUE);
+ }
+ return (value ^ term()); /* recursive descent */
+ }
+
if ('(' == argv[pos][0] && '\000' == argv[pos][1])
{
***************
*** 469,476 ****
case 'r': /* file is readable? */
unary_advance ();
! fd = open (argv[pos - 1], O_RDONLY, 0600);
! if (value = fd != -1)
! close (fd);
!
return (TRUE == value);
--- 506,510 ----
case 'r': /* file is readable? */
unary_advance ();
! value = -1 != access (argv[pos - 1], R_OK);
return (TRUE == value);
***************
*** 477,487 ****
case 'w': /* File is writeable? */
unary_advance ();
! fd = open (argv[pos - 1], O_WRONLY, 0600);
! if (value = fd != -1)
! close (fd);
!
return (TRUE == value);
! case 'x': /* File is executable? */
unary_advance ();
value = -1 != access (argv[pos - 1], X_OK);
--- 511,518 ----
case 'w': /* File is writeable? */
unary_advance ();
! value = -1 != access (argv[pos - 1], W_OK);
return (TRUE == value);
! case 'x': /* File is executable? Should we use executable_file() for this?*/
unary_advance ();
value = -1 != access (argv[pos - 1], X_OK);
***************
*** 600,609 ****
/*
! * or:
! * or '-o' term
* term
*/
static int
! or ()
{
auto int value;
--- 631,640 ----
/*
! * and:
! * and '-a' term
* term
*/
static int
! and ()
{
auto int value;
***************
*** 610,616 ****
value = term ();
! while (pos < argc && '-' == argv[pos][0] && 'o' == argv[pos][1] && '\000' == argv[pos][2]) {
advance(0);
! value = TRUTH_OR (value, term ());
}
return (TRUE == value);
--- 641,647 ----
value = term ();
! while (pos < argc && '-' == argv[pos][0] && 'a' == argv[pos][1] && '\000' == argv[pos][2]) {
advance(0);
! value = TRUTH_AND (value, term ());
}
return (TRUE == value);
***************
*** 618,634 ****
/*
! * and:
! * and '-a' or
! * or
*/
static int
! and()
{
auto int value;
! value = or();
! while (pos < argc && '-' == argv[pos][0] && 'a' == argv[pos][1] && '\000' == argv[pos][2]) {
! advance(1);
! value = TRUTH_AND (value, or());
}
return (TRUE == value);
--- 649,665 ----
/*
! * or:
! * or '-o' and
! * and
*/
static int
! or()
{
auto int value;
! value = and();
! while (pos < argc && '-' == argv[pos][0] && 'o' == argv[pos][1] && '\000' == argv[pos][2]) {
! advance(0);
! value = TRUTH_OR (value, and());
}
return (TRUE == value);
***************
*** 637,642 ****
/*
* expr:
! * '!' expr
! * and
*/
int
--- 668,672 ----
/*
* expr:
! * or
*/
int
***************
*** 643,660 ****
expr()
{
- auto int value;
-
if (pos >= argc)
beyond();
! value = FALSE;
!
! /* Deal with leading "not"'s. */
! while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) {
! advance(1);
!
! /* This has to be rewritten to handle the TRUTH and FALSE stuff. */
! value ^= (TRUE);
! }
! return value ^ and(); /* Same with this. */
}
--- 673,679 ----
expr()
{
if (pos >= argc)
beyond();
! return FALSE ^ or(); /* Same with this. */
}
***************
*** 687,690 ****
--- 706,710 ----
test_exit (SHELL_BOOLEAN (FALSE));
if (']' != margv[margc][0] || '\000' != margv[margc][1]) {
+ argv = margv; /* for test_syntax_error */
test_syntax_error ("missing `]'\n");
}
Chet Ramey "We are preparing to think about contemplating
Network Services Group, CWRU preliminary work on plans to develop a
chet@cwjcc.INS.CWRU.Edu schedule for producing the 10th Edition of
the Unix Programmers Manual." -- Andrew Hume