*** empty log message ***
[coreutils.git] / src / test.c
blob1608aa8a282a0d252e8aa9f6c4f338f1dda09778
1 /* GNU test program (ksb and mjb) */
3 /* Modified to run with the GNU shell by bfox. */
5 /* Copyright (C) 1987-1996, 1997, 1998 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 #define TEST_STANDALONE 1
33 #if !defined (TEST_STANDALONE)
34 # include "shell.h"
35 # include "posixstat.h"
36 # include "filecntl.h"
37 #else /* TEST_STANDALONE */
38 # include "system.h"
39 # include "group-member.h"
40 # include "error.h"
41 # if !defined (S_IXUGO)
42 # define S_IXUGO 0111
43 # endif /* S_IXUGO */
44 # if defined (_POSIX_VERSION)
45 # include <limits.h>
46 # else /* !_POSIX_VERSION */
47 # include <sys/param.h>
48 # endif /* _POSIX_VERSION */
49 # define whitespace(c) (((c) == ' ') || ((c) == '\t'))
50 # define digit(c) ((c) >= '0' && (c) <= '9')
51 # define digit_value(c) ((c) - '0')
52 char *program_name;
53 #endif /* TEST_STANDALONE */
55 #if !defined (_POSIX_VERSION)
56 # include <sys/file.h>
57 #endif /* !_POSIX_VERSION */
59 #include <errno.h>
60 #ifndef errno
61 extern int errno;
62 #endif
64 #undef STREQ
65 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
67 #if !defined (member)
68 # define member(c, s) ((c) ? (strchr ((s), (c)) ? 1 : 0) : 0)
69 #endif /* !member */
71 extern gid_t getegid ();
72 extern uid_t geteuid ();
74 #if !defined (R_OK)
75 # define R_OK 4
76 # define W_OK 2
77 # define X_OK 1
78 # define F_OK 0
79 #endif /* R_OK */
81 /* This name is used solely when printing --version information. */
82 #define COMMAND_NAME "test"
84 /* The following few defines control the truth and false output of each stage.
85 TRUE and FALSE are what we use to compute the final output value.
86 SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
87 TRUTH_OR is how to do logical or with TRUE and FALSE.
88 TRUTH_AND is how to do logical and with TRUE and FALSE..
89 Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
90 SHELL_BOOLEAN = (!value). */
91 #define TRUE 1
92 #define FALSE 0
93 #define SHELL_BOOLEAN(value) (!(value))
94 #define TRUTH_OR(a, b) ((a) | (b))
95 #define TRUTH_AND(a, b) ((a) & (b))
97 #if defined (TEST_STANDALONE)
98 # define test_exit(val) exit (val)
99 #else
100 static jmp_buf test_exit_buf;
101 static int test_error_return = 0;
102 # define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
103 #endif /* !TEST_STANDALONE */
105 static int pos; /* The offset of the current argument in ARGV. */
106 static int argc; /* The number of arguments present in ARGV. */
107 static char **argv; /* The argument list. */
109 static int unop PARAMS ((int op));
110 static int binop PARAMS ((char *s));
111 static int unary_operator PARAMS ((void));
112 static int binary_operator PARAMS ((void));
113 static int two_arguments PARAMS ((void));
114 static int three_arguments PARAMS ((void));
115 static int posixtest PARAMS ((void));
117 static int expr PARAMS ((void));
118 static int term PARAMS ((void));
119 static int and PARAMS ((void));
120 static int or PARAMS ((void));
122 #if __GNUC__ >= 2 && defined (__GNUC_MINOR__) \
123 && __GNUC_MINOR__ >= 5 && !defined (__STRICT_ANSI__)
124 # define NO_RETURN_ATTRIBUTE __attribute__ ((noreturn))
125 #else
126 # define NO_RETURN_ATTRIBUTE /* empty */
127 #endif
129 static void test_syntax_error PARAMS ((char *format, char *arg)) NO_RETURN_ATTRIBUTE;
130 static void beyond PARAMS ((void)) NO_RETURN_ATTRIBUTE;
132 static void
133 test_syntax_error (char *format, char *arg)
135 fprintf (stderr, "%s: ", argv[0]);
136 fprintf (stderr, format, arg);
137 fflush (stderr);
138 test_exit (SHELL_BOOLEAN (FALSE));
141 /* A wrapper for stat () which disallows pathnames that are empty strings. */
142 static int
143 test_stat (char *path, struct stat *finfo)
145 if (*path == '\0')
147 errno = ENOENT;
148 return (-1);
150 return (stat (path, finfo));
153 /* Do the same thing access(2) does, but use the effective uid and gid,
154 and don't make the mistake of telling root that any file is executable.
155 But this loses when the containing filesystem is mounted e.g. read-only. */
156 static int
157 eaccess (char *path, int mode)
159 struct stat st;
160 static int euid = -1;
162 if (test_stat (path, &st) < 0)
163 return (-1);
165 if (euid == -1)
166 euid = geteuid ();
168 if (euid == 0)
170 /* Root can read or write any file. */
171 if (mode != X_OK)
172 return (0);
174 /* Root can execute any file that has any one of the execute
175 bits set. */
176 if (st.st_mode & S_IXUGO)
177 return (0);
180 if (st.st_uid == euid) /* owner */
181 mode <<= 6;
182 else if (group_member (st.st_gid))
183 mode <<= 3;
185 if (st.st_mode & mode)
186 return (0);
188 return (-1);
191 /* Increment our position in the argument list. Check that we're not
192 past the end of the argument list. This check is supressed if the
193 argument is FALSE. Made a macro for efficiency. */
194 #define advance(f) \
195 do \
197 ++pos; \
198 if ((f) && pos >= argc) \
199 beyond (); \
201 while (0)
203 #if !defined (advance)
204 static int
205 advance (int f)
207 ++pos;
209 if (f && pos >= argc)
210 beyond ();
212 #endif /* advance */
214 #define unary_advance() \
215 do \
217 advance (1); \
218 ++pos; \
220 while (0)
223 * beyond - call when we're beyond the end of the argument list (an
224 * error condition)
226 static void
227 beyond (void)
229 test_syntax_error (_("argument expected\n"), NULL);
232 /* Syntax error for when an integer argument was expected, but
233 something else was found. */
234 static void
235 integer_expected_error (char *pch)
237 test_syntax_error (_("integer expression expected %s\n"), pch);
240 /* Return nonzero if the characters pointed to by STRING constitute a
241 valid number. Stuff the converted number into RESULT if RESULT is
242 a non-null pointer to a long. */
243 static int
244 isint (register char *string, long int *result)
246 int sign;
247 long value;
249 sign = 1;
250 value = 0;
252 if (result)
253 *result = 0;
255 /* Skip leading whitespace characters. */
256 while (whitespace (*string))
257 string++;
259 if (!*string)
260 return (0);
262 /* We allow leading `-' or `+'. */
263 if (*string == '-' || *string == '+')
265 if (!digit (string[1]))
266 return (0);
268 if (*string == '-')
269 sign = -1;
271 string++;
274 while (digit (*string))
276 if (result)
277 value = (value * 10) + digit_value (*string);
278 string++;
281 /* Skip trailing whitespace, if any. */
282 while (whitespace (*string))
283 string++;
285 /* Error if not at end of string. */
286 if (*string)
287 return (0);
289 if (result)
291 value *= sign;
292 *result = value;
295 return (1);
298 /* Find the modification time of FILE, and stuff it into AGE, a pointer
299 to a long. Return nonzero if successful, else zero. */
300 static int
301 age_of (char *filename, long int *age)
303 struct stat finfo;
305 if (test_stat (filename, &finfo) < 0)
306 return (0);
308 if (age)
309 *age = finfo.st_mtime;
311 return (1);
315 * term - parse a term and return 1 or 0 depending on whether the term
316 * evaluates to true or false, respectively.
318 * term ::=
319 * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
320 * '-'('L'|'x') filename
321 * '-t' [ int ]
322 * '-'('z'|'n') string
323 * string
324 * string ('!='|'=') string
325 * <int> '-'(eq|ne|le|lt|ge|gt) <int>
326 * file '-'(nt|ot|ef) file
327 * '(' <expr> ')'
328 * int ::=
329 * '-l' string
330 * positive and negative integers
332 static int
333 term (void)
335 int value;
337 if (pos >= argc)
338 beyond ();
340 /* Deal with leading "not"'s. */
341 if ('!' == argv[pos][0] && '\000' == argv[pos][1])
343 value = FALSE;
344 while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
346 advance (1);
347 value ^= (TRUE);
350 return (value ^ (term ()));
353 /* A paren-bracketed argument. */
354 if (argv[pos][0] == '(' && !argv[pos][1])
356 advance (1);
357 value = expr ();
358 if (!argv[pos])
359 test_syntax_error (_("')' expected\n"), NULL);
360 else
361 if (argv[pos][0] != ')' || argv[pos][1])
362 test_syntax_error (_("')' expected, found %s\n"), argv[pos]);
363 advance (0);
364 return (TRUE == (value));
367 /* are there enough arguments left that this could be dyadic? */
368 if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
369 ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
370 value = binary_operator ();
372 /* Might be a switch type argument */
373 else if ('-' == argv[pos][0] && argv[pos][1] && 0 == argv[pos][2])
375 if (unop (argv[pos][1]))
376 value = unary_operator ();
377 else
378 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
380 else
382 value = (argv[pos][0] != '\0');
383 advance (0);
386 return (value);
389 static int
390 binary_operator (void)
392 register int op;
393 struct stat stat_buf, stat_spare;
394 long int l, r, value;
395 /* Are the left and right integer expressions of the form '-l string'? */
396 int l_is_l, r_is_l;
398 if (strcmp (argv[pos], "-l") == 0)
400 l_is_l = 1;
401 op = pos + 2;
403 /* Make sure that OP is still a valid binary operator. */
404 if ((op >= argc - 1) || (binop (argv[op]) == 0))
405 test_syntax_error (_("%s: binary operator expected\n"), argv[op]);
407 advance (0);
409 else
411 l_is_l = 0;
412 op = pos + 1;
415 if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0))
417 r_is_l = 1;
418 advance (0);
420 else
421 r_is_l = 0;
423 if (argv[op][0] == '-')
425 /* check for eq, nt, and stuff */
426 switch (argv[op][1])
428 default:
429 break;
431 case 'l':
432 if (argv[op][2] == 't' && !argv[op][3])
434 /* lt */
435 if (l_is_l)
436 l = strlen (argv[op - 1]);
437 else
439 if (!isint (argv[op - 1], &l))
440 integer_expected_error (_("before -lt"));
443 if (r_is_l)
444 r = strlen (argv[op + 2]);
445 else
447 if (!isint (argv[op + 1], &r))
448 integer_expected_error (_("after -lt"));
450 pos += 3;
451 return (TRUE == (l < r));
454 if (argv[op][2] == 'e' && !argv[op][3])
456 /* le */
457 if (l_is_l)
458 l = strlen (argv[op - 1]);
459 else
461 if (!isint (argv[op - 1], &l))
462 integer_expected_error (_("before -le"));
464 if (r_is_l)
465 r = strlen (argv[op + 2]);
466 else
468 if (!isint (argv[op + 1], &r))
469 integer_expected_error (_("after -le"));
471 pos += 3;
472 return (TRUE == (l <= r));
474 break;
476 case 'g':
477 if (argv[op][2] == 't' && !argv[op][3])
479 /* gt integer greater than */
480 if (l_is_l)
481 l = strlen (argv[op - 1]);
482 else
484 if (!isint (argv[op - 1], &l))
485 integer_expected_error (_("before -gt"));
487 if (r_is_l)
488 r = strlen (argv[op + 2]);
489 else
491 if (!isint (argv[op + 1], &r))
492 integer_expected_error (_("after -gt"));
494 pos += 3;
495 return (TRUE == (l > r));
498 if (argv[op][2] == 'e' && !argv[op][3])
500 /* ge - integer greater than or equal to */
501 if (l_is_l)
502 l = strlen (argv[op - 1]);
503 else
505 if (!isint (argv[op - 1], &l))
506 integer_expected_error (_("before -ge"));
508 if (r_is_l)
509 r = strlen (argv[op + 2]);
510 else
512 if (!isint (argv[op + 1], &r))
513 integer_expected_error (_("after -ge"));
515 pos += 3;
516 return (TRUE == (l >= r));
518 break;
520 case 'n':
521 if (argv[op][2] == 't' && !argv[op][3])
523 /* nt - newer than */
524 pos += 3;
525 if (l_is_l || r_is_l)
526 test_syntax_error (_("-nt does not accept -l\n"), NULL);
527 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
528 return (TRUE == (l > r));
529 else
530 return (FALSE);
533 if (argv[op][2] == 'e' && !argv[op][3])
535 /* ne - integer not equal */
536 if (l_is_l)
537 l = strlen (argv[op - 1]);
538 else
540 if (!isint (argv[op - 1], &l))
541 integer_expected_error (_("before -ne"));
543 if (r_is_l)
544 r = strlen (argv[op + 2]);
545 else
547 if (!isint (argv[op + 1], &r))
548 integer_expected_error (_("after -ne"));
550 pos += 3;
551 return (TRUE == (l != r));
553 break;
555 case 'e':
556 if (argv[op][2] == 'q' && !argv[op][3])
558 /* eq - integer equal */
559 if (l_is_l)
560 l = strlen (argv[op - 1]);
561 else
563 if (!isint (argv[op - 1], &l))
564 integer_expected_error (_("before -eq"));
566 if (r_is_l)
567 r = strlen (argv[op + 2]);
568 else
570 if (!isint (argv[op + 1], &r))
571 integer_expected_error (_("after -eq"));
573 pos += 3;
574 return (TRUE == (l == r));
577 if (argv[op][2] == 'f' && !argv[op][3])
579 /* ef - hard link? */
580 pos += 3;
581 if (l_is_l || r_is_l)
582 test_syntax_error (_("-ef does not accept -l\n"), NULL);
583 if (stat (argv[op - 1], &stat_buf) < 0)
584 return (FALSE);
585 if (stat (argv[op + 1], &stat_spare) < 0)
586 return (FALSE);
587 return (TRUE ==
588 (stat_buf.st_dev == stat_spare.st_dev &&
589 stat_buf.st_ino == stat_spare.st_ino));
591 break;
593 case 'o':
594 if ('t' == argv[op][2] && '\000' == argv[op][3])
596 /* ot - older than */
597 pos += 3;
598 if (l_is_l || r_is_l)
599 test_syntax_error (_("-nt does not accept -l\n"), NULL);
600 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
601 return (TRUE == (l < r));
602 return (FALSE);
604 break;
606 test_syntax_error (_("unknown binary operator"), argv[op]);
609 if (argv[op][0] == '=' && !argv[op][1])
611 value = (strcmp (argv[pos], argv[pos + 2]) == 0);
612 pos += 3;
613 return (TRUE == value);
616 if (strcmp (argv[op], "!=") == 0)
618 value = (strcmp (argv[pos], argv[pos + 2]) != 0);
619 pos += 3;
620 return (TRUE == value);
623 /* Not reached. */
624 abort ();
627 static int
628 unary_operator (void)
630 long fd, value;
631 struct stat stat_buf;
633 switch (argv[pos][1])
635 default:
636 return (FALSE);
638 /* All of the following unary operators use unary_advance (), which
639 checks to make sure that there is an argument, and then advances
640 pos right past it. This means that pos - 1 is the location of the
641 argument. */
643 case 'a': /* file exists in the file system? */
644 case 'e':
645 unary_advance ();
646 value = -1 != test_stat (argv[pos - 1], &stat_buf);
647 return (TRUE == value);
649 case 'r': /* file is readable? */
650 unary_advance ();
651 value = -1 != eaccess (argv[pos - 1], R_OK);
652 return (TRUE == value);
654 case 'w': /* File is writable? */
655 unary_advance ();
656 value = -1 != eaccess (argv[pos - 1], W_OK);
657 return (TRUE == value);
659 case 'x': /* File is executable? */
660 unary_advance ();
661 value = -1 != eaccess (argv[pos - 1], X_OK);
662 return (TRUE == value);
664 case 'O': /* File is owned by you? */
665 unary_advance ();
666 if (test_stat (argv[pos - 1], &stat_buf) < 0)
667 return (FALSE);
669 return (TRUE == (geteuid () == stat_buf.st_uid));
671 case 'G': /* File is owned by your group? */
672 unary_advance ();
673 if (test_stat (argv[pos - 1], &stat_buf) < 0)
674 return (FALSE);
676 return (TRUE == (getegid () == stat_buf.st_gid));
678 case 'f': /* File is a file? */
679 unary_advance ();
680 if (test_stat (argv[pos - 1], &stat_buf) < 0)
681 return (FALSE);
683 /* Under POSIX, -f is true if the given file exists
684 and is a regular file. */
685 return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
686 (0 == (stat_buf.st_mode & S_IFMT))));
688 case 'd': /* File is a directory? */
689 unary_advance ();
690 if (test_stat (argv[pos - 1], &stat_buf) < 0)
691 return (FALSE);
693 return (TRUE == (S_ISDIR (stat_buf.st_mode)));
695 case 's': /* File has something in it? */
696 unary_advance ();
697 if (test_stat (argv[pos - 1], &stat_buf) < 0)
698 return (FALSE);
700 return (TRUE == (stat_buf.st_size > (off_t) 0));
702 case 'S': /* File is a socket? */
703 #if !defined (S_ISSOCK)
704 return (FALSE);
705 #else
706 unary_advance ();
708 if (test_stat (argv[pos - 1], &stat_buf) < 0)
709 return (FALSE);
711 return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
712 #endif /* S_ISSOCK */
714 case 'c': /* File is character special? */
715 unary_advance ();
716 if (test_stat (argv[pos - 1], &stat_buf) < 0)
717 return (FALSE);
719 return (TRUE == (S_ISCHR (stat_buf.st_mode)));
721 case 'b': /* File is block special? */
722 unary_advance ();
723 if (test_stat (argv[pos - 1], &stat_buf) < 0)
724 return (FALSE);
726 return (TRUE == (S_ISBLK (stat_buf.st_mode)));
728 case 'p': /* File is a named pipe? */
729 unary_advance ();
730 #ifndef S_ISFIFO
731 return (FALSE);
732 #else
733 if (test_stat (argv[pos - 1], &stat_buf) < 0)
734 return (FALSE);
735 return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
736 #endif /* S_ISFIFO */
738 case 'L': /* Same as -h */
739 /*FALLTHROUGH*/
741 case 'h': /* File is a symbolic link? */
742 unary_advance ();
743 #ifndef S_ISLNK
744 return (FALSE);
745 #else
746 /* An empty filename is not a valid pathname. */
747 if ((argv[pos - 1][0] == '\0') ||
748 (lstat (argv[pos - 1], &stat_buf) < 0))
749 return (FALSE);
751 return (TRUE == (S_ISLNK (stat_buf.st_mode)));
752 #endif /* S_IFLNK */
754 case 'u': /* File is setuid? */
755 unary_advance ();
756 #ifndef S_ISUID
757 return (FALSE);
758 #else
759 if (test_stat (argv[pos - 1], &stat_buf) < 0)
760 return (FALSE);
762 return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
763 #endif
765 case 'g': /* File is setgid? */
766 unary_advance ();
767 #ifndef S_ISGID
768 return (FALSE);
769 #else
770 if (test_stat (argv[pos - 1], &stat_buf) < 0)
771 return (FALSE);
773 return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
774 #endif
776 case 'k': /* File has sticky bit set? */
777 unary_advance ();
778 if (test_stat (argv[pos - 1], &stat_buf) < 0)
779 return (FALSE);
780 #ifndef S_ISVTX
781 /* This is not Posix, and is not defined on some Posix systems. */
782 return (FALSE);
783 #else
784 return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
785 #endif
787 case 't': /* File (fd) is a terminal? */
788 advance (0);
789 if (pos < argc)
791 if (!isint (argv[pos], &fd))
792 integer_expected_error (_("after -t"));
793 advance (0);
795 else
797 fd = 1;
799 return (TRUE == (isatty ((int) 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"
980 void
981 usage (int status)
983 if (status != 0)
984 fprintf (stderr, _("Try `%s --help' for more information.\n"),
985 program_name);
986 else
988 printf (_("\
989 Usage: %s EXPRESSION\n\
990 or: [ EXPRESSION ]\n\
991 or: %s OPTION\n\
993 program_name, program_name);
994 printf (_("\
995 Exit with the status determined by EXPRESSION.\n\
997 --help display this help and exit\n\
998 --version output version information and exit\n\
1000 EXPRESSION is true or false and sets exit status. It is one of:\n\
1001 "));
1002 printf (_("\
1004 ( EXPRESSION ) EXPRESSION is true\n\
1005 ! EXPRESSION EXPRESSION is false\n\
1006 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\
1007 EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\
1009 [-n] STRING the length of STRING is nonzero\n\
1010 -z STRING the length of STRING is zero\n\
1011 STRING1 = STRING2 the strings are equal\n\
1012 STRING1 != STRING2 the strings are not equal\n\
1014 INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\
1015 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\
1016 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\
1017 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\
1018 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\
1019 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\
1020 "));
1021 printf (_("\
1023 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\
1024 FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\
1025 FILE1 -ot FILE2 FILE1 is older than FILE2\n\
1027 -b FILE FILE exists and is block special\n\
1028 -c FILE FILE exists and is character special\n\
1029 -d FILE FILE exists and is a directory\n\
1030 -e FILE FILE exists\n\
1031 -f FILE FILE exists and is a regular file\n\
1032 -g FILE FILE exists and is set-group-ID\n\
1033 -G FILE FILE exists and is owned by the effective group ID\n\
1034 -k FILE FILE exists and has its sticky bit set\n\
1035 -L FILE FILE exists and is a symbolic link\n\
1036 -O FILE FILE exists and is owned by the effective user ID\n\
1037 -p FILE FILE exists and is a named pipe\n\
1038 -r FILE FILE exists and is readable\n\
1039 -s FILE FILE exists and has a size greater than zero\n\
1040 -S FILE FILE exists and is a socket\n\
1041 -t [FD] file descriptor FD (stdout by default) is opened on a terminal\n\
1042 -u FILE FILE exists and its set-user-ID bit is set\n\
1043 -w FILE FILE exists and is writable\n\
1044 -x FILE FILE exists and is executable\n\
1045 "));
1046 printf (_("\
1048 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
1049 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
1050 "));
1051 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
1053 exit (status);
1055 #endif /* TEST_STANDALONE */
1057 #if !defined (TEST_STANDALONE)
1058 # define main test_command
1059 #endif
1062 * [:
1063 * '[' expr ']'
1064 * test:
1065 * test expr
1068 main (int margc, char **margv)
1070 int value;
1072 #if !defined (TEST_STANDALONE)
1073 int code;
1075 code = setjmp (test_exit_buf);
1077 if (code)
1078 return (test_error_return);
1079 #else /* TEST_STANDALONE */
1080 program_name = margv[0];
1081 setlocale (LC_ALL, "");
1082 bindtextdomain (PACKAGE, LOCALEDIR);
1083 textdomain (PACKAGE);
1084 #endif /* TEST_STANDALONE */
1086 argv = margv;
1088 if (margv[0] && strcmp (margv[0], "[") == 0)
1090 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
1091 if (getenv ("POSIXLY_CORRECT") == NULL)
1092 parse_long_options (argc, argv, COMMAND_NAME, GNU_PACKAGE, VERSION, usage);
1094 --margc;
1096 if (margc < 2)
1097 test_exit (SHELL_BOOLEAN (FALSE));
1099 if (margv[margc] && strcmp (margv[margc], "]") != 0)
1100 test_syntax_error (_("missing `]'\n"), NULL);
1103 argc = margc;
1104 pos = 1;
1106 if (pos >= argc)
1107 test_exit (SHELL_BOOLEAN (FALSE));
1109 parse_long_options (argc, argv, COMMAND_NAME, GNU_PACKAGE, VERSION, usage);
1110 value = posixtest ();
1112 if (pos != argc)
1113 test_syntax_error (_("too many arguments\n"), NULL);
1115 test_exit (SHELL_BOOLEAN (value));