From 9fed987cf27c75e141a9fe3dac1ca4923ea48b6d Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 26 Jul 2003 12:22:42 +0000 Subject: [PATCH] Include exitfail.h. (TEST_FAILURE): New constant, used for exit status if 'test' fails. (test-syntax_error): Use it. (binary_operator): Now takes bool arg specifying whether left operand is -l ARG, so that caller determines this rather than us. All uses changed. (term): Use posixtest to evaluate parenthesized subexpressions. (unary_operator, one_argument): Remove support for -t without operand. (one_argument): Take argument from argv[pos]. (one_argument, two_arguments, three_arguments): Advance pos. All callers changed. (three_arguments): Look for binary ops before "!". Then look for parenthesized one_argument expressions, instead of trusting expr () to do the right thing. (posixtest): Now takes number of args. All callers changed. Treat "( A B )" like "A B". (main): Set exit_failure to TEST_FAILURE. Don't depend on POSIXLY_CORRECT, as we now conform to POSIX by default. (main) [!LBRACKET]: Do not recognize "--help" or "--verbose" unless. --- src/test.c | 163 +++++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 80 deletions(-) diff --git a/src/test.c b/src/test.c index 95cff6ebf..fa00a396b 100644 --- a/src/test.c +++ b/src/test.c @@ -27,17 +27,22 @@ #include #include -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "test" - #define TEST_STANDALONE 1 #ifndef LBRACKET # define LBRACKET 0 #endif +/* The official name of this program (e.g., no `g' prefix). */ +#if LBRACKET +# define PROGRAM_NAME "[" +#else +# define PROGRAM_NAME "test" +#endif + #include "system.h" #include "error.h" +#include "exitfail.h" #include "euidaccess.h" #ifndef _POSIX_VERSION @@ -63,9 +68,6 @@ extern uid_t geteuid (); # define F_OK 0 #endif /* R_OK */ -/* This name is used solely when printing --version information. */ -#define PROGRAM_NAME "test" - /* The following few defines control the truth and false output of each stage. TRUE and FALSE are what we use to compute the final output value. SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. @@ -79,6 +81,9 @@ extern uid_t geteuid (); #define TRUTH_OR(a, b) ((a) | (b)) #define TRUTH_AND(a, b) ((a) & (b)) +/* Exit status for syntax errors, etc. */ +enum { TEST_FAILURE = 2 }; + #if defined (TEST_STANDALONE) # define test_exit(val) exit (val) #else @@ -94,10 +99,10 @@ static char **argv; /* The argument list. */ static int test_unop (char const *s); static int binop (char *s); static int unary_operator (void); -static int binary_operator (void); +static int binary_operator (bool); static int two_arguments (void); static int three_arguments (void); -static int posixtest (void); +static int posixtest (int); static int expr (void); static int term (void); @@ -114,7 +119,7 @@ test_syntax_error (char const *format, char const *arg) fprintf (stderr, "%s: ", argv[0]); fprintf (stderr, format, arg); fflush (stderr); - test_exit (SHELL_BOOLEAN (FALSE)); + test_exit (TEST_FAILURE); } #if HAVE_SETREUID && HAVE_SETREGID @@ -318,8 +323,20 @@ term (void) /* A paren-bracketed argument. */ if (argv[pos][0] == '(' && argv[pos][1] == '\0') { + int nargs; + advance (1); - value = expr (); + + for (nargs = 1; + pos + nargs < argc && ! STREQ (argv[pos + nargs], ")"); + nargs++) + if (nargs == 4) + { + nargs = argc - pos; + break; + } + + value = posixtest (nargs); if (argv[pos] == 0) test_syntax_error (_("')' expected\n"), NULL); else @@ -330,9 +347,10 @@ term (void) } /* are there enough arguments left that this could be dyadic? */ - if (((pos + 3 <= argc) && binop (argv[pos + 1])) || - ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2])))) - value = binary_operator (); + if (pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2])) + value = binary_operator (true); + else if (pos + 3 <= argc && binop (argv[pos + 1])) + value = binary_operator (false); /* Might be a switch type argument */ else if (argv[pos][0] == '-' && argv[pos][1] && argv[pos][2] == '\0') @@ -352,31 +370,18 @@ term (void) } static int -binary_operator (void) +binary_operator (bool l_is_l) { register int op; struct stat stat_buf, stat_spare; intmax_t l, r; int value; - /* Are the left and right integer expressions of the form '-l string'? */ - int l_is_l, r_is_l; - - if (strcmp (argv[pos], "-l") == 0) - { - l_is_l = 1; - op = pos + 2; - - /* Make sure that OP is still a valid binary operator. */ - if ((op >= argc - 1) || (binop (argv[op]) == 0)) - test_syntax_error (_("%s: binary operator expected\n"), argv[op]); + /* Is the right integer expression of the form '-l string'? */ + int r_is_l; - advance (0); - } - else - { - l_is_l = 0; - op = pos + 1; - } + if (l_is_l) + advance (0); + op = pos + 1; if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0)) { @@ -758,17 +763,9 @@ unary_operator (void) case 't': /* File (fd) is a terminal? */ { intmax_t fd; - advance (0); - if (pos < argc) - { - if (!isint (argv[pos], &fd)) - integer_expected_error (_("after -t")); - advance (0); - } - else - { - fd = 1; - } + unary_advance (); + if (!isint (argv[pos - 1], &fd)) + integer_expected_error (_("after -t")); return (TRUE == (fd == (int) fd && isatty (fd))); } @@ -866,12 +863,9 @@ test_unop (char const *op) } static int -one_argument (const char *s) +one_argument (void) { - if (! getenv ("POSIXLY_CORRECT") && STREQ (s, "-t")) - return (TRUE == (isatty (1))); - - return strlen (s) != 0; + return argv[pos++][0] != '\0'; } static int @@ -880,7 +874,10 @@ two_arguments (void) int value; if (STREQ (argv[pos], "!")) - value = ! one_argument (argv[pos+1]); + { + advance (0); + value = ! one_argument (); + } else if (argv[pos][0] == '-' && argv[pos][1] != '\0' && argv[pos][2] == '\0') @@ -900,18 +897,20 @@ three_arguments (void) { int value; - if (STREQ (argv[pos], "!")) + if (binop (argv[pos + 1])) + value = binary_operator (false); + else if (STREQ (argv[pos], "!")) { advance (1); value = !two_arguments (); } - else if (binop (argv[pos+1])) + else if (STREQ (argv[pos], "(") && STREQ (argv[pos + 2], ")")) { - value = binary_operator (); - pos = argc; + advance (0); + value = one_argument (); + advance (0); } - else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) || - (argv[pos][0] == '(')) + else if (STREQ (argv[pos + 1], "-a") || STREQ (argv[pos + 1], "-o")) value = expr (); else test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]); @@ -920,25 +919,18 @@ three_arguments (void) /* This is an implementation of a Posix.2 proposal by David Korn. */ static int -posixtest (void) +posixtest (int nargs) { int value; - switch (argc - 1) /* one extra passed in */ + switch (nargs) { - case 0: - value = FALSE; - pos = argc; - break; - case 1: - value = one_argument (argv[1]); - pos = argc; + value = one_argument (); break; case 2: value = two_arguments (); - pos = argc; break; case 3: @@ -952,9 +944,18 @@ posixtest (void) value = !three_arguments (); break; } + if (STREQ (argv[pos], "(") && STREQ (argv[pos + 3], ")")) + { + advance (0); + value = two_arguments (); + advance (0); + break; + } /* FALLTHROUGH */ case 5: default: + if (nargs <= 0) + abort (); value = expr (); } @@ -972,13 +973,10 @@ usage (int status) program_name); else { - printf (_("\ -Usage: %s EXPRESSION\n\ - or: [ EXPRESSION ]\n\ - or: %s OPTION\n\ -"), - program_name, program_name); fputs (_("\ +Usage: test EXPRESSION\n\ + or: [ EXPRESSION ]\n\ + or: [ OPTION\n\ Exit with the status determined by EXPRESSION.\n\ \n\ "), stdout); @@ -1087,22 +1085,27 @@ main (int margc, char **margv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); + exit_failure = TEST_FAILURE; atexit (close_stdout); #endif /* TEST_STANDALONE */ - /* Recognize --help or --version unless POSIXLY_CORRECT is set. */ - if (! getenv ("POSIXLY_CORRECT")) - parse_long_options (margc, margv, PROGRAM_NAME, GNU_PACKAGE, VERSION, - AUTHORS, usage); - argv = margv; if (LBRACKET) { - --margc; + /* Recognize --help or --version, but only when invoked in the + "[" form, and when the last argument is not "]". POSIX + allows "[ --help" and "[ --version" to have the usual GNU + behavior, but it requires "test --help" and "test --version" + to exit silently with status 1. */ + if (margc < 2 || strcmp (margv[margc - 1], "]") != 0) + { + parse_long_options (margc, margv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + test_syntax_error (_("missing `]'\n"), NULL); + } - if (margc < 1 || strcmp (margv[margc], "]") != 0) - test_syntax_error (_("missing `]'\n"), NULL); + --margc; } argc = margc; @@ -1111,7 +1114,7 @@ main (int margc, char **margv) if (pos >= argc) test_exit (SHELL_BOOLEAN (FALSE)); - value = posixtest (); + value = posixtest (argc - 1); if (pos != argc) test_syntax_error (_("too many arguments\n"), NULL); -- 2.34.1