* lib/getline.h : added declaration of getstr.
[findutils.git] / find / parser.c
bloba9edd9a653dd6345ad729e87b08d9275b4644ccc
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 P_((char *argv[], int *arg_ptr));
59 static boolean parse_and P_((char *argv[], int *arg_ptr));
60 static boolean parse_anewer P_((char *argv[], int *arg_ptr));
61 static boolean parse_atime P_((char *argv[], int *arg_ptr));
62 boolean parse_close P_((char *argv[], int *arg_ptr));
63 static boolean parse_cmin P_((char *argv[], int *arg_ptr));
64 static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
65 static boolean parse_comma P_((char *argv[], int *arg_ptr));
66 static boolean parse_ctime P_((char *argv[], int *arg_ptr));
67 static boolean parse_daystart P_((char *argv[], int *arg_ptr));
68 static boolean parse_depth P_((char *argv[], int *arg_ptr));
69 static boolean parse_empty P_((char *argv[], int *arg_ptr));
70 static boolean parse_exec P_((char *argv[], int *arg_ptr));
71 static boolean parse_false P_((char *argv[], int *arg_ptr));
72 static boolean parse_fls P_((char *argv[], int *arg_ptr));
73 static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
74 static boolean parse_follow P_((char *argv[], int *arg_ptr));
75 static boolean parse_fprint P_((char *argv[], int *arg_ptr));
76 static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
77 static boolean parse_fstype P_((char *argv[], int *arg_ptr));
78 static boolean parse_gid P_((char *argv[], int *arg_ptr));
79 static boolean parse_group P_((char *argv[], int *arg_ptr));
80 static boolean parse_help P_((char *argv[], int *arg_ptr));
81 static boolean parse_ilname P_((char *argv[], int *arg_ptr));
82 static boolean parse_iname P_((char *argv[], int *arg_ptr));
83 static boolean parse_inum P_((char *argv[], int *arg_ptr));
84 static boolean parse_ipath P_((char *argv[], int *arg_ptr));
85 static boolean parse_iregex P_((char *argv[], int *arg_ptr));
86 static boolean parse_links P_((char *argv[], int *arg_ptr));
87 static boolean parse_lname P_((char *argv[], int *arg_ptr));
88 static boolean parse_ls P_((char *argv[], int *arg_ptr));
89 static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
90 static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
91 static boolean parse_mmin P_((char *argv[], int *arg_ptr));
92 static boolean parse_mtime P_((char *argv[], int *arg_ptr));
93 static boolean parse_name P_((char *argv[], int *arg_ptr));
94 static boolean parse_negate P_((char *argv[], int *arg_ptr));
95 static boolean parse_newer P_((char *argv[], int *arg_ptr));
96 static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
97 static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
98 static boolean parse_nouser P_((char *argv[], int *arg_ptr));
99 static boolean parse_ok P_((char *argv[], int *arg_ptr));
100 boolean parse_open P_((char *argv[], int *arg_ptr));
101 static boolean parse_or P_((char *argv[], int *arg_ptr));
102 static boolean parse_path P_((char *argv[], int *arg_ptr));
103 static boolean parse_perm P_((char *argv[], int *arg_ptr));
104 boolean parse_print P_((char *argv[], int *arg_ptr));
105 static boolean parse_print0 P_((char *argv[], int *arg_ptr));
106 static boolean parse_printf P_((char *argv[], int *arg_ptr));
107 static boolean parse_prune P_((char *argv[], int *arg_ptr));
108 static boolean parse_regex P_((char *argv[], int *arg_ptr));
109 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
110 static boolean parse_size P_((char *argv[], int *arg_ptr));
111 static boolean parse_true P_((char *argv[], int *arg_ptr));
112 static boolean parse_type P_((char *argv[], int *arg_ptr));
113 static boolean parse_uid P_((char *argv[], int *arg_ptr));
114 static boolean parse_used P_((char *argv[], int *arg_ptr));
115 static boolean parse_user P_((char *argv[], int *arg_ptr));
116 static boolean parse_version P_((char *argv[], int *arg_ptr));
117 static boolean parse_xdev P_((char *argv[], int *arg_ptr));
118 static boolean parse_xtype P_((char *argv[], int *arg_ptr));
120 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
121 static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
122 static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
123 static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
124 static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
125 static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
126 static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
127 static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
128 static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
129 static FILE *open_output_file P_((char *path));
131 #ifdef DEBUG
132 char *find_pred_name P_((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 (search_name)
230 char *search_name;
232 int i;
234 if (*search_name == '-')
235 search_name++;
236 for (i = 0; parse_table[i].parser_name != 0; i++)
237 if (strcmp (parse_table[i].parser_name, search_name) == 0)
238 return (parse_table[i].parser_func);
239 return (NULL);
242 /* The parsers are responsible to continue scanning ARGV for
243 their arguments. Each parser knows what is and isn't
244 allowed for itself.
246 ARGV is the argument array.
247 *ARG_PTR is the index to start at in ARGV,
248 updated to point beyond the last element consumed.
250 The predicate structure is updated with the new information. */
252 static boolean
253 parse_amin (argv, arg_ptr)
254 char *argv[];
255 int *arg_ptr;
257 struct predicate *our_pred;
258 unsigned long num;
259 enum comparison_type c_type;
261 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
262 return (false);
263 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
264 return (false);
265 our_pred = insert_primary (pred_amin);
266 our_pred->args.info.kind = c_type;
267 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
268 (*arg_ptr)++;
269 return (true);
272 static boolean
273 parse_and (argv, arg_ptr)
274 char *argv[];
275 int *arg_ptr;
277 struct predicate *our_pred;
279 our_pred = get_new_pred ();
280 our_pred->pred_func = pred_and;
281 #ifdef DEBUG
282 our_pred->p_name = find_pred_name (pred_and);
283 #endif /* DEBUG */
284 our_pred->p_type = BI_OP;
285 our_pred->p_prec = AND_PREC;
286 our_pred->need_stat = false;
287 return (true);
290 static boolean
291 parse_anewer (argv, arg_ptr)
292 char *argv[];
293 int *arg_ptr;
295 struct predicate *our_pred;
296 struct stat stat_newer;
298 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
299 return (false);
300 if ((*xstat) (argv[*arg_ptr], &stat_newer))
301 error (1, errno, "%s", argv[*arg_ptr]);
302 our_pred = insert_primary (pred_anewer);
303 our_pred->args.time = stat_newer.st_mtime;
304 (*arg_ptr)++;
305 return (true);
308 static boolean
309 parse_atime (argv, arg_ptr)
310 char *argv[];
311 int *arg_ptr;
313 return (insert_time (argv, arg_ptr, pred_atime));
316 boolean
317 parse_close (argv, arg_ptr)
318 char *argv[];
319 int *arg_ptr;
321 struct predicate *our_pred;
323 our_pred = get_new_pred ();
324 our_pred->pred_func = pred_close;
325 #ifdef DEBUG
326 our_pred->p_name = find_pred_name (pred_close);
327 #endif /* DEBUG */
328 our_pred->p_type = CLOSE_PAREN;
329 our_pred->p_prec = NO_PREC;
330 our_pred->need_stat = false;
331 return (true);
334 static boolean
335 parse_cmin (argv, arg_ptr)
336 char *argv[];
337 int *arg_ptr;
339 struct predicate *our_pred;
340 unsigned long num;
341 enum comparison_type c_type;
343 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
344 return (false);
345 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
346 return (false);
347 our_pred = insert_primary (pred_cmin);
348 our_pred->args.info.kind = c_type;
349 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
350 (*arg_ptr)++;
351 return (true);
354 static boolean
355 parse_cnewer (argv, arg_ptr)
356 char *argv[];
357 int *arg_ptr;
359 struct predicate *our_pred;
360 struct stat stat_newer;
362 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
363 return (false);
364 if ((*xstat) (argv[*arg_ptr], &stat_newer))
365 error (1, errno, "%s", argv[*arg_ptr]);
366 our_pred = insert_primary (pred_cnewer);
367 our_pred->args.time = stat_newer.st_mtime;
368 (*arg_ptr)++;
369 return (true);
372 static boolean
373 parse_comma (argv, arg_ptr)
374 char *argv[];
375 int *arg_ptr;
377 struct predicate *our_pred;
379 our_pred = get_new_pred ();
380 our_pred->pred_func = pred_comma;
381 #ifdef DEBUG
382 our_pred->p_name = find_pred_name (pred_comma);
383 #endif /* DEBUG */
384 our_pred->p_type = BI_OP;
385 our_pred->p_prec = COMMA_PREC;
386 our_pred->need_stat = false;
387 return (true);
390 static boolean
391 parse_ctime (argv, arg_ptr)
392 char *argv[];
393 int *arg_ptr;
395 return (insert_time (argv, arg_ptr, pred_ctime));
398 static boolean
399 parse_daystart (argv, arg_ptr)
400 char *argv[];
401 int *arg_ptr;
403 struct tm *local;
405 if (full_days == false)
407 cur_day_start += DAYSECS;
408 local = localtime (&cur_day_start);
409 cur_day_start -= local->tm_sec + local->tm_min * 60
410 + local->tm_hour * 3600;
411 full_days = true;
413 return (true);
416 static boolean
417 parse_depth (argv, arg_ptr)
418 char *argv[];
419 int *arg_ptr;
421 do_dir_first = false;
422 return (true);
425 static boolean
426 parse_empty (argv, arg_ptr)
427 char *argv[];
428 int *arg_ptr;
430 insert_primary (pred_empty);
431 return (true);
434 static boolean
435 parse_exec (argv, arg_ptr)
436 char *argv[];
437 int *arg_ptr;
439 return (insert_exec_ok (pred_exec, argv, arg_ptr));
442 static boolean
443 parse_false (argv, arg_ptr)
444 char *argv[];
445 int *arg_ptr;
447 struct predicate *our_pred;
449 our_pred = insert_primary (pred_false);
450 our_pred->need_stat = false;
451 return (true);
454 static boolean
455 parse_fls (argv, arg_ptr)
456 char *argv[];
457 int *arg_ptr;
459 struct predicate *our_pred;
461 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
462 return (false);
463 our_pred = insert_primary (pred_fls);
464 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
465 our_pred->side_effects = true;
466 (*arg_ptr)++;
467 return (true);
470 static boolean
471 parse_fprintf (argv, arg_ptr)
472 char *argv[];
473 int *arg_ptr;
475 FILE *fp;
477 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
478 return (false);
479 if (argv[*arg_ptr + 1] == NULL)
481 /* Ensure we get "missing arg" message, not "invalid arg". */
482 (*arg_ptr)++;
483 return (false);
485 fp = open_output_file (argv[*arg_ptr]);
486 (*arg_ptr)++;
487 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
490 static boolean
491 parse_follow (argv, arg_ptr)
492 char *argv[];
493 int *arg_ptr;
495 dereference = true;
496 xstat = stat;
497 no_leaf_check = true;
498 return (true);
501 static boolean
502 parse_fprint (argv, arg_ptr)
503 char *argv[];
504 int *arg_ptr;
506 struct predicate *our_pred;
508 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
509 return (false);
510 our_pred = insert_primary (pred_fprint);
511 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
512 our_pred->side_effects = true;
513 our_pred->need_stat = false;
514 (*arg_ptr)++;
515 return (true);
518 static boolean
519 parse_fprint0 (argv, arg_ptr)
520 char *argv[];
521 int *arg_ptr;
523 struct predicate *our_pred;
525 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
526 return (false);
527 our_pred = insert_primary (pred_fprint0);
528 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
529 our_pred->side_effects = true;
530 our_pred->need_stat = false;
531 (*arg_ptr)++;
532 return (true);
535 static boolean
536 parse_fstype (argv, arg_ptr)
537 char *argv[];
538 int *arg_ptr;
540 struct predicate *our_pred;
542 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
543 return (false);
544 our_pred = insert_primary (pred_fstype);
545 our_pred->args.str = argv[*arg_ptr];
546 (*arg_ptr)++;
547 return (true);
550 static boolean
551 parse_gid (argv, arg_ptr)
552 char *argv[];
553 int *arg_ptr;
555 return (insert_num (argv, arg_ptr, pred_gid));
558 static boolean
559 parse_group (argv, arg_ptr)
560 char *argv[];
561 int *arg_ptr;
563 struct group *cur_gr;
564 struct predicate *our_pred;
565 gid_t gid;
566 int gid_len;
568 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
569 return (false);
570 cur_gr = getgrnam (argv[*arg_ptr]);
571 endgrent ();
572 if (cur_gr != NULL)
573 gid = cur_gr->gr_gid;
574 else
576 gid_len = strspn (argv[*arg_ptr], "0123456789");
577 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
578 return (false);
579 gid = atoi (argv[*arg_ptr]);
581 our_pred = insert_primary (pred_group);
582 our_pred->args.gid = gid;
583 (*arg_ptr)++;
584 return (true);
587 static boolean
588 parse_help (argv, arg_ptr)
589 char *argv[];
590 int *arg_ptr;
592 printf (_("\
593 Usage: %s [path...] [expression]\n"), program_name);
594 printf (_("\
595 default path is the current directory; default expression is -print\n\
596 expression may consist of:\n\
597 operators (decreasing precedence; -and is implicit where no others are given):\n\
598 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
599 printf (_("\
600 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
601 options (always true): -daystart -depth -follow --help\n\
602 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
603 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
604 printf (_("\
605 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
606 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
607 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
608 printf (_("\
609 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
610 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
611 -xtype [bcdpfls]\n"));
612 printf (_("\
613 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
614 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
615 exit (0);
618 static boolean
619 parse_ilname (argv, arg_ptr)
620 char *argv[];
621 int *arg_ptr;
623 struct predicate *our_pred;
625 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
626 return (false);
627 our_pred = insert_primary (pred_ilname);
628 our_pred->args.str = argv[*arg_ptr];
629 (*arg_ptr)++;
630 return (true);
633 static boolean
634 parse_iname (argv, arg_ptr)
635 char *argv[];
636 int *arg_ptr;
638 struct predicate *our_pred;
640 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
641 return (false);
642 our_pred = insert_primary (pred_iname);
643 our_pred->need_stat = false;
644 our_pred->args.str = argv[*arg_ptr];
645 (*arg_ptr)++;
646 return (true);
649 static boolean
650 parse_inum (argv, arg_ptr)
651 char *argv[];
652 int *arg_ptr;
654 return (insert_num (argv, arg_ptr, pred_inum));
657 static boolean
658 parse_ipath (argv, arg_ptr)
659 char *argv[];
660 int *arg_ptr;
662 struct predicate *our_pred;
664 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
665 return (false);
666 our_pred = insert_primary (pred_ipath);
667 our_pred->need_stat = false;
668 our_pred->args.str = argv[*arg_ptr];
669 (*arg_ptr)++;
670 return (true);
673 static boolean
674 parse_iregex (argv, arg_ptr)
675 char *argv[];
676 int *arg_ptr;
678 return insert_regex (argv, arg_ptr, true);
681 static boolean
682 parse_links (argv, arg_ptr)
683 char *argv[];
684 int *arg_ptr;
686 return (insert_num (argv, arg_ptr, pred_links));
689 static boolean
690 parse_lname (argv, arg_ptr)
691 char *argv[];
692 int *arg_ptr;
694 struct predicate *our_pred;
696 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
697 return (false);
698 our_pred = insert_primary (pred_lname);
699 our_pred->args.str = argv[*arg_ptr];
700 (*arg_ptr)++;
701 return (true);
704 static boolean
705 parse_ls (argv, arg_ptr)
706 char *argv[];
707 int *arg_ptr;
709 struct predicate *our_pred;
711 our_pred = insert_primary (pred_ls);
712 our_pred->side_effects = true;
713 return (true);
716 static boolean
717 parse_maxdepth (argv, arg_ptr)
718 char *argv[];
719 int *arg_ptr;
721 int depth_len;
723 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
724 return (false);
725 depth_len = strspn (argv[*arg_ptr], "0123456789");
726 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
727 return (false);
728 maxdepth = atoi (argv[*arg_ptr]);
729 if (maxdepth < 0)
730 return (false);
731 (*arg_ptr)++;
732 return (true);
735 static boolean
736 parse_mindepth (argv, arg_ptr)
737 char *argv[];
738 int *arg_ptr;
740 int depth_len;
742 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
743 return (false);
744 depth_len = strspn (argv[*arg_ptr], "0123456789");
745 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
746 return (false);
747 mindepth = atoi (argv[*arg_ptr]);
748 if (mindepth < 0)
749 return (false);
750 (*arg_ptr)++;
751 return (true);
754 static boolean
755 parse_mmin (argv, arg_ptr)
756 char *argv[];
757 int *arg_ptr;
759 struct predicate *our_pred;
760 unsigned long num;
761 enum comparison_type c_type;
763 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
764 return (false);
765 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
766 return (false);
767 our_pred = insert_primary (pred_mmin);
768 our_pred->args.info.kind = c_type;
769 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
770 (*arg_ptr)++;
771 return (true);
774 static boolean
775 parse_mtime (argv, arg_ptr)
776 char *argv[];
777 int *arg_ptr;
779 return (insert_time (argv, arg_ptr, pred_mtime));
782 static boolean
783 parse_name (argv, arg_ptr)
784 char *argv[];
785 int *arg_ptr;
787 struct predicate *our_pred;
789 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
790 return (false);
791 our_pred = insert_primary (pred_name);
792 our_pred->need_stat = false;
793 our_pred->args.str = argv[*arg_ptr];
794 (*arg_ptr)++;
795 return (true);
798 static boolean
799 parse_negate (argv, arg_ptr)
800 char *argv[];
801 int *arg_ptr;
803 struct predicate *our_pred;
805 our_pred = get_new_pred_chk_op ();
806 our_pred->pred_func = pred_negate;
807 #ifdef DEBUG
808 our_pred->p_name = find_pred_name (pred_negate);
809 #endif /* DEBUG */
810 our_pred->p_type = UNI_OP;
811 our_pred->p_prec = NEGATE_PREC;
812 our_pred->need_stat = false;
813 return (true);
816 static boolean
817 parse_newer (argv, arg_ptr)
818 char *argv[];
819 int *arg_ptr;
821 struct predicate *our_pred;
822 struct stat stat_newer;
824 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
825 return (false);
826 if ((*xstat) (argv[*arg_ptr], &stat_newer))
827 error (1, errno, "%s", argv[*arg_ptr]);
828 our_pred = insert_primary (pred_newer);
829 our_pred->args.time = stat_newer.st_mtime;
830 (*arg_ptr)++;
831 return (true);
834 static boolean
835 parse_noleaf (argv, arg_ptr)
836 char *argv[];
837 int *arg_ptr;
839 no_leaf_check = true;
840 return true;
843 #ifdef CACHE_IDS
844 /* Arbitrary amount by which to increase size
845 of `uid_unused' and `gid_unused'. */
846 #define ALLOC_STEP 2048
848 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
849 char *uid_unused = NULL;
851 /* Number of elements in `uid_unused'. */
852 unsigned uid_allocated;
854 /* Similar for GIDs and group entries. */
855 char *gid_unused = NULL;
856 unsigned gid_allocated;
857 #endif
859 static boolean
860 parse_nogroup (argv, arg_ptr)
861 char *argv[];
862 int *arg_ptr;
864 struct predicate *our_pred;
866 our_pred = insert_primary (pred_nogroup);
867 #ifdef CACHE_IDS
868 if (gid_unused == NULL)
870 struct group *gr;
872 gid_allocated = ALLOC_STEP;
873 gid_unused = xmalloc (gid_allocated);
874 memset (gid_unused, 1, gid_allocated);
875 setgrent ();
876 while ((gr = getgrent ()) != NULL)
878 if ((unsigned) gr->gr_gid >= gid_allocated)
880 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
881 gid_unused = xrealloc (gid_unused, new_allocated);
882 memset (gid_unused + gid_allocated, 1,
883 new_allocated - gid_allocated);
884 gid_allocated = new_allocated;
886 gid_unused[(unsigned) gr->gr_gid] = 0;
888 endgrent ();
890 #endif
891 return (true);
894 static boolean
895 parse_nouser (argv, arg_ptr)
896 char *argv[];
897 int *arg_ptr;
899 struct predicate *our_pred;
901 our_pred = insert_primary (pred_nouser);
902 #ifdef CACHE_IDS
903 if (uid_unused == NULL)
905 struct passwd *pw;
907 uid_allocated = ALLOC_STEP;
908 uid_unused = xmalloc (uid_allocated);
909 memset (uid_unused, 1, uid_allocated);
910 setpwent ();
911 while ((pw = getpwent ()) != NULL)
913 if ((unsigned) pw->pw_uid >= uid_allocated)
915 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
916 uid_unused = xrealloc (uid_unused, new_allocated);
917 memset (uid_unused + uid_allocated, 1,
918 new_allocated - uid_allocated);
919 uid_allocated = new_allocated;
921 uid_unused[(unsigned) pw->pw_uid] = 0;
923 endpwent ();
925 #endif
926 return (true);
929 static boolean
930 parse_ok (argv, arg_ptr)
931 char *argv[];
932 int *arg_ptr;
934 return (insert_exec_ok (pred_ok, argv, arg_ptr));
937 boolean
938 parse_open (argv, arg_ptr)
939 char *argv[];
940 int *arg_ptr;
942 struct predicate *our_pred;
944 our_pred = get_new_pred_chk_op ();
945 our_pred->pred_func = pred_open;
946 #ifdef DEBUG
947 our_pred->p_name = find_pred_name (pred_open);
948 #endif /* DEBUG */
949 our_pred->p_type = OPEN_PAREN;
950 our_pred->p_prec = NO_PREC;
951 our_pred->need_stat = false;
952 return (true);
955 static boolean
956 parse_or (argv, arg_ptr)
957 char *argv[];
958 int *arg_ptr;
960 struct predicate *our_pred;
962 our_pred = get_new_pred ();
963 our_pred->pred_func = pred_or;
964 #ifdef DEBUG
965 our_pred->p_name = find_pred_name (pred_or);
966 #endif /* DEBUG */
967 our_pred->p_type = BI_OP;
968 our_pred->p_prec = OR_PREC;
969 our_pred->need_stat = false;
970 return (true);
973 static boolean
974 parse_path (argv, arg_ptr)
975 char *argv[];
976 int *arg_ptr;
978 struct predicate *our_pred;
980 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
981 return (false);
982 our_pred = insert_primary (pred_path);
983 our_pred->need_stat = false;
984 our_pred->args.str = argv[*arg_ptr];
985 (*arg_ptr)++;
986 return (true);
989 static boolean
990 parse_perm (argv, arg_ptr)
991 char *argv[];
992 int *arg_ptr;
994 unsigned long perm_val;
995 int mode_start = 0;
996 struct mode_change *change;
997 struct predicate *our_pred;
999 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1000 return (false);
1002 switch (argv[*arg_ptr][0])
1004 case '-':
1005 case '+':
1006 mode_start = 1;
1007 break;
1008 default:
1009 /* empty */
1010 break;
1013 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1014 if (change == MODE_INVALID)
1015 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1016 else if (change == MODE_MEMORY_EXHAUSTED)
1017 error (1, 0, _("virtual memory exhausted"));
1018 perm_val = mode_adjust (0, change);
1019 mode_free (change);
1021 our_pred = insert_primary (pred_perm);
1023 switch (argv[*arg_ptr][0])
1025 case '-':
1026 /* Set magic flag to indicate true if at least the given bits are set. */
1027 our_pred->args.perm = (perm_val & 07777) | 010000;
1028 break;
1029 case '+':
1030 /* Set magic flag to indicate true if any of the given bits are set. */
1031 our_pred->args.perm = (perm_val & 07777) | 020000;
1032 break;
1033 default:
1034 /* True if exactly the given bits are set. */
1035 our_pred->args.perm = (perm_val & 07777);
1036 break;
1038 (*arg_ptr)++;
1039 return (true);
1042 boolean
1043 parse_print (argv, arg_ptr)
1044 char *argv[];
1045 int *arg_ptr;
1047 struct predicate *our_pred;
1049 our_pred = insert_primary (pred_print);
1050 /* -print has the side effect of printing. This prevents us
1051 from doing undesired multiple printing when the user has
1052 already specified -print. */
1053 our_pred->side_effects = true;
1054 our_pred->need_stat = false;
1055 return (true);
1058 static boolean
1059 parse_print0 (argv, arg_ptr)
1060 char *argv[];
1061 int *arg_ptr;
1063 struct predicate *our_pred;
1065 our_pred = insert_primary (pred_print0);
1066 /* -print0 has the side effect of printing. This prevents us
1067 from doing undesired multiple printing when the user has
1068 already specified -print0. */
1069 our_pred->side_effects = true;
1070 our_pred->need_stat = false;
1071 return (true);
1074 static boolean
1075 parse_printf (argv, arg_ptr)
1076 char *argv[];
1077 int *arg_ptr;
1079 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1080 return (false);
1081 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1084 static boolean
1085 parse_prune (argv, arg_ptr)
1086 char *argv[];
1087 int *arg_ptr;
1089 struct predicate *our_pred;
1091 our_pred = insert_primary (pred_prune);
1092 our_pred->need_stat = false;
1093 return (true);
1096 static boolean
1097 parse_regex (argv, arg_ptr)
1098 char *argv[];
1099 int *arg_ptr;
1101 return insert_regex (argv, arg_ptr, false);
1104 static boolean
1105 insert_regex (argv, arg_ptr, ignore_case)
1106 char *argv[];
1107 int *arg_ptr;
1108 boolean ignore_case;
1110 struct predicate *our_pred;
1111 struct re_pattern_buffer *re;
1112 const char *error_message;
1114 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1115 return (false);
1116 our_pred = insert_primary (pred_regex);
1117 our_pred->need_stat = false;
1118 re = (struct re_pattern_buffer *)
1119 xmalloc (sizeof (struct re_pattern_buffer));
1120 our_pred->args.regex = re;
1121 re->allocated = 100;
1122 re->buffer = (unsigned char *) xmalloc (re->allocated);
1123 re->fastmap = NULL;
1125 if (ignore_case)
1127 unsigned i;
1129 re->translate = xmalloc (256);
1130 /* Map uppercase characters to corresponding lowercase ones. */
1131 for (i = 0; i < 256; i++)
1132 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1134 else
1135 re->translate = NULL;
1137 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1138 re);
1139 if (error_message)
1140 error (1, 0, "%s", error_message);
1141 (*arg_ptr)++;
1142 return (true);
1145 static boolean
1146 parse_size (argv, arg_ptr)
1147 char *argv[];
1148 int *arg_ptr;
1150 struct predicate *our_pred;
1151 unsigned long num;
1152 enum comparison_type c_type;
1153 int blksize = 512;
1154 int len;
1156 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1157 return (false);
1158 len = strlen (argv[*arg_ptr]);
1159 if (len == 0)
1160 error (1, 0, _("invalid null argument to -size"));
1161 switch (argv[*arg_ptr][len - 1])
1163 case 'b':
1164 blksize = 512;
1165 argv[*arg_ptr][len - 1] = '\0';
1166 break;
1168 case 'c':
1169 blksize = 1;
1170 argv[*arg_ptr][len - 1] = '\0';
1171 break;
1173 case 'k':
1174 blksize = 1024;
1175 argv[*arg_ptr][len - 1] = '\0';
1176 break;
1178 case 'w':
1179 blksize = 2;
1180 argv[*arg_ptr][len - 1] = '\0';
1181 break;
1183 case '0':
1184 case '1':
1185 case '2':
1186 case '3':
1187 case '4':
1188 case '5':
1189 case '6':
1190 case '7':
1191 case '8':
1192 case '9':
1193 break;
1195 default:
1196 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1198 if (!get_num (argv[*arg_ptr], &num, &c_type))
1199 return (false);
1200 our_pred = insert_primary (pred_size);
1201 our_pred->args.size.kind = c_type;
1202 our_pred->args.size.blocksize = blksize;
1203 our_pred->args.size.size = num;
1204 (*arg_ptr)++;
1205 return (true);
1208 static boolean
1209 parse_true (argv, arg_ptr)
1210 char *argv[];
1211 int *arg_ptr;
1213 struct predicate *our_pred;
1215 our_pred = insert_primary (pred_true);
1216 our_pred->need_stat = false;
1217 return (true);
1220 static boolean
1221 parse_type (argv, arg_ptr)
1222 char *argv[];
1223 int *arg_ptr;
1225 return insert_type (argv, arg_ptr, pred_type);
1228 static boolean
1229 parse_uid (argv, arg_ptr)
1230 char *argv[];
1231 int *arg_ptr;
1233 return (insert_num (argv, arg_ptr, pred_uid));
1236 static boolean
1237 parse_used (argv, arg_ptr)
1238 char *argv[];
1239 int *arg_ptr;
1242 struct predicate *our_pred;
1243 unsigned long num_days;
1244 enum comparison_type c_type;
1246 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1247 return (false);
1248 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1249 return (false);
1250 our_pred = insert_primary (pred_used);
1251 our_pred->args.info.kind = c_type;
1252 our_pred->args.info.l_val = num_days * DAYSECS;
1253 (*arg_ptr)++;
1254 return (true);
1257 static boolean
1258 parse_user (argv, arg_ptr)
1259 char *argv[];
1260 int *arg_ptr;
1262 struct passwd *cur_pwd;
1263 struct predicate *our_pred;
1264 uid_t uid;
1265 int uid_len;
1267 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1268 return (false);
1269 cur_pwd = getpwnam (argv[*arg_ptr]);
1270 endpwent ();
1271 if (cur_pwd != NULL)
1272 uid = cur_pwd->pw_uid;
1273 else
1275 uid_len = strspn (argv[*arg_ptr], "0123456789");
1276 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1277 return (false);
1278 uid = atoi (argv[*arg_ptr]);
1280 our_pred = insert_primary (pred_user);
1281 our_pred->args.uid = uid;
1282 (*arg_ptr)++;
1283 return (true);
1286 static boolean
1287 parse_version (argv, arg_ptr)
1288 char *argv[];
1289 int *arg_ptr;
1291 extern char *version_string;
1293 fflush (stderr);
1294 printf (_("GNU find version %s\n"), version_string);
1295 exit (0);
1298 static boolean
1299 parse_xdev (argv, arg_ptr)
1300 char *argv[];
1301 int *arg_ptr;
1303 stay_on_filesystem = true;
1304 return true;
1307 static boolean
1308 parse_xtype (argv, arg_ptr)
1309 char *argv[];
1310 int *arg_ptr;
1312 return insert_type (argv, arg_ptr, pred_xtype);
1315 static boolean
1316 insert_type (argv, arg_ptr, which_pred)
1317 char *argv[];
1318 int *arg_ptr;
1319 boolean (*which_pred) ();
1321 unsigned long type_cell;
1322 struct predicate *our_pred;
1324 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1325 || (strlen (argv[*arg_ptr]) != 1))
1326 return (false);
1327 switch (argv[*arg_ptr][0])
1329 case 'b': /* block special */
1330 type_cell = S_IFBLK;
1331 break;
1332 case 'c': /* character special */
1333 type_cell = S_IFCHR;
1334 break;
1335 case 'd': /* directory */
1336 type_cell = S_IFDIR;
1337 break;
1338 case 'f': /* regular file */
1339 type_cell = S_IFREG;
1340 break;
1341 #ifdef S_IFLNK
1342 case 'l': /* symbolic link */
1343 type_cell = S_IFLNK;
1344 break;
1345 #endif
1346 #ifdef S_IFIFO
1347 case 'p': /* pipe */
1348 type_cell = S_IFIFO;
1349 break;
1350 #endif
1351 #ifdef S_IFSOCK
1352 case 's': /* socket */
1353 type_cell = S_IFSOCK;
1354 break;
1355 #endif
1356 default: /* None of the above ... nuke 'em. */
1357 return (false);
1359 our_pred = insert_primary (which_pred);
1360 our_pred->args.type = type_cell;
1361 (*arg_ptr)++; /* Move on to next argument. */
1362 return (true);
1365 /* If true, we've determined that the current fprintf predicate
1366 uses stat information. */
1367 static boolean fprintf_stat_needed;
1369 static boolean
1370 insert_fprintf (fp, func, argv, arg_ptr)
1371 FILE *fp;
1372 boolean (*func) ();
1373 char *argv[];
1374 int *arg_ptr;
1376 char *format; /* Beginning of unprocessed format string. */
1377 register char *scan; /* Current address in scanning `format'. */
1378 register char *scan2; /* Address inside of element being scanned. */
1379 struct segment **segmentp; /* Address of current segment. */
1380 struct predicate *our_pred;
1382 format = argv[(*arg_ptr)++];
1384 fprintf_stat_needed = false; /* Might be overridden later. */
1385 our_pred = insert_primary (func);
1386 our_pred->side_effects = true;
1387 our_pred->args.printf_vec.stream = fp;
1388 segmentp = &our_pred->args.printf_vec.segment;
1389 *segmentp = NULL;
1391 for (scan = format; *scan; scan++)
1393 if (*scan == '\\')
1395 scan2 = scan + 1;
1396 if (*scan2 >= '0' && *scan2 <= '7')
1398 register int n, i;
1400 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1401 i++, scan2++)
1402 n = 8 * n + *scan2 - '0';
1403 scan2--;
1404 *scan = n;
1406 else
1408 switch (*scan2)
1410 case 'a':
1411 *scan = 7;
1412 break;
1413 case 'b':
1414 *scan = '\b';
1415 break;
1416 case 'c':
1417 make_segment (segmentp, format, scan - format, KIND_STOP);
1418 our_pred->need_stat = fprintf_stat_needed;
1419 return (true);
1420 case 'f':
1421 *scan = '\f';
1422 break;
1423 case 'n':
1424 *scan = '\n';
1425 break;
1426 case 'r':
1427 *scan = '\r';
1428 break;
1429 case 't':
1430 *scan = '\t';
1431 break;
1432 case 'v':
1433 *scan = '\v';
1434 break;
1435 case '\\':
1436 /* *scan = '\\'; * it already is */
1437 break;
1438 default:
1439 error (0, 0,
1440 _("warning: unrecognized escape `\\%c'"), *scan2);
1441 scan++;
1442 continue;
1445 segmentp = make_segment (segmentp, format, scan - format + 1,
1446 KIND_PLAIN);
1447 format = scan2 + 1; /* Move past the escape. */
1448 scan = scan2; /* Incremented immediately by `for'. */
1450 else if (*scan == '%')
1452 if (scan[1] == '%')
1454 segmentp = make_segment (segmentp, format, scan - format + 1,
1455 KIND_PLAIN);
1456 scan++;
1457 format = scan + 1;
1458 continue;
1460 /* Scan past flags, width and precision, to verify kind. */
1461 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1462 /* Do nothing. */ ;
1463 while (ISDIGIT (*scan2))
1464 scan2++;
1465 if (*scan2 == '.')
1466 for (scan2++; ISDIGIT (*scan2); scan2++)
1467 /* Do nothing. */ ;
1468 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1470 segmentp = make_segment (segmentp, format, scan2 - format,
1471 (int) *scan2);
1472 scan = scan2;
1473 format = scan + 1;
1475 else if (strchr ("ACT", *scan2) && scan2[1])
1477 segmentp = make_segment (segmentp, format, scan2 - format,
1478 *scan2 | (scan2[1] << 8));
1479 scan = scan2 + 1;
1480 format = scan + 1;
1481 continue;
1483 else
1485 /* An unrecognized % escape. Print the char after the %. */
1486 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1487 *scan2);
1488 segmentp = make_segment (segmentp, format, scan - format,
1489 KIND_PLAIN);
1490 format = scan + 1;
1491 continue;
1496 if (scan > format)
1497 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1498 our_pred->need_stat = fprintf_stat_needed;
1499 return (true);
1502 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1503 from the text in FORMAT, which has length LEN.
1504 Return the address of the `next' pointer of the new segment. */
1506 static struct segment **
1507 make_segment (segment, format, len, kind)
1508 struct segment **segment;
1509 char *format;
1510 int len, kind;
1512 char *fmt;
1514 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1516 (*segment)->kind = kind;
1517 (*segment)->next = NULL;
1518 (*segment)->text_len = len;
1520 fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
1521 strncpy (fmt, format, len);
1522 fmt += len;
1524 switch (kind & 0xff)
1526 case KIND_PLAIN: /* Plain text string, no % conversion. */
1527 case KIND_STOP: /* Terminate argument, no newline. */
1528 break;
1530 case 'a': /* atime in `ctime' format */
1531 case 'c': /* ctime in `ctime' format */
1532 case 'F': /* filesystem type */
1533 case 'g': /* group name */
1534 case 'l': /* object of symlink */
1535 case 't': /* mtime in `ctime' format */
1536 case 'u': /* user name */
1537 case 'A': /* atime in user-specified strftime format */
1538 case 'C': /* ctime in user-specified strftime format */
1539 case 'T': /* mtime in user-specified strftime format */
1540 fprintf_stat_needed = true;
1541 /* FALLTHROUGH */
1542 case 'f': /* basename of path */
1543 case 'h': /* leading directories part of path */
1544 case 'H': /* ARGV element file was found under */
1545 case 'p': /* pathname */
1546 case 'P': /* pathname with ARGV element stripped */
1547 *fmt++ = 's';
1548 break;
1550 case 'b': /* size in 512-byte blocks */
1551 case 'k': /* size in 1K blocks */
1552 case 's': /* size in bytes */
1553 *fmt++ = 'l';
1554 /*FALLTHROUGH*/
1555 case 'n': /* number of links */
1556 fprintf_stat_needed = true;
1557 /* FALLTHROUGH */
1558 case 'd': /* depth in search tree (0 = ARGV element) */
1559 *fmt++ = 'd';
1560 break;
1562 case 'i': /* inode number */
1563 *fmt++ = 'l';
1564 /*FALLTHROUGH*/
1565 case 'G': /* GID number */
1566 case 'U': /* UID number */
1567 *fmt++ = 'u';
1568 fprintf_stat_needed = true;
1569 break;
1571 case 'm': /* mode as octal number (perms only) */
1572 *fmt++ = 'o';
1573 fprintf_stat_needed = true;
1574 break;
1576 *fmt = '\0';
1578 return (&(*segment)->next);
1581 static boolean
1582 insert_exec_ok (func, argv, arg_ptr)
1583 boolean (*func) ();
1584 char *argv[];
1585 int *arg_ptr;
1587 int start, end; /* Indexes in ARGV of start & end of cmd. */
1588 int num_paths; /* Number of args with path replacements. */
1589 int path_pos; /* Index in array of path replacements. */
1590 int vec_pos; /* Index in array of args. */
1591 struct predicate *our_pred;
1592 struct exec_val *execp; /* Pointer for efficiency. */
1594 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1595 return (false);
1597 /* Count the number of args with path replacements, up until the ';'. */
1598 start = *arg_ptr;
1599 for (end = start, num_paths = 0;
1600 (argv[end] != NULL)
1601 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1602 end++)
1603 if (strstr (argv[end], "{}"))
1604 num_paths++;
1605 /* Fail if no command given or no semicolon found. */
1606 if ((end == start) || (argv[end] == NULL))
1608 *arg_ptr = end;
1609 return (false);
1612 our_pred = insert_primary (func);
1613 our_pred->side_effects = true;
1614 execp = &our_pred->args.exec_vec;
1615 execp->paths =
1616 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1617 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1618 /* Record the positions of all args, and the args with path replacements. */
1619 for (end = start, path_pos = vec_pos = 0;
1620 (argv[end] != NULL)
1621 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1622 end++)
1624 register char *p;
1626 execp->paths[path_pos].count = 0;
1627 for (p = argv[end]; *p; ++p)
1628 if (p[0] == '{' && p[1] == '}')
1630 execp->paths[path_pos].count++;
1631 ++p;
1633 if (execp->paths[path_pos].count)
1635 execp->paths[path_pos].offset = vec_pos;
1636 execp->paths[path_pos].origarg = argv[end];
1637 path_pos++;
1639 execp->vec[vec_pos++] = argv[end];
1641 execp->paths[path_pos].offset = -1;
1642 execp->vec[vec_pos] = NULL;
1644 if (argv[end] == NULL)
1645 *arg_ptr = end;
1646 else
1647 *arg_ptr = end + 1;
1648 return (true);
1651 /* Get a number of days and comparison type.
1652 STR is the ASCII representation.
1653 Set *NUM_DAYS to the number of days, taken as being from
1654 the current moment (or possibly midnight). Thus the sense of the
1655 comparison type appears to be reversed.
1656 Set *COMP_TYPE to the kind of comparison that is requested.
1658 Return true if all okay, false if input error.
1660 Used by -atime, -ctime and -mtime (parsers) to
1661 get the appropriate information for a time predicate processor. */
1663 static boolean
1664 get_num_days (str, num_days, comp_type)
1665 char *str;
1666 unsigned long *num_days;
1667 enum comparison_type *comp_type;
1669 int len_days; /* length of field */
1671 if (str == NULL)
1672 return (false);
1673 switch (str[0])
1675 case '+':
1676 *comp_type = COMP_LT;
1677 str++;
1678 break;
1679 case '-':
1680 *comp_type = COMP_GT;
1681 str++;
1682 break;
1683 case '0':
1684 case '1':
1685 case '2':
1686 case '3':
1687 case '4':
1688 case '5':
1689 case '6':
1690 case '7':
1691 case '8':
1692 case '9':
1693 *comp_type = COMP_EQ;
1694 break;
1695 default:
1696 return (false);
1699 /* We know the first char has been reasonable. Find the
1700 number of days to play with. */
1701 len_days = strspn (str, "0123456789");
1702 if ((len_days == 0) || (str[len_days] != '\0'))
1703 return (false);
1704 *num_days = (unsigned long) atol (str);
1705 return (true);
1708 /* Insert a time predicate PRED.
1709 ARGV is a pointer to the argument array.
1710 ARG_PTR is a pointer to an index into the array, incremented if
1711 all went well.
1713 Return true if input is valid, false if not.
1715 A new predicate node is assigned, along with an argument node
1716 obtained with malloc.
1718 Used by -atime, -ctime, and -mtime parsers. */
1720 static boolean
1721 insert_time (argv, arg_ptr, pred)
1722 char *argv[];
1723 int *arg_ptr;
1724 PFB pred;
1726 struct predicate *our_pred;
1727 unsigned long num_days;
1728 enum comparison_type c_type;
1730 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1731 return (false);
1732 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1733 return (false);
1734 our_pred = insert_primary (pred);
1735 our_pred->args.info.kind = c_type;
1736 our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
1737 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
1738 (*arg_ptr)++;
1739 #ifdef DEBUG
1740 printf (_("inserting %s\n"), our_pred->p_name);
1741 printf (_(" type: %s %s "),
1742 (c_type == COMP_GT) ? "gt" :
1743 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1744 (c_type == COMP_GT) ? " >" :
1745 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1746 printf ("%ld %s", our_pred->args.info.l_val,
1747 ctime (&our_pred->args.info.l_val));
1748 if (c_type == COMP_EQ)
1750 our_pred->args.info.l_val += DAYSECS;
1751 printf (" < %ld %s", our_pred->args.info.l_val,
1752 ctime (&our_pred->args.info.l_val));
1753 our_pred->args.info.l_val -= DAYSECS;
1755 #endif /* DEBUG */
1756 return (true);
1759 /* Get a number with comparision information.
1760 The sense of the comparision information is 'normal'; that is,
1761 '+' looks for inums or links > than the number and '-' less than.
1763 STR is the ASCII representation of the number.
1764 Set *NUM to the number.
1765 Set *COMP_TYPE to the kind of comparison that is requested.
1767 Return true if all okay, false if input error.
1769 Used by the -inum and -links predicate parsers. */
1771 static boolean
1772 get_num (str, num, comp_type)
1773 char *str;
1774 unsigned long *num;
1775 enum comparison_type *comp_type;
1777 int len_num; /* Length of field. */
1779 if (str == NULL)
1780 return (false);
1781 switch (str[0])
1783 case '+':
1784 *comp_type = COMP_GT;
1785 str++;
1786 break;
1787 case '-':
1788 *comp_type = COMP_LT;
1789 str++;
1790 break;
1791 case '0':
1792 case '1':
1793 case '2':
1794 case '3':
1795 case '4':
1796 case '5':
1797 case '6':
1798 case '7':
1799 case '8':
1800 case '9':
1801 *comp_type = COMP_EQ;
1802 break;
1803 default:
1804 return (false);
1807 /* We know the first char has been reasonable. Find the number of
1808 days to play with. */
1809 len_num = strspn (str, "0123456789");
1810 if ((len_num == 0) || (str[len_num] != '\0'))
1811 return (false);
1812 *num = (unsigned long) atol (str);
1813 return (true);
1816 /* Insert a number predicate.
1817 ARGV is a pointer to the argument array.
1818 *ARG_PTR is an index into ARGV, incremented if all went well.
1819 *PRED is the predicate processor to insert.
1821 Return true if input is valid, false if error.
1823 A new predicate node is assigned, along with an argument node
1824 obtained with malloc.
1826 Used by -inum and -links parsers. */
1828 static boolean
1829 insert_num (argv, arg_ptr, pred)
1830 char *argv[];
1831 int *arg_ptr;
1832 PFB pred;
1834 struct predicate *our_pred;
1835 unsigned long num;
1836 enum comparison_type c_type;
1838 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1839 return (false);
1840 if (!get_num (argv[*arg_ptr], &num, &c_type))
1841 return (false);
1842 our_pred = insert_primary (pred);
1843 our_pred->args.info.kind = c_type;
1844 our_pred->args.info.l_val = num;
1845 (*arg_ptr)++;
1846 #ifdef DEBUG
1847 printf (_("inserting %s\n"), our_pred->p_name);
1848 printf (_(" type: %s %s "),
1849 (c_type == COMP_GT) ? "gt" :
1850 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1851 (c_type == COMP_GT) ? " >" :
1852 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1853 printf ("%ld\n", our_pred->args.info.l_val);
1854 #endif /* DEBUG */
1855 return (true);
1858 static FILE *
1859 open_output_file (path)
1860 char *path;
1862 FILE *f;
1864 if (!strcmp (path, "/dev/stderr"))
1865 return (stderr);
1866 else if (!strcmp (path, "/dev/stdout"))
1867 return (stdout);
1868 f = fopen (path, "w");
1869 if (f == NULL)
1870 error (1, errno, "%s", path);
1871 return (f);