/* GNU test program (ksb and mjb) */                                            This is the test utility
                                                                                
/* Modified to run with the GNU shell by bfox. */                               
                                                                                
/* Copyright (C) 1987-2018 Free Software Foundation, Inc.                       
                                                                                
   This program is free software: you can redistribute it and/or modify         
   it under the terms of the GNU General Public License as published by         
   the Free Software Foundation, either version 3 of the License, or            
   (at your option) any later version.                                          
                                                                                
   This program is distributed in the hope that it will be useful,              
   but WITHOUT ANY WARRANTY; without even the implied warranty of               
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                
   GNU General Public License for more details.                                 
                                                                                
   You should have received a copy of the GNU General Public License            
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */   
                                                                                
/* Define TEST_STANDALONE to get the /bin/test version.  Otherwise, you get     
   the shell builtin version. */                                                
                                                                                
/* Without this pragma, gcc 4.6.2 20111027 mistakenly suggests that             
   the advance function might be candidate for attribute 'pure'.  */            
#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__                      Line 25
# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"                      Line 26
#endif                                                                          Line 27
                                                                                
#include <config.h>                                                             Provides system specific information
#include <stdio.h>                                                              Provides standard I/O capability
#include <sys/types.h>                                                          Provides system data types
                                                                                
#define TEST_STANDALONE 1                                                       Line 33
                                                                                
#ifndef LBRACKET                                                                Line 35
# define LBRACKET 0                                                             Line 36
#endif                                                                          Line 37
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#if LBRACKET                                                                    Line 40
# define PROGRAM_NAME "["                                                       Line 41
#else                                                                           Line 42
# define PROGRAM_NAME "test"                                                    Line 43
#endif                                                                          Line 44
                                                                                
#include "system.h"                                                             ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
#include "stat-time.h"                                                          ...!includes auto-comment...
#include "strnumcmp.h"                                                          ...!includes auto-comment...
                                                                                
#include <stdarg.h>                                                             ...!includes auto-comment...
#include "verror.h"                                                             ...!includes auto-comment......!includes auto-comment...
                                                                                
#if HAVE_SYS_PARAM_H                                                            Line 54
# include <sys/param.h>                                                         Line 55
#endif                                                                          Line 56
                                                                                
/* Exit status for syntax errors, etc.  */                                      
enum { TEST_TRUE, TEST_FALSE, TEST_FAILURE };                                   Line 59
                                                                                
#if defined TEST_STANDALONE                                                     Line 61
# define test_exit(val) exit (val)                                              Line 62
# define test_main_return(val) return val                                       Line 63
#else                                                                           Line 64
   static jmp_buf test_exit_buf;                                                Line 65
   static int test_error_return = 0;                                            Line 66
# define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)     Line 67
# define test_main_return(val) test_exit (val)                                  Line 68
#endif /* !TEST_STANDALONE */                                                   Line 69
                                                                                
static int pos;  /* The offset of the current argument in ARGV. */              Line 71
static int argc; /* The number of arguments present in ARGV. */                 Line 72
static char **argv; /* The argument list. */                                    Line 73
                                                                                
static bool test_unop (char const *s);                                          Line 75
static bool unary_operator (void);                                              Line 76
static bool binary_operator (bool);                                             Line 77
static bool two_arguments (void);                                               Line 78
static bool three_arguments (void);                                             Line 79
static bool posixtest (int);                                                    Line 80
                                                                                
static bool expr (void);                                                        Line 82
static bool term (void);                                                        Line 83
static bool and (void);                                                         Line 84
static bool or (void);                                                          Line 85
                                                                                
static void test_syntax_error (char const *format, ...)                         Line 87
     ATTRIBUTE_NORETURN;                                                        Line 88
static void beyond (void) ATTRIBUTE_NORETURN;                                   Line 89
                                                                                
static void                                                                     Line 91
test_syntax_error (char const *format, ...)                                     Line 92
{                                                                               
  va_list ap;                                                                   Line 94
  va_start (ap, format);                                                        Line 95
  verror (0, 0, format, ap);                                                    Line 96
  test_exit (TEST_FAILURE);                                                     Line 97
}                                                                               Block 2
                                                                                
/* Increment our position in the argument list.  Check that we're not           
   past the end of the argument list.  This check is suppressed if the          
   argument is false.  */                                                       
                                                                                
static void                                                                     Line 104
advance (bool f)                                                                Line 105
{                                                                               
  ++pos;                                                                        Line 107
                                                                                
  if (f && pos >= argc)                                                         Line 109
    beyond ();                                                                  Line 110
}                                                                               Block 3
                                                                                
static void                                                                     Line 113
unary_advance (void)                                                            Line 114
{                                                                               
  advance (true);                                                               Line 116
  ++pos;                                                                        Line 117
}                                                                               Block 4
                                                                                
/*                                                                              
 * beyond - call when we're beyond the end of the argument list (an             
 * error condition)                                                             
 */                                                                             
static void                                                                     Line 124
beyond (void)                                                                   Line 125
{                                                                               
  test_syntax_error (_("missing argument after %s"), quote (argv[argc - 1]));   Line 127
}                                                                               Block 5
                                                                                
/* If the characters pointed to by STRING constitute a valid number,            
   return a pointer to the start of the number, skipping any blanks or          
   leading '+'.  Otherwise, report an error and exit.  */                       
static char const *                                                             Line 133
find_int (char const *string)                                                   Line 134
{                                                                               
  char const *p;                                                                Line 136
  char const *number_start;                                                     Line 137
                                                                                
  for (p = string; isblank (to_uchar (*p)); p++)                                Line 139
    continue;                                                                   Line 140
                                                                                
  if (*p == '+')                                                                Line 142
    {                                                                           
      p++;                                                                      Line 144
      number_start = p;                                                         Line 145
    }                                                                           
  else                                                                          Line 147
    {                                                                           
      number_start = p;                                                         Line 149
      p += (*p == '-');                                                         Line 150
    }                                                                           
                                                                                
  if (ISDIGIT (*p++))                                                           Line 153
    {                                                                           
      while (ISDIGIT (*p))                                                      Line 155
        p++;                                                                    Line 156
      while (isblank (to_uchar (*p)))                                           Line 157
        p++;                                                                    Line 158
      if (!*p)                                                                  Line 159
        return number_start;                                                    Line 160
    }                                                                           
                                                                                
  test_syntax_error (_("invalid integer %s"), quote (string));                  Line 163
}                                                                               Block 6
                                                                                
/* Find the modification time of FILE, and stuff it into *MTIME.                
   Return true if successful.  */                                               
static bool                                                                     Line 168
get_mtime (char const *filename, struct timespec *mtime)                        Line 169
{                                                                               
  struct stat finfo;                                                            Line 171
  bool ok = (stat (filename, &finfo) == 0);                                     Line 172...!syscalls auto-comment...
#ifdef lint                                                                     Line 173
  static struct timespec const zero;                                            Line 174
  *mtime = zero;                                                                Line 175
#endif                                                                          Line 176
  if (ok)                                                                       Line 177
    *mtime = get_stat_mtime (&finfo);                                           Line 178
  return ok;                                                                    Line 179
}                                                                               Block 7
                                                                                
/* Return true if S is one of the test command's binary operators.  */          
static bool                                                                     Line 183
binop (char const *s)                                                           Line 184
{                                                                               
  return ((STREQ (s,   "=")) || (STREQ (s,  "!=")) || (STREQ (s, "==")) ||      Line 186
          (STREQ (s,   "-nt")) ||                                               Line 187
          (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||     Line 188
          (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||     Line 189
          (STREQ (s, "-gt")) || (STREQ (s, "-ge")));                            Line 190
}                                                                               Block 8
                                                                                
/*                                                                              
 * 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                                                                     
 * '-'('z'|'n') string                                                          
 * string                                                                       
 * string ('!='|'=') string                                                     
 * <int> '-'(eq|ne|le|lt|ge|gt) <int>                                           
 * file '-'(nt|ot|ef) file                                                      
 * '(' <expr> ')'                                                               
 * int ::=                                                                      
 * '-l' string                                                                  
 * positive and negative integers                                               
 */                                                                             
static bool                                                                     Line 211
term (void)                                                                     Line 212
{                                                                               
  bool value;                                                                   Line 214
  bool negated = false;                                                         Line 215
                                                                                
  /* Deal with leading 'not's.  */                                              
  while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')             Line 218
    {                                                                           
      advance (true);                                                           Line 220
      negated = !negated;                                                       Line 221
    }                                                                           
                                                                                
  if (pos >= argc)                                                              Line 224
    beyond ();                                                                  Line 225
                                                                                
  /* A paren-bracketed argument. */                                             
  if (argv[pos][0] == '(' && argv[pos][1] == '\0')                              Line 228
    {                                                                           
      int nargs;                                                                Line 230
                                                                                
      advance (true);                                                           Line 232
                                                                                
      for (nargs = 1;                                                           Line 234
           pos + nargs < argc && ! STREQ (argv[pos + nargs], ")");              Line 235
           nargs++)                                                             Line 236
        if (nargs == 4)                                                         Line 237
          {                                                                     
            nargs = argc - pos;                                                 Line 239
            break;                                                              Line 240
          }                                                                     
                                                                                
      value = posixtest (nargs);                                                Line 243
      if (argv[pos] == 0)                                                       Line 244
        test_syntax_error (_("%s expected"), quote (")"));                      Line 245
      else                                                                      Line 246
        if (argv[pos][0] != ')' || argv[pos][1])                                Line 247
          test_syntax_error (_("%s expected, found %s"),                        Line 248
                             quote_n (0, ")"), quote_n (1, argv[pos]));         Line 249
      advance (false);                                                          Line 250
    }                                                                           
                                                                                
  /* Are there enough arguments left that this could be dyadic?  */             
  else if (4 <= argc - pos && STREQ (argv[pos], "-l") && binop (argv[pos + 2])) Line 254
    value = binary_operator (true);                                             Line 255
  else if (3 <= argc - pos && binop (argv[pos + 1]))                            Line 256
    value = binary_operator (false);                                            Line 257
                                                                                
  /* It might be a switch type argument.  */                                    
  else if (argv[pos][0] == '-' && argv[pos][1] && argv[pos][2] == '\0')         Line 260
    {                                                                           
      if (test_unop (argv[pos]))                                                Line 262
        value = unary_operator ();                                              Line 263
      else                                                                      Line 264
        test_syntax_error (_("%s: unary operator expected"), quote (argv[pos]));Line 265
    }                                                                           
  else                                                                          Line 267
    {                                                                           
      value = (argv[pos][0] != '\0');                                           Line 269
      advance (false);                                                          Line 270
    }                                                                           
                                                                                
  return negated ^ value;                                                       Line 273
}                                                                               Block 9
                                                                                
static bool                                                                     Line 276
binary_operator (bool l_is_l)                                                   Line 277
{                                                                               
  int op;                                                                       Line 279
  struct stat stat_buf, stat_spare;                                             Line 280
  /* Is the right integer expression of the form '-l string'? */                
  bool r_is_l;                                                                  Line 282
                                                                                
  if (l_is_l)                                                                   Line 284
    advance (false);                                                            Line 285
  op = pos + 1;                                                                 Line 286
                                                                                
  if ((op < argc - 2) && STREQ (argv[op + 1], "-l"))                            Line 288
    {                                                                           
      r_is_l = true;                                                            Line 290
      advance (false);                                                          Line 291
    }                                                                           
  else                                                                          Line 293
    r_is_l = false;                                                             Line 294
                                                                                
  if (argv[op][0] == '-')                                                       Line 296
    {                                                                           
      /* check for eq, nt, and stuff */                                         
      if ((((argv[op][1] == 'l' || argv[op][1] == 'g')                          Line 299
            && (argv[op][2] == 'e' || argv[op][2] == 't'))                      Line 300
           || (argv[op][1] == 'e' && argv[op][2] == 'q')                        Line 301
           || (argv[op][1] == 'n' && argv[op][2] == 'e'))                       Line 302
          && !argv[op][3])                                                      Line 303
        {                                                                       
          char lbuf[INT_BUFSIZE_BOUND (uintmax_t)];                             Line 305
          char rbuf[INT_BUFSIZE_BOUND (uintmax_t)];                             Line 306
          char const *l = (l_is_l                                               Line 307
                           ? umaxtostr (strlen (argv[op - 1]), lbuf)            Line 308
                           : find_int (argv[op - 1]));                          Line 309
          char const *r = (r_is_l                                               Line 310
                           ? umaxtostr (strlen (argv[op + 2]), rbuf)            Line 311
                           : find_int (argv[op + 1]));                          Line 312
          int cmp = strintcmp (l, r);                                           Line 313
          bool xe_operator = (argv[op][2] == 'e');                              Line 314
          pos += 3;                                                             Line 315
          return (argv[op][1] == 'l' ? cmp < xe_operator                        Line 316
                  : argv[op][1] == 'g' ? cmp > - xe_operator                    Line 317
                  : (cmp != 0) == xe_operator);                                 Line 318
        }                                                                       
                                                                                
      switch (argv[op][1])                                                      Line 321
        {                                                                       
        default:                                                                Line 323
          break;                                                                Line 324
                                                                                
        case 'n':                                                               Line 326
          if (argv[op][2] == 't' && !argv[op][3])                               Line 327
            {                                                                   
              /* nt - newer than */                                             
              struct timespec lt, rt;                                           Line 330
              bool le, re;                                                      Line 331
              pos += 3;                                                         Line 332
              if (l_is_l || r_is_l)                                             Line 333
                test_syntax_error (_("-nt does not accept -l"), NULL);          Line 334
              le = get_mtime (argv[op - 1], <);                               Line 335
              re = get_mtime (argv[op + 1], &rt);                               Line 336
              return le && (!re || timespec_cmp (lt, rt) > 0);                  Line 337
            }                                                                   
          break;                                                                Line 339
                                                                                
        case 'e':                                                               Line 341
          if (argv[op][2] == 'f' && !argv[op][3])                               Line 342
            {                                                                   
              /* ef - hard link? */                                             
              pos += 3;                                                         Line 345
              if (l_is_l || r_is_l)                                             Line 346
                test_syntax_error (_("-ef does not accept -l"), NULL);          Line 347
              return (stat (argv[op - 1], &stat_buf) == 0                       Line 348...!syscalls auto-comment...
                      && stat (argv[op + 1], &stat_spare) == 0                  Line 349...!syscalls auto-comment...
                      && stat_buf.st_dev == stat_spare.st_dev                   Line 350
                      && stat_buf.st_ino == stat_spare.st_ino);                 Line 351
            }                                                                   
          break;                                                                Line 353
                                                                                
        case 'o':                                                               Line 355
          if ('t' == argv[op][2] && '\000' == argv[op][3])                      Line 356
            {                                                                   
              /* ot - older than */                                             
              struct timespec lt, rt;                                           Line 359
              bool le, re;                                                      Line 360
              pos += 3;                                                         Line 361
              if (l_is_l || r_is_l)                                             Line 362
                test_syntax_error (_("-ot does not accept -l"), NULL);          Line 363
              le = get_mtime (argv[op - 1], <);                               Line 364
              re = get_mtime (argv[op + 1], &rt);                               Line 365
              return re && (!le || timespec_cmp (lt, rt) < 0);                  Line 366
            }                                                                   
          break;                                                                Line 368
        }                                                                       
                                                                                
      /* FIXME: is this dead code? */                                           
      test_syntax_error (_("%s: unknown binary operator"), quote (argv[op]));   Line 372
    }                                                                           
                                                                                
  if (argv[op][0] == '='                                                        Line 375
      && (!argv[op][1] || ((argv[op][1] == '=') && !argv[op][2])))              Line 376
    {                                                                           
      bool value = STREQ (argv[pos], argv[pos + 2]);                            Line 378
      pos += 3;                                                                 Line 379
      return value;                                                             Line 380
    }                                                                           
                                                                                
  if (STREQ (argv[op], "!="))                                                   Line 383
    {                                                                           
      bool value = !STREQ (argv[pos], argv[pos + 2]);                           Line 385
      pos += 3;                                                                 Line 386
      return value;                                                             Line 387
    }                                                                           
                                                                                
  /* Not reached.  */                                                           
  abort ();                                                                     ...!common auto-comment...
}                                                                               Block 10
                                                                                
static bool                                                                     Line 394
unary_operator (void)                                                           Line 395
{                                                                               
  struct stat stat_buf;                                                         Line 397
                                                                                
  switch (argv[pos][1])                                                         Line 399
    {                                                                           
    default:                                                                    Line 401
      return false;                                                             Line 402
                                                                                
      /* All of the following unary operators use unary_advance (), which       
         checks to make sure that there is an argument, and then advances       
         pos right past it.  This means that pos - 1 is the location of the     
         argument. */                                                           
                                                                                
    case 'a':   /* file exists in the file system? */                           Line 409
    case 'e':                                                                   Line 410
      unary_advance ();                                                         Line 411
      return stat (argv[pos - 1], &stat_buf) == 0;                              Line 412...!syscalls auto-comment...
                                                                                
    case 'r':   /* file is readable? */                                         Line 414
      unary_advance ();                                                         Line 415
      return euidaccess (argv[pos - 1], R_OK) == 0;                             Line 416
                                                                                
    case 'w':   /* File is writable? */                                         Line 418
      unary_advance ();                                                         Line 419
      return euidaccess (argv[pos - 1], W_OK) == 0;                             Line 420
                                                                                
    case 'x':   /* File is executable? */                                       Line 422
      unary_advance ();                                                         Line 423
      return euidaccess (argv[pos - 1], X_OK) == 0;                             Line 424
                                                                                
    case 'O':   /* File is owned by you? */                                     Line 426
      {                                                                         
        unary_advance ();                                                       Line 428
        if (stat (argv[pos - 1], &stat_buf) != 0)                               Line 429...!syscalls auto-comment...
          return false;                                                         Line 430
        errno = 0;                                                              Line 431
        uid_t euid = geteuid ();                                                Line 432uid_t geteuid(void)
The geteuid() function shall return the
effective user ID of the calling process.
The geteuid() function shall not modify
errno.
uid_t NO_UID = -1; Line 433 return ! (euid == NO_UID && errno) && euid == stat_buf.st_uid; Line 434 } case 'G': /* File is owned by your group? */ Line 437 { unary_advance (); Line 439 if (stat (argv[pos - 1], &stat_buf) != 0) Line 440...!syscalls auto-comment... return false; Line 441 errno = 0; Line 442 gid_t egid = getegid (); Line 443...!syscalls auto-comment... gid_t NO_GID = -1; Line 444 return ! (egid == NO_GID && errno) && egid == stat_buf.st_gid; Line 445 } case 'f': /* File is a file? */ Line 448 unary_advance (); Line 449 /* Under POSIX, -f is true if the given file exists and is a regular file. */ return (stat (argv[pos - 1], &stat_buf) == 0 Line 452...!syscalls auto-comment... && S_ISREG (stat_buf.st_mode)); Line 453 case 'd': /* File is a directory? */ Line 455 unary_advance (); Line 456 return (stat (argv[pos - 1], &stat_buf) == 0 Line 457...!syscalls auto-comment... && S_ISDIR (stat_buf.st_mode)); Line 458 case 's': /* File has something in it? */ Line 460 unary_advance (); Line 461 return (stat (argv[pos - 1], &stat_buf) == 0 Line 462...!syscalls auto-comment... && 0 < stat_buf.st_size); Line 463 case 'S': /* File is a socket? */ Line 465 unary_advance (); Line 466 return (stat (argv[pos - 1], &stat_buf) == 0 Line 467...!syscalls auto-comment... && S_ISSOCK (stat_buf.st_mode)); Line 468 case 'c': /* File is character special? */ Line 470 unary_advance (); Line 471 return (stat (argv[pos - 1], &stat_buf) == 0 Line 472...!syscalls auto-comment... && S_ISCHR (stat_buf.st_mode)); Line 473 case 'b': /* File is block special? */ Line 475 unary_advance (); Line 476 return (stat (argv[pos - 1], &stat_buf) == 0 Line 477...!syscalls auto-comment... && S_ISBLK (stat_buf.st_mode)); Line 478 case 'p': /* File is a named pipe? */ Line 480 unary_advance (); Line 481 return (stat (argv[pos - 1], &stat_buf) == 0 Line 482...!syscalls auto-comment... && S_ISFIFO (stat_buf.st_mode)); Line 483 case 'L': /* Same as -h */ Line 485 /*FALLTHROUGH*/ case 'h': /* File is a symbolic link? */ Line 488 unary_advance (); Line 489 return (lstat (argv[pos - 1], &stat_buf) == 0 Line 490...!syscalls auto-comment... && S_ISLNK (stat_buf.st_mode)); Line 491 case 'u': /* File is setuid? */ Line 493 unary_advance (); Line 494 return (stat (argv[pos - 1], &stat_buf) == 0 Line 495...!syscalls auto-comment... && (stat_buf.st_mode & S_ISUID)); Line 496 case 'g': /* File is setgid? */ Line 498 unary_advance (); Line 499 return (stat (argv[pos - 1], &stat_buf) == 0 Line 500...!syscalls auto-comment... && (stat_buf.st_mode & S_ISGID)); Line 501 case 'k': /* File has sticky bit set? */ Line 503 unary_advance (); Line 504 return (stat (argv[pos - 1], &stat_buf) == 0 Line 505...!syscalls auto-comment... && (stat_buf.st_mode & S_ISVTX)); Line 506 case 't': /* File (fd) is a terminal? */ Line 508 { long int fd; Line 510 char const *arg; Line 511 unary_advance (); Line 512 arg = find_int (argv[pos - 1]); Line 513 errno = 0; Line 514 fd = strtol (arg, NULL, 10); Line 515 return (errno != ERANGE && 0 <= fd && fd <= INT_MAX && isatty (fd)); Line 516 } case 'n': /* True if arg has some length. */ Line 519 unary_advance (); Line 520 return argv[pos - 1][0] != 0; Line 521 case 'z': /* True if arg has no length. */ Line 523 unary_advance (); Line 524 return argv[pos - 1][0] == '\0'; Line 525 } } Block 11
/* * and: * term * term '-a' and */ static bool Line 534 and (void) Line 535 { bool value = true; Line 537 while (true) Line 539 { value &= term (); Line 541 if (! (pos < argc && STREQ (argv[pos], "-a"))) Line 542 return value; Line 543 advance (false); Line 544 } } Block 12 /* * or: * and * and '-o' or */ static bool Line 553 or (void) Line 554 { bool value = false; Line 556 while (true) Line 558 { value |= and (); Line 560 if (! (pos < argc && STREQ (argv[pos], "-o"))) Line 561 return value; Line 562 advance (false); Line 563 } } Block 13 /* * expr: * or */ static bool Line 571 expr (void) Line 572 { if (pos >= argc) Line 574 beyond (); Line 575 return or (); /* Same with this. */ Line 577 } Block 14 /* Return true if OP is one of the test command's unary operators. */ static bool Line 581 test_unop (char const *op) Line 582 { if (op[0] != '-') Line 584 return false; Line 585 switch (op[1]) Line 587 { case 'a': case 'b': case 'c': case 'd': case 'e': Line 589 case 'f': case 'g': case 'h': case 'k': case 'n': Line 590 case 'o': case 'p': case 'r': case 's': case 't': Line 591 case 'u': case 'w': case 'x': case 'z': Line 592 case 'G': case 'L': case 'O': case 'S': case 'N': Line 593 return true; Line 594 default: Line 595 return false; Line 596 } } Block 15 static bool Line 600 one_argument (void) Line 601 { return argv[pos++][0] != '\0'; Line 603 } Block 16 static bool Line 606 two_arguments (void) Line 607 { bool value; Line 609 if (STREQ (argv[pos], "!")) Line 611 { advance (false); Line 613 value = ! one_argument (); Line 614 } else if (argv[pos][0] == '-' Line 616 && argv[pos][1] != '\0' Line 617 && argv[pos][2] == '\0') Line 618 { if (test_unop (argv[pos])) Line 620 value = unary_operator (); Line 621 else Line 622 test_syntax_error (_("%s: unary operator expected"), quote (argv[pos]));Line 623 } else Line 625 beyond (); Line 626 return (value); Line 627 } Block 17 static bool Line 630 three_arguments (void) Line 631 { bool value; Line 633 if (binop (argv[pos + 1])) Line 635 value = binary_operator (false); Line 636 else if (STREQ (argv[pos], "!")) Line 637 { advance (true); Line 639 value = !two_arguments (); Line 640 } else if (STREQ (argv[pos], "(") && STREQ (argv[pos + 2], ")")) Line 642 { advance (false); Line 644 value = one_argument (); Line 645 advance (false); Line 646 } else if (STREQ (argv[pos + 1], "-a") || STREQ (argv[pos + 1], "-o")) Line 648 value = expr (); Line 649 else Line 650 test_syntax_error (_("%s: binary operator expected"), quote (argv[pos+1])); Line 651 return (value); Line 652 } Block 18 /* This is an implementation of a Posix.2 proposal by David Korn. */ static bool Line 656 posixtest (int nargs) Line 657 { bool value; Line 659 switch (nargs) Line 661 { case 1: Line 663 value = one_argument (); Line 664 break; Line 665 case 2: Line 667 value = two_arguments (); Line 668 break; Line 669 case 3: Line 671 value = three_arguments (); Line 672 break; Line 673 case 4: Line 675 if (STREQ (argv[pos], "!")) Line 676 { advance (true); Line 678 value = !three_arguments (); Line 679 break; Line 680 } if (STREQ (argv[pos], "(") && STREQ (argv[pos + 3], ")")) Line 682 { advance (false); Line 684 value = two_arguments (); Line 685 advance (false); Line 686 break; Line 687 } FALLTHROUGH; Line 689 case 5: Line 690 default: Line 691 if (nargs <= 0) Line 692 abort (); ...!common auto-comment... value = expr (); Line 694 } return (value); Line 697 } Block 19 #if defined TEST_STANDALONE Line 700 void Line 702 usage (int status) Line 703 { if (status != EXIT_SUCCESS) Line 705 emit_try_help (); ...!common auto-comment... else Line 707 { fputs (_("\ Line 709 Usage: test EXPRESSION\n\ Line 710 or: test\n\ Line 711 or: [ EXPRESSION ]\n\ Line 712 or: [ ]\n\ Line 713 or: [ OPTION\n\ Line 714 "), stdout); Line 715 fputs (_("\ Line 716 Exit with the status determined by EXPRESSION.\n\ Line 717 \n\ "), stdout); Line 719 fputs (HELP_OPTION_DESCRIPTION, stdout); Line 720 fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 721 fputs (_("\ Line 722 \n\ An omitted EXPRESSION defaults to false. Otherwise,\n\ Line 724 EXPRESSION is true or false and sets exit status. It is one of:\n\ Line 725 "), stdout); Line 726 fputs (_("\ Line 727 \n\ ( EXPRESSION ) EXPRESSION is true\n\ Line 729 ! EXPRESSION EXPRESSION is false\n\ Line 730 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\ Line 731 EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\ Line 732 "), stdout); Line 733 fputs (_("\ Line 734 \n\ -n STRING the length of STRING is nonzero\n\ Line 736 STRING equivalent to -n STRING\n\ Line 737 -z STRING the length of STRING is zero\n\ Line 738 STRING1 = STRING2 the strings are equal\n\ Line 739 STRING1 != STRING2 the strings are not equal\n\ Line 740 "), stdout); Line 741 fputs (_("\ Line 742 \n\ INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\ Line 744 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\ Line 745 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\ Line 746 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\ Line 747 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\ Line 748 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\ Line 749 "), stdout); Line 750 fputs (_("\ Line 751 \n\ FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\ Line 753 FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\ Line 754 FILE1 -ot FILE2 FILE1 is older than FILE2\n\ Line 755 "), stdout); Line 756 fputs (_("\ Line 757 \n\ -b FILE FILE exists and is block special\n\ Line 759 -c FILE FILE exists and is character special\n\ Line 760 -d FILE FILE exists and is a directory\n\ Line 761 -e FILE FILE exists\n\ Line 762 "), stdout); Line 763 fputs (_("\ Line 764 -f FILE FILE exists and is a regular file\n\ Line 765 -g FILE FILE exists and is set-group-ID\n\ Line 766 -G FILE FILE exists and is owned by the effective group ID\n\ Line 767 -h FILE FILE exists and is a symbolic link (same as -L)\n\ Line 768...!syscalls auto-comment... -k FILE FILE exists and has its sticky bit set\n\ Line 769 "), stdout); Line 770 fputs (_("\ Line 771 -L FILE FILE exists and is a symbolic link (same as -h)\n\ Line 772...!syscalls auto-comment... -O FILE FILE exists and is owned by the effective user ID\n\ Line 773 -p FILE FILE exists and is a named pipe\n\ Line 774 -r FILE FILE exists and read permission is granted\n\ Line 775 -s FILE FILE exists and has a size greater than zero\n\ Line 776 "), stdout); Line 777 fputs (_("\ Line 778 -S FILE FILE exists and is a socket\n\ Line 779 -t FD file descriptor FD is opened on a terminal\n\ Line 780 -u FILE FILE exists and its set-user-ID bit is set\n\ Line 781 -w FILE FILE exists and write permission is granted\n\ Line 782 -x FILE FILE exists and execute (or search) permission is granted\n\ Line 783 "), stdout); Line 784 fputs (_("\ Line 785 \n\ Except for -h and -L, all FILE-related tests dereference symbolic links.\n\ Line 787 Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\Line 788 INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\ Line 789 "), stdout); Line 790 fputs (_("\ Line 791 \n\ NOTE: Binary -a and -o are inherently ambiguous. Use 'test EXPR1 && test\n\ Line 793 EXPR2' or 'test EXPR1 || test EXPR2' instead.\n\ Line 794 "), stdout); Line 795 fputs (_("\ Line 796 \n\ NOTE: [ honors the --help and --version options, but test does not.\n\ Line 798 test treats each of those as it treats any other nonempty STRING.\n\ Line 799 "), stdout); Line 800 printf (USAGE_BUILTIN_WARNING, _("test and/or [")); Line 801 emit_ancillary_info (PROGRAM_NAME); Line 802 } exit (status); Line 804 } Block 20 #endif /* TEST_STANDALONE */ Line 806 #if !defined TEST_STANDALONE Line 808 # define main test_command Line 809 #endif Line 810 #define AUTHORS \ Line 812 proper_name ("Kevin Braunsdorf"), \ Line 813 proper_name ("Matthew Bradburn") Line 814 /* * [: * '[' expr ']' * test: * test expr */ int main (int margc, char **margv) Line 823 { bool value; Line 825 #if !defined TEST_STANDALONE Line 827 int code; Line 828 code = setjmp (test_exit_buf); Line 830 if (code) Line 832 return (test_error_return); Line 833 #else /* TEST_STANDALONE */ Line 834 initialize_main (&margc, &margv); VMS-specific entry point handling wildcard expansion set_program_name (margv[0]); Retains program name and discards path setlocale (LC_ALL, ""); Sets up internationalization (i18n) bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function textdomain (PACKAGE); Sets text domain for _() [gettext()] function initialize_exit_failure (TEST_FAILURE); Line 841 atexit (close_stdout); Close stdout on exit (see gnulib) #endif /* TEST_STANDALONE */ Line 843 argv = margv; Line 845 if (LBRACKET) Line 847 { /* Recognize --help or --version, but only when invoked in the "[" form, when the last argument is not "]". Use direct parsing, rather than parse_long_options, to avoid accepting abbreviations. POSIX allows "[ --help" and "[ --version" to have the usual GNU behavior, but it requires "test --help" and "test --version" to exit silently with status 0. */ if (margc == 2) Line 855 { if (STREQ (margv[1], "--help")) Line 857 usage (EXIT_SUCCESS); Line 858 if (STREQ (margv[1], "--version")) Line 860 { version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,Line 862 (char *) NULL); Line 863 test_main_return (EXIT_SUCCESS); Line 864 } } if (margc < 2 || !STREQ (margv[margc - 1], "]")) Line 867 test_syntax_error (_("missing %s"), quote ("]")); Line 868 --margc; Line 870 } argc = margc; Line 873 pos = 1; Line 874 if (pos >= argc) Line 876 test_main_return (TEST_FALSE); Line 877 value = posixtest (argc - 1); Line 879 if (pos != argc) Line 881 test_syntax_error (_("extra argument %s"), quote (argv[pos])); Line 882 test_main_return (value ? TEST_TRUE : TEST_FALSE); Line 884 } Block 21