.
[coreutils.git] / src / test.c
blob28059aab82f8c7bf467492a87d84fa42e0c3569c
1 /* GNU test program (ksb and mjb) */
3 /* Modified to run with the GNU shell by bfox. */
5 /* Copyright (C) 1987-1996, 1997 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] && 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 r, 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? (fd) defaults to stdout. */
788 advance (0);
789 if (pos < argc && isint (argv[pos], &r))
791 advance (0);
792 return (TRUE == (isatty ((int) r)));
794 return (TRUE == (isatty (1)));
796 case 'n': /* True if arg has some length. */
797 unary_advance ();
798 return (TRUE == (argv[pos - 1][0] != 0));
800 case 'z': /* True if arg has no length. */
801 unary_advance ();
802 return (TRUE == (argv[pos - 1][0] == '\0'));
807 * and:
808 * term
809 * term '-a' and
811 static int
812 and (void)
814 int value;
816 value = term ();
817 while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
819 advance (0);
820 value = TRUTH_AND (value, and ());
822 return (TRUE == value);
826 * or:
827 * and
828 * and '-o' or
830 static int
831 or (void)
833 int value;
835 value = and ();
837 while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
839 advance (0);
840 value = TRUTH_OR (value, or ());
843 return (TRUE == value);
847 * expr:
848 * or
850 static int
851 expr (void)
853 if (pos >= argc)
854 beyond ();
856 return (FALSE ^ (or ())); /* Same with this. */
859 /* Return TRUE if S is one of the test command's binary operators. */
860 static int
861 binop (char *s)
863 return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) ||
864 (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
865 (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
866 (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
869 /* Return nonzero if OP is one of the test command's unary operators. */
870 static int
871 unop (int op)
873 return (member (op, "abcdefgkLhprsStuwxOGnz"));
876 static int
877 two_arguments (void)
879 int value;
881 if (STREQ (argv[pos], "!"))
882 value = strlen (argv[pos+1]) == 0;
883 else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0'))
885 if (unop (argv[pos][1]))
886 value = unary_operator ();
887 else
888 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
890 else
891 beyond ();
892 return (value);
895 static int
896 three_arguments (void)
898 int value;
900 if (STREQ (argv[pos], "!"))
902 advance (1);
903 value = !two_arguments ();
905 else if (binop (argv[pos+1]))
907 value = binary_operator ();
908 pos = argc;
910 else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
911 (argv[pos][0] == '('))
912 value = expr ();
913 else
914 test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
915 return (value);
918 /* This is an implementation of a Posix.2 proposal by David Korn. */
919 static int
920 posixtest (void)
922 int value;
924 switch (argc - 1) /* one extra passed in */
926 case 0:
927 value = FALSE;
928 pos = argc;
929 break;
931 case 1:
932 value = strlen (argv[1]) != 0;
933 pos = argc;
934 break;
936 case 2:
937 value = two_arguments ();
938 pos = argc;
939 break;
941 case 3:
942 value = three_arguments ();
943 break;
945 case 4:
946 if (STREQ (argv[pos], "!"))
948 advance (1);
949 value = !three_arguments ();
950 break;
952 /* FALLTHROUGH */
953 case 5:
954 default:
955 value = expr ();
958 return (value);
961 #if defined (TEST_STANDALONE)
962 # include "long-options.h"
964 static void
965 usage (int status)
967 if (status != 0)
968 fprintf (stderr, _("Try `%s --help' for more information.\n"),
969 program_name);
970 else
972 printf (_("\
973 Usage: %s EXPRESSION\n\
974 or: [ EXPRESSION ]\n\
975 or: %s OPTION\n\
977 program_name, program_name);
978 printf (_("\
979 Exit with the status determined by EXPRESSION.\n\
981 --help display this help and exit\n\
982 --version output version information and exit\n\
984 EXPRESSION is true or false and sets exit status. It is one of:\n\
985 "));
986 printf (_("\
988 ( EXPRESSION ) EXPRESSION is true\n\
989 ! EXPRESSION EXPRESSION is false\n\
990 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\
991 EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\
993 [-n] STRING the length of STRING is nonzero\n\
994 -z STRING the length of STRING is zero\n\
995 STRING1 = STRING2 the strings are equal\n\
996 STRING1 != STRING2 the strings are not equal\n\
998 INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\
999 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\
1000 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\
1001 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\
1002 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\
1003 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\
1004 "));
1005 printf (_("\
1007 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\
1008 FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\
1009 FILE1 -ot FILE2 FILE1 is older than FILE2\n\
1011 -b FILE FILE exists and is block special\n\
1012 -c FILE FILE exists and is character special\n\
1013 -d FILE FILE exists and is a directory\n\
1014 -e FILE FILE exists\n\
1015 -f FILE FILE exists and is a regular file\n\
1016 -g FILE FILE exists and is set-group-ID\n\
1017 -G FILE FILE exists and is owned by the effective group ID\n\
1018 -k FILE FILE exists and has its sticky bit set\n\
1019 -L FILE FILE exists and is a symbolic link\n\
1020 -O FILE FILE exists and is owned by the effective user ID\n\
1021 -p FILE FILE exists and is a named pipe\n\
1022 -r FILE FILE exists and is readable\n\
1023 -s FILE FILE exists and has a size greater than zero\n\
1024 -S FILE FILE exists and is a socket\n\
1025 -t [FD] file descriptor FD (stdout by default) is opened on a terminal\n\
1026 -u FILE FILE exists and its set-user-ID bit is set\n\
1027 -w FILE FILE exists and is writable\n\
1028 -x FILE FILE exists and is executable\n\
1029 "));
1030 printf (_("\
1032 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
1033 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
1034 "));
1035 puts (_("\nReport bugs to <sh-utils-bugs@gnu.org>."));
1037 exit (status);
1039 #endif /* TEST_STANDALONE */
1041 #if !defined (TEST_STANDALONE)
1042 # define main test_command
1043 #endif
1046 * [:
1047 * '[' expr ']'
1048 * test:
1049 * test expr
1052 main (int margc, char **margv)
1054 int value;
1056 #if !defined (TEST_STANDALONE)
1057 int code;
1059 code = setjmp (test_exit_buf);
1061 if (code)
1062 return (test_error_return);
1063 #else /* TEST_STANDALONE */
1064 program_name = margv[0];
1065 setlocale (LC_ALL, "");
1066 bindtextdomain (PACKAGE, LOCALEDIR);
1067 textdomain (PACKAGE);
1068 #endif /* TEST_STANDALONE */
1070 argv = margv;
1072 if (margv[0] && strcmp (margv[0], "[") == 0)
1074 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
1075 if (getenv ("POSIXLY_CORRECT") == NULL)
1076 parse_long_options (argc, argv, COMMAND_NAME, GNU_PACKAGE, VERSION, usage);
1078 --margc;
1080 if (margc < 2)
1081 test_exit (SHELL_BOOLEAN (FALSE));
1083 if (margv[margc] && strcmp (margv[margc], "]") != 0)
1084 test_syntax_error (_("missing `]'\n"), NULL);
1087 argc = margc;
1088 pos = 1;
1090 if (pos >= argc)
1091 test_exit (SHELL_BOOLEAN (FALSE));
1093 parse_long_options (argc, argv, COMMAND_NAME, GNU_PACKAGE, VERSION, usage);
1094 value = posixtest ();
1096 if (pos != argc)
1097 test_syntax_error (_("too many arguments\n"), NULL);
1099 test_exit (SHELL_BOOLEAN (value));