1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 #include "../gnulib/lib/modechange.h"
27 #include "../gnulib/lib/xstrtol.h"
28 #include "../gnulib/lib/xalloc.h"
33 # define _(Text) gettext (Text)
38 # define N_(String) gettext_noop (String)
40 /* See locate.c for explanation as to why not use (String) */
41 # define N_(String) String
44 #if !defined (isascii) || defined (STDC_HEADERS)
51 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
52 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
61 static boolean parse_amin
PARAMS((char *argv
[], int *arg_ptr
));
62 static boolean parse_and
PARAMS((char *argv
[], int *arg_ptr
));
63 static boolean parse_anewer
PARAMS((char *argv
[], int *arg_ptr
));
64 static boolean parse_atime
PARAMS((char *argv
[], int *arg_ptr
));
65 boolean parse_close
PARAMS((char *argv
[], int *arg_ptr
));
66 static boolean parse_cmin
PARAMS((char *argv
[], int *arg_ptr
));
67 static boolean parse_cnewer
PARAMS((char *argv
[], int *arg_ptr
));
68 static boolean parse_comma
PARAMS((char *argv
[], int *arg_ptr
));
69 static boolean parse_ctime
PARAMS((char *argv
[], int *arg_ptr
));
70 static boolean parse_daystart
PARAMS((char *argv
[], int *arg_ptr
));
71 static boolean parse_delete
PARAMS((char *argv
[], int *arg_ptr
));
72 static boolean parse_d
PARAMS((char *argv
[], int *arg_ptr
));
73 static boolean parse_depth
PARAMS((char *argv
[], int *arg_ptr
));
74 static boolean parse_empty
PARAMS((char *argv
[], int *arg_ptr
));
75 static boolean parse_exec
PARAMS((char *argv
[], int *arg_ptr
));
76 static boolean parse_false
PARAMS((char *argv
[], int *arg_ptr
));
77 static boolean parse_fls
PARAMS((char *argv
[], int *arg_ptr
));
78 static boolean parse_fprintf
PARAMS((char *argv
[], int *arg_ptr
));
79 static boolean parse_follow
PARAMS((char *argv
[], int *arg_ptr
));
80 static boolean parse_fprint
PARAMS((char *argv
[], int *arg_ptr
));
81 static boolean parse_fprint0
PARAMS((char *argv
[], int *arg_ptr
));
82 static boolean parse_fstype
PARAMS((char *argv
[], int *arg_ptr
));
83 static boolean parse_gid
PARAMS((char *argv
[], int *arg_ptr
));
84 static boolean parse_group
PARAMS((char *argv
[], int *arg_ptr
));
85 static boolean parse_help
PARAMS((char *argv
[], int *arg_ptr
));
86 static boolean parse_ilname
PARAMS((char *argv
[], int *arg_ptr
));
87 static boolean parse_iname
PARAMS((char *argv
[], int *arg_ptr
));
88 static boolean parse_inum
PARAMS((char *argv
[], int *arg_ptr
));
89 static boolean parse_ipath
PARAMS((char *argv
[], int *arg_ptr
));
90 static boolean parse_iregex
PARAMS((char *argv
[], int *arg_ptr
));
91 static boolean parse_iwholename
PARAMS((char *argv
[], int *arg_ptr
));
92 static boolean parse_links
PARAMS((char *argv
[], int *arg_ptr
));
93 static boolean parse_lname
PARAMS((char *argv
[], int *arg_ptr
));
94 static boolean parse_ls
PARAMS((char *argv
[], int *arg_ptr
));
95 static boolean parse_maxdepth
PARAMS((char *argv
[], int *arg_ptr
));
96 static boolean parse_mindepth
PARAMS((char *argv
[], int *arg_ptr
));
97 static boolean parse_mmin
PARAMS((char *argv
[], int *arg_ptr
));
98 static boolean parse_mtime
PARAMS((char *argv
[], int *arg_ptr
));
99 static boolean parse_name
PARAMS((char *argv
[], int *arg_ptr
));
100 static boolean parse_negate
PARAMS((char *argv
[], int *arg_ptr
));
101 static boolean parse_newer
PARAMS((char *argv
[], int *arg_ptr
));
102 static boolean parse_noleaf
PARAMS((char *argv
[], int *arg_ptr
));
103 static boolean parse_nogroup
PARAMS((char *argv
[], int *arg_ptr
));
104 static boolean parse_nouser
PARAMS((char *argv
[], int *arg_ptr
));
105 static boolean parse_nowarn
PARAMS((char *argv
[], int *arg_ptr
));
106 static boolean parse_ok
PARAMS((char *argv
[], int *arg_ptr
));
107 boolean parse_open
PARAMS((char *argv
[], int *arg_ptr
));
108 static boolean parse_or
PARAMS((char *argv
[], int *arg_ptr
));
109 static boolean parse_path
PARAMS((char *argv
[], int *arg_ptr
));
110 static boolean parse_perm
PARAMS((char *argv
[], int *arg_ptr
));
111 boolean parse_print
PARAMS((char *argv
[], int *arg_ptr
));
112 static boolean parse_print0
PARAMS((char *argv
[], int *arg_ptr
));
113 static boolean parse_printf
PARAMS((char *argv
[], int *arg_ptr
));
114 static boolean parse_prune
PARAMS((char *argv
[], int *arg_ptr
));
115 static boolean parse_regex
PARAMS((char *argv
[], int *arg_ptr
));
116 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
117 static boolean parse_size
PARAMS((char *argv
[], int *arg_ptr
));
118 static boolean parse_true
PARAMS((char *argv
[], int *arg_ptr
));
119 static boolean parse_type
PARAMS((char *argv
[], int *arg_ptr
));
120 static boolean parse_uid
PARAMS((char *argv
[], int *arg_ptr
));
121 static boolean parse_used
PARAMS((char *argv
[], int *arg_ptr
));
122 static boolean parse_user
PARAMS((char *argv
[], int *arg_ptr
));
123 static boolean parse_version
PARAMS((char *argv
[], int *arg_ptr
));
124 static boolean parse_wholename
PARAMS((char *argv
[], int *arg_ptr
));
125 static boolean parse_xdev
PARAMS((char *argv
[], int *arg_ptr
));
126 static boolean parse_ignore_race
PARAMS((char *argv
[], int *arg_ptr
));
127 static boolean parse_noignore_race
PARAMS((char *argv
[], int *arg_ptr
));
128 static boolean parse_warn
PARAMS((char *argv
[], int *arg_ptr
));
129 static boolean parse_xtype
PARAMS((char *argv
[], int *arg_ptr
));
130 static boolean parse_quit
PARAMS((char *argv
[], int *arg_ptr
));
132 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
133 static boolean insert_type
PARAMS((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
134 static boolean insert_fprintf
PARAMS((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
135 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
136 static boolean insert_exec_ok
PARAMS((boolean (*func
)(), char *argv
[], int *arg_ptr
));
137 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
138 static boolean insert_time
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
139 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
140 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
141 static FILE *open_output_file
PARAMS((char *path
));
144 char *find_pred_name
PARAMS((PFB pred_func
));
151 ARG_OPTION
, /* regular options like -maxdepth */
152 ARG_POSITIONAL_OPTION
, /* options whose position is important (-follow) */
153 ARG_TEST
, /* a like -name */
154 ARG_PUNCTUATION
, /* like -o or ( */
155 ARG_ACTION
/* like -print */
166 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
167 If they are in some Unix versions of find, they are marked `Unix'. */
169 static struct parser_table
const parse_table
[] =
171 {ARG_PUNCTUATION
, "!", parse_negate
},
172 {ARG_PUNCTUATION
, "not", parse_negate
}, /* GNU */
173 {ARG_PUNCTUATION
, "(", parse_open
},
174 {ARG_PUNCTUATION
, ")", parse_close
},
175 {ARG_PUNCTUATION
, ",", parse_comma
}, /* GNU */
176 {ARG_PUNCTUATION
, "a", parse_and
},
177 {ARG_TEST
, "amin", parse_amin
}, /* GNU */
178 {ARG_PUNCTUATION
, "and", parse_and
}, /* GNU */
179 {ARG_TEST
, "anewer", parse_anewer
}, /* GNU */
180 {ARG_TEST
, "atime", parse_atime
},
181 {ARG_TEST
, "cmin", parse_cmin
}, /* GNU */
182 {ARG_TEST
, "cnewer", parse_cnewer
}, /* GNU */
183 #ifdef UNIMPLEMENTED_UNIX
184 /* It's pretty ugly for find to know about archive formats.
185 Plus what it could do with cpio archives is very limited.
186 Better to leave it out. */
187 {ARG_UNIMPLEMENTED
, "cpio", parse_cpio
}, /* Unix */
189 {ARG_TEST
, "ctime", parse_ctime
},
190 {ARG_POSITIONAL_OPTION
, "daystart", parse_daystart
}, /* GNU */
191 {ARG_ACTION
, "delete", parse_delete
}, /* GNU, Mac OS, FreeBSD */
192 {ARG_OPTION
, "d", parse_d
}, /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
193 {ARG_OPTION
, "depth", parse_depth
},
194 {ARG_TEST
, "empty", parse_empty
}, /* GNU */
195 {ARG_ACTION
, "exec", parse_exec
},
196 {ARG_TEST
, "false", parse_false
}, /* GNU */
197 {ARG_ACTION
, "fls", parse_fls
}, /* GNU */
198 {ARG_POSITIONAL_OPTION
, "follow", parse_follow
}, /* GNU, Unix */
199 {ARG_ACTION
, "fprint", parse_fprint
}, /* GNU */
200 {ARG_ACTION
, "fprint0", parse_fprint0
}, /* GNU */
201 {ARG_ACTION
, "fprintf", parse_fprintf
}, /* GNU */
202 {ARG_TEST
, "fstype", parse_fstype
}, /* GNU, Unix */
203 {ARG_TEST
, "gid", parse_gid
}, /* GNU */
204 {ARG_TEST
, "group", parse_group
},
205 {ARG_TEST
, "help", parse_help
}, /* GNU */
206 {ARG_TEST
, "-help", parse_help
}, /* GNU */
207 {ARG_OPTION
, "ignore_readdir_race", parse_ignore_race
}, /* GNU */
208 {ARG_TEST
, "ilname", parse_ilname
}, /* GNU */
209 {ARG_TEST
, "iname", parse_iname
}, /* GNU */
210 {ARG_TEST
, "inum", parse_inum
}, /* GNU, Unix */
211 {ARG_TEST
, "ipath", parse_ipath
}, /* GNU, deprecated in favour of iwholename */
212 {ARG_TEST
, "iregex", parse_iregex
}, /* GNU */
213 {ARG_TEST
, "iwholename", parse_iwholename
}, /* GNU */
214 {ARG_TEST
, "links", parse_links
},
215 {ARG_TEST
, "lname", parse_lname
}, /* GNU */
216 {ARG_ACTION
, "ls", parse_ls
}, /* GNU, Unix */
217 {ARG_OPTION
, "maxdepth", parse_maxdepth
}, /* GNU */
218 {ARG_OPTION
, "mindepth", parse_mindepth
}, /* GNU */
219 {ARG_TEST
, "mmin", parse_mmin
}, /* GNU */
220 {ARG_OPTION
, "mount", parse_xdev
}, /* Unix */
221 {ARG_TEST
, "mtime", parse_mtime
},
222 {ARG_TEST
, "name", parse_name
},
223 #ifdef UNIMPLEMENTED_UNIX
224 {ARG_UNIMPLEMENTED
, "ncpio", parse_ncpio
}, /* Unix */
226 {ARG_TEST
, "newer", parse_newer
},
227 {ARG_OPTION
, "noleaf", parse_noleaf
}, /* GNU */
228 {ARG_TEST
, "nogroup", parse_nogroup
},
229 {ARG_TEST
, "nouser", parse_nouser
},
230 {ARG_OPTION
, "noignore_readdir_race", parse_noignore_race
},/* GNU */
231 {ARG_OPTION
, "nowarn", parse_nowarn
}, /* GNU */
232 {ARG_PUNCTUATION
, "o", parse_or
},
233 {ARG_PUNCTUATION
, "or", parse_or
}, /* GNU */
234 {ARG_ACTION
, "ok", parse_ok
},
235 {ARG_TEST
, "path", parse_path
}, /* GNU, HP-UX, GNU prefers wholename */
236 {ARG_TEST
, "perm", parse_perm
},
237 {ARG_ACTION
, "print", parse_print
},
238 {ARG_ACTION
, "print0", parse_print0
}, /* GNU */
239 {ARG_ACTION
, "printf", parse_printf
}, /* GNU */
240 {ARG_TEST
, "prune", parse_prune
},
241 {ARG_ACTION
, "quit", parse_quit
}, /* GNU */
242 {ARG_TEST
, "regex", parse_regex
}, /* GNU */
243 {ARG_TEST
, "size", parse_size
},
244 {ARG_TEST
, "true", parse_true
}, /* GNU */
245 {ARG_TEST
, "type", parse_type
},
246 {ARG_TEST
, "uid", parse_uid
}, /* GNU */
247 {ARG_TEST
, "used", parse_used
}, /* GNU */
248 {ARG_TEST
, "user", parse_user
},
249 {ARG_TEST
, "version", parse_version
}, /* GNU */
250 {ARG_TEST
, "-version", parse_version
}, /* GNU */
251 {ARG_OPTION
, "warn", parse_warn
}, /* GNU */
252 {ARG_TEST
, "wholename", parse_wholename
}, /* GNU, replaces -path */
253 {ARG_OPTION
, "xdev", parse_xdev
},
254 {ARG_TEST
, "xtype", parse_xtype
}, /* GNU */
259 static const char *first_nonoption_arg
= NULL
;
261 /* Return a pointer to the parser function to invoke for predicate
263 Return NULL if SEARCH_NAME is not a valid predicate name. */
266 find_parser (char *search_name
)
269 const char *original_arg
= search_name
;
271 if (*search_name
== '-')
273 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
275 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
277 /* If this is an option, but we have already had a
278 * non-option argument, the user may be under the
279 * impression that the behaviour of the option
280 * argument is conditional on some preceding
281 * tests. This might typically be the case with,
282 * for example, -maxdepth.
284 * The options -daystart and -follow are exempt
285 * from this treatment, since their positioning
286 * in the command line does have an effect on
287 * subsequent tests but not previous ones. That
288 * might be intentional on the part of the user.
290 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
292 /* Something other than -follow/-daystart.
293 * If this is an option, check if it followed
294 * a non-option and if so, issue a warning.
296 if (parse_table
[i
].type
== ARG_OPTION
)
298 if ((first_nonoption_arg
!= NULL
)
301 /* option which folows a non-option */
303 _("warning: you have specified the %s "
304 "option after a non-option argument %s, "
305 "but options are not positional (%s affects "
306 "tests specified before it as well as those "
307 "specified after it). Please specify options "
308 "before other arguments.\n"),
316 /* Not an option or a positional option,
317 * so remember we've seen it in order to
318 * use it in a possible future warning message.
320 if (first_nonoption_arg
== NULL
)
322 first_nonoption_arg
= original_arg
;
327 return (parse_table
[i
].parser_func
);
333 /* The parsers are responsible to continue scanning ARGV for
334 their arguments. Each parser knows what is and isn't
337 ARGV is the argument array.
338 *ARG_PTR is the index to start at in ARGV,
339 updated to point beyond the last element consumed.
341 The predicate structure is updated with the new information. */
344 parse_amin (char **argv
, int *arg_ptr
)
346 struct predicate
*our_pred
;
348 enum comparison_type c_type
;
351 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
353 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
355 t
= cur_day_start
+ DAYSECS
- num
* 60;
356 our_pred
= insert_primary (pred_amin
);
357 our_pred
->args
.info
.kind
= c_type
;
358 our_pred
->args
.info
.negative
= t
< 0;
359 our_pred
->args
.info
.l_val
= t
;
365 parse_and (char **argv
, int *arg_ptr
)
367 struct predicate
*our_pred
;
372 our_pred
= get_new_pred ();
373 our_pred
->pred_func
= pred_and
;
375 our_pred
->p_name
= find_pred_name (pred_and
);
377 our_pred
->p_type
= BI_OP
;
378 our_pred
->p_prec
= AND_PREC
;
379 our_pred
->need_stat
= false;
384 parse_anewer (char **argv
, int *arg_ptr
)
386 struct predicate
*our_pred
;
387 struct stat stat_newer
;
389 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
391 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
392 error (1, errno
, "%s", argv
[*arg_ptr
]);
393 our_pred
= insert_primary (pred_anewer
);
394 our_pred
->args
.time
= stat_newer
.st_mtime
;
400 parse_atime (char **argv
, int *arg_ptr
)
402 return (insert_time (argv
, arg_ptr
, pred_atime
));
406 parse_close (char **argv
, int *arg_ptr
)
408 struct predicate
*our_pred
;
413 our_pred
= get_new_pred ();
414 our_pred
->pred_func
= pred_close
;
416 our_pred
->p_name
= find_pred_name (pred_close
);
418 our_pred
->p_type
= CLOSE_PAREN
;
419 our_pred
->p_prec
= NO_PREC
;
420 our_pred
->need_stat
= false;
425 parse_cmin (char **argv
, int *arg_ptr
)
427 struct predicate
*our_pred
;
429 enum comparison_type c_type
;
432 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
434 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
436 t
= cur_day_start
+ DAYSECS
- num
* 60;
437 our_pred
= insert_primary (pred_cmin
);
438 our_pred
->args
.info
.kind
= c_type
;
439 our_pred
->args
.info
.negative
= t
< 0;
440 our_pred
->args
.info
.l_val
= t
;
446 parse_cnewer (char **argv
, int *arg_ptr
)
448 struct predicate
*our_pred
;
449 struct stat stat_newer
;
451 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
453 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
454 error (1, errno
, "%s", argv
[*arg_ptr
]);
455 our_pred
= insert_primary (pred_cnewer
);
456 our_pred
->args
.time
= stat_newer
.st_mtime
;
462 parse_comma (char **argv
, int *arg_ptr
)
464 struct predicate
*our_pred
;
469 our_pred
= get_new_pred ();
470 our_pred
->pred_func
= pred_comma
;
472 our_pred
->p_name
= find_pred_name (pred_comma
);
474 our_pred
->p_type
= BI_OP
;
475 our_pred
->p_prec
= COMMA_PREC
;
476 our_pred
->need_stat
= false;
481 parse_ctime (char **argv
, int *arg_ptr
)
483 return (insert_time (argv
, arg_ptr
, pred_ctime
));
487 parse_daystart (char **argv
, int *arg_ptr
)
494 if (full_days
== false)
496 cur_day_start
+= DAYSECS
;
497 local
= localtime (&cur_day_start
);
498 cur_day_start
-= (local
499 ? (local
->tm_sec
+ local
->tm_min
* 60
500 + local
->tm_hour
* 3600)
501 : cur_day_start
% DAYSECS
);
508 parse_delete (argv
, arg_ptr
)
512 struct predicate
*our_pred
;
516 our_pred
= insert_primary (pred_delete
);
517 our_pred
->side_effects
= true;
518 our_pred
->no_default_print
= true;
519 /* -delete implies -depth */
520 do_dir_first
= false;
525 parse_depth (char **argv
, int *arg_ptr
)
530 do_dir_first
= false;
535 parse_d (char **argv
, int *arg_ptr
)
543 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
545 return parse_depth(argv
, arg_ptr
);
549 parse_empty (char **argv
, int *arg_ptr
)
554 insert_primary (pred_empty
);
559 parse_exec (char **argv
, int *arg_ptr
)
561 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
565 parse_false (char **argv
, int *arg_ptr
)
567 struct predicate
*our_pred
;
572 our_pred
= insert_primary (pred_false
);
573 our_pred
->need_stat
= false;
578 parse_fls (char **argv
, int *arg_ptr
)
580 struct predicate
*our_pred
;
582 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
584 our_pred
= insert_primary (pred_fls
);
585 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
586 our_pred
->side_effects
= true;
587 our_pred
->no_default_print
= true;
593 parse_fprintf (char **argv
, int *arg_ptr
)
597 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
599 if (argv
[*arg_ptr
+ 1] == NULL
)
601 /* Ensure we get "missing arg" message, not "invalid arg". */
605 fp
= open_output_file (argv
[*arg_ptr
]);
607 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
611 parse_follow (char **argv
, int *arg_ptr
)
616 set_follow_state(SYMLINK_ALWAYS_DEREF
);
621 parse_fprint (char **argv
, int *arg_ptr
)
623 struct predicate
*our_pred
;
625 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
627 our_pred
= insert_primary (pred_fprint
);
628 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
629 our_pred
->side_effects
= true;
630 our_pred
->no_default_print
= true;
631 our_pred
->need_stat
= false;
637 parse_fprint0 (char **argv
, int *arg_ptr
)
639 struct predicate
*our_pred
;
641 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
643 our_pred
= insert_primary (pred_fprint0
);
644 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
645 our_pred
->side_effects
= true;
646 our_pred
->no_default_print
= true;
647 our_pred
->need_stat
= false;
653 parse_fstype (char **argv
, int *arg_ptr
)
655 struct predicate
*our_pred
;
657 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
659 our_pred
= insert_primary (pred_fstype
);
660 our_pred
->args
.str
= argv
[*arg_ptr
];
666 parse_gid (char **argv
, int *arg_ptr
)
668 return (insert_num (argv
, arg_ptr
, pred_gid
));
672 parse_group (char **argv
, int *arg_ptr
)
674 struct group
*cur_gr
;
675 struct predicate
*our_pred
;
679 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
681 cur_gr
= getgrnam (argv
[*arg_ptr
]);
684 gid
= cur_gr
->gr_gid
;
687 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
688 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
690 gid
= atoi (argv
[*arg_ptr
]);
692 our_pred
= insert_primary (pred_group
);
693 our_pred
->args
.gid
= gid
;
699 parse_help (char **argv
, int *arg_ptr
)
705 Usage: %s [path...] [expression]\n"), program_name
);
707 default path is the current directory; default expression is -print\n\
708 expression may consist of: operators, options, tests, and actions:\n"));
710 operators (decreasing precedence; -and is implicit where no others are given):\n\
711 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
712 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
714 positional options (always true): -daystart -follow\n\
715 normal options (always true, specified before other expressions):\n\
716 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
717 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
719 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
720 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
721 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
722 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
724 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
725 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
726 -used N -user NAME -xtype [bcdpfls]\n"));
728 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
729 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
731 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
732 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
733 email to <bug-findutils@gnu.org>."));
738 parse_ilname (char **argv
, int *arg_ptr
)
740 struct predicate
*our_pred
;
742 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
744 our_pred
= insert_primary (pred_ilname
);
745 our_pred
->args
.str
= argv
[*arg_ptr
];
751 /* sanity check the fnmatch() function to make sure
752 * it really is the GNU version.
755 fnmatch_sanitycheck()
757 /* fprintf(stderr, "Performing find sanity check..."); */
758 if (0 != fnmatch("foo", "foo", 0)
759 || 0 == fnmatch("Foo", "foo", 0)
760 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
762 error (1, 0, _("sanity check of the fnmatch() library function failed."));
763 /* fprintf(stderr, "FAILED\n"); */
767 /* fprintf(stderr, "OK\n"); */
774 parse_iname (char **argv
, int *arg_ptr
)
776 struct predicate
*our_pred
;
778 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
781 fnmatch_sanitycheck();
783 our_pred
= insert_primary (pred_iname
);
784 our_pred
->need_stat
= false;
785 our_pred
->args
.str
= argv
[*arg_ptr
];
791 parse_inum (char **argv
, int *arg_ptr
)
793 return (insert_num (argv
, arg_ptr
, pred_inum
));
796 /* -ipath is deprecated (at RMS's request) in favour of
797 * -iwholename. See the node "GNU Manuals" in standards.texi
798 * for the rationale for this (basically, GNU prefers the use
799 * of the phrase "file name" to "path name"
802 parse_ipath (char **argv
, int *arg_ptr
)
805 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
807 return parse_iwholename(argv
, arg_ptr
);
811 parse_iwholename (char **argv
, int *arg_ptr
)
813 struct predicate
*our_pred
;
815 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
818 fnmatch_sanitycheck();
820 our_pred
= insert_primary (pred_ipath
);
821 our_pred
->need_stat
= false;
822 our_pred
->args
.str
= argv
[*arg_ptr
];
828 parse_iregex (char **argv
, int *arg_ptr
)
830 return insert_regex (argv
, arg_ptr
, true);
834 parse_links (char **argv
, int *arg_ptr
)
836 return (insert_num (argv
, arg_ptr
, pred_links
));
840 parse_lname (char **argv
, int *arg_ptr
)
842 struct predicate
*our_pred
;
847 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
850 fnmatch_sanitycheck();
852 our_pred
= insert_primary (pred_lname
);
853 our_pred
->args
.str
= argv
[*arg_ptr
];
859 parse_ls (char **argv
, int *arg_ptr
)
861 struct predicate
*our_pred
;
866 our_pred
= insert_primary (pred_ls
);
867 our_pred
->side_effects
= true;
868 our_pred
->no_default_print
= true;
873 parse_maxdepth (char **argv
, int *arg_ptr
)
877 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
879 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
880 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
882 maxdepth
= atoi (argv
[*arg_ptr
]);
890 parse_mindepth (char **argv
, int *arg_ptr
)
894 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
896 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
897 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
899 mindepth
= atoi (argv
[*arg_ptr
]);
907 parse_mmin (char **argv
, int *arg_ptr
)
909 struct predicate
*our_pred
;
911 enum comparison_type c_type
;
914 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
916 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
918 t
= cur_day_start
+ DAYSECS
- num
* 60;
919 our_pred
= insert_primary (pred_mmin
);
920 our_pred
->args
.info
.kind
= c_type
;
921 our_pred
->args
.info
.negative
= t
< 0;
922 our_pred
->args
.info
.l_val
= t
;
928 parse_mtime (char **argv
, int *arg_ptr
)
930 return (insert_time (argv
, arg_ptr
, pred_mtime
));
934 parse_name (char **argv
, int *arg_ptr
)
936 struct predicate
*our_pred
;
941 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
943 our_pred
= insert_primary (pred_name
);
944 our_pred
->need_stat
= false;
945 our_pred
->args
.str
= argv
[*arg_ptr
];
951 parse_negate (char **argv
, int *arg_ptr
)
953 struct predicate
*our_pred
;
958 our_pred
= get_new_pred_chk_op ();
959 our_pred
->pred_func
= pred_negate
;
961 our_pred
->p_name
= find_pred_name (pred_negate
);
963 our_pred
->p_type
= UNI_OP
;
964 our_pred
->p_prec
= NEGATE_PREC
;
965 our_pred
->need_stat
= false;
970 parse_newer (char **argv
, int *arg_ptr
)
972 struct predicate
*our_pred
;
973 struct stat stat_newer
;
978 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
980 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
981 error (1, errno
, "%s", argv
[*arg_ptr
]);
982 our_pred
= insert_primary (pred_newer
);
983 our_pred
->args
.time
= stat_newer
.st_mtime
;
989 parse_noleaf (char **argv
, int *arg_ptr
)
994 no_leaf_check
= true;
999 /* Arbitrary amount by which to increase size
1000 of `uid_unused' and `gid_unused'. */
1001 #define ALLOC_STEP 2048
1003 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1004 char *uid_unused
= NULL
;
1006 /* Number of elements in `uid_unused'. */
1007 unsigned uid_allocated
;
1009 /* Similar for GIDs and group entries. */
1010 char *gid_unused
= NULL
;
1011 unsigned gid_allocated
;
1015 parse_nogroup (char **argv
, int *arg_ptr
)
1017 struct predicate
*our_pred
;
1022 our_pred
= insert_primary (pred_nogroup
);
1024 if (gid_unused
== NULL
)
1028 gid_allocated
= ALLOC_STEP
;
1029 gid_unused
= xmalloc (gid_allocated
);
1030 memset (gid_unused
, 1, gid_allocated
);
1032 while ((gr
= getgrent ()) != NULL
)
1034 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1036 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1037 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1038 memset (gid_unused
+ gid_allocated
, 1,
1039 new_allocated
- gid_allocated
);
1040 gid_allocated
= new_allocated
;
1042 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1051 parse_nouser (char **argv
, int *arg_ptr
)
1053 struct predicate
*our_pred
;
1058 our_pred
= insert_primary (pred_nouser
);
1060 if (uid_unused
== NULL
)
1064 uid_allocated
= ALLOC_STEP
;
1065 uid_unused
= xmalloc (uid_allocated
);
1066 memset (uid_unused
, 1, uid_allocated
);
1068 while ((pw
= getpwent ()) != NULL
)
1070 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1072 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1073 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1074 memset (uid_unused
+ uid_allocated
, 1,
1075 new_allocated
- uid_allocated
);
1076 uid_allocated
= new_allocated
;
1078 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1087 parse_nowarn (char **argv
, int *arg_ptr
)
1097 parse_ok (char **argv
, int *arg_ptr
)
1099 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
1103 parse_open (char **argv
, int *arg_ptr
)
1105 struct predicate
*our_pred
;
1110 our_pred
= get_new_pred_chk_op ();
1111 our_pred
->pred_func
= pred_open
;
1113 our_pred
->p_name
= find_pred_name (pred_open
);
1115 our_pred
->p_type
= OPEN_PAREN
;
1116 our_pred
->p_prec
= NO_PREC
;
1117 our_pred
->need_stat
= false;
1122 parse_or (char **argv
, int *arg_ptr
)
1124 struct predicate
*our_pred
;
1129 our_pred
= get_new_pred ();
1130 our_pred
->pred_func
= pred_or
;
1132 our_pred
->p_name
= find_pred_name (pred_or
);
1134 our_pred
->p_type
= BI_OP
;
1135 our_pred
->p_prec
= OR_PREC
;
1136 our_pred
->need_stat
= false;
1140 /* -path is deprecated (at RMS's request) in favour of
1141 * -iwholename. See the node "GNU Manuals" in standards.texi
1142 * for the rationale for this (basically, GNU prefers the use
1143 * of the phrase "file name" to "path name".
1145 * We do not issue a warning that this usage is deprecated
1146 * since HPUX find supports this predicate also.
1149 parse_path (char **argv
, int *arg_ptr
)
1151 return parse_wholename(argv
, arg_ptr
);
1155 parse_wholename (char **argv
, int *arg_ptr
)
1157 struct predicate
*our_pred
;
1159 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1161 our_pred
= insert_primary (pred_path
);
1162 our_pred
->need_stat
= false;
1163 our_pred
->args
.str
= argv
[*arg_ptr
];
1169 parse_perm (char **argv
, int *arg_ptr
)
1173 struct mode_change
*change
;
1174 struct predicate
*our_pred
;
1176 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1179 switch (argv
[*arg_ptr
][0])
1190 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1191 if (change
== MODE_INVALID
)
1192 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1193 else if (change
== MODE_MEMORY_EXHAUSTED
)
1194 error (1, 0, _("virtual memory exhausted"));
1195 perm_val
= mode_adjust (0, change
);
1198 our_pred
= insert_primary (pred_perm
);
1200 switch (argv
[*arg_ptr
][0])
1203 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1206 our_pred
->args
.perm
.kind
= PERM_ANY
;
1209 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1212 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1218 parse_print (char **argv
, int *arg_ptr
)
1220 struct predicate
*our_pred
;
1225 our_pred
= insert_primary (pred_print
);
1226 /* -print has the side effect of printing. This prevents us
1227 from doing undesired multiple printing when the user has
1228 already specified -print. */
1229 our_pred
->side_effects
= true;
1230 our_pred
->no_default_print
= true;
1231 our_pred
->need_stat
= false;
1236 parse_print0 (char **argv
, int *arg_ptr
)
1238 struct predicate
*our_pred
;
1243 our_pred
= insert_primary (pred_print0
);
1244 /* -print0 has the side effect of printing. This prevents us
1245 from doing undesired multiple printing when the user has
1246 already specified -print0. */
1247 our_pred
->side_effects
= true;
1248 our_pred
->no_default_print
= true;
1249 our_pred
->need_stat
= false;
1254 parse_printf (char **argv
, int *arg_ptr
)
1256 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1258 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1262 parse_prune (char **argv
, int *arg_ptr
)
1264 struct predicate
*our_pred
;
1269 our_pred
= insert_primary (pred_prune
);
1270 our_pred
->need_stat
= false;
1271 /* -prune has a side effect that it does not descend into
1272 the current directory. */
1273 our_pred
->side_effects
= true;
1278 parse_quit (char **argv
, int *arg_ptr
)
1280 struct predicate
*our_pred
= insert_primary (pred_quit
);
1283 our_pred
->need_stat
= false;
1289 parse_regex (char **argv
, int *arg_ptr
)
1291 return insert_regex (argv
, arg_ptr
, false);
1295 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1297 struct predicate
*our_pred
;
1298 struct re_pattern_buffer
*re
;
1299 const char *error_message
;
1301 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1303 our_pred
= insert_primary (pred_regex
);
1304 our_pred
->need_stat
= false;
1305 re
= (struct re_pattern_buffer
*)
1306 xmalloc (sizeof (struct re_pattern_buffer
));
1307 our_pred
->args
.regex
= re
;
1308 re
->allocated
= 100;
1309 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1314 re_syntax_options
|= RE_ICASE
;
1318 re_syntax_options
&= ~RE_ICASE
;
1320 re
->translate
= NULL
;
1322 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1325 error (1, 0, "%s", error_message
);
1331 parse_size (char **argv
, int *arg_ptr
)
1333 struct predicate
*our_pred
;
1335 enum comparison_type c_type
;
1339 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1341 len
= strlen (argv
[*arg_ptr
]);
1343 error (1, 0, _("invalid null argument to -size"));
1344 switch (argv
[*arg_ptr
][len
- 1])
1348 argv
[*arg_ptr
][len
- 1] = '\0';
1353 argv
[*arg_ptr
][len
- 1] = '\0';
1358 argv
[*arg_ptr
][len
- 1] = '\0';
1361 case 'M': /* Megabytes */
1362 blksize
= 1024*1024;
1363 argv
[*arg_ptr
][len
- 1] = '\0';
1366 case 'G': /* Gigabytes */
1367 blksize
= 1024*1024*1024;
1368 argv
[*arg_ptr
][len
- 1] = '\0';
1373 argv
[*arg_ptr
][len
- 1] = '\0';
1389 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1391 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1393 our_pred
= insert_primary (pred_size
);
1394 our_pred
->args
.size
.kind
= c_type
;
1395 our_pred
->args
.size
.blocksize
= blksize
;
1396 our_pred
->args
.size
.size
= num
;
1402 parse_true (char **argv
, int *arg_ptr
)
1404 struct predicate
*our_pred
;
1409 our_pred
= insert_primary (pred_true
);
1410 our_pred
->need_stat
= false;
1415 parse_type (char **argv
, int *arg_ptr
)
1417 return insert_type (argv
, arg_ptr
, pred_type
);
1421 parse_uid (char **argv
, int *arg_ptr
)
1423 return (insert_num (argv
, arg_ptr
, pred_uid
));
1427 parse_used (char **argv
, int *arg_ptr
)
1429 struct predicate
*our_pred
;
1431 enum comparison_type c_type
;
1434 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1436 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1438 t
= num_days
* DAYSECS
;
1439 our_pred
= insert_primary (pred_used
);
1440 our_pred
->args
.info
.kind
= c_type
;
1441 our_pred
->args
.info
.negative
= t
< 0;
1442 our_pred
->args
.info
.l_val
= t
;
1448 parse_user (char **argv
, int *arg_ptr
)
1450 struct passwd
*cur_pwd
;
1451 struct predicate
*our_pred
;
1455 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1457 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1459 if (cur_pwd
!= NULL
)
1460 uid
= cur_pwd
->pw_uid
;
1463 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1464 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1466 uid
= atoi (argv
[*arg_ptr
]);
1468 our_pred
= insert_primary (pred_user
);
1469 our_pred
->args
.uid
= uid
;
1475 parse_version (char **argv
, int *arg_ptr
)
1477 extern char *version_string
;
1482 printf (_("GNU find version %s\n"), version_string
);
1487 parse_xdev (char **argv
, int *arg_ptr
)
1491 stay_on_filesystem
= true;
1496 parse_ignore_race (char **argv
, int *arg_ptr
)
1500 ignore_readdir_race
= true;
1505 parse_noignore_race (char **argv
, int *arg_ptr
)
1509 ignore_readdir_race
= false;
1514 parse_warn (char **argv
, int *arg_ptr
)
1523 parse_xtype (char **argv
, int *arg_ptr
)
1527 return insert_type (argv
, arg_ptr
, pred_xtype
);
1531 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1534 struct predicate
*our_pred
;
1536 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1537 || (strlen (argv
[*arg_ptr
]) != 1))
1539 switch (argv
[*arg_ptr
][0])
1541 case 'b': /* block special */
1542 type_cell
= S_IFBLK
;
1544 case 'c': /* character special */
1545 type_cell
= S_IFCHR
;
1547 case 'd': /* directory */
1548 type_cell
= S_IFDIR
;
1550 case 'f': /* regular file */
1551 type_cell
= S_IFREG
;
1554 case 'l': /* symbolic link */
1555 type_cell
= S_IFLNK
;
1559 case 'p': /* pipe */
1560 type_cell
= S_IFIFO
;
1564 case 's': /* socket */
1565 type_cell
= S_IFSOCK
;
1569 case 'D': /* Solaris door */
1570 type_cell
= S_IFDOOR
;
1573 default: /* None of the above ... nuke 'em. */
1576 our_pred
= insert_primary (which_pred
);
1577 our_pred
->args
.type
= type_cell
;
1578 (*arg_ptr
)++; /* Move on to next argument. */
1582 /* If true, we've determined that the current fprintf predicate
1583 uses stat information. */
1584 static boolean fprintf_stat_needed
;
1587 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1589 char *format
; /* Beginning of unprocessed format string. */
1590 register char *scan
; /* Current address in scanning `format'. */
1591 register char *scan2
; /* Address inside of element being scanned. */
1592 struct segment
**segmentp
; /* Address of current segment. */
1593 struct predicate
*our_pred
;
1595 format
= argv
[(*arg_ptr
)++];
1597 fprintf_stat_needed
= false; /* Might be overridden later. */
1598 our_pred
= insert_primary (func
);
1599 our_pred
->side_effects
= true;
1600 our_pred
->no_default_print
= true;
1601 our_pred
->args
.printf_vec
.stream
= fp
;
1602 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1605 for (scan
= format
; *scan
; scan
++)
1610 if (*scan2
>= '0' && *scan2
<= '7')
1614 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1616 n
= 8 * n
+ *scan2
- '0';
1631 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1632 our_pred
->need_stat
= fprintf_stat_needed
;
1650 /* *scan = '\\'; * it already is */
1654 _("warning: unrecognized escape `\\%c'"), *scan2
);
1659 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1661 format
= scan2
+ 1; /* Move past the escape. */
1662 scan
= scan2
; /* Incremented immediately by `for'. */
1664 else if (*scan
== '%')
1668 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1674 /* Scan past flags, width and precision, to verify kind. */
1675 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1677 while (ISDIGIT (*scan2
))
1680 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1682 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2
))
1684 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1689 else if (strchr ("ACT", *scan2
) && scan2
[1])
1691 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1692 *scan2
| (scan2
[1] << 8));
1699 /* An unrecognized % escape. Print the char after the %. */
1700 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1702 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1711 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1712 our_pred
->need_stat
= fprintf_stat_needed
;
1716 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1717 from the text in FORMAT, which has length LEN.
1718 Return the address of the `next' pointer of the new segment. */
1720 static struct segment
**
1721 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1725 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1727 (*segment
)->kind
= kind
;
1728 (*segment
)->next
= NULL
;
1729 (*segment
)->text_len
= len
;
1731 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1732 strncpy (fmt
, format
, len
);
1735 switch (kind
& 0xff)
1737 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1738 case KIND_STOP
: /* Terminate argument, no newline. */
1741 case 'a': /* atime in `ctime' format */
1742 case 'A': /* atime in user-specified strftime format */
1743 case 'c': /* ctime in `ctime' format */
1744 case 'C': /* ctime in user-specified strftime format */
1745 case 'F': /* filesystem type */
1746 case 'g': /* group name */
1747 case 'i': /* inode number */
1748 case 'l': /* object of symlink */
1749 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1750 case 's': /* size in bytes */
1751 case 't': /* mtime in `ctime' format */
1752 case 'T': /* mtime in user-specified strftime format */
1753 case 'u': /* user name */
1754 case 'y': /* file type */
1755 case 'Y': /* symlink pointed file type */
1756 fprintf_stat_needed
= true;
1758 case 'f': /* basename of path */
1759 case 'h': /* leading directories part of path */
1760 case 'H': /* ARGV element file was found under */
1761 case 'p': /* pathname */
1762 case 'P': /* pathname with ARGV element stripped */
1766 /* Numeric items that one might expect to honour
1767 * #, 0, + flags but which do not.
1769 case 'G': /* GID number */
1770 case 'U': /* UID number */
1771 case 'b': /* size in 512-byte blocks */
1772 case 'D': /* Filesystem device on which the file exits */
1773 case 'k': /* size in 1K blocks */
1774 case 'n': /* number of links */
1775 fprintf_stat_needed
= true;
1778 /* Numeric items that DO honour #, 0, + flags.
1780 case 'd': /* depth in search tree (0 = ARGV element) */
1784 case 'm': /* mode as octal number (perms only) */
1786 fprintf_stat_needed
= true;
1791 return (&(*segment
)->next
);
1794 /* handles both exec and ok predicate */
1796 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1798 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1799 int num_paths
; /* Number of args with path replacements. */
1800 int path_pos
; /* Index in array of path replacements. */
1801 int vec_pos
; /* Index in array of args. */
1802 struct predicate
*our_pred
;
1803 struct exec_val
*execp
; /* Pointer for efficiency. */
1805 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1808 /* Count the number of args with path replacements, up until the ';'. */
1810 for (end
= start
, num_paths
= 0;
1812 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1814 if (strstr (argv
[end
], "{}"))
1816 /* Fail if no command given or no semicolon found. */
1817 if ((end
== start
) || (argv
[end
] == NULL
))
1823 our_pred
= insert_primary (func
);
1824 our_pred
->side_effects
= true;
1825 our_pred
->no_default_print
= true;
1826 execp
= &our_pred
->args
.exec_vec
;
1828 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1829 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1830 /* Record the positions of all args, and the args with path replacements. */
1831 for (end
= start
, path_pos
= vec_pos
= 0;
1833 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1838 execp
->paths
[path_pos
].count
= 0;
1839 for (p
= argv
[end
]; *p
; ++p
)
1840 if (p
[0] == '{' && p
[1] == '}')
1842 execp
->paths
[path_pos
].count
++;
1845 if (execp
->paths
[path_pos
].count
)
1847 execp
->paths
[path_pos
].offset
= vec_pos
;
1848 execp
->paths
[path_pos
].origarg
= argv
[end
];
1851 execp
->vec
[vec_pos
++] = argv
[end
];
1853 execp
->paths
[path_pos
].offset
= -1;
1854 execp
->vec
[vec_pos
] = NULL
;
1856 if (argv
[end
] == NULL
)
1863 /* Get a number of days and comparison type.
1864 STR is the ASCII representation.
1865 Set *NUM_DAYS to the number of days, taken as being from
1866 the current moment (or possibly midnight). Thus the sense of the
1867 comparison type appears to be reversed.
1868 Set *COMP_TYPE to the kind of comparison that is requested.
1870 Return true if all okay, false if input error.
1872 Used by -atime, -ctime and -mtime (parsers) to
1873 get the appropriate information for a time predicate processor. */
1876 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1878 boolean r
= get_num (str
, num_days
, comp_type
);
1882 case COMP_LT
: *comp_type
= COMP_GT
; break;
1883 case COMP_GT
: *comp_type
= COMP_LT
; break;
1889 /* Insert a time predicate PRED.
1890 ARGV is a pointer to the argument array.
1891 ARG_PTR is a pointer to an index into the array, incremented if
1894 Return true if input is valid, false if not.
1896 A new predicate node is assigned, along with an argument node
1897 obtained with malloc.
1899 Used by -atime, -ctime, and -mtime parsers. */
1902 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1904 struct predicate
*our_pred
;
1906 enum comparison_type c_type
;
1909 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1911 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1914 /* Figure out the timestamp value we are looking for. */
1915 t
= ( cur_day_start
- num_days
* DAYSECS
1916 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1920 /* We introduce a scope in which 'val' can be declared, for the
1921 * benefit of compilers that are really C89 compilers
1922 * which support intmax_t because config.h #defines it
1924 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1925 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1928 /* Check for possibility of an overflow */
1929 if ( (intmax_t)t
!= val
)
1931 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1936 our_pred
= insert_primary (pred
);
1937 our_pred
->args
.info
.kind
= c_type
;
1938 our_pred
->args
.info
.negative
= t
< 0;
1939 our_pred
->args
.info
.l_val
= t
;
1942 fprintf (stderr
, _("inserting %s\n"), our_pred
->p_name
);
1943 fprintf (stderr
, _(" type: %s %s "),
1944 (c_type
== COMP_GT
) ? "gt" :
1945 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1946 (c_type
== COMP_GT
) ? " >" :
1947 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1948 t
= our_pred
->args
.info
.l_val
;
1949 fprintf (stderr
, "%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1950 if (c_type
== COMP_EQ
)
1952 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1955 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1956 our_pred
->args
.info
.l_val
-= DAYSECS
;
1962 /* Get a number with comparision information.
1963 The sense of the comparision information is 'normal'; that is,
1964 '+' looks for a count > than the number and '-' less than.
1966 STR is the ASCII representation of the number.
1967 Set *NUM to the number.
1968 Set *COMP_TYPE to the kind of comparison that is requested.
1970 Return true if all okay, false if input error. */
1973 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1980 *comp_type
= COMP_GT
;
1984 *comp_type
= COMP_LT
;
1988 *comp_type
= COMP_EQ
;
1992 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1995 /* Insert a number predicate.
1996 ARGV is a pointer to the argument array.
1997 *ARG_PTR is an index into ARGV, incremented if all went well.
1998 *PRED is the predicate processor to insert.
2000 Return true if input is valid, false if error.
2002 A new predicate node is assigned, along with an argument node
2003 obtained with malloc.
2005 Used by -inum and -links parsers. */
2008 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
2010 struct predicate
*our_pred
;
2012 enum comparison_type c_type
;
2014 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2016 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2018 our_pred
= insert_primary (pred
);
2019 our_pred
->args
.info
.kind
= c_type
;
2020 our_pred
->args
.info
.l_val
= num
;
2023 fprintf (stderr
, _("inserting %s\n"), our_pred
->p_name
);
2024 fprintf (stderr
, _(" type: %s %s "),
2025 (c_type
== COMP_GT
) ? "gt" :
2026 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2027 (c_type
== COMP_GT
) ? " >" :
2028 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2029 fprintf (stderr
, "%ju\n", our_pred
->args
.info
.l_val
);
2035 open_output_file (char *path
)
2039 if (!strcmp (path
, "/dev/stderr"))
2041 else if (!strcmp (path
, "/dev/stdout"))
2043 f
= fopen (path
, "w");
2045 error (1, errno
, "%s", path
);