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)
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 #include "../gnulib/lib/modechange.h"
27 #include "../gnulib/lib/xstrtol.h"
32 # define _(Text) gettext (Text)
37 # define N_(String) gettext_noop (String)
39 /* See locate.c for explanation as to why not use (String) */
40 # define N_(String) String
43 #if !defined (isascii) || defined (STDC_HEADERS)
50 #define ISDIGIT(c) (isascii (c) && isdigit (c))
51 #define ISUPPER(c) (isascii (c) && isupper (c))
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_delete
PARAMS((char *argv
[], int *arg_ptr
));
71 static boolean parse_d
PARAMS((char *argv
[], int *arg_ptr
));
72 static boolean parse_depth
PARAMS((char *argv
[], int *arg_ptr
));
73 static boolean parse_empty
PARAMS((char *argv
[], int *arg_ptr
));
74 static boolean parse_exec
PARAMS((char *argv
[], int *arg_ptr
));
75 static boolean parse_false
PARAMS((char *argv
[], int *arg_ptr
));
76 static boolean parse_fls
PARAMS((char *argv
[], int *arg_ptr
));
77 static boolean parse_fprintf
PARAMS((char *argv
[], int *arg_ptr
));
78 static boolean parse_follow
PARAMS((char *argv
[], int *arg_ptr
));
79 static boolean parse_fprint
PARAMS((char *argv
[], int *arg_ptr
));
80 static boolean parse_fprint0
PARAMS((char *argv
[], int *arg_ptr
));
81 static boolean parse_fstype
PARAMS((char *argv
[], int *arg_ptr
));
82 static boolean parse_gid
PARAMS((char *argv
[], int *arg_ptr
));
83 static boolean parse_group
PARAMS((char *argv
[], int *arg_ptr
));
84 static boolean parse_help
PARAMS((char *argv
[], int *arg_ptr
));
85 static boolean parse_ilname
PARAMS((char *argv
[], int *arg_ptr
));
86 static boolean parse_iname
PARAMS((char *argv
[], int *arg_ptr
));
87 static boolean parse_inum
PARAMS((char *argv
[], int *arg_ptr
));
88 static boolean parse_ipath
PARAMS((char *argv
[], int *arg_ptr
));
89 static boolean parse_iregex
PARAMS((char *argv
[], int *arg_ptr
));
90 static boolean parse_iwholename
PARAMS((char *argv
[], int *arg_ptr
));
91 static boolean parse_links
PARAMS((char *argv
[], int *arg_ptr
));
92 static boolean parse_lname
PARAMS((char *argv
[], int *arg_ptr
));
93 static boolean parse_ls
PARAMS((char *argv
[], int *arg_ptr
));
94 static boolean parse_maxdepth
PARAMS((char *argv
[], int *arg_ptr
));
95 static boolean parse_mindepth
PARAMS((char *argv
[], int *arg_ptr
));
96 static boolean parse_mmin
PARAMS((char *argv
[], int *arg_ptr
));
97 static boolean parse_mtime
PARAMS((char *argv
[], int *arg_ptr
));
98 static boolean parse_name
PARAMS((char *argv
[], int *arg_ptr
));
99 static boolean parse_negate
PARAMS((char *argv
[], int *arg_ptr
));
100 static boolean parse_newer
PARAMS((char *argv
[], int *arg_ptr
));
101 static boolean parse_noleaf
PARAMS((char *argv
[], int *arg_ptr
));
102 static boolean parse_nogroup
PARAMS((char *argv
[], int *arg_ptr
));
103 static boolean parse_nouser
PARAMS((char *argv
[], int *arg_ptr
));
104 static boolean parse_nowarn
PARAMS((char *argv
[], int *arg_ptr
));
105 static boolean parse_ok
PARAMS((char *argv
[], int *arg_ptr
));
106 boolean parse_open
PARAMS((char *argv
[], int *arg_ptr
));
107 static boolean parse_or
PARAMS((char *argv
[], int *arg_ptr
));
108 static boolean parse_path
PARAMS((char *argv
[], int *arg_ptr
));
109 static boolean parse_perm
PARAMS((char *argv
[], int *arg_ptr
));
110 boolean parse_print
PARAMS((char *argv
[], int *arg_ptr
));
111 static boolean parse_print0
PARAMS((char *argv
[], int *arg_ptr
));
112 static boolean parse_printf
PARAMS((char *argv
[], int *arg_ptr
));
113 static boolean parse_prune
PARAMS((char *argv
[], int *arg_ptr
));
114 static boolean parse_regex
PARAMS((char *argv
[], int *arg_ptr
));
115 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
116 static boolean parse_size
PARAMS((char *argv
[], int *arg_ptr
));
117 static boolean parse_true
PARAMS((char *argv
[], int *arg_ptr
));
118 static boolean parse_type
PARAMS((char *argv
[], int *arg_ptr
));
119 static boolean parse_uid
PARAMS((char *argv
[], int *arg_ptr
));
120 static boolean parse_used
PARAMS((char *argv
[], int *arg_ptr
));
121 static boolean parse_user
PARAMS((char *argv
[], int *arg_ptr
));
122 static boolean parse_version
PARAMS((char *argv
[], int *arg_ptr
));
123 static boolean parse_wholename
PARAMS((char *argv
[], int *arg_ptr
));
124 static boolean parse_xdev
PARAMS((char *argv
[], int *arg_ptr
));
125 static boolean parse_ignore_race
PARAMS((char *argv
[], int *arg_ptr
));
126 static boolean parse_noignore_race
PARAMS((char *argv
[], int *arg_ptr
));
127 static boolean parse_warn
PARAMS((char *argv
[], int *arg_ptr
));
128 static boolean parse_xtype
PARAMS((char *argv
[], int *arg_ptr
));
129 static boolean parse_quit
PARAMS((char *argv
[], int *arg_ptr
));
131 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
132 static boolean insert_type
PARAMS((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
133 static boolean insert_fprintf
PARAMS((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
134 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
135 static boolean insert_exec_ok
PARAMS((boolean (*func
)(), char *argv
[], int *arg_ptr
));
136 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
137 static boolean insert_time
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
138 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
139 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
140 static FILE *open_output_file
PARAMS((char *path
));
143 char *find_pred_name
PARAMS((PFB pred_func
));
150 ARG_OPTION
, /* regular options like -maxdepth */
151 ARG_POSITIONAL_OPTION
, /* options whose position is important (-follow) */
152 ARG_TEST
, /* a like -name */
153 ARG_PUNCTUATION
, /* like -o or ( */
154 ARG_ACTION
/* like -print */
165 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
166 If they are in some Unix versions of find, they are marked `Unix'. */
168 static struct parser_table
const parse_table
[] =
170 {ARG_PUNCTUATION
, "!", parse_negate
},
171 {ARG_PUNCTUATION
, "not", parse_negate
}, /* GNU */
172 {ARG_PUNCTUATION
, "(", parse_open
},
173 {ARG_PUNCTUATION
, ")", parse_close
},
174 {ARG_PUNCTUATION
, ",", parse_comma
}, /* GNU */
175 {ARG_PUNCTUATION
, "a", parse_and
},
176 {ARG_TEST
, "amin", parse_amin
}, /* GNU */
177 {ARG_PUNCTUATION
, "and", parse_and
}, /* GNU */
178 {ARG_TEST
, "anewer", parse_anewer
}, /* GNU */
179 {ARG_TEST
, "atime", parse_atime
},
180 {ARG_TEST
, "cmin", parse_cmin
}, /* GNU */
181 {ARG_TEST
, "cnewer", parse_cnewer
}, /* GNU */
182 #ifdef UNIMPLEMENTED_UNIX
183 /* It's pretty ugly for find to know about archive formats.
184 Plus what it could do with cpio archives is very limited.
185 Better to leave it out. */
186 {ARG_UNIMPLEMENTED
, "cpio", parse_cpio
}, /* Unix */
188 {ARG_TEST
, "ctime", parse_ctime
},
189 {ARG_POSITIONAL_OPTION
, "daystart", parse_daystart
}, /* GNU */
190 {ARG_ACTION
, "delete", parse_delete
}, /* GNU, Mac OS, FreeBSD */
191 {ARG_OPTION
, "d", parse_d
}, /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
192 {ARG_OPTION
, "depth", parse_depth
},
193 {ARG_TEST
, "empty", parse_empty
}, /* GNU */
194 {ARG_ACTION
, "exec", parse_exec
},
195 {ARG_TEST
, "false", parse_false
}, /* GNU */
196 {ARG_ACTION
, "fls", parse_fls
}, /* GNU */
197 {ARG_POSITIONAL_OPTION
, "follow", parse_follow
}, /* GNU, Unix */
198 {ARG_ACTION
, "fprint", parse_fprint
}, /* GNU */
199 {ARG_ACTION
, "fprint0", parse_fprint0
}, /* GNU */
200 {ARG_ACTION
, "fprintf", parse_fprintf
}, /* GNU */
201 {ARG_TEST
, "fstype", parse_fstype
}, /* GNU, Unix */
202 {ARG_TEST
, "gid", parse_gid
}, /* GNU */
203 {ARG_TEST
, "group", parse_group
},
204 {ARG_TEST
, "help", parse_help
}, /* GNU */
205 {ARG_TEST
, "-help", parse_help
}, /* GNU */
206 {ARG_OPTION
, "ignore_readdir_race", parse_ignore_race
}, /* GNU */
207 {ARG_TEST
, "ilname", parse_ilname
}, /* GNU */
208 {ARG_TEST
, "iname", parse_iname
}, /* GNU */
209 {ARG_TEST
, "inum", parse_inum
}, /* GNU, Unix */
210 {ARG_TEST
, "ipath", parse_ipath
}, /* GNU, deprecated in favour of iwholename */
211 {ARG_TEST
, "iregex", parse_iregex
}, /* GNU */
212 {ARG_TEST
, "iwholename", parse_iwholename
}, /* GNU */
213 {ARG_TEST
, "links", parse_links
},
214 {ARG_TEST
, "lname", parse_lname
}, /* GNU */
215 {ARG_ACTION
, "ls", parse_ls
}, /* GNU, Unix */
216 {ARG_OPTION
, "maxdepth", parse_maxdepth
}, /* GNU */
217 {ARG_OPTION
, "mindepth", parse_mindepth
}, /* GNU */
218 {ARG_TEST
, "mmin", parse_mmin
}, /* GNU */
219 {ARG_OPTION
, "mount", parse_xdev
}, /* Unix */
220 {ARG_TEST
, "mtime", parse_mtime
},
221 {ARG_TEST
, "name", parse_name
},
222 #ifdef UNIMPLEMENTED_UNIX
223 {ARG_UNIMPLEMENTED
, "ncpio", parse_ncpio
}, /* Unix */
225 {ARG_TEST
, "newer", parse_newer
},
226 {ARG_OPTION
, "noleaf", parse_noleaf
}, /* GNU */
227 {ARG_TEST
, "nogroup", parse_nogroup
},
228 {ARG_TEST
, "nouser", parse_nouser
},
229 {ARG_OPTION
, "noignore_readdir_race", parse_noignore_race
},/* GNU */
230 {ARG_OPTION
, "nowarn", parse_nowarn
}, /* GNU */
231 {ARG_PUNCTUATION
, "o", parse_or
},
232 {ARG_PUNCTUATION
, "or", parse_or
}, /* GNU */
233 {ARG_ACTION
, "ok", parse_ok
},
234 {ARG_TEST
, "path", parse_path
}, /* GNU, HP-UX, GNU prefers wholename */
235 {ARG_TEST
, "perm", parse_perm
},
236 {ARG_ACTION
, "print", parse_print
},
237 {ARG_ACTION
, "print0", parse_print0
}, /* GNU */
238 {ARG_ACTION
, "printf", parse_printf
}, /* GNU */
239 {ARG_TEST
, "prune", parse_prune
},
240 {ARG_ACTION
, "quit", parse_quit
}, /* GNU */
241 {ARG_TEST
, "regex", parse_regex
}, /* GNU */
242 {ARG_TEST
, "size", parse_size
},
243 {ARG_TEST
, "true", parse_true
}, /* GNU */
244 {ARG_TEST
, "type", parse_type
},
245 {ARG_TEST
, "uid", parse_uid
}, /* GNU */
246 {ARG_TEST
, "used", parse_used
}, /* GNU */
247 {ARG_TEST
, "user", parse_user
},
248 {ARG_TEST
, "version", parse_version
}, /* GNU */
249 {ARG_TEST
, "-version", parse_version
}, /* GNU */
250 {ARG_OPTION
, "warn", parse_warn
}, /* GNU */
251 {ARG_TEST
, "wholename", parse_wholename
}, /* GNU, replaces -path */
252 {ARG_TEST
, "xdev", parse_xdev
},
253 {ARG_TEST
, "xtype", parse_xtype
}, /* GNU */
258 static const char *first_nonoption_arg
= NULL
;
260 /* Return a pointer to the parser function to invoke for predicate
262 Return NULL if SEARCH_NAME is not a valid predicate name. */
265 find_parser (char *search_name
)
268 const char *original_arg
= search_name
;
270 if (*search_name
== '-')
272 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
274 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
276 /* If this is an option, but we have already had a
277 * non-option argument, the user may be under the
278 * impression that the behaviour of the option
279 * argument is conditional on some preceding
280 * tests. This might typically be the case with,
281 * for example, -maxdepth.
283 * The options -daystart and -follow are exempt
284 * from this treatment, since their positioning
285 * in the command line does have an effect on
286 * subsequent tests but not previous ones. That
287 * might be intentional on the part of the user.
289 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
291 /* Something other than -follow/-daystart.
292 * If this is an option, check if it followed
293 * a non-option and if so, issue a warning.
295 if (parse_table
[i
].type
== ARG_OPTION
)
297 if ((first_nonoption_arg
!= NULL
)
300 /* option which folows a non-option */
302 _("warning: you have specified the %s "
303 "option after a non-option argument %s, "
304 "but options are not positional (%s affects "
305 "tests specified before it as well as those "
306 "specified after it). Please specify options "
307 "before other arguments.\n"),
315 /* Not an option or a positional option,
316 * so remember we've seen it in order to
317 * use it in a possible future warning message.
319 if (first_nonoption_arg
== NULL
)
321 first_nonoption_arg
= original_arg
;
326 return (parse_table
[i
].parser_func
);
332 /* The parsers are responsible to continue scanning ARGV for
333 their arguments. Each parser knows what is and isn't
336 ARGV is the argument array.
337 *ARG_PTR is the index to start at in ARGV,
338 updated to point beyond the last element consumed.
340 The predicate structure is updated with the new information. */
343 parse_amin (char **argv
, int *arg_ptr
)
345 struct predicate
*our_pred
;
347 enum comparison_type c_type
;
350 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
352 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
354 t
= cur_day_start
+ DAYSECS
- num
* 60;
355 our_pred
= insert_primary (pred_amin
);
356 our_pred
->args
.info
.kind
= c_type
;
357 our_pred
->args
.info
.negative
= t
< 0;
358 our_pred
->args
.info
.l_val
= t
;
364 parse_and (char **argv
, int *arg_ptr
)
366 struct predicate
*our_pred
;
371 our_pred
= get_new_pred ();
372 our_pred
->pred_func
= pred_and
;
374 our_pred
->p_name
= find_pred_name (pred_and
);
376 our_pred
->p_type
= BI_OP
;
377 our_pred
->p_prec
= AND_PREC
;
378 our_pred
->need_stat
= false;
383 parse_anewer (char **argv
, int *arg_ptr
)
385 struct predicate
*our_pred
;
386 struct stat stat_newer
;
388 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
390 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
391 error (1, errno
, "%s", argv
[*arg_ptr
]);
392 our_pred
= insert_primary (pred_anewer
);
393 our_pred
->args
.time
= stat_newer
.st_mtime
;
399 parse_atime (char **argv
, int *arg_ptr
)
401 return (insert_time (argv
, arg_ptr
, pred_atime
));
405 parse_close (char **argv
, int *arg_ptr
)
407 struct predicate
*our_pred
;
412 our_pred
= get_new_pred ();
413 our_pred
->pred_func
= pred_close
;
415 our_pred
->p_name
= find_pred_name (pred_close
);
417 our_pred
->p_type
= CLOSE_PAREN
;
418 our_pred
->p_prec
= NO_PREC
;
419 our_pred
->need_stat
= false;
424 parse_cmin (char **argv
, int *arg_ptr
)
426 struct predicate
*our_pred
;
428 enum comparison_type c_type
;
431 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
433 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
435 t
= cur_day_start
+ DAYSECS
- num
* 60;
436 our_pred
= insert_primary (pred_cmin
);
437 our_pred
->args
.info
.kind
= c_type
;
438 our_pred
->args
.info
.negative
= t
< 0;
439 our_pred
->args
.info
.l_val
= t
;
445 parse_cnewer (char **argv
, int *arg_ptr
)
447 struct predicate
*our_pred
;
448 struct stat stat_newer
;
450 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
452 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
453 error (1, errno
, "%s", argv
[*arg_ptr
]);
454 our_pred
= insert_primary (pred_cnewer
);
455 our_pred
->args
.time
= stat_newer
.st_mtime
;
461 parse_comma (char **argv
, int *arg_ptr
)
463 struct predicate
*our_pred
;
468 our_pred
= get_new_pred ();
469 our_pred
->pred_func
= pred_comma
;
471 our_pred
->p_name
= find_pred_name (pred_comma
);
473 our_pred
->p_type
= BI_OP
;
474 our_pred
->p_prec
= COMMA_PREC
;
475 our_pred
->need_stat
= false;
480 parse_ctime (char **argv
, int *arg_ptr
)
482 return (insert_time (argv
, arg_ptr
, pred_ctime
));
486 parse_daystart (char **argv
, int *arg_ptr
)
493 if (full_days
== false)
495 cur_day_start
+= DAYSECS
;
496 local
= localtime (&cur_day_start
);
497 cur_day_start
-= (local
498 ? (local
->tm_sec
+ local
->tm_min
* 60
499 + local
->tm_hour
* 3600)
500 : cur_day_start
% DAYSECS
);
507 parse_delete (argv
, arg_ptr
)
511 struct predicate
*our_pred
;
515 our_pred
= insert_primary (pred_delete
);
516 our_pred
->side_effects
= true;
517 our_pred
->no_default_print
= true;
518 /* -delete implies -depth */
519 do_dir_first
= false;
524 parse_depth (char **argv
, int *arg_ptr
)
529 do_dir_first
= false;
534 parse_d (char **argv
, int *arg_ptr
)
542 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
544 return parse_depth(argv
, arg_ptr
);
548 parse_empty (char **argv
, int *arg_ptr
)
553 insert_primary (pred_empty
);
558 parse_exec (char **argv
, int *arg_ptr
)
560 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
564 parse_false (char **argv
, int *arg_ptr
)
566 struct predicate
*our_pred
;
571 our_pred
= insert_primary (pred_false
);
572 our_pred
->need_stat
= false;
577 parse_fls (char **argv
, int *arg_ptr
)
579 struct predicate
*our_pred
;
581 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
583 our_pred
= insert_primary (pred_fls
);
584 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
585 our_pred
->side_effects
= true;
586 our_pred
->no_default_print
= true;
592 parse_fprintf (char **argv
, int *arg_ptr
)
596 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
598 if (argv
[*arg_ptr
+ 1] == NULL
)
600 /* Ensure we get "missing arg" message, not "invalid arg". */
604 fp
= open_output_file (argv
[*arg_ptr
]);
606 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
610 parse_follow (char **argv
, int *arg_ptr
)
615 set_follow_state(SYMLINK_ALWAYS_DEREF
);
620 parse_fprint (char **argv
, int *arg_ptr
)
622 struct predicate
*our_pred
;
624 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
626 our_pred
= insert_primary (pred_fprint
);
627 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
628 our_pred
->side_effects
= true;
629 our_pred
->no_default_print
= true;
630 our_pred
->need_stat
= false;
636 parse_fprint0 (char **argv
, int *arg_ptr
)
638 struct predicate
*our_pred
;
640 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
642 our_pred
= insert_primary (pred_fprint0
);
643 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
644 our_pred
->side_effects
= true;
645 our_pred
->no_default_print
= true;
646 our_pred
->need_stat
= false;
652 parse_fstype (char **argv
, int *arg_ptr
)
654 struct predicate
*our_pred
;
656 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
658 our_pred
= insert_primary (pred_fstype
);
659 our_pred
->args
.str
= argv
[*arg_ptr
];
665 parse_gid (char **argv
, int *arg_ptr
)
667 return (insert_num (argv
, arg_ptr
, pred_gid
));
671 parse_group (char **argv
, int *arg_ptr
)
673 struct group
*cur_gr
;
674 struct predicate
*our_pred
;
678 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
680 cur_gr
= getgrnam (argv
[*arg_ptr
]);
683 gid
= cur_gr
->gr_gid
;
686 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
687 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
689 gid
= atoi (argv
[*arg_ptr
]);
691 our_pred
= insert_primary (pred_group
);
692 our_pred
->args
.gid
= gid
;
698 parse_help (char **argv
, int *arg_ptr
)
704 Usage: %s [path...] [expression]\n"), program_name
);
706 default path is the current directory; default expression is -print\n\
707 expression may consist of:\n\
708 operators (decreasing precedence; -and is implicit where no others are given):\n\
709 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2"));
710 puts (_(" EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
711 positional options (always true): -daystart -follow\n\
712 normal options (always true, specified before other expressions): -depth\n\
713 --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
714 -ignore_readdir_race -noignore_readdir_race\n\
715 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
717 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
718 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
719 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
721 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
722 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
723 -used N -user NAME -xtype [bcdpfls]"));
725 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
726 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
728 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
729 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
730 email to <bug-findutils@gnu.org>."));
735 parse_ilname (char **argv
, int *arg_ptr
)
737 struct predicate
*our_pred
;
739 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
741 our_pred
= insert_primary (pred_ilname
);
742 our_pred
->args
.str
= argv
[*arg_ptr
];
748 /* sanity check the fnmatch() function to make sure
749 * it really is the GNU version.
752 fnmatch_sanitycheck()
754 /* fprintf(stderr, "Performing find sanity check..."); */
755 if (0 != fnmatch("foo", "foo", 0)
756 || 0 == fnmatch("Foo", "foo", 0)
757 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
759 error (1, 0, _("sanity check of the fnmatch() library function failed."));
760 /* fprintf(stderr, "FAILED\n"); */
764 /* fprintf(stderr, "OK\n"); */
771 parse_iname (char **argv
, int *arg_ptr
)
773 struct predicate
*our_pred
;
775 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
778 fnmatch_sanitycheck();
780 our_pred
= insert_primary (pred_iname
);
781 our_pred
->need_stat
= false;
782 our_pred
->args
.str
= argv
[*arg_ptr
];
788 parse_inum (char **argv
, int *arg_ptr
)
790 return (insert_num (argv
, arg_ptr
, pred_inum
));
793 /* -ipath is deprecated (at RMS's request) in favour of
794 * -iwholename. See the node "GNU Manuals" in standards.texi
795 * for the rationale for this (basically, GNU prefers the use
796 * of the phrase "file name" to "path name"
799 parse_ipath (char **argv
, int *arg_ptr
)
802 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
804 return parse_iwholename(argv
, arg_ptr
);
808 parse_iwholename (char **argv
, int *arg_ptr
)
810 struct predicate
*our_pred
;
812 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
815 fnmatch_sanitycheck();
817 our_pred
= insert_primary (pred_ipath
);
818 our_pred
->need_stat
= false;
819 our_pred
->args
.str
= argv
[*arg_ptr
];
825 parse_iregex (char **argv
, int *arg_ptr
)
827 return insert_regex (argv
, arg_ptr
, true);
831 parse_links (char **argv
, int *arg_ptr
)
833 return (insert_num (argv
, arg_ptr
, pred_links
));
837 parse_lname (char **argv
, int *arg_ptr
)
839 struct predicate
*our_pred
;
844 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
847 fnmatch_sanitycheck();
849 our_pred
= insert_primary (pred_lname
);
850 our_pred
->args
.str
= argv
[*arg_ptr
];
856 parse_ls (char **argv
, int *arg_ptr
)
858 struct predicate
*our_pred
;
863 our_pred
= insert_primary (pred_ls
);
864 our_pred
->side_effects
= true;
865 our_pred
->no_default_print
= true;
870 parse_maxdepth (char **argv
, int *arg_ptr
)
874 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
876 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
877 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
879 maxdepth
= atoi (argv
[*arg_ptr
]);
887 parse_mindepth (char **argv
, int *arg_ptr
)
891 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
893 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
894 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
896 mindepth
= atoi (argv
[*arg_ptr
]);
904 parse_mmin (char **argv
, int *arg_ptr
)
906 struct predicate
*our_pred
;
908 enum comparison_type c_type
;
911 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
913 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
915 t
= cur_day_start
+ DAYSECS
- num
* 60;
916 our_pred
= insert_primary (pred_mmin
);
917 our_pred
->args
.info
.kind
= c_type
;
918 our_pred
->args
.info
.negative
= t
< 0;
919 our_pred
->args
.info
.l_val
= t
;
925 parse_mtime (char **argv
, int *arg_ptr
)
927 return (insert_time (argv
, arg_ptr
, pred_mtime
));
931 parse_name (char **argv
, int *arg_ptr
)
933 struct predicate
*our_pred
;
938 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
940 our_pred
= insert_primary (pred_name
);
941 our_pred
->need_stat
= false;
942 our_pred
->args
.str
= argv
[*arg_ptr
];
948 parse_negate (char **argv
, int *arg_ptr
)
950 struct predicate
*our_pred
;
955 our_pred
= get_new_pred_chk_op ();
956 our_pred
->pred_func
= pred_negate
;
958 our_pred
->p_name
= find_pred_name (pred_negate
);
960 our_pred
->p_type
= UNI_OP
;
961 our_pred
->p_prec
= NEGATE_PREC
;
962 our_pred
->need_stat
= false;
967 parse_newer (char **argv
, int *arg_ptr
)
969 struct predicate
*our_pred
;
970 struct stat stat_newer
;
975 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
977 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
978 error (1, errno
, "%s", argv
[*arg_ptr
]);
979 our_pred
= insert_primary (pred_newer
);
980 our_pred
->args
.time
= stat_newer
.st_mtime
;
986 parse_noleaf (char **argv
, int *arg_ptr
)
991 no_leaf_check
= true;
996 /* Arbitrary amount by which to increase size
997 of `uid_unused' and `gid_unused'. */
998 #define ALLOC_STEP 2048
1000 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1001 char *uid_unused
= NULL
;
1003 /* Number of elements in `uid_unused'. */
1004 unsigned uid_allocated
;
1006 /* Similar for GIDs and group entries. */
1007 char *gid_unused
= NULL
;
1008 unsigned gid_allocated
;
1012 parse_nogroup (char **argv
, int *arg_ptr
)
1014 struct predicate
*our_pred
;
1019 our_pred
= insert_primary (pred_nogroup
);
1021 if (gid_unused
== NULL
)
1025 gid_allocated
= ALLOC_STEP
;
1026 gid_unused
= xmalloc (gid_allocated
);
1027 memset (gid_unused
, 1, gid_allocated
);
1029 while ((gr
= getgrent ()) != NULL
)
1031 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1033 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1034 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1035 memset (gid_unused
+ gid_allocated
, 1,
1036 new_allocated
- gid_allocated
);
1037 gid_allocated
= new_allocated
;
1039 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1048 parse_nouser (char **argv
, int *arg_ptr
)
1050 struct predicate
*our_pred
;
1055 our_pred
= insert_primary (pred_nouser
);
1057 if (uid_unused
== NULL
)
1061 uid_allocated
= ALLOC_STEP
;
1062 uid_unused
= xmalloc (uid_allocated
);
1063 memset (uid_unused
, 1, uid_allocated
);
1065 while ((pw
= getpwent ()) != NULL
)
1067 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1069 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1070 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1071 memset (uid_unused
+ uid_allocated
, 1,
1072 new_allocated
- uid_allocated
);
1073 uid_allocated
= new_allocated
;
1075 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1084 parse_nowarn (char **argv
, int *arg_ptr
)
1094 parse_ok (char **argv
, int *arg_ptr
)
1096 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
1100 parse_open (char **argv
, int *arg_ptr
)
1102 struct predicate
*our_pred
;
1107 our_pred
= get_new_pred_chk_op ();
1108 our_pred
->pred_func
= pred_open
;
1110 our_pred
->p_name
= find_pred_name (pred_open
);
1112 our_pred
->p_type
= OPEN_PAREN
;
1113 our_pred
->p_prec
= NO_PREC
;
1114 our_pred
->need_stat
= false;
1119 parse_or (char **argv
, int *arg_ptr
)
1121 struct predicate
*our_pred
;
1126 our_pred
= get_new_pred ();
1127 our_pred
->pred_func
= pred_or
;
1129 our_pred
->p_name
= find_pred_name (pred_or
);
1131 our_pred
->p_type
= BI_OP
;
1132 our_pred
->p_prec
= OR_PREC
;
1133 our_pred
->need_stat
= false;
1137 /* -path is deprecated (at RMS's request) in favour of
1138 * -iwholename. See the node "GNU Manuals" in standards.texi
1139 * for the rationale for this (basically, GNU prefers the use
1140 * of the phrase "file name" to "path name".
1142 * We do not issue a warning that this usage is deprecated
1143 * since HPUX find supports this predicate also.
1146 parse_path (char **argv
, int *arg_ptr
)
1148 return parse_wholename(argv
, arg_ptr
);
1152 parse_wholename (char **argv
, int *arg_ptr
)
1154 struct predicate
*our_pred
;
1156 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1158 our_pred
= insert_primary (pred_path
);
1159 our_pred
->need_stat
= false;
1160 our_pred
->args
.str
= argv
[*arg_ptr
];
1166 parse_perm (char **argv
, int *arg_ptr
)
1170 struct mode_change
*change
;
1171 struct predicate
*our_pred
;
1173 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1176 switch (argv
[*arg_ptr
][0])
1187 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1188 if (change
== MODE_INVALID
)
1189 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1190 else if (change
== MODE_MEMORY_EXHAUSTED
)
1191 error (1, 0, _("virtual memory exhausted"));
1192 perm_val
= mode_adjust (0, change
);
1195 our_pred
= insert_primary (pred_perm
);
1197 switch (argv
[*arg_ptr
][0])
1200 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1203 our_pred
->args
.perm
.kind
= PERM_ANY
;
1206 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1209 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1215 parse_print (char **argv
, int *arg_ptr
)
1217 struct predicate
*our_pred
;
1222 our_pred
= insert_primary (pred_print
);
1223 /* -print has the side effect of printing. This prevents us
1224 from doing undesired multiple printing when the user has
1225 already specified -print. */
1226 our_pred
->side_effects
= true;
1227 our_pred
->no_default_print
= true;
1228 our_pred
->need_stat
= false;
1233 parse_print0 (char **argv
, int *arg_ptr
)
1235 struct predicate
*our_pred
;
1240 our_pred
= insert_primary (pred_print0
);
1241 /* -print0 has the side effect of printing. This prevents us
1242 from doing undesired multiple printing when the user has
1243 already specified -print0. */
1244 our_pred
->side_effects
= true;
1245 our_pred
->no_default_print
= true;
1246 our_pred
->need_stat
= false;
1251 parse_printf (char **argv
, int *arg_ptr
)
1253 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1255 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1259 parse_prune (char **argv
, int *arg_ptr
)
1261 struct predicate
*our_pred
;
1266 our_pred
= insert_primary (pred_prune
);
1267 our_pred
->need_stat
= false;
1268 /* -prune has a side effect that it does not descend into
1269 the current directory. */
1270 our_pred
->side_effects
= true;
1275 parse_quit (char **argv
, int *arg_ptr
)
1277 struct predicate
*our_pred
= insert_primary (pred_quit
);
1280 our_pred
->need_stat
= false;
1286 parse_regex (char **argv
, int *arg_ptr
)
1288 return insert_regex (argv
, arg_ptr
, false);
1292 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1294 struct predicate
*our_pred
;
1295 struct re_pattern_buffer
*re
;
1296 const char *error_message
;
1298 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1300 our_pred
= insert_primary (pred_regex
);
1301 our_pred
->need_stat
= false;
1302 re
= (struct re_pattern_buffer
*)
1303 xmalloc (sizeof (struct re_pattern_buffer
));
1304 our_pred
->args
.regex
= re
;
1305 re
->allocated
= 100;
1306 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1311 re_syntax_options
|= RE_ICASE
;
1315 re_syntax_options
&= ~RE_ICASE
;
1317 re
->translate
= NULL
;
1319 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1322 error (1, 0, "%s", error_message
);
1328 parse_size (char **argv
, int *arg_ptr
)
1330 struct predicate
*our_pred
;
1332 enum comparison_type c_type
;
1336 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1338 len
= strlen (argv
[*arg_ptr
]);
1340 error (1, 0, _("invalid null argument to -size"));
1341 switch (argv
[*arg_ptr
][len
- 1])
1345 argv
[*arg_ptr
][len
- 1] = '\0';
1350 argv
[*arg_ptr
][len
- 1] = '\0';
1355 argv
[*arg_ptr
][len
- 1] = '\0';
1358 case 'M': /* Megabytes */
1359 blksize
= 1024*1024;
1360 argv
[*arg_ptr
][len
- 1] = '\0';
1363 case 'G': /* Gigabytes */
1364 blksize
= 1024*1024*1024;
1365 argv
[*arg_ptr
][len
- 1] = '\0';
1370 argv
[*arg_ptr
][len
- 1] = '\0';
1386 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1388 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1390 our_pred
= insert_primary (pred_size
);
1391 our_pred
->args
.size
.kind
= c_type
;
1392 our_pred
->args
.size
.blocksize
= blksize
;
1393 our_pred
->args
.size
.size
= num
;
1399 parse_true (char **argv
, int *arg_ptr
)
1401 struct predicate
*our_pred
;
1406 our_pred
= insert_primary (pred_true
);
1407 our_pred
->need_stat
= false;
1412 parse_type (char **argv
, int *arg_ptr
)
1414 return insert_type (argv
, arg_ptr
, pred_type
);
1418 parse_uid (char **argv
, int *arg_ptr
)
1420 return (insert_num (argv
, arg_ptr
, pred_uid
));
1424 parse_used (char **argv
, int *arg_ptr
)
1426 struct predicate
*our_pred
;
1428 enum comparison_type c_type
;
1431 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1433 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1435 t
= num_days
* DAYSECS
;
1436 our_pred
= insert_primary (pred_used
);
1437 our_pred
->args
.info
.kind
= c_type
;
1438 our_pred
->args
.info
.negative
= t
< 0;
1439 our_pred
->args
.info
.l_val
= t
;
1445 parse_user (char **argv
, int *arg_ptr
)
1447 struct passwd
*cur_pwd
;
1448 struct predicate
*our_pred
;
1452 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1454 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1456 if (cur_pwd
!= NULL
)
1457 uid
= cur_pwd
->pw_uid
;
1460 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1461 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1463 uid
= atoi (argv
[*arg_ptr
]);
1465 our_pred
= insert_primary (pred_user
);
1466 our_pred
->args
.uid
= uid
;
1472 parse_version (char **argv
, int *arg_ptr
)
1474 extern char *version_string
;
1479 printf (_("GNU find version %s\n"), version_string
);
1484 parse_xdev (char **argv
, int *arg_ptr
)
1488 stay_on_filesystem
= true;
1493 parse_ignore_race (char **argv
, int *arg_ptr
)
1497 ignore_readdir_race
= true;
1502 parse_noignore_race (char **argv
, int *arg_ptr
)
1506 ignore_readdir_race
= false;
1511 parse_warn (char **argv
, int *arg_ptr
)
1520 parse_xtype (char **argv
, int *arg_ptr
)
1524 return insert_type (argv
, arg_ptr
, pred_xtype
);
1528 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1531 struct predicate
*our_pred
;
1533 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1534 || (strlen (argv
[*arg_ptr
]) != 1))
1536 switch (argv
[*arg_ptr
][0])
1538 case 'b': /* block special */
1539 type_cell
= S_IFBLK
;
1541 case 'c': /* character special */
1542 type_cell
= S_IFCHR
;
1544 case 'd': /* directory */
1545 type_cell
= S_IFDIR
;
1547 case 'f': /* regular file */
1548 type_cell
= S_IFREG
;
1551 case 'l': /* symbolic link */
1552 type_cell
= S_IFLNK
;
1556 case 'p': /* pipe */
1557 type_cell
= S_IFIFO
;
1561 case 's': /* socket */
1562 type_cell
= S_IFSOCK
;
1566 case 'D': /* Solaris door */
1567 type_cell
= S_IFDOOR
;
1570 default: /* None of the above ... nuke 'em. */
1573 our_pred
= insert_primary (which_pred
);
1574 our_pred
->args
.type
= type_cell
;
1575 (*arg_ptr
)++; /* Move on to next argument. */
1579 /* If true, we've determined that the current fprintf predicate
1580 uses stat information. */
1581 static boolean fprintf_stat_needed
;
1584 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1586 char *format
; /* Beginning of unprocessed format string. */
1587 register char *scan
; /* Current address in scanning `format'. */
1588 register char *scan2
; /* Address inside of element being scanned. */
1589 struct segment
**segmentp
; /* Address of current segment. */
1590 struct predicate
*our_pred
;
1592 format
= argv
[(*arg_ptr
)++];
1594 fprintf_stat_needed
= false; /* Might be overridden later. */
1595 our_pred
= insert_primary (func
);
1596 our_pred
->side_effects
= true;
1597 our_pred
->no_default_print
= true;
1598 our_pred
->args
.printf_vec
.stream
= fp
;
1599 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1602 for (scan
= format
; *scan
; scan
++)
1607 if (*scan2
>= '0' && *scan2
<= '7')
1611 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1613 n
= 8 * n
+ *scan2
- '0';
1628 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1629 our_pred
->need_stat
= fprintf_stat_needed
;
1647 /* *scan = '\\'; * it already is */
1651 _("warning: unrecognized escape `\\%c'"), *scan2
);
1656 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1658 format
= scan2
+ 1; /* Move past the escape. */
1659 scan
= scan2
; /* Incremented immediately by `for'. */
1661 else if (*scan
== '%')
1665 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1671 /* Scan past flags, width and precision, to verify kind. */
1672 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1674 while (ISDIGIT (*scan2
))
1677 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1679 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2
))
1681 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1686 else if (strchr ("ACT", *scan2
) && scan2
[1])
1688 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1689 *scan2
| (scan2
[1] << 8));
1696 /* An unrecognized % escape. Print the char after the %. */
1697 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1699 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1708 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1709 our_pred
->need_stat
= fprintf_stat_needed
;
1713 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1714 from the text in FORMAT, which has length LEN.
1715 Return the address of the `next' pointer of the new segment. */
1717 static struct segment
**
1718 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1722 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1724 (*segment
)->kind
= kind
;
1725 (*segment
)->next
= NULL
;
1726 (*segment
)->text_len
= len
;
1728 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1729 strncpy (fmt
, format
, len
);
1732 switch (kind
& 0xff)
1734 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1735 case KIND_STOP
: /* Terminate argument, no newline. */
1738 case 'a': /* atime in `ctime' format */
1739 case 'A': /* atime in user-specified strftime format */
1740 case 'c': /* ctime in `ctime' format */
1741 case 'C': /* ctime in user-specified strftime format */
1742 case 'F': /* filesystem type */
1743 case 'g': /* group name */
1744 case 'i': /* inode number */
1745 case 'l': /* object of symlink */
1746 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1747 case 's': /* size in bytes */
1748 case 't': /* mtime in `ctime' format */
1749 case 'T': /* mtime in user-specified strftime format */
1750 case 'u': /* user name */
1751 case 'y': /* file type */
1752 case 'Y': /* symlink pointed file type */
1753 fprintf_stat_needed
= true;
1755 case 'f': /* basename of path */
1756 case 'h': /* leading directories part of path */
1757 case 'H': /* ARGV element file was found under */
1758 case 'p': /* pathname */
1759 case 'P': /* pathname with ARGV element stripped */
1763 /* Numeric items that one might expect to honour
1764 * #, 0, + flags but which do not.
1766 case 'G': /* GID number */
1767 case 'U': /* UID number */
1768 case 'b': /* size in 512-byte blocks */
1769 case 'D': /* Filesystem device on which the file exits */
1770 case 'k': /* size in 1K blocks */
1771 case 'n': /* number of links */
1772 fprintf_stat_needed
= true;
1775 /* Numeric items that DO honour #, 0, + flags.
1777 case 'd': /* depth in search tree (0 = ARGV element) */
1781 case 'm': /* mode as octal number (perms only) */
1783 fprintf_stat_needed
= true;
1788 return (&(*segment
)->next
);
1791 /* handles both exec and ok predicate */
1793 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1795 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1796 int num_paths
; /* Number of args with path replacements. */
1797 int path_pos
; /* Index in array of path replacements. */
1798 int vec_pos
; /* Index in array of args. */
1799 struct predicate
*our_pred
;
1800 struct exec_val
*execp
; /* Pointer for efficiency. */
1802 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1805 /* Count the number of args with path replacements, up until the ';'. */
1807 for (end
= start
, num_paths
= 0;
1809 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1811 if (strstr (argv
[end
], "{}"))
1813 /* Fail if no command given or no semicolon found. */
1814 if ((end
== start
) || (argv
[end
] == NULL
))
1820 our_pred
= insert_primary (func
);
1821 our_pred
->side_effects
= true;
1822 our_pred
->no_default_print
= true;
1823 execp
= &our_pred
->args
.exec_vec
;
1825 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1826 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1827 /* Record the positions of all args, and the args with path replacements. */
1828 for (end
= start
, path_pos
= vec_pos
= 0;
1830 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1835 execp
->paths
[path_pos
].count
= 0;
1836 for (p
= argv
[end
]; *p
; ++p
)
1837 if (p
[0] == '{' && p
[1] == '}')
1839 execp
->paths
[path_pos
].count
++;
1842 if (execp
->paths
[path_pos
].count
)
1844 execp
->paths
[path_pos
].offset
= vec_pos
;
1845 execp
->paths
[path_pos
].origarg
= argv
[end
];
1848 execp
->vec
[vec_pos
++] = argv
[end
];
1850 execp
->paths
[path_pos
].offset
= -1;
1851 execp
->vec
[vec_pos
] = NULL
;
1853 if (argv
[end
] == NULL
)
1860 /* Get a number of days and comparison type.
1861 STR is the ASCII representation.
1862 Set *NUM_DAYS to the number of days, taken as being from
1863 the current moment (or possibly midnight). Thus the sense of the
1864 comparison type appears to be reversed.
1865 Set *COMP_TYPE to the kind of comparison that is requested.
1867 Return true if all okay, false if input error.
1869 Used by -atime, -ctime and -mtime (parsers) to
1870 get the appropriate information for a time predicate processor. */
1873 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1875 boolean r
= get_num (str
, num_days
, comp_type
);
1879 case COMP_LT
: *comp_type
= COMP_GT
; break;
1880 case COMP_GT
: *comp_type
= COMP_LT
; break;
1886 /* Insert a time predicate PRED.
1887 ARGV is a pointer to the argument array.
1888 ARG_PTR is a pointer to an index into the array, incremented if
1891 Return true if input is valid, false if not.
1893 A new predicate node is assigned, along with an argument node
1894 obtained with malloc.
1896 Used by -atime, -ctime, and -mtime parsers. */
1899 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1901 struct predicate
*our_pred
;
1903 enum comparison_type c_type
;
1906 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1908 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1911 /* Figure out the timestamp value we are looking for. */
1912 t
= ( cur_day_start
- num_days
* DAYSECS
1913 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1917 /* We introduce a scope in which 'val' can be declared, for the
1918 * benefit of compilers that are really C89 compilers
1919 * which support intmax_t because config.h #defines it
1921 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1922 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1925 /* Check for possibility of an overflow */
1926 if ( (intmax_t)t
!= val
)
1928 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1933 our_pred
= insert_primary (pred
);
1934 our_pred
->args
.info
.kind
= c_type
;
1935 our_pred
->args
.info
.negative
= t
< 0;
1936 our_pred
->args
.info
.l_val
= t
;
1939 printf (_("inserting %s\n"), our_pred
->p_name
);
1940 printf (_(" type: %s %s "),
1941 (c_type
== COMP_GT
) ? "gt" :
1942 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1943 (c_type
== COMP_GT
) ? " >" :
1944 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1945 t
= our_pred
->args
.info
.l_val
;
1946 printf ("%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1947 if (c_type
== COMP_EQ
)
1949 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1950 printf (" < %ju %s",
1951 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1952 our_pred
->args
.info
.l_val
-= DAYSECS
;
1958 /* Get a number with comparision information.
1959 The sense of the comparision information is 'normal'; that is,
1960 '+' looks for a count > than the number and '-' less than.
1962 STR is the ASCII representation of the number.
1963 Set *NUM to the number.
1964 Set *COMP_TYPE to the kind of comparison that is requested.
1966 Return true if all okay, false if input error. */
1969 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1976 *comp_type
= COMP_GT
;
1980 *comp_type
= COMP_LT
;
1984 *comp_type
= COMP_EQ
;
1988 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1991 /* Insert a number predicate.
1992 ARGV is a pointer to the argument array.
1993 *ARG_PTR is an index into ARGV, incremented if all went well.
1994 *PRED is the predicate processor to insert.
1996 Return true if input is valid, false if error.
1998 A new predicate node is assigned, along with an argument node
1999 obtained with malloc.
2001 Used by -inum and -links parsers. */
2004 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
2006 struct predicate
*our_pred
;
2008 enum comparison_type c_type
;
2010 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2012 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2014 our_pred
= insert_primary (pred
);
2015 our_pred
->args
.info
.kind
= c_type
;
2016 our_pred
->args
.info
.l_val
= num
;
2019 printf (_("inserting %s\n"), our_pred
->p_name
);
2020 printf (_(" type: %s %s "),
2021 (c_type
== COMP_GT
) ? "gt" :
2022 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2023 (c_type
== COMP_GT
) ? " >" :
2024 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2025 printf ("%ju\n", our_pred
->args
.info
.l_val
);
2031 open_output_file (char *path
)
2035 if (!strcmp (path
, "/dev/stderr"))
2037 else if (!strcmp (path
, "/dev/stdout"))
2039 f
= fopen (path
, "w");
2041 error (1, errno
, "%s", path
);