* xargs/Makefile.am: add ansi2knr
[findutils.git] / find / parser.c
blobf72f0c5ccaef186b77fac55d3b93ab50c1b34520
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94 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 <config.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include "modechange.h"
26 #include "defs.h"
27 #include "modetype.h"
29 #if ENABLE_NLS
30 # include <libintl.h>
31 # define _(Text) gettext (Text)
32 #else
33 # define _(Text) Text
34 #endif
35 #ifdef gettext_noop
36 # define N_(String) gettext_noop (String)
37 #else
38 # define N_(String) (String)
39 #endif
41 #if !defined (isascii) || defined (STDC_HEADERS)
42 #ifdef isascii
43 #undef isascii
44 #endif
45 #define isascii(c) 1
46 #endif
48 #define ISDIGIT(c) (isascii (c) && isdigit (c))
49 #define ISUPPER(c) (isascii (c) && isupper (c))
51 #ifndef HAVE_ENDGRENT
52 #define endgrent()
53 #endif
54 #ifndef HAVE_ENDPWENT
55 #define endpwent()
56 #endif
58 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
59 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
60 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
61 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
62 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
64 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
65 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
97 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
99 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
100 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
101 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
103 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
104 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
106 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
107 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
108 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
109 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
110 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
112 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
113 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
114 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
115 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
116 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
117 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
118 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
120 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
121 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
122 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
123 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
124 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
125 static boolean get_num_days PARAMS((char *str, unsigned long *num_days, enum comparison_type *comp_type));
126 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
127 static boolean get_num PARAMS((char *str, unsigned long *num, enum comparison_type *comp_type));
128 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
129 static FILE *open_output_file PARAMS((char *path));
131 #ifdef DEBUG
132 char *find_pred_name PARAMS((PFB pred_func));
133 #endif /* DEBUG */
135 struct parser_table
137 char *parser_name;
138 PFB parser_func;
141 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
142 If they are in some Unix versions of find, they are marked `Unix'. */
144 static struct parser_table const parse_table[] =
146 {"!", parse_negate},
147 {"not", parse_negate}, /* GNU */
148 {"(", parse_open},
149 {")", parse_close},
150 {",", parse_comma}, /* GNU */
151 {"a", parse_and},
152 {"amin", parse_amin}, /* GNU */
153 {"and", parse_and}, /* GNU */
154 {"anewer", parse_anewer}, /* GNU */
155 {"atime", parse_atime},
156 {"cmin", parse_cmin}, /* GNU */
157 {"cnewer", parse_cnewer}, /* GNU */
158 #ifdef UNIMPLEMENTED_UNIX
159 /* It's pretty ugly for find to know about archive formats.
160 Plus what it could do with cpio archives is very limited.
161 Better to leave it out. */
162 {"cpio", parse_cpio}, /* Unix */
163 #endif
164 {"ctime", parse_ctime},
165 {"daystart", parse_daystart}, /* GNU */
166 {"depth", parse_depth},
167 {"empty", parse_empty}, /* GNU */
168 {"exec", parse_exec},
169 {"false", parse_false}, /* GNU */
170 {"fls", parse_fls}, /* GNU */
171 {"follow", parse_follow}, /* GNU, Unix */
172 {"fprint", parse_fprint}, /* GNU */
173 {"fprint0", parse_fprint0}, /* GNU */
174 {"fprintf", parse_fprintf}, /* GNU */
175 {"fstype", parse_fstype}, /* GNU, Unix */
176 {"gid", parse_gid}, /* GNU */
177 {"group", parse_group},
178 {"help", parse_help}, /* GNU */
179 {"-help", parse_help}, /* GNU */
180 {"ilname", parse_ilname}, /* GNU */
181 {"iname", parse_iname}, /* GNU */
182 {"inum", parse_inum}, /* GNU, Unix */
183 {"ipath", parse_ipath}, /* GNU */
184 {"iregex", parse_iregex}, /* GNU */
185 {"links", parse_links},
186 {"lname", parse_lname}, /* GNU */
187 {"ls", parse_ls}, /* GNU, Unix */
188 {"maxdepth", parse_maxdepth}, /* GNU */
189 {"mindepth", parse_mindepth}, /* GNU */
190 {"mmin", parse_mmin}, /* GNU */
191 {"mount", parse_xdev}, /* Unix */
192 {"mtime", parse_mtime},
193 {"name", parse_name},
194 #ifdef UNIMPLEMENTED_UNIX
195 {"ncpio", parse_ncpio}, /* Unix */
196 #endif
197 {"newer", parse_newer},
198 {"noleaf", parse_noleaf}, /* GNU */
199 {"nogroup", parse_nogroup},
200 {"nouser", parse_nouser},
201 {"o", parse_or},
202 {"or", parse_or}, /* GNU */
203 {"ok", parse_ok},
204 {"path", parse_path}, /* GNU, HP-UX */
205 {"perm", parse_perm},
206 {"print", parse_print},
207 {"print0", parse_print0}, /* GNU */
208 {"printf", parse_printf}, /* GNU */
209 {"prune", parse_prune},
210 {"regex", parse_regex}, /* GNU */
211 {"size", parse_size},
212 {"true", parse_true}, /* GNU */
213 {"type", parse_type},
214 {"uid", parse_uid}, /* GNU */
215 {"used", parse_used}, /* GNU */
216 {"user", parse_user},
217 {"version", parse_version}, /* GNU */
218 {"-version", parse_version}, /* GNU */
219 {"xdev", parse_xdev},
220 {"xtype", parse_xtype}, /* GNU */
221 {0, 0}
224 /* Return a pointer to the parser function to invoke for predicate
225 SEARCH_NAME.
226 Return NULL if SEARCH_NAME is not a valid predicate name. */
229 find_parser (char *search_name)
231 int i;
233 if (*search_name == '-')
234 search_name++;
235 for (i = 0; parse_table[i].parser_name != 0; i++)
236 if (strcmp (parse_table[i].parser_name, search_name) == 0)
237 return (parse_table[i].parser_func);
238 return (NULL);
241 /* The parsers are responsible to continue scanning ARGV for
242 their arguments. Each parser knows what is and isn't
243 allowed for itself.
245 ARGV is the argument array.
246 *ARG_PTR is the index to start at in ARGV,
247 updated to point beyond the last element consumed.
249 The predicate structure is updated with the new information. */
251 static boolean
252 parse_amin (char **argv, int *arg_ptr)
254 struct predicate *our_pred;
255 unsigned long num;
256 enum comparison_type c_type;
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 our_pred = insert_primary (pred_amin);
263 our_pred->args.info.kind = c_type;
264 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
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 unsigned long num;
328 enum comparison_type c_type;
330 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
331 return (false);
332 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
333 return (false);
334 our_pred = insert_primary (pred_cmin);
335 our_pred->args.info.kind = c_type;
336 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
337 (*arg_ptr)++;
338 return (true);
341 static boolean
342 parse_cnewer (char **argv, int *arg_ptr)
344 struct predicate *our_pred;
345 struct stat stat_newer;
347 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
348 return (false);
349 if ((*xstat) (argv[*arg_ptr], &stat_newer))
350 error (1, errno, "%s", argv[*arg_ptr]);
351 our_pred = insert_primary (pred_cnewer);
352 our_pred->args.time = stat_newer.st_mtime;
353 (*arg_ptr)++;
354 return (true);
357 static boolean
358 parse_comma (char **argv, int *arg_ptr)
360 struct predicate *our_pred;
362 our_pred = get_new_pred ();
363 our_pred->pred_func = pred_comma;
364 #ifdef DEBUG
365 our_pred->p_name = find_pred_name (pred_comma);
366 #endif /* DEBUG */
367 our_pred->p_type = BI_OP;
368 our_pred->p_prec = COMMA_PREC;
369 our_pred->need_stat = false;
370 return (true);
373 static boolean
374 parse_ctime (char **argv, int *arg_ptr)
376 return (insert_time (argv, arg_ptr, pred_ctime));
379 static boolean
380 parse_daystart (char **argv, int *arg_ptr)
382 struct tm *local;
384 if (full_days == false)
386 cur_day_start += DAYSECS;
387 local = localtime (&cur_day_start);
388 cur_day_start -= local->tm_sec + local->tm_min * 60
389 + local->tm_hour * 3600;
390 full_days = true;
392 return (true);
395 static boolean
396 parse_depth (char **argv, int *arg_ptr)
398 do_dir_first = false;
399 return (true);
402 static boolean
403 parse_empty (char **argv, int *arg_ptr)
405 insert_primary (pred_empty);
406 return (true);
409 static boolean
410 parse_exec (char **argv, int *arg_ptr)
412 return (insert_exec_ok (pred_exec, argv, arg_ptr));
415 static boolean
416 parse_false (char **argv, int *arg_ptr)
418 struct predicate *our_pred;
420 our_pred = insert_primary (pred_false);
421 our_pred->need_stat = false;
422 return (true);
425 static boolean
426 parse_fls (char **argv, int *arg_ptr)
428 struct predicate *our_pred;
430 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
431 return (false);
432 our_pred = insert_primary (pred_fls);
433 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
434 our_pred->side_effects = true;
435 (*arg_ptr)++;
436 return (true);
439 static boolean
440 parse_fprintf (char **argv, int *arg_ptr)
442 FILE *fp;
444 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
445 return (false);
446 if (argv[*arg_ptr + 1] == NULL)
448 /* Ensure we get "missing arg" message, not "invalid arg". */
449 (*arg_ptr)++;
450 return (false);
452 fp = open_output_file (argv[*arg_ptr]);
453 (*arg_ptr)++;
454 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
457 static boolean
458 parse_follow (char **argv, int *arg_ptr)
460 dereference = true;
461 xstat = stat;
462 no_leaf_check = true;
463 return (true);
466 static boolean
467 parse_fprint (char **argv, int *arg_ptr)
469 struct predicate *our_pred;
471 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
472 return (false);
473 our_pred = insert_primary (pred_fprint);
474 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
475 our_pred->side_effects = true;
476 our_pred->need_stat = false;
477 (*arg_ptr)++;
478 return (true);
481 static boolean
482 parse_fprint0 (char **argv, int *arg_ptr)
484 struct predicate *our_pred;
486 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
487 return (false);
488 our_pred = insert_primary (pred_fprint0);
489 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
490 our_pred->side_effects = true;
491 our_pred->need_stat = false;
492 (*arg_ptr)++;
493 return (true);
496 static boolean
497 parse_fstype (char **argv, int *arg_ptr)
499 struct predicate *our_pred;
501 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
502 return (false);
503 our_pred = insert_primary (pred_fstype);
504 our_pred->args.str = argv[*arg_ptr];
505 (*arg_ptr)++;
506 return (true);
509 static boolean
510 parse_gid (char **argv, int *arg_ptr)
512 return (insert_num (argv, arg_ptr, pred_gid));
515 static boolean
516 parse_group (char **argv, int *arg_ptr)
518 struct group *cur_gr;
519 struct predicate *our_pred;
520 gid_t gid;
521 int gid_len;
523 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
524 return (false);
525 cur_gr = getgrnam (argv[*arg_ptr]);
526 endgrent ();
527 if (cur_gr != NULL)
528 gid = cur_gr->gr_gid;
529 else
531 gid_len = strspn (argv[*arg_ptr], "0123456789");
532 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
533 return (false);
534 gid = atoi (argv[*arg_ptr]);
536 our_pred = insert_primary (pred_group);
537 our_pred->args.gid = gid;
538 (*arg_ptr)++;
539 return (true);
542 static boolean
543 parse_help (char **argv, int *arg_ptr)
545 printf (_("\
546 Usage: %s [path...] [expression]\n"), program_name);
547 printf (_("\
548 default path is the current directory; default expression is -print\n\
549 expression may consist of:\n\
550 operators (decreasing precedence; -and is implicit where no others are given):\n\
551 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
552 printf (_("\
553 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
554 options (always true): -daystart -depth -follow --help\n\
555 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
556 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
557 printf (_("\
558 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
559 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
560 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
561 printf (_("\
562 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
563 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
564 -xtype [bcdpfls]\n"));
565 printf (_("\
566 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
567 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
568 exit (0);
571 static boolean
572 parse_ilname (char **argv, int *arg_ptr)
574 struct predicate *our_pred;
576 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
577 return (false);
578 our_pred = insert_primary (pred_ilname);
579 our_pred->args.str = argv[*arg_ptr];
580 (*arg_ptr)++;
581 return (true);
584 static boolean
585 parse_iname (char **argv, int *arg_ptr)
587 struct predicate *our_pred;
589 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
590 return (false);
591 our_pred = insert_primary (pred_iname);
592 our_pred->need_stat = false;
593 our_pred->args.str = argv[*arg_ptr];
594 (*arg_ptr)++;
595 return (true);
598 static boolean
599 parse_inum (char **argv, int *arg_ptr)
601 return (insert_num (argv, arg_ptr, pred_inum));
604 static boolean
605 parse_ipath (char **argv, int *arg_ptr)
607 struct predicate *our_pred;
609 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
610 return (false);
611 our_pred = insert_primary (pred_ipath);
612 our_pred->need_stat = false;
613 our_pred->args.str = argv[*arg_ptr];
614 (*arg_ptr)++;
615 return (true);
618 static boolean
619 parse_iregex (char **argv, int *arg_ptr)
621 return insert_regex (argv, arg_ptr, true);
624 static boolean
625 parse_links (char **argv, int *arg_ptr)
627 return (insert_num (argv, arg_ptr, pred_links));
630 static boolean
631 parse_lname (char **argv, int *arg_ptr)
633 struct predicate *our_pred;
635 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
636 return (false);
637 our_pred = insert_primary (pred_lname);
638 our_pred->args.str = argv[*arg_ptr];
639 (*arg_ptr)++;
640 return (true);
643 static boolean
644 parse_ls (char **argv, int *arg_ptr)
646 struct predicate *our_pred;
648 our_pred = insert_primary (pred_ls);
649 our_pred->side_effects = true;
650 return (true);
653 static boolean
654 parse_maxdepth (char **argv, int *arg_ptr)
656 int depth_len;
658 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
659 return (false);
660 depth_len = strspn (argv[*arg_ptr], "0123456789");
661 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
662 return (false);
663 maxdepth = atoi (argv[*arg_ptr]);
664 if (maxdepth < 0)
665 return (false);
666 (*arg_ptr)++;
667 return (true);
670 static boolean
671 parse_mindepth (char **argv, int *arg_ptr)
673 int depth_len;
675 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
676 return (false);
677 depth_len = strspn (argv[*arg_ptr], "0123456789");
678 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
679 return (false);
680 mindepth = atoi (argv[*arg_ptr]);
681 if (mindepth < 0)
682 return (false);
683 (*arg_ptr)++;
684 return (true);
687 static boolean
688 parse_mmin (char **argv, int *arg_ptr)
690 struct predicate *our_pred;
691 unsigned long num;
692 enum comparison_type c_type;
694 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
695 return (false);
696 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
697 return (false);
698 our_pred = insert_primary (pred_mmin);
699 our_pred->args.info.kind = c_type;
700 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
701 (*arg_ptr)++;
702 return (true);
705 static boolean
706 parse_mtime (char **argv, int *arg_ptr)
708 return (insert_time (argv, arg_ptr, pred_mtime));
711 static boolean
712 parse_name (char **argv, int *arg_ptr)
714 struct predicate *our_pred;
716 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
717 return (false);
718 our_pred = insert_primary (pred_name);
719 our_pred->need_stat = false;
720 our_pred->args.str = argv[*arg_ptr];
721 (*arg_ptr)++;
722 return (true);
725 static boolean
726 parse_negate (char **argv, int *arg_ptr)
728 struct predicate *our_pred;
730 our_pred = get_new_pred_chk_op ();
731 our_pred->pred_func = pred_negate;
732 #ifdef DEBUG
733 our_pred->p_name = find_pred_name (pred_negate);
734 #endif /* DEBUG */
735 our_pred->p_type = UNI_OP;
736 our_pred->p_prec = NEGATE_PREC;
737 our_pred->need_stat = false;
738 return (true);
741 static boolean
742 parse_newer (char **argv, int *arg_ptr)
744 struct predicate *our_pred;
745 struct stat stat_newer;
747 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
748 return (false);
749 if ((*xstat) (argv[*arg_ptr], &stat_newer))
750 error (1, errno, "%s", argv[*arg_ptr]);
751 our_pred = insert_primary (pred_newer);
752 our_pred->args.time = stat_newer.st_mtime;
753 (*arg_ptr)++;
754 return (true);
757 static boolean
758 parse_noleaf (char **argv, int *arg_ptr)
760 no_leaf_check = true;
761 return true;
764 #ifdef CACHE_IDS
765 /* Arbitrary amount by which to increase size
766 of `uid_unused' and `gid_unused'. */
767 #define ALLOC_STEP 2048
769 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
770 char *uid_unused = NULL;
772 /* Number of elements in `uid_unused'. */
773 unsigned uid_allocated;
775 /* Similar for GIDs and group entries. */
776 char *gid_unused = NULL;
777 unsigned gid_allocated;
778 #endif
780 static boolean
781 parse_nogroup (char **argv, int *arg_ptr)
783 struct predicate *our_pred;
785 our_pred = insert_primary (pred_nogroup);
786 #ifdef CACHE_IDS
787 if (gid_unused == NULL)
789 struct group *gr;
791 gid_allocated = ALLOC_STEP;
792 gid_unused = xmalloc (gid_allocated);
793 memset (gid_unused, 1, gid_allocated);
794 setgrent ();
795 while ((gr = getgrent ()) != NULL)
797 if ((unsigned) gr->gr_gid >= gid_allocated)
799 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
800 gid_unused = xrealloc (gid_unused, new_allocated);
801 memset (gid_unused + gid_allocated, 1,
802 new_allocated - gid_allocated);
803 gid_allocated = new_allocated;
805 gid_unused[(unsigned) gr->gr_gid] = 0;
807 endgrent ();
809 #endif
810 return (true);
813 static boolean
814 parse_nouser (char **argv, int *arg_ptr)
816 struct predicate *our_pred;
818 our_pred = insert_primary (pred_nouser);
819 #ifdef CACHE_IDS
820 if (uid_unused == NULL)
822 struct passwd *pw;
824 uid_allocated = ALLOC_STEP;
825 uid_unused = xmalloc (uid_allocated);
826 memset (uid_unused, 1, uid_allocated);
827 setpwent ();
828 while ((pw = getpwent ()) != NULL)
830 if ((unsigned) pw->pw_uid >= uid_allocated)
832 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
833 uid_unused = xrealloc (uid_unused, new_allocated);
834 memset (uid_unused + uid_allocated, 1,
835 new_allocated - uid_allocated);
836 uid_allocated = new_allocated;
838 uid_unused[(unsigned) pw->pw_uid] = 0;
840 endpwent ();
842 #endif
843 return (true);
846 static boolean
847 parse_ok (char **argv, int *arg_ptr)
849 return (insert_exec_ok (pred_ok, argv, arg_ptr));
852 boolean
853 parse_open (char **argv, int *arg_ptr)
855 struct predicate *our_pred;
857 our_pred = get_new_pred_chk_op ();
858 our_pred->pred_func = pred_open;
859 #ifdef DEBUG
860 our_pred->p_name = find_pred_name (pred_open);
861 #endif /* DEBUG */
862 our_pred->p_type = OPEN_PAREN;
863 our_pred->p_prec = NO_PREC;
864 our_pred->need_stat = false;
865 return (true);
868 static boolean
869 parse_or (char **argv, int *arg_ptr)
871 struct predicate *our_pred;
873 our_pred = get_new_pred ();
874 our_pred->pred_func = pred_or;
875 #ifdef DEBUG
876 our_pred->p_name = find_pred_name (pred_or);
877 #endif /* DEBUG */
878 our_pred->p_type = BI_OP;
879 our_pred->p_prec = OR_PREC;
880 our_pred->need_stat = false;
881 return (true);
884 static boolean
885 parse_path (char **argv, int *arg_ptr)
887 struct predicate *our_pred;
889 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
890 return (false);
891 our_pred = insert_primary (pred_path);
892 our_pred->need_stat = false;
893 our_pred->args.str = argv[*arg_ptr];
894 (*arg_ptr)++;
895 return (true);
898 static boolean
899 parse_perm (char **argv, int *arg_ptr)
901 unsigned long perm_val;
902 int mode_start = 0;
903 struct mode_change *change;
904 struct predicate *our_pred;
906 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
907 return (false);
909 switch (argv[*arg_ptr][0])
911 case '-':
912 case '+':
913 mode_start = 1;
914 break;
915 default:
916 /* empty */
917 break;
920 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
921 if (change == MODE_INVALID)
922 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
923 else if (change == MODE_MEMORY_EXHAUSTED)
924 error (1, 0, _("virtual memory exhausted"));
925 perm_val = mode_adjust (0, change);
926 mode_free (change);
928 our_pred = insert_primary (pred_perm);
930 switch (argv[*arg_ptr][0])
932 case '-':
933 /* Set magic flag to indicate true if at least the given bits are set. */
934 our_pred->args.perm = (perm_val & 07777) | 010000;
935 break;
936 case '+':
937 /* Set magic flag to indicate true if any of the given bits are set. */
938 our_pred->args.perm = (perm_val & 07777) | 020000;
939 break;
940 default:
941 /* True if exactly the given bits are set. */
942 our_pred->args.perm = (perm_val & 07777);
943 break;
945 (*arg_ptr)++;
946 return (true);
949 boolean
950 parse_print (char **argv, int *arg_ptr)
952 struct predicate *our_pred;
954 our_pred = insert_primary (pred_print);
955 /* -print has the side effect of printing. This prevents us
956 from doing undesired multiple printing when the user has
957 already specified -print. */
958 our_pred->side_effects = true;
959 our_pred->need_stat = false;
960 return (true);
963 static boolean
964 parse_print0 (char **argv, int *arg_ptr)
966 struct predicate *our_pred;
968 our_pred = insert_primary (pred_print0);
969 /* -print0 has the side effect of printing. This prevents us
970 from doing undesired multiple printing when the user has
971 already specified -print0. */
972 our_pred->side_effects = true;
973 our_pred->need_stat = false;
974 return (true);
977 static boolean
978 parse_printf (char **argv, int *arg_ptr)
980 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
981 return (false);
982 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
985 static boolean
986 parse_prune (char **argv, int *arg_ptr)
988 struct predicate *our_pred;
990 our_pred = insert_primary (pred_prune);
991 our_pred->need_stat = false;
992 return (true);
995 static boolean
996 parse_regex (char **argv, int *arg_ptr)
998 return insert_regex (argv, arg_ptr, false);
1001 static boolean
1002 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1004 struct predicate *our_pred;
1005 struct re_pattern_buffer *re;
1006 const char *error_message;
1008 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1009 return (false);
1010 our_pred = insert_primary (pred_regex);
1011 our_pred->need_stat = false;
1012 re = (struct re_pattern_buffer *)
1013 xmalloc (sizeof (struct re_pattern_buffer));
1014 our_pred->args.regex = re;
1015 re->allocated = 100;
1016 re->buffer = (unsigned char *) xmalloc (re->allocated);
1017 re->fastmap = NULL;
1019 if (ignore_case)
1021 unsigned i;
1023 re->translate = xmalloc (256);
1024 /* Map uppercase characters to corresponding lowercase ones. */
1025 for (i = 0; i < 256; i++)
1026 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1028 else
1029 re->translate = NULL;
1031 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1032 re);
1033 if (error_message)
1034 error (1, 0, "%s", error_message);
1035 (*arg_ptr)++;
1036 return (true);
1039 static boolean
1040 parse_size (char **argv, int *arg_ptr)
1042 struct predicate *our_pred;
1043 unsigned long num;
1044 enum comparison_type c_type;
1045 int blksize = 512;
1046 int len;
1048 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1049 return (false);
1050 len = strlen (argv[*arg_ptr]);
1051 if (len == 0)
1052 error (1, 0, _("invalid null argument to -size"));
1053 switch (argv[*arg_ptr][len - 1])
1055 case 'b':
1056 blksize = 512;
1057 argv[*arg_ptr][len - 1] = '\0';
1058 break;
1060 case 'c':
1061 blksize = 1;
1062 argv[*arg_ptr][len - 1] = '\0';
1063 break;
1065 case 'k':
1066 blksize = 1024;
1067 argv[*arg_ptr][len - 1] = '\0';
1068 break;
1070 case 'w':
1071 blksize = 2;
1072 argv[*arg_ptr][len - 1] = '\0';
1073 break;
1075 case '0':
1076 case '1':
1077 case '2':
1078 case '3':
1079 case '4':
1080 case '5':
1081 case '6':
1082 case '7':
1083 case '8':
1084 case '9':
1085 break;
1087 default:
1088 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1090 if (!get_num (argv[*arg_ptr], &num, &c_type))
1091 return (false);
1092 our_pred = insert_primary (pred_size);
1093 our_pred->args.size.kind = c_type;
1094 our_pred->args.size.blocksize = blksize;
1095 our_pred->args.size.size = num;
1096 (*arg_ptr)++;
1097 return (true);
1100 static boolean
1101 parse_true (char **argv, int *arg_ptr)
1103 struct predicate *our_pred;
1105 our_pred = insert_primary (pred_true);
1106 our_pred->need_stat = false;
1107 return (true);
1110 static boolean
1111 parse_type (char **argv, int *arg_ptr)
1113 return insert_type (argv, arg_ptr, pred_type);
1116 static boolean
1117 parse_uid (char **argv, int *arg_ptr)
1119 return (insert_num (argv, arg_ptr, pred_uid));
1122 static boolean
1123 parse_used (char **argv, int *arg_ptr)
1125 struct predicate *our_pred;
1126 unsigned long num_days;
1127 enum comparison_type c_type;
1129 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1130 return (false);
1131 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1132 return (false);
1133 our_pred = insert_primary (pred_used);
1134 our_pred->args.info.kind = c_type;
1135 our_pred->args.info.l_val = num_days * DAYSECS;
1136 (*arg_ptr)++;
1137 return (true);
1140 static boolean
1141 parse_user (char **argv, int *arg_ptr)
1143 struct passwd *cur_pwd;
1144 struct predicate *our_pred;
1145 uid_t uid;
1146 int uid_len;
1148 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1149 return (false);
1150 cur_pwd = getpwnam (argv[*arg_ptr]);
1151 endpwent ();
1152 if (cur_pwd != NULL)
1153 uid = cur_pwd->pw_uid;
1154 else
1156 uid_len = strspn (argv[*arg_ptr], "0123456789");
1157 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1158 return (false);
1159 uid = atoi (argv[*arg_ptr]);
1161 our_pred = insert_primary (pred_user);
1162 our_pred->args.uid = uid;
1163 (*arg_ptr)++;
1164 return (true);
1167 static boolean
1168 parse_version (char **argv, int *arg_ptr)
1170 extern char *version_string;
1172 fflush (stderr);
1173 printf (_("GNU find version %s\n"), version_string);
1174 exit (0);
1177 static boolean
1178 parse_xdev (char **argv, int *arg_ptr)
1180 stay_on_filesystem = true;
1181 return true;
1184 static boolean
1185 parse_xtype (char **argv, int *arg_ptr)
1187 return insert_type (argv, arg_ptr, pred_xtype);
1190 static boolean
1191 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1193 unsigned long type_cell;
1194 struct predicate *our_pred;
1196 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1197 || (strlen (argv[*arg_ptr]) != 1))
1198 return (false);
1199 switch (argv[*arg_ptr][0])
1201 case 'b': /* block special */
1202 type_cell = S_IFBLK;
1203 break;
1204 case 'c': /* character special */
1205 type_cell = S_IFCHR;
1206 break;
1207 case 'd': /* directory */
1208 type_cell = S_IFDIR;
1209 break;
1210 case 'f': /* regular file */
1211 type_cell = S_IFREG;
1212 break;
1213 #ifdef S_IFLNK
1214 case 'l': /* symbolic link */
1215 type_cell = S_IFLNK;
1216 break;
1217 #endif
1218 #ifdef S_IFIFO
1219 case 'p': /* pipe */
1220 type_cell = S_IFIFO;
1221 break;
1222 #endif
1223 #ifdef S_IFSOCK
1224 case 's': /* socket */
1225 type_cell = S_IFSOCK;
1226 break;
1227 #endif
1228 default: /* None of the above ... nuke 'em. */
1229 return (false);
1231 our_pred = insert_primary (which_pred);
1232 our_pred->args.type = type_cell;
1233 (*arg_ptr)++; /* Move on to next argument. */
1234 return (true);
1237 /* If true, we've determined that the current fprintf predicate
1238 uses stat information. */
1239 static boolean fprintf_stat_needed;
1241 static boolean
1242 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1244 char *format; /* Beginning of unprocessed format string. */
1245 register char *scan; /* Current address in scanning `format'. */
1246 register char *scan2; /* Address inside of element being scanned. */
1247 struct segment **segmentp; /* Address of current segment. */
1248 struct predicate *our_pred;
1250 format = argv[(*arg_ptr)++];
1252 fprintf_stat_needed = false; /* Might be overridden later. */
1253 our_pred = insert_primary (func);
1254 our_pred->side_effects = true;
1255 our_pred->args.printf_vec.stream = fp;
1256 segmentp = &our_pred->args.printf_vec.segment;
1257 *segmentp = NULL;
1259 for (scan = format; *scan; scan++)
1261 if (*scan == '\\')
1263 scan2 = scan + 1;
1264 if (*scan2 >= '0' && *scan2 <= '7')
1266 register int n, i;
1268 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1269 i++, scan2++)
1270 n = 8 * n + *scan2 - '0';
1271 scan2--;
1272 *scan = n;
1274 else
1276 switch (*scan2)
1278 case 'a':
1279 *scan = 7;
1280 break;
1281 case 'b':
1282 *scan = '\b';
1283 break;
1284 case 'c':
1285 make_segment (segmentp, format, scan - format, KIND_STOP);
1286 our_pred->need_stat = fprintf_stat_needed;
1287 return (true);
1288 case 'f':
1289 *scan = '\f';
1290 break;
1291 case 'n':
1292 *scan = '\n';
1293 break;
1294 case 'r':
1295 *scan = '\r';
1296 break;
1297 case 't':
1298 *scan = '\t';
1299 break;
1300 case 'v':
1301 *scan = '\v';
1302 break;
1303 case '\\':
1304 /* *scan = '\\'; * it already is */
1305 break;
1306 default:
1307 error (0, 0,
1308 _("warning: unrecognized escape `\\%c'"), *scan2);
1309 scan++;
1310 continue;
1313 segmentp = make_segment (segmentp, format, scan - format + 1,
1314 KIND_PLAIN);
1315 format = scan2 + 1; /* Move past the escape. */
1316 scan = scan2; /* Incremented immediately by `for'. */
1318 else if (*scan == '%')
1320 if (scan[1] == '%')
1322 segmentp = make_segment (segmentp, format, scan - format + 1,
1323 KIND_PLAIN);
1324 scan++;
1325 format = scan + 1;
1326 continue;
1328 /* Scan past flags, width and precision, to verify kind. */
1329 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1330 /* Do nothing. */ ;
1331 while (ISDIGIT (*scan2))
1332 scan2++;
1333 if (*scan2 == '.')
1334 for (scan2++; ISDIGIT (*scan2); scan2++)
1335 /* Do nothing. */ ;
1336 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1338 segmentp = make_segment (segmentp, format, scan2 - format,
1339 (int) *scan2);
1340 scan = scan2;
1341 format = scan + 1;
1343 else if (strchr ("ACT", *scan2) && scan2[1])
1345 segmentp = make_segment (segmentp, format, scan2 - format,
1346 *scan2 | (scan2[1] << 8));
1347 scan = scan2 + 1;
1348 format = scan + 1;
1349 continue;
1351 else
1353 /* An unrecognized % escape. Print the char after the %. */
1354 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1355 *scan2);
1356 segmentp = make_segment (segmentp, format, scan - format,
1357 KIND_PLAIN);
1358 format = scan + 1;
1359 continue;
1364 if (scan > format)
1365 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1366 our_pred->need_stat = fprintf_stat_needed;
1367 return (true);
1370 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1371 from the text in FORMAT, which has length LEN.
1372 Return the address of the `next' pointer of the new segment. */
1374 static struct segment **
1375 make_segment (struct segment **segment, char *format, int len, int kind)
1377 char *fmt;
1379 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1381 (*segment)->kind = kind;
1382 (*segment)->next = NULL;
1383 (*segment)->text_len = len;
1385 fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
1386 strncpy (fmt, format, len);
1387 fmt += len;
1389 switch (kind & 0xff)
1391 case KIND_PLAIN: /* Plain text string, no % conversion. */
1392 case KIND_STOP: /* Terminate argument, no newline. */
1393 break;
1395 case 'a': /* atime in `ctime' format */
1396 case 'c': /* ctime in `ctime' format */
1397 case 'F': /* filesystem type */
1398 case 'g': /* group name */
1399 case 'l': /* object of symlink */
1400 case 't': /* mtime in `ctime' format */
1401 case 'u': /* user name */
1402 case 'A': /* atime in user-specified strftime format */
1403 case 'C': /* ctime in user-specified strftime format */
1404 case 'T': /* mtime in user-specified strftime format */
1405 fprintf_stat_needed = true;
1406 /* FALLTHROUGH */
1407 case 'f': /* basename of path */
1408 case 'h': /* leading directories part of path */
1409 case 'H': /* ARGV element file was found under */
1410 case 'p': /* pathname */
1411 case 'P': /* pathname with ARGV element stripped */
1412 *fmt++ = 's';
1413 break;
1415 case 'b': /* size in 512-byte blocks */
1416 case 'k': /* size in 1K blocks */
1417 case 's': /* size in bytes */
1418 *fmt++ = 'l';
1419 /*FALLTHROUGH*/
1420 case 'n': /* number of links */
1421 fprintf_stat_needed = true;
1422 /* FALLTHROUGH */
1423 case 'd': /* depth in search tree (0 = ARGV element) */
1424 *fmt++ = 'd';
1425 break;
1427 case 'i': /* inode number */
1428 *fmt++ = 'l';
1429 /*FALLTHROUGH*/
1430 case 'G': /* GID number */
1431 case 'U': /* UID number */
1432 *fmt++ = 'u';
1433 fprintf_stat_needed = true;
1434 break;
1436 case 'm': /* mode as octal number (perms only) */
1437 *fmt++ = 'o';
1438 fprintf_stat_needed = true;
1439 break;
1441 *fmt = '\0';
1443 return (&(*segment)->next);
1446 static boolean
1447 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1449 int start, end; /* Indexes in ARGV of start & end of cmd. */
1450 int num_paths; /* Number of args with path replacements. */
1451 int path_pos; /* Index in array of path replacements. */
1452 int vec_pos; /* Index in array of args. */
1453 struct predicate *our_pred;
1454 struct exec_val *execp; /* Pointer for efficiency. */
1456 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1457 return (false);
1459 /* Count the number of args with path replacements, up until the ';'. */
1460 start = *arg_ptr;
1461 for (end = start, num_paths = 0;
1462 (argv[end] != NULL)
1463 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1464 end++)
1465 if (strstr (argv[end], "{}"))
1466 num_paths++;
1467 /* Fail if no command given or no semicolon found. */
1468 if ((end == start) || (argv[end] == NULL))
1470 *arg_ptr = end;
1471 return (false);
1474 our_pred = insert_primary (func);
1475 our_pred->side_effects = true;
1476 execp = &our_pred->args.exec_vec;
1477 execp->paths =
1478 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1479 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1480 /* Record the positions of all args, and the args with path replacements. */
1481 for (end = start, path_pos = vec_pos = 0;
1482 (argv[end] != NULL)
1483 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1484 end++)
1486 register char *p;
1488 execp->paths[path_pos].count = 0;
1489 for (p = argv[end]; *p; ++p)
1490 if (p[0] == '{' && p[1] == '}')
1492 execp->paths[path_pos].count++;
1493 ++p;
1495 if (execp->paths[path_pos].count)
1497 execp->paths[path_pos].offset = vec_pos;
1498 execp->paths[path_pos].origarg = argv[end];
1499 path_pos++;
1501 execp->vec[vec_pos++] = argv[end];
1503 execp->paths[path_pos].offset = -1;
1504 execp->vec[vec_pos] = NULL;
1506 if (argv[end] == NULL)
1507 *arg_ptr = end;
1508 else
1509 *arg_ptr = end + 1;
1510 return (true);
1513 /* Get a number of days and comparison type.
1514 STR is the ASCII representation.
1515 Set *NUM_DAYS to the number of days, taken as being from
1516 the current moment (or possibly midnight). Thus the sense of the
1517 comparison type appears to be reversed.
1518 Set *COMP_TYPE to the kind of comparison that is requested.
1520 Return true if all okay, false if input error.
1522 Used by -atime, -ctime and -mtime (parsers) to
1523 get the appropriate information for a time predicate processor. */
1525 static boolean
1526 get_num_days (char *str, long unsigned int *num_days, enum comparison_type *comp_type)
1528 int len_days; /* length of field */
1530 if (str == NULL)
1531 return (false);
1532 switch (str[0])
1534 case '+':
1535 *comp_type = COMP_LT;
1536 str++;
1537 break;
1538 case '-':
1539 *comp_type = COMP_GT;
1540 str++;
1541 break;
1542 case '0':
1543 case '1':
1544 case '2':
1545 case '3':
1546 case '4':
1547 case '5':
1548 case '6':
1549 case '7':
1550 case '8':
1551 case '9':
1552 *comp_type = COMP_EQ;
1553 break;
1554 default:
1555 return (false);
1558 /* We know the first char has been reasonable. Find the
1559 number of days to play with. */
1560 len_days = strspn (str, "0123456789");
1561 if ((len_days == 0) || (str[len_days] != '\0'))
1562 return (false);
1563 *num_days = (unsigned long) atol (str);
1564 return (true);
1567 /* Insert a time predicate PRED.
1568 ARGV is a pointer to the argument array.
1569 ARG_PTR is a pointer to an index into the array, incremented if
1570 all went well.
1572 Return true if input is valid, false if not.
1574 A new predicate node is assigned, along with an argument node
1575 obtained with malloc.
1577 Used by -atime, -ctime, and -mtime parsers. */
1579 static boolean
1580 insert_time (char **argv, int *arg_ptr, PFB pred)
1582 struct predicate *our_pred;
1583 unsigned long num_days;
1584 enum comparison_type c_type;
1586 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1587 return (false);
1588 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1589 return (false);
1590 our_pred = insert_primary (pred);
1591 our_pred->args.info.kind = c_type;
1592 our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
1593 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
1594 (*arg_ptr)++;
1595 #ifdef DEBUG
1596 printf (_("inserting %s\n"), our_pred->p_name);
1597 printf (_(" type: %s %s "),
1598 (c_type == COMP_GT) ? "gt" :
1599 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1600 (c_type == COMP_GT) ? " >" :
1601 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1602 printf ("%ld %s", our_pred->args.info.l_val,
1603 ctime (&our_pred->args.info.l_val));
1604 if (c_type == COMP_EQ)
1606 our_pred->args.info.l_val += DAYSECS;
1607 printf (" < %ld %s", our_pred->args.info.l_val,
1608 ctime (&our_pred->args.info.l_val));
1609 our_pred->args.info.l_val -= DAYSECS;
1611 #endif /* DEBUG */
1612 return (true);
1615 /* Get a number with comparision information.
1616 The sense of the comparision information is 'normal'; that is,
1617 '+' looks for inums or links > than the number and '-' less than.
1619 STR is the ASCII representation of the number.
1620 Set *NUM to the number.
1621 Set *COMP_TYPE to the kind of comparison that is requested.
1623 Return true if all okay, false if input error.
1625 Used by the -inum and -links predicate parsers. */
1627 static boolean
1628 get_num (char *str, long unsigned int *num, enum comparison_type *comp_type)
1630 int len_num; /* Length of field. */
1632 if (str == NULL)
1633 return (false);
1634 switch (str[0])
1636 case '+':
1637 *comp_type = COMP_GT;
1638 str++;
1639 break;
1640 case '-':
1641 *comp_type = COMP_LT;
1642 str++;
1643 break;
1644 case '0':
1645 case '1':
1646 case '2':
1647 case '3':
1648 case '4':
1649 case '5':
1650 case '6':
1651 case '7':
1652 case '8':
1653 case '9':
1654 *comp_type = COMP_EQ;
1655 break;
1656 default:
1657 return (false);
1660 /* We know the first char has been reasonable. Find the number of
1661 days to play with. */
1662 len_num = strspn (str, "0123456789");
1663 if ((len_num == 0) || (str[len_num] != '\0'))
1664 return (false);
1665 *num = (unsigned long) atol (str);
1666 return (true);
1669 /* Insert a number predicate.
1670 ARGV is a pointer to the argument array.
1671 *ARG_PTR is an index into ARGV, incremented if all went well.
1672 *PRED is the predicate processor to insert.
1674 Return true if input is valid, false if error.
1676 A new predicate node is assigned, along with an argument node
1677 obtained with malloc.
1679 Used by -inum and -links parsers. */
1681 static boolean
1682 insert_num (char **argv, int *arg_ptr, PFB pred)
1684 struct predicate *our_pred;
1685 unsigned long num;
1686 enum comparison_type c_type;
1688 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1689 return (false);
1690 if (!get_num (argv[*arg_ptr], &num, &c_type))
1691 return (false);
1692 our_pred = insert_primary (pred);
1693 our_pred->args.info.kind = c_type;
1694 our_pred->args.info.l_val = num;
1695 (*arg_ptr)++;
1696 #ifdef DEBUG
1697 printf (_("inserting %s\n"), our_pred->p_name);
1698 printf (_(" type: %s %s "),
1699 (c_type == COMP_GT) ? "gt" :
1700 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1701 (c_type == COMP_GT) ? " >" :
1702 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1703 printf ("%ld\n", our_pred->args.info.l_val);
1704 #endif /* DEBUG */
1705 return (true);
1708 static FILE *
1709 open_output_file (char *path)
1711 FILE *f;
1713 if (!strcmp (path, "/dev/stderr"))
1714 return (stderr);
1715 else if (!strcmp (path, "/dev/stdout"))
1716 return (stdout);
1717 f = fopen (path, "w");
1718 if (f == NULL)
1719 error (1, errno, "%s", path);
1720 return (f);