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., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
26 #include "../gnulib/lib/modechange.h"
28 #include "../gnulib/lib/xstrtol.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 (c) && isdigit (c))
52 #define ISUPPER(c) (isascii (c) && isupper (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_depth
PARAMS((char *argv
[], int *arg_ptr
));
72 static boolean parse_empty
PARAMS((char *argv
[], int *arg_ptr
));
73 static boolean parse_exec
PARAMS((char *argv
[], int *arg_ptr
));
74 static boolean parse_false
PARAMS((char *argv
[], int *arg_ptr
));
75 static boolean parse_fls
PARAMS((char *argv
[], int *arg_ptr
));
76 static boolean parse_fprintf
PARAMS((char *argv
[], int *arg_ptr
));
77 static boolean parse_follow
PARAMS((char *argv
[], int *arg_ptr
));
78 static boolean parse_fprint
PARAMS((char *argv
[], int *arg_ptr
));
79 static boolean parse_fprint0
PARAMS((char *argv
[], int *arg_ptr
));
80 static boolean parse_fstype
PARAMS((char *argv
[], int *arg_ptr
));
81 static boolean parse_gid
PARAMS((char *argv
[], int *arg_ptr
));
82 static boolean parse_group
PARAMS((char *argv
[], int *arg_ptr
));
83 static boolean parse_help
PARAMS((char *argv
[], int *arg_ptr
));
84 static boolean parse_ilname
PARAMS((char *argv
[], int *arg_ptr
));
85 static boolean parse_iname
PARAMS((char *argv
[], int *arg_ptr
));
86 static boolean parse_inum
PARAMS((char *argv
[], int *arg_ptr
));
87 static boolean parse_ipath
PARAMS((char *argv
[], int *arg_ptr
));
88 static boolean parse_iregex
PARAMS((char *argv
[], int *arg_ptr
));
89 static boolean parse_iwholename
PARAMS((char *argv
[], int *arg_ptr
));
90 static boolean parse_links
PARAMS((char *argv
[], int *arg_ptr
));
91 static boolean parse_lname
PARAMS((char *argv
[], int *arg_ptr
));
92 static boolean parse_ls
PARAMS((char *argv
[], int *arg_ptr
));
93 static boolean parse_maxdepth
PARAMS((char *argv
[], int *arg_ptr
));
94 static boolean parse_mindepth
PARAMS((char *argv
[], int *arg_ptr
));
95 static boolean parse_mmin
PARAMS((char *argv
[], int *arg_ptr
));
96 static boolean parse_mtime
PARAMS((char *argv
[], int *arg_ptr
));
97 static boolean parse_name
PARAMS((char *argv
[], int *arg_ptr
));
98 static boolean parse_negate
PARAMS((char *argv
[], int *arg_ptr
));
99 static boolean parse_newer
PARAMS((char *argv
[], int *arg_ptr
));
100 static boolean parse_noleaf
PARAMS((char *argv
[], int *arg_ptr
));
101 static boolean parse_nogroup
PARAMS((char *argv
[], int *arg_ptr
));
102 static boolean parse_nouser
PARAMS((char *argv
[], int *arg_ptr
));
103 static boolean parse_ok
PARAMS((char *argv
[], int *arg_ptr
));
104 boolean parse_open
PARAMS((char *argv
[], int *arg_ptr
));
105 static boolean parse_or
PARAMS((char *argv
[], int *arg_ptr
));
106 static boolean parse_path
PARAMS((char *argv
[], int *arg_ptr
));
107 static boolean parse_perm
PARAMS((char *argv
[], int *arg_ptr
));
108 boolean parse_print
PARAMS((char *argv
[], int *arg_ptr
));
109 static boolean parse_print0
PARAMS((char *argv
[], int *arg_ptr
));
110 static boolean parse_printf
PARAMS((char *argv
[], int *arg_ptr
));
111 static boolean parse_prune
PARAMS((char *argv
[], int *arg_ptr
));
112 static boolean parse_regex
PARAMS((char *argv
[], int *arg_ptr
));
113 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
114 static boolean parse_size
PARAMS((char *argv
[], int *arg_ptr
));
115 static boolean parse_true
PARAMS((char *argv
[], int *arg_ptr
));
116 static boolean parse_type
PARAMS((char *argv
[], int *arg_ptr
));
117 static boolean parse_uid
PARAMS((char *argv
[], int *arg_ptr
));
118 static boolean parse_used
PARAMS((char *argv
[], int *arg_ptr
));
119 static boolean parse_user
PARAMS((char *argv
[], int *arg_ptr
));
120 static boolean parse_version
PARAMS((char *argv
[], int *arg_ptr
));
121 static boolean parse_wholename
PARAMS((char *argv
[], int *arg_ptr
));
122 static boolean parse_xdev
PARAMS((char *argv
[], int *arg_ptr
));
123 static boolean parse_ignore_race
PARAMS((char *argv
[], int *arg_ptr
));
124 static boolean parse_noignore_race
PARAMS((char *argv
[], int *arg_ptr
));
125 static boolean parse_xtype
PARAMS((char *argv
[], int *arg_ptr
));
127 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
128 static boolean insert_type
PARAMS((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
129 static boolean insert_fprintf
PARAMS((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
130 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
131 static boolean insert_exec_ok
PARAMS((boolean (*func
)(), char *argv
[], int *arg_ptr
));
132 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
133 static boolean insert_time
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
134 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
135 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
136 static FILE *open_output_file
PARAMS((char *path
));
139 char *find_pred_name
PARAMS((PFB pred_func
));
148 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
149 If they are in some Unix versions of find, they are marked `Unix'. */
151 static struct parser_table
const parse_table
[] =
154 {"not", parse_negate
}, /* GNU */
157 {",", parse_comma
}, /* GNU */
159 {"amin", parse_amin
}, /* GNU */
160 {"and", parse_and
}, /* GNU */
161 {"anewer", parse_anewer
}, /* GNU */
162 {"atime", parse_atime
},
163 {"cmin", parse_cmin
}, /* GNU */
164 {"cnewer", parse_cnewer
}, /* GNU */
165 #ifdef UNIMPLEMENTED_UNIX
166 /* It's pretty ugly for find to know about archive formats.
167 Plus what it could do with cpio archives is very limited.
168 Better to leave it out. */
169 {"cpio", parse_cpio
}, /* Unix */
171 {"ctime", parse_ctime
},
172 {"daystart", parse_daystart
}, /* GNU */
173 {"depth", parse_depth
},
174 {"empty", parse_empty
}, /* GNU */
175 {"exec", parse_exec
},
176 {"false", parse_false
}, /* GNU */
177 {"fls", parse_fls
}, /* GNU */
178 {"follow", parse_follow
}, /* GNU, Unix */
179 {"fprint", parse_fprint
}, /* GNU */
180 {"fprint0", parse_fprint0
}, /* GNU */
181 {"fprintf", parse_fprintf
}, /* GNU */
182 {"fstype", parse_fstype
}, /* GNU, Unix */
183 {"gid", parse_gid
}, /* GNU */
184 {"group", parse_group
},
185 {"help", parse_help
}, /* GNU */
186 {"-help", parse_help
}, /* GNU */
187 {"ignore_readdir_race", parse_ignore_race
}, /* GNU */
188 {"ilname", parse_ilname
}, /* GNU */
189 {"iname", parse_iname
}, /* GNU */
190 {"inum", parse_inum
}, /* GNU, Unix */
191 {"ipath", parse_ipath
}, /* GNU, deprecated in favour of iwholename */
192 {"iregex", parse_iregex
}, /* GNU */
193 {"iwholename", parse_iwholename
}, /* GNU */
194 {"links", parse_links
},
195 {"lname", parse_lname
}, /* GNU */
196 {"ls", parse_ls
}, /* GNU, Unix */
197 {"maxdepth", parse_maxdepth
}, /* GNU */
198 {"mindepth", parse_mindepth
}, /* GNU */
199 {"mmin", parse_mmin
}, /* GNU */
200 {"mount", parse_xdev
}, /* Unix */
201 {"mtime", parse_mtime
},
202 {"name", parse_name
},
203 #ifdef UNIMPLEMENTED_UNIX
204 {"ncpio", parse_ncpio
}, /* Unix */
206 {"newer", parse_newer
},
207 {"noleaf", parse_noleaf
}, /* GNU */
208 {"nogroup", parse_nogroup
},
209 {"nouser", parse_nouser
},
210 {"noignore_readdir_race", parse_noignore_race
}, /* GNU */
212 {"or", parse_or
}, /* GNU */
214 {"path", parse_path
}, /* GNU, HP-UX, GNU prefers wholename */
215 {"perm", parse_perm
},
216 {"print", parse_print
},
217 {"print0", parse_print0
}, /* GNU */
218 {"printf", parse_printf
}, /* GNU */
219 {"prune", parse_prune
},
220 {"regex", parse_regex
}, /* GNU */
221 {"size", parse_size
},
222 {"true", parse_true
}, /* GNU */
223 {"type", parse_type
},
224 {"uid", parse_uid
}, /* GNU */
225 {"used", parse_used
}, /* GNU */
226 {"user", parse_user
},
227 {"version", parse_version
}, /* GNU */
228 {"-version", parse_version
}, /* GNU */
229 {"wholename", parse_wholename
}, /* GNU, replaces -path */
231 {"xdev", parse_xdev
},
232 {"xtype", parse_xtype
}, /* GNU */
236 /* Return a pointer to the parser function to invoke for predicate
238 Return NULL if SEARCH_NAME is not a valid predicate name. */
241 find_parser (char *search_name
)
245 if (*search_name
== '-')
247 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
248 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
249 return (parse_table
[i
].parser_func
);
253 /* The parsers are responsible to continue scanning ARGV for
254 their arguments. Each parser knows what is and isn't
257 ARGV is the argument array.
258 *ARG_PTR is the index to start at in ARGV,
259 updated to point beyond the last element consumed.
261 The predicate structure is updated with the new information. */
264 parse_amin (char **argv
, int *arg_ptr
)
266 struct predicate
*our_pred
;
268 enum comparison_type c_type
;
271 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
273 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
275 t
= cur_day_start
+ DAYSECS
- num
* 60;
276 our_pred
= insert_primary (pred_amin
);
277 our_pred
->args
.info
.kind
= c_type
;
278 our_pred
->args
.info
.negative
= t
< 0;
279 our_pred
->args
.info
.l_val
= t
;
285 parse_and (char **argv
, int *arg_ptr
)
287 struct predicate
*our_pred
;
289 our_pred
= get_new_pred ();
290 our_pred
->pred_func
= pred_and
;
292 our_pred
->p_name
= find_pred_name (pred_and
);
294 our_pred
->p_type
= BI_OP
;
295 our_pred
->p_prec
= AND_PREC
;
296 our_pred
->need_stat
= false;
301 parse_anewer (char **argv
, int *arg_ptr
)
303 struct predicate
*our_pred
;
304 struct stat stat_newer
;
306 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
308 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
309 error (1, errno
, "%s", argv
[*arg_ptr
]);
310 our_pred
= insert_primary (pred_anewer
);
311 our_pred
->args
.time
= stat_newer
.st_mtime
;
317 parse_atime (char **argv
, int *arg_ptr
)
319 return (insert_time (argv
, arg_ptr
, pred_atime
));
323 parse_close (char **argv
, int *arg_ptr
)
325 struct predicate
*our_pred
;
327 our_pred
= get_new_pred ();
328 our_pred
->pred_func
= pred_close
;
330 our_pred
->p_name
= find_pred_name (pred_close
);
332 our_pred
->p_type
= CLOSE_PAREN
;
333 our_pred
->p_prec
= NO_PREC
;
334 our_pred
->need_stat
= false;
339 parse_cmin (char **argv
, int *arg_ptr
)
341 struct predicate
*our_pred
;
343 enum comparison_type c_type
;
346 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
348 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
350 t
= cur_day_start
+ DAYSECS
- num
* 60;
351 our_pred
= insert_primary (pred_cmin
);
352 our_pred
->args
.info
.kind
= c_type
;
353 our_pred
->args
.info
.negative
= t
< 0;
354 our_pred
->args
.info
.l_val
= t
;
360 parse_cnewer (char **argv
, int *arg_ptr
)
362 struct predicate
*our_pred
;
363 struct stat stat_newer
;
365 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
367 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
368 error (1, errno
, "%s", argv
[*arg_ptr
]);
369 our_pred
= insert_primary (pred_cnewer
);
370 our_pred
->args
.time
= stat_newer
.st_mtime
;
376 parse_comma (char **argv
, int *arg_ptr
)
378 struct predicate
*our_pred
;
380 our_pred
= get_new_pred ();
381 our_pred
->pred_func
= pred_comma
;
383 our_pred
->p_name
= find_pred_name (pred_comma
);
385 our_pred
->p_type
= BI_OP
;
386 our_pred
->p_prec
= COMMA_PREC
;
387 our_pred
->need_stat
= false;
392 parse_ctime (char **argv
, int *arg_ptr
)
394 return (insert_time (argv
, arg_ptr
, pred_ctime
));
398 parse_daystart (char **argv
, int *arg_ptr
)
402 if (full_days
== false)
404 cur_day_start
+= DAYSECS
;
405 local
= localtime (&cur_day_start
);
406 cur_day_start
-= (local
407 ? (local
->tm_sec
+ local
->tm_min
* 60
408 + local
->tm_hour
* 3600)
409 : cur_day_start
% DAYSECS
);
416 parse_depth (char **argv
, int *arg_ptr
)
418 do_dir_first
= false;
423 parse_empty (char **argv
, int *arg_ptr
)
425 insert_primary (pred_empty
);
430 parse_exec (char **argv
, int *arg_ptr
)
432 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
436 parse_false (char **argv
, int *arg_ptr
)
438 struct predicate
*our_pred
;
440 our_pred
= insert_primary (pred_false
);
441 our_pred
->need_stat
= false;
446 parse_fls (char **argv
, int *arg_ptr
)
448 struct predicate
*our_pred
;
450 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
452 our_pred
= insert_primary (pred_fls
);
453 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
454 our_pred
->side_effects
= true;
455 our_pred
->no_default_print
= true;
461 parse_fprintf (char **argv
, int *arg_ptr
)
465 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
467 if (argv
[*arg_ptr
+ 1] == NULL
)
469 /* Ensure we get "missing arg" message, not "invalid arg". */
473 fp
= open_output_file (argv
[*arg_ptr
]);
475 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
479 parse_follow (char **argv
, int *arg_ptr
)
483 no_leaf_check
= true;
488 parse_fprint (char **argv
, int *arg_ptr
)
490 struct predicate
*our_pred
;
492 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
494 our_pred
= insert_primary (pred_fprint
);
495 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
496 our_pred
->side_effects
= true;
497 our_pred
->no_default_print
= true;
498 our_pred
->need_stat
= false;
504 parse_fprint0 (char **argv
, int *arg_ptr
)
506 struct predicate
*our_pred
;
508 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
510 our_pred
= insert_primary (pred_fprint0
);
511 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
512 our_pred
->side_effects
= true;
513 our_pred
->no_default_print
= true;
514 our_pred
->need_stat
= false;
520 parse_fstype (char **argv
, int *arg_ptr
)
522 struct predicate
*our_pred
;
524 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
526 our_pred
= insert_primary (pred_fstype
);
527 our_pred
->args
.str
= argv
[*arg_ptr
];
533 parse_gid (char **argv
, int *arg_ptr
)
535 return (insert_num (argv
, arg_ptr
, pred_gid
));
539 parse_group (char **argv
, int *arg_ptr
)
541 struct group
*cur_gr
;
542 struct predicate
*our_pred
;
546 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
548 cur_gr
= getgrnam (argv
[*arg_ptr
]);
551 gid
= cur_gr
->gr_gid
;
554 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
555 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
557 gid
= atoi (argv
[*arg_ptr
]);
559 our_pred
= insert_primary (pred_group
);
560 our_pred
->args
.gid
= gid
;
566 parse_help (char **argv
, int *arg_ptr
)
569 Usage: %s [path...] [expression]\n"), program_name
);
571 default path is the current directory; default expression is -print\n\
572 expression may consist of:\n\
573 operators (decreasing precedence; -and is implicit where no others are given):\n\
574 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
576 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
577 options (always true): -daystart -depth -follow --help\n\
578 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
579 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
581 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
582 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
583 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
585 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
586 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
587 -used N -user NAME -xtype [bcdpfls]\n"));
589 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
590 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
591 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
592 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
593 email to <bug-findutils@gnu.org>."));
598 parse_ilname (char **argv
, int *arg_ptr
)
600 struct predicate
*our_pred
;
602 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
604 our_pred
= insert_primary (pred_ilname
);
605 our_pred
->args
.str
= argv
[*arg_ptr
];
611 /* sanity check the fnmatch() function to make sure
612 * it really is the GNU version.
615 fnmatch_sanitycheck()
617 /* fprintf(stderr, "Performing find sanity check..."); */
618 if (0 != fnmatch("foo", "foo", 0)
619 || 0 == fnmatch("Foo", "foo", 0)
620 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
622 error (1, 0, _("sanity check of the fnmatch() library function failed."));
623 /* fprintf(stderr, "FAILED\n"); */
627 /* fprintf(stderr, "OK\n"); */
634 parse_iname (char **argv
, int *arg_ptr
)
636 struct predicate
*our_pred
;
638 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
641 fnmatch_sanitycheck();
643 our_pred
= insert_primary (pred_iname
);
644 our_pred
->need_stat
= false;
645 our_pred
->args
.str
= argv
[*arg_ptr
];
651 parse_inum (char **argv
, int *arg_ptr
)
653 return (insert_num (argv
, arg_ptr
, pred_inum
));
656 /* -ipath is deprecated (at RMS's request) in favour of
657 * -iwholename. See the node "GNU Manuals" in standards.texi
658 * for the rationale for this (basically, GNU prefers the use
659 * of the phrase "file name" to "path name"
662 parse_ipath (char **argv
, int *arg_ptr
)
665 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
667 return parse_iwholename(argv
, arg_ptr
);
671 parse_iwholename (char **argv
, int *arg_ptr
)
673 struct predicate
*our_pred
;
675 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
678 fnmatch_sanitycheck();
680 our_pred
= insert_primary (pred_ipath
);
681 our_pred
->need_stat
= false;
682 our_pred
->args
.str
= argv
[*arg_ptr
];
688 parse_iregex (char **argv
, int *arg_ptr
)
690 return insert_regex (argv
, arg_ptr
, true);
694 parse_links (char **argv
, int *arg_ptr
)
696 return (insert_num (argv
, arg_ptr
, pred_links
));
700 parse_lname (char **argv
, int *arg_ptr
)
702 struct predicate
*our_pred
;
704 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
707 fnmatch_sanitycheck();
709 our_pred
= insert_primary (pred_lname
);
710 our_pred
->args
.str
= argv
[*arg_ptr
];
716 parse_ls (char **argv
, int *arg_ptr
)
718 struct predicate
*our_pred
;
720 our_pred
= insert_primary (pred_ls
);
721 our_pred
->side_effects
= true;
722 our_pred
->no_default_print
= true;
727 parse_maxdepth (char **argv
, int *arg_ptr
)
731 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
733 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
734 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
736 maxdepth
= atoi (argv
[*arg_ptr
]);
744 parse_mindepth (char **argv
, int *arg_ptr
)
748 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
750 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
751 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
753 mindepth
= atoi (argv
[*arg_ptr
]);
761 parse_mmin (char **argv
, int *arg_ptr
)
763 struct predicate
*our_pred
;
765 enum comparison_type c_type
;
768 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
770 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
772 t
= cur_day_start
+ DAYSECS
- num
* 60;
773 our_pred
= insert_primary (pred_mmin
);
774 our_pred
->args
.info
.kind
= c_type
;
775 our_pred
->args
.info
.negative
= t
< 0;
776 our_pred
->args
.info
.l_val
= t
;
782 parse_mtime (char **argv
, int *arg_ptr
)
784 return (insert_time (argv
, arg_ptr
, pred_mtime
));
788 parse_name (char **argv
, int *arg_ptr
)
790 struct predicate
*our_pred
;
792 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
794 our_pred
= insert_primary (pred_name
);
795 our_pred
->need_stat
= false;
796 our_pred
->args
.str
= argv
[*arg_ptr
];
802 parse_negate (char **argv
, int *arg_ptr
)
804 struct predicate
*our_pred
;
806 our_pred
= get_new_pred_chk_op ();
807 our_pred
->pred_func
= pred_negate
;
809 our_pred
->p_name
= find_pred_name (pred_negate
);
811 our_pred
->p_type
= UNI_OP
;
812 our_pred
->p_prec
= NEGATE_PREC
;
813 our_pred
->need_stat
= false;
818 parse_newer (char **argv
, int *arg_ptr
)
820 struct predicate
*our_pred
;
821 struct stat stat_newer
;
823 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
825 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
826 error (1, errno
, "%s", argv
[*arg_ptr
]);
827 our_pred
= insert_primary (pred_newer
);
828 our_pred
->args
.time
= stat_newer
.st_mtime
;
834 parse_noleaf (char **argv
, int *arg_ptr
)
836 no_leaf_check
= true;
841 /* Arbitrary amount by which to increase size
842 of `uid_unused' and `gid_unused'. */
843 #define ALLOC_STEP 2048
845 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
846 char *uid_unused
= NULL
;
848 /* Number of elements in `uid_unused'. */
849 unsigned uid_allocated
;
851 /* Similar for GIDs and group entries. */
852 char *gid_unused
= NULL
;
853 unsigned gid_allocated
;
857 parse_nogroup (char **argv
, int *arg_ptr
)
859 struct predicate
*our_pred
;
861 our_pred
= insert_primary (pred_nogroup
);
863 if (gid_unused
== NULL
)
867 gid_allocated
= ALLOC_STEP
;
868 gid_unused
= xmalloc (gid_allocated
);
869 memset (gid_unused
, 1, gid_allocated
);
871 while ((gr
= getgrent ()) != NULL
)
873 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
875 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
876 gid_unused
= xrealloc (gid_unused
, new_allocated
);
877 memset (gid_unused
+ gid_allocated
, 1,
878 new_allocated
- gid_allocated
);
879 gid_allocated
= new_allocated
;
881 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
890 parse_nouser (char **argv
, int *arg_ptr
)
892 struct predicate
*our_pred
;
894 our_pred
= insert_primary (pred_nouser
);
896 if (uid_unused
== NULL
)
900 uid_allocated
= ALLOC_STEP
;
901 uid_unused
= xmalloc (uid_allocated
);
902 memset (uid_unused
, 1, uid_allocated
);
904 while ((pw
= getpwent ()) != NULL
)
906 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
908 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
909 uid_unused
= xrealloc (uid_unused
, new_allocated
);
910 memset (uid_unused
+ uid_allocated
, 1,
911 new_allocated
- uid_allocated
);
912 uid_allocated
= new_allocated
;
914 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
923 parse_ok (char **argv
, int *arg_ptr
)
925 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
929 parse_open (char **argv
, int *arg_ptr
)
931 struct predicate
*our_pred
;
933 our_pred
= get_new_pred_chk_op ();
934 our_pred
->pred_func
= pred_open
;
936 our_pred
->p_name
= find_pred_name (pred_open
);
938 our_pred
->p_type
= OPEN_PAREN
;
939 our_pred
->p_prec
= NO_PREC
;
940 our_pred
->need_stat
= false;
945 parse_or (char **argv
, int *arg_ptr
)
947 struct predicate
*our_pred
;
949 our_pred
= get_new_pred ();
950 our_pred
->pred_func
= pred_or
;
952 our_pred
->p_name
= find_pred_name (pred_or
);
954 our_pred
->p_type
= BI_OP
;
955 our_pred
->p_prec
= OR_PREC
;
956 our_pred
->need_stat
= false;
960 /* -path is deprecated (at RMS's request) in favour of
961 * -iwholename. See the node "GNU Manuals" in standards.texi
962 * for the rationale for this (basically, GNU prefers the use
963 * of the phrase "file name" to "path name".
965 * We do not issue a warning that this usage is deprecated
966 * since HPUX find supports this predicate also.
969 parse_path (char **argv
, int *arg_ptr
)
971 return parse_wholename(argv
, arg_ptr
);
975 parse_wholename (char **argv
, int *arg_ptr
)
977 struct predicate
*our_pred
;
979 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
981 our_pred
= insert_primary (pred_path
);
982 our_pred
->need_stat
= false;
983 our_pred
->args
.str
= argv
[*arg_ptr
];
989 parse_perm (char **argv
, int *arg_ptr
)
993 struct mode_change
*change
;
994 struct predicate
*our_pred
;
996 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
999 switch (argv
[*arg_ptr
][0])
1010 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1011 if (change
== MODE_INVALID
)
1012 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1013 else if (change
== MODE_MEMORY_EXHAUSTED
)
1014 error (1, 0, _("virtual memory exhausted"));
1015 perm_val
= mode_adjust (0, change
);
1018 our_pred
= insert_primary (pred_perm
);
1020 switch (argv
[*arg_ptr
][0])
1023 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1026 our_pred
->args
.perm
.kind
= PERM_ANY
;
1029 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1032 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1038 parse_print (char **argv
, int *arg_ptr
)
1040 struct predicate
*our_pred
;
1042 our_pred
= insert_primary (pred_print
);
1043 /* -print has the side effect of printing. This prevents us
1044 from doing undesired multiple printing when the user has
1045 already specified -print. */
1046 our_pred
->side_effects
= true;
1047 our_pred
->no_default_print
= true;
1048 our_pred
->need_stat
= false;
1053 parse_print0 (char **argv
, int *arg_ptr
)
1055 struct predicate
*our_pred
;
1057 our_pred
= insert_primary (pred_print0
);
1058 /* -print0 has the side effect of printing. This prevents us
1059 from doing undesired multiple printing when the user has
1060 already specified -print0. */
1061 our_pred
->side_effects
= true;
1062 our_pred
->no_default_print
= true;
1063 our_pred
->need_stat
= false;
1068 parse_printf (char **argv
, int *arg_ptr
)
1070 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1072 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1076 parse_prune (char **argv
, int *arg_ptr
)
1078 struct predicate
*our_pred
;
1080 our_pred
= insert_primary (pred_prune
);
1081 our_pred
->need_stat
= false;
1082 /* -prune has a side effect that it does not descend into
1083 the current directory. */
1084 our_pred
->side_effects
= true;
1089 parse_regex (char **argv
, int *arg_ptr
)
1091 return insert_regex (argv
, arg_ptr
, false);
1095 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1097 struct predicate
*our_pred
;
1098 struct re_pattern_buffer
*re
;
1099 const char *error_message
;
1101 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1103 our_pred
= insert_primary (pred_regex
);
1104 our_pred
->need_stat
= false;
1105 re
= (struct re_pattern_buffer
*)
1106 xmalloc (sizeof (struct re_pattern_buffer
));
1107 our_pred
->args
.regex
= re
;
1108 re
->allocated
= 100;
1109 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1116 re
->translate
= xmalloc (256);
1117 /* Map uppercase characters to corresponding lowercase ones. */
1118 for (i
= 0; i
< 256; i
++)
1119 re
->translate
[i
] = ISUPPER (i
) ? tolower (i
) : i
;
1122 re
->translate
= NULL
;
1124 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1127 error (1, 0, "%s", error_message
);
1133 parse_size (char **argv
, int *arg_ptr
)
1135 struct predicate
*our_pred
;
1137 enum comparison_type c_type
;
1141 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1143 len
= strlen (argv
[*arg_ptr
]);
1145 error (1, 0, _("invalid null argument to -size"));
1146 switch (argv
[*arg_ptr
][len
- 1])
1150 argv
[*arg_ptr
][len
- 1] = '\0';
1155 argv
[*arg_ptr
][len
- 1] = '\0';
1160 argv
[*arg_ptr
][len
- 1] = '\0';
1163 case 'M': /* Megabytes */
1164 blksize
= 1024*1024;
1165 argv
[*arg_ptr
][len
- 1] = '\0';
1168 case 'G': /* Gigabytes */
1169 blksize
= 1024*1024*1024;
1170 argv
[*arg_ptr
][len
- 1] = '\0';
1175 argv
[*arg_ptr
][len
- 1] = '\0';
1191 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1193 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1195 our_pred
= insert_primary (pred_size
);
1196 our_pred
->args
.size
.kind
= c_type
;
1197 our_pred
->args
.size
.blocksize
= blksize
;
1198 our_pred
->args
.size
.size
= num
;
1204 parse_true (char **argv
, int *arg_ptr
)
1206 struct predicate
*our_pred
;
1208 our_pred
= insert_primary (pred_true
);
1209 our_pred
->need_stat
= false;
1214 parse_type (char **argv
, int *arg_ptr
)
1216 return insert_type (argv
, arg_ptr
, pred_type
);
1220 parse_uid (char **argv
, int *arg_ptr
)
1222 return (insert_num (argv
, arg_ptr
, pred_uid
));
1226 parse_used (char **argv
, int *arg_ptr
)
1228 struct predicate
*our_pred
;
1230 enum comparison_type c_type
;
1233 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1235 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1237 t
= num_days
* DAYSECS
;
1238 our_pred
= insert_primary (pred_used
);
1239 our_pred
->args
.info
.kind
= c_type
;
1240 our_pred
->args
.info
.negative
= t
< 0;
1241 our_pred
->args
.info
.l_val
= t
;
1247 parse_user (char **argv
, int *arg_ptr
)
1249 struct passwd
*cur_pwd
;
1250 struct predicate
*our_pred
;
1254 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1256 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1258 if (cur_pwd
!= NULL
)
1259 uid
= cur_pwd
->pw_uid
;
1262 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1263 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1265 uid
= atoi (argv
[*arg_ptr
]);
1267 our_pred
= insert_primary (pred_user
);
1268 our_pred
->args
.uid
= uid
;
1274 parse_version (char **argv
, int *arg_ptr
)
1276 extern char *version_string
;
1279 printf (_("GNU find version %s\n"), version_string
);
1284 parse_xdev (char **argv
, int *arg_ptr
)
1286 stay_on_filesystem
= true;
1291 parse_ignore_race (char **argv
, int *arg_ptr
)
1293 ignore_readdir_race
= true;
1298 parse_noignore_race (char **argv
, int *arg_ptr
)
1300 ignore_readdir_race
= false;
1305 parse_xtype (char **argv
, int *arg_ptr
)
1307 return insert_type (argv
, arg_ptr
, pred_xtype
);
1311 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1314 struct predicate
*our_pred
;
1316 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1317 || (strlen (argv
[*arg_ptr
]) != 1))
1319 switch (argv
[*arg_ptr
][0])
1321 case 'b': /* block special */
1322 type_cell
= S_IFBLK
;
1324 case 'c': /* character special */
1325 type_cell
= S_IFCHR
;
1327 case 'd': /* directory */
1328 type_cell
= S_IFDIR
;
1330 case 'f': /* regular file */
1331 type_cell
= S_IFREG
;
1334 case 'l': /* symbolic link */
1335 type_cell
= S_IFLNK
;
1339 case 'p': /* pipe */
1340 type_cell
= S_IFIFO
;
1344 case 's': /* socket */
1345 type_cell
= S_IFSOCK
;
1349 case 'D': /* Solaris door */
1350 type_cell
= S_IFDOOR
;
1353 default: /* None of the above ... nuke 'em. */
1356 our_pred
= insert_primary (which_pred
);
1357 our_pred
->args
.type
= type_cell
;
1358 (*arg_ptr
)++; /* Move on to next argument. */
1362 /* If true, we've determined that the current fprintf predicate
1363 uses stat information. */
1364 static boolean fprintf_stat_needed
;
1367 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1369 char *format
; /* Beginning of unprocessed format string. */
1370 register char *scan
; /* Current address in scanning `format'. */
1371 register char *scan2
; /* Address inside of element being scanned. */
1372 struct segment
**segmentp
; /* Address of current segment. */
1373 struct predicate
*our_pred
;
1375 format
= argv
[(*arg_ptr
)++];
1377 fprintf_stat_needed
= false; /* Might be overridden later. */
1378 our_pred
= insert_primary (func
);
1379 our_pred
->side_effects
= true;
1380 our_pred
->no_default_print
= true;
1381 our_pred
->args
.printf_vec
.stream
= fp
;
1382 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1385 for (scan
= format
; *scan
; scan
++)
1390 if (*scan2
>= '0' && *scan2
<= '7')
1394 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1396 n
= 8 * n
+ *scan2
- '0';
1411 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1412 our_pred
->need_stat
= fprintf_stat_needed
;
1430 /* *scan = '\\'; * it already is */
1434 _("warning: unrecognized escape `\\%c'"), *scan2
);
1439 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1441 format
= scan2
+ 1; /* Move past the escape. */
1442 scan
= scan2
; /* Incremented immediately by `for'. */
1444 else if (*scan
== '%')
1448 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1454 /* Scan past flags, width and precision, to verify kind. */
1455 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1457 while (ISDIGIT (*scan2
))
1460 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1462 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2
))
1464 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1469 else if (strchr ("ACT", *scan2
) && scan2
[1])
1471 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1472 *scan2
| (scan2
[1] << 8));
1479 /* An unrecognized % escape. Print the char after the %. */
1480 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1482 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1491 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1492 our_pred
->need_stat
= fprintf_stat_needed
;
1496 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1497 from the text in FORMAT, which has length LEN.
1498 Return the address of the `next' pointer of the new segment. */
1500 static struct segment
**
1501 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1505 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1507 (*segment
)->kind
= kind
;
1508 (*segment
)->next
= NULL
;
1509 (*segment
)->text_len
= len
;
1511 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1512 strncpy (fmt
, format
, len
);
1515 switch (kind
& 0xff)
1517 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1518 case KIND_STOP
: /* Terminate argument, no newline. */
1521 case 'a': /* atime in `ctime' format */
1522 case 'A': /* atime in user-specified strftime format */
1523 case 'b': /* size in 512-byte blocks */
1524 case 'c': /* ctime in `ctime' format */
1525 case 'C': /* ctime in user-specified strftime format */
1526 case 'F': /* filesystem type */
1527 case 'G': /* GID number */
1528 case 'g': /* group name */
1529 case 'i': /* inode number */
1530 case 'k': /* size in 1K blocks */
1531 case 'l': /* object of symlink */
1532 case 'n': /* number of links */
1533 case 's': /* size in bytes */
1534 case 't': /* mtime in `ctime' format */
1535 case 'T': /* mtime in user-specified strftime format */
1536 case 'U': /* UID number */
1537 case 'u': /* user name */
1538 fprintf_stat_needed
= true;
1540 case 'f': /* basename of path */
1541 case 'h': /* leading directories part of path */
1542 case 'H': /* ARGV element file was found under */
1543 case 'p': /* pathname */
1544 case 'P': /* pathname with ARGV element stripped */
1548 case 'd': /* depth in search tree (0 = ARGV element) */
1552 case 'm': /* mode as octal number (perms only) */
1554 fprintf_stat_needed
= true;
1559 return (&(*segment
)->next
);
1562 /* handles both exec and ok predicate */
1564 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1566 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1567 int num_paths
; /* Number of args with path replacements. */
1568 int path_pos
; /* Index in array of path replacements. */
1569 int vec_pos
; /* Index in array of args. */
1570 struct predicate
*our_pred
;
1571 struct exec_val
*execp
; /* Pointer for efficiency. */
1573 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1576 /* Count the number of args with path replacements, up until the ';'. */
1578 for (end
= start
, num_paths
= 0;
1580 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1582 if (strstr (argv
[end
], "{}"))
1584 /* Fail if no command given or no semicolon found. */
1585 if ((end
== start
) || (argv
[end
] == NULL
))
1591 our_pred
= insert_primary (func
);
1592 our_pred
->side_effects
= true;
1593 our_pred
->no_default_print
= true;
1594 execp
= &our_pred
->args
.exec_vec
;
1596 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1597 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1598 /* Record the positions of all args, and the args with path replacements. */
1599 for (end
= start
, path_pos
= vec_pos
= 0;
1601 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1606 execp
->paths
[path_pos
].count
= 0;
1607 for (p
= argv
[end
]; *p
; ++p
)
1608 if (p
[0] == '{' && p
[1] == '}')
1610 execp
->paths
[path_pos
].count
++;
1613 if (execp
->paths
[path_pos
].count
)
1615 execp
->paths
[path_pos
].offset
= vec_pos
;
1616 execp
->paths
[path_pos
].origarg
= argv
[end
];
1619 execp
->vec
[vec_pos
++] = argv
[end
];
1621 execp
->paths
[path_pos
].offset
= -1;
1622 execp
->vec
[vec_pos
] = NULL
;
1624 if (argv
[end
] == NULL
)
1631 /* Get a number of days and comparison type.
1632 STR is the ASCII representation.
1633 Set *NUM_DAYS to the number of days, taken as being from
1634 the current moment (or possibly midnight). Thus the sense of the
1635 comparison type appears to be reversed.
1636 Set *COMP_TYPE to the kind of comparison that is requested.
1638 Return true if all okay, false if input error.
1640 Used by -atime, -ctime and -mtime (parsers) to
1641 get the appropriate information for a time predicate processor. */
1644 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1646 boolean r
= get_num (str
, num_days
, comp_type
);
1650 case COMP_LT
: *comp_type
= COMP_GT
; break;
1651 case COMP_GT
: *comp_type
= COMP_LT
; break;
1657 /* Insert a time predicate PRED.
1658 ARGV is a pointer to the argument array.
1659 ARG_PTR is a pointer to an index into the array, incremented if
1662 Return true if input is valid, false if not.
1664 A new predicate node is assigned, along with an argument node
1665 obtained with malloc.
1667 Used by -atime, -ctime, and -mtime parsers. */
1670 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1672 struct predicate
*our_pred
;
1674 enum comparison_type c_type
;
1677 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1679 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1682 /* Figure out the timestamp value we are looking for. */
1683 t
= ( cur_day_start
- num_days
* DAYSECS
1684 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1688 /* We introduce a scope in which 'val' can be declared, for the
1689 * benefit of compilers that are really C89 compilers
1690 * which support intmax_t because config.h #defines it
1692 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1693 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1696 /* Check for possibility of an overflow */
1697 if ( (intmax_t)t
!= val
)
1699 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1704 our_pred
= insert_primary (pred
);
1705 our_pred
->args
.info
.kind
= c_type
;
1706 our_pred
->args
.info
.negative
= t
< 0;
1707 our_pred
->args
.info
.l_val
= t
;
1710 printf (_("inserting %s\n"), our_pred
->p_name
);
1711 printf (_(" type: %s %s "),
1712 (c_type
== COMP_GT
) ? "gt" :
1713 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1714 (c_type
== COMP_GT
) ? " >" :
1715 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1716 t
= our_pred
->args
.info
.l_val
;
1717 printf ("%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1718 if (c_type
== COMP_EQ
)
1720 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1721 printf (" < %ju %s",
1722 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1723 our_pred
->args
.info
.l_val
-= DAYSECS
;
1729 /* Get a number with comparision information.
1730 The sense of the comparision information is 'normal'; that is,
1731 '+' looks for a count > than the number and '-' less than.
1733 STR is the ASCII representation of the number.
1734 Set *NUM to the number.
1735 Set *COMP_TYPE to the kind of comparison that is requested.
1737 Return true if all okay, false if input error. */
1740 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1742 int len_num
; /* Length of field. */
1749 *comp_type
= COMP_GT
;
1753 *comp_type
= COMP_LT
;
1757 *comp_type
= COMP_EQ
;
1761 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1764 /* Insert a number predicate.
1765 ARGV is a pointer to the argument array.
1766 *ARG_PTR is an index into ARGV, incremented if all went well.
1767 *PRED is the predicate processor to insert.
1769 Return true if input is valid, false if error.
1771 A new predicate node is assigned, along with an argument node
1772 obtained with malloc.
1774 Used by -inum and -links parsers. */
1777 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
1779 struct predicate
*our_pred
;
1781 enum comparison_type c_type
;
1783 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1785 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1787 our_pred
= insert_primary (pred
);
1788 our_pred
->args
.info
.kind
= c_type
;
1789 our_pred
->args
.info
.l_val
= num
;
1792 printf (_("inserting %s\n"), our_pred
->p_name
);
1793 printf (_(" type: %s %s "),
1794 (c_type
== COMP_GT
) ? "gt" :
1795 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1796 (c_type
== COMP_GT
) ? " >" :
1797 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
1798 printf ("%ju\n", our_pred
->args
.info
.l_val
);
1804 open_output_file (char *path
)
1808 if (!strcmp (path
, "/dev/stderr"))
1810 else if (!strcmp (path
, "/dev/stdout"))
1812 f
= fopen (path
, "w");
1814 error (1, errno
, "%s", path
);