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 "modechange.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 if (0 != fnmatch("foo", "foo", 0)
618 || 0 == fnmatch("Foo", "foo", 0)
619 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
621 error (1, 0, _("sanity check of the fnmatch() library function failed."));
631 parse_iname (char **argv
, int *arg_ptr
)
633 struct predicate
*our_pred
;
635 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
638 fnmatch_sanitycheck();
640 our_pred
= insert_primary (pred_iname
);
641 our_pred
->need_stat
= false;
642 our_pred
->args
.str
= argv
[*arg_ptr
];
648 parse_inum (char **argv
, int *arg_ptr
)
650 return (insert_num (argv
, arg_ptr
, pred_inum
));
653 /* -ipath is deprecated (at RMS's request) in favour of
654 * -iwholename. See the node "GNU Manuals" in standards.texi
655 * for the rationale for this (basically, GNU prefers the use
656 * of the phrase "file name" to "path name"
659 parse_ipath (char **argv
, int *arg_ptr
)
662 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
664 return parse_iwholename(argv
, arg_ptr
);
668 parse_iwholename (char **argv
, int *arg_ptr
)
670 struct predicate
*our_pred
;
672 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
675 fnmatch_sanitycheck();
677 our_pred
= insert_primary (pred_ipath
);
678 our_pred
->need_stat
= false;
679 our_pred
->args
.str
= argv
[*arg_ptr
];
685 parse_iregex (char **argv
, int *arg_ptr
)
687 return insert_regex (argv
, arg_ptr
, true);
691 parse_links (char **argv
, int *arg_ptr
)
693 return (insert_num (argv
, arg_ptr
, pred_links
));
697 parse_lname (char **argv
, int *arg_ptr
)
699 struct predicate
*our_pred
;
701 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
704 fnmatch_sanitycheck();
706 our_pred
= insert_primary (pred_lname
);
707 our_pred
->args
.str
= argv
[*arg_ptr
];
713 parse_ls (char **argv
, int *arg_ptr
)
715 struct predicate
*our_pred
;
717 our_pred
= insert_primary (pred_ls
);
718 our_pred
->side_effects
= true;
719 our_pred
->no_default_print
= true;
724 parse_maxdepth (char **argv
, int *arg_ptr
)
728 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
730 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
731 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
733 maxdepth
= atoi (argv
[*arg_ptr
]);
741 parse_mindepth (char **argv
, int *arg_ptr
)
745 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
747 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
748 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
750 mindepth
= atoi (argv
[*arg_ptr
]);
758 parse_mmin (char **argv
, int *arg_ptr
)
760 struct predicate
*our_pred
;
762 enum comparison_type c_type
;
765 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
767 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
769 t
= cur_day_start
+ DAYSECS
- num
* 60;
770 our_pred
= insert_primary (pred_mmin
);
771 our_pred
->args
.info
.kind
= c_type
;
772 our_pred
->args
.info
.negative
= t
< 0;
773 our_pred
->args
.info
.l_val
= t
;
779 parse_mtime (char **argv
, int *arg_ptr
)
781 return (insert_time (argv
, arg_ptr
, pred_mtime
));
785 parse_name (char **argv
, int *arg_ptr
)
787 struct predicate
*our_pred
;
789 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
791 our_pred
= insert_primary (pred_name
);
792 our_pred
->need_stat
= false;
793 our_pred
->args
.str
= argv
[*arg_ptr
];
799 parse_negate (char **argv
, int *arg_ptr
)
801 struct predicate
*our_pred
;
803 our_pred
= get_new_pred_chk_op ();
804 our_pred
->pred_func
= pred_negate
;
806 our_pred
->p_name
= find_pred_name (pred_negate
);
808 our_pred
->p_type
= UNI_OP
;
809 our_pred
->p_prec
= NEGATE_PREC
;
810 our_pred
->need_stat
= false;
815 parse_newer (char **argv
, int *arg_ptr
)
817 struct predicate
*our_pred
;
818 struct stat stat_newer
;
820 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
822 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
823 error (1, errno
, "%s", argv
[*arg_ptr
]);
824 our_pred
= insert_primary (pred_newer
);
825 our_pred
->args
.time
= stat_newer
.st_mtime
;
831 parse_noleaf (char **argv
, int *arg_ptr
)
833 no_leaf_check
= true;
838 /* Arbitrary amount by which to increase size
839 of `uid_unused' and `gid_unused'. */
840 #define ALLOC_STEP 2048
842 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
843 char *uid_unused
= NULL
;
845 /* Number of elements in `uid_unused'. */
846 unsigned uid_allocated
;
848 /* Similar for GIDs and group entries. */
849 char *gid_unused
= NULL
;
850 unsigned gid_allocated
;
854 parse_nogroup (char **argv
, int *arg_ptr
)
856 struct predicate
*our_pred
;
858 our_pred
= insert_primary (pred_nogroup
);
860 if (gid_unused
== NULL
)
864 gid_allocated
= ALLOC_STEP
;
865 gid_unused
= xmalloc (gid_allocated
);
866 memset (gid_unused
, 1, gid_allocated
);
868 while ((gr
= getgrent ()) != NULL
)
870 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
872 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
873 gid_unused
= xrealloc (gid_unused
, new_allocated
);
874 memset (gid_unused
+ gid_allocated
, 1,
875 new_allocated
- gid_allocated
);
876 gid_allocated
= new_allocated
;
878 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
887 parse_nouser (char **argv
, int *arg_ptr
)
889 struct predicate
*our_pred
;
891 our_pred
= insert_primary (pred_nouser
);
893 if (uid_unused
== NULL
)
897 uid_allocated
= ALLOC_STEP
;
898 uid_unused
= xmalloc (uid_allocated
);
899 memset (uid_unused
, 1, uid_allocated
);
901 while ((pw
= getpwent ()) != NULL
)
903 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
905 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
906 uid_unused
= xrealloc (uid_unused
, new_allocated
);
907 memset (uid_unused
+ uid_allocated
, 1,
908 new_allocated
- uid_allocated
);
909 uid_allocated
= new_allocated
;
911 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
920 parse_ok (char **argv
, int *arg_ptr
)
922 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
926 parse_open (char **argv
, int *arg_ptr
)
928 struct predicate
*our_pred
;
930 our_pred
= get_new_pred_chk_op ();
931 our_pred
->pred_func
= pred_open
;
933 our_pred
->p_name
= find_pred_name (pred_open
);
935 our_pred
->p_type
= OPEN_PAREN
;
936 our_pred
->p_prec
= NO_PREC
;
937 our_pred
->need_stat
= false;
942 parse_or (char **argv
, int *arg_ptr
)
944 struct predicate
*our_pred
;
946 our_pred
= get_new_pred ();
947 our_pred
->pred_func
= pred_or
;
949 our_pred
->p_name
= find_pred_name (pred_or
);
951 our_pred
->p_type
= BI_OP
;
952 our_pred
->p_prec
= OR_PREC
;
953 our_pred
->need_stat
= false;
957 /* -path is deprecated (at RMS's request) in favour of
958 * -iwholename. See the node "GNU Manuals" in standards.texi
959 * for the rationale for this (basically, GNU prefers the use
960 * of the phrase "file name" to "path name".
962 * We do not issue a warning that this usage is deprecated
963 * since HPUX find supports this predicate also.
966 parse_path (char **argv
, int *arg_ptr
)
968 return parse_wholename(argv
, arg_ptr
);
972 parse_wholename (char **argv
, int *arg_ptr
)
974 struct predicate
*our_pred
;
976 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
978 our_pred
= insert_primary (pred_path
);
979 our_pred
->need_stat
= false;
980 our_pred
->args
.str
= argv
[*arg_ptr
];
986 parse_perm (char **argv
, int *arg_ptr
)
990 struct mode_change
*change
;
991 struct predicate
*our_pred
;
993 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
996 switch (argv
[*arg_ptr
][0])
1007 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1008 if (change
== MODE_INVALID
)
1009 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1010 else if (change
== MODE_MEMORY_EXHAUSTED
)
1011 error (1, 0, _("virtual memory exhausted"));
1012 perm_val
= mode_adjust (0, change
);
1015 our_pred
= insert_primary (pred_perm
);
1017 switch (argv
[*arg_ptr
][0])
1020 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1023 our_pred
->args
.perm
.kind
= PERM_ANY
;
1026 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1029 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1035 parse_print (char **argv
, int *arg_ptr
)
1037 struct predicate
*our_pred
;
1039 our_pred
= insert_primary (pred_print
);
1040 /* -print has the side effect of printing. This prevents us
1041 from doing undesired multiple printing when the user has
1042 already specified -print. */
1043 our_pred
->side_effects
= true;
1044 our_pred
->no_default_print
= true;
1045 our_pred
->need_stat
= false;
1050 parse_print0 (char **argv
, int *arg_ptr
)
1052 struct predicate
*our_pred
;
1054 our_pred
= insert_primary (pred_print0
);
1055 /* -print0 has the side effect of printing. This prevents us
1056 from doing undesired multiple printing when the user has
1057 already specified -print0. */
1058 our_pred
->side_effects
= true;
1059 our_pred
->no_default_print
= true;
1060 our_pred
->need_stat
= false;
1065 parse_printf (char **argv
, int *arg_ptr
)
1067 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1069 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1073 parse_prune (char **argv
, int *arg_ptr
)
1075 struct predicate
*our_pred
;
1077 our_pred
= insert_primary (pred_prune
);
1078 our_pred
->need_stat
= false;
1079 /* -prune has a side effect that it does not descend into
1080 the current directory. */
1081 our_pred
->side_effects
= true;
1086 parse_regex (char **argv
, int *arg_ptr
)
1088 return insert_regex (argv
, arg_ptr
, false);
1092 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1094 struct predicate
*our_pred
;
1095 struct re_pattern_buffer
*re
;
1096 const char *error_message
;
1098 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1100 our_pred
= insert_primary (pred_regex
);
1101 our_pred
->need_stat
= false;
1102 re
= (struct re_pattern_buffer
*)
1103 xmalloc (sizeof (struct re_pattern_buffer
));
1104 our_pred
->args
.regex
= re
;
1105 re
->allocated
= 100;
1106 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1113 re
->translate
= xmalloc (256);
1114 /* Map uppercase characters to corresponding lowercase ones. */
1115 for (i
= 0; i
< 256; i
++)
1116 re
->translate
[i
] = ISUPPER (i
) ? tolower (i
) : i
;
1119 re
->translate
= NULL
;
1121 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1124 error (1, 0, "%s", error_message
);
1130 parse_size (char **argv
, int *arg_ptr
)
1132 struct predicate
*our_pred
;
1134 enum comparison_type c_type
;
1138 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1140 len
= strlen (argv
[*arg_ptr
]);
1142 error (1, 0, _("invalid null argument to -size"));
1143 switch (argv
[*arg_ptr
][len
- 1])
1147 argv
[*arg_ptr
][len
- 1] = '\0';
1152 argv
[*arg_ptr
][len
- 1] = '\0';
1157 argv
[*arg_ptr
][len
- 1] = '\0';
1160 case 'M': /* Megabytes */
1161 blksize
= 1024*1024;
1162 argv
[*arg_ptr
][len
- 1] = '\0';
1165 case 'G': /* Gigabytes */
1166 blksize
= 1024*1024*1024;
1167 argv
[*arg_ptr
][len
- 1] = '\0';
1172 argv
[*arg_ptr
][len
- 1] = '\0';
1188 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1190 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1192 our_pred
= insert_primary (pred_size
);
1193 our_pred
->args
.size
.kind
= c_type
;
1194 our_pred
->args
.size
.blocksize
= blksize
;
1195 our_pred
->args
.size
.size
= num
;
1201 parse_true (char **argv
, int *arg_ptr
)
1203 struct predicate
*our_pred
;
1205 our_pred
= insert_primary (pred_true
);
1206 our_pred
->need_stat
= false;
1211 parse_type (char **argv
, int *arg_ptr
)
1213 return insert_type (argv
, arg_ptr
, pred_type
);
1217 parse_uid (char **argv
, int *arg_ptr
)
1219 return (insert_num (argv
, arg_ptr
, pred_uid
));
1223 parse_used (char **argv
, int *arg_ptr
)
1225 struct predicate
*our_pred
;
1227 enum comparison_type c_type
;
1230 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1232 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1234 t
= num_days
* DAYSECS
;
1235 our_pred
= insert_primary (pred_used
);
1236 our_pred
->args
.info
.kind
= c_type
;
1237 our_pred
->args
.info
.negative
= t
< 0;
1238 our_pred
->args
.info
.l_val
= t
;
1244 parse_user (char **argv
, int *arg_ptr
)
1246 struct passwd
*cur_pwd
;
1247 struct predicate
*our_pred
;
1251 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1253 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1255 if (cur_pwd
!= NULL
)
1256 uid
= cur_pwd
->pw_uid
;
1259 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1260 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1262 uid
= atoi (argv
[*arg_ptr
]);
1264 our_pred
= insert_primary (pred_user
);
1265 our_pred
->args
.uid
= uid
;
1271 parse_version (char **argv
, int *arg_ptr
)
1273 extern char *version_string
;
1276 printf (_("GNU find version %s\n"), version_string
);
1281 parse_xdev (char **argv
, int *arg_ptr
)
1283 stay_on_filesystem
= true;
1288 parse_ignore_race (char **argv
, int *arg_ptr
)
1290 ignore_readdir_race
= true;
1295 parse_noignore_race (char **argv
, int *arg_ptr
)
1297 ignore_readdir_race
= false;
1302 parse_xtype (char **argv
, int *arg_ptr
)
1304 return insert_type (argv
, arg_ptr
, pred_xtype
);
1308 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1311 struct predicate
*our_pred
;
1313 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1314 || (strlen (argv
[*arg_ptr
]) != 1))
1316 switch (argv
[*arg_ptr
][0])
1318 case 'b': /* block special */
1319 type_cell
= S_IFBLK
;
1321 case 'c': /* character special */
1322 type_cell
= S_IFCHR
;
1324 case 'd': /* directory */
1325 type_cell
= S_IFDIR
;
1327 case 'f': /* regular file */
1328 type_cell
= S_IFREG
;
1331 case 'l': /* symbolic link */
1332 type_cell
= S_IFLNK
;
1336 case 'p': /* pipe */
1337 type_cell
= S_IFIFO
;
1341 case 's': /* socket */
1342 type_cell
= S_IFSOCK
;
1346 case 'D': /* Solaris door */
1347 type_cell
= S_IFDOOR
;
1350 default: /* None of the above ... nuke 'em. */
1353 our_pred
= insert_primary (which_pred
);
1354 our_pred
->args
.type
= type_cell
;
1355 (*arg_ptr
)++; /* Move on to next argument. */
1359 /* If true, we've determined that the current fprintf predicate
1360 uses stat information. */
1361 static boolean fprintf_stat_needed
;
1364 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1366 char *format
; /* Beginning of unprocessed format string. */
1367 register char *scan
; /* Current address in scanning `format'. */
1368 register char *scan2
; /* Address inside of element being scanned. */
1369 struct segment
**segmentp
; /* Address of current segment. */
1370 struct predicate
*our_pred
;
1372 format
= argv
[(*arg_ptr
)++];
1374 fprintf_stat_needed
= false; /* Might be overridden later. */
1375 our_pred
= insert_primary (func
);
1376 our_pred
->side_effects
= true;
1377 our_pred
->no_default_print
= true;
1378 our_pred
->args
.printf_vec
.stream
= fp
;
1379 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1382 for (scan
= format
; *scan
; scan
++)
1387 if (*scan2
>= '0' && *scan2
<= '7')
1391 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1393 n
= 8 * n
+ *scan2
- '0';
1408 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1409 our_pred
->need_stat
= fprintf_stat_needed
;
1427 /* *scan = '\\'; * it already is */
1431 _("warning: unrecognized escape `\\%c'"), *scan2
);
1436 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1438 format
= scan2
+ 1; /* Move past the escape. */
1439 scan
= scan2
; /* Incremented immediately by `for'. */
1441 else if (*scan
== '%')
1445 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1451 /* Scan past flags, width and precision, to verify kind. */
1452 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1454 while (ISDIGIT (*scan2
))
1457 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1459 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2
))
1461 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1466 else if (strchr ("ACT", *scan2
) && scan2
[1])
1468 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1469 *scan2
| (scan2
[1] << 8));
1476 /* An unrecognized % escape. Print the char after the %. */
1477 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1479 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1488 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1489 our_pred
->need_stat
= fprintf_stat_needed
;
1493 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1494 from the text in FORMAT, which has length LEN.
1495 Return the address of the `next' pointer of the new segment. */
1497 static struct segment
**
1498 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1502 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1504 (*segment
)->kind
= kind
;
1505 (*segment
)->next
= NULL
;
1506 (*segment
)->text_len
= len
;
1508 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1509 strncpy (fmt
, format
, len
);
1512 switch (kind
& 0xff)
1514 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1515 case KIND_STOP
: /* Terminate argument, no newline. */
1518 case 'a': /* atime in `ctime' format */
1519 case 'A': /* atime in user-specified strftime format */
1520 case 'b': /* size in 512-byte blocks */
1521 case 'c': /* ctime in `ctime' format */
1522 case 'C': /* ctime in user-specified strftime format */
1523 case 'F': /* filesystem type */
1524 case 'G': /* GID number */
1525 case 'g': /* group name */
1526 case 'i': /* inode number */
1527 case 'k': /* size in 1K blocks */
1528 case 'l': /* object of symlink */
1529 case 'n': /* number of links */
1530 case 's': /* size in bytes */
1531 case 't': /* mtime in `ctime' format */
1532 case 'T': /* mtime in user-specified strftime format */
1533 case 'U': /* UID number */
1534 case 'u': /* user name */
1535 fprintf_stat_needed
= true;
1537 case 'f': /* basename of path */
1538 case 'h': /* leading directories part of path */
1539 case 'H': /* ARGV element file was found under */
1540 case 'p': /* pathname */
1541 case 'P': /* pathname with ARGV element stripped */
1545 case 'd': /* depth in search tree (0 = ARGV element) */
1549 case 'm': /* mode as octal number (perms only) */
1551 fprintf_stat_needed
= true;
1556 return (&(*segment
)->next
);
1559 /* handles both exec and ok predicate */
1561 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1563 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1564 int num_paths
; /* Number of args with path replacements. */
1565 int path_pos
; /* Index in array of path replacements. */
1566 int vec_pos
; /* Index in array of args. */
1567 struct predicate
*our_pred
;
1568 struct exec_val
*execp
; /* Pointer for efficiency. */
1570 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1573 /* Count the number of args with path replacements, up until the ';'. */
1575 for (end
= start
, num_paths
= 0;
1577 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1579 if (strstr (argv
[end
], "{}"))
1581 /* Fail if no command given or no semicolon found. */
1582 if ((end
== start
) || (argv
[end
] == NULL
))
1588 our_pred
= insert_primary (func
);
1589 our_pred
->side_effects
= true;
1590 our_pred
->no_default_print
= true;
1591 execp
= &our_pred
->args
.exec_vec
;
1593 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1594 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1595 /* Record the positions of all args, and the args with path replacements. */
1596 for (end
= start
, path_pos
= vec_pos
= 0;
1598 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1603 execp
->paths
[path_pos
].count
= 0;
1604 for (p
= argv
[end
]; *p
; ++p
)
1605 if (p
[0] == '{' && p
[1] == '}')
1607 execp
->paths
[path_pos
].count
++;
1610 if (execp
->paths
[path_pos
].count
)
1612 execp
->paths
[path_pos
].offset
= vec_pos
;
1613 execp
->paths
[path_pos
].origarg
= argv
[end
];
1616 execp
->vec
[vec_pos
++] = argv
[end
];
1618 execp
->paths
[path_pos
].offset
= -1;
1619 execp
->vec
[vec_pos
] = NULL
;
1621 if (argv
[end
] == NULL
)
1628 /* Get a number of days and comparison type.
1629 STR is the ASCII representation.
1630 Set *NUM_DAYS to the number of days, taken as being from
1631 the current moment (or possibly midnight). Thus the sense of the
1632 comparison type appears to be reversed.
1633 Set *COMP_TYPE to the kind of comparison that is requested.
1635 Return true if all okay, false if input error.
1637 Used by -atime, -ctime and -mtime (parsers) to
1638 get the appropriate information for a time predicate processor. */
1641 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1643 boolean r
= get_num (str
, num_days
, comp_type
);
1647 case COMP_LT
: *comp_type
= COMP_GT
; break;
1648 case COMP_GT
: *comp_type
= COMP_LT
; break;
1654 /* Insert a time predicate PRED.
1655 ARGV is a pointer to the argument array.
1656 ARG_PTR is a pointer to an index into the array, incremented if
1659 Return true if input is valid, false if not.
1661 A new predicate node is assigned, along with an argument node
1662 obtained with malloc.
1664 Used by -atime, -ctime, and -mtime parsers. */
1667 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1669 struct predicate
*our_pred
;
1671 enum comparison_type c_type
;
1674 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1676 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1679 /* Figure out the timestamp value we are looking for. */
1680 t
= ( cur_day_start
- num_days
* DAYSECS
1681 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1685 /* We introduce a scope in which 'val' can be declared, for the
1686 * benefit of compilers that are really C89 compilers
1687 * which support intmax_t because config.h #defines it
1689 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1690 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1693 /* Check for possibility of an overflow */
1694 if ( (intmax_t)t
!= val
)
1696 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1701 our_pred
= insert_primary (pred
);
1702 our_pred
->args
.info
.kind
= c_type
;
1703 our_pred
->args
.info
.negative
= t
< 0;
1704 our_pred
->args
.info
.l_val
= t
;
1707 printf (_("inserting %s\n"), our_pred
->p_name
);
1708 printf (_(" type: %s %s "),
1709 (c_type
== COMP_GT
) ? "gt" :
1710 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1711 (c_type
== COMP_GT
) ? " >" :
1712 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1713 t
= our_pred
->args
.info
.l_val
;
1714 printf ("%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1715 if (c_type
== COMP_EQ
)
1717 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1718 printf (" < %ju %s",
1719 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1720 our_pred
->args
.info
.l_val
-= DAYSECS
;
1726 /* Get a number with comparision information.
1727 The sense of the comparision information is 'normal'; that is,
1728 '+' looks for a count > than the number and '-' less than.
1730 STR is the ASCII representation of the number.
1731 Set *NUM to the number.
1732 Set *COMP_TYPE to the kind of comparison that is requested.
1734 Return true if all okay, false if input error. */
1737 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1739 int len_num
; /* Length of field. */
1746 *comp_type
= COMP_GT
;
1750 *comp_type
= COMP_LT
;
1754 *comp_type
= COMP_EQ
;
1758 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1761 /* Insert a number predicate.
1762 ARGV is a pointer to the argument array.
1763 *ARG_PTR is an index into ARGV, incremented if all went well.
1764 *PRED is the predicate processor to insert.
1766 Return true if input is valid, false if error.
1768 A new predicate node is assigned, along with an argument node
1769 obtained with malloc.
1771 Used by -inum and -links parsers. */
1774 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
1776 struct predicate
*our_pred
;
1778 enum comparison_type c_type
;
1780 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1782 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1784 our_pred
= insert_primary (pred
);
1785 our_pred
->args
.info
.kind
= c_type
;
1786 our_pred
->args
.info
.l_val
= num
;
1789 printf (_("inserting %s\n"), our_pred
->p_name
);
1790 printf (_(" type: %s %s "),
1791 (c_type
== COMP_GT
) ? "gt" :
1792 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1793 (c_type
== COMP_GT
) ? " >" :
1794 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
1795 printf ("%ju\n", our_pred
->args
.info
.l_val
);
1801 open_output_file (char *path
)
1805 if (!strcmp (path
, "/dev/stderr"))
1807 else if (!strcmp (path
, "/dev/stdout"))
1809 f
= fopen (path
, "w");
1811 error (1, errno
, "%s", path
);