Fix for compilation (on AIX 4.3) with GCC 2.x.
[findutils.git] / find / parser.c
blobc03230e219bbe88459459ffaaa5c213cb6878e83
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 "modechange.h"
27 #include "modetype.h"
28 #include "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 # define N_(String) (String)
41 #endif
43 #if !defined (isascii) || defined (STDC_HEADERS)
44 #ifdef isascii
45 #undef isascii
46 #endif
47 #define isascii(c) 1
48 #endif
50 #define ISDIGIT(c) (isascii (c) && isdigit (c))
51 #define ISUPPER(c) (isascii (c) && isupper (c))
53 #ifndef HAVE_ENDGRENT
54 #define endgrent()
55 #endif
56 #ifndef HAVE_ENDPWENT
57 #define endpwent()
58 #endif
60 static boolean parse_amin PARAMS((char *argv[], int *arg_ptr));
61 static boolean parse_and PARAMS((char *argv[], int *arg_ptr));
62 static boolean parse_anewer PARAMS((char *argv[], int *arg_ptr));
63 static boolean parse_atime PARAMS((char *argv[], int *arg_ptr));
64 boolean parse_close PARAMS((char *argv[], int *arg_ptr));
65 static boolean parse_cmin PARAMS((char *argv[], int *arg_ptr));
66 static boolean parse_cnewer PARAMS((char *argv[], int *arg_ptr));
67 static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
68 static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
69 static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
70 static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
71 static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
72 static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
73 static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
74 static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
75 static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
76 static boolean parse_follow PARAMS((char *argv[], int *arg_ptr));
77 static boolean parse_fprint PARAMS((char *argv[], int *arg_ptr));
78 static boolean parse_fprint0 PARAMS((char *argv[], int *arg_ptr));
79 static boolean parse_fstype PARAMS((char *argv[], int *arg_ptr));
80 static boolean parse_gid PARAMS((char *argv[], int *arg_ptr));
81 static boolean parse_group PARAMS((char *argv[], int *arg_ptr));
82 static boolean parse_help PARAMS((char *argv[], int *arg_ptr));
83 static boolean parse_ilname PARAMS((char *argv[], int *arg_ptr));
84 static boolean parse_iname PARAMS((char *argv[], int *arg_ptr));
85 static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
86 static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
87 static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
88 static boolean parse_iwholename PARAMS((char *argv[], int *arg_ptr));
89 static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
90 static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
91 static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
92 static boolean parse_maxdepth PARAMS((char *argv[], int *arg_ptr));
93 static boolean parse_mindepth PARAMS((char *argv[], int *arg_ptr));
94 static boolean parse_mmin PARAMS((char *argv[], int *arg_ptr));
95 static boolean parse_mtime PARAMS((char *argv[], int *arg_ptr));
96 static boolean parse_name PARAMS((char *argv[], int *arg_ptr));
97 static boolean parse_negate PARAMS((char *argv[], int *arg_ptr));
98 static boolean parse_newer PARAMS((char *argv[], int *arg_ptr));
99 static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
100 static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
101 static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
102 static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
103 boolean parse_open PARAMS((char *argv[], int *arg_ptr));
104 static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
105 static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
106 static boolean parse_perm PARAMS((char *argv[], int *arg_ptr));
107 boolean parse_print PARAMS((char *argv[], int *arg_ptr));
108 static boolean parse_print0 PARAMS((char *argv[], int *arg_ptr));
109 static boolean parse_printf PARAMS((char *argv[], int *arg_ptr));
110 static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
111 static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
112 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
113 static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
114 static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
115 static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
116 static boolean parse_uid PARAMS((char *argv[], int *arg_ptr));
117 static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
118 static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
119 static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
120 static boolean parse_wholename PARAMS((char *argv[], int *arg_ptr));
121 static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
122 static boolean parse_ignore_race PARAMS((char *argv[], int *arg_ptr));
123 static boolean parse_noignore_race PARAMS((char *argv[], int *arg_ptr));
124 static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
126 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
127 static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
128 static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
129 static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
130 static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
131 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
132 static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
133 static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
134 static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
135 static FILE *open_output_file PARAMS((char *path));
137 #ifdef DEBUG
138 char *find_pred_name PARAMS((PFB pred_func));
139 #endif /* DEBUG */
141 struct parser_table
143 char *parser_name;
144 PFB parser_func;
147 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
148 If they are in some Unix versions of find, they are marked `Unix'. */
150 static struct parser_table const parse_table[] =
152 {"!", parse_negate},
153 {"not", parse_negate}, /* GNU */
154 {"(", parse_open},
155 {")", parse_close},
156 {",", parse_comma}, /* GNU */
157 {"a", parse_and},
158 {"amin", parse_amin}, /* GNU */
159 {"and", parse_and}, /* GNU */
160 {"anewer", parse_anewer}, /* GNU */
161 {"atime", parse_atime},
162 {"cmin", parse_cmin}, /* GNU */
163 {"cnewer", parse_cnewer}, /* GNU */
164 #ifdef UNIMPLEMENTED_UNIX
165 /* It's pretty ugly for find to know about archive formats.
166 Plus what it could do with cpio archives is very limited.
167 Better to leave it out. */
168 {"cpio", parse_cpio}, /* Unix */
169 #endif
170 {"ctime", parse_ctime},
171 {"daystart", parse_daystart}, /* GNU */
172 {"depth", parse_depth},
173 {"empty", parse_empty}, /* GNU */
174 {"exec", parse_exec},
175 {"false", parse_false}, /* GNU */
176 {"fls", parse_fls}, /* GNU */
177 {"follow", parse_follow}, /* GNU, Unix */
178 {"fprint", parse_fprint}, /* GNU */
179 {"fprint0", parse_fprint0}, /* GNU */
180 {"fprintf", parse_fprintf}, /* GNU */
181 {"fstype", parse_fstype}, /* GNU, Unix */
182 {"gid", parse_gid}, /* GNU */
183 {"group", parse_group},
184 {"help", parse_help}, /* GNU */
185 {"-help", parse_help}, /* GNU */
186 {"ignore_readdir_race", parse_ignore_race}, /* GNU */
187 {"ilname", parse_ilname}, /* GNU */
188 {"iname", parse_iname}, /* GNU */
189 {"inum", parse_inum}, /* GNU, Unix */
190 {"ipath", parse_ipath}, /* GNU, deprecated in favour of iwholename */
191 {"iregex", parse_iregex}, /* GNU */
192 {"iwholename", parse_iwholename}, /* GNU */
193 {"links", parse_links},
194 {"lname", parse_lname}, /* GNU */
195 {"ls", parse_ls}, /* GNU, Unix */
196 {"maxdepth", parse_maxdepth}, /* GNU */
197 {"mindepth", parse_mindepth}, /* GNU */
198 {"mmin", parse_mmin}, /* GNU */
199 {"mount", parse_xdev}, /* Unix */
200 {"mtime", parse_mtime},
201 {"name", parse_name},
202 #ifdef UNIMPLEMENTED_UNIX
203 {"ncpio", parse_ncpio}, /* Unix */
204 #endif
205 {"newer", parse_newer},
206 {"noleaf", parse_noleaf}, /* GNU */
207 {"nogroup", parse_nogroup},
208 {"nouser", parse_nouser},
209 {"noignore_readdir_race", parse_noignore_race}, /* GNU */
210 {"o", parse_or},
211 {"or", parse_or}, /* GNU */
212 {"ok", parse_ok},
213 {"path", parse_path}, /* GNU, HP-UX, GNU prefers wholename */
214 {"perm", parse_perm},
215 {"print", parse_print},
216 {"print0", parse_print0}, /* GNU */
217 {"printf", parse_printf}, /* GNU */
218 {"prune", parse_prune},
219 {"regex", parse_regex}, /* GNU */
220 {"size", parse_size},
221 {"true", parse_true}, /* GNU */
222 {"type", parse_type},
223 {"uid", parse_uid}, /* GNU */
224 {"used", parse_used}, /* GNU */
225 {"user", parse_user},
226 {"version", parse_version}, /* GNU */
227 {"-version", parse_version}, /* GNU */
228 {"wholename", parse_wholename}, /* GNU, replaces -path */
230 {"xdev", parse_xdev},
231 {"xtype", parse_xtype}, /* GNU */
232 {0, 0}
235 /* Return a pointer to the parser function to invoke for predicate
236 SEARCH_NAME.
237 Return NULL if SEARCH_NAME is not a valid predicate name. */
240 find_parser (char *search_name)
242 int i;
244 if (*search_name == '-')
245 search_name++;
246 for (i = 0; parse_table[i].parser_name != 0; i++)
247 if (strcmp (parse_table[i].parser_name, search_name) == 0)
248 return (parse_table[i].parser_func);
249 return (NULL);
252 /* The parsers are responsible to continue scanning ARGV for
253 their arguments. Each parser knows what is and isn't
254 allowed for itself.
256 ARGV is the argument array.
257 *ARG_PTR is the index to start at in ARGV,
258 updated to point beyond the last element consumed.
260 The predicate structure is updated with the new information. */
262 static boolean
263 parse_amin (char **argv, int *arg_ptr)
265 struct predicate *our_pred;
266 uintmax_t num;
267 enum comparison_type c_type;
268 time_t t;
270 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
271 return (false);
272 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
273 return (false);
274 t = cur_day_start + DAYSECS - num * 60;
275 our_pred = insert_primary (pred_amin);
276 our_pred->args.info.kind = c_type;
277 our_pred->args.info.negative = t < 0;
278 our_pred->args.info.l_val = t;
279 (*arg_ptr)++;
280 return (true);
283 static boolean
284 parse_and (char **argv, int *arg_ptr)
286 struct predicate *our_pred;
288 our_pred = get_new_pred ();
289 our_pred->pred_func = pred_and;
290 #ifdef DEBUG
291 our_pred->p_name = find_pred_name (pred_and);
292 #endif /* DEBUG */
293 our_pred->p_type = BI_OP;
294 our_pred->p_prec = AND_PREC;
295 our_pred->need_stat = false;
296 return (true);
299 static boolean
300 parse_anewer (char **argv, int *arg_ptr)
302 struct predicate *our_pred;
303 struct stat stat_newer;
305 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
306 return (false);
307 if ((*xstat) (argv[*arg_ptr], &stat_newer))
308 error (1, errno, "%s", argv[*arg_ptr]);
309 our_pred = insert_primary (pred_anewer);
310 our_pred->args.time = stat_newer.st_mtime;
311 (*arg_ptr)++;
312 return (true);
315 static boolean
316 parse_atime (char **argv, int *arg_ptr)
318 return (insert_time (argv, arg_ptr, pred_atime));
321 boolean
322 parse_close (char **argv, int *arg_ptr)
324 struct predicate *our_pred;
326 our_pred = get_new_pred ();
327 our_pred->pred_func = pred_close;
328 #ifdef DEBUG
329 our_pred->p_name = find_pred_name (pred_close);
330 #endif /* DEBUG */
331 our_pred->p_type = CLOSE_PAREN;
332 our_pred->p_prec = NO_PREC;
333 our_pred->need_stat = false;
334 return (true);
337 static boolean
338 parse_cmin (char **argv, int *arg_ptr)
340 struct predicate *our_pred;
341 uintmax_t num;
342 enum comparison_type c_type;
343 time_t t;
345 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
346 return (false);
347 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
348 return (false);
349 t = cur_day_start + DAYSECS - num * 60;
350 our_pred = insert_primary (pred_cmin);
351 our_pred->args.info.kind = c_type;
352 our_pred->args.info.negative = t < 0;
353 our_pred->args.info.l_val = t;
354 (*arg_ptr)++;
355 return (true);
358 static boolean
359 parse_cnewer (char **argv, int *arg_ptr)
361 struct predicate *our_pred;
362 struct stat stat_newer;
364 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
365 return (false);
366 if ((*xstat) (argv[*arg_ptr], &stat_newer))
367 error (1, errno, "%s", argv[*arg_ptr]);
368 our_pred = insert_primary (pred_cnewer);
369 our_pred->args.time = stat_newer.st_mtime;
370 (*arg_ptr)++;
371 return (true);
374 static boolean
375 parse_comma (char **argv, int *arg_ptr)
377 struct predicate *our_pred;
379 our_pred = get_new_pred ();
380 our_pred->pred_func = pred_comma;
381 #ifdef DEBUG
382 our_pred->p_name = find_pred_name (pred_comma);
383 #endif /* DEBUG */
384 our_pred->p_type = BI_OP;
385 our_pred->p_prec = COMMA_PREC;
386 our_pred->need_stat = false;
387 return (true);
390 static boolean
391 parse_ctime (char **argv, int *arg_ptr)
393 return (insert_time (argv, arg_ptr, pred_ctime));
396 static boolean
397 parse_daystart (char **argv, int *arg_ptr)
399 struct tm *local;
401 if (full_days == false)
403 cur_day_start += DAYSECS;
404 local = localtime (&cur_day_start);
405 cur_day_start -= (local
406 ? (local->tm_sec + local->tm_min * 60
407 + local->tm_hour * 3600)
408 : cur_day_start % DAYSECS);
409 full_days = true;
411 return (true);
414 static boolean
415 parse_depth (char **argv, int *arg_ptr)
417 do_dir_first = false;
418 return (true);
421 static boolean
422 parse_empty (char **argv, int *arg_ptr)
424 insert_primary (pred_empty);
425 return (true);
428 static boolean
429 parse_exec (char **argv, int *arg_ptr)
431 return (insert_exec_ok (pred_exec, argv, arg_ptr));
434 static boolean
435 parse_false (char **argv, int *arg_ptr)
437 struct predicate *our_pred;
439 our_pred = insert_primary (pred_false);
440 our_pred->need_stat = false;
441 return (true);
444 static boolean
445 parse_fls (char **argv, int *arg_ptr)
447 struct predicate *our_pred;
449 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
450 return (false);
451 our_pred = insert_primary (pred_fls);
452 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
453 our_pred->side_effects = true;
454 our_pred->no_default_print = true;
455 (*arg_ptr)++;
456 return (true);
459 static boolean
460 parse_fprintf (char **argv, int *arg_ptr)
462 FILE *fp;
464 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
465 return (false);
466 if (argv[*arg_ptr + 1] == NULL)
468 /* Ensure we get "missing arg" message, not "invalid arg". */
469 (*arg_ptr)++;
470 return (false);
472 fp = open_output_file (argv[*arg_ptr]);
473 (*arg_ptr)++;
474 return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
477 static boolean
478 parse_follow (char **argv, int *arg_ptr)
480 dereference = true;
481 xstat = stat;
482 no_leaf_check = true;
483 return (true);
486 static boolean
487 parse_fprint (char **argv, int *arg_ptr)
489 struct predicate *our_pred;
491 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
492 return (false);
493 our_pred = insert_primary (pred_fprint);
494 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
495 our_pred->side_effects = true;
496 our_pred->no_default_print = true;
497 our_pred->need_stat = false;
498 (*arg_ptr)++;
499 return (true);
502 static boolean
503 parse_fprint0 (char **argv, int *arg_ptr)
505 struct predicate *our_pred;
507 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
508 return (false);
509 our_pred = insert_primary (pred_fprint0);
510 our_pred->args.stream = open_output_file (argv[*arg_ptr]);
511 our_pred->side_effects = true;
512 our_pred->no_default_print = true;
513 our_pred->need_stat = false;
514 (*arg_ptr)++;
515 return (true);
518 static boolean
519 parse_fstype (char **argv, int *arg_ptr)
521 struct predicate *our_pred;
523 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
524 return (false);
525 our_pred = insert_primary (pred_fstype);
526 our_pred->args.str = argv[*arg_ptr];
527 (*arg_ptr)++;
528 return (true);
531 static boolean
532 parse_gid (char **argv, int *arg_ptr)
534 return (insert_num (argv, arg_ptr, pred_gid));
537 static boolean
538 parse_group (char **argv, int *arg_ptr)
540 struct group *cur_gr;
541 struct predicate *our_pred;
542 gid_t gid;
543 int gid_len;
545 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
546 return (false);
547 cur_gr = getgrnam (argv[*arg_ptr]);
548 endgrent ();
549 if (cur_gr != NULL)
550 gid = cur_gr->gr_gid;
551 else
553 gid_len = strspn (argv[*arg_ptr], "0123456789");
554 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
555 return (false);
556 gid = atoi (argv[*arg_ptr]);
558 our_pred = insert_primary (pred_group);
559 our_pred->args.gid = gid;
560 (*arg_ptr)++;
561 return (true);
564 static boolean
565 parse_help (char **argv, int *arg_ptr)
567 printf (_("\
568 Usage: %s [path...] [expression]\n"), program_name);
569 puts (_("\
570 default path is the current directory; default expression is -print\n\
571 expression may consist of:\n\
572 operators (decreasing precedence; -and is implicit where no others are given):\n\
573 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
574 puts (_("\
575 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
576 options (always true): -daystart -depth -follow --help\n\
577 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
578 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
579 puts (_("\
580 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
581 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
582 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
583 puts (_("\
584 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
585 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
586 -used N -user NAME -xtype [bcdpfls]\n"));
587 puts (_("\
588 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
589 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
590 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
591 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
592 email to <bug-findutils@gnu.org>."));
593 exit (0);
596 static boolean
597 parse_ilname (char **argv, int *arg_ptr)
599 struct predicate *our_pred;
601 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
602 return (false);
603 our_pred = insert_primary (pred_ilname);
604 our_pred->args.str = argv[*arg_ptr];
605 (*arg_ptr)++;
606 return (true);
610 /* sanity check the fnmatch() function to make sure
611 * it really is the GNU version.
613 static boolean
614 fnmatch_sanitycheck()
616 if (0 != fnmatch("foo", "foo", 0)
617 || 0 == fnmatch("Foo", "foo", 0)
618 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
620 error (1, 0, _("sanity check of the fnmatch() library function failed."));
621 return false;
624 return true;
629 static boolean
630 parse_iname (char **argv, int *arg_ptr)
632 struct predicate *our_pred;
634 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
635 return (false);
637 fnmatch_sanitycheck();
639 our_pred = insert_primary (pred_iname);
640 our_pred->need_stat = false;
641 our_pred->args.str = argv[*arg_ptr];
642 (*arg_ptr)++;
643 return (true);
646 static boolean
647 parse_inum (char **argv, int *arg_ptr)
649 return (insert_num (argv, arg_ptr, pred_inum));
652 /* -ipath is deprecated (at RMS's request) in favour of
653 * -iwholename. See the node "GNU Manuals" in standards.texi
654 * for the rationale for this (basically, GNU prefers the use
655 * of the phrase "file name" to "path name"
657 static boolean
658 parse_ipath (char **argv, int *arg_ptr)
660 error (0, 0,
661 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
663 return parse_iwholename(argv, arg_ptr);
666 static boolean
667 parse_iwholename (char **argv, int *arg_ptr)
669 struct predicate *our_pred;
671 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
672 return (false);
674 fnmatch_sanitycheck();
676 our_pred = insert_primary (pred_ipath);
677 our_pred->need_stat = false;
678 our_pred->args.str = argv[*arg_ptr];
679 (*arg_ptr)++;
680 return (true);
683 static boolean
684 parse_iregex (char **argv, int *arg_ptr)
686 return insert_regex (argv, arg_ptr, true);
689 static boolean
690 parse_links (char **argv, int *arg_ptr)
692 return (insert_num (argv, arg_ptr, pred_links));
695 static boolean
696 parse_lname (char **argv, int *arg_ptr)
698 struct predicate *our_pred;
700 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
701 return (false);
703 fnmatch_sanitycheck();
705 our_pred = insert_primary (pred_lname);
706 our_pred->args.str = argv[*arg_ptr];
707 (*arg_ptr)++;
708 return (true);
711 static boolean
712 parse_ls (char **argv, int *arg_ptr)
714 struct predicate *our_pred;
716 our_pred = insert_primary (pred_ls);
717 our_pred->side_effects = true;
718 our_pred->no_default_print = true;
719 return (true);
722 static boolean
723 parse_maxdepth (char **argv, int *arg_ptr)
725 int depth_len;
727 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
728 return (false);
729 depth_len = strspn (argv[*arg_ptr], "0123456789");
730 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
731 return (false);
732 maxdepth = atoi (argv[*arg_ptr]);
733 if (maxdepth < 0)
734 return (false);
735 (*arg_ptr)++;
736 return (true);
739 static boolean
740 parse_mindepth (char **argv, int *arg_ptr)
742 int depth_len;
744 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
745 return (false);
746 depth_len = strspn (argv[*arg_ptr], "0123456789");
747 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
748 return (false);
749 mindepth = atoi (argv[*arg_ptr]);
750 if (mindepth < 0)
751 return (false);
752 (*arg_ptr)++;
753 return (true);
756 static boolean
757 parse_mmin (char **argv, int *arg_ptr)
759 struct predicate *our_pred;
760 uintmax_t num;
761 enum comparison_type c_type;
762 time_t t;
764 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
765 return (false);
766 if (!get_num_days (argv[*arg_ptr], &num, &c_type))
767 return (false);
768 t = cur_day_start + DAYSECS - num * 60;
769 our_pred = insert_primary (pred_mmin);
770 our_pred->args.info.kind = c_type;
771 our_pred->args.info.negative = t < 0;
772 our_pred->args.info.l_val = t;
773 (*arg_ptr)++;
774 return (true);
777 static boolean
778 parse_mtime (char **argv, int *arg_ptr)
780 return (insert_time (argv, arg_ptr, pred_mtime));
783 static boolean
784 parse_name (char **argv, int *arg_ptr)
786 struct predicate *our_pred;
788 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
789 return (false);
790 our_pred = insert_primary (pred_name);
791 our_pred->need_stat = false;
792 our_pred->args.str = argv[*arg_ptr];
793 (*arg_ptr)++;
794 return (true);
797 static boolean
798 parse_negate (char **argv, int *arg_ptr)
800 struct predicate *our_pred;
802 our_pred = get_new_pred_chk_op ();
803 our_pred->pred_func = pred_negate;
804 #ifdef DEBUG
805 our_pred->p_name = find_pred_name (pred_negate);
806 #endif /* DEBUG */
807 our_pred->p_type = UNI_OP;
808 our_pred->p_prec = NEGATE_PREC;
809 our_pred->need_stat = false;
810 return (true);
813 static boolean
814 parse_newer (char **argv, int *arg_ptr)
816 struct predicate *our_pred;
817 struct stat stat_newer;
819 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
820 return (false);
821 if ((*xstat) (argv[*arg_ptr], &stat_newer))
822 error (1, errno, "%s", argv[*arg_ptr]);
823 our_pred = insert_primary (pred_newer);
824 our_pred->args.time = stat_newer.st_mtime;
825 (*arg_ptr)++;
826 return (true);
829 static boolean
830 parse_noleaf (char **argv, int *arg_ptr)
832 no_leaf_check = true;
833 return true;
836 #ifdef CACHE_IDS
837 /* Arbitrary amount by which to increase size
838 of `uid_unused' and `gid_unused'. */
839 #define ALLOC_STEP 2048
841 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
842 char *uid_unused = NULL;
844 /* Number of elements in `uid_unused'. */
845 unsigned uid_allocated;
847 /* Similar for GIDs and group entries. */
848 char *gid_unused = NULL;
849 unsigned gid_allocated;
850 #endif
852 static boolean
853 parse_nogroup (char **argv, int *arg_ptr)
855 struct predicate *our_pred;
857 our_pred = insert_primary (pred_nogroup);
858 #ifdef CACHE_IDS
859 if (gid_unused == NULL)
861 struct group *gr;
863 gid_allocated = ALLOC_STEP;
864 gid_unused = xmalloc (gid_allocated);
865 memset (gid_unused, 1, gid_allocated);
866 setgrent ();
867 while ((gr = getgrent ()) != NULL)
869 if ((unsigned) gr->gr_gid >= gid_allocated)
871 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
872 gid_unused = xrealloc (gid_unused, new_allocated);
873 memset (gid_unused + gid_allocated, 1,
874 new_allocated - gid_allocated);
875 gid_allocated = new_allocated;
877 gid_unused[(unsigned) gr->gr_gid] = 0;
879 endgrent ();
881 #endif
882 return (true);
885 static boolean
886 parse_nouser (char **argv, int *arg_ptr)
888 struct predicate *our_pred;
890 our_pred = insert_primary (pred_nouser);
891 #ifdef CACHE_IDS
892 if (uid_unused == NULL)
894 struct passwd *pw;
896 uid_allocated = ALLOC_STEP;
897 uid_unused = xmalloc (uid_allocated);
898 memset (uid_unused, 1, uid_allocated);
899 setpwent ();
900 while ((pw = getpwent ()) != NULL)
902 if ((unsigned) pw->pw_uid >= uid_allocated)
904 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
905 uid_unused = xrealloc (uid_unused, new_allocated);
906 memset (uid_unused + uid_allocated, 1,
907 new_allocated - uid_allocated);
908 uid_allocated = new_allocated;
910 uid_unused[(unsigned) pw->pw_uid] = 0;
912 endpwent ();
914 #endif
915 return (true);
918 static boolean
919 parse_ok (char **argv, int *arg_ptr)
921 return (insert_exec_ok (pred_ok, argv, arg_ptr));
924 boolean
925 parse_open (char **argv, int *arg_ptr)
927 struct predicate *our_pred;
929 our_pred = get_new_pred_chk_op ();
930 our_pred->pred_func = pred_open;
931 #ifdef DEBUG
932 our_pred->p_name = find_pred_name (pred_open);
933 #endif /* DEBUG */
934 our_pred->p_type = OPEN_PAREN;
935 our_pred->p_prec = NO_PREC;
936 our_pred->need_stat = false;
937 return (true);
940 static boolean
941 parse_or (char **argv, int *arg_ptr)
943 struct predicate *our_pred;
945 our_pred = get_new_pred ();
946 our_pred->pred_func = pred_or;
947 #ifdef DEBUG
948 our_pred->p_name = find_pred_name (pred_or);
949 #endif /* DEBUG */
950 our_pred->p_type = BI_OP;
951 our_pred->p_prec = OR_PREC;
952 our_pred->need_stat = false;
953 return (true);
956 /* -path is deprecated (at RMS's request) in favour of
957 * -iwholename. See the node "GNU Manuals" in standards.texi
958 * for the rationale for this (basically, GNU prefers the use
959 * of the phrase "file name" to "path name".
961 * We do not issue a warning that this usage is deprecated
962 * since HPUX find supports this predicate also.
964 static boolean
965 parse_path (char **argv, int *arg_ptr)
967 return parse_wholename(argv, arg_ptr);
970 static boolean
971 parse_wholename (char **argv, int *arg_ptr)
973 struct predicate *our_pred;
975 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
976 return (false);
977 our_pred = insert_primary (pred_path);
978 our_pred->need_stat = false;
979 our_pred->args.str = argv[*arg_ptr];
980 (*arg_ptr)++;
981 return (true);
984 static boolean
985 parse_perm (char **argv, int *arg_ptr)
987 mode_t perm_val;
988 int mode_start = 0;
989 struct mode_change *change;
990 struct predicate *our_pred;
992 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
993 return (false);
995 switch (argv[*arg_ptr][0])
997 case '-':
998 case '+':
999 mode_start = 1;
1000 break;
1001 default:
1002 /* empty */
1003 break;
1006 change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
1007 if (change == MODE_INVALID)
1008 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
1009 else if (change == MODE_MEMORY_EXHAUSTED)
1010 error (1, 0, _("virtual memory exhausted"));
1011 perm_val = mode_adjust (0, change);
1012 mode_free (change);
1014 our_pred = insert_primary (pred_perm);
1016 switch (argv[*arg_ptr][0])
1018 case '-':
1019 our_pred->args.perm.kind = PERM_AT_LEAST;
1020 break;
1021 case '+':
1022 our_pred->args.perm.kind = PERM_ANY;
1023 break;
1024 default:
1025 our_pred->args.perm.kind = PERM_EXACT;
1026 break;
1028 our_pred->args.perm.val = perm_val & MODE_ALL;
1029 (*arg_ptr)++;
1030 return (true);
1033 boolean
1034 parse_print (char **argv, int *arg_ptr)
1036 struct predicate *our_pred;
1038 our_pred = insert_primary (pred_print);
1039 /* -print has the side effect of printing. This prevents us
1040 from doing undesired multiple printing when the user has
1041 already specified -print. */
1042 our_pred->side_effects = true;
1043 our_pred->no_default_print = true;
1044 our_pred->need_stat = false;
1045 return (true);
1048 static boolean
1049 parse_print0 (char **argv, int *arg_ptr)
1051 struct predicate *our_pred;
1053 our_pred = insert_primary (pred_print0);
1054 /* -print0 has the side effect of printing. This prevents us
1055 from doing undesired multiple printing when the user has
1056 already specified -print0. */
1057 our_pred->side_effects = true;
1058 our_pred->no_default_print = true;
1059 our_pred->need_stat = false;
1060 return (true);
1063 static boolean
1064 parse_printf (char **argv, int *arg_ptr)
1066 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1067 return (false);
1068 return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
1071 static boolean
1072 parse_prune (char **argv, int *arg_ptr)
1074 struct predicate *our_pred;
1076 our_pred = insert_primary (pred_prune);
1077 our_pred->need_stat = false;
1078 /* -prune has a side effect that it does not descend into
1079 the current directory. */
1080 our_pred->side_effects = true;
1081 return (true);
1084 static boolean
1085 parse_regex (char **argv, int *arg_ptr)
1087 return insert_regex (argv, arg_ptr, false);
1090 static boolean
1091 insert_regex (char **argv, int *arg_ptr, boolean ignore_case)
1093 struct predicate *our_pred;
1094 struct re_pattern_buffer *re;
1095 const char *error_message;
1097 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1098 return (false);
1099 our_pred = insert_primary (pred_regex);
1100 our_pred->need_stat = false;
1101 re = (struct re_pattern_buffer *)
1102 xmalloc (sizeof (struct re_pattern_buffer));
1103 our_pred->args.regex = re;
1104 re->allocated = 100;
1105 re->buffer = (unsigned char *) xmalloc (re->allocated);
1106 re->fastmap = NULL;
1108 if (ignore_case)
1110 unsigned i;
1112 re->translate = xmalloc (256);
1113 /* Map uppercase characters to corresponding lowercase ones. */
1114 for (i = 0; i < 256; i++)
1115 re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1117 else
1118 re->translate = NULL;
1120 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1121 re);
1122 if (error_message)
1123 error (1, 0, "%s", error_message);
1124 (*arg_ptr)++;
1125 return (true);
1128 static boolean
1129 parse_size (char **argv, int *arg_ptr)
1131 struct predicate *our_pred;
1132 uintmax_t num;
1133 enum comparison_type c_type;
1134 int blksize = 512;
1135 int len;
1137 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1138 return (false);
1139 len = strlen (argv[*arg_ptr]);
1140 if (len == 0)
1141 error (1, 0, _("invalid null argument to -size"));
1142 switch (argv[*arg_ptr][len - 1])
1144 case 'b':
1145 blksize = 512;
1146 argv[*arg_ptr][len - 1] = '\0';
1147 break;
1149 case 'c':
1150 blksize = 1;
1151 argv[*arg_ptr][len - 1] = '\0';
1152 break;
1154 case 'k':
1155 blksize = 1024;
1156 argv[*arg_ptr][len - 1] = '\0';
1157 break;
1159 case 'M': /* Megabytes */
1160 blksize = 1024*1024;
1161 argv[*arg_ptr][len - 1] = '\0';
1162 break;
1164 case 'G': /* Gigabytes */
1165 blksize = 1024*1024*1024;
1166 argv[*arg_ptr][len - 1] = '\0';
1167 break;
1169 case 'w':
1170 blksize = 2;
1171 argv[*arg_ptr][len - 1] = '\0';
1172 break;
1174 case '0':
1175 case '1':
1176 case '2':
1177 case '3':
1178 case '4':
1179 case '5':
1180 case '6':
1181 case '7':
1182 case '8':
1183 case '9':
1184 break;
1186 default:
1187 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
1189 if (!get_num (argv[*arg_ptr], &num, &c_type))
1190 return (false);
1191 our_pred = insert_primary (pred_size);
1192 our_pred->args.size.kind = c_type;
1193 our_pred->args.size.blocksize = blksize;
1194 our_pred->args.size.size = num;
1195 (*arg_ptr)++;
1196 return (true);
1199 static boolean
1200 parse_true (char **argv, int *arg_ptr)
1202 struct predicate *our_pred;
1204 our_pred = insert_primary (pred_true);
1205 our_pred->need_stat = false;
1206 return (true);
1209 static boolean
1210 parse_type (char **argv, int *arg_ptr)
1212 return insert_type (argv, arg_ptr, pred_type);
1215 static boolean
1216 parse_uid (char **argv, int *arg_ptr)
1218 return (insert_num (argv, arg_ptr, pred_uid));
1221 static boolean
1222 parse_used (char **argv, int *arg_ptr)
1224 struct predicate *our_pred;
1225 uintmax_t num_days;
1226 enum comparison_type c_type;
1227 time_t t;
1229 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1230 return (false);
1231 if (!get_num (argv[*arg_ptr], &num_days, &c_type))
1232 return (false);
1233 t = num_days * DAYSECS;
1234 our_pred = insert_primary (pred_used);
1235 our_pred->args.info.kind = c_type;
1236 our_pred->args.info.negative = t < 0;
1237 our_pred->args.info.l_val = t;
1238 (*arg_ptr)++;
1239 return (true);
1242 static boolean
1243 parse_user (char **argv, int *arg_ptr)
1245 struct passwd *cur_pwd;
1246 struct predicate *our_pred;
1247 uid_t uid;
1248 int uid_len;
1250 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1251 return (false);
1252 cur_pwd = getpwnam (argv[*arg_ptr]);
1253 endpwent ();
1254 if (cur_pwd != NULL)
1255 uid = cur_pwd->pw_uid;
1256 else
1258 uid_len = strspn (argv[*arg_ptr], "0123456789");
1259 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
1260 return (false);
1261 uid = atoi (argv[*arg_ptr]);
1263 our_pred = insert_primary (pred_user);
1264 our_pred->args.uid = uid;
1265 (*arg_ptr)++;
1266 return (true);
1269 static boolean
1270 parse_version (char **argv, int *arg_ptr)
1272 extern char *version_string;
1274 fflush (stderr);
1275 printf (_("GNU find version %s\n"), version_string);
1276 exit (0);
1279 static boolean
1280 parse_xdev (char **argv, int *arg_ptr)
1282 stay_on_filesystem = true;
1283 return true;
1286 static boolean
1287 parse_ignore_race (char **argv, int *arg_ptr)
1289 ignore_readdir_race = true;
1290 return true;
1293 static boolean
1294 parse_noignore_race (char **argv, int *arg_ptr)
1296 ignore_readdir_race = false;
1297 return true;
1300 static boolean
1301 parse_xtype (char **argv, int *arg_ptr)
1303 return insert_type (argv, arg_ptr, pred_xtype);
1306 static boolean
1307 insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
1309 mode_t type_cell;
1310 struct predicate *our_pred;
1312 if ((argv == NULL) || (argv[*arg_ptr] == NULL)
1313 || (strlen (argv[*arg_ptr]) != 1))
1314 return (false);
1315 switch (argv[*arg_ptr][0])
1317 case 'b': /* block special */
1318 type_cell = S_IFBLK;
1319 break;
1320 case 'c': /* character special */
1321 type_cell = S_IFCHR;
1322 break;
1323 case 'd': /* directory */
1324 type_cell = S_IFDIR;
1325 break;
1326 case 'f': /* regular file */
1327 type_cell = S_IFREG;
1328 break;
1329 #ifdef S_IFLNK
1330 case 'l': /* symbolic link */
1331 type_cell = S_IFLNK;
1332 break;
1333 #endif
1334 #ifdef S_IFIFO
1335 case 'p': /* pipe */
1336 type_cell = S_IFIFO;
1337 break;
1338 #endif
1339 #ifdef S_IFSOCK
1340 case 's': /* socket */
1341 type_cell = S_IFSOCK;
1342 break;
1343 #endif
1344 #ifdef S_IFDOOR
1345 case 'D': /* Solaris door */
1346 type_cell = S_IFDOOR;
1347 break;
1348 #endif
1349 default: /* None of the above ... nuke 'em. */
1350 return (false);
1352 our_pred = insert_primary (which_pred);
1353 our_pred->args.type = type_cell;
1354 (*arg_ptr)++; /* Move on to next argument. */
1355 return (true);
1358 /* If true, we've determined that the current fprintf predicate
1359 uses stat information. */
1360 static boolean fprintf_stat_needed;
1362 static boolean
1363 insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1365 char *format; /* Beginning of unprocessed format string. */
1366 register char *scan; /* Current address in scanning `format'. */
1367 register char *scan2; /* Address inside of element being scanned. */
1368 struct segment **segmentp; /* Address of current segment. */
1369 struct predicate *our_pred;
1371 format = argv[(*arg_ptr)++];
1373 fprintf_stat_needed = false; /* Might be overridden later. */
1374 our_pred = insert_primary (func);
1375 our_pred->side_effects = true;
1376 our_pred->no_default_print = true;
1377 our_pred->args.printf_vec.stream = fp;
1378 segmentp = &our_pred->args.printf_vec.segment;
1379 *segmentp = NULL;
1381 for (scan = format; *scan; scan++)
1383 if (*scan == '\\')
1385 scan2 = scan + 1;
1386 if (*scan2 >= '0' && *scan2 <= '7')
1388 register int n, i;
1390 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
1391 i++, scan2++)
1392 n = 8 * n + *scan2 - '0';
1393 scan2--;
1394 *scan = n;
1396 else
1398 switch (*scan2)
1400 case 'a':
1401 *scan = 7;
1402 break;
1403 case 'b':
1404 *scan = '\b';
1405 break;
1406 case 'c':
1407 make_segment (segmentp, format, scan - format, KIND_STOP);
1408 our_pred->need_stat = fprintf_stat_needed;
1409 return (true);
1410 case 'f':
1411 *scan = '\f';
1412 break;
1413 case 'n':
1414 *scan = '\n';
1415 break;
1416 case 'r':
1417 *scan = '\r';
1418 break;
1419 case 't':
1420 *scan = '\t';
1421 break;
1422 case 'v':
1423 *scan = '\v';
1424 break;
1425 case '\\':
1426 /* *scan = '\\'; * it already is */
1427 break;
1428 default:
1429 error (0, 0,
1430 _("warning: unrecognized escape `\\%c'"), *scan2);
1431 scan++;
1432 continue;
1435 segmentp = make_segment (segmentp, format, scan - format + 1,
1436 KIND_PLAIN);
1437 format = scan2 + 1; /* Move past the escape. */
1438 scan = scan2; /* Incremented immediately by `for'. */
1440 else if (*scan == '%')
1442 if (scan[1] == '%')
1444 segmentp = make_segment (segmentp, format, scan - format + 1,
1445 KIND_PLAIN);
1446 scan++;
1447 format = scan + 1;
1448 continue;
1450 /* Scan past flags, width and precision, to verify kind. */
1451 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
1452 /* Do nothing. */ ;
1453 while (ISDIGIT (*scan2))
1454 scan2++;
1455 if (*scan2 == '.')
1456 for (scan2++; ISDIGIT (*scan2); scan2++)
1457 /* Do nothing. */ ;
1458 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
1460 segmentp = make_segment (segmentp, format, scan2 - format,
1461 (int) *scan2);
1462 scan = scan2;
1463 format = scan + 1;
1465 else if (strchr ("ACT", *scan2) && scan2[1])
1467 segmentp = make_segment (segmentp, format, scan2 - format,
1468 *scan2 | (scan2[1] << 8));
1469 scan = scan2 + 1;
1470 format = scan + 1;
1471 continue;
1473 else
1475 /* An unrecognized % escape. Print the char after the %. */
1476 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1477 *scan2);
1478 segmentp = make_segment (segmentp, format, scan - format,
1479 KIND_PLAIN);
1480 format = scan + 1;
1481 continue;
1486 if (scan > format)
1487 make_segment (segmentp, format, scan - format, KIND_PLAIN);
1488 our_pred->need_stat = fprintf_stat_needed;
1489 return (true);
1492 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1493 from the text in FORMAT, which has length LEN.
1494 Return the address of the `next' pointer of the new segment. */
1496 static struct segment **
1497 make_segment (struct segment **segment, char *format, int len, int kind)
1499 char *fmt;
1501 *segment = (struct segment *) xmalloc (sizeof (struct segment));
1503 (*segment)->kind = kind;
1504 (*segment)->next = NULL;
1505 (*segment)->text_len = len;
1507 fmt = (*segment)->text = xmalloc (len + sizeof "d");
1508 strncpy (fmt, format, len);
1509 fmt += len;
1511 switch (kind & 0xff)
1513 case KIND_PLAIN: /* Plain text string, no % conversion. */
1514 case KIND_STOP: /* Terminate argument, no newline. */
1515 break;
1517 case 'a': /* atime in `ctime' format */
1518 case 'A': /* atime in user-specified strftime format */
1519 case 'b': /* size in 512-byte blocks */
1520 case 'c': /* ctime in `ctime' format */
1521 case 'C': /* ctime in user-specified strftime format */
1522 case 'F': /* filesystem type */
1523 case 'G': /* GID number */
1524 case 'g': /* group name */
1525 case 'i': /* inode number */
1526 case 'k': /* size in 1K blocks */
1527 case 'l': /* object of symlink */
1528 case 'n': /* number of links */
1529 case 's': /* size in bytes */
1530 case 't': /* mtime in `ctime' format */
1531 case 'T': /* mtime in user-specified strftime format */
1532 case 'U': /* UID number */
1533 case 'u': /* user name */
1534 fprintf_stat_needed = true;
1535 /* FALLTHROUGH */
1536 case 'f': /* basename of path */
1537 case 'h': /* leading directories part of path */
1538 case 'H': /* ARGV element file was found under */
1539 case 'p': /* pathname */
1540 case 'P': /* pathname with ARGV element stripped */
1541 *fmt++ = 's';
1542 break;
1544 case 'd': /* depth in search tree (0 = ARGV element) */
1545 *fmt++ = 'd';
1546 break;
1548 case 'm': /* mode as octal number (perms only) */
1549 *fmt++ = 'o';
1550 fprintf_stat_needed = true;
1551 break;
1553 *fmt = '\0';
1555 return (&(*segment)->next);
1558 /* handles both exec and ok predicate */
1559 static boolean
1560 insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1562 int start, end; /* Indexes in ARGV of start & end of cmd. */
1563 int num_paths; /* Number of args with path replacements. */
1564 int path_pos; /* Index in array of path replacements. */
1565 int vec_pos; /* Index in array of args. */
1566 struct predicate *our_pred;
1567 struct exec_val *execp; /* Pointer for efficiency. */
1569 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1570 return (false);
1572 /* Count the number of args with path replacements, up until the ';'. */
1573 start = *arg_ptr;
1574 for (end = start, num_paths = 0;
1575 (argv[end] != NULL)
1576 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1577 end++)
1578 if (strstr (argv[end], "{}"))
1579 num_paths++;
1580 /* Fail if no command given or no semicolon found. */
1581 if ((end == start) || (argv[end] == NULL))
1583 *arg_ptr = end;
1584 return (false);
1587 our_pred = insert_primary (func);
1588 our_pred->side_effects = true;
1589 our_pred->no_default_print = true;
1590 execp = &our_pred->args.exec_vec;
1591 execp->paths =
1592 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1593 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1594 /* Record the positions of all args, and the args with path replacements. */
1595 for (end = start, path_pos = vec_pos = 0;
1596 (argv[end] != NULL)
1597 && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
1598 end++)
1600 register char *p;
1602 execp->paths[path_pos].count = 0;
1603 for (p = argv[end]; *p; ++p)
1604 if (p[0] == '{' && p[1] == '}')
1606 execp->paths[path_pos].count++;
1607 ++p;
1609 if (execp->paths[path_pos].count)
1611 execp->paths[path_pos].offset = vec_pos;
1612 execp->paths[path_pos].origarg = argv[end];
1613 path_pos++;
1615 execp->vec[vec_pos++] = argv[end];
1617 execp->paths[path_pos].offset = -1;
1618 execp->vec[vec_pos] = NULL;
1620 if (argv[end] == NULL)
1621 *arg_ptr = end;
1622 else
1623 *arg_ptr = end + 1;
1624 return (true);
1627 /* Get a number of days and comparison type.
1628 STR is the ASCII representation.
1629 Set *NUM_DAYS to the number of days, taken as being from
1630 the current moment (or possibly midnight). Thus the sense of the
1631 comparison type appears to be reversed.
1632 Set *COMP_TYPE to the kind of comparison that is requested.
1634 Return true if all okay, false if input error.
1636 Used by -atime, -ctime and -mtime (parsers) to
1637 get the appropriate information for a time predicate processor. */
1639 static boolean
1640 get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
1642 boolean r = get_num (str, num_days, comp_type);
1643 if (r)
1644 switch (*comp_type)
1646 case COMP_LT: *comp_type = COMP_GT; break;
1647 case COMP_GT: *comp_type = COMP_LT; break;
1648 default: break;
1650 return r;
1653 /* Insert a time predicate PRED.
1654 ARGV is a pointer to the argument array.
1655 ARG_PTR is a pointer to an index into the array, incremented if
1656 all went well.
1658 Return true if input is valid, false if not.
1660 A new predicate node is assigned, along with an argument node
1661 obtained with malloc.
1663 Used by -atime, -ctime, and -mtime parsers. */
1665 static boolean
1666 insert_time (char **argv, int *arg_ptr, PFB pred)
1668 struct predicate *our_pred;
1669 uintmax_t num_days;
1670 enum comparison_type c_type;
1671 time_t t;
1673 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1674 return (false);
1675 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1676 return (false);
1678 /* Figure out the timestamp value we are looking for. */
1679 t = ( cur_day_start - num_days * DAYSECS
1680 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1681 #if 1
1682 if (1)
1684 /* We introduce a scope in which 'val' can be declared, for the
1685 * benefit of compilers that are really C89 compilers
1686 * which support intmax_t because config.h #defines it
1688 intmax_t val = ( (intmax_t)cur_day_start - num_days * DAYSECS
1689 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
1690 t = val;
1692 /* Check for possibility of an overflow */
1693 if ( (intmax_t)t != val )
1695 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
1698 #endif
1700 our_pred = insert_primary (pred);
1701 our_pred->args.info.kind = c_type;
1702 our_pred->args.info.negative = t < 0;
1703 our_pred->args.info.l_val = t;
1704 (*arg_ptr)++;
1705 #ifdef DEBUG
1706 printf (_("inserting %s\n"), our_pred->p_name);
1707 printf (_(" type: %s %s "),
1708 (c_type == COMP_GT) ? "gt" :
1709 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1710 (c_type == COMP_GT) ? " >" :
1711 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1712 t = our_pred->args.info.l_val;
1713 printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1714 if (c_type == COMP_EQ)
1716 t = our_pred->args.info.l_val += DAYSECS;
1717 printf (" < %ju %s",
1718 (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1719 our_pred->args.info.l_val -= DAYSECS;
1721 #endif /* DEBUG */
1722 return (true);
1725 /* Get a number with comparision information.
1726 The sense of the comparision information is 'normal'; that is,
1727 '+' looks for a count > than the number and '-' less than.
1729 STR is the ASCII representation of the number.
1730 Set *NUM to the number.
1731 Set *COMP_TYPE to the kind of comparison that is requested.
1733 Return true if all okay, false if input error. */
1735 static boolean
1736 get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1738 int len_num; /* Length of field. */
1740 if (str == NULL)
1741 return (false);
1742 switch (str[0])
1744 case '+':
1745 *comp_type = COMP_GT;
1746 str++;
1747 break;
1748 case '-':
1749 *comp_type = COMP_LT;
1750 str++;
1751 break;
1752 default:
1753 *comp_type = COMP_EQ;
1754 break;
1757 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK;
1760 /* Insert a number predicate.
1761 ARGV is a pointer to the argument array.
1762 *ARG_PTR is an index into ARGV, incremented if all went well.
1763 *PRED is the predicate processor to insert.
1765 Return true if input is valid, false if error.
1767 A new predicate node is assigned, along with an argument node
1768 obtained with malloc.
1770 Used by -inum and -links parsers. */
1772 static boolean
1773 insert_num (char **argv, int *arg_ptr, PFB pred)
1775 struct predicate *our_pred;
1776 uintmax_t num;
1777 enum comparison_type c_type;
1779 if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1780 return (false);
1781 if (!get_num (argv[*arg_ptr], &num, &c_type))
1782 return (false);
1783 our_pred = insert_primary (pred);
1784 our_pred->args.info.kind = c_type;
1785 our_pred->args.info.l_val = num;
1786 (*arg_ptr)++;
1787 #ifdef DEBUG
1788 printf (_("inserting %s\n"), our_pred->p_name);
1789 printf (_(" type: %s %s "),
1790 (c_type == COMP_GT) ? "gt" :
1791 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1792 (c_type == COMP_GT) ? " >" :
1793 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1794 printf ("%ju\n", our_pred->args.info.l_val);
1795 #endif /* DEBUG */
1796 return (true);
1799 static FILE *
1800 open_output_file (char *path)
1802 FILE *f;
1804 if (!strcmp (path, "/dev/stderr"))
1805 return (stderr);
1806 else if (!strcmp (path, "/dev/stdout"))
1807 return (stdout);
1808 f = fopen (path, "w");
1809 if (f == NULL)
1810 error (1, errno, "%s", path);
1811 return (f);