summaryrefslogtreecommitdiff
path: root/find/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'find/parser.c')
-rw-r--r--find/parser.c3864
1 files changed, 1117 insertions, 2747 deletions
diff --git a/find/parser.c b/find/parser.c
index b7ef88f8..3d85a9a3 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -1,11 +1,10 @@
/* parser.c -- convert the command line args into an expression tree.
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
- 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ 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.
+ the Free Software Foundation; either version 2, 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
@@ -13,58 +12,19 @@
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 <http://www.gnu.org/licenses/>.
-*/
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
-
-#include "defs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
#include <ctype.h>
-#include <math.h>
-#include <assert.h>
+#include <stdio.h>
#include <pwd.h>
-#include <errno.h>
#include <grp.h>
-#include <fnmatch.h>
#include "modechange.h"
+#include "defs.h"
#include "modetype.h"
-#include "xstrtol.h"
-#include "xalloc.h"
-#include "quote.h"
-#include "quotearg.h"
-#include "buildcmd.h"
-#include "nextelem.h"
-#include "stdio-safer.h"
-#include "regextype.h"
-#include "stat-time.h"
-#include "xstrtod.h"
-#include "fts_.h"
-#include "getdate.h"
-#include "error.h"
-#include "findutils-version.h"
-
-#include <fcntl.h>
-
-
-/* The presence of unistd.h is assumed by gnulib these days, so we
- * might as well assume it too.
- */
-/* We need <unistd.h> for isatty(). */
-#include <unistd.h>
-#include <sys/stat.h>
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
-#ifdef gettext_noop
-# define N_(String) gettext_noop (String)
-#else
-/* See locate.c for explanation as to why not use (String) */
-# define N_(String) String
-#endif
#if !defined (isascii) || defined (STDC_HEADERS)
#ifdef isascii
@@ -73,594 +33,225 @@
#define isascii(c) 1
#endif
-#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
-#define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#define ISUPPER(c) (isascii (c) && isupper (c))
-#ifndef HAVE_ENDGRENT
-#define endgrent()
+#ifndef _POSIX_VERSION
+/* POSIX.1 header files should declare these. */
+struct group *getgrnam ();
+struct passwd *getpwnam ();
+#endif
+
+#ifdef CACHE_IDS
+/* These two aren't specified by POSIX.1. */
+struct group *getgrent ();
+struct passwd *getpwent ();
+#endif
+
+#ifndef S_IFLNK
+#define lstat stat
+#endif
+
+char *strstr ();
+int lstat ();
+int stat ();
+#ifndef atol /* for Linux */
+long atol ();
#endif
-#ifndef HAVE_ENDPWENT
+struct tm *localtime ();
+
+#ifdef _POSIX_SOURCE
+#define endgrent()
#define endpwent()
+#else
+void endgrent ();
+void endpwent ();
#endif
-static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
-static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-#if 0
-static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-#endif
-static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-
-boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
-
-
-static boolean insert_type PARAMS((char **argv, int *arg_ptr,
- const struct parser_table *entry,
- PRED_FUNC which_pred));
-static boolean insert_regex PARAMS((char *argv[], int *arg_ptr,
- const struct parser_table *entry,
- int regex_options));
-static boolean insert_fprintf (struct format_val *vec,
- const struct parser_table *entry,
- PRED_FUNC func,
- const char *format);
-
-static struct segment **make_segment PARAMS((struct segment **segment,
- char *format, int len,
- int kind, char format_char,
- char aux_format_char,
- struct predicate *pred));
-static boolean insert_exec_ok PARAMS((const char *action,
- const struct parser_table *entry,
- int dirfd,
- char *argv[],
- int *arg_ptr));
-static boolean get_comp_type PARAMS((const char **str,
- enum comparison_type *comp_type));
-static boolean get_relative_timestamp PARAMS((const char *str,
- struct time_val *tval,
- struct timespec origin,
- double sec_per_unit,
- const char *overflowmessage));
-static boolean get_num PARAMS((const char *str,
- uintmax_t *num,
- enum comparison_type *comp_type));
-static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr,
- const struct parser_table *entry));
-static void open_output_file (const char *path, struct format_val *p);
-static void open_stdout (struct format_val *p);
-static boolean stream_is_tty(FILE *fp);
-static boolean parse_noop PARAMS((const struct parser_table* entry,
- char **argv, int *arg_ptr));
-
-#define PASTE(x,y) x##y
-#define STRINGIFY(s) #s
-
-#define PARSE_OPTION(what,suffix) \
- { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_POSOPT(what,suffix) \
- { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_TEST(what,suffix) \
- { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-#define PARSE_TEST_NP(what,suffix) \
- { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_ACTION(what,suffix) \
- { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-#define PARSE_ACTION_NP(what,suffix) \
- { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
-
-#define PARSE_PUNCTUATION(what,suffix) \
- { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
-
-
-/* Predicates we cannot handle in the usual way. If you add an entry
- * to this table, double-check the switch statement in
- * pred_sanity_check() to make sure that the new case is being
- * correctly handled.
- */
-static struct parser_table const parse_entry_newerXY =
- {
- ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
- };
+static boolean parse_amin P_((char *argv[], int *arg_ptr));
+static boolean parse_and P_((char *argv[], int *arg_ptr));
+static boolean parse_anewer P_((char *argv[], int *arg_ptr));
+static boolean parse_atime P_((char *argv[], int *arg_ptr));
+boolean parse_close P_((char *argv[], int *arg_ptr));
+static boolean parse_cmin P_((char *argv[], int *arg_ptr));
+static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
+static boolean parse_comma P_((char *argv[], int *arg_ptr));
+static boolean parse_ctime P_((char *argv[], int *arg_ptr));
+static boolean parse_daystart P_((char *argv[], int *arg_ptr));
+static boolean parse_depth P_((char *argv[], int *arg_ptr));
+static boolean parse_empty P_((char *argv[], int *arg_ptr));
+static boolean parse_exec P_((char *argv[], int *arg_ptr));
+static boolean parse_false P_((char *argv[], int *arg_ptr));
+static boolean parse_fls P_((char *argv[], int *arg_ptr));
+static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
+static boolean parse_follow P_((char *argv[], int *arg_ptr));
+static boolean parse_fprint P_((char *argv[], int *arg_ptr));
+static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
+static boolean parse_fstype P_((char *argv[], int *arg_ptr));
+static boolean parse_gid P_((char *argv[], int *arg_ptr));
+static boolean parse_group P_((char *argv[], int *arg_ptr));
+static boolean parse_help P_((char *argv[], int *arg_ptr));
+static boolean parse_ilname P_((char *argv[], int *arg_ptr));
+static boolean parse_iname P_((char *argv[], int *arg_ptr));
+static boolean parse_inum P_((char *argv[], int *arg_ptr));
+static boolean parse_ipath P_((char *argv[], int *arg_ptr));
+static boolean parse_iregex P_((char *argv[], int *arg_ptr));
+static boolean parse_links P_((char *argv[], int *arg_ptr));
+static boolean parse_lname P_((char *argv[], int *arg_ptr));
+static boolean parse_ls P_((char *argv[], int *arg_ptr));
+static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
+static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
+static boolean parse_mmin P_((char *argv[], int *arg_ptr));
+static boolean parse_mtime P_((char *argv[], int *arg_ptr));
+static boolean parse_name P_((char *argv[], int *arg_ptr));
+static boolean parse_negate P_((char *argv[], int *arg_ptr));
+static boolean parse_newer P_((char *argv[], int *arg_ptr));
+static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
+static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
+static boolean parse_nouser P_((char *argv[], int *arg_ptr));
+static boolean parse_ok P_((char *argv[], int *arg_ptr));
+boolean parse_open P_((char *argv[], int *arg_ptr));
+static boolean parse_or P_((char *argv[], int *arg_ptr));
+static boolean parse_path P_((char *argv[], int *arg_ptr));
+static boolean parse_perm P_((char *argv[], int *arg_ptr));
+boolean parse_print P_((char *argv[], int *arg_ptr));
+static boolean parse_print0 P_((char *argv[], int *arg_ptr));
+static boolean parse_printf P_((char *argv[], int *arg_ptr));
+static boolean parse_prune P_((char *argv[], int *arg_ptr));
+static boolean parse_regex P_((char *argv[], int *arg_ptr));
+static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
+static boolean parse_size P_((char *argv[], int *arg_ptr));
+static boolean parse_true P_((char *argv[], int *arg_ptr));
+static boolean parse_type P_((char *argv[], int *arg_ptr));
+static boolean parse_uid P_((char *argv[], int *arg_ptr));
+static boolean parse_used P_((char *argv[], int *arg_ptr));
+static boolean parse_user P_((char *argv[], int *arg_ptr));
+static boolean parse_version P_((char *argv[], int *arg_ptr));
+static boolean parse_xdev P_((char *argv[], int *arg_ptr));
+static boolean parse_xtype P_((char *argv[], int *arg_ptr));
+
+static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
+static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
+static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
+static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
+static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
+static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
+static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
+static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
+static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
+static FILE *open_output_file P_((char *path));
+
+#ifdef DEBUG
+char *find_pred_name _P((PFB pred_func));
+#endif /* DEBUG */
+
+struct parser_table
+{
+ char *parser_name;
+ PFB parser_func;
+};
/* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
If they are in some Unix versions of find, they are marked `Unix'. */
static struct parser_table const parse_table[] =
{
- PARSE_PUNCTUATION("!", negate), /* POSIX */
- PARSE_PUNCTUATION("not", negate), /* GNU */
- PARSE_PUNCTUATION("(", openparen), /* POSIX */
- PARSE_PUNCTUATION(")", closeparen), /* POSIX */
- PARSE_PUNCTUATION(",", comma), /* GNU */
- PARSE_PUNCTUATION("a", and), /* POSIX */
- PARSE_TEST ("amin", amin), /* GNU */
- PARSE_PUNCTUATION("and", and), /* GNU */
- PARSE_TEST ("anewer", anewer), /* GNU */
- {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
- PARSE_TEST ("cmin", cmin), /* GNU */
- PARSE_TEST ("cnewer", cnewer), /* GNU */
- {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
- PARSE_POSOPT ("daystart", daystart), /* GNU */
- PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
- PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
- PARSE_OPTION ("depth", depth), /* POSIX */
- PARSE_TEST ("empty", empty), /* GNU */
- {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
- {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
- PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
- PARSE_ACTION ("fls", fls), /* GNU */
- PARSE_POSOPT ("follow", follow), /* GNU, Unix */
- PARSE_ACTION ("fprint", fprint), /* GNU */
- PARSE_ACTION ("fprint0", fprint0), /* GNU */
- {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
- PARSE_TEST ("fstype", fstype), /* GNU, Unix */
- PARSE_TEST ("gid", gid), /* GNU */
- PARSE_TEST ("group", group), /* POSIX */
- PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
- PARSE_TEST ("ilname", ilname), /* GNU */
- PARSE_TEST ("iname", iname), /* GNU */
- PARSE_TEST ("inum", inum), /* GNU, Unix */
- PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
- PARSE_TEST_NP ("iregex", iregex), /* GNU */
- PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
- PARSE_TEST ("links", links), /* POSIX */
- PARSE_TEST ("lname", lname), /* GNU */
- PARSE_ACTION ("ls", ls), /* GNU, Unix */
- PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
- PARSE_OPTION ("mindepth", mindepth), /* GNU */
- PARSE_TEST ("mmin", mmin), /* GNU */
- PARSE_OPTION ("mount", xdev), /* Unix */
- {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
- PARSE_TEST ("name", name),
-#ifdef UNIMPLEMENTED_UNIX
- PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
-#endif
- PARSE_TEST ("newer", newer), /* POSIX */
- {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
- PARSE_OPTION ("noleaf", noleaf), /* GNU */
- PARSE_TEST ("nogroup", nogroup), /* POSIX */
- PARSE_TEST ("nouser", nouser), /* POSIX */
- PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
- PARSE_POSOPT ("nowarn", nowarn), /* GNU */
- PARSE_PUNCTUATION("o", or), /* POSIX */
- PARSE_PUNCTUATION("or", or), /* GNU */
- PARSE_ACTION ("ok", ok), /* POSIX */
- PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
- PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
- PARSE_TEST ("perm", perm), /* POSIX */
- PARSE_ACTION ("print", print), /* POSIX */
- PARSE_ACTION ("print0", print0), /* GNU */
- {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
- PARSE_ACTION ("prune", prune), /* POSIX */
- PARSE_ACTION ("quit", quit), /* GNU */
- {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
- PARSE_TEST ("regex", regex), /* GNU */
- PARSE_OPTION ("regextype", regextype), /* GNU */
- PARSE_TEST ("samefile", samefile), /* GNU */
-#if 0
- PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
-#endif
- PARSE_TEST ("size", size), /* POSIX */
- PARSE_TEST ("type", type), /* POSIX */
- PARSE_TEST ("uid", uid), /* GNU */
- PARSE_TEST ("used", used), /* GNU */
- PARSE_TEST ("user", user), /* POSIX */
- PARSE_OPTION ("warn", warn), /* GNU */
- PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
- {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
- PARSE_OPTION ("xdev", xdev), /* POSIX */
- PARSE_TEST ("xtype", xtype), /* GNU */
+ {"!", parse_negate},
+ {"not", parse_negate}, /* GNU */
+ {"(", parse_open},
+ {")", parse_close},
+ {",", parse_comma}, /* GNU */
+ {"a", parse_and},
+ {"amin", parse_amin}, /* GNU */
+ {"and", parse_and}, /* GNU */
+ {"anewer", parse_anewer}, /* GNU */
+ {"atime", parse_atime},
+ {"cmin", parse_cmin}, /* GNU */
+ {"cnewer", parse_cnewer}, /* GNU */
#ifdef UNIMPLEMENTED_UNIX
/* It's pretty ugly for find to know about archive formats.
Plus what it could do with cpio archives is very limited.
Better to leave it out. */
- PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
+ {"cpio", parse_cpio}, /* Unix */
+#endif
+ {"ctime", parse_ctime},
+ {"daystart", parse_daystart}, /* GNU */
+ {"depth", parse_depth},
+ {"empty", parse_empty}, /* GNU */
+ {"exec", parse_exec},
+ {"false", parse_false}, /* GNU */
+ {"fls", parse_fls}, /* GNU */
+ {"follow", parse_follow}, /* GNU, Unix */
+ {"fprint", parse_fprint}, /* GNU */
+ {"fprint0", parse_fprint0}, /* GNU */
+ {"fprintf", parse_fprintf}, /* GNU */
+ {"fstype", parse_fstype}, /* GNU, Unix */
+ {"gid", parse_gid}, /* GNU */
+ {"group", parse_group},
+ {"help", parse_help}, /* GNU */
+ {"-help", parse_help}, /* GNU */
+ {"ilname", parse_ilname}, /* GNU */
+ {"iname", parse_iname}, /* GNU */
+ {"inum", parse_inum}, /* GNU, Unix */
+ {"ipath", parse_ipath}, /* GNU */
+ {"iregex", parse_iregex}, /* GNU */
+ {"links", parse_links},
+ {"lname", parse_lname}, /* GNU */
+ {"ls", parse_ls}, /* GNU, Unix */
+ {"maxdepth", parse_maxdepth}, /* GNU */
+ {"mindepth", parse_mindepth}, /* GNU */
+ {"mmin", parse_mmin}, /* GNU */
+ {"mount", parse_xdev}, /* Unix */
+ {"mtime", parse_mtime},
+ {"name", parse_name},
+#ifdef UNIMPLEMENTED_UNIX
+ {"ncpio", parse_ncpio}, /* Unix */
#endif
- /* gnulib's stdbool.h might have made true and false into macros,
- * so we can't leave named 'true' and 'false' tokens, so we have
- * to expeant the relevant entries longhand.
- */
- {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
- {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
- {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
-
- /* Various other cases that don't fit neatly into our macro scheme. */
- {ARG_TEST, "help", parse_help, NULL}, /* GNU */
- {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
- {ARG_TEST, "version", parse_version, NULL}, /* GNU */
- {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
- {0, 0, 0, 0}
+ {"newer", parse_newer},
+ {"noleaf", parse_noleaf}, /* GNU */
+ {"nogroup", parse_nogroup},
+ {"nouser", parse_nouser},
+ {"o", parse_or},
+ {"or", parse_or}, /* GNU */
+ {"ok", parse_ok},
+ {"path", parse_path}, /* GNU, HP-UX */
+ {"perm", parse_perm},
+ {"print", parse_print},
+ {"print0", parse_print0}, /* GNU */
+ {"printf", parse_printf}, /* GNU */
+ {"prune", parse_prune},
+ {"regex", parse_regex}, /* GNU */
+ {"size", parse_size},
+ {"true", parse_true}, /* GNU */
+ {"type", parse_type},
+ {"uid", parse_uid}, /* GNU */
+ {"used", parse_used}, /* GNU */
+ {"user", parse_user},
+ {"version", parse_version}, /* GNU */
+ {"-version", parse_version}, /* GNU */
+ {"xdev", parse_xdev},
+ {"xtype", parse_xtype}, /* GNU */
+ {0, 0}
};
-
-static const char *first_nonoption_arg = NULL;
-static const struct parser_table *noop = NULL;
-
-
-void
-check_option_combinations(const struct predicate *p)
-{
- enum { seen_delete=1u, seen_prune=2u };
- unsigned int predicates = 0u;
-
- while (p)
- {
- if (p->pred_func == pred_delete)
- predicates |= seen_delete;
- else if (p->pred_func == pred_prune)
- predicates |= seen_prune;
- p = p->pred_next;
- }
-
- if ((predicates & seen_prune) && (predicates & seen_delete))
- {
- /* The user specified both -delete and -prune. One might test
- * this by first doing
- * find dirs .... -prune ..... -print
- * to fnd out what's going to get deleted, and then switch to
- * find dirs .... -prune ..... -delete
- * once we are happy. Unfortunately, the -delete action also
- * implicitly turns on -depth, which will affect the behaviour
- * of -prune (in fact, it makes it a no-op). In this case we
- * would like to prevent unfortunate accidents, so we require
- * the user to have explicitly used -depth.
- *
- * We only get away with this because the -delete predicate is not
- * in POSIX. If it was, we couldn't issue a fatal error here.
- */
- if (!options.explicit_depth)
- {
- /* This fixes Savannah bug #20865. */
- error (1, 0, _("The -delete action atomatically turns on -depth, "
- "but -prune does nothing when -depth is in effect. "
- "If you want to carry on anyway, just explicitly use "
- "the -depth option."));
- }
- }
-}
-
-
-static const struct parser_table*
-get_noop(void)
-{
- int i;
- if (NULL == noop)
- {
- for (i = 0; parse_table[i].parser_name != 0; i++)
- {
- if (ARG_NOOP ==parse_table[i].type)
- {
- noop = &(parse_table[i]);
- break;
- }
- }
- }
- return noop;
-}
-
-static int
-get_stat_Ytime(const struct stat *p,
- char what,
- struct timespec *ret)
-{
- switch (what)
- {
- case 'a':
- *ret = get_stat_atime(p);
- return 1;
- case 'B':
- *ret = get_stat_birthtime(p);
- return (ret->tv_nsec >= 0);
- case 'c':
- *ret = get_stat_ctime(p);
- return 1;
- case 'm':
- *ret = get_stat_mtime(p);
- return 1;
- default:
- assert (0);
- abort();
- }
-}
-
-void
-set_follow_state(enum SymlinkOption opt)
-{
- if (options.debug_options & DebugStat)
- {
- /* For DebugStat, the choice is made at runtime within debug_stat()
- * by checking the contents of the symlink_handling variable.
- */
- options.xstat = debug_stat;
- }
- else
- {
- switch (opt)
- {
- case SYMLINK_ALWAYS_DEREF: /* -L */
- options.xstat = optionl_stat;
- options.no_leaf_check = true;
- break;
-
- case SYMLINK_NEVER_DEREF: /* -P (default) */
- options.xstat = optionp_stat;
- /* Can't turn no_leaf_check off because the user might have specified
- * -noleaf anyway
- */
- break;
-
- case SYMLINK_DEREF_ARGSONLY: /* -H */
- options.xstat = optionh_stat;
- options.no_leaf_check = true;
- }
- }
- options.symlink_handling = opt;
-}
-
-
-void
-parse_begin_user_args (char **args, int argno,
- const struct predicate *last,
- const struct predicate *predicates)
-{
- (void) args;
- (void) argno;
- (void) last;
- (void) predicates;
- first_nonoption_arg = NULL;
-}
-
-void
-parse_end_user_args (char **args, int argno,
- const struct predicate *last,
- const struct predicate *predicates)
-{
- /* does nothing */
- (void) args;
- (void) argno;
- (void) last;
- (void) predicates;
-}
-
-
-/* Check that it is legal to fid the given primary in its
- * position and return it.
- */
-const struct parser_table*
-found_parser(const char *original_arg, const struct parser_table *entry)
-{
- /* If this is an option, but we have already had a
- * non-option argument, the user may be under the
- * impression that the behaviour of the option
- * argument is conditional on some preceding
- * tests. This might typically be the case with,
- * for example, -maxdepth.
- *
- * The options -daystart and -follow are exempt
- * from this treatment, since their positioning
- * in the command line does have an effect on
- * subsequent tests but not previous ones. That
- * might be intentional on the part of the user.
- */
- if (entry->type != ARG_POSITIONAL_OPTION)
- {
- /* Something other than -follow/-daystart.
- * If this is an option, check if it followed
- * a non-option and if so, issue a warning.
- */
- if (entry->type == ARG_OPTION)
- {
- if ((first_nonoption_arg != NULL)
- && options.warnings )
- {
- /* option which follows a non-option */
- error (0, 0,
- _("warning: you have specified the %s "
- "option after a non-option argument %s, "
- "but options are not positional (%s affects "
- "tests specified before it as well as those "
- "specified after it). Please specify options "
- "before other arguments.\n"),
- original_arg,
- first_nonoption_arg,
- original_arg);
- }
- }
- else
- {
- /* Not an option or a positional option,
- * so remember we've seen it in order to
- * use it in a possible future warning message.
- */
- if (first_nonoption_arg == NULL)
- {
- first_nonoption_arg = original_arg;
- }
- }
- }
-
- return entry;
-}
-
-
/* Return a pointer to the parser function to invoke for predicate
SEARCH_NAME.
Return NULL if SEARCH_NAME is not a valid predicate name. */
-const struct parser_table*
-find_parser (char *search_name)
+PFB
+find_parser (search_name)
+ char *search_name;
{
int i;
- const char *original_arg = search_name;
-
- /* Ugh. Special case -newerXY. */
- if (0 == strncmp("-newer", search_name, 6)
- && (8 == strlen(search_name)))
- {
- return found_parser(original_arg, &parse_entry_newerXY);
- }
-
+
if (*search_name == '-')
search_name++;
-
for (i = 0; parse_table[i].parser_name != 0; i++)
- {
- if (strcmp (parse_table[i].parser_name, search_name) == 0)
- {
- return found_parser(original_arg, &parse_table[i]);
- }
- }
- return NULL;
-}
-
-static float
-estimate_file_age_success_rate(float num_days)
-{
- if (num_days < 0.1)
- {
- /* Assume 1% of files have timestamps in the future */
- return 0.01f;
- }
- else if (num_days < 1)
- {
- /* Assume 30% of files have timestamps today */
- return 0.3f;
- }
- else if (num_days > 100)
- {
- /* Assume 30% of files are very old */
- return 0.3f;
- }
- else
- {
- /* Assume 39% of files are between 1 and 100 days old. */
- return 0.39f;
- }
+ if (strcmp (parse_table[i].parser_name, search_name) == 0)
+ return (parse_table[i].parser_func);
+ return (NULL);
}
-static float
-estimate_timestamp_success_rate(time_t when)
-{
- /* This calculation ignores the nanoseconds field of the
- * origin, but I don't think that makes much difference
- * to our estimate.
- */
- int num_days = (options.cur_day_start.tv_sec - when) / 86400;
- return estimate_file_age_success_rate(num_days);
-}
-
-/* Collect an argument from the argument list, or
- * return false.
- */
-static boolean
-collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
-{
- if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- *collected_arg = NULL;
- return false;
- }
- else
- {
- *collected_arg = argv[*arg_ptr];
- (*arg_ptr)++;
- return true;
- }
-}
-
-static boolean
-collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
-{
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- if (0 == (options.xstat)(filename, p))
- {
- return true;
- }
- else
- {
- fatal_file_error(filename);
- }
- }
- else
- {
- return false;
- }
-}
-
/* The parsers are responsible to continue scanning ARGV for
their arguments. Each parser knows what is and isn't
allowed for itself.
@@ -671,925 +262,595 @@ collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
The predicate structure is updated with the new information. */
-
static boolean
-parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_amin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
+{
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_amin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
+}
+
+static boolean
+parse_and (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
+ our_pred = get_new_pred ();
our_pred->pred_func = pred_and;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_and);
+#endif /* DEBUG */
our_pred->p_type = BI_OP;
our_pred->p_prec = AND_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_anewer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
+ struct predicate *our_pred;
struct stat stat_newer;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime.xval = XVAL_ATIME;
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_anewer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
+}
+
+static boolean
+parse_atime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
+{
+ return (insert_time (argv, arg_ptr, pred_atime));
}
boolean
-parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_close (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
- our_pred->pred_func = pred_closeparen;
+ our_pred = get_new_pred ();
+ our_pred->pred_func = pred_close;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_close);
+#endif /* DEBUG */
our_pred->p_type = CLOSE_PAREN;
our_pred->p_prec = NO_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_cmin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct stat stat_newer;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_cmin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_cnewer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
+ struct stat stat_newer;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
- our_pred->pred_func = pred_comma;
- our_pred->p_type = BI_OP;
- our_pred->p_prec = COMMA_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_cnewer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_comma (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct tm *local;
-
- (void) entry;
- (void) argv;
- (void) arg_ptr;
+ struct predicate *our_pred;
- if (options.full_days == false)
- {
- options.cur_day_start.tv_sec += DAYSECS;
- options.cur_day_start.tv_nsec = 0;
- local = localtime (&options.cur_day_start.tv_sec);
- options.cur_day_start.tv_sec -= (local
- ? (local->tm_sec + local->tm_min * 60
- + local->tm_hour * 3600)
- : options.cur_day_start.tv_sec % DAYSECS);
- options.full_days = true;
- }
- return true;
+ our_pred = get_new_pred ();
+ our_pred->pred_func = pred_comma;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_comma);
+#endif /* DEBUG */
+ our_pred->p_type = BI_OP;
+ our_pred->p_prec = COMMA_PREC;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
+parse_ctime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->side_effects = our_pred->no_default_print = true;
- /* -delete implies -depth */
- options.do_dir_first = false;
-
- /* We do not need stat information because we check for the case
- * (errno==EISDIR) in pred_delete.
- */
- our_pred->need_stat = our_pred->need_type = false;
-
- our_pred->est_success_rate = 1.0f;
- return true;
+ return (insert_time (argv, arg_ptr, pred_ctime));
}
static boolean
-parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_daystart (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) entry;
- (void) argv;
+ struct tm *local;
- options.do_dir_first = false;
- options.explicit_depth = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- if (options.warnings)
+ if (full_days == false)
{
- error (0, 0,
- _("warning: the -d option is deprecated; please use "
- "-depth instead, because the latter is a "
- "POSIX-compliant feature."));
+ cur_day_start += DAYSECS;
+ local = localtime (&cur_day_start);
+ cur_day_start -= local->tm_sec + local->tm_min * 60
+ + local->tm_hour * 3600;
+ full_days = true;
}
- return parse_depth(entry, argv, arg_ptr);
+ return (true);
}
-
+
static boolean
-parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_depth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
- return true;
+ do_dir_first = false;
+ return (true);
}
-
+
static boolean
-parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_empty (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
+ insert_primary (pred_empty);
+ return (true);
}
static boolean
-parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_exec (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
+ return (insert_exec_ok (pred_exec, argv, arg_ptr));
}
static boolean
-parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_false (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
-
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = our_pred->no_default_print = false;
- our_pred->est_success_rate = 0.0f;
- return true;
-}
-static boolean
-insert_fls (const struct parser_table* entry, const char *filename)
-{
- struct predicate *our_pred = insert_primary (entry);
- if (filename)
- open_output_file (filename, &our_pred->args.printf_vec);
- else
- open_stdout (&our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->est_success_rate = 1.0f;
- return true;
+ our_pred = insert_primary (pred_false);
+ our_pred->need_stat = false;
+ return (true);
}
-
static boolean
-parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fls (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *filename;
- return collect_arg(argv, arg_ptr, &filename)
- && insert_fls(entry, filename);
-}
+ struct predicate *our_pred;
-static boolean
-parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- set_follow_state(SYMLINK_ALWAYS_DEREF);
- return parse_noop(entry, argv, arg_ptr);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fls);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ (*arg_ptr)++;
+ return (true);
}
-static boolean
-parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
+static boolean
+parse_fprintf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- our_pred = insert_primary (entry);
- open_output_file (filename, &our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
- }
- else
+ FILE *fp;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (argv[*arg_ptr + 1] == NULL)
{
- return false;
+ /* Ensure we get "missing arg" message, not "invalid arg". */
+ (*arg_ptr)++;
+ return (false);
}
+ fp = open_output_file (argv[*arg_ptr]);
+ (*arg_ptr)++;
+ return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
}
-static boolean
-insert_fprint(const struct parser_table* entry, const char *filename)
+static boolean
+parse_follow (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred = insert_primary (entry);
- if (filename)
- open_output_file (filename, &our_pred->args.printf_vec);
- else
- open_stdout (&our_pred->args.printf_vec);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ dereference = true;
+ xstat = stat;
+ no_leaf_check = true;
+ return (true);
}
-
static boolean
-parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fprint (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- return insert_fprint(entry, filename);
- else
- return false;
-}
+ struct predicate *our_pred;
-static float estimate_fstype_success_rate(const char *fsname)
-{
- struct stat dir_stat;
- const char *dir = "/";
- if (0 == stat(dir, &dir_stat))
- {
- const char *fstype = filesystem_type(&dir_stat, dir);
- /* Assume most files are on the same file system type as the root fs. */
- if (0 == strcmp(fsname, fstype))
- return 0.7f;
- else
- return 0.3f;
- }
- return 1.0f;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fprint);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fprint0 (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *typename;
- if (collect_arg(argv, arg_ptr, &typename))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = typename;
-
- /* This is an expensive operation, so although there are
- * circumstances where it is selective, we ignore this fact
- * because we probably don't want to promote this test to the
- * front anyway.
- */
- our_pred->est_success_rate = estimate_fstype_success_rate(typename);
- return true;
- }
- else
- {
- return false;
- }
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fprint0);
+ our_pred->args.stream = open_output_file (argv[*arg_ptr]);
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_fstype (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
- }
- else
- {
- return false;
- }
-}
+ struct predicate *our_pred;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_fstype);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
+}
-static int
-safe_atoi (const char *s)
+static boolean
+parse_gid (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- long lval;
- char *end;
-
- errno = 0;
- lval = strtol(s, &end, 10);
- if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
- {
- /* max/min possible value, or an error. */
- if (errno == ERANGE)
- {
- /* too big, or too small. */
- error(1, errno, "%s", s);
- }
- else
- {
- /* not a valid number */
- error(1, errno, "%s", s);
- }
- /* Otherwise, we do a range chack against INT_MAX and INT_MIN
- * below.
- */
- }
-
- if (lval > INT_MAX || lval < INT_MIN)
- {
- /* The number was in range for long, but not int. */
- errno = ERANGE;
- error(1, errno, "%s", s);
- }
- else if (*end)
- {
- error(1, errno, "Unexpected suffix %s on %s",
- quotearg_n_style(0, options.err_quoting_style, end),
- quotearg_n_style(1, options.err_quoting_style, s));
- }
- else if (end == s)
- {
- error(1, errno, "Expected an integer: %s",
- quotearg_n_style(0, options.err_quoting_style, s));
- }
- return (int)lval;
+ return (insert_num (argv, arg_ptr, pred_gid));
}
-
static boolean
-parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_group (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *groupname;
+ struct group *cur_gr;
+ struct predicate *our_pred;
+ gid_t gid;
+ int gid_len;
- if (collect_arg(argv, arg_ptr, &groupname))
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ cur_gr = getgrnam (argv[*arg_ptr]);
+ endgrent ();
+ if (cur_gr != NULL)
+ gid = cur_gr->gr_gid;
+ else
{
- gid_t gid;
- struct predicate *our_pred;
- struct group *cur_gr = getgrnam(groupname);
- endgrent();
- if (cur_gr)
- {
- gid = cur_gr->gr_gid;
- }
- else
- {
- const int gid_len = strspn (groupname, "0123456789");
- if (gid_len)
- {
- if (groupname[gid_len] == 0)
- {
- gid = safe_atoi (groupname);
- }
- else
- {
- /* XXX: no test in test suite for this */
- error(1, 0, _("%s is not the name of an existing group and"
- " it does not look like a numeric group ID "
- "because it has the unexpected suffix %s"),
- quotearg_n_style(0, options.err_quoting_style, groupname),
- quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
- return false;
- }
- }
- else
- {
- if (*groupname)
- {
- /* XXX: no test in test suite for this */
- error(1, 0, _("%s is not the name of an existing group"),
- quotearg_n_style(0, options.err_quoting_style, groupname));
- }
- else
- {
- error(1, 0, _("argument to -group is empty, but should be a group name"));
- }
- return false;
- }
- }
- our_pred = insert_primary (entry);
- our_pred->args.gid = gid;
- our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
+ gid_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
+ return (false);
+ gid = atoi (argv[*arg_ptr]);
}
- return false;
+ our_pred = insert_primary (pred_group);
+ our_pred->args.gid = gid;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_help (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) entry;
- (void) argv;
- (void) arg_ptr;
-
- usage(stdout, 0, NULL);
- puts (_("\n\
+ printf ("\
+Usage: %s [path...] [expression]\n", program_name);
+ printf ("\
default path is the current directory; default expression is -print\n\
-expression may consist of: operators, options, tests, and actions:\n"));
- puts (_("\
+expression may consist of:\n\
operators (decreasing precedence; -and is implicit where no others are given):\n\
- ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
- EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
- puts (_("\
-positional options (always true): -daystart -follow -regextype\n\n\
-normal options (always true, specified before other expressions):\n\
- -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
- --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
- puts (_("\
-tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
+ ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
+ printf ("\
+ EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
+options (always true): -daystart -depth -follow --help\n\
+ -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
+tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
+ printf ("\
-cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
- -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
- -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
- puts (_("\
+ -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
+ -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
+ printf ("\
-nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
- -readable -writable -executable\n\
- -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
- -used N -user NAME -xtype [bcdpfls]\n"));
- puts (_("\
-actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
- -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
- -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
- -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
-"));
- puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
-page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
-email to <bug-findutils@gnu.org>."));
+ -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
+ -xtype [bcdpfls]\n");
+ printf ("\
+actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
+ -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
exit (0);
}
-static float
-estimate_pattern_match_rate(const char *pattern, int is_regex)
-{
- if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
- {
- /* A wildcard; assume the pattern matches most files. */
- return 0.8f;
- }
- else
- {
- return 0.1f;
- }
-}
-
static boolean
-parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ilname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = name;
- /* Use the generic glob pattern estimator to figure out how many
- * links will match, but bear in mind that most files won't be links.
- */
- our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
- return true;
- }
- else
- {
- return false;
- }
-}
-
+ struct predicate *our_pred;
-/* sanity check the fnmatch() function to make sure that case folding
- * is supported (as opposed to just having the flag ignored).
- */
-static boolean
-fnmatch_sanitycheck(void)
-{
- static boolean checked = false;
- if (!checked)
- {
- if (0 != fnmatch("foo", "foo", 0)
- || 0 == fnmatch("Foo", "foo", 0)
- || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
- {
- error (1, 0, _("sanity check of the fnmatch() library function failed."));
- return false;
- }
- checked = true;
- }
- return checked;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_ilname);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-check_name_arg(const char *pred, const char *arg)
+parse_iname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- if (options.warnings && strchr(arg, '/'))
- {
- error(0, 0,_("warning: Unix filenames usually don't contain slashes "
- "(though pathnames do). That means that '%s %s' will "
- "probably evaluate to false all the time on this system. "
- "You might find the '-wholename' test more useful, or "
- "perhaps '-samefile'. Alternatively, if you are using "
- "GNU grep, you could "
- "use 'find ... -print0 | grep -FzZ %s'."),
- pred,
- safely_quote_err_filename(0, arg),
- safely_quote_err_filename(1, arg));
- }
- return true; /* allow it anyway */
-}
-
-
+ struct predicate *our_pred;
-static boolean
-parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- fnmatch_sanitycheck();
- if (collect_arg(argv, arg_ptr, &name))
- {
- if (check_name_arg("-iname", name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
- return true;
- }
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_iname);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_inum (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- /* inode number is exact match only, so very low proportions of
- * files match
- */
- p->est_success_rate = 1e-6;
- return true;
- }
- else
- {
- return false;
- }
+ return (insert_num (argv, arg_ptr, pred_inum));
}
-/* -ipath is deprecated (at RMS's request) in favour of
- * -iwholename. See the node "GNU Manuals" in standards.texi
- * for the rationale for this (basically, GNU prefers the use
- * of the phrase "file name" to "path name"
- */
static boolean
-parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ipath (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
+ struct predicate *our_pred;
- fnmatch_sanitycheck ();
- if (collect_arg (argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_ipath);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_iregex (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return parse_ipath (entry, argv, arg_ptr);
+ return insert_regex (argv, arg_ptr, true);
}
static boolean
-parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_links (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
+ return (insert_num (argv, arg_ptr, pred_links));
}
static boolean
-parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_lname (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- if (p->args.numinfo.l_val == 1)
- p->est_success_rate = 0.99;
- else if (p->args.numinfo.l_val == 2)
- p->est_success_rate = 0.01;
- else
- p->est_success_rate = 1e-3;
- return true;
- }
- else
- {
- return false;
- }
-}
+ struct predicate *our_pred;
-static boolean
-parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- fnmatch_sanitycheck();
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.str = name;
- our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
- return true;
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_lname);
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ls (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- (void) &argv;
- (void) &arg_ptr;
- return insert_fls(entry, NULL);
+ struct predicate *our_pred;
+
+ our_pred = insert_primary (pred_ls);
+ our_pred->side_effects = true;
+ return (true);
}
static boolean
-insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
- int *limitptr)
+parse_maxdepth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *depthstr;
int depth_len;
- const char *predicate = argv[(*arg_ptr)-1];
- if (collect_arg(argv, arg_ptr, &depthstr))
- {
- depth_len = strspn (depthstr, "0123456789");
- if ((depth_len > 0) && (depthstr[depth_len] == 0))
- {
- (*limitptr) = safe_atoi (depthstr);
- if (*limitptr >= 0)
- {
- return parse_noop(entry, argv, arg_ptr);
- }
- }
- error(1, 0, _("Expected a positive decimal integer argument to %s, but got %s"),
- predicate,
- quotearg_n_style(0, options.err_quoting_style, depthstr));
- return false;
- }
- /* missing argument */
- return false;
-}
-
-static boolean
-parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ depth_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
+ return (false);
+ maxdepth = atoi (argv[*arg_ptr]);
+ if (maxdepth < 0)
+ return (false);
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_mindepth (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
+ int depth_len;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ depth_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
+ return (false);
+ mindepth = atoi (argv[*arg_ptr]);
+ if (mindepth < 0)
+ return (false);
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-do_parse_xmin (const struct parser_table* entry,
- char **argv,
- int *arg_ptr,
- enum xval xv)
+parse_mmin (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *minutes;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- if (collect_arg(argv, arg_ptr, &minutes))
- {
- struct time_val tval;
- tval.xval = xv;
- struct timespec origin = options.cur_day_start;
- origin.tv_sec += DAYSECS;
- if (get_relative_timestamp(minutes, &tval, origin, 60,
- "arithmetic overflow while converting %s "
- "minutes to a number of seconds"))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
- return true;
- }
- }
- return false;
-}
-static boolean
-parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
-}
-
-static boolean
-parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_mmin);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_mtime (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
+ return (insert_time (argv, arg_ptr, pred_mtime));
}
static boolean
-parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_name (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- fnmatch_sanitycheck();
- if (check_name_arg("-name", name))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
- return true;
- }
- }
- return false;
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_name);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_negate (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) &argv;
- (void) &arg_ptr;
-
- our_pred = get_new_pred_chk_op (entry);
+ our_pred = get_new_pred_chk_op ();
our_pred->pred_func = pred_negate;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_negate);
+#endif /* DEBUG */
our_pred->p_type = UNI_OP;
our_pred->p_prec = NEGATE_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_newer (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
struct stat stat_newer;
- set_stat_placeholders(&stat_newer);
- if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
- {
- our_pred = insert_primary (entry);
- our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
- our_pred->args.reftime.xval = XVAL_MTIME;
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
- return true;
- }
- return false;
-}
-
-
-static boolean
-parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- (void) argv;
- (void) arg_ptr;
-
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- return false;
- }
- else if (8u != strlen(argv[*arg_ptr]))
- {
- return false;
- }
- else
- {
- char x, y;
- const char validchars[] = "aBcmt";
-
- assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
- x = argv[*arg_ptr][6];
- y = argv[*arg_ptr][7];
-
-
-#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
- if ('B' == x || 'B' == y)
- {
- error(0, 0,
- _("This system does not provide a way to find the birth time of a file."));
- return 0;
- }
-#endif
-
- /* -newertY (for any Y) is invalid. */
- if (x == 't'
- || 0 == strchr(validchars, x)
- || 0 == strchr( validchars, y))
- {
- return false;
- }
- else
- {
- struct predicate *our_pred;
-
- /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
- * past the test name (for most other tests, this is already done)
- */
- (*arg_ptr)++;
-
- our_pred = insert_primary (entry);
-
-
- switch (x)
- {
- case 'a':
- our_pred->args.reftime.xval = XVAL_ATIME;
- break;
- case 'B':
- our_pred->args.reftime.xval = XVAL_BIRTHTIME;
- break;
- case 'c':
- our_pred->args.reftime.xval = XVAL_CTIME;
- break;
- case 'm':
- our_pred->args.reftime.xval = XVAL_MTIME;
- break;
- default:
- assert (strchr(validchars, x));
- assert (0);
- }
-
- if ('t' == y)
- {
- if (!get_date(&our_pred->args.reftime.ts,
- argv[*arg_ptr],
- &options.start_time))
- {
- error(1, 0,
- _("I cannot figure out how to interpret %s as a date or time"),
- quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
- }
- }
- else
- {
- struct stat stat_newer;
-
- /* Stat the named file. */
- set_stat_placeholders(&stat_newer);
- if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
- fatal_file_error(argv[*arg_ptr]);
-
- if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
- {
- /* We cannot extract a timestamp from the struct stat. */
- error(1, 0, _("Cannot obtain birth time of file %s"),
- safely_quote_err_filename(0, argv[*arg_ptr]));
- }
- }
- our_pred->args.reftime.kind = COMP_GT;
- our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
- (*arg_ptr)++;
-
- assert (our_pred->pred_func != NULL);
- assert (our_pred->pred_func == pred_newerXY);
- assert (our_pred->need_stat);
- return true;
- }
- }
+ return (false);
+ if ((*xstat) (argv[*arg_ptr], &stat_newer))
+ error (1, errno, "%s", argv[*arg_ptr]);
+ our_pred = insert_primary (pred_newer);
+ our_pred->args.time = stat_newer.st_mtime;
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_noleaf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- options.no_leaf_check = true;
- return parse_noop(entry, argv, arg_ptr);
+ no_leaf_check = true;
+ return true;
}
#ifdef CACHE_IDS
@@ -1609,15 +870,13 @@ unsigned gid_allocated;
#endif
static boolean
-parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_nogroup (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) &argv;
- (void) &arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 1e-4;
+ our_pred = insert_primary (pred_nogroup);
#ifdef CACHE_IDS
if (gid_unused == NULL)
{
@@ -1642,19 +901,17 @@ parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
endgrent ();
}
#endif
- return true;
+ return (true);
}
static boolean
-parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_nouser (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = 1e-3;
+ our_pred = insert_primary (pred_nouser);
#ifdef CACHE_IDS
if (uid_unused == NULL)
{
@@ -1679,399 +936,242 @@ parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
endpwent ();
}
#endif
- return true;
-}
-
-static boolean
-parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.warnings = false;
- return parse_noop(entry, argv, arg_ptr);
+ return (true);
}
static boolean
-parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_ok (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
-}
-
-static boolean
-parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
+ return (insert_exec_ok (pred_ok, argv, arg_ptr));
}
boolean
-parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_open (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred_chk_op (entry);
- our_pred->pred_func = pred_openparen;
+ our_pred = get_new_pred_chk_op ();
+ our_pred->pred_func = pred_open;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_open);
+#endif /* DEBUG */
our_pred->p_type = OPEN_PAREN;
our_pred->p_prec = NO_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_or (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = get_new_pred (entry);
+ our_pred = get_new_pred ();
our_pred->pred_func = pred_or;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_or);
+#endif /* DEBUG */
our_pred->p_type = BI_OP;
our_pred->p_prec = OR_PREC;
- our_pred->need_stat = our_pred->need_type = false;
- return true;
-}
-
-/* For some time, -path was deprecated (at RMS's request) in favour of
- * -iwholename. See the node "GNU Manuals" in standards.texi for the
- * rationale for this (basically, GNU prefers the use of the phrase
- * "file name" to "path name".
- *
- * We do not issue a warning that this usage is deprecated
- * since
- * (a) HPUX find supports this predicate also and
- * (b) it will soon be in POSIX anyway.
- */
-static boolean
-parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *name;
- if (collect_arg(argv, arg_ptr, &name))
- {
- struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->args.str = name;
- our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
- return true;
- }
- return false;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_path (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return parse_path (entry, argv, arg_ptr);
-}
+ struct predicate *our_pred;
-static void
-non_posix_mode(const char *mode)
-{
- if (options.posixly_correct)
- {
- error (1, 0, _("Mode %s is not valid when POSIXLY_CORRECT is on."),
- quotearg_n_style(0, options.err_quoting_style, mode));
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_path);
+ our_pred->need_stat = false;
+ our_pred->args.str = argv[*arg_ptr];
+ (*arg_ptr)++;
+ return (true);
}
-
static boolean
-parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_perm (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- mode_t perm_val[2];
- float rate;
+ unsigned long perm_val;
int mode_start = 0;
- boolean havekind = false;
- enum permissions_type kind = PERM_EXACT;
- struct mode_change *change = NULL;
+ struct mode_change *change;
struct predicate *our_pred;
- const char *perm_expr;
- if (!collect_arg(argv, arg_ptr, &perm_expr))
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
- switch (perm_expr[0])
+ switch (argv[*arg_ptr][0])
{
case '-':
+ case '+':
mode_start = 1;
- kind = PERM_AT_LEAST;
- havekind = true;
- rate = 0.2;
- break;
-
- case '+':
- change = mode_compile (perm_expr);
- if (NULL == change)
- {
- /* Most likely the caller is an old script that is still
- * using the obsolete GNU syntax '-perm +MODE'. This old
- * syntax was withdrawn in favor of '-perm /MODE' because
- * it is incompatible with POSIX in some cases, but we
- * still support uses of it that are not incompatible with
- * POSIX.
- *
- * Example: POSIXLY_CORRECT=y find -perm +a+x
- */
- non_posix_mode(perm_expr);
-
- /* support the previous behaviour. */
- mode_start = 1;
- kind = PERM_ANY;
- rate = 0.3;
- }
- else
- {
- /* This is a POSIX-compatible usage */
- mode_start = 0;
- kind = PERM_EXACT;
- rate = 0.1;
- }
- havekind = true;
- break;
-
- case '/': /* GNU extension */
- non_posix_mode(perm_expr);
- mode_start = 1;
- kind = PERM_ANY;
- havekind = true;
- rate = 0.3;
break;
-
default:
- /* For example, '-perm 0644', which is valid and matches
- * only files whose mode is exactly 0644.
- */
- mode_start = 0;
- kind = PERM_EXACT;
- havekind = true;
- rate = 0.01;
+ /* empty */
break;
}
- if (NULL == change)
- {
- change = mode_compile (perm_expr + mode_start);
- if (NULL == change)
- error (1, 0, _("invalid mode %s"),
- quotearg_n_style(0, options.err_quoting_style, perm_expr));
- }
- perm_val[0] = mode_adjust (0, false, 0, change, NULL);
- perm_val[1] = mode_adjust (0, true, 0, change, NULL);
- free (change);
-
- if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
- {
- /* The meaning of -perm /000 will change in the future. It
- * currently matches no files, but like -perm -000 it should
- * match all files.
- *
- * Starting in 2005, we used to issue a warning message
- * informing the user that the behaviour would change in the
- * future. We have now changed the behaviour and issue a
- * warning message that the behaviour recently changed.
- */
- error (0, 0,
- _("warning: you have specified a mode pattern %s (which is "
- "equivalent to /000). The meaning of -perm /000 has now been "
- "changed to be consistent with -perm -000; that is, while it "
- "used to match no files, it now matches all files."),
- perm_expr);
-
- kind = PERM_AT_LEAST;
- havekind = true;
-
- /* The "magic" number below is just the fraction of files on my
- * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
- * Actual totals are 1472 and 1073833.
- */
- rate = 0.9986; /* probably matches anything but a broken symlink */
- }
-
- our_pred = insert_primary (entry);
- our_pred->est_success_rate = rate;
- if (havekind)
- {
- our_pred->args.perm.kind = kind;
- }
- else
+ change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
+ if (change == MODE_INVALID)
+ error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
+ else if (change == MODE_MEMORY_EXHAUSTED)
+ error (1, 0, "virtual memory exhausted");
+ perm_val = mode_adjust (0, change);
+ mode_free (change);
+
+ our_pred = insert_primary (pred_perm);
+
+ switch (argv[*arg_ptr][0])
{
-
- switch (perm_expr[0])
- {
- case '-':
- our_pred->args.perm.kind = PERM_AT_LEAST;
- break;
- case '+':
- our_pred->args.perm.kind = PERM_ANY;
- break;
- default:
- our_pred->args.perm.kind = PERM_EXACT;
- break;
- }
+ case '-':
+ /* Set magic flag to indicate true if at least the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777) | 010000;
+ break;
+ case '+':
+ /* Set magic flag to indicate true if any of the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777) | 020000;
+ break;
+ default:
+ /* True if exactly the given bits are set. */
+ our_pred->args.perm = (perm_val & 07777);
+ break;
}
- memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
- return true;
+ (*arg_ptr)++;
+ return (true);
}
boolean
-parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_print (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
+ our_pred = insert_primary (pred_print);
/* -print has the side effect of printing. This prevents us
from doing undesired multiple printing when the user has
already specified -print. */
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_stat = our_pred->need_type = false;
- open_stdout(&our_pred->args.printf_vec);
- return true;
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ return (true);
}
static boolean
-parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_print0 (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_fprint(entry, NULL);
-}
+ struct predicate *our_pred;
-static boolean
-parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *format;
- if (collect_arg(argv, arg_ptr, &format))
- {
- struct format_val fmt;
- open_stdout(&fmt);
- return insert_fprintf (&fmt, entry, pred_fprintf, format);
- }
- return false;
+ our_pred = insert_primary (pred_print0);
+ /* -print0 has the side effect of printing. This prevents us
+ from doing undesired multiple printing when the user has
+ already specified -print0. */
+ our_pred->side_effects = true;
+ our_pred->need_stat = false;
+ return (true);
}
-static boolean
-parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
+static boolean
+parse_printf (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *format, *filename;
- if (collect_arg(argv, arg_ptr, &filename))
- {
- if (collect_arg(argv, arg_ptr, &format))
- {
- struct format_val fmt;
- open_output_file (filename, &fmt);
- return insert_fprintf (&fmt, entry, pred_fprintf, format);
- }
- }
- return false;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
}
static boolean
-parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_prune (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- /* -prune has a side effect that it does not descend into
- the current directory. */
- our_pred->side_effects = true;
- our_pred->no_default_print = false;
- return true;
-}
-
-static boolean
-parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- struct predicate *our_pred = insert_primary (entry);
- (void) argv;
- (void) arg_ptr;
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = true; /* Exiting is a side effect... */
- our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
- our_pred->est_success_rate = 1.0f;
- return true;
-}
-
-
-static boolean
-parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *type_name;
- if (collect_arg(argv, arg_ptr, &type_name))
- {
- /* collect the regex type name */
- options.regex_options = get_regex_type(type_name);
- return parse_noop(entry, argv, arg_ptr);
- }
- return false;
+ our_pred = insert_primary (pred_prune);
+ our_pred->need_stat = false;
+ return (true);
}
-
static boolean
-parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_regex (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_regex (argv, arg_ptr, entry, options.regex_options);
+ return insert_regex (argv, arg_ptr, false);
}
static boolean
-insert_regex (char **argv,
- int *arg_ptr,
- const struct parser_table *entry,
- int regex_options)
+insert_regex (argv, arg_ptr, ignore_case)
+ char *argv[];
+ int *arg_ptr;
+ boolean ignore_case;
{
- const char *rx;
- if (collect_arg(argv, arg_ptr, &rx))
+ struct predicate *our_pred;
+ struct re_pattern_buffer *re;
+ const char *error_message;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ our_pred = insert_primary (pred_regex);
+ our_pred->need_stat = false;
+ re = (struct re_pattern_buffer *)
+ xmalloc (sizeof (struct re_pattern_buffer));
+ our_pred->args.regex = re;
+ re->allocated = 100;
+ re->buffer = (unsigned char *) xmalloc (re->allocated);
+ re->fastmap = NULL;
+
+ if (ignore_case)
{
- struct re_pattern_buffer *re;
- const char *error_message;
- struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
- our_pred->need_stat = our_pred->need_type = false;
- re = xmalloc (sizeof (struct re_pattern_buffer));
- our_pred->args.regex = re;
- re->allocated = 100;
- re->buffer = xmalloc (re->allocated);
- re->fastmap = NULL;
+ unsigned i;
- re_set_syntax(regex_options);
- re->syntax = regex_options;
- re->translate = NULL;
-
- error_message = re_compile_pattern (rx, strlen(rx), re);
- if (error_message)
- error (1, 0, "%s", error_message);
- our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
- return true;
+ re->translate = xmalloc (256);
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < 256; i++)
+ re->translate[i] = ISUPPER (i) ? tolower (i) : i;
}
- return false;
+ else
+ re->translate = NULL;
+
+ error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
+ re);
+ if (error_message)
+ error (1, 0, "%s", error_message);
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_size (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
struct predicate *our_pred;
- uintmax_t num;
- char suffix;
+ unsigned long num;
enum comparison_type c_type;
-
int blksize = 512;
int len;
- /* XXX: cannot (yet) convert to ue collect_arg() as this
- * function modifies the args in-place.
- */
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- return false;
-
+ return (false);
len = strlen (argv[*arg_ptr]);
if (len == 0)
- error (1, 0, _("invalid null argument to -size"));
-
- suffix = argv[*arg_ptr][len - 1];
- switch (suffix)
+ error (1, 0, "invalid null argument to -size");
+ switch (argv[*arg_ptr][len - 1])
{
case 'b':
blksize = 512;
@@ -2088,16 +1188,6 @@ parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
argv[*arg_ptr][len - 1] = '\0';
break;
- case 'M': /* Megabytes */
- blksize = 1024*1024;
- argv[*arg_ptr][len - 1] = '\0';
- break;
-
- case 'G': /* Gigabytes */
- blksize = 1024*1024*1024;
- argv[*arg_ptr][len - 1] = '\0';
- break;
-
case 'w':
blksize = 2;
argv[*arg_ptr][len - 1] = '\0';
@@ -2116,577 +1206,198 @@ parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
break;
default:
- error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
+ error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
}
- /* TODO: accept fractional megabytes etc. ? */
if (!get_num (argv[*arg_ptr], &num, &c_type))
- {
- error(1, 0,
- _("Invalid argument `%s%c' to -size"),
- argv[*arg_ptr], (int)suffix);
- return false;
- }
- our_pred = insert_primary (entry);
+ return (false);
+ our_pred = insert_primary (pred_size);
our_pred->args.size.kind = c_type;
our_pred->args.size.blocksize = blksize;
our_pred->args.size.size = num;
- our_pred->need_stat = true;
- our_pred->need_type = false;
-
- if (COMP_GT == c_type)
- our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
- else if (COMP_LT == c_type)
- our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
- else
- our_pred->est_success_rate = 0.01;
-
(*arg_ptr)++;
- return true;
+ return (true);
}
-
static boolean
-parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_true (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- /* General idea: stat the file, remember device and inode numbers.
- * If a candidate file matches those, it's the same file.
- */
struct predicate *our_pred;
- struct stat st, fst;
- int fd, openflags;
-
- set_stat_placeholders(&st);
- if (!collect_arg_stat_info(argv, arg_ptr, &st))
- return false;
-
- set_stat_placeholders(&fst);
- /* POSIX systems are free to re-use the inode number of a deleted
- * file. To ensure that we are not fooled by inode reuse, we hold
- * the file open if we can. This would prevent the system reusing
- * the file.
- */
- fd = -3; /* means, uninitialised */
- openflags = O_RDONLY;
-
- if (options.symlink_handling == SYMLINK_NEVER_DEREF)
- {
- if (options.open_nofollow_available)
- {
- assert (O_NOFOLLOW != 0);
- openflags |= O_NOFOLLOW;
- fd = -1; /* safe to open it. */
- }
- else
- {
- if (S_ISLNK(st.st_mode))
- {
- /* no way to ensure that a symlink will not be followed
- * by open(2), so fall back on using lstat(). Accept
- * the risk that the named file will be deleted and
- * replaced with another having the same inode.
- *
- * Avoid opening the file.
- */
- fd = -2; /* Do not open it */
- }
- else
- {
- fd = -1;
- /* Race condition here: the file might become a symlink here. */
- }
- }
- }
- else
- {
- /* We want to dereference the symlink anyway */
- fd = -1; /* safe to open it without O_NOFOLLOW */
- }
- assert (fd != -3); /* check we made a decision */
- if (fd == -1)
- {
- /* Race condition here. The file might become a
- * symbolic link in between out call to stat and
- * the call to open.
- */
- fd = open(argv[*arg_ptr], openflags);
-
- if (fd >= 0)
- {
- /* We stat the file again here to prevent a race condition
- * between the first stat and the call to open(2).
- */
- if (0 != fstat(fd, &fst))
- {
- fatal_file_error(argv[*arg_ptr]);
- }
- else
- {
- /* Worry about the race condition. If the file became a
- * symlink after our first stat and before our call to
- * open, fst may contain the stat information for the
- * destination of the link, not the link itself.
- */
- if ((*options.xstat) (argv[*arg_ptr], &st))
- fatal_file_error(argv[*arg_ptr]);
-
- if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
- && (!options.open_nofollow_available))
- {
- if (S_ISLNK(st.st_mode))
- {
- /* We lost the race. Leave the data in st. The
- * file descriptor points to the wrong thing.
- */
- close(fd);
- fd = -1;
- }
- else
- {
- /* Several possibilities here:
- * 1. There was no race
- * 2. The file changed into a symlink after the stat and
- * before the open, and then back into a non-symlink
- * before the second stat.
- *
- * In case (1) there is no problem. In case (2),
- * the stat() and fstat() calls will have returned
- * different data. O_NOFOLLOW was not available,
- * so the open() call may have followed a symlink
- * even if the -P option is in effect.
- */
- if ((st.st_dev == fst.st_dev)
- && (st.st_ino == fst.st_ino))
- {
- /* No race. No need to copy fst to st,
- * since they should be identical (modulo
- * differences in padding bytes).
- */
- }
- else
- {
- /* We lost the race. Leave the data in st. The
- * file descriptor points to the wrong thing.
- */
- close(fd);
- fd = -1;
- }
- }
- }
- else
- {
- st = fst;
- }
- }
- }
- }
-
- our_pred = insert_primary (entry);
- our_pred->args.samefileid.ino = st.st_ino;
- our_pred->args.samefileid.dev = st.st_dev;
- our_pred->args.samefileid.fd = fd;
- our_pred->need_type = false;
- our_pred->need_stat = true;
- our_pred->est_success_rate = 0.01f;
- return true;
+ our_pred = insert_primary (pred_true);
+ our_pred->need_stat = false;
+ return (true);
}
-#if 0
-/* This function is commented out partly because support for it is
- * uneven.
- */
static boolean
-parse_show_control_chars (const struct parser_table* entry,
- char **argv,
- int *arg_ptr)
+parse_type (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- const char *arg;
- const char *errmsg = _("The -show-control-chars option takes "
- "a single argument which "
- "must be 'literal' or 'safe'");
-
- if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- {
- error (1, errno, "%s", errmsg);
- return false;
- }
- else
- {
- arg = argv[*arg_ptr];
-
- if (0 == strcmp("literal", arg))
- {
- options.literal_control_chars = true;
- }
- else if (0 == strcmp("safe", arg))
- {
- options.literal_control_chars = false;
- }
- else
- {
- error (1, errno, "%s", errmsg);
- return false;
- }
- (*arg_ptr)++; /* consume the argument. */
- return true;
- }
+ return insert_type (argv, arg_ptr, pred_type);
}
-#endif
-
static boolean
-parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_uid (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- struct predicate *our_pred;
-
- (void) argv;
- (void) arg_ptr;
-
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->est_success_rate = 1.0f;
- return true;
+ return (insert_num (argv, arg_ptr, pred_uid));
}
static boolean
-parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- (void) entry;
- return parse_true(get_noop(), argv, arg_ptr);
-}
+parse_used (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
-static boolean
-parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
{
struct predicate *our_pred;
- (void) argv;
- (void) arg_ptr;
- our_pred = insert_primary (entry);
- our_pred->need_stat = our_pred->need_type = false;
- our_pred->side_effects = our_pred->no_default_print = false;
- if (pred_is(our_pred, pred_executable))
- our_pred->est_success_rate = 0.2;
- else
- our_pred->est_success_rate = 0.9;
- return true;
-}
-
-static boolean
-parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- return insert_type (argv, arg_ptr, entry, pred_type);
-}
+ unsigned long num_days;
+ enum comparison_type c_type;
-static boolean
-parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- struct predicate *p = insert_num (argv, arg_ptr, entry);
- if (p)
- {
- p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
- return true;
- }
- else
- {
- return false;
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num (argv[*arg_ptr], &num_days, &c_type))
+ return (false);
+ our_pred = insert_primary (pred_used);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = num_days * DAYSECS;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_user (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
+ struct passwd *cur_pwd;
struct predicate *our_pred;
- struct time_val tval;
- const char *offset_str;
- const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
+ uid_t uid;
+ int uid_len;
- if (collect_arg(argv, arg_ptr, &offset_str))
- {
- /* The timespec is actually a delta value, so we use an origin of 0. */
- struct timespec zero = {0,0};
- if (get_relative_timestamp(offset_str, &tval, zero, DAYSECS, errmsg))
- {
- our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
- return true;
- }
- else
- {
- error(1, 0, _("Invalid argument %s to -used"), offset_str);
- return false;
- }
- }
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ cur_pwd = getpwnam (argv[*arg_ptr]);
+ endpwent ();
+ if (cur_pwd != NULL)
+ uid = cur_pwd->pw_uid;
else
{
- return false; /* missing argument */
+ uid_len = strspn (argv[*arg_ptr], "0123456789");
+ if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
+ return (false);
+ uid = atoi (argv[*arg_ptr]);
}
+ our_pred = insert_primary (pred_user);
+ our_pred->args.uid = uid;
+ (*arg_ptr)++;
+ return (true);
}
static boolean
-parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- const char *username;
-
- if (collect_arg(argv, arg_ptr, &username))
- {
- struct predicate *our_pred;
- uid_t uid;
- struct passwd *cur_pwd = getpwnam(username);
- endpwent();
- if (cur_pwd != NULL)
- {
- uid = cur_pwd->pw_uid;
- }
- else
- {
- int uid_len = strspn (username, "0123456789");
- if (uid_len && (username[uid_len]==0))
- uid = safe_atoi (username);
- else
- return false;
- }
- our_pred = insert_primary (entry);
- our_pred->args.uid = uid;
- our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
- return true;
- }
- return false;
-}
-
-static boolean
-parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_version (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- int features = 0;
- int flags;
-
- (void) argv;
- (void) arg_ptr;
- (void) entry;
-
- display_findutils_version("find");
- printf (_("Features enabled: "));
-
-#if CACHE_IDS
- printf("CACHE_IDS ");
- ++features;
-#endif
-#if DEBUG
- printf("DEBUG ");
- ++features;
-#endif
-#if DEBUG_STAT
- printf("DEBUG_STAT ");
- ++features;
-#endif
-#if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
- printf("D_TYPE ");
- ++features;
-#endif
-#if defined O_NOFOLLOW
- printf("O_NOFOLLOW(%s) ",
- (options.open_nofollow_available ? "enabled" : "disabled"));
- ++features;
-#endif
-#if defined LEAF_OPTIMISATION
- printf("LEAF_OPTIMISATION ");
- ++features;
-#endif
+ extern char *version_string;
- flags = 0;
- if (is_fts_enabled(&flags))
- {
- int nflags = 0;
- printf("FTS(");
- ++features;
-
- if (flags & FTS_CWDFD)
- {
- if (nflags)
- {
- printf(",");
- }
- printf("FTS_CWDFD");
- ++nflags;
- }
- printf(") ");
- }
-
- printf("CBO(level=%d) ", (int)(options.optimisation_level));
- ++features;
-
- if (0 == features)
- {
- /* For the moment, leave this as English in case someone wants
- to parse these strings. */
- printf("none");
- }
- printf("\n");
-
+ fflush (stderr);
+ printf ("GNU find version %s\n", version_string);
exit (0);
}
static boolean
-parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_xdev (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- options.stay_on_filesystem = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.ignore_readdir_race = true;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.ignore_readdir_race = false;
- return parse_noop(entry, argv, arg_ptr);
-}
-
-static boolean
-parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
-{
- options.warnings = true;
- return parse_noop(entry, argv, arg_ptr);
+ stay_on_filesystem = true;
+ return true;
}
static boolean
-parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
+parse_xtype (argv, arg_ptr)
+ char *argv[];
+ int *arg_ptr;
{
- return insert_type (argv, arg_ptr, entry, pred_xtype);
+ return insert_type (argv, arg_ptr, pred_xtype);
}
static boolean
-insert_type (char **argv, int *arg_ptr,
- const struct parser_table *entry,
- PRED_FUNC which_pred)
+insert_type (argv, arg_ptr, which_pred)
+ char *argv[];
+ int *arg_ptr;
+ boolean (*which_pred) ();
{
- mode_t type_cell;
+ unsigned long type_cell;
struct predicate *our_pred;
- float rate = 0.5;
- const char *typeletter;
- if (collect_arg(argv, arg_ptr, &typeletter))
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL)
+ || (strlen (argv[*arg_ptr]) != 1))
+ return (false);
+ switch (argv[*arg_ptr][0])
{
- if (strlen(typeletter) != 1u)
- {
- error(1, 0, _("Arguments to -type should contain only one letter"));
- return false;
- }
-
- switch (typeletter[0])
- {
- case 'b': /* block special */
- type_cell = S_IFBLK;
- rate = 0.01f;
- break;
- case 'c': /* character special */
- type_cell = S_IFCHR;
- rate = 0.01f;
- break;
- case 'd': /* directory */
- type_cell = S_IFDIR;
- rate = 0.4f;
- break;
- case 'f': /* regular file */
- type_cell = S_IFREG;
- rate = 0.95f;
- break;
+ case 'b': /* block special */
+ type_cell = S_IFBLK;
+ break;
+ case 'c': /* character special */
+ type_cell = S_IFCHR;
+ break;
+ case 'd': /* directory */
+ type_cell = S_IFDIR;
+ break;
+ case 'f': /* regular file */
+ type_cell = S_IFREG;
+ break;
#ifdef S_IFLNK
- case 'l': /* symbolic link */
- type_cell = S_IFLNK;
- rate = 0.1f;
- break;
+ case 'l': /* symbolic link */
+ type_cell = S_IFLNK;
+ break;
#endif
#ifdef S_IFIFO
- case 'p': /* pipe */
- type_cell = S_IFIFO;
- rate = 0.01f;
- break;
+ case 'p': /* pipe */
+ type_cell = S_IFIFO;
+ break;
#endif
#ifdef S_IFSOCK
- case 's': /* socket */
- type_cell = S_IFSOCK;
- rate = 0.01f;
- break;
-#endif
-#ifdef S_IFDOOR
- case 'D': /* Solaris door */
- type_cell = S_IFDOOR;
- rate = 0.01f;
- break;
+ case 's': /* socket */
+ type_cell = S_IFSOCK;
+ break;
#endif
- default: /* None of the above ... nuke 'em. */
- error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
- return false;
- }
- our_pred = insert_primary_withpred (entry, which_pred);
- our_pred->est_success_rate = rate;
-
- /* Figure out if we will need to stat the file, because if we don't
- * need to follow symlinks, we can avoid a stat call by using
- * struct dirent.d_type.
- */
- if (which_pred == pred_xtype)
- {
- our_pred->need_stat = true;
- our_pred->need_type = false;
- }
- else
- {
- our_pred->need_stat = false; /* struct dirent is enough */
- our_pred->need_type = true;
- }
- our_pred->args.type = type_cell;
- return true;
+ default: /* None of the above ... nuke 'em. */
+ return (false);
}
- return false;
+ our_pred = insert_primary (which_pred);
+ our_pred->args.type = type_cell;
+ (*arg_ptr)++; /* Move on to next argument. */
+ return (true);
}
+/* If true, we've determined that the current fprintf predicate
+ uses stat information. */
+static boolean fprintf_stat_needed;
-/* Return true if the file accessed via FP is a terminal.
- */
-static boolean
-stream_is_tty(FILE *fp)
-{
- int fd = fileno(fp);
- if (-1 == fd)
- {
- return false; /* not a valid stream */
- }
- else
- {
- return isatty(fd) ? true : false;
- }
-
-}
-
-
-
-
-/* XXX: do we need to pass FUNC to this function? */
static boolean
-insert_fprintf (struct format_val *vec,
- const struct parser_table *entry, PRED_FUNC func,
- const char *format_const)
+insert_fprintf (fp, func, argv, arg_ptr)
+ FILE *fp;
+ boolean (*func) ();
+ char *argv[];
+ int *arg_ptr;
{
- char *format = (char*)format_const; /* XXX: casting away constness */
+ char *format; /* Beginning of unprocessed format string. */
register char *scan; /* Current address in scanning `format'. */
register char *scan2; /* Address inside of element being scanned. */
struct segment **segmentp; /* Address of current segment. */
struct predicate *our_pred;
- our_pred = insert_primary_withpred (entry, func);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->args.printf_vec = *vec;
- our_pred->need_type = false;
- our_pred->need_stat = false;
- our_pred->p_cost = NeedsNothing;
+ format = argv[(*arg_ptr)++];
+ fprintf_stat_needed = false; /* Might be overridden later. */
+ our_pred = insert_primary (func);
+ our_pred->side_effects = true;
+ our_pred->args.printf_vec.stream = fp;
segmentp = &our_pred->args.printf_vec.segment;
*segmentp = NULL;
@@ -2716,12 +1427,9 @@ insert_fprintf (struct format_val *vec,
*scan = '\b';
break;
case 'c':
- make_segment (segmentp, format, scan - format,
- KIND_STOP, 0, 0,
- our_pred);
- if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
- our_pred->p_cost = NeedsStatInfo;
- return true;
+ make_segment (segmentp, format, scan - format, KIND_STOP);
+ our_pred->need_stat = fprintf_stat_needed;
+ return (true);
case 'f':
*scan = '\f';
break;
@@ -2741,30 +1449,22 @@ insert_fprintf (struct format_val *vec,
/* *scan = '\\'; * it already is */
break;
default:
- error (0, 0,
- _("warning: unrecognized escape `\\%c'"), *scan2);
+ error (0, 0, "warning: unrecognized escape `\\%c'", *scan2);
scan++;
continue;
}
}
segmentp = make_segment (segmentp, format, scan - format + 1,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
format = scan2 + 1; /* Move past the escape. */
scan = scan2; /* Incremented immediately by `for'. */
}
else if (*scan == '%')
{
- if (scan[1] == 0)
- {
- /* Trailing %. We don't like those. */
- error (1, 0, _("error: %s at end of format string"), scan);
- }
- else if (scan[1] == '%')
+ if (scan[1] == '%')
{
segmentp = make_segment (segmentp, format, scan - format + 1,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
scan++;
format = scan + 1;
continue;
@@ -2777,19 +1477,17 @@ insert_fprintf (struct format_val *vec,
if (*scan2 == '.')
for (scan2++; ISDIGIT (*scan2); scan2++)
/* Do nothing. */ ;
- if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
+ if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
{
segmentp = make_segment (segmentp, format, scan2 - format,
- KIND_FORMAT, *scan2, 0,
- our_pred);
+ (int) *scan2);
scan = scan2;
format = scan + 1;
}
- else if (strchr ("ABCT", *scan2) && scan2[1])
+ else if (strchr ("ACT", *scan2) && scan2[1])
{
segmentp = make_segment (segmentp, format, scan2 - format,
- KIND_FORMAT, scan2[0], scan2[1],
- our_pred);
+ *scan2 | (scan2[1] << 8));
scan = scan2 + 1;
format = scan + 1;
continue;
@@ -2797,11 +1495,10 @@ insert_fprintf (struct format_val *vec,
else
{
/* An unrecognized % escape. Print the char after the %. */
- error (0, 0, _("warning: unrecognized format directive `%%%c'"),
+ error (0, 0, "warning: unrecognized format directive `%%%c'",
*scan2);
segmentp = make_segment (segmentp, format, scan - format,
- KIND_PLAIN, 0, 0,
- our_pred);
+ KIND_PLAIN);
format = scan + 1;
continue;
}
@@ -2809,9 +1506,9 @@ insert_fprintf (struct format_val *vec,
}
if (scan > format)
- make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
- our_pred);
- return true;
+ make_segment (segmentp, format, scan - format, KIND_PLAIN);
+ our_pred->need_stat = fprintf_stat_needed;
+ return (true);
}
/* Create a new fprintf segment in *SEGMENT, with type KIND,
@@ -2819,476 +1516,208 @@ insert_fprintf (struct format_val *vec,
Return the address of the `next' pointer of the new segment. */
static struct segment **
-make_segment (struct segment **segment,
- char *format,
- int len,
- int kind,
- char format_char,
- char aux_format_char,
- struct predicate *pred)
-{
- enum EvaluationCost mycost = NeedsNothing;
+make_segment (segment, format, len, kind)
+ struct segment **segment;
+ char *format;
+ int len, kind;
+{
char *fmt;
- *segment = xmalloc (sizeof (struct segment));
+ *segment = (struct segment *) xmalloc (sizeof (struct segment));
- (*segment)->segkind = kind;
- (*segment)->format_char[0] = format_char;
- (*segment)->format_char[1] = aux_format_char;
+ (*segment)->kind = kind;
(*segment)->next = NULL;
(*segment)->text_len = len;
- fmt = (*segment)->text = xmalloc (len + sizeof "d");
+ fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
strncpy (fmt, format, len);
fmt += len;
- switch (kind)
+ switch (kind & 0xff)
{
case KIND_PLAIN: /* Plain text string, no % conversion. */
case KIND_STOP: /* Terminate argument, no newline. */
- assert (0 == format_char);
- assert (0 == aux_format_char);
- *fmt = '\0';
- if (mycost > pred->p_cost)
- pred->p_cost = NeedsNothing;
- return &(*segment)->next;
break;
- }
- assert (kind == KIND_FORMAT);
- switch (format_char)
- {
- case 'l': /* object of symlink */
- pred->need_stat = true;
- mycost = NeedsLinkName;
- *fmt++ = 's';
- break;
-
- case 'y': /* file type */
- pred->need_type = true;
- mycost = NeedsType;
- *fmt++ = 's';
- break;
-
case 'a': /* atime in `ctime' format */
- case 'A': /* atime in user-specified strftime format */
- case 'B': /* birth time in user-specified strftime format */
case 'c': /* ctime in `ctime' format */
- case 'C': /* ctime in user-specified strftime format */
- case 'F': /* file system type */
+ case 'F': /* filesystem type */
case 'g': /* group name */
- case 'i': /* inode number */
- case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
- case 's': /* size in bytes */
+ case 'l': /* object of symlink */
case 't': /* mtime in `ctime' format */
- case 'T': /* mtime in user-specified strftime format */
case 'u': /* user name */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 's';
- break;
-
- case 'S': /* sparseness */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 'g';
- break;
-
- case 'Y': /* symlink pointed file type */
- pred->need_stat = true;
- mycost = NeedsType; /* true for amortised effect */
- *fmt++ = 's';
- break;
-
+ case 'A': /* atime in user-specified strftime format */
+ case 'C': /* ctime in user-specified strftime format */
+ case 'T': /* mtime in user-specified strftime format */
+ fprintf_stat_needed = true;
+ /* FALLTHROUGH */
case 'f': /* basename of path */
case 'h': /* leading directories part of path */
+ case 'H': /* ARGV element file was found under */
case 'p': /* pathname */
case 'P': /* pathname with ARGV element stripped */
*fmt++ = 's';
break;
- case 'H': /* ARGV element file was found under */
- *fmt++ = 's';
- break;
-
- /* Numeric items that one might expect to honour
- * #, 0, + flags but which do not.
- */
- case 'G': /* GID number */
- case 'U': /* UID number */
- case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
- case 'D': /* Filesystem device on which the file exits */
+ case 'b': /* size in 512-byte blocks */
case 'k': /* size in 1K blocks */
+ case 's': /* size in bytes */
+ *fmt++ = 'l';
+ /*FALLTHROUGH*/
case 'n': /* number of links */
- pred->need_stat = true;
- mycost = NeedsStatInfo;
- *fmt++ = 's';
- break;
-
- /* Numeric items that DO honour #, 0, + flags.
- */
+ fprintf_stat_needed = true;
+ /* FALLTHROUGH */
case 'd': /* depth in search tree (0 = ARGV element) */
*fmt++ = 'd';
break;
- case 'm': /* mode as octal number (perms only) */
- *fmt++ = 'o';
- pred->need_stat = true;
- mycost = NeedsStatInfo;
+ case 'i': /* inode number */
+ *fmt++ = 'l';
+ /*FALLTHROUGH*/
+ case 'G': /* GID number */
+ case 'U': /* UID number */
+ *fmt++ = 'u';
+ fprintf_stat_needed = true;
break;
- case '{':
- case '[':
- case '(':
- error (1, 0,
- _("error: the format directive `%%%c' is reserved for future use"),
- (int)kind);
- /*NOTREACHED*/
+ case 'm': /* mode as octal number (perms only) */
+ *fmt++ = 'o';
+ fprintf_stat_needed = true;
break;
}
*fmt = '\0';
- if (mycost > pred->p_cost)
- pred->p_cost = mycost;
- return &(*segment)->next;
-}
-
-static void
-check_path_safety(const char *action, char **argv)
-{
- char *s;
- const char *path = getenv("PATH");
- if (NULL == path)
- {
- /* $PATH is not set. Assume the OS default is safe.
- * That may not be true on Windows, but I'm not aware
- * of a way to get Windows to avoid searching the
- * current directory anyway.
- */
- return;
- }
-
- (void)argv;
-
- s = next_element(path, 1);
- while ((s = next_element ((char *) NULL, 1)) != NULL)
- {
- if (0 == strcmp(s, "."))
- {
- error(1, 0, _("The current directory is included in the PATH "
- "environment variable, which is insecure in "
- "combination with the %s action of find. "
- "Please remove the current directory from your "
- "$PATH (that is, remove \".\" or leading or trailing "
- "colons)"),
- action);
- }
- else if ('/' != s[0])
- {
- /* Relative paths are also dangerous in $PATH. */
- error(1, 0, _("The relative path %s is included in the PATH "
- "environment variable, which is insecure in "
- "combination with the %s action of find. "
- "Please remove that entry from $PATH"),
- safely_quote_err_filename(0, s),
- action);
- }
- }
+ return (&(*segment)->next);
}
-
-/* handles both exec and ok predicate */
static boolean
-new_insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dirfd,
- char **argv,
- int *arg_ptr)
+insert_exec_ok (func, argv, arg_ptr)
+ boolean (*func) ();
+ char *argv[];
+ int *arg_ptr;
{
int start, end; /* Indexes in ARGV of start & end of cmd. */
- int i; /* Index into cmd args */
- int saw_braces; /* True if previous arg was '{}'. */
- boolean allow_plus; /* True if + is a valid terminator */
- int brace_count; /* Number of instances of {}. */
- PRED_FUNC func = entry->pred_func;
- enum BC_INIT_STATUS bcstatus;
-
+ int num_paths; /* Number of args with path replacements. */
+ int path_pos; /* Index in array of path replacements. */
+ int vec_pos; /* Index in array of args. */
struct predicate *our_pred;
struct exec_val *execp; /* Pointer for efficiency. */
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
- return false;
+ return (false);
- our_pred = insert_primary_withpred (entry, func);
- our_pred->side_effects = our_pred->no_default_print = true;
- our_pred->need_type = our_pred->need_stat = false;
-
- execp = &our_pred->args.exec_vec;
-
- if ((func != pred_okdir) && (func != pred_ok))
- {
- allow_plus = true;
- execp->close_stdin = false;
- }
- else
- {
- allow_plus = false;
- /* If find reads stdin (i.e. for -ok and similar), close stdin
- * in the child to prevent some script from consiming the output
- * intended for find.
- */
- execp->close_stdin = true;
- }
-
-
- if ((func == pred_execdir) || (func == pred_okdir))
- {
- options.ignore_readdir_race = false;
- check_path_safety(action, argv);
- execp->use_current_dir = true;
- }
- else
- {
- execp->use_current_dir = false;
- }
-
- our_pred->args.exec_vec.multiple = 0;
-
- /* Count the number of args with path replacements, up until the ';'.
- * Also figure out if the command is terminated by ";" or by "+".
- */
+ /* Count the number of args with path replacements, up until the ';'. */
start = *arg_ptr;
- for (end = start, saw_braces=0, brace_count=0;
+ for (end = start, num_paths = 0;
(argv[end] != NULL)
&& ((argv[end][0] != ';') || (argv[end][1] != '\0'));
end++)
- {
- /* For -exec and -execdir, "{} +" can terminate the command. */
- if ( allow_plus
- && argv[end][0] == '+' && argv[end][1] == 0
- && saw_braces)
- {
- our_pred->args.exec_vec.multiple = 1;
- break;
- }
-
- saw_braces = 0;
- if (mbsstr (argv[end], "{}"))
- {
- saw_braces = 1;
- ++brace_count;
-
- if (0 == end && (func == pred_execdir || func == pred_okdir))
- {
- /* The POSIX standard says that {} replacement should
- * occur even in the utility name. This is insecure
- * since it means we will be executing a command whose
- * name is chosen according to whatever find finds in
- * the file system. That can be influenced by an
- * attacker. Hence for -execdir and -okdir this is not
- * allowed. We can specify this as those options are
- * not defined by POSIX.
- */
- error(1, 0, _("You may not use {} within the utility name for "
- "-execdir and -okdir, because this is a potential "
- "security problem."));
- }
- }
- }
-
+ if (strstr (argv[end], "{}"))
+ num_paths++;
/* Fail if no command given or no semicolon found. */
if ((end == start) || (argv[end] == NULL))
{
*arg_ptr = end;
- free(our_pred);
- return false;
- }
-
- if (our_pred->args.exec_vec.multiple && brace_count > 1)
- {
-
- const char *suffix;
- if (func == pred_execdir)
- suffix = "dir";
- else
- suffix = "";
-
- error(1, 0,
- _("Only one instance of {} is supported with -exec%s ... +"),
- suffix);
- }
-
- /* We use a switch statement here so that the compiler warns us when
- * we forget to handle a newly invented enum value.
- *
- * Like xargs, we allow 2KiB of headroom for the launched utility to
- * export its own environment variables before calling something
- * else.
- */
- bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
- switch (bcstatus)
- {
- case BC_INIT_ENV_TOO_BIG:
- case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
- error(1, 0,
- _("The environment is too large for exec()."));
- break;
- case BC_INIT_OK:
- /* Good news. Carry on. */
- break;
+ return (false);
}
- bc_use_sensible_arg_max(&execp->ctl);
-
- execp->ctl.exec_callback = launch;
-
- if (our_pred->args.exec_vec.multiple)
+ our_pred = insert_primary (func);
+ our_pred->side_effects = true;
+ execp = &our_pred->args.exec_vec;
+ execp->paths =
+ (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
+ execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
+ /* Record the positions of all args, and the args with path replacements. */
+ for (end = start, path_pos = vec_pos = 0;
+ (argv[end] != NULL)
+ && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
+ end++)
{
- /* "+" terminator, so we can just append our arguments after the
- * command and initial arguments.
- */
- execp->replace_vec = NULL;
- execp->ctl.replace_pat = NULL;
- execp->ctl.rplen = 0;
- execp->ctl.lines_per_exec = 0; /* no limit */
- execp->ctl.args_per_exec = 0; /* no limit */
+ register char *p;
- /* remember how many arguments there are */
- execp->ctl.initial_argc = (end-start) - 1;
-
- /* execp->state = xmalloc(sizeof struct buildcmd_state); */
- bc_init_state(&execp->ctl, &execp->state, execp);
-
- /* Gather the initial arguments. Skip the {}. */
- for (i=start; i<end-1; ++i)
+ execp->paths[path_pos].count = 0;
+ for (p = argv[end]; *p; ++p)
+ if (p[0] == '{' && p[1] == '}')
+ {
+ execp->paths[path_pos].count++;
+ ++p;
+ }
+ if (execp->paths[path_pos].count)
{
- bc_push_arg(&execp->ctl, &execp->state,
- argv[i], strlen(argv[i])+1,
- NULL, 0,
- 1);
+ execp->paths[path_pos].offset = vec_pos;
+ execp->paths[path_pos].origarg = argv[end];
+ path_pos++;
}
+ execp->vec[vec_pos++] = argv[end];
}
- else
- {
- /* Semicolon terminator - more than one {} is supported, so we
- * have to do brace-replacement.
- */
- execp->num_args = end - start;
-
- execp->ctl.replace_pat = "{}";
- execp->ctl.rplen = strlen(execp->ctl.replace_pat);
- execp->ctl.lines_per_exec = 0; /* no limit */
- execp->ctl.args_per_exec = 0; /* no limit */
- execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
+ execp->paths[path_pos].offset = -1;
+ execp->vec[vec_pos] = NULL;
-
- /* execp->state = xmalloc(sizeof(*(execp->state))); */
- bc_init_state(&execp->ctl, &execp->state, execp);
-
- /* Remember the (pre-replacement) arguments for later. */
- for (i=0; i<execp->num_args; ++i)
- {
- execp->replace_vec[i] = argv[i+start];
- }
- }
-
if (argv[end] == NULL)
*arg_ptr = end;
else
*arg_ptr = end + 1;
-
- return true;
-}
-
-
-
-static boolean
-insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dirfd,
- char **argv,
- int *arg_ptr)
-{
- return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
+ return (true);
}
-
-
-/* Get a timestamp and comparison type.
-
+/* Get a number of days and comparison type.
STR is the ASCII representation.
- Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
- relative to ORIGIN (usually the current moment or midnight).
- Thus the sense of the comparison type appears to be reversed.
+ Set *NUM_DAYS to the number of days, taken as being from
+ the current moment (or possibly midnight). Thus the sense of the
+ comparison type appears to be reversed.
Set *COMP_TYPE to the kind of comparison that is requested.
- Issue OVERFLOWMESSAGE if overflow occurs.
+
Return true if all okay, false if input error.
Used by -atime, -ctime and -mtime (parsers) to
get the appropriate information for a time predicate processor. */
static boolean
-get_relative_timestamp (const char *str,
- struct time_val *result,
- struct timespec origin,
- double sec_per_unit,
- const char *overflowmessage)
+get_num_days (str, num_days, comp_type)
+ char *str;
+ unsigned long *num_days;
+ enum comparison_type *comp_type;
{
- uintmax_t checkval;
- double offset, seconds, nanosec;
-
- if (get_comp_type(&str, &result->kind))
- {
- /* Invert the sense of the comparison */
- switch (result->kind)
- {
- case COMP_LT: result->kind = COMP_GT; break;
- case COMP_GT: result->kind = COMP_LT; break;
- default: break;
- }
+ int len_days; /* length of field */
- /* Convert the ASCII number into floating-point. */
- if (xstrtod(str, NULL, &offset, strtod))
- {
- /* Separate the floating point number the user specified
- * (which is a number of days, or minutes, etc) into an
- * integral number of seconds (SECONDS) and a fraction (NANOSEC).
- */
- nanosec = modf(offset * sec_per_unit, &seconds);
- nanosec *= 1.0e9; /* convert from fractional seconds to ns. */
-
- result->ts.tv_sec = origin.tv_sec - seconds;
- result->ts.tv_nsec = origin.tv_nsec - nanosec;
- checkval = (uintmax_t)origin.tv_sec - seconds;
-
- if (origin.tv_nsec < nanosec)
- {
- /* Perform a carry operation */
- result->ts.tv_nsec += 1000000000;
- result->ts.tv_sec -= 1;
- checkval -= 1;
- }
- /* Check for overflow. */
- if (checkval != result->ts.tv_sec)
- {
- /* an overflow has occurred. */
- error (1, 0, overflowmessage, str);
- }
- return true;
- }
- else
- {
- /* Conversion from ASCII to double failed. */
- return false;
- }
- }
- else
+ if (str == NULL)
+ return (false);
+ switch (str[0])
{
- return false;
+ case '+':
+ *comp_type = COMP_LT;
+ str++;
+ break;
+ case '-':
+ *comp_type = COMP_GT;
+ str++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ *comp_type = COMP_EQ;
+ break;
+ default:
+ return (false);
}
+
+ /* We know the first char has been reasonable. Find the
+ number of days to play with. */
+ len_days = strspn (str, "0123456789");
+ if ((len_days == 0) || (str[len_days] != '\0'))
+ return (false);
+ *num_days = (unsigned long) atol (str);
+ return (true);
}
-/* Insert a time predicate based on the information in ENTRY.
+/* Insert a time predicate PRED.
ARGV is a pointer to the argument array.
ARG_PTR is a pointer to an index into the array, incremented if
all went well.
@@ -3300,137 +1729,100 @@ get_relative_timestamp (const char *str,
Used by -atime, -ctime, and -mtime parsers. */
-static boolean
-parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
+static boolean
+insert_time (argv, arg_ptr, pred)
+ char *argv[];
+ int *arg_ptr;
+ PFB pred;
{
struct predicate *our_pred;
- struct time_val tval;
- enum comparison_type comp;
- const char *timearg, *orig_timearg;
- const char *errmsg = "arithmetic overflow while converting %s "
- "days to a number of seconds";
- struct timespec origin;
-
- if (!collect_arg(argv, arg_ptr, &timearg))
- return false;
- orig_timearg = timearg;
-
- /* Decide the origin by previewing the comparison type. */
- origin = options.cur_day_start;
-
- if (get_comp_type(&timearg, &comp))
- {
- /* Remember, we invert the sense of the comparison, so this tests
- * against COMP_LT instead of COMP_GT...
- */
- if (COMP_LT == comp)
- {
- uintmax_t expected = origin.tv_sec + (DAYSECS-1);
- origin.tv_sec += (DAYSECS-1);
- if (origin.tv_sec != expected)
- {
- error(1, 0,
- _("arithmetic overflow when trying to calculate the end of today"));
- }
- }
- }
- /* We discard the value of comp here, as get_relative_timestamp
- * will set tval.kind. For that to work, we have to restore
- * timearg so that it points to the +/- prefix, if any. get_comp_type()
- * will have advanced timearg, so we restore it.
- */
- timearg = orig_timearg;
-
- if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
- return false;
-
- our_pred = insert_primary (entry);
- our_pred->args.reftime = tval;
- our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
+ unsigned long num_days;
+ enum comparison_type c_type;
- if (options.debug_options & DebugExpressionTree)
- {
- time_t t;
-
- fprintf (stderr, "inserting %s\n", our_pred->p_name);
- fprintf (stderr, " type: %s %s ",
- (tval.kind == COMP_GT) ? "gt" :
- ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
- (tval.kind == COMP_GT) ? " >" :
- ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
- t = our_pred->args.reftime.ts.tv_sec;
- fprintf (stderr, "%ju %s",
- (uintmax_t) our_pred->args.reftime.ts.tv_sec,
- ctime (&t));
- if (tval.kind == COMP_EQ)
- {
- t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
- fprintf (stderr, " < %ju %s",
- (uintmax_t) t, ctime (&t));
- }
- }
-
- return true;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
+ return (false);
+ our_pred = insert_primary (pred);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
+ + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
+ (*arg_ptr)++;
+#ifdef DEBUG
+ printf ("inserting %s\n", our_pred->p_name);
+ printf (" type: %s %s ",
+ (c_type == COMP_GT) ? "gt" :
+ ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
+ (c_type == COMP_GT) ? " >" :
+ ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
+ printf ("%ld %s", our_pred->args.info.l_val,
+ ctime (&our_pred->args.info.l_val));
+ if (c_type == COMP_EQ)
+ {
+ our_pred->args.info.l_val += DAYSECS;
+ printf (" < %ld %s", our_pred->args.info.l_val,
+ ctime (&our_pred->args.info.l_val));
+ our_pred->args.info.l_val -= DAYSECS;
+ }
+#endif /* DEBUG */
+ return (true);
}
-/* Get the comparison type prefix (if any) from a number argument.
- The prefix is at *STR.
+/* Get a number with comparision information.
+ The sense of the comparision information is 'normal'; that is,
+ '+' looks for inums or links > than the number and '-' less than.
+
+ STR is the ASCII representation of the number.
+ Set *NUM to the number.
Set *COMP_TYPE to the kind of comparison that is requested.
- Advance *STR beyond any initial comparison prefix.
+
+ Return true if all okay, false if input error.
+
+ Used by the -inum and -links predicate parsers. */
- Return true if all okay, false if input error. */
static boolean
-get_comp_type(const char **str, enum comparison_type *comp_type)
+get_num (str, num, comp_type)
+ char *str;
+ unsigned long *num;
+ enum comparison_type *comp_type;
{
- switch (**str)
+ int len_num; /* Length of field. */
+
+ if (str == NULL)
+ return (false);
+ switch (str[0])
{
case '+':
*comp_type = COMP_GT;
- (*str)++;
+ str++;
break;
case '-':
*comp_type = COMP_LT;
- (*str)++;
+ str++;
break;
- default:
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
*comp_type = COMP_EQ;
break;
+ default:
+ return (false);
}
- return true;
-}
-
-
-
-
-
-/* Get a number with comparison information.
- The sense of the comparison information is 'normal'; that is,
- '+' looks for a count > than the number and '-' less than.
-
- STR is the ASCII representation of the number.
- Set *NUM to the number.
- Set *COMP_TYPE to the kind of comparison that is requested.
-
- Return true if all okay, false if input error. */
-
-static boolean
-get_num (const char *str,
- uintmax_t *num,
- enum comparison_type *comp_type)
-{
- char *pend;
-
- if (str == NULL)
- return false;
- /* Figure out the comparison type if the caller accepts one. */
- if (comp_type)
- {
- if (!get_comp_type(&str, comp_type))
- return false;
- }
-
- return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
+ /* We know the first char has been reasonable. Find the number of
+ days to play with. */
+ len_num = strspn (str, "0123456789");
+ if ((len_num == 0) || (str[len_num] != '\0'))
+ return (false);
+ *num = (unsigned long) atol (str);
+ return (true);
}
/* Insert a number predicate.
@@ -3445,70 +1837,48 @@ get_num (const char *str,
Used by -inum and -links parsers. */
-static struct predicate *
-insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
+static boolean
+insert_num (argv, arg_ptr, pred)
+ char *argv[];
+ int *arg_ptr;
+ PFB pred;
{
- const char *numstr;
-
- if (collect_arg(argv, arg_ptr, &numstr))
- {
- uintmax_t num;
- enum comparison_type c_type;
+ struct predicate *our_pred;
+ unsigned long num;
+ enum comparison_type c_type;
- if (get_num (numstr, &num, &c_type))
- {
- struct predicate *our_pred = insert_primary (entry);
- our_pred->args.numinfo.kind = c_type;
- our_pred->args.numinfo.l_val = num;
-
- if (options.debug_options & DebugExpressionTree)
- {
- fprintf (stderr, "inserting %s\n", our_pred->p_name);
- fprintf (stderr, " type: %s %s ",
- (c_type == COMP_GT) ? "gt" :
- ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
- (c_type == COMP_GT) ? " >" :
- ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
- fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
- }
- return our_pred;
- }
- }
- return NULL;
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return (false);
+ if (!get_num (argv[*arg_ptr], &num, &c_type))
+ return (false);
+ our_pred = insert_primary (pred);
+ our_pred->args.info.kind = c_type;
+ our_pred->args.info.l_val = num;
+ (*arg_ptr)++;
+#ifdef DEBUG
+ printf ("inserting %s\n", our_pred->p_name);
+ printf (" type: %s %s ",
+ (c_type == COMP_GT) ? "gt" :
+ ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
+ (c_type == COMP_GT) ? " >" :
+ ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
+ printf ("%ld\n", our_pred->args.info.l_val);
+#endif /* DEBUG */
+ return (true);
}
-static void
-open_output_file (const char *path, struct format_val *p)
+static FILE *
+open_output_file (path)
+ char *path;
{
- p->segment = NULL;
- p->quote_opts = clone_quoting_options (NULL);
-
+ FILE *f;
+
if (!strcmp (path, "/dev/stderr"))
- {
- p->stream = stderr;
- p->filename = _("standard error");
- }
+ return (stderr);
else if (!strcmp (path, "/dev/stdout"))
- {
- p->stream = stdout;
- p->filename = _("standard output");
- }
- else
- {
- p->stream = fopen_safer (path, "w");
- p->filename = path;
-
- if (p->stream == NULL)
- {
- fatal_file_error(path);
- }
- }
-
- p->dest_is_tty = stream_is_tty(p->stream);
-}
-
-static void
-open_stdout (struct format_val *p)
-{
- open_output_file("/dev/stdout", p);
+ return (stdout);
+ f = fopen (path, "w");
+ if (f == NULL)
+ error (1, errno, "%s", path);
+ return (f);
}