prepare for 4.2.8
[findutils.git] / find / parser.c
blobcfdbdf3f8e29e55a0d02fbf3bf6b7fab821d6ad1
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)
7 any later version.
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,
17 USA.
20 #include "defs.h"
21 #include <ctype.h>
22 #include <pwd.h>
23 #include <grp.h>
24 #include <fnmatch.h>
25 #include "../gnulib/lib/modechange.h"
26 #include "modetype.h"
27 #include "../gnulib/lib/xstrtol.h"
30 #if ENABLE_NLS
31 # include <libintl.h>
32 # define _(Text) gettext (Text)
33 #else
34 # define _(Text) Text
35 #endif
36 #ifdef gettext_noop
37 # define N_(String) gettext_noop (String)
38 #else
39 /* See locate.c for explanation as to why not use (String) */
40 # define N_(String) String
41 #endif
43 #if !defined (isascii) || defined (STDC_HEADERS)
44 #ifdef isascii
45 #undef isascii
46 #endif
47 #define isascii(c) 1
48 #endif
50 #define ISDIGIT(c) (isascii (c) && isdigit (c))
51 #define ISUPPER(c) (isascii (c) && isupper (c))
53 #ifndef HAVE_ENDGRENT
54 #define endgrent()
55 #endif
56 #ifndef HAVE_ENDPWENT
57 #define endpwent()
58 #endif
60 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
61 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
62 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
64 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
65 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_delete PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_d PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_iwholename PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
97 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
99 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
100 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
101 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
103 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
104 static boolean parse_nowarn PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
106 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
107 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
108 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
109 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
110 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
112 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
113 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
114 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
115 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
116 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
117 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
118 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
119 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
120 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
121 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
122 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
123 static boolean parse_wholename PARAMS((char *argv[], int *arg_ptr));
124 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
125 static boolean parse_ignore_race PARAMS((char *argv[], int *arg_ptr));
126 static boolean parse_noignore_race PARAMS((char *argv[], int *arg_ptr));
127 static boolean parse_warn PARAMS((char *argv[], int *arg_ptr));
128 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
129 static boolean parse_quit PARAMS((char *argv[], int *arg_ptr));
131 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
132 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
133 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
134 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
135 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
136 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
137 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
138 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
139 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
140 static FILE *open_output_file PARAMS((char *path));
142 #ifdef DEBUG
143 char *find_pred_name PARAMS((PFB pred_func));
144 #endif /* DEBUG */
148 enum arg_type
150 ARG_OPTION, /* regular options like -maxdepth */
151 ARG_POSITIONAL_OPTION, /* options whose position is important (-follow) */
152 ARG_TEST, /* a like -name */
153 ARG_PUNCTUATION, /* like -o or ( */
154 ARG_ACTION /* like -print */
158 struct parser_table
160 enum arg_type type;
161 char *parser_name;
162 PFB parser_func;
165 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
166 If they are in some Unix versions of find, they are marked `Unix'. */
168 static struct parser_table const parse_table[] =
170 {ARG_PUNCTUATION, "!", parse_negate},
171 {ARG_PUNCTUATION, "not", parse_negate}, /* GNU */
172 {ARG_PUNCTUATION, "(", parse_open},
173 {ARG_PUNCTUATION, ")", parse_close},
174 {ARG_PUNCTUATION, ",", parse_comma}, /* GNU */
175 {ARG_PUNCTUATION, "a", parse_and},
176 {ARG_TEST, "amin", parse_amin}, /* GNU */
177 {ARG_PUNCTUATION, "and", parse_and}, /* GNU */
178 {ARG_TEST, "anewer", parse_anewer}, /* GNU */
179 {ARG_TEST, "atime", parse_atime},
180 {ARG_TEST, "cmin", parse_cmin}, /* GNU */
181 {ARG_TEST, "cnewer", parse_cnewer}, /* GNU */
182 #ifdef UNIMPLEMENTED_UNIX
183 /* It's pretty ugly for find to know about archive formats.
184 Plus what it could do with cpio archives is very limited.
185 Better to leave it out. */
186 {ARG_UNIMPLEMENTED, "cpio", parse_cpio}, /* Unix */
187 #endif
188 {ARG_TEST, "ctime", parse_ctime},
189 {ARG_POSITIONAL_OPTION, "daystart", parse_daystart}, /* GNU */
190 {ARG_ACTION, "delete", parse_delete}, /* GNU, Mac OS, FreeBSD */
191 {ARG_OPTION, "d", parse_d}, /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
192 {ARG_OPTION, "depth", parse_depth},
193 {ARG_TEST, "empty", parse_empty}, /* GNU */
194 {ARG_ACTION, "exec", parse_exec},
195 {ARG_TEST, "false", parse_false}, /* GNU */
196 {ARG_ACTION, "fls", parse_fls}, /* GNU */
197 {ARG_POSITIONAL_OPTION, "follow", parse_follow}, /* GNU, Unix */
198 {ARG_ACTION, "fprint", parse_fprint}, /* GNU */
199 {ARG_ACTION, "fprint0", parse_fprint0}, /* GNU */
200 {ARG_ACTION, "fprintf", parse_fprintf}, /* GNU */
201 {ARG_TEST, "fstype", parse_fstype}, /* GNU, Unix */
202 {ARG_TEST, "gid", parse_gid}, /* GNU */
203 {ARG_TEST, "group", parse_group},
204 {ARG_TEST, "help", parse_help}, /* GNU */
205 {ARG_TEST, "-help", parse_help}, /* GNU */
206 {ARG_OPTION, "ignore_readdir_race", parse_ignore_race}, /* GNU */
207 {ARG_TEST, "ilname", parse_ilname}, /* GNU */
208 {ARG_TEST, "iname", parse_iname}, /* GNU */
209 {ARG_TEST, "inum", parse_inum}, /* GNU, Unix */
210 {ARG_TEST, "ipath", parse_ipath}, /* GNU, deprecated in favour of iwholename */
211 {ARG_TEST, "iregex", parse_iregex}, /* GNU */
212 {ARG_TEST, "iwholename", parse_iwholename}, /* GNU */
213 {ARG_TEST, "links", parse_links},
214 {ARG_TEST, "lname", parse_lname}, /* GNU */
215 {ARG_ACTION, "ls", parse_ls}, /* GNU, Unix */
216 {ARG_OPTION, "maxdepth", parse_maxdepth}, /* GNU */
217 {ARG_OPTION, "mindepth", parse_mindepth}, /* GNU */
218 {ARG_TEST, "mmin", parse_mmin}, /* GNU */
219 {ARG_OPTION, "mount", parse_xdev}, /* Unix */
220 {ARG_TEST, "mtime", parse_mtime},
221 {ARG_TEST, "name", parse_name},
222 #ifdef UNIMPLEMENTED_UNIX
223 {ARG_UNIMPLEMENTED, "ncpio", parse_ncpio}, /* Unix */
224 #endif
225 {ARG_TEST, "newer", parse_newer},
226 {ARG_OPTION, "noleaf", parse_noleaf}, /* GNU */
227 {ARG_TEST, "nogroup", parse_nogroup},
228 {ARG_TEST, "nouser", parse_nouser},
229 {ARG_OPTION, "noignore_readdir_race", parse_noignore_race},/* GNU */
230 {ARG_OPTION, "nowarn", parse_nowarn}, /* GNU */
231 {ARG_PUNCTUATION, "o", parse_or},
232 {ARG_PUNCTUATION, "or", parse_or}, /* GNU */
233 {ARG_ACTION, "ok", parse_ok},
234 {ARG_TEST, "path", parse_path}, /* GNU, HP-UX, GNU prefers wholename */
235 {ARG_TEST, "perm", parse_perm},
236 {ARG_ACTION, "print", parse_print},
237 {ARG_ACTION, "print0", parse_print0}, /* GNU */
238 {ARG_ACTION, "printf", parse_printf}, /* GNU */
239 {ARG_TEST, "prune", parse_prune},
240 {ARG_ACTION, "quit", parse_quit}, /* GNU */
241 {ARG_TEST, "regex", parse_regex}, /* GNU */
242 {ARG_TEST, "size", parse_size},
243 {ARG_TEST, "true", parse_true}, /* GNU */
244 {ARG_TEST, "type", parse_type},
245 {ARG_TEST, "uid", parse_uid}, /* GNU */
246 {ARG_TEST, "used", parse_used}, /* GNU */
247 {ARG_TEST, "user", parse_user},
248 {ARG_TEST, "version", parse_version}, /* GNU */
249 {ARG_TEST, "-version", parse_version}, /* GNU */
250 {ARG_OPTION, "warn", parse_warn}, /* GNU */
251 {ARG_TEST, "wholename", parse_wholename}, /* GNU, replaces -path */
252 {ARG_TEST, "xdev", parse_xdev},
253 {ARG_TEST, "xtype", parse_xtype}, /* GNU */
254 {0, 0, 0}
258 static const char *first_nonoption_arg = NULL;
260 /* Return a pointer to the parser function to invoke for predicate
261 SEARCH_NAME.
262 Return NULL if SEARCH_NAME is not a valid predicate name. */
265 find_parser (char *search_name)
267 int i;
268 const char *original_arg = search_name;
270 if (*search_name == '-')
271 search_name++;
272 for (i = 0; parse_table[i].parser_name != 0; i++)
274 if (strcmp (parse_table[i].parser_name, search_name) == 0)
276 /* If this is an option, but we have already had a
277 * non-option argument, the user may be under the
278 * impression that the behaviour of the option
279 * argument is conditional on some preceding
280 * tests. This might typically be the case with,
281 * for example, -maxdepth.
283 * The options -daystart and -follow are exempt
284 * from this treatment, since their positioning
285 * in the command line does have an effect on
286 * subsequent tests but not previous ones. That
287 * might be intentional on the part of the user.
289 if (parse_table[i].type != ARG_POSITIONAL_OPTION)
291 /* Something other than -follow/-daystart.
292 * If this is an option, check if it followed
293 * a non-option and if so, issue a warning.
295 if (parse_table[i].type == ARG_OPTION)
297 if ((first_nonoption_arg != NULL)
298 && warnings )
300 /* option which folows a non-option */
301 error (0, 0,
302 _("warning: you have specified the %s "
303 "option after a non-option argument %s, "
304 "but options are not positional (%s affects "
305 "tests specified before it as well as those "
306 "specified after it). Please specify options "
307 "before other arguments.\n"),
308 original_arg,
309 first_nonoption_arg,
310 original_arg);
313 else
315 /* Not an option or a positional option,
316 * so remember we've seen it in order to
317 * use it in a possible future warning message.
319 if (first_nonoption_arg == NULL)
321 first_nonoption_arg = original_arg;
326 return (parse_table[i].parser_func);
329 return NULL;
332 /* The parsers are responsible to continue scanning ARGV for
333 their arguments. Each parser knows what is and isn't
334 allowed for itself.
336 ARGV is the argument array.
337 *ARG_PTR is the index to start at in ARGV,
338 updated to point beyond the last element consumed.
340 The predicate structure is updated with the new information. */
342 static boolean
343 parse_amin (char **argv, int *arg_ptr)
345 struct predicate *our_pred;
346 uintmax_t num;
347 enum comparison_type c_type;
348 time_t t;
350 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
351 return (false);
352 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
353 return (false);
354 t = cur_day_start + DAYSECS - num * 60;
355 our_pred = insert_primary (pred_amin);
356 our_pred->args.info.kind = c_type;
357 our_pred->args.info.negative = t < 0;
358 our_pred->args.info.l_val = t;
359 (*arg_ptr)++;
360 return (true);
363 static boolean
364 parse_and (char **argv, int *arg_ptr)
366 struct predicate *our_pred;
368 (void) argv;
369 (void) arg_ptr;
371 our_pred = get_new_pred ();
372 our_pred->pred_func = pred_and;
373 #ifdef DEBUG
374 our_pred->p_name = find_pred_name (pred_and);
375 #endif /* DEBUG */
376 our_pred->p_type = BI_OP;
377 our_pred->p_prec = AND_PREC;
378 our_pred->need_stat = false;
379 return (true);
382 static boolean
383 parse_anewer (char **argv, int *arg_ptr)
385 struct predicate *our_pred;
386 struct stat stat_newer;
388 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
389 return (false);
390 if ((*xstat) (argv[*arg_ptr], &stat_newer))
391 error (1, errno, "%s", argv[*arg_ptr]);
392 our_pred = insert_primary (pred_anewer);
393 our_pred->args.time = stat_newer.st_mtime;
394 (*arg_ptr)++;
395 return (true);
398 static boolean
399 parse_atime (char **argv, int *arg_ptr)
401 return (insert_time (argv, arg_ptr, pred_atime));
404 boolean
405 parse_close (char **argv, int *arg_ptr)
407 struct predicate *our_pred;
409 (void) argv;
410 (void) arg_ptr;
412 our_pred = get_new_pred ();
413 our_pred->pred_func = pred_close;
414 #ifdef DEBUG
415 our_pred->p_name = find_pred_name (pred_close);
416 #endif /* DEBUG */
417 our_pred->p_type = CLOSE_PAREN;
418 our_pred->p_prec = NO_PREC;
419 our_pred->need_stat = false;
420 return (true);
423 static boolean
424 parse_cmin (char **argv, int *arg_ptr)
426 struct predicate *our_pred;
427 uintmax_t num;
428 enum comparison_type c_type;
429 time_t t;
431 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
432 return (false);
433 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
434 return (false);
435 t = cur_day_start + DAYSECS - num * 60;
436 our_pred = insert_primary (pred_cmin);
437 our_pred->args.info.kind = c_type;
438 our_pred->args.info.negative = t < 0;
439 our_pred->args.info.l_val = t;
440 (*arg_ptr)++;
441 return (true);
444 static boolean
445 parse_cnewer (char **argv, int *arg_ptr)
447 struct predicate *our_pred;
448 struct stat stat_newer;
450 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
451 return (false);
452 if ((*xstat) (argv[*arg_ptr], &stat_newer))
453 error (1, errno, "%s", argv[*arg_ptr]);
454 our_pred = insert_primary (pred_cnewer);
455 our_pred->args.time = stat_newer.st_mtime;
456 (*arg_ptr)++;
457 return (true);
460 static boolean
461 parse_comma (char **argv, int *arg_ptr)
463 struct predicate *our_pred;
465 (void) argv;
466 (void) arg_ptr;
468 our_pred = get_new_pred ();
469 our_pred->pred_func = pred_comma;
470 #ifdef DEBUG
471 our_pred->p_name = find_pred_name (pred_comma);
472 #endif /* DEBUG */
473 our_pred->p_type = BI_OP;
474 our_pred->p_prec = COMMA_PREC;
475 our_pred->need_stat = false;
476 return (true);
479 static boolean
480 parse_ctime (char **argv, int *arg_ptr)
482 return (insert_time (argv, arg_ptr, pred_ctime));
485 static boolean
486 parse_daystart (char **argv, int *arg_ptr)
488 struct tm *local;
490 (void) argv;
491 (void) arg_ptr;
493 if (full_days == false)
495 cur_day_start += DAYSECS;
496 local = localtime (&cur_day_start);
497 cur_day_start -= (local
498 ? (local->tm_sec + local->tm_min * 60
499 + local->tm_hour * 3600)
500 : cur_day_start % DAYSECS);
501 full_days = true;
503 return (true);
506 static boolean
507 parse_delete (argv, arg_ptr)
508 char *argv[];
509 int *arg_ptr;
511 struct predicate *our_pred;
512 (void) argv;
513 (void) arg_ptr;
515 our_pred = insert_primary (pred_delete);
516 our_pred->side_effects = true;
517 our_pred->no_default_print = true;
518 /* -delete implies -depth */
519 do_dir_first = false;
520 return (true);
523 static boolean
524 parse_depth (char **argv, int *arg_ptr)
526 (void) argv;
527 (void) arg_ptr;
529 do_dir_first = false;
530 return (true);
533 static boolean
534 parse_d (char **argv, int *arg_ptr)
536 (void) argv;
537 (void) arg_ptr;
539 if (warnings)
541 error (0, 0,
542 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
544 return parse_depth(argv, arg_ptr);
547 static boolean
548 parse_empty (char **argv, int *arg_ptr)
550 (void) argv;
551 (void) arg_ptr;
553 insert_primary (pred_empty);
554 return (true);
557 static boolean
558 parse_exec (char **argv, int *arg_ptr)
560 return (insert_exec_ok (pred_exec, argv, arg_ptr));
563 static boolean
564 parse_false (char **argv, int *arg_ptr)
566 struct predicate *our_pred;
568 (void) argv;
569 (void) arg_ptr;
571 our_pred = insert_primary (pred_false);
572 our_pred->need_stat = false;
573 return (true);
576 static boolean
577 parse_fls (char **argv, int *arg_ptr)
579 struct predicate *our_pred;
581 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
582 return (false);
583 our_pred = insert_primary (pred_fls);
584 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
585 our_pred->side_effects = true;
586 our_pred->no_default_print = true;
587 (*arg_ptr)++;
588 return (true);
591 static boolean
592 parse_fprintf (char **argv, int *arg_ptr)
594 FILE *fp;
596 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
597 return (false);
598 if (argv[*arg_ptr + 1] == NULL)
600 /* Ensure we get "missing arg" message, not "invalid arg". */
601 (*arg_ptr)++;
602 return (false);
604 fp = open_output_file (argv[*arg_ptr]);
605 (*arg_ptr)++;
606 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
609 static boolean
610 parse_follow (char **argv, int *arg_ptr)
612 (void) argv;
613 (void) arg_ptr;
615 set_follow_state(SYMLINK_ALWAYS_DEREF);
616 return true;
619 static boolean
620 parse_fprint (char **argv, int *arg_ptr)
622 struct predicate *our_pred;
624 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
625 return (false);
626 our_pred = insert_primary (pred_fprint);
627 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
628 our_pred->side_effects = true;
629 our_pred->no_default_print = true;
630 our_pred->need_stat = false;
631 (*arg_ptr)++;
632 return (true);
635 static boolean
636 parse_fprint0 (char **argv, int *arg_ptr)
638 struct predicate *our_pred;
640 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
641 return (false);
642 our_pred = insert_primary (pred_fprint0);
643 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
644 our_pred->side_effects = true;
645 our_pred->no_default_print = true;
646 our_pred->need_stat = false;
647 (*arg_ptr)++;
648 return (true);
651 static boolean
652 parse_fstype (char **argv, int *arg_ptr)
654 struct predicate *our_pred;
656 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
657 return (false);
658 our_pred = insert_primary (pred_fstype);
659 our_pred->args.str = argv[*arg_ptr];
660 (*arg_ptr)++;
661 return (true);
664 static boolean
665 parse_gid (char **argv, int *arg_ptr)
667 return (insert_num (argv, arg_ptr, pred_gid));
670 static boolean
671 parse_group (char **argv, int *arg_ptr)
673 struct group *cur_gr;
674 struct predicate *our_pred;
675 gid_t gid;
676 int gid_len;
678 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
679 return (false);
680 cur_gr = getgrnam (argv[*arg_ptr]);
681 endgrent ();
682 if (cur_gr != NULL)
683 gid = cur_gr->gr_gid;
684 else
686 gid_len = strspn (argv[*arg_ptr], "0123456789");
687 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
688 return (false);
689 gid = atoi (argv[*arg_ptr]);
691 our_pred = insert_primary (pred_group);
692 our_pred->args.gid = gid;
693 (*arg_ptr)++;
694 return (true);
697 static boolean
698 parse_help (char **argv, int *arg_ptr)
700 (void) argv;
701 (void) arg_ptr;
703 printf (_("\
704 Usage: %s [path...] [expression]\n"), program_name);
705 puts (_("\
706 default path is the current directory; default expression is -print\n\
707 expression may consist of:\n\
708 operators (decreasing precedence; -and is implicit where no others are given):\n\
709 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2"));
710 puts (_(" EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
711 positional options (always true): -daystart -follow\n\
712 normal options (always true, specified before other expressions): -depth\n\
713 --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
714 -ignore_readdir_race -noignore_readdir_race\n\
715 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
716 puts (_("\
717 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
718 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
719 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
720 puts (_("\
721 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
722 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
723 -used N -user NAME -xtype [bcdpfls]"));
724 puts (_("\
725 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
726 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
727 -quit\n"));
728 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
729 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
730 email to <bug-findutils@gnu.org>."));
731 exit (0);
734 static boolean
735 parse_ilname (char **argv, int *arg_ptr)
737 struct predicate *our_pred;
739 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
740 return (false);
741 our_pred = insert_primary (pred_ilname);
742 our_pred->args.str = argv[*arg_ptr];
743 (*arg_ptr)++;
744 return (true);
748 /* sanity check the fnmatch() function to make sure
749 * it really is the GNU version.
751 static boolean
752 fnmatch_sanitycheck()
754 /* fprintf(stderr, "Performing find sanity check..."); */
755 if (0 != fnmatch("foo", "foo", 0)
756 || 0 == fnmatch("Foo", "foo", 0)
757 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
759 error (1, 0, _("sanity check of the fnmatch() library function failed."));
760 /* fprintf(stderr, "FAILED\n"); */
761 return false;
764 /* fprintf(stderr, "OK\n"); */
765 return true;
770 static boolean
771 parse_iname (char **argv, int *arg_ptr)
773 struct predicate *our_pred;
775 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
776 return (false);
778 fnmatch_sanitycheck();
780 our_pred = insert_primary (pred_iname);
781 our_pred->need_stat = false;
782 our_pred->args.str = argv[*arg_ptr];
783 (*arg_ptr)++;
784 return (true);
787 static boolean
788 parse_inum (char **argv, int *arg_ptr)
790 return (insert_num (argv, arg_ptr, pred_inum));
793 /* -ipath is deprecated (at RMS's request) in favour of
794 * -iwholename. See the node "GNU Manuals" in standards.texi
795 * for the rationale for this (basically, GNU prefers the use
796 * of the phrase "file name" to "path name"
798 static boolean
799 parse_ipath (char **argv, int *arg_ptr)
801 error (0, 0,
802 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
804 return parse_iwholename(argv, arg_ptr);
807 static boolean
808 parse_iwholename (char **argv, int *arg_ptr)
810 struct predicate *our_pred;
812 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
813 return (false);
815 fnmatch_sanitycheck();
817 our_pred = insert_primary (pred_ipath);
818 our_pred->need_stat = false;
819 our_pred->args.str = argv[*arg_ptr];
820 (*arg_ptr)++;
821 return (true);
824 static boolean
825 parse_iregex (char **argv, int *arg_ptr)
827 return insert_regex (argv, arg_ptr, true);
830 static boolean
831 parse_links (char **argv, int *arg_ptr)
833 return (insert_num (argv, arg_ptr, pred_links));
836 static boolean
837 parse_lname (char **argv, int *arg_ptr)
839 struct predicate *our_pred;
841 (void) argv;
842 (void) arg_ptr;
844 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
845 return (false);
847 fnmatch_sanitycheck();
849 our_pred = insert_primary (pred_lname);
850 our_pred->args.str = argv[*arg_ptr];
851 (*arg_ptr)++;
852 return (true);
855 static boolean
856 parse_ls (char **argv, int *arg_ptr)
858 struct predicate *our_pred;
860 (void) &argv;
861 (void) &arg_ptr;
863 our_pred = insert_primary (pred_ls);
864 our_pred->side_effects = true;
865 our_pred->no_default_print = true;
866 return (true);
869 static boolean
870 parse_maxdepth (char **argv, int *arg_ptr)
872 int depth_len;
874 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
875 return (false);
876 depth_len = strspn (argv[*arg_ptr], "0123456789");
877 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
878 return (false);
879 maxdepth = atoi (argv[*arg_ptr]);
880 if (maxdepth < 0)
881 return (false);
882 (*arg_ptr)++;
883 return (true);
886 static boolean
887 parse_mindepth (char **argv, int *arg_ptr)
889 int depth_len;
891 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
892 return (false);
893 depth_len = strspn (argv[*arg_ptr], "0123456789");
894 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
895 return (false);
896 mindepth = atoi (argv[*arg_ptr]);
897 if (mindepth < 0)
898 return (false);
899 (*arg_ptr)++;
900 return (true);
903 static boolean
904 parse_mmin (char **argv, int *arg_ptr)
906 struct predicate *our_pred;
907 uintmax_t num;
908 enum comparison_type c_type;
909 time_t t;
911 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
912 return (false);
913 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
914 return (false);
915 t = cur_day_start + DAYSECS - num * 60;
916 our_pred = insert_primary (pred_mmin);
917 our_pred->args.info.kind = c_type;
918 our_pred->args.info.negative = t < 0;
919 our_pred->args.info.l_val = t;
920 (*arg_ptr)++;
921 return (true);
924 static boolean
925 parse_mtime (char **argv, int *arg_ptr)
927 return (insert_time (argv, arg_ptr, pred_mtime));
930 static boolean
931 parse_name (char **argv, int *arg_ptr)
933 struct predicate *our_pred;
935 (void) argv;
936 (void) arg_ptr;
938 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
939 return (false);
940 our_pred = insert_primary (pred_name);
941 our_pred->need_stat = false;
942 our_pred->args.str = argv[*arg_ptr];
943 (*arg_ptr)++;
944 return (true);
947 static boolean
948 parse_negate (char **argv, int *arg_ptr)
950 struct predicate *our_pred;
952 (void) &argv;
953 (void) &arg_ptr;
955 our_pred = get_new_pred_chk_op ();
956 our_pred->pred_func = pred_negate;
957 #ifdef DEBUG
958 our_pred->p_name = find_pred_name (pred_negate);
959 #endif /* DEBUG */
960 our_pred->p_type = UNI_OP;
961 our_pred->p_prec = NEGATE_PREC;
962 our_pred->need_stat = false;
963 return (true);
966 static boolean
967 parse_newer (char **argv, int *arg_ptr)
969 struct predicate *our_pred;
970 struct stat stat_newer;
972 (void) argv;
973 (void) arg_ptr;
975 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
976 return (false);
977 if ((*xstat) (argv[*arg_ptr], &stat_newer))
978 error (1, errno, "%s", argv[*arg_ptr]);
979 our_pred = insert_primary (pred_newer);
980 our_pred->args.time = stat_newer.st_mtime;
981 (*arg_ptr)++;
982 return (true);
985 static boolean
986 parse_noleaf (char **argv, int *arg_ptr)
988 (void) &argv;
989 (void) &arg_ptr;
991 no_leaf_check = true;
992 return true;
995 #ifdef CACHE_IDS
996 /* Arbitrary amount by which to increase size
997 of `uid_unused' and `gid_unused'. */
998 #define ALLOC_STEP 2048
1000 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1001 char *uid_unused = NULL;
1003 /* Number of elements in `uid_unused'. */
1004 unsigned uid_allocated;
1006 /* Similar for GIDs and group entries. */
1007 char *gid_unused = NULL;
1008 unsigned gid_allocated;
1009 #endif
1011 static boolean
1012 parse_nogroup (char **argv, int *arg_ptr)
1014 struct predicate *our_pred;
1016 (void) &argv;
1017 (void) &arg_ptr;
1019 our_pred = insert_primary (pred_nogroup);
1020 #ifdef CACHE_IDS
1021 if (gid_unused == NULL)
1023 struct group *gr;
1025 gid_allocated = ALLOC_STEP;
1026 gid_unused = xmalloc (gid_allocated);
1027 memset (gid_unused, 1, gid_allocated);
1028 setgrent ();
1029 while ((gr = getgrent ()) != NULL)
1031 if ((unsigned) gr->gr_gid >= gid_allocated)
1033 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1034 gid_unused = xrealloc (gid_unused, new_allocated);
1035 memset (gid_unused + gid_allocated, 1,
1036 new_allocated - gid_allocated);
1037 gid_allocated = new_allocated;
1039 gid_unused[(unsigned) gr->gr_gid] = 0;
1041 endgrent ();
1043 #endif
1044 return (true);
1047 static boolean
1048 parse_nouser (char **argv, int *arg_ptr)
1050 struct predicate *our_pred;
1051 (void) argv;
1052 (void) arg_ptr;
1055 our_pred = insert_primary (pred_nouser);
1056 #ifdef CACHE_IDS
1057 if (uid_unused == NULL)
1059 struct passwd *pw;
1061 uid_allocated = ALLOC_STEP;
1062 uid_unused = xmalloc (uid_allocated);
1063 memset (uid_unused, 1, uid_allocated);
1064 setpwent ();
1065 while ((pw = getpwent ()) != NULL)
1067 if ((unsigned) pw->pw_uid >= uid_allocated)
1069 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1070 uid_unused = xrealloc (uid_unused, new_allocated);
1071 memset (uid_unused + uid_allocated, 1,
1072 new_allocated - uid_allocated);
1073 uid_allocated = new_allocated;
1075 uid_unused[(unsigned) pw->pw_uid] = 0;
1077 endpwent ();
1079 #endif
1080 return (true);
1083 static boolean
1084 parse_nowarn (char **argv, int *arg_ptr)
1086 (void) argv;
1087 (void) arg_ptr;
1089 warnings = false;
1090 return true;;
1093 static boolean
1094 parse_ok (char **argv, int *arg_ptr)
1096 return (insert_exec_ok (pred_ok, argv, arg_ptr));
1099 boolean
1100 parse_open (char **argv, int *arg_ptr)
1102 struct predicate *our_pred;
1104 (void) argv;
1105 (void) arg_ptr;
1107 our_pred = get_new_pred_chk_op ();
1108 our_pred->pred_func = pred_open;
1109 #ifdef DEBUG
1110 our_pred->p_name = find_pred_name (pred_open);
1111 #endif /* DEBUG */
1112 our_pred->p_type = OPEN_PAREN;
1113 our_pred->p_prec = NO_PREC;
1114 our_pred->need_stat = false;
1115 return (true);
1118 static boolean
1119 parse_or (char **argv, int *arg_ptr)
1121 struct predicate *our_pred;
1123 (void) argv;
1124 (void) arg_ptr;
1126 our_pred = get_new_pred ();
1127 our_pred->pred_func = pred_or;
1128 #ifdef DEBUG
1129 our_pred->p_name = find_pred_name (pred_or);
1130 #endif /* DEBUG */
1131 our_pred->p_type = BI_OP;
1132 our_pred->p_prec = OR_PREC;
1133 our_pred->need_stat = false;
1134 return (true);
1137 /* -path is deprecated (at RMS's request) in favour of
1138 * -iwholename. See the node "GNU Manuals" in standards.texi
1139 * for the rationale for this (basically, GNU prefers the use
1140 * of the phrase "file name" to "path name".
1142 * We do not issue a warning that this usage is deprecated
1143 * since HPUX find supports this predicate also.
1145 static boolean
1146 parse_path (char **argv, int *arg_ptr)
1148 return parse_wholename(argv, arg_ptr);
1151 static boolean
1152 parse_wholename (char **argv, int *arg_ptr)
1154 struct predicate *our_pred;
1156 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1157 return (false);
1158 our_pred = insert_primary (pred_path);
1159 our_pred->need_stat = false;
1160 our_pred->args.str = argv[*arg_ptr];
1161 (*arg_ptr)++;
1162 return (true);
1165 static boolean
1166 parse_perm (char **argv, int *arg_ptr)
1168 mode_t perm_val;
1169 int mode_start = 0;
1170 struct mode_change *change;
1171 struct predicate *our_pred;
1173 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1174 return (false);
1176 switch (argv[*arg_ptr][0])
1178 case '-':
1179 case '+':
1180 mode_start = 1;
1181 break;
1182 default:
1183 /* empty */
1184 break;
1187 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1188 if (change == MODE_INVALID)
1189 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1190 else if (change == MODE_MEMORY_EXHAUSTED)
1191 error (1, 0, _("virtual memory exhausted"));
1192 perm_val = mode_adjust (0, change);
1193 mode_free (change);
1195 our_pred = insert_primary (pred_perm);
1197 switch (argv[*arg_ptr][0])
1199 case '-':
1200 our_pred->args.perm.kind = PERM_AT_LEAST;
1201 break;
1202 case '+':
1203 our_pred->args.perm.kind = PERM_ANY;
1204 break;
1205 default:
1206 our_pred->args.perm.kind = PERM_EXACT;
1207 break;
1209 our_pred->args.perm.val = perm_val & MODE_ALL;
1210 (*arg_ptr)++;
1211 return (true);
1214 boolean
1215 parse_print (char **argv, int *arg_ptr)
1217 struct predicate *our_pred;
1219 (void) argv;
1220 (void) arg_ptr;
1222 our_pred = insert_primary (pred_print);
1223 /* -print has the side effect of printing. This prevents us
1224 from doing undesired multiple printing when the user has
1225 already specified -print. */
1226 our_pred->side_effects = true;
1227 our_pred->no_default_print = true;
1228 our_pred->need_stat = false;
1229 return (true);
1232 static boolean
1233 parse_print0 (char **argv, int *arg_ptr)
1235 struct predicate *our_pred;
1237 (void) argv;
1238 (void) arg_ptr;
1240 our_pred = insert_primary (pred_print0);
1241 /* -print0 has the side effect of printing. This prevents us
1242 from doing undesired multiple printing when the user has
1243 already specified -print0. */
1244 our_pred->side_effects = true;
1245 our_pred->no_default_print = true;
1246 our_pred->need_stat = false;
1247 return (true);
1250 static boolean
1251 parse_printf (char **argv, int *arg_ptr)
1253 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1254 return (false);
1255 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1258 static boolean
1259 parse_prune (char **argv, int *arg_ptr)
1261 struct predicate *our_pred;
1263 (void) argv;
1264 (void) arg_ptr;
1266 our_pred = insert_primary (pred_prune);
1267 our_pred->need_stat = false;
1268 /* -prune has a side effect that it does not descend into
1269 the current directory. */
1270 our_pred->side_effects = true;
1271 return (true);
1274 static boolean
1275 parse_quit (char **argv, int *arg_ptr)
1277 struct predicate *our_pred = insert_primary (pred_quit);
1278 (void) argv;
1279 (void) arg_ptr;
1280 our_pred->need_stat = false;
1281 return true;
1285 static boolean
1286 parse_regex (char **argv, int *arg_ptr)
1288 return insert_regex (argv, arg_ptr, false);
1291 static boolean
1292 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1294 struct predicate *our_pred;
1295 struct re_pattern_buffer *re;
1296 const char *error_message;
1298 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1299 return (false);
1300 our_pred = insert_primary (pred_regex);
1301 our_pred->need_stat = false;
1302 re = (struct re_pattern_buffer *)
1303 xmalloc (sizeof (struct re_pattern_buffer));
1304 our_pred->args.regex = re;
1305 re->allocated = 100;
1306 re->buffer = (unsigned char *) xmalloc (re->allocated);
1307 re->fastmap = NULL;
1309 if (ignore_case)
1311 re_syntax_options |= RE_ICASE;
1313 else
1315 re_syntax_options &= ~RE_ICASE;
1317 re->translate = NULL;
1319 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1320 re);
1321 if (error_message)
1322 error (1, 0, "%s", error_message);
1323 (*arg_ptr)++;
1324 return (true);
1327 static boolean
1328 parse_size (char **argv, int *arg_ptr)
1330 struct predicate *our_pred;
1331 uintmax_t num;
1332 enum comparison_type c_type;
1333 int blksize = 512;
1334 int len;
1336 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1337 return (false);
1338 len = strlen (argv[*arg_ptr]);
1339 if (len == 0)
1340 error (1, 0, _("invalid null argument to -size"));
1341 switch (argv[*arg_ptr][len - 1])
1343 case 'b':
1344 blksize = 512;
1345 argv[*arg_ptr][len - 1] = '\0';
1346 break;
1348 case 'c':
1349 blksize = 1;
1350 argv[*arg_ptr][len - 1] = '\0';
1351 break;
1353 case 'k':
1354 blksize = 1024;
1355 argv[*arg_ptr][len - 1] = '\0';
1356 break;
1358 case 'M': /* Megabytes */
1359 blksize = 1024*1024;
1360 argv[*arg_ptr][len - 1] = '\0';
1361 break;
1363 case 'G': /* Gigabytes */
1364 blksize = 1024*1024*1024;
1365 argv[*arg_ptr][len - 1] = '\0';
1366 break;
1368 case 'w':
1369 blksize = 2;
1370 argv[*arg_ptr][len - 1] = '\0';
1371 break;
1373 case '0':
1374 case '1':
1375 case '2':
1376 case '3':
1377 case '4':
1378 case '5':
1379 case '6':
1380 case '7':
1381 case '8':
1382 case '9':
1383 break;
1385 default:
1386 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1388 if (!get_num (argv[*arg_ptr], &num, &c_type))
1389 return (false);
1390 our_pred = insert_primary (pred_size);
1391 our_pred->args.size.kind = c_type;
1392 our_pred->args.size.blocksize = blksize;
1393 our_pred->args.size.size = num;
1394 (*arg_ptr)++;
1395 return (true);
1398 static boolean
1399 parse_true (char **argv, int *arg_ptr)
1401 struct predicate *our_pred;
1403 (void) argv;
1404 (void) arg_ptr;
1406 our_pred = insert_primary (pred_true);
1407 our_pred->need_stat = false;
1408 return (true);
1411 static boolean
1412 parse_type (char **argv, int *arg_ptr)
1414 return insert_type (argv, arg_ptr, pred_type);
1417 static boolean
1418 parse_uid (char **argv, int *arg_ptr)
1420 return (insert_num (argv, arg_ptr, pred_uid));
1423 static boolean
1424 parse_used (char **argv, int *arg_ptr)
1426 struct predicate *our_pred;
1427 uintmax_t num_days;
1428 enum comparison_type c_type;
1429 time_t t;
1431 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1432 return (false);
1433 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1434 return (false);
1435 t = num_days * DAYSECS;
1436 our_pred = insert_primary (pred_used);
1437 our_pred->args.info.kind = c_type;
1438 our_pred->args.info.negative = t < 0;
1439 our_pred->args.info.l_val = t;
1440 (*arg_ptr)++;
1441 return (true);
1444 static boolean
1445 parse_user (char **argv, int *arg_ptr)
1447 struct passwd *cur_pwd;
1448 struct predicate *our_pred;
1449 uid_t uid;
1450 int uid_len;
1452 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1453 return (false);
1454 cur_pwd = getpwnam (argv[*arg_ptr]);
1455 endpwent ();
1456 if (cur_pwd != NULL)
1457 uid = cur_pwd->pw_uid;
1458 else
1460 uid_len = strspn (argv[*arg_ptr], "0123456789");
1461 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1462 return (false);
1463 uid = atoi (argv[*arg_ptr]);
1465 our_pred = insert_primary (pred_user);
1466 our_pred->args.uid = uid;
1467 (*arg_ptr)++;
1468 return (true);
1471 static boolean
1472 parse_version (char **argv, int *arg_ptr)
1474 extern char *version_string;
1475 (void) argv;
1476 (void) arg_ptr;
1478 fflush (stderr);
1479 printf (_("GNU find version %s\n"), version_string);
1480 exit (0);
1483 static boolean
1484 parse_xdev (char **argv, int *arg_ptr)
1486 (void) argv;
1487 (void) arg_ptr;
1488 stay_on_filesystem = true;
1489 return true;
1492 static boolean
1493 parse_ignore_race (char **argv, int *arg_ptr)
1495 (void) argv;
1496 (void) arg_ptr;
1497 ignore_readdir_race = true;
1498 return true;
1501 static boolean
1502 parse_noignore_race (char **argv, int *arg_ptr)
1504 (void) argv;
1505 (void) arg_ptr;
1506 ignore_readdir_race = false;
1507 return true;
1510 static boolean
1511 parse_warn (char **argv, int *arg_ptr)
1513 (void) argv;
1514 (void) arg_ptr;
1515 warnings = true;
1516 return true;
1519 static boolean
1520 parse_xtype (char **argv, int *arg_ptr)
1522 (void) argv;
1523 (void) arg_ptr;
1524 return insert_type (argv, arg_ptr, pred_xtype);
1527 static boolean
1528 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1530 mode_t type_cell;
1531 struct predicate *our_pred;
1533 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1534 || (strlen (argv[*arg_ptr]) != 1))
1535 return (false);
1536 switch (argv[*arg_ptr][0])
1538 case 'b': /* block special */
1539 type_cell = S_IFBLK;
1540 break;
1541 case 'c': /* character special */
1542 type_cell = S_IFCHR;
1543 break;
1544 case 'd': /* directory */
1545 type_cell = S_IFDIR;
1546 break;
1547 case 'f': /* regular file */
1548 type_cell = S_IFREG;
1549 break;
1550 #ifdef S_IFLNK
1551 case 'l': /* symbolic link */
1552 type_cell = S_IFLNK;
1553 break;
1554 #endif
1555 #ifdef S_IFIFO
1556 case 'p': /* pipe */
1557 type_cell = S_IFIFO;
1558 break;
1559 #endif
1560 #ifdef S_IFSOCK
1561 case 's': /* socket */
1562 type_cell = S_IFSOCK;
1563 break;
1564 #endif
1565 #ifdef S_IFDOOR
1566 case 'D': /* Solaris door */
1567 type_cell = S_IFDOOR;
1568 break;
1569 #endif
1570 default: /* None of the above ... nuke 'em. */
1571 return (false);
1573 our_pred = insert_primary (which_pred);
1574 our_pred->args.type = type_cell;
1575 (*arg_ptr)++; /* Move on to next argument. */
1576 return (true);
1579 /* If true, we've determined that the current fprintf predicate
1580 uses stat information. */
1581 static boolean fprintf_stat_needed;
1583 static boolean
1584 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1586 char *format; /* Beginning of unprocessed format string. */
1587 register char *scan; /* Current address in scanning `format'. */
1588 register char *scan2; /* Address inside of element being scanned. */
1589 struct segment **segmentp; /* Address of current segment. */
1590 struct predicate *our_pred;
1592 format = argv[(*arg_ptr)++];
1594 fprintf_stat_needed = false; /* Might be overridden later. */
1595 our_pred = insert_primary (func);
1596 our_pred->side_effects = true;
1597 our_pred->no_default_print = true;
1598 our_pred->args.printf_vec.stream = fp;
1599 segmentp = &our_pred->args.printf_vec.segment;
1600 *segmentp = NULL;
1602 for (scan = format; *scan; scan++)
1604 if (*scan == '\\')
1606 scan2 = scan + 1;
1607 if (*scan2 >= '0' && *scan2 <= '7')
1609 register int n, i;
1611 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1612 i++, scan2++)
1613 n = 8 * n + *scan2 - '0';
1614 scan2--;
1615 *scan = n;
1617 else
1619 switch (*scan2)
1621 case 'a':
1622 *scan = 7;
1623 break;
1624 case 'b':
1625 *scan = '\b';
1626 break;
1627 case 'c':
1628 make_segment (segmentp, format, scan - format, KIND_STOP);
1629 our_pred->need_stat = fprintf_stat_needed;
1630 return (true);
1631 case 'f':
1632 *scan = '\f';
1633 break;
1634 case 'n':
1635 *scan = '\n';
1636 break;
1637 case 'r':
1638 *scan = '\r';
1639 break;
1640 case 't':
1641 *scan = '\t';
1642 break;
1643 case 'v':
1644 *scan = '\v';
1645 break;
1646 case '\\':
1647 /* *scan = '\\'; * it already is */
1648 break;
1649 default:
1650 error (0, 0,
1651 _("warning: unrecognized escape `\\%c'"), *scan2);
1652 scan++;
1653 continue;
1656 segmentp = make_segment (segmentp, format, scan - format + 1,
1657 KIND_PLAIN);
1658 format = scan2 + 1; /* Move past the escape. */
1659 scan = scan2; /* Incremented immediately by `for'. */
1661 else if (*scan == '%')
1663 if (scan[1] == '%')
1665 segmentp = make_segment (segmentp, format, scan - format + 1,
1666 KIND_PLAIN);
1667 scan++;
1668 format = scan + 1;
1669 continue;
1671 /* Scan past flags, width and precision, to verify kind. */
1672 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1673 /* Do nothing. */ ;
1674 while (ISDIGIT (*scan2))
1675 scan2++;
1676 if (*scan2 == '.')
1677 for (scan2++; ISDIGIT (*scan2); scan2++)
1678 /* Do nothing. */ ;
1679 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1681 segmentp = make_segment (segmentp, format, scan2 - format,
1682 (int) *scan2);
1683 scan = scan2;
1684 format = scan + 1;
1686 else if (strchr ("ACT", *scan2) && scan2[1])
1688 segmentp = make_segment (segmentp, format, scan2 - format,
1689 *scan2 | (scan2[1] << 8));
1690 scan = scan2 + 1;
1691 format = scan + 1;
1692 continue;
1694 else
1696 /* An unrecognized % escape. Print the char after the %. */
1697 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1698 *scan2);
1699 segmentp = make_segment (segmentp, format, scan - format,
1700 KIND_PLAIN);
1701 format = scan + 1;
1702 continue;
1707 if (scan > format)
1708 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1709 our_pred->need_stat = fprintf_stat_needed;
1710 return (true);
1713 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1714 from the text in FORMAT, which has length LEN.
1715 Return the address of the `next' pointer of the new segment. */
1717 static struct segment **
1718 make_segment (struct segment **segment, char *format, int len, int kind)
1720 char *fmt;
1722 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1724 (*segment)->kind = kind;
1725 (*segment)->next = NULL;
1726 (*segment)->text_len = len;
1728 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1729 strncpy (fmt, format, len);
1730 fmt += len;
1732 switch (kind & 0xff)
1734 case KIND_PLAIN: /* Plain text string, no % conversion. */
1735 case KIND_STOP: /* Terminate argument, no newline. */
1736 break;
1738 case 'a': /* atime in `ctime' format */
1739 case 'A': /* atime in user-specified strftime format */
1740 case 'c': /* ctime in `ctime' format */
1741 case 'C': /* ctime in user-specified strftime format */
1742 case 'F': /* filesystem type */
1743 case 'g': /* group name */
1744 case 'i': /* inode number */
1745 case 'l': /* object of symlink */
1746 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1747 case 's': /* size in bytes */
1748 case 't': /* mtime in `ctime' format */
1749 case 'T': /* mtime in user-specified strftime format */
1750 case 'u': /* user name */
1751 case 'y': /* file type */
1752 case 'Y': /* symlink pointed file type */
1753 fprintf_stat_needed = true;
1754 /* FALLTHROUGH */
1755 case 'f': /* basename of path */
1756 case 'h': /* leading directories part of path */
1757 case 'H': /* ARGV element file was found under */
1758 case 'p': /* pathname */
1759 case 'P': /* pathname with ARGV element stripped */
1760 *fmt++ = 's';
1761 break;
1763 /* Numeric items that one might expect to honour
1764 * #, 0, + flags but which do not.
1766 case 'G': /* GID number */
1767 case 'U': /* UID number */
1768 case 'b': /* size in 512-byte blocks */
1769 case 'D': /* Filesystem device on which the file exits */
1770 case 'k': /* size in 1K blocks */
1771 case 'n': /* number of links */
1772 fprintf_stat_needed = true;
1773 *fmt++ = 's';
1775 /* Numeric items that DO honour #, 0, + flags.
1777 case 'd': /* depth in search tree (0 = ARGV element) */
1778 *fmt++ = 'd';
1779 break;
1781 case 'm': /* mode as octal number (perms only) */
1782 *fmt++ = 'o';
1783 fprintf_stat_needed = true;
1784 break;
1786 *fmt = '\0';
1788 return (&(*segment)->next);
1791 /* handles both exec and ok predicate */
1792 static boolean
1793 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1795 int start, end; /* Indexes in ARGV of start & end of cmd. */
1796 int num_paths; /* Number of args with path replacements. */
1797 int path_pos; /* Index in array of path replacements. */
1798 int vec_pos; /* Index in array of args. */
1799 struct predicate *our_pred;
1800 struct exec_val *execp; /* Pointer for efficiency. */
1802 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1803 return (false);
1805 /* Count the number of args with path replacements, up until the ';'. */
1806 start = *arg_ptr;
1807 for (end = start, num_paths = 0;
1808 (argv[end] != NULL)
1809 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1810 end++)
1811 if (strstr (argv[end], "{}"))
1812 num_paths++;
1813 /* Fail if no command given or no semicolon found. */
1814 if ((end == start) || (argv[end] == NULL))
1816 *arg_ptr = end;
1817 return (false);
1820 our_pred = insert_primary (func);
1821 our_pred->side_effects = true;
1822 our_pred->no_default_print = true;
1823 execp = &our_pred->args.exec_vec;
1824 execp->paths =
1825 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1826 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1827 /* Record the positions of all args, and the args with path replacements. */
1828 for (end = start, path_pos = vec_pos = 0;
1829 (argv[end] != NULL)
1830 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1831 end++)
1833 register char *p;
1835 execp->paths[path_pos].count = 0;
1836 for (p = argv[end]; *p; ++p)
1837 if (p[0] == '{' && p[1] == '}')
1839 execp->paths[path_pos].count++;
1840 ++p;
1842 if (execp->paths[path_pos].count)
1844 execp->paths[path_pos].offset = vec_pos;
1845 execp->paths[path_pos].origarg = argv[end];
1846 path_pos++;
1848 execp->vec[vec_pos++] = argv[end];
1850 execp->paths[path_pos].offset = -1;
1851 execp->vec[vec_pos] = NULL;
1853 if (argv[end] == NULL)
1854 *arg_ptr = end;
1855 else
1856 *arg_ptr = end + 1;
1857 return (true);
1860 /* Get a number of days and comparison type.
1861 STR is the ASCII representation.
1862 Set *NUM_DAYS to the number of days, taken as being from
1863 the current moment (or possibly midnight). Thus the sense of the
1864 comparison type appears to be reversed.
1865 Set *COMP_TYPE to the kind of comparison that is requested.
1867 Return true if all okay, false if input error.
1869 Used by -atime, -ctime and -mtime (parsers) to
1870 get the appropriate information for a time predicate processor. */
1872 static boolean
1873 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1875 boolean r = get_num (str, num_days, comp_type);
1876 if (r)
1877 switch (*comp_type)
1879 case COMP_LT: *comp_type = COMP_GT; break;
1880 case COMP_GT: *comp_type = COMP_LT; break;
1881 default: break;
1883 return r;
1886 /* Insert a time predicate PRED.
1887 ARGV is a pointer to the argument array.
1888 ARG_PTR is a pointer to an index into the array, incremented if
1889 all went well.
1891 Return true if input is valid, false if not.
1893 A new predicate node is assigned, along with an argument node
1894 obtained with malloc.
1896 Used by -atime, -ctime, and -mtime parsers. */
1898 static boolean
1899 insert_time (char **argv, int *arg_ptr, PFB pred)
1901 struct predicate *our_pred;
1902 uintmax_t num_days;
1903 enum comparison_type c_type;
1904 time_t t;
1906 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1907 return (false);
1908 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1909 return (false);
1911 /* Figure out the timestamp value we are looking for. */
1912 t = ( cur_day_start - num_days * DAYSECS
1913 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1914 #if 1
1915 if (1)
1917 /* We introduce a scope in which 'val' can be declared, for the
1918 * benefit of compilers that are really C89 compilers
1919 * which support intmax_t because config.h #defines it
1921 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1922 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1923 t = val;
1925 /* Check for possibility of an overflow */
1926 if ( (intmax_t)t != val )
1928 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1931 #endif
1933 our_pred = insert_primary (pred);
1934 our_pred->args.info.kind = c_type;
1935 our_pred->args.info.negative = t < 0;
1936 our_pred->args.info.l_val = t;
1937 (*arg_ptr)++;
1938 #ifdef DEBUG
1939 printf (_("inserting %s\n"), our_pred->p_name);
1940 printf (_(" type: %s %s "),
1941 (c_type == COMP_GT) ? "gt" :
1942 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1943 (c_type == COMP_GT) ? " >" :
1944 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1945 t = our_pred->args.info.l_val;
1946 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1947 if (c_type == COMP_EQ)
1949 t = our_pred->args.info.l_val += DAYSECS;
1950 printf (" < %ju %s",
1951 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1952 our_pred->args.info.l_val -= DAYSECS;
1954 #endif /* DEBUG */
1955 return (true);
1958 /* Get a number with comparision information.
1959 The sense of the comparision information is 'normal'; that is,
1960 '+' looks for a count > than the number and '-' less than.
1962 STR is the ASCII representation of the number.
1963 Set *NUM to the number.
1964 Set *COMP_TYPE to the kind of comparison that is requested.
1966 Return true if all okay, false if input error. */
1968 static boolean
1969 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1971 if (str == NULL)
1972 return (false);
1973 switch (str[0])
1975 case '+':
1976 *comp_type = COMP_GT;
1977 str++;
1978 break;
1979 case '-':
1980 *comp_type = COMP_LT;
1981 str++;
1982 break;
1983 default:
1984 *comp_type = COMP_EQ;
1985 break;
1988 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1991 /* Insert a number predicate.
1992 ARGV is a pointer to the argument array.
1993 *ARG_PTR is an index into ARGV, incremented if all went well.
1994 *PRED is the predicate processor to insert.
1996 Return true if input is valid, false if error.
1998 A new predicate node is assigned, along with an argument node
1999 obtained with malloc.
2001 Used by -inum and -links parsers. */
2003 static boolean
2004 insert_num (char **argv, int *arg_ptr, PFB pred)
2006 struct predicate *our_pred;
2007 uintmax_t num;
2008 enum comparison_type c_type;
2010 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2011 return (false);
2012 if (!get_num (argv[*arg_ptr], &num, &c_type))
2013 return (false);
2014 our_pred = insert_primary (pred);
2015 our_pred->args.info.kind = c_type;
2016 our_pred->args.info.l_val = num;
2017 (*arg_ptr)++;
2018 #ifdef DEBUG
2019 printf (_("inserting %s\n"), our_pred->p_name);
2020 printf (_(" type: %s %s "),
2021 (c_type == COMP_GT) ? "gt" :
2022 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2023 (c_type == COMP_GT) ? " >" :
2024 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2025 printf ("%ju\n", our_pred->args.info.l_val);
2026 #endif /* DEBUG */
2027 return (true);
2030 static FILE *
2031 open_output_file (char *path)
2033 FILE *f;
2035 if (!strcmp (path, "/dev/stderr"))
2036 return (stderr);
2037 else if (!strcmp (path, "/dev/stdout"))
2038 return (stdout);
2039 f = fopen (path, "w");
2040 if (f == NULL)
2041 error (1, errno, "%s", path);
2042 return (f);