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 # define N_(String) (String)
43 #if !defined (isascii) || defined (STDC_HEADERS)
50 #define ISDIGIT(c) (isascii (c) && isdigit (c))
51 #define ISUPPER(c) (isascii (c) && isupper (c))
60 static boolean parse_amin
PARAMS((char *argv
[], int *arg_ptr
));
61 static boolean parse_and
PARAMS((char *argv
[], int *arg_ptr
));
62 static boolean parse_anewer
PARAMS((char *argv
[], int *arg_ptr
));
63 static boolean parse_atime
PARAMS((char *argv
[], int *arg_ptr
));
64 boolean parse_close
PARAMS((char *argv
[], int *arg_ptr
));
65 static boolean parse_cmin
PARAMS((char *argv
[], int *arg_ptr
));
66 static boolean parse_cnewer
PARAMS((char *argv
[], int *arg_ptr
));
67 static boolean parse_comma
PARAMS((char *argv
[], int *arg_ptr
));
68 static boolean parse_ctime
PARAMS((char *argv
[], int *arg_ptr
));
69 static boolean parse_daystart
PARAMS((char *argv
[], int *arg_ptr
));
70 static boolean parse_depth
PARAMS((char *argv
[], int *arg_ptr
));
71 static boolean parse_empty
PARAMS((char *argv
[], int *arg_ptr
));
72 static boolean parse_exec
PARAMS((char *argv
[], int *arg_ptr
));
73 static boolean parse_false
PARAMS((char *argv
[], int *arg_ptr
));
74 static boolean parse_fls
PARAMS((char *argv
[], int *arg_ptr
));
75 static boolean parse_fprintf
PARAMS((char *argv
[], int *arg_ptr
));
76 static boolean parse_follow
PARAMS((char *argv
[], int *arg_ptr
));
77 static boolean parse_fprint
PARAMS((char *argv
[], int *arg_ptr
));
78 static boolean parse_fprint0
PARAMS((char *argv
[], int *arg_ptr
));
79 static boolean parse_fstype
PARAMS((char *argv
[], int *arg_ptr
));
80 static boolean parse_gid
PARAMS((char *argv
[], int *arg_ptr
));
81 static boolean parse_group
PARAMS((char *argv
[], int *arg_ptr
));
82 static boolean parse_help
PARAMS((char *argv
[], int *arg_ptr
));
83 static boolean parse_ilname
PARAMS((char *argv
[], int *arg_ptr
));
84 static boolean parse_iname
PARAMS((char *argv
[], int *arg_ptr
));
85 static boolean parse_inum
PARAMS((char *argv
[], int *arg_ptr
));
86 static boolean parse_ipath
PARAMS((char *argv
[], int *arg_ptr
));
87 static boolean parse_iregex
PARAMS((char *argv
[], int *arg_ptr
));
88 static boolean parse_iwholename
PARAMS((char *argv
[], int *arg_ptr
));
89 static boolean parse_links
PARAMS((char *argv
[], int *arg_ptr
));
90 static boolean parse_lname
PARAMS((char *argv
[], int *arg_ptr
));
91 static boolean parse_ls
PARAMS((char *argv
[], int *arg_ptr
));
92 static boolean parse_maxdepth
PARAMS((char *argv
[], int *arg_ptr
));
93 static boolean parse_mindepth
PARAMS((char *argv
[], int *arg_ptr
));
94 static boolean parse_mmin
PARAMS((char *argv
[], int *arg_ptr
));
95 static boolean parse_mtime
PARAMS((char *argv
[], int *arg_ptr
));
96 static boolean parse_name
PARAMS((char *argv
[], int *arg_ptr
));
97 static boolean parse_negate
PARAMS((char *argv
[], int *arg_ptr
));
98 static boolean parse_newer
PARAMS((char *argv
[], int *arg_ptr
));
99 static boolean parse_noleaf
PARAMS((char *argv
[], int *arg_ptr
));
100 static boolean parse_nogroup
PARAMS((char *argv
[], int *arg_ptr
));
101 static boolean parse_nouser
PARAMS((char *argv
[], int *arg_ptr
));
102 static boolean parse_ok
PARAMS((char *argv
[], int *arg_ptr
));
103 boolean parse_open
PARAMS((char *argv
[], int *arg_ptr
));
104 static boolean parse_or
PARAMS((char *argv
[], int *arg_ptr
));
105 static boolean parse_path
PARAMS((char *argv
[], int *arg_ptr
));
106 static boolean parse_perm
PARAMS((char *argv
[], int *arg_ptr
));
107 boolean parse_print
PARAMS((char *argv
[], int *arg_ptr
));
108 static boolean parse_print0
PARAMS((char *argv
[], int *arg_ptr
));
109 static boolean parse_printf
PARAMS((char *argv
[], int *arg_ptr
));
110 static boolean parse_prune
PARAMS((char *argv
[], int *arg_ptr
));
111 static boolean parse_regex
PARAMS((char *argv
[], int *arg_ptr
));
112 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
113 static boolean parse_size
PARAMS((char *argv
[], int *arg_ptr
));
114 static boolean parse_true
PARAMS((char *argv
[], int *arg_ptr
));
115 static boolean parse_type
PARAMS((char *argv
[], int *arg_ptr
));
116 static boolean parse_uid
PARAMS((char *argv
[], int *arg_ptr
));
117 static boolean parse_used
PARAMS((char *argv
[], int *arg_ptr
));
118 static boolean parse_user
PARAMS((char *argv
[], int *arg_ptr
));
119 static boolean parse_version
PARAMS((char *argv
[], int *arg_ptr
));
120 static boolean parse_wholename
PARAMS((char *argv
[], int *arg_ptr
));
121 static boolean parse_xdev
PARAMS((char *argv
[], int *arg_ptr
));
122 static boolean parse_ignore_race
PARAMS((char *argv
[], int *arg_ptr
));
123 static boolean parse_noignore_race
PARAMS((char *argv
[], int *arg_ptr
));
124 static boolean parse_xtype
PARAMS((char *argv
[], int *arg_ptr
));
126 static boolean insert_regex
PARAMS((char *argv
[], int *arg_ptr
, boolean ignore_case
));
127 static boolean insert_type
PARAMS((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
128 static boolean insert_fprintf
PARAMS((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
129 static struct segment
**make_segment
PARAMS((struct segment
**segment
, char *format
, int len
, int kind
));
130 static boolean insert_exec_ok
PARAMS((boolean (*func
)(), char *argv
[], int *arg_ptr
));
131 static boolean get_num_days
PARAMS((char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
));
132 static boolean insert_time
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
133 static boolean get_num
PARAMS((char *str
, uintmax_t *num
, enum comparison_type
*comp_type
));
134 static boolean insert_num
PARAMS((char *argv
[], int *arg_ptr
, PFB pred
));
135 static FILE *open_output_file
PARAMS((char *path
));
138 char *find_pred_name
PARAMS((PFB pred_func
));
147 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
148 If they are in some Unix versions of find, they are marked `Unix'. */
150 static struct parser_table
const parse_table
[] =
153 {"not", parse_negate
}, /* GNU */
156 {",", parse_comma
}, /* GNU */
158 {"amin", parse_amin
}, /* GNU */
159 {"and", parse_and
}, /* GNU */
160 {"anewer", parse_anewer
}, /* GNU */
161 {"atime", parse_atime
},
162 {"cmin", parse_cmin
}, /* GNU */
163 {"cnewer", parse_cnewer
}, /* GNU */
164 #ifdef UNIMPLEMENTED_UNIX
165 /* It's pretty ugly for find to know about archive formats.
166 Plus what it could do with cpio archives is very limited.
167 Better to leave it out. */
168 {"cpio", parse_cpio
}, /* Unix */
170 {"ctime", parse_ctime
},
171 {"daystart", parse_daystart
}, /* GNU */
172 {"depth", parse_depth
},
173 {"empty", parse_empty
}, /* GNU */
174 {"exec", parse_exec
},
175 {"false", parse_false
}, /* GNU */
176 {"fls", parse_fls
}, /* GNU */
177 {"follow", parse_follow
}, /* GNU, Unix */
178 {"fprint", parse_fprint
}, /* GNU */
179 {"fprint0", parse_fprint0
}, /* GNU */
180 {"fprintf", parse_fprintf
}, /* GNU */
181 {"fstype", parse_fstype
}, /* GNU, Unix */
182 {"gid", parse_gid
}, /* GNU */
183 {"group", parse_group
},
184 {"help", parse_help
}, /* GNU */
185 {"-help", parse_help
}, /* GNU */
186 {"ignore_readdir_race", parse_ignore_race
}, /* GNU */
187 {"ilname", parse_ilname
}, /* GNU */
188 {"iname", parse_iname
}, /* GNU */
189 {"inum", parse_inum
}, /* GNU, Unix */
190 {"ipath", parse_ipath
}, /* GNU, deprecated in favour of iwholename */
191 {"iregex", parse_iregex
}, /* GNU */
192 {"iwholename", parse_iwholename
}, /* GNU */
193 {"links", parse_links
},
194 {"lname", parse_lname
}, /* GNU */
195 {"ls", parse_ls
}, /* GNU, Unix */
196 {"maxdepth", parse_maxdepth
}, /* GNU */
197 {"mindepth", parse_mindepth
}, /* GNU */
198 {"mmin", parse_mmin
}, /* GNU */
199 {"mount", parse_xdev
}, /* Unix */
200 {"mtime", parse_mtime
},
201 {"name", parse_name
},
202 #ifdef UNIMPLEMENTED_UNIX
203 {"ncpio", parse_ncpio
}, /* Unix */
205 {"newer", parse_newer
},
206 {"noleaf", parse_noleaf
}, /* GNU */
207 {"nogroup", parse_nogroup
},
208 {"nouser", parse_nouser
},
209 {"noignore_readdir_race", parse_noignore_race
}, /* GNU */
211 {"or", parse_or
}, /* GNU */
213 {"path", parse_path
}, /* GNU, HP-UX, GNU prefers wholename */
214 {"perm", parse_perm
},
215 {"print", parse_print
},
216 {"print0", parse_print0
}, /* GNU */
217 {"printf", parse_printf
}, /* GNU */
218 {"prune", parse_prune
},
219 {"regex", parse_regex
}, /* GNU */
220 {"size", parse_size
},
221 {"true", parse_true
}, /* GNU */
222 {"type", parse_type
},
223 {"uid", parse_uid
}, /* GNU */
224 {"used", parse_used
}, /* GNU */
225 {"user", parse_user
},
226 {"version", parse_version
}, /* GNU */
227 {"-version", parse_version
}, /* GNU */
228 {"wholename", parse_wholename
}, /* GNU, replaces -path */
230 {"xdev", parse_xdev
},
231 {"xtype", parse_xtype
}, /* GNU */
235 /* Return a pointer to the parser function to invoke for predicate
237 Return NULL if SEARCH_NAME is not a valid predicate name. */
240 find_parser (char *search_name
)
244 if (*search_name
== '-')
246 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
247 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
248 return (parse_table
[i
].parser_func
);
252 /* The parsers are responsible to continue scanning ARGV for
253 their arguments. Each parser knows what is and isn't
256 ARGV is the argument array.
257 *ARG_PTR is the index to start at in ARGV,
258 updated to point beyond the last element consumed.
260 The predicate structure is updated with the new information. */
263 parse_amin (char **argv
, int *arg_ptr
)
265 struct predicate
*our_pred
;
267 enum comparison_type c_type
;
270 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
272 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
274 t
= cur_day_start
+ DAYSECS
- num
* 60;
275 our_pred
= insert_primary (pred_amin
);
276 our_pred
->args
.info
.kind
= c_type
;
277 our_pred
->args
.info
.negative
= t
< 0;
278 our_pred
->args
.info
.l_val
= t
;
284 parse_and (char **argv
, int *arg_ptr
)
286 struct predicate
*our_pred
;
288 our_pred
= get_new_pred ();
289 our_pred
->pred_func
= pred_and
;
291 our_pred
->p_name
= find_pred_name (pred_and
);
293 our_pred
->p_type
= BI_OP
;
294 our_pred
->p_prec
= AND_PREC
;
295 our_pred
->need_stat
= false;
300 parse_anewer (char **argv
, int *arg_ptr
)
302 struct predicate
*our_pred
;
303 struct stat stat_newer
;
305 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
307 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
308 error (1, errno
, "%s", argv
[*arg_ptr
]);
309 our_pred
= insert_primary (pred_anewer
);
310 our_pred
->args
.time
= stat_newer
.st_mtime
;
316 parse_atime (char **argv
, int *arg_ptr
)
318 return (insert_time (argv
, arg_ptr
, pred_atime
));
322 parse_close (char **argv
, int *arg_ptr
)
324 struct predicate
*our_pred
;
326 our_pred
= get_new_pred ();
327 our_pred
->pred_func
= pred_close
;
329 our_pred
->p_name
= find_pred_name (pred_close
);
331 our_pred
->p_type
= CLOSE_PAREN
;
332 our_pred
->p_prec
= NO_PREC
;
333 our_pred
->need_stat
= false;
338 parse_cmin (char **argv
, int *arg_ptr
)
340 struct predicate
*our_pred
;
342 enum comparison_type c_type
;
345 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
347 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
349 t
= cur_day_start
+ DAYSECS
- num
* 60;
350 our_pred
= insert_primary (pred_cmin
);
351 our_pred
->args
.info
.kind
= c_type
;
352 our_pred
->args
.info
.negative
= t
< 0;
353 our_pred
->args
.info
.l_val
= t
;
359 parse_cnewer (char **argv
, int *arg_ptr
)
361 struct predicate
*our_pred
;
362 struct stat stat_newer
;
364 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
366 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
367 error (1, errno
, "%s", argv
[*arg_ptr
]);
368 our_pred
= insert_primary (pred_cnewer
);
369 our_pred
->args
.time
= stat_newer
.st_mtime
;
375 parse_comma (char **argv
, int *arg_ptr
)
377 struct predicate
*our_pred
;
379 our_pred
= get_new_pred ();
380 our_pred
->pred_func
= pred_comma
;
382 our_pred
->p_name
= find_pred_name (pred_comma
);
384 our_pred
->p_type
= BI_OP
;
385 our_pred
->p_prec
= COMMA_PREC
;
386 our_pred
->need_stat
= false;
391 parse_ctime (char **argv
, int *arg_ptr
)
393 return (insert_time (argv
, arg_ptr
, pred_ctime
));
397 parse_daystart (char **argv
, int *arg_ptr
)
401 if (full_days
== false)
403 cur_day_start
+= DAYSECS
;
404 local
= localtime (&cur_day_start
);
405 cur_day_start
-= (local
406 ? (local
->tm_sec
+ local
->tm_min
* 60
407 + local
->tm_hour
* 3600)
408 : cur_day_start
% DAYSECS
);
415 parse_depth (char **argv
, int *arg_ptr
)
417 do_dir_first
= false;
422 parse_empty (char **argv
, int *arg_ptr
)
424 insert_primary (pred_empty
);
429 parse_exec (char **argv
, int *arg_ptr
)
431 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
435 parse_false (char **argv
, int *arg_ptr
)
437 struct predicate
*our_pred
;
439 our_pred
= insert_primary (pred_false
);
440 our_pred
->need_stat
= false;
445 parse_fls (char **argv
, int *arg_ptr
)
447 struct predicate
*our_pred
;
449 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
451 our_pred
= insert_primary (pred_fls
);
452 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
453 our_pred
->side_effects
= true;
454 our_pred
->no_default_print
= true;
460 parse_fprintf (char **argv
, int *arg_ptr
)
464 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
466 if (argv
[*arg_ptr
+ 1] == NULL
)
468 /* Ensure we get "missing arg" message, not "invalid arg". */
472 fp
= open_output_file (argv
[*arg_ptr
]);
474 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
478 parse_follow (char **argv
, int *arg_ptr
)
482 no_leaf_check
= true;
487 parse_fprint (char **argv
, int *arg_ptr
)
489 struct predicate
*our_pred
;
491 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
493 our_pred
= insert_primary (pred_fprint
);
494 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
495 our_pred
->side_effects
= true;
496 our_pred
->no_default_print
= true;
497 our_pred
->need_stat
= false;
503 parse_fprint0 (char **argv
, int *arg_ptr
)
505 struct predicate
*our_pred
;
507 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
509 our_pred
= insert_primary (pred_fprint0
);
510 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
511 our_pred
->side_effects
= true;
512 our_pred
->no_default_print
= true;
513 our_pred
->need_stat
= false;
519 parse_fstype (char **argv
, int *arg_ptr
)
521 struct predicate
*our_pred
;
523 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
525 our_pred
= insert_primary (pred_fstype
);
526 our_pred
->args
.str
= argv
[*arg_ptr
];
532 parse_gid (char **argv
, int *arg_ptr
)
534 return (insert_num (argv
, arg_ptr
, pred_gid
));
538 parse_group (char **argv
, int *arg_ptr
)
540 struct group
*cur_gr
;
541 struct predicate
*our_pred
;
545 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
547 cur_gr
= getgrnam (argv
[*arg_ptr
]);
550 gid
= cur_gr
->gr_gid
;
553 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
554 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
556 gid
= atoi (argv
[*arg_ptr
]);
558 our_pred
= insert_primary (pred_group
);
559 our_pred
->args
.gid
= gid
;
565 parse_help (char **argv
, int *arg_ptr
)
568 Usage: %s [path...] [expression]\n"), program_name
);
570 default path is the current directory; default expression is -print\n\
571 expression may consist of:\n\
572 operators (decreasing precedence; -and is implicit where no others are given):\n\
573 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
575 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
576 options (always true): -daystart -depth -follow --help\n\
577 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
578 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N"));
580 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
581 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
582 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
584 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
585 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
586 -used N -user NAME -xtype [bcdpfls]\n"));
588 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
589 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
590 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
591 page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
592 email to <bug-findutils@gnu.org>."));
597 parse_ilname (char **argv
, int *arg_ptr
)
599 struct predicate
*our_pred
;
601 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
603 our_pred
= insert_primary (pred_ilname
);
604 our_pred
->args
.str
= argv
[*arg_ptr
];
610 /* sanity check the fnmatch() function to make sure
611 * it really is the GNU version.
614 fnmatch_sanitycheck()
616 if (0 != fnmatch("foo", "foo", 0)
617 || 0 == fnmatch("Foo", "foo", 0)
618 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD
))
620 error (1, 0, _("sanity check of the fnmatch() library function failed."));
630 parse_iname (char **argv
, int *arg_ptr
)
632 struct predicate
*our_pred
;
634 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
637 fnmatch_sanitycheck();
639 our_pred
= insert_primary (pred_iname
);
640 our_pred
->need_stat
= false;
641 our_pred
->args
.str
= argv
[*arg_ptr
];
647 parse_inum (char **argv
, int *arg_ptr
)
649 return (insert_num (argv
, arg_ptr
, pred_inum
));
652 /* -ipath is deprecated (at RMS's request) in favour of
653 * -iwholename. See the node "GNU Manuals" in standards.texi
654 * for the rationale for this (basically, GNU prefers the use
655 * of the phrase "file name" to "path name"
658 parse_ipath (char **argv
, int *arg_ptr
)
661 _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
663 return parse_iwholename(argv
, arg_ptr
);
667 parse_iwholename (char **argv
, int *arg_ptr
)
669 struct predicate
*our_pred
;
671 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
674 fnmatch_sanitycheck();
676 our_pred
= insert_primary (pred_ipath
);
677 our_pred
->need_stat
= false;
678 our_pred
->args
.str
= argv
[*arg_ptr
];
684 parse_iregex (char **argv
, int *arg_ptr
)
686 return insert_regex (argv
, arg_ptr
, true);
690 parse_links (char **argv
, int *arg_ptr
)
692 return (insert_num (argv
, arg_ptr
, pred_links
));
696 parse_lname (char **argv
, int *arg_ptr
)
698 struct predicate
*our_pred
;
700 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
703 fnmatch_sanitycheck();
705 our_pred
= insert_primary (pred_lname
);
706 our_pred
->args
.str
= argv
[*arg_ptr
];
712 parse_ls (char **argv
, int *arg_ptr
)
714 struct predicate
*our_pred
;
716 our_pred
= insert_primary (pred_ls
);
717 our_pred
->side_effects
= true;
718 our_pred
->no_default_print
= true;
723 parse_maxdepth (char **argv
, int *arg_ptr
)
727 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
729 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
730 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
732 maxdepth
= atoi (argv
[*arg_ptr
]);
740 parse_mindepth (char **argv
, int *arg_ptr
)
744 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
746 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
747 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
749 mindepth
= atoi (argv
[*arg_ptr
]);
757 parse_mmin (char **argv
, int *arg_ptr
)
759 struct predicate
*our_pred
;
761 enum comparison_type c_type
;
764 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
766 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
768 t
= cur_day_start
+ DAYSECS
- num
* 60;
769 our_pred
= insert_primary (pred_mmin
);
770 our_pred
->args
.info
.kind
= c_type
;
771 our_pred
->args
.info
.negative
= t
< 0;
772 our_pred
->args
.info
.l_val
= t
;
778 parse_mtime (char **argv
, int *arg_ptr
)
780 return (insert_time (argv
, arg_ptr
, pred_mtime
));
784 parse_name (char **argv
, int *arg_ptr
)
786 struct predicate
*our_pred
;
788 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
790 our_pred
= insert_primary (pred_name
);
791 our_pred
->need_stat
= false;
792 our_pred
->args
.str
= argv
[*arg_ptr
];
798 parse_negate (char **argv
, int *arg_ptr
)
800 struct predicate
*our_pred
;
802 our_pred
= get_new_pred_chk_op ();
803 our_pred
->pred_func
= pred_negate
;
805 our_pred
->p_name
= find_pred_name (pred_negate
);
807 our_pred
->p_type
= UNI_OP
;
808 our_pred
->p_prec
= NEGATE_PREC
;
809 our_pred
->need_stat
= false;
814 parse_newer (char **argv
, int *arg_ptr
)
816 struct predicate
*our_pred
;
817 struct stat stat_newer
;
819 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
821 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
822 error (1, errno
, "%s", argv
[*arg_ptr
]);
823 our_pred
= insert_primary (pred_newer
);
824 our_pred
->args
.time
= stat_newer
.st_mtime
;
830 parse_noleaf (char **argv
, int *arg_ptr
)
832 no_leaf_check
= true;
837 /* Arbitrary amount by which to increase size
838 of `uid_unused' and `gid_unused'. */
839 #define ALLOC_STEP 2048
841 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
842 char *uid_unused
= NULL
;
844 /* Number of elements in `uid_unused'. */
845 unsigned uid_allocated
;
847 /* Similar for GIDs and group entries. */
848 char *gid_unused
= NULL
;
849 unsigned gid_allocated
;
853 parse_nogroup (char **argv
, int *arg_ptr
)
855 struct predicate
*our_pred
;
857 our_pred
= insert_primary (pred_nogroup
);
859 if (gid_unused
== NULL
)
863 gid_allocated
= ALLOC_STEP
;
864 gid_unused
= xmalloc (gid_allocated
);
865 memset (gid_unused
, 1, gid_allocated
);
867 while ((gr
= getgrent ()) != NULL
)
869 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
871 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
872 gid_unused
= xrealloc (gid_unused
, new_allocated
);
873 memset (gid_unused
+ gid_allocated
, 1,
874 new_allocated
- gid_allocated
);
875 gid_allocated
= new_allocated
;
877 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
886 parse_nouser (char **argv
, int *arg_ptr
)
888 struct predicate
*our_pred
;
890 our_pred
= insert_primary (pred_nouser
);
892 if (uid_unused
== NULL
)
896 uid_allocated
= ALLOC_STEP
;
897 uid_unused
= xmalloc (uid_allocated
);
898 memset (uid_unused
, 1, uid_allocated
);
900 while ((pw
= getpwent ()) != NULL
)
902 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
904 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
905 uid_unused
= xrealloc (uid_unused
, new_allocated
);
906 memset (uid_unused
+ uid_allocated
, 1,
907 new_allocated
- uid_allocated
);
908 uid_allocated
= new_allocated
;
910 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
919 parse_ok (char **argv
, int *arg_ptr
)
921 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
925 parse_open (char **argv
, int *arg_ptr
)
927 struct predicate
*our_pred
;
929 our_pred
= get_new_pred_chk_op ();
930 our_pred
->pred_func
= pred_open
;
932 our_pred
->p_name
= find_pred_name (pred_open
);
934 our_pred
->p_type
= OPEN_PAREN
;
935 our_pred
->p_prec
= NO_PREC
;
936 our_pred
->need_stat
= false;
941 parse_or (char **argv
, int *arg_ptr
)
943 struct predicate
*our_pred
;
945 our_pred
= get_new_pred ();
946 our_pred
->pred_func
= pred_or
;
948 our_pred
->p_name
= find_pred_name (pred_or
);
950 our_pred
->p_type
= BI_OP
;
951 our_pred
->p_prec
= OR_PREC
;
952 our_pred
->need_stat
= false;
956 /* -path is deprecated (at RMS's request) in favour of
957 * -iwholename. See the node "GNU Manuals" in standards.texi
958 * for the rationale for this (basically, GNU prefers the use
959 * of the phrase "file name" to "path name".
961 * We do not issue a warning that this usage is deprecated
962 * since HPUX find supports this predicate also.
965 parse_path (char **argv
, int *arg_ptr
)
967 return parse_wholename(argv
, arg_ptr
);
971 parse_wholename (char **argv
, int *arg_ptr
)
973 struct predicate
*our_pred
;
975 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
977 our_pred
= insert_primary (pred_path
);
978 our_pred
->need_stat
= false;
979 our_pred
->args
.str
= argv
[*arg_ptr
];
985 parse_perm (char **argv
, int *arg_ptr
)
989 struct mode_change
*change
;
990 struct predicate
*our_pred
;
992 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
995 switch (argv
[*arg_ptr
][0])
1006 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1007 if (change
== MODE_INVALID
)
1008 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1009 else if (change
== MODE_MEMORY_EXHAUSTED
)
1010 error (1, 0, _("virtual memory exhausted"));
1011 perm_val
= mode_adjust (0, change
);
1014 our_pred
= insert_primary (pred_perm
);
1016 switch (argv
[*arg_ptr
][0])
1019 our_pred
->args
.perm
.kind
= PERM_AT_LEAST
;
1022 our_pred
->args
.perm
.kind
= PERM_ANY
;
1025 our_pred
->args
.perm
.kind
= PERM_EXACT
;
1028 our_pred
->args
.perm
.val
= perm_val
& MODE_ALL
;
1034 parse_print (char **argv
, int *arg_ptr
)
1036 struct predicate
*our_pred
;
1038 our_pred
= insert_primary (pred_print
);
1039 /* -print has the side effect of printing. This prevents us
1040 from doing undesired multiple printing when the user has
1041 already specified -print. */
1042 our_pred
->side_effects
= true;
1043 our_pred
->no_default_print
= true;
1044 our_pred
->need_stat
= false;
1049 parse_print0 (char **argv
, int *arg_ptr
)
1051 struct predicate
*our_pred
;
1053 our_pred
= insert_primary (pred_print0
);
1054 /* -print0 has the side effect of printing. This prevents us
1055 from doing undesired multiple printing when the user has
1056 already specified -print0. */
1057 our_pred
->side_effects
= true;
1058 our_pred
->no_default_print
= true;
1059 our_pred
->need_stat
= false;
1064 parse_printf (char **argv
, int *arg_ptr
)
1066 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1068 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1072 parse_prune (char **argv
, int *arg_ptr
)
1074 struct predicate
*our_pred
;
1076 our_pred
= insert_primary (pred_prune
);
1077 our_pred
->need_stat
= false;
1078 /* -prune has a side effect that it does not descend into
1079 the current directory. */
1080 our_pred
->side_effects
= true;
1085 parse_regex (char **argv
, int *arg_ptr
)
1087 return insert_regex (argv
, arg_ptr
, false);
1091 insert_regex (char **argv
, int *arg_ptr
, boolean ignore_case
)
1093 struct predicate
*our_pred
;
1094 struct re_pattern_buffer
*re
;
1095 const char *error_message
;
1097 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1099 our_pred
= insert_primary (pred_regex
);
1100 our_pred
->need_stat
= false;
1101 re
= (struct re_pattern_buffer
*)
1102 xmalloc (sizeof (struct re_pattern_buffer
));
1103 our_pred
->args
.regex
= re
;
1104 re
->allocated
= 100;
1105 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1112 re
->translate
= xmalloc (256);
1113 /* Map uppercase characters to corresponding lowercase ones. */
1114 for (i
= 0; i
< 256; i
++)
1115 re
->translate
[i
] = ISUPPER (i
) ? tolower (i
) : i
;
1118 re
->translate
= NULL
;
1120 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1123 error (1, 0, "%s", error_message
);
1129 parse_size (char **argv
, int *arg_ptr
)
1131 struct predicate
*our_pred
;
1133 enum comparison_type c_type
;
1137 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1139 len
= strlen (argv
[*arg_ptr
]);
1141 error (1, 0, _("invalid null argument to -size"));
1142 switch (argv
[*arg_ptr
][len
- 1])
1146 argv
[*arg_ptr
][len
- 1] = '\0';
1151 argv
[*arg_ptr
][len
- 1] = '\0';
1156 argv
[*arg_ptr
][len
- 1] = '\0';
1159 case 'M': /* Megabytes */
1160 blksize
= 1024*1024;
1161 argv
[*arg_ptr
][len
- 1] = '\0';
1164 case 'G': /* Gigabytes */
1165 blksize
= 1024*1024*1024;
1166 argv
[*arg_ptr
][len
- 1] = '\0';
1171 argv
[*arg_ptr
][len
- 1] = '\0';
1187 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1189 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1191 our_pred
= insert_primary (pred_size
);
1192 our_pred
->args
.size
.kind
= c_type
;
1193 our_pred
->args
.size
.blocksize
= blksize
;
1194 our_pred
->args
.size
.size
= num
;
1200 parse_true (char **argv
, int *arg_ptr
)
1202 struct predicate
*our_pred
;
1204 our_pred
= insert_primary (pred_true
);
1205 our_pred
->need_stat
= false;
1210 parse_type (char **argv
, int *arg_ptr
)
1212 return insert_type (argv
, arg_ptr
, pred_type
);
1216 parse_uid (char **argv
, int *arg_ptr
)
1218 return (insert_num (argv
, arg_ptr
, pred_uid
));
1222 parse_used (char **argv
, int *arg_ptr
)
1224 struct predicate
*our_pred
;
1226 enum comparison_type c_type
;
1229 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1231 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1233 t
= num_days
* DAYSECS
;
1234 our_pred
= insert_primary (pred_used
);
1235 our_pred
->args
.info
.kind
= c_type
;
1236 our_pred
->args
.info
.negative
= t
< 0;
1237 our_pred
->args
.info
.l_val
= t
;
1243 parse_user (char **argv
, int *arg_ptr
)
1245 struct passwd
*cur_pwd
;
1246 struct predicate
*our_pred
;
1250 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1252 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1254 if (cur_pwd
!= NULL
)
1255 uid
= cur_pwd
->pw_uid
;
1258 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1259 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1261 uid
= atoi (argv
[*arg_ptr
]);
1263 our_pred
= insert_primary (pred_user
);
1264 our_pred
->args
.uid
= uid
;
1270 parse_version (char **argv
, int *arg_ptr
)
1272 extern char *version_string
;
1275 printf (_("GNU find version %s\n"), version_string
);
1280 parse_xdev (char **argv
, int *arg_ptr
)
1282 stay_on_filesystem
= true;
1287 parse_ignore_race (char **argv
, int *arg_ptr
)
1289 ignore_readdir_race
= true;
1294 parse_noignore_race (char **argv
, int *arg_ptr
)
1296 ignore_readdir_race
= false;
1301 parse_xtype (char **argv
, int *arg_ptr
)
1303 return insert_type (argv
, arg_ptr
, pred_xtype
);
1307 insert_type (char **argv
, int *arg_ptr
, boolean (*which_pred
) (/* ??? */))
1310 struct predicate
*our_pred
;
1312 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1313 || (strlen (argv
[*arg_ptr
]) != 1))
1315 switch (argv
[*arg_ptr
][0])
1317 case 'b': /* block special */
1318 type_cell
= S_IFBLK
;
1320 case 'c': /* character special */
1321 type_cell
= S_IFCHR
;
1323 case 'd': /* directory */
1324 type_cell
= S_IFDIR
;
1326 case 'f': /* regular file */
1327 type_cell
= S_IFREG
;
1330 case 'l': /* symbolic link */
1331 type_cell
= S_IFLNK
;
1335 case 'p': /* pipe */
1336 type_cell
= S_IFIFO
;
1340 case 's': /* socket */
1341 type_cell
= S_IFSOCK
;
1345 case 'D': /* Solaris door */
1346 type_cell
= S_IFDOOR
;
1349 default: /* None of the above ... nuke 'em. */
1352 our_pred
= insert_primary (which_pred
);
1353 our_pred
->args
.type
= type_cell
;
1354 (*arg_ptr
)++; /* Move on to next argument. */
1358 /* If true, we've determined that the current fprintf predicate
1359 uses stat information. */
1360 static boolean fprintf_stat_needed
;
1363 insert_fprintf (FILE *fp
, boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1365 char *format
; /* Beginning of unprocessed format string. */
1366 register char *scan
; /* Current address in scanning `format'. */
1367 register char *scan2
; /* Address inside of element being scanned. */
1368 struct segment
**segmentp
; /* Address of current segment. */
1369 struct predicate
*our_pred
;
1371 format
= argv
[(*arg_ptr
)++];
1373 fprintf_stat_needed
= false; /* Might be overridden later. */
1374 our_pred
= insert_primary (func
);
1375 our_pred
->side_effects
= true;
1376 our_pred
->no_default_print
= true;
1377 our_pred
->args
.printf_vec
.stream
= fp
;
1378 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1381 for (scan
= format
; *scan
; scan
++)
1386 if (*scan2
>= '0' && *scan2
<= '7')
1390 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1392 n
= 8 * n
+ *scan2
- '0';
1407 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1408 our_pred
->need_stat
= fprintf_stat_needed
;
1426 /* *scan = '\\'; * it already is */
1430 _("warning: unrecognized escape `\\%c'"), *scan2
);
1435 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1437 format
= scan2
+ 1; /* Move past the escape. */
1438 scan
= scan2
; /* Incremented immediately by `for'. */
1440 else if (*scan
== '%')
1444 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1450 /* Scan past flags, width and precision, to verify kind. */
1451 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1453 while (ISDIGIT (*scan2
))
1456 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1458 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2
))
1460 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1465 else if (strchr ("ACT", *scan2
) && scan2
[1])
1467 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1468 *scan2
| (scan2
[1] << 8));
1475 /* An unrecognized % escape. Print the char after the %. */
1476 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1478 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1487 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1488 our_pred
->need_stat
= fprintf_stat_needed
;
1492 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1493 from the text in FORMAT, which has length LEN.
1494 Return the address of the `next' pointer of the new segment. */
1496 static struct segment
**
1497 make_segment (struct segment
**segment
, char *format
, int len
, int kind
)
1501 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1503 (*segment
)->kind
= kind
;
1504 (*segment
)->next
= NULL
;
1505 (*segment
)->text_len
= len
;
1507 fmt
= (*segment
)->text
= xmalloc (len
+ sizeof "d");
1508 strncpy (fmt
, format
, len
);
1511 switch (kind
& 0xff)
1513 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1514 case KIND_STOP
: /* Terminate argument, no newline. */
1517 case 'a': /* atime in `ctime' format */
1518 case 'A': /* atime in user-specified strftime format */
1519 case 'b': /* size in 512-byte blocks */
1520 case 'c': /* ctime in `ctime' format */
1521 case 'C': /* ctime in user-specified strftime format */
1522 case 'F': /* filesystem type */
1523 case 'G': /* GID number */
1524 case 'g': /* group name */
1525 case 'i': /* inode number */
1526 case 'k': /* size in 1K blocks */
1527 case 'l': /* object of symlink */
1528 case 'n': /* number of links */
1529 case 's': /* size in bytes */
1530 case 't': /* mtime in `ctime' format */
1531 case 'T': /* mtime in user-specified strftime format */
1532 case 'U': /* UID number */
1533 case 'u': /* user name */
1534 fprintf_stat_needed
= true;
1536 case 'f': /* basename of path */
1537 case 'h': /* leading directories part of path */
1538 case 'H': /* ARGV element file was found under */
1539 case 'p': /* pathname */
1540 case 'P': /* pathname with ARGV element stripped */
1544 case 'd': /* depth in search tree (0 = ARGV element) */
1548 case 'm': /* mode as octal number (perms only) */
1550 fprintf_stat_needed
= true;
1555 return (&(*segment
)->next
);
1558 /* handles both exec and ok predicate */
1560 insert_exec_ok (boolean (*func
) (/* ??? */), char **argv
, int *arg_ptr
)
1562 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1563 int num_paths
; /* Number of args with path replacements. */
1564 int path_pos
; /* Index in array of path replacements. */
1565 int vec_pos
; /* Index in array of args. */
1566 struct predicate
*our_pred
;
1567 struct exec_val
*execp
; /* Pointer for efficiency. */
1569 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1572 /* Count the number of args with path replacements, up until the ';'. */
1574 for (end
= start
, num_paths
= 0;
1576 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1578 if (strstr (argv
[end
], "{}"))
1580 /* Fail if no command given or no semicolon found. */
1581 if ((end
== start
) || (argv
[end
] == NULL
))
1587 our_pred
= insert_primary (func
);
1588 our_pred
->side_effects
= true;
1589 our_pred
->no_default_print
= true;
1590 execp
= &our_pred
->args
.exec_vec
;
1592 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1593 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1594 /* Record the positions of all args, and the args with path replacements. */
1595 for (end
= start
, path_pos
= vec_pos
= 0;
1597 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1602 execp
->paths
[path_pos
].count
= 0;
1603 for (p
= argv
[end
]; *p
; ++p
)
1604 if (p
[0] == '{' && p
[1] == '}')
1606 execp
->paths
[path_pos
].count
++;
1609 if (execp
->paths
[path_pos
].count
)
1611 execp
->paths
[path_pos
].offset
= vec_pos
;
1612 execp
->paths
[path_pos
].origarg
= argv
[end
];
1615 execp
->vec
[vec_pos
++] = argv
[end
];
1617 execp
->paths
[path_pos
].offset
= -1;
1618 execp
->vec
[vec_pos
] = NULL
;
1620 if (argv
[end
] == NULL
)
1627 /* Get a number of days and comparison type.
1628 STR is the ASCII representation.
1629 Set *NUM_DAYS to the number of days, taken as being from
1630 the current moment (or possibly midnight). Thus the sense of the
1631 comparison type appears to be reversed.
1632 Set *COMP_TYPE to the kind of comparison that is requested.
1634 Return true if all okay, false if input error.
1636 Used by -atime, -ctime and -mtime (parsers) to
1637 get the appropriate information for a time predicate processor. */
1640 get_num_days (char *str
, uintmax_t *num_days
, enum comparison_type
*comp_type
)
1642 boolean r
= get_num (str
, num_days
, comp_type
);
1646 case COMP_LT
: *comp_type
= COMP_GT
; break;
1647 case COMP_GT
: *comp_type
= COMP_LT
; break;
1653 /* Insert a time predicate PRED.
1654 ARGV is a pointer to the argument array.
1655 ARG_PTR is a pointer to an index into the array, incremented if
1658 Return true if input is valid, false if not.
1660 A new predicate node is assigned, along with an argument node
1661 obtained with malloc.
1663 Used by -atime, -ctime, and -mtime parsers. */
1666 insert_time (char **argv
, int *arg_ptr
, PFB pred
)
1668 struct predicate
*our_pred
;
1670 enum comparison_type c_type
;
1673 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1675 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1678 /* Figure out the timestamp value we are looking for. */
1679 t
= ( cur_day_start
- num_days
* DAYSECS
1680 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1684 /* We introduce a scope in which 'val' can be declared, for the
1685 * benefit of compilers that are really C89 compilers
1686 * which support intmax_t because config.h #defines it
1688 intmax_t val
= ( (intmax_t)cur_day_start
- num_days
* DAYSECS
1689 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0));
1692 /* Check for possibility of an overflow */
1693 if ( (intmax_t)t
!= val
)
1695 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv
[*arg_ptr
]);
1700 our_pred
= insert_primary (pred
);
1701 our_pred
->args
.info
.kind
= c_type
;
1702 our_pred
->args
.info
.negative
= t
< 0;
1703 our_pred
->args
.info
.l_val
= t
;
1706 printf (_("inserting %s\n"), our_pred
->p_name
);
1707 printf (_(" type: %s %s "),
1708 (c_type
== COMP_GT
) ? "gt" :
1709 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1710 (c_type
== COMP_GT
) ? " >" :
1711 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1712 t
= our_pred
->args
.info
.l_val
;
1713 printf ("%ju %s", (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1714 if (c_type
== COMP_EQ
)
1716 t
= our_pred
->args
.info
.l_val
+= DAYSECS
;
1717 printf (" < %ju %s",
1718 (uintmax_t) our_pred
->args
.info
.l_val
, ctime (&t
));
1719 our_pred
->args
.info
.l_val
-= DAYSECS
;
1725 /* Get a number with comparision information.
1726 The sense of the comparision information is 'normal'; that is,
1727 '+' looks for a count > than the number and '-' less than.
1729 STR is the ASCII representation of the number.
1730 Set *NUM to the number.
1731 Set *COMP_TYPE to the kind of comparison that is requested.
1733 Return true if all okay, false if input error. */
1736 get_num (char *str
, uintmax_t *num
, enum comparison_type
*comp_type
)
1738 int len_num
; /* Length of field. */
1745 *comp_type
= COMP_GT
;
1749 *comp_type
= COMP_LT
;
1753 *comp_type
= COMP_EQ
;
1757 return xstrtoumax (str
, NULL
, 10, num
, "") == LONGINT_OK
;
1760 /* Insert a number predicate.
1761 ARGV is a pointer to the argument array.
1762 *ARG_PTR is an index into ARGV, incremented if all went well.
1763 *PRED is the predicate processor to insert.
1765 Return true if input is valid, false if error.
1767 A new predicate node is assigned, along with an argument node
1768 obtained with malloc.
1770 Used by -inum and -links parsers. */
1773 insert_num (char **argv
, int *arg_ptr
, PFB pred
)
1775 struct predicate
*our_pred
;
1777 enum comparison_type c_type
;
1779 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1781 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1783 our_pred
= insert_primary (pred
);
1784 our_pred
->args
.info
.kind
= c_type
;
1785 our_pred
->args
.info
.l_val
= num
;
1788 printf (_("inserting %s\n"), our_pred
->p_name
);
1789 printf (_(" type: %s %s "),
1790 (c_type
== COMP_GT
) ? "gt" :
1791 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1792 (c_type
== COMP_GT
) ? " >" :
1793 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
1794 printf ("%ju\n", our_pred
->args
.info
.l_val
);
1800 open_output_file (char *path
)
1804 if (!strcmp (path
, "/dev/stderr"))
1806 else if (!strcmp (path
, "/dev/stdout"))
1808 f
= fopen (path
, "w");
1810 error (1, errno
, "%s", path
);