*** empty log message ***
[findutils.git] / find / parser.c
blob3d85a9a3869fd5dcc88d1f45d54e1b1e47956a2e
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 _POSIX_VERSION
40 /* POSIX.1 header files should declare these. */
41 struct group *getgrnam ();
42 struct passwd *getpwnam ();
43 #endif
45 #ifdef CACHE_IDS
46 /* These two aren't specified by POSIX.1. */
47 struct group *getgrent ();
48 struct passwd *getpwent ();
49 #endif
51 #ifndef S_IFLNK
52 #define lstat stat
53 #endif
55 char *strstr ();
56 int lstat ();
57 int stat ();
58 #ifndef atol /* for Linux */
59 long atol ();
60 #endif
61 struct tm *localtime ();
63 #ifdef _POSIX_SOURCE
64 #define endgrent()
65 #define endpwent()
66 #else
67 void endgrent ();
68 void endpwent ();
69 #endif
71 static boolean parse_amin P_((char *argv[], int *arg_ptr));
72 static boolean parse_and P_((char *argv[], int *arg_ptr));
73 static boolean parse_anewer P_((char *argv[], int *arg_ptr));
74 static boolean parse_atime P_((char *argv[], int *arg_ptr));
75 boolean parse_close P_((char *argv[], int *arg_ptr));
76 static boolean parse_cmin P_((char *argv[], int *arg_ptr));
77 static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
78 static boolean parse_comma P_((char *argv[], int *arg_ptr));
79 static boolean parse_ctime P_((char *argv[], int *arg_ptr));
80 static boolean parse_daystart P_((char *argv[], int *arg_ptr));
81 static boolean parse_depth P_((char *argv[], int *arg_ptr));
82 static boolean parse_empty P_((char *argv[], int *arg_ptr));
83 static boolean parse_exec P_((char *argv[], int *arg_ptr));
84 static boolean parse_false P_((char *argv[], int *arg_ptr));
85 static boolean parse_fls P_((char *argv[], int *arg_ptr));
86 static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
87 static boolean parse_follow P_((char *argv[], int *arg_ptr));
88 static boolean parse_fprint P_((char *argv[], int *arg_ptr));
89 static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
90 static boolean parse_fstype P_((char *argv[], int *arg_ptr));
91 static boolean parse_gid P_((char *argv[], int *arg_ptr));
92 static boolean parse_group P_((char *argv[], int *arg_ptr));
93 static boolean parse_help P_((char *argv[], int *arg_ptr));
94 static boolean parse_ilname P_((char *argv[], int *arg_ptr));
95 static boolean parse_iname P_((char *argv[], int *arg_ptr));
96 static boolean parse_inum P_((char *argv[], int *arg_ptr));
97 static boolean parse_ipath P_((char *argv[], int *arg_ptr));
98 static boolean parse_iregex P_((char *argv[], int *arg_ptr));
99 static boolean parse_links P_((char *argv[], int *arg_ptr));
100 static boolean parse_lname P_((char *argv[], int *arg_ptr));
101 static boolean parse_ls P_((char *argv[], int *arg_ptr));
102 static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
103 static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
104 static boolean parse_mmin P_((char *argv[], int *arg_ptr));
105 static boolean parse_mtime P_((char *argv[], int *arg_ptr));
106 static boolean parse_name P_((char *argv[], int *arg_ptr));
107 static boolean parse_negate P_((char *argv[], int *arg_ptr));
108 static boolean parse_newer P_((char *argv[], int *arg_ptr));
109 static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
110 static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
111 static boolean parse_nouser P_((char *argv[], int *arg_ptr));
112 static boolean parse_ok P_((char *argv[], int *arg_ptr));
113 boolean parse_open P_((char *argv[], int *arg_ptr));
114 static boolean parse_or P_((char *argv[], int *arg_ptr));
115 static boolean parse_path P_((char *argv[], int *arg_ptr));
116 static boolean parse_perm P_((char *argv[], int *arg_ptr));
117 boolean parse_print P_((char *argv[], int *arg_ptr));
118 static boolean parse_print0 P_((char *argv[], int *arg_ptr));
119 static boolean parse_printf P_((char *argv[], int *arg_ptr));
120 static boolean parse_prune P_((char *argv[], int *arg_ptr));
121 static boolean parse_regex P_((char *argv[], int *arg_ptr));
122 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
123 static boolean parse_size P_((char *argv[], int *arg_ptr));
124 static boolean parse_true P_((char *argv[], int *arg_ptr));
125 static boolean parse_type P_((char *argv[], int *arg_ptr));
126 static boolean parse_uid P_((char *argv[], int *arg_ptr));
127 static boolean parse_used P_((char *argv[], int *arg_ptr));
128 static boolean parse_user P_((char *argv[], int *arg_ptr));
129 static boolean parse_version P_((char *argv[], int *arg_ptr));
130 static boolean parse_xdev P_((char *argv[], int *arg_ptr));
131 static boolean parse_xtype P_((char *argv[], int *arg_ptr));
133 static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
134 static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
135 static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
136 static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
137 static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
138 static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
139 static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
140 static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
141 static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
142 static FILE *open_output_file P_((char *path));
144 #ifdef DEBUG
145 char *find_pred_name _P((PFB pred_func));
146 #endif /* DEBUG */
148 struct parser_table
150 char *parser_name;
151 PFB parser_func;
154 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
155 If they are in some Unix versions of find, they are marked `Unix'. */
157 static struct parser_table const parse_table[] =
159 {"!", parse_negate},
160 {"not", parse_negate}, /* GNU */
161 {"(", parse_open},
162 {")", parse_close},
163 {",", parse_comma}, /* GNU */
164 {"a", parse_and},
165 {"amin", parse_amin}, /* GNU */
166 {"and", parse_and}, /* GNU */
167 {"anewer", parse_anewer}, /* GNU */
168 {"atime", parse_atime},
169 {"cmin", parse_cmin}, /* GNU */
170 {"cnewer", parse_cnewer}, /* GNU */
171 #ifdef UNIMPLEMENTED_UNIX
172 /* It's pretty ugly for find to know about archive formats.
173 Plus what it could do with cpio archives is very limited.
174 Better to leave it out. */
175 {"cpio", parse_cpio}, /* Unix */
176 #endif
177 {"ctime", parse_ctime},
178 {"daystart", parse_daystart}, /* GNU */
179 {"depth", parse_depth},
180 {"empty", parse_empty}, /* GNU */
181 {"exec", parse_exec},
182 {"false", parse_false}, /* GNU */
183 {"fls", parse_fls}, /* GNU */
184 {"follow", parse_follow}, /* GNU, Unix */
185 {"fprint", parse_fprint}, /* GNU */
186 {"fprint0", parse_fprint0}, /* GNU */
187 {"fprintf", parse_fprintf}, /* GNU */
188 {"fstype", parse_fstype}, /* GNU, Unix */
189 {"gid", parse_gid}, /* GNU */
190 {"group", parse_group},
191 {"help", parse_help}, /* GNU */
192 {"-help", parse_help}, /* GNU */
193 {"ilname", parse_ilname}, /* GNU */
194 {"iname", parse_iname}, /* GNU */
195 {"inum", parse_inum}, /* GNU, Unix */
196 {"ipath", parse_ipath}, /* GNU */
197 {"iregex", parse_iregex}, /* GNU */
198 {"links", parse_links},
199 {"lname", parse_lname}, /* GNU */
200 {"ls", parse_ls}, /* GNU, Unix */
201 {"maxdepth", parse_maxdepth}, /* GNU */
202 {"mindepth", parse_mindepth}, /* GNU */
203 {"mmin", parse_mmin}, /* GNU */
204 {"mount", parse_xdev}, /* Unix */
205 {"mtime", parse_mtime},
206 {"name", parse_name},
207 #ifdef UNIMPLEMENTED_UNIX
208 {"ncpio", parse_ncpio}, /* Unix */
209 #endif
210 {"newer", parse_newer},
211 {"noleaf", parse_noleaf}, /* GNU */
212 {"nogroup", parse_nogroup},
213 {"nouser", parse_nouser},
214 {"o", parse_or},
215 {"or", parse_or}, /* GNU */
216 {"ok", parse_ok},
217 {"path", parse_path}, /* GNU, HP-UX */
218 {"perm", parse_perm},
219 {"print", parse_print},
220 {"print0", parse_print0}, /* GNU */
221 {"printf", parse_printf}, /* GNU */
222 {"prune", parse_prune},
223 {"regex", parse_regex}, /* GNU */
224 {"size", parse_size},
225 {"true", parse_true}, /* GNU */
226 {"type", parse_type},
227 {"uid", parse_uid}, /* GNU */
228 {"used", parse_used}, /* GNU */
229 {"user", parse_user},
230 {"version", parse_version}, /* GNU */
231 {"-version", parse_version}, /* GNU */
232 {"xdev", parse_xdev},
233 {"xtype", parse_xtype}, /* GNU */
234 {0, 0}
237 /* Return a pointer to the parser function to invoke for predicate
238 SEARCH_NAME.
239 Return NULL if SEARCH_NAME is not a valid predicate name. */
242 find_parser (search_name)
243 char *search_name;
245 int i;
247 if (*search_name == '-')
248 search_name++;
249 for (i = 0; parse_table[i].parser_name != 0; i++)
250 if (strcmp (parse_table[i].parser_name, search_name) == 0)
251 return (parse_table[i].parser_func);
252 return (NULL);
255 /* The parsers are responsible to continue scanning ARGV for
256 their arguments. Each parser knows what is and isn't
257 allowed for itself.
259 ARGV is the argument array.
260 *ARG_PTR is the index to start at in ARGV,
261 updated to point beyond the last element consumed.
263 The predicate structure is updated with the new information. */
265 static boolean
266 parse_amin (argv, arg_ptr)
267 char *argv[];
268 int *arg_ptr;
270 struct predicate *our_pred;
271 unsigned long num;
272 enum comparison_type c_type;
274 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
275 return (false);
276 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
277 return (false);
278 our_pred = insert_primary (pred_amin);
279 our_pred->args.info.kind = c_type;
280 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
281 (*arg_ptr)++;
282 return (true);
285 static boolean
286 parse_and (argv, arg_ptr)
287 char *argv[];
288 int *arg_ptr;
290 struct predicate *our_pred;
292 our_pred = get_new_pred ();
293 our_pred->pred_func = pred_and;
294 #ifdef DEBUG
295 our_pred->p_name = find_pred_name (pred_and);
296 #endif /* DEBUG */
297 our_pred->p_type = BI_OP;
298 our_pred->p_prec = AND_PREC;
299 our_pred->need_stat = false;
300 return (true);
303 static boolean
304 parse_anewer (argv, arg_ptr)
305 char *argv[];
306 int *arg_ptr;
308 struct predicate *our_pred;
309 struct stat stat_newer;
311 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
312 return (false);
313 if ((*xstat) (argv[*arg_ptr], &stat_newer))
314 error (1, errno, "%s", argv[*arg_ptr]);
315 our_pred = insert_primary (pred_anewer);
316 our_pred->args.time = stat_newer.st_mtime;
317 (*arg_ptr)++;
318 return (true);
321 static boolean
322 parse_atime (argv, arg_ptr)
323 char *argv[];
324 int *arg_ptr;
326 return (insert_time (argv, arg_ptr, pred_atime));
329 boolean
330 parse_close (argv, arg_ptr)
331 char *argv[];
332 int *arg_ptr;
334 struct predicate *our_pred;
336 our_pred = get_new_pred ();
337 our_pred->pred_func = pred_close;
338 #ifdef DEBUG
339 our_pred->p_name = find_pred_name (pred_close);
340 #endif /* DEBUG */
341 our_pred->p_type = CLOSE_PAREN;
342 our_pred->p_prec = NO_PREC;
343 our_pred->need_stat = false;
344 return (true);
347 static boolean
348 parse_cmin (argv, arg_ptr)
349 char *argv[];
350 int *arg_ptr;
352 struct predicate *our_pred;
353 unsigned long num;
354 enum comparison_type c_type;
356 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
357 return (false);
358 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
359 return (false);
360 our_pred = insert_primary (pred_cmin);
361 our_pred->args.info.kind = c_type;
362 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
363 (*arg_ptr)++;
364 return (true);
367 static boolean
368 parse_cnewer (argv, arg_ptr)
369 char *argv[];
370 int *arg_ptr;
372 struct predicate *our_pred;
373 struct stat stat_newer;
375 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
376 return (false);
377 if ((*xstat) (argv[*arg_ptr], &stat_newer))
378 error (1, errno, "%s", argv[*arg_ptr]);
379 our_pred = insert_primary (pred_cnewer);
380 our_pred->args.time = stat_newer.st_mtime;
381 (*arg_ptr)++;
382 return (true);
385 static boolean
386 parse_comma (argv, arg_ptr)
387 char *argv[];
388 int *arg_ptr;
390 struct predicate *our_pred;
392 our_pred = get_new_pred ();
393 our_pred->pred_func = pred_comma;
394 #ifdef DEBUG
395 our_pred->p_name = find_pred_name (pred_comma);
396 #endif /* DEBUG */
397 our_pred->p_type = BI_OP;
398 our_pred->p_prec = COMMA_PREC;
399 our_pred->need_stat = false;
400 return (true);
403 static boolean
404 parse_ctime (argv, arg_ptr)
405 char *argv[];
406 int *arg_ptr;
408 return (insert_time (argv, arg_ptr, pred_ctime));
411 static boolean
412 parse_daystart (argv, arg_ptr)
413 char *argv[];
414 int *arg_ptr;
416 struct tm *local;
418 if (full_days == false)
420 cur_day_start += DAYSECS;
421 local = localtime (&cur_day_start);
422 cur_day_start -= local->tm_sec + local->tm_min * 60
423 + local->tm_hour * 3600;
424 full_days = true;
426 return (true);
429 static boolean
430 parse_depth (argv, arg_ptr)
431 char *argv[];
432 int *arg_ptr;
434 do_dir_first = false;
435 return (true);
438 static boolean
439 parse_empty (argv, arg_ptr)
440 char *argv[];
441 int *arg_ptr;
443 insert_primary (pred_empty);
444 return (true);
447 static boolean
448 parse_exec (argv, arg_ptr)
449 char *argv[];
450 int *arg_ptr;
452 return (insert_exec_ok (pred_exec, argv, arg_ptr));
455 static boolean
456 parse_false (argv, arg_ptr)
457 char *argv[];
458 int *arg_ptr;
460 struct predicate *our_pred;
462 our_pred = insert_primary (pred_false);
463 our_pred->need_stat = false;
464 return (true);
467 static boolean
468 parse_fls (argv, arg_ptr)
469 char *argv[];
470 int *arg_ptr;
472 struct predicate *our_pred;
474 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
475 return (false);
476 our_pred = insert_primary (pred_fls);
477 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
478 our_pred->side_effects = true;
479 (*arg_ptr)++;
480 return (true);
483 static boolean
484 parse_fprintf (argv, arg_ptr)
485 char *argv[];
486 int *arg_ptr;
488 FILE *fp;
490 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
491 return (false);
492 if (argv[*arg_ptr + 1] == NULL)
494 /* Ensure we get "missing arg" message, not "invalid arg". */
495 (*arg_ptr)++;
496 return (false);
498 fp = open_output_file (argv[*arg_ptr]);
499 (*arg_ptr)++;
500 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
503 static boolean
504 parse_follow (argv, arg_ptr)
505 char *argv[];
506 int *arg_ptr;
508 dereference = true;
509 xstat = stat;
510 no_leaf_check = true;
511 return (true);
514 static boolean
515 parse_fprint (argv, arg_ptr)
516 char *argv[];
517 int *arg_ptr;
519 struct predicate *our_pred;
521 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
522 return (false);
523 our_pred = insert_primary (pred_fprint);
524 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
525 our_pred->side_effects = true;
526 our_pred->need_stat = false;
527 (*arg_ptr)++;
528 return (true);
531 static boolean
532 parse_fprint0 (argv, arg_ptr)
533 char *argv[];
534 int *arg_ptr;
536 struct predicate *our_pred;
538 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
539 return (false);
540 our_pred = insert_primary (pred_fprint0);
541 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
542 our_pred->side_effects = true;
543 our_pred->need_stat = false;
544 (*arg_ptr)++;
545 return (true);
548 static boolean
549 parse_fstype (argv, arg_ptr)
550 char *argv[];
551 int *arg_ptr;
553 struct predicate *our_pred;
555 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
556 return (false);
557 our_pred = insert_primary (pred_fstype);
558 our_pred->args.str = argv[*arg_ptr];
559 (*arg_ptr)++;
560 return (true);
563 static boolean
564 parse_gid (argv, arg_ptr)
565 char *argv[];
566 int *arg_ptr;
568 return (insert_num (argv, arg_ptr, pred_gid));
571 static boolean
572 parse_group (argv, arg_ptr)
573 char *argv[];
574 int *arg_ptr;
576 struct group *cur_gr;
577 struct predicate *our_pred;
578 gid_t gid;
579 int gid_len;
581 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
582 return (false);
583 cur_gr = getgrnam (argv[*arg_ptr]);
584 endgrent ();
585 if (cur_gr != NULL)
586 gid = cur_gr->gr_gid;
587 else
589 gid_len = strspn (argv[*arg_ptr], "0123456789");
590 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
591 return (false);
592 gid = atoi (argv[*arg_ptr]);
594 our_pred = insert_primary (pred_group);
595 our_pred->args.gid = gid;
596 (*arg_ptr)++;
597 return (true);
600 static boolean
601 parse_help (argv, arg_ptr)
602 char *argv[];
603 int *arg_ptr;
605 printf ("\
606 Usage: %s [path...] [expression]\n", program_name);
607 printf ("\
608 default path is the current directory; default expression is -print\n\
609 expression may consist of:\n\
610 operators (decreasing precedence; -and is implicit where no others are given):\n\
611 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
612 printf ("\
613 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
614 options (always true): -daystart -depth -follow --help\n\
615 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
616 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
617 printf ("\
618 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
619 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
620 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
621 printf ("\
622 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
623 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
624 -xtype [bcdpfls]\n");
625 printf ("\
626 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
627 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
628 exit (0);
631 static boolean
632 parse_ilname (argv, arg_ptr)
633 char *argv[];
634 int *arg_ptr;
636 struct predicate *our_pred;
638 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
639 return (false);
640 our_pred = insert_primary (pred_ilname);
641 our_pred->args.str = argv[*arg_ptr];
642 (*arg_ptr)++;
643 return (true);
646 static boolean
647 parse_iname (argv, arg_ptr)
648 char *argv[];
649 int *arg_ptr;
651 struct predicate *our_pred;
653 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
654 return (false);
655 our_pred = insert_primary (pred_iname);
656 our_pred->need_stat = false;
657 our_pred->args.str = argv[*arg_ptr];
658 (*arg_ptr)++;
659 return (true);
662 static boolean
663 parse_inum (argv, arg_ptr)
664 char *argv[];
665 int *arg_ptr;
667 return (insert_num (argv, arg_ptr, pred_inum));
670 static boolean
671 parse_ipath (argv, arg_ptr)
672 char *argv[];
673 int *arg_ptr;
675 struct predicate *our_pred;
677 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
678 return (false);
679 our_pred = insert_primary (pred_ipath);
680 our_pred->need_stat = false;
681 our_pred->args.str = argv[*arg_ptr];
682 (*arg_ptr)++;
683 return (true);
686 static boolean
687 parse_iregex (argv, arg_ptr)
688 char *argv[];
689 int *arg_ptr;
691 return insert_regex (argv, arg_ptr, true);
694 static boolean
695 parse_links (argv, arg_ptr)
696 char *argv[];
697 int *arg_ptr;
699 return (insert_num (argv, arg_ptr, pred_links));
702 static boolean
703 parse_lname (argv, arg_ptr)
704 char *argv[];
705 int *arg_ptr;
707 struct predicate *our_pred;
709 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
710 return (false);
711 our_pred = insert_primary (pred_lname);
712 our_pred->args.str = argv[*arg_ptr];
713 (*arg_ptr)++;
714 return (true);
717 static boolean
718 parse_ls (argv, arg_ptr)
719 char *argv[];
720 int *arg_ptr;
722 struct predicate *our_pred;
724 our_pred = insert_primary (pred_ls);
725 our_pred->side_effects = true;
726 return (true);
729 static boolean
730 parse_maxdepth (argv, arg_ptr)
731 char *argv[];
732 int *arg_ptr;
734 int depth_len;
736 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
737 return (false);
738 depth_len = strspn (argv[*arg_ptr], "0123456789");
739 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
740 return (false);
741 maxdepth = atoi (argv[*arg_ptr]);
742 if (maxdepth < 0)
743 return (false);
744 (*arg_ptr)++;
745 return (true);
748 static boolean
749 parse_mindepth (argv, arg_ptr)
750 char *argv[];
751 int *arg_ptr;
753 int depth_len;
755 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
756 return (false);
757 depth_len = strspn (argv[*arg_ptr], "0123456789");
758 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
759 return (false);
760 mindepth = atoi (argv[*arg_ptr]);
761 if (mindepth < 0)
762 return (false);
763 (*arg_ptr)++;
764 return (true);
767 static boolean
768 parse_mmin (argv, arg_ptr)
769 char *argv[];
770 int *arg_ptr;
772 struct predicate *our_pred;
773 unsigned long num;
774 enum comparison_type c_type;
776 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
777 return (false);
778 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
779 return (false);
780 our_pred = insert_primary (pred_mmin);
781 our_pred->args.info.kind = c_type;
782 our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
783 (*arg_ptr)++;
784 return (true);
787 static boolean
788 parse_mtime (argv, arg_ptr)
789 char *argv[];
790 int *arg_ptr;
792 return (insert_time (argv, arg_ptr, pred_mtime));
795 static boolean
796 parse_name (argv, arg_ptr)
797 char *argv[];
798 int *arg_ptr;
800 struct predicate *our_pred;
802 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
803 return (false);
804 our_pred = insert_primary (pred_name);
805 our_pred->need_stat = false;
806 our_pred->args.str = argv[*arg_ptr];
807 (*arg_ptr)++;
808 return (true);
811 static boolean
812 parse_negate (argv, arg_ptr)
813 char *argv[];
814 int *arg_ptr;
816 struct predicate *our_pred;
818 our_pred = get_new_pred_chk_op ();
819 our_pred->pred_func = pred_negate;
820 #ifdef DEBUG
821 our_pred->p_name = find_pred_name (pred_negate);
822 #endif /* DEBUG */
823 our_pred->p_type = UNI_OP;
824 our_pred->p_prec = NEGATE_PREC;
825 our_pred->need_stat = false;
826 return (true);
829 static boolean
830 parse_newer (argv, arg_ptr)
831 char *argv[];
832 int *arg_ptr;
834 struct predicate *our_pred;
835 struct stat stat_newer;
837 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
838 return (false);
839 if ((*xstat) (argv[*arg_ptr], &stat_newer))
840 error (1, errno, "%s", argv[*arg_ptr]);
841 our_pred = insert_primary (pred_newer);
842 our_pred->args.time = stat_newer.st_mtime;
843 (*arg_ptr)++;
844 return (true);
847 static boolean
848 parse_noleaf (argv, arg_ptr)
849 char *argv[];
850 int *arg_ptr;
852 no_leaf_check = true;
853 return true;
856 #ifdef CACHE_IDS
857 /* Arbitrary amount by which to increase size
858 of `uid_unused' and `gid_unused'. */
859 #define ALLOC_STEP 2048
861 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
862 char *uid_unused = NULL;
864 /* Number of elements in `uid_unused'. */
865 unsigned uid_allocated;
867 /* Similar for GIDs and group entries. */
868 char *gid_unused = NULL;
869 unsigned gid_allocated;
870 #endif
872 static boolean
873 parse_nogroup (argv, arg_ptr)
874 char *argv[];
875 int *arg_ptr;
877 struct predicate *our_pred;
879 our_pred = insert_primary (pred_nogroup);
880 #ifdef CACHE_IDS
881 if (gid_unused == NULL)
883 struct group *gr;
885 gid_allocated = ALLOC_STEP;
886 gid_unused = xmalloc (gid_allocated);
887 memset (gid_unused, 1, gid_allocated);
888 setgrent ();
889 while ((gr = getgrent ()) != NULL)
891 if ((unsigned) gr->gr_gid >= gid_allocated)
893 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
894 gid_unused = xrealloc (gid_unused, new_allocated);
895 memset (gid_unused + gid_allocated, 1,
896 new_allocated - gid_allocated);
897 gid_allocated = new_allocated;
899 gid_unused[(unsigned) gr->gr_gid] = 0;
901 endgrent ();
903 #endif
904 return (true);
907 static boolean
908 parse_nouser (argv, arg_ptr)
909 char *argv[];
910 int *arg_ptr;
912 struct predicate *our_pred;
914 our_pred = insert_primary (pred_nouser);
915 #ifdef CACHE_IDS
916 if (uid_unused == NULL)
918 struct passwd *pw;
920 uid_allocated = ALLOC_STEP;
921 uid_unused = xmalloc (uid_allocated);
922 memset (uid_unused, 1, uid_allocated);
923 setpwent ();
924 while ((pw = getpwent ()) != NULL)
926 if ((unsigned) pw->pw_uid >= uid_allocated)
928 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
929 uid_unused = xrealloc (uid_unused, new_allocated);
930 memset (uid_unused + uid_allocated, 1,
931 new_allocated - uid_allocated);
932 uid_allocated = new_allocated;
934 uid_unused[(unsigned) pw->pw_uid] = 0;
936 endpwent ();
938 #endif
939 return (true);
942 static boolean
943 parse_ok (argv, arg_ptr)
944 char *argv[];
945 int *arg_ptr;
947 return (insert_exec_ok (pred_ok, argv, arg_ptr));
950 boolean
951 parse_open (argv, arg_ptr)
952 char *argv[];
953 int *arg_ptr;
955 struct predicate *our_pred;
957 our_pred = get_new_pred_chk_op ();
958 our_pred->pred_func = pred_open;
959 #ifdef DEBUG
960 our_pred->p_name = find_pred_name (pred_open);
961 #endif /* DEBUG */
962 our_pred->p_type = OPEN_PAREN;
963 our_pred->p_prec = NO_PREC;
964 our_pred->need_stat = false;
965 return (true);
968 static boolean
969 parse_or (argv, arg_ptr)
970 char *argv[];
971 int *arg_ptr;
973 struct predicate *our_pred;
975 our_pred = get_new_pred ();
976 our_pred->pred_func = pred_or;
977 #ifdef DEBUG
978 our_pred->p_name = find_pred_name (pred_or);
979 #endif /* DEBUG */
980 our_pred->p_type = BI_OP;
981 our_pred->p_prec = OR_PREC;
982 our_pred->need_stat = false;
983 return (true);
986 static boolean
987 parse_path (argv, arg_ptr)
988 char *argv[];
989 int *arg_ptr;
991 struct predicate *our_pred;
993 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
994 return (false);
995 our_pred = insert_primary (pred_path);
996 our_pred->need_stat = false;
997 our_pred->args.str = argv[*arg_ptr];
998 (*arg_ptr)++;
999 return (true);
1002 static boolean
1003 parse_perm (argv, arg_ptr)
1004 char *argv[];
1005 int *arg_ptr;
1007 unsigned long perm_val;
1008 int mode_start = 0;
1009 struct mode_change *change;
1010 struct predicate *our_pred;
1012 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1013 return (false);
1015 switch (argv[*arg_ptr][0])
1017 case '-':
1018 case '+':
1019 mode_start = 1;
1020 break;
1021 default:
1022 /* empty */
1023 break;
1026 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1027 if (change == MODE_INVALID)
1028 error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
1029 else if (change == MODE_MEMORY_EXHAUSTED)
1030 error (1, 0, "virtual memory exhausted");
1031 perm_val = mode_adjust (0, change);
1032 mode_free (change);
1034 our_pred = insert_primary (pred_perm);
1036 switch (argv[*arg_ptr][0])
1038 case '-':
1039 /* Set magic flag to indicate true if at least the given bits are set. */
1040 our_pred->args.perm = (perm_val & 07777) | 010000;
1041 break;
1042 case '+':
1043 /* Set magic flag to indicate true if any of the given bits are set. */
1044 our_pred->args.perm = (perm_val & 07777) | 020000;
1045 break;
1046 default:
1047 /* True if exactly the given bits are set. */
1048 our_pred->args.perm = (perm_val & 07777);
1049 break;
1051 (*arg_ptr)++;
1052 return (true);
1055 boolean
1056 parse_print (argv, arg_ptr)
1057 char *argv[];
1058 int *arg_ptr;
1060 struct predicate *our_pred;
1062 our_pred = insert_primary (pred_print);
1063 /* -print has the side effect of printing. This prevents us
1064 from doing undesired multiple printing when the user has
1065 already specified -print. */
1066 our_pred->side_effects = true;
1067 our_pred->need_stat = false;
1068 return (true);
1071 static boolean
1072 parse_print0 (argv, arg_ptr)
1073 char *argv[];
1074 int *arg_ptr;
1076 struct predicate *our_pred;
1078 our_pred = insert_primary (pred_print0);
1079 /* -print0 has the side effect of printing. This prevents us
1080 from doing undesired multiple printing when the user has
1081 already specified -print0. */
1082 our_pred->side_effects = true;
1083 our_pred->need_stat = false;
1084 return (true);
1087 static boolean
1088 parse_printf (argv, arg_ptr)
1089 char *argv[];
1090 int *arg_ptr;
1092 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1093 return (false);
1094 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1097 static boolean
1098 parse_prune (argv, arg_ptr)
1099 char *argv[];
1100 int *arg_ptr;
1102 struct predicate *our_pred;
1104 our_pred = insert_primary (pred_prune);
1105 our_pred->need_stat = false;
1106 return (true);
1109 static boolean
1110 parse_regex (argv, arg_ptr)
1111 char *argv[];
1112 int *arg_ptr;
1114 return insert_regex (argv, arg_ptr, false);
1117 static boolean
1118 insert_regex (argv, arg_ptr, ignore_case)
1119 char *argv[];
1120 int *arg_ptr;
1121 boolean ignore_case;
1123 struct predicate *our_pred;
1124 struct re_pattern_buffer *re;
1125 const char *error_message;
1127 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1128 return (false);
1129 our_pred = insert_primary (pred_regex);
1130 our_pred->need_stat = false;
1131 re = (struct re_pattern_buffer *)
1132 xmalloc (sizeof (struct re_pattern_buffer));
1133 our_pred->args.regex = re;
1134 re->allocated = 100;
1135 re->buffer = (unsigned char *) xmalloc (re->allocated);
1136 re->fastmap = NULL;
1138 if (ignore_case)
1140 unsigned i;
1142 re->translate = xmalloc (256);
1143 /* Map uppercase characters to corresponding lowercase ones. */
1144 for (i = 0; i < 256; i++)
1145 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1147 else
1148 re->translate = NULL;
1150 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1151 re);
1152 if (error_message)
1153 error (1, 0, "%s", error_message);
1154 (*arg_ptr)++;
1155 return (true);
1158 static boolean
1159 parse_size (argv, arg_ptr)
1160 char *argv[];
1161 int *arg_ptr;
1163 struct predicate *our_pred;
1164 unsigned long num;
1165 enum comparison_type c_type;
1166 int blksize = 512;
1167 int len;
1169 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1170 return (false);
1171 len = strlen (argv[*arg_ptr]);
1172 if (len == 0)
1173 error (1, 0, "invalid null argument to -size");
1174 switch (argv[*arg_ptr][len - 1])
1176 case 'b':
1177 blksize = 512;
1178 argv[*arg_ptr][len - 1] = '\0';
1179 break;
1181 case 'c':
1182 blksize = 1;
1183 argv[*arg_ptr][len - 1] = '\0';
1184 break;
1186 case 'k':
1187 blksize = 1024;
1188 argv[*arg_ptr][len - 1] = '\0';
1189 break;
1191 case 'w':
1192 blksize = 2;
1193 argv[*arg_ptr][len - 1] = '\0';
1194 break;
1196 case '0':
1197 case '1':
1198 case '2':
1199 case '3':
1200 case '4':
1201 case '5':
1202 case '6':
1203 case '7':
1204 case '8':
1205 case '9':
1206 break;
1208 default:
1209 error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
1211 if (!get_num (argv[*arg_ptr], &num, &c_type))
1212 return (false);
1213 our_pred = insert_primary (pred_size);
1214 our_pred->args.size.kind = c_type;
1215 our_pred->args.size.blocksize = blksize;
1216 our_pred->args.size.size = num;
1217 (*arg_ptr)++;
1218 return (true);
1221 static boolean
1222 parse_true (argv, arg_ptr)
1223 char *argv[];
1224 int *arg_ptr;
1226 struct predicate *our_pred;
1228 our_pred = insert_primary (pred_true);
1229 our_pred->need_stat = false;
1230 return (true);
1233 static boolean
1234 parse_type (argv, arg_ptr)
1235 char *argv[];
1236 int *arg_ptr;
1238 return insert_type (argv, arg_ptr, pred_type);
1241 static boolean
1242 parse_uid (argv, arg_ptr)
1243 char *argv[];
1244 int *arg_ptr;
1246 return (insert_num (argv, arg_ptr, pred_uid));
1249 static boolean
1250 parse_used (argv, arg_ptr)
1251 char *argv[];
1252 int *arg_ptr;
1255 struct predicate *our_pred;
1256 unsigned long num_days;
1257 enum comparison_type c_type;
1259 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1260 return (false);
1261 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1262 return (false);
1263 our_pred = insert_primary (pred_used);
1264 our_pred->args.info.kind = c_type;
1265 our_pred->args.info.l_val = num_days * DAYSECS;
1266 (*arg_ptr)++;
1267 return (true);
1270 static boolean
1271 parse_user (argv, arg_ptr)
1272 char *argv[];
1273 int *arg_ptr;
1275 struct passwd *cur_pwd;
1276 struct predicate *our_pred;
1277 uid_t uid;
1278 int uid_len;
1280 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1281 return (false);
1282 cur_pwd = getpwnam (argv[*arg_ptr]);
1283 endpwent ();
1284 if (cur_pwd != NULL)
1285 uid = cur_pwd->pw_uid;
1286 else
1288 uid_len = strspn (argv[*arg_ptr], "0123456789");
1289 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1290 return (false);
1291 uid = atoi (argv[*arg_ptr]);
1293 our_pred = insert_primary (pred_user);
1294 our_pred->args.uid = uid;
1295 (*arg_ptr)++;
1296 return (true);
1299 static boolean
1300 parse_version (argv, arg_ptr)
1301 char *argv[];
1302 int *arg_ptr;
1304 extern char *version_string;
1306 fflush (stderr);
1307 printf ("GNU find version %s\n", version_string);
1308 exit (0);
1311 static boolean
1312 parse_xdev (argv, arg_ptr)
1313 char *argv[];
1314 int *arg_ptr;
1316 stay_on_filesystem = true;
1317 return true;
1320 static boolean
1321 parse_xtype (argv, arg_ptr)
1322 char *argv[];
1323 int *arg_ptr;
1325 return insert_type (argv, arg_ptr, pred_xtype);
1328 static boolean
1329 insert_type (argv, arg_ptr, which_pred)
1330 char *argv[];
1331 int *arg_ptr;
1332 boolean (*which_pred) ();
1334 unsigned long type_cell;
1335 struct predicate *our_pred;
1337 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1338 || (strlen (argv[*arg_ptr]) != 1))
1339 return (false);
1340 switch (argv[*arg_ptr][0])
1342 case 'b': /* block special */
1343 type_cell = S_IFBLK;
1344 break;
1345 case 'c': /* character special */
1346 type_cell = S_IFCHR;
1347 break;
1348 case 'd': /* directory */
1349 type_cell = S_IFDIR;
1350 break;
1351 case 'f': /* regular file */
1352 type_cell = S_IFREG;
1353 break;
1354 #ifdef S_IFLNK
1355 case 'l': /* symbolic link */
1356 type_cell = S_IFLNK;
1357 break;
1358 #endif
1359 #ifdef S_IFIFO
1360 case 'p': /* pipe */
1361 type_cell = S_IFIFO;
1362 break;
1363 #endif
1364 #ifdef S_IFSOCK
1365 case 's': /* socket */
1366 type_cell = S_IFSOCK;
1367 break;
1368 #endif
1369 default: /* None of the above ... nuke 'em. */
1370 return (false);
1372 our_pred = insert_primary (which_pred);
1373 our_pred->args.type = type_cell;
1374 (*arg_ptr)++; /* Move on to next argument. */
1375 return (true);
1378 /* If true, we've determined that the current fprintf predicate
1379 uses stat information. */
1380 static boolean fprintf_stat_needed;
1382 static boolean
1383 insert_fprintf (fp, func, argv, arg_ptr)
1384 FILE *fp;
1385 boolean (*func) ();
1386 char *argv[];
1387 int *arg_ptr;
1389 char *format; /* Beginning of unprocessed format string. */
1390 register char *scan; /* Current address in scanning `format'. */
1391 register char *scan2; /* Address inside of element being scanned. */
1392 struct segment **segmentp; /* Address of current segment. */
1393 struct predicate *our_pred;
1395 format = argv[(*arg_ptr)++];
1397 fprintf_stat_needed = false; /* Might be overridden later. */
1398 our_pred = insert_primary (func);
1399 our_pred->side_effects = true;
1400 our_pred->args.printf_vec.stream = fp;
1401 segmentp = &our_pred->args.printf_vec.segment;
1402 *segmentp = NULL;
1404 for (scan = format; *scan; scan++)
1406 if (*scan == '\\')
1408 scan2 = scan + 1;
1409 if (*scan2 >= '0' && *scan2 <= '7')
1411 register int n, i;
1413 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1414 i++, scan2++)
1415 n = 8 * n + *scan2 - '0';
1416 scan2--;
1417 *scan = n;
1419 else
1421 switch (*scan2)
1423 case 'a':
1424 *scan = 7;
1425 break;
1426 case 'b':
1427 *scan = '\b';
1428 break;
1429 case 'c':
1430 make_segment (segmentp, format, scan - format, KIND_STOP);
1431 our_pred->need_stat = fprintf_stat_needed;
1432 return (true);
1433 case 'f':
1434 *scan = '\f';
1435 break;
1436 case 'n':
1437 *scan = '\n';
1438 break;
1439 case 'r':
1440 *scan = '\r';
1441 break;
1442 case 't':
1443 *scan = '\t';
1444 break;
1445 case 'v':
1446 *scan = '\v';
1447 break;
1448 case '\\':
1449 /* *scan = '\\'; * it already is */
1450 break;
1451 default:
1452 error (0, 0, "warning: unrecognized escape `\\%c'", *scan2);
1453 scan++;
1454 continue;
1457 segmentp = make_segment (segmentp, format, scan - format + 1,
1458 KIND_PLAIN);
1459 format = scan2 + 1; /* Move past the escape. */
1460 scan = scan2; /* Incremented immediately by `for'. */
1462 else if (*scan == '%')
1464 if (scan[1] == '%')
1466 segmentp = make_segment (segmentp, format, scan - format + 1,
1467 KIND_PLAIN);
1468 scan++;
1469 format = scan + 1;
1470 continue;
1472 /* Scan past flags, width and precision, to verify kind. */
1473 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1474 /* Do nothing. */ ;
1475 while (ISDIGIT (*scan2))
1476 scan2++;
1477 if (*scan2 == '.')
1478 for (scan2++; ISDIGIT (*scan2); scan2++)
1479 /* Do nothing. */ ;
1480 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1482 segmentp = make_segment (segmentp, format, scan2 - format,
1483 (int) *scan2);
1484 scan = scan2;
1485 format = scan + 1;
1487 else if (strchr ("ACT", *scan2) && scan2[1])
1489 segmentp = make_segment (segmentp, format, scan2 - format,
1490 *scan2 | (scan2[1] << 8));
1491 scan = scan2 + 1;
1492 format = scan + 1;
1493 continue;
1495 else
1497 /* An unrecognized % escape. Print the char after the %. */
1498 error (0, 0, "warning: unrecognized format directive `%%%c'",
1499 *scan2);
1500 segmentp = make_segment (segmentp, format, scan - format,
1501 KIND_PLAIN);
1502 format = scan + 1;
1503 continue;
1508 if (scan > format)
1509 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1510 our_pred->need_stat = fprintf_stat_needed;
1511 return (true);
1514 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1515 from the text in FORMAT, which has length LEN.
1516 Return the address of the `next' pointer of the new segment. */
1518 static struct segment **
1519 make_segment (segment, format, len, kind)
1520 struct segment **segment;
1521 char *format;
1522 int len, kind;
1524 char *fmt;
1526 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1528 (*segment)->kind = kind;
1529 (*segment)->next = NULL;
1530 (*segment)->text_len = len;
1532 fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */
1533 strncpy (fmt, format, len);
1534 fmt += len;
1536 switch (kind & 0xff)
1538 case KIND_PLAIN: /* Plain text string, no % conversion. */
1539 case KIND_STOP: /* Terminate argument, no newline. */
1540 break;
1542 case 'a': /* atime in `ctime' format */
1543 case 'c': /* ctime in `ctime' format */
1544 case 'F': /* filesystem type */
1545 case 'g': /* group name */
1546 case 'l': /* object of symlink */
1547 case 't': /* mtime in `ctime' format */
1548 case 'u': /* user name */
1549 case 'A': /* atime in user-specified strftime format */
1550 case 'C': /* ctime in user-specified strftime format */
1551 case 'T': /* mtime in user-specified strftime format */
1552 fprintf_stat_needed = true;
1553 /* FALLTHROUGH */
1554 case 'f': /* basename of path */
1555 case 'h': /* leading directories part of path */
1556 case 'H': /* ARGV element file was found under */
1557 case 'p': /* pathname */
1558 case 'P': /* pathname with ARGV element stripped */
1559 *fmt++ = 's';
1560 break;
1562 case 'b': /* size in 512-byte blocks */
1563 case 'k': /* size in 1K blocks */
1564 case 's': /* size in bytes */
1565 *fmt++ = 'l';
1566 /*FALLTHROUGH*/
1567 case 'n': /* number of links */
1568 fprintf_stat_needed = true;
1569 /* FALLTHROUGH */
1570 case 'd': /* depth in search tree (0 = ARGV element) */
1571 *fmt++ = 'd';
1572 break;
1574 case 'i': /* inode number */
1575 *fmt++ = 'l';
1576 /*FALLTHROUGH*/
1577 case 'G': /* GID number */
1578 case 'U': /* UID number */
1579 *fmt++ = 'u';
1580 fprintf_stat_needed = true;
1581 break;
1583 case 'm': /* mode as octal number (perms only) */
1584 *fmt++ = 'o';
1585 fprintf_stat_needed = true;
1586 break;
1588 *fmt = '\0';
1590 return (&(*segment)->next);
1593 static boolean
1594 insert_exec_ok (func, argv, arg_ptr)
1595 boolean (*func) ();
1596 char *argv[];
1597 int *arg_ptr;
1599 int start, end; /* Indexes in ARGV of start & end of cmd. */
1600 int num_paths; /* Number of args with path replacements. */
1601 int path_pos; /* Index in array of path replacements. */
1602 int vec_pos; /* Index in array of args. */
1603 struct predicate *our_pred;
1604 struct exec_val *execp; /* Pointer for efficiency. */
1606 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1607 return (false);
1609 /* Count the number of args with path replacements, up until the ';'. */
1610 start = *arg_ptr;
1611 for (end = start, num_paths = 0;
1612 (argv[end] != NULL)
1613 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1614 end++)
1615 if (strstr (argv[end], "{}"))
1616 num_paths++;
1617 /* Fail if no command given or no semicolon found. */
1618 if ((end == start) || (argv[end] == NULL))
1620 *arg_ptr = end;
1621 return (false);
1624 our_pred = insert_primary (func);
1625 our_pred->side_effects = true;
1626 execp = &our_pred->args.exec_vec;
1627 execp->paths =
1628 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1629 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1630 /* Record the positions of all args, and the args with path replacements. */
1631 for (end = start, path_pos = vec_pos = 0;
1632 (argv[end] != NULL)
1633 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1634 end++)
1636 register char *p;
1638 execp->paths[path_pos].count = 0;
1639 for (p = argv[end]; *p; ++p)
1640 if (p[0] == '{' && p[1] == '}')
1642 execp->paths[path_pos].count++;
1643 ++p;
1645 if (execp->paths[path_pos].count)
1647 execp->paths[path_pos].offset = vec_pos;
1648 execp->paths[path_pos].origarg = argv[end];
1649 path_pos++;
1651 execp->vec[vec_pos++] = argv[end];
1653 execp->paths[path_pos].offset = -1;
1654 execp->vec[vec_pos] = NULL;
1656 if (argv[end] == NULL)
1657 *arg_ptr = end;
1658 else
1659 *arg_ptr = end + 1;
1660 return (true);
1663 /* Get a number of days and comparison type.
1664 STR is the ASCII representation.
1665 Set *NUM_DAYS to the number of days, taken as being from
1666 the current moment (or possibly midnight). Thus the sense of the
1667 comparison type appears to be reversed.
1668 Set *COMP_TYPE to the kind of comparison that is requested.
1670 Return true if all okay, false if input error.
1672 Used by -atime, -ctime and -mtime (parsers) to
1673 get the appropriate information for a time predicate processor. */
1675 static boolean
1676 get_num_days (str, num_days, comp_type)
1677 char *str;
1678 unsigned long *num_days;
1679 enum comparison_type *comp_type;
1681 int len_days; /* length of field */
1683 if (str == NULL)
1684 return (false);
1685 switch (str[0])
1687 case '+':
1688 *comp_type = COMP_LT;
1689 str++;
1690 break;
1691 case '-':
1692 *comp_type = COMP_GT;
1693 str++;
1694 break;
1695 case '0':
1696 case '1':
1697 case '2':
1698 case '3':
1699 case '4':
1700 case '5':
1701 case '6':
1702 case '7':
1703 case '8':
1704 case '9':
1705 *comp_type = COMP_EQ;
1706 break;
1707 default:
1708 return (false);
1711 /* We know the first char has been reasonable. Find the
1712 number of days to play with. */
1713 len_days = strspn (str, "0123456789");
1714 if ((len_days == 0) || (str[len_days] != '\0'))
1715 return (false);
1716 *num_days = (unsigned long) atol (str);
1717 return (true);
1720 /* Insert a time predicate PRED.
1721 ARGV is a pointer to the argument array.
1722 ARG_PTR is a pointer to an index into the array, incremented if
1723 all went well.
1725 Return true if input is valid, false if not.
1727 A new predicate node is assigned, along with an argument node
1728 obtained with malloc.
1730 Used by -atime, -ctime, and -mtime parsers. */
1732 static boolean
1733 insert_time (argv, arg_ptr, pred)
1734 char *argv[];
1735 int *arg_ptr;
1736 PFB pred;
1738 struct predicate *our_pred;
1739 unsigned long num_days;
1740 enum comparison_type c_type;
1742 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1743 return (false);
1744 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1745 return (false);
1746 our_pred = insert_primary (pred);
1747 our_pred->args.info.kind = c_type;
1748 our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
1749 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
1750 (*arg_ptr)++;
1751 #ifdef DEBUG
1752 printf ("inserting %s\n", our_pred->p_name);
1753 printf (" type: %s %s ",
1754 (c_type == COMP_GT) ? "gt" :
1755 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1756 (c_type == COMP_GT) ? " >" :
1757 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1758 printf ("%ld %s", our_pred->args.info.l_val,
1759 ctime (&our_pred->args.info.l_val));
1760 if (c_type == COMP_EQ)
1762 our_pred->args.info.l_val += DAYSECS;
1763 printf (" < %ld %s", our_pred->args.info.l_val,
1764 ctime (&our_pred->args.info.l_val));
1765 our_pred->args.info.l_val -= DAYSECS;
1767 #endif /* DEBUG */
1768 return (true);
1771 /* Get a number with comparision information.
1772 The sense of the comparision information is 'normal'; that is,
1773 '+' looks for inums or links > than the number and '-' less than.
1775 STR is the ASCII representation of the number.
1776 Set *NUM to the number.
1777 Set *COMP_TYPE to the kind of comparison that is requested.
1779 Return true if all okay, false if input error.
1781 Used by the -inum and -links predicate parsers. */
1783 static boolean
1784 get_num (str, num, comp_type)
1785 char *str;
1786 unsigned long *num;
1787 enum comparison_type *comp_type;
1789 int len_num; /* Length of field. */
1791 if (str == NULL)
1792 return (false);
1793 switch (str[0])
1795 case '+':
1796 *comp_type = COMP_GT;
1797 str++;
1798 break;
1799 case '-':
1800 *comp_type = COMP_LT;
1801 str++;
1802 break;
1803 case '0':
1804 case '1':
1805 case '2':
1806 case '3':
1807 case '4':
1808 case '5':
1809 case '6':
1810 case '7':
1811 case '8':
1812 case '9':
1813 *comp_type = COMP_EQ;
1814 break;
1815 default:
1816 return (false);
1819 /* We know the first char has been reasonable. Find the number of
1820 days to play with. */
1821 len_num = strspn (str, "0123456789");
1822 if ((len_num == 0) || (str[len_num] != '\0'))
1823 return (false);
1824 *num = (unsigned long) atol (str);
1825 return (true);
1828 /* Insert a number predicate.
1829 ARGV is a pointer to the argument array.
1830 *ARG_PTR is an index into ARGV, incremented if all went well.
1831 *PRED is the predicate processor to insert.
1833 Return true if input is valid, false if error.
1835 A new predicate node is assigned, along with an argument node
1836 obtained with malloc.
1838 Used by -inum and -links parsers. */
1840 static boolean
1841 insert_num (argv, arg_ptr, pred)
1842 char *argv[];
1843 int *arg_ptr;
1844 PFB pred;
1846 struct predicate *our_pred;
1847 unsigned long num;
1848 enum comparison_type c_type;
1850 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1851 return (false);
1852 if (!get_num (argv[*arg_ptr], &num, &c_type))
1853 return (false);
1854 our_pred = insert_primary (pred);
1855 our_pred->args.info.kind = c_type;
1856 our_pred->args.info.l_val = num;
1857 (*arg_ptr)++;
1858 #ifdef DEBUG
1859 printf ("inserting %s\n", our_pred->p_name);
1860 printf (" type: %s %s ",
1861 (c_type == COMP_GT) ? "gt" :
1862 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1863 (c_type == COMP_GT) ? " >" :
1864 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1865 printf ("%ld\n", our_pred->args.info.l_val);
1866 #endif /* DEBUG */
1867 return (true);
1870 static FILE *
1871 open_output_file (path)
1872 char *path;
1874 FILE *f;
1876 if (!strcmp (path, "/dev/stderr"))
1877 return (stderr);
1878 else if (!strcmp (path, "/dev/stdout"))
1879 return (stdout);
1880 f = fopen (path, "w");
1881 if (f == NULL)
1882 error (1, errno, "%s", path);
1883 return (f);