LCOV - code coverage report
Current view: top level - bash-4.4.23 - test.c (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 199 318 62.6 %
Date: 2020-10-29 14:49:28 Functions: 15 20 75.0 %

          Line data    Source code
       1             : /* test.c - GNU test program (ksb and mjb) */
       2             : 
       3             : /* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
       4             : 
       5             : /* Copyright (C) 1987-2010 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
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    Bash is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : /* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching
      24             :    binary operators. */
      25             : /* #define PATTERN_MATCHING */
      26             : 
      27             : #if defined (HAVE_CONFIG_H)
      28             : #  include <config.h>
      29             : #endif
      30             : 
      31             : #include <stdio.h>
      32             : 
      33             : #include "bashtypes.h"
      34             : 
      35             : #if !defined (HAVE_LIMITS_H) && defined (HAVE_SYS_PARAM_H)
      36             : #  include <sys/param.h>
      37             : #endif
      38             : 
      39             : #if defined (HAVE_UNISTD_H)
      40             : #  include <unistd.h>
      41             : #endif
      42             : 
      43             : #include <errno.h>
      44             : #if !defined (errno)
      45             : extern int errno;
      46             : #endif /* !errno */
      47             : 
      48             : #if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
      49             : #  include <sys/file.h>
      50             : #endif /* !_POSIX_VERSION */
      51             : #include "posixstat.h"
      52             : #include "filecntl.h"
      53             : #include "stat-time.h"
      54             : 
      55             : #include "bashintl.h"
      56             : 
      57             : #include "shell.h"
      58             : #include "pathexp.h"
      59             : #include "test.h"
      60             : #include "builtins/common.h"
      61             : 
      62             : #include <glob/strmatch.h>
      63             : 
      64             : #if !defined (STRLEN)
      65             : #  define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
      66             : #endif
      67             : 
      68             : #if !defined (STREQ)
      69             : #  define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
      70             : #endif /* !STREQ */
      71             : #define STRCOLLEQ(a, b) ((a)[0] == (b)[0] && strcoll ((a), (b)) == 0)
      72             : 
      73             : #if !defined (R_OK)
      74             : #define R_OK 4
      75             : #define W_OK 2
      76             : #define X_OK 1
      77             : #define F_OK 0
      78             : #endif /* R_OK */
      79             : 
      80             : #define EQ      0
      81             : #define NE      1
      82             : #define LT      2
      83             : #define GT      3
      84             : #define LE      4
      85             : #define GE      5
      86             : 
      87             : #define NT      0
      88             : #define OT      1
      89             : #define EF      2
      90             : 
      91             : /* The following few defines control the truth and false output of each stage.
      92             :    TRUE and FALSE are what we use to compute the final output value.
      93             :    SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
      94             :    Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */
      95             : #define TRUE 1
      96             : #define FALSE 0
      97             : #define SHELL_BOOLEAN(value) (!(value))
      98             : 
      99             : #define TEST_ERREXIT_STATUS     2
     100             : 
     101             : static procenv_t test_exit_buf;
     102             : static int test_error_return;
     103             : #define test_exit(val) \
     104             :         do { test_error_return = val; sh_longjmp (test_exit_buf, 1); } while (0)
     105             : 
     106             : extern int sh_stat __P((const char *, struct stat *));
     107             : 
     108             : static int pos;         /* The offset of the current argument in ARGV. */
     109             : static int argc;        /* The number of arguments present in ARGV. */
     110             : static char **argv;     /* The argument list. */
     111             : static int noeval;
     112             : 
     113             : static void test_syntax_error __P((char *, char *)) __attribute__((__noreturn__));
     114             : static void beyond __P((void)) __attribute__((__noreturn__));
     115             : static void integer_expected_error __P((char *)) __attribute__((__noreturn__));
     116             : 
     117             : static int unary_operator __P((void));
     118             : static int binary_operator __P((void));
     119             : static int two_arguments __P((void));
     120             : static int three_arguments __P((void));
     121             : static int posixtest __P((void));
     122             : 
     123             : static int expr __P((void));
     124             : static int term __P((void));
     125             : static int and __P((void));
     126             : static int or __P((void));
     127             : 
     128             : static int filecomp __P((char *, char *, int));
     129             : static int arithcomp __P((char *, char *, int, int));
     130             : static int patcomp __P((char *, char *, int));
     131             : 
     132             : static void
     133       70678 : test_syntax_error (format, arg)
     134             :      char *format, *arg;
     135             : {
     136       70678 :   builtin_error (format, arg);
     137       70678 :   test_exit (TEST_ERREXIT_STATUS);
     138             : }
     139             : 
     140             : /*
     141             :  * beyond - call when we're beyond the end of the argument list (an
     142             :  *      error condition)
     143             :  */
     144             : static void
     145           0 : beyond ()
     146             : {
     147           0 :   test_syntax_error (_("argument expected"), (char *)NULL);
     148             : }
     149             : 
     150             : /* Syntax error for when an integer argument was expected, but
     151             :    something else was found. */
     152             : static void
     153           0 : integer_expected_error (pch)
     154             :      char *pch;
     155             : {
     156           0 :   test_syntax_error (_("%s: integer expression expected"), pch);
     157             : }
     158             : 
     159             : /* Increment our position in the argument list.  Check that we're not
     160             :    past the end of the argument list.  This check is suppressed if the
     161             :    argument is FALSE.  Made a macro for efficiency. */
     162             : #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
     163             : #define unary_advance() do { advance (1); ++pos; } while (0)
     164             : 
     165             : /*
     166             :  * expr:
     167             :  *      or
     168             :  */
     169             : static int
     170         311 : expr ()
     171             : {
     172         311 :   if (pos >= argc)
     173           0 :     beyond ();
     174             : 
     175         311 :   return (FALSE ^ or ());               /* Same with this. */
     176             : }
     177             : 
     178             : /*
     179             :  * or:
     180             :  *      and
     181             :  *      and '-o' or
     182             :  */
     183             : static int
     184         311 : or ()
     185             : {
     186         311 :   int value, v2;
     187             : 
     188         311 :   value = and ();
     189         311 :   if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
     190             :     {
     191           0 :       advance (0);
     192           0 :       v2 = or ();
     193           0 :       return (value || v2);
     194             :     }
     195             : 
     196             :   return (value);
     197             : }
     198             : 
     199             : /*
     200             :  * and:
     201             :  *      term
     202             :  *      term '-a' and
     203             :  */
     204             : static int
     205         311 : and ()
     206             : {
     207         311 :   int value, v2;
     208             : 
     209         311 :   value = term ();
     210         311 :   if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
     211             :     {
     212           0 :       advance (0);
     213           0 :       v2 = and ();
     214           0 :       return (value && v2);
     215             :     }
     216             :   return (value);
     217             : }
     218             : 
     219             : /*
     220             :  * term - parse a term and return 1 or 0 depending on whether the term
     221             :  *      evaluates to true or false, respectively.
     222             :  *
     223             :  * term ::=
     224             :  *      '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename
     225             :  *      '-'('G'|'L'|'O'|'S'|'N') filename
     226             :  *      '-t' [int]
     227             :  *      '-'('z'|'n') string
     228             :  *      '-'('v'|'R') varname
     229             :  *      '-o' option
     230             :  *      string
     231             :  *      string ('!='|'='|'==') string
     232             :  *      <int> '-'(eq|ne|le|lt|ge|gt) <int>
     233             :  *      file '-'(nt|ot|ef) file
     234             :  *      '(' <expr> ')'
     235             :  * int ::=
     236             :  *      positive and negative integers
     237             :  */
     238             : static int
     239         363 : term ()
     240             : {
     241         363 :   int value;
     242             : 
     243         363 :   if (pos >= argc)
     244           0 :     beyond ();
     245             : 
     246             :   /* Deal with leading `not's. */
     247         363 :   if (argv[pos][0] == '!' && argv[pos][1] == '\0')
     248             :     {
     249             :       value = 0;
     250         104 :       while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')
     251             :         {
     252          52 :           advance (1);
     253          52 :           value = 1 - value;
     254             :         }
     255             : 
     256          52 :       return (value ? !term() : term());
     257             :     }
     258             : 
     259             :   /* A paren-bracketed argument. */
     260         311 :   if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */
     261             :     {
     262           0 :       advance (1);
     263           0 :       value = expr ();
     264           0 :       if (argv[pos] == 0) /* ( */
     265           0 :         test_syntax_error (_("`)' expected"), (char *)NULL);
     266           0 :       else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */
     267           0 :         test_syntax_error (_("`)' expected, found %s"), argv[pos]);
     268           0 :       advance (0);
     269           0 :       return (value);
     270             :     }
     271             : 
     272             :   /* are there enough arguments left that this could be dyadic? */
     273         311 :   if ((pos + 3 <= argc) && test_binop (argv[pos + 1]))
     274          81 :     value = binary_operator ();
     275             : 
     276             :   /* Might be a switch type argument */
     277         230 :   else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
     278             :     {
     279          75 :       if (test_unop (argv[pos]))
     280          75 :         value = unary_operator ();
     281             :       else
     282           0 :         test_syntax_error (_("%s: unary operator expected"), argv[pos]);
     283             :     }
     284             :   else
     285             :     {
     286         155 :       value = argv[pos][0] != '\0';
     287         155 :       advance (0);
     288             :     }
     289             : 
     290             :   return (value);
     291             : }
     292             : 
     293             : static int
     294             : stat_mtime (fn, st, ts)
     295             :      char *fn;
     296             :      struct stat *st;
     297             :      struct timespec *ts;
     298             : {
     299           0 :   int r;
     300             : 
     301           0 :   r = sh_stat (fn, st);
     302           0 :   if (r < 0)
     303             :     return r;
     304           0 :   *ts = get_stat_mtime (st);
     305           0 :   return 0;
     306             : }
     307             : 
     308             : static int
     309           0 : filecomp (s, t, op)
     310             :      char *s, *t;
     311             :      int op;
     312             : {
     313           0 :   struct stat st1, st2;
     314           0 :   struct timespec ts1, ts2;
     315           0 :   int r1, r2;
     316             : 
     317           0 :   if ((r1 = stat_mtime (s, &st1, &ts1)) < 0)
     318             :     {
     319           0 :       if (op == EF)
     320             :         return (FALSE);
     321             :     }
     322           0 :   if ((r2 = stat_mtime (t, &st2, &ts2)) < 0)
     323             :     {
     324           0 :       if (op == EF)
     325             :         return (FALSE);
     326             :     }
     327             :   
     328           0 :   switch (op)
     329             :     {
     330           0 :     case OT: return (r1 < r2 || (r2 == 0 && timespec_cmp (ts1, ts2) < 0));
     331           0 :     case NT: return (r1 > r2 || (r1 == 0 && timespec_cmp (ts1, ts2) > 0));
     332           0 :     case EF: return (same_file (s, t, &st1, &st2));
     333             :     }
     334             :   return (FALSE);
     335             : }
     336             : 
     337             : static int
     338           0 : arithcomp (s, t, op, flags)
     339             :      char *s, *t;
     340             :      int op, flags;
     341             : {
     342           0 :   intmax_t l, r;
     343           0 :   int expok;
     344             : 
     345           0 :   if (flags & TEST_ARITHEXP)
     346             :     {
     347           0 :       l = evalexp (s, &expok);
     348           0 :       if (expok == 0)
     349             :         return (FALSE);         /* should probably longjmp here */
     350           0 :       r = evalexp (t, &expok);
     351           0 :       if (expok == 0)
     352             :         return (FALSE);         /* ditto */
     353             :     }
     354             :   else
     355             :     {
     356           0 :       if (legal_number (s, &l) == 0)
     357           0 :         integer_expected_error (s);
     358           0 :       if (legal_number (t, &r) == 0)
     359           0 :         integer_expected_error (t);
     360             :     }
     361             : 
     362           0 :   switch (op)
     363             :     {
     364           0 :     case EQ: return (l == r);
     365           0 :     case NE: return (l != r);
     366           0 :     case LT: return (l < r);
     367           0 :     case GT: return (l > r);
     368           0 :     case LE: return (l <= r);
     369           0 :     case GE: return (l >= r);
     370             :     }
     371             : 
     372             :   return (FALSE);
     373             : }
     374             : 
     375             : static int
     376           0 : patcomp (string, pat, op)
     377             :      char *string, *pat;
     378             :      int op;
     379             : {
     380           0 :   int m;
     381             : 
     382           0 :   m = strmatch (pat, string, FNMATCH_EXTFLAG|FNMATCH_IGNCASE);
     383           0 :   return ((op == EQ) ? (m == 0) : (m != 0));
     384             : }
     385             : 
     386             : int
     387       83778 : binary_test (op, arg1, arg2, flags)
     388             :      char *op, *arg1, *arg2;
     389             :      int flags;
     390             : {
     391       83778 :   int patmatch;
     392             : 
     393       83778 :   patmatch = (flags & TEST_PATMATCH);
     394             : 
     395       83778 :   if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0')))
     396         138 :     return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2));
     397       83709 :   else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0')
     398             :     {
     399             : #if defined (HAVE_STRCOLL)
     400           0 :       if (shell_compatibility_level > 40 && flags & TEST_LOCALE)
     401           0 :         return ((op[0] == '>') ? (strcoll (arg1, arg2) > 0) : (strcoll (arg1, arg2) < 0));
     402             :       else
     403             : #endif
     404           0 :         return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0));
     405             :     }
     406       83709 :   else if (op[0] == '!' && op[1] == '=' && op[2] == '\0')
     407      167406 :     return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0));
     408             :     
     409             : 
     410           0 :   else if (op[2] == 't')
     411             :     {
     412           0 :       switch (op[1])
     413             :         {
     414           0 :         case 'n': return (filecomp (arg1, arg2, NT));           /* -nt */
     415           0 :         case 'o': return (filecomp (arg1, arg2, OT));           /* -ot */
     416           0 :         case 'l': return (arithcomp (arg1, arg2, LT, flags));   /* -lt */
     417           0 :         case 'g': return (arithcomp (arg1, arg2, GT, flags));   /* -gt */
     418             :         }
     419             :     }
     420           0 :   else if (op[1] == 'e')
     421             :     {
     422           0 :       switch (op[2])
     423             :         {
     424           0 :         case 'f': return (filecomp (arg1, arg2, EF));           /* -ef */
     425           0 :         case 'q': return (arithcomp (arg1, arg2, EQ, flags));   /* -eq */
     426             :         }
     427             :     }
     428           0 :   else if (op[2] == 'e')
     429             :     {
     430           0 :       switch (op[1])
     431             :         {
     432           0 :         case 'n': return (arithcomp (arg1, arg2, NE, flags));   /* -ne */
     433           0 :         case 'g': return (arithcomp (arg1, arg2, GE, flags));   /* -ge */
     434           0 :         case 'l': return (arithcomp (arg1, arg2, LE, flags));   /* -le */
     435             :         }
     436             :     }
     437             : 
     438             :   return (FALSE);       /* should never get here */
     439             : }
     440             : 
     441             : 
     442             : static int
     443       83778 : binary_operator ()
     444             : {
     445       83778 :   int value;
     446       83778 :   char *w;
     447             : 
     448       83778 :   w = argv[pos + 1];
     449       83778 :   if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */
     450       83709 :       ((w[0] == '>' || w[0] == '<') && w[1] == '\0') ||           /* <, > */
     451       83709 :       (w[0] == '!' && w[1] == '=' && w[2] == '\0'))             /* != */
     452             :     {
     453       83778 :       value = binary_test (w, argv[pos], argv[pos + 2], 0);
     454       83778 :       pos += 3;
     455       83778 :       return (value);
     456             :     }
     457             : 
     458             : #if defined (PATTERN_MATCHING)
     459             :   if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0')
     460             :     {
     461             :       value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE);
     462             :       pos += 3;
     463             :       return (value);
     464             :     }
     465             : #endif
     466             : 
     467           0 :   if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0)
     468             :     {
     469           0 :       test_syntax_error (_("%s: binary operator expected"), w);
     470             :       /* NOTREACHED */
     471             :       return (FALSE);
     472             :     }
     473             : 
     474           0 :   value = binary_test (w, argv[pos], argv[pos + 2], 0);
     475           0 :   pos += 3;
     476           0 :   return value;
     477             : }
     478             : 
     479             : static int
     480    23846746 : unary_operator ()
     481             : {
     482    23846746 :   char *op;
     483    23846746 :   intmax_t r;
     484             : 
     485    23846746 :   op = argv[pos];
     486    47693492 :   if (test_unop (op) == 0)
     487             :     return (FALSE);
     488             : 
     489             :   /* the only tricky case is `-t', which may or may not take an argument. */
     490    23846746 :   if (op[1] == 't')
     491             :     {
     492          13 :       advance (0);
     493          13 :       if (pos < argc)
     494             :         {
     495          13 :           if (legal_number (argv[pos], &r))
     496             :             {
     497           0 :               advance (0);
     498           0 :               return (unary_test (op, argv[pos - 1]));
     499             :             }
     500             :           else
     501             :             return (FALSE);
     502             :         }
     503             :       else
     504           0 :         return (unary_test (op, "1"));
     505             :     }
     506             : 
     507             :   /* All of the unary operators take an argument, so we first call
     508             :      unary_advance (), which checks to make sure that there is an
     509             :      argument, and then advances pos right past it.  This means that
     510             :      pos - 1 is the location of the argument. */
     511    23846733 :   unary_advance ();
     512    23846733 :   return (unary_test (op, argv[pos - 1]));
     513             : }
     514             : 
     515             : int
     516    23846733 : unary_test (op, arg)
     517             :      char *op, *arg;
     518             : {
     519    23846733 :   intmax_t r;
     520    23846733 :   struct stat stat_buf;
     521    23846733 :   SHELL_VAR *v;
     522             :      
     523    23846733 :   switch (op[1])
     524             :     {
     525          33 :     case 'a':                   /* file exists in the file system? */
     526             :     case 'e':
     527          33 :       return (sh_stat (arg, &stat_buf) == 0);
     528             : 
     529     9143245 :     case 'r':                   /* file is readable? */
     530     9143245 :       return (sh_eaccess (arg, R_OK) == 0);
     531             : 
     532           5 :     case 'w':                   /* File is writeable? */
     533           5 :       return (sh_eaccess (arg, W_OK) == 0);
     534             : 
     535       28380 :     case 'x':                   /* File is executable? */
     536       28380 :       return (sh_eaccess (arg, X_OK) == 0);
     537             : 
     538          22 :     case 'O':                   /* File is owned by you? */
     539          22 :       return (sh_stat (arg, &stat_buf) == 0 &&
     540          12 :               (uid_t) current_user.euid == (uid_t) stat_buf.st_uid);
     541             : 
     542          13 :     case 'G':                   /* File is owned by your group? */
     543          13 :       return (sh_stat (arg, &stat_buf) == 0 &&
     544          13 :               (gid_t) current_user.egid == (gid_t) stat_buf.st_gid);
     545             : 
     546          12 :     case 'N':
     547          12 :       return (sh_stat (arg, &stat_buf) == 0 &&
     548          12 :               stat_buf.st_atime <= stat_buf.st_mtime);
     549             : 
     550     5514302 :     case 'f':                   /* File is a file? */
     551     5514302 :       if (sh_stat (arg, &stat_buf) < 0)
     552             :         return (FALSE);
     553             : 
     554             :       /* -f is true if the given file exists and is a regular file. */
     555             : #if defined (S_IFMT)
     556     5399723 :       return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0);
     557             : #else
     558             :       return (S_ISREG (stat_buf.st_mode));
     559             : #endif /* !S_IFMT */
     560             : 
     561          26 :     case 'd':                   /* File is a directory? */
     562          26 :       return (sh_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode)));
     563             : 
     564          16 :     case 's':                   /* File has something in it? */
     565          16 :       return (sh_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0);
     566             : 
     567          12 :     case 'S':                   /* File is a socket? */
     568             : #if !defined (S_ISSOCK)
     569             :       return (FALSE);
     570             : #else
     571          12 :       return (sh_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode));
     572             : #endif /* S_ISSOCK */
     573             : 
     574       17228 :     case 'c':                   /* File is character special? */
     575       17228 :       return (sh_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode));
     576             : 
     577          16 :     case 'b':                   /* File is block special? */
     578          16 :       return (sh_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode));
     579             : 
     580          13 :     case 'p':                   /* File is a named pipe? */
     581             : #ifndef S_ISFIFO
     582             :       return (FALSE);
     583             : #else
     584          13 :       return (sh_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode));
     585             : #endif /* S_ISFIFO */
     586             : 
     587          25 :     case 'L':                   /* Same as -h  */
     588             :     case 'h':                   /* File is a symbolic link? */
     589             : #if !defined (S_ISLNK) || !defined (HAVE_LSTAT)
     590             :       return (FALSE);
     591             : #else
     592          50 :       return ((arg[0] != '\0') &&
     593          25 :               (lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode));
     594             : #endif /* S_IFLNK && HAVE_LSTAT */
     595             : 
     596          12 :     case 'u':                   /* File is setuid? */
     597          12 :       return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0);
     598             : 
     599          22 :     case 'g':                   /* File is setgid? */
     600          22 :       return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0);
     601             : 
     602          13 :     case 'k':                   /* File has sticky bit set? */
     603             : #if !defined (S_ISVTX)
     604             :       /* This is not Posix, and is not defined on some Posix systems. */
     605             :       return (FALSE);
     606             : #else
     607          13 :       return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0);
     608             : #endif
     609             : 
     610           0 :     case 't':   /* File fd is a terminal? */
     611           0 :       if (legal_number (arg, &r) == 0)
     612             :         return (FALSE);
     613           0 :       return ((r == (int)r) && isatty ((int)r));
     614             : 
     615          16 :     case 'n':                   /* True if arg has some length. */
     616          16 :       return (arg[0] != '\0');
     617             : 
     618     9143255 :     case 'z':                   /* True if arg has no length. */
     619     9143255 :       return (arg[0] == '\0');
     620             : 
     621          11 :     case 'o':                   /* True if option `arg' is set. */
     622          11 :       return (minus_o_option_value (arg) == 1);
     623             : 
     624          45 :     case 'v':
     625          45 :       v = find_variable (arg);
     626             : #if defined (ARRAY_VARS)
     627          45 :       if (v == 0 && valid_array_reference (arg, 0))
     628             :         {
     629           0 :           char *t;
     630           0 :           t = array_value (arg, 0, 0, (int *)0, (arrayind_t *)0);
     631           0 :           return (t ? TRUE : FALSE);
     632             :         }
     633          45 :      else if (v && invisible_p (v) == 0 && array_p (v))
     634             :         {
     635           0 :           char *t;
     636             :           /* [[ -v foo ]] == [[ -v foo[0] ]] */
     637           0 :           t = array_reference (array_cell (v), 0);
     638           0 :           return (t ? TRUE : FALSE);
     639             :         }
     640          45 :       else if (v && invisible_p (v) == 0 && assoc_p (v))
     641             :         {
     642           0 :           char *t;
     643           0 :           t = assoc_reference (assoc_cell (v), "0");
     644           0 :           return (t ? TRUE : FALSE);
     645             :         }
     646             : #endif
     647          45 :       return (v && invisible_p (v) == 0 && var_isset (v) ? TRUE : FALSE);
     648             : 
     649          11 :     case 'R':
     650          11 :       v = find_variable_noref (arg);
     651          11 :       return ((v && invisible_p (v) == 0 && var_isset (v) && nameref_p (v)) ? TRUE : FALSE);
     652             :     }
     653             : 
     654             :   /* We can't actually get here, but this shuts up gcc. */
     655             :   return (FALSE);
     656             : }
     657             : 
     658             : /* Return TRUE if OP is one of the test command's binary operators. */
     659             : int
     660     3308577 : test_binop (op)
     661             :      char *op;
     662             : {
     663     3308577 :   if (op[0] == '=' && op[1] == '\0')
     664             :     return (1);         /* '=' */
     665     3308517 :   else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0')  /* string <, > */
     666             :     return (1);
     667     3308517 :   else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0')
     668             :     return (1);         /* `==' and `!=' */
     669             : #if defined (PATTERN_MATCHING)
     670             :   else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!'))
     671             :     return (1);
     672             : #endif
     673     3224790 :   else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0')
     674             :     return (0);
     675             :   else
     676             :     {
     677          13 :       if (op[2] == 't')
     678           0 :         switch (op[1])
     679             :           {
     680             :           case 'n':             /* -nt */
     681             :           case 'o':             /* -ot */
     682             :           case 'l':             /* -lt */
     683             :           case 'g':             /* -gt */
     684             :             return (1);
     685           0 :           default:
     686           0 :             return (0);
     687             :           }
     688          13 :       else if (op[1] == 'e')
     689           0 :         switch (op[2])
     690             :           {
     691             :           case 'q':             /* -eq */
     692             :           case 'f':             /* -ef */
     693             :             return (1);
     694           0 :           default:
     695           0 :             return (0);
     696             :           }
     697          13 :       else if (op[2] == 'e')
     698           0 :         switch (op[1])
     699             :           {
     700             :           case 'n':             /* -ne */
     701             :           case 'g':             /* -ge */
     702             :           case 'l':             /* -le */
     703             :             return (1);
     704           0 :           default:
     705           0 :             return (0);
     706             :           }
     707             :       else
     708             :         return (0);
     709             :     }
     710             : }
     711             : 
     712             : /* Return non-zero if OP is one of the test command's unary operators. */
     713             : int
     714           9 : test_unop (op)
     715             :      char *op;
     716             : {
     717    23846755 :   if (op[0] != '-' || op[2] != 0)
     718             :     return (0);
     719             : 
     720    23846830 :   switch (op[1])
     721             :     {
     722             :     case 'a': case 'b': case 'c': case 'd': case 'e':
     723             :     case 'f': case 'g': case 'h': case 'k': case 'n':
     724             :     case 'o': case 'p': case 'r': case 's': case 't':
     725             :     case 'u': case 'v': case 'w': case 'x': case 'z':
     726             :     case 'G': case 'L': case 'O': case 'S': case 'N':
     727             :     case 'R':
     728             :       return (1);
     729             :     }
     730             : 
     731             :   return (0);
     732             : }
     733             : 
     734             : static int
     735    23871616 : two_arguments ()
     736             : {
     737    23871616 :   if (argv[pos][0] == '!' && argv[pos][1] == '\0')
     738        1941 :     return (argv[pos + 1][0] == '\0');
     739    23869675 :   else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
     740             :     {
     741    23847014 :       if (test_unop (argv[pos]))
     742    23846671 :         return (unary_operator ());
     743             :       else
     744         343 :         test_syntax_error (_("%s: unary operator expected"), argv[pos]);
     745             :     }
     746             :   else
     747       22661 :     test_syntax_error (_("%s: unary operator expected"), argv[pos]);
     748             : 
     749             :   return (0);
     750             : }
     751             : 
     752             : #define ANDOR(s)  (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o'))
     753             : 
     754             : /* This could be augmented to handle `-t' as equivalent to `-t 1', but
     755             :    POSIX requires that `-t' be given an argument. */
     756             : #define ONE_ARG_TEST(s)         ((s)[0] != '\0')
     757             : 
     758             : static int
     759     3308257 : three_arguments ()
     760             : {
     761     3308257 :   int value;
     762             : 
     763     3308257 :   if (test_binop (argv[pos+1]))
     764             :     {
     765       83697 :       value = binary_operator ();
     766       83697 :       pos = argc;
     767             :     }
     768     3224560 :   else if (ANDOR (argv[pos+1]))
     769             :     {
     770          20 :       if (argv[pos+1][1] == 'a')
     771          10 :         value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]);
     772             :       else
     773          10 :         value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]);
     774          20 :       pos = argc;
     775             :     }
     776     3224540 :   else if (argv[pos][0] == '!' && argv[pos][1] == '\0')
     777             :     {
     778     3207819 :       advance (1);
     779     3207819 :       value = !two_arguments ();
     780             :     }
     781       16721 :   else if (argv[pos][0] == '(' && argv[pos+2][0] == ')')
     782             :     {
     783           0 :       value = ONE_ARG_TEST(argv[pos+1]);
     784           0 :       pos = argc;
     785             :     }
     786             :   else
     787       16721 :     test_syntax_error (_("%s: binary operator expected"), argv[pos+1]);
     788             : 
     789     3277427 :   return (value);
     790             : }
     791             : 
     792             : /* This is an implementation of a Posix.2 proposal by David Korn. */
     793             : static int
     794    23975026 : posixtest ()
     795             : {
     796    23975026 :   int value;
     797             : 
     798    23975026 :   switch (argc - 1)     /* one extra passed in */
     799             :     {
     800           0 :       case 0:
     801           0 :         value = FALSE;
     802           0 :         pos = argc;
     803           0 :         break;
     804             : 
     805        2661 :       case 1:
     806        2661 :         value = ONE_ARG_TEST(argv[1]);
     807        2661 :         pos = argc;
     808        2661 :         break;
     809             : 
     810    20663797 :       case 2:
     811    20663797 :         value = two_arguments ();
     812    20654902 :         pos = argc;
     813    20654902 :         break;
     814             : 
     815     3308107 :       case 3:
     816     3308107 :         value = three_arguments ();
     817     3308107 :         break;
     818             : 
     819         256 :       case 4:
     820         256 :         if (argv[pos][0] == '!' && argv[pos][1] == '\0')
     821             :           {
     822         150 :             advance (1);
     823         150 :             value = !three_arguments ();
     824           9 :             break;
     825             :           }
     826         106 :         else if (argv[pos][0] == '(' && argv[pos][1] == '\0' && argv[argc-1][0] == ')' && argv[argc-1][1] == '\0')
     827             :           {
     828           0 :             advance (1);
     829           0 :             value = two_arguments ();
     830           0 :             pos = argc;
     831           0 :             break;
     832             :           }
     833             :         /* FALLTHROUGH */
     834             :       default:
     835         311 :         value = expr ();
     836             :     }
     837             : 
     838    23935301 :   return (value);
     839             : }
     840             : 
     841             : /*
     842             :  * [:
     843             :  *      '[' expr ']'
     844             :  * test:
     845             :  *      test expr
     846             :  */
     847             : int
     848    24005686 : test_command (margc, margv)
     849             :      int margc;
     850             :      char **margv;
     851             : {
     852    24005686 :   int value;
     853    24005686 :   int code;
     854             : 
     855    24005686 :   USE_VAR(margc);
     856             : 
     857    24005686 :   code = setjmp_nosigs (test_exit_buf);
     858             : 
     859    48011372 :   if (code)
     860    48011372 :     return (test_error_return);
     861             : 
     862    24005686 :   argv = margv;
     863             : 
     864    24005686 :   if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0')
     865             :     {
     866    24005669 :       --margc;
     867             : 
     868    24005669 :       if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
     869       30639 :         test_syntax_error (_("missing `]'"), (char *)NULL);
     870             : 
     871    23975030 :       if (margc < 2)
     872          21 :         test_exit (SHELL_BOOLEAN (FALSE));
     873             :     }
     874             : 
     875    23975026 :   argc = margc;
     876    23975026 :   pos = 1;
     877             : 
     878    23975026 :   if (pos >= argc)
     879           0 :     test_exit (SHELL_BOOLEAN (FALSE));
     880             : 
     881    23975026 :   noeval = 0;
     882    23975026 :   value = posixtest ();
     883             : 
     884    23935301 :   if (pos != argc)
     885         314 :     test_syntax_error (_("too many arguments"), (char *)NULL);
     886             : 
     887    24005686 :   test_exit (SHELL_BOOLEAN (value));
     888             : }

Generated by: LCOV version 1.14.0.6.4058