Include exitfail.h.
authorJim Meyering <jim@meyering.net>
Sat, 26 Jul 2003 12:22:42 +0000 (12:22 +0000)
committerJim Meyering <jim@meyering.net>
Sat, 26 Jul 2003 12:22:42 +0000 (12:22 +0000)
(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

index 95cff6ebf835fd0bcc3174dbce7415c79632d35e..fa00a396b4fdb86623cd022602bcc3efbc95e3e9 100644 (file)
 #include <stdio.h>
 #include <sys/types.h>
 
-/* 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);