Don't include headers already included by system.h:
[platform/upstream/coreutils.git] / src / test.c
1 /* GNU test program (ksb and mjb) */
2
3 /* Modified to run with the GNU shell by bfox. */
4
5 /* Copyright (C) 1987-2003 Free Software Foundation, Inc.
6
7    This file is part of GNU Bash, the Bourne Again SHell.
8
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.
13
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.
18
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.  */
22
23 /* Define TEST_STANDALONE to get the /bin/test version.  Otherwise, you get
24    the shell builtin version. */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29
30 /* The official name of this program (e.g., no `g' prefix).  */
31 #define PROGRAM_NAME "test"
32
33 #define TEST_STANDALONE 1
34
35 #ifndef LBRACKET
36 # define LBRACKET 0
37 #endif
38
39 #include "system.h"
40 #include "error.h"
41 #include "euidaccess.h"
42
43 #ifndef _POSIX_VERSION
44 # include <sys/param.h>
45 #endif /* _POSIX_VERSION */
46 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
47 #define digit(c)  ((c) >= '0' && (c) <= '9')
48 #define digit_value(c) ((c) - '0')
49
50 char *program_name;
51
52 #if !defined (_POSIX_VERSION)
53 # include <sys/file.h>
54 #endif /* !_POSIX_VERSION */
55
56 extern gid_t getegid ();
57 extern uid_t geteuid ();
58
59 #if !defined (R_OK)
60 # define R_OK 4
61 # define W_OK 2
62 # define X_OK 1
63 # define F_OK 0
64 #endif /* R_OK */
65
66 /* This name is used solely when printing --version information.  */
67 #define PROGRAM_NAME "test"
68
69 /* The following few defines control the truth and false output of each stage.
70    TRUE and FALSE are what we use to compute the final output value.
71    SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
72    TRUTH_OR is how to do logical or with TRUE and FALSE.
73    TRUTH_AND is how to do logical and with TRUE and FALSE..
74    Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
75     SHELL_BOOLEAN = (!value). */
76 #define TRUE 1
77 #define FALSE 0
78 #define SHELL_BOOLEAN(value) (!(value))
79 #define TRUTH_OR(a, b) ((a) | (b))
80 #define TRUTH_AND(a, b) ((a) & (b))
81
82 #if defined (TEST_STANDALONE)
83 # define test_exit(val) exit (val)
84 #else
85    static jmp_buf test_exit_buf;
86    static int test_error_return = 0;
87 # define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
88 #endif /* !TEST_STANDALONE */
89
90 static int pos;         /* The offset of the current argument in ARGV. */
91 static int argc;        /* The number of arguments present in ARGV. */
92 static char **argv;     /* The argument list. */
93
94 static int test_unop (char const *s);
95 static int binop (char *s);
96 static int unary_operator (void);
97 static int binary_operator (void);
98 static int two_arguments (void);
99 static int three_arguments (void);
100 static int posixtest (void);
101
102 static int expr (void);
103 static int term (void);
104 static int and (void);
105 static int or (void);
106
107 static void test_syntax_error (char const *format, char const *arg)
108      ATTRIBUTE_NORETURN;
109 static void beyond (void) ATTRIBUTE_NORETURN;
110
111 static void
112 test_syntax_error (char const *format, char const *arg)
113 {
114   fprintf (stderr, "%s: ", argv[0]);
115   fprintf (stderr, format, arg);
116   fflush (stderr);
117   test_exit (SHELL_BOOLEAN (FALSE));
118 }
119
120 #if HAVE_SETREUID && HAVE_SETREGID
121 /* Do the same thing access(2) does, but use the effective uid and gid.  */
122
123 static int
124 eaccess (char const *file, int mode)
125 {
126   static int have_ids;
127   static uid_t uid, euid;
128   static gid_t gid, egid;
129   int result;
130
131   if (have_ids == 0)
132     {
133       have_ids = 1;
134       uid = getuid ();
135       gid = getgid ();
136       euid = geteuid ();
137       egid = getegid ();
138     }
139
140   /* Set the real user and group IDs to the effective ones.  */
141   if (uid != euid)
142     setreuid (euid, uid);
143   if (gid != egid)
144     setregid (egid, gid);
145
146   result = access (file, mode);
147
148   /* Restore them.  */
149   if (uid != euid)
150     setreuid (uid, euid);
151   if (gid != egid)
152     setregid (gid, egid);
153
154   return result;
155 }
156 #else
157 # define eaccess(F, M) euidaccess (F, M)
158 #endif
159
160 /* Increment our position in the argument list.  Check that we're not
161    past the end of the argument list.  This check is supressed if the
162    argument is FALSE.  Made a macro for efficiency. */
163 #define advance(f)                                                      \
164   do                                                                    \
165     {                                                                   \
166       ++pos;                                                            \
167       if ((f) && pos >= argc)                                           \
168         beyond ();                                                      \
169     }                                                                   \
170   while (0)
171
172 #if !defined (advance)
173 static int
174 advance (int f)
175 {
176   ++pos;
177
178   if (f && pos >= argc)
179     beyond ();
180 }
181 #endif /* advance */
182
183 #define unary_advance()                                                 \
184   do                                                                    \
185     {                                                                   \
186       advance (1);                                                      \
187       ++pos;                                                            \
188     }                                                                   \
189   while (0)
190
191 /*
192  * beyond - call when we're beyond the end of the argument list (an
193  *      error condition)
194  */
195 static void
196 beyond (void)
197 {
198   test_syntax_error (_("argument expected\n"), NULL);
199 }
200
201 /* Syntax error for when an integer argument was expected, but
202    something else was found. */
203 static void
204 integer_expected_error (char const *pch)
205 {
206   test_syntax_error (_("%s: integer expression expected\n"), pch);
207 }
208
209 /* Return nonzero if the characters pointed to by STRING constitute a
210    valid number.  Stuff the converted number into RESULT if RESULT is
211    not null.  */
212 static int
213 isint (register char *string, intmax_t *result)
214 {
215   int sign;
216   intmax_t value;
217
218   sign = 1;
219   value = 0;
220
221   if (result)
222     *result = 0;
223
224   /* Skip leading whitespace characters. */
225   while (whitespace (*string))
226     string++;
227
228   if (!*string)
229     return (0);
230
231   /* We allow leading `-' or `+'. */
232   if (*string == '-' || *string == '+')
233     {
234       if (!digit (string[1]))
235         return (0);
236
237       if (*string == '-')
238         sign = -1;
239
240       string++;
241     }
242
243   while (digit (*string))
244     {
245       if (result)
246         value = (value * 10) + digit_value (*string);
247       string++;
248     }
249
250   /* Skip trailing whitespace, if any. */
251   while (whitespace (*string))
252     string++;
253
254   /* Error if not at end of string. */
255   if (*string)
256     return (0);
257
258   if (result)
259     {
260       value *= sign;
261       *result = value;
262     }
263
264   return (1);
265 }
266
267 /* Find the modification time of FILE, and stuff it into *AGE.
268    Return 0 if successful, -1 if not.  */
269 static int
270 age_of (char *filename, time_t *age)
271 {
272   struct stat finfo;
273   int r = stat (filename, &finfo);
274   if (r == 0)
275     *age = finfo.st_mtime;
276   return r;
277 }
278
279 /*
280  * term - parse a term and return 1 or 0 depending on whether the term
281  *      evaluates to true or false, respectively.
282  *
283  * term ::=
284  *      '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
285  *      '-'('L'|'x') filename
286  *      '-t' [ int ]
287  *      '-'('z'|'n') string
288  *      string
289  *      string ('!='|'=') string
290  *      <int> '-'(eq|ne|le|lt|ge|gt) <int>
291  *      file '-'(nt|ot|ef) file
292  *      '(' <expr> ')'
293  * int ::=
294  *      '-l' string
295  *      positive and negative integers
296  */
297 static int
298 term (void)
299 {
300   int value;
301
302   if (pos >= argc)
303     beyond ();
304
305   /* Deal with leading `not's. */
306   if (argv[pos][0] == '!' && argv[pos][1] == '\0')
307     {
308       value = 0;
309       while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')
310         {
311           advance (1);
312           value = 1 - value;
313         }
314
315       return (value ? !term() : term());
316     }
317
318   /* A paren-bracketed argument. */
319   if (argv[pos][0] == '(' && argv[pos][1] == '\0')
320     {
321       advance (1);
322       value = expr ();
323       if (argv[pos] == 0)
324         test_syntax_error (_("')' expected\n"), NULL);
325       else
326         if (argv[pos][0] != ')' || argv[pos][1])
327           test_syntax_error (_("')' expected, found %s\n"), argv[pos]);
328       advance (0);
329       return (value);
330     }
331
332   /* are there enough arguments left that this could be dyadic? */
333   if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
334       ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
335     value = binary_operator ();
336
337   /* Might be a switch type argument */
338   else if (argv[pos][0] == '-' && argv[pos][1] && argv[pos][2] == '\0')
339     {
340       if (test_unop (argv[pos]))
341         value = unary_operator ();
342       else
343         test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
344     }
345   else
346     {
347       value = (argv[pos][0] != '\0');
348       advance (0);
349     }
350
351   return (value);
352 }
353
354 static int
355 binary_operator (void)
356 {
357   register int op;
358   struct stat stat_buf, stat_spare;
359   intmax_t l, r;
360   int value;
361   /* Are the left and right integer expressions of the form '-l string'? */
362   int l_is_l, r_is_l;
363
364   if (strcmp (argv[pos], "-l") == 0)
365     {
366       l_is_l = 1;
367       op = pos + 2;
368
369       /* Make sure that OP is still a valid binary operator. */
370       if ((op >= argc - 1) || (binop (argv[op]) == 0))
371         test_syntax_error (_("%s: binary operator expected\n"), argv[op]);
372
373       advance (0);
374     }
375   else
376     {
377       l_is_l = 0;
378       op = pos + 1;
379     }
380
381   if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0))
382     {
383       r_is_l = 1;
384       advance (0);
385     }
386   else
387     r_is_l = 0;
388
389   if (argv[op][0] == '-')
390     {
391       /* check for eq, nt, and stuff */
392       switch (argv[op][1])
393         {
394         default:
395           break;
396
397         case 'l':
398           if (argv[op][2] == 't' && !argv[op][3])
399             {
400               /* lt */
401               if (l_is_l)
402                 l = strlen (argv[op - 1]);
403               else
404                 {
405                   if (!isint (argv[op - 1], &l))
406                     integer_expected_error (_("before -lt"));
407                 }
408
409               if (r_is_l)
410                 r = strlen (argv[op + 2]);
411               else
412                 {
413                   if (!isint (argv[op + 1], &r))
414                     integer_expected_error (_("after -lt"));
415                 }
416               pos += 3;
417               return (TRUE == (l < r));
418             }
419
420           if (argv[op][2] == 'e' && !argv[op][3])
421             {
422               /* le */
423               if (l_is_l)
424                 l = strlen (argv[op - 1]);
425               else
426                 {
427                   if (!isint (argv[op - 1], &l))
428                     integer_expected_error (_("before -le"));
429                 }
430               if (r_is_l)
431                 r = strlen (argv[op + 2]);
432               else
433                 {
434                   if (!isint (argv[op + 1], &r))
435                     integer_expected_error (_("after -le"));
436                 }
437               pos += 3;
438               return (TRUE == (l <= r));
439             }
440           break;
441
442         case 'g':
443           if (argv[op][2] == 't' && !argv[op][3])
444             {
445               /* gt integer greater than */
446               if (l_is_l)
447                 l = strlen (argv[op - 1]);
448               else
449                 {
450                   if (!isint (argv[op - 1], &l))
451                     integer_expected_error (_("before -gt"));
452                 }
453               if (r_is_l)
454                 r = strlen (argv[op + 2]);
455               else
456                 {
457                   if (!isint (argv[op + 1], &r))
458                     integer_expected_error (_("after -gt"));
459                 }
460               pos += 3;
461               return (TRUE == (l > r));
462             }
463
464           if (argv[op][2] == 'e' && !argv[op][3])
465             {
466               /* ge - integer greater than or equal to */
467               if (l_is_l)
468                 l = strlen (argv[op - 1]);
469               else
470                 {
471                   if (!isint (argv[op - 1], &l))
472                     integer_expected_error (_("before -ge"));
473                 }
474               if (r_is_l)
475                 r = strlen (argv[op + 2]);
476               else
477                 {
478                   if (!isint (argv[op + 1], &r))
479                     integer_expected_error (_("after -ge"));
480                 }
481               pos += 3;
482               return (TRUE == (l >= r));
483             }
484           break;
485
486         case 'n':
487           if (argv[op][2] == 't' && !argv[op][3])
488             {
489               /* nt - newer than */
490               time_t lt, rt;
491               int le, re;
492               pos += 3;
493               if (l_is_l || r_is_l)
494                 test_syntax_error (_("-nt does not accept -l\n"), NULL);
495               le = age_of (argv[op - 1], &lt);
496               re = age_of (argv[op + 1], &rt);
497               return le > re || (le == 0 && lt > rt);
498             }
499
500           if (argv[op][2] == 'e' && !argv[op][3])
501             {
502               /* ne - integer not equal */
503               if (l_is_l)
504                 l = strlen (argv[op - 1]);
505               else
506                 {
507                   if (!isint (argv[op - 1], &l))
508                     integer_expected_error (_("before -ne"));
509                 }
510               if (r_is_l)
511                 r = strlen (argv[op + 2]);
512               else
513                 {
514                   if (!isint (argv[op + 1], &r))
515                     integer_expected_error (_("after -ne"));
516                 }
517               pos += 3;
518               return (TRUE == (l != r));
519             }
520           break;
521
522         case 'e':
523           if (argv[op][2] == 'q' && !argv[op][3])
524             {
525               /* eq - integer equal */
526               if (l_is_l)
527                 l = strlen (argv[op - 1]);
528               else
529                 {
530                   if (!isint (argv[op - 1], &l))
531                     integer_expected_error (_("before -eq"));
532                 }
533               if (r_is_l)
534                 r = strlen (argv[op + 2]);
535               else
536                 {
537                   if (!isint (argv[op + 1], &r))
538                     integer_expected_error (_("after -eq"));
539                 }
540               pos += 3;
541               return (TRUE == (l == r));
542             }
543
544           if (argv[op][2] == 'f' && !argv[op][3])
545             {
546               /* ef - hard link? */
547               pos += 3;
548               if (l_is_l || r_is_l)
549                 test_syntax_error (_("-ef does not accept -l\n"), NULL);
550               if (stat (argv[op - 1], &stat_buf) < 0)
551                 return (FALSE);
552               if (stat (argv[op + 1], &stat_spare) < 0)
553                 return (FALSE);
554               return (TRUE ==
555                       (stat_buf.st_dev == stat_spare.st_dev &&
556                        stat_buf.st_ino == stat_spare.st_ino));
557             }
558           break;
559
560         case 'o':
561           if ('t' == argv[op][2] && '\000' == argv[op][3])
562             {
563               /* ot - older than */
564               time_t lt, rt;
565               int le, re;
566               pos += 3;
567               if (l_is_l || r_is_l)
568                 test_syntax_error (_("-ot does not accept -l\n"), NULL);
569               le = age_of (argv[op - 1], &lt);
570               re = age_of (argv[op + 1], &rt);
571               return le < re || (re == 0 && lt < rt);
572             }
573           break;
574         }
575
576       /* FIXME: is this dead code? */
577       test_syntax_error (_("unknown binary operator\n"), argv[op]);
578     }
579
580   if (argv[op][0] == '=' && !argv[op][1])
581     {
582       value = (strcmp (argv[pos], argv[pos + 2]) == 0);
583       pos += 3;
584       return (TRUE == value);
585     }
586
587   if (strcmp (argv[op], "!=") == 0)
588     {
589       value = (strcmp (argv[pos], argv[pos + 2]) != 0);
590       pos += 3;
591       return (TRUE == value);
592     }
593
594   /* Not reached.  */
595   abort ();
596 }
597
598 static int
599 unary_operator (void)
600 {
601   int value;
602   struct stat stat_buf;
603
604   switch (argv[pos][1])
605     {
606     default:
607       return (FALSE);
608
609       /* All of the following unary operators use unary_advance (), which
610          checks to make sure that there is an argument, and then advances
611          pos right past it.  This means that pos - 1 is the location of the
612          argument. */
613
614     case 'a':                   /* file exists in the file system? */
615     case 'e':
616       unary_advance ();
617       value = -1 != stat (argv[pos - 1], &stat_buf);
618       return (TRUE == value);
619
620     case 'r':                   /* file is readable? */
621       unary_advance ();
622       value = -1 != eaccess (argv[pos - 1], R_OK);
623       return (TRUE == value);
624
625     case 'w':                   /* File is writable? */
626       unary_advance ();
627       value = -1 != eaccess (argv[pos - 1], W_OK);
628       return (TRUE == value);
629
630     case 'x':                   /* File is executable? */
631       unary_advance ();
632       value = -1 != eaccess (argv[pos - 1], X_OK);
633       return (TRUE == value);
634
635     case 'O':                   /* File is owned by you? */
636       unary_advance ();
637       if (stat (argv[pos - 1], &stat_buf) < 0)
638         return (FALSE);
639
640       return (TRUE == (geteuid () == stat_buf.st_uid));
641
642     case 'G':                   /* File is owned by your group? */
643       unary_advance ();
644       if (stat (argv[pos - 1], &stat_buf) < 0)
645         return (FALSE);
646
647       return (TRUE == (getegid () == stat_buf.st_gid));
648
649     case 'f':                   /* File is a file? */
650       unary_advance ();
651       if (stat (argv[pos - 1], &stat_buf) < 0)
652         return (FALSE);
653
654       /* Under POSIX, -f is true if the given file exists
655          and is a regular file. */
656       return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
657                        (0 == (stat_buf.st_mode & S_IFMT))));
658
659     case 'd':                   /* File is a directory? */
660       unary_advance ();
661       if (stat (argv[pos - 1], &stat_buf) < 0)
662         return (FALSE);
663
664       return (TRUE == (S_ISDIR (stat_buf.st_mode)));
665
666     case 's':                   /* File has something in it? */
667       unary_advance ();
668       if (stat (argv[pos - 1], &stat_buf) < 0)
669         return (FALSE);
670
671       return (TRUE == (stat_buf.st_size > (off_t) 0));
672
673     case 'S':                   /* File is a socket? */
674 #if !defined (S_ISSOCK)
675       return (FALSE);
676 #else
677       unary_advance ();
678
679       if (stat (argv[pos - 1], &stat_buf) < 0)
680         return (FALSE);
681
682       return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
683 #endif                          /* S_ISSOCK */
684
685     case 'c':                   /* File is character special? */
686       unary_advance ();
687       if (stat (argv[pos - 1], &stat_buf) < 0)
688         return (FALSE);
689
690       return (TRUE == (S_ISCHR (stat_buf.st_mode)));
691
692     case 'b':                   /* File is block special? */
693       unary_advance ();
694       if (stat (argv[pos - 1], &stat_buf) < 0)
695         return (FALSE);
696
697       return (TRUE == (S_ISBLK (stat_buf.st_mode)));
698
699     case 'p':                   /* File is a named pipe? */
700       unary_advance ();
701 #ifndef S_ISFIFO
702       return (FALSE);
703 #else
704       if (stat (argv[pos - 1], &stat_buf) < 0)
705         return (FALSE);
706       return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
707 #endif                          /* S_ISFIFO */
708
709     case 'L':                   /* Same as -h  */
710       /*FALLTHROUGH*/
711
712     case 'h':                   /* File is a symbolic link? */
713       unary_advance ();
714 #ifndef S_ISLNK
715       return (FALSE);
716 #else
717       /* An empty filename is not a valid pathname. */
718       if ((argv[pos - 1][0] == '\0') ||
719           (lstat (argv[pos - 1], &stat_buf) < 0))
720         return (FALSE);
721
722       return (TRUE == (S_ISLNK (stat_buf.st_mode)));
723 #endif                          /* S_IFLNK */
724
725     case 'u':                   /* File is setuid? */
726       unary_advance ();
727 #ifndef S_ISUID
728       return (FALSE);
729 #else
730       if (stat (argv[pos - 1], &stat_buf) < 0)
731         return (FALSE);
732
733       return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
734 #endif
735
736     case 'g':                   /* File is setgid? */
737       unary_advance ();
738 #ifndef S_ISGID
739       return (FALSE);
740 #else
741       if (stat (argv[pos - 1], &stat_buf) < 0)
742         return (FALSE);
743
744       return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
745 #endif
746
747     case 'k':                   /* File has sticky bit set? */
748       unary_advance ();
749       if (stat (argv[pos - 1], &stat_buf) < 0)
750         return (FALSE);
751 #ifndef S_ISVTX
752       /* This is not Posix, and is not defined on some Posix systems. */
753       return (FALSE);
754 #else
755       return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
756 #endif
757
758     case 't':                   /* File (fd) is a terminal? */
759       {
760         intmax_t fd;
761         advance (0);
762         if (pos < argc)
763           {
764             if (!isint (argv[pos], &fd))
765               integer_expected_error (_("after -t"));
766             advance (0);
767           }
768         else
769           {
770             fd = 1;
771           }
772         return (TRUE == (fd == (int) fd && isatty (fd)));
773       }
774
775     case 'n':                   /* True if arg has some length. */
776       unary_advance ();
777       return (TRUE == (argv[pos - 1][0] != 0));
778
779     case 'z':                   /* True if arg has no length. */
780       unary_advance ();
781       return (TRUE == (argv[pos - 1][0] == '\0'));
782     }
783 }
784
785 /*
786  * and:
787  *      term
788  *      term '-a' and
789  */
790 static int
791 and (void)
792 {
793   int value;
794
795   value = term ();
796   while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
797     {
798       advance (0);
799       value = TRUTH_AND (value, and ());
800     }
801   return (TRUE == value);
802 }
803
804 /*
805  * or:
806  *      and
807  *      and '-o' or
808  */
809 static int
810 or (void)
811 {
812   int value;
813
814   value = and ();
815
816   while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
817     {
818       advance (0);
819       value = TRUTH_OR (value, or ());
820     }
821
822   return (TRUE == value);
823 }
824
825 /*
826  * expr:
827  *      or
828  */
829 static int
830 expr (void)
831 {
832   if (pos >= argc)
833     beyond ();
834
835   return (FALSE ^ (or ()));             /* Same with this. */
836 }
837
838 /* Return TRUE if S is one of the test command's binary operators. */
839 static int
840 binop (char *s)
841 {
842   return ((STREQ (s,   "=")) || (STREQ (s,  "!=")) || (STREQ (s, "-nt")) ||
843           (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
844           (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
845           (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
846 }
847
848 /* Return nonzero if OP is one of the test command's unary operators. */
849 static int
850 test_unop (char const *op)
851 {
852   if (op[0] != '-')
853     return (0);
854
855   switch (op[1])
856     {
857     case 'a': case 'b': case 'c': case 'd': case 'e':
858     case 'f': case 'g': case 'h': case 'k': case 'n':
859     case 'o': case 'p': case 'r': case 's': case 't':
860     case 'u': case 'w': case 'x': case 'z':
861     case 'G': case 'L': case 'O': case 'S': case 'N':
862       return (1);
863     }
864
865   return (0);
866 }
867
868 static int
869 one_argument (const char *s)
870 {
871   if (! getenv ("POSIXLY_CORRECT") && STREQ (s, "-t"))
872     return (TRUE == (isatty (1)));
873
874   return strlen (s) != 0;
875 }
876
877 static int
878 two_arguments (void)
879 {
880   int value;
881
882   if (STREQ (argv[pos], "!"))
883     value = ! one_argument (argv[pos+1]);
884   else if (argv[pos][0] == '-'
885            && argv[pos][1] != '\0'
886            && argv[pos][2] == '\0')
887     {
888       if (test_unop (argv[pos]))
889         value = unary_operator ();
890       else
891         test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
892     }
893   else
894     beyond ();
895   return (value);
896 }
897
898 static int
899 three_arguments (void)
900 {
901   int value;
902
903   if (STREQ (argv[pos], "!"))
904     {
905       advance (1);
906       value = !two_arguments ();
907     }
908   else if (binop (argv[pos+1]))
909     {
910       value = binary_operator ();
911       pos = argc;
912     }
913   else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
914            (argv[pos][0] == '('))
915     value = expr ();
916   else
917     test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
918   return (value);
919 }
920
921 /* This is an implementation of a Posix.2 proposal by David Korn. */
922 static int
923 posixtest (void)
924 {
925   int value;
926
927   switch (argc - 1)     /* one extra passed in */
928     {
929       case 0:
930         value = FALSE;
931         pos = argc;
932         break;
933
934       case 1:
935         value = one_argument (argv[1]);
936         pos = argc;
937         break;
938
939       case 2:
940         value = two_arguments ();
941         pos = argc;
942         break;
943
944       case 3:
945         value = three_arguments ();
946         break;
947
948       case 4:
949         if (STREQ (argv[pos], "!"))
950           {
951             advance (1);
952             value = !three_arguments ();
953             break;
954           }
955         /* FALLTHROUGH */
956       case 5:
957       default:
958         value = expr ();
959     }
960
961   return (value);
962 }
963
964 #if defined (TEST_STANDALONE)
965 # include "long-options.h"
966
967 void
968 usage (int status)
969 {
970   if (status != 0)
971     fprintf (stderr, _("Try `%s --help' for more information.\n"),
972              program_name);
973   else
974     {
975       printf (_("\
976 Usage: %s EXPRESSION\n\
977   or:  [ EXPRESSION ]\n\
978   or:  %s OPTION\n\
979 "),
980               program_name, program_name);
981       fputs (_("\
982 Exit with the status determined by EXPRESSION.\n\
983 \n\
984 "), stdout);
985       fputs (HELP_OPTION_DESCRIPTION, stdout);
986       fputs (VERSION_OPTION_DESCRIPTION, stdout);
987       fputs (_("\
988 \n\
989 EXPRESSION is true or false and sets exit status.  It is one of:\n\
990 "), stdout);
991       fputs (_("\
992 \n\
993   ( EXPRESSION )               EXPRESSION is true\n\
994   ! EXPRESSION                 EXPRESSION is false\n\
995   EXPRESSION1 -a EXPRESSION2   both EXPRESSION1 and EXPRESSION2 are true\n\
996   EXPRESSION1 -o EXPRESSION2   either EXPRESSION1 or EXPRESSION2 is true\n\
997 "), stdout);
998       fputs (_("\
999 \n\
1000   [-n] STRING          the length of STRING is nonzero\n\
1001   -z STRING            the length of STRING is zero\n\
1002   STRING1 = STRING2    the strings are equal\n\
1003   STRING1 != STRING2   the strings are not equal\n\
1004 "), stdout);
1005       fputs (_("\
1006 \n\
1007   INTEGER1 -eq INTEGER2   INTEGER1 is equal to INTEGER2\n\
1008   INTEGER1 -ge INTEGER2   INTEGER1 is greater than or equal to INTEGER2\n\
1009   INTEGER1 -gt INTEGER2   INTEGER1 is greater than INTEGER2\n\
1010   INTEGER1 -le INTEGER2   INTEGER1 is less than or equal to INTEGER2\n\
1011   INTEGER1 -lt INTEGER2   INTEGER1 is less than INTEGER2\n\
1012   INTEGER1 -ne INTEGER2   INTEGER1 is not equal to INTEGER2\n\
1013 "), stdout);
1014       fputs (_("\
1015 \n\
1016   FILE1 -ef FILE2   FILE1 and FILE2 have the same device and inode numbers\n\
1017   FILE1 -nt FILE2   FILE1 is newer (modification date) than FILE2\n\
1018   FILE1 -ot FILE2   FILE1 is older than FILE2\n\
1019 "), stdout);
1020       fputs (_("\
1021 \n\
1022   -b FILE     FILE exists and is block special\n\
1023   -c FILE     FILE exists and is character special\n\
1024   -d FILE     FILE exists and is a directory\n\
1025   -e FILE     FILE exists\n\
1026 "), stdout);
1027       fputs (_("\
1028   -f FILE     FILE exists and is a regular file\n\
1029   -g FILE     FILE exists and is set-group-ID\n\
1030   -h FILE     FILE exists and is a symbolic link (same as -L)\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 "), stdout);
1034       fputs (_("\
1035   -L FILE     FILE exists and is a symbolic link (same as -h)\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 "), stdout);
1041       fputs (_("\
1042   -S FILE     FILE exists and is a socket\n\
1043   -t [FD]     file descriptor FD (stdout by default) is opened on a terminal\n\
1044   -u FILE     FILE exists and its set-user-ID bit is set\n\
1045   -w FILE     FILE exists and is writable\n\
1046   -x FILE     FILE exists and is executable\n\
1047 "), stdout);
1048       fputs (_("\
1049 \n\
1050 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
1051 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
1052 "), stdout);
1053       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1054     }
1055   exit (status);
1056 }
1057 #endif /* TEST_STANDALONE */
1058
1059 #if !defined (TEST_STANDALONE)
1060 # define main test_command
1061 #endif
1062
1063 #define AUTHORS N_ ("Kevin Braunsdorf and Matthew Bradburn")
1064
1065 /*
1066  * [:
1067  *      '[' expr ']'
1068  * test:
1069  *      test expr
1070  */
1071 int
1072 main (int margc, char **margv)
1073 {
1074   int value;
1075
1076 #if !defined (TEST_STANDALONE)
1077   int code;
1078
1079   code = setjmp (test_exit_buf);
1080
1081   if (code)
1082     return (test_error_return);
1083 #else /* TEST_STANDALONE */
1084   initialize_main (&margc, &margv);
1085   program_name = margv[0];
1086   setlocale (LC_ALL, "");
1087   bindtextdomain (PACKAGE, LOCALEDIR);
1088   textdomain (PACKAGE);
1089
1090   atexit (close_stdout);
1091 #endif /* TEST_STANDALONE */
1092
1093   /* Recognize --help or --version unless POSIXLY_CORRECT is set.  */
1094   if (! getenv ("POSIXLY_CORRECT"))
1095     parse_long_options (margc, margv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
1096                         AUTHORS, usage);
1097
1098   argv = margv;
1099
1100   if (LBRACKET)
1101     {
1102       --margc;
1103
1104       if (margc < 1 || strcmp (margv[margc], "]") != 0)
1105         test_syntax_error (_("missing `]'\n"), NULL);
1106     }
1107
1108   argc = margc;
1109   pos = 1;
1110
1111   if (pos >= argc)
1112     test_exit (SHELL_BOOLEAN (FALSE));
1113
1114   value = posixtest ();
1115
1116   if (pos != argc)
1117     test_syntax_error (_("too many arguments\n"), NULL);
1118
1119   test_exit (SHELL_BOOLEAN (value));
1120 }