Readability improvement to the usage message.
[findutils.git] / find / parser.c
blob25070b4de83cddfde0371f03a630285c99f2bf6c
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 (_("\n\
707 default path is the current directory; default expression is -print\n\
708 expression may consist of: operators, options, tests, and actions:\n"));
709 puts (_("\
710 operators (decreasing precedence; -and is implicit where no others are given):\n\
711 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
712 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
713 puts (_("\
714 positional options (always true): -daystart -follow\n\
715 normal options (always true, specified before other expressions):\n\
716 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
717 --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
718 puts (_("\
719 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
720 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
721 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
722 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
723 puts (_("\
724 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
725 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
726 -used N -user NAME -xtype [bcdpfls]\n"));
727 puts (_("\
728 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
729 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
730 -quit\n"));
731 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
732 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
733 email to <bug-findutils@gnu.org>."));
734 exit (0);
737 static boolean
738 parse_ilname (char **argv, int *arg_ptr)
740 struct predicate *our_pred;
742 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
743 return (false);
744 our_pred = insert_primary (pred_ilname);
745 our_pred->args.str = argv[*arg_ptr];
746 (*arg_ptr)++;
747 return (true);
751 /* sanity check the fnmatch() function to make sure
752 * it really is the GNU version.
754 static boolean
755 fnmatch_sanitycheck()
757 /* fprintf(stderr, "Performing find sanity check..."); */
758 if (0 != fnmatch("foo", "foo", 0)
759 || 0 == fnmatch("Foo", "foo", 0)
760 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
762 error (1, 0, _("sanity check of the fnmatch() library function failed."));
763 /* fprintf(stderr, "FAILED\n"); */
764 return false;
767 /* fprintf(stderr, "OK\n"); */
768 return true;
773 static boolean
774 parse_iname (char **argv, int *arg_ptr)
776 struct predicate *our_pred;
778 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
779 return (false);
781 fnmatch_sanitycheck();
783 our_pred = insert_primary (pred_iname);
784 our_pred->need_stat = false;
785 our_pred->args.str = argv[*arg_ptr];
786 (*arg_ptr)++;
787 return (true);
790 static boolean
791 parse_inum (char **argv, int *arg_ptr)
793 return (insert_num (argv, arg_ptr, pred_inum));
796 /* -ipath is deprecated (at RMS's request) in favour of
797 * -iwholename. See the node "GNU Manuals" in standards.texi
798 * for the rationale for this (basically, GNU prefers the use
799 * of the phrase "file name" to "path name"
801 static boolean
802 parse_ipath (char **argv, int *arg_ptr)
804 error (0, 0,
805 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
807 return parse_iwholename(argv, arg_ptr);
810 static boolean
811 parse_iwholename (char **argv, int *arg_ptr)
813 struct predicate *our_pred;
815 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
816 return (false);
818 fnmatch_sanitycheck();
820 our_pred = insert_primary (pred_ipath);
821 our_pred->need_stat = false;
822 our_pred->args.str = argv[*arg_ptr];
823 (*arg_ptr)++;
824 return (true);
827 static boolean
828 parse_iregex (char **argv, int *arg_ptr)
830 return insert_regex (argv, arg_ptr, true);
833 static boolean
834 parse_links (char **argv, int *arg_ptr)
836 return (insert_num (argv, arg_ptr, pred_links));
839 static boolean
840 parse_lname (char **argv, int *arg_ptr)
842 struct predicate *our_pred;
844 (void) argv;
845 (void) arg_ptr;
847 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
848 return (false);
850 fnmatch_sanitycheck();
852 our_pred = insert_primary (pred_lname);
853 our_pred->args.str = argv[*arg_ptr];
854 (*arg_ptr)++;
855 return (true);
858 static boolean
859 parse_ls (char **argv, int *arg_ptr)
861 struct predicate *our_pred;
863 (void) &argv;
864 (void) &arg_ptr;
866 our_pred = insert_primary (pred_ls);
867 our_pred->side_effects = true;
868 our_pred->no_default_print = true;
869 return (true);
872 static boolean
873 parse_maxdepth (char **argv, int *arg_ptr)
875 int depth_len;
877 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
878 return (false);
879 depth_len = strspn (argv[*arg_ptr], "0123456789");
880 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
881 return (false);
882 maxdepth = atoi (argv[*arg_ptr]);
883 if (maxdepth < 0)
884 return (false);
885 (*arg_ptr)++;
886 return (true);
889 static boolean
890 parse_mindepth (char **argv, int *arg_ptr)
892 int depth_len;
894 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
895 return (false);
896 depth_len = strspn (argv[*arg_ptr], "0123456789");
897 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
898 return (false);
899 mindepth = atoi (argv[*arg_ptr]);
900 if (mindepth < 0)
901 return (false);
902 (*arg_ptr)++;
903 return (true);
906 static boolean
907 parse_mmin (char **argv, int *arg_ptr)
909 struct predicate *our_pred;
910 uintmax_t num;
911 enum comparison_type c_type;
912 time_t t;
914 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
915 return (false);
916 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
917 return (false);
918 t = cur_day_start + DAYSECS - num * 60;
919 our_pred = insert_primary (pred_mmin);
920 our_pred->args.info.kind = c_type;
921 our_pred->args.info.negative = t < 0;
922 our_pred->args.info.l_val = t;
923 (*arg_ptr)++;
924 return (true);
927 static boolean
928 parse_mtime (char **argv, int *arg_ptr)
930 return (insert_time (argv, arg_ptr, pred_mtime));
933 static boolean
934 parse_name (char **argv, int *arg_ptr)
936 struct predicate *our_pred;
938 (void) argv;
939 (void) arg_ptr;
941 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
942 return (false);
943 our_pred = insert_primary (pred_name);
944 our_pred->need_stat = false;
945 our_pred->args.str = argv[*arg_ptr];
946 (*arg_ptr)++;
947 return (true);
950 static boolean
951 parse_negate (char **argv, int *arg_ptr)
953 struct predicate *our_pred;
955 (void) &argv;
956 (void) &arg_ptr;
958 our_pred = get_new_pred_chk_op ();
959 our_pred->pred_func = pred_negate;
960 #ifdef DEBUG
961 our_pred->p_name = find_pred_name (pred_negate);
962 #endif /* DEBUG */
963 our_pred->p_type = UNI_OP;
964 our_pred->p_prec = NEGATE_PREC;
965 our_pred->need_stat = false;
966 return (true);
969 static boolean
970 parse_newer (char **argv, int *arg_ptr)
972 struct predicate *our_pred;
973 struct stat stat_newer;
975 (void) argv;
976 (void) arg_ptr;
978 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
979 return (false);
980 if ((*xstat) (argv[*arg_ptr], &stat_newer))
981 error (1, errno, "%s", argv[*arg_ptr]);
982 our_pred = insert_primary (pred_newer);
983 our_pred->args.time = stat_newer.st_mtime;
984 (*arg_ptr)++;
985 return (true);
988 static boolean
989 parse_noleaf (char **argv, int *arg_ptr)
991 (void) &argv;
992 (void) &arg_ptr;
994 no_leaf_check = true;
995 return true;
998 #ifdef CACHE_IDS
999 /* Arbitrary amount by which to increase size
1000 of `uid_unused' and `gid_unused'. */
1001 #define ALLOC_STEP 2048
1003 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1004 char *uid_unused = NULL;
1006 /* Number of elements in `uid_unused'. */
1007 unsigned uid_allocated;
1009 /* Similar for GIDs and group entries. */
1010 char *gid_unused = NULL;
1011 unsigned gid_allocated;
1012 #endif
1014 static boolean
1015 parse_nogroup (char **argv, int *arg_ptr)
1017 struct predicate *our_pred;
1019 (void) &argv;
1020 (void) &arg_ptr;
1022 our_pred = insert_primary (pred_nogroup);
1023 #ifdef CACHE_IDS
1024 if (gid_unused == NULL)
1026 struct group *gr;
1028 gid_allocated = ALLOC_STEP;
1029 gid_unused = xmalloc (gid_allocated);
1030 memset (gid_unused, 1, gid_allocated);
1031 setgrent ();
1032 while ((gr = getgrent ()) != NULL)
1034 if ((unsigned) gr->gr_gid >= gid_allocated)
1036 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
1037 gid_unused = xrealloc (gid_unused, new_allocated);
1038 memset (gid_unused + gid_allocated, 1,
1039 new_allocated - gid_allocated);
1040 gid_allocated = new_allocated;
1042 gid_unused[(unsigned) gr->gr_gid] = 0;
1044 endgrent ();
1046 #endif
1047 return (true);
1050 static boolean
1051 parse_nouser (char **argv, int *arg_ptr)
1053 struct predicate *our_pred;
1054 (void) argv;
1055 (void) arg_ptr;
1058 our_pred = insert_primary (pred_nouser);
1059 #ifdef CACHE_IDS
1060 if (uid_unused == NULL)
1062 struct passwd *pw;
1064 uid_allocated = ALLOC_STEP;
1065 uid_unused = xmalloc (uid_allocated);
1066 memset (uid_unused, 1, uid_allocated);
1067 setpwent ();
1068 while ((pw = getpwent ()) != NULL)
1070 if ((unsigned) pw->pw_uid >= uid_allocated)
1072 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
1073 uid_unused = xrealloc (uid_unused, new_allocated);
1074 memset (uid_unused + uid_allocated, 1,
1075 new_allocated - uid_allocated);
1076 uid_allocated = new_allocated;
1078 uid_unused[(unsigned) pw->pw_uid] = 0;
1080 endpwent ();
1082 #endif
1083 return (true);
1086 static boolean
1087 parse_nowarn (char **argv, int *arg_ptr)
1089 (void) argv;
1090 (void) arg_ptr;
1092 warnings = false;
1093 return true;;
1096 static boolean
1097 parse_ok (char **argv, int *arg_ptr)
1099 return (insert_exec_ok (pred_ok, argv, arg_ptr));
1102 boolean
1103 parse_open (char **argv, int *arg_ptr)
1105 struct predicate *our_pred;
1107 (void) argv;
1108 (void) arg_ptr;
1110 our_pred = get_new_pred_chk_op ();
1111 our_pred->pred_func = pred_open;
1112 #ifdef DEBUG
1113 our_pred->p_name = find_pred_name (pred_open);
1114 #endif /* DEBUG */
1115 our_pred->p_type = OPEN_PAREN;
1116 our_pred->p_prec = NO_PREC;
1117 our_pred->need_stat = false;
1118 return (true);
1121 static boolean
1122 parse_or (char **argv, int *arg_ptr)
1124 struct predicate *our_pred;
1126 (void) argv;
1127 (void) arg_ptr;
1129 our_pred = get_new_pred ();
1130 our_pred->pred_func = pred_or;
1131 #ifdef DEBUG
1132 our_pred->p_name = find_pred_name (pred_or);
1133 #endif /* DEBUG */
1134 our_pred->p_type = BI_OP;
1135 our_pred->p_prec = OR_PREC;
1136 our_pred->need_stat = false;
1137 return (true);
1140 /* -path is deprecated (at RMS's request) in favour of
1141 * -iwholename. See the node "GNU Manuals" in standards.texi
1142 * for the rationale for this (basically, GNU prefers the use
1143 * of the phrase "file name" to "path name".
1145 * We do not issue a warning that this usage is deprecated
1146 * since HPUX find supports this predicate also.
1148 static boolean
1149 parse_path (char **argv, int *arg_ptr)
1151 return parse_wholename(argv, arg_ptr);
1154 static boolean
1155 parse_wholename (char **argv, int *arg_ptr)
1157 struct predicate *our_pred;
1159 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1160 return (false);
1161 our_pred = insert_primary (pred_path);
1162 our_pred->need_stat = false;
1163 our_pred->args.str = argv[*arg_ptr];
1164 (*arg_ptr)++;
1165 return (true);
1168 static boolean
1169 parse_perm (char **argv, int *arg_ptr)
1171 mode_t perm_val;
1172 int mode_start = 0;
1173 struct mode_change *change;
1174 struct predicate *our_pred;
1176 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1177 return (false);
1179 switch (argv[*arg_ptr][0])
1181 case '-':
1182 case '+':
1183 mode_start = 1;
1184 break;
1185 default:
1186 /* empty */
1187 break;
1190 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1191 if (change == MODE_INVALID)
1192 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1193 else if (change == MODE_MEMORY_EXHAUSTED)
1194 error (1, 0, _("virtual memory exhausted"));
1195 perm_val = mode_adjust (0, change);
1196 mode_free (change);
1198 our_pred = insert_primary (pred_perm);
1200 switch (argv[*arg_ptr][0])
1202 case '-':
1203 our_pred->args.perm.kind = PERM_AT_LEAST;
1204 break;
1205 case '+':
1206 our_pred->args.perm.kind = PERM_ANY;
1207 break;
1208 default:
1209 our_pred->args.perm.kind = PERM_EXACT;
1210 break;
1212 our_pred->args.perm.val = perm_val & MODE_ALL;
1213 (*arg_ptr)++;
1214 return (true);
1217 boolean
1218 parse_print (char **argv, int *arg_ptr)
1220 struct predicate *our_pred;
1222 (void) argv;
1223 (void) arg_ptr;
1225 our_pred = insert_primary (pred_print);
1226 /* -print has the side effect of printing. This prevents us
1227 from doing undesired multiple printing when the user has
1228 already specified -print. */
1229 our_pred->side_effects = true;
1230 our_pred->no_default_print = true;
1231 our_pred->need_stat = false;
1232 return (true);
1235 static boolean
1236 parse_print0 (char **argv, int *arg_ptr)
1238 struct predicate *our_pred;
1240 (void) argv;
1241 (void) arg_ptr;
1243 our_pred = insert_primary (pred_print0);
1244 /* -print0 has the side effect of printing. This prevents us
1245 from doing undesired multiple printing when the user has
1246 already specified -print0. */
1247 our_pred->side_effects = true;
1248 our_pred->no_default_print = true;
1249 our_pred->need_stat = false;
1250 return (true);
1253 static boolean
1254 parse_printf (char **argv, int *arg_ptr)
1256 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1257 return (false);
1258 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1261 static boolean
1262 parse_prune (char **argv, int *arg_ptr)
1264 struct predicate *our_pred;
1266 (void) argv;
1267 (void) arg_ptr;
1269 our_pred = insert_primary (pred_prune);
1270 our_pred->need_stat = false;
1271 /* -prune has a side effect that it does not descend into
1272 the current directory. */
1273 our_pred->side_effects = true;
1274 return (true);
1277 static boolean
1278 parse_quit (char **argv, int *arg_ptr)
1280 struct predicate *our_pred = insert_primary (pred_quit);
1281 (void) argv;
1282 (void) arg_ptr;
1283 our_pred->need_stat = false;
1284 return true;
1288 static boolean
1289 parse_regex (char **argv, int *arg_ptr)
1291 return insert_regex (argv, arg_ptr, false);
1294 static boolean
1295 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1297 struct predicate *our_pred;
1298 struct re_pattern_buffer *re;
1299 const char *error_message;
1301 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1302 return (false);
1303 our_pred = insert_primary (pred_regex);
1304 our_pred->need_stat = false;
1305 re = (struct re_pattern_buffer *)
1306 xmalloc (sizeof (struct re_pattern_buffer));
1307 our_pred->args.regex = re;
1308 re->allocated = 100;
1309 re->buffer = (unsigned char *) xmalloc (re->allocated);
1310 re->fastmap = NULL;
1312 if (ignore_case)
1314 re_syntax_options |= RE_ICASE;
1316 else
1318 re_syntax_options &= ~RE_ICASE;
1320 re->translate = NULL;
1322 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1323 re);
1324 if (error_message)
1325 error (1, 0, "%s", error_message);
1326 (*arg_ptr)++;
1327 return (true);
1330 static boolean
1331 parse_size (char **argv, int *arg_ptr)
1333 struct predicate *our_pred;
1334 uintmax_t num;
1335 enum comparison_type c_type;
1336 int blksize = 512;
1337 int len;
1339 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1340 return (false);
1341 len = strlen (argv[*arg_ptr]);
1342 if (len == 0)
1343 error (1, 0, _("invalid null argument to -size"));
1344 switch (argv[*arg_ptr][len - 1])
1346 case 'b':
1347 blksize = 512;
1348 argv[*arg_ptr][len - 1] = '\0';
1349 break;
1351 case 'c':
1352 blksize = 1;
1353 argv[*arg_ptr][len - 1] = '\0';
1354 break;
1356 case 'k':
1357 blksize = 1024;
1358 argv[*arg_ptr][len - 1] = '\0';
1359 break;
1361 case 'M': /* Megabytes */
1362 blksize = 1024*1024;
1363 argv[*arg_ptr][len - 1] = '\0';
1364 break;
1366 case 'G': /* Gigabytes */
1367 blksize = 1024*1024*1024;
1368 argv[*arg_ptr][len - 1] = '\0';
1369 break;
1371 case 'w':
1372 blksize = 2;
1373 argv[*arg_ptr][len - 1] = '\0';
1374 break;
1376 case '0':
1377 case '1':
1378 case '2':
1379 case '3':
1380 case '4':
1381 case '5':
1382 case '6':
1383 case '7':
1384 case '8':
1385 case '9':
1386 break;
1388 default:
1389 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1391 if (!get_num (argv[*arg_ptr], &num, &c_type))
1392 return (false);
1393 our_pred = insert_primary (pred_size);
1394 our_pred->args.size.kind = c_type;
1395 our_pred->args.size.blocksize = blksize;
1396 our_pred->args.size.size = num;
1397 (*arg_ptr)++;
1398 return (true);
1401 static boolean
1402 parse_true (char **argv, int *arg_ptr)
1404 struct predicate *our_pred;
1406 (void) argv;
1407 (void) arg_ptr;
1409 our_pred = insert_primary (pred_true);
1410 our_pred->need_stat = false;
1411 return (true);
1414 static boolean
1415 parse_type (char **argv, int *arg_ptr)
1417 return insert_type (argv, arg_ptr, pred_type);
1420 static boolean
1421 parse_uid (char **argv, int *arg_ptr)
1423 return (insert_num (argv, arg_ptr, pred_uid));
1426 static boolean
1427 parse_used (char **argv, int *arg_ptr)
1429 struct predicate *our_pred;
1430 uintmax_t num_days;
1431 enum comparison_type c_type;
1432 time_t t;
1434 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1435 return (false);
1436 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1437 return (false);
1438 t = num_days * DAYSECS;
1439 our_pred = insert_primary (pred_used);
1440 our_pred->args.info.kind = c_type;
1441 our_pred->args.info.negative = t < 0;
1442 our_pred->args.info.l_val = t;
1443 (*arg_ptr)++;
1444 return (true);
1447 static boolean
1448 parse_user (char **argv, int *arg_ptr)
1450 struct passwd *cur_pwd;
1451 struct predicate *our_pred;
1452 uid_t uid;
1453 int uid_len;
1455 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1456 return (false);
1457 cur_pwd = getpwnam (argv[*arg_ptr]);
1458 endpwent ();
1459 if (cur_pwd != NULL)
1460 uid = cur_pwd->pw_uid;
1461 else
1463 uid_len = strspn (argv[*arg_ptr], "0123456789");
1464 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1465 return (false);
1466 uid = atoi (argv[*arg_ptr]);
1468 our_pred = insert_primary (pred_user);
1469 our_pred->args.uid = uid;
1470 (*arg_ptr)++;
1471 return (true);
1474 static boolean
1475 parse_version (char **argv, int *arg_ptr)
1477 extern char *version_string;
1478 (void) argv;
1479 (void) arg_ptr;
1481 fflush (stderr);
1482 printf (_("GNU find version %s\n"), version_string);
1483 exit (0);
1486 static boolean
1487 parse_xdev (char **argv, int *arg_ptr)
1489 (void) argv;
1490 (void) arg_ptr;
1491 stay_on_filesystem = true;
1492 return true;
1495 static boolean
1496 parse_ignore_race (char **argv, int *arg_ptr)
1498 (void) argv;
1499 (void) arg_ptr;
1500 ignore_readdir_race = true;
1501 return true;
1504 static boolean
1505 parse_noignore_race (char **argv, int *arg_ptr)
1507 (void) argv;
1508 (void) arg_ptr;
1509 ignore_readdir_race = false;
1510 return true;
1513 static boolean
1514 parse_warn (char **argv, int *arg_ptr)
1516 (void) argv;
1517 (void) arg_ptr;
1518 warnings = true;
1519 return true;
1522 static boolean
1523 parse_xtype (char **argv, int *arg_ptr)
1525 (void) argv;
1526 (void) arg_ptr;
1527 return insert_type (argv, arg_ptr, pred_xtype);
1530 static boolean
1531 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1533 mode_t type_cell;
1534 struct predicate *our_pred;
1536 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1537 || (strlen (argv[*arg_ptr]) != 1))
1538 return (false);
1539 switch (argv[*arg_ptr][0])
1541 case 'b': /* block special */
1542 type_cell = S_IFBLK;
1543 break;
1544 case 'c': /* character special */
1545 type_cell = S_IFCHR;
1546 break;
1547 case 'd': /* directory */
1548 type_cell = S_IFDIR;
1549 break;
1550 case 'f': /* regular file */
1551 type_cell = S_IFREG;
1552 break;
1553 #ifdef S_IFLNK
1554 case 'l': /* symbolic link */
1555 type_cell = S_IFLNK;
1556 break;
1557 #endif
1558 #ifdef S_IFIFO
1559 case 'p': /* pipe */
1560 type_cell = S_IFIFO;
1561 break;
1562 #endif
1563 #ifdef S_IFSOCK
1564 case 's': /* socket */
1565 type_cell = S_IFSOCK;
1566 break;
1567 #endif
1568 #ifdef S_IFDOOR
1569 case 'D': /* Solaris door */
1570 type_cell = S_IFDOOR;
1571 break;
1572 #endif
1573 default: /* None of the above ... nuke 'em. */
1574 return (false);
1576 our_pred = insert_primary (which_pred);
1577 our_pred->args.type = type_cell;
1578 (*arg_ptr)++; /* Move on to next argument. */
1579 return (true);
1582 /* If true, we've determined that the current fprintf predicate
1583 uses stat information. */
1584 static boolean fprintf_stat_needed;
1586 static boolean
1587 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1589 char *format; /* Beginning of unprocessed format string. */
1590 register char *scan; /* Current address in scanning `format'. */
1591 register char *scan2; /* Address inside of element being scanned. */
1592 struct segment **segmentp; /* Address of current segment. */
1593 struct predicate *our_pred;
1595 format = argv[(*arg_ptr)++];
1597 fprintf_stat_needed = false; /* Might be overridden later. */
1598 our_pred = insert_primary (func);
1599 our_pred->side_effects = true;
1600 our_pred->no_default_print = true;
1601 our_pred->args.printf_vec.stream = fp;
1602 segmentp = &our_pred->args.printf_vec.segment;
1603 *segmentp = NULL;
1605 for (scan = format; *scan; scan++)
1607 if (*scan == '\\')
1609 scan2 = scan + 1;
1610 if (*scan2 >= '0' && *scan2 <= '7')
1612 register int n, i;
1614 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1615 i++, scan2++)
1616 n = 8 * n + *scan2 - '0';
1617 scan2--;
1618 *scan = n;
1620 else
1622 switch (*scan2)
1624 case 'a':
1625 *scan = 7;
1626 break;
1627 case 'b':
1628 *scan = '\b';
1629 break;
1630 case 'c':
1631 make_segment (segmentp, format, scan - format, KIND_STOP);
1632 our_pred->need_stat = fprintf_stat_needed;
1633 return (true);
1634 case 'f':
1635 *scan = '\f';
1636 break;
1637 case 'n':
1638 *scan = '\n';
1639 break;
1640 case 'r':
1641 *scan = '\r';
1642 break;
1643 case 't':
1644 *scan = '\t';
1645 break;
1646 case 'v':
1647 *scan = '\v';
1648 break;
1649 case '\\':
1650 /* *scan = '\\'; * it already is */
1651 break;
1652 default:
1653 error (0, 0,
1654 _("warning: unrecognized escape `\\%c'"), *scan2);
1655 scan++;
1656 continue;
1659 segmentp = make_segment (segmentp, format, scan - format + 1,
1660 KIND_PLAIN);
1661 format = scan2 + 1; /* Move past the escape. */
1662 scan = scan2; /* Incremented immediately by `for'. */
1664 else if (*scan == '%')
1666 if (scan[1] == '%')
1668 segmentp = make_segment (segmentp, format, scan - format + 1,
1669 KIND_PLAIN);
1670 scan++;
1671 format = scan + 1;
1672 continue;
1674 /* Scan past flags, width and precision, to verify kind. */
1675 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1676 /* Do nothing. */ ;
1677 while (ISDIGIT (*scan2))
1678 scan2++;
1679 if (*scan2 == '.')
1680 for (scan2++; ISDIGIT (*scan2); scan2++)
1681 /* Do nothing. */ ;
1682 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1684 segmentp = make_segment (segmentp, format, scan2 - format,
1685 (int) *scan2);
1686 scan = scan2;
1687 format = scan + 1;
1689 else if (strchr ("ACT", *scan2) && scan2[1])
1691 segmentp = make_segment (segmentp, format, scan2 - format,
1692 *scan2 | (scan2[1] << 8));
1693 scan = scan2 + 1;
1694 format = scan + 1;
1695 continue;
1697 else
1699 /* An unrecognized % escape. Print the char after the %. */
1700 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1701 *scan2);
1702 segmentp = make_segment (segmentp, format, scan - format,
1703 KIND_PLAIN);
1704 format = scan + 1;
1705 continue;
1710 if (scan > format)
1711 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1712 our_pred->need_stat = fprintf_stat_needed;
1713 return (true);
1716 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1717 from the text in FORMAT, which has length LEN.
1718 Return the address of the `next' pointer of the new segment. */
1720 static struct segment **
1721 make_segment (struct segment **segment, char *format, int len, int kind)
1723 char *fmt;
1725 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1727 (*segment)->kind = kind;
1728 (*segment)->next = NULL;
1729 (*segment)->text_len = len;
1731 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1732 strncpy (fmt, format, len);
1733 fmt += len;
1735 switch (kind & 0xff)
1737 case KIND_PLAIN: /* Plain text string, no % conversion. */
1738 case KIND_STOP: /* Terminate argument, no newline. */
1739 break;
1741 case 'a': /* atime in `ctime' format */
1742 case 'A': /* atime in user-specified strftime format */
1743 case 'c': /* ctime in `ctime' format */
1744 case 'C': /* ctime in user-specified strftime format */
1745 case 'F': /* filesystem type */
1746 case 'g': /* group name */
1747 case 'i': /* inode number */
1748 case 'l': /* object of symlink */
1749 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1750 case 's': /* size in bytes */
1751 case 't': /* mtime in `ctime' format */
1752 case 'T': /* mtime in user-specified strftime format */
1753 case 'u': /* user name */
1754 case 'y': /* file type */
1755 case 'Y': /* symlink pointed file type */
1756 fprintf_stat_needed = true;
1757 /* FALLTHROUGH */
1758 case 'f': /* basename of path */
1759 case 'h': /* leading directories part of path */
1760 case 'H': /* ARGV element file was found under */
1761 case 'p': /* pathname */
1762 case 'P': /* pathname with ARGV element stripped */
1763 *fmt++ = 's';
1764 break;
1766 /* Numeric items that one might expect to honour
1767 * #, 0, + flags but which do not.
1769 case 'G': /* GID number */
1770 case 'U': /* UID number */
1771 case 'b': /* size in 512-byte blocks */
1772 case 'D': /* Filesystem device on which the file exits */
1773 case 'k': /* size in 1K blocks */
1774 case 'n': /* number of links */
1775 fprintf_stat_needed = true;
1776 *fmt++ = 's';
1778 /* Numeric items that DO honour #, 0, + flags.
1780 case 'd': /* depth in search tree (0 = ARGV element) */
1781 *fmt++ = 'd';
1782 break;
1784 case 'm': /* mode as octal number (perms only) */
1785 *fmt++ = 'o';
1786 fprintf_stat_needed = true;
1787 break;
1789 *fmt = '\0';
1791 return (&(*segment)->next);
1794 /* handles both exec and ok predicate */
1795 static boolean
1796 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1798 int start, end; /* Indexes in ARGV of start & end of cmd. */
1799 int num_paths; /* Number of args with path replacements. */
1800 int path_pos; /* Index in array of path replacements. */
1801 int vec_pos; /* Index in array of args. */
1802 struct predicate *our_pred;
1803 struct exec_val *execp; /* Pointer for efficiency. */
1805 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1806 return (false);
1808 /* Count the number of args with path replacements, up until the ';'. */
1809 start = *arg_ptr;
1810 for (end = start, num_paths = 0;
1811 (argv[end] != NULL)
1812 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1813 end++)
1814 if (strstr (argv[end], "{}"))
1815 num_paths++;
1816 /* Fail if no command given or no semicolon found. */
1817 if ((end == start) || (argv[end] == NULL))
1819 *arg_ptr = end;
1820 return (false);
1823 our_pred = insert_primary (func);
1824 our_pred->side_effects = true;
1825 our_pred->no_default_print = true;
1826 execp = &our_pred->args.exec_vec;
1827 execp->paths =
1828 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1829 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1830 /* Record the positions of all args, and the args with path replacements. */
1831 for (end = start, path_pos = vec_pos = 0;
1832 (argv[end] != NULL)
1833 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1834 end++)
1836 register char *p;
1838 execp->paths[path_pos].count = 0;
1839 for (p = argv[end]; *p; ++p)
1840 if (p[0] == '{' && p[1] == '}')
1842 execp->paths[path_pos].count++;
1843 ++p;
1845 if (execp->paths[path_pos].count)
1847 execp->paths[path_pos].offset = vec_pos;
1848 execp->paths[path_pos].origarg = argv[end];
1849 path_pos++;
1851 execp->vec[vec_pos++] = argv[end];
1853 execp->paths[path_pos].offset = -1;
1854 execp->vec[vec_pos] = NULL;
1856 if (argv[end] == NULL)
1857 *arg_ptr = end;
1858 else
1859 *arg_ptr = end + 1;
1860 return (true);
1863 /* Get a number of days and comparison type.
1864 STR is the ASCII representation.
1865 Set *NUM_DAYS to the number of days, taken as being from
1866 the current moment (or possibly midnight). Thus the sense of the
1867 comparison type appears to be reversed.
1868 Set *COMP_TYPE to the kind of comparison that is requested.
1870 Return true if all okay, false if input error.
1872 Used by -atime, -ctime and -mtime (parsers) to
1873 get the appropriate information for a time predicate processor. */
1875 static boolean
1876 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1878 boolean r = get_num (str, num_days, comp_type);
1879 if (r)
1880 switch (*comp_type)
1882 case COMP_LT: *comp_type = COMP_GT; break;
1883 case COMP_GT: *comp_type = COMP_LT; break;
1884 default: break;
1886 return r;
1889 /* Insert a time predicate PRED.
1890 ARGV is a pointer to the argument array.
1891 ARG_PTR is a pointer to an index into the array, incremented if
1892 all went well.
1894 Return true if input is valid, false if not.
1896 A new predicate node is assigned, along with an argument node
1897 obtained with malloc.
1899 Used by -atime, -ctime, and -mtime parsers. */
1901 static boolean
1902 insert_time (char **argv, int *arg_ptr, PFB pred)
1904 struct predicate *our_pred;
1905 uintmax_t num_days;
1906 enum comparison_type c_type;
1907 time_t t;
1909 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1910 return (false);
1911 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1912 return (false);
1914 /* Figure out the timestamp value we are looking for. */
1915 t = ( cur_day_start - num_days * DAYSECS
1916 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1917 #if 1
1918 if (1)
1920 /* We introduce a scope in which 'val' can be declared, for the
1921 * benefit of compilers that are really C89 compilers
1922 * which support intmax_t because config.h #defines it
1924 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1925 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1926 t = val;
1928 /* Check for possibility of an overflow */
1929 if ( (intmax_t)t != val )
1931 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1934 #endif
1936 our_pred = insert_primary (pred);
1937 our_pred->args.info.kind = c_type;
1938 our_pred->args.info.negative = t < 0;
1939 our_pred->args.info.l_val = t;
1940 (*arg_ptr)++;
1941 #ifdef DEBUG
1942 fprintf (stderr, _("inserting %s\n"), our_pred->p_name);
1943 fprintf (stderr, _(" type: %s %s "),
1944 (c_type == COMP_GT) ? "gt" :
1945 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1946 (c_type == COMP_GT) ? " >" :
1947 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1948 t = our_pred->args.info.l_val;
1949 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1950 if (c_type == COMP_EQ)
1952 t = our_pred->args.info.l_val += DAYSECS;
1953 fprintf (stderr,
1954 " < %ju %s",
1955 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1956 our_pred->args.info.l_val -= DAYSECS;
1958 #endif /* DEBUG */
1959 return (true);
1962 /* Get a number with comparision information.
1963 The sense of the comparision information is 'normal'; that is,
1964 '+' looks for a count > than the number and '-' less than.
1966 STR is the ASCII representation of the number.
1967 Set *NUM to the number.
1968 Set *COMP_TYPE to the kind of comparison that is requested.
1970 Return true if all okay, false if input error. */
1972 static boolean
1973 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1975 if (str == NULL)
1976 return (false);
1977 switch (str[0])
1979 case '+':
1980 *comp_type = COMP_GT;
1981 str++;
1982 break;
1983 case '-':
1984 *comp_type = COMP_LT;
1985 str++;
1986 break;
1987 default:
1988 *comp_type = COMP_EQ;
1989 break;
1992 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1995 /* Insert a number predicate.
1996 ARGV is a pointer to the argument array.
1997 *ARG_PTR is an index into ARGV, incremented if all went well.
1998 *PRED is the predicate processor to insert.
2000 Return true if input is valid, false if error.
2002 A new predicate node is assigned, along with an argument node
2003 obtained with malloc.
2005 Used by -inum and -links parsers. */
2007 static boolean
2008 insert_num (char **argv, int *arg_ptr, PFB pred)
2010 struct predicate *our_pred;
2011 uintmax_t num;
2012 enum comparison_type c_type;
2014 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
2015 return (false);
2016 if (!get_num (argv[*arg_ptr], &num, &c_type))
2017 return (false);
2018 our_pred = insert_primary (pred);
2019 our_pred->args.info.kind = c_type;
2020 our_pred->args.info.l_val = num;
2021 (*arg_ptr)++;
2022 #ifdef DEBUG
2023 fprintf (stderr, _("inserting %s\n"), our_pred->p_name);
2024 fprintf (stderr, _(" type: %s %s "),
2025 (c_type == COMP_GT) ? "gt" :
2026 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
2027 (c_type == COMP_GT) ? " >" :
2028 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
2029 fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
2030 #endif /* DEBUG */
2031 return (true);
2034 static FILE *
2035 open_output_file (char *path)
2037 FILE *f;
2039 if (!strcmp (path, "/dev/stderr"))
2040 return (stderr);
2041 else if (!strcmp (path, "/dev/stdout"))
2042 return (stdout);
2043 f = fopen (path, "w");
2044 if (f == NULL)
2045 error (1, errno, "%s", path);
2046 return (f);