Use gnulib-tool --import to import the gnulib code, rather than the odd way we were...
[findutils.git] / find / parser.c
blob34946cb40c41e72fd7257333fffbc4386225f434
1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.
20 #define _GNU_SOURCE
21 #include "defs.h"
22 #include <ctype.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <fnmatch.h>
26 #include "../gnulib/lib/modechange.h"
27 #include "modetype.h"
28 #include "../gnulib/lib/xstrtol.h"
31 #if ENABLE_NLS
32 # include <libintl.h>
33 # define _(Text) gettext (Text)
34 #else
35 # define _(Text) Text
36 #endif
37 #ifdef gettext_noop
38 # define N_(String) gettext_noop (String)
39 #else
40 /* See locate.c for explanation as to why not use (String) */
41 # define N_(String) String
42 #endif
44 #if !defined (isascii) || defined (STDC_HEADERS)
45 #ifdef isascii
46 #undef isascii
47 #endif
48 #define isascii(c) 1
49 #endif
51 #define ISDIGIT(c) (isascii (c) && isdigit (c))
52 #define ISUPPER(c) (isascii (c) && isupper (c))
54 #ifndef HAVE_ENDGRENT
55 #define endgrent()
56 #endif
57 #ifndef HAVE_ENDPWENT
58 #define endpwent()
59 #endif
61 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
62 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
64 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
65 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_iwholename PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
97 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
99 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
100 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
101 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
103 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
104 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
106 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
107 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
108 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
109 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
110 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
112 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
113 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
114 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
115 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
116 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
117 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
118 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
119 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
120 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
121 static boolean parse_wholename PARAMS((char *argv[], int *arg_ptr));
122 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
123 static boolean parse_ignore_race PARAMS((char *argv[], int *arg_ptr));
124 static boolean parse_noignore_race PARAMS((char *argv[], int *arg_ptr));
125 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
127 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
128 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
129 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
130 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
131 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
132 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
133 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
134 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
135 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
136 static FILE *open_output_file PARAMS((char *path));
138 #ifdef DEBUG
139 char *find_pred_name PARAMS((PFB pred_func));
140 #endif /* DEBUG */
142 struct parser_table
144 char *parser_name;
145 PFB parser_func;
148 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
149 If they are in some Unix versions of find, they are marked `Unix'. */
151 static struct parser_table const parse_table[] =
153 {"!", parse_negate},
154 {"not", parse_negate}, /* GNU */
155 {"(", parse_open},
156 {")", parse_close},
157 {",", parse_comma}, /* GNU */
158 {"a", parse_and},
159 {"amin", parse_amin}, /* GNU */
160 {"and", parse_and}, /* GNU */
161 {"anewer", parse_anewer}, /* GNU */
162 {"atime", parse_atime},
163 {"cmin", parse_cmin}, /* GNU */
164 {"cnewer", parse_cnewer}, /* GNU */
165 #ifdef UNIMPLEMENTED_UNIX
166 /* It's pretty ugly for find to know about archive formats.
167 Plus what it could do with cpio archives is very limited.
168 Better to leave it out. */
169 {"cpio", parse_cpio}, /* Unix */
170 #endif
171 {"ctime", parse_ctime},
172 {"daystart", parse_daystart}, /* GNU */
173 {"depth", parse_depth},
174 {"empty", parse_empty}, /* GNU */
175 {"exec", parse_exec},
176 {"false", parse_false}, /* GNU */
177 {"fls", parse_fls}, /* GNU */
178 {"follow", parse_follow}, /* GNU, Unix */
179 {"fprint", parse_fprint}, /* GNU */
180 {"fprint0", parse_fprint0}, /* GNU */
181 {"fprintf", parse_fprintf}, /* GNU */
182 {"fstype", parse_fstype}, /* GNU, Unix */
183 {"gid", parse_gid}, /* GNU */
184 {"group", parse_group},
185 {"help", parse_help}, /* GNU */
186 {"-help", parse_help}, /* GNU */
187 {"ignore_readdir_race", parse_ignore_race}, /* GNU */
188 {"ilname", parse_ilname}, /* GNU */
189 {"iname", parse_iname}, /* GNU */
190 {"inum", parse_inum}, /* GNU, Unix */
191 {"ipath", parse_ipath}, /* GNU, deprecated in favour of iwholename */
192 {"iregex", parse_iregex}, /* GNU */
193 {"iwholename", parse_iwholename}, /* GNU */
194 {"links", parse_links},
195 {"lname", parse_lname}, /* GNU */
196 {"ls", parse_ls}, /* GNU, Unix */
197 {"maxdepth", parse_maxdepth}, /* GNU */
198 {"mindepth", parse_mindepth}, /* GNU */
199 {"mmin", parse_mmin}, /* GNU */
200 {"mount", parse_xdev}, /* Unix */
201 {"mtime", parse_mtime},
202 {"name", parse_name},
203 #ifdef UNIMPLEMENTED_UNIX
204 {"ncpio", parse_ncpio}, /* Unix */
205 #endif
206 {"newer", parse_newer},
207 {"noleaf", parse_noleaf}, /* GNU */
208 {"nogroup", parse_nogroup},
209 {"nouser", parse_nouser},
210 {"noignore_readdir_race", parse_noignore_race}, /* GNU */
211 {"o", parse_or},
212 {"or", parse_or}, /* GNU */
213 {"ok", parse_ok},
214 {"path", parse_path}, /* GNU, HP-UX, GNU prefers wholename */
215 {"perm", parse_perm},
216 {"print", parse_print},
217 {"print0", parse_print0}, /* GNU */
218 {"printf", parse_printf}, /* GNU */
219 {"prune", parse_prune},
220 {"regex", parse_regex}, /* GNU */
221 {"size", parse_size},
222 {"true", parse_true}, /* GNU */
223 {"type", parse_type},
224 {"uid", parse_uid}, /* GNU */
225 {"used", parse_used}, /* GNU */
226 {"user", parse_user},
227 {"version", parse_version}, /* GNU */
228 {"-version", parse_version}, /* GNU */
229 {"wholename", parse_wholename}, /* GNU, replaces -path */
231 {"xdev", parse_xdev},
232 {"xtype", parse_xtype}, /* GNU */
233 {0, 0}
236 /* Return a pointer to the parser function to invoke for predicate
237 SEARCH_NAME.
238 Return NULL if SEARCH_NAME is not a valid predicate name. */
241 find_parser (char *search_name)
243 int i;
245 if (*search_name == '-')
246 search_name++;
247 for (i = 0; parse_table[i].parser_name != 0; i++)
248 if (strcmp (parse_table[i].parser_name, search_name) == 0)
249 return (parse_table[i].parser_func);
250 return (NULL);
253 /* The parsers are responsible to continue scanning ARGV for
254 their arguments. Each parser knows what is and isn't
255 allowed for itself.
257 ARGV is the argument array.
258 *ARG_PTR is the index to start at in ARGV,
259 updated to point beyond the last element consumed.
261 The predicate structure is updated with the new information. */
263 static boolean
264 parse_amin (char **argv, int *arg_ptr)
266 struct predicate *our_pred;
267 uintmax_t num;
268 enum comparison_type c_type;
269 time_t t;
271 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
272 return (false);
273 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
274 return (false);
275 t = cur_day_start + DAYSECS - num * 60;
276 our_pred = insert_primary (pred_amin);
277 our_pred->args.info.kind = c_type;
278 our_pred->args.info.negative = t < 0;
279 our_pred->args.info.l_val = t;
280 (*arg_ptr)++;
281 return (true);
284 static boolean
285 parse_and (char **argv, int *arg_ptr)
287 struct predicate *our_pred;
289 our_pred = get_new_pred ();
290 our_pred->pred_func = pred_and;
291 #ifdef DEBUG
292 our_pred->p_name = find_pred_name (pred_and);
293 #endif /* DEBUG */
294 our_pred->p_type = BI_OP;
295 our_pred->p_prec = AND_PREC;
296 our_pred->need_stat = false;
297 return (true);
300 static boolean
301 parse_anewer (char **argv, int *arg_ptr)
303 struct predicate *our_pred;
304 struct stat stat_newer;
306 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
307 return (false);
308 if ((*xstat) (argv[*arg_ptr], &stat_newer))
309 error (1, errno, "%s", argv[*arg_ptr]);
310 our_pred = insert_primary (pred_anewer);
311 our_pred->args.time = stat_newer.st_mtime;
312 (*arg_ptr)++;
313 return (true);
316 static boolean
317 parse_atime (char **argv, int *arg_ptr)
319 return (insert_time (argv, arg_ptr, pred_atime));
322 boolean
323 parse_close (char **argv, int *arg_ptr)
325 struct predicate *our_pred;
327 our_pred = get_new_pred ();
328 our_pred->pred_func = pred_close;
329 #ifdef DEBUG
330 our_pred->p_name = find_pred_name (pred_close);
331 #endif /* DEBUG */
332 our_pred->p_type = CLOSE_PAREN;
333 our_pred->p_prec = NO_PREC;
334 our_pred->need_stat = false;
335 return (true);
338 static boolean
339 parse_cmin (char **argv, int *arg_ptr)
341 struct predicate *our_pred;
342 uintmax_t num;
343 enum comparison_type c_type;
344 time_t t;
346 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
347 return (false);
348 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
349 return (false);
350 t = cur_day_start + DAYSECS - num * 60;
351 our_pred = insert_primary (pred_cmin);
352 our_pred->args.info.kind = c_type;
353 our_pred->args.info.negative = t < 0;
354 our_pred->args.info.l_val = t;
355 (*arg_ptr)++;
356 return (true);
359 static boolean
360 parse_cnewer (char **argv, int *arg_ptr)
362 struct predicate *our_pred;
363 struct stat stat_newer;
365 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
366 return (false);
367 if ((*xstat) (argv[*arg_ptr], &stat_newer))
368 error (1, errno, "%s", argv[*arg_ptr]);
369 our_pred = insert_primary (pred_cnewer);
370 our_pred->args.time = stat_newer.st_mtime;
371 (*arg_ptr)++;
372 return (true);
375 static boolean
376 parse_comma (char **argv, int *arg_ptr)
378 struct predicate *our_pred;
380 our_pred = get_new_pred ();
381 our_pred->pred_func = pred_comma;
382 #ifdef DEBUG
383 our_pred->p_name = find_pred_name (pred_comma);
384 #endif /* DEBUG */
385 our_pred->p_type = BI_OP;
386 our_pred->p_prec = COMMA_PREC;
387 our_pred->need_stat = false;
388 return (true);
391 static boolean
392 parse_ctime (char **argv, int *arg_ptr)
394 return (insert_time (argv, arg_ptr, pred_ctime));
397 static boolean
398 parse_daystart (char **argv, int *arg_ptr)
400 struct tm *local;
402 if (full_days == false)
404 cur_day_start += DAYSECS;
405 local = localtime (&cur_day_start);
406 cur_day_start -= (local
407 ? (local->tm_sec + local->tm_min * 60
408 + local->tm_hour * 3600)
409 : cur_day_start % DAYSECS);
410 full_days = true;
412 return (true);
415 static boolean
416 parse_depth (char **argv, int *arg_ptr)
418 do_dir_first = false;
419 return (true);
422 static boolean
423 parse_empty (char **argv, int *arg_ptr)
425 insert_primary (pred_empty);
426 return (true);
429 static boolean
430 parse_exec (char **argv, int *arg_ptr)
432 return (insert_exec_ok (pred_exec, argv, arg_ptr));
435 static boolean
436 parse_false (char **argv, int *arg_ptr)
438 struct predicate *our_pred;
440 our_pred = insert_primary (pred_false);
441 our_pred->need_stat = false;
442 return (true);
445 static boolean
446 parse_fls (char **argv, int *arg_ptr)
448 struct predicate *our_pred;
450 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
451 return (false);
452 our_pred = insert_primary (pred_fls);
453 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
454 our_pred->side_effects = true;
455 our_pred->no_default_print = true;
456 (*arg_ptr)++;
457 return (true);
460 static boolean
461 parse_fprintf (char **argv, int *arg_ptr)
463 FILE *fp;
465 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
466 return (false);
467 if (argv[*arg_ptr + 1] == NULL)
469 /* Ensure we get "missing arg" message, not "invalid arg". */
470 (*arg_ptr)++;
471 return (false);
473 fp = open_output_file (argv[*arg_ptr]);
474 (*arg_ptr)++;
475 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
478 static boolean
479 parse_follow (char **argv, int *arg_ptr)
481 dereference = true;
482 xstat = stat;
483 no_leaf_check = true;
484 return (true);
487 static boolean
488 parse_fprint (char **argv, int *arg_ptr)
490 struct predicate *our_pred;
492 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
493 return (false);
494 our_pred = insert_primary (pred_fprint);
495 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
496 our_pred->side_effects = true;
497 our_pred->no_default_print = true;
498 our_pred->need_stat = false;
499 (*arg_ptr)++;
500 return (true);
503 static boolean
504 parse_fprint0 (char **argv, 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_fprint0);
511 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
512 our_pred->side_effects = true;
513 our_pred->no_default_print = true;
514 our_pred->need_stat = false;
515 (*arg_ptr)++;
516 return (true);
519 static boolean
520 parse_fstype (char **argv, int *arg_ptr)
522 struct predicate *our_pred;
524 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
525 return (false);
526 our_pred = insert_primary (pred_fstype);
527 our_pred->args.str = argv[*arg_ptr];
528 (*arg_ptr)++;
529 return (true);
532 static boolean
533 parse_gid (char **argv, int *arg_ptr)
535 return (insert_num (argv, arg_ptr, pred_gid));
538 static boolean
539 parse_group (char **argv, int *arg_ptr)
541 struct group *cur_gr;
542 struct predicate *our_pred;
543 gid_t gid;
544 int gid_len;
546 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
547 return (false);
548 cur_gr = getgrnam (argv[*arg_ptr]);
549 endgrent ();
550 if (cur_gr != NULL)
551 gid = cur_gr->gr_gid;
552 else
554 gid_len = strspn (argv[*arg_ptr], "0123456789");
555 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
556 return (false);
557 gid = atoi (argv[*arg_ptr]);
559 our_pred = insert_primary (pred_group);
560 our_pred->args.gid = gid;
561 (*arg_ptr)++;
562 return (true);
565 static boolean
566 parse_help (char **argv, int *arg_ptr)
568 printf (_("\
569 Usage: %s [path...] [expression]\n"), program_name);
570 puts (_("\
571 default path is the current directory; default expression is -print\n\
572 expression may consist of:\n\
573 operators (decreasing precedence; -and is implicit where no others are given):\n\
574 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
575 puts (_("\
576 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
577 options (always true): -daystart -depth -follow --help\n\
578 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
579 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
580 puts (_("\
581 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
582 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
583 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
584 puts (_("\
585 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
586 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
587 -used N -user NAME -xtype [bcdpfls]\n"));
588 puts (_("\
589 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
590 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
591 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
592 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
593 email to <bug-findutils@gnu.org>."));
594 exit (0);
597 static boolean
598 parse_ilname (char **argv, int *arg_ptr)
600 struct predicate *our_pred;
602 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
603 return (false);
604 our_pred = insert_primary (pred_ilname);
605 our_pred->args.str = argv[*arg_ptr];
606 (*arg_ptr)++;
607 return (true);
611 /* sanity check the fnmatch() function to make sure
612 * it really is the GNU version.
614 static boolean
615 fnmatch_sanitycheck()
617 /* fprintf(stderr, "Performing find sanity check..."); */
618 if (0 != fnmatch("foo", "foo", 0)
619 || 0 == fnmatch("Foo", "foo", 0)
620 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
622 error (1, 0, _("sanity check of the fnmatch() library function failed."));
623 /* fprintf(stderr, "FAILED\n"); */
624 return false;
627 /* fprintf(stderr, "OK\n"); */
628 return true;
633 static boolean
634 parse_iname (char **argv, int *arg_ptr)
636 struct predicate *our_pred;
638 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
639 return (false);
641 fnmatch_sanitycheck();
643 our_pred = insert_primary (pred_iname);
644 our_pred->need_stat = false;
645 our_pred->args.str = argv[*arg_ptr];
646 (*arg_ptr)++;
647 return (true);
650 static boolean
651 parse_inum (char **argv, int *arg_ptr)
653 return (insert_num (argv, arg_ptr, pred_inum));
656 /* -ipath is deprecated (at RMS's request) in favour of
657 * -iwholename. See the node "GNU Manuals" in standards.texi
658 * for the rationale for this (basically, GNU prefers the use
659 * of the phrase "file name" to "path name"
661 static boolean
662 parse_ipath (char **argv, int *arg_ptr)
664 error (0, 0,
665 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
667 return parse_iwholename(argv, arg_ptr);
670 static boolean
671 parse_iwholename (char **argv, int *arg_ptr)
673 struct predicate *our_pred;
675 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
676 return (false);
678 fnmatch_sanitycheck();
680 our_pred = insert_primary (pred_ipath);
681 our_pred->need_stat = false;
682 our_pred->args.str = argv[*arg_ptr];
683 (*arg_ptr)++;
684 return (true);
687 static boolean
688 parse_iregex (char **argv, int *arg_ptr)
690 return insert_regex (argv, arg_ptr, true);
693 static boolean
694 parse_links (char **argv, int *arg_ptr)
696 return (insert_num (argv, arg_ptr, pred_links));
699 static boolean
700 parse_lname (char **argv, int *arg_ptr)
702 struct predicate *our_pred;
704 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
705 return (false);
707 fnmatch_sanitycheck();
709 our_pred = insert_primary (pred_lname);
710 our_pred->args.str = argv[*arg_ptr];
711 (*arg_ptr)++;
712 return (true);
715 static boolean
716 parse_ls (char **argv, int *arg_ptr)
718 struct predicate *our_pred;
720 our_pred = insert_primary (pred_ls);
721 our_pred->side_effects = true;
722 our_pred->no_default_print = true;
723 return (true);
726 static boolean
727 parse_maxdepth (char **argv, int *arg_ptr)
729 int depth_len;
731 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
732 return (false);
733 depth_len = strspn (argv[*arg_ptr], "0123456789");
734 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
735 return (false);
736 maxdepth = atoi (argv[*arg_ptr]);
737 if (maxdepth < 0)
738 return (false);
739 (*arg_ptr)++;
740 return (true);
743 static boolean
744 parse_mindepth (char **argv, int *arg_ptr)
746 int depth_len;
748 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
749 return (false);
750 depth_len = strspn (argv[*arg_ptr], "0123456789");
751 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
752 return (false);
753 mindepth = atoi (argv[*arg_ptr]);
754 if (mindepth < 0)
755 return (false);
756 (*arg_ptr)++;
757 return (true);
760 static boolean
761 parse_mmin (char **argv, int *arg_ptr)
763 struct predicate *our_pred;
764 uintmax_t num;
765 enum comparison_type c_type;
766 time_t t;
768 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
769 return (false);
770 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
771 return (false);
772 t = cur_day_start + DAYSECS - num * 60;
773 our_pred = insert_primary (pred_mmin);
774 our_pred->args.info.kind = c_type;
775 our_pred->args.info.negative = t < 0;
776 our_pred->args.info.l_val = t;
777 (*arg_ptr)++;
778 return (true);
781 static boolean
782 parse_mtime (char **argv, int *arg_ptr)
784 return (insert_time (argv, arg_ptr, pred_mtime));
787 static boolean
788 parse_name (char **argv, int *arg_ptr)
790 struct predicate *our_pred;
792 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
793 return (false);
794 our_pred = insert_primary (pred_name);
795 our_pred->need_stat = false;
796 our_pred->args.str = argv[*arg_ptr];
797 (*arg_ptr)++;
798 return (true);
801 static boolean
802 parse_negate (char **argv, int *arg_ptr)
804 struct predicate *our_pred;
806 our_pred = get_new_pred_chk_op ();
807 our_pred->pred_func = pred_negate;
808 #ifdef DEBUG
809 our_pred->p_name = find_pred_name (pred_negate);
810 #endif /* DEBUG */
811 our_pred->p_type = UNI_OP;
812 our_pred->p_prec = NEGATE_PREC;
813 our_pred->need_stat = false;
814 return (true);
817 static boolean
818 parse_newer (char **argv, int *arg_ptr)
820 struct predicate *our_pred;
821 struct stat stat_newer;
823 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
824 return (false);
825 if ((*xstat) (argv[*arg_ptr], &stat_newer))
826 error (1, errno, "%s", argv[*arg_ptr]);
827 our_pred = insert_primary (pred_newer);
828 our_pred->args.time = stat_newer.st_mtime;
829 (*arg_ptr)++;
830 return (true);
833 static boolean
834 parse_noleaf (char **argv, int *arg_ptr)
836 no_leaf_check = true;
837 return true;
840 #ifdef CACHE_IDS
841 /* Arbitrary amount by which to increase size
842 of `uid_unused' and `gid_unused'. */
843 #define ALLOC_STEP 2048
845 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
846 char *uid_unused = NULL;
848 /* Number of elements in `uid_unused'. */
849 unsigned uid_allocated;
851 /* Similar for GIDs and group entries. */
852 char *gid_unused = NULL;
853 unsigned gid_allocated;
854 #endif
856 static boolean
857 parse_nogroup (char **argv, int *arg_ptr)
859 struct predicate *our_pred;
861 our_pred = insert_primary (pred_nogroup);
862 #ifdef CACHE_IDS
863 if (gid_unused == NULL)
865 struct group *gr;
867 gid_allocated = ALLOC_STEP;
868 gid_unused = xmalloc (gid_allocated);
869 memset (gid_unused, 1, gid_allocated);
870 setgrent ();
871 while ((gr = getgrent ()) != NULL)
873 if ((unsigned) gr->gr_gid >= gid_allocated)
875 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
876 gid_unused = xrealloc (gid_unused, new_allocated);
877 memset (gid_unused + gid_allocated, 1,
878 new_allocated - gid_allocated);
879 gid_allocated = new_allocated;
881 gid_unused[(unsigned) gr->gr_gid] = 0;
883 endgrent ();
885 #endif
886 return (true);
889 static boolean
890 parse_nouser (char **argv, int *arg_ptr)
892 struct predicate *our_pred;
894 our_pred = insert_primary (pred_nouser);
895 #ifdef CACHE_IDS
896 if (uid_unused == NULL)
898 struct passwd *pw;
900 uid_allocated = ALLOC_STEP;
901 uid_unused = xmalloc (uid_allocated);
902 memset (uid_unused, 1, uid_allocated);
903 setpwent ();
904 while ((pw = getpwent ()) != NULL)
906 if ((unsigned) pw->pw_uid >= uid_allocated)
908 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
909 uid_unused = xrealloc (uid_unused, new_allocated);
910 memset (uid_unused + uid_allocated, 1,
911 new_allocated - uid_allocated);
912 uid_allocated = new_allocated;
914 uid_unused[(unsigned) pw->pw_uid] = 0;
916 endpwent ();
918 #endif
919 return (true);
922 static boolean
923 parse_ok (char **argv, int *arg_ptr)
925 return (insert_exec_ok (pred_ok, argv, arg_ptr));
928 boolean
929 parse_open (char **argv, int *arg_ptr)
931 struct predicate *our_pred;
933 our_pred = get_new_pred_chk_op ();
934 our_pred->pred_func = pred_open;
935 #ifdef DEBUG
936 our_pred->p_name = find_pred_name (pred_open);
937 #endif /* DEBUG */
938 our_pred->p_type = OPEN_PAREN;
939 our_pred->p_prec = NO_PREC;
940 our_pred->need_stat = false;
941 return (true);
944 static boolean
945 parse_or (char **argv, int *arg_ptr)
947 struct predicate *our_pred;
949 our_pred = get_new_pred ();
950 our_pred->pred_func = pred_or;
951 #ifdef DEBUG
952 our_pred->p_name = find_pred_name (pred_or);
953 #endif /* DEBUG */
954 our_pred->p_type = BI_OP;
955 our_pred->p_prec = OR_PREC;
956 our_pred->need_stat = false;
957 return (true);
960 /* -path is deprecated (at RMS's request) in favour of
961 * -iwholename. See the node "GNU Manuals" in standards.texi
962 * for the rationale for this (basically, GNU prefers the use
963 * of the phrase "file name" to "path name".
965 * We do not issue a warning that this usage is deprecated
966 * since HPUX find supports this predicate also.
968 static boolean
969 parse_path (char **argv, int *arg_ptr)
971 return parse_wholename(argv, arg_ptr);
974 static boolean
975 parse_wholename (char **argv, int *arg_ptr)
977 struct predicate *our_pred;
979 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
980 return (false);
981 our_pred = insert_primary (pred_path);
982 our_pred->need_stat = false;
983 our_pred->args.str = argv[*arg_ptr];
984 (*arg_ptr)++;
985 return (true);
988 static boolean
989 parse_perm (char **argv, int *arg_ptr)
991 mode_t perm_val;
992 int mode_start = 0;
993 struct mode_change *change;
994 struct predicate *our_pred;
996 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
997 return (false);
999 switch (argv[*arg_ptr][0])
1001 case '-':
1002 case '+':
1003 mode_start = 1;
1004 break;
1005 default:
1006 /* empty */
1007 break;
1010 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1011 if (change == MODE_INVALID)
1012 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1013 else if (change == MODE_MEMORY_EXHAUSTED)
1014 error (1, 0, _("virtual memory exhausted"));
1015 perm_val = mode_adjust (0, change);
1016 mode_free (change);
1018 our_pred = insert_primary (pred_perm);
1020 switch (argv[*arg_ptr][0])
1022 case '-':
1023 our_pred->args.perm.kind = PERM_AT_LEAST;
1024 break;
1025 case '+':
1026 our_pred->args.perm.kind = PERM_ANY;
1027 break;
1028 default:
1029 our_pred->args.perm.kind = PERM_EXACT;
1030 break;
1032 our_pred->args.perm.val = perm_val & MODE_ALL;
1033 (*arg_ptr)++;
1034 return (true);
1037 boolean
1038 parse_print (char **argv, int *arg_ptr)
1040 struct predicate *our_pred;
1042 our_pred = insert_primary (pred_print);
1043 /* -print has the side effect of printing. This prevents us
1044 from doing undesired multiple printing when the user has
1045 already specified -print. */
1046 our_pred->side_effects = true;
1047 our_pred->no_default_print = true;
1048 our_pred->need_stat = false;
1049 return (true);
1052 static boolean
1053 parse_print0 (char **argv, int *arg_ptr)
1055 struct predicate *our_pred;
1057 our_pred = insert_primary (pred_print0);
1058 /* -print0 has the side effect of printing. This prevents us
1059 from doing undesired multiple printing when the user has
1060 already specified -print0. */
1061 our_pred->side_effects = true;
1062 our_pred->no_default_print = true;
1063 our_pred->need_stat = false;
1064 return (true);
1067 static boolean
1068 parse_printf (char **argv, int *arg_ptr)
1070 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1071 return (false);
1072 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1075 static boolean
1076 parse_prune (char **argv, int *arg_ptr)
1078 struct predicate *our_pred;
1080 our_pred = insert_primary (pred_prune);
1081 our_pred->need_stat = false;
1082 /* -prune has a side effect that it does not descend into
1083 the current directory. */
1084 our_pred->side_effects = true;
1085 return (true);
1088 static boolean
1089 parse_regex (char **argv, int *arg_ptr)
1091 return insert_regex (argv, arg_ptr, false);
1094 static boolean
1095 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1097 struct predicate *our_pred;
1098 struct re_pattern_buffer *re;
1099 const char *error_message;
1101 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1102 return (false);
1103 our_pred = insert_primary (pred_regex);
1104 our_pred->need_stat = false;
1105 re = (struct re_pattern_buffer *)
1106 xmalloc (sizeof (struct re_pattern_buffer));
1107 our_pred->args.regex = re;
1108 re->allocated = 100;
1109 re->buffer = (unsigned char *) xmalloc (re->allocated);
1110 re->fastmap = NULL;
1112 if (ignore_case)
1114 unsigned i;
1116 re->translate = xmalloc (256);
1117 /* Map uppercase characters to corresponding lowercase ones. */
1118 for (i = 0; i < 256; i++)
1119 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1121 else
1122 re->translate = NULL;
1124 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1125 re);
1126 if (error_message)
1127 error (1, 0, "%s", error_message);
1128 (*arg_ptr)++;
1129 return (true);
1132 static boolean
1133 parse_size (char **argv, int *arg_ptr)
1135 struct predicate *our_pred;
1136 uintmax_t num;
1137 enum comparison_type c_type;
1138 int blksize = 512;
1139 int len;
1141 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1142 return (false);
1143 len = strlen (argv[*arg_ptr]);
1144 if (len == 0)
1145 error (1, 0, _("invalid null argument to -size"));
1146 switch (argv[*arg_ptr][len - 1])
1148 case 'b':
1149 blksize = 512;
1150 argv[*arg_ptr][len - 1] = '\0';
1151 break;
1153 case 'c':
1154 blksize = 1;
1155 argv[*arg_ptr][len - 1] = '\0';
1156 break;
1158 case 'k':
1159 blksize = 1024;
1160 argv[*arg_ptr][len - 1] = '\0';
1161 break;
1163 case 'M': /* Megabytes */
1164 blksize = 1024*1024;
1165 argv[*arg_ptr][len - 1] = '\0';
1166 break;
1168 case 'G': /* Gigabytes */
1169 blksize = 1024*1024*1024;
1170 argv[*arg_ptr][len - 1] = '\0';
1171 break;
1173 case 'w':
1174 blksize = 2;
1175 argv[*arg_ptr][len - 1] = '\0';
1176 break;
1178 case '0':
1179 case '1':
1180 case '2':
1181 case '3':
1182 case '4':
1183 case '5':
1184 case '6':
1185 case '7':
1186 case '8':
1187 case '9':
1188 break;
1190 default:
1191 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1193 if (!get_num (argv[*arg_ptr], &num, &c_type))
1194 return (false);
1195 our_pred = insert_primary (pred_size);
1196 our_pred->args.size.kind = c_type;
1197 our_pred->args.size.blocksize = blksize;
1198 our_pred->args.size.size = num;
1199 (*arg_ptr)++;
1200 return (true);
1203 static boolean
1204 parse_true (char **argv, int *arg_ptr)
1206 struct predicate *our_pred;
1208 our_pred = insert_primary (pred_true);
1209 our_pred->need_stat = false;
1210 return (true);
1213 static boolean
1214 parse_type (char **argv, int *arg_ptr)
1216 return insert_type (argv, arg_ptr, pred_type);
1219 static boolean
1220 parse_uid (char **argv, int *arg_ptr)
1222 return (insert_num (argv, arg_ptr, pred_uid));
1225 static boolean
1226 parse_used (char **argv, int *arg_ptr)
1228 struct predicate *our_pred;
1229 uintmax_t num_days;
1230 enum comparison_type c_type;
1231 time_t t;
1233 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1234 return (false);
1235 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1236 return (false);
1237 t = num_days * DAYSECS;
1238 our_pred = insert_primary (pred_used);
1239 our_pred->args.info.kind = c_type;
1240 our_pred->args.info.negative = t < 0;
1241 our_pred->args.info.l_val = t;
1242 (*arg_ptr)++;
1243 return (true);
1246 static boolean
1247 parse_user (char **argv, int *arg_ptr)
1249 struct passwd *cur_pwd;
1250 struct predicate *our_pred;
1251 uid_t uid;
1252 int uid_len;
1254 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1255 return (false);
1256 cur_pwd = getpwnam (argv[*arg_ptr]);
1257 endpwent ();
1258 if (cur_pwd != NULL)
1259 uid = cur_pwd->pw_uid;
1260 else
1262 uid_len = strspn (argv[*arg_ptr], "0123456789");
1263 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1264 return (false);
1265 uid = atoi (argv[*arg_ptr]);
1267 our_pred = insert_primary (pred_user);
1268 our_pred->args.uid = uid;
1269 (*arg_ptr)++;
1270 return (true);
1273 static boolean
1274 parse_version (char **argv, int *arg_ptr)
1276 extern char *version_string;
1278 fflush (stderr);
1279 printf (_("GNU find version %s\n"), version_string);
1280 exit (0);
1283 static boolean
1284 parse_xdev (char **argv, int *arg_ptr)
1286 stay_on_filesystem = true;
1287 return true;
1290 static boolean
1291 parse_ignore_race (char **argv, int *arg_ptr)
1293 ignore_readdir_race = true;
1294 return true;
1297 static boolean
1298 parse_noignore_race (char **argv, int *arg_ptr)
1300 ignore_readdir_race = false;
1301 return true;
1304 static boolean
1305 parse_xtype (char **argv, int *arg_ptr)
1307 return insert_type (argv, arg_ptr, pred_xtype);
1310 static boolean
1311 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1313 mode_t type_cell;
1314 struct predicate *our_pred;
1316 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1317 || (strlen (argv[*arg_ptr]) != 1))
1318 return (false);
1319 switch (argv[*arg_ptr][0])
1321 case 'b': /* block special */
1322 type_cell = S_IFBLK;
1323 break;
1324 case 'c': /* character special */
1325 type_cell = S_IFCHR;
1326 break;
1327 case 'd': /* directory */
1328 type_cell = S_IFDIR;
1329 break;
1330 case 'f': /* regular file */
1331 type_cell = S_IFREG;
1332 break;
1333 #ifdef S_IFLNK
1334 case 'l': /* symbolic link */
1335 type_cell = S_IFLNK;
1336 break;
1337 #endif
1338 #ifdef S_IFIFO
1339 case 'p': /* pipe */
1340 type_cell = S_IFIFO;
1341 break;
1342 #endif
1343 #ifdef S_IFSOCK
1344 case 's': /* socket */
1345 type_cell = S_IFSOCK;
1346 break;
1347 #endif
1348 #ifdef S_IFDOOR
1349 case 'D': /* Solaris door */
1350 type_cell = S_IFDOOR;
1351 break;
1352 #endif
1353 default: /* None of the above ... nuke 'em. */
1354 return (false);
1356 our_pred = insert_primary (which_pred);
1357 our_pred->args.type = type_cell;
1358 (*arg_ptr)++; /* Move on to next argument. */
1359 return (true);
1362 /* If true, we've determined that the current fprintf predicate
1363 uses stat information. */
1364 static boolean fprintf_stat_needed;
1366 static boolean
1367 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1369 char *format; /* Beginning of unprocessed format string. */
1370 register char *scan; /* Current address in scanning `format'. */
1371 register char *scan2; /* Address inside of element being scanned. */
1372 struct segment **segmentp; /* Address of current segment. */
1373 struct predicate *our_pred;
1375 format = argv[(*arg_ptr)++];
1377 fprintf_stat_needed = false; /* Might be overridden later. */
1378 our_pred = insert_primary (func);
1379 our_pred->side_effects = true;
1380 our_pred->no_default_print = true;
1381 our_pred->args.printf_vec.stream = fp;
1382 segmentp = &our_pred->args.printf_vec.segment;
1383 *segmentp = NULL;
1385 for (scan = format; *scan; scan++)
1387 if (*scan == '\\')
1389 scan2 = scan + 1;
1390 if (*scan2 >= '0' && *scan2 <= '7')
1392 register int n, i;
1394 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1395 i++, scan2++)
1396 n = 8 * n + *scan2 - '0';
1397 scan2--;
1398 *scan = n;
1400 else
1402 switch (*scan2)
1404 case 'a':
1405 *scan = 7;
1406 break;
1407 case 'b':
1408 *scan = '\b';
1409 break;
1410 case 'c':
1411 make_segment (segmentp, format, scan - format, KIND_STOP);
1412 our_pred->need_stat = fprintf_stat_needed;
1413 return (true);
1414 case 'f':
1415 *scan = '\f';
1416 break;
1417 case 'n':
1418 *scan = '\n';
1419 break;
1420 case 'r':
1421 *scan = '\r';
1422 break;
1423 case 't':
1424 *scan = '\t';
1425 break;
1426 case 'v':
1427 *scan = '\v';
1428 break;
1429 case '\\':
1430 /* *scan = '\\'; * it already is */
1431 break;
1432 default:
1433 error (0, 0,
1434 _("warning: unrecognized escape `\\%c'"), *scan2);
1435 scan++;
1436 continue;
1439 segmentp = make_segment (segmentp, format, scan - format + 1,
1440 KIND_PLAIN);
1441 format = scan2 + 1; /* Move past the escape. */
1442 scan = scan2; /* Incremented immediately by `for'. */
1444 else if (*scan == '%')
1446 if (scan[1] == '%')
1448 segmentp = make_segment (segmentp, format, scan - format + 1,
1449 KIND_PLAIN);
1450 scan++;
1451 format = scan + 1;
1452 continue;
1454 /* Scan past flags, width and precision, to verify kind. */
1455 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1456 /* Do nothing. */ ;
1457 while (ISDIGIT (*scan2))
1458 scan2++;
1459 if (*scan2 == '.')
1460 for (scan2++; ISDIGIT (*scan2); scan2++)
1461 /* Do nothing. */ ;
1462 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1464 segmentp = make_segment (segmentp, format, scan2 - format,
1465 (int) *scan2);
1466 scan = scan2;
1467 format = scan + 1;
1469 else if (strchr ("ACT", *scan2) && scan2[1])
1471 segmentp = make_segment (segmentp, format, scan2 - format,
1472 *scan2 | (scan2[1] << 8));
1473 scan = scan2 + 1;
1474 format = scan + 1;
1475 continue;
1477 else
1479 /* An unrecognized % escape. Print the char after the %. */
1480 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1481 *scan2);
1482 segmentp = make_segment (segmentp, format, scan - format,
1483 KIND_PLAIN);
1484 format = scan + 1;
1485 continue;
1490 if (scan > format)
1491 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1492 our_pred->need_stat = fprintf_stat_needed;
1493 return (true);
1496 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1497 from the text in FORMAT, which has length LEN.
1498 Return the address of the `next' pointer of the new segment. */
1500 static struct segment **
1501 make_segment (struct segment **segment, char *format, int len, int kind)
1503 char *fmt;
1505 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1507 (*segment)->kind = kind;
1508 (*segment)->next = NULL;
1509 (*segment)->text_len = len;
1511 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1512 strncpy (fmt, format, len);
1513 fmt += len;
1515 switch (kind & 0xff)
1517 case KIND_PLAIN: /* Plain text string, no % conversion. */
1518 case KIND_STOP: /* Terminate argument, no newline. */
1519 break;
1521 case 'a': /* atime in `ctime' format */
1522 case 'A': /* atime in user-specified strftime format */
1523 case 'b': /* size in 512-byte blocks */
1524 case 'c': /* ctime in `ctime' format */
1525 case 'C': /* ctime in user-specified strftime format */
1526 case 'F': /* filesystem type */
1527 case 'G': /* GID number */
1528 case 'g': /* group name */
1529 case 'i': /* inode number */
1530 case 'k': /* size in 1K blocks */
1531 case 'l': /* object of symlink */
1532 case 'n': /* number of links */
1533 case 's': /* size in bytes */
1534 case 't': /* mtime in `ctime' format */
1535 case 'T': /* mtime in user-specified strftime format */
1536 case 'U': /* UID number */
1537 case 'u': /* user name */
1538 fprintf_stat_needed = true;
1539 /* FALLTHROUGH */
1540 case 'f': /* basename of path */
1541 case 'h': /* leading directories part of path */
1542 case 'H': /* ARGV element file was found under */
1543 case 'p': /* pathname */
1544 case 'P': /* pathname with ARGV element stripped */
1545 *fmt++ = 's';
1546 break;
1548 case 'd': /* depth in search tree (0 = ARGV element) */
1549 *fmt++ = 'd';
1550 break;
1552 case 'm': /* mode as octal number (perms only) */
1553 *fmt++ = 'o';
1554 fprintf_stat_needed = true;
1555 break;
1557 *fmt = '\0';
1559 return (&(*segment)->next);
1562 /* handles both exec and ok predicate */
1563 static boolean
1564 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1566 int start, end; /* Indexes in ARGV of start & end of cmd. */
1567 int num_paths; /* Number of args with path replacements. */
1568 int path_pos; /* Index in array of path replacements. */
1569 int vec_pos; /* Index in array of args. */
1570 struct predicate *our_pred;
1571 struct exec_val *execp; /* Pointer for efficiency. */
1573 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1574 return (false);
1576 /* Count the number of args with path replacements, up until the ';'. */
1577 start = *arg_ptr;
1578 for (end = start, num_paths = 0;
1579 (argv[end] != NULL)
1580 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1581 end++)
1582 if (strstr (argv[end], "{}"))
1583 num_paths++;
1584 /* Fail if no command given or no semicolon found. */
1585 if ((end == start) || (argv[end] == NULL))
1587 *arg_ptr = end;
1588 return (false);
1591 our_pred = insert_primary (func);
1592 our_pred->side_effects = true;
1593 our_pred->no_default_print = true;
1594 execp = &our_pred->args.exec_vec;
1595 execp->paths =
1596 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1597 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1598 /* Record the positions of all args, and the args with path replacements. */
1599 for (end = start, path_pos = vec_pos = 0;
1600 (argv[end] != NULL)
1601 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1602 end++)
1604 register char *p;
1606 execp->paths[path_pos].count = 0;
1607 for (p = argv[end]; *p; ++p)
1608 if (p[0] == '{' && p[1] == '}')
1610 execp->paths[path_pos].count++;
1611 ++p;
1613 if (execp->paths[path_pos].count)
1615 execp->paths[path_pos].offset = vec_pos;
1616 execp->paths[path_pos].origarg = argv[end];
1617 path_pos++;
1619 execp->vec[vec_pos++] = argv[end];
1621 execp->paths[path_pos].offset = -1;
1622 execp->vec[vec_pos] = NULL;
1624 if (argv[end] == NULL)
1625 *arg_ptr = end;
1626 else
1627 *arg_ptr = end + 1;
1628 return (true);
1631 /* Get a number of days and comparison type.
1632 STR is the ASCII representation.
1633 Set *NUM_DAYS to the number of days, taken as being from
1634 the current moment (or possibly midnight). Thus the sense of the
1635 comparison type appears to be reversed.
1636 Set *COMP_TYPE to the kind of comparison that is requested.
1638 Return true if all okay, false if input error.
1640 Used by -atime, -ctime and -mtime (parsers) to
1641 get the appropriate information for a time predicate processor. */
1643 static boolean
1644 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1646 boolean r = get_num (str, num_days, comp_type);
1647 if (r)
1648 switch (*comp_type)
1650 case COMP_LT: *comp_type = COMP_GT; break;
1651 case COMP_GT: *comp_type = COMP_LT; break;
1652 default: break;
1654 return r;
1657 /* Insert a time predicate PRED.
1658 ARGV is a pointer to the argument array.
1659 ARG_PTR is a pointer to an index into the array, incremented if
1660 all went well.
1662 Return true if input is valid, false if not.
1664 A new predicate node is assigned, along with an argument node
1665 obtained with malloc.
1667 Used by -atime, -ctime, and -mtime parsers. */
1669 static boolean
1670 insert_time (char **argv, int *arg_ptr, PFB pred)
1672 struct predicate *our_pred;
1673 uintmax_t num_days;
1674 enum comparison_type c_type;
1675 time_t t;
1677 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1678 return (false);
1679 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1680 return (false);
1682 /* Figure out the timestamp value we are looking for. */
1683 t = ( cur_day_start - num_days * DAYSECS
1684 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1685 #if 1
1686 if (1)
1688 /* We introduce a scope in which 'val' can be declared, for the
1689 * benefit of compilers that are really C89 compilers
1690 * which support intmax_t because config.h #defines it
1692 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1693 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1694 t = val;
1696 /* Check for possibility of an overflow */
1697 if ( (intmax_t)t != val )
1699 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1702 #endif
1704 our_pred = insert_primary (pred);
1705 our_pred->args.info.kind = c_type;
1706 our_pred->args.info.negative = t < 0;
1707 our_pred->args.info.l_val = t;
1708 (*arg_ptr)++;
1709 #ifdef DEBUG
1710 printf (_("inserting %s\n"), our_pred->p_name);
1711 printf (_(" type: %s %s "),
1712 (c_type == COMP_GT) ? "gt" :
1713 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1714 (c_type == COMP_GT) ? " >" :
1715 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1716 t = our_pred->args.info.l_val;
1717 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1718 if (c_type == COMP_EQ)
1720 t = our_pred->args.info.l_val += DAYSECS;
1721 printf (" < %ju %s",
1722 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1723 our_pred->args.info.l_val -= DAYSECS;
1725 #endif /* DEBUG */
1726 return (true);
1729 /* Get a number with comparision information.
1730 The sense of the comparision information is 'normal'; that is,
1731 '+' looks for a count > than the number and '-' less than.
1733 STR is the ASCII representation of the number.
1734 Set *NUM to the number.
1735 Set *COMP_TYPE to the kind of comparison that is requested.
1737 Return true if all okay, false if input error. */
1739 static boolean
1740 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1742 int len_num; /* Length of field. */
1744 if (str == NULL)
1745 return (false);
1746 switch (str[0])
1748 case '+':
1749 *comp_type = COMP_GT;
1750 str++;
1751 break;
1752 case '-':
1753 *comp_type = COMP_LT;
1754 str++;
1755 break;
1756 default:
1757 *comp_type = COMP_EQ;
1758 break;
1761 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1764 /* Insert a number predicate.
1765 ARGV is a pointer to the argument array.
1766 *ARG_PTR is an index into ARGV, incremented if all went well.
1767 *PRED is the predicate processor to insert.
1769 Return true if input is valid, false if error.
1771 A new predicate node is assigned, along with an argument node
1772 obtained with malloc.
1774 Used by -inum and -links parsers. */
1776 static boolean
1777 insert_num (char **argv, int *arg_ptr, PFB pred)
1779 struct predicate *our_pred;
1780 uintmax_t num;
1781 enum comparison_type c_type;
1783 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1784 return (false);
1785 if (!get_num (argv[*arg_ptr], &num, &c_type))
1786 return (false);
1787 our_pred = insert_primary (pred);
1788 our_pred->args.info.kind = c_type;
1789 our_pred->args.info.l_val = num;
1790 (*arg_ptr)++;
1791 #ifdef DEBUG
1792 printf (_("inserting %s\n"), our_pred->p_name);
1793 printf (_(" type: %s %s "),
1794 (c_type == COMP_GT) ? "gt" :
1795 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1796 (c_type == COMP_GT) ? " >" :
1797 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1798 printf ("%ju\n", our_pred->args.info.l_val);
1799 #endif /* DEBUG */
1800 return (true);
1803 static FILE *
1804 open_output_file (char *path)
1806 FILE *f;
1808 if (!strcmp (path, "/dev/stderr"))
1809 return (stderr);
1810 else if (!strcmp (path, "/dev/stdout"))
1811 return (stdout);
1812 f = fopen (path, "w");
1813 if (f == NULL)
1814 error (1, errno, "%s", path);
1815 return (f);