1) Fix -E (no escape char) mode, has error with 0xFF char
[unix-history] / usr.bin / find / function.c
index f7eb8fd..c56634f 100644 (file)
@@ -1,6 +1,6 @@
 /*-
 /*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Cimarron D. Taylor of the University of California, Berkeley.
  *
  * This code is derived from software contributed to Berkeley by
  * Cimarron D. Taylor of the University of California, Berkeley.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)function.c 5.17 (Berkeley) 5/24/91";
+static char sccsid[] = "@(#)function.c 8.1 (Berkeley) 6/6/93";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/ucred.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
+
+#include <err.h>
 #include <errno.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
 #include <grp.h>
 #include <pwd.h>
 #include <grp.h>
 #include <pwd.h>
-#include <fts.h>
-#include <unistd.h>
-#include <tzfile.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fnmatch.h>
-#include "find.h"
+#include <tzfile.h>
+#include <unistd.h>
 
 
-#define        FIND_EQUAL      0
-#define        FIND_LESSTHAN   1
-#define        FIND_GREATER    2
+#include "find.h"
 
 
-#define        COMPARE(a, b) { \
-       switch(plan->flags) { \
-       case FIND_EQUAL: \
-               return(a == b); \
-       case FIND_LESSTHAN: \
-               return(a < b); \
-       case FIND_GREATER: \
-               return(a > b); \
-       } \
-       return(0); \
+#define        COMPARE(a, b) {                                                 \
+       switch (plan->flags) {                                          \
+       case F_EQUAL:                                                   \
+               return (a == b);                                        \
+       case F_LESSTHAN:                                                \
+               return (a < b);                                         \
+       case F_GREATER:                                                 \
+               return (a > b);                                         \
+       default:                                                        \
+               abort();                                                \
+       }                                                               \
 }
 
 }
 
-static PLAN *palloc __P((enum ntype, int (*)()));
+static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
 
 /*
  * find_parsenum --
  *     Parse a string of the form [+-]# and return the value.
  */
 
 /*
  * find_parsenum --
  *     Parse a string of the form [+-]# and return the value.
  */
-long
-find_parsenum(plan, option, str, endch)
+static long
+find_parsenum(plan, option, vp, endch)
        PLAN *plan;
        PLAN *plan;
-       char *option, *str, *endch;
+       char *option, *vp, *endch;
 {
        long value;
 {
        long value;
-       char *endchar;          /* pointer to character ending conversion */
+       char *endchar, *str;    /* Pointer to character ending conversion. */
     
     
-       /* determine comparison from leading + or - */
-       switch(*str) {
+       /* Determine comparison from leading + or -. */
+       str = vp;
+       switch (*str) {
        case '+':
                ++str;
        case '+':
                ++str;
-               plan->flags = FIND_GREATER;
+               plan->flags = F_GREATER;
                break;
        case '-':
                ++str;
                break;
        case '-':
                ++str;
-               plan->flags = FIND_LESSTHAN;
+               plan->flags = F_LESSTHAN;
                break;
        default:
                break;
        default:
-               plan->flags = FIND_EQUAL;
+               plan->flags = F_EQUAL;
                break;
        }
     
        /*
                break;
        }
     
        /*
-        * convert the string with strtol().  Note, if strtol() returns zero
+        * Convert the string with strtol().  Note, if strtol() returns zero
         * and endchar points to the beginning of the string we know we have
         * a syntax error.
         */
        value = strtol(str, &endchar, 10);
         * and endchar points to the beginning of the string we know we have
         * a syntax error.
         */
        value = strtol(str, &endchar, 10);
-       if (!value && endchar == str ||
-           endchar[0] && (!endch || endchar[0] != *endch))
-               err("%s: %s", option, "illegal numeric value");
+       if (value == 0 && endchar == str)
+               errx(1, "%s: %s: illegal numeric value", option, vp);
+       if (endchar[0] && (endch == NULL || endchar[0] != *endch))
+               errx(1, "%s: %s: illegal trailing character", option, vp);
        if (endch)
                *endch = endchar[0];
        if (endch)
                *endch = endchar[0];
-       return(value);
+       return (value);
 }
 
 }
 
+/*
+ * The value of n for the inode times (atime, ctime, and mtime) is a range,
+ * i.e. n matches from (n - 1) to n 24 hour periods.  This interacts with
+ * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
+ * user wanted.  Correct so that -1 is "less than 1".
+ */
+#define        TIME_CORRECT(p, ttype)                                          \
+       if ((p)->type == ttype && (p)->flags == F_LESSTHAN)             \
+               ++((p)->t_data);
+
 /*
  * -atime n functions --
  *
  *     True if the difference between the file access time and the
  *     current time is n 24 hour periods.
 /*
  * -atime n functions --
  *
  *     True if the difference between the file access time and the
  *     current time is n 24 hour periods.
- *
  */
  */
+int
 f_atime(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
 f_atime(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statb.st_atime +
+       COMPARE((now - entry->fts_statp->st_atime +
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
@@ -140,7 +153,8 @@ c_atime(arg)
 
        new = palloc(N_ATIME, f_atime);
        new->t_data = find_parsenum(new, "-atime", arg, NULL);
 
        new = palloc(N_ATIME, f_atime);
        new->t_data = find_parsenum(new, "-atime", arg, NULL);
-       return(new);
+       TIME_CORRECT(new, N_ATIME);
+       return (new);
 }
 /*
  * -ctime n functions --
 }
 /*
  * -ctime n functions --
@@ -148,13 +162,14 @@ c_atime(arg)
  *     True if the difference between the last change of file
  *     status information and the current time is n 24 hour periods.
  */
  *     True if the difference between the last change of file
  *     status information and the current time is n 24 hour periods.
  */
+int
 f_ctime(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
 f_ctime(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statb.st_ctime +
+       COMPARE((now - entry->fts_statp->st_ctime +
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
@@ -167,8 +182,9 @@ c_ctime(arg)
        ftsoptions &= ~FTS_NOSTAT;
 
        new = palloc(N_CTIME, f_ctime);
        ftsoptions &= ~FTS_NOSTAT;
 
        new = palloc(N_CTIME, f_ctime);
-       new->t_data = find_parsenum(new, "-ctime", arg, (char *)NULL);
-       return(new);
+       new->t_data = find_parsenum(new, "-ctime", arg, NULL);
+       TIME_CORRECT(new, N_CTIME);
+       return (new);
 }
 
 /*
 }
 
 /*
@@ -178,12 +194,12 @@ c_ctime(arg)
  *     so that all entries in a directory are acted on before the directory
  *     itself.
  */
  *     so that all entries in a directory are acted on before the directory
  *     itself.
  */
-/* ARGSUSED */
+int
 f_always_true(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_always_true(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return(1);
+       return (1);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -191,7 +207,7 @@ c_depth()
 {
        isdepth = 1;
 
 {
        isdepth = 1;
 
-       return(palloc(N_DEPTH, f_always_true));
+       return (palloc(N_DEPTH, f_always_true));
 }
  
 /*
 }
  
 /*
@@ -206,6 +222,7 @@ c_depth()
  *     The primary -ok is different in that it requests affirmation of the
  *     user before executing the utility.
  */
  *     The primary -ok is different in that it requests affirmation of the
  *     user before executing the utility.
  */
+int
 f_exec(plan, entry)
        register PLAN *plan;
        FTSENT *entry;
 f_exec(plan, entry)
        register PLAN *plan;
        FTSENT *entry;
@@ -220,26 +237,24 @@ f_exec(plan, entry)
                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                            entry->fts_path, plan->e_len[cnt]);
 
                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                            entry->fts_path, plan->e_len[cnt]);
 
-       if (plan->flags && !queryuser(plan->e_argv))
-               return(0);
+       if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
+               return (0);
 
 
-       switch(pid = vfork()) {
+       switch (pid = vfork()) {
        case -1:
        case -1:
-               err("fork: %s", strerror(errno));
+               err(1, "fork");
                /* NOTREACHED */
        case 0:
                if (fchdir(dotfd)) {
                /* NOTREACHED */
        case 0:
                if (fchdir(dotfd)) {
-                       (void)fprintf(stderr,
-                           "find: chdir: %s\n", strerror(errno));
+                       warn("chdir");
                        _exit(1);
                }
                execvp(plan->e_argv[0], plan->e_argv);
                        _exit(1);
                }
                execvp(plan->e_argv[0], plan->e_argv);
-               (void)fprintf(stderr,
-                   "find: %s: %s\n", plan->e_argv[0], strerror(errno));
+               warn("%s", plan->e_argv[0]);
                _exit(1);
        }
        pid = waitpid(pid, &status, 0);
                _exit(1);
        }
        pid = waitpid(pid, &status, 0);
-       return(pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
+       return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
 }
  
 /*
 }
  
 /*
@@ -261,12 +276,13 @@ c_exec(argvp, isok)
        isoutput = 1;
     
        new = palloc(N_EXEC, f_exec);
        isoutput = 1;
     
        new = palloc(N_EXEC, f_exec);
-       new->flags = isok;
+       if (isok)
+               new->flags = F_NEEDOK;
 
        for (ap = argv = *argvp;; ++ap) {
                if (!*ap)
 
        for (ap = argv = *argvp;; ++ap) {
                if (!*ap)
-                       err("%s: %s",
-                           isok ? "-ok" : "-exec", "no terminating \";\"");
+                       errx(1,
+                           "%s: no terminating \";\"", isok ? "-ok" : "-exec");
                if (**ap == ';')
                        break;
        }
                if (**ap == ';')
                        break;
        }
@@ -292,7 +308,7 @@ c_exec(argvp, isok)
        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
 
        *argvp = argv + 1;
        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
 
        *argvp = argv + 1;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -307,7 +323,7 @@ c_follow()
        ftsoptions &= ~FTS_PHYSICAL;
        ftsoptions |= FTS_LOGICAL;
 
        ftsoptions &= ~FTS_PHYSICAL;
        ftsoptions |= FTS_LOGICAL;
 
-       return(palloc(N_FOLLOW, f_always_true));
+       return (palloc(N_FOLLOW, f_always_true));
 }
  
 /*
 }
  
 /*
@@ -315,18 +331,20 @@ c_follow()
  *
  *     True if the file is of a certain type.
  */
  *
  *     True if the file is of a certain type.
  */
+int
 f_fstype(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
 f_fstype(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
-       static struct statfs sb;
+       struct statfs sb;
+       static short val;
        char *p, save[2];
 
        char *p, save[2];
 
-       /* only check when we cross mount point */
-       if (first || curdev != entry->fts_statb.st_dev) {
-               curdev = entry->fts_statb.st_dev;
+       /* Only check when we cross mount point. */
+       if (first || curdev != entry->fts_statp->st_dev) {
+               curdev = entry->fts_statp->st_dev;
 
                /*
                 * Statfs follows symlinks; find wants the link's file system,
 
                /*
                 * Statfs follows symlinks; find wants the link's file system,
@@ -334,7 +352,7 @@ f_fstype(plan, entry)
                 */
                if (entry->fts_info == FTS_SL ||
                    entry->fts_info == FTS_SLNONE) {
                 */
                if (entry->fts_info == FTS_SL ||
                    entry->fts_info == FTS_SLNONE) {
-                       if (p = rindex(entry->fts_accpath, '/'))
+                       if (p = strrchr(entry->fts_accpath, '/'))
                                ++p;
                        else
                                p = entry->fts_accpath;
                                ++p;
                        else
                                p = entry->fts_accpath;
@@ -347,7 +365,7 @@ f_fstype(plan, entry)
                        p = NULL;
 
                if (statfs(entry->fts_accpath, &sb))
                        p = NULL;
 
                if (statfs(entry->fts_accpath, &sb))
-                       err("%s: %s", entry->fts_accpath, strerror(errno));
+                       err(1, "%s", entry->fts_accpath);
 
                if (p) {
                        p[0] = save[0];
 
                if (p) {
                        p[0] = save[0];
@@ -355,9 +373,25 @@ f_fstype(plan, entry)
                }
 
                first = 0;
                }
 
                first = 0;
+               switch (plan->flags) {
+               case F_MTFLAG:
+                       val = sb.f_flags;
+                       break;
+               case F_MTTYPE:
+                       val = sb.f_type;
+                       break;
+               default:
+                       abort();
+               }
+       }
+       switch(plan->flags) {
+       case F_MTFLAG:
+               return (val & plan->mt_data);   
+       case F_MTTYPE:
+               return (val == plan->mt_data);
+       default:
+               abort();
        }
        }
-       return(plan->flags == MOUNT_NONE ?
-           sb.f_flags & plan->m_flags : sb.f_type == plan->flags);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -369,71 +403,60 @@ c_fstype(arg)
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_FSTYPE, f_fstype);
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_FSTYPE, f_fstype);
-       switch(*arg) {
-       case 'f':
-               if (!strcmp(arg, "fdesc")) {
-#ifdef MOUNT_FDESC
-                       new->flags = MOUNT_FDESC;
-                       return(new);
-#else
-                       err("unknown file type %s", arg);
-#endif
-               }
-               break;
+       switch (*arg) {
        case 'i':
                if (!strcmp(arg, "isofs")) {
        case 'i':
                if (!strcmp(arg, "isofs")) {
-                       new->flags = MOUNT_ISOFS;
-                       return(new);
-               }
-               break;
-       case 'k':
-               if (!strcmp(arg, "kernfs")) {
-#ifdef MOUNT_KERNFS
-                       new->flags = MOUNT_KERNFS;
-                       return(new);
-#else
-                       err("unknown file type %s", arg);
-#endif
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_ISOFS;
+                       return (new);
                }
                break;
        case 'l':
                if (!strcmp(arg, "local")) {
                }
                break;
        case 'l':
                if (!strcmp(arg, "local")) {
-                       new->flags = MOUNT_NONE;
-                       new->m_flags = MNT_LOCAL;
-                       return(new);
+                       new->flags = F_MTFLAG;
+                       new->mt_data = MNT_LOCAL;
+                       return (new);
                }
                break;
        case 'm':
                if (!strcmp(arg, "mfs")) {
                }
                break;
        case 'm':
                if (!strcmp(arg, "mfs")) {
-                       new->flags = MOUNT_MFS;
-                       return(new);
-               }
-               if (!strcmp(arg, "msdos")) {
-                       new->flags = MOUNT_MSDOS;
-                       return(new);
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_MFS;
+                       return (new);
                }
                break;
        case 'n':
                if (!strcmp(arg, "nfs")) {
                }
                break;
        case 'n':
                if (!strcmp(arg, "nfs")) {
-                       new->flags = MOUNT_NFS;
-                       return(new);
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_NFS;
+                       return (new);
+               }
+               break;
+#ifdef MOUNT_PC
+       case 'p':
+               if (!strcmp(arg, "pc")) {
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_PC;
+                       return (new);
                }
                break;
                }
                break;
+#endif
        case 'r':
                if (!strcmp(arg, "rdonly")) {
        case 'r':
                if (!strcmp(arg, "rdonly")) {
-                       new->flags = MOUNT_NONE;
-                       new->m_flags = MNT_RDONLY;
-                       return(new);
+                       new->flags = F_MTFLAG;
+                       new->mt_data = MNT_RDONLY;
+                       return (new);
                }
                break;
        case 'u':
                if (!strcmp(arg, "ufs")) {
                }
                break;
        case 'u':
                if (!strcmp(arg, "ufs")) {
-                       new->flags = MOUNT_UFS;
-                       return(new);
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_UFS;
+                       return (new);
                }
                break;
        }
                }
                break;
        }
-       err("unknown file type %s", arg);
+       errx(1, "%s: unknown file type", arg);
        /* NOTREACHED */
 }
  
        /* NOTREACHED */
 }
  
@@ -444,11 +467,12 @@ c_fstype(arg)
  *     an equivalent of the getgrnam() function does not return a valid group
  *     name, gname is taken as a group ID.
  */
  *     an equivalent of the getgrnam() function does not return a valid group
  *     name, gname is taken as a group ID.
  */
+int
 f_group(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_group(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_gid == plan->g_data);
+       return (entry->fts_statp->st_gid == plan->g_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -465,13 +489,13 @@ c_group(gname)
        if (g == NULL) {
                gid = atoi(gname);
                if (gid == 0 && gname[0] != '0')
        if (g == NULL) {
                gid = atoi(gname);
                if (gid == 0 && gname[0] != '0')
-                       err("%s: %s", "-group", "no such group");
+                       errx(1, "-group: %s: no such group", gname);
        } else
                gid = g->gr_gid;
     
        new = palloc(N_GROUP, f_group);
        new->g_data = gid;
        } else
                gid = g->gr_gid;
     
        new = palloc(N_GROUP, f_group);
        new->g_data = gid;
-       return(new);
+       return (new);
 }
 
 /*
 }
 
 /*
@@ -479,11 +503,12 @@ c_group(gname)
  *
  *     True if the file has inode # n.
  */
  *
  *     True if the file has inode # n.
  */
+int
 f_inum(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_inum(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       COMPARE(entry->fts_statb.st_ino, plan->i_data);
+       COMPARE(entry->fts_statp->st_ino, plan->i_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -495,8 +520,8 @@ c_inum(arg)
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_INUM, f_inum);
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_INUM, f_inum);
-       new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL);
-       return(new);
+       new->i_data = find_parsenum(new, "-inum", arg, NULL);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -504,11 +529,12 @@ c_inum(arg)
  *
  *     True if the file has n links.
  */
  *
  *     True if the file has n links.
  */
+int
 f_links(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_links(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       COMPARE(entry->fts_statb.st_nlink, plan->l_data);
+       COMPARE(entry->fts_statp->st_nlink, plan->l_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -520,8 +546,8 @@ c_links(arg)
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_LINKS, f_links);
        ftsoptions &= ~FTS_NOSTAT;
     
        new = palloc(N_LINKS, f_links);
-       new->l_data = (nlink_t)find_parsenum(new, "-links", arg, (char *)NULL);
-       return(new);
+       new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -529,13 +555,13 @@ c_links(arg)
  *
  *     Always true - prints the current entry to stdout in "ls" format.
  */
  *
  *     Always true - prints the current entry to stdout in "ls" format.
  */
-/* ARGSUSED */
+int
 f_ls(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_ls(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb);
-       return(1);
+       printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
+       return (1);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -544,7 +570,38 @@ c_ls()
        ftsoptions &= ~FTS_NOSTAT;
        isoutput = 1;
     
        ftsoptions &= ~FTS_NOSTAT;
        isoutput = 1;
     
-       return(palloc(N_LS, f_ls));
+       return (palloc(N_LS, f_ls));
+}
+
+/*
+ * -mtime n functions --
+ *
+ *     True if the difference between the file modification time and the
+ *     current time is n 24 hour periods.
+ */
+int
+f_mtime(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       extern time_t now;
+
+       COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
+           SECSPERDAY, plan->t_data);
+}
+PLAN *
+c_mtime(arg)
+       char *arg;
+{
+       PLAN *new;
+
+       ftsoptions &= ~FTS_NOSTAT;
+
+       new = palloc(N_MTIME, f_mtime);
+       new->t_data = find_parsenum(new, "-mtime", arg, NULL);
+       TIME_CORRECT(new, N_MTIME);
+       return (new);
 }
 
 /*
 }
 
 /*
@@ -553,11 +610,12 @@ c_ls()
  *     True if the basename of the filename being examined
  *     matches pattern using Pattern Matching Notation S3.14
  */
  *     True if the basename of the filename being examined
  *     matches pattern using Pattern Matching Notation S3.14
  */
+int
 f_name(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_name(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return(!fnmatch(plan->c_data, entry->fts_name, 0));
+       return (!fnmatch(plan->c_data, entry->fts_name, 0));
 }
  
 PLAN *
 }
  
 PLAN *
@@ -568,7 +626,7 @@ c_name(pattern)
 
        new = palloc(N_NAME, f_name);
        new->c_data = pattern;
 
        new = palloc(N_NAME, f_name);
        new->c_data = pattern;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -578,11 +636,12 @@ c_name(pattern)
  *     then the modification time of the file named by the pathname
  *     file.
  */
  *     then the modification time of the file named by the pathname
  *     file.
  */
+int
 f_newer(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_newer(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_mtime > plan->t_data);
+       return (entry->fts_statp->st_mtime > plan->t_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -595,10 +654,10 @@ c_newer(filename)
        ftsoptions &= ~FTS_NOSTAT;
 
        if (stat(filename, &sb))
        ftsoptions &= ~FTS_NOSTAT;
 
        if (stat(filename, &sb))
-               err("%s: %s", filename, strerror(errno));
+               err(1, "%s", filename);
        new = palloc(N_NEWER, f_newer);
        new->t_data = sb.st_mtime;
        new = palloc(N_NEWER, f_newer);
        new->t_data = sb.st_mtime;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -607,14 +666,14 @@ c_newer(filename)
  *     True if file belongs to a user ID for which the equivalent
  *     of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
  */
  *     True if file belongs to a user ID for which the equivalent
  *     of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
  */
-/* ARGSUSED */
+int
 f_nogroup(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        char *group_from_gid();
 
 f_nogroup(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        char *group_from_gid();
 
-       return(group_from_gid(entry->fts_statb.st_gid, 1) ? 1 : 0);
+       return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -622,7 +681,7 @@ c_nogroup()
 {
        ftsoptions &= ~FTS_NOSTAT;
 
 {
        ftsoptions &= ~FTS_NOSTAT;
 
-       return(palloc(N_NOGROUP, f_nogroup));
+       return (palloc(N_NOGROUP, f_nogroup));
 }
  
 /*
 }
  
 /*
@@ -631,14 +690,14 @@ c_nogroup()
  *     True if file belongs to a user ID for which the equivalent
  *     of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
  */
  *     True if file belongs to a user ID for which the equivalent
  *     of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
  */
-/* ARGSUSED */
+int
 f_nouser(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        char *user_from_uid();
 
 f_nouser(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        char *user_from_uid();
 
-       return(user_from_uid(entry->fts_statb.st_uid, 1) ? 1 : 0);
+       return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -646,7 +705,32 @@ c_nouser()
 {
        ftsoptions &= ~FTS_NOSTAT;
 
 {
        ftsoptions &= ~FTS_NOSTAT;
 
-       return(palloc(N_NOUSER, f_nouser));
+       return (palloc(N_NOUSER, f_nouser));
+}
+/*
+ * -path functions --
+ *
+ *     True if the path of the filename being examined
+ *     matches pattern using Pattern Matching Notation S3.14
+ */
+int
+f_path(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       return (!fnmatch(plan->c_data, entry->fts_path, 0));
+}
+PLAN *
+c_path(pattern)
+       char *pattern;
+{
+       PLAN *new;
+
+       new = palloc(N_NAME, f_path);
+       new->c_data = pattern;
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -656,18 +740,19 @@ c_nouser()
  *     with a leading digit, it's treated as an octal mode, otherwise as a
  *     symbolic mode.
  */
  *     with a leading digit, it's treated as an octal mode, otherwise as a
  *     symbolic mode.
  */
+int
 f_perm(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        mode_t mode;
 
 f_perm(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        mode_t mode;
 
-       mode = entry->fts_statb.st_mode &
+       mode = entry->fts_statp->st_mode &
            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
-       if (plan->flags)
-               return((plan->m_data | mode) == mode);
+       if (plan->flags == F_ATLEAST)
+               return ((plan->m_data | mode) == mode);
        else
        else
-               return(mode == plan->m_data);
+               return (mode == plan->m_data);
        /* NOTREACHED */
 }
  
        /* NOTREACHED */
 }
  
@@ -683,15 +768,15 @@ c_perm(perm)
        new = palloc(N_PERM, f_perm);
 
        if (*perm == '-') {
        new = palloc(N_PERM, f_perm);
 
        if (*perm == '-') {
-               new->flags = 1;
+               new->flags = F_ATLEAST;
                ++perm;
        }
 
        if ((set = setmode(perm)) == NULL)
                ++perm;
        }
 
        if ((set = setmode(perm)) == NULL)
-               err("%s: %s", "-perm", "illegal mode string");
+               err(1, "-perm: %s: illegal mode string", perm);
 
        new->m_data = getmode(set, 0);
 
        new->m_data = getmode(set, 0);
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -700,13 +785,23 @@ c_perm(perm)
  *     Always true, causes the current pathame to be written to
  *     standard output.
  */
  *     Always true, causes the current pathame to be written to
  *     standard output.
  */
-/* ARGSUSED */
+int
 f_print(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_print(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       (void)printf("%s\n", entry->fts_path);
-       return(1);
+       if (plan->flags & F_PRINTF) {
+               printf(plan->c_data, entry->fts_path);
+       } else {
+               fputs(entry->fts_path, stdout);
+       }
+
+       if (plan->flags & F_PRINT0) {
+               fputc('\0', stdout);
+       } else {
+               fputc('\n', stdout);
+       }
+       return (1);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -714,15 +809,36 @@ c_print()
 {
        isoutput = 1;
 
 {
        isoutput = 1;
 
-       return(palloc(N_PRINT, f_print));
+       return (palloc(N_PRINT, f_print));
+}
+
+PLAN *
+c_print0()
+{
+       PLAN *rv = palloc(N_PRINT, f_print);
+       rv->flags = F_PRINT0;
+       isoutput = 1;
+       return rv;
+}
+
+PLAN *
+c_printf(arg)
+       char *arg;
+{
+       PLAN *rv = palloc(N_PRINT, f_print);
+       rv->flags = F_PRINTF;
+       rv->c_data = arg;
+       isoutput = 1;
+       return rv;
 }
 }
+
  
 /*
  * -prune functions --
  *
  *     Prune a portion of the hierarchy.
  */
  
 /*
  * -prune functions --
  *
  *     Prune a portion of the hierarchy.
  */
-/* ARGSUSED */
+int
 f_prune(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 f_prune(plan, entry)
        PLAN *plan;
        FTSENT *entry;
@@ -730,14 +846,14 @@ f_prune(plan, entry)
        extern FTS *tree;
 
        if (fts_set(tree, entry, FTS_SKIP))
        extern FTS *tree;
 
        if (fts_set(tree, entry, FTS_SKIP))
-               err("%s: %s", entry->fts_path, strerror(errno));
-       return(1);
+               err(1, "%s", entry->fts_path);
+       return (1);
 }
  
 PLAN *
 c_prune()
 {
 }
  
 PLAN *
 c_prune()
 {
-       return(palloc(N_PRUNE, f_prune));
+       return (palloc(N_PRUNE, f_prune));
 }
  
 /*
 }
  
 /*
@@ -750,14 +866,15 @@ c_prune()
 #define        FIND_SIZE       512
 static int divsize = 1;
 
 #define        FIND_SIZE       512
 static int divsize = 1;
 
+int
 f_size(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        off_t size;
 
 f_size(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        off_t size;
 
-       size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) /
-           FIND_SIZE : entry->fts_statb.st_size;
+       size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
+           FIND_SIZE : entry->fts_statp->st_size;
        COMPARE(size, plan->o_data);
 }
  
        COMPARE(size, plan->o_data);
 }
  
@@ -771,10 +888,11 @@ c_size(arg)
        ftsoptions &= ~FTS_NOSTAT;
 
        new = palloc(N_SIZE, f_size);
        ftsoptions &= ~FTS_NOSTAT;
 
        new = palloc(N_SIZE, f_size);
+       endch = 'c';
        new->o_data = find_parsenum(new, "-size", arg, &endch);
        if (endch == 'c')
                divsize = 0;
        new->o_data = find_parsenum(new, "-size", arg, &endch);
        if (endch == 'c')
                divsize = 0;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -784,11 +902,12 @@ c_size(arg)
  *     block special file, character special file, directory, FIFO, or
  *     regular file, respectively.
  */
  *     block special file, character special file, directory, FIFO, or
  *     regular file, respectively.
  */
+int
 f_type(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_type(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return((entry->fts_statb.st_mode & S_IFMT) == plan->m_data);
+       return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -823,12 +942,12 @@ c_type(typestring)
                mask = S_IFSOCK;
                break;
        default:
                mask = S_IFSOCK;
                break;
        default:
-               err("%s: %s", "-type", "unknown type");
+               errx(1, "-type: %s: unknown type", typestring);
        }
     
        new = palloc(N_TYPE, f_type);
        new->m_data = mask;
        }
     
        new = palloc(N_TYPE, f_type);
        new->m_data = mask;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -838,11 +957,12 @@ c_type(typestring)
  *     an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
  *     return a valid user name, uname is taken as a user ID.
  */
  *     an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
  *     return a valid user name, uname is taken as a user ID.
  */
+int
 f_user(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
 f_user(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_uid == plan->u_data);
+       return (entry->fts_statp->st_uid == plan->u_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -859,13 +979,13 @@ c_user(username)
        if (p == NULL) {
                uid = atoi(username);
                if (uid == 0 && username[0] != '0')
        if (p == NULL) {
                uid = atoi(username);
                if (uid == 0 && username[0] != '0')
-                       err("%s: %s", "-user", "no such user");
+                       errx(1, "-user: %s: no such user", username);
        } else
                uid = p->pw_uid;
 
        new = palloc(N_USER, f_user);
        new->u_data = uid;
        } else
                uid = p->pw_uid;
 
        new = palloc(N_USER, f_user);
        new->u_data = uid;
-       return(new);
+       return (new);
 }
  
 /*
 }
  
 /*
@@ -879,7 +999,7 @@ c_xdev()
 {
        ftsoptions |= FTS_XDEV;
 
 {
        ftsoptions |= FTS_XDEV;
 
-       return(palloc(N_XDEV, f_always_true));
+       return (palloc(N_XDEV, f_always_true));
 }
 
 /*
 }
 
 /*
@@ -887,6 +1007,7 @@ c_xdev()
  *
  *     True if expression is true.
  */
  *
  *     True if expression is true.
  */
+int
 f_expr(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 f_expr(plan, entry)
        PLAN *plan;
        FTSENT *entry;
@@ -896,7 +1017,7 @@ f_expr(plan, entry)
 
        for (p = plan->p_data[0];
            p && (state = (p->eval)(p, entry)); p = p->next);
 
        for (p = plan->p_data[0];
            p && (state = (p->eval)(p, entry)); p = p->next);
-       return(state);
+       return (state);
 }
  
 /*
 }
  
 /*
@@ -907,49 +1028,21 @@ f_expr(plan, entry)
 PLAN *
 c_openparen()
 {
 PLAN *
 c_openparen()
 {
-       return(palloc(N_OPENPAREN, (int (*)())-1));
+       return (palloc(N_OPENPAREN, (int (*)())-1));
 }
  
 PLAN *
 c_closeparen()
 {
 }
  
 PLAN *
 c_closeparen()
 {
-       return(palloc(N_CLOSEPAREN, (int (*)())-1));
+       return (palloc(N_CLOSEPAREN, (int (*)())-1));
 }
  
 }
  
-/*
- * -mtime n functions --
- *
- *     True if the difference between the file modification time and the
- *     current time is n 24 hour periods.
- */
-f_mtime(plan, entry)
-       PLAN *plan;
-       FTSENT *entry;
-{
-       extern time_t now;
-
-       COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) /
-           SECSPERDAY, plan->t_data);
-}
-PLAN *
-c_mtime(arg)
-       char *arg;
-{
-       PLAN *new;
-
-       ftsoptions &= ~FTS_NOSTAT;
-
-       new = palloc(N_MTIME, f_mtime);
-       new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
-       return(new);
-}
-
 /*
  * ! expression functions --
  *
  *     Negation of a primary; the unary NOT operator.
  */
 /*
  * ! expression functions --
  *
  *     Negation of a primary; the unary NOT operator.
  */
+int
 f_not(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 f_not(plan, entry)
        PLAN *plan;
        FTSENT *entry;
@@ -959,13 +1052,13 @@ f_not(plan, entry)
 
        for (p = plan->p_data[0];
            p && (state = (p->eval)(p, entry)); p = p->next);
 
        for (p = plan->p_data[0];
            p && (state = (p->eval)(p, entry)); p = p->next);
-       return(!state);
+       return (!state);
 }
  
 PLAN *
 c_not()
 {
 }
  
 PLAN *
 c_not()
 {
-       return(palloc(N_NOT, f_not));
+       return (palloc(N_NOT, f_not));
 }
  
 /*
 }
  
 /*
@@ -974,6 +1067,7 @@ c_not()
  *     Alternation of primaries; the OR operator.  The second expression is
  * not evaluated if the first expression is true.
  */
  *     Alternation of primaries; the OR operator.  The second expression is
  * not evaluated if the first expression is true.
  */
+int
 f_or(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 f_or(plan, entry)
        PLAN *plan;
        FTSENT *entry;
@@ -985,23 +1079,23 @@ f_or(plan, entry)
            p && (state = (p->eval)(p, entry)); p = p->next);
 
        if (state)
            p && (state = (p->eval)(p, entry)); p = p->next);
 
        if (state)
-               return(1);
+               return (1);
 
        for (p = plan->p_data[1];
            p && (state = (p->eval)(p, entry)); p = p->next);
 
        for (p = plan->p_data[1];
            p && (state = (p->eval)(p, entry)); p = p->next);
-       return(state);
+       return (state);
 }
 
 PLAN *
 c_or()
 {
 }
 
 PLAN *
 c_or()
 {
-       return(palloc(N_OR, f_or));
+       return (palloc(N_OR, f_or));
 }
 
 static PLAN *
 palloc(t, f)
        enum ntype t;
 }
 
 static PLAN *
 palloc(t, f)
        enum ntype t;
-       int (*f)();
+       int (*f) __P((PLAN *, FTSENT *));
 {
        PLAN *new;
 
 {
        PLAN *new;
 
@@ -1010,8 +1104,8 @@ palloc(t, f)
                new->eval = f;
                new->flags = 0;
                new->next = NULL;
                new->eval = f;
                new->flags = 0;
                new->next = NULL;
-               return(new);
+               return (new);
        }
        }
-       err("%s", strerror(errno));
+       err(1, NULL);
        /* NOTREACHED */
 }
        /* NOTREACHED */
 }