They add the following commands:

-anewer
   -cnewer
   -mnewer
   -okdir
   -newer[acm][acmt]

 With it, you can form queries like

     find . -newerct '1 minute ago' -print

 As an extra bonus, the program is ANSI-fied - the original version
 relies on some obscure features of K&R C.

(This PR was submitted in 1999, and the submittor has kept the patch
updated ever since, hats off for him guys, and how about you close a PR ??)

PR:		9374
Submitted by:	Martin Birgmeier <Martin.Birgmeier@aon.at>
This commit is contained in:
Poul-Henning Kamp 2001-05-03 18:05:35 +00:00
parent 96fc25ff5e
commit ea92232a82
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76250
9 changed files with 914 additions and 1048 deletions

View File

@ -3,6 +3,9 @@
CFLAGS+= -Wall
PROG= find
SRCS= find.c function.c ls.c main.c misc.c operator.c option.c
SRCS= find.c function.c ls.c main.c misc.c operator.c option.c getdate.y
CLEANFILES+= getdate.c y.tab.h
CFLAGS+= -I${.CURDIR}/../../gnu/usr.bin/cvs/lib -DHAVE_CONFIG_H
.PATH: ${.CURDIR}/../../contrib/cvs/lib
.include <bsd.prog.mk>

View File

@ -47,50 +47,68 @@ PLAN *paren_squish __P((PLAN *));
struct stat;
void printlong __P((char *, char *, struct stat *));
int queryuser __P((char **));
OPTION *option __P((char *));
PLAN *c_amin __P((char *));
PLAN *c_atime __P((char *));
PLAN *c_cmin __P((char *));
PLAN *c_ctime __P((char *));
PLAN *c_delete __P((void));
PLAN *c_depth __P((void));
PLAN *c_empty __P((void));
PLAN *c_exec __P((char ***, int));
PLAN *c_flags __P((char *));
PLAN *c_execdir __P((char ***));
PLAN *c_follow __P((void));
creat_f c_Xmin;
creat_f c_Xtime;
creat_f c_and;
creat_f c_delete;
creat_f c_depth;
creat_f c_empty;
creat_f c_exec;
creat_f c_flags;
creat_f c_follow;
#if !defined(__NetBSD__)
PLAN *c_fstype __P((char *));
creat_f c_fstype;
#endif
PLAN *c_group __P((char *));
PLAN *c_iname __P((char *));
PLAN *c_inum __P((char *));
PLAN *c_ipath __P((char *));
PLAN *c_iregex __P((char *));
PLAN *c_links __P((char *));
PLAN *c_ls __P((void));
PLAN *c_name __P((char *));
PLAN *c_newer __P((char *));
PLAN *c_nogroup __P((void));
PLAN *c_nouser __P((void));
PLAN *c_path __P((char *));
PLAN *c_perm __P((char *));
PLAN *c_print __P((void));
PLAN *c_print0 __P((void));
PLAN *c_prune __P((void));
PLAN *c_regex __P((char *));
PLAN *c_size __P((char *));
PLAN *c_type __P((char *));
PLAN *c_user __P((char *));
PLAN *c_xdev __P((void));
PLAN *c_openparen __P((void));
PLAN *c_closeparen __P((void));
PLAN *c_maxdepth __P((char *));
PLAN *c_mindepth __P((char *));
PLAN *c_mmin __P((char *));
PLAN *c_mtime __P((char *));
PLAN *c_not __P((void));
PLAN *c_or __P((void));
creat_f c_group;
creat_f c_inum;
creat_f c_links;
creat_f c_ls;
creat_f c_mXXdepth;
creat_f c_name;
creat_f c_newer;
creat_f c_nogroup;
creat_f c_nouser;
creat_f c_perm;
creat_f c_print;
creat_f c_regex;
creat_f c_simple;
creat_f c_size;
creat_f c_type;
creat_f c_user;
creat_f c_xdev;
exec_f f_Xmin;
exec_f f_Xtime;
exec_f f_always_true;
exec_f f_closeparen;
exec_f f_delete;
exec_f f_empty;
exec_f f_exec;
exec_f f_expr;
exec_f f_flags;
exec_f f_fstype;
exec_f f_group;
exec_f f_inum;
exec_f f_links;
exec_f f_ls;
exec_f f_name;
exec_f f_newer;
exec_f f_nogroup;
exec_f f_not;
exec_f f_nouser;
exec_f f_openparen;
exec_f f_or;
exec_f f_path;
exec_f f_perm;
exec_f f_print;
exec_f f_print0;
exec_f f_prune;
exec_f f_regex;
exec_f f_size;
exec_f f_type;
exec_f f_user;
extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs;
extern int mindepth, maxdepth;

View File

@ -160,6 +160,9 @@ True if the difference between the file last access time and the time
was started, rounded up to the next full minute, is
.Ar n
minutes.
.It Ic -anewer Ar file
Same as
.Ic -neweram .
.It Ic -atime Ar n
True if the difference between the file last access time and the time
.Nm
@ -173,6 +176,9 @@ information and the time
was started, rounded up to the next full minute, is
.Ar n
minutes.
.It Ic -cnewer Ar file
Same as
.Ic -newercm .
.It Ic -ctime Ar n
True if the difference between the time of last change of file status
information and the time
@ -256,6 +262,9 @@ will be displayed instead of the size in bytes.
If the file is a symbolic link, the pathname of the linked\-to file will be
displayed preceded by ``\->''.
The format is identical to that produced by ``ls \-dgils''.
.It Ic -mnewer Ar file
Same as
.Ic -newer .
.It Ic -maxdepth Ar n
True if the depth of the current file into the tree is less than or equal to
.Ar n .
@ -287,6 +296,14 @@ If the response is other than ``y'' the command is not executed and the
value of the
.Ar \&ok
expression is false.
.It Ic \&-okdir Ar utility Op argument ... ;
The
.Ic \&-okdir
primary is identical to the
.Ic -execdir
primary with the same exception as described for the
.Ic \&-ok
primary.
.It Ic -name Ar pattern
True if the last component of the pathname being examined matches
.Ar pattern .
@ -312,6 +329,46 @@ but the match is case insensitive.
.It Ic -newer Ar file
True if the current file has a more recent last modification time than
.Ar file .
.It Ic -newerXY Ar file
True if the current file has a more recent last access time (
.Ic X
=
.Ic a
), change time (
.Ic X
=
.Ic c
), or modification time (
.Ic X
=
.Ic m
) than the last access time (
.Ic Y
=
.Ic a
), change time (
.Ic Y
=
.Ic c
), or modification time (
.Ic Y
=
.Ic m
) of
.Ar file .
In addition, if
.Ic Y
=
.Ic t ,
then
.Ar file
is instead interpreted as a direct date specification of the form
understood by
.Xr cvs 1 .
Note that
.Ic -newermm
is equivalent to
.Ic -newer .
.It Ic -nouser
True if the file belongs to an unknown user.
.It Ic -nogroup
@ -512,10 +569,14 @@ and owned by ``wnj''.
.It Li "find / \e( -newer ttt -or -user wnj \e) -print"
Print out a list of all the files that are either owned by ``wnj'' or
that are newer than ``ttt''.
.It Li "find . -newerct '1 minute ago' -print"
Print out a list of all the files whose inode change time is more
recent than the current time minus one minute.
.El
.Sh SEE ALSO
.Xr chflags 1 ,
.Xr chmod 1 ,
.Xr cvs 1 ,
.Xr locate 1 ,
.Xr whereis 1 ,
.Xr which 1 ,

View File

@ -116,17 +116,24 @@ find_formplan(argv)
* necessary, and add a -print node on the end.
*/
if (!isoutput) {
OPTION *p;
char **argv = 0;
if (plan == NULL) {
new = c_print();
p = option("-print");
new = (p->create)(p, &argv);
tail = plan = new;
} else {
new = c_openparen();
p = option("(");
new = (p->create)(p, &argv);
new->next = plan;
plan = new;
new = c_closeparen();
p = option(")");
new = (p->create)(p, &argv);
tail->next = new;
tail = new;
new = c_print();
p = option("-print");
new = (p->create)(p, &argv);
tail->next = new;
tail = new;
}
@ -220,7 +227,7 @@ find_execute(plan, paths)
* false or all have been executed. This is where we do all
* the work specified by the user on the command line.
*/
for (p = plan; p && (p->eval)(p, entry); p = p->next);
for (p = plan; p && (p->execute)(p, entry); p = p->next);
if (maxdepth != -1 && entry->fts_level >= maxdepth) {
if (fts_set(tree, entry, FTS_SKIP))

View File

@ -39,37 +39,46 @@
#include <regex.h>
/* node type */
enum ntype {
N_AND = 1, /* must start > 0 */
N_AMIN, N_ATIME, N_CLOSEPAREN, N_CMIN, N_CTIME, N_DEPTH,
N_EMPTY, N_EXEC, N_EXECDIR, N_EXPR, N_FLAGS,
N_FOLLOW, N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, N_MMIN,
N_MTIME, N_NAME, N_INAME, N_PATH, N_IPATH, N_REGEX, N_IREGEX,
N_NEWER, N_NOGROUP, N_NOT, N_NOUSER, N_OK, N_OPENPAREN, N_OR,
N_PERM, N_PRINT, N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
N_PRINT0, N_DELETE, N_MAXDEPTH, N_MINDEPTH
};
/* forward declarations */
struct _plandata;
struct _option;
/* execute function */
typedef int exec_f __P((struct _plandata *, FTSENT *));
/* create function */
typedef struct _plandata *creat_f(struct _option *, char ***);
/* function modifiers */
#define F_NEEDOK 0x00000001 /* -ok vs. -exec */
#define F_EXECDIR 0x00000002 /* -execdir vs. -exec */
#define F_TIME_A 0x00000004 /* one of -atime, -anewer, -newera* */
#define F_TIME_C 0x00000008 /* one of -ctime, -cnewer, -newerc* */
#define F_TIME2_A 0x00000010 /* one of -newer?a */
#define F_TIME2_C 0x00000020 /* one of -newer?c */
#define F_TIME2_T 0x00000040 /* one of -newer?t */
#define F_MAXDEPTH F_TIME_A /* maxdepth vs. mindepth */
/* command line function modifiers */
#define F_EQUAL 0x00000000 /* [acm]min [acm]time inum links size */
#define F_LESSTHAN 0x00000100
#define F_GREATER 0x00000200
#define F_ELG_MASK 0x00000300
#define F_ATLEAST 0x00000400 /* flags perm */
#define F_ANY 0x00000800 /* perm */
#define F_MTMASK 0x00003000
#define F_MTFLAG 0x00000000 /* fstype */
#define F_MTTYPE 0x00001000
#define F_MTUNKNOWN 0x00002000
#define F_IGNCASE 0x00010000 /* iname ipath iregex */
/* node definition */
typedef struct _plandata {
struct _plandata *next; /* next node */
int (*eval) /* node evaluation function */
__P((struct _plandata *, FTSENT *));
#define F_EQUAL 1 /* [acm]time inum links size */
#define F_LESSTHAN 2
#define F_GREATER 3
#define F_NEEDOK 1 /* exec ok */
#define F_MTFLAG 1 /* fstype */
#define F_MTTYPE 2
#define F_ATLEAST 1 /* perm */
#define F_ANY 2 /* perm */
int flags; /* private flags */
enum ntype type; /* plan node type */
struct _plandata *next; /* next node */
exec_f *execute; /* node evaluation function */
int flags; /* private flags */
union {
gid_t _g_data; /* gid */
ino_t _i_data; /* inode */
mode_t _m_data; /* mode mask */
gid_t _g_data; /* gid */
ino_t _i_data; /* inode */
mode_t _m_data; /* mode mask */
struct {
u_long _f_flags;
u_long _f_mask;
@ -110,12 +119,8 @@ typedef struct _plandata {
typedef struct _option {
char *name; /* option name */
enum ntype token; /* token type */
PLAN *(*create)(); /* create function: DON'T PROTOTYPE! */
#define O_NONE 0x01 /* no call required */
#define O_ZERO 0x02 /* pass: nothing */
#define O_ARGV 0x04 /* pass: argv, increment argv */
#define O_ARGVP 0x08 /* pass: *argv, N_OK || N_EXEC || N_EXECDIR */
creat_f *create; /* create function */
exec_f *execute; /* execute function */
int flags;
} OPTION;

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,7 @@ printlong(name, accpath, sb)
{
char modep[15], *user_from_uid(), *group_from_gid();
(void)printf("%6lu %4qd ", (u_long)sb->st_ino, sb->st_blocks);
(void)printf("%6lu %4qd ", (u_long) sb->st_ino, sb->st_blocks);
(void)strmode(sb->st_mode, modep);
(void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, UT_NAMESIZE,
user_from_uid(sb->st_uid, 0), UT_NAMESIZE,

View File

@ -72,7 +72,7 @@ yanknode(planp)
* yankexpr --
* Removes one expression from the plan. This is used mainly by
* paren_squish. In comments below, an expression is either a
* simple node or a N_EXPR node containing a list of simple nodes.
* simple node or a f_expr node containing a list of simple nodes.
*/
static PLAN *
yankexpr(planp)
@ -82,7 +82,6 @@ yankexpr(planp)
PLAN *node; /* pointer to returned node or expression */
PLAN *tail; /* pointer to tail of subplan */
PLAN *subplan; /* pointer to head of ( ) expression */
int f_expr();
/* first pull the top node from the plan */
if ((node = yanknode(planp)) == NULL)
@ -94,23 +93,22 @@ yankexpr(planp)
* just return it and unwind our recursion; all other nodes are
* complete expressions, so just return them.
*/
if (node->type == N_OPENPAREN)
if (node->execute == f_openparen)
for (tail = subplan = NULL;;) {
if ((next = yankexpr(planp)) == NULL)
err(1, "(: missing closing ')'");
/*
* If we find a closing ')' we store the collected
* subplan in our '(' node and convert the node to
* a N_EXPR. The ')' we found is ignored. Otherwise,
* a f_expr. The ')' we found is ignored. Otherwise,
* we just continue to add whatever we get to our
* subplan.
*/
if (next->type == N_CLOSEPAREN) {
if (next->execute == f_closeparen) {
if (subplan == NULL)
errx(1, "(): empty inner expression");
node->p_data[0] = subplan;
node->type = N_EXPR;
node->eval = f_expr;
node->execute = f_expr;
break;
} else {
if (subplan == NULL)
@ -141,14 +139,14 @@ paren_squish(plan)
/*
* the basic idea is to have yankexpr do all our work and just
* collect it's results together.
* collect its results together.
*/
while ((expr = yankexpr(&plan)) != NULL) {
/*
* if we find an unclaimed ')' it means there is a missing
* '(' someplace.
*/
if (expr->type == N_CLOSEPAREN)
if (expr->execute == f_closeparen)
errx(1, "): no beginning '('");
/* add the expression to our result plan */
@ -172,18 +170,18 @@ not_squish(plan)
PLAN *plan; /* plan to process */
{
register PLAN *next; /* next node being processed */
register PLAN *node; /* temporary node used in N_NOT processing */
register PLAN *node; /* temporary node used in f_not processing */
register PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
tail = result = next = NULL;
tail = result = NULL;
while ((next = yanknode(&plan)) != NULL) {
while (next = yanknode(&plan)) {
/*
* if we encounter a ( expression ) then look for nots in
* the expr subplan.
*/
if (next->type == N_EXPR)
if (next->execute == f_expr)
next->p_data[0] = not_squish(next->p_data[0]);
/*
@ -191,23 +189,23 @@ not_squish(plan)
* it in the not's subplan. As an optimization we compress
* several not's to zero or one not.
*/
if (next->type == N_NOT) {
if (next->execute == f_not) {
int notlevel = 1;
node = yanknode(&plan);
while (node != NULL && node->type == N_NOT) {
while (node != NULL && node->execute == f_not) {
++notlevel;
node = yanknode(&plan);
}
if (node == NULL)
errx(1, "!: no following expression");
if (node->type == N_OR)
if (node->execute == f_or)
errx(1, "!: nothing between ! and -o");
/*
* If we encounter ! ( expr ) then look for nots in
* the expr subplan.
*/
if (node->type == N_EXPR)
if (node->execute == f_expr)
node->p_data[0] = not_squish(node->p_data[0]);
if (notlevel % 2 != 1)
next = node;
@ -246,11 +244,11 @@ or_squish(plan)
* if we encounter a ( expression ) then look for or's in
* the expr subplan.
*/
if (next->type == N_EXPR)
if (next->execute == f_expr)
next->p_data[0] = or_squish(next->p_data[0]);
/* if we encounter a not then look for or's in the subplan */
if (next->type == N_NOT)
if (next->execute == f_not)
next->p_data[0] = or_squish(next->p_data[0]);
/*
@ -258,7 +256,7 @@ or_squish(plan)
* or's first subplan and then recursively collect the
* remaining stuff into the second subplan and return the or.
*/
if (next->type == N_OR) {
if (next->execute == f_or) {
if (result == NULL)
errx(1, "-o: no expression before -o");
next->p_data[0] = result;

View File

@ -54,62 +54,75 @@ static const char rcsid[] =
#include "find.h"
static OPTION *option __P((char *));
/* NB: the following table must be sorted lexically. */
static OPTION const options[] = {
{ "!", N_NOT, c_not, O_ZERO },
{ "(", N_OPENPAREN, c_openparen, O_ZERO },
{ ")", N_CLOSEPAREN, c_closeparen, O_ZERO },
{ "-a", N_AND, NULL, O_NONE },
{ "-amin", N_AMIN, c_amin, O_ARGV },
{ "-and", N_AND, NULL, O_NONE },
{ "-atime", N_ATIME, c_atime, O_ARGV },
{ "-cmin", N_CMIN, c_cmin, O_ARGV },
{ "-ctime", N_CTIME, c_ctime, O_ARGV },
{ "-delete", N_DELETE, c_delete, O_ZERO },
{ "-depth", N_DEPTH, c_depth, O_ZERO },
{ "-empty", N_EMPTY, c_empty, O_ZERO },
{ "-exec", N_EXEC, c_exec, O_ARGVP },
{ "-execdir", N_EXECDIR, c_execdir, O_ARGVP },
{ "-flags", N_FLAGS, c_flags, O_ARGV },
{ "-follow", N_FOLLOW, c_follow, O_ZERO },
{ "!", c_simple, f_not, 0 },
{ "(", c_simple, f_openparen, 0 },
{ ")", c_simple, f_closeparen, 0 },
{ "-a", c_and, NULL, 0 },
{ "-amin", c_Xmin, f_Xmin, F_TIME_A },
{ "-and", c_and, NULL, 0 },
{ "-anewer", c_newer, f_newer, F_TIME_A },
{ "-atime", c_Xtime, f_Xtime, F_TIME_A },
{ "-cmin", c_Xmin, f_Xmin, F_TIME_C },
{ "-cnewer", c_newer, f_newer, F_TIME_C },
{ "-ctime", c_Xtime, f_Xtime, F_TIME_C },
{ "-delete", c_delete, f_delete, 0 },
{ "-depth", c_depth, f_always_true, 0 },
{ "-empty", c_empty, f_empty, 0 },
{ "-exec", c_exec, f_exec, 0 },
{ "-execdir", c_exec, f_exec, F_EXECDIR },
{ "-flags", c_flags, f_flags, 0 },
{ "-follow", c_follow, f_always_true, 0 },
/*
* NetBSD doesn't provide a getvfsbyname(), so this option
* is not available if using a NetBSD kernel.
*/
#if !defined(__NetBSD__)
{ "-fstype", N_FSTYPE, c_fstype, O_ARGV },
{ "-fstype", c_fstype, f_fstype, 0 },
#endif
{ "-group", N_GROUP, c_group, O_ARGV },
{ "-iname", N_INAME, c_iname, O_ARGV },
{ "-inum", N_INUM, c_inum, O_ARGV },
{ "-ipath", N_IPATH, c_ipath, O_ARGV },
{ "-iregex", N_IREGEX, c_iregex, O_ARGV },
{ "-links", N_LINKS, c_links, O_ARGV },
{ "-ls", N_LS, c_ls, O_ZERO },
{ "-maxdepth", N_MAXDEPTH, c_maxdepth, O_ARGV },
{ "-mindepth", N_MINDEPTH, c_mindepth, O_ARGV },
{ "-mmin", N_MMIN, c_mmin, O_ARGV },
{ "-mtime", N_MTIME, c_mtime, O_ARGV },
{ "-name", N_NAME, c_name, O_ARGV },
{ "-newer", N_NEWER, c_newer, O_ARGV },
{ "-nogroup", N_NOGROUP, c_nogroup, O_ZERO },
{ "-nouser", N_NOUSER, c_nouser, O_ZERO },
{ "-o", N_OR, c_or, O_ZERO },
{ "-ok", N_OK, c_exec, O_ARGVP },
{ "-or", N_OR, c_or, O_ZERO },
{ "-path", N_PATH, c_path, O_ARGV },
{ "-perm", N_PERM, c_perm, O_ARGV },
{ "-print", N_PRINT, c_print, O_ZERO },
{ "-print0", N_PRINT0, c_print0, O_ZERO },
{ "-prune", N_PRUNE, c_prune, O_ZERO },
{ "-regex", N_REGEX, c_regex, O_ARGV },
{ "-size", N_SIZE, c_size, O_ARGV },
{ "-type", N_TYPE, c_type, O_ARGV },
{ "-user", N_USER, c_user, O_ARGV },
{ "-xdev", N_XDEV, c_xdev, O_ZERO },
{ "-group", c_group, f_group, 0 },
{ "-iname", c_name, f_name, F_IGNCASE },
{ "-inum", c_inum, f_inum, 0 },
{ "-ipath", c_name, f_path, F_IGNCASE },
{ "-iregex", c_regex, f_regex, F_IGNCASE },
{ "-links", c_links, f_links, 0 },
{ "-ls", c_ls, f_ls, 0 },
{ "-maxdepth", c_mXXdepth, f_always_true, F_MAXDEPTH },
{ "-mindepth", c_mXXdepth, f_always_true, 0 },
{ "-mmin", c_Xmin, f_Xmin, 0 },
{ "-mnewer", c_newer, f_newer, 0 },
{ "-mtime", c_Xtime, f_Xtime, 0 },
{ "-name", c_name, f_name, 0 },
{ "-newer", c_newer, f_newer, 0 },
{ "-neweraa", c_newer, f_newer, F_TIME_A | F_TIME2_A },
{ "-newerac", c_newer, f_newer, F_TIME_A | F_TIME2_C },
{ "-neweram", c_newer, f_newer, F_TIME_A },
{ "-newerat", c_newer, f_newer, F_TIME_A | F_TIME2_T },
{ "-newerca", c_newer, f_newer, F_TIME_C | F_TIME2_A },
{ "-newercc", c_newer, f_newer, F_TIME_C | F_TIME2_C },
{ "-newercm", c_newer, f_newer, F_TIME_C },
{ "-newerct", c_newer, f_newer, F_TIME_C | F_TIME2_T },
{ "-newerma", c_newer, f_newer, F_TIME2_A },
{ "-newermc", c_newer, f_newer, F_TIME2_C },
{ "-newermm", c_newer, f_newer, 0 },
{ "-newermt", c_newer, f_newer, F_TIME2_T },
{ "-nogroup", c_nogroup, f_nogroup, 0 },
{ "-nouser", c_nouser, f_nouser, 0 },
{ "-o", c_simple, f_or, 0 },
{ "-ok", c_exec, f_exec, F_NEEDOK },
{ "-okdir", c_exec, f_exec, F_NEEDOK | F_EXECDIR },
{ "-or", c_simple, f_or, 0 },
{ "-path", c_name, f_path, 0 },
{ "-perm", c_perm, f_perm, 0 },
{ "-print", c_print, f_print, 0 },
{ "-print0", c_print, f_print0, 0 },
{ "-prune", c_simple, f_prune, 0 },
{ "-regex", c_regex, f_regex, 0 },
{ "-size", c_size, f_size, 0 },
{ "-type", c_type, f_type, 0 },
{ "-user", c_user, f_user, 0 },
{ "-xdev", c_xdev, f_always_true, 0 },
};
/*
@ -133,30 +146,13 @@ find_create(argvp)
if ((p = option(*argv)) == NULL)
errx(1, "%s: unknown option", *argv);
++argv;
if (p->flags & (O_ARGV|O_ARGVP) && !*argv)
errx(1, "%s: requires additional arguments", *--argv);
switch(p->flags) {
case O_NONE:
new = NULL;
break;
case O_ZERO:
new = (p->create)();
break;
case O_ARGV:
new = (p->create)(*argv++);
break;
case O_ARGVP:
new = (p->create)(&argv, p->token == N_OK);
break;
default:
abort();
}
new = (p->create)(p, &argv);
*argvp = argv;
return (new);
}
static OPTION *
OPTION *
option(name)
char *name;
{