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