*** empty log message ***
[findutils.git] / find / parser.c
blob9211a3c7b83306a9f0248ad9134e15c793992c5f
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 !defined (isascii) || defined (STDC_HEADERS)
30 #ifdef isascii
31 #undef isascii
32 #endif
33 #define isascii(c) 1
34 #endif
36 #define ISDIGIT(c) (isascii (c) && isdigit (c))
37 #define ISUPPER(c) (isascii (c) && isupper (c))
39 #ifndef HAVE_ENDGRENT
40 #define endgrent()
41 #endif
42 #ifndef HAVE_ENDPWENT
43 #define endpwent()
44 #endif
46 static boolean parse_amin P_((char *argv[], int *arg_ptr));
47 static boolean parse_and P_((char *argv[], int *arg_ptr));
48 static boolean parse_anewer P_((char *argv[], int *arg_ptr));
49 static boolean parse_atime P_((char *argv[], int *arg_ptr));
50 boolean parse_close P_((char *argv[], int *arg_ptr));
51 static boolean parse_cmin P_((char *argv[], int *arg_ptr));
52 static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
53 static boolean parse_comma P_((char *argv[], int *arg_ptr));
54 static boolean parse_ctime P_((char *argv[], int *arg_ptr));
55 static boolean parse_daystart P_((char *argv[], int *arg_ptr));
56 static boolean parse_depth P_((char *argv[], int *arg_ptr));
57 static boolean parse_empty P_((char *argv[], int *arg_ptr));
58 static boolean parse_exec P_((char *argv[], int *arg_ptr));
59 static boolean parse_false P_((char *argv[], int *arg_ptr));
60 static boolean parse_fls P_((char *argv[], int *arg_ptr));
61 static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
62 static boolean parse_follow P_((char *argv[], int *arg_ptr));
63 static boolean parse_fprint P_((char *argv[], int *arg_ptr));
64 static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
65 static boolean parse_fstype P_((char *argv[], int *arg_ptr));
66 static boolean parse_gid P_((char *argv[], int *arg_ptr));
67 static boolean parse_group P_((char *argv[], int *arg_ptr));
68 static boolean parse_help P_((char *argv[], int *arg_ptr));
69 static boolean parse_ilname P_((char *argv[], int *arg_ptr));
70 static boolean parse_iname P_((char *argv[], int *arg_ptr));
71 static boolean parse_inum P_((char *argv[], int *arg_ptr));
72 static boolean parse_ipath P_((char *argv[], int *arg_ptr));
73 static boolean parse_iregex P_((char *argv[], int *arg_ptr));
74 static boolean parse_links P_((char *argv[], int *arg_ptr));
75 static boolean parse_lname P_((char *argv[], int *arg_ptr));
76 static boolean parse_ls P_((char *argv[], int *arg_ptr));
77 static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
78 static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
79 static boolean parse_mmin P_((char *argv[], int *arg_ptr));
80 static boolean parse_mtime P_((char *argv[], int *arg_ptr));
81 static boolean parse_name P_((char *argv[], int *arg_ptr));
82 static boolean parse_negate P_((char *argv[], int *arg_ptr));
83 static boolean parse_newer P_((char *argv[], int *arg_ptr));
84 static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
85 static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
86 static boolean parse_nouser P_((char *argv[], int *arg_ptr));
87 static boolean parse_ok P_((char *argv[], int *arg_ptr));
88 boolean parse_open P_((char *argv[], int *arg_ptr));
89 static boolean parse_or P_((char *argv[], int *arg_ptr));
90 static boolean parse_path P_((char *argv[], int *arg_ptr));
91 static boolean parse_perm P_((char *argv[], int *arg_ptr));
92 boolean parse_print P_((char *argv[], int *arg_ptr));
93 static boolean parse_print0 P_((char *argv[], int *arg_ptr));
94 static boolean parse_printf P_((char *argv[], int *arg_ptr));
95 static boolean parse_prune P_((char *argv[], int *arg_ptr));
96 static boolean parse_regex P_((char *argv[], int *arg_ptr));
97 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
98 static boolean parse_size P_((char *argv[], int *arg_ptr));
99 static boolean parse_true P_((char *argv[], int *arg_ptr));
100 static boolean parse_type P_((char *argv[], int *arg_ptr));
101 static boolean parse_uid P_((char *argv[], int *arg_ptr));
102 static boolean parse_used P_((char *argv[], int *arg_ptr));
103 static boolean parse_user P_((char *argv[], int *arg_ptr));
104 static boolean parse_version P_((char *argv[], int *arg_ptr));
105 static boolean parse_xdev P_((char *argv[], int *arg_ptr));
106 static boolean parse_xtype P_((char *argv[], int *arg_ptr));
108 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
109 static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
110 static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
111 static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
112 static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
113 static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
114 static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
115 static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
116 static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
117 static FILE *open_output_file P_((char *path));
119 #ifdef DEBUG
120 char *find_pred_name _P((PFB pred_func));
121 #endif /* DEBUG */
123 struct parser_table
125 char *parser_name;
126 PFB parser_func;
129 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
130 If they are in some Unix versions of find, they are marked `Unix'. */
132 static struct parser_table const parse_table[] =
134 {"!", parse_negate},
135 {"not", parse_negate}, /* GNU */
136 {"(", parse_open},
137 {")", parse_close},
138 {",", parse_comma}, /* GNU */
139 {"a", parse_and},
140 {"amin", parse_amin}, /* GNU */
141 {"and", parse_and}, /* GNU */
142 {"anewer", parse_anewer}, /* GNU */
143 {"atime", parse_atime},
144 {"cmin", parse_cmin}, /* GNU */
145 {"cnewer", parse_cnewer}, /* GNU */
146 #ifdef UNIMPLEMENTED_UNIX
147 /* It's pretty ugly for find to know about archive formats.
148 Plus what it could do with cpio archives is very limited.
149 Better to leave it out. */
150 {"cpio", parse_cpio}, /* Unix */
151 #endif
152 {"ctime", parse_ctime},
153 {"daystart", parse_daystart}, /* GNU */
154 {"depth", parse_depth},
155 {"empty", parse_empty}, /* GNU */
156 {"exec", parse_exec},
157 {"false", parse_false}, /* GNU */
158 {"fls", parse_fls}, /* GNU */
159 {"follow", parse_follow}, /* GNU, Unix */
160 {"fprint", parse_fprint}, /* GNU */
161 {"fprint0", parse_fprint0}, /* GNU */
162 {"fprintf", parse_fprintf}, /* GNU */
163 {"fstype", parse_fstype}, /* GNU, Unix */
164 {"gid", parse_gid}, /* GNU */
165 {"group", parse_group},
166 {"help", parse_help}, /* GNU */
167 {"-help", parse_help}, /* GNU */
168 {"ilname", parse_ilname}, /* GNU */
169 {"iname", parse_iname}, /* GNU */
170 {"inum", parse_inum}, /* GNU, Unix */
171 {"ipath", parse_ipath}, /* GNU */
172 {"iregex", parse_iregex}, /* GNU */
173 {"links", parse_links},
174 {"lname", parse_lname}, /* GNU */
175 {"ls", parse_ls}, /* GNU, Unix */
176 {"maxdepth", parse_maxdepth}, /* GNU */
177 {"mindepth", parse_mindepth}, /* GNU */
178 {"mmin", parse_mmin}, /* GNU */
179 {"mount", parse_xdev}, /* Unix */
180 {"mtime", parse_mtime},
181 {"name", parse_name},
182 #ifdef UNIMPLEMENTED_UNIX
183 {"ncpio", parse_ncpio}, /* Unix */
184 #endif
185 {"newer", parse_newer},
186 {"noleaf", parse_noleaf}, /* GNU */
187 {"nogroup", parse_nogroup},
188 {"nouser", parse_nouser},
189 {"o", parse_or},
190 {"or", parse_or}, /* GNU */
191 {"ok", parse_ok},
192 {"path", parse_path}, /* GNU, HP-UX */
193 {"perm", parse_perm},
194 {"print", parse_print},
195 {"print0", parse_print0}, /* GNU */
196 {"printf", parse_printf}, /* GNU */
197 {"prune", parse_prune},
198 {"regex", parse_regex}, /* GNU */
199 {"size", parse_size},
200 {"true", parse_true}, /* GNU */
201 {"type", parse_type},
202 {"uid", parse_uid}, /* GNU */
203 {"used", parse_used}, /* GNU */
204 {"user", parse_user},
205 {"version", parse_version}, /* GNU */
206 {"-version", parse_version}, /* GNU */
207 {"xdev", parse_xdev},
208 {"xtype", parse_xtype}, /* GNU */
209 {0, 0}
212 /* Return a pointer to the parser function to invoke for predicate
213 SEARCH_NAME.
214 Return NULL if SEARCH_NAME is not a valid predicate name. */
217 find_parser (search_name)
218 char *search_name;
220 int i;
222 if (*search_name == '-')
223 search_name++;
224 for (i = 0; parse_table[i].parser_name != 0; i++)
225 if (strcmp (parse_table[i].parser_name, search_name) == 0)
226 return (parse_table[i].parser_func);
227 return (NULL);
230 /* The parsers are responsible to continue scanning ARGV for
231 their arguments. Each parser knows what is and isn't
232 allowed for itself.
234 ARGV is the argument array.
235 *ARG_PTR is the index to start at in ARGV,
236 updated to point beyond the last element consumed.
238 The predicate structure is updated with the new information. */
240 static boolean
241 parse_amin (argv, arg_ptr)
242 char *argv[];
243 int *arg_ptr;
245 struct predicate *our_pred;
246 unsigned long num;
247 enum comparison_type c_type;
249 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
250 return (false);
251 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
252 return (false);
253 our_pred = insert_primary (pred_amin);
254 our_pred->args.info.kind = c_type;
255 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
256 (*arg_ptr)++;
257 return (true);
260 static boolean
261 parse_and (argv, arg_ptr)
262 char *argv[];
263 int *arg_ptr;
265 struct predicate *our_pred;
267 our_pred = get_new_pred ();
268 our_pred->pred_func = pred_and;
269 #ifdef DEBUG
270 our_pred->p_name = find_pred_name (pred_and);
271 #endif /* DEBUG */
272 our_pred->p_type = BI_OP;
273 our_pred->p_prec = AND_PREC;
274 our_pred->need_stat = false;
275 return (true);
278 static boolean
279 parse_anewer (argv, arg_ptr)
280 char *argv[];
281 int *arg_ptr;
283 struct predicate *our_pred;
284 struct stat stat_newer;
286 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
287 return (false);
288 if ((*xstat) (argv[*arg_ptr], &stat_newer))
289 error (1, errno, "%s", argv[*arg_ptr]);
290 our_pred = insert_primary (pred_anewer);
291 our_pred->args.time = stat_newer.st_mtime;
292 (*arg_ptr)++;
293 return (true);
296 static boolean
297 parse_atime (argv, arg_ptr)
298 char *argv[];
299 int *arg_ptr;
301 return (insert_time (argv, arg_ptr, pred_atime));
304 boolean
305 parse_close (argv, arg_ptr)
306 char *argv[];
307 int *arg_ptr;
309 struct predicate *our_pred;
311 our_pred = get_new_pred ();
312 our_pred->pred_func = pred_close;
313 #ifdef DEBUG
314 our_pred->p_name = find_pred_name (pred_close);
315 #endif /* DEBUG */
316 our_pred->p_type = CLOSE_PAREN;
317 our_pred->p_prec = NO_PREC;
318 our_pred->need_stat = false;
319 return (true);
322 static boolean
323 parse_cmin (argv, arg_ptr)
324 char *argv[];
325 int *arg_ptr;
327 struct predicate *our_pred;
328 unsigned long num;
329 enum comparison_type c_type;
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 our_pred = insert_primary (pred_cmin);
336 our_pred->args.info.kind = c_type;
337 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
338 (*arg_ptr)++;
339 return (true);
342 static boolean
343 parse_cnewer (argv, arg_ptr)
344 char *argv[];
345 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 (argv, arg_ptr)
362 char *argv[];
363 int *arg_ptr;
365 struct predicate *our_pred;
367 our_pred = get_new_pred ();
368 our_pred->pred_func = pred_comma;
369 #ifdef DEBUG
370 our_pred->p_name = find_pred_name (pred_comma);
371 #endif /* DEBUG */
372 our_pred->p_type = BI_OP;
373 our_pred->p_prec = COMMA_PREC;
374 our_pred->need_stat = false;
375 return (true);
378 static boolean
379 parse_ctime (argv, arg_ptr)
380 char *argv[];
381 int *arg_ptr;
383 return (insert_time (argv, arg_ptr, pred_ctime));
386 static boolean
387 parse_daystart (argv, arg_ptr)
388 char *argv[];
389 int *arg_ptr;
391 struct tm *local;
393 if (full_days == false)
395 cur_day_start += DAYSECS;
396 local = localtime (&cur_day_start);
397 cur_day_start -= local->tm_sec + local->tm_min * 60
398 + local->tm_hour * 3600;
399 full_days = true;
401 return (true);
404 static boolean
405 parse_depth (argv, arg_ptr)
406 char *argv[];
407 int *arg_ptr;
409 do_dir_first = false;
410 return (true);
413 static boolean
414 parse_empty (argv, arg_ptr)
415 char *argv[];
416 int *arg_ptr;
418 insert_primary (pred_empty);
419 return (true);
422 static boolean
423 parse_exec (argv, arg_ptr)
424 char *argv[];
425 int *arg_ptr;
427 return (insert_exec_ok (pred_exec, argv, arg_ptr));
430 static boolean
431 parse_false (argv, arg_ptr)
432 char *argv[];
433 int *arg_ptr;
435 struct predicate *our_pred;
437 our_pred = insert_primary (pred_false);
438 our_pred->need_stat = false;
439 return (true);
442 static boolean
443 parse_fls (argv, arg_ptr)
444 char *argv[];
445 int *arg_ptr;
447 struct predicate *our_pred;
449 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
450 return (false);
451 our_pred = insert_primary (pred_fls);
452 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
453 our_pred->side_effects = true;
454 (*arg_ptr)++;
455 return (true);
458 static boolean
459 parse_fprintf (argv, arg_ptr)
460 char *argv[];
461 int *arg_ptr;
463 FILE *fp;
465 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
466 return (false);
467 if (argv[*arg_ptr + 1] == NULL)
469 /* Ensure we get "missing arg" message, not "invalid arg". */
470 (*arg_ptr)++;
471 return (false);
473 fp = open_output_file (argv[*arg_ptr]);
474 (*arg_ptr)++;
475 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
478 static boolean
479 parse_follow (argv, arg_ptr)
480 char *argv[];
481 int *arg_ptr;
483 dereference = true;
484 xstat = stat;
485 no_leaf_check = true;
486 return (true);
489 static boolean
490 parse_fprint (argv, arg_ptr)
491 char *argv[];
492 int *arg_ptr;
494 struct predicate *our_pred;
496 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
497 return (false);
498 our_pred = insert_primary (pred_fprint);
499 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
500 our_pred->side_effects = true;
501 our_pred->need_stat = false;
502 (*arg_ptr)++;
503 return (true);
506 static boolean
507 parse_fprint0 (argv, arg_ptr)
508 char *argv[];
509 int *arg_ptr;
511 struct predicate *our_pred;
513 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
514 return (false);
515 our_pred = insert_primary (pred_fprint0);
516 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
517 our_pred->side_effects = true;
518 our_pred->need_stat = false;
519 (*arg_ptr)++;
520 return (true);
523 static boolean
524 parse_fstype (argv, arg_ptr)
525 char *argv[];
526 int *arg_ptr;
528 struct predicate *our_pred;
530 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
531 return (false);
532 our_pred = insert_primary (pred_fstype);
533 our_pred->args.str = argv[*arg_ptr];
534 (*arg_ptr)++;
535 return (true);
538 static boolean
539 parse_gid (argv, arg_ptr)
540 char *argv[];
541 int *arg_ptr;
543 return (insert_num (argv, arg_ptr, pred_gid));
546 static boolean
547 parse_group (argv, arg_ptr)
548 char *argv[];
549 int *arg_ptr;
551 struct group *cur_gr;
552 struct predicate *our_pred;
553 gid_t gid;
554 int gid_len;
556 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
557 return (false);
558 cur_gr = getgrnam (argv[*arg_ptr]);
559 endgrent ();
560 if (cur_gr != NULL)
561 gid = cur_gr->gr_gid;
562 else
564 gid_len = strspn (argv[*arg_ptr], "0123456789");
565 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
566 return (false);
567 gid = atoi (argv[*arg_ptr]);
569 our_pred = insert_primary (pred_group);
570 our_pred->args.gid = gid;
571 (*arg_ptr)++;
572 return (true);
575 static boolean
576 parse_help (argv, arg_ptr)
577 char *argv[];
578 int *arg_ptr;
580 printf ("\
581 Usage: %s [path...] [expression]\n", program_name);
582 printf ("\
583 default path is the current directory; default expression is -print\n\
584 expression may consist of:\n\
585 operators (decreasing precedence; -and is implicit where no others are given):\n\
586 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
587 printf ("\
588 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
589 options (always true): -daystart -depth -follow --help\n\
590 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
591 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
592 printf ("\
593 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
594 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
595 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
596 printf ("\
597 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
598 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
599 -xtype [bcdpfls]\n");
600 printf ("\
601 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
602 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
603 exit (0);
606 static boolean
607 parse_ilname (argv, arg_ptr)
608 char *argv[];
609 int *arg_ptr;
611 struct predicate *our_pred;
613 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
614 return (false);
615 our_pred = insert_primary (pred_ilname);
616 our_pred->args.str = argv[*arg_ptr];
617 (*arg_ptr)++;
618 return (true);
621 static boolean
622 parse_iname (argv, arg_ptr)
623 char *argv[];
624 int *arg_ptr;
626 struct predicate *our_pred;
628 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
629 return (false);
630 our_pred = insert_primary (pred_iname);
631 our_pred->need_stat = false;
632 our_pred->args.str = argv[*arg_ptr];
633 (*arg_ptr)++;
634 return (true);
637 static boolean
638 parse_inum (argv, arg_ptr)
639 char *argv[];
640 int *arg_ptr;
642 return (insert_num (argv, arg_ptr, pred_inum));
645 static boolean
646 parse_ipath (argv, arg_ptr)
647 char *argv[];
648 int *arg_ptr;
650 struct predicate *our_pred;
652 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
653 return (false);
654 our_pred = insert_primary (pred_ipath);
655 our_pred->need_stat = false;
656 our_pred->args.str = argv[*arg_ptr];
657 (*arg_ptr)++;
658 return (true);
661 static boolean
662 parse_iregex (argv, arg_ptr)
663 char *argv[];
664 int *arg_ptr;
666 return insert_regex (argv, arg_ptr, true);
669 static boolean
670 parse_links (argv, arg_ptr)
671 char *argv[];
672 int *arg_ptr;
674 return (insert_num (argv, arg_ptr, pred_links));
677 static boolean
678 parse_lname (argv, arg_ptr)
679 char *argv[];
680 int *arg_ptr;
682 struct predicate *our_pred;
684 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
685 return (false);
686 our_pred = insert_primary (pred_lname);
687 our_pred->args.str = argv[*arg_ptr];
688 (*arg_ptr)++;
689 return (true);
692 static boolean
693 parse_ls (argv, arg_ptr)
694 char *argv[];
695 int *arg_ptr;
697 struct predicate *our_pred;
699 our_pred = insert_primary (pred_ls);
700 our_pred->side_effects = true;
701 return (true);
704 static boolean
705 parse_maxdepth (argv, arg_ptr)
706 char *argv[];
707 int *arg_ptr;
709 int depth_len;
711 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
712 return (false);
713 depth_len = strspn (argv[*arg_ptr], "0123456789");
714 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
715 return (false);
716 maxdepth = atoi (argv[*arg_ptr]);
717 if (maxdepth < 0)
718 return (false);
719 (*arg_ptr)++;
720 return (true);
723 static boolean
724 parse_mindepth (argv, arg_ptr)
725 char *argv[];
726 int *arg_ptr;
728 int depth_len;
730 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
731 return (false);
732 depth_len = strspn (argv[*arg_ptr], "0123456789");
733 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
734 return (false);
735 mindepth = atoi (argv[*arg_ptr]);
736 if (mindepth < 0)
737 return (false);
738 (*arg_ptr)++;
739 return (true);
742 static boolean
743 parse_mmin (argv, arg_ptr)
744 char *argv[];
745 int *arg_ptr;
747 struct predicate *our_pred;
748 unsigned long num;
749 enum comparison_type c_type;
751 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
752 return (false);
753 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
754 return (false);
755 our_pred = insert_primary (pred_mmin);
756 our_pred->args.info.kind = c_type;
757 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
758 (*arg_ptr)++;
759 return (true);
762 static boolean
763 parse_mtime (argv, arg_ptr)
764 char *argv[];
765 int *arg_ptr;
767 return (insert_time (argv, arg_ptr, pred_mtime));
770 static boolean
771 parse_name (argv, arg_ptr)
772 char *argv[];
773 int *arg_ptr;
775 struct predicate *our_pred;
777 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
778 return (false);
779 our_pred = insert_primary (pred_name);
780 our_pred->need_stat = false;
781 our_pred->args.str = argv[*arg_ptr];
782 (*arg_ptr)++;
783 return (true);
786 static boolean
787 parse_negate (argv, arg_ptr)
788 char *argv[];
789 int *arg_ptr;
791 struct predicate *our_pred;
793 our_pred = get_new_pred_chk_op ();
794 our_pred->pred_func = pred_negate;
795 #ifdef DEBUG
796 our_pred->p_name = find_pred_name (pred_negate);
797 #endif /* DEBUG */
798 our_pred->p_type = UNI_OP;
799 our_pred->p_prec = NEGATE_PREC;
800 our_pred->need_stat = false;
801 return (true);
804 static boolean
805 parse_newer (argv, arg_ptr)
806 char *argv[];
807 int *arg_ptr;
809 struct predicate *our_pred;
810 struct stat stat_newer;
812 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
813 return (false);
814 if ((*xstat) (argv[*arg_ptr], &stat_newer))
815 error (1, errno, "%s", argv[*arg_ptr]);
816 our_pred = insert_primary (pred_newer);
817 our_pred->args.time = stat_newer.st_mtime;
818 (*arg_ptr)++;
819 return (true);
822 static boolean
823 parse_noleaf (argv, arg_ptr)
824 char *argv[];
825 int *arg_ptr;
827 no_leaf_check = true;
828 return true;
831 #ifdef CACHE_IDS
832 /* Arbitrary amount by which to increase size
833 of `uid_unused' and `gid_unused'. */
834 #define ALLOC_STEP 2048
836 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
837 char *uid_unused = NULL;
839 /* Number of elements in `uid_unused'. */
840 unsigned uid_allocated;
842 /* Similar for GIDs and group entries. */
843 char *gid_unused = NULL;
844 unsigned gid_allocated;
845 #endif
847 static boolean
848 parse_nogroup (argv, arg_ptr)
849 char *argv[];
850 int *arg_ptr;
852 struct predicate *our_pred;
854 our_pred = insert_primary (pred_nogroup);
855 #ifdef CACHE_IDS
856 if (gid_unused == NULL)
858 struct group *gr;
860 gid_allocated = ALLOC_STEP;
861 gid_unused = xmalloc (gid_allocated);
862 memset (gid_unused, 1, gid_allocated);
863 setgrent ();
864 while ((gr = getgrent ()) != NULL)
866 if ((unsigned) gr->gr_gid >= gid_allocated)
868 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
869 gid_unused = xrealloc (gid_unused, new_allocated);
870 memset (gid_unused + gid_allocated, 1,
871 new_allocated - gid_allocated);
872 gid_allocated = new_allocated;
874 gid_unused[(unsigned) gr->gr_gid] = 0;
876 endgrent ();
878 #endif
879 return (true);
882 static boolean
883 parse_nouser (argv, arg_ptr)
884 char *argv[];
885 int *arg_ptr;
887 struct predicate *our_pred;
889 our_pred = insert_primary (pred_nouser);
890 #ifdef CACHE_IDS
891 if (uid_unused == NULL)
893 struct passwd *pw;
895 uid_allocated = ALLOC_STEP;
896 uid_unused = xmalloc (uid_allocated);
897 memset (uid_unused, 1, uid_allocated);
898 setpwent ();
899 while ((pw = getpwent ()) != NULL)
901 if ((unsigned) pw->pw_uid >= uid_allocated)
903 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
904 uid_unused = xrealloc (uid_unused, new_allocated);
905 memset (uid_unused + uid_allocated, 1,
906 new_allocated - uid_allocated);
907 uid_allocated = new_allocated;
909 uid_unused[(unsigned) pw->pw_uid] = 0;
911 endpwent ();
913 #endif
914 return (true);
917 static boolean
918 parse_ok (argv, arg_ptr)
919 char *argv[];
920 int *arg_ptr;
922 return (insert_exec_ok (pred_ok, argv, arg_ptr));
925 boolean
926 parse_open (argv, arg_ptr)
927 char *argv[];
928 int *arg_ptr;
930 struct predicate *our_pred;
932 our_pred = get_new_pred_chk_op ();
933 our_pred->pred_func = pred_open;
934 #ifdef DEBUG
935 our_pred->p_name = find_pred_name (pred_open);
936 #endif /* DEBUG */
937 our_pred->p_type = OPEN_PAREN;
938 our_pred->p_prec = NO_PREC;
939 our_pred->need_stat = false;
940 return (true);
943 static boolean
944 parse_or (argv, arg_ptr)
945 char *argv[];
946 int *arg_ptr;
948 struct predicate *our_pred;
950 our_pred = get_new_pred ();
951 our_pred->pred_func = pred_or;
952 #ifdef DEBUG
953 our_pred->p_name = find_pred_name (pred_or);
954 #endif /* DEBUG */
955 our_pred->p_type = BI_OP;
956 our_pred->p_prec = OR_PREC;
957 our_pred->need_stat = false;
958 return (true);
961 static boolean
962 parse_path (argv, arg_ptr)
963 char *argv[];
964 int *arg_ptr;
966 struct predicate *our_pred;
968 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
969 return (false);
970 our_pred = insert_primary (pred_path);
971 our_pred->need_stat = false;
972 our_pred->args.str = argv[*arg_ptr];
973 (*arg_ptr)++;
974 return (true);
977 static boolean
978 parse_perm (argv, arg_ptr)
979 char *argv[];
980 int *arg_ptr;
982 unsigned long perm_val;
983 int mode_start = 0;
984 struct mode_change *change;
985 struct predicate *our_pred;
987 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
988 return (false);
990 switch (argv[*arg_ptr][0])
992 case '-':
993 case '+':
994 mode_start = 1;
995 break;
996 default:
997 /* empty */
998 break;
1001 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1002 if (change == MODE_INVALID)
1003 error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
1004 else if (change == MODE_MEMORY_EXHAUSTED)
1005 error (1, 0, "virtual memory exhausted");
1006 perm_val = mode_adjust (0, change);
1007 mode_free (change);
1009 our_pred = insert_primary (pred_perm);
1011 switch (argv[*arg_ptr][0])
1013 case '-':
1014 /* Set magic flag to indicate true if at least the given bits are set. */
1015 our_pred->args.perm = (perm_val & 07777) | 010000;
1016 break;
1017 case '+':
1018 /* Set magic flag to indicate true if any of the given bits are set. */
1019 our_pred->args.perm = (perm_val & 07777) | 020000;
1020 break;
1021 default:
1022 /* True if exactly the given bits are set. */
1023 our_pred->args.perm = (perm_val & 07777);
1024 break;
1026 (*arg_ptr)++;
1027 return (true);
1030 boolean
1031 parse_print (argv, arg_ptr)
1032 char *argv[];
1033 int *arg_ptr;
1035 struct predicate *our_pred;
1037 our_pred = insert_primary (pred_print);
1038 /* -print has the side effect of printing. This prevents us
1039 from doing undesired multiple printing when the user has
1040 already specified -print. */
1041 our_pred->side_effects = true;
1042 our_pred->need_stat = false;
1043 return (true);
1046 static boolean
1047 parse_print0 (argv, arg_ptr)
1048 char *argv[];
1049 int *arg_ptr;
1051 struct predicate *our_pred;
1053 our_pred = insert_primary (pred_print0);
1054 /* -print0 has the side effect of printing. This prevents us
1055 from doing undesired multiple printing when the user has
1056 already specified -print0. */
1057 our_pred->side_effects = true;
1058 our_pred->need_stat = false;
1059 return (true);
1062 static boolean
1063 parse_printf (argv, arg_ptr)
1064 char *argv[];
1065 int *arg_ptr;
1067 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1068 return (false);
1069 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1072 static boolean
1073 parse_prune (argv, arg_ptr)
1074 char *argv[];
1075 int *arg_ptr;
1077 struct predicate *our_pred;
1079 our_pred = insert_primary (pred_prune);
1080 our_pred->need_stat = false;
1081 return (true);
1084 static boolean
1085 parse_regex (argv, arg_ptr)
1086 char *argv[];
1087 int *arg_ptr;
1089 return insert_regex (argv, arg_ptr, false);
1092 static boolean
1093 insert_regex (argv, arg_ptr, ignore_case)
1094 char *argv[];
1095 int *arg_ptr;
1096 boolean ignore_case;
1098 struct predicate *our_pred;
1099 struct re_pattern_buffer *re;
1100 const char *error_message;
1102 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1103 return (false);
1104 our_pred = insert_primary (pred_regex);
1105 our_pred->need_stat = false;
1106 re = (struct re_pattern_buffer *)
1107 xmalloc (sizeof (struct re_pattern_buffer));
1108 our_pred->args.regex = re;
1109 re->allocated = 100;
1110 re->buffer = (unsigned char *) xmalloc (re->allocated);
1111 re->fastmap = NULL;
1113 if (ignore_case)
1115 unsigned i;
1117 re->translate = xmalloc (256);
1118 /* Map uppercase characters to corresponding lowercase ones. */
1119 for (i = 0; i < 256; i++)
1120 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1122 else
1123 re->translate = NULL;
1125 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1126 re);
1127 if (error_message)
1128 error (1, 0, "%s", error_message);
1129 (*arg_ptr)++;
1130 return (true);
1133 static boolean
1134 parse_size (argv, arg_ptr)
1135 char *argv[];
1136 int *arg_ptr;
1138 struct predicate *our_pred;
1139 unsigned long num;
1140 enum comparison_type c_type;
1141 int blksize = 512;
1142 int len;
1144 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1145 return (false);
1146 len = strlen (argv[*arg_ptr]);
1147 if (len == 0)
1148 error (1, 0, "invalid null argument to -size");
1149 switch (argv[*arg_ptr][len - 1])
1151 case 'b':
1152 blksize = 512;
1153 argv[*arg_ptr][len - 1] = '\0';
1154 break;
1156 case 'c':
1157 blksize = 1;
1158 argv[*arg_ptr][len - 1] = '\0';
1159 break;
1161 case 'k':
1162 blksize = 1024;
1163 argv[*arg_ptr][len - 1] = '\0';
1164 break;
1166 case 'w':
1167 blksize = 2;
1168 argv[*arg_ptr][len - 1] = '\0';
1169 break;
1171 case '0':
1172 case '1':
1173 case '2':
1174 case '3':
1175 case '4':
1176 case '5':
1177 case '6':
1178 case '7':
1179 case '8':
1180 case '9':
1181 break;
1183 default:
1184 error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
1186 if (!get_num (argv[*arg_ptr], &num, &c_type))
1187 return (false);
1188 our_pred = insert_primary (pred_size);
1189 our_pred->args.size.kind = c_type;
1190 our_pred->args.size.blocksize = blksize;
1191 our_pred->args.size.size = num;
1192 (*arg_ptr)++;
1193 return (true);
1196 static boolean
1197 parse_true (argv, arg_ptr)
1198 char *argv[];
1199 int *arg_ptr;
1201 struct predicate *our_pred;
1203 our_pred = insert_primary (pred_true);
1204 our_pred->need_stat = false;
1205 return (true);
1208 static boolean
1209 parse_type (argv, arg_ptr)
1210 char *argv[];
1211 int *arg_ptr;
1213 return insert_type (argv, arg_ptr, pred_type);
1216 static boolean
1217 parse_uid (argv, arg_ptr)
1218 char *argv[];
1219 int *arg_ptr;
1221 return (insert_num (argv, arg_ptr, pred_uid));
1224 static boolean
1225 parse_used (argv, arg_ptr)
1226 char *argv[];
1227 int *arg_ptr;
1230 struct predicate *our_pred;
1231 unsigned long num_days;
1232 enum comparison_type c_type;
1234 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1235 return (false);
1236 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1237 return (false);
1238 our_pred = insert_primary (pred_used);
1239 our_pred->args.info.kind = c_type;
1240 our_pred->args.info.l_val = num_days * DAYSECS;
1241 (*arg_ptr)++;
1242 return (true);
1245 static boolean
1246 parse_user (argv, arg_ptr)
1247 char *argv[];
1248 int *arg_ptr;
1250 struct passwd *cur_pwd;
1251 struct predicate *our_pred;
1252 uid_t uid;
1253 int uid_len;
1255 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1256 return (false);
1257 cur_pwd = getpwnam (argv[*arg_ptr]);
1258 endpwent ();
1259 if (cur_pwd != NULL)
1260 uid = cur_pwd->pw_uid;
1261 else
1263 uid_len = strspn (argv[*arg_ptr], "0123456789");
1264 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1265 return (false);
1266 uid = atoi (argv[*arg_ptr]);
1268 our_pred = insert_primary (pred_user);
1269 our_pred->args.uid = uid;
1270 (*arg_ptr)++;
1271 return (true);
1274 static boolean
1275 parse_version (argv, arg_ptr)
1276 char *argv[];
1277 int *arg_ptr;
1279 extern char *version_string;
1281 fflush (stderr);
1282 printf ("GNU find version %s\n", version_string);
1283 exit (0);
1286 static boolean
1287 parse_xdev (argv, arg_ptr)
1288 char *argv[];
1289 int *arg_ptr;
1291 stay_on_filesystem = true;
1292 return true;
1295 static boolean
1296 parse_xtype (argv, arg_ptr)
1297 char *argv[];
1298 int *arg_ptr;
1300 return insert_type (argv, arg_ptr, pred_xtype);
1303 static boolean
1304 insert_type (argv, arg_ptr, which_pred)
1305 char *argv[];
1306 int *arg_ptr;
1307 boolean (*which_pred) ();
1309 unsigned long type_cell;
1310 struct predicate *our_pred;
1312 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1313 || (strlen (argv[*arg_ptr]) != 1))
1314 return (false);
1315 switch (argv[*arg_ptr][0])
1317 case 'b': /* block special */
1318 type_cell = S_IFBLK;
1319 break;
1320 case 'c': /* character special */
1321 type_cell = S_IFCHR;
1322 break;
1323 case 'd': /* directory */
1324 type_cell = S_IFDIR;
1325 break;
1326 case 'f': /* regular file */
1327 type_cell = S_IFREG;
1328 break;
1329 #ifdef S_IFLNK
1330 case 'l': /* symbolic link */
1331 type_cell = S_IFLNK;
1332 break;
1333 #endif
1334 #ifdef S_IFIFO
1335 case 'p': /* pipe */
1336 type_cell = S_IFIFO;
1337 break;
1338 #endif
1339 #ifdef S_IFSOCK
1340 case 's': /* socket */
1341 type_cell = S_IFSOCK;
1342 break;
1343 #endif
1344 default: /* None of the above ... nuke 'em. */
1345 return (false);
1347 our_pred = insert_primary (which_pred);
1348 our_pred->args.type = type_cell;
1349 (*arg_ptr)++; /* Move on to next argument. */
1350 return (true);
1353 /* If true, we've determined that the current fprintf predicate
1354 uses stat information. */
1355 static boolean fprintf_stat_needed;
1357 static boolean
1358 insert_fprintf (fp, func, argv, arg_ptr)
1359 FILE *fp;
1360 boolean (*func) ();
1361 char *argv[];
1362 int *arg_ptr;
1364 char *format; /* Beginning of unprocessed format string. */
1365 register char *scan; /* Current address in scanning `format'. */
1366 register char *scan2; /* Address inside of element being scanned. */
1367 struct segment **segmentp; /* Address of current segment. */
1368 struct predicate *our_pred;
1370 format = argv[(*arg_ptr)++];
1372 fprintf_stat_needed = false; /* Might be overridden later. */
1373 our_pred = insert_primary (func);
1374 our_pred->side_effects = true;
1375 our_pred->args.printf_vec.stream = fp;
1376 segmentp = &our_pred->args.printf_vec.segment;
1377 *segmentp = NULL;
1379 for (scan = format; *scan; scan++)
1381 if (*scan == '\\')
1383 scan2 = scan + 1;
1384 if (*scan2 >= '0' && *scan2 <= '7')
1386 register int n, i;
1388 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1389 i++, scan2++)
1390 n = 8 * n + *scan2 - '0';
1391 scan2--;
1392 *scan = n;
1394 else
1396 switch (*scan2)
1398 case 'a':
1399 *scan = 7;
1400 break;
1401 case 'b':
1402 *scan = '\b';
1403 break;
1404 case 'c':
1405 make_segment (segmentp, format, scan - format, KIND_STOP);
1406 our_pred->need_stat = fprintf_stat_needed;
1407 return (true);
1408 case 'f':
1409 *scan = '\f';
1410 break;
1411 case 'n':
1412 *scan = '\n';
1413 break;
1414 case 'r':
1415 *scan = '\r';
1416 break;
1417 case 't':
1418 *scan = '\t';
1419 break;
1420 case 'v':
1421 *scan = '\v';
1422 break;
1423 case '\\':
1424 /* *scan = '\\'; * it already is */
1425 break;
1426 default:
1427 error (0, 0, "warning: unrecognized escape `\\%c'", *scan2);
1428 scan++;
1429 continue;
1432 segmentp = make_segment (segmentp, format, scan - format + 1,
1433 KIND_PLAIN);
1434 format = scan2 + 1; /* Move past the escape. */
1435 scan = scan2; /* Incremented immediately by `for'. */
1437 else if (*scan == '%')
1439 if (scan[1] == '%')
1441 segmentp = make_segment (segmentp, format, scan - format + 1,
1442 KIND_PLAIN);
1443 scan++;
1444 format = scan + 1;
1445 continue;
1447 /* Scan past flags, width and precision, to verify kind. */
1448 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1449 /* Do nothing. */ ;
1450 while (ISDIGIT (*scan2))
1451 scan2++;
1452 if (*scan2 == '.')
1453 for (scan2++; ISDIGIT (*scan2); scan2++)
1454 /* Do nothing. */ ;
1455 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1457 segmentp = make_segment (segmentp, format, scan2 - format,
1458 (int) *scan2);
1459 scan = scan2;
1460 format = scan + 1;
1462 else if (strchr ("ACT", *scan2) && scan2[1])
1464 segmentp = make_segment (segmentp, format, scan2 - format,
1465 *scan2 | (scan2[1] << 8));
1466 scan = scan2 + 1;
1467 format = scan + 1;
1468 continue;
1470 else
1472 /* An unrecognized % escape. Print the char after the %. */
1473 error (0, 0, "warning: unrecognized format directive `%%%c'",
1474 *scan2);
1475 segmentp = make_segment (segmentp, format, scan - format,
1476 KIND_PLAIN);
1477 format = scan + 1;
1478 continue;
1483 if (scan > format)
1484 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1485 our_pred->need_stat = fprintf_stat_needed;
1486 return (true);
1489 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1490 from the text in FORMAT, which has length LEN.
1491 Return the address of the `next' pointer of the new segment. */
1493 static struct segment **
1494 make_segment (segment, format, len, kind)
1495 struct segment **segment;
1496 char *format;
1497 int len, kind;
1499 char *fmt;
1501 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1503 (*segment)->kind = kind;
1504 (*segment)->next = NULL;
1505 (*segment)->text_len = len;
1507 fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
1508 strncpy (fmt, format, len);
1509 fmt += len;
1511 switch (kind & 0xff)
1513 case KIND_PLAIN: /* Plain text string, no % conversion. */
1514 case KIND_STOP: /* Terminate argument, no newline. */
1515 break;
1517 case 'a': /* atime in `ctime' format */
1518 case 'c': /* ctime in `ctime' format */
1519 case 'F': /* filesystem type */
1520 case 'g': /* group name */
1521 case 'l': /* object of symlink */
1522 case 't': /* mtime in `ctime' format */
1523 case 'u': /* user name */
1524 case 'A': /* atime in user-specified strftime format */
1525 case 'C': /* ctime in user-specified strftime format */
1526 case 'T': /* mtime in user-specified strftime format */
1527 fprintf_stat_needed = true;
1528 /* FALLTHROUGH */
1529 case 'f': /* basename of path */
1530 case 'h': /* leading directories part of path */
1531 case 'H': /* ARGV element file was found under */
1532 case 'p': /* pathname */
1533 case 'P': /* pathname with ARGV element stripped */
1534 *fmt++ = 's';
1535 break;
1537 case 'b': /* size in 512-byte blocks */
1538 case 'k': /* size in 1K blocks */
1539 case 's': /* size in bytes */
1540 *fmt++ = 'l';
1541 /*FALLTHROUGH*/
1542 case 'n': /* number of links */
1543 fprintf_stat_needed = true;
1544 /* FALLTHROUGH */
1545 case 'd': /* depth in search tree (0 = ARGV element) */
1546 *fmt++ = 'd';
1547 break;
1549 case 'i': /* inode number */
1550 *fmt++ = 'l';
1551 /*FALLTHROUGH*/
1552 case 'G': /* GID number */
1553 case 'U': /* UID number */
1554 *fmt++ = 'u';
1555 fprintf_stat_needed = true;
1556 break;
1558 case 'm': /* mode as octal number (perms only) */
1559 *fmt++ = 'o';
1560 fprintf_stat_needed = true;
1561 break;
1563 *fmt = '\0';
1565 return (&(*segment)->next);
1568 static boolean
1569 insert_exec_ok (func, argv, arg_ptr)
1570 boolean (*func) ();
1571 char *argv[];
1572 int *arg_ptr;
1574 int start, end; /* Indexes in ARGV of start & end of cmd. */
1575 int num_paths; /* Number of args with path replacements. */
1576 int path_pos; /* Index in array of path replacements. */
1577 int vec_pos; /* Index in array of args. */
1578 struct predicate *our_pred;
1579 struct exec_val *execp; /* Pointer for efficiency. */
1581 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1582 return (false);
1584 /* Count the number of args with path replacements, up until the ';'. */
1585 start = *arg_ptr;
1586 for (end = start, num_paths = 0;
1587 (argv[end] != NULL)
1588 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1589 end++)
1590 if (strstr (argv[end], "{}"))
1591 num_paths++;
1592 /* Fail if no command given or no semicolon found. */
1593 if ((end == start) || (argv[end] == NULL))
1595 *arg_ptr = end;
1596 return (false);
1599 our_pred = insert_primary (func);
1600 our_pred->side_effects = true;
1601 execp = &our_pred->args.exec_vec;
1602 execp->paths =
1603 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1604 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1605 /* Record the positions of all args, and the args with path replacements. */
1606 for (end = start, path_pos = vec_pos = 0;
1607 (argv[end] != NULL)
1608 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1609 end++)
1611 register char *p;
1613 execp->paths[path_pos].count = 0;
1614 for (p = argv[end]; *p; ++p)
1615 if (p[0] == '{' && p[1] == '}')
1617 execp->paths[path_pos].count++;
1618 ++p;
1620 if (execp->paths[path_pos].count)
1622 execp->paths[path_pos].offset = vec_pos;
1623 execp->paths[path_pos].origarg = argv[end];
1624 path_pos++;
1626 execp->vec[vec_pos++] = argv[end];
1628 execp->paths[path_pos].offset = -1;
1629 execp->vec[vec_pos] = NULL;
1631 if (argv[end] == NULL)
1632 *arg_ptr = end;
1633 else
1634 *arg_ptr = end + 1;
1635 return (true);
1638 /* Get a number of days and comparison type.
1639 STR is the ASCII representation.
1640 Set *NUM_DAYS to the number of days, taken as being from
1641 the current moment (or possibly midnight). Thus the sense of the
1642 comparison type appears to be reversed.
1643 Set *COMP_TYPE to the kind of comparison that is requested.
1645 Return true if all okay, false if input error.
1647 Used by -atime, -ctime and -mtime (parsers) to
1648 get the appropriate information for a time predicate processor. */
1650 static boolean
1651 get_num_days (str, num_days, comp_type)
1652 char *str;
1653 unsigned long *num_days;
1654 enum comparison_type *comp_type;
1656 int len_days; /* length of field */
1658 if (str == NULL)
1659 return (false);
1660 switch (str[0])
1662 case '+':
1663 *comp_type = COMP_LT;
1664 str++;
1665 break;
1666 case '-':
1667 *comp_type = COMP_GT;
1668 str++;
1669 break;
1670 case '0':
1671 case '1':
1672 case '2':
1673 case '3':
1674 case '4':
1675 case '5':
1676 case '6':
1677 case '7':
1678 case '8':
1679 case '9':
1680 *comp_type = COMP_EQ;
1681 break;
1682 default:
1683 return (false);
1686 /* We know the first char has been reasonable. Find the
1687 number of days to play with. */
1688 len_days = strspn (str, "0123456789");
1689 if ((len_days == 0) || (str[len_days] != '\0'))
1690 return (false);
1691 *num_days = (unsigned long) atol (str);
1692 return (true);
1695 /* Insert a time predicate PRED.
1696 ARGV is a pointer to the argument array.
1697 ARG_PTR is a pointer to an index into the array, incremented if
1698 all went well.
1700 Return true if input is valid, false if not.
1702 A new predicate node is assigned, along with an argument node
1703 obtained with malloc.
1705 Used by -atime, -ctime, and -mtime parsers. */
1707 static boolean
1708 insert_time (argv, arg_ptr, pred)
1709 char *argv[];
1710 int *arg_ptr;
1711 PFB pred;
1713 struct predicate *our_pred;
1714 unsigned long num_days;
1715 enum comparison_type c_type;
1717 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1718 return (false);
1719 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1720 return (false);
1721 our_pred = insert_primary (pred);
1722 our_pred->args.info.kind = c_type;
1723 our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
1724 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
1725 (*arg_ptr)++;
1726 #ifdef DEBUG
1727 printf ("inserting %s\n", our_pred->p_name);
1728 printf (" type: %s %s ",
1729 (c_type == COMP_GT) ? "gt" :
1730 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1731 (c_type == COMP_GT) ? " >" :
1732 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1733 printf ("%ld %s", our_pred->args.info.l_val,
1734 ctime (&our_pred->args.info.l_val));
1735 if (c_type == COMP_EQ)
1737 our_pred->args.info.l_val += DAYSECS;
1738 printf (" < %ld %s", our_pred->args.info.l_val,
1739 ctime (&our_pred->args.info.l_val));
1740 our_pred->args.info.l_val -= DAYSECS;
1742 #endif /* DEBUG */
1743 return (true);
1746 /* Get a number with comparision information.
1747 The sense of the comparision information is 'normal'; that is,
1748 '+' looks for inums or links > than the number and '-' less than.
1750 STR is the ASCII representation of the number.
1751 Set *NUM to the number.
1752 Set *COMP_TYPE to the kind of comparison that is requested.
1754 Return true if all okay, false if input error.
1756 Used by the -inum and -links predicate parsers. */
1758 static boolean
1759 get_num (str, num, comp_type)
1760 char *str;
1761 unsigned long *num;
1762 enum comparison_type *comp_type;
1764 int len_num; /* Length of field. */
1766 if (str == NULL)
1767 return (false);
1768 switch (str[0])
1770 case '+':
1771 *comp_type = COMP_GT;
1772 str++;
1773 break;
1774 case '-':
1775 *comp_type = COMP_LT;
1776 str++;
1777 break;
1778 case '0':
1779 case '1':
1780 case '2':
1781 case '3':
1782 case '4':
1783 case '5':
1784 case '6':
1785 case '7':
1786 case '8':
1787 case '9':
1788 *comp_type = COMP_EQ;
1789 break;
1790 default:
1791 return (false);
1794 /* We know the first char has been reasonable. Find the number of
1795 days to play with. */
1796 len_num = strspn (str, "0123456789");
1797 if ((len_num == 0) || (str[len_num] != '\0'))
1798 return (false);
1799 *num = (unsigned long) atol (str);
1800 return (true);
1803 /* Insert a number predicate.
1804 ARGV is a pointer to the argument array.
1805 *ARG_PTR is an index into ARGV, incremented if all went well.
1806 *PRED is the predicate processor to insert.
1808 Return true if input is valid, false if error.
1810 A new predicate node is assigned, along with an argument node
1811 obtained with malloc.
1813 Used by -inum and -links parsers. */
1815 static boolean
1816 insert_num (argv, arg_ptr, pred)
1817 char *argv[];
1818 int *arg_ptr;
1819 PFB pred;
1821 struct predicate *our_pred;
1822 unsigned long num;
1823 enum comparison_type c_type;
1825 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1826 return (false);
1827 if (!get_num (argv[*arg_ptr], &num, &c_type))
1828 return (false);
1829 our_pred = insert_primary (pred);
1830 our_pred->args.info.kind = c_type;
1831 our_pred->args.info.l_val = num;
1832 (*arg_ptr)++;
1833 #ifdef DEBUG
1834 printf ("inserting %s\n", our_pred->p_name);
1835 printf (" type: %s %s ",
1836 (c_type == COMP_GT) ? "gt" :
1837 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1838 (c_type == COMP_GT) ? " >" :
1839 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1840 printf ("%ld\n", our_pred->args.info.l_val);
1841 #endif /* DEBUG */
1842 return (true);
1845 static FILE *
1846 open_output_file (path)
1847 char *path;
1849 FILE *f;
1851 if (!strcmp (path, "/dev/stderr"))
1852 return (stderr);
1853 else if (!strcmp (path, "/dev/stdout"))
1854 return (stdout);
1855 f = fopen (path, "w");
1856 if (f == NULL)
1857 error (1, errno, "%s", path);
1858 return (f);