* doc/find.texi (Directories): changed wording for "-prune".
[findutils.git] / find / parser.c
blob890f434da15ce66b5557540c45a4842f0eb86ae5
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #include "defs.h"
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <grp.h>
22 #include "modechange.h"
23 #include "modetype.h"
24 #include "xstrtol.h"
26 #if ENABLE_NLS
27 # include <libintl.h>
28 # define _(Text) gettext (Text)
29 #else
30 # define _(Text) Text
31 #endif
32 #ifdef gettext_noop
33 # define N_(String) gettext_noop (String)
34 #else
35 # define N_(String) (String)
36 #endif
38 #if !defined (isascii) || defined (STDC_HEADERS)
39 #ifdef isascii
40 #undef isascii
41 #endif
42 #define isascii(c) 1
43 #endif
45 #define ISDIGIT(c) (isascii (c) && isdigit (c))
46 #define ISUPPER(c) (isascii (c) && isupper (c))
48 #ifndef HAVE_ENDGRENT
49 #define endgrent()
50 #endif
51 #ifndef HAVE_ENDPWENT
52 #define endpwent()
53 #endif
55 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
56 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
57 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
58 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
59 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
60 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
61 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
62 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
64 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
65 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
97 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
99 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
100 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
101 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
103 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
104 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
106 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
107 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
108 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
109 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
110 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
112 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
113 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
114 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
115 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
117 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
118 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
119 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
120 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
121 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
122 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
123 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
124 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
125 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
126 static FILE *open_output_file PARAMS((char *path));
128 #ifdef DEBUG
129 char *find_pred_name PARAMS((PFB pred_func));
130 #endif /* DEBUG */
132 struct parser_table
134 char *parser_name;
135 PFB parser_func;
138 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
139 If they are in some Unix versions of find, they are marked `Unix'. */
141 static struct parser_table const parse_table[] =
143 {"!", parse_negate},
144 {"not", parse_negate}, /* GNU */
145 {"(", parse_open},
146 {")", parse_close},
147 {",", parse_comma}, /* GNU */
148 {"a", parse_and},
149 {"amin", parse_amin}, /* GNU */
150 {"and", parse_and}, /* GNU */
151 {"anewer", parse_anewer}, /* GNU */
152 {"atime", parse_atime},
153 {"cmin", parse_cmin}, /* GNU */
154 {"cnewer", parse_cnewer}, /* GNU */
155 #ifdef UNIMPLEMENTED_UNIX
156 /* It's pretty ugly for find to know about archive formats.
157 Plus what it could do with cpio archives is very limited.
158 Better to leave it out. */
159 {"cpio", parse_cpio}, /* Unix */
160 #endif
161 {"ctime", parse_ctime},
162 {"daystart", parse_daystart}, /* GNU */
163 {"depth", parse_depth},
164 {"empty", parse_empty}, /* GNU */
165 {"exec", parse_exec},
166 {"false", parse_false}, /* GNU */
167 {"fls", parse_fls}, /* GNU */
168 {"follow", parse_follow}, /* GNU, Unix */
169 {"fprint", parse_fprint}, /* GNU */
170 {"fprint0", parse_fprint0}, /* GNU */
171 {"fprintf", parse_fprintf}, /* GNU */
172 {"fstype", parse_fstype}, /* GNU, Unix */
173 {"gid", parse_gid}, /* GNU */
174 {"group", parse_group},
175 {"help", parse_help}, /* GNU */
176 {"-help", parse_help}, /* GNU */
177 {"ilname", parse_ilname}, /* GNU */
178 {"iname", parse_iname}, /* GNU */
179 {"inum", parse_inum}, /* GNU, Unix */
180 {"ipath", parse_ipath}, /* GNU */
181 {"iregex", parse_iregex}, /* GNU */
182 {"links", parse_links},
183 {"lname", parse_lname}, /* GNU */
184 {"ls", parse_ls}, /* GNU, Unix */
185 {"maxdepth", parse_maxdepth}, /* GNU */
186 {"mindepth", parse_mindepth}, /* GNU */
187 {"mmin", parse_mmin}, /* GNU */
188 {"mount", parse_xdev}, /* Unix */
189 {"mtime", parse_mtime},
190 {"name", parse_name},
191 #ifdef UNIMPLEMENTED_UNIX
192 {"ncpio", parse_ncpio}, /* Unix */
193 #endif
194 {"newer", parse_newer},
195 {"noleaf", parse_noleaf}, /* GNU */
196 {"nogroup", parse_nogroup},
197 {"nouser", parse_nouser},
198 {"o", parse_or},
199 {"or", parse_or}, /* GNU */
200 {"ok", parse_ok},
201 {"path", parse_path}, /* GNU, HP-UX */
202 {"perm", parse_perm},
203 {"print", parse_print},
204 {"print0", parse_print0}, /* GNU */
205 {"printf", parse_printf}, /* GNU */
206 {"prune", parse_prune},
207 {"regex", parse_regex}, /* GNU */
208 {"size", parse_size},
209 {"true", parse_true}, /* GNU */
210 {"type", parse_type},
211 {"uid", parse_uid}, /* GNU */
212 {"used", parse_used}, /* GNU */
213 {"user", parse_user},
214 {"version", parse_version}, /* GNU */
215 {"-version", parse_version}, /* GNU */
216 {"xdev", parse_xdev},
217 {"xtype", parse_xtype}, /* GNU */
218 {0, 0}
221 /* Return a pointer to the parser function to invoke for predicate
222 SEARCH_NAME.
223 Return NULL if SEARCH_NAME is not a valid predicate name. */
226 find_parser (char *search_name)
228 int i;
230 if (*search_name == '-')
231 search_name++;
232 for (i = 0; parse_table[i].parser_name != 0; i++)
233 if (strcmp (parse_table[i].parser_name, search_name) == 0)
234 return (parse_table[i].parser_func);
235 return (NULL);
238 /* The parsers are responsible to continue scanning ARGV for
239 their arguments. Each parser knows what is and isn't
240 allowed for itself.
242 ARGV is the argument array.
243 *ARG_PTR is the index to start at in ARGV,
244 updated to point beyond the last element consumed.
246 The predicate structure is updated with the new information. */
248 static boolean
249 parse_amin (char **argv, int *arg_ptr)
251 struct predicate *our_pred;
252 uintmax_t num;
253 enum comparison_type c_type;
254 time_t t;
256 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
257 return (false);
258 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
259 return (false);
260 t = cur_day_start + DAYSECS - num * 60;
261 our_pred = insert_primary (pred_amin);
262 our_pred->args.info.kind = c_type;
263 our_pred->args.info.negative = t < 0;
264 our_pred->args.info.l_val = t;
265 (*arg_ptr)++;
266 return (true);
269 static boolean
270 parse_and (char **argv, int *arg_ptr)
272 struct predicate *our_pred;
274 our_pred = get_new_pred ();
275 our_pred->pred_func = pred_and;
276 #ifdef DEBUG
277 our_pred->p_name = find_pred_name (pred_and);
278 #endif /* DEBUG */
279 our_pred->p_type = BI_OP;
280 our_pred->p_prec = AND_PREC;
281 our_pred->need_stat = false;
282 return (true);
285 static boolean
286 parse_anewer (char **argv, int *arg_ptr)
288 struct predicate *our_pred;
289 struct stat stat_newer;
291 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
292 return (false);
293 if ((*xstat) (argv[*arg_ptr], &stat_newer))
294 error (1, errno, "%s", argv[*arg_ptr]);
295 our_pred = insert_primary (pred_anewer);
296 our_pred->args.time = stat_newer.st_mtime;
297 (*arg_ptr)++;
298 return (true);
301 static boolean
302 parse_atime (char **argv, int *arg_ptr)
304 return (insert_time (argv, arg_ptr, pred_atime));
307 boolean
308 parse_close (char **argv, int *arg_ptr)
310 struct predicate *our_pred;
312 our_pred = get_new_pred ();
313 our_pred->pred_func = pred_close;
314 #ifdef DEBUG
315 our_pred->p_name = find_pred_name (pred_close);
316 #endif /* DEBUG */
317 our_pred->p_type = CLOSE_PAREN;
318 our_pred->p_prec = NO_PREC;
319 our_pred->need_stat = false;
320 return (true);
323 static boolean
324 parse_cmin (char **argv, int *arg_ptr)
326 struct predicate *our_pred;
327 uintmax_t num;
328 enum comparison_type c_type;
329 time_t t;
331 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
332 return (false);
333 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
334 return (false);
335 t = cur_day_start + DAYSECS - num * 60;
336 our_pred = insert_primary (pred_cmin);
337 our_pred->args.info.kind = c_type;
338 our_pred->args.info.negative = t < 0;
339 our_pred->args.info.l_val = t;
340 (*arg_ptr)++;
341 return (true);
344 static boolean
345 parse_cnewer (char **argv, int *arg_ptr)
347 struct predicate *our_pred;
348 struct stat stat_newer;
350 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
351 return (false);
352 if ((*xstat) (argv[*arg_ptr], &stat_newer))
353 error (1, errno, "%s", argv[*arg_ptr]);
354 our_pred = insert_primary (pred_cnewer);
355 our_pred->args.time = stat_newer.st_mtime;
356 (*arg_ptr)++;
357 return (true);
360 static boolean
361 parse_comma (char **argv, int *arg_ptr)
363 struct predicate *our_pred;
365 our_pred = get_new_pred ();
366 our_pred->pred_func = pred_comma;
367 #ifdef DEBUG
368 our_pred->p_name = find_pred_name (pred_comma);
369 #endif /* DEBUG */
370 our_pred->p_type = BI_OP;
371 our_pred->p_prec = COMMA_PREC;
372 our_pred->need_stat = false;
373 return (true);
376 static boolean
377 parse_ctime (char **argv, int *arg_ptr)
379 return (insert_time (argv, arg_ptr, pred_ctime));
382 static boolean
383 parse_daystart (char **argv, int *arg_ptr)
385 struct tm *local;
387 if (full_days == false)
389 cur_day_start += DAYSECS;
390 local = localtime (&cur_day_start);
391 cur_day_start -= (local
392 ? (local->tm_sec + local->tm_min * 60
393 + local->tm_hour * 3600)
394 : cur_day_start % DAYSECS);
395 full_days = true;
397 return (true);
400 static boolean
401 parse_depth (char **argv, int *arg_ptr)
403 do_dir_first = false;
404 return (true);
407 static boolean
408 parse_empty (char **argv, int *arg_ptr)
410 insert_primary (pred_empty);
411 return (true);
414 static boolean
415 parse_exec (char **argv, int *arg_ptr)
417 return (insert_exec_ok (pred_exec, argv, arg_ptr));
420 static boolean
421 parse_false (char **argv, int *arg_ptr)
423 struct predicate *our_pred;
425 our_pred = insert_primary (pred_false);
426 our_pred->need_stat = false;
427 return (true);
430 static boolean
431 parse_fls (char **argv, int *arg_ptr)
433 struct predicate *our_pred;
435 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
436 return (false);
437 our_pred = insert_primary (pred_fls);
438 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
439 our_pred->side_effects = true;
440 (*arg_ptr)++;
441 return (true);
444 static boolean
445 parse_fprintf (char **argv, int *arg_ptr)
447 FILE *fp;
449 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
450 return (false);
451 if (argv[*arg_ptr + 1] == NULL)
453 /* Ensure we get "missing arg" message, not "invalid arg". */
454 (*arg_ptr)++;
455 return (false);
457 fp = open_output_file (argv[*arg_ptr]);
458 (*arg_ptr)++;
459 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
462 static boolean
463 parse_follow (char **argv, int *arg_ptr)
465 dereference = true;
466 xstat = stat;
467 no_leaf_check = true;
468 return (true);
471 static boolean
472 parse_fprint (char **argv, int *arg_ptr)
474 struct predicate *our_pred;
476 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
477 return (false);
478 our_pred = insert_primary (pred_fprint);
479 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
480 our_pred->side_effects = true;
481 our_pred->need_stat = false;
482 (*arg_ptr)++;
483 return (true);
486 static boolean
487 parse_fprint0 (char **argv, int *arg_ptr)
489 struct predicate *our_pred;
491 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
492 return (false);
493 our_pred = insert_primary (pred_fprint0);
494 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
495 our_pred->side_effects = true;
496 our_pred->need_stat = false;
497 (*arg_ptr)++;
498 return (true);
501 static boolean
502 parse_fstype (char **argv, int *arg_ptr)
504 struct predicate *our_pred;
506 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
507 return (false);
508 our_pred = insert_primary (pred_fstype);
509 our_pred->args.str = argv[*arg_ptr];
510 (*arg_ptr)++;
511 return (true);
514 static boolean
515 parse_gid (char **argv, int *arg_ptr)
517 return (insert_num (argv, arg_ptr, pred_gid));
520 static boolean
521 parse_group (char **argv, int *arg_ptr)
523 struct group *cur_gr;
524 struct predicate *our_pred;
525 gid_t gid;
526 int gid_len;
528 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
529 return (false);
530 cur_gr = getgrnam (argv[*arg_ptr]);
531 endgrent ();
532 if (cur_gr != NULL)
533 gid = cur_gr->gr_gid;
534 else
536 gid_len = strspn (argv[*arg_ptr], "0123456789");
537 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
538 return (false);
539 gid = atoi (argv[*arg_ptr]);
541 our_pred = insert_primary (pred_group);
542 our_pred->args.gid = gid;
543 (*arg_ptr)++;
544 return (true);
547 static boolean
548 parse_help (char **argv, int *arg_ptr)
550 printf (_("\
551 Usage: %s [path...] [expression]\n"), program_name);
552 printf (_("\
553 default path is the current directory; default expression is -print\n\
554 expression may consist of:\n\
555 operators (decreasing precedence; -and is implicit where no others are given):\n\
556 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
557 printf (_("\
558 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
559 options (always true): -daystart -depth -follow --help\n\
560 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
561 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
562 printf (_("\
563 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
564 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
565 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
566 printf (_("\
567 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
568 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
569 -xtype [bcdpfls]\n"));
570 printf (_("\
571 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
572 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
573 exit (0);
576 static boolean
577 parse_ilname (char **argv, int *arg_ptr)
579 struct predicate *our_pred;
581 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
582 return (false);
583 our_pred = insert_primary (pred_ilname);
584 our_pred->args.str = argv[*arg_ptr];
585 (*arg_ptr)++;
586 return (true);
589 static boolean
590 parse_iname (char **argv, int *arg_ptr)
592 struct predicate *our_pred;
594 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
595 return (false);
596 our_pred = insert_primary (pred_iname);
597 our_pred->need_stat = false;
598 our_pred->args.str = argv[*arg_ptr];
599 (*arg_ptr)++;
600 return (true);
603 static boolean
604 parse_inum (char **argv, int *arg_ptr)
606 return (insert_num (argv, arg_ptr, pred_inum));
609 static boolean
610 parse_ipath (char **argv, int *arg_ptr)
612 struct predicate *our_pred;
614 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
615 return (false);
616 our_pred = insert_primary (pred_ipath);
617 our_pred->need_stat = false;
618 our_pred->args.str = argv[*arg_ptr];
619 (*arg_ptr)++;
620 return (true);
623 static boolean
624 parse_iregex (char **argv, int *arg_ptr)
626 return insert_regex (argv, arg_ptr, true);
629 static boolean
630 parse_links (char **argv, int *arg_ptr)
632 return (insert_num (argv, arg_ptr, pred_links));
635 static boolean
636 parse_lname (char **argv, int *arg_ptr)
638 struct predicate *our_pred;
640 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
641 return (false);
642 our_pred = insert_primary (pred_lname);
643 our_pred->args.str = argv[*arg_ptr];
644 (*arg_ptr)++;
645 return (true);
648 static boolean
649 parse_ls (char **argv, int *arg_ptr)
651 struct predicate *our_pred;
653 our_pred = insert_primary (pred_ls);
654 our_pred->side_effects = true;
655 return (true);
658 static boolean
659 parse_maxdepth (char **argv, int *arg_ptr)
661 int depth_len;
663 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
664 return (false);
665 depth_len = strspn (argv[*arg_ptr], "0123456789");
666 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
667 return (false);
668 maxdepth = atoi (argv[*arg_ptr]);
669 if (maxdepth < 0)
670 return (false);
671 (*arg_ptr)++;
672 return (true);
675 static boolean
676 parse_mindepth (char **argv, int *arg_ptr)
678 int depth_len;
680 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
681 return (false);
682 depth_len = strspn (argv[*arg_ptr], "0123456789");
683 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
684 return (false);
685 mindepth = atoi (argv[*arg_ptr]);
686 if (mindepth < 0)
687 return (false);
688 (*arg_ptr)++;
689 return (true);
692 static boolean
693 parse_mmin (char **argv, int *arg_ptr)
695 struct predicate *our_pred;
696 uintmax_t num;
697 enum comparison_type c_type;
698 time_t t;
700 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
701 return (false);
702 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
703 return (false);
704 t = cur_day_start + DAYSECS - num * 60;
705 our_pred = insert_primary (pred_mmin);
706 our_pred->args.info.kind = c_type;
707 our_pred->args.info.negative = t < 0;
708 our_pred->args.info.l_val = t;
709 (*arg_ptr)++;
710 return (true);
713 static boolean
714 parse_mtime (char **argv, int *arg_ptr)
716 return (insert_time (argv, arg_ptr, pred_mtime));
719 static boolean
720 parse_name (char **argv, int *arg_ptr)
722 struct predicate *our_pred;
724 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
725 return (false);
726 our_pred = insert_primary (pred_name);
727 our_pred->need_stat = false;
728 our_pred->args.str = argv[*arg_ptr];
729 (*arg_ptr)++;
730 return (true);
733 static boolean
734 parse_negate (char **argv, int *arg_ptr)
736 struct predicate *our_pred;
738 our_pred = get_new_pred_chk_op ();
739 our_pred->pred_func = pred_negate;
740 #ifdef DEBUG
741 our_pred->p_name = find_pred_name (pred_negate);
742 #endif /* DEBUG */
743 our_pred->p_type = UNI_OP;
744 our_pred->p_prec = NEGATE_PREC;
745 our_pred->need_stat = false;
746 return (true);
749 static boolean
750 parse_newer (char **argv, int *arg_ptr)
752 struct predicate *our_pred;
753 struct stat stat_newer;
755 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
756 return (false);
757 if ((*xstat) (argv[*arg_ptr], &stat_newer))
758 error (1, errno, "%s", argv[*arg_ptr]);
759 our_pred = insert_primary (pred_newer);
760 our_pred->args.time = stat_newer.st_mtime;
761 (*arg_ptr)++;
762 return (true);
765 static boolean
766 parse_noleaf (char **argv, int *arg_ptr)
768 no_leaf_check = true;
769 return true;
772 #ifdef CACHE_IDS
773 /* Arbitrary amount by which to increase size
774 of `uid_unused' and `gid_unused'. */
775 #define ALLOC_STEP 2048
777 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
778 char *uid_unused = NULL;
780 /* Number of elements in `uid_unused'. */
781 unsigned uid_allocated;
783 /* Similar for GIDs and group entries. */
784 char *gid_unused = NULL;
785 unsigned gid_allocated;
786 #endif
788 static boolean
789 parse_nogroup (char **argv, int *arg_ptr)
791 struct predicate *our_pred;
793 our_pred = insert_primary (pred_nogroup);
794 #ifdef CACHE_IDS
795 if (gid_unused == NULL)
797 struct group *gr;
799 gid_allocated = ALLOC_STEP;
800 gid_unused = xmalloc (gid_allocated);
801 memset (gid_unused, 1, gid_allocated);
802 setgrent ();
803 while ((gr = getgrent ()) != NULL)
805 if ((unsigned) gr->gr_gid >= gid_allocated)
807 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
808 gid_unused = xrealloc (gid_unused, new_allocated);
809 memset (gid_unused + gid_allocated, 1,
810 new_allocated - gid_allocated);
811 gid_allocated = new_allocated;
813 gid_unused[(unsigned) gr->gr_gid] = 0;
815 endgrent ();
817 #endif
818 return (true);
821 static boolean
822 parse_nouser (char **argv, int *arg_ptr)
824 struct predicate *our_pred;
826 our_pred = insert_primary (pred_nouser);
827 #ifdef CACHE_IDS
828 if (uid_unused == NULL)
830 struct passwd *pw;
832 uid_allocated = ALLOC_STEP;
833 uid_unused = xmalloc (uid_allocated);
834 memset (uid_unused, 1, uid_allocated);
835 setpwent ();
836 while ((pw = getpwent ()) != NULL)
838 if ((unsigned) pw->pw_uid >= uid_allocated)
840 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
841 uid_unused = xrealloc (uid_unused, new_allocated);
842 memset (uid_unused + uid_allocated, 1,
843 new_allocated - uid_allocated);
844 uid_allocated = new_allocated;
846 uid_unused[(unsigned) pw->pw_uid] = 0;
848 endpwent ();
850 #endif
851 return (true);
854 static boolean
855 parse_ok (char **argv, int *arg_ptr)
857 return (insert_exec_ok (pred_ok, argv, arg_ptr));
860 boolean
861 parse_open (char **argv, int *arg_ptr)
863 struct predicate *our_pred;
865 our_pred = get_new_pred_chk_op ();
866 our_pred->pred_func = pred_open;
867 #ifdef DEBUG
868 our_pred->p_name = find_pred_name (pred_open);
869 #endif /* DEBUG */
870 our_pred->p_type = OPEN_PAREN;
871 our_pred->p_prec = NO_PREC;
872 our_pred->need_stat = false;
873 return (true);
876 static boolean
877 parse_or (char **argv, int *arg_ptr)
879 struct predicate *our_pred;
881 our_pred = get_new_pred ();
882 our_pred->pred_func = pred_or;
883 #ifdef DEBUG
884 our_pred->p_name = find_pred_name (pred_or);
885 #endif /* DEBUG */
886 our_pred->p_type = BI_OP;
887 our_pred->p_prec = OR_PREC;
888 our_pred->need_stat = false;
889 return (true);
892 static boolean
893 parse_path (char **argv, int *arg_ptr)
895 struct predicate *our_pred;
897 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
898 return (false);
899 our_pred = insert_primary (pred_path);
900 our_pred->need_stat = false;
901 our_pred->args.str = argv[*arg_ptr];
902 (*arg_ptr)++;
903 return (true);
906 static boolean
907 parse_perm (char **argv, int *arg_ptr)
909 mode_t perm_val;
910 int mode_start = 0;
911 struct mode_change *change;
912 struct predicate *our_pred;
914 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
915 return (false);
917 switch (argv[*arg_ptr][0])
919 case '-':
920 case '+':
921 mode_start = 1;
922 break;
923 default:
924 /* empty */
925 break;
928 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
929 if (change == MODE_INVALID)
930 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
931 else if (change == MODE_MEMORY_EXHAUSTED)
932 error (1, 0, _("virtual memory exhausted"));
933 perm_val = mode_adjust (0, change);
934 mode_free (change);
936 our_pred = insert_primary (pred_perm);
938 switch (argv[*arg_ptr][0])
940 case '-':
941 our_pred->args.perm.kind = PERM_AT_LEAST;
942 break;
943 case '+':
944 our_pred->args.perm.kind = PERM_ANY;
945 break;
946 default:
947 our_pred->args.perm.kind = PERM_EXACT;
948 break;
950 our_pred->args.perm.val = perm_val & MODE_ALL;
951 (*arg_ptr)++;
952 return (true);
955 boolean
956 parse_print (char **argv, int *arg_ptr)
958 struct predicate *our_pred;
960 our_pred = insert_primary (pred_print);
961 /* -print has the side effect of printing. This prevents us
962 from doing undesired multiple printing when the user has
963 already specified -print. */
964 our_pred->side_effects = true;
965 our_pred->need_stat = false;
966 return (true);
969 static boolean
970 parse_print0 (char **argv, int *arg_ptr)
972 struct predicate *our_pred;
974 our_pred = insert_primary (pred_print0);
975 /* -print0 has the side effect of printing. This prevents us
976 from doing undesired multiple printing when the user has
977 already specified -print0. */
978 our_pred->side_effects = true;
979 our_pred->need_stat = false;
980 return (true);
983 static boolean
984 parse_printf (char **argv, int *arg_ptr)
986 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
987 return (false);
988 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
991 static boolean
992 parse_prune (char **argv, int *arg_ptr)
994 struct predicate *our_pred;
996 our_pred = insert_primary (pred_prune);
997 our_pred->need_stat = false;
998 /* -prune has a side effect that it does not descend into
999 the current directory. */
1000 our_pred->side_effects = true;
1001 return (true);
1004 static boolean
1005 parse_regex (char **argv, int *arg_ptr)
1007 return insert_regex (argv, arg_ptr, false);
1010 static boolean
1011 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1013 struct predicate *our_pred;
1014 struct re_pattern_buffer *re;
1015 const char *error_message;
1017 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1018 return (false);
1019 our_pred = insert_primary (pred_regex);
1020 our_pred->need_stat = false;
1021 re = (struct re_pattern_buffer *)
1022 xmalloc (sizeof (struct re_pattern_buffer));
1023 our_pred->args.regex = re;
1024 re->allocated = 100;
1025 re->buffer = (unsigned char *) xmalloc (re->allocated);
1026 re->fastmap = NULL;
1028 if (ignore_case)
1030 unsigned i;
1032 re->translate = xmalloc (256);
1033 /* Map uppercase characters to corresponding lowercase ones. */
1034 for (i = 0; i < 256; i++)
1035 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1037 else
1038 re->translate = NULL;
1040 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1041 re);
1042 if (error_message)
1043 error (1, 0, "%s", error_message);
1044 (*arg_ptr)++;
1045 return (true);
1048 static boolean
1049 parse_size (char **argv, int *arg_ptr)
1051 struct predicate *our_pred;
1052 uintmax_t num;
1053 enum comparison_type c_type;
1054 int blksize = 512;
1055 int len;
1057 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1058 return (false);
1059 len = strlen (argv[*arg_ptr]);
1060 if (len == 0)
1061 error (1, 0, _("invalid null argument to -size"));
1062 switch (argv[*arg_ptr][len - 1])
1064 case 'b':
1065 blksize = 512;
1066 argv[*arg_ptr][len - 1] = '\0';
1067 break;
1069 case 'c':
1070 blksize = 1;
1071 argv[*arg_ptr][len - 1] = '\0';
1072 break;
1074 case 'k':
1075 blksize = 1024;
1076 argv[*arg_ptr][len - 1] = '\0';
1077 break;
1079 case 'w':
1080 blksize = 2;
1081 argv[*arg_ptr][len - 1] = '\0';
1082 break;
1084 case '0':
1085 case '1':
1086 case '2':
1087 case '3':
1088 case '4':
1089 case '5':
1090 case '6':
1091 case '7':
1092 case '8':
1093 case '9':
1094 break;
1096 default:
1097 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1099 if (!get_num (argv[*arg_ptr], &num, &c_type))
1100 return (false);
1101 our_pred = insert_primary (pred_size);
1102 our_pred->args.size.kind = c_type;
1103 our_pred->args.size.blocksize = blksize;
1104 our_pred->args.size.size = num;
1105 (*arg_ptr)++;
1106 return (true);
1109 static boolean
1110 parse_true (char **argv, int *arg_ptr)
1112 struct predicate *our_pred;
1114 our_pred = insert_primary (pred_true);
1115 our_pred->need_stat = false;
1116 return (true);
1119 static boolean
1120 parse_type (char **argv, int *arg_ptr)
1122 return insert_type (argv, arg_ptr, pred_type);
1125 static boolean
1126 parse_uid (char **argv, int *arg_ptr)
1128 return (insert_num (argv, arg_ptr, pred_uid));
1131 static boolean
1132 parse_used (char **argv, int *arg_ptr)
1134 struct predicate *our_pred;
1135 uintmax_t num_days;
1136 enum comparison_type c_type;
1137 time_t t;
1139 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1140 return (false);
1141 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1142 return (false);
1143 t = num_days * DAYSECS;
1144 our_pred = insert_primary (pred_used);
1145 our_pred->args.info.kind = c_type;
1146 our_pred->args.info.negative = t < 0;
1147 our_pred->args.info.l_val = t;
1148 (*arg_ptr)++;
1149 return (true);
1152 static boolean
1153 parse_user (char **argv, int *arg_ptr)
1155 struct passwd *cur_pwd;
1156 struct predicate *our_pred;
1157 uid_t uid;
1158 int uid_len;
1160 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1161 return (false);
1162 cur_pwd = getpwnam (argv[*arg_ptr]);
1163 endpwent ();
1164 if (cur_pwd != NULL)
1165 uid = cur_pwd->pw_uid;
1166 else
1168 uid_len = strspn (argv[*arg_ptr], "0123456789");
1169 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1170 return (false);
1171 uid = atoi (argv[*arg_ptr]);
1173 our_pred = insert_primary (pred_user);
1174 our_pred->args.uid = uid;
1175 (*arg_ptr)++;
1176 return (true);
1179 static boolean
1180 parse_version (char **argv, int *arg_ptr)
1182 extern char *version_string;
1184 fflush (stderr);
1185 printf (_("GNU find version %s\n"), version_string);
1186 exit (0);
1189 static boolean
1190 parse_xdev (char **argv, int *arg_ptr)
1192 stay_on_filesystem = true;
1193 return true;
1196 static boolean
1197 parse_xtype (char **argv, int *arg_ptr)
1199 return insert_type (argv, arg_ptr, pred_xtype);
1202 static boolean
1203 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1205 mode_t type_cell;
1206 struct predicate *our_pred;
1208 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1209 || (strlen (argv[*arg_ptr]) != 1))
1210 return (false);
1211 switch (argv[*arg_ptr][0])
1213 case 'b': /* block special */
1214 type_cell = S_IFBLK;
1215 break;
1216 case 'c': /* character special */
1217 type_cell = S_IFCHR;
1218 break;
1219 case 'd': /* directory */
1220 type_cell = S_IFDIR;
1221 break;
1222 case 'f': /* regular file */
1223 type_cell = S_IFREG;
1224 break;
1225 #ifdef S_IFLNK
1226 case 'l': /* symbolic link */
1227 type_cell = S_IFLNK;
1228 break;
1229 #endif
1230 #ifdef S_IFIFO
1231 case 'p': /* pipe */
1232 type_cell = S_IFIFO;
1233 break;
1234 #endif
1235 #ifdef S_IFSOCK
1236 case 's': /* socket */
1237 type_cell = S_IFSOCK;
1238 break;
1239 #endif
1240 default: /* None of the above ... nuke 'em. */
1241 return (false);
1243 our_pred = insert_primary (which_pred);
1244 our_pred->args.type = type_cell;
1245 (*arg_ptr)++; /* Move on to next argument. */
1246 return (true);
1249 /* If true, we've determined that the current fprintf predicate
1250 uses stat information. */
1251 static boolean fprintf_stat_needed;
1253 static boolean
1254 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1256 char *format; /* Beginning of unprocessed format string. */
1257 register char *scan; /* Current address in scanning `format'. */
1258 register char *scan2; /* Address inside of element being scanned. */
1259 struct segment **segmentp; /* Address of current segment. */
1260 struct predicate *our_pred;
1262 format = argv[(*arg_ptr)++];
1264 fprintf_stat_needed = false; /* Might be overridden later. */
1265 our_pred = insert_primary (func);
1266 our_pred->side_effects = true;
1267 our_pred->args.printf_vec.stream = fp;
1268 segmentp = &our_pred->args.printf_vec.segment;
1269 *segmentp = NULL;
1271 for (scan = format; *scan; scan++)
1273 if (*scan == '\\')
1275 scan2 = scan + 1;
1276 if (*scan2 >= '0' && *scan2 <= '7')
1278 register int n, i;
1280 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1281 i++, scan2++)
1282 n = 8 * n + *scan2 - '0';
1283 scan2--;
1284 *scan = n;
1286 else
1288 switch (*scan2)
1290 case 'a':
1291 *scan = 7;
1292 break;
1293 case 'b':
1294 *scan = '\b';
1295 break;
1296 case 'c':
1297 make_segment (segmentp, format, scan - format, KIND_STOP);
1298 our_pred->need_stat = fprintf_stat_needed;
1299 return (true);
1300 case 'f':
1301 *scan = '\f';
1302 break;
1303 case 'n':
1304 *scan = '\n';
1305 break;
1306 case 'r':
1307 *scan = '\r';
1308 break;
1309 case 't':
1310 *scan = '\t';
1311 break;
1312 case 'v':
1313 *scan = '\v';
1314 break;
1315 case '\\':
1316 /* *scan = '\\'; * it already is */
1317 break;
1318 default:
1319 error (0, 0,
1320 _("warning: unrecognized escape `\\%c'"), *scan2);
1321 scan++;
1322 continue;
1325 segmentp = make_segment (segmentp, format, scan - format + 1,
1326 KIND_PLAIN);
1327 format = scan2 + 1; /* Move past the escape. */
1328 scan = scan2; /* Incremented immediately by `for'. */
1330 else if (*scan == '%')
1332 if (scan[1] == '%')
1334 segmentp = make_segment (segmentp, format, scan - format + 1,
1335 KIND_PLAIN);
1336 scan++;
1337 format = scan + 1;
1338 continue;
1340 /* Scan past flags, width and precision, to verify kind. */
1341 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1342 /* Do nothing. */ ;
1343 while (ISDIGIT (*scan2))
1344 scan2++;
1345 if (*scan2 == '.')
1346 for (scan2++; ISDIGIT (*scan2); scan2++)
1347 /* Do nothing. */ ;
1348 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1350 segmentp = make_segment (segmentp, format, scan2 - format,
1351 (int) *scan2);
1352 scan = scan2;
1353 format = scan + 1;
1355 else if (strchr ("ACT", *scan2) && scan2[1])
1357 segmentp = make_segment (segmentp, format, scan2 - format,
1358 *scan2 | (scan2[1] << 8));
1359 scan = scan2 + 1;
1360 format = scan + 1;
1361 continue;
1363 else
1365 /* An unrecognized % escape. Print the char after the %. */
1366 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1367 *scan2);
1368 segmentp = make_segment (segmentp, format, scan - format,
1369 KIND_PLAIN);
1370 format = scan + 1;
1371 continue;
1376 if (scan > format)
1377 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1378 our_pred->need_stat = fprintf_stat_needed;
1379 return (true);
1382 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1383 from the text in FORMAT, which has length LEN.
1384 Return the address of the `next' pointer of the new segment. */
1386 static struct segment **
1387 make_segment (struct segment **segment, char *format, int len, int kind)
1389 char *fmt;
1391 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1393 (*segment)->kind = kind;
1394 (*segment)->next = NULL;
1395 (*segment)->text_len = len;
1397 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1398 strncpy (fmt, format, len);
1399 fmt += len;
1401 switch (kind & 0xff)
1403 case KIND_PLAIN: /* Plain text string, no % conversion. */
1404 case KIND_STOP: /* Terminate argument, no newline. */
1405 break;
1407 case 'a': /* atime in `ctime' format */
1408 case 'A': /* atime in user-specified strftime format */
1409 case 'b': /* size in 512-byte blocks */
1410 case 'c': /* ctime in `ctime' format */
1411 case 'C': /* ctime in user-specified strftime format */
1412 case 'F': /* filesystem type */
1413 case 'G': /* GID number */
1414 case 'g': /* group name */
1415 case 'i': /* inode number */
1416 case 'k': /* size in 1K blocks */
1417 case 'l': /* object of symlink */
1418 case 'n': /* number of links */
1419 case 's': /* size in bytes */
1420 case 't': /* mtime in `ctime' format */
1421 case 'T': /* mtime in user-specified strftime format */
1422 case 'U': /* UID number */
1423 case 'u': /* user name */
1424 fprintf_stat_needed = true;
1425 /* FALLTHROUGH */
1426 case 'f': /* basename of path */
1427 case 'h': /* leading directories part of path */
1428 case 'H': /* ARGV element file was found under */
1429 case 'p': /* pathname */
1430 case 'P': /* pathname with ARGV element stripped */
1431 *fmt++ = 's';
1432 break;
1434 case 'd': /* depth in search tree (0 = ARGV element) */
1435 *fmt++ = 'd';
1436 break;
1438 case 'm': /* mode as octal number (perms only) */
1439 *fmt++ = 'o';
1440 fprintf_stat_needed = true;
1441 break;
1443 *fmt = '\0';
1445 return (&(*segment)->next);
1448 static boolean
1449 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1451 int start, end; /* Indexes in ARGV of start & end of cmd. */
1452 int num_paths; /* Number of args with path replacements. */
1453 int path_pos; /* Index in array of path replacements. */
1454 int vec_pos; /* Index in array of args. */
1455 struct predicate *our_pred;
1456 struct exec_val *execp; /* Pointer for efficiency. */
1458 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1459 return (false);
1461 /* Count the number of args with path replacements, up until the ';'. */
1462 start = *arg_ptr;
1463 for (end = start, num_paths = 0;
1464 (argv[end] != NULL)
1465 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1466 end++)
1467 if (strstr (argv[end], "{}"))
1468 num_paths++;
1469 /* Fail if no command given or no semicolon found. */
1470 if ((end == start) || (argv[end] == NULL))
1472 *arg_ptr = end;
1473 return (false);
1476 our_pred = insert_primary (func);
1477 our_pred->side_effects = true;
1478 execp = &our_pred->args.exec_vec;
1479 execp->paths =
1480 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1481 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1482 /* Record the positions of all args, and the args with path replacements. */
1483 for (end = start, path_pos = vec_pos = 0;
1484 (argv[end] != NULL)
1485 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1486 end++)
1488 register char *p;
1490 execp->paths[path_pos].count = 0;
1491 for (p = argv[end]; *p; ++p)
1492 if (p[0] == '{' && p[1] == '}')
1494 execp->paths[path_pos].count++;
1495 ++p;
1497 if (execp->paths[path_pos].count)
1499 execp->paths[path_pos].offset = vec_pos;
1500 execp->paths[path_pos].origarg = argv[end];
1501 path_pos++;
1503 execp->vec[vec_pos++] = argv[end];
1505 execp->paths[path_pos].offset = -1;
1506 execp->vec[vec_pos] = NULL;
1508 if (argv[end] == NULL)
1509 *arg_ptr = end;
1510 else
1511 *arg_ptr = end + 1;
1512 return (true);
1515 /* Get a number of days and comparison type.
1516 STR is the ASCII representation.
1517 Set *NUM_DAYS to the number of days, taken as being from
1518 the current moment (or possibly midnight). Thus the sense of the
1519 comparison type appears to be reversed.
1520 Set *COMP_TYPE to the kind of comparison that is requested.
1522 Return true if all okay, false if input error.
1524 Used by -atime, -ctime and -mtime (parsers) to
1525 get the appropriate information for a time predicate processor. */
1527 static boolean
1528 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1530 boolean r = get_num (str, num_days, comp_type);
1531 if (r)
1532 switch (*comp_type)
1534 case COMP_LT: *comp_type = COMP_GT; break;
1535 case COMP_GT: *comp_type = COMP_LT; break;
1536 default: break;
1538 return r;
1541 /* Insert a time predicate PRED.
1542 ARGV is a pointer to the argument array.
1543 ARG_PTR is a pointer to an index into the array, incremented if
1544 all went well.
1546 Return true if input is valid, false if not.
1548 A new predicate node is assigned, along with an argument node
1549 obtained with malloc.
1551 Used by -atime, -ctime, and -mtime parsers. */
1553 static boolean
1554 insert_time (char **argv, int *arg_ptr, PFB pred)
1556 struct predicate *our_pred;
1557 uintmax_t num_days;
1558 enum comparison_type c_type;
1559 time_t t;
1561 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1562 return (false);
1563 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1564 return (false);
1565 t = (cur_day_start - num_days * DAYSECS
1566 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1567 our_pred = insert_primary (pred);
1568 our_pred->args.info.kind = c_type;
1569 our_pred->args.info.negative = t < 0;
1570 our_pred->args.info.l_val = t;
1571 (*arg_ptr)++;
1572 #ifdef DEBUG
1573 printf (_("inserting %s\n"), our_pred->p_name);
1574 printf (_(" type: %s %s "),
1575 (c_type == COMP_GT) ? "gt" :
1576 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1577 (c_type == COMP_GT) ? " >" :
1578 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1579 t = our_pred->args.info.l_val;
1580 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1581 if (c_type == COMP_EQ)
1583 t = our_pred->args.info.l_val += DAYSECS;
1584 printf (" < %ju %s",
1585 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1586 our_pred->args.info.l_val -= DAYSECS;
1588 #endif /* DEBUG */
1589 return (true);
1592 /* Get a number with comparision information.
1593 The sense of the comparision information is 'normal'; that is,
1594 '+' looks for a count > than the number and '-' less than.
1596 STR is the ASCII representation of the number.
1597 Set *NUM to the number.
1598 Set *COMP_TYPE to the kind of comparison that is requested.
1600 Return true if all okay, false if input error. */
1602 static boolean
1603 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1605 int len_num; /* Length of field. */
1607 if (str == NULL)
1608 return (false);
1609 switch (str[0])
1611 case '+':
1612 *comp_type = COMP_GT;
1613 str++;
1614 break;
1615 case '-':
1616 *comp_type = COMP_LT;
1617 str++;
1618 break;
1619 default:
1620 *comp_type = COMP_EQ;
1621 break;
1624 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1627 /* Insert a number predicate.
1628 ARGV is a pointer to the argument array.
1629 *ARG_PTR is an index into ARGV, incremented if all went well.
1630 *PRED is the predicate processor to insert.
1632 Return true if input is valid, false if error.
1634 A new predicate node is assigned, along with an argument node
1635 obtained with malloc.
1637 Used by -inum and -links parsers. */
1639 static boolean
1640 insert_num (char **argv, int *arg_ptr, PFB pred)
1642 struct predicate *our_pred;
1643 uintmax_t num;
1644 enum comparison_type c_type;
1646 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1647 return (false);
1648 if (!get_num (argv[*arg_ptr], &num, &c_type))
1649 return (false);
1650 our_pred = insert_primary (pred);
1651 our_pred->args.info.kind = c_type;
1652 our_pred->args.info.l_val = num;
1653 (*arg_ptr)++;
1654 #ifdef DEBUG
1655 printf (_("inserting %s\n"), our_pred->p_name);
1656 printf (_(" type: %s %s "),
1657 (c_type == COMP_GT) ? "gt" :
1658 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1659 (c_type == COMP_GT) ? " >" :
1660 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1661 printf ("%ju\n", our_pred->args.info.l_val);
1662 #endif /* DEBUG */
1663 return (true);
1666 static FILE *
1667 open_output_file (char *path)
1669 FILE *f;
1671 if (!strcmp (path, "/dev/stderr"))
1672 return (stderr);
1673 else if (!strcmp (path, "/dev/stdout"))
1674 return (stdout);
1675 f = fopen (path, "w");
1676 if (f == NULL)
1677 error (1, errno, "%s", path);
1678 return (f);