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