Resolves Savannah bug 4380, that updatedb generates an empty database if one of the...
[findutils.git] / find / parser.c
blob00245cb5b0a1a0479e7f16767531439ff4bd8a13
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., 9 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 "modechange.h"
25 #include "modetype.h"
26 #include "xstrtol.h"
28 #if ENABLE_NLS
29 # include <libintl.h>
30 # define _(Text) gettext (Text)
31 #else
32 # define _(Text) Text
33 #endif
34 #ifdef gettext_noop
35 # define N_(String) gettext_noop (String)
36 #else
37 # define N_(String) (String)
38 #endif
40 #if !defined (isascii) || defined (STDC_HEADERS)
41 #ifdef isascii
42 #undef isascii
43 #endif
44 #define isascii(c) 1
45 #endif
47 #define ISDIGIT(c) (isascii (c) && isdigit (c))
48 #define ISUPPER(c) (isascii (c) && isupper (c))
50 #ifndef HAVE_ENDGRENT
51 #define endgrent()
52 #endif
53 #ifndef HAVE_ENDPWENT
54 #define endpwent()
55 #endif
57 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
58 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
59 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
60 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
61 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
62 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
64 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
65 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
97 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
99 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
100 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
101 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
103 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
104 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
106 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
107 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
108 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
109 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
110 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
112 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
113 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
114 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
115 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
116 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
117 static boolean parse_ignore_race PARAMS((char *argv[], int *arg_ptr));
118 static boolean parse_noignore_race PARAMS((char *argv[], int *arg_ptr));
119 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
121 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
122 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
123 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
124 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
125 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
126 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
127 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
128 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
129 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
130 static FILE *open_output_file PARAMS((char *path));
132 #ifdef DEBUG
133 char *find_pred_name PARAMS((PFB pred_func));
134 #endif /* DEBUG */
136 struct parser_table
138 char *parser_name;
139 PFB parser_func;
142 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
143 If they are in some Unix versions of find, they are marked `Unix'. */
145 static struct parser_table const parse_table[] =
147 {"!", parse_negate},
148 {"not", parse_negate}, /* GNU */
149 {"(", parse_open},
150 {")", parse_close},
151 {",", parse_comma}, /* GNU */
152 {"a", parse_and},
153 {"amin", parse_amin}, /* GNU */
154 {"and", parse_and}, /* GNU */
155 {"anewer", parse_anewer}, /* GNU */
156 {"atime", parse_atime},
157 {"cmin", parse_cmin}, /* GNU */
158 {"cnewer", parse_cnewer}, /* GNU */
159 #ifdef UNIMPLEMENTED_UNIX
160 /* It's pretty ugly for find to know about archive formats.
161 Plus what it could do with cpio archives is very limited.
162 Better to leave it out. */
163 {"cpio", parse_cpio}, /* Unix */
164 #endif
165 {"ctime", parse_ctime},
166 {"daystart", parse_daystart}, /* GNU */
167 {"depth", parse_depth},
168 {"empty", parse_empty}, /* GNU */
169 {"exec", parse_exec},
170 {"false", parse_false}, /* GNU */
171 {"fls", parse_fls}, /* GNU */
172 {"follow", parse_follow}, /* GNU, Unix */
173 {"fprint", parse_fprint}, /* GNU */
174 {"fprint0", parse_fprint0}, /* GNU */
175 {"fprintf", parse_fprintf}, /* GNU */
176 {"fstype", parse_fstype}, /* GNU, Unix */
177 {"gid", parse_gid}, /* GNU */
178 {"group", parse_group},
179 {"help", parse_help}, /* GNU */
180 {"-help", parse_help}, /* GNU */
181 {"ignore_readdir_race", parse_ignore_race}, /* GNU */
182 {"ilname", parse_ilname}, /* GNU */
183 {"iname", parse_iname}, /* GNU */
184 {"inum", parse_inum}, /* GNU, Unix */
185 {"ipath", parse_ipath}, /* GNU */
186 {"iregex", parse_iregex}, /* GNU */
187 {"links", parse_links},
188 {"lname", parse_lname}, /* GNU */
189 {"ls", parse_ls}, /* GNU, Unix */
190 {"maxdepth", parse_maxdepth}, /* GNU */
191 {"mindepth", parse_mindepth}, /* GNU */
192 {"mmin", parse_mmin}, /* GNU */
193 {"mount", parse_xdev}, /* Unix */
194 {"mtime", parse_mtime},
195 {"name", parse_name},
196 #ifdef UNIMPLEMENTED_UNIX
197 {"ncpio", parse_ncpio}, /* Unix */
198 #endif
199 {"newer", parse_newer},
200 {"noleaf", parse_noleaf}, /* GNU */
201 {"nogroup", parse_nogroup},
202 {"nouser", parse_nouser},
203 {"noignore_readdir_race", parse_noignore_race}, /* GNU */
204 {"o", parse_or},
205 {"or", parse_or}, /* GNU */
206 {"ok", parse_ok},
207 {"path", parse_path}, /* GNU, HP-UX */
208 {"perm", parse_perm},
209 {"print", parse_print},
210 {"print0", parse_print0}, /* GNU */
211 {"printf", parse_printf}, /* GNU */
212 {"prune", parse_prune},
213 {"regex", parse_regex}, /* GNU */
214 {"size", parse_size},
215 {"true", parse_true}, /* GNU */
216 {"type", parse_type},
217 {"uid", parse_uid}, /* GNU */
218 {"used", parse_used}, /* GNU */
219 {"user", parse_user},
220 {"version", parse_version}, /* GNU */
221 {"-version", parse_version}, /* GNU */
222 {"xdev", parse_xdev},
223 {"xtype", parse_xtype}, /* GNU */
224 {0, 0}
227 /* Return a pointer to the parser function to invoke for predicate
228 SEARCH_NAME.
229 Return NULL if SEARCH_NAME is not a valid predicate name. */
232 find_parser (char *search_name)
234 int i;
236 if (*search_name == '-')
237 search_name++;
238 for (i = 0; parse_table[i].parser_name != 0; i++)
239 if (strcmp (parse_table[i].parser_name, search_name) == 0)
240 return (parse_table[i].parser_func);
241 return (NULL);
244 /* The parsers are responsible to continue scanning ARGV for
245 their arguments. Each parser knows what is and isn't
246 allowed for itself.
248 ARGV is the argument array.
249 *ARG_PTR is the index to start at in ARGV,
250 updated to point beyond the last element consumed.
252 The predicate structure is updated with the new information. */
254 static boolean
255 parse_amin (char **argv, int *arg_ptr)
257 struct predicate *our_pred;
258 uintmax_t num;
259 enum comparison_type c_type;
260 time_t t;
262 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
263 return (false);
264 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
265 return (false);
266 t = cur_day_start + DAYSECS - num * 60;
267 our_pred = insert_primary (pred_amin);
268 our_pred->args.info.kind = c_type;
269 our_pred->args.info.negative = t < 0;
270 our_pred->args.info.l_val = t;
271 (*arg_ptr)++;
272 return (true);
275 static boolean
276 parse_and (char **argv, int *arg_ptr)
278 struct predicate *our_pred;
280 our_pred = get_new_pred ();
281 our_pred->pred_func = pred_and;
282 #ifdef DEBUG
283 our_pred->p_name = find_pred_name (pred_and);
284 #endif /* DEBUG */
285 our_pred->p_type = BI_OP;
286 our_pred->p_prec = AND_PREC;
287 our_pred->need_stat = false;
288 return (true);
291 static boolean
292 parse_anewer (char **argv, int *arg_ptr)
294 struct predicate *our_pred;
295 struct stat stat_newer;
297 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
298 return (false);
299 if ((*xstat) (argv[*arg_ptr], &stat_newer))
300 error (1, errno, "%s", argv[*arg_ptr]);
301 our_pred = insert_primary (pred_anewer);
302 our_pred->args.time = stat_newer.st_mtime;
303 (*arg_ptr)++;
304 return (true);
307 static boolean
308 parse_atime (char **argv, int *arg_ptr)
310 return (insert_time (argv, arg_ptr, pred_atime));
313 boolean
314 parse_close (char **argv, int *arg_ptr)
316 struct predicate *our_pred;
318 our_pred = get_new_pred ();
319 our_pred->pred_func = pred_close;
320 #ifdef DEBUG
321 our_pred->p_name = find_pred_name (pred_close);
322 #endif /* DEBUG */
323 our_pred->p_type = CLOSE_PAREN;
324 our_pred->p_prec = NO_PREC;
325 our_pred->need_stat = false;
326 return (true);
329 static boolean
330 parse_cmin (char **argv, int *arg_ptr)
332 struct predicate *our_pred;
333 uintmax_t num;
334 enum comparison_type c_type;
335 time_t t;
337 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
338 return (false);
339 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
340 return (false);
341 t = cur_day_start + DAYSECS - num * 60;
342 our_pred = insert_primary (pred_cmin);
343 our_pred->args.info.kind = c_type;
344 our_pred->args.info.negative = t < 0;
345 our_pred->args.info.l_val = t;
346 (*arg_ptr)++;
347 return (true);
350 static boolean
351 parse_cnewer (char **argv, int *arg_ptr)
353 struct predicate *our_pred;
354 struct stat stat_newer;
356 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
357 return (false);
358 if ((*xstat) (argv[*arg_ptr], &stat_newer))
359 error (1, errno, "%s", argv[*arg_ptr]);
360 our_pred = insert_primary (pred_cnewer);
361 our_pred->args.time = stat_newer.st_mtime;
362 (*arg_ptr)++;
363 return (true);
366 static boolean
367 parse_comma (char **argv, int *arg_ptr)
369 struct predicate *our_pred;
371 our_pred = get_new_pred ();
372 our_pred->pred_func = pred_comma;
373 #ifdef DEBUG
374 our_pred->p_name = find_pred_name (pred_comma);
375 #endif /* DEBUG */
376 our_pred->p_type = BI_OP;
377 our_pred->p_prec = COMMA_PREC;
378 our_pred->need_stat = false;
379 return (true);
382 static boolean
383 parse_ctime (char **argv, int *arg_ptr)
385 return (insert_time (argv, arg_ptr, pred_ctime));
388 static boolean
389 parse_daystart (char **argv, int *arg_ptr)
391 struct tm *local;
393 if (full_days == false)
395 cur_day_start += DAYSECS;
396 local = localtime (&cur_day_start);
397 cur_day_start -= (local
398 ? (local->tm_sec + local->tm_min * 60
399 + local->tm_hour * 3600)
400 : cur_day_start % DAYSECS);
401 full_days = true;
403 return (true);
406 static boolean
407 parse_depth (char **argv, int *arg_ptr)
409 do_dir_first = false;
410 return (true);
413 static boolean
414 parse_empty (char **argv, int *arg_ptr)
416 insert_primary (pred_empty);
417 return (true);
420 static boolean
421 parse_exec (char **argv, int *arg_ptr)
423 return (insert_exec_ok (pred_exec, argv, arg_ptr));
426 static boolean
427 parse_false (char **argv, int *arg_ptr)
429 struct predicate *our_pred;
431 our_pred = insert_primary (pred_false);
432 our_pred->need_stat = false;
433 return (true);
436 static boolean
437 parse_fls (char **argv, int *arg_ptr)
439 struct predicate *our_pred;
441 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
442 return (false);
443 our_pred = insert_primary (pred_fls);
444 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
445 our_pred->side_effects = true;
446 our_pred->no_default_print = true;
447 (*arg_ptr)++;
448 return (true);
451 static boolean
452 parse_fprintf (char **argv, int *arg_ptr)
454 FILE *fp;
456 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
457 return (false);
458 if (argv[*arg_ptr + 1] == NULL)
460 /* Ensure we get "missing arg" message, not "invalid arg". */
461 (*arg_ptr)++;
462 return (false);
464 fp = open_output_file (argv[*arg_ptr]);
465 (*arg_ptr)++;
466 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
469 static boolean
470 parse_follow (char **argv, int *arg_ptr)
472 dereference = true;
473 xstat = stat;
474 no_leaf_check = true;
475 return (true);
478 static boolean
479 parse_fprint (char **argv, int *arg_ptr)
481 struct predicate *our_pred;
483 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
484 return (false);
485 our_pred = insert_primary (pred_fprint);
486 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
487 our_pred->side_effects = true;
488 our_pred->no_default_print = true;
489 our_pred->need_stat = false;
490 (*arg_ptr)++;
491 return (true);
494 static boolean
495 parse_fprint0 (char **argv, int *arg_ptr)
497 struct predicate *our_pred;
499 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
500 return (false);
501 our_pred = insert_primary (pred_fprint0);
502 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
503 our_pred->side_effects = true;
504 our_pred->no_default_print = true;
505 our_pred->need_stat = false;
506 (*arg_ptr)++;
507 return (true);
510 static boolean
511 parse_fstype (char **argv, int *arg_ptr)
513 struct predicate *our_pred;
515 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
516 return (false);
517 our_pred = insert_primary (pred_fstype);
518 our_pred->args.str = argv[*arg_ptr];
519 (*arg_ptr)++;
520 return (true);
523 static boolean
524 parse_gid (char **argv, int *arg_ptr)
526 return (insert_num (argv, arg_ptr, pred_gid));
529 static boolean
530 parse_group (char **argv, int *arg_ptr)
532 struct group *cur_gr;
533 struct predicate *our_pred;
534 gid_t gid;
535 int gid_len;
537 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
538 return (false);
539 cur_gr = getgrnam (argv[*arg_ptr]);
540 endgrent ();
541 if (cur_gr != NULL)
542 gid = cur_gr->gr_gid;
543 else
545 gid_len = strspn (argv[*arg_ptr], "0123456789");
546 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
547 return (false);
548 gid = atoi (argv[*arg_ptr]);
550 our_pred = insert_primary (pred_group);
551 our_pred->args.gid = gid;
552 (*arg_ptr)++;
553 return (true);
556 static boolean
557 parse_help (char **argv, int *arg_ptr)
559 printf (_("\
560 Usage: %s [path...] [expression]\n"), program_name);
561 puts (_("\
562 default path is the current directory; default expression is -print\n\
563 expression may consist of:\n\
564 operators (decreasing precedence; -and is implicit where no others are given):\n\
565 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
566 puts (_("\
567 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
568 options (always true): -daystart -depth -follow --help\n\
569 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
570 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
571 puts (_("\
572 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
573 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
574 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
575 puts (_("\
576 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
577 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
578 -xtype [bcdpfls]\n"));
579 puts (_("\
580 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
581 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
582 puts (_("\nReport bugs to <bug-findutils@gnu.org>."));
583 exit (0);
586 static boolean
587 parse_ilname (char **argv, int *arg_ptr)
589 struct predicate *our_pred;
591 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
592 return (false);
593 our_pred = insert_primary (pred_ilname);
594 our_pred->args.str = argv[*arg_ptr];
595 (*arg_ptr)++;
596 return (true);
599 static boolean
600 parse_iname (char **argv, int *arg_ptr)
602 struct predicate *our_pred;
604 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
605 return (false);
606 our_pred = insert_primary (pred_iname);
607 our_pred->need_stat = false;
608 our_pred->args.str = argv[*arg_ptr];
609 (*arg_ptr)++;
610 return (true);
613 static boolean
614 parse_inum (char **argv, int *arg_ptr)
616 return (insert_num (argv, arg_ptr, pred_inum));
619 static boolean
620 parse_ipath (char **argv, int *arg_ptr)
622 struct predicate *our_pred;
624 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
625 return (false);
626 our_pred = insert_primary (pred_ipath);
627 our_pred->need_stat = false;
628 our_pred->args.str = argv[*arg_ptr];
629 (*arg_ptr)++;
630 return (true);
633 static boolean
634 parse_iregex (char **argv, int *arg_ptr)
636 return insert_regex (argv, arg_ptr, true);
639 static boolean
640 parse_links (char **argv, int *arg_ptr)
642 return (insert_num (argv, arg_ptr, pred_links));
645 static boolean
646 parse_lname (char **argv, int *arg_ptr)
648 struct predicate *our_pred;
650 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
651 return (false);
652 our_pred = insert_primary (pred_lname);
653 our_pred->args.str = argv[*arg_ptr];
654 (*arg_ptr)++;
655 return (true);
658 static boolean
659 parse_ls (char **argv, int *arg_ptr)
661 struct predicate *our_pred;
663 our_pred = insert_primary (pred_ls);
664 our_pred->side_effects = true;
665 our_pred->no_default_print = true;
666 return (true);
669 static boolean
670 parse_maxdepth (char **argv, int *arg_ptr)
672 int depth_len;
674 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
675 return (false);
676 depth_len = strspn (argv[*arg_ptr], "0123456789");
677 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
678 return (false);
679 maxdepth = atoi (argv[*arg_ptr]);
680 if (maxdepth < 0)
681 return (false);
682 (*arg_ptr)++;
683 return (true);
686 static boolean
687 parse_mindepth (char **argv, int *arg_ptr)
689 int depth_len;
691 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
692 return (false);
693 depth_len = strspn (argv[*arg_ptr], "0123456789");
694 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
695 return (false);
696 mindepth = atoi (argv[*arg_ptr]);
697 if (mindepth < 0)
698 return (false);
699 (*arg_ptr)++;
700 return (true);
703 static boolean
704 parse_mmin (char **argv, int *arg_ptr)
706 struct predicate *our_pred;
707 uintmax_t num;
708 enum comparison_type c_type;
709 time_t t;
711 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
712 return (false);
713 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
714 return (false);
715 t = cur_day_start + DAYSECS - num * 60;
716 our_pred = insert_primary (pred_mmin);
717 our_pred->args.info.kind = c_type;
718 our_pred->args.info.negative = t < 0;
719 our_pred->args.info.l_val = t;
720 (*arg_ptr)++;
721 return (true);
724 static boolean
725 parse_mtime (char **argv, int *arg_ptr)
727 return (insert_time (argv, arg_ptr, pred_mtime));
730 static boolean
731 parse_name (char **argv, int *arg_ptr)
733 struct predicate *our_pred;
735 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
736 return (false);
737 our_pred = insert_primary (pred_name);
738 our_pred->need_stat = false;
739 our_pred->args.str = argv[*arg_ptr];
740 (*arg_ptr)++;
741 return (true);
744 static boolean
745 parse_negate (char **argv, int *arg_ptr)
747 struct predicate *our_pred;
749 our_pred = get_new_pred_chk_op ();
750 our_pred->pred_func = pred_negate;
751 #ifdef DEBUG
752 our_pred->p_name = find_pred_name (pred_negate);
753 #endif /* DEBUG */
754 our_pred->p_type = UNI_OP;
755 our_pred->p_prec = NEGATE_PREC;
756 our_pred->need_stat = false;
757 return (true);
760 static boolean
761 parse_newer (char **argv, int *arg_ptr)
763 struct predicate *our_pred;
764 struct stat stat_newer;
766 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
767 return (false);
768 if ((*xstat) (argv[*arg_ptr], &stat_newer))
769 error (1, errno, "%s", argv[*arg_ptr]);
770 our_pred = insert_primary (pred_newer);
771 our_pred->args.time = stat_newer.st_mtime;
772 (*arg_ptr)++;
773 return (true);
776 static boolean
777 parse_noleaf (char **argv, int *arg_ptr)
779 no_leaf_check = true;
780 return true;
783 #ifdef CACHE_IDS
784 /* Arbitrary amount by which to increase size
785 of `uid_unused' and `gid_unused'. */
786 #define ALLOC_STEP 2048
788 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
789 char *uid_unused = NULL;
791 /* Number of elements in `uid_unused'. */
792 unsigned uid_allocated;
794 /* Similar for GIDs and group entries. */
795 char *gid_unused = NULL;
796 unsigned gid_allocated;
797 #endif
799 static boolean
800 parse_nogroup (char **argv, int *arg_ptr)
802 struct predicate *our_pred;
804 our_pred = insert_primary (pred_nogroup);
805 #ifdef CACHE_IDS
806 if (gid_unused == NULL)
808 struct group *gr;
810 gid_allocated = ALLOC_STEP;
811 gid_unused = xmalloc (gid_allocated);
812 memset (gid_unused, 1, gid_allocated);
813 setgrent ();
814 while ((gr = getgrent ()) != NULL)
816 if ((unsigned) gr->gr_gid >= gid_allocated)
818 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
819 gid_unused = xrealloc (gid_unused, new_allocated);
820 memset (gid_unused + gid_allocated, 1,
821 new_allocated - gid_allocated);
822 gid_allocated = new_allocated;
824 gid_unused[(unsigned) gr->gr_gid] = 0;
826 endgrent ();
828 #endif
829 return (true);
832 static boolean
833 parse_nouser (char **argv, int *arg_ptr)
835 struct predicate *our_pred;
837 our_pred = insert_primary (pred_nouser);
838 #ifdef CACHE_IDS
839 if (uid_unused == NULL)
841 struct passwd *pw;
843 uid_allocated = ALLOC_STEP;
844 uid_unused = xmalloc (uid_allocated);
845 memset (uid_unused, 1, uid_allocated);
846 setpwent ();
847 while ((pw = getpwent ()) != NULL)
849 if ((unsigned) pw->pw_uid >= uid_allocated)
851 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
852 uid_unused = xrealloc (uid_unused, new_allocated);
853 memset (uid_unused + uid_allocated, 1,
854 new_allocated - uid_allocated);
855 uid_allocated = new_allocated;
857 uid_unused[(unsigned) pw->pw_uid] = 0;
859 endpwent ();
861 #endif
862 return (true);
865 static boolean
866 parse_ok (char **argv, int *arg_ptr)
868 return (insert_exec_ok (pred_ok, argv, arg_ptr));
871 boolean
872 parse_open (char **argv, int *arg_ptr)
874 struct predicate *our_pred;
876 our_pred = get_new_pred_chk_op ();
877 our_pred->pred_func = pred_open;
878 #ifdef DEBUG
879 our_pred->p_name = find_pred_name (pred_open);
880 #endif /* DEBUG */
881 our_pred->p_type = OPEN_PAREN;
882 our_pred->p_prec = NO_PREC;
883 our_pred->need_stat = false;
884 return (true);
887 static boolean
888 parse_or (char **argv, int *arg_ptr)
890 struct predicate *our_pred;
892 our_pred = get_new_pred ();
893 our_pred->pred_func = pred_or;
894 #ifdef DEBUG
895 our_pred->p_name = find_pred_name (pred_or);
896 #endif /* DEBUG */
897 our_pred->p_type = BI_OP;
898 our_pred->p_prec = OR_PREC;
899 our_pred->need_stat = false;
900 return (true);
903 static boolean
904 parse_path (char **argv, int *arg_ptr)
906 struct predicate *our_pred;
908 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
909 return (false);
910 our_pred = insert_primary (pred_path);
911 our_pred->need_stat = false;
912 our_pred->args.str = argv[*arg_ptr];
913 (*arg_ptr)++;
914 return (true);
917 static boolean
918 parse_perm (char **argv, int *arg_ptr)
920 mode_t perm_val;
921 int mode_start = 0;
922 struct mode_change *change;
923 struct predicate *our_pred;
925 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
926 return (false);
928 switch (argv[*arg_ptr][0])
930 case '-':
931 case '+':
932 mode_start = 1;
933 break;
934 default:
935 /* empty */
936 break;
939 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
940 if (change == MODE_INVALID)
941 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
942 else if (change == MODE_MEMORY_EXHAUSTED)
943 error (1, 0, _("virtual memory exhausted"));
944 perm_val = mode_adjust (0, change);
945 mode_free (change);
947 our_pred = insert_primary (pred_perm);
949 switch (argv[*arg_ptr][0])
951 case '-':
952 our_pred->args.perm.kind = PERM_AT_LEAST;
953 break;
954 case '+':
955 our_pred->args.perm.kind = PERM_ANY;
956 break;
957 default:
958 our_pred->args.perm.kind = PERM_EXACT;
959 break;
961 our_pred->args.perm.val = perm_val & MODE_ALL;
962 (*arg_ptr)++;
963 return (true);
966 boolean
967 parse_print (char **argv, int *arg_ptr)
969 struct predicate *our_pred;
971 our_pred = insert_primary (pred_print);
972 /* -print has the side effect of printing. This prevents us
973 from doing undesired multiple printing when the user has
974 already specified -print. */
975 our_pred->side_effects = true;
976 our_pred->no_default_print = true;
977 our_pred->need_stat = false;
978 return (true);
981 static boolean
982 parse_print0 (char **argv, int *arg_ptr)
984 struct predicate *our_pred;
986 our_pred = insert_primary (pred_print0);
987 /* -print0 has the side effect of printing. This prevents us
988 from doing undesired multiple printing when the user has
989 already specified -print0. */
990 our_pred->side_effects = true;
991 our_pred->no_default_print = true;
992 our_pred->need_stat = false;
993 return (true);
996 static boolean
997 parse_printf (char **argv, int *arg_ptr)
999 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1000 return (false);
1001 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1004 static boolean
1005 parse_prune (char **argv, int *arg_ptr)
1007 struct predicate *our_pred;
1009 our_pred = insert_primary (pred_prune);
1010 our_pred->need_stat = false;
1011 /* -prune has a side effect that it does not descend into
1012 the current directory. */
1013 our_pred->side_effects = true;
1014 return (true);
1017 static boolean
1018 parse_regex (char **argv, int *arg_ptr)
1020 return insert_regex (argv, arg_ptr, false);
1023 static boolean
1024 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1026 struct predicate *our_pred;
1027 struct re_pattern_buffer *re;
1028 const char *error_message;
1030 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1031 return (false);
1032 our_pred = insert_primary (pred_regex);
1033 our_pred->need_stat = false;
1034 re = (struct re_pattern_buffer *)
1035 xmalloc (sizeof (struct re_pattern_buffer));
1036 our_pred->args.regex = re;
1037 re->allocated = 100;
1038 re->buffer = (unsigned char *) xmalloc (re->allocated);
1039 re->fastmap = NULL;
1041 if (ignore_case)
1043 unsigned i;
1045 re->translate = xmalloc (256);
1046 /* Map uppercase characters to corresponding lowercase ones. */
1047 for (i = 0; i < 256; i++)
1048 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1050 else
1051 re->translate = NULL;
1053 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1054 re);
1055 if (error_message)
1056 error (1, 0, "%s", error_message);
1057 (*arg_ptr)++;
1058 return (true);
1061 static boolean
1062 parse_size (char **argv, int *arg_ptr)
1064 struct predicate *our_pred;
1065 uintmax_t num;
1066 enum comparison_type c_type;
1067 int blksize = 512;
1068 int len;
1070 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1071 return (false);
1072 len = strlen (argv[*arg_ptr]);
1073 if (len == 0)
1074 error (1, 0, _("invalid null argument to -size"));
1075 switch (argv[*arg_ptr][len - 1])
1077 case 'b':
1078 blksize = 512;
1079 argv[*arg_ptr][len - 1] = '\0';
1080 break;
1082 case 'c':
1083 blksize = 1;
1084 argv[*arg_ptr][len - 1] = '\0';
1085 break;
1087 case 'k':
1088 blksize = 1024;
1089 argv[*arg_ptr][len - 1] = '\0';
1090 break;
1092 case 'M': /* Megabytes */
1093 blksize = 1024*1024;
1094 argv[*arg_ptr][len - 1] = '\0';
1095 break;
1097 case 'G': /* Gigabytes */
1098 blksize = 1024*1024*1024;
1099 argv[*arg_ptr][len - 1] = '\0';
1100 break;
1102 case 'w':
1103 blksize = 2;
1104 argv[*arg_ptr][len - 1] = '\0';
1105 break;
1107 case '0':
1108 case '1':
1109 case '2':
1110 case '3':
1111 case '4':
1112 case '5':
1113 case '6':
1114 case '7':
1115 case '8':
1116 case '9':
1117 break;
1119 default:
1120 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1122 if (!get_num (argv[*arg_ptr], &num, &c_type))
1123 return (false);
1124 our_pred = insert_primary (pred_size);
1125 our_pred->args.size.kind = c_type;
1126 our_pred->args.size.blocksize = blksize;
1127 our_pred->args.size.size = num;
1128 (*arg_ptr)++;
1129 return (true);
1132 static boolean
1133 parse_true (char **argv, int *arg_ptr)
1135 struct predicate *our_pred;
1137 our_pred = insert_primary (pred_true);
1138 our_pred->need_stat = false;
1139 return (true);
1142 static boolean
1143 parse_type (char **argv, int *arg_ptr)
1145 return insert_type (argv, arg_ptr, pred_type);
1148 static boolean
1149 parse_uid (char **argv, int *arg_ptr)
1151 return (insert_num (argv, arg_ptr, pred_uid));
1154 static boolean
1155 parse_used (char **argv, int *arg_ptr)
1157 struct predicate *our_pred;
1158 uintmax_t num_days;
1159 enum comparison_type c_type;
1160 time_t t;
1162 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1163 return (false);
1164 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1165 return (false);
1166 t = num_days * DAYSECS;
1167 our_pred = insert_primary (pred_used);
1168 our_pred->args.info.kind = c_type;
1169 our_pred->args.info.negative = t < 0;
1170 our_pred->args.info.l_val = t;
1171 (*arg_ptr)++;
1172 return (true);
1175 static boolean
1176 parse_user (char **argv, int *arg_ptr)
1178 struct passwd *cur_pwd;
1179 struct predicate *our_pred;
1180 uid_t uid;
1181 int uid_len;
1183 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1184 return (false);
1185 cur_pwd = getpwnam (argv[*arg_ptr]);
1186 endpwent ();
1187 if (cur_pwd != NULL)
1188 uid = cur_pwd->pw_uid;
1189 else
1191 uid_len = strspn (argv[*arg_ptr], "0123456789");
1192 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1193 return (false);
1194 uid = atoi (argv[*arg_ptr]);
1196 our_pred = insert_primary (pred_user);
1197 our_pred->args.uid = uid;
1198 (*arg_ptr)++;
1199 return (true);
1202 static boolean
1203 parse_version (char **argv, int *arg_ptr)
1205 extern char *version_string;
1207 fflush (stderr);
1208 printf (_("GNU find version %s\n"), version_string);
1209 exit (0);
1212 static boolean
1213 parse_xdev (char **argv, int *arg_ptr)
1215 stay_on_filesystem = true;
1216 return true;
1219 static boolean
1220 parse_ignore_race (char **argv, int *arg_ptr)
1222 ignore_readdir_race = true;
1223 return true;
1226 static boolean
1227 parse_noignore_race (char **argv, int *arg_ptr)
1229 ignore_readdir_race = false;
1230 return true;
1233 static boolean
1234 parse_xtype (char **argv, int *arg_ptr)
1236 return insert_type (argv, arg_ptr, pred_xtype);
1239 static boolean
1240 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1242 mode_t type_cell;
1243 struct predicate *our_pred;
1245 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1246 || (strlen (argv[*arg_ptr]) != 1))
1247 return (false);
1248 switch (argv[*arg_ptr][0])
1250 case 'b': /* block special */
1251 type_cell = S_IFBLK;
1252 break;
1253 case 'c': /* character special */
1254 type_cell = S_IFCHR;
1255 break;
1256 case 'd': /* directory */
1257 type_cell = S_IFDIR;
1258 break;
1259 case 'f': /* regular file */
1260 type_cell = S_IFREG;
1261 break;
1262 #ifdef S_IFLNK
1263 case 'l': /* symbolic link */
1264 type_cell = S_IFLNK;
1265 break;
1266 #endif
1267 #ifdef S_IFIFO
1268 case 'p': /* pipe */
1269 type_cell = S_IFIFO;
1270 break;
1271 #endif
1272 #ifdef S_IFSOCK
1273 case 's': /* socket */
1274 type_cell = S_IFSOCK;
1275 break;
1276 #endif
1277 #ifdef S_IFDOOR
1278 case 'D': /* Solaris door */
1279 type_cell = S_IFDOOR;
1280 break;
1281 #endif
1282 default: /* None of the above ... nuke 'em. */
1283 return (false);
1285 our_pred = insert_primary (which_pred);
1286 our_pred->args.type = type_cell;
1287 (*arg_ptr)++; /* Move on to next argument. */
1288 return (true);
1291 /* If true, we've determined that the current fprintf predicate
1292 uses stat information. */
1293 static boolean fprintf_stat_needed;
1295 static boolean
1296 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1298 char *format; /* Beginning of unprocessed format string. */
1299 register char *scan; /* Current address in scanning `format'. */
1300 register char *scan2; /* Address inside of element being scanned. */
1301 struct segment **segmentp; /* Address of current segment. */
1302 struct predicate *our_pred;
1304 format = argv[(*arg_ptr)++];
1306 fprintf_stat_needed = false; /* Might be overridden later. */
1307 our_pred = insert_primary (func);
1308 our_pred->side_effects = true;
1309 our_pred->no_default_print = true;
1310 our_pred->args.printf_vec.stream = fp;
1311 segmentp = &our_pred->args.printf_vec.segment;
1312 *segmentp = NULL;
1314 for (scan = format; *scan; scan++)
1316 if (*scan == '\\')
1318 scan2 = scan + 1;
1319 if (*scan2 >= '0' && *scan2 <= '7')
1321 register int n, i;
1323 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1324 i++, scan2++)
1325 n = 8 * n + *scan2 - '0';
1326 scan2--;
1327 *scan = n;
1329 else
1331 switch (*scan2)
1333 case 'a':
1334 *scan = 7;
1335 break;
1336 case 'b':
1337 *scan = '\b';
1338 break;
1339 case 'c':
1340 make_segment (segmentp, format, scan - format, KIND_STOP);
1341 our_pred->need_stat = fprintf_stat_needed;
1342 return (true);
1343 case 'f':
1344 *scan = '\f';
1345 break;
1346 case 'n':
1347 *scan = '\n';
1348 break;
1349 case 'r':
1350 *scan = '\r';
1351 break;
1352 case 't':
1353 *scan = '\t';
1354 break;
1355 case 'v':
1356 *scan = '\v';
1357 break;
1358 case '\\':
1359 /* *scan = '\\'; * it already is */
1360 break;
1361 default:
1362 error (0, 0,
1363 _("warning: unrecognized escape `\\%c'"), *scan2);
1364 scan++;
1365 continue;
1368 segmentp = make_segment (segmentp, format, scan - format + 1,
1369 KIND_PLAIN);
1370 format = scan2 + 1; /* Move past the escape. */
1371 scan = scan2; /* Incremented immediately by `for'. */
1373 else if (*scan == '%')
1375 if (scan[1] == '%')
1377 segmentp = make_segment (segmentp, format, scan - format + 1,
1378 KIND_PLAIN);
1379 scan++;
1380 format = scan + 1;
1381 continue;
1383 /* Scan past flags, width and precision, to verify kind. */
1384 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1385 /* Do nothing. */ ;
1386 while (ISDIGIT (*scan2))
1387 scan2++;
1388 if (*scan2 == '.')
1389 for (scan2++; ISDIGIT (*scan2); scan2++)
1390 /* Do nothing. */ ;
1391 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1393 segmentp = make_segment (segmentp, format, scan2 - format,
1394 (int) *scan2);
1395 scan = scan2;
1396 format = scan + 1;
1398 else if (strchr ("ACT", *scan2) && scan2[1])
1400 segmentp = make_segment (segmentp, format, scan2 - format,
1401 *scan2 | (scan2[1] << 8));
1402 scan = scan2 + 1;
1403 format = scan + 1;
1404 continue;
1406 else
1408 /* An unrecognized % escape. Print the char after the %. */
1409 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1410 *scan2);
1411 segmentp = make_segment (segmentp, format, scan - format,
1412 KIND_PLAIN);
1413 format = scan + 1;
1414 continue;
1419 if (scan > format)
1420 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1421 our_pred->need_stat = fprintf_stat_needed;
1422 return (true);
1425 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1426 from the text in FORMAT, which has length LEN.
1427 Return the address of the `next' pointer of the new segment. */
1429 static struct segment **
1430 make_segment (struct segment **segment, char *format, int len, int kind)
1432 char *fmt;
1434 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1436 (*segment)->kind = kind;
1437 (*segment)->next = NULL;
1438 (*segment)->text_len = len;
1440 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1441 strncpy (fmt, format, len);
1442 fmt += len;
1444 switch (kind & 0xff)
1446 case KIND_PLAIN: /* Plain text string, no % conversion. */
1447 case KIND_STOP: /* Terminate argument, no newline. */
1448 break;
1450 case 'a': /* atime in `ctime' format */
1451 case 'A': /* atime in user-specified strftime format */
1452 case 'b': /* size in 512-byte blocks */
1453 case 'c': /* ctime in `ctime' format */
1454 case 'C': /* ctime in user-specified strftime format */
1455 case 'F': /* filesystem type */
1456 case 'G': /* GID number */
1457 case 'g': /* group name */
1458 case 'i': /* inode number */
1459 case 'k': /* size in 1K blocks */
1460 case 'l': /* object of symlink */
1461 case 'n': /* number of links */
1462 case 's': /* size in bytes */
1463 case 't': /* mtime in `ctime' format */
1464 case 'T': /* mtime in user-specified strftime format */
1465 case 'U': /* UID number */
1466 case 'u': /* user name */
1467 fprintf_stat_needed = true;
1468 /* FALLTHROUGH */
1469 case 'f': /* basename of path */
1470 case 'h': /* leading directories part of path */
1471 case 'H': /* ARGV element file was found under */
1472 case 'p': /* pathname */
1473 case 'P': /* pathname with ARGV element stripped */
1474 *fmt++ = 's';
1475 break;
1477 case 'd': /* depth in search tree (0 = ARGV element) */
1478 *fmt++ = 'd';
1479 break;
1481 case 'm': /* mode as octal number (perms only) */
1482 *fmt++ = 'o';
1483 fprintf_stat_needed = true;
1484 break;
1486 *fmt = '\0';
1488 return (&(*segment)->next);
1491 /* handles both exec and ok predicate */
1492 static boolean
1493 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1495 int start, end; /* Indexes in ARGV of start & end of cmd. */
1496 int num_paths; /* Number of args with path replacements. */
1497 int path_pos; /* Index in array of path replacements. */
1498 int vec_pos; /* Index in array of args. */
1499 struct predicate *our_pred;
1500 struct exec_val *execp; /* Pointer for efficiency. */
1502 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1503 return (false);
1505 /* Count the number of args with path replacements, up until the ';'. */
1506 start = *arg_ptr;
1507 for (end = start, num_paths = 0;
1508 (argv[end] != NULL)
1509 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1510 end++)
1511 if (strstr (argv[end], "{}"))
1512 num_paths++;
1513 /* Fail if no command given or no semicolon found. */
1514 if ((end == start) || (argv[end] == NULL))
1516 *arg_ptr = end;
1517 return (false);
1520 our_pred = insert_primary (func);
1521 our_pred->side_effects = true;
1522 our_pred->no_default_print = true;
1523 execp = &our_pred->args.exec_vec;
1524 execp->paths =
1525 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1526 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1527 /* Record the positions of all args, and the args with path replacements. */
1528 for (end = start, path_pos = vec_pos = 0;
1529 (argv[end] != NULL)
1530 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1531 end++)
1533 register char *p;
1535 execp->paths[path_pos].count = 0;
1536 for (p = argv[end]; *p; ++p)
1537 if (p[0] == '{' && p[1] == '}')
1539 execp->paths[path_pos].count++;
1540 ++p;
1542 if (execp->paths[path_pos].count)
1544 execp->paths[path_pos].offset = vec_pos;
1545 execp->paths[path_pos].origarg = argv[end];
1546 path_pos++;
1548 execp->vec[vec_pos++] = argv[end];
1550 execp->paths[path_pos].offset = -1;
1551 execp->vec[vec_pos] = NULL;
1553 if (argv[end] == NULL)
1554 *arg_ptr = end;
1555 else
1556 *arg_ptr = end + 1;
1557 return (true);
1560 /* Get a number of days and comparison type.
1561 STR is the ASCII representation.
1562 Set *NUM_DAYS to the number of days, taken as being from
1563 the current moment (or possibly midnight). Thus the sense of the
1564 comparison type appears to be reversed.
1565 Set *COMP_TYPE to the kind of comparison that is requested.
1567 Return true if all okay, false if input error.
1569 Used by -atime, -ctime and -mtime (parsers) to
1570 get the appropriate information for a time predicate processor. */
1572 static boolean
1573 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1575 boolean r = get_num (str, num_days, comp_type);
1576 if (r)
1577 switch (*comp_type)
1579 case COMP_LT: *comp_type = COMP_GT; break;
1580 case COMP_GT: *comp_type = COMP_LT; break;
1581 default: break;
1583 return r;
1586 /* Insert a time predicate PRED.
1587 ARGV is a pointer to the argument array.
1588 ARG_PTR is a pointer to an index into the array, incremented if
1589 all went well.
1591 Return true if input is valid, false if not.
1593 A new predicate node is assigned, along with an argument node
1594 obtained with malloc.
1596 Used by -atime, -ctime, and -mtime parsers. */
1598 static boolean
1599 insert_time (char **argv, int *arg_ptr, PFB pred)
1601 struct predicate *our_pred;
1602 uintmax_t num_days;
1603 enum comparison_type c_type;
1604 time_t t;
1606 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1607 return (false);
1608 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1609 return (false);
1611 /* Figure out the timestamp value we are looking for. */
1612 t = ( cur_day_start - num_days * DAYSECS
1613 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1614 #if 1
1615 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1616 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1617 t = val;
1619 /* Check for possibility of an overflow */
1620 if ( (intmax_t)t != val )
1622 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1624 #endif
1626 our_pred = insert_primary (pred);
1627 our_pred->args.info.kind = c_type;
1628 our_pred->args.info.negative = t < 0;
1629 our_pred->args.info.l_val = t;
1630 (*arg_ptr)++;
1631 #ifdef DEBUG
1632 printf (_("inserting %s\n"), our_pred->p_name);
1633 printf (_(" type: %s %s "),
1634 (c_type == COMP_GT) ? "gt" :
1635 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1636 (c_type == COMP_GT) ? " >" :
1637 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1638 t = our_pred->args.info.l_val;
1639 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1640 if (c_type == COMP_EQ)
1642 t = our_pred->args.info.l_val += DAYSECS;
1643 printf (" < %ju %s",
1644 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1645 our_pred->args.info.l_val -= DAYSECS;
1647 #endif /* DEBUG */
1648 return (true);
1651 /* Get a number with comparision information.
1652 The sense of the comparision information is 'normal'; that is,
1653 '+' looks for a count > than the number and '-' less than.
1655 STR is the ASCII representation of the number.
1656 Set *NUM to the number.
1657 Set *COMP_TYPE to the kind of comparison that is requested.
1659 Return true if all okay, false if input error. */
1661 static boolean
1662 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1664 int len_num; /* Length of field. */
1666 if (str == NULL)
1667 return (false);
1668 switch (str[0])
1670 case '+':
1671 *comp_type = COMP_GT;
1672 str++;
1673 break;
1674 case '-':
1675 *comp_type = COMP_LT;
1676 str++;
1677 break;
1678 default:
1679 *comp_type = COMP_EQ;
1680 break;
1683 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1686 /* Insert a number predicate.
1687 ARGV is a pointer to the argument array.
1688 *ARG_PTR is an index into ARGV, incremented if all went well.
1689 *PRED is the predicate processor to insert.
1691 Return true if input is valid, false if error.
1693 A new predicate node is assigned, along with an argument node
1694 obtained with malloc.
1696 Used by -inum and -links parsers. */
1698 static boolean
1699 insert_num (char **argv, int *arg_ptr, PFB pred)
1701 struct predicate *our_pred;
1702 uintmax_t num;
1703 enum comparison_type c_type;
1705 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1706 return (false);
1707 if (!get_num (argv[*arg_ptr], &num, &c_type))
1708 return (false);
1709 our_pred = insert_primary (pred);
1710 our_pred->args.info.kind = c_type;
1711 our_pred->args.info.l_val = num;
1712 (*arg_ptr)++;
1713 #ifdef DEBUG
1714 printf (_("inserting %s\n"), our_pred->p_name);
1715 printf (_(" type: %s %s "),
1716 (c_type == COMP_GT) ? "gt" :
1717 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1718 (c_type == COMP_GT) ? " >" :
1719 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1720 printf ("%ju\n", our_pred->args.info.l_val);
1721 #endif /* DEBUG */
1722 return (true);
1725 static FILE *
1726 open_output_file (char *path)
1728 FILE *f;
1730 if (!strcmp (path, "/dev/stderr"))
1731 return (stderr);
1732 else if (!strcmp (path, "/dev/stdout"))
1733 return (stdout);
1734 f = fopen (path, "w");
1735 if (f == NULL)
1736 error (1, errno, "%s", path);
1737 return (f);