*** empty log message ***
[coreutils.git] / src / test.c
blobf7b16f27c8dd96f455513b17c8bd8e7920577e96
1 /* GNU test program (ksb and mjb) */
3 /* Modified to run with the GNU shell by bfox. */
5 /* Copyright (C) 1987-2002 Free Software Foundation, Inc.
7 This file is part of GNU Bash, the Bourne Again SHell.
9 Bash is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
12 version.
14 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 /* Define TEST_STANDALONE to get the /bin/test version. Otherwise, you get
24 the shell builtin version. */
25 /* #define TEST_STANDALONE */
27 #include <config.h>
28 #include <stdio.h>
29 #include <sys/types.h>
31 /* The official name of this program (e.g., no `g' prefix). */
32 #define PROGRAM_NAME "test"
34 #define TEST_STANDALONE 1
36 #if !defined (TEST_STANDALONE)
37 # include "shell.h"
38 # include "posixstat.h"
39 # include "filecntl.h"
40 #else /* TEST_STANDALONE */
41 # include "system.h"
42 # include "group-member.h"
43 # include "error.h"
44 # if !defined (S_IXUGO)
45 # define S_IXUGO 0111
46 # endif /* S_IXUGO */
47 # if defined (_POSIX_VERSION)
48 # include <limits.h>
49 # else /* !_POSIX_VERSION */
50 # include <sys/param.h>
51 # endif /* _POSIX_VERSION */
52 # define whitespace(c) (((c) == ' ') || ((c) == '\t'))
53 # define digit(c) ((c) >= '0' && (c) <= '9')
54 # define digit_value(c) ((c) - '0')
55 char *program_name;
56 #endif /* TEST_STANDALONE */
58 #if !defined (_POSIX_VERSION)
59 # include <sys/file.h>
60 #endif /* !_POSIX_VERSION */
62 #include <errno.h>
63 #ifndef errno
64 extern int errno;
65 #endif
67 #undef STREQ
68 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
70 #if !defined (member)
71 # define member(c, s) ((c) ? (strchr ((s), (c)) ? 1 : 0) : 0)
72 #endif /* !member */
74 extern gid_t getegid ();
75 extern uid_t geteuid ();
77 #if !defined (R_OK)
78 # define R_OK 4
79 # define W_OK 2
80 # define X_OK 1
81 # define F_OK 0
82 #endif /* R_OK */
84 /* This name is used solely when printing --version information. */
85 #define PROGRAM_NAME "test"
87 /* The following few defines control the truth and false output of each stage.
88 TRUE and FALSE are what we use to compute the final output value.
89 SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
90 TRUTH_OR is how to do logical or with TRUE and FALSE.
91 TRUTH_AND is how to do logical and with TRUE and FALSE..
92 Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
93 SHELL_BOOLEAN = (!value). */
94 #define TRUE 1
95 #define FALSE 0
96 #define SHELL_BOOLEAN(value) (!(value))
97 #define TRUTH_OR(a, b) ((a) | (b))
98 #define TRUTH_AND(a, b) ((a) & (b))
100 #if defined (TEST_STANDALONE)
101 # define test_exit(val) exit (val)
102 #else
103 static jmp_buf test_exit_buf;
104 static int test_error_return = 0;
105 # define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
106 #endif /* !TEST_STANDALONE */
108 static int pos; /* The offset of the current argument in ARGV. */
109 static int argc; /* The number of arguments present in ARGV. */
110 static char **argv; /* The argument list. */
112 static int unop PARAMS ((int op));
113 static int binop PARAMS ((char *s));
114 static int unary_operator PARAMS ((void));
115 static int binary_operator PARAMS ((void));
116 static int two_arguments PARAMS ((void));
117 static int three_arguments PARAMS ((void));
118 static int posixtest PARAMS ((void));
120 static int expr PARAMS ((void));
121 static int term PARAMS ((void));
122 static int and PARAMS ((void));
123 static int or PARAMS ((void));
125 static void test_syntax_error PARAMS ((char const *format, char const *arg))
126 ATTRIBUTE_NORETURN;
127 static void beyond PARAMS ((void)) ATTRIBUTE_NORETURN;
129 static void
130 test_syntax_error (char const *format, char const *arg)
132 fprintf (stderr, "%s: ", argv[0]);
133 fprintf (stderr, format, arg);
134 fflush (stderr);
135 test_exit (SHELL_BOOLEAN (FALSE));
138 /* A wrapper for stat () which disallows pathnames that are empty strings. */
139 static int
140 test_stat (char *path, struct stat *finfo)
142 if (*path == '\0')
144 errno = ENOENT;
145 return (-1);
147 return (stat (path, finfo));
150 /* Do the same thing access(2) does, but use the effective uid and gid,
151 and don't make the mistake of telling root that any file is executable.
152 But this loses when the containing filesystem is mounted e.g. read-only. */
153 static int
154 eaccess (char *path, int mode)
156 struct stat st;
157 static int euid = -1;
159 if (test_stat (path, &st) < 0)
160 return (-1);
162 if (euid == -1)
163 euid = geteuid ();
165 if (euid == 0)
167 /* Root can read or write any file. */
168 if (mode != X_OK)
169 return (0);
171 /* Root can execute any file that has any one of the execute
172 bits set. */
173 if (st.st_mode & S_IXUGO)
174 return (0);
177 if (st.st_uid == euid) /* owner */
178 mode <<= 6;
179 else if (group_member (st.st_gid))
180 mode <<= 3;
182 if (st.st_mode & mode)
183 return (0);
185 return (-1);
188 /* Increment our position in the argument list. Check that we're not
189 past the end of the argument list. This check is supressed if the
190 argument is FALSE. Made a macro for efficiency. */
191 #define advance(f) \
192 do \
194 ++pos; \
195 if ((f) && pos >= argc) \
196 beyond (); \
198 while (0)
200 #if !defined (advance)
201 static int
202 advance (int f)
204 ++pos;
206 if (f && pos >= argc)
207 beyond ();
209 #endif /* advance */
211 #define unary_advance() \
212 do \
214 advance (1); \
215 ++pos; \
217 while (0)
220 * beyond - call when we're beyond the end of the argument list (an
221 * error condition)
223 static void
224 beyond (void)
226 test_syntax_error (_("argument expected\n"), NULL);
229 /* Syntax error for when an integer argument was expected, but
230 something else was found. */
231 static void
232 integer_expected_error (char const *pch)
234 test_syntax_error (_("integer expression expected %s\n"), pch);
237 /* Return nonzero if the characters pointed to by STRING constitute a
238 valid number. Stuff the converted number into RESULT if RESULT is
239 not null. */
240 static int
241 isint (register char *string, intmax_t *result)
243 int sign;
244 intmax_t value;
246 sign = 1;
247 value = 0;
249 if (result)
250 *result = 0;
252 /* Skip leading whitespace characters. */
253 while (whitespace (*string))
254 string++;
256 if (!*string)
257 return (0);
259 /* We allow leading `-' or `+'. */
260 if (*string == '-' || *string == '+')
262 if (!digit (string[1]))
263 return (0);
265 if (*string == '-')
266 sign = -1;
268 string++;
271 while (digit (*string))
273 if (result)
274 value = (value * 10) + digit_value (*string);
275 string++;
278 /* Skip trailing whitespace, if any. */
279 while (whitespace (*string))
280 string++;
282 /* Error if not at end of string. */
283 if (*string)
284 return (0);
286 if (result)
288 value *= sign;
289 *result = value;
292 return (1);
295 /* Find the modification time of FILE, and stuff it into *AGE.
296 Return 0 if successful, -1 if not. */
297 static int
298 age_of (char *filename, time_t *age)
300 struct stat finfo;
301 int r = test_stat (filename, &finfo);
302 if (r == 0)
303 *age = finfo.st_mtime;
304 return r;
308 * term - parse a term and return 1 or 0 depending on whether the term
309 * evaluates to true or false, respectively.
311 * term ::=
312 * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
313 * '-'('L'|'x') filename
314 * '-t' [ int ]
315 * '-'('z'|'n') string
316 * string
317 * string ('!='|'=') string
318 * <int> '-'(eq|ne|le|lt|ge|gt) <int>
319 * file '-'(nt|ot|ef) file
320 * '(' <expr> ')'
321 * int ::=
322 * '-l' string
323 * positive and negative integers
325 static int
326 term (void)
328 int value;
330 if (pos >= argc)
331 beyond ();
333 /* Deal with leading "not"'s. */
334 if ('!' == argv[pos][0] && '\000' == argv[pos][1])
336 value = FALSE;
337 while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
339 advance (1);
340 value ^= (TRUE);
343 return (value ^ (term ()));
346 /* A paren-bracketed argument. */
347 if (argv[pos][0] == '(' && !argv[pos][1])
349 advance (1);
350 value = expr ();
351 if (!argv[pos])
352 test_syntax_error (_("')' expected\n"), NULL);
353 else
354 if (argv[pos][0] != ')' || argv[pos][1])
355 test_syntax_error (_("')' expected, found %s\n"), argv[pos]);
356 advance (0);
357 return (TRUE == (value));
360 /* are there enough arguments left that this could be dyadic? */
361 if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
362 ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
363 value = binary_operator ();
365 /* Might be a switch type argument */
366 else if ('-' == argv[pos][0] && argv[pos][1] && 0 == argv[pos][2])
368 if (unop (argv[pos][1]))
369 value = unary_operator ();
370 else
371 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
373 else
375 value = (argv[pos][0] != '\0');
376 advance (0);
379 return (value);
382 static int
383 binary_operator (void)
385 register int op;
386 struct stat stat_buf, stat_spare;
387 intmax_t l, r;
388 int value;
389 /* Are the left and right integer expressions of the form '-l string'? */
390 int l_is_l, r_is_l;
392 if (strcmp (argv[pos], "-l") == 0)
394 l_is_l = 1;
395 op = pos + 2;
397 /* Make sure that OP is still a valid binary operator. */
398 if ((op >= argc - 1) || (binop (argv[op]) == 0))
399 test_syntax_error (_("%s: binary operator expected\n"), argv[op]);
401 advance (0);
403 else
405 l_is_l = 0;
406 op = pos + 1;
409 if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0))
411 r_is_l = 1;
412 advance (0);
414 else
415 r_is_l = 0;
417 if (argv[op][0] == '-')
419 /* check for eq, nt, and stuff */
420 switch (argv[op][1])
422 default:
423 break;
425 case 'l':
426 if (argv[op][2] == 't' && !argv[op][3])
428 /* lt */
429 if (l_is_l)
430 l = strlen (argv[op - 1]);
431 else
433 if (!isint (argv[op - 1], &l))
434 integer_expected_error (_("before -lt"));
437 if (r_is_l)
438 r = strlen (argv[op + 2]);
439 else
441 if (!isint (argv[op + 1], &r))
442 integer_expected_error (_("after -lt"));
444 pos += 3;
445 return (TRUE == (l < r));
448 if (argv[op][2] == 'e' && !argv[op][3])
450 /* le */
451 if (l_is_l)
452 l = strlen (argv[op - 1]);
453 else
455 if (!isint (argv[op - 1], &l))
456 integer_expected_error (_("before -le"));
458 if (r_is_l)
459 r = strlen (argv[op + 2]);
460 else
462 if (!isint (argv[op + 1], &r))
463 integer_expected_error (_("after -le"));
465 pos += 3;
466 return (TRUE == (l <= r));
468 break;
470 case 'g':
471 if (argv[op][2] == 't' && !argv[op][3])
473 /* gt integer greater than */
474 if (l_is_l)
475 l = strlen (argv[op - 1]);
476 else
478 if (!isint (argv[op - 1], &l))
479 integer_expected_error (_("before -gt"));
481 if (r_is_l)
482 r = strlen (argv[op + 2]);
483 else
485 if (!isint (argv[op + 1], &r))
486 integer_expected_error (_("after -gt"));
488 pos += 3;
489 return (TRUE == (l > r));
492 if (argv[op][2] == 'e' && !argv[op][3])
494 /* ge - integer greater than or equal to */
495 if (l_is_l)
496 l = strlen (argv[op - 1]);
497 else
499 if (!isint (argv[op - 1], &l))
500 integer_expected_error (_("before -ge"));
502 if (r_is_l)
503 r = strlen (argv[op + 2]);
504 else
506 if (!isint (argv[op + 1], &r))
507 integer_expected_error (_("after -ge"));
509 pos += 3;
510 return (TRUE == (l >= r));
512 break;
514 case 'n':
515 if (argv[op][2] == 't' && !argv[op][3])
517 /* nt - newer than */
518 time_t lt, rt;
519 int le, re;
520 pos += 3;
521 if (l_is_l || r_is_l)
522 test_syntax_error (_("-nt does not accept -l\n"), NULL);
523 le = age_of (argv[op - 1], &lt);
524 re = age_of (argv[op + 1], &rt);
525 return le > re || (le == 0 && lt > rt);
528 if (argv[op][2] == 'e' && !argv[op][3])
530 /* ne - integer not equal */
531 if (l_is_l)
532 l = strlen (argv[op - 1]);
533 else
535 if (!isint (argv[op - 1], &l))
536 integer_expected_error (_("before -ne"));
538 if (r_is_l)
539 r = strlen (argv[op + 2]);
540 else
542 if (!isint (argv[op + 1], &r))
543 integer_expected_error (_("after -ne"));
545 pos += 3;
546 return (TRUE == (l != r));
548 break;
550 case 'e':
551 if (argv[op][2] == 'q' && !argv[op][3])
553 /* eq - integer equal */
554 if (l_is_l)
555 l = strlen (argv[op - 1]);
556 else
558 if (!isint (argv[op - 1], &l))
559 integer_expected_error (_("before -eq"));
561 if (r_is_l)
562 r = strlen (argv[op + 2]);
563 else
565 if (!isint (argv[op + 1], &r))
566 integer_expected_error (_("after -eq"));
568 pos += 3;
569 return (TRUE == (l == r));
572 if (argv[op][2] == 'f' && !argv[op][3])
574 /* ef - hard link? */
575 pos += 3;
576 if (l_is_l || r_is_l)
577 test_syntax_error (_("-ef does not accept -l\n"), NULL);
578 if (stat (argv[op - 1], &stat_buf) < 0)
579 return (FALSE);
580 if (stat (argv[op + 1], &stat_spare) < 0)
581 return (FALSE);
582 return (TRUE ==
583 (stat_buf.st_dev == stat_spare.st_dev &&
584 stat_buf.st_ino == stat_spare.st_ino));
586 break;
588 case 'o':
589 if ('t' == argv[op][2] && '\000' == argv[op][3])
591 /* ot - older than */
592 time_t lt, rt;
593 int le, re;
594 pos += 3;
595 if (l_is_l || r_is_l)
596 test_syntax_error (_("-ot does not accept -l\n"), NULL);
597 le = age_of (argv[op - 1], &lt);
598 re = age_of (argv[op + 1], &rt);
599 return le < re || (re == 0 && lt < rt);
601 break;
603 test_syntax_error (_("unknown binary operator"), argv[op]);
606 if (argv[op][0] == '=' && !argv[op][1])
608 value = (strcmp (argv[pos], argv[pos + 2]) == 0);
609 pos += 3;
610 return (TRUE == value);
613 if (strcmp (argv[op], "!=") == 0)
615 value = (strcmp (argv[pos], argv[pos + 2]) != 0);
616 pos += 3;
617 return (TRUE == value);
620 /* Not reached. */
621 abort ();
624 static int
625 unary_operator (void)
627 int value;
628 struct stat stat_buf;
630 switch (argv[pos][1])
632 default:
633 return (FALSE);
635 /* All of the following unary operators use unary_advance (), which
636 checks to make sure that there is an argument, and then advances
637 pos right past it. This means that pos - 1 is the location of the
638 argument. */
640 case 'a': /* file exists in the file system? */
641 case 'e':
642 unary_advance ();
643 value = -1 != test_stat (argv[pos - 1], &stat_buf);
644 return (TRUE == value);
646 case 'r': /* file is readable? */
647 unary_advance ();
648 value = -1 != eaccess (argv[pos - 1], R_OK);
649 return (TRUE == value);
651 case 'w': /* File is writable? */
652 unary_advance ();
653 value = -1 != eaccess (argv[pos - 1], W_OK);
654 return (TRUE == value);
656 case 'x': /* File is executable? */
657 unary_advance ();
658 value = -1 != eaccess (argv[pos - 1], X_OK);
659 return (TRUE == value);
661 case 'O': /* File is owned by you? */
662 unary_advance ();
663 if (test_stat (argv[pos - 1], &stat_buf) < 0)
664 return (FALSE);
666 return (TRUE == (geteuid () == stat_buf.st_uid));
668 case 'G': /* File is owned by your group? */
669 unary_advance ();
670 if (test_stat (argv[pos - 1], &stat_buf) < 0)
671 return (FALSE);
673 return (TRUE == (getegid () == stat_buf.st_gid));
675 case 'f': /* File is a file? */
676 unary_advance ();
677 if (test_stat (argv[pos - 1], &stat_buf) < 0)
678 return (FALSE);
680 /* Under POSIX, -f is true if the given file exists
681 and is a regular file. */
682 return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
683 (0 == (stat_buf.st_mode & S_IFMT))));
685 case 'd': /* File is a directory? */
686 unary_advance ();
687 if (test_stat (argv[pos - 1], &stat_buf) < 0)
688 return (FALSE);
690 return (TRUE == (S_ISDIR (stat_buf.st_mode)));
692 case 's': /* File has something in it? */
693 unary_advance ();
694 if (test_stat (argv[pos - 1], &stat_buf) < 0)
695 return (FALSE);
697 return (TRUE == (stat_buf.st_size > (off_t) 0));
699 case 'S': /* File is a socket? */
700 #if !defined (S_ISSOCK)
701 return (FALSE);
702 #else
703 unary_advance ();
705 if (test_stat (argv[pos - 1], &stat_buf) < 0)
706 return (FALSE);
708 return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
709 #endif /* S_ISSOCK */
711 case 'c': /* File is character special? */
712 unary_advance ();
713 if (test_stat (argv[pos - 1], &stat_buf) < 0)
714 return (FALSE);
716 return (TRUE == (S_ISCHR (stat_buf.st_mode)));
718 case 'b': /* File is block special? */
719 unary_advance ();
720 if (test_stat (argv[pos - 1], &stat_buf) < 0)
721 return (FALSE);
723 return (TRUE == (S_ISBLK (stat_buf.st_mode)));
725 case 'p': /* File is a named pipe? */
726 unary_advance ();
727 #ifndef S_ISFIFO
728 return (FALSE);
729 #else
730 if (test_stat (argv[pos - 1], &stat_buf) < 0)
731 return (FALSE);
732 return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
733 #endif /* S_ISFIFO */
735 case 'L': /* Same as -h */
736 /*FALLTHROUGH*/
738 case 'h': /* File is a symbolic link? */
739 unary_advance ();
740 #ifndef S_ISLNK
741 return (FALSE);
742 #else
743 /* An empty filename is not a valid pathname. */
744 if ((argv[pos - 1][0] == '\0') ||
745 (lstat (argv[pos - 1], &stat_buf) < 0))
746 return (FALSE);
748 return (TRUE == (S_ISLNK (stat_buf.st_mode)));
749 #endif /* S_IFLNK */
751 case 'u': /* File is setuid? */
752 unary_advance ();
753 #ifndef S_ISUID
754 return (FALSE);
755 #else
756 if (test_stat (argv[pos - 1], &stat_buf) < 0)
757 return (FALSE);
759 return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
760 #endif
762 case 'g': /* File is setgid? */
763 unary_advance ();
764 #ifndef S_ISGID
765 return (FALSE);
766 #else
767 if (test_stat (argv[pos - 1], &stat_buf) < 0)
768 return (FALSE);
770 return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
771 #endif
773 case 'k': /* File has sticky bit set? */
774 unary_advance ();
775 if (test_stat (argv[pos - 1], &stat_buf) < 0)
776 return (FALSE);
777 #ifndef S_ISVTX
778 /* This is not Posix, and is not defined on some Posix systems. */
779 return (FALSE);
780 #else
781 return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
782 #endif
784 case 't': /* File (fd) is a terminal? */
786 intmax_t fd;
787 advance (0);
788 if (pos < argc)
790 if (!isint (argv[pos], &fd))
791 integer_expected_error (_("after -t"));
792 advance (0);
794 else
796 fd = 1;
798 return (TRUE == (fd == (int) fd && isatty (fd)));
801 case 'n': /* True if arg has some length. */
802 unary_advance ();
803 return (TRUE == (argv[pos - 1][0] != 0));
805 case 'z': /* True if arg has no length. */
806 unary_advance ();
807 return (TRUE == (argv[pos - 1][0] == '\0'));
812 * and:
813 * term
814 * term '-a' and
816 static int
817 and (void)
819 int value;
821 value = term ();
822 while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
824 advance (0);
825 value = TRUTH_AND (value, and ());
827 return (TRUE == value);
831 * or:
832 * and
833 * and '-o' or
835 static int
836 or (void)
838 int value;
840 value = and ();
842 while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
844 advance (0);
845 value = TRUTH_OR (value, or ());
848 return (TRUE == value);
852 * expr:
853 * or
855 static int
856 expr (void)
858 if (pos >= argc)
859 beyond ();
861 return (FALSE ^ (or ())); /* Same with this. */
864 /* Return TRUE if S is one of the test command's binary operators. */
865 static int
866 binop (char *s)
868 return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) ||
869 (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
870 (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
871 (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
874 /* Return nonzero if OP is one of the test command's unary operators. */
875 static int
876 unop (int op)
878 return (member (op, "abcdefgkLhprsStuwxOGnz"));
881 static int
882 one_argument (const char *s)
884 if (STREQ (s, "-t"))
885 return (TRUE == (isatty (1)));
887 return strlen (s) != 0;
890 static int
891 two_arguments (void)
893 int value;
895 if (STREQ (argv[pos], "!"))
896 value = ! one_argument (argv[pos+1]);
897 else if (argv[pos][0] == '-'
898 && argv[pos][1] != '\0'
899 && argv[pos][2] == '\0')
901 if (unop (argv[pos][1]))
902 value = unary_operator ();
903 else
904 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
906 else
907 beyond ();
908 return (value);
911 static int
912 three_arguments (void)
914 int value;
916 if (STREQ (argv[pos], "!"))
918 advance (1);
919 value = !two_arguments ();
921 else if (binop (argv[pos+1]))
923 value = binary_operator ();
924 pos = argc;
926 else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
927 (argv[pos][0] == '('))
928 value = expr ();
929 else
930 test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
931 return (value);
934 /* This is an implementation of a Posix.2 proposal by David Korn. */
935 static int
936 posixtest (void)
938 int value;
940 switch (argc - 1) /* one extra passed in */
942 case 0:
943 value = FALSE;
944 pos = argc;
945 break;
947 case 1:
948 value = one_argument (argv[1]);
949 pos = argc;
950 break;
952 case 2:
953 value = two_arguments ();
954 pos = argc;
955 break;
957 case 3:
958 value = three_arguments ();
959 break;
961 case 4:
962 if (STREQ (argv[pos], "!"))
964 advance (1);
965 value = !three_arguments ();
966 break;
968 /* FALLTHROUGH */
969 case 5:
970 default:
971 value = expr ();
974 return (value);
977 #if defined (TEST_STANDALONE)
978 # include "long-options.h"
979 # include "closeout.h"
981 void
982 usage (int status)
984 if (status != 0)
985 fprintf (stderr, _("Try `%s --help' for more information.\n"),
986 program_name);
987 else
989 printf (_("\
990 Usage: %s EXPRESSION\n\
991 or: [ EXPRESSION ]\n\
992 or: %s OPTION\n\
994 program_name, program_name);
995 fputs (_("\
996 Exit with the status determined by EXPRESSION.\n\
998 "), stdout);
999 fputs (HELP_OPTION_DESCRIPTION, stdout);
1000 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1001 fputs (_("\
1003 EXPRESSION is true or false and sets exit status. It is one of:\n\
1004 "), stdout);
1005 fputs (_("\
1007 ( EXPRESSION ) EXPRESSION is true\n\
1008 ! EXPRESSION EXPRESSION is false\n\
1009 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\
1010 EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\
1011 "), stdout);
1012 fputs (_("\
1014 [-n] STRING the length of STRING is nonzero\n\
1015 -z STRING the length of STRING is zero\n\
1016 STRING1 = STRING2 the strings are equal\n\
1017 STRING1 != STRING2 the strings are not equal\n\
1018 "), stdout);
1019 fputs (_("\
1021 INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\
1022 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\
1023 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\
1024 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\
1025 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\
1026 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\
1027 "), stdout);
1028 fputs (_("\
1030 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\
1031 FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\
1032 FILE1 -ot FILE2 FILE1 is older than FILE2\n\
1033 "), stdout);
1034 fputs (_("\
1036 -b FILE FILE exists and is block special\n\
1037 -c FILE FILE exists and is character special\n\
1038 -d FILE FILE exists and is a directory\n\
1039 -e FILE FILE exists\n\
1040 "), stdout);
1041 fputs (_("\
1042 -f FILE FILE exists and is a regular file\n\
1043 -g FILE FILE exists and is set-group-ID\n\
1044 -h FILE FILE exists and is a symbolic link (same as -L)\n\
1045 -G FILE FILE exists and is owned by the effective group ID\n\
1046 -k FILE FILE exists and has its sticky bit set\n\
1047 "), stdout);
1048 fputs (_("\
1049 -L FILE FILE exists and is a symbolic link (same as -h)\n\
1050 -O FILE FILE exists and is owned by the effective user ID\n\
1051 -p FILE FILE exists and is a named pipe\n\
1052 -r FILE FILE exists and is readable\n\
1053 -s FILE FILE exists and has a size greater than zero\n\
1054 "), stdout);
1055 fputs (_("\
1056 -S FILE FILE exists and is a socket\n\
1057 -t [FD] file descriptor FD (stdout by default) is opened on a terminal\n\
1058 -u FILE FILE exists and its set-user-ID bit is set\n\
1059 -w FILE FILE exists and is writable\n\
1060 -x FILE FILE exists and is executable\n\
1061 "), stdout);
1062 fputs (_("\
1064 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
1065 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
1066 "), stdout);
1067 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1069 exit (status);
1071 #endif /* TEST_STANDALONE */
1073 #if !defined (TEST_STANDALONE)
1074 # define main test_command
1075 #endif
1077 #define AUTHORS N_ ("FIXME: ksb and mjb")
1080 * [:
1081 * '[' expr ']'
1082 * test:
1083 * test expr
1086 main (int margc, char **margv)
1088 int value;
1090 #if !defined (TEST_STANDALONE)
1091 int code;
1093 code = setjmp (test_exit_buf);
1095 if (code)
1096 return (test_error_return);
1097 #else /* TEST_STANDALONE */
1098 program_name = margv[0];
1099 setlocale (LC_ALL, "");
1100 bindtextdomain (PACKAGE, LOCALEDIR);
1101 textdomain (PACKAGE);
1103 atexit (close_stdout);
1104 #endif /* TEST_STANDALONE */
1106 argv = margv;
1108 if (margv[0] && strcmp (margv[0], "[") == 0)
1110 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
1111 if (getenv ("POSIXLY_CORRECT") == NULL)
1112 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
1113 AUTHORS, usage);
1115 --margc;
1117 if (margc < 2)
1118 test_exit (SHELL_BOOLEAN (FALSE));
1120 if (margv[margc] && strcmp (margv[margc], "]") != 0)
1121 test_syntax_error (_("missing `]'\n"), NULL);
1124 argc = margc;
1125 pos = 1;
1127 if (pos >= argc)
1128 test_exit (SHELL_BOOLEAN (FALSE));
1130 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
1131 AUTHORS, usage);
1132 value = posixtest ();
1134 if (pos != argc)
1135 test_syntax_error (_("too many arguments\n"), NULL);
1137 test_exit (SHELL_BOOLEAN (value));