1 /* parser.c -- convert the command line args into an expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
19 #include <sys/types.h>
25 #include "modechange.h"
29 #if !defined (isascii) || defined (STDC_HEADERS)
36 #define ISDIGIT(c) (isascii (c) && isdigit (c))
37 #define ISUPPER(c) (isascii (c) && isupper (c))
39 #ifndef _POSIX_VERSION
40 /* POSIX.1 header files should declare these. */
41 struct group
*getgrnam ();
42 struct passwd
*getpwnam ();
46 /* These two aren't specified by POSIX.1. */
47 struct group
*getgrent ();
48 struct passwd
*getpwent ();
58 #ifndef atol /* for Linux */
61 struct tm
*localtime ();
71 static boolean parse_amin
P_((char *argv
[], int *arg_ptr
));
72 static boolean parse_and
P_((char *argv
[], int *arg_ptr
));
73 static boolean parse_anewer
P_((char *argv
[], int *arg_ptr
));
74 static boolean parse_atime
P_((char *argv
[], int *arg_ptr
));
75 boolean parse_close
P_((char *argv
[], int *arg_ptr
));
76 static boolean parse_cmin
P_((char *argv
[], int *arg_ptr
));
77 static boolean parse_cnewer
P_((char *argv
[], int *arg_ptr
));
78 static boolean parse_comma
P_((char *argv
[], int *arg_ptr
));
79 static boolean parse_ctime
P_((char *argv
[], int *arg_ptr
));
80 static boolean parse_daystart
P_((char *argv
[], int *arg_ptr
));
81 static boolean parse_depth
P_((char *argv
[], int *arg_ptr
));
82 static boolean parse_empty
P_((char *argv
[], int *arg_ptr
));
83 static boolean parse_exec
P_((char *argv
[], int *arg_ptr
));
84 static boolean parse_false
P_((char *argv
[], int *arg_ptr
));
85 static boolean parse_fls
P_((char *argv
[], int *arg_ptr
));
86 static boolean parse_fprintf
P_((char *argv
[], int *arg_ptr
));
87 static boolean parse_follow
P_((char *argv
[], int *arg_ptr
));
88 static boolean parse_fprint
P_((char *argv
[], int *arg_ptr
));
89 static boolean parse_fprint0
P_((char *argv
[], int *arg_ptr
));
90 static boolean parse_fstype
P_((char *argv
[], int *arg_ptr
));
91 static boolean parse_gid
P_((char *argv
[], int *arg_ptr
));
92 static boolean parse_group
P_((char *argv
[], int *arg_ptr
));
93 static boolean parse_help
P_((char *argv
[], int *arg_ptr
));
94 static boolean parse_ilname
P_((char *argv
[], int *arg_ptr
));
95 static boolean parse_iname
P_((char *argv
[], int *arg_ptr
));
96 static boolean parse_inum
P_((char *argv
[], int *arg_ptr
));
97 static boolean parse_ipath
P_((char *argv
[], int *arg_ptr
));
98 static boolean parse_iregex
P_((char *argv
[], int *arg_ptr
));
99 static boolean parse_links
P_((char *argv
[], int *arg_ptr
));
100 static boolean parse_lname
P_((char *argv
[], int *arg_ptr
));
101 static boolean parse_ls
P_((char *argv
[], int *arg_ptr
));
102 static boolean parse_maxdepth
P_((char *argv
[], int *arg_ptr
));
103 static boolean parse_mindepth
P_((char *argv
[], int *arg_ptr
));
104 static boolean parse_mmin
P_((char *argv
[], int *arg_ptr
));
105 static boolean parse_mtime
P_((char *argv
[], int *arg_ptr
));
106 static boolean parse_name
P_((char *argv
[], int *arg_ptr
));
107 static boolean parse_negate
P_((char *argv
[], int *arg_ptr
));
108 static boolean parse_newer
P_((char *argv
[], int *arg_ptr
));
109 static boolean parse_noleaf
P_((char *argv
[], int *arg_ptr
));
110 static boolean parse_nogroup
P_((char *argv
[], int *arg_ptr
));
111 static boolean parse_nouser
P_((char *argv
[], int *arg_ptr
));
112 static boolean parse_ok
P_((char *argv
[], int *arg_ptr
));
113 boolean parse_open
P_((char *argv
[], int *arg_ptr
));
114 static boolean parse_or
P_((char *argv
[], int *arg_ptr
));
115 static boolean parse_path
P_((char *argv
[], int *arg_ptr
));
116 static boolean parse_perm
P_((char *argv
[], int *arg_ptr
));
117 boolean parse_print
P_((char *argv
[], int *arg_ptr
));
118 static boolean parse_print0
P_((char *argv
[], int *arg_ptr
));
119 static boolean parse_printf
P_((char *argv
[], int *arg_ptr
));
120 static boolean parse_prune
P_((char *argv
[], int *arg_ptr
));
121 static boolean parse_regex
P_((char *argv
[], int *arg_ptr
));
122 static boolean insert_regex
P_((char *argv
[], int *arg_ptr
, boolean ignore_case
));
123 static boolean parse_size
P_((char *argv
[], int *arg_ptr
));
124 static boolean parse_true
P_((char *argv
[], int *arg_ptr
));
125 static boolean parse_type
P_((char *argv
[], int *arg_ptr
));
126 static boolean parse_uid
P_((char *argv
[], int *arg_ptr
));
127 static boolean parse_used
P_((char *argv
[], int *arg_ptr
));
128 static boolean parse_user
P_((char *argv
[], int *arg_ptr
));
129 static boolean parse_version
P_((char *argv
[], int *arg_ptr
));
130 static boolean parse_xdev
P_((char *argv
[], int *arg_ptr
));
131 static boolean parse_xtype
P_((char *argv
[], int *arg_ptr
));
133 static boolean insert_regex
P_((char *argv
[], int *arg_ptr
, boolean ignore_case
));
134 static boolean insert_type
P_((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
135 static boolean insert_fprintf
P_((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
136 static struct segment
**make_segment
P_((struct segment
**segment
, char *format
, int len
, int kind
));
137 static boolean insert_exec_ok
P_((boolean (*func
)(), char *argv
[], int *arg_ptr
));
138 static boolean get_num_days
P_((char *str
, unsigned long *num_days
, enum comparison_type
*comp_type
));
139 static boolean insert_time
P_((char *argv
[], int *arg_ptr
, PFB pred
));
140 static boolean get_num
P_((char *str
, unsigned long *num
, enum comparison_type
*comp_type
));
141 static boolean insert_num
P_((char *argv
[], int *arg_ptr
, PFB pred
));
142 static FILE *open_output_file
P_((char *path
));
145 char *find_pred_name
_P((PFB pred_func
));
154 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
155 If they are in some Unix versions of find, they are marked `Unix'. */
157 static struct parser_table
const parse_table
[] =
160 {"not", parse_negate
}, /* GNU */
163 {",", parse_comma
}, /* GNU */
165 {"amin", parse_amin
}, /* GNU */
166 {"and", parse_and
}, /* GNU */
167 {"anewer", parse_anewer
}, /* GNU */
168 {"atime", parse_atime
},
169 {"cmin", parse_cmin
}, /* GNU */
170 {"cnewer", parse_cnewer
}, /* GNU */
171 #ifdef UNIMPLEMENTED_UNIX
172 /* It's pretty ugly for find to know about archive formats.
173 Plus what it could do with cpio archives is very limited.
174 Better to leave it out. */
175 {"cpio", parse_cpio
}, /* Unix */
177 {"ctime", parse_ctime
},
178 {"daystart", parse_daystart
}, /* GNU */
179 {"depth", parse_depth
},
180 {"empty", parse_empty
}, /* GNU */
181 {"exec", parse_exec
},
182 {"false", parse_false
}, /* GNU */
183 {"fls", parse_fls
}, /* GNU */
184 {"follow", parse_follow
}, /* GNU, Unix */
185 {"fprint", parse_fprint
}, /* GNU */
186 {"fprint0", parse_fprint0
}, /* GNU */
187 {"fprintf", parse_fprintf
}, /* GNU */
188 {"fstype", parse_fstype
}, /* GNU, Unix */
189 {"gid", parse_gid
}, /* GNU */
190 {"group", parse_group
},
191 {"help", parse_help
}, /* GNU */
192 {"-help", parse_help
}, /* GNU */
193 {"ilname", parse_ilname
}, /* GNU */
194 {"iname", parse_iname
}, /* GNU */
195 {"inum", parse_inum
}, /* GNU, Unix */
196 {"ipath", parse_ipath
}, /* GNU */
197 {"iregex", parse_iregex
}, /* GNU */
198 {"links", parse_links
},
199 {"lname", parse_lname
}, /* GNU */
200 {"ls", parse_ls
}, /* GNU, Unix */
201 {"maxdepth", parse_maxdepth
}, /* GNU */
202 {"mindepth", parse_mindepth
}, /* GNU */
203 {"mmin", parse_mmin
}, /* GNU */
204 {"mount", parse_xdev
}, /* Unix */
205 {"mtime", parse_mtime
},
206 {"name", parse_name
},
207 #ifdef UNIMPLEMENTED_UNIX
208 {"ncpio", parse_ncpio
}, /* Unix */
210 {"newer", parse_newer
},
211 {"noleaf", parse_noleaf
}, /* GNU */
212 {"nogroup", parse_nogroup
},
213 {"nouser", parse_nouser
},
215 {"or", parse_or
}, /* GNU */
217 {"path", parse_path
}, /* GNU, HP-UX */
218 {"perm", parse_perm
},
219 {"print", parse_print
},
220 {"print0", parse_print0
}, /* GNU */
221 {"printf", parse_printf
}, /* GNU */
222 {"prune", parse_prune
},
223 {"regex", parse_regex
}, /* GNU */
224 {"size", parse_size
},
225 {"true", parse_true
}, /* GNU */
226 {"type", parse_type
},
227 {"uid", parse_uid
}, /* GNU */
228 {"used", parse_used
}, /* GNU */
229 {"user", parse_user
},
230 {"version", parse_version
}, /* GNU */
231 {"-version", parse_version
}, /* GNU */
232 {"xdev", parse_xdev
},
233 {"xtype", parse_xtype
}, /* GNU */
237 /* Return a pointer to the parser function to invoke for predicate
239 Return NULL if SEARCH_NAME is not a valid predicate name. */
242 find_parser (search_name
)
247 if (*search_name
== '-')
249 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
250 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
251 return (parse_table
[i
].parser_func
);
255 /* The parsers are responsible to continue scanning ARGV for
256 their arguments. Each parser knows what is and isn't
259 ARGV is the argument array.
260 *ARG_PTR is the index to start at in ARGV,
261 updated to point beyond the last element consumed.
263 The predicate structure is updated with the new information. */
266 parse_amin (argv
, arg_ptr
)
270 struct predicate
*our_pred
;
272 enum comparison_type c_type
;
274 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
276 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
278 our_pred
= insert_primary (pred_amin
);
279 our_pred
->args
.info
.kind
= c_type
;
280 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
286 parse_and (argv
, arg_ptr
)
290 struct predicate
*our_pred
;
292 our_pred
= get_new_pred ();
293 our_pred
->pred_func
= pred_and
;
295 our_pred
->p_name
= find_pred_name (pred_and
);
297 our_pred
->p_type
= BI_OP
;
298 our_pred
->p_prec
= AND_PREC
;
299 our_pred
->need_stat
= false;
304 parse_anewer (argv
, arg_ptr
)
308 struct predicate
*our_pred
;
309 struct stat stat_newer
;
311 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
313 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
314 error (1, errno
, "%s", argv
[*arg_ptr
]);
315 our_pred
= insert_primary (pred_anewer
);
316 our_pred
->args
.time
= stat_newer
.st_mtime
;
322 parse_atime (argv
, arg_ptr
)
326 return (insert_time (argv
, arg_ptr
, pred_atime
));
330 parse_close (argv
, arg_ptr
)
334 struct predicate
*our_pred
;
336 our_pred
= get_new_pred ();
337 our_pred
->pred_func
= pred_close
;
339 our_pred
->p_name
= find_pred_name (pred_close
);
341 our_pred
->p_type
= CLOSE_PAREN
;
342 our_pred
->p_prec
= NO_PREC
;
343 our_pred
->need_stat
= false;
348 parse_cmin (argv
, arg_ptr
)
352 struct predicate
*our_pred
;
354 enum comparison_type c_type
;
356 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
358 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
360 our_pred
= insert_primary (pred_cmin
);
361 our_pred
->args
.info
.kind
= c_type
;
362 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
368 parse_cnewer (argv
, arg_ptr
)
372 struct predicate
*our_pred
;
373 struct stat stat_newer
;
375 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
377 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
378 error (1, errno
, "%s", argv
[*arg_ptr
]);
379 our_pred
= insert_primary (pred_cnewer
);
380 our_pred
->args
.time
= stat_newer
.st_mtime
;
386 parse_comma (argv
, arg_ptr
)
390 struct predicate
*our_pred
;
392 our_pred
= get_new_pred ();
393 our_pred
->pred_func
= pred_comma
;
395 our_pred
->p_name
= find_pred_name (pred_comma
);
397 our_pred
->p_type
= BI_OP
;
398 our_pred
->p_prec
= COMMA_PREC
;
399 our_pred
->need_stat
= false;
404 parse_ctime (argv
, arg_ptr
)
408 return (insert_time (argv
, arg_ptr
, pred_ctime
));
412 parse_daystart (argv
, arg_ptr
)
418 if (full_days
== false)
420 cur_day_start
+= DAYSECS
;
421 local
= localtime (&cur_day_start
);
422 cur_day_start
-= local
->tm_sec
+ local
->tm_min
* 60
423 + local
->tm_hour
* 3600;
430 parse_depth (argv
, arg_ptr
)
434 do_dir_first
= false;
439 parse_empty (argv
, arg_ptr
)
443 insert_primary (pred_empty
);
448 parse_exec (argv
, arg_ptr
)
452 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
456 parse_false (argv
, arg_ptr
)
460 struct predicate
*our_pred
;
462 our_pred
= insert_primary (pred_false
);
463 our_pred
->need_stat
= false;
468 parse_fls (argv
, arg_ptr
)
472 struct predicate
*our_pred
;
474 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
476 our_pred
= insert_primary (pred_fls
);
477 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
478 our_pred
->side_effects
= true;
484 parse_fprintf (argv
, arg_ptr
)
490 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
492 if (argv
[*arg_ptr
+ 1] == NULL
)
494 /* Ensure we get "missing arg" message, not "invalid arg". */
498 fp
= open_output_file (argv
[*arg_ptr
]);
500 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
504 parse_follow (argv
, arg_ptr
)
510 no_leaf_check
= true;
515 parse_fprint (argv
, arg_ptr
)
519 struct predicate
*our_pred
;
521 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
523 our_pred
= insert_primary (pred_fprint
);
524 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
525 our_pred
->side_effects
= true;
526 our_pred
->need_stat
= false;
532 parse_fprint0 (argv
, arg_ptr
)
536 struct predicate
*our_pred
;
538 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
540 our_pred
= insert_primary (pred_fprint0
);
541 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
542 our_pred
->side_effects
= true;
543 our_pred
->need_stat
= false;
549 parse_fstype (argv
, arg_ptr
)
553 struct predicate
*our_pred
;
555 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
557 our_pred
= insert_primary (pred_fstype
);
558 our_pred
->args
.str
= argv
[*arg_ptr
];
564 parse_gid (argv
, arg_ptr
)
568 return (insert_num (argv
, arg_ptr
, pred_gid
));
572 parse_group (argv
, arg_ptr
)
576 struct group
*cur_gr
;
577 struct predicate
*our_pred
;
581 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
583 cur_gr
= getgrnam (argv
[*arg_ptr
]);
586 gid
= cur_gr
->gr_gid
;
589 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
590 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
592 gid
= atoi (argv
[*arg_ptr
]);
594 our_pred
= insert_primary (pred_group
);
595 our_pred
->args
.gid
= gid
;
601 parse_help (argv
, arg_ptr
)
606 Usage: %s [path...] [expression]\n", program_name
);
608 default path is the current directory; default expression is -print\n\
609 expression may consist of:\n\
610 operators (decreasing precedence; -and is implicit where no others are given):\n\
611 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
613 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
614 options (always true): -daystart -depth -follow --help\n\
615 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
616 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
618 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
619 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
620 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
622 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
623 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
624 -xtype [bcdpfls]\n");
626 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
627 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
632 parse_ilname (argv
, arg_ptr
)
636 struct predicate
*our_pred
;
638 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
640 our_pred
= insert_primary (pred_ilname
);
641 our_pred
->args
.str
= argv
[*arg_ptr
];
647 parse_iname (argv
, arg_ptr
)
651 struct predicate
*our_pred
;
653 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
655 our_pred
= insert_primary (pred_iname
);
656 our_pred
->need_stat
= false;
657 our_pred
->args
.str
= argv
[*arg_ptr
];
663 parse_inum (argv
, arg_ptr
)
667 return (insert_num (argv
, arg_ptr
, pred_inum
));
671 parse_ipath (argv
, arg_ptr
)
675 struct predicate
*our_pred
;
677 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
679 our_pred
= insert_primary (pred_ipath
);
680 our_pred
->need_stat
= false;
681 our_pred
->args
.str
= argv
[*arg_ptr
];
687 parse_iregex (argv
, arg_ptr
)
691 return insert_regex (argv
, arg_ptr
, true);
695 parse_links (argv
, arg_ptr
)
699 return (insert_num (argv
, arg_ptr
, pred_links
));
703 parse_lname (argv
, arg_ptr
)
707 struct predicate
*our_pred
;
709 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
711 our_pred
= insert_primary (pred_lname
);
712 our_pred
->args
.str
= argv
[*arg_ptr
];
718 parse_ls (argv
, arg_ptr
)
722 struct predicate
*our_pred
;
724 our_pred
= insert_primary (pred_ls
);
725 our_pred
->side_effects
= true;
730 parse_maxdepth (argv
, arg_ptr
)
736 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
738 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
739 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
741 maxdepth
= atoi (argv
[*arg_ptr
]);
749 parse_mindepth (argv
, arg_ptr
)
755 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
757 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
758 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
760 mindepth
= atoi (argv
[*arg_ptr
]);
768 parse_mmin (argv
, arg_ptr
)
772 struct predicate
*our_pred
;
774 enum comparison_type c_type
;
776 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
778 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
780 our_pred
= insert_primary (pred_mmin
);
781 our_pred
->args
.info
.kind
= c_type
;
782 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
788 parse_mtime (argv
, arg_ptr
)
792 return (insert_time (argv
, arg_ptr
, pred_mtime
));
796 parse_name (argv
, arg_ptr
)
800 struct predicate
*our_pred
;
802 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
804 our_pred
= insert_primary (pred_name
);
805 our_pred
->need_stat
= false;
806 our_pred
->args
.str
= argv
[*arg_ptr
];
812 parse_negate (argv
, arg_ptr
)
816 struct predicate
*our_pred
;
818 our_pred
= get_new_pred_chk_op ();
819 our_pred
->pred_func
= pred_negate
;
821 our_pred
->p_name
= find_pred_name (pred_negate
);
823 our_pred
->p_type
= UNI_OP
;
824 our_pred
->p_prec
= NEGATE_PREC
;
825 our_pred
->need_stat
= false;
830 parse_newer (argv
, arg_ptr
)
834 struct predicate
*our_pred
;
835 struct stat stat_newer
;
837 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
839 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
840 error (1, errno
, "%s", argv
[*arg_ptr
]);
841 our_pred
= insert_primary (pred_newer
);
842 our_pred
->args
.time
= stat_newer
.st_mtime
;
848 parse_noleaf (argv
, arg_ptr
)
852 no_leaf_check
= true;
857 /* Arbitrary amount by which to increase size
858 of `uid_unused' and `gid_unused'. */
859 #define ALLOC_STEP 2048
861 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
862 char *uid_unused
= NULL
;
864 /* Number of elements in `uid_unused'. */
865 unsigned uid_allocated
;
867 /* Similar for GIDs and group entries. */
868 char *gid_unused
= NULL
;
869 unsigned gid_allocated
;
873 parse_nogroup (argv
, arg_ptr
)
877 struct predicate
*our_pred
;
879 our_pred
= insert_primary (pred_nogroup
);
881 if (gid_unused
== NULL
)
885 gid_allocated
= ALLOC_STEP
;
886 gid_unused
= xmalloc (gid_allocated
);
887 memset (gid_unused
, 1, gid_allocated
);
889 while ((gr
= getgrent ()) != NULL
)
891 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
893 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
894 gid_unused
= xrealloc (gid_unused
, new_allocated
);
895 memset (gid_unused
+ gid_allocated
, 1,
896 new_allocated
- gid_allocated
);
897 gid_allocated
= new_allocated
;
899 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
908 parse_nouser (argv
, arg_ptr
)
912 struct predicate
*our_pred
;
914 our_pred
= insert_primary (pred_nouser
);
916 if (uid_unused
== NULL
)
920 uid_allocated
= ALLOC_STEP
;
921 uid_unused
= xmalloc (uid_allocated
);
922 memset (uid_unused
, 1, uid_allocated
);
924 while ((pw
= getpwent ()) != NULL
)
926 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
928 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
929 uid_unused
= xrealloc (uid_unused
, new_allocated
);
930 memset (uid_unused
+ uid_allocated
, 1,
931 new_allocated
- uid_allocated
);
932 uid_allocated
= new_allocated
;
934 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
943 parse_ok (argv
, arg_ptr
)
947 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
951 parse_open (argv
, arg_ptr
)
955 struct predicate
*our_pred
;
957 our_pred
= get_new_pred_chk_op ();
958 our_pred
->pred_func
= pred_open
;
960 our_pred
->p_name
= find_pred_name (pred_open
);
962 our_pred
->p_type
= OPEN_PAREN
;
963 our_pred
->p_prec
= NO_PREC
;
964 our_pred
->need_stat
= false;
969 parse_or (argv
, arg_ptr
)
973 struct predicate
*our_pred
;
975 our_pred
= get_new_pred ();
976 our_pred
->pred_func
= pred_or
;
978 our_pred
->p_name
= find_pred_name (pred_or
);
980 our_pred
->p_type
= BI_OP
;
981 our_pred
->p_prec
= OR_PREC
;
982 our_pred
->need_stat
= false;
987 parse_path (argv
, arg_ptr
)
991 struct predicate
*our_pred
;
993 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
995 our_pred
= insert_primary (pred_path
);
996 our_pred
->need_stat
= false;
997 our_pred
->args
.str
= argv
[*arg_ptr
];
1003 parse_perm (argv
, arg_ptr
)
1007 unsigned long perm_val
;
1009 struct mode_change
*change
;
1010 struct predicate
*our_pred
;
1012 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1015 switch (argv
[*arg_ptr
][0])
1026 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1027 if (change
== MODE_INVALID
)
1028 error (1, 0, "invalid mode `%s'", argv
[*arg_ptr
]);
1029 else if (change
== MODE_MEMORY_EXHAUSTED
)
1030 error (1, 0, "virtual memory exhausted");
1031 perm_val
= mode_adjust (0, change
);
1034 our_pred
= insert_primary (pred_perm
);
1036 switch (argv
[*arg_ptr
][0])
1039 /* Set magic flag to indicate true if at least the given bits are set. */
1040 our_pred
->args
.perm
= (perm_val
& 07777) | 010000;
1043 /* Set magic flag to indicate true if any of the given bits are set. */
1044 our_pred
->args
.perm
= (perm_val
& 07777) | 020000;
1047 /* True if exactly the given bits are set. */
1048 our_pred
->args
.perm
= (perm_val
& 07777);
1056 parse_print (argv
, arg_ptr
)
1060 struct predicate
*our_pred
;
1062 our_pred
= insert_primary (pred_print
);
1063 /* -print has the side effect of printing. This prevents us
1064 from doing undesired multiple printing when the user has
1065 already specified -print. */
1066 our_pred
->side_effects
= true;
1067 our_pred
->need_stat
= false;
1072 parse_print0 (argv
, arg_ptr
)
1076 struct predicate
*our_pred
;
1078 our_pred
= insert_primary (pred_print0
);
1079 /* -print0 has the side effect of printing. This prevents us
1080 from doing undesired multiple printing when the user has
1081 already specified -print0. */
1082 our_pred
->side_effects
= true;
1083 our_pred
->need_stat
= false;
1088 parse_printf (argv
, arg_ptr
)
1092 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1094 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1098 parse_prune (argv
, arg_ptr
)
1102 struct predicate
*our_pred
;
1104 our_pred
= insert_primary (pred_prune
);
1105 our_pred
->need_stat
= false;
1110 parse_regex (argv
, arg_ptr
)
1114 return insert_regex (argv
, arg_ptr
, false);
1118 insert_regex (argv
, arg_ptr
, ignore_case
)
1121 boolean ignore_case
;
1123 struct predicate
*our_pred
;
1124 struct re_pattern_buffer
*re
;
1125 const char *error_message
;
1127 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1129 our_pred
= insert_primary (pred_regex
);
1130 our_pred
->need_stat
= false;
1131 re
= (struct re_pattern_buffer
*)
1132 xmalloc (sizeof (struct re_pattern_buffer
));
1133 our_pred
->args
.regex
= re
;
1134 re
->allocated
= 100;
1135 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1142 re
->translate
= xmalloc (256);
1143 /* Map uppercase characters to corresponding lowercase ones. */
1144 for (i
= 0; i
< 256; i
++)
1145 re
->translate
[i
] = ISUPPER (i
) ? tolower (i
) : i
;
1148 re
->translate
= NULL
;
1150 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1153 error (1, 0, "%s", error_message
);
1159 parse_size (argv
, arg_ptr
)
1163 struct predicate
*our_pred
;
1165 enum comparison_type c_type
;
1169 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1171 len
= strlen (argv
[*arg_ptr
]);
1173 error (1, 0, "invalid null argument to -size");
1174 switch (argv
[*arg_ptr
][len
- 1])
1178 argv
[*arg_ptr
][len
- 1] = '\0';
1183 argv
[*arg_ptr
][len
- 1] = '\0';
1188 argv
[*arg_ptr
][len
- 1] = '\0';
1193 argv
[*arg_ptr
][len
- 1] = '\0';
1209 error (1, 0, "invalid -size type `%c'", argv
[*arg_ptr
][len
- 1]);
1211 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1213 our_pred
= insert_primary (pred_size
);
1214 our_pred
->args
.size
.kind
= c_type
;
1215 our_pred
->args
.size
.blocksize
= blksize
;
1216 our_pred
->args
.size
.size
= num
;
1222 parse_true (argv
, arg_ptr
)
1226 struct predicate
*our_pred
;
1228 our_pred
= insert_primary (pred_true
);
1229 our_pred
->need_stat
= false;
1234 parse_type (argv
, arg_ptr
)
1238 return insert_type (argv
, arg_ptr
, pred_type
);
1242 parse_uid (argv
, arg_ptr
)
1246 return (insert_num (argv
, arg_ptr
, pred_uid
));
1250 parse_used (argv
, arg_ptr
)
1255 struct predicate
*our_pred
;
1256 unsigned long num_days
;
1257 enum comparison_type c_type
;
1259 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1261 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1263 our_pred
= insert_primary (pred_used
);
1264 our_pred
->args
.info
.kind
= c_type
;
1265 our_pred
->args
.info
.l_val
= num_days
* DAYSECS
;
1271 parse_user (argv
, arg_ptr
)
1275 struct passwd
*cur_pwd
;
1276 struct predicate
*our_pred
;
1280 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1282 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1284 if (cur_pwd
!= NULL
)
1285 uid
= cur_pwd
->pw_uid
;
1288 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1289 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1291 uid
= atoi (argv
[*arg_ptr
]);
1293 our_pred
= insert_primary (pred_user
);
1294 our_pred
->args
.uid
= uid
;
1300 parse_version (argv
, arg_ptr
)
1304 extern char *version_string
;
1307 printf ("GNU find version %s\n", version_string
);
1312 parse_xdev (argv
, arg_ptr
)
1316 stay_on_filesystem
= true;
1321 parse_xtype (argv
, arg_ptr
)
1325 return insert_type (argv
, arg_ptr
, pred_xtype
);
1329 insert_type (argv
, arg_ptr
, which_pred
)
1332 boolean (*which_pred
) ();
1334 unsigned long type_cell
;
1335 struct predicate
*our_pred
;
1337 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1338 || (strlen (argv
[*arg_ptr
]) != 1))
1340 switch (argv
[*arg_ptr
][0])
1342 case 'b': /* block special */
1343 type_cell
= S_IFBLK
;
1345 case 'c': /* character special */
1346 type_cell
= S_IFCHR
;
1348 case 'd': /* directory */
1349 type_cell
= S_IFDIR
;
1351 case 'f': /* regular file */
1352 type_cell
= S_IFREG
;
1355 case 'l': /* symbolic link */
1356 type_cell
= S_IFLNK
;
1360 case 'p': /* pipe */
1361 type_cell
= S_IFIFO
;
1365 case 's': /* socket */
1366 type_cell
= S_IFSOCK
;
1369 default: /* None of the above ... nuke 'em. */
1372 our_pred
= insert_primary (which_pred
);
1373 our_pred
->args
.type
= type_cell
;
1374 (*arg_ptr
)++; /* Move on to next argument. */
1378 /* If true, we've determined that the current fprintf predicate
1379 uses stat information. */
1380 static boolean fprintf_stat_needed
;
1383 insert_fprintf (fp
, func
, argv
, arg_ptr
)
1389 char *format
; /* Beginning of unprocessed format string. */
1390 register char *scan
; /* Current address in scanning `format'. */
1391 register char *scan2
; /* Address inside of element being scanned. */
1392 struct segment
**segmentp
; /* Address of current segment. */
1393 struct predicate
*our_pred
;
1395 format
= argv
[(*arg_ptr
)++];
1397 fprintf_stat_needed
= false; /* Might be overridden later. */
1398 our_pred
= insert_primary (func
);
1399 our_pred
->side_effects
= true;
1400 our_pred
->args
.printf_vec
.stream
= fp
;
1401 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1404 for (scan
= format
; *scan
; scan
++)
1409 if (*scan2
>= '0' && *scan2
<= '7')
1413 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1415 n
= 8 * n
+ *scan2
- '0';
1430 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1431 our_pred
->need_stat
= fprintf_stat_needed
;
1449 /* *scan = '\\'; * it already is */
1452 error (0, 0, "warning: unrecognized escape `\\%c'", *scan2
);
1457 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1459 format
= scan2
+ 1; /* Move past the escape. */
1460 scan
= scan2
; /* Incremented immediately by `for'. */
1462 else if (*scan
== '%')
1466 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1472 /* Scan past flags, width and precision, to verify kind. */
1473 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1475 while (ISDIGIT (*scan2
))
1478 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1480 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2
))
1482 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1487 else if (strchr ("ACT", *scan2
) && scan2
[1])
1489 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1490 *scan2
| (scan2
[1] << 8));
1497 /* An unrecognized % escape. Print the char after the %. */
1498 error (0, 0, "warning: unrecognized format directive `%%%c'",
1500 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1509 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1510 our_pred
->need_stat
= fprintf_stat_needed
;
1514 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1515 from the text in FORMAT, which has length LEN.
1516 Return the address of the `next' pointer of the new segment. */
1518 static struct segment
**
1519 make_segment (segment
, format
, len
, kind
)
1520 struct segment
**segment
;
1526 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1528 (*segment
)->kind
= kind
;
1529 (*segment
)->next
= NULL
;
1530 (*segment
)->text_len
= len
;
1532 fmt
= (*segment
)->text
= xmalloc (len
+ 3); /* room for "ld\0" */
1533 strncpy (fmt
, format
, len
);
1536 switch (kind
& 0xff)
1538 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1539 case KIND_STOP
: /* Terminate argument, no newline. */
1542 case 'a': /* atime in `ctime' format */
1543 case 'c': /* ctime in `ctime' format */
1544 case 'F': /* filesystem type */
1545 case 'g': /* group name */
1546 case 'l': /* object of symlink */
1547 case 't': /* mtime in `ctime' format */
1548 case 'u': /* user name */
1549 case 'A': /* atime in user-specified strftime format */
1550 case 'C': /* ctime in user-specified strftime format */
1551 case 'T': /* mtime in user-specified strftime format */
1552 fprintf_stat_needed
= true;
1554 case 'f': /* basename of path */
1555 case 'h': /* leading directories part of path */
1556 case 'H': /* ARGV element file was found under */
1557 case 'p': /* pathname */
1558 case 'P': /* pathname with ARGV element stripped */
1562 case 'b': /* size in 512-byte blocks */
1563 case 'k': /* size in 1K blocks */
1564 case 's': /* size in bytes */
1567 case 'n': /* number of links */
1568 fprintf_stat_needed
= true;
1570 case 'd': /* depth in search tree (0 = ARGV element) */
1574 case 'i': /* inode number */
1577 case 'G': /* GID number */
1578 case 'U': /* UID number */
1580 fprintf_stat_needed
= true;
1583 case 'm': /* mode as octal number (perms only) */
1585 fprintf_stat_needed
= true;
1590 return (&(*segment
)->next
);
1594 insert_exec_ok (func
, argv
, arg_ptr
)
1599 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1600 int num_paths
; /* Number of args with path replacements. */
1601 int path_pos
; /* Index in array of path replacements. */
1602 int vec_pos
; /* Index in array of args. */
1603 struct predicate
*our_pred
;
1604 struct exec_val
*execp
; /* Pointer for efficiency. */
1606 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1609 /* Count the number of args with path replacements, up until the ';'. */
1611 for (end
= start
, num_paths
= 0;
1613 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1615 if (strstr (argv
[end
], "{}"))
1617 /* Fail if no command given or no semicolon found. */
1618 if ((end
== start
) || (argv
[end
] == NULL
))
1624 our_pred
= insert_primary (func
);
1625 our_pred
->side_effects
= true;
1626 execp
= &our_pred
->args
.exec_vec
;
1628 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1629 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1630 /* Record the positions of all args, and the args with path replacements. */
1631 for (end
= start
, path_pos
= vec_pos
= 0;
1633 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1638 execp
->paths
[path_pos
].count
= 0;
1639 for (p
= argv
[end
]; *p
; ++p
)
1640 if (p
[0] == '{' && p
[1] == '}')
1642 execp
->paths
[path_pos
].count
++;
1645 if (execp
->paths
[path_pos
].count
)
1647 execp
->paths
[path_pos
].offset
= vec_pos
;
1648 execp
->paths
[path_pos
].origarg
= argv
[end
];
1651 execp
->vec
[vec_pos
++] = argv
[end
];
1653 execp
->paths
[path_pos
].offset
= -1;
1654 execp
->vec
[vec_pos
] = NULL
;
1656 if (argv
[end
] == NULL
)
1663 /* Get a number of days and comparison type.
1664 STR is the ASCII representation.
1665 Set *NUM_DAYS to the number of days, taken as being from
1666 the current moment (or possibly midnight). Thus the sense of the
1667 comparison type appears to be reversed.
1668 Set *COMP_TYPE to the kind of comparison that is requested.
1670 Return true if all okay, false if input error.
1672 Used by -atime, -ctime and -mtime (parsers) to
1673 get the appropriate information for a time predicate processor. */
1676 get_num_days (str
, num_days
, comp_type
)
1678 unsigned long *num_days
;
1679 enum comparison_type
*comp_type
;
1681 int len_days
; /* length of field */
1688 *comp_type
= COMP_LT
;
1692 *comp_type
= COMP_GT
;
1705 *comp_type
= COMP_EQ
;
1711 /* We know the first char has been reasonable. Find the
1712 number of days to play with. */
1713 len_days
= strspn (str
, "0123456789");
1714 if ((len_days
== 0) || (str
[len_days
] != '\0'))
1716 *num_days
= (unsigned long) atol (str
);
1720 /* Insert a time predicate PRED.
1721 ARGV is a pointer to the argument array.
1722 ARG_PTR is a pointer to an index into the array, incremented if
1725 Return true if input is valid, false if not.
1727 A new predicate node is assigned, along with an argument node
1728 obtained with malloc.
1730 Used by -atime, -ctime, and -mtime parsers. */
1733 insert_time (argv
, arg_ptr
, pred
)
1738 struct predicate
*our_pred
;
1739 unsigned long num_days
;
1740 enum comparison_type c_type
;
1742 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1744 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1746 our_pred
= insert_primary (pred
);
1747 our_pred
->args
.info
.kind
= c_type
;
1748 our_pred
->args
.info
.l_val
= cur_day_start
- num_days
* DAYSECS
1749 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0);
1752 printf ("inserting %s\n", our_pred
->p_name
);
1753 printf (" type: %s %s ",
1754 (c_type
== COMP_GT
) ? "gt" :
1755 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1756 (c_type
== COMP_GT
) ? " >" :
1757 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1758 printf ("%ld %s", our_pred
->args
.info
.l_val
,
1759 ctime (&our_pred
->args
.info
.l_val
));
1760 if (c_type
== COMP_EQ
)
1762 our_pred
->args
.info
.l_val
+= DAYSECS
;
1763 printf (" < %ld %s", our_pred
->args
.info
.l_val
,
1764 ctime (&our_pred
->args
.info
.l_val
));
1765 our_pred
->args
.info
.l_val
-= DAYSECS
;
1771 /* Get a number with comparision information.
1772 The sense of the comparision information is 'normal'; that is,
1773 '+' looks for inums or links > than the number and '-' less than.
1775 STR is the ASCII representation of the number.
1776 Set *NUM to the number.
1777 Set *COMP_TYPE to the kind of comparison that is requested.
1779 Return true if all okay, false if input error.
1781 Used by the -inum and -links predicate parsers. */
1784 get_num (str
, num
, comp_type
)
1787 enum comparison_type
*comp_type
;
1789 int len_num
; /* Length of field. */
1796 *comp_type
= COMP_GT
;
1800 *comp_type
= COMP_LT
;
1813 *comp_type
= COMP_EQ
;
1819 /* We know the first char has been reasonable. Find the number of
1820 days to play with. */
1821 len_num
= strspn (str
, "0123456789");
1822 if ((len_num
== 0) || (str
[len_num
] != '\0'))
1824 *num
= (unsigned long) atol (str
);
1828 /* Insert a number predicate.
1829 ARGV is a pointer to the argument array.
1830 *ARG_PTR is an index into ARGV, incremented if all went well.
1831 *PRED is the predicate processor to insert.
1833 Return true if input is valid, false if error.
1835 A new predicate node is assigned, along with an argument node
1836 obtained with malloc.
1838 Used by -inum and -links parsers. */
1841 insert_num (argv
, arg_ptr
, pred
)
1846 struct predicate
*our_pred
;
1848 enum comparison_type c_type
;
1850 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1852 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1854 our_pred
= insert_primary (pred
);
1855 our_pred
->args
.info
.kind
= c_type
;
1856 our_pred
->args
.info
.l_val
= num
;
1859 printf ("inserting %s\n", our_pred
->p_name
);
1860 printf (" type: %s %s ",
1861 (c_type
== COMP_GT
) ? "gt" :
1862 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1863 (c_type
== COMP_GT
) ? " >" :
1864 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
1865 printf ("%ld\n", our_pred
->args
.info
.l_val
);
1871 open_output_file (path
)
1876 if (!strcmp (path
, "/dev/stderr"))
1878 else if (!strcmp (path
, "/dev/stdout"))
1880 f
= fopen (path
, "w");
1882 error (1, errno
, "%s", path
);