/* 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