/* Modified to run with the GNU shell by bfox. */
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2005, 2007-2008 Free Software Foundation, Inc.
- This file is part of GNU Bash, the Bourne Again SHell.
+ 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.
- Bash 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 2, or (at your option) any later
- version.
-
- Bash 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.
+ 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, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Define TEST_STANDALONE to get the /bin/test version. Otherwise, you get
the shell builtin version. */
#endif
#include "system.h"
-#include "error.h"
#include "euidaccess.h"
-#include "inttostr.h"
#include "quote.h"
+#include "stat-time.h"
#include "strnumcmp.h"
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
-char *program_name;
-
/* Exit status for syntax errors, etc. */
enum { TEST_TRUE, TEST_FALSE, TEST_FAILURE };
-#if defined (TEST_STANDALONE)
+#if defined TEST_STANDALONE
# define test_exit(val) exit (val)
#else
static jmp_buf test_exit_buf;
{
fprintf (stderr, "%s: ", argv[0]);
fprintf (stderr, format, arg);
+ fputc ('\n', stderr);
fflush (stderr);
test_exit (TEST_FAILURE);
}
char const *p;
char const *number_start;
- for (p = string; ISBLANK (to_uchar (*p)); p++)
+ for (p = string; isblank (to_uchar (*p)); p++)
continue;
if (*p == '+')
{
while (ISDIGIT (*p))
p++;
- while (ISBLANK (to_uchar (*p)))
+ while (isblank (to_uchar (*p)))
p++;
if (!*p)
return number_start;
}
- test_syntax_error (_("invalid integer %s\n"), quote (string));
+ test_syntax_error (_("invalid integer %s"), quote (string));
}
-/* Find the modification time of FILE, and stuff it into *AGE.
- If the timestamp has a nonoseconds part, stuff that into *NS;
- otherwise stuff zero into *NS.
+/* Find the modification time of FILE, and stuff it into *MTIME.
Return true if successful. */
static bool
-age_of (char const *filename, time_t *age, long *ns)
+get_mtime (char const *filename, struct timespec *mtime)
{
struct stat finfo;
bool ok = (stat (filename, &finfo) == 0);
+#ifdef lint
+ static struct timespec const zero;
+ *mtime = zero;
+#endif
if (ok)
- {
- *age = finfo.st_mtime;
- *ns = TIMESPEC_NS (finfo.st_mtim);
- }
+ *mtime = get_stat_mtime (&finfo);
return ok;
}
value = posixtest (nargs);
if (argv[pos] == 0)
- test_syntax_error (_("')' expected\n"), NULL);
+ test_syntax_error (_("')' expected"), NULL);
else
if (argv[pos][0] != ')' || argv[pos][1])
- test_syntax_error (_("')' expected, found %s\n"), argv[pos]);
+ test_syntax_error (_("')' expected, found %s"), argv[pos]);
advance (false);
}
if (test_unop (argv[pos]))
value = unary_operator ();
else
- test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
+ test_syntax_error (_("%s: unary operator expected"), argv[pos]);
}
else
{
if (argv[op][2] == 't' && !argv[op][3])
{
/* nt - newer than */
- time_t lt IF_LINT (= 0);
- time_t rt IF_LINT (= 0);
- long l_ns IF_LINT (= 0);
- long r_ns IF_LINT (= 0);
+ struct timespec lt, rt;
bool le, re;
pos += 3;
if (l_is_l | r_is_l)
- test_syntax_error (_("-nt does not accept -l\n"), NULL);
- le = age_of (argv[op - 1], <, &l_ns);
- re = age_of (argv[op + 1], &rt, &r_ns);
- if (le && re && (rt == lt))
- return l_ns > r_ns;
- else
- return le > re || (le && lt > rt);
+ test_syntax_error (_("-nt does not accept -l"), NULL);
+ le = get_mtime (argv[op - 1], <);
+ re = get_mtime (argv[op + 1], &rt);
+ return le && (!re || timespec_cmp (lt, rt) > 0);
}
break;
/* ef - hard link? */
pos += 3;
if (l_is_l | r_is_l)
- test_syntax_error (_("-ef does not accept -l\n"), NULL);
+ test_syntax_error (_("-ef does not accept -l"), NULL);
return (stat (argv[op - 1], &stat_buf) == 0
&& stat (argv[op + 1], &stat_spare) == 0
&& stat_buf.st_dev == stat_spare.st_dev
if ('t' == argv[op][2] && '\000' == argv[op][3])
{
/* ot - older than */
- time_t lt IF_LINT (= 0);
- time_t rt IF_LINT (= 0);
- long l_ns IF_LINT (= 0);
- long r_ns IF_LINT (= 0);
+ struct timespec lt, rt;
bool le, re;
pos += 3;
if (l_is_l | r_is_l)
- test_syntax_error (_("-ot does not accept -l\n"), NULL);
- le = age_of (argv[op - 1], <, &l_ns);
- re = age_of (argv[op + 1], &rt, &r_ns);
- if (le && re && (lt == rt))
- return l_ns < r_ns;
- else
- return le < re || (re && lt < rt);
+ test_syntax_error (_("-ot does not accept -l"), NULL);
+ le = get_mtime (argv[op - 1], <);
+ re = get_mtime (argv[op + 1], &rt);
+ return re && (!le || timespec_cmp (lt, rt) < 0);
}
break;
}
/* FIXME: is this dead code? */
- test_syntax_error (_("unknown binary operator\n"), argv[op]);
+ test_syntax_error (_("unknown binary operator"), argv[op]);
}
if (argv[op][0] == '=' && !argv[op][1])
if (test_unop (argv[pos]))
value = unary_operator ();
else
- test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
+ test_syntax_error (_("%s: unary operator expected"), argv[pos]);
}
else
beyond ();
else if (STREQ (argv[pos + 1], "-a") || STREQ (argv[pos + 1], "-o"))
value = expr ();
else
- test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
+ test_syntax_error (_("%s: binary operator expected"), argv[pos+1]);
return (value);
}
return (value);
}
-#if defined (TEST_STANDALONE)
+#if defined TEST_STANDALONE
# include "long-options.h"
void
Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
"), stdout);
+ fputs (_("\
+\n\
+NOTE: [ honors the --help and --version options, but test does not.\n\
+test treats each of those as it treats any other nonempty STRING.\n\
+"), stdout);
printf (USAGE_BUILTIN_WARNING, _("test and/or ["));
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ emit_bug_reporting_address ();
}
exit (status);
}
#endif /* TEST_STANDALONE */
-#if !defined (TEST_STANDALONE)
+#if !defined TEST_STANDALONE
# define main test_command
#endif
-#define AUTHORS "Kevin Braunsdorf", "Matthew Bradburn"
+#define AUTHORS \
+ proper_name ("Kevin Braunsdorf"), \
+ proper_name ("Matthew Bradburn")
/*
* [:
{
bool value;
-#if !defined (TEST_STANDALONE)
+#if !defined TEST_STANDALONE
int code;
code = setjmp (test_exit_buf);
return (test_error_return);
#else /* TEST_STANDALONE */
initialize_main (&margc, &margv);
- program_name = margv[0];
+ set_program_name (margv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
"[" form, and when the last argument is not "]". POSIX
allows "[ --help" and "[ --version" to have the usual GNU
behavior, but it requires "test --help" and "test --version"
- to exit silently with status 1. */
+ to exit silently with status 0. */
if (margc < 2 || !STREQ (margv[margc - 1], "]"))
{
- parse_long_options (margc, margv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
+ parse_long_options (margc, margv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
usage, AUTHORS, (char const *) NULL);
- test_syntax_error (_("missing `]'\n"), NULL);
+ test_syntax_error (_("missing `]'"), NULL);
}
--margc;