*** empty log message ***
[coreutils.git] / src / test.c
blob8b5f7a8a7673ab2ba5cd46b55fa4429c0a0c271a
1 /* GNU test program (ksb and mjb) */
3 /* Modified to run with the GNU shell by bfox. */
5 /* Copyright (C) 1987-2000 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 *format, char *arg))
126 ATTRIBUTE_NORETURN;
127 static void beyond PARAMS ((void)) ATTRIBUTE_NORETURN;
129 static void
130 test_syntax_error (char *format, char *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 *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 a non-null pointer to a long. */
240 static int
241 isint (register char *string, long int *result)
243 int sign;
244 long 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, a pointer
296 to a long. Return nonzero if successful, else zero. */
297 static int
298 age_of (char *filename, long int *age)
300 struct stat finfo;
302 if (test_stat (filename, &finfo) < 0)
303 return (0);
305 if (age)
306 *age = finfo.st_mtime;
308 return (1);
312 * term - parse a term and return 1 or 0 depending on whether the term
313 * evaluates to true or false, respectively.
315 * term ::=
316 * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
317 * '-'('L'|'x') filename
318 * '-t' [ int ]
319 * '-'('z'|'n') string
320 * string
321 * string ('!='|'=') string
322 * <int> '-'(eq|ne|le|lt|ge|gt) <int>
323 * file '-'(nt|ot|ef) file
324 * '(' <expr> ')'
325 * int ::=
326 * '-l' string
327 * positive and negative integers
329 static int
330 term (void)
332 int value;
334 if (pos >= argc)
335 beyond ();
337 /* Deal with leading "not"'s. */
338 if ('!' == argv[pos][0] && '\000' == argv[pos][1])
340 value = FALSE;
341 while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
343 advance (1);
344 value ^= (TRUE);
347 return (value ^ (term ()));
350 /* A paren-bracketed argument. */
351 if (argv[pos][0] == '(' && !argv[pos][1])
353 advance (1);
354 value = expr ();
355 if (!argv[pos])
356 test_syntax_error (_("')' expected\n"), NULL);
357 else
358 if (argv[pos][0] != ')' || argv[pos][1])
359 test_syntax_error (_("')' expected, found %s\n"), argv[pos]);
360 advance (0);
361 return (TRUE == (value));
364 /* are there enough arguments left that this could be dyadic? */
365 if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
366 ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
367 value = binary_operator ();
369 /* Might be a switch type argument */
370 else if ('-' == argv[pos][0] && argv[pos][1] && 0 == argv[pos][2])
372 if (unop (argv[pos][1]))
373 value = unary_operator ();
374 else
375 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
377 else
379 value = (argv[pos][0] != '\0');
380 advance (0);
383 return (value);
386 static int
387 binary_operator (void)
389 register int op;
390 struct stat stat_buf, stat_spare;
391 long int l, r, value;
392 /* Are the left and right integer expressions of the form '-l string'? */
393 int l_is_l, r_is_l;
395 if (strcmp (argv[pos], "-l") == 0)
397 l_is_l = 1;
398 op = pos + 2;
400 /* Make sure that OP is still a valid binary operator. */
401 if ((op >= argc - 1) || (binop (argv[op]) == 0))
402 test_syntax_error (_("%s: binary operator expected\n"), argv[op]);
404 advance (0);
406 else
408 l_is_l = 0;
409 op = pos + 1;
412 if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0))
414 r_is_l = 1;
415 advance (0);
417 else
418 r_is_l = 0;
420 if (argv[op][0] == '-')
422 /* check for eq, nt, and stuff */
423 switch (argv[op][1])
425 default:
426 break;
428 case 'l':
429 if (argv[op][2] == 't' && !argv[op][3])
431 /* lt */
432 if (l_is_l)
433 l = strlen (argv[op - 1]);
434 else
436 if (!isint (argv[op - 1], &l))
437 integer_expected_error (_("before -lt"));
440 if (r_is_l)
441 r = strlen (argv[op + 2]);
442 else
444 if (!isint (argv[op + 1], &r))
445 integer_expected_error (_("after -lt"));
447 pos += 3;
448 return (TRUE == (l < r));
451 if (argv[op][2] == 'e' && !argv[op][3])
453 /* le */
454 if (l_is_l)
455 l = strlen (argv[op - 1]);
456 else
458 if (!isint (argv[op - 1], &l))
459 integer_expected_error (_("before -le"));
461 if (r_is_l)
462 r = strlen (argv[op + 2]);
463 else
465 if (!isint (argv[op + 1], &r))
466 integer_expected_error (_("after -le"));
468 pos += 3;
469 return (TRUE == (l <= r));
471 break;
473 case 'g':
474 if (argv[op][2] == 't' && !argv[op][3])
476 /* gt integer greater than */
477 if (l_is_l)
478 l = strlen (argv[op - 1]);
479 else
481 if (!isint (argv[op - 1], &l))
482 integer_expected_error (_("before -gt"));
484 if (r_is_l)
485 r = strlen (argv[op + 2]);
486 else
488 if (!isint (argv[op + 1], &r))
489 integer_expected_error (_("after -gt"));
491 pos += 3;
492 return (TRUE == (l > r));
495 if (argv[op][2] == 'e' && !argv[op][3])
497 /* ge - integer greater than or equal to */
498 if (l_is_l)
499 l = strlen (argv[op - 1]);
500 else
502 if (!isint (argv[op - 1], &l))
503 integer_expected_error (_("before -ge"));
505 if (r_is_l)
506 r = strlen (argv[op + 2]);
507 else
509 if (!isint (argv[op + 1], &r))
510 integer_expected_error (_("after -ge"));
512 pos += 3;
513 return (TRUE == (l >= r));
515 break;
517 case 'n':
518 if (argv[op][2] == 't' && !argv[op][3])
520 /* nt - newer than */
521 pos += 3;
522 if (l_is_l || r_is_l)
523 test_syntax_error (_("-nt does not accept -l\n"), NULL);
524 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
525 return (TRUE == (l > r));
526 else
527 return (FALSE);
530 if (argv[op][2] == 'e' && !argv[op][3])
532 /* ne - integer not equal */
533 if (l_is_l)
534 l = strlen (argv[op - 1]);
535 else
537 if (!isint (argv[op - 1], &l))
538 integer_expected_error (_("before -ne"));
540 if (r_is_l)
541 r = strlen (argv[op + 2]);
542 else
544 if (!isint (argv[op + 1], &r))
545 integer_expected_error (_("after -ne"));
547 pos += 3;
548 return (TRUE == (l != r));
550 break;
552 case 'e':
553 if (argv[op][2] == 'q' && !argv[op][3])
555 /* eq - integer equal */
556 if (l_is_l)
557 l = strlen (argv[op - 1]);
558 else
560 if (!isint (argv[op - 1], &l))
561 integer_expected_error (_("before -eq"));
563 if (r_is_l)
564 r = strlen (argv[op + 2]);
565 else
567 if (!isint (argv[op + 1], &r))
568 integer_expected_error (_("after -eq"));
570 pos += 3;
571 return (TRUE == (l == r));
574 if (argv[op][2] == 'f' && !argv[op][3])
576 /* ef - hard link? */
577 pos += 3;
578 if (l_is_l || r_is_l)
579 test_syntax_error (_("-ef does not accept -l\n"), NULL);
580 if (stat (argv[op - 1], &stat_buf) < 0)
581 return (FALSE);
582 if (stat (argv[op + 1], &stat_spare) < 0)
583 return (FALSE);
584 return (TRUE ==
585 (stat_buf.st_dev == stat_spare.st_dev &&
586 stat_buf.st_ino == stat_spare.st_ino));
588 break;
590 case 'o':
591 if ('t' == argv[op][2] && '\000' == argv[op][3])
593 /* ot - older than */
594 pos += 3;
595 if (l_is_l || r_is_l)
596 test_syntax_error (_("-nt does not accept -l\n"), NULL);
597 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
598 return (TRUE == (l < r));
599 return (FALSE);
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 long fd, 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? */
785 advance (0);
786 if (pos < argc)
788 if (!isint (argv[pos], &fd))
789 integer_expected_error (_("after -t"));
790 advance (0);
792 else
794 fd = 1;
796 return (TRUE == (isatty ((int) fd)));
798 case 'n': /* True if arg has some length. */
799 unary_advance ();
800 return (TRUE == (argv[pos - 1][0] != 0));
802 case 'z': /* True if arg has no length. */
803 unary_advance ();
804 return (TRUE == (argv[pos - 1][0] == '\0'));
809 * and:
810 * term
811 * term '-a' and
813 static int
814 and (void)
816 int value;
818 value = term ();
819 while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
821 advance (0);
822 value = TRUTH_AND (value, and ());
824 return (TRUE == value);
828 * or:
829 * and
830 * and '-o' or
832 static int
833 or (void)
835 int value;
837 value = and ();
839 while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
841 advance (0);
842 value = TRUTH_OR (value, or ());
845 return (TRUE == value);
849 * expr:
850 * or
852 static int
853 expr (void)
855 if (pos >= argc)
856 beyond ();
858 return (FALSE ^ (or ())); /* Same with this. */
861 /* Return TRUE if S is one of the test command's binary operators. */
862 static int
863 binop (char *s)
865 return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) ||
866 (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
867 (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
868 (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
871 /* Return nonzero if OP is one of the test command's unary operators. */
872 static int
873 unop (int op)
875 return (member (op, "abcdefgkLhprsStuwxOGnz"));
878 static int
879 one_argument (const char *s)
881 if (STREQ (s, "-t"))
882 return (TRUE == (isatty (1)));
884 return strlen (s) != 0;
887 static int
888 two_arguments (void)
890 int value;
892 if (STREQ (argv[pos], "!"))
893 value = ! one_argument (argv[pos+1]);
894 else if (argv[pos][0] == '-'
895 && argv[pos][1] != '\0'
896 && argv[pos][2] == '\0')
898 if (unop (argv[pos][1]))
899 value = unary_operator ();
900 else
901 test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
903 else
904 beyond ();
905 return (value);
908 static int
909 three_arguments (void)
911 int value;
913 if (STREQ (argv[pos], "!"))
915 advance (1);
916 value = !two_arguments ();
918 else if (binop (argv[pos+1]))
920 value = binary_operator ();
921 pos = argc;
923 else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
924 (argv[pos][0] == '('))
925 value = expr ();
926 else
927 test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
928 return (value);
931 /* This is an implementation of a Posix.2 proposal by David Korn. */
932 static int
933 posixtest (void)
935 int value;
937 switch (argc - 1) /* one extra passed in */
939 case 0:
940 value = FALSE;
941 pos = argc;
942 break;
944 case 1:
945 value = one_argument (argv[1]);
946 pos = argc;
947 break;
949 case 2:
950 value = two_arguments ();
951 pos = argc;
952 break;
954 case 3:
955 value = three_arguments ();
956 break;
958 case 4:
959 if (STREQ (argv[pos], "!"))
961 advance (1);
962 value = !three_arguments ();
963 break;
965 /* FALLTHROUGH */
966 case 5:
967 default:
968 value = expr ();
971 return (value);
974 #if defined (TEST_STANDALONE)
975 # include "long-options.h"
976 # include "closeout.h"
978 void
979 usage (int status)
981 if (status != 0)
982 fprintf (stderr, _("Try `%s --help' for more information.\n"),
983 program_name);
984 else
986 printf (_("\
987 Usage: %s EXPRESSION\n\
988 or: [ EXPRESSION ]\n\
989 or: %s OPTION\n\
991 program_name, program_name);
992 printf (_("\
993 Exit with the status determined by EXPRESSION.\n\
995 --help display this help and exit\n\
996 --version output version information and exit\n\
998 EXPRESSION is true or false and sets exit status. It is one of:\n\
999 "));
1000 printf (_("\
1002 ( EXPRESSION ) EXPRESSION is true\n\
1003 ! EXPRESSION EXPRESSION is false\n\
1004 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\
1005 EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\
1007 [-n] STRING the length of STRING is nonzero\n\
1008 -z STRING the length of STRING is zero\n\
1009 STRING1 = STRING2 the strings are equal\n\
1010 STRING1 != STRING2 the strings are not equal\n\
1012 INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\
1013 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\
1014 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\
1015 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\
1016 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\
1017 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\
1018 "));
1019 printf (_("\
1021 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\
1022 FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\
1023 FILE1 -ot FILE2 FILE1 is older than FILE2\n\
1025 -b FILE FILE exists and is block special\n\
1026 -c FILE FILE exists and is character special\n\
1027 -d FILE FILE exists and is a directory\n\
1028 -e FILE FILE exists\n\
1029 -f FILE FILE exists and is a regular file\n\
1030 -g FILE FILE exists and is set-group-ID\n\
1031 -G FILE FILE exists and is owned by the effective group ID\n\
1032 -k FILE FILE exists and has its sticky bit set\n\
1033 -L FILE FILE exists and is a symbolic link\n\
1034 -O FILE FILE exists and is owned by the effective user ID\n\
1035 -p FILE FILE exists and is a named pipe\n\
1036 -r FILE FILE exists and is readable\n\
1037 -s FILE FILE exists and has a size greater than zero\n\
1038 -S FILE FILE exists and is a socket\n\
1039 -t [FD] file descriptor FD (stdout by default) is opened on a terminal\n\
1040 -u FILE FILE exists and its set-user-ID bit is set\n\
1041 -w FILE FILE exists and is writable\n\
1042 -x FILE FILE exists and is executable\n\
1043 "));
1044 printf (_("\
1046 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
1047 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
1048 "));
1049 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
1051 exit (status);
1053 #endif /* TEST_STANDALONE */
1055 #if !defined (TEST_STANDALONE)
1056 # define main test_command
1057 #endif
1059 #define AUTHORS "FIXME: ksb and mjb"
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);
1085 atexit (close_stdout);
1086 #endif /* TEST_STANDALONE */
1088 argv = margv;
1090 if (margv[0] && strcmp (margv[0], "[") == 0)
1092 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
1093 if (getenv ("POSIXLY_CORRECT") == NULL)
1094 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
1095 AUTHORS, usage);
1097 --margc;
1099 if (margc < 2)
1100 test_exit (SHELL_BOOLEAN (FALSE));
1102 if (margv[margc] && strcmp (margv[margc], "]") != 0)
1103 test_syntax_error (_("missing `]'\n"), NULL);
1106 argc = margc;
1107 pos = 1;
1109 if (pos >= argc)
1110 test_exit (SHELL_BOOLEAN (FALSE));
1112 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
1113 AUTHORS, usage);
1114 value = posixtest ();
1116 if (pos != argc)
1117 test_syntax_error (_("too many arguments\n"), NULL);
1119 test_exit (SHELL_BOOLEAN (value));