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