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"
28 #include "../gnulib/lib/xalloc.h"
33 # define _(Text) gettext (Text)
38 # define N_(String) gettext_noop (String)
40 /* See locate.c for explanation as to why not use (String) */
41 # define N_(String) String
44 #if !defined (isascii) || defined (STDC_HEADERS)
51 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
52 #define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
61 static boolean parse_amin
PARAMS((char *argv
[], int *arg_ptr
));
62 static boolean parse_and
PARAMS((char *argv
[], int *arg_ptr
));
63 static boolean parse_anewer
PARAMS((char *argv
[], int *arg_ptr
));
64 static boolean parse_atime
PARAMS((char *argv
[], int *arg_ptr
));
65 boolean parse_close
PARAMS((char *argv
[], int *arg_ptr
));
66 static boolean parse_cmin
PARAMS((char *argv
[], int *arg_ptr
));
67 static boolean parse_cnewer
PARAMS((char *argv
[], int *arg_ptr
));
68 static boolean parse_comma
PARAMS((char *argv
[], int *arg_ptr
));
69 static boolean parse_ctime
PARAMS((char *argv
[], int *arg_ptr
));
70 static boolean parse_daystart
PARAMS((char *argv
[], int *arg_ptr
));
71 static boolean parse_delete
PARAMS((char *argv
[], int *arg_ptr
));
72 static boolean parse_d
PARAMS((char *argv
[], int *arg_ptr
));
73 static boolean parse_depth
PARAMS((char *argv
[], int *arg_ptr
));
74 static boolean parse_empty
PARAMS((char *argv
[], int *arg_ptr
));
75 static boolean parse_exec
PARAMS((char *argv
[], int *arg_ptr
));
76 static boolean parse_false
PARAMS((char *argv
[], int *arg_ptr
));
77 static boolean parse_fls
PARAMS((char *argv
[], int *arg_ptr
));
78 static boolean parse_fprintf
PARAMS((char *argv
[], int *arg_ptr
));
79 static boolean parse_follow
PARAMS((char *argv
[], int *arg_ptr
));
80 static boolean parse_fprint
PARAMS((char *argv
[], int *arg_ptr
));
81 static boolean parse_fprint0
PARAMS((char *argv
[], int *arg_ptr
));
82 static boolean parse_fstype
PARAMS((char *argv
[], int *arg_ptr
));
83 static boolean parse_gid
PARAMS((char *argv
[], int *arg_ptr
));
84 static boolean parse_group
PARAMS((char *argv
[], int *arg_ptr
));
85 static boolean parse_help
PARAMS((char *argv
[], int *arg_ptr
));
86 static boolean parse_ilname
PARAMS((char *argv
[], int *arg_ptr
));
87 static boolean parse_iname
PARAMS((char *argv
[], int *arg_ptr
));
88 static boolean parse_inum
PARAMS((char *argv
[], int *arg_ptr
));
89 static boolean parse_ipath
PARAMS((char *argv
[], int *arg_ptr
));
90 static boolean parse_iregex
PARAMS((char *argv
[], int *arg_ptr
));
91 static boolean parse_iwholename
PARAMS((char *argv
[], int *arg_ptr
));
92 static boolean parse_links
PARAMS((char *argv
[], int *arg_ptr
));
93 static boolean parse_lname
PARAMS((char *argv
[], int *arg_ptr
));
94 static boolean parse_ls
PARAMS((char *argv
[], int *arg_ptr
));
95 static boolean parse_maxdepth
PARAMS((char *argv
[], int *arg_ptr
));
96 static boolean parse_mindepth
PARAMS((char *argv
[], int *arg_ptr
));
97 static boolean parse_mmin
PARAMS((char *argv
[], int *arg_ptr
));
98 static boolean parse_mtime
PARAMS((char *argv
[], int *arg_ptr
));
99 static boolean parse_name
PARAMS((char *argv
[], int *arg_ptr
));
100 static boolean parse_negate
PARAMS((char *argv
[], int *arg_ptr
));
101 static boolean parse_newer
PARAMS((char *argv
[], int *arg_ptr
));
102 static boolean parse_noleaf
PARAMS((char *argv
[], int *arg_ptr
));
103 static boolean parse_nogroup
PARAMS((char *argv
[], int *arg_ptr
));
104 static boolean parse_nouser
PARAMS((char *argv
[], int *arg_ptr
));
105 static boolean parse_nowarn
PARAMS((char *argv
[], int *arg_ptr
));
106 static boolean parse_ok
PARAMS((char *argv
[], int *arg_ptr
));
107 boolean parse_open
PARAMS((char *argv
[], int *arg_ptr
));
108 static boolean parse_or
PARAMS((char *argv
[], int *arg_ptr
));
109 static boolean parse_path
PARAMS((char *argv
[], int *arg_ptr
));
110 static boolean parse_perm
PARAMS((char *argv
[], int *arg_ptr
));
111 boolean parse_print
PARAMS((char *argv
[], int *arg_ptr
));
112 static boolean parse_print0
PARAMS((char *argv
[], int *arg_ptr
));
113 static boolean parse_printf
PARAMS((char *argv
[], int *arg_ptr
));
114 static boolean parse_prune
PARAMS((char *argv
[], int *arg_ptr
));
115 static boolean parse_regex
PARAMS((char *argv
[], int *arg_ptr
));
116 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
117 static boolean parse_size
PARAMS((char *argv
[], int *arg_ptr
));
118 static boolean parse_true
PARAMS((char *argv
[], int *arg_ptr
));
119 static boolean parse_type
PARAMS((char *argv
[], int *arg_ptr
));
120 static boolean parse_uid
PARAMS((char *argv
[], int *arg_ptr
));
121 static boolean parse_used
PARAMS((char *argv
[], int *arg_ptr
));
122 static boolean parse_user
PARAMS((char *argv
[], int *arg_ptr
));
123 static boolean parse_version
PARAMS((char *argv
[], int *arg_ptr
));
124 static boolean parse_wholename
PARAMS((char *argv
[], int *arg_ptr
));
125 static boolean parse_xdev
PARAMS((char *argv
[], int *arg_ptr
));
126 static boolean parse_ignore_race
PARAMS((char *argv
[], int *arg_ptr
));
127 static boolean parse_noignore_race
PARAMS((char *argv
[], int *arg_ptr
));
128 static boolean parse_warn
PARAMS((char *argv
[], int *arg_ptr
));
129 static boolean parse_xtype
PARAMS((char *argv
[], int *arg_ptr
));
130 static boolean parse_quit
PARAMS((char *argv
[], int *arg_ptr
));
132 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
133 static boolean insert_type
PARAMS((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
134 static boolean insert_fprintf
PARAMS((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
135 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
136 static boolean insert_exec_ok
PARAMS((boolean (*func
)(), char *argv
[], int *arg_ptr
));
137 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
138 static boolean insert_time
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
139 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
140 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
141 static FILE *open_output_file
PARAMS((char *path
));
144 char *find_pred_name
PARAMS((PFB pred_func
));
151 ARG_OPTION
, /* regular options like -maxdepth */
152 ARG_POSITIONAL_OPTION
, /* options whose position is important (-follow) */
153 ARG_TEST
, /* a like -name */
154 ARG_PUNCTUATION
, /* like -o or ( */
155 ARG_ACTION
/* like -print */
166 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
167 If they are in some Unix versions of find, they are marked `Unix'. */
169 static struct parser_table
const parse_table
[] =
171 {ARG_PUNCTUATION
, "!", parse_negate
},
172 {ARG_PUNCTUATION
, "not", parse_negate
}, /* GNU */
173 {ARG_PUNCTUATION
, "(", parse_open
},
174 {ARG_PUNCTUATION
, ")", parse_close
},
175 {ARG_PUNCTUATION
, ",", parse_comma
}, /* GNU */
176 {ARG_PUNCTUATION
, "a", parse_and
},
177 {ARG_TEST
, "amin", parse_amin
}, /* GNU */
178 {ARG_PUNCTUATION
, "and", parse_and
}, /* GNU */
179 {ARG_TEST
, "anewer", parse_anewer
}, /* GNU */
180 {ARG_TEST
, "atime", parse_atime
},
181 {ARG_TEST
, "cmin", parse_cmin
}, /* GNU */
182 {ARG_TEST
, "cnewer", parse_cnewer
}, /* GNU */
183 #ifdef UNIMPLEMENTED_UNIX
184 /* It's pretty ugly for find to know about archive formats.
185 Plus what it could do with cpio archives is very limited.
186 Better to leave it out. */
187 {ARG_UNIMPLEMENTED
, "cpio", parse_cpio
}, /* Unix */
189 {ARG_TEST
, "ctime", parse_ctime
},
190 {ARG_POSITIONAL_OPTION
, "daystart", parse_daystart
}, /* GNU */
191 {ARG_ACTION
, "delete", parse_delete
}, /* GNU, Mac OS, FreeBSD */
192 {ARG_OPTION
, "d", parse_d
}, /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
193 {ARG_OPTION
, "depth", parse_depth
},
194 {ARG_TEST
, "empty", parse_empty
}, /* GNU */
195 {ARG_ACTION
, "exec", parse_exec
},
196 {ARG_TEST
, "false", parse_false
}, /* GNU */
197 {ARG_ACTION
, "fls", parse_fls
}, /* GNU */
198 {ARG_POSITIONAL_OPTION
, "follow", parse_follow
}, /* GNU, Unix */
199 {ARG_ACTION
, "fprint", parse_fprint
}, /* GNU */
200 {ARG_ACTION
, "fprint0", parse_fprint0
}, /* GNU */
201 {ARG_ACTION
, "fprintf", parse_fprintf
}, /* GNU */
202 {ARG_TEST
, "fstype", parse_fstype
}, /* GNU, Unix */
203 {ARG_TEST
, "gid", parse_gid
}, /* GNU */
204 {ARG_TEST
, "group", parse_group
},
205 {ARG_TEST
, "help", parse_help
}, /* GNU */
206 {ARG_TEST
, "-help", parse_help
}, /* GNU */
207 {ARG_OPTION
, "ignore_readdir_race", parse_ignore_race
}, /* GNU */
208 {ARG_TEST
, "ilname", parse_ilname
}, /* GNU */
209 {ARG_TEST
, "iname", parse_iname
}, /* GNU */
210 {ARG_TEST
, "inum", parse_inum
}, /* GNU, Unix */
211 {ARG_TEST
, "ipath", parse_ipath
}, /* GNU, deprecated in favour of iwholename */
212 {ARG_TEST
, "iregex", parse_iregex
}, /* GNU */
213 {ARG_TEST
, "iwholename", parse_iwholename
}, /* GNU */
214 {ARG_TEST
, "links", parse_links
},
215 {ARG_TEST
, "lname", parse_lname
}, /* GNU */
216 {ARG_ACTION
, "ls", parse_ls
}, /* GNU, Unix */
217 {ARG_OPTION
, "maxdepth", parse_maxdepth
}, /* GNU */
218 {ARG_OPTION
, "mindepth", parse_mindepth
}, /* GNU */
219 {ARG_TEST
, "mmin", parse_mmin
}, /* GNU */
220 {ARG_OPTION
, "mount", parse_xdev
}, /* Unix */
221 {ARG_TEST
, "mtime", parse_mtime
},
222 {ARG_TEST
, "name", parse_name
},
223 #ifdef UNIMPLEMENTED_UNIX
224 {ARG_UNIMPLEMENTED
, "ncpio", parse_ncpio
}, /* Unix */
226 {ARG_TEST
, "newer", parse_newer
},
227 {ARG_OPTION
, "noleaf", parse_noleaf
}, /* GNU */
228 {ARG_TEST
, "nogroup", parse_nogroup
},
229 {ARG_TEST
, "nouser", parse_nouser
},
230 {ARG_OPTION
, "noignore_readdir_race", parse_noignore_race
},/* GNU */
231 {ARG_OPTION
, "nowarn", parse_nowarn
}, /* GNU */
232 {ARG_PUNCTUATION
, "o", parse_or
},
233 {ARG_PUNCTUATION
, "or", parse_or
}, /* GNU */
234 {ARG_ACTION
, "ok", parse_ok
},
235 {ARG_TEST
, "path", parse_path
}, /* GNU, HP-UX, GNU prefers wholename */
236 {ARG_TEST
, "perm", parse_perm
},
237 {ARG_ACTION
, "print", parse_print
},
238 {ARG_ACTION
, "print0", parse_print0
}, /* GNU */
239 {ARG_ACTION
, "printf", parse_printf
}, /* GNU */
240 {ARG_TEST
, "prune", parse_prune
},
241 {ARG_ACTION
, "quit", parse_quit
}, /* GNU */
242 {ARG_TEST
, "regex", parse_regex
}, /* GNU */
243 {ARG_TEST
, "size", parse_size
},
244 {ARG_TEST
, "true", parse_true
}, /* GNU */
245 {ARG_TEST
, "type", parse_type
},
246 {ARG_TEST
, "uid", parse_uid
}, /* GNU */
247 {ARG_TEST
, "used", parse_used
}, /* GNU */
248 {ARG_TEST
, "user", parse_user
},
249 {ARG_TEST
, "version", parse_version
}, /* GNU */
250 {ARG_TEST
, "-version", parse_version
}, /* GNU */
251 {ARG_OPTION
, "warn", parse_warn
}, /* GNU */
252 {ARG_TEST
, "wholename", parse_wholename
}, /* GNU, replaces -path */
253 {ARG_OPTION
, "xdev", parse_xdev
},
254 {ARG_TEST
, "xtype", parse_xtype
}, /* GNU */
259 static const char *first_nonoption_arg
= NULL
;
261 /* Return a pointer to the parser function to invoke for predicate
263 Return NULL if SEARCH_NAME is not a valid predicate name. */
266 find_parser (char *search_name
)
269 const char *original_arg
= search_name
;
271 if (*search_name
== '-')
273 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
275 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
277 /* If this is an option, but we have already had a
278 * non-option argument, the user may be under the
279 * impression that the behaviour of the option
280 * argument is conditional on some preceding
281 * tests. This might typically be the case with,
282 * for example, -maxdepth.
284 * The options -daystart and -follow are exempt
285 * from this treatment, since their positioning
286 * in the command line does have an effect on
287 * subsequent tests but not previous ones. That
288 * might be intentional on the part of the user.
290 if (parse_table
[i
].type
!= ARG_POSITIONAL_OPTION
)
292 /* Something other than -follow/-daystart.
293 * If this is an option, check if it followed
294 * a non-option and if so, issue a warning.
296 if (parse_table
[i
].type
== ARG_OPTION
)
298 if ((first_nonoption_arg
!= NULL
)
301 /* option which folows a non-option */
303 _("warning: you have specified the %s "
304 "option after a non-option argument %s, "
305 "but options are not positional (%s affects "
306 "tests specified before it as well as those "
307 "specified after it). Please specify options "
308 "before other arguments.\n"),
316 /* Not an option or a positional option,
317 * so remember we've seen it in order to
318 * use it in a possible future warning message.
320 if (first_nonoption_arg
== NULL
)
322 first_nonoption_arg
= original_arg
;
327 return (parse_table
[i
].parser_func
);
333 /* The parsers are responsible to continue scanning ARGV for
334 their arguments. Each parser knows what is and isn't
337 ARGV is the argument array.
338 *ARG_PTR is the index to start at in ARGV,
339 updated to point beyond the last element consumed.
341 The predicate structure is updated with the new information. */
344 parse_amin (char **argv
, int *arg_ptr
)
346 struct predicate
*our_pred
;
348 enum comparison_type c_type
;
351 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
353 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
355 t
= cur_day_start
+ DAYSECS
- num
* 60;
356 our_pred
= insert_primary (pred_amin
);
357 our_pred
->args
.info
.kind
= c_type
;
358 our_pred
->args
.info
.negative
= t
< 0;
359 our_pred
->args
.info
.l_val
= t
;
365 parse_and (char **argv
, int *arg_ptr
)
367 struct predicate
*our_pred
;
372 our_pred
= get_new_pred ();
373 our_pred
->pred_func
= pred_and
;
375 our_pred
->p_name
= find_pred_name (pred_and
);
377 our_pred
->p_type
= BI_OP
;
378 our_pred
->p_prec
= AND_PREC
;
379 our_pred
->need_stat
= false;
384 parse_anewer (char **argv
, int *arg_ptr
)
386 struct predicate
*our_pred
;
387 struct stat stat_newer
;
389 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
391 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
392 error (1, errno
, "%s", argv
[*arg_ptr
]);
393 our_pred
= insert_primary (pred_anewer
);
394 our_pred
->args
.time
= stat_newer
.st_mtime
;
400 parse_atime (char **argv
, int *arg_ptr
)
402 return (insert_time (argv
, arg_ptr
, pred_atime
));
406 parse_close (char **argv
, int *arg_ptr
)
408 struct predicate
*our_pred
;
413 our_pred
= get_new_pred ();
414 our_pred
->pred_func
= pred_close
;
416 our_pred
->p_name
= find_pred_name (pred_close
);
418 our_pred
->p_type
= CLOSE_PAREN
;
419 our_pred
->p_prec
= NO_PREC
;
420 our_pred
->need_stat
= false;
425 parse_cmin (char **argv
, int *arg_ptr
)
427 struct predicate
*our_pred
;
429 enum comparison_type c_type
;
432 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
434 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
436 t
= cur_day_start
+ DAYSECS
- num
* 60;
437 our_pred
= insert_primary (pred_cmin
);
438 our_pred
->args
.info
.kind
= c_type
;
439 our_pred
->args
.info
.negative
= t
< 0;
440 our_pred
->args
.info
.l_val
= t
;
446 parse_cnewer (char **argv
, int *arg_ptr
)
448 struct predicate
*our_pred
;
449 struct stat stat_newer
;
451 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
453 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
454 error (1, errno
, "%s", argv
[*arg_ptr
]);
455 our_pred
= insert_primary (pred_cnewer
);
456 our_pred
->args
.time
= stat_newer
.st_mtime
;
462 parse_comma (char **argv
, int *arg_ptr
)
464 struct predicate
*our_pred
;
469 our_pred
= get_new_pred ();
470 our_pred
->pred_func
= pred_comma
;
472 our_pred
->p_name
= find_pred_name (pred_comma
);
474 our_pred
->p_type
= BI_OP
;
475 our_pred
->p_prec
= COMMA_PREC
;
476 our_pred
->need_stat
= false;
481 parse_ctime (char **argv
, int *arg_ptr
)
483 return (insert_time (argv
, arg_ptr
, pred_ctime
));
487 parse_daystart (char **argv
, int *arg_ptr
)
494 if (full_days
== false)
496 cur_day_start
+= DAYSECS
;
497 local
= localtime (&cur_day_start
);
498 cur_day_start
-= (local
499 ? (local
->tm_sec
+ local
->tm_min
* 60
500 + local
->tm_hour
* 3600)
501 : cur_day_start
% DAYSECS
);
508 parse_delete (argv
, arg_ptr
)
512 struct predicate
*our_pred
;
516 our_pred
= insert_primary (pred_delete
);
517 our_pred
->side_effects
= true;
518 our_pred
->no_default_print
= true;
519 /* -delete implies -depth */
520 do_dir_first
= false;
525 parse_depth (char **argv
, int *arg_ptr
)
530 do_dir_first
= false;
535 parse_d (char **argv
, int *arg_ptr
)
543 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
545 return parse_depth(argv
, arg_ptr
);
549 parse_empty (char **argv
, int *arg_ptr
)
554 insert_primary (pred_empty
);
559 parse_exec (char **argv
, int *arg_ptr
)
561 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
565 parse_false (char **argv
, int *arg_ptr
)
567 struct predicate
*our_pred
;
572 our_pred
= insert_primary (pred_false
);
573 our_pred
->need_stat
= false;
578 parse_fls (char **argv
, int *arg_ptr
)
580 struct predicate
*our_pred
;
582 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
584 our_pred
= insert_primary (pred_fls
);
585 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
586 our_pred
->side_effects
= true;
587 our_pred
->no_default_print
= true;
593 parse_fprintf (char **argv
, int *arg_ptr
)
597 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
599 if (argv
[*arg_ptr
+ 1] == NULL
)
601 /* Ensure we get "missing arg" message, not "invalid arg". */
605 fp
= open_output_file (argv
[*arg_ptr
]);
607 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
611 parse_follow (char **argv
, int *arg_ptr
)
616 set_follow_state(SYMLINK_ALWAYS_DEREF
);
621 parse_fprint (char **argv
, int *arg_ptr
)
623 struct predicate
*our_pred
;
625 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
627 our_pred
= insert_primary (pred_fprint
);
628 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
629 our_pred
->side_effects
= true;
630 our_pred
->no_default_print
= true;
631 our_pred
->need_stat
= false;
637 parse_fprint0 (char **argv
, int *arg_ptr
)
639 struct predicate
*our_pred
;
641 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
643 our_pred
= insert_primary (pred_fprint0
);
644 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
645 our_pred
->side_effects
= true;
646 our_pred
->no_default_print
= true;
647 our_pred
->need_stat
= false;
653 parse_fstype (char **argv
, int *arg_ptr
)
655 struct predicate
*our_pred
;
657 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
659 our_pred
= insert_primary (pred_fstype
);
660 our_pred
->args
.str
= argv
[*arg_ptr
];
666 parse_gid (char **argv
, int *arg_ptr
)
668 return (insert_num (argv
, arg_ptr
, pred_gid
));
672 parse_group (char **argv
, int *arg_ptr
)
674 struct group
*cur_gr
;
675 struct predicate
*our_pred
;
679 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
681 cur_gr
= getgrnam (argv
[*arg_ptr
]);
684 gid
= cur_gr
->gr_gid
;
687 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
688 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
690 gid
= atoi (argv
[*arg_ptr
]);
692 our_pred
= insert_primary (pred_group
);
693 our_pred
->args
.gid
= gid
;
699 parse_help (char **argv
, int *arg_ptr
)
705 Usage: %s [path...] [expression]\n"), program_name
);
707 default path is the current directory; default expression is -print\n\
708 expression may consist of:\n\
709 operators (decreasing precedence; -and is implicit where no others are given):\n\
710 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2"));
711 puts (_(" EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
712 positional options (always true): -daystart -follow\n\
713 normal options (always true, specified before other expressions): -depth\n\
714 --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
715 -ignore_readdir_race -noignore_readdir_race\n\
716 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
718 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
719 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
720 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
722 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
723 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
724 -used N -user NAME -xtype [bcdpfls]"));
726 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
727 -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
729 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
730 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
731 email to <bug-findutils@gnu.org>."));
736 parse_ilname (char **argv
, int *arg_ptr
)
738 struct predicate
*our_pred
;
740 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
742 our_pred
= insert_primary (pred_ilname
);
743 our_pred
->args
.str
= argv
[*arg_ptr
];
749 /* sanity check the fnmatch() function to make sure
750 * it really is the GNU version.
753 fnmatch_sanitycheck()
755 /* fprintf(stderr, "Performing find sanity check..."); */
756 if (0 != fnmatch("foo", "foo", 0)
757 || 0 == fnmatch("Foo", "foo", 0)
758 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
760 error (1, 0, _("sanity check of the fnmatch() library function failed."));
761 /* fprintf(stderr, "FAILED\n"); */
765 /* fprintf(stderr, "OK\n"); */
772 parse_iname (char **argv
, int *arg_ptr
)
774 struct predicate
*our_pred
;
776 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
779 fnmatch_sanitycheck();
781 our_pred
= insert_primary (pred_iname
);
782 our_pred
->need_stat
= false;
783 our_pred
->args
.str
= argv
[*arg_ptr
];
789 parse_inum (char **argv
, int *arg_ptr
)
791 return (insert_num (argv
, arg_ptr
, pred_inum
));
794 /* -ipath is deprecated (at RMS's request) in favour of
795 * -iwholename. See the node "GNU Manuals" in standards.texi
796 * for the rationale for this (basically, GNU prefers the use
797 * of the phrase "file name" to "path name"
800 parse_ipath (char **argv
, int *arg_ptr
)
803 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
805 return parse_iwholename(argv
, arg_ptr
);
809 parse_iwholename (char **argv
, int *arg_ptr
)
811 struct predicate
*our_pred
;
813 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
816 fnmatch_sanitycheck();
818 our_pred
= insert_primary (pred_ipath
);
819 our_pred
->need_stat
= false;
820 our_pred
->args
.str
= argv
[*arg_ptr
];
826 parse_iregex (char **argv
, int *arg_ptr
)
828 return insert_regex (argv
, arg_ptr
, true);
832 parse_links (char **argv
, int *arg_ptr
)
834 return (insert_num (argv
, arg_ptr
, pred_links
));
838 parse_lname (char **argv
, int *arg_ptr
)
840 struct predicate
*our_pred
;
845 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
848 fnmatch_sanitycheck();
850 our_pred
= insert_primary (pred_lname
);
851 our_pred
->args
.str
= argv
[*arg_ptr
];
857 parse_ls (char **argv
, int *arg_ptr
)
859 struct predicate
*our_pred
;
864 our_pred
= insert_primary (pred_ls
);
865 our_pred
->side_effects
= true;
866 our_pred
->no_default_print
= true;
871 parse_maxdepth (char **argv
, int *arg_ptr
)
875 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
877 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
878 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
880 maxdepth
= atoi (argv
[*arg_ptr
]);
888 parse_mindepth (char **argv
, int *arg_ptr
)
892 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
894 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
895 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
897 mindepth
= atoi (argv
[*arg_ptr
]);
905 parse_mmin (char **argv
, int *arg_ptr
)
907 struct predicate
*our_pred
;
909 enum comparison_type c_type
;
912 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
914 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
916 t
= cur_day_start
+ DAYSECS
- num
* 60;
917 our_pred
= insert_primary (pred_mmin
);
918 our_pred
->args
.info
.kind
= c_type
;
919 our_pred
->args
.info
.negative
= t
< 0;
920 our_pred
->args
.info
.l_val
= t
;
926 parse_mtime (char **argv
, int *arg_ptr
)
928 return (insert_time (argv
, arg_ptr
, pred_mtime
));
932 parse_name (char **argv
, int *arg_ptr
)
934 struct predicate
*our_pred
;
939 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
941 our_pred
= insert_primary (pred_name
);
942 our_pred
->need_stat
= false;
943 our_pred
->args
.str
= argv
[*arg_ptr
];
949 parse_negate (char **argv
, int *arg_ptr
)
951 struct predicate
*our_pred
;
956 our_pred
= get_new_pred_chk_op ();
957 our_pred
->pred_func
= pred_negate
;
959 our_pred
->p_name
= find_pred_name (pred_negate
);
961 our_pred
->p_type
= UNI_OP
;
962 our_pred
->p_prec
= NEGATE_PREC
;
963 our_pred
->need_stat
= false;
968 parse_newer (char **argv
, int *arg_ptr
)
970 struct predicate
*our_pred
;
971 struct stat stat_newer
;
976 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
978 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
979 error (1, errno
, "%s", argv
[*arg_ptr
]);
980 our_pred
= insert_primary (pred_newer
);
981 our_pred
->args
.time
= stat_newer
.st_mtime
;
987 parse_noleaf (char **argv
, int *arg_ptr
)
992 no_leaf_check
= true;
997 /* Arbitrary amount by which to increase size
998 of `uid_unused' and `gid_unused'. */
999 #define ALLOC_STEP 2048
1001 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
1002 char *uid_unused
= NULL
;
1004 /* Number of elements in `uid_unused'. */
1005 unsigned uid_allocated
;
1007 /* Similar for GIDs and group entries. */
1008 char *gid_unused
= NULL
;
1009 unsigned gid_allocated
;
1013 parse_nogroup (char **argv
, int *arg_ptr
)
1015 struct predicate
*our_pred
;
1020 our_pred
= insert_primary (pred_nogroup
);
1022 if (gid_unused
== NULL
)
1026 gid_allocated
= ALLOC_STEP
;
1027 gid_unused
= xmalloc (gid_allocated
);
1028 memset (gid_unused
, 1, gid_allocated
);
1030 while ((gr
= getgrent ()) != NULL
)
1032 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
1034 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
1035 gid_unused
= xrealloc (gid_unused
, new_allocated
);
1036 memset (gid_unused
+ gid_allocated
, 1,
1037 new_allocated
- gid_allocated
);
1038 gid_allocated
= new_allocated
;
1040 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
1049 parse_nouser (char **argv
, int *arg_ptr
)
1051 struct predicate
*our_pred
;
1056 our_pred
= insert_primary (pred_nouser
);
1058 if (uid_unused
== NULL
)
1062 uid_allocated
= ALLOC_STEP
;
1063 uid_unused
= xmalloc (uid_allocated
);
1064 memset (uid_unused
, 1, uid_allocated
);
1066 while ((pw
= getpwent ()) != NULL
)
1068 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
1070 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
1071 uid_unused
= xrealloc (uid_unused
, new_allocated
);
1072 memset (uid_unused
+ uid_allocated
, 1,
1073 new_allocated
- uid_allocated
);
1074 uid_allocated
= new_allocated
;
1076 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
1085 parse_nowarn (char **argv
, int *arg_ptr
)
1095 parse_ok (char **argv
, int *arg_ptr
)
1097 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
1101 parse_open (char **argv
, int *arg_ptr
)
1103 struct predicate
*our_pred
;
1108 our_pred
= get_new_pred_chk_op ();
1109 our_pred
->pred_func
= pred_open
;
1111 our_pred
->p_name
= find_pred_name (pred_open
);
1113 our_pred
->p_type
= OPEN_PAREN
;
1114 our_pred
->p_prec
= NO_PREC
;
1115 our_pred
->need_stat
= false;
1120 parse_or (char **argv
, int *arg_ptr
)
1122 struct predicate
*our_pred
;
1127 our_pred
= get_new_pred ();
1128 our_pred
->pred_func
= pred_or
;
1130 our_pred
->p_name
= find_pred_name (pred_or
);
1132 our_pred
->p_type
= BI_OP
;
1133 our_pred
->p_prec
= OR_PREC
;
1134 our_pred
->need_stat
= false;
1138 /* -path is deprecated (at RMS's request) in favour of
1139 * -iwholename. See the node "GNU Manuals" in standards.texi
1140 * for the rationale for this (basically, GNU prefers the use
1141 * of the phrase "file name" to "path name".
1143 * We do not issue a warning that this usage is deprecated
1144 * since HPUX find supports this predicate also.
1147 parse_path (char **argv
, int *arg_ptr
)
1149 return parse_wholename(argv
, arg_ptr
);
1153 parse_wholename (char **argv
, int *arg_ptr
)
1155 struct predicate
*our_pred
;
1157 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1159 our_pred
= insert_primary (pred_path
);
1160 our_pred
->need_stat
= false;
1161 our_pred
->args
.str
= argv
[*arg_ptr
];
1167 parse_perm (char **argv
, int *arg_ptr
)
1171 struct mode_change
*change
;
1172 struct predicate
*our_pred
;
1174 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1177 switch (argv
[*arg_ptr
][0])
1188 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1189 if (change
== MODE_INVALID
)
1190 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1191 else if (change
== MODE_MEMORY_EXHAUSTED
)
1192 error (1, 0, _("virtual memory exhausted"));
1193 perm_val
= mode_adjust (0, change
);
1196 our_pred
= insert_primary (pred_perm
);
1198 switch (argv
[*arg_ptr
][0])
1201 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1204 our_pred
->args
.perm
.kind
= PERM_ANY
;
1207 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1210 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1216 parse_print (char **argv
, int *arg_ptr
)
1218 struct predicate
*our_pred
;
1223 our_pred
= insert_primary (pred_print
);
1224 /* -print has the side effect of printing. This prevents us
1225 from doing undesired multiple printing when the user has
1226 already specified -print. */
1227 our_pred
->side_effects
= true;
1228 our_pred
->no_default_print
= true;
1229 our_pred
->need_stat
= false;
1234 parse_print0 (char **argv
, int *arg_ptr
)
1236 struct predicate
*our_pred
;
1241 our_pred
= insert_primary (pred_print0
);
1242 /* -print0 has the side effect of printing. This prevents us
1243 from doing undesired multiple printing when the user has
1244 already specified -print0. */
1245 our_pred
->side_effects
= true;
1246 our_pred
->no_default_print
= true;
1247 our_pred
->need_stat
= false;
1252 parse_printf (char **argv
, int *arg_ptr
)
1254 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1256 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1260 parse_prune (char **argv
, int *arg_ptr
)
1262 struct predicate
*our_pred
;
1267 our_pred
= insert_primary (pred_prune
);
1268 our_pred
->need_stat
= false;
1269 /* -prune has a side effect that it does not descend into
1270 the current directory. */
1271 our_pred
->side_effects
= true;
1276 parse_quit (char **argv
, int *arg_ptr
)
1278 struct predicate
*our_pred
= insert_primary (pred_quit
);
1281 our_pred
->need_stat
= false;
1287 parse_regex (char **argv
, int *arg_ptr
)
1289 return insert_regex (argv
, arg_ptr
, false);
1293 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1295 struct predicate
*our_pred
;
1296 struct re_pattern_buffer
*re
;
1297 const char *error_message
;
1299 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1301 our_pred
= insert_primary (pred_regex
);
1302 our_pred
->need_stat
= false;
1303 re
= (struct re_pattern_buffer
*)
1304 xmalloc (sizeof (struct re_pattern_buffer
));
1305 our_pred
->args
.regex
= re
;
1306 re
->allocated
= 100;
1307 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1312 re_syntax_options
|= RE_ICASE
;
1316 re_syntax_options
&= ~RE_ICASE
;
1318 re
->translate
= NULL
;
1320 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1323 error (1, 0, "%s", error_message
);
1329 parse_size (char **argv
, int *arg_ptr
)
1331 struct predicate
*our_pred
;
1333 enum comparison_type c_type
;
1337 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1339 len
= strlen (argv
[*arg_ptr
]);
1341 error (1, 0, _("invalid null argument to -size"));
1342 switch (argv
[*arg_ptr
][len
- 1])
1346 argv
[*arg_ptr
][len
- 1] = '\0';
1351 argv
[*arg_ptr
][len
- 1] = '\0';
1356 argv
[*arg_ptr
][len
- 1] = '\0';
1359 case 'M': /* Megabytes */
1360 blksize
= 1024*1024;
1361 argv
[*arg_ptr
][len
- 1] = '\0';
1364 case 'G': /* Gigabytes */
1365 blksize
= 1024*1024*1024;
1366 argv
[*arg_ptr
][len
- 1] = '\0';
1371 argv
[*arg_ptr
][len
- 1] = '\0';
1387 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1389 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1391 our_pred
= insert_primary (pred_size
);
1392 our_pred
->args
.size
.kind
= c_type
;
1393 our_pred
->args
.size
.blocksize
= blksize
;
1394 our_pred
->args
.size
.size
= num
;
1400 parse_true (char **argv
, int *arg_ptr
)
1402 struct predicate
*our_pred
;
1407 our_pred
= insert_primary (pred_true
);
1408 our_pred
->need_stat
= false;
1413 parse_type (char **argv
, int *arg_ptr
)
1415 return insert_type (argv
, arg_ptr
, pred_type
);
1419 parse_uid (char **argv
, int *arg_ptr
)
1421 return (insert_num (argv
, arg_ptr
, pred_uid
));
1425 parse_used (char **argv
, int *arg_ptr
)
1427 struct predicate
*our_pred
;
1429 enum comparison_type c_type
;
1432 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1434 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1436 t
= num_days
* DAYSECS
;
1437 our_pred
= insert_primary (pred_used
);
1438 our_pred
->args
.info
.kind
= c_type
;
1439 our_pred
->args
.info
.negative
= t
< 0;
1440 our_pred
->args
.info
.l_val
= t
;
1446 parse_user (char **argv
, int *arg_ptr
)
1448 struct passwd
*cur_pwd
;
1449 struct predicate
*our_pred
;
1453 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1455 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1457 if (cur_pwd
!= NULL
)
1458 uid
= cur_pwd
->pw_uid
;
1461 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1462 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1464 uid
= atoi (argv
[*arg_ptr
]);
1466 our_pred
= insert_primary (pred_user
);
1467 our_pred
->args
.uid
= uid
;
1473 parse_version (char **argv
, int *arg_ptr
)
1475 extern char *version_string
;
1480 printf (_("GNU find version %s\n"), version_string
);
1485 parse_xdev (char **argv
, int *arg_ptr
)
1489 stay_on_filesystem
= true;
1494 parse_ignore_race (char **argv
, int *arg_ptr
)
1498 ignore_readdir_race
= true;
1503 parse_noignore_race (char **argv
, int *arg_ptr
)
1507 ignore_readdir_race
= false;
1512 parse_warn (char **argv
, int *arg_ptr
)
1521 parse_xtype (char **argv
, int *arg_ptr
)
1525 return insert_type (argv
, arg_ptr
, pred_xtype
);
1529 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1532 struct predicate
*our_pred
;
1534 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1535 || (strlen (argv
[*arg_ptr
]) != 1))
1537 switch (argv
[*arg_ptr
][0])
1539 case 'b': /* block special */
1540 type_cell
= S_IFBLK
;
1542 case 'c': /* character special */
1543 type_cell
= S_IFCHR
;
1545 case 'd': /* directory */
1546 type_cell
= S_IFDIR
;
1548 case 'f': /* regular file */
1549 type_cell
= S_IFREG
;
1552 case 'l': /* symbolic link */
1553 type_cell
= S_IFLNK
;
1557 case 'p': /* pipe */
1558 type_cell
= S_IFIFO
;
1562 case 's': /* socket */
1563 type_cell
= S_IFSOCK
;
1567 case 'D': /* Solaris door */
1568 type_cell
= S_IFDOOR
;
1571 default: /* None of the above ... nuke 'em. */
1574 our_pred
= insert_primary (which_pred
);
1575 our_pred
->args
.type
= type_cell
;
1576 (*arg_ptr
)++; /* Move on to next argument. */
1580 /* If true, we've determined that the current fprintf predicate
1581 uses stat information. */
1582 static boolean fprintf_stat_needed
;
1585 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1587 char *format
; /* Beginning of unprocessed format string. */
1588 register char *scan
; /* Current address in scanning `format'. */
1589 register char *scan2
; /* Address inside of element being scanned. */
1590 struct segment
**segmentp
; /* Address of current segment. */
1591 struct predicate
*our_pred
;
1593 format
= argv
[(*arg_ptr
)++];
1595 fprintf_stat_needed
= false; /* Might be overridden later. */
1596 our_pred
= insert_primary (func
);
1597 our_pred
->side_effects
= true;
1598 our_pred
->no_default_print
= true;
1599 our_pred
->args
.printf_vec
.stream
= fp
;
1600 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1603 for (scan
= format
; *scan
; scan
++)
1608 if (*scan2
>= '0' && *scan2
<= '7')
1612 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1614 n
= 8 * n
+ *scan2
- '0';
1629 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1630 our_pred
->need_stat
= fprintf_stat_needed
;
1648 /* *scan = '\\'; * it already is */
1652 _("warning: unrecognized escape `\\%c'"), *scan2
);
1657 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1659 format
= scan2
+ 1; /* Move past the escape. */
1660 scan
= scan2
; /* Incremented immediately by `for'. */
1662 else if (*scan
== '%')
1666 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1672 /* Scan past flags, width and precision, to verify kind. */
1673 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1675 while (ISDIGIT (*scan2
))
1678 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1680 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2
))
1682 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1687 else if (strchr ("ACT", *scan2
) && scan2
[1])
1689 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1690 *scan2
| (scan2
[1] << 8));
1697 /* An unrecognized % escape. Print the char after the %. */
1698 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1700 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1709 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1710 our_pred
->need_stat
= fprintf_stat_needed
;
1714 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1715 from the text in FORMAT, which has length LEN.
1716 Return the address of the `next' pointer of the new segment. */
1718 static struct segment
**
1719 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1723 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1725 (*segment
)->kind
= kind
;
1726 (*segment
)->next
= NULL
;
1727 (*segment
)->text_len
= len
;
1729 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1730 strncpy (fmt
, format
, len
);
1733 switch (kind
& 0xff)
1735 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1736 case KIND_STOP
: /* Terminate argument, no newline. */
1739 case 'a': /* atime in `ctime' format */
1740 case 'A': /* atime in user-specified strftime format */
1741 case 'c': /* ctime in `ctime' format */
1742 case 'C': /* ctime in user-specified strftime format */
1743 case 'F': /* filesystem type */
1744 case 'g': /* group name */
1745 case 'i': /* inode number */
1746 case 'l': /* object of symlink */
1747 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1748 case 's': /* size in bytes */
1749 case 't': /* mtime in `ctime' format */
1750 case 'T': /* mtime in user-specified strftime format */
1751 case 'u': /* user name */
1752 case 'y': /* file type */
1753 case 'Y': /* symlink pointed file type */
1754 fprintf_stat_needed
= true;
1756 case 'f': /* basename of path */
1757 case 'h': /* leading directories part of path */
1758 case 'H': /* ARGV element file was found under */
1759 case 'p': /* pathname */
1760 case 'P': /* pathname with ARGV element stripped */
1764 /* Numeric items that one might expect to honour
1765 * #, 0, + flags but which do not.
1767 case 'G': /* GID number */
1768 case 'U': /* UID number */
1769 case 'b': /* size in 512-byte blocks */
1770 case 'D': /* Filesystem device on which the file exits */
1771 case 'k': /* size in 1K blocks */
1772 case 'n': /* number of links */
1773 fprintf_stat_needed
= true;
1776 /* Numeric items that DO honour #, 0, + flags.
1778 case 'd': /* depth in search tree (0 = ARGV element) */
1782 case 'm': /* mode as octal number (perms only) */
1784 fprintf_stat_needed
= true;
1789 return (&(*segment
)->next
);
1792 /* handles both exec and ok predicate */
1794 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1796 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1797 int num_paths
; /* Number of args with path replacements. */
1798 int path_pos
; /* Index in array of path replacements. */
1799 int vec_pos
; /* Index in array of args. */
1800 struct predicate
*our_pred
;
1801 struct exec_val
*execp
; /* Pointer for efficiency. */
1803 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1806 /* Count the number of args with path replacements, up until the ';'. */
1808 for (end
= start
, num_paths
= 0;
1810 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1812 if (strstr (argv
[end
], "{}"))
1814 /* Fail if no command given or no semicolon found. */
1815 if ((end
== start
) || (argv
[end
] == NULL
))
1821 our_pred
= insert_primary (func
);
1822 our_pred
->side_effects
= true;
1823 our_pred
->no_default_print
= true;
1824 execp
= &our_pred
->args
.exec_vec
;
1826 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1827 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1828 /* Record the positions of all args, and the args with path replacements. */
1829 for (end
= start
, path_pos
= vec_pos
= 0;
1831 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1836 execp
->paths
[path_pos
].count
= 0;
1837 for (p
= argv
[end
]; *p
; ++p
)
1838 if (p
[0] == '{' && p
[1] == '}')
1840 execp
->paths
[path_pos
].count
++;
1843 if (execp
->paths
[path_pos
].count
)
1845 execp
->paths
[path_pos
].offset
= vec_pos
;
1846 execp
->paths
[path_pos
].origarg
= argv
[end
];
1849 execp
->vec
[vec_pos
++] = argv
[end
];
1851 execp
->paths
[path_pos
].offset
= -1;
1852 execp
->vec
[vec_pos
] = NULL
;
1854 if (argv
[end
] == NULL
)
1861 /* Get a number of days and comparison type.
1862 STR is the ASCII representation.
1863 Set *NUM_DAYS to the number of days, taken as being from
1864 the current moment (or possibly midnight). Thus the sense of the
1865 comparison type appears to be reversed.
1866 Set *COMP_TYPE to the kind of comparison that is requested.
1868 Return true if all okay, false if input error.
1870 Used by -atime, -ctime and -mtime (parsers) to
1871 get the appropriate information for a time predicate processor. */
1874 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1876 boolean r
= get_num (str
, num_days
, comp_type
);
1880 case COMP_LT
: *comp_type
= COMP_GT
; break;
1881 case COMP_GT
: *comp_type
= COMP_LT
; break;
1887 /* Insert a time predicate PRED.
1888 ARGV is a pointer to the argument array.
1889 ARG_PTR is a pointer to an index into the array, incremented if
1892 Return true if input is valid, false if not.
1894 A new predicate node is assigned, along with an argument node
1895 obtained with malloc.
1897 Used by -atime, -ctime, and -mtime parsers. */
1900 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1902 struct predicate
*our_pred
;
1904 enum comparison_type c_type
;
1907 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1909 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1912 /* Figure out the timestamp value we are looking for. */
1913 t
= ( cur_day_start
- num_days
* DAYSECS
1914 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1918 /* We introduce a scope in which 'val' can be declared, for the
1919 * benefit of compilers that are really C89 compilers
1920 * which support intmax_t because config.h #defines it
1922 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1923 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1926 /* Check for possibility of an overflow */
1927 if ( (intmax_t)t
!= val
)
1929 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1934 our_pred
= insert_primary (pred
);
1935 our_pred
->args
.info
.kind
= c_type
;
1936 our_pred
->args
.info
.negative
= t
< 0;
1937 our_pred
->args
.info
.l_val
= t
;
1940 printf (_("inserting %s\n"), our_pred
->p_name
);
1941 printf (_(" type: %s %s "),
1942 (c_type
== COMP_GT
) ? "gt" :
1943 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1944 (c_type
== COMP_GT
) ? " >" :
1945 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1946 t
= our_pred
->args
.info
.l_val
;
1947 printf ("%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1948 if (c_type
== COMP_EQ
)
1950 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1951 printf (" < %ju %s",
1952 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1953 our_pred
->args
.info
.l_val
-= DAYSECS
;
1959 /* Get a number with comparision information.
1960 The sense of the comparision information is 'normal'; that is,
1961 '+' looks for a count > than the number and '-' less than.
1963 STR is the ASCII representation of the number.
1964 Set *NUM to the number.
1965 Set *COMP_TYPE to the kind of comparison that is requested.
1967 Return true if all okay, false if input error. */
1970 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1977 *comp_type
= COMP_GT
;
1981 *comp_type
= COMP_LT
;
1985 *comp_type
= COMP_EQ
;
1989 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1992 /* Insert a number predicate.
1993 ARGV is a pointer to the argument array.
1994 *ARG_PTR is an index into ARGV, incremented if all went well.
1995 *PRED is the predicate processor to insert.
1997 Return true if input is valid, false if error.
1999 A new predicate node is assigned, along with an argument node
2000 obtained with malloc.
2002 Used by -inum and -links parsers. */
2005 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
2007 struct predicate
*our_pred
;
2009 enum comparison_type c_type
;
2011 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
2013 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
2015 our_pred
= insert_primary (pred
);
2016 our_pred
->args
.info
.kind
= c_type
;
2017 our_pred
->args
.info
.l_val
= num
;
2020 printf (_("inserting %s\n"), our_pred
->p_name
);
2021 printf (_(" type: %s %s "),
2022 (c_type
== COMP_GT
) ? "gt" :
2023 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
2024 (c_type
== COMP_GT
) ? " >" :
2025 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
2026 printf ("%ju\n", our_pred
->args
.info
.l_val
);
2032 open_output_file (char *path
)
2036 if (!strcmp (path
, "/dev/stderr"))
2038 else if (!strcmp (path
, "/dev/stdout"))
2040 f
= fopen (path
, "w");
2042 error (1, errno
, "%s", path
);