X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=test.c;h=dae19ac694f2e0898c73b0a03714c26bfdd130a4;hb=ccc6cda312fea9f0468ee65b8f368e9653e1380b;hp=d8356f1b162006c93be6d9254f6f5662b3ae8fc0;hpb=726f63884db0132f01745f1fb4465e6621088ccf;p=platform%2Fupstream%2Fbash.git diff --git a/test.c b/test.c index d8356f1..dae19ac 100644 --- a/test.c +++ b/test.c @@ -20,22 +20,52 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Define STANDALONE to get the /bin/test version. Otherwise, you get +/* Define STANDALONE to get the /bin/test version. Otherwise, you get the shell builtin version. */ /* #define STANDALONE */ +/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching + binary operators. */ +/* #define PATTERN_MATCHING */ + +#if defined (HAVE_CONFIG_H) +# include +#endif + #include -#include "bashtypes.h" + +#if defined (STANDALONE) +# include +#else +# include "bashtypes.h" +#endif + +#if defined (HAVE_LIMITS_H) +# include +#else +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if !defined (_POSIX_VERSION) +# include +#endif /* !_POSIX_VERSION */ +#include "posixstat.h" +#include "filecntl.h" #if !defined (STANDALONE) -# if !defined (_POSIX_VERSION) -# include -# endif /* !_POSIX_VERSION */ -# include "posixstat.h" -# include "filecntl.h" # include "shell.h" +# include "builtins/common.h" +# define main test_command +# define isint legal_number +# define getuid() current_user.uid +# define geteuid() current_user.euid +# define getgid() current_user.gid +# define getegid() current_user.egid #else /* STANDALONE */ -# include "system.h" # if !defined (S_IXUGO) # define S_IXUGO 0111 # endif @@ -65,33 +95,14 @@ extern int errno; #endif /* !member */ /* Make gid_t and uid_t mean something for non-posix systems. */ -#if !defined (_POSIX_VERSION) && !defined (HAVE_UID_T) +#if defined (STANDALONE) && !defined (_POSIX_VERSION) && !defined (HAVE_UID_T) # if !defined (gid_t) # define gid_t int # endif # if !defined (uid_t) # define uid_t int # endif -#endif /* !_POSIX_VERSION */ - -/* What type are the user and group ids? GID_T is actually the type of - the members of the array that getgroups(3) fills in from its second - argument. */ -#if defined (INT_GROUPS_ARRAY) -# define GID_T int -# define UID_T int -#else /* !INT_GROUPS_ARRAY */ -# define GID_T gid_t -# define UID_T uid_t -#endif /* !INT_GROUPS_ARRAY */ - -#if !defined (Linux) && !defined (USGr4_2) && !defined (SunOS5) -extern gid_t getegid (); -extern uid_t geteuid (); -# if !defined (sony) -extern gid_t getgid (); -# endif /* !sony */ -#endif /* !Linux && !USGr4_2 && !SunOS5 */ +#endif /* STANDALONE && !_POSIX_VERSION && !HAVE_UID_T */ #if !defined (R_OK) #define R_OK 4 @@ -100,24 +111,30 @@ extern gid_t getgid (); #define F_OK 0 #endif /* R_OK */ +#define EQ 0 +#define NE 1 +#define LT 2 +#define GT 3 +#define LE 4 +#define GE 5 + +#define NT 0 +#define OT 1 +#define EF 2 + /* The following few defines control the truth and false output of each stage. TRUE and FALSE are what we use to compute the final output value. SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. - TRUTH_OR is how to do logical or with TRUE and FALSE. - TRUTH_AND is how to do logical and with TRUE and FALSE.. - Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b, - SHELL_BOOLEAN = (!value). */ + Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */ #define TRUE 1 #define FALSE 0 #define SHELL_BOOLEAN(value) (!(value)) -#define TRUTH_OR(a, b) ((a) | (b)) -#define TRUTH_AND(a, b) ((a) & (b)) #if defined (STANDALONE) # define test_exit(val) exit (val) #else - static jmp_buf test_exit_buf; - static int test_error_return = 0; +static procenv_t test_exit_buf; +static int test_error_return; # define test_exit(val) \ do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) #endif /* STANDALONE */ @@ -128,7 +145,7 @@ extern gid_t getgid (); non-AFS files. I hate AFS. */ # define EACCESS(path, mode) access(path, mode) #else -# define EACCESS(path, mode) eaccess(path, mode) +# define EACCESS(path, mode) test_eaccess(path, mode) #endif /* AFS */ static int pos; /* The offset of the current argument in ARGV. */ @@ -136,7 +153,9 @@ static int argc; /* The number of arguments present in ARGV. */ static char **argv; /* The argument list. */ static int noeval; +#if defined (STANDALONE) static int isint (); +#endif static int unop (); static int binop (); static int unary_operator (); @@ -150,6 +169,8 @@ static int term (); static int and (); static int or (); +static void beyond (); + static void test_syntax_error (format, arg) char *format, *arg; @@ -157,11 +178,12 @@ test_syntax_error (format, arg) #if !defined (STANDALONE) extern int interactive_shell; extern char *get_name_for_error (); - if (!interactive_shell) + if (interactive_shell == 0) fprintf (stderr, "%s: ", get_name_for_error ()); #endif fprintf (stderr, "%s: ", argv[0]); fprintf (stderr, format, arg); + fprintf (stderr, "\n"); fflush (stderr); test_exit (SHELL_BOOLEAN (FALSE)); } @@ -178,19 +200,28 @@ test_stat (path, finfo) errno = ENOENT; return (-1); } -#if !defined (HAVE_DEV_FD) if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0) { - int fd; +#if !defined (HAVE_DEV_FD) + long fd; if (isint (path + 8, &fd)) - return (fstat (fd, finfo)); + return (fstat ((int)fd, finfo)); else { errno = EBADF; return (-1); } - } +#else + /* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a + trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx. + On most systems, with the notable exception of linux, this is + effectively a no-op. */ + char pbuf[32]; + strcpy (pbuf, DEV_FD_PREFIX); + strcat (pbuf, path + 8); + return (stat (pbuf, finfo)); #endif /* !HAVE_DEV_FD */ + } return (stat (path, finfo)); } @@ -198,7 +229,7 @@ test_stat (path, finfo) and don't make the mistake of telling root that any file is executable. */ static int -eaccess (path, mode) +test_eaccess (path, mode) char *path; int mode; { @@ -209,11 +240,7 @@ eaccess (path, mode) return (-1); if (euid == -1) -#if defined (SHELL) - euid = current_user.euid; -#else euid = geteuid (); -#endif if (euid == 0) { @@ -240,68 +267,67 @@ eaccess (path, mode) #if defined (HAVE_GETGROUPS) /* The number of groups that this user is a member of. */ -static int ngroups = 0; -static GID_T *group_array = (GID_T *)NULL; -static int default_group_array_size = 0; +static int ngroups, maxgroups; +static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; #endif /* HAVE_GETGROUPS */ #if !defined (NOGROUP) -# define NOGROUP (GID_T) -1 +# define NOGROUP (gid_t) -1 #endif +#if defined (HAVE_GETGROUPS) + +# if defined (NGROUPS_MAX) +# define getmaxgroups() NGROUPS_MAX +# else /* !NGROUPS_MAX */ +# if defined (NGROUPS) +# define getmaxgroups() NGROUPS +# else /* !NGROUPS */ +# define getmaxgroups() 64 +# endif /* !NGROUPS */ +# endif /* !NGROUPS_MAX */ + +#endif /* HAVE_GETGROUPS */ + /* Return non-zero if GID is one that we have in our groups list. */ int group_member (gid) - GID_T gid; + gid_t gid; { - static GID_T pgid = (GID_T)NOGROUP; - static GID_T egid = (GID_T)NOGROUP; - - if (pgid == (GID_T)NOGROUP) -#if defined (SHELL) - pgid = (GID_T) current_user.gid; -#else /* !SHELL */ - pgid = (GID_T) getgid (); -#endif /* !SHELL */ - - if (egid == (GID_T)NOGROUP) -#if defined (SHELL) - egid = (GID_T) current_user.egid; -#else /* !SHELL */ - egid = (GID_T) getegid (); -#endif /* !SHELL */ + static gid_t pgid = (gid_t)NOGROUP; + static gid_t egid = (gid_t)NOGROUP; +#if defined (HAVE_GETGROUPS) + register int i; +#endif + + if (pgid == (gid_t)NOGROUP) + pgid = (gid_t) getgid (); + + if (egid == (gid_t)NOGROUP) + egid = (gid_t) getegid (); if (gid == pgid || gid == egid) return (1); #if defined (HAVE_GETGROUPS) /* getgroups () returns the number of elements that it was able to - place into the array. We simply continue to call getgroups () - until the number of elements placed into the array is smaller than - the physical size of the array. */ - - while (ngroups == default_group_array_size) + place into the array. */ + if (ngroups == 0) { - default_group_array_size += 64; - - group_array = (GID_T *) - xrealloc (group_array, default_group_array_size * sizeof (GID_T)); - - ngroups = getgroups (default_group_array_size, group_array); + if (maxgroups == 0) + maxgroups = getmaxgroups (); + group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); + ngroups = getgroups (maxgroups, group_array); } /* In case of error, the user loses. */ - if (ngroups < 0) + if (ngroups <= 0) return (0); /* Search through the list looking for GID. */ - { - register int i; - - for (i = 0; i < ngroups; i++) - if (gid == group_array[i]) - return (1); - } + for (i = 0; i < ngroups; i++) + if (gid == (gid_t)group_array[i]) + return (1); #endif /* HAVE_GETGROUPS */ return (0); @@ -310,32 +336,17 @@ group_member (gid) /* Increment our position in the argument list. Check that we're not past the end of the argument list. This check is supressed if the argument is FALSE. Made a macro for efficiency. */ -#if !defined (lint) #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0) -#endif - -#if !defined (advance) -static int -advance (f) - int f; -{ - ++pos; - - if (f && pos >= argc) - beyond (); -} -#endif /* advance */ - #define unary_advance() do { advance (1); ++pos; } while (0) /* * beyond - call when we're beyond the end of the argument list (an * error condition) */ -static int +static void beyond () { - test_syntax_error ("argument expected\n", (char *)NULL); + test_syntax_error ("argument expected", (char *)NULL); } /* Syntax error for when an integer argument was expected, but @@ -344,9 +355,10 @@ static void integer_expected_error (pch) char *pch; { - test_syntax_error ("integer expression expected %s\n", pch); + test_syntax_error ("%s: integer expression expected", pch); } +#if defined (STANDALONE) /* Return non-zero if the characters pointed to by STRING constitute a valid number. Stuff the converted number into RESULT if RESULT is a non-null pointer to a long. */ @@ -406,41 +418,23 @@ isint (string, result) return (1); } - -/* Find the modification time of FILE, and stuff it into AGE, a pointer - to a long. Return non-zero if successful, else zero. */ -static int -age_of (filename, age) - char *filename; - long *age; -{ - struct stat finfo; - - if (test_stat (filename, &finfo) < 0) - return (0); - - if (age) - *age = finfo.st_mtime; - - return (1); -} +#endif /* STANDALONE */ /* * term - parse a term and return 1 or 0 depending on whether the term * evaluates to true or false, respectively. * * term ::= - * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename - * '-'('L'|'x') filename - * '-t' [ int ] + * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'p'|'r'|'s'|'u'|'w'|'x') filename + * '-'('G'|'L'|'O'|'S') filename + * '-t' [int] * '-'('z'|'n') string * string - * string ('!='|'=') string + * string ('!='|'='|'==') string * '-'(eq|ne|le|lt|ge|gt) * file '-'(nt|ot|ef) file * '(' ')' * int ::= - * '-l' string * positive and negative integers */ static int @@ -451,48 +445,47 @@ term () if (pos >= argc) beyond (); - /* Deal with leading "not"'s. */ - if ('!' == argv[pos][0] && '\000' == argv[pos][1]) + /* Deal with leading `not's. */ + if (argv[pos][0] == '!' && argv[pos][1] == '\0') { - value = FALSE; - while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) + value = 0; + while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); - value ^= (TRUE); + value = 1 - value; } - return (value ^ (term ())); + return (value ? !term() : term()); } - /* A paren-bracketed argument. */ - if (argv[pos][0] == '(' && !argv[pos][1]) + /* A paren-bracketed argument. */ + if (argv[pos][0] == '(' && argv[pos][1] == '\0') { advance (1); value = expr (); if (argv[pos] == 0) - test_syntax_error ("`)' expected\n"); + test_syntax_error ("`)' expected", (char *)NULL); else if (argv[pos][0] != ')' || argv[pos][1]) - test_syntax_error ("`)' expected, found %s\n", argv[pos]); + test_syntax_error ("`)' expected, found %s", argv[pos]); advance (0); - return (TRUE == (value)); + return (value); } /* are there enough arguments left that this could be dyadic? */ - if (((pos + 3 <= argc) && binop (argv[pos + 1])) || - ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2])))) + if ((pos + 3 <= argc) && binop (argv[pos + 1])) value = binary_operator (); /* Might be a switch type argument */ - else if ('-' == argv[pos][0] && 0 == argv[pos][2]) + else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { if (unop (argv[pos][1])) value = unary_operator (); else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); } else { - value = (argv[pos][0] != '\0'); + value = argv[pos][0] != '\0'; advance (0); } @@ -500,248 +493,147 @@ term () } static int -binary_operator () +filecomp (s, t, op) + char *s, *t; + int op; { - register int op; - struct stat stat_buf, stat_spare; - long int l, r, value; - /* Are the left and right integer expressions of the form '-l string'? */ - int l_is_l, r_is_l; + struct stat st1, st2; - if (argv[pos][0] == '-' && argv[pos][1] == 'l' && !argv[pos][2]) + if (test_stat (s, &st1) < 0 || test_stat (t, &st2) < 0) + return (FALSE); + switch (op) { - l_is_l = 1; - op = pos + 2; + case OT: return (st1.st_mtime < st2.st_mtime); + case NT: return (st1.st_mtime > st2.st_mtime); + case EF: return ((st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino)); + } + return (FALSE); +} - /* Make sure that OP is still a valid binary operator. */ - if ((op >= argc - 1) || (binop (argv[op]) == 0)) - test_syntax_error ("%s: binary operator expected\n", argv[op]); +static int +arithcomp (s, t, op) + char *s, *t; + int op; +{ + long l, r; - advance (0); + if (isint (s, &l) == 0) + integer_expected_error (s); + if (isint (t, &r) == 0) + integer_expected_error (t); + switch (op) + { + case EQ: return (l == r); + case NE: return (l != r); + case LT: return (l < r); + case GT: return (l > r); + case LE: return (l <= r); + case GE: return (l >= r); } - else + return (FALSE); +} + +#if defined (PATTERN_MATCHING) +static int +patcomp (string, pat, op) + char *string, *pat; + int op; +{ + int m; + + m = fnmatch (pat, string, 0); + switch (op) { - l_is_l = 0; - op = pos + 1; + case EQ: return (m == 0); + case NE: return (m != 0); } +} +#endif /* PATTERN_MATCHING */ - if ((op < argc - 2) && - (argv[op + 1][0] == '-' && argv[op + 1][1] == 'l' && !argv[op + 1][2])) +static int +binary_operator () +{ + int value; + char *w; + + w = argv[pos + 1]; + if (w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) { - r_is_l = 1; - advance (0); + value = STREQ (argv[pos], argv[pos + 2]); + pos += 3; + return (value); + } + if ((w[0] == '>' || w[0] == '<') && w[1] == '\0') + { + value = (w[0] == '>') ? strcmp (argv[pos], argv[pos + 2]) > 0 + : strcmp (argv[pos], argv[pos + 2]) < 0; + pos += 3; + return (value); + } +#if defined (PATTERN_MATCHING) + if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0') + { + value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE); + pos += 3; + return (value); + } +#endif + if (w[0] == '!' && w[1] == '=' && w[2] == '\0') + { + value = STREQ (argv[pos], argv[pos + 2]) == 0; + pos += 3; + return (value); + } + + if (w[0] != '-' || w[3] != '\0') + { + test_syntax_error ("%s: binary operator expected", w); + /* NOTREACHED */ + return (FALSE); } - else - r_is_l = 0; - if (argv[op][0] == '-') + w++; + if (w[1] == 't') { - /* check for eq, nt, and stuff */ - switch (argv[op][1]) + switch (w[0]) { - default: - break; - - case 'l': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* lt */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -lt"); - } - - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -lt"); - } - pos += 3; - return (TRUE == (l < r)); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* le */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -le"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -le"); - } - pos += 3; - return (TRUE == (l <= r)); - } - break; - - case 'g': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* gt integer greater than */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -gt"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -gt"); - } - pos += 3; - return (TRUE == (l > r)); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* ge - integer greater than or equal to */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -ge"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -ge"); - } - pos += 3; - return (TRUE == (l >= r)); - } - break; - - case 'n': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* nt - newer than */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-nt does not accept -l\n", (char *)NULL); - if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r)) - return (TRUE == (l > r)); - else - return (FALSE); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* ne - integer not equal */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -ne"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -ne"); - } - pos += 3; - return (TRUE == (l != r)); - } - break; - - case 'e': - if (argv[op][2] == 'q' && !argv[op][3]) - { - /* eq - integer equal */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -eq"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -eq"); - } - pos += 3; - return (TRUE == (l == r)); - } - - if (argv[op][2] == 'f' && !argv[op][3]) - { - /* ef - hard link? */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-ef does not accept -l\n", (char *)NULL); - if (test_stat (argv[op - 1], &stat_buf) < 0) - return (FALSE); - if (test_stat (argv[op + 1], &stat_spare) < 0) - return (FALSE); - return (TRUE == - (stat_buf.st_dev == stat_spare.st_dev && - stat_buf.st_ino == stat_spare.st_ino)); - } - break; - - case 'o': - if ('t' == argv[op][2] && '\000' == argv[op][3]) - { - /* ot - older than */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-nt does not accept -l\n", (char *)NULL); - if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r)) - return (TRUE == (l < r)); - return (FALSE); - } - break; + case 'n': value = filecomp (argv[pos], argv[pos + 2], NT); break; + case 'o': value = filecomp (argv[pos], argv[pos + 2], OT); break; + case 'l': value = arithcomp (argv[pos], argv[pos + 2], LT); break; + case 'g': value = arithcomp (argv[pos], argv[pos + 2], GT); break; + default: test_syntax_error ("-%s: binary operator expected", w); } - test_syntax_error ("%s: unknown binary operator", argv[op]); } - - if (argv[op][0] == '=' && !argv[op][1]) + else if (w[0] == 'e') { - value = (argv[pos][0] == argv[pos+2][0]) && - (strcmp (argv[pos], argv[pos + 2]) == 0); - pos += 3; - return (TRUE == value); + switch (w[1]) + { + case 'q': value = arithcomp (argv[pos], argv[pos + 2], EQ); break; + case 'f': value = filecomp (argv[pos], argv[pos + 2], EF); break; + default: test_syntax_error ("-%s: binary operator expected", w); + } } - - if (argv[op][0] == '!' && argv[op][1] == '=' && !argv[op][2]) + else if (w[1] == 'e') { - value = (argv[pos][0] != argv[pos + 2][0]) || - (strcmp (argv[pos], argv[pos + 2]) != 0); - pos += 3; - return (TRUE == value); + switch (w[0]) + { + case 'n': value = arithcomp (argv[pos], argv[pos + 2], NE); break; + case 'g': value = arithcomp (argv[pos], argv[pos + 2], GE); break; + case 'l': value = arithcomp (argv[pos], argv[pos + 2], LE); break; + default: test_syntax_error ("-%s: binary operator expected", w); + } } - return (FALSE); + else + test_syntax_error ("-%s: binary operator expected", w); + + pos += 3; + return value; } static int unary_operator () { - long r, value; + long r; struct stat stat_buf; switch (argv[pos][1]) @@ -757,166 +649,136 @@ unary_operator () case 'a': /* file exists in the file system? */ case 'e': unary_advance (); - value = -1 != test_stat (argv[pos - 1], &stat_buf); - return (TRUE == value); + return (test_stat (argv[pos - 1], &stat_buf) == 0); case 'r': /* file is readable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], R_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], R_OK) == 0); case 'w': /* File is writeable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], W_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], W_OK) == 0); case 'x': /* File is executable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], X_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], X_OK) == 0); case 'O': /* File is owned by you? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - -#if defined (SHELL) - return (TRUE == ((UID_T) current_user.euid == (UID_T) stat_buf.st_uid)); -#else - return (TRUE == ((UID_T) geteuid () == (UID_T) stat_buf.st_uid)); -#endif /* !SHEL */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (uid_t) geteuid () == (uid_t) stat_buf.st_uid); case 'G': /* File is owned by your group? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == ((GID_T) getegid () == (GID_T) stat_buf.st_gid)); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (gid_t) getegid () == (gid_t) stat_buf.st_gid); case 'f': /* File is a file? */ unary_advance (); if (test_stat (argv[pos - 1], &stat_buf) < 0) return (FALSE); - /* Under POSIX, -f is true if the given file exists - and is a regular file. */ + /* -f is true if the given file exists and is a regular file. */ #if defined (S_IFMT) - return (TRUE == ((S_ISREG (stat_buf.st_mode)) || - (0 == (stat_buf.st_mode & S_IFMT)))); + return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0); #else - return (TRUE == (S_ISREG (stat_buf.st_mode))); + return (S_ISREG (stat_buf.st_mode)); #endif /* !S_IFMT */ case 'd': /* File is a directory? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISDIR (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (S_ISDIR (stat_buf.st_mode))); case 's': /* File has something in it? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (stat_buf.st_size > (off_t) 0)); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + stat_buf.st_size > (off_t) 0); case 'S': /* File is a socket? */ #if !defined (S_ISSOCK) return (FALSE); #else unary_advance (); - - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISSOCK (stat_buf.st_mode))); -#endif /* S_ISSOCK */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISSOCK (stat_buf.st_mode)); +#endif /* S_ISSOCK */ case 'c': /* File is character special? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISCHR (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISCHR (stat_buf.st_mode)); case 'b': /* File is block special? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISBLK (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISBLK (stat_buf.st_mode)); case 'p': /* File is a named pipe? */ unary_advance (); #ifndef S_ISFIFO return (FALSE); #else - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - return (TRUE == (S_ISFIFO (stat_buf.st_mode))); -#endif /* S_ISFIFO */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISFIFO (stat_buf.st_mode)); +#endif /* S_ISFIFO */ case 'L': /* Same as -h */ - /*FALLTHROUGH*/ - case 'h': /* File is a symbolic link? */ unary_advance (); -#ifndef S_ISLNK +#if !defined (S_ISLNK) || !defined (HAVE_LSTAT) return (FALSE); #else - /* An empty filename is not a valid pathname. */ - if ((argv[pos - 1][0] == '\0') || - (lstat (argv[pos - 1], &stat_buf) < 0)) - return (FALSE); - - return (TRUE == (S_ISLNK (stat_buf.st_mode))); -#endif /* S_IFLNK */ + return ((argv[pos - 1][0] != '\0') && + (lstat (argv[pos - 1], &stat_buf) == 0) && + S_ISLNK (stat_buf.st_mode)); +#endif /* S_IFLNK && HAVE_LSTAT */ case 'u': /* File is setuid? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (0 != (stat_buf.st_mode & S_ISUID))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISUID) != 0); case 'g': /* File is setgid? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (0 != (stat_buf.st_mode & S_ISGID))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISGID) != 0); case 'k': /* File has sticky bit set? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); #if !defined (S_ISVTX) /* This is not Posix, and is not defined on some Posix systems. */ return (FALSE); #else - return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISVTX) != 0); #endif - case 't': /* File (fd) is a terminal? (fd) defaults to stdout. */ + case 't': /* File fd is a terminal? fd defaults to stdout. */ advance (0); if (pos < argc && isint (argv[pos], &r)) { advance (0); - return (TRUE == (isatty ((int) r))); + return (isatty ((int)r)); } - return (TRUE == (isatty (1))); + return (isatty (1)); case 'n': /* True if arg has some length. */ unary_advance (); - return (TRUE == (argv[pos - 1][0] != 0)); + return (argv[pos - 1][0] != '\0'); case 'z': /* True if arg has no length. */ unary_advance (); - return (TRUE == (argv[pos - 1][0] == '\0')); + return (argv[pos - 1][0] == '\0'); + +#if !defined (STANDALONE) + case 'o': + unary_advance (); + return (minus_o_option_value (argv[pos - 1]) == 1); +#endif /* !STANDALONE */ } } - + /* * and: * term @@ -925,15 +787,16 @@ unary_operator () static int and () { - int value; + int value, v2; value = term (); while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) { advance (0); - value = TRUTH_AND (value, and ()); + v2 = and (); + return (value && v2); } - return (TRUE == value); + return (value); } /* @@ -944,17 +807,17 @@ and () static int or () { - int value; + int value, v2; value = and (); - while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) { advance (0); - value = TRUTH_OR (value, or ()); + v2 = or (); + return (value || v2); } - return (TRUE == value); + return (value); } /* @@ -967,7 +830,7 @@ expr () if (pos >= argc) beyond (); - return (FALSE ^ (or ())); /* Same with this. */ + return (FALSE ^ or ()); /* Same with this. */ } /* Return TRUE if S is one of the test command's binary operators. */ @@ -975,10 +838,56 @@ static int binop (s) char *s; { - return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) || - (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) || - (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) || - (STREQ (s, "-gt")) || (STREQ (s, "-ge"))); + char *t; + + if (s[0] == '=' && s[1] == '\0') + return (1); /* '=' */ + else if (s[1] == '\0' && (s[0] == '<' || s[0] == '>')) /* string <, > */ + return (1); + else if (s[2] == '\0' && s[1] == '=' && (s[0] == '=' || s[0] == '!')) + return (1); /* `==' and `!=' */ +#if defined (PATTERN_MATCHING) + else if (s[2] == '\0' && s[1] == '~' && (s[0] == '=' || s[0] == '!')) + return (1); +#endif + else if (s[0] != '-' || s[2] == '\0' || s[3] != '\0') + return (0); + else + { + t = s + 1; + if (t[1] == 't') + switch (t[0]) + { + case 'n': /* -nt */ + case 'o': /* -ot */ + case 'l': /* -lt */ + case 'g': /* -gt */ + return (1); + default: + return (0); + } + else if (t[0] == 'e') + switch (t[1]) + { + case 'q': /* -eq */ + case 'f': /* -ef */ + return (1); + default: + return (0); + } + else if (t[1] == 'e') + switch (t[0]) + { + case 'n': /* -ne */ + case 'l': /* -le */ + case 'g': /* -ge */ + return (1); + default: + return (0); + } + else + return (0); + } } /* Return non-zero if OP is one of the test command's unary operators. */ @@ -986,51 +895,74 @@ static int unop (op) int op; { - return (member (op, "abcdefgkLhprsStuwxOGnz")); + switch (op) + { + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'k': case 'n': + case 'p': case 'r': case 's': case 't': case 'u': + case 'w': case 'x': case 'z': + case 'G': case 'L': case 'O': case 'S': +#if !defined (STANDALONE) + case 'o': +#endif + return (1); + } + return (0); } static int two_arguments () { - int value; - - if (argv[pos][0] == '!' && !argv[pos][1]) - value = argv[pos + 1][0] == '\0'; - else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0')) + if (argv[pos][0] == '!' && argv[pos][1] == '\0') + return (argv[pos + 1][0] == '\0'); + else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { if (unop (argv[pos][1])) - value = unary_operator (); + return (unary_operator ()); else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); } else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); - return (value); + return (0); } +#define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o')) + +#define ONE_ARG_TEST(s) ((s)[0] != '\0') + static int three_arguments () { int value; - if (argv[pos][0] == '!' && !argv[pos][1]) + if (binop (argv[pos+1])) + { + value = binary_operator (); + pos = argc; + } + else if (ANDOR (argv[pos+1])) + { + if (argv[pos+1][1] == 'a') + value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]); + else + value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); + pos = argc; + } + else if (argv[pos][0] == '!' && !argv[pos][1]) { advance (1); value = !two_arguments (); } - else if (binop (argv[pos+1])) + else if (argv[pos][0] == '(' && argv[pos+2][0] == ')') { - value = binary_operator (); + value = ONE_ARG_TEST(argv[pos+1]); pos = argc; } - /* Check for -a or -o or a parenthesized subexpression. */ - else if ((argv[pos+1][0] == '-' && !argv[pos+1][2] && - (argv[pos+1][1] == 'a' || argv[pos+1][1] == 'o')) || - (argv[pos][0] == '(')) - value = expr (); else - test_syntax_error ("%s: binary operator expected\n", argv[pos+1]); + test_syntax_error ("%s: binary operator expected", argv[pos+1]); + return (value); } @@ -1048,7 +980,7 @@ posixtest () break; case 1: - value = argv[1][0] != '\0'; + value = ONE_ARG_TEST(argv[1]); pos = argc; break; @@ -1062,14 +994,13 @@ posixtest () break; case 4: - if (STREQ (argv[pos], "!")) + if (argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); value = !three_arguments (); break; } /* FALLTHROUGH */ - case 5: default: value = expr (); } @@ -1084,11 +1015,7 @@ posixtest () * test expr */ int -#if defined (STANDALONE) main (margc, margv) -#else -test_command (margc, margv) -#endif /* STANDALONE */ int margc; char **margv; { @@ -1101,11 +1028,11 @@ test_command (margc, margv) if (code) return (test_error_return); -#endif /* STANDALONE */ +#endif /* !STANDALONE */ argv = margv; - if (margv[0] && margv[0][0] == '[' && !margv[0][1]) + if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0') { --margc; @@ -1113,7 +1040,7 @@ test_command (margc, margv) test_exit (SHELL_BOOLEAN (FALSE)); if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1])) - test_syntax_error ("missing `]'\n", (char *)NULL); + test_syntax_error ("missing `]'", (char *)NULL); } argc = margc; @@ -1126,7 +1053,7 @@ test_command (margc, margv) value = posixtest (); if (pos != argc) - test_syntax_error ("too many arguments\n", (char *)NULL); + test_syntax_error ("too many arguments", (char *)NULL); test_exit (SHELL_BOOLEAN (value)); }