Fixed savannah bug 11175, wrongly chdir()ing into directories specified on the comman...
[findutils.git] / find / parser.c
blob5555b7847153edabb73474fe8c9822efaa1a01d8
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"
28 #include "../gnulib/lib/xalloc.h"
31 #if ENABLE_NLS
32 # include <libintl.h>
33 # define _(Text) gettext (Text)
34 #else
35 # define _(Text) Text
36 #endif
37 #ifdef gettext_noop
38 # define N_(String) gettext_noop (String)
39 #else
40 /* See locate.c for explanation as to why not use (String) */
41 # define N_(String) String
42 #endif
44 #if !defined (isascii) || defined (STDC_HEADERS)
45 #ifdef isascii
46 #undef isascii
47 #endif
48 #define isascii(c) 1
49 #endif
51 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
52 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
54 #ifndef HAVE_ENDGRENT
55 #define endgrent()
56 #endif
57 #ifndef HAVE_ENDPWENT
58 #define endpwent()
59 #endif
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));
143 #ifdef DEBUG
144 char *find_pred_name PARAMS((PFB pred_func));
145 #endif /* DEBUG */
149 enum arg_type
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 */
159 struct parser_table
161 enum arg_type type;
162 char *parser_name;
163 PFB parser_func;
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 */
188 #endif
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 */
225 #endif
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 */
255 {0, 0, 0}
259 static const char *first_nonoption_arg = NULL;
261 /* Return a pointer to the parser function to invoke for predicate
262 SEARCH_NAME.
263 Return NULL if SEARCH_NAME is not a valid predicate name. */
266 find_parser (char *search_name)
268 int i;
269 const char *original_arg = search_name;
271 if (*search_name == '-')
272 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)
299 && warnings )
301 /* option which folows a non-option */
302 error (0, 0,
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"),
309 original_arg,
310 first_nonoption_arg,
311 original_arg);
314 else
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);
330 return NULL;
333 /* The parsers are responsible to continue scanning ARGV for
334 their arguments. Each parser knows what is and isn't
335 allowed for itself.
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. */
343 static boolean
344 parse_amin (char **argv, int *arg_ptr)
346 struct predicate *our_pred;
347 uintmax_t num;
348 enum comparison_type c_type;
349 time_t t;
351 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
352 return (false);
353 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
354 return (false);
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;
360 (*arg_ptr)++;
361 return (true);
364 static boolean
365 parse_and (char **argv, int *arg_ptr)
367 struct predicate *our_pred;
369 (void) argv;
370 (void) arg_ptr;
372 our_pred = get_new_pred ();
373 our_pred->pred_func = pred_and;
374 #ifdef DEBUG
375 our_pred->p_name = find_pred_name (pred_and);
376 #endif /* DEBUG */
377 our_pred->p_type = BI_OP;
378 our_pred->p_prec = AND_PREC;
379 our_pred->need_stat = false;
380 return (true);
383 static boolean
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))
390 return (false);
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;
395 (*arg_ptr)++;
396 return (true);
399 static boolean
400 parse_atime (char **argv, int *arg_ptr)
402 return (insert_time (argv, arg_ptr, pred_atime));
405 boolean
406 parse_close (char **argv, int *arg_ptr)
408 struct predicate *our_pred;
410 (void) argv;
411 (void) arg_ptr;
413 our_pred = get_new_pred ();
414 our_pred->pred_func = pred_close;
415 #ifdef DEBUG
416 our_pred->p_name = find_pred_name (pred_close);
417 #endif /* DEBUG */
418 our_pred->p_type = CLOSE_PAREN;
419 our_pred->p_prec = NO_PREC;
420 our_pred->need_stat = false;
421 return (true);
424 static boolean
425 parse_cmin (char **argv, int *arg_ptr)
427 struct predicate *our_pred;
428 uintmax_t num;
429 enum comparison_type c_type;
430 time_t t;
432 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
433 return (false);
434 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
435 return (false);
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;
441 (*arg_ptr)++;
442 return (true);
445 static boolean
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))
452 return (false);
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;
457 (*arg_ptr)++;
458 return (true);
461 static boolean
462 parse_comma (char **argv, int *arg_ptr)
464 struct predicate *our_pred;
466 (void) argv;
467 (void) arg_ptr;
469 our_pred = get_new_pred ();
470 our_pred->pred_func = pred_comma;
471 #ifdef DEBUG
472 our_pred->p_name = find_pred_name (pred_comma);
473 #endif /* DEBUG */
474 our_pred->p_type = BI_OP;
475 our_pred->p_prec = COMMA_PREC;
476 our_pred->need_stat = false;
477 return (true);
480 static boolean
481 parse_ctime (char **argv, int *arg_ptr)
483 return (insert_time (argv, arg_ptr, pred_ctime));
486 static boolean
487 parse_daystart (char **argv, int *arg_ptr)
489 struct tm *local;
491 (void) argv;
492 (void) 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);
502 full_days = true;
504 return (true);
507 static boolean
508 parse_delete (argv, arg_ptr)
509 char *argv[];
510 int *arg_ptr;
512 struct predicate *our_pred;
513 (void) argv;
514 (void) arg_ptr;
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;
521 return (true);
524 static boolean
525 parse_depth (char **argv, int *arg_ptr)
527 (void) argv;
528 (void) arg_ptr;
530 do_dir_first = false;
531 return (true);
534 static boolean
535 parse_d (char **argv, int *arg_ptr)
537 (void) argv;
538 (void) arg_ptr;
540 if (warnings)
542 error (0, 0,
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);
548 static boolean
549 parse_empty (char **argv, int *arg_ptr)
551 (void) argv;
552 (void) arg_ptr;
554 insert_primary (pred_empty);
555 return (true);
558 static boolean
559 parse_exec (char **argv, int *arg_ptr)
561 return (insert_exec_ok (pred_exec, argv, arg_ptr));
564 static boolean
565 parse_false (char **argv, int *arg_ptr)
567 struct predicate *our_pred;
569 (void) argv;
570 (void) arg_ptr;
572 our_pred = insert_primary (pred_false);
573 our_pred->need_stat = false;
574 return (true);
577 static boolean
578 parse_fls (char **argv, int *arg_ptr)
580 struct predicate *our_pred;
582 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
583 return (false);
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;
588 (*arg_ptr)++;
589 return (true);
592 static boolean
593 parse_fprintf (char **argv, int *arg_ptr)
595 FILE *fp;
597 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
598 return (false);
599 if (argv[*arg_ptr + 1] == NULL)
601 /* Ensure we get "missing arg" message, not "invalid arg". */
602 (*arg_ptr)++;
603 return (false);
605 fp = open_output_file (argv[*arg_ptr]);
606 (*arg_ptr)++;
607 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
610 static boolean
611 parse_follow (char **argv, int *arg_ptr)
613 (void) argv;
614 (void) arg_ptr;
616 set_follow_state(SYMLINK_ALWAYS_DEREF);
617 return true;
620 static boolean
621 parse_fprint (char **argv, int *arg_ptr)
623 struct predicate *our_pred;
625 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
626 return (false);
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;
632 (*arg_ptr)++;
633 return (true);
636 static boolean
637 parse_fprint0 (char **argv, int *arg_ptr)
639 struct predicate *our_pred;
641 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
642 return (false);
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;
648 (*arg_ptr)++;
649 return (true);
652 static boolean
653 parse_fstype (char **argv, int *arg_ptr)
655 struct predicate *our_pred;
657 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
658 return (false);
659 our_pred = insert_primary (pred_fstype);
660 our_pred->args.str = argv[*arg_ptr];
661 (*arg_ptr)++;
662 return (true);
665 static boolean
666 parse_gid (char **argv, int *arg_ptr)
668 return (insert_num (argv, arg_ptr, pred_gid));
671 static boolean
672 parse_group (char **argv, int *arg_ptr)
674 struct group *cur_gr;
675 struct predicate *our_pred;
676 gid_t gid;
677 int gid_len;
679 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
680 return (false);
681 cur_gr = getgrnam (argv[*arg_ptr]);
682 endgrent ();
683 if (cur_gr != NULL)
684 gid = cur_gr->gr_gid;
685 else
687 gid_len = strspn (argv[*arg_ptr], "0123456789");
688 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
689 return (false);
690 gid = atoi (argv[*arg_ptr]);
692 our_pred = insert_primary (pred_group);
693 our_pred->args.gid = gid;
694 (*arg_ptr)++;
695 return (true);
698 static boolean
699 parse_help (char **argv, int *arg_ptr)
701 (void) argv;
702 (void) arg_ptr;
704 printf (_("\
705 Usage: %s [path...] [expression]\n"), program_name);
706 puts (_("\
707 default path is the current directory; default expression is -print\n\
708 expression may consist of:\n\
709 operators (decreasing precedence; -and is implicit where no others are given):\n\
710 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2"));
711 puts (_(" EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
712 positional options (always true): -daystart -follow\n\
713 normal options (always true, specified before other expressions): -depth\n\
714 --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
715 -ignore_readdir_race -noignore_readdir_race\n\
716 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
717 puts (_("\
718 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
719 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
720 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
721 puts (_("\
722 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
723 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
724 -used N -user NAME -xtype [bcdpfls]"));
725 puts (_("\
726 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
727 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
728 -quit\n"));
729 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
730 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
731 email to <bug-findutils@gnu.org>."));
732 exit (0);
735 static boolean
736 parse_ilname (char **argv, int *arg_ptr)
738 struct predicate *our_pred;
740 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
741 return (false);
742 our_pred = insert_primary (pred_ilname);
743 our_pred->args.str = argv[*arg_ptr];
744 (*arg_ptr)++;
745 return (true);
749 /* sanity check the fnmatch() function to make sure
750 * it really is the GNU version.
752 static boolean
753 fnmatch_sanitycheck()
755 /* fprintf(stderr, "Performing find sanity check..."); */
756 if (0 != fnmatch("foo", "foo", 0)
757 || 0 == fnmatch("Foo", "foo", 0)
758 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
760 error (1, 0, _("sanity check of the fnmatch() library function failed."));
761 /* fprintf(stderr, "FAILED\n"); */
762 return false;
765 /* fprintf(stderr, "OK\n"); */
766 return true;
771 static boolean
772 parse_iname (char **argv, int *arg_ptr)
774 struct predicate *our_pred;
776 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
777 return (false);
779 fnmatch_sanitycheck();
781 our_pred = insert_primary (pred_iname);
782 our_pred->need_stat = false;
783 our_pred->args.str = argv[*arg_ptr];
784 (*arg_ptr)++;
785 return (true);
788 static boolean
789 parse_inum (char **argv, int *arg_ptr)
791 return (insert_num (argv, arg_ptr, pred_inum));
794 /* -ipath is deprecated (at RMS's request) in favour of
795 * -iwholename. See the node "GNU Manuals" in standards.texi
796 * for the rationale for this (basically, GNU prefers the use
797 * of the phrase "file name" to "path name"
799 static boolean
800 parse_ipath (char **argv, int *arg_ptr)
802 error (0, 0,
803 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
805 return parse_iwholename(argv, arg_ptr);
808 static boolean
809 parse_iwholename (char **argv, int *arg_ptr)
811 struct predicate *our_pred;
813 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
814 return (false);
816 fnmatch_sanitycheck();
818 our_pred = insert_primary (pred_ipath);
819 our_pred->need_stat = false;
820 our_pred->args.str = argv[*arg_ptr];
821 (*arg_ptr)++;
822 return (true);
825 static boolean
826 parse_iregex (char **argv, int *arg_ptr)
828 return insert_regex (argv, arg_ptr, true);
831 static boolean
832 parse_links (char **argv, int *arg_ptr)
834 return (insert_num (argv, arg_ptr, pred_links));
837 static boolean
838 parse_lname (char **argv, int *arg_ptr)
840 struct predicate *our_pred;
842 (void) argv;
843 (void) arg_ptr;
845 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
846 return (false);
848 fnmatch_sanitycheck();
850 our_pred = insert_primary (pred_lname);
851 our_pred->args.str = argv[*arg_ptr];
852 (*arg_ptr)++;
853 return (true);
856 static boolean
857 parse_ls (char **argv, int *arg_ptr)
859 struct predicate *our_pred;
861 (void) &argv;
862 (void) &arg_ptr;
864 our_pred = insert_primary (pred_ls);
865 our_pred->side_effects = true;
866 our_pred->no_default_print = true;
867 return (true);
870 static boolean
871 parse_maxdepth (char **argv, int *arg_ptr)
873 int depth_len;
875 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
876 return (false);
877 depth_len = strspn (argv[*arg_ptr], "0123456789");
878 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
879 return (false);
880 maxdepth = atoi (argv[*arg_ptr]);
881 if (maxdepth < 0)
882 return (false);
883 (*arg_ptr)++;
884 return (true);
887 static boolean
888 parse_mindepth (char **argv, int *arg_ptr)
890 int depth_len;
892 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
893 return (false);
894 depth_len = strspn (argv[*arg_ptr], "0123456789");
895 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
896 return (false);
897 mindepth = atoi (argv[*arg_ptr]);
898 if (mindepth < 0)
899 return (false);
900 (*arg_ptr)++;
901 return (true);
904 static boolean
905 parse_mmin (char **argv, int *arg_ptr)
907 struct predicate *our_pred;
908 uintmax_t num;
909 enum comparison_type c_type;
910 time_t t;
912 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
913 return (false);
914 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
915 return (false);
916 t = cur_day_start + DAYSECS - num * 60;
917 our_pred = insert_primary (pred_mmin);
918 our_pred->args.info.kind = c_type;
919 our_pred->args.info.negative = t < 0;
920 our_pred->args.info.l_val = t;
921 (*arg_ptr)++;
922 return (true);
925 static boolean
926 parse_mtime (char **argv, int *arg_ptr)
928 return (insert_time (argv, arg_ptr, pred_mtime));
931 static boolean
932 parse_name (char **argv, int *arg_ptr)
934 struct predicate *our_pred;
936 (void) argv;
937 (void) arg_ptr;
939 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
940 return (false);
941 our_pred = insert_primary (pred_name);
942 our_pred->need_stat = false;
943 our_pred->args.str = argv[*arg_ptr];
944 (*arg_ptr)++;
945 return (true);
948 static boolean
949 parse_negate (char **argv, int *arg_ptr)
951 struct predicate *our_pred;
953 (void) &argv;
954 (void) &arg_ptr;
956 our_pred = get_new_pred_chk_op ();
957 our_pred->pred_func = pred_negate;
958 #ifdef DEBUG
959 our_pred->p_name = find_pred_name (pred_negate);
960 #endif /* DEBUG */
961 our_pred->p_type = UNI_OP;
962 our_pred->p_prec = NEGATE_PREC;
963 our_pred->need_stat = false;
964 return (true);
967 static boolean
968 parse_newer (char **argv, int *arg_ptr)
970 struct predicate *our_pred;
971 struct stat stat_newer;
973 (void) argv;
974 (void) arg_ptr;
976 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
977 return (false);
978 if ((*xstat) (argv[*arg_ptr], &stat_newer))
979 error (1, errno, "%s", argv[*arg_ptr]);
980 our_pred = insert_primary (pred_newer);
981 our_pred->args.time = stat_newer.st_mtime;
982 (*arg_ptr)++;
983 return (true);
986 static boolean
987 parse_noleaf (char **argv, int *arg_ptr)
989 (void) &argv;
990 (void) &arg_ptr;
992 no_leaf_check = true;
993 return true;
996 #ifdef CACHE_IDS
997 /* Arbitrary amount by which to increase size
998 of `uid_unused' and `gid_unused'. */
999 #define ALLOC_STEP 2048
1001 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1002 char *uid_unused = NULL;
1004 /* Number of elements in `uid_unused'. */
1005 unsigned uid_allocated;
1007 /* Similar for GIDs and group entries. */
1008 char *gid_unused = NULL;
1009 unsigned gid_allocated;
1010 #endif
1012 static boolean
1013 parse_nogroup (char **argv, int *arg_ptr)
1015 struct predicate *our_pred;
1017 (void) &argv;
1018 (void) &arg_ptr;
1020 our_pred = insert_primary (pred_nogroup);
1021 #ifdef CACHE_IDS
1022 if (gid_unused == NULL)
1024 struct group *gr;
1026 gid_allocated = ALLOC_STEP;
1027 gid_unused = xmalloc (gid_allocated);
1028 memset (gid_unused, 1, gid_allocated);
1029 setgrent ();
1030 while ((gr = getgrent ()) != NULL)
1032 if ((unsigned) gr->gr_gid >= gid_allocated)
1034 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1035 gid_unused = xrealloc (gid_unused, new_allocated);
1036 memset (gid_unused + gid_allocated, 1,
1037 new_allocated - gid_allocated);
1038 gid_allocated = new_allocated;
1040 gid_unused[(unsigned) gr->gr_gid] = 0;
1042 endgrent ();
1044 #endif
1045 return (true);
1048 static boolean
1049 parse_nouser (char **argv, int *arg_ptr)
1051 struct predicate *our_pred;
1052 (void) argv;
1053 (void) arg_ptr;
1056 our_pred = insert_primary (pred_nouser);
1057 #ifdef CACHE_IDS
1058 if (uid_unused == NULL)
1060 struct passwd *pw;
1062 uid_allocated = ALLOC_STEP;
1063 uid_unused = xmalloc (uid_allocated);
1064 memset (uid_unused, 1, uid_allocated);
1065 setpwent ();
1066 while ((pw = getpwent ()) != NULL)
1068 if ((unsigned) pw->pw_uid >= uid_allocated)
1070 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1071 uid_unused = xrealloc (uid_unused, new_allocated);
1072 memset (uid_unused + uid_allocated, 1,
1073 new_allocated - uid_allocated);
1074 uid_allocated = new_allocated;
1076 uid_unused[(unsigned) pw->pw_uid] = 0;
1078 endpwent ();
1080 #endif
1081 return (true);
1084 static boolean
1085 parse_nowarn (char **argv, int *arg_ptr)
1087 (void) argv;
1088 (void) arg_ptr;
1090 warnings = false;
1091 return true;;
1094 static boolean
1095 parse_ok (char **argv, int *arg_ptr)
1097 return (insert_exec_ok (pred_ok, argv, arg_ptr));
1100 boolean
1101 parse_open (char **argv, int *arg_ptr)
1103 struct predicate *our_pred;
1105 (void) argv;
1106 (void) arg_ptr;
1108 our_pred = get_new_pred_chk_op ();
1109 our_pred->pred_func = pred_open;
1110 #ifdef DEBUG
1111 our_pred->p_name = find_pred_name (pred_open);
1112 #endif /* DEBUG */
1113 our_pred->p_type = OPEN_PAREN;
1114 our_pred->p_prec = NO_PREC;
1115 our_pred->need_stat = false;
1116 return (true);
1119 static boolean
1120 parse_or (char **argv, int *arg_ptr)
1122 struct predicate *our_pred;
1124 (void) argv;
1125 (void) arg_ptr;
1127 our_pred = get_new_pred ();
1128 our_pred->pred_func = pred_or;
1129 #ifdef DEBUG
1130 our_pred->p_name = find_pred_name (pred_or);
1131 #endif /* DEBUG */
1132 our_pred->p_type = BI_OP;
1133 our_pred->p_prec = OR_PREC;
1134 our_pred->need_stat = false;
1135 return (true);
1138 /* -path is deprecated (at RMS's request) in favour of
1139 * -iwholename. See the node "GNU Manuals" in standards.texi
1140 * for the rationale for this (basically, GNU prefers the use
1141 * of the phrase "file name" to "path name".
1143 * We do not issue a warning that this usage is deprecated
1144 * since HPUX find supports this predicate also.
1146 static boolean
1147 parse_path (char **argv, int *arg_ptr)
1149 return parse_wholename(argv, arg_ptr);
1152 static boolean
1153 parse_wholename (char **argv, int *arg_ptr)
1155 struct predicate *our_pred;
1157 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1158 return (false);
1159 our_pred = insert_primary (pred_path);
1160 our_pred->need_stat = false;
1161 our_pred->args.str = argv[*arg_ptr];
1162 (*arg_ptr)++;
1163 return (true);
1166 static boolean
1167 parse_perm (char **argv, int *arg_ptr)
1169 mode_t perm_val;
1170 int mode_start = 0;
1171 struct mode_change *change;
1172 struct predicate *our_pred;
1174 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1175 return (false);
1177 switch (argv[*arg_ptr][0])
1179 case '-':
1180 case '+':
1181 mode_start = 1;
1182 break;
1183 default:
1184 /* empty */
1185 break;
1188 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1189 if (change == MODE_INVALID)
1190 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1191 else if (change == MODE_MEMORY_EXHAUSTED)
1192 error (1, 0, _("virtual memory exhausted"));
1193 perm_val = mode_adjust (0, change);
1194 mode_free (change);
1196 our_pred = insert_primary (pred_perm);
1198 switch (argv[*arg_ptr][0])
1200 case '-':
1201 our_pred->args.perm.kind = PERM_AT_LEAST;
1202 break;
1203 case '+':
1204 our_pred->args.perm.kind = PERM_ANY;
1205 break;
1206 default:
1207 our_pred->args.perm.kind = PERM_EXACT;
1208 break;
1210 our_pred->args.perm.val = perm_val & MODE_ALL;
1211 (*arg_ptr)++;
1212 return (true);
1215 boolean
1216 parse_print (char **argv, int *arg_ptr)
1218 struct predicate *our_pred;
1220 (void) argv;
1221 (void) arg_ptr;
1223 our_pred = insert_primary (pred_print);
1224 /* -print has the side effect of printing. This prevents us
1225 from doing undesired multiple printing when the user has
1226 already specified -print. */
1227 our_pred->side_effects = true;
1228 our_pred->no_default_print = true;
1229 our_pred->need_stat = false;
1230 return (true);
1233 static boolean
1234 parse_print0 (char **argv, int *arg_ptr)
1236 struct predicate *our_pred;
1238 (void) argv;
1239 (void) arg_ptr;
1241 our_pred = insert_primary (pred_print0);
1242 /* -print0 has the side effect of printing. This prevents us
1243 from doing undesired multiple printing when the user has
1244 already specified -print0. */
1245 our_pred->side_effects = true;
1246 our_pred->no_default_print = true;
1247 our_pred->need_stat = false;
1248 return (true);
1251 static boolean
1252 parse_printf (char **argv, int *arg_ptr)
1254 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1255 return (false);
1256 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1259 static boolean
1260 parse_prune (char **argv, int *arg_ptr)
1262 struct predicate *our_pred;
1264 (void) argv;
1265 (void) arg_ptr;
1267 our_pred = insert_primary (pred_prune);
1268 our_pred->need_stat = false;
1269 /* -prune has a side effect that it does not descend into
1270 the current directory. */
1271 our_pred->side_effects = true;
1272 return (true);
1275 static boolean
1276 parse_quit (char **argv, int *arg_ptr)
1278 struct predicate *our_pred = insert_primary (pred_quit);
1279 (void) argv;
1280 (void) arg_ptr;
1281 our_pred->need_stat = false;
1282 return true;
1286 static boolean
1287 parse_regex (char **argv, int *arg_ptr)
1289 return insert_regex (argv, arg_ptr, false);
1292 static boolean
1293 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1295 struct predicate *our_pred;
1296 struct re_pattern_buffer *re;
1297 const char *error_message;
1299 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1300 return (false);
1301 our_pred = insert_primary (pred_regex);
1302 our_pred->need_stat = false;
1303 re = (struct re_pattern_buffer *)
1304 xmalloc (sizeof (struct re_pattern_buffer));
1305 our_pred->args.regex = re;
1306 re->allocated = 100;
1307 re->buffer = (unsigned char *) xmalloc (re->allocated);
1308 re->fastmap = NULL;
1310 if (ignore_case)
1312 re_syntax_options |= RE_ICASE;
1314 else
1316 re_syntax_options &= ~RE_ICASE;
1318 re->translate = NULL;
1320 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1321 re);
1322 if (error_message)
1323 error (1, 0, "%s", error_message);
1324 (*arg_ptr)++;
1325 return (true);
1328 static boolean
1329 parse_size (char **argv, int *arg_ptr)
1331 struct predicate *our_pred;
1332 uintmax_t num;
1333 enum comparison_type c_type;
1334 int blksize = 512;
1335 int len;
1337 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1338 return (false);
1339 len = strlen (argv[*arg_ptr]);
1340 if (len == 0)
1341 error (1, 0, _("invalid null argument to -size"));
1342 switch (argv[*arg_ptr][len - 1])
1344 case 'b':
1345 blksize = 512;
1346 argv[*arg_ptr][len - 1] = '\0';
1347 break;
1349 case 'c':
1350 blksize = 1;
1351 argv[*arg_ptr][len - 1] = '\0';
1352 break;
1354 case 'k':
1355 blksize = 1024;
1356 argv[*arg_ptr][len - 1] = '\0';
1357 break;
1359 case 'M': /* Megabytes */
1360 blksize = 1024*1024;
1361 argv[*arg_ptr][len - 1] = '\0';
1362 break;
1364 case 'G': /* Gigabytes */
1365 blksize = 1024*1024*1024;
1366 argv[*arg_ptr][len - 1] = '\0';
1367 break;
1369 case 'w':
1370 blksize = 2;
1371 argv[*arg_ptr][len - 1] = '\0';
1372 break;
1374 case '0':
1375 case '1':
1376 case '2':
1377 case '3':
1378 case '4':
1379 case '5':
1380 case '6':
1381 case '7':
1382 case '8':
1383 case '9':
1384 break;
1386 default:
1387 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1389 if (!get_num (argv[*arg_ptr], &num, &c_type))
1390 return (false);
1391 our_pred = insert_primary (pred_size);
1392 our_pred->args.size.kind = c_type;
1393 our_pred->args.size.blocksize = blksize;
1394 our_pred->args.size.size = num;
1395 (*arg_ptr)++;
1396 return (true);
1399 static boolean
1400 parse_true (char **argv, int *arg_ptr)
1402 struct predicate *our_pred;
1404 (void) argv;
1405 (void) arg_ptr;
1407 our_pred = insert_primary (pred_true);
1408 our_pred->need_stat = false;
1409 return (true);
1412 static boolean
1413 parse_type (char **argv, int *arg_ptr)
1415 return insert_type (argv, arg_ptr, pred_type);
1418 static boolean
1419 parse_uid (char **argv, int *arg_ptr)
1421 return (insert_num (argv, arg_ptr, pred_uid));
1424 static boolean
1425 parse_used (char **argv, int *arg_ptr)
1427 struct predicate *our_pred;
1428 uintmax_t num_days;
1429 enum comparison_type c_type;
1430 time_t t;
1432 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1433 return (false);
1434 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1435 return (false);
1436 t = num_days * DAYSECS;
1437 our_pred = insert_primary (pred_used);
1438 our_pred->args.info.kind = c_type;
1439 our_pred->args.info.negative = t < 0;
1440 our_pred->args.info.l_val = t;
1441 (*arg_ptr)++;
1442 return (true);
1445 static boolean
1446 parse_user (char **argv, int *arg_ptr)
1448 struct passwd *cur_pwd;
1449 struct predicate *our_pred;
1450 uid_t uid;
1451 int uid_len;
1453 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1454 return (false);
1455 cur_pwd = getpwnam (argv[*arg_ptr]);
1456 endpwent ();
1457 if (cur_pwd != NULL)
1458 uid = cur_pwd->pw_uid;
1459 else
1461 uid_len = strspn (argv[*arg_ptr], "0123456789");
1462 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1463 return (false);
1464 uid = atoi (argv[*arg_ptr]);
1466 our_pred = insert_primary (pred_user);
1467 our_pred->args.uid = uid;
1468 (*arg_ptr)++;
1469 return (true);
1472 static boolean
1473 parse_version (char **argv, int *arg_ptr)
1475 extern char *version_string;
1476 (void) argv;
1477 (void) arg_ptr;
1479 fflush (stderr);
1480 printf (_("GNU find version %s\n"), version_string);
1481 exit (0);
1484 static boolean
1485 parse_xdev (char **argv, int *arg_ptr)
1487 (void) argv;
1488 (void) arg_ptr;
1489 stay_on_filesystem = true;
1490 return true;
1493 static boolean
1494 parse_ignore_race (char **argv, int *arg_ptr)
1496 (void) argv;
1497 (void) arg_ptr;
1498 ignore_readdir_race = true;
1499 return true;
1502 static boolean
1503 parse_noignore_race (char **argv, int *arg_ptr)
1505 (void) argv;
1506 (void) arg_ptr;
1507 ignore_readdir_race = false;
1508 return true;
1511 static boolean
1512 parse_warn (char **argv, int *arg_ptr)
1514 (void) argv;
1515 (void) arg_ptr;
1516 warnings = true;
1517 return true;
1520 static boolean
1521 parse_xtype (char **argv, int *arg_ptr)
1523 (void) argv;
1524 (void) arg_ptr;
1525 return insert_type (argv, arg_ptr, pred_xtype);
1528 static boolean
1529 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1531 mode_t type_cell;
1532 struct predicate *our_pred;
1534 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1535 || (strlen (argv[*arg_ptr]) != 1))
1536 return (false);
1537 switch (argv[*arg_ptr][0])
1539 case 'b': /* block special */
1540 type_cell = S_IFBLK;
1541 break;
1542 case 'c': /* character special */
1543 type_cell = S_IFCHR;
1544 break;
1545 case 'd': /* directory */
1546 type_cell = S_IFDIR;
1547 break;
1548 case 'f': /* regular file */
1549 type_cell = S_IFREG;
1550 break;
1551 #ifdef S_IFLNK
1552 case 'l': /* symbolic link */
1553 type_cell = S_IFLNK;
1554 break;
1555 #endif
1556 #ifdef S_IFIFO
1557 case 'p': /* pipe */
1558 type_cell = S_IFIFO;
1559 break;
1560 #endif
1561 #ifdef S_IFSOCK
1562 case 's': /* socket */
1563 type_cell = S_IFSOCK;
1564 break;
1565 #endif
1566 #ifdef S_IFDOOR
1567 case 'D': /* Solaris door */
1568 type_cell = S_IFDOOR;
1569 break;
1570 #endif
1571 default: /* None of the above ... nuke 'em. */
1572 return (false);
1574 our_pred = insert_primary (which_pred);
1575 our_pred->args.type = type_cell;
1576 (*arg_ptr)++; /* Move on to next argument. */
1577 return (true);
1580 /* If true, we've determined that the current fprintf predicate
1581 uses stat information. */
1582 static boolean fprintf_stat_needed;
1584 static boolean
1585 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1587 char *format; /* Beginning of unprocessed format string. */
1588 register char *scan; /* Current address in scanning `format'. */
1589 register char *scan2; /* Address inside of element being scanned. */
1590 struct segment **segmentp; /* Address of current segment. */
1591 struct predicate *our_pred;
1593 format = argv[(*arg_ptr)++];
1595 fprintf_stat_needed = false; /* Might be overridden later. */
1596 our_pred = insert_primary (func);
1597 our_pred->side_effects = true;
1598 our_pred->no_default_print = true;
1599 our_pred->args.printf_vec.stream = fp;
1600 segmentp = &our_pred->args.printf_vec.segment;
1601 *segmentp = NULL;
1603 for (scan = format; *scan; scan++)
1605 if (*scan == '\\')
1607 scan2 = scan + 1;
1608 if (*scan2 >= '0' && *scan2 <= '7')
1610 register int n, i;
1612 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1613 i++, scan2++)
1614 n = 8 * n + *scan2 - '0';
1615 scan2--;
1616 *scan = n;
1618 else
1620 switch (*scan2)
1622 case 'a':
1623 *scan = 7;
1624 break;
1625 case 'b':
1626 *scan = '\b';
1627 break;
1628 case 'c':
1629 make_segment (segmentp, format, scan - format, KIND_STOP);
1630 our_pred->need_stat = fprintf_stat_needed;
1631 return (true);
1632 case 'f':
1633 *scan = '\f';
1634 break;
1635 case 'n':
1636 *scan = '\n';
1637 break;
1638 case 'r':
1639 *scan = '\r';
1640 break;
1641 case 't':
1642 *scan = '\t';
1643 break;
1644 case 'v':
1645 *scan = '\v';
1646 break;
1647 case '\\':
1648 /* *scan = '\\'; * it already is */
1649 break;
1650 default:
1651 error (0, 0,
1652 _("warning: unrecognized escape `\\%c'"), *scan2);
1653 scan++;
1654 continue;
1657 segmentp = make_segment (segmentp, format, scan - format + 1,
1658 KIND_PLAIN);
1659 format = scan2 + 1; /* Move past the escape. */
1660 scan = scan2; /* Incremented immediately by `for'. */
1662 else if (*scan == '%')
1664 if (scan[1] == '%')
1666 segmentp = make_segment (segmentp, format, scan - format + 1,
1667 KIND_PLAIN);
1668 scan++;
1669 format = scan + 1;
1670 continue;
1672 /* Scan past flags, width and precision, to verify kind. */
1673 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1674 /* Do nothing. */ ;
1675 while (ISDIGIT (*scan2))
1676 scan2++;
1677 if (*scan2 == '.')
1678 for (scan2++; ISDIGIT (*scan2); scan2++)
1679 /* Do nothing. */ ;
1680 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1682 segmentp = make_segment (segmentp, format, scan2 - format,
1683 (int) *scan2);
1684 scan = scan2;
1685 format = scan + 1;
1687 else if (strchr ("ACT", *scan2) && scan2[1])
1689 segmentp = make_segment (segmentp, format, scan2 - format,
1690 *scan2 | (scan2[1] << 8));
1691 scan = scan2 + 1;
1692 format = scan + 1;
1693 continue;
1695 else
1697 /* An unrecognized % escape. Print the char after the %. */
1698 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1699 *scan2);
1700 segmentp = make_segment (segmentp, format, scan - format,
1701 KIND_PLAIN);
1702 format = scan + 1;
1703 continue;
1708 if (scan > format)
1709 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1710 our_pred->need_stat = fprintf_stat_needed;
1711 return (true);
1714 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1715 from the text in FORMAT, which has length LEN.
1716 Return the address of the `next' pointer of the new segment. */
1718 static struct segment **
1719 make_segment (struct segment **segment, char *format, int len, int kind)
1721 char *fmt;
1723 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1725 (*segment)->kind = kind;
1726 (*segment)->next = NULL;
1727 (*segment)->text_len = len;
1729 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1730 strncpy (fmt, format, len);
1731 fmt += len;
1733 switch (kind & 0xff)
1735 case KIND_PLAIN: /* Plain text string, no % conversion. */
1736 case KIND_STOP: /* Terminate argument, no newline. */
1737 break;
1739 case 'a': /* atime in `ctime' format */
1740 case 'A': /* atime in user-specified strftime format */
1741 case 'c': /* ctime in `ctime' format */
1742 case 'C': /* ctime in user-specified strftime format */
1743 case 'F': /* filesystem type */
1744 case 'g': /* group name */
1745 case 'i': /* inode number */
1746 case 'l': /* object of symlink */
1747 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1748 case 's': /* size in bytes */
1749 case 't': /* mtime in `ctime' format */
1750 case 'T': /* mtime in user-specified strftime format */
1751 case 'u': /* user name */
1752 case 'y': /* file type */
1753 case 'Y': /* symlink pointed file type */
1754 fprintf_stat_needed = true;
1755 /* FALLTHROUGH */
1756 case 'f': /* basename of path */
1757 case 'h': /* leading directories part of path */
1758 case 'H': /* ARGV element file was found under */
1759 case 'p': /* pathname */
1760 case 'P': /* pathname with ARGV element stripped */
1761 *fmt++ = 's';
1762 break;
1764 /* Numeric items that one might expect to honour
1765 * #, 0, + flags but which do not.
1767 case 'G': /* GID number */
1768 case 'U': /* UID number */
1769 case 'b': /* size in 512-byte blocks */
1770 case 'D': /* Filesystem device on which the file exits */
1771 case 'k': /* size in 1K blocks */
1772 case 'n': /* number of links */
1773 fprintf_stat_needed = true;
1774 *fmt++ = 's';
1776 /* Numeric items that DO honour #, 0, + flags.
1778 case 'd': /* depth in search tree (0 = ARGV element) */
1779 *fmt++ = 'd';
1780 break;
1782 case 'm': /* mode as octal number (perms only) */
1783 *fmt++ = 'o';
1784 fprintf_stat_needed = true;
1785 break;
1787 *fmt = '\0';
1789 return (&(*segment)->next);
1792 /* handles both exec and ok predicate */
1793 static boolean
1794 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1796 int start, end; /* Indexes in ARGV of start & end of cmd. */
1797 int num_paths; /* Number of args with path replacements. */
1798 int path_pos; /* Index in array of path replacements. */
1799 int vec_pos; /* Index in array of args. */
1800 struct predicate *our_pred;
1801 struct exec_val *execp; /* Pointer for efficiency. */
1803 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1804 return (false);
1806 /* Count the number of args with path replacements, up until the ';'. */
1807 start = *arg_ptr;
1808 for (end = start, num_paths = 0;
1809 (argv[end] != NULL)
1810 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1811 end++)
1812 if (strstr (argv[end], "{}"))
1813 num_paths++;
1814 /* Fail if no command given or no semicolon found. */
1815 if ((end == start) || (argv[end] == NULL))
1817 *arg_ptr = end;
1818 return (false);
1821 our_pred = insert_primary (func);
1822 our_pred->side_effects = true;
1823 our_pred->no_default_print = true;
1824 execp = &our_pred->args.exec_vec;
1825 execp->paths =
1826 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1827 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1828 /* Record the positions of all args, and the args with path replacements. */
1829 for (end = start, path_pos = vec_pos = 0;
1830 (argv[end] != NULL)
1831 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1832 end++)
1834 register char *p;
1836 execp->paths[path_pos].count = 0;
1837 for (p = argv[end]; *p; ++p)
1838 if (p[0] == '{' && p[1] == '}')
1840 execp->paths[path_pos].count++;
1841 ++p;
1843 if (execp->paths[path_pos].count)
1845 execp->paths[path_pos].offset = vec_pos;
1846 execp->paths[path_pos].origarg = argv[end];
1847 path_pos++;
1849 execp->vec[vec_pos++] = argv[end];
1851 execp->paths[path_pos].offset = -1;
1852 execp->vec[vec_pos] = NULL;
1854 if (argv[end] == NULL)
1855 *arg_ptr = end;
1856 else
1857 *arg_ptr = end + 1;
1858 return (true);
1861 /* Get a number of days and comparison type.
1862 STR is the ASCII representation.
1863 Set *NUM_DAYS to the number of days, taken as being from
1864 the current moment (or possibly midnight). Thus the sense of the
1865 comparison type appears to be reversed.
1866 Set *COMP_TYPE to the kind of comparison that is requested.
1868 Return true if all okay, false if input error.
1870 Used by -atime, -ctime and -mtime (parsers) to
1871 get the appropriate information for a time predicate processor. */
1873 static boolean
1874 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1876 boolean r = get_num (str, num_days, comp_type);
1877 if (r)
1878 switch (*comp_type)
1880 case COMP_LT: *comp_type = COMP_GT; break;
1881 case COMP_GT: *comp_type = COMP_LT; break;
1882 default: break;
1884 return r;
1887 /* Insert a time predicate PRED.
1888 ARGV is a pointer to the argument array.
1889 ARG_PTR is a pointer to an index into the array, incremented if
1890 all went well.
1892 Return true if input is valid, false if not.
1894 A new predicate node is assigned, along with an argument node
1895 obtained with malloc.
1897 Used by -atime, -ctime, and -mtime parsers. */
1899 static boolean
1900 insert_time (char **argv, int *arg_ptr, PFB pred)
1902 struct predicate *our_pred;
1903 uintmax_t num_days;
1904 enum comparison_type c_type;
1905 time_t t;
1907 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1908 return (false);
1909 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1910 return (false);
1912 /* Figure out the timestamp value we are looking for. */
1913 t = ( cur_day_start - num_days * DAYSECS
1914 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1915 #if 1
1916 if (1)
1918 /* We introduce a scope in which 'val' can be declared, for the
1919 * benefit of compilers that are really C89 compilers
1920 * which support intmax_t because config.h #defines it
1922 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1923 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1924 t = val;
1926 /* Check for possibility of an overflow */
1927 if ( (intmax_t)t != val )
1929 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1932 #endif
1934 our_pred = insert_primary (pred);
1935 our_pred->args.info.kind = c_type;
1936 our_pred->args.info.negative = t < 0;
1937 our_pred->args.info.l_val = t;
1938 (*arg_ptr)++;
1939 #ifdef DEBUG
1940 printf (_("inserting %s\n"), our_pred->p_name);
1941 printf (_(" type: %s %s "),
1942 (c_type == COMP_GT) ? "gt" :
1943 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1944 (c_type == COMP_GT) ? " >" :
1945 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1946 t = our_pred->args.info.l_val;
1947 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1948 if (c_type == COMP_EQ)
1950 t = our_pred->args.info.l_val += DAYSECS;
1951 printf (" < %ju %s",
1952 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1953 our_pred->args.info.l_val -= DAYSECS;
1955 #endif /* DEBUG */
1956 return (true);
1959 /* Get a number with comparision information.
1960 The sense of the comparision information is 'normal'; that is,
1961 '+' looks for a count > than the number and '-' less than.
1963 STR is the ASCII representation of the number.
1964 Set *NUM to the number.
1965 Set *COMP_TYPE to the kind of comparison that is requested.
1967 Return true if all okay, false if input error. */
1969 static boolean
1970 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1972 if (str == NULL)
1973 return (false);
1974 switch (str[0])
1976 case '+':
1977 *comp_type = COMP_GT;
1978 str++;
1979 break;
1980 case '-':
1981 *comp_type = COMP_LT;
1982 str++;
1983 break;
1984 default:
1985 *comp_type = COMP_EQ;
1986 break;
1989 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1992 /* Insert a number predicate.
1993 ARGV is a pointer to the argument array.
1994 *ARG_PTR is an index into ARGV, incremented if all went well.
1995 *PRED is the predicate processor to insert.
1997 Return true if input is valid, false if error.
1999 A new predicate node is assigned, along with an argument node
2000 obtained with malloc.
2002 Used by -inum and -links parsers. */
2004 static boolean
2005 insert_num (char **argv, int *arg_ptr, PFB pred)
2007 struct predicate *our_pred;
2008 uintmax_t num;
2009 enum comparison_type c_type;
2011 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2012 return (false);
2013 if (!get_num (argv[*arg_ptr], &num, &c_type))
2014 return (false);
2015 our_pred = insert_primary (pred);
2016 our_pred->args.info.kind = c_type;
2017 our_pred->args.info.l_val = num;
2018 (*arg_ptr)++;
2019 #ifdef DEBUG
2020 printf (_("inserting %s\n"), our_pred->p_name);
2021 printf (_(" type: %s %s "),
2022 (c_type == COMP_GT) ? "gt" :
2023 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2024 (c_type == COMP_GT) ? " >" :
2025 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2026 printf ("%ju\n", our_pred->args.info.l_val);
2027 #endif /* DEBUG */
2028 return (true);
2031 static FILE *
2032 open_output_file (char *path)
2034 FILE *f;
2036 if (!strcmp (path, "/dev/stderr"))
2037 return (stderr);
2038 else if (!strcmp (path, "/dev/stdout"))
2039 return (stdout);
2040 f = fopen (path, "w");
2041 if (f == NULL)
2042 error (1, errno, "%s", path);
2043 return (f);