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"
31 # define _(Text) gettext (Text)
36 # define N_(String) gettext_noop (String)
38 # define N_(String) (String)
41 #if !defined (isascii) || defined (STDC_HEADERS)
48 #define ISDIGIT(c) (isascii (c) && isdigit (c))
49 #define ISUPPER(c) (isascii (c) && isupper (c))
58 static boolean parse_amin
P_((char *argv
[], int *arg_ptr
));
59 static boolean parse_and
P_((char *argv
[], int *arg_ptr
));
60 static boolean parse_anewer
P_((char *argv
[], int *arg_ptr
));
61 static boolean parse_atime
P_((char *argv
[], int *arg_ptr
));
62 boolean parse_close
P_((char *argv
[], int *arg_ptr
));
63 static boolean parse_cmin
P_((char *argv
[], int *arg_ptr
));
64 static boolean parse_cnewer
P_((char *argv
[], int *arg_ptr
));
65 static boolean parse_comma
P_((char *argv
[], int *arg_ptr
));
66 static boolean parse_ctime
P_((char *argv
[], int *arg_ptr
));
67 static boolean parse_daystart
P_((char *argv
[], int *arg_ptr
));
68 static boolean parse_depth
P_((char *argv
[], int *arg_ptr
));
69 static boolean parse_empty
P_((char *argv
[], int *arg_ptr
));
70 static boolean parse_exec
P_((char *argv
[], int *arg_ptr
));
71 static boolean parse_false
P_((char *argv
[], int *arg_ptr
));
72 static boolean parse_fls
P_((char *argv
[], int *arg_ptr
));
73 static boolean parse_fprintf
P_((char *argv
[], int *arg_ptr
));
74 static boolean parse_follow
P_((char *argv
[], int *arg_ptr
));
75 static boolean parse_fprint
P_((char *argv
[], int *arg_ptr
));
76 static boolean parse_fprint0
P_((char *argv
[], int *arg_ptr
));
77 static boolean parse_fstype
P_((char *argv
[], int *arg_ptr
));
78 static boolean parse_gid
P_((char *argv
[], int *arg_ptr
));
79 static boolean parse_group
P_((char *argv
[], int *arg_ptr
));
80 static boolean parse_help
P_((char *argv
[], int *arg_ptr
));
81 static boolean parse_ilname
P_((char *argv
[], int *arg_ptr
));
82 static boolean parse_iname
P_((char *argv
[], int *arg_ptr
));
83 static boolean parse_inum
P_((char *argv
[], int *arg_ptr
));
84 static boolean parse_ipath
P_((char *argv
[], int *arg_ptr
));
85 static boolean parse_iregex
P_((char *argv
[], int *arg_ptr
));
86 static boolean parse_links
P_((char *argv
[], int *arg_ptr
));
87 static boolean parse_lname
P_((char *argv
[], int *arg_ptr
));
88 static boolean parse_ls
P_((char *argv
[], int *arg_ptr
));
89 static boolean parse_maxdepth
P_((char *argv
[], int *arg_ptr
));
90 static boolean parse_mindepth
P_((char *argv
[], int *arg_ptr
));
91 static boolean parse_mmin
P_((char *argv
[], int *arg_ptr
));
92 static boolean parse_mtime
P_((char *argv
[], int *arg_ptr
));
93 static boolean parse_name
P_((char *argv
[], int *arg_ptr
));
94 static boolean parse_negate
P_((char *argv
[], int *arg_ptr
));
95 static boolean parse_newer
P_((char *argv
[], int *arg_ptr
));
96 static boolean parse_noleaf
P_((char *argv
[], int *arg_ptr
));
97 static boolean parse_nogroup
P_((char *argv
[], int *arg_ptr
));
98 static boolean parse_nouser
P_((char *argv
[], int *arg_ptr
));
99 static boolean parse_ok
P_((char *argv
[], int *arg_ptr
));
100 boolean parse_open
P_((char *argv
[], int *arg_ptr
));
101 static boolean parse_or
P_((char *argv
[], int *arg_ptr
));
102 static boolean parse_path
P_((char *argv
[], int *arg_ptr
));
103 static boolean parse_perm
P_((char *argv
[], int *arg_ptr
));
104 boolean parse_print
P_((char *argv
[], int *arg_ptr
));
105 static boolean parse_print0
P_((char *argv
[], int *arg_ptr
));
106 static boolean parse_printf
P_((char *argv
[], int *arg_ptr
));
107 static boolean parse_prune
P_((char *argv
[], int *arg_ptr
));
108 static boolean parse_regex
P_((char *argv
[], int *arg_ptr
));
109 static boolean insert_regex
P_((char *argv
[], int *arg_ptr
, boolean ignore_case
));
110 static boolean parse_size
P_((char *argv
[], int *arg_ptr
));
111 static boolean parse_true
P_((char *argv
[], int *arg_ptr
));
112 static boolean parse_type
P_((char *argv
[], int *arg_ptr
));
113 static boolean parse_uid
P_((char *argv
[], int *arg_ptr
));
114 static boolean parse_used
P_((char *argv
[], int *arg_ptr
));
115 static boolean parse_user
P_((char *argv
[], int *arg_ptr
));
116 static boolean parse_version
P_((char *argv
[], int *arg_ptr
));
117 static boolean parse_xdev
P_((char *argv
[], int *arg_ptr
));
118 static boolean parse_xtype
P_((char *argv
[], int *arg_ptr
));
120 static boolean insert_regex
P_((char *argv
[], int *arg_ptr
, boolean ignore_case
));
121 static boolean insert_type
P_((char *argv
[], int *arg_ptr
, boolean (*which_pred
)()));
122 static boolean insert_fprintf
P_((FILE *fp
, boolean (*func
)(), char *argv
[], int *arg_ptr
));
123 static struct segment
**make_segment
P_((struct segment
**segment
, char *format
, int len
, int kind
));
124 static boolean insert_exec_ok
P_((boolean (*func
)(), char *argv
[], int *arg_ptr
));
125 static boolean get_num_days
P_((char *str
, unsigned long *num_days
, enum comparison_type
*comp_type
));
126 static boolean insert_time
P_((char *argv
[], int *arg_ptr
, PFB pred
));
127 static boolean get_num
P_((char *str
, unsigned long *num
, enum comparison_type
*comp_type
));
128 static boolean insert_num
P_((char *argv
[], int *arg_ptr
, PFB pred
));
129 static FILE *open_output_file
P_((char *path
));
132 char *find_pred_name
P_((PFB pred_func
));
141 /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
142 If they are in some Unix versions of find, they are marked `Unix'. */
144 static struct parser_table
const parse_table
[] =
147 {"not", parse_negate
}, /* GNU */
150 {",", parse_comma
}, /* GNU */
152 {"amin", parse_amin
}, /* GNU */
153 {"and", parse_and
}, /* GNU */
154 {"anewer", parse_anewer
}, /* GNU */
155 {"atime", parse_atime
},
156 {"cmin", parse_cmin
}, /* GNU */
157 {"cnewer", parse_cnewer
}, /* GNU */
158 #ifdef UNIMPLEMENTED_UNIX
159 /* It's pretty ugly for find to know about archive formats.
160 Plus what it could do with cpio archives is very limited.
161 Better to leave it out. */
162 {"cpio", parse_cpio
}, /* Unix */
164 {"ctime", parse_ctime
},
165 {"daystart", parse_daystart
}, /* GNU */
166 {"depth", parse_depth
},
167 {"empty", parse_empty
}, /* GNU */
168 {"exec", parse_exec
},
169 {"false", parse_false
}, /* GNU */
170 {"fls", parse_fls
}, /* GNU */
171 {"follow", parse_follow
}, /* GNU, Unix */
172 {"fprint", parse_fprint
}, /* GNU */
173 {"fprint0", parse_fprint0
}, /* GNU */
174 {"fprintf", parse_fprintf
}, /* GNU */
175 {"fstype", parse_fstype
}, /* GNU, Unix */
176 {"gid", parse_gid
}, /* GNU */
177 {"group", parse_group
},
178 {"help", parse_help
}, /* GNU */
179 {"-help", parse_help
}, /* GNU */
180 {"ilname", parse_ilname
}, /* GNU */
181 {"iname", parse_iname
}, /* GNU */
182 {"inum", parse_inum
}, /* GNU, Unix */
183 {"ipath", parse_ipath
}, /* GNU */
184 {"iregex", parse_iregex
}, /* GNU */
185 {"links", parse_links
},
186 {"lname", parse_lname
}, /* GNU */
187 {"ls", parse_ls
}, /* GNU, Unix */
188 {"maxdepth", parse_maxdepth
}, /* GNU */
189 {"mindepth", parse_mindepth
}, /* GNU */
190 {"mmin", parse_mmin
}, /* GNU */
191 {"mount", parse_xdev
}, /* Unix */
192 {"mtime", parse_mtime
},
193 {"name", parse_name
},
194 #ifdef UNIMPLEMENTED_UNIX
195 {"ncpio", parse_ncpio
}, /* Unix */
197 {"newer", parse_newer
},
198 {"noleaf", parse_noleaf
}, /* GNU */
199 {"nogroup", parse_nogroup
},
200 {"nouser", parse_nouser
},
202 {"or", parse_or
}, /* GNU */
204 {"path", parse_path
}, /* GNU, HP-UX */
205 {"perm", parse_perm
},
206 {"print", parse_print
},
207 {"print0", parse_print0
}, /* GNU */
208 {"printf", parse_printf
}, /* GNU */
209 {"prune", parse_prune
},
210 {"regex", parse_regex
}, /* GNU */
211 {"size", parse_size
},
212 {"true", parse_true
}, /* GNU */
213 {"type", parse_type
},
214 {"uid", parse_uid
}, /* GNU */
215 {"used", parse_used
}, /* GNU */
216 {"user", parse_user
},
217 {"version", parse_version
}, /* GNU */
218 {"-version", parse_version
}, /* GNU */
219 {"xdev", parse_xdev
},
220 {"xtype", parse_xtype
}, /* GNU */
224 /* Return a pointer to the parser function to invoke for predicate
226 Return NULL if SEARCH_NAME is not a valid predicate name. */
229 find_parser (search_name
)
234 if (*search_name
== '-')
236 for (i
= 0; parse_table
[i
].parser_name
!= 0; i
++)
237 if (strcmp (parse_table
[i
].parser_name
, search_name
) == 0)
238 return (parse_table
[i
].parser_func
);
242 /* The parsers are responsible to continue scanning ARGV for
243 their arguments. Each parser knows what is and isn't
246 ARGV is the argument array.
247 *ARG_PTR is the index to start at in ARGV,
248 updated to point beyond the last element consumed.
250 The predicate structure is updated with the new information. */
253 parse_amin (argv
, arg_ptr
)
257 struct predicate
*our_pred
;
259 enum comparison_type c_type
;
261 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
263 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
265 our_pred
= insert_primary (pred_amin
);
266 our_pred
->args
.info
.kind
= c_type
;
267 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
273 parse_and (argv
, arg_ptr
)
277 struct predicate
*our_pred
;
279 our_pred
= get_new_pred ();
280 our_pred
->pred_func
= pred_and
;
282 our_pred
->p_name
= find_pred_name (pred_and
);
284 our_pred
->p_type
= BI_OP
;
285 our_pred
->p_prec
= AND_PREC
;
286 our_pred
->need_stat
= false;
291 parse_anewer (argv
, arg_ptr
)
295 struct predicate
*our_pred
;
296 struct stat stat_newer
;
298 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
300 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
301 error (1, errno
, "%s", argv
[*arg_ptr
]);
302 our_pred
= insert_primary (pred_anewer
);
303 our_pred
->args
.time
= stat_newer
.st_mtime
;
309 parse_atime (argv
, arg_ptr
)
313 return (insert_time (argv
, arg_ptr
, pred_atime
));
317 parse_close (argv
, arg_ptr
)
321 struct predicate
*our_pred
;
323 our_pred
= get_new_pred ();
324 our_pred
->pred_func
= pred_close
;
326 our_pred
->p_name
= find_pred_name (pred_close
);
328 our_pred
->p_type
= CLOSE_PAREN
;
329 our_pred
->p_prec
= NO_PREC
;
330 our_pred
->need_stat
= false;
335 parse_cmin (argv
, arg_ptr
)
339 struct predicate
*our_pred
;
341 enum comparison_type c_type
;
343 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
345 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
347 our_pred
= insert_primary (pred_cmin
);
348 our_pred
->args
.info
.kind
= c_type
;
349 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
355 parse_cnewer (argv
, arg_ptr
)
359 struct predicate
*our_pred
;
360 struct stat stat_newer
;
362 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
364 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
365 error (1, errno
, "%s", argv
[*arg_ptr
]);
366 our_pred
= insert_primary (pred_cnewer
);
367 our_pred
->args
.time
= stat_newer
.st_mtime
;
373 parse_comma (argv
, 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 (argv
, arg_ptr
)
395 return (insert_time (argv
, arg_ptr
, pred_ctime
));
399 parse_daystart (argv
, arg_ptr
)
405 if (full_days
== false)
407 cur_day_start
+= DAYSECS
;
408 local
= localtime (&cur_day_start
);
409 cur_day_start
-= local
->tm_sec
+ local
->tm_min
* 60
410 + local
->tm_hour
* 3600;
417 parse_depth (argv
, arg_ptr
)
421 do_dir_first
= false;
426 parse_empty (argv
, arg_ptr
)
430 insert_primary (pred_empty
);
435 parse_exec (argv
, arg_ptr
)
439 return (insert_exec_ok (pred_exec
, argv
, arg_ptr
));
443 parse_false (argv
, arg_ptr
)
447 struct predicate
*our_pred
;
449 our_pred
= insert_primary (pred_false
);
450 our_pred
->need_stat
= false;
455 parse_fls (argv
, arg_ptr
)
459 struct predicate
*our_pred
;
461 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
463 our_pred
= insert_primary (pred_fls
);
464 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
465 our_pred
->side_effects
= true;
471 parse_fprintf (argv
, arg_ptr
)
477 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
479 if (argv
[*arg_ptr
+ 1] == NULL
)
481 /* Ensure we get "missing arg" message, not "invalid arg". */
485 fp
= open_output_file (argv
[*arg_ptr
]);
487 return (insert_fprintf (fp
, pred_fprintf
, argv
, arg_ptr
));
491 parse_follow (argv
, arg_ptr
)
497 no_leaf_check
= true;
502 parse_fprint (argv
, arg_ptr
)
506 struct predicate
*our_pred
;
508 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
510 our_pred
= insert_primary (pred_fprint
);
511 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
512 our_pred
->side_effects
= true;
513 our_pred
->need_stat
= false;
519 parse_fprint0 (argv
, arg_ptr
)
523 struct predicate
*our_pred
;
525 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
527 our_pred
= insert_primary (pred_fprint0
);
528 our_pred
->args
.stream
= open_output_file (argv
[*arg_ptr
]);
529 our_pred
->side_effects
= true;
530 our_pred
->need_stat
= false;
536 parse_fstype (argv
, arg_ptr
)
540 struct predicate
*our_pred
;
542 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
544 our_pred
= insert_primary (pred_fstype
);
545 our_pred
->args
.str
= argv
[*arg_ptr
];
551 parse_gid (argv
, arg_ptr
)
555 return (insert_num (argv
, arg_ptr
, pred_gid
));
559 parse_group (argv
, arg_ptr
)
563 struct group
*cur_gr
;
564 struct predicate
*our_pred
;
568 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
570 cur_gr
= getgrnam (argv
[*arg_ptr
]);
573 gid
= cur_gr
->gr_gid
;
576 gid_len
= strspn (argv
[*arg_ptr
], "0123456789");
577 if ((gid_len
== 0) || (argv
[*arg_ptr
][gid_len
] != '\0'))
579 gid
= atoi (argv
[*arg_ptr
]);
581 our_pred
= insert_primary (pred_group
);
582 our_pred
->args
.gid
= gid
;
588 parse_help (argv
, arg_ptr
)
593 Usage: %s [path...] [expression]\n"), program_name
);
595 default path is the current directory; default expression is -print\n\
596 expression may consist of:\n\
597 operators (decreasing precedence; -and is implicit where no others are given):\n\
598 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
600 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
601 options (always true): -daystart -depth -follow --help\n\
602 -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
603 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
605 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
606 -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
607 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
609 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
610 -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
611 -xtype [bcdpfls]\n"));
613 actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
614 -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
619 parse_ilname (argv
, arg_ptr
)
623 struct predicate
*our_pred
;
625 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
627 our_pred
= insert_primary (pred_ilname
);
628 our_pred
->args
.str
= argv
[*arg_ptr
];
634 parse_iname (argv
, arg_ptr
)
638 struct predicate
*our_pred
;
640 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
642 our_pred
= insert_primary (pred_iname
);
643 our_pred
->need_stat
= false;
644 our_pred
->args
.str
= argv
[*arg_ptr
];
650 parse_inum (argv
, arg_ptr
)
654 return (insert_num (argv
, arg_ptr
, pred_inum
));
658 parse_ipath (argv
, arg_ptr
)
662 struct predicate
*our_pred
;
664 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
666 our_pred
= insert_primary (pred_ipath
);
667 our_pred
->need_stat
= false;
668 our_pred
->args
.str
= argv
[*arg_ptr
];
674 parse_iregex (argv
, arg_ptr
)
678 return insert_regex (argv
, arg_ptr
, true);
682 parse_links (argv
, arg_ptr
)
686 return (insert_num (argv
, arg_ptr
, pred_links
));
690 parse_lname (argv
, arg_ptr
)
694 struct predicate
*our_pred
;
696 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
698 our_pred
= insert_primary (pred_lname
);
699 our_pred
->args
.str
= argv
[*arg_ptr
];
705 parse_ls (argv
, arg_ptr
)
709 struct predicate
*our_pred
;
711 our_pred
= insert_primary (pred_ls
);
712 our_pred
->side_effects
= true;
717 parse_maxdepth (argv
, arg_ptr
)
723 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
725 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
726 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
728 maxdepth
= atoi (argv
[*arg_ptr
]);
736 parse_mindepth (argv
, arg_ptr
)
742 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
744 depth_len
= strspn (argv
[*arg_ptr
], "0123456789");
745 if ((depth_len
== 0) || (argv
[*arg_ptr
][depth_len
] != '\0'))
747 mindepth
= atoi (argv
[*arg_ptr
]);
755 parse_mmin (argv
, arg_ptr
)
759 struct predicate
*our_pred
;
761 enum comparison_type c_type
;
763 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
765 if (!get_num_days (argv
[*arg_ptr
], &num
, &c_type
))
767 our_pred
= insert_primary (pred_mmin
);
768 our_pred
->args
.info
.kind
= c_type
;
769 our_pred
->args
.info
.l_val
= cur_day_start
+ DAYSECS
- num
* 60;
775 parse_mtime (argv
, arg_ptr
)
779 return (insert_time (argv
, arg_ptr
, pred_mtime
));
783 parse_name (argv
, 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 (argv
, arg_ptr
)
803 struct predicate
*our_pred
;
805 our_pred
= get_new_pred_chk_op ();
806 our_pred
->pred_func
= pred_negate
;
808 our_pred
->p_name
= find_pred_name (pred_negate
);
810 our_pred
->p_type
= UNI_OP
;
811 our_pred
->p_prec
= NEGATE_PREC
;
812 our_pred
->need_stat
= false;
817 parse_newer (argv
, arg_ptr
)
821 struct predicate
*our_pred
;
822 struct stat stat_newer
;
824 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
826 if ((*xstat
) (argv
[*arg_ptr
], &stat_newer
))
827 error (1, errno
, "%s", argv
[*arg_ptr
]);
828 our_pred
= insert_primary (pred_newer
);
829 our_pred
->args
.time
= stat_newer
.st_mtime
;
835 parse_noleaf (argv
, arg_ptr
)
839 no_leaf_check
= true;
844 /* Arbitrary amount by which to increase size
845 of `uid_unused' and `gid_unused'. */
846 #define ALLOC_STEP 2048
848 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
849 char *uid_unused
= NULL
;
851 /* Number of elements in `uid_unused'. */
852 unsigned uid_allocated
;
854 /* Similar for GIDs and group entries. */
855 char *gid_unused
= NULL
;
856 unsigned gid_allocated
;
860 parse_nogroup (argv
, arg_ptr
)
864 struct predicate
*our_pred
;
866 our_pred
= insert_primary (pred_nogroup
);
868 if (gid_unused
== NULL
)
872 gid_allocated
= ALLOC_STEP
;
873 gid_unused
= xmalloc (gid_allocated
);
874 memset (gid_unused
, 1, gid_allocated
);
876 while ((gr
= getgrent ()) != NULL
)
878 if ((unsigned) gr
->gr_gid
>= gid_allocated
)
880 unsigned new_allocated
= (unsigned) gr
->gr_gid
+ ALLOC_STEP
;
881 gid_unused
= xrealloc (gid_unused
, new_allocated
);
882 memset (gid_unused
+ gid_allocated
, 1,
883 new_allocated
- gid_allocated
);
884 gid_allocated
= new_allocated
;
886 gid_unused
[(unsigned) gr
->gr_gid
] = 0;
895 parse_nouser (argv
, arg_ptr
)
899 struct predicate
*our_pred
;
901 our_pred
= insert_primary (pred_nouser
);
903 if (uid_unused
== NULL
)
907 uid_allocated
= ALLOC_STEP
;
908 uid_unused
= xmalloc (uid_allocated
);
909 memset (uid_unused
, 1, uid_allocated
);
911 while ((pw
= getpwent ()) != NULL
)
913 if ((unsigned) pw
->pw_uid
>= uid_allocated
)
915 unsigned new_allocated
= (unsigned) pw
->pw_uid
+ ALLOC_STEP
;
916 uid_unused
= xrealloc (uid_unused
, new_allocated
);
917 memset (uid_unused
+ uid_allocated
, 1,
918 new_allocated
- uid_allocated
);
919 uid_allocated
= new_allocated
;
921 uid_unused
[(unsigned) pw
->pw_uid
] = 0;
930 parse_ok (argv
, arg_ptr
)
934 return (insert_exec_ok (pred_ok
, argv
, arg_ptr
));
938 parse_open (argv
, arg_ptr
)
942 struct predicate
*our_pred
;
944 our_pred
= get_new_pred_chk_op ();
945 our_pred
->pred_func
= pred_open
;
947 our_pred
->p_name
= find_pred_name (pred_open
);
949 our_pred
->p_type
= OPEN_PAREN
;
950 our_pred
->p_prec
= NO_PREC
;
951 our_pred
->need_stat
= false;
956 parse_or (argv
, arg_ptr
)
960 struct predicate
*our_pred
;
962 our_pred
= get_new_pred ();
963 our_pred
->pred_func
= pred_or
;
965 our_pred
->p_name
= find_pred_name (pred_or
);
967 our_pred
->p_type
= BI_OP
;
968 our_pred
->p_prec
= OR_PREC
;
969 our_pred
->need_stat
= false;
974 parse_path (argv
, arg_ptr
)
978 struct predicate
*our_pred
;
980 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
982 our_pred
= insert_primary (pred_path
);
983 our_pred
->need_stat
= false;
984 our_pred
->args
.str
= argv
[*arg_ptr
];
990 parse_perm (argv
, arg_ptr
)
994 unsigned long perm_val
;
996 struct mode_change
*change
;
997 struct predicate
*our_pred
;
999 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1002 switch (argv
[*arg_ptr
][0])
1013 change
= mode_compile (argv
[*arg_ptr
] + mode_start
, MODE_MASK_PLUS
);
1014 if (change
== MODE_INVALID
)
1015 error (1, 0, _("invalid mode `%s'"), argv
[*arg_ptr
]);
1016 else if (change
== MODE_MEMORY_EXHAUSTED
)
1017 error (1, 0, _("virtual memory exhausted"));
1018 perm_val
= mode_adjust (0, change
);
1021 our_pred
= insert_primary (pred_perm
);
1023 switch (argv
[*arg_ptr
][0])
1026 /* Set magic flag to indicate true if at least the given bits are set. */
1027 our_pred
->args
.perm
= (perm_val
& 07777) | 010000;
1030 /* Set magic flag to indicate true if any of the given bits are set. */
1031 our_pred
->args
.perm
= (perm_val
& 07777) | 020000;
1034 /* True if exactly the given bits are set. */
1035 our_pred
->args
.perm
= (perm_val
& 07777);
1043 parse_print (argv
, arg_ptr
)
1047 struct predicate
*our_pred
;
1049 our_pred
= insert_primary (pred_print
);
1050 /* -print has the side effect of printing. This prevents us
1051 from doing undesired multiple printing when the user has
1052 already specified -print. */
1053 our_pred
->side_effects
= true;
1054 our_pred
->need_stat
= false;
1059 parse_print0 (argv
, arg_ptr
)
1063 struct predicate
*our_pred
;
1065 our_pred
= insert_primary (pred_print0
);
1066 /* -print0 has the side effect of printing. This prevents us
1067 from doing undesired multiple printing when the user has
1068 already specified -print0. */
1069 our_pred
->side_effects
= true;
1070 our_pred
->need_stat
= false;
1075 parse_printf (argv
, arg_ptr
)
1079 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1081 return (insert_fprintf (stdout
, pred_fprintf
, argv
, arg_ptr
));
1085 parse_prune (argv
, arg_ptr
)
1089 struct predicate
*our_pred
;
1091 our_pred
= insert_primary (pred_prune
);
1092 our_pred
->need_stat
= false;
1097 parse_regex (argv
, arg_ptr
)
1101 return insert_regex (argv
, arg_ptr
, false);
1105 insert_regex (argv
, arg_ptr
, ignore_case
)
1108 boolean ignore_case
;
1110 struct predicate
*our_pred
;
1111 struct re_pattern_buffer
*re
;
1112 const char *error_message
;
1114 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1116 our_pred
= insert_primary (pred_regex
);
1117 our_pred
->need_stat
= false;
1118 re
= (struct re_pattern_buffer
*)
1119 xmalloc (sizeof (struct re_pattern_buffer
));
1120 our_pred
->args
.regex
= re
;
1121 re
->allocated
= 100;
1122 re
->buffer
= (unsigned char *) xmalloc (re
->allocated
);
1129 re
->translate
= xmalloc (256);
1130 /* Map uppercase characters to corresponding lowercase ones. */
1131 for (i
= 0; i
< 256; i
++)
1132 re
->translate
[i
] = ISUPPER (i
) ? tolower (i
) : i
;
1135 re
->translate
= NULL
;
1137 error_message
= re_compile_pattern (argv
[*arg_ptr
], strlen (argv
[*arg_ptr
]),
1140 error (1, 0, "%s", error_message
);
1146 parse_size (argv
, arg_ptr
)
1150 struct predicate
*our_pred
;
1152 enum comparison_type c_type
;
1156 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1158 len
= strlen (argv
[*arg_ptr
]);
1160 error (1, 0, _("invalid null argument to -size"));
1161 switch (argv
[*arg_ptr
][len
- 1])
1165 argv
[*arg_ptr
][len
- 1] = '\0';
1170 argv
[*arg_ptr
][len
- 1] = '\0';
1175 argv
[*arg_ptr
][len
- 1] = '\0';
1180 argv
[*arg_ptr
][len
- 1] = '\0';
1196 error (1, 0, _("invalid -size type `%c'"), argv
[*arg_ptr
][len
- 1]);
1198 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1200 our_pred
= insert_primary (pred_size
);
1201 our_pred
->args
.size
.kind
= c_type
;
1202 our_pred
->args
.size
.blocksize
= blksize
;
1203 our_pred
->args
.size
.size
= num
;
1209 parse_true (argv
, arg_ptr
)
1213 struct predicate
*our_pred
;
1215 our_pred
= insert_primary (pred_true
);
1216 our_pred
->need_stat
= false;
1221 parse_type (argv
, arg_ptr
)
1225 return insert_type (argv
, arg_ptr
, pred_type
);
1229 parse_uid (argv
, arg_ptr
)
1233 return (insert_num (argv
, arg_ptr
, pred_uid
));
1237 parse_used (argv
, arg_ptr
)
1242 struct predicate
*our_pred
;
1243 unsigned long num_days
;
1244 enum comparison_type c_type
;
1246 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1248 if (!get_num (argv
[*arg_ptr
], &num_days
, &c_type
))
1250 our_pred
= insert_primary (pred_used
);
1251 our_pred
->args
.info
.kind
= c_type
;
1252 our_pred
->args
.info
.l_val
= num_days
* DAYSECS
;
1258 parse_user (argv
, arg_ptr
)
1262 struct passwd
*cur_pwd
;
1263 struct predicate
*our_pred
;
1267 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1269 cur_pwd
= getpwnam (argv
[*arg_ptr
]);
1271 if (cur_pwd
!= NULL
)
1272 uid
= cur_pwd
->pw_uid
;
1275 uid_len
= strspn (argv
[*arg_ptr
], "0123456789");
1276 if ((uid_len
== 0) || (argv
[*arg_ptr
][uid_len
] != '\0'))
1278 uid
= atoi (argv
[*arg_ptr
]);
1280 our_pred
= insert_primary (pred_user
);
1281 our_pred
->args
.uid
= uid
;
1287 parse_version (argv
, arg_ptr
)
1291 extern char *version_string
;
1294 printf (_("GNU find version %s\n"), version_string
);
1299 parse_xdev (argv
, arg_ptr
)
1303 stay_on_filesystem
= true;
1308 parse_xtype (argv
, arg_ptr
)
1312 return insert_type (argv
, arg_ptr
, pred_xtype
);
1316 insert_type (argv
, arg_ptr
, which_pred
)
1319 boolean (*which_pred
) ();
1321 unsigned long type_cell
;
1322 struct predicate
*our_pred
;
1324 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
)
1325 || (strlen (argv
[*arg_ptr
]) != 1))
1327 switch (argv
[*arg_ptr
][0])
1329 case 'b': /* block special */
1330 type_cell
= S_IFBLK
;
1332 case 'c': /* character special */
1333 type_cell
= S_IFCHR
;
1335 case 'd': /* directory */
1336 type_cell
= S_IFDIR
;
1338 case 'f': /* regular file */
1339 type_cell
= S_IFREG
;
1342 case 'l': /* symbolic link */
1343 type_cell
= S_IFLNK
;
1347 case 'p': /* pipe */
1348 type_cell
= S_IFIFO
;
1352 case 's': /* socket */
1353 type_cell
= S_IFSOCK
;
1356 default: /* None of the above ... nuke 'em. */
1359 our_pred
= insert_primary (which_pred
);
1360 our_pred
->args
.type
= type_cell
;
1361 (*arg_ptr
)++; /* Move on to next argument. */
1365 /* If true, we've determined that the current fprintf predicate
1366 uses stat information. */
1367 static boolean fprintf_stat_needed
;
1370 insert_fprintf (fp
, func
, argv
, arg_ptr
)
1376 char *format
; /* Beginning of unprocessed format string. */
1377 register char *scan
; /* Current address in scanning `format'. */
1378 register char *scan2
; /* Address inside of element being scanned. */
1379 struct segment
**segmentp
; /* Address of current segment. */
1380 struct predicate
*our_pred
;
1382 format
= argv
[(*arg_ptr
)++];
1384 fprintf_stat_needed
= false; /* Might be overridden later. */
1385 our_pred
= insert_primary (func
);
1386 our_pred
->side_effects
= true;
1387 our_pred
->args
.printf_vec
.stream
= fp
;
1388 segmentp
= &our_pred
->args
.printf_vec
.segment
;
1391 for (scan
= format
; *scan
; scan
++)
1396 if (*scan2
>= '0' && *scan2
<= '7')
1400 for (i
= n
= 0; i
< 3 && (*scan2
>= '0' && *scan2
<= '7');
1402 n
= 8 * n
+ *scan2
- '0';
1417 make_segment (segmentp
, format
, scan
- format
, KIND_STOP
);
1418 our_pred
->need_stat
= fprintf_stat_needed
;
1436 /* *scan = '\\'; * it already is */
1440 _("warning: unrecognized escape `\\%c'"), *scan2
);
1445 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1447 format
= scan2
+ 1; /* Move past the escape. */
1448 scan
= scan2
; /* Incremented immediately by `for'. */
1450 else if (*scan
== '%')
1454 segmentp
= make_segment (segmentp
, format
, scan
- format
+ 1,
1460 /* Scan past flags, width and precision, to verify kind. */
1461 for (scan2
= scan
; *++scan2
&& strchr ("-+ #", *scan2
);)
1463 while (ISDIGIT (*scan2
))
1466 for (scan2
++; ISDIGIT (*scan2
); scan2
++)
1468 if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2
))
1470 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1475 else if (strchr ("ACT", *scan2
) && scan2
[1])
1477 segmentp
= make_segment (segmentp
, format
, scan2
- format
,
1478 *scan2
| (scan2
[1] << 8));
1485 /* An unrecognized % escape. Print the char after the %. */
1486 error (0, 0, _("warning: unrecognized format directive `%%%c'"),
1488 segmentp
= make_segment (segmentp
, format
, scan
- format
,
1497 make_segment (segmentp
, format
, scan
- format
, KIND_PLAIN
);
1498 our_pred
->need_stat
= fprintf_stat_needed
;
1502 /* Create a new fprintf segment in *SEGMENT, with type KIND,
1503 from the text in FORMAT, which has length LEN.
1504 Return the address of the `next' pointer of the new segment. */
1506 static struct segment
**
1507 make_segment (segment
, format
, len
, kind
)
1508 struct segment
**segment
;
1514 *segment
= (struct segment
*) xmalloc (sizeof (struct segment
));
1516 (*segment
)->kind
= kind
;
1517 (*segment
)->next
= NULL
;
1518 (*segment
)->text_len
= len
;
1520 fmt
= (*segment
)->text
= xmalloc (len
+ 3); /* room for "ld\0" */
1521 strncpy (fmt
, format
, len
);
1524 switch (kind
& 0xff)
1526 case KIND_PLAIN
: /* Plain text string, no % conversion. */
1527 case KIND_STOP
: /* Terminate argument, no newline. */
1530 case 'a': /* atime in `ctime' format */
1531 case 'c': /* ctime in `ctime' format */
1532 case 'F': /* filesystem type */
1533 case 'g': /* group name */
1534 case 'l': /* object of symlink */
1535 case 't': /* mtime in `ctime' format */
1536 case 'u': /* user name */
1537 case 'A': /* atime in user-specified strftime format */
1538 case 'C': /* ctime in user-specified strftime format */
1539 case 'T': /* mtime in user-specified strftime format */
1540 fprintf_stat_needed
= true;
1542 case 'f': /* basename of path */
1543 case 'h': /* leading directories part of path */
1544 case 'H': /* ARGV element file was found under */
1545 case 'p': /* pathname */
1546 case 'P': /* pathname with ARGV element stripped */
1550 case 'b': /* size in 512-byte blocks */
1551 case 'k': /* size in 1K blocks */
1552 case 's': /* size in bytes */
1555 case 'n': /* number of links */
1556 fprintf_stat_needed
= true;
1558 case 'd': /* depth in search tree (0 = ARGV element) */
1562 case 'i': /* inode number */
1565 case 'G': /* GID number */
1566 case 'U': /* UID number */
1568 fprintf_stat_needed
= true;
1571 case 'm': /* mode as octal number (perms only) */
1573 fprintf_stat_needed
= true;
1578 return (&(*segment
)->next
);
1582 insert_exec_ok (func
, argv
, arg_ptr
)
1587 int start
, end
; /* Indexes in ARGV of start & end of cmd. */
1588 int num_paths
; /* Number of args with path replacements. */
1589 int path_pos
; /* Index in array of path replacements. */
1590 int vec_pos
; /* Index in array of args. */
1591 struct predicate
*our_pred
;
1592 struct exec_val
*execp
; /* Pointer for efficiency. */
1594 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1597 /* Count the number of args with path replacements, up until the ';'. */
1599 for (end
= start
, num_paths
= 0;
1601 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1603 if (strstr (argv
[end
], "{}"))
1605 /* Fail if no command given or no semicolon found. */
1606 if ((end
== start
) || (argv
[end
] == NULL
))
1612 our_pred
= insert_primary (func
);
1613 our_pred
->side_effects
= true;
1614 execp
= &our_pred
->args
.exec_vec
;
1616 (struct path_arg
*) xmalloc (sizeof (struct path_arg
) * (num_paths
+ 1));
1617 execp
->vec
= (char **) xmalloc (sizeof (char *) * (end
- start
+ 1));
1618 /* Record the positions of all args, and the args with path replacements. */
1619 for (end
= start
, path_pos
= vec_pos
= 0;
1621 && ((argv
[end
][0] != ';') || (argv
[end
][1] != '\0'));
1626 execp
->paths
[path_pos
].count
= 0;
1627 for (p
= argv
[end
]; *p
; ++p
)
1628 if (p
[0] == '{' && p
[1] == '}')
1630 execp
->paths
[path_pos
].count
++;
1633 if (execp
->paths
[path_pos
].count
)
1635 execp
->paths
[path_pos
].offset
= vec_pos
;
1636 execp
->paths
[path_pos
].origarg
= argv
[end
];
1639 execp
->vec
[vec_pos
++] = argv
[end
];
1641 execp
->paths
[path_pos
].offset
= -1;
1642 execp
->vec
[vec_pos
] = NULL
;
1644 if (argv
[end
] == NULL
)
1651 /* Get a number of days and comparison type.
1652 STR is the ASCII representation.
1653 Set *NUM_DAYS to the number of days, taken as being from
1654 the current moment (or possibly midnight). Thus the sense of the
1655 comparison type appears to be reversed.
1656 Set *COMP_TYPE to the kind of comparison that is requested.
1658 Return true if all okay, false if input error.
1660 Used by -atime, -ctime and -mtime (parsers) to
1661 get the appropriate information for a time predicate processor. */
1664 get_num_days (str
, num_days
, comp_type
)
1666 unsigned long *num_days
;
1667 enum comparison_type
*comp_type
;
1669 int len_days
; /* length of field */
1676 *comp_type
= COMP_LT
;
1680 *comp_type
= COMP_GT
;
1693 *comp_type
= COMP_EQ
;
1699 /* We know the first char has been reasonable. Find the
1700 number of days to play with. */
1701 len_days
= strspn (str
, "0123456789");
1702 if ((len_days
== 0) || (str
[len_days
] != '\0'))
1704 *num_days
= (unsigned long) atol (str
);
1708 /* Insert a time predicate PRED.
1709 ARGV is a pointer to the argument array.
1710 ARG_PTR is a pointer to an index into the array, incremented if
1713 Return true if input is valid, false if not.
1715 A new predicate node is assigned, along with an argument node
1716 obtained with malloc.
1718 Used by -atime, -ctime, and -mtime parsers. */
1721 insert_time (argv
, arg_ptr
, pred
)
1726 struct predicate
*our_pred
;
1727 unsigned long num_days
;
1728 enum comparison_type c_type
;
1730 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1732 if (!get_num_days (argv
[*arg_ptr
], &num_days
, &c_type
))
1734 our_pred
= insert_primary (pred
);
1735 our_pred
->args
.info
.kind
= c_type
;
1736 our_pred
->args
.info
.l_val
= cur_day_start
- num_days
* DAYSECS
1737 + ((c_type
== COMP_GT
) ? DAYSECS
- 1 : 0);
1740 printf (_("inserting %s\n"), our_pred
->p_name
);
1741 printf (_(" type: %s %s "),
1742 (c_type
== COMP_GT
) ? "gt" :
1743 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1744 (c_type
== COMP_GT
) ? " >" :
1745 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? ">=" : " ?")));
1746 printf ("%ld %s", our_pred
->args
.info
.l_val
,
1747 ctime (&our_pred
->args
.info
.l_val
));
1748 if (c_type
== COMP_EQ
)
1750 our_pred
->args
.info
.l_val
+= DAYSECS
;
1751 printf (" < %ld %s", our_pred
->args
.info
.l_val
,
1752 ctime (&our_pred
->args
.info
.l_val
));
1753 our_pred
->args
.info
.l_val
-= DAYSECS
;
1759 /* Get a number with comparision information.
1760 The sense of the comparision information is 'normal'; that is,
1761 '+' looks for inums or links > than the number and '-' less than.
1763 STR is the ASCII representation of the number.
1764 Set *NUM to the number.
1765 Set *COMP_TYPE to the kind of comparison that is requested.
1767 Return true if all okay, false if input error.
1769 Used by the -inum and -links predicate parsers. */
1772 get_num (str
, num
, comp_type
)
1775 enum comparison_type
*comp_type
;
1777 int len_num
; /* Length of field. */
1784 *comp_type
= COMP_GT
;
1788 *comp_type
= COMP_LT
;
1801 *comp_type
= COMP_EQ
;
1807 /* We know the first char has been reasonable. Find the number of
1808 days to play with. */
1809 len_num
= strspn (str
, "0123456789");
1810 if ((len_num
== 0) || (str
[len_num
] != '\0'))
1812 *num
= (unsigned long) atol (str
);
1816 /* Insert a number predicate.
1817 ARGV is a pointer to the argument array.
1818 *ARG_PTR is an index into ARGV, incremented if all went well.
1819 *PRED is the predicate processor to insert.
1821 Return true if input is valid, false if error.
1823 A new predicate node is assigned, along with an argument node
1824 obtained with malloc.
1826 Used by -inum and -links parsers. */
1829 insert_num (argv
, arg_ptr
, pred
)
1834 struct predicate
*our_pred
;
1836 enum comparison_type c_type
;
1838 if ((argv
== NULL
) || (argv
[*arg_ptr
] == NULL
))
1840 if (!get_num (argv
[*arg_ptr
], &num
, &c_type
))
1842 our_pred
= insert_primary (pred
);
1843 our_pred
->args
.info
.kind
= c_type
;
1844 our_pred
->args
.info
.l_val
= num
;
1847 printf (_("inserting %s\n"), our_pred
->p_name
);
1848 printf (_(" type: %s %s "),
1849 (c_type
== COMP_GT
) ? "gt" :
1850 ((c_type
== COMP_LT
) ? "lt" : ((c_type
== COMP_EQ
) ? "eq" : "?")),
1851 (c_type
== COMP_GT
) ? " >" :
1852 ((c_type
== COMP_LT
) ? " <" : ((c_type
== COMP_EQ
) ? " =" : " ?")));
1853 printf ("%ld\n", our_pred
->args
.info
.l_val
);
1859 open_output_file (path
)
1864 if (!strcmp (path
, "/dev/stderr"))
1866 else if (!strcmp (path
, "/dev/stdout"))
1868 f
= fopen (path
, "w");
1870 error (1, errno
, "%s", path
);