Detect arithmetic overflow (poorly) in insert_time(), which diagnoses
[findutils.git] / find / parser.c
blobbe58a3a5027233b21a846579fccf9b2daefd45ec
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_xtype PARAMS((char *argv[], int *arg_ptr));
119 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
120 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
121 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
122 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
123 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
124 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
125 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
126 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
127 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
128 static FILE *open_output_file PARAMS((char *path));
130 #ifdef DEBUG
131 char *find_pred_name PARAMS((PFB pred_func));
132 #endif /* DEBUG */
134 struct parser_table
136 char *parser_name;
137 PFB parser_func;
140 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
141 If they are in some Unix versions of find, they are marked `Unix'. */
143 static struct parser_table const parse_table[] =
145 {"!", parse_negate},
146 {"not", parse_negate}, /* GNU */
147 {"(", parse_open},
148 {")", parse_close},
149 {",", parse_comma}, /* GNU */
150 {"a", parse_and},
151 {"amin", parse_amin}, /* GNU */
152 {"and", parse_and}, /* GNU */
153 {"anewer", parse_anewer}, /* GNU */
154 {"atime", parse_atime},
155 {"cmin", parse_cmin}, /* GNU */
156 {"cnewer", parse_cnewer}, /* GNU */
157 #ifdef UNIMPLEMENTED_UNIX
158 /* It's pretty ugly for find to know about archive formats.
159 Plus what it could do with cpio archives is very limited.
160 Better to leave it out. */
161 {"cpio", parse_cpio}, /* Unix */
162 #endif
163 {"ctime", parse_ctime},
164 {"daystart", parse_daystart}, /* GNU */
165 {"depth", parse_depth},
166 {"empty", parse_empty}, /* GNU */
167 {"exec", parse_exec},
168 {"false", parse_false}, /* GNU */
169 {"fls", parse_fls}, /* GNU */
170 {"follow", parse_follow}, /* GNU, Unix */
171 {"fprint", parse_fprint}, /* GNU */
172 {"fprint0", parse_fprint0}, /* GNU */
173 {"fprintf", parse_fprintf}, /* GNU */
174 {"fstype", parse_fstype}, /* GNU, Unix */
175 {"gid", parse_gid}, /* GNU */
176 {"group", parse_group},
177 {"help", parse_help}, /* GNU */
178 {"-help", parse_help}, /* GNU */
179 {"ilname", parse_ilname}, /* GNU */
180 {"iname", parse_iname}, /* GNU */
181 {"inum", parse_inum}, /* GNU, Unix */
182 {"ipath", parse_ipath}, /* GNU */
183 {"iregex", parse_iregex}, /* GNU */
184 {"links", parse_links},
185 {"lname", parse_lname}, /* GNU */
186 {"ls", parse_ls}, /* GNU, Unix */
187 {"maxdepth", parse_maxdepth}, /* GNU */
188 {"mindepth", parse_mindepth}, /* GNU */
189 {"mmin", parse_mmin}, /* GNU */
190 {"mount", parse_xdev}, /* Unix */
191 {"mtime", parse_mtime},
192 {"name", parse_name},
193 #ifdef UNIMPLEMENTED_UNIX
194 {"ncpio", parse_ncpio}, /* Unix */
195 #endif
196 {"newer", parse_newer},
197 {"noleaf", parse_noleaf}, /* GNU */
198 {"nogroup", parse_nogroup},
199 {"nouser", parse_nouser},
200 {"o", parse_or},
201 {"or", parse_or}, /* GNU */
202 {"ok", parse_ok},
203 {"path", parse_path}, /* GNU, HP-UX */
204 {"perm", parse_perm},
205 {"print", parse_print},
206 {"print0", parse_print0}, /* GNU */
207 {"printf", parse_printf}, /* GNU */
208 {"prune", parse_prune},
209 {"regex", parse_regex}, /* GNU */
210 {"size", parse_size},
211 {"true", parse_true}, /* GNU */
212 {"type", parse_type},
213 {"uid", parse_uid}, /* GNU */
214 {"used", parse_used}, /* GNU */
215 {"user", parse_user},
216 {"version", parse_version}, /* GNU */
217 {"-version", parse_version}, /* GNU */
218 {"xdev", parse_xdev},
219 {"xtype", parse_xtype}, /* GNU */
220 {0, 0}
223 /* Return a pointer to the parser function to invoke for predicate
224 SEARCH_NAME.
225 Return NULL if SEARCH_NAME is not a valid predicate name. */
228 find_parser (char *search_name)
230 int i;
232 if (*search_name == '-')
233 search_name++;
234 for (i = 0; parse_table[i].parser_name != 0; i++)
235 if (strcmp (parse_table[i].parser_name, search_name) == 0)
236 return (parse_table[i].parser_func);
237 return (NULL);
240 /* The parsers are responsible to continue scanning ARGV for
241 their arguments. Each parser knows what is and isn't
242 allowed for itself.
244 ARGV is the argument array.
245 *ARG_PTR is the index to start at in ARGV,
246 updated to point beyond the last element consumed.
248 The predicate structure is updated with the new information. */
250 static boolean
251 parse_amin (char **argv, int *arg_ptr)
253 struct predicate *our_pred;
254 uintmax_t num;
255 enum comparison_type c_type;
256 time_t t;
258 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
259 return (false);
260 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
261 return (false);
262 t = cur_day_start + DAYSECS - num * 60;
263 our_pred = insert_primary (pred_amin);
264 our_pred->args.info.kind = c_type;
265 our_pred->args.info.negative = t < 0;
266 our_pred->args.info.l_val = t;
267 (*arg_ptr)++;
268 return (true);
271 static boolean
272 parse_and (char **argv, int *arg_ptr)
274 struct predicate *our_pred;
276 our_pred = get_new_pred ();
277 our_pred->pred_func = pred_and;
278 #ifdef DEBUG
279 our_pred->p_name = find_pred_name (pred_and);
280 #endif /* DEBUG */
281 our_pred->p_type = BI_OP;
282 our_pred->p_prec = AND_PREC;
283 our_pred->need_stat = false;
284 return (true);
287 static boolean
288 parse_anewer (char **argv, int *arg_ptr)
290 struct predicate *our_pred;
291 struct stat stat_newer;
293 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
294 return (false);
295 if ((*xstat) (argv[*arg_ptr], &stat_newer))
296 error (1, errno, "%s", argv[*arg_ptr]);
297 our_pred = insert_primary (pred_anewer);
298 our_pred->args.time = stat_newer.st_mtime;
299 (*arg_ptr)++;
300 return (true);
303 static boolean
304 parse_atime (char **argv, int *arg_ptr)
306 return (insert_time (argv, arg_ptr, pred_atime));
309 boolean
310 parse_close (char **argv, int *arg_ptr)
312 struct predicate *our_pred;
314 our_pred = get_new_pred ();
315 our_pred->pred_func = pred_close;
316 #ifdef DEBUG
317 our_pred->p_name = find_pred_name (pred_close);
318 #endif /* DEBUG */
319 our_pred->p_type = CLOSE_PAREN;
320 our_pred->p_prec = NO_PREC;
321 our_pred->need_stat = false;
322 return (true);
325 static boolean
326 parse_cmin (char **argv, int *arg_ptr)
328 struct predicate *our_pred;
329 uintmax_t num;
330 enum comparison_type c_type;
331 time_t t;
333 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
334 return (false);
335 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
336 return (false);
337 t = cur_day_start + DAYSECS - num * 60;
338 our_pred = insert_primary (pred_cmin);
339 our_pred->args.info.kind = c_type;
340 our_pred->args.info.negative = t < 0;
341 our_pred->args.info.l_val = t;
342 (*arg_ptr)++;
343 return (true);
346 static boolean
347 parse_cnewer (char **argv, int *arg_ptr)
349 struct predicate *our_pred;
350 struct stat stat_newer;
352 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
353 return (false);
354 if ((*xstat) (argv[*arg_ptr], &stat_newer))
355 error (1, errno, "%s", argv[*arg_ptr]);
356 our_pred = insert_primary (pred_cnewer);
357 our_pred->args.time = stat_newer.st_mtime;
358 (*arg_ptr)++;
359 return (true);
362 static boolean
363 parse_comma (char **argv, int *arg_ptr)
365 struct predicate *our_pred;
367 our_pred = get_new_pred ();
368 our_pred->pred_func = pred_comma;
369 #ifdef DEBUG
370 our_pred->p_name = find_pred_name (pred_comma);
371 #endif /* DEBUG */
372 our_pred->p_type = BI_OP;
373 our_pred->p_prec = COMMA_PREC;
374 our_pred->need_stat = false;
375 return (true);
378 static boolean
379 parse_ctime (char **argv, int *arg_ptr)
381 return (insert_time (argv, arg_ptr, pred_ctime));
384 static boolean
385 parse_daystart (char **argv, int *arg_ptr)
387 struct tm *local;
389 if (full_days == false)
391 cur_day_start += DAYSECS;
392 local = localtime (&cur_day_start);
393 cur_day_start -= (local
394 ? (local->tm_sec + local->tm_min * 60
395 + local->tm_hour * 3600)
396 : cur_day_start % DAYSECS);
397 full_days = true;
399 return (true);
402 static boolean
403 parse_depth (char **argv, int *arg_ptr)
405 do_dir_first = false;
406 return (true);
409 static boolean
410 parse_empty (char **argv, int *arg_ptr)
412 insert_primary (pred_empty);
413 return (true);
416 static boolean
417 parse_exec (char **argv, int *arg_ptr)
419 return (insert_exec_ok (pred_exec, argv, arg_ptr));
422 static boolean
423 parse_false (char **argv, int *arg_ptr)
425 struct predicate *our_pred;
427 our_pred = insert_primary (pred_false);
428 our_pred->need_stat = false;
429 return (true);
432 static boolean
433 parse_fls (char **argv, int *arg_ptr)
435 struct predicate *our_pred;
437 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
438 return (false);
439 our_pred = insert_primary (pred_fls);
440 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
441 our_pred->side_effects = true;
442 our_pred->no_default_print = true;
443 (*arg_ptr)++;
444 return (true);
447 static boolean
448 parse_fprintf (char **argv, int *arg_ptr)
450 FILE *fp;
452 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
453 return (false);
454 if (argv[*arg_ptr + 1] == NULL)
456 /* Ensure we get "missing arg" message, not "invalid arg". */
457 (*arg_ptr)++;
458 return (false);
460 fp = open_output_file (argv[*arg_ptr]);
461 (*arg_ptr)++;
462 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
465 static boolean
466 parse_follow (char **argv, int *arg_ptr)
468 dereference = true;
469 xstat = stat;
470 no_leaf_check = true;
471 return (true);
474 static boolean
475 parse_fprint (char **argv, int *arg_ptr)
477 struct predicate *our_pred;
479 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
480 return (false);
481 our_pred = insert_primary (pred_fprint);
482 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
483 our_pred->side_effects = true;
484 our_pred->no_default_print = true;
485 our_pred->need_stat = false;
486 (*arg_ptr)++;
487 return (true);
490 static boolean
491 parse_fprint0 (char **argv, int *arg_ptr)
493 struct predicate *our_pred;
495 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
496 return (false);
497 our_pred = insert_primary (pred_fprint0);
498 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
499 our_pred->side_effects = true;
500 our_pred->no_default_print = true;
501 our_pred->need_stat = false;
502 (*arg_ptr)++;
503 return (true);
506 static boolean
507 parse_fstype (char **argv, int *arg_ptr)
509 struct predicate *our_pred;
511 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
512 return (false);
513 our_pred = insert_primary (pred_fstype);
514 our_pred->args.str = argv[*arg_ptr];
515 (*arg_ptr)++;
516 return (true);
519 static boolean
520 parse_gid (char **argv, int *arg_ptr)
522 return (insert_num (argv, arg_ptr, pred_gid));
525 static boolean
526 parse_group (char **argv, int *arg_ptr)
528 struct group *cur_gr;
529 struct predicate *our_pred;
530 gid_t gid;
531 int gid_len;
533 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
534 return (false);
535 cur_gr = getgrnam (argv[*arg_ptr]);
536 endgrent ();
537 if (cur_gr != NULL)
538 gid = cur_gr->gr_gid;
539 else
541 gid_len = strspn (argv[*arg_ptr], "0123456789");
542 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
543 return (false);
544 gid = atoi (argv[*arg_ptr]);
546 our_pred = insert_primary (pred_group);
547 our_pred->args.gid = gid;
548 (*arg_ptr)++;
549 return (true);
552 static boolean
553 parse_help (char **argv, int *arg_ptr)
555 printf (_("\
556 Usage: %s [path...] [expression]\n"), program_name);
557 puts (_("\
558 default path is the current directory; default expression is -print\n\
559 expression may consist of:\n\
560 operators (decreasing precedence; -and is implicit where no others are given):\n\
561 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
562 puts (_("\
563 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
564 options (always true): -daystart -depth -follow --help\n\
565 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
566 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
567 puts (_("\
568 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
569 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
570 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
571 puts (_("\
572 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
573 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
574 -xtype [bcdpfls]\n"));
575 puts (_("\
576 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
577 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
578 puts (_("\nReport bugs to <bug-findutils@gnu.org>."));
579 exit (0);
582 static boolean
583 parse_ilname (char **argv, int *arg_ptr)
585 struct predicate *our_pred;
587 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
588 return (false);
589 our_pred = insert_primary (pred_ilname);
590 our_pred->args.str = argv[*arg_ptr];
591 (*arg_ptr)++;
592 return (true);
595 static boolean
596 parse_iname (char **argv, int *arg_ptr)
598 struct predicate *our_pred;
600 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
601 return (false);
602 our_pred = insert_primary (pred_iname);
603 our_pred->need_stat = false;
604 our_pred->args.str = argv[*arg_ptr];
605 (*arg_ptr)++;
606 return (true);
609 static boolean
610 parse_inum (char **argv, int *arg_ptr)
612 return (insert_num (argv, arg_ptr, pred_inum));
615 static boolean
616 parse_ipath (char **argv, int *arg_ptr)
618 struct predicate *our_pred;
620 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
621 return (false);
622 our_pred = insert_primary (pred_ipath);
623 our_pred->need_stat = false;
624 our_pred->args.str = argv[*arg_ptr];
625 (*arg_ptr)++;
626 return (true);
629 static boolean
630 parse_iregex (char **argv, int *arg_ptr)
632 return insert_regex (argv, arg_ptr, true);
635 static boolean
636 parse_links (char **argv, int *arg_ptr)
638 return (insert_num (argv, arg_ptr, pred_links));
641 static boolean
642 parse_lname (char **argv, int *arg_ptr)
644 struct predicate *our_pred;
646 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
647 return (false);
648 our_pred = insert_primary (pred_lname);
649 our_pred->args.str = argv[*arg_ptr];
650 (*arg_ptr)++;
651 return (true);
654 static boolean
655 parse_ls (char **argv, int *arg_ptr)
657 struct predicate *our_pred;
659 our_pred = insert_primary (pred_ls);
660 our_pred->side_effects = true;
661 our_pred->no_default_print = true;
662 return (true);
665 static boolean
666 parse_maxdepth (char **argv, int *arg_ptr)
668 int depth_len;
670 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
671 return (false);
672 depth_len = strspn (argv[*arg_ptr], "0123456789");
673 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
674 return (false);
675 maxdepth = atoi (argv[*arg_ptr]);
676 if (maxdepth < 0)
677 return (false);
678 (*arg_ptr)++;
679 return (true);
682 static boolean
683 parse_mindepth (char **argv, int *arg_ptr)
685 int depth_len;
687 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
688 return (false);
689 depth_len = strspn (argv[*arg_ptr], "0123456789");
690 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
691 return (false);
692 mindepth = atoi (argv[*arg_ptr]);
693 if (mindepth < 0)
694 return (false);
695 (*arg_ptr)++;
696 return (true);
699 static boolean
700 parse_mmin (char **argv, int *arg_ptr)
702 struct predicate *our_pred;
703 uintmax_t num;
704 enum comparison_type c_type;
705 time_t t;
707 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
708 return (false);
709 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
710 return (false);
711 t = cur_day_start + DAYSECS - num * 60;
712 our_pred = insert_primary (pred_mmin);
713 our_pred->args.info.kind = c_type;
714 our_pred->args.info.negative = t < 0;
715 our_pred->args.info.l_val = t;
716 (*arg_ptr)++;
717 return (true);
720 static boolean
721 parse_mtime (char **argv, int *arg_ptr)
723 return (insert_time (argv, arg_ptr, pred_mtime));
726 static boolean
727 parse_name (char **argv, int *arg_ptr)
729 struct predicate *our_pred;
731 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
732 return (false);
733 our_pred = insert_primary (pred_name);
734 our_pred->need_stat = false;
735 our_pred->args.str = argv[*arg_ptr];
736 (*arg_ptr)++;
737 return (true);
740 static boolean
741 parse_negate (char **argv, int *arg_ptr)
743 struct predicate *our_pred;
745 our_pred = get_new_pred_chk_op ();
746 our_pred->pred_func = pred_negate;
747 #ifdef DEBUG
748 our_pred->p_name = find_pred_name (pred_negate);
749 #endif /* DEBUG */
750 our_pred->p_type = UNI_OP;
751 our_pred->p_prec = NEGATE_PREC;
752 our_pred->need_stat = false;
753 return (true);
756 static boolean
757 parse_newer (char **argv, int *arg_ptr)
759 struct predicate *our_pred;
760 struct stat stat_newer;
762 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
763 return (false);
764 if ((*xstat) (argv[*arg_ptr], &stat_newer))
765 error (1, errno, "%s", argv[*arg_ptr]);
766 our_pred = insert_primary (pred_newer);
767 our_pred->args.time = stat_newer.st_mtime;
768 (*arg_ptr)++;
769 return (true);
772 static boolean
773 parse_noleaf (char **argv, int *arg_ptr)
775 no_leaf_check = true;
776 return true;
779 #ifdef CACHE_IDS
780 /* Arbitrary amount by which to increase size
781 of `uid_unused' and `gid_unused'. */
782 #define ALLOC_STEP 2048
784 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
785 char *uid_unused = NULL;
787 /* Number of elements in `uid_unused'. */
788 unsigned uid_allocated;
790 /* Similar for GIDs and group entries. */
791 char *gid_unused = NULL;
792 unsigned gid_allocated;
793 #endif
795 static boolean
796 parse_nogroup (char **argv, int *arg_ptr)
798 struct predicate *our_pred;
800 our_pred = insert_primary (pred_nogroup);
801 #ifdef CACHE_IDS
802 if (gid_unused == NULL)
804 struct group *gr;
806 gid_allocated = ALLOC_STEP;
807 gid_unused = xmalloc (gid_allocated);
808 memset (gid_unused, 1, gid_allocated);
809 setgrent ();
810 while ((gr = getgrent ()) != NULL)
812 if ((unsigned) gr->gr_gid >= gid_allocated)
814 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
815 gid_unused = xrealloc (gid_unused, new_allocated);
816 memset (gid_unused + gid_allocated, 1,
817 new_allocated - gid_allocated);
818 gid_allocated = new_allocated;
820 gid_unused[(unsigned) gr->gr_gid] = 0;
822 endgrent ();
824 #endif
825 return (true);
828 static boolean
829 parse_nouser (char **argv, int *arg_ptr)
831 struct predicate *our_pred;
833 our_pred = insert_primary (pred_nouser);
834 #ifdef CACHE_IDS
835 if (uid_unused == NULL)
837 struct passwd *pw;
839 uid_allocated = ALLOC_STEP;
840 uid_unused = xmalloc (uid_allocated);
841 memset (uid_unused, 1, uid_allocated);
842 setpwent ();
843 while ((pw = getpwent ()) != NULL)
845 if ((unsigned) pw->pw_uid >= uid_allocated)
847 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
848 uid_unused = xrealloc (uid_unused, new_allocated);
849 memset (uid_unused + uid_allocated, 1,
850 new_allocated - uid_allocated);
851 uid_allocated = new_allocated;
853 uid_unused[(unsigned) pw->pw_uid] = 0;
855 endpwent ();
857 #endif
858 return (true);
861 static boolean
862 parse_ok (char **argv, int *arg_ptr)
864 return (insert_exec_ok (pred_ok, argv, arg_ptr));
867 boolean
868 parse_open (char **argv, int *arg_ptr)
870 struct predicate *our_pred;
872 our_pred = get_new_pred_chk_op ();
873 our_pred->pred_func = pred_open;
874 #ifdef DEBUG
875 our_pred->p_name = find_pred_name (pred_open);
876 #endif /* DEBUG */
877 our_pred->p_type = OPEN_PAREN;
878 our_pred->p_prec = NO_PREC;
879 our_pred->need_stat = false;
880 return (true);
883 static boolean
884 parse_or (char **argv, int *arg_ptr)
886 struct predicate *our_pred;
888 our_pred = get_new_pred ();
889 our_pred->pred_func = pred_or;
890 #ifdef DEBUG
891 our_pred->p_name = find_pred_name (pred_or);
892 #endif /* DEBUG */
893 our_pred->p_type = BI_OP;
894 our_pred->p_prec = OR_PREC;
895 our_pred->need_stat = false;
896 return (true);
899 static boolean
900 parse_path (char **argv, int *arg_ptr)
902 struct predicate *our_pred;
904 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
905 return (false);
906 our_pred = insert_primary (pred_path);
907 our_pred->need_stat = false;
908 our_pred->args.str = argv[*arg_ptr];
909 (*arg_ptr)++;
910 return (true);
913 static boolean
914 parse_perm (char **argv, int *arg_ptr)
916 mode_t perm_val;
917 int mode_start = 0;
918 struct mode_change *change;
919 struct predicate *our_pred;
921 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
922 return (false);
924 switch (argv[*arg_ptr][0])
926 case '-':
927 case '+':
928 mode_start = 1;
929 break;
930 default:
931 /* empty */
932 break;
935 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
936 if (change == MODE_INVALID)
937 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
938 else if (change == MODE_MEMORY_EXHAUSTED)
939 error (1, 0, _("virtual memory exhausted"));
940 perm_val = mode_adjust (0, change);
941 mode_free (change);
943 our_pred = insert_primary (pred_perm);
945 switch (argv[*arg_ptr][0])
947 case '-':
948 our_pred->args.perm.kind = PERM_AT_LEAST;
949 break;
950 case '+':
951 our_pred->args.perm.kind = PERM_ANY;
952 break;
953 default:
954 our_pred->args.perm.kind = PERM_EXACT;
955 break;
957 our_pred->args.perm.val = perm_val & MODE_ALL;
958 (*arg_ptr)++;
959 return (true);
962 boolean
963 parse_print (char **argv, int *arg_ptr)
965 struct predicate *our_pred;
967 our_pred = insert_primary (pred_print);
968 /* -print has the side effect of printing. This prevents us
969 from doing undesired multiple printing when the user has
970 already specified -print. */
971 our_pred->side_effects = true;
972 our_pred->no_default_print = true;
973 our_pred->need_stat = false;
974 return (true);
977 static boolean
978 parse_print0 (char **argv, int *arg_ptr)
980 struct predicate *our_pred;
982 our_pred = insert_primary (pred_print0);
983 /* -print0 has the side effect of printing. This prevents us
984 from doing undesired multiple printing when the user has
985 already specified -print0. */
986 our_pred->side_effects = true;
987 our_pred->no_default_print = true;
988 our_pred->need_stat = false;
989 return (true);
992 static boolean
993 parse_printf (char **argv, int *arg_ptr)
995 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
996 return (false);
997 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1000 static boolean
1001 parse_prune (char **argv, int *arg_ptr)
1003 struct predicate *our_pred;
1005 our_pred = insert_primary (pred_prune);
1006 our_pred->need_stat = false;
1007 /* -prune has a side effect that it does not descend into
1008 the current directory. */
1009 our_pred->side_effects = true;
1010 return (true);
1013 static boolean
1014 parse_regex (char **argv, int *arg_ptr)
1016 return insert_regex (argv, arg_ptr, false);
1019 static boolean
1020 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1022 struct predicate *our_pred;
1023 struct re_pattern_buffer *re;
1024 const char *error_message;
1026 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1027 return (false);
1028 our_pred = insert_primary (pred_regex);
1029 our_pred->need_stat = false;
1030 re = (struct re_pattern_buffer *)
1031 xmalloc (sizeof (struct re_pattern_buffer));
1032 our_pred->args.regex = re;
1033 re->allocated = 100;
1034 re->buffer = (unsigned char *) xmalloc (re->allocated);
1035 re->fastmap = NULL;
1037 if (ignore_case)
1039 unsigned i;
1041 re->translate = xmalloc (256);
1042 /* Map uppercase characters to corresponding lowercase ones. */
1043 for (i = 0; i < 256; i++)
1044 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1046 else
1047 re->translate = NULL;
1049 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1050 re);
1051 if (error_message)
1052 error (1, 0, "%s", error_message);
1053 (*arg_ptr)++;
1054 return (true);
1057 static boolean
1058 parse_size (char **argv, int *arg_ptr)
1060 struct predicate *our_pred;
1061 uintmax_t num;
1062 enum comparison_type c_type;
1063 int blksize = 512;
1064 int len;
1066 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1067 return (false);
1068 len = strlen (argv[*arg_ptr]);
1069 if (len == 0)
1070 error (1, 0, _("invalid null argument to -size"));
1071 switch (argv[*arg_ptr][len - 1])
1073 case 'b':
1074 blksize = 512;
1075 argv[*arg_ptr][len - 1] = '\0';
1076 break;
1078 case 'c':
1079 blksize = 1;
1080 argv[*arg_ptr][len - 1] = '\0';
1081 break;
1083 case 'k':
1084 blksize = 1024;
1085 argv[*arg_ptr][len - 1] = '\0';
1086 break;
1088 case 'w':
1089 blksize = 2;
1090 argv[*arg_ptr][len - 1] = '\0';
1091 break;
1093 case '0':
1094 case '1':
1095 case '2':
1096 case '3':
1097 case '4':
1098 case '5':
1099 case '6':
1100 case '7':
1101 case '8':
1102 case '9':
1103 break;
1105 default:
1106 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1108 if (!get_num (argv[*arg_ptr], &num, &c_type))
1109 return (false);
1110 our_pred = insert_primary (pred_size);
1111 our_pred->args.size.kind = c_type;
1112 our_pred->args.size.blocksize = blksize;
1113 our_pred->args.size.size = num;
1114 (*arg_ptr)++;
1115 return (true);
1118 static boolean
1119 parse_true (char **argv, int *arg_ptr)
1121 struct predicate *our_pred;
1123 our_pred = insert_primary (pred_true);
1124 our_pred->need_stat = false;
1125 return (true);
1128 static boolean
1129 parse_type (char **argv, int *arg_ptr)
1131 return insert_type (argv, arg_ptr, pred_type);
1134 static boolean
1135 parse_uid (char **argv, int *arg_ptr)
1137 return (insert_num (argv, arg_ptr, pred_uid));
1140 static boolean
1141 parse_used (char **argv, int *arg_ptr)
1143 struct predicate *our_pred;
1144 uintmax_t num_days;
1145 enum comparison_type c_type;
1146 time_t t;
1148 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1149 return (false);
1150 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1151 return (false);
1152 t = num_days * DAYSECS;
1153 our_pred = insert_primary (pred_used);
1154 our_pred->args.info.kind = c_type;
1155 our_pred->args.info.negative = t < 0;
1156 our_pred->args.info.l_val = t;
1157 (*arg_ptr)++;
1158 return (true);
1161 static boolean
1162 parse_user (char **argv, int *arg_ptr)
1164 struct passwd *cur_pwd;
1165 struct predicate *our_pred;
1166 uid_t uid;
1167 int uid_len;
1169 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1170 return (false);
1171 cur_pwd = getpwnam (argv[*arg_ptr]);
1172 endpwent ();
1173 if (cur_pwd != NULL)
1174 uid = cur_pwd->pw_uid;
1175 else
1177 uid_len = strspn (argv[*arg_ptr], "0123456789");
1178 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1179 return (false);
1180 uid = atoi (argv[*arg_ptr]);
1182 our_pred = insert_primary (pred_user);
1183 our_pred->args.uid = uid;
1184 (*arg_ptr)++;
1185 return (true);
1188 static boolean
1189 parse_version (char **argv, int *arg_ptr)
1191 extern char *version_string;
1193 fflush (stderr);
1194 printf (_("GNU find version %s\n"), version_string);
1195 exit (0);
1198 static boolean
1199 parse_xdev (char **argv, int *arg_ptr)
1201 stay_on_filesystem = true;
1202 return true;
1205 static boolean
1206 parse_xtype (char **argv, int *arg_ptr)
1208 return insert_type (argv, arg_ptr, pred_xtype);
1211 static boolean
1212 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1214 mode_t type_cell;
1215 struct predicate *our_pred;
1217 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1218 || (strlen (argv[*arg_ptr]) != 1))
1219 return (false);
1220 switch (argv[*arg_ptr][0])
1222 case 'b': /* block special */
1223 type_cell = S_IFBLK;
1224 break;
1225 case 'c': /* character special */
1226 type_cell = S_IFCHR;
1227 break;
1228 case 'd': /* directory */
1229 type_cell = S_IFDIR;
1230 break;
1231 case 'f': /* regular file */
1232 type_cell = S_IFREG;
1233 break;
1234 #ifdef S_IFLNK
1235 case 'l': /* symbolic link */
1236 type_cell = S_IFLNK;
1237 break;
1238 #endif
1239 #ifdef S_IFIFO
1240 case 'p': /* pipe */
1241 type_cell = S_IFIFO;
1242 break;
1243 #endif
1244 #ifdef S_IFSOCK
1245 case 's': /* socket */
1246 type_cell = S_IFSOCK;
1247 break;
1248 #endif
1249 #ifdef S_IFDOOR
1250 case 'D': /* Solaris door */
1251 type_cell = S_IFDOOR;
1252 break;
1253 #endif
1254 default: /* None of the above ... nuke 'em. */
1255 return (false);
1257 our_pred = insert_primary (which_pred);
1258 our_pred->args.type = type_cell;
1259 (*arg_ptr)++; /* Move on to next argument. */
1260 return (true);
1263 /* If true, we've determined that the current fprintf predicate
1264 uses stat information. */
1265 static boolean fprintf_stat_needed;
1267 static boolean
1268 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1270 char *format; /* Beginning of unprocessed format string. */
1271 register char *scan; /* Current address in scanning `format'. */
1272 register char *scan2; /* Address inside of element being scanned. */
1273 struct segment **segmentp; /* Address of current segment. */
1274 struct predicate *our_pred;
1276 format = argv[(*arg_ptr)++];
1278 fprintf_stat_needed = false; /* Might be overridden later. */
1279 our_pred = insert_primary (func);
1280 our_pred->side_effects = true;
1281 our_pred->no_default_print = true;
1282 our_pred->args.printf_vec.stream = fp;
1283 segmentp = &our_pred->args.printf_vec.segment;
1284 *segmentp = NULL;
1286 for (scan = format; *scan; scan++)
1288 if (*scan == '\\')
1290 scan2 = scan + 1;
1291 if (*scan2 >= '0' && *scan2 <= '7')
1293 register int n, i;
1295 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1296 i++, scan2++)
1297 n = 8 * n + *scan2 - '0';
1298 scan2--;
1299 *scan = n;
1301 else
1303 switch (*scan2)
1305 case 'a':
1306 *scan = 7;
1307 break;
1308 case 'b':
1309 *scan = '\b';
1310 break;
1311 case 'c':
1312 make_segment (segmentp, format, scan - format, KIND_STOP);
1313 our_pred->need_stat = fprintf_stat_needed;
1314 return (true);
1315 case 'f':
1316 *scan = '\f';
1317 break;
1318 case 'n':
1319 *scan = '\n';
1320 break;
1321 case 'r':
1322 *scan = '\r';
1323 break;
1324 case 't':
1325 *scan = '\t';
1326 break;
1327 case 'v':
1328 *scan = '\v';
1329 break;
1330 case '\\':
1331 /* *scan = '\\'; * it already is */
1332 break;
1333 default:
1334 error (0, 0,
1335 _("warning: unrecognized escape `\\%c'"), *scan2);
1336 scan++;
1337 continue;
1340 segmentp = make_segment (segmentp, format, scan - format + 1,
1341 KIND_PLAIN);
1342 format = scan2 + 1; /* Move past the escape. */
1343 scan = scan2; /* Incremented immediately by `for'. */
1345 else if (*scan == '%')
1347 if (scan[1] == '%')
1349 segmentp = make_segment (segmentp, format, scan - format + 1,
1350 KIND_PLAIN);
1351 scan++;
1352 format = scan + 1;
1353 continue;
1355 /* Scan past flags, width and precision, to verify kind. */
1356 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1357 /* Do nothing. */ ;
1358 while (ISDIGIT (*scan2))
1359 scan2++;
1360 if (*scan2 == '.')
1361 for (scan2++; ISDIGIT (*scan2); scan2++)
1362 /* Do nothing. */ ;
1363 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1365 segmentp = make_segment (segmentp, format, scan2 - format,
1366 (int) *scan2);
1367 scan = scan2;
1368 format = scan + 1;
1370 else if (strchr ("ACT", *scan2) && scan2[1])
1372 segmentp = make_segment (segmentp, format, scan2 - format,
1373 *scan2 | (scan2[1] << 8));
1374 scan = scan2 + 1;
1375 format = scan + 1;
1376 continue;
1378 else
1380 /* An unrecognized % escape. Print the char after the %. */
1381 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1382 *scan2);
1383 segmentp = make_segment (segmentp, format, scan - format,
1384 KIND_PLAIN);
1385 format = scan + 1;
1386 continue;
1391 if (scan > format)
1392 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1393 our_pred->need_stat = fprintf_stat_needed;
1394 return (true);
1397 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1398 from the text in FORMAT, which has length LEN.
1399 Return the address of the `next' pointer of the new segment. */
1401 static struct segment **
1402 make_segment (struct segment **segment, char *format, int len, int kind)
1404 char *fmt;
1406 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1408 (*segment)->kind = kind;
1409 (*segment)->next = NULL;
1410 (*segment)->text_len = len;
1412 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1413 strncpy (fmt, format, len);
1414 fmt += len;
1416 switch (kind & 0xff)
1418 case KIND_PLAIN: /* Plain text string, no % conversion. */
1419 case KIND_STOP: /* Terminate argument, no newline. */
1420 break;
1422 case 'a': /* atime in `ctime' format */
1423 case 'A': /* atime in user-specified strftime format */
1424 case 'b': /* size in 512-byte blocks */
1425 case 'c': /* ctime in `ctime' format */
1426 case 'C': /* ctime in user-specified strftime format */
1427 case 'F': /* filesystem type */
1428 case 'G': /* GID number */
1429 case 'g': /* group name */
1430 case 'i': /* inode number */
1431 case 'k': /* size in 1K blocks */
1432 case 'l': /* object of symlink */
1433 case 'n': /* number of links */
1434 case 's': /* size in bytes */
1435 case 't': /* mtime in `ctime' format */
1436 case 'T': /* mtime in user-specified strftime format */
1437 case 'U': /* UID number */
1438 case 'u': /* user name */
1439 fprintf_stat_needed = true;
1440 /* FALLTHROUGH */
1441 case 'f': /* basename of path */
1442 case 'h': /* leading directories part of path */
1443 case 'H': /* ARGV element file was found under */
1444 case 'p': /* pathname */
1445 case 'P': /* pathname with ARGV element stripped */
1446 *fmt++ = 's';
1447 break;
1449 case 'd': /* depth in search tree (0 = ARGV element) */
1450 *fmt++ = 'd';
1451 break;
1453 case 'm': /* mode as octal number (perms only) */
1454 *fmt++ = 'o';
1455 fprintf_stat_needed = true;
1456 break;
1458 *fmt = '\0';
1460 return (&(*segment)->next);
1463 /* handles both exec and ok predicate */
1464 static boolean
1465 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1467 int start, end; /* Indexes in ARGV of start & end of cmd. */
1468 int num_paths; /* Number of args with path replacements. */
1469 int path_pos; /* Index in array of path replacements. */
1470 int vec_pos; /* Index in array of args. */
1471 struct predicate *our_pred;
1472 struct exec_val *execp; /* Pointer for efficiency. */
1474 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1475 return (false);
1477 /* Count the number of args with path replacements, up until the ';'. */
1478 start = *arg_ptr;
1479 for (end = start, num_paths = 0;
1480 (argv[end] != NULL)
1481 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1482 end++)
1483 if (strstr (argv[end], "{}"))
1484 num_paths++;
1485 /* Fail if no command given or no semicolon found. */
1486 if ((end == start) || (argv[end] == NULL))
1488 *arg_ptr = end;
1489 return (false);
1492 our_pred = insert_primary (func);
1493 our_pred->side_effects = true;
1494 our_pred->no_default_print = true;
1495 execp = &our_pred->args.exec_vec;
1496 execp->paths =
1497 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1498 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1499 /* Record the positions of all args, and the args with path replacements. */
1500 for (end = start, path_pos = vec_pos = 0;
1501 (argv[end] != NULL)
1502 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1503 end++)
1505 register char *p;
1507 execp->paths[path_pos].count = 0;
1508 for (p = argv[end]; *p; ++p)
1509 if (p[0] == '{' && p[1] == '}')
1511 execp->paths[path_pos].count++;
1512 ++p;
1514 if (execp->paths[path_pos].count)
1516 execp->paths[path_pos].offset = vec_pos;
1517 execp->paths[path_pos].origarg = argv[end];
1518 path_pos++;
1520 execp->vec[vec_pos++] = argv[end];
1522 execp->paths[path_pos].offset = -1;
1523 execp->vec[vec_pos] = NULL;
1525 if (argv[end] == NULL)
1526 *arg_ptr = end;
1527 else
1528 *arg_ptr = end + 1;
1529 return (true);
1532 /* Get a number of days and comparison type.
1533 STR is the ASCII representation.
1534 Set *NUM_DAYS to the number of days, taken as being from
1535 the current moment (or possibly midnight). Thus the sense of the
1536 comparison type appears to be reversed.
1537 Set *COMP_TYPE to the kind of comparison that is requested.
1539 Return true if all okay, false if input error.
1541 Used by -atime, -ctime and -mtime (parsers) to
1542 get the appropriate information for a time predicate processor. */
1544 static boolean
1545 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1547 boolean r = get_num (str, num_days, comp_type);
1548 if (r)
1549 switch (*comp_type)
1551 case COMP_LT: *comp_type = COMP_GT; break;
1552 case COMP_GT: *comp_type = COMP_LT; break;
1553 default: break;
1555 return r;
1558 /* Insert a time predicate PRED.
1559 ARGV is a pointer to the argument array.
1560 ARG_PTR is a pointer to an index into the array, incremented if
1561 all went well.
1563 Return true if input is valid, false if not.
1565 A new predicate node is assigned, along with an argument node
1566 obtained with malloc.
1568 Used by -atime, -ctime, and -mtime parsers. */
1570 static boolean
1571 insert_time (char **argv, int *arg_ptr, PFB pred)
1573 struct predicate *our_pred;
1574 uintmax_t num_days;
1575 enum comparison_type c_type;
1576 time_t t;
1578 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1579 return (false);
1580 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1581 return (false);
1583 /* Figure out the timestamp value we are looking for. */
1584 t = ( cur_day_start - num_days * DAYSECS
1585 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1586 #if 1
1587 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1588 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1589 t = val;
1591 /* Check for possibility of an overflow */
1592 if ( (intmax_t)t != val )
1594 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1596 #endif
1598 our_pred = insert_primary (pred);
1599 our_pred->args.info.kind = c_type;
1600 our_pred->args.info.negative = t < 0;
1601 our_pred->args.info.l_val = t;
1602 (*arg_ptr)++;
1603 #ifdef DEBUG
1604 printf (_("inserting %s\n"), our_pred->p_name);
1605 printf (_(" type: %s %s "),
1606 (c_type == COMP_GT) ? "gt" :
1607 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1608 (c_type == COMP_GT) ? " >" :
1609 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1610 t = our_pred->args.info.l_val;
1611 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1612 if (c_type == COMP_EQ)
1614 t = our_pred->args.info.l_val += DAYSECS;
1615 printf (" < %ju %s",
1616 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1617 our_pred->args.info.l_val -= DAYSECS;
1619 #endif /* DEBUG */
1620 return (true);
1623 /* Get a number with comparision information.
1624 The sense of the comparision information is 'normal'; that is,
1625 '+' looks for a count > than the number and '-' less than.
1627 STR is the ASCII representation of the number.
1628 Set *NUM to the number.
1629 Set *COMP_TYPE to the kind of comparison that is requested.
1631 Return true if all okay, false if input error. */
1633 static boolean
1634 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1636 int len_num; /* Length of field. */
1638 if (str == NULL)
1639 return (false);
1640 switch (str[0])
1642 case '+':
1643 *comp_type = COMP_GT;
1644 str++;
1645 break;
1646 case '-':
1647 *comp_type = COMP_LT;
1648 str++;
1649 break;
1650 default:
1651 *comp_type = COMP_EQ;
1652 break;
1655 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1658 /* Insert a number predicate.
1659 ARGV is a pointer to the argument array.
1660 *ARG_PTR is an index into ARGV, incremented if all went well.
1661 *PRED is the predicate processor to insert.
1663 Return true if input is valid, false if error.
1665 A new predicate node is assigned, along with an argument node
1666 obtained with malloc.
1668 Used by -inum and -links parsers. */
1670 static boolean
1671 insert_num (char **argv, int *arg_ptr, PFB pred)
1673 struct predicate *our_pred;
1674 uintmax_t num;
1675 enum comparison_type c_type;
1677 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1678 return (false);
1679 if (!get_num (argv[*arg_ptr], &num, &c_type))
1680 return (false);
1681 our_pred = insert_primary (pred);
1682 our_pred->args.info.kind = c_type;
1683 our_pred->args.info.l_val = num;
1684 (*arg_ptr)++;
1685 #ifdef DEBUG
1686 printf (_("inserting %s\n"), our_pred->p_name);
1687 printf (_(" type: %s %s "),
1688 (c_type == COMP_GT) ? "gt" :
1689 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1690 (c_type == COMP_GT) ? " >" :
1691 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1692 printf ("%ju\n", our_pred->args.info.l_val);
1693 #endif /* DEBUG */
1694 return (true);
1697 static FILE *
1698 open_output_file (char *path)
1700 FILE *f;
1702 if (!strcmp (path, "/dev/stderr"))
1703 return (stderr);
1704 else if (!strcmp (path, "/dev/stdout"))
1705 return (stdout);
1706 f = fopen (path, "w");
1707 if (f == NULL)
1708 error (1, errno, "%s", path);
1709 return (f);