Mercurial > hg > toybox
comparison toys/pending/find.c @ 874:c326f55c74bd
More find cleanup
author | Felix Janda <felix.janda@posteo.de> |
---|---|
date | Sat, 20 Apr 2013 17:25:41 +0200 |
parents | 1700c6bfc8f5 |
children | 2650f5f56bab |
comparison
equal
deleted
inserted
replaced
873:d90f14e011b8 | 874:c326f55c74bd |
---|---|
26 * -exec action | 26 * -exec action |
27 */ | 27 */ |
28 | 28 |
29 #define FOR_find | 29 #define FOR_find |
30 #include "toys.h" | 30 #include "toys.h" |
31 | |
32 GLOBALS( | |
33 char *dir; | |
34 ) | |
35 | |
36 #define SECONDS_PER_DAY (24*60*60) | |
37 | |
38 int have_action; | |
39 | 31 |
40 struct filter_node { | 32 struct filter_node { |
41 struct filter_node *next; | 33 struct filter_node *next; |
42 int op; | 34 int op; |
43 union { | 35 union { |
52 char **exec_args; | 44 char **exec_args; |
53 } e; | 45 } e; |
54 } data; | 46 } data; |
55 }; | 47 }; |
56 | 48 |
57 static struct filter_node *filter_root; | 49 GLOBALS( |
50 char *dir; | |
51 int have_action; | |
52 struct filter_node *filter_root; | |
53 ) | |
54 | |
55 #define SECONDS_PER_DAY (24*60*60) | |
58 | 56 |
59 /* filter operation types */ | 57 /* filter operation types */ |
60 #define OP_UNKNOWN 0 | 58 #define OP_UNKNOWN 0 |
61 #define OP_OR 2 | 59 #define OP_OR 2 |
62 #define OP_AND 3 | 60 #define OP_AND 3 |
72 #define CHECK_TYPE 9 | 70 #define CHECK_TYPE 9 |
73 | 71 |
74 #define ACTION_PRINT 20 | 72 #define ACTION_PRINT 20 |
75 #define ACTION_PRINT0 21 | 73 #define ACTION_PRINT0 21 |
76 #define ACTION_EXEC 22 | 74 #define ACTION_EXEC 22 |
75 | |
76 #define IS_ACTION(x) (x >= 20) | |
77 | 77 |
78 #define TEST_LT 0 | 78 #define TEST_LT 0 |
79 #define TEST_EQ 1 | 79 #define TEST_EQ 1 |
80 #define TEST_GT 2 | 80 #define TEST_GT 2 |
81 | 81 |
202 return 1; | 202 return 1; |
203 } | 203 } |
204 | 204 |
205 static int check_node_callback(struct dirtree *node) | 205 static int check_node_callback(struct dirtree *node) |
206 { | 206 { |
207 char *path; | |
208 int plen = 0; | |
209 int result; | 207 int result; |
210 struct filter_node *junk; | 208 struct filter_node *junk; |
211 | 209 |
212 /* only recurse on "." at the root */ | 210 /* only recurse on "." at the root */ |
213 /* so, don't recurse on 1) non-root "." and 2) any ".." */ | 211 /* so, don't recurse on 1) non-root "." and 2) any ".." */ |
215 if (node->name[0] == '.' && | 213 if (node->name[0] == '.' && |
216 ((!node->name[1] && node->parent) || | 214 ((!node->name[1] && node->parent) || |
217 (node->name[1]=='.' && !node->name[2]))) | 215 (node->name[1]=='.' && !node->name[2]))) |
218 return 0; | 216 return 0; |
219 | 217 |
220 result = evaluate(filter_root, node, &junk); | 218 result = evaluate(TT.filter_root, node, &junk); |
221 if (result & !have_action) { | 219 if (result & !TT.have_action) { |
222 /* default action is just print the path */ | 220 /* default action is just print the path */ |
221 char *path; | |
222 int plen = 0; | |
223 path = dirtree_path(node, &plen); | 223 path = dirtree_path(node, &plen); |
224 printf("%s\n", path); | 224 printf("%s\n", path); |
225 free(path); | 225 free(path); |
226 } | 226 } |
227 return DIRTREE_RECURSE; | 227 return DIRTREE_RECURSE; |
229 | 229 |
230 | 230 |
231 static void build_filter_list(void) | 231 static void build_filter_list(void) |
232 { | 232 { |
233 struct filter_node *node_list, *op_stack, *node, *op_node, *next; | 233 struct filter_node *node_list, *op_stack, *node, *op_node, *next; |
234 char *arg, **arg_array; | 234 char **arg; |
235 int i, j; | 235 int j; |
236 int prevop = 0; | 236 int prevop = 0; |
237 | 237 |
238 /* part optargs here and build a filter list in prefix format */ | 238 /* part optargs here and build a filter list in prefix format */ |
239 | 239 |
240 TT.dir = "."; | 240 TT.dir = "."; |
241 node_list = NULL; | 241 node_list = NULL; |
242 have_action = 0; | 242 TT.have_action = 0; |
243 for(i=0; toys.optargs[i]; i++) { | 243 for (arg = toys.optargs; *arg; arg++) { |
244 node = (struct filter_node *) | 244 struct { |
245 xmalloc(sizeof(struct filter_node)); | 245 char *arg; |
246 int op; | |
247 int extrarg; | |
248 } arg_map[] = {{"-o", OP_OR, 0}, | |
249 {"-a", OP_AND, 0}, | |
250 {"!", OP_NOT, 0}, | |
251 {"(", LPAREN, 0}, | |
252 {")", RPAREN, 0}, | |
253 {"-name", CHECK_NAME, 1}, | |
254 {"-mtime", CHECK_MTIME, 1}, | |
255 {"-type", CHECK_TYPE, 1}, | |
256 {"-print", ACTION_PRINT, 0}, | |
257 {"-print0", ACTION_PRINT0, 0}, | |
258 {"-exec", ACTION_EXEC, 1} | |
259 }; | |
260 mode_t types[]={S_IFREG,S_IFDIR,S_IFCHR,S_IFBLK,S_IFLNK,S_IFSOCK,S_IFIFO}; | |
261 char **arg_array; | |
262 node = (struct filter_node *) xmalloc(sizeof(struct filter_node)); | |
246 node->op = OP_UNKNOWN; | 263 node->op = OP_UNKNOWN; |
247 arg = toys.optargs[i]; | 264 for (j=0; j < sizeof(arg_map)/sizeof(*arg_map); j++) { |
248 if (!strcmp(arg, "-o")) node->op = OP_OR; | 265 if (!strcmp(*arg, arg_map[j].arg)) { |
249 if (!strcmp(arg, "-a")) node->op = OP_AND; | 266 node->op = arg_map[j].op; |
250 if (!strcmp(arg, "!")) node->op = OP_NOT; | 267 if (arg_map[j].extrarg && !*(++arg)) |
251 if (!strcmp(arg, "(")) node->op = LPAREN; | 268 error_exit("Missing argument to %s", arg_map[j].arg); |
252 if (!strcmp(arg, ")")) node->op = RPAREN; | 269 break; |
253 | 270 } |
254 if (!strcmp(arg, "-name")) { | 271 } |
255 node->op = CHECK_NAME; | 272 |
256 arg = toys.optargs[++i]; | 273 switch(node->op) { |
257 if (!arg) error_exit("Missing argument to -name"); | 274 case CHECK_NAME: |
258 node->data.name_regex = arg; | 275 node->data.name_regex = *arg; |
259 } | 276 break; |
260 | 277 case CHECK_MTIME: |
261 if (!strcmp(arg, "-mtime")) { | 278 switch(**arg) { |
262 node->op = CHECK_MTIME; | 279 case '+': |
263 arg = toys.optargs[++i]; | 280 node->data.t.time_op=TEST_GT; |
264 if (!arg) error_exit("Missing argument to -mtime"); | 281 arg++; |
265 switch(arg[0]) { | 282 break; |
266 case '+': | 283 case '-': |
267 node->data.t.time_op=TEST_GT; | 284 node->data.t.time_op=TEST_LT; |
285 arg++; | |
286 break; | |
287 default: | |
288 node->data.t.time_op=TEST_EQ; | |
289 break; | |
290 } | |
291 /* convert to days (very crudely) */ | |
292 node->data.t.time = atoi(*arg)/SECONDS_PER_DAY; | |
293 break; | |
294 case CHECK_TYPE: | |
295 if (-1 == (j = stridx("fdcblsp", **arg))) | |
296 error_exit("bad type '%s'", *arg); | |
297 else node->data.type = types[j]; | |
298 break; | |
299 case ACTION_EXEC: | |
300 arg_array = xmalloc(sizeof(char *)); | |
301 for (j = 0; *arg && strcmp(*arg, ";"); j++) { | |
302 /* new method */ | |
303 arg_array = xrealloc(arg_array, sizeof(char *) * (j+2)); | |
304 arg_array[j] = *arg; | |
305 if (!strcmp(*arg, "{}")) node->data.e.arg_path_index = j; | |
306 | |
268 arg++; | 307 arg++; |
269 break; | 308 } |
270 case '-': | 309 if (!*arg) error_exit("need ';' in exec"); |
271 node->data.t.time_op=TEST_LT; | 310 arg_array[j] = 0; |
272 arg++; | 311 node->data.e.exec_args = arg_array; |
273 break; | 312 break; |
274 default: | 313 } |
275 node->data.t.time_op=TEST_EQ; | 314 |
276 break; | 315 TT.have_action |= IS_ACTION(node->op); |
277 } | 316 |
278 /* convert to days (very crudely) */ | |
279 node->data.t.time = atoi(arg)/SECONDS_PER_DAY; | |
280 } | |
281 | |
282 if (!strcmp(arg, "-type")) { | |
283 mode_t types[]={S_IFREG,S_IFDIR,S_IFCHR,S_IFBLK,S_IFLNK,S_IFSOCK,S_IFIFO}; | |
284 int j; | |
285 | |
286 node->op = CHECK_TYPE; | |
287 arg = toys.optargs[++i]; | |
288 if (!arg) error_exit("Missing argument to -type"); | |
289 if (-1 == (j = stridx("fdcblsp", *arg))) | |
290 error_exit("bad type '%s'", arg); | |
291 else node->data.type = types[j]; | |
292 } | |
293 if (!strcmp(arg, "-print")) { | |
294 node->op = ACTION_PRINT; | |
295 have_action = 1; | |
296 } | |
297 if (!strcmp(arg, "-print0")) { | |
298 node->op = ACTION_PRINT0; | |
299 have_action = 1; | |
300 } | |
301 if (!strcmp(arg, "-exec")) { | |
302 node->op = ACTION_EXEC; | |
303 have_action = 1; | |
304 arg_array = xmalloc(sizeof(char *)); | |
305 arg = toys.optargs[++i]; | |
306 for (j = 0; arg && strcmp(arg, ";"); j++) { | |
307 /* new method */ | |
308 arg_array = xrealloc(arg_array, sizeof(char *) * (j+2)); | |
309 arg_array[j] = arg; | |
310 if (!strcmp(arg, "{}")) node->data.e.arg_path_index = j; | |
311 | |
312 arg = toys.optargs[++i]; | |
313 } | |
314 if (!arg) error_exit("need ';' in exec"); | |
315 arg_array[j] = 0; | |
316 node->data.e.exec_args = arg_array; | |
317 } | |
318 if (node->op == OP_UNKNOWN) { | 317 if (node->op == OP_UNKNOWN) { |
319 if (arg[0] == '-') error_exit("bad option '%s'", arg); | 318 if (**arg == '-') error_exit("bad option '%s'", *arg); |
320 else TT.dir = arg; | 319 else TT.dir = *arg; |
321 } else { | 320 } else { |
322 // add OP_AND where necessary | 321 // add OP_AND where necessary |
323 if (node_list) { | 322 if (node_list) { |
324 int o1 = node_list->op, o2 = node->op; | 323 int o1 = node_list->op, o2 = node->op; |
325 if ((o1>MAX_OP && o2>MAX_OP) || | 324 if ((o1>MAX_OP && o2>MAX_OP) || |
338 } | 337 } |
339 | 338 |
340 } | 339 } |
341 | 340 |
342 /* now convert from infix to prefix */ | 341 /* now convert from infix to prefix */ |
343 filter_root = NULL; | 342 TT.filter_root = NULL; |
344 op_stack = NULL; | 343 op_stack = NULL; |
345 node = node_list; | 344 node = node_list; |
346 while( node ) { | 345 while( node ) { |
347 int op = node->op; | 346 int op = node->op; |
348 next = node->next; | 347 next = node->next; |
356 op_node = op_stack; | 355 op_node = op_stack; |
357 while (op_node) { | 356 while (op_node) { |
358 /* remove from op_stack */ | 357 /* remove from op_stack */ |
359 op_stack = op_node->next; | 358 op_stack = op_node->next; |
360 /* push to output */ | 359 /* push to output */ |
361 op_node->next = filter_root; | 360 op_node->next = TT.filter_root; |
362 filter_root = op_node; | 361 TT.filter_root = op_node; |
363 /* get next node */ | 362 /* get next node */ |
364 op_node = op_stack; | 363 op_node = op_stack; |
365 } | 364 } |
366 } | 365 } |
367 if (node) { | 366 if (node) { |
371 } | 370 } |
372 prevop = op*(op!=RPAREN); | 371 prevop = op*(op!=RPAREN); |
373 } | 372 } |
374 else { | 373 else { |
375 /* push to output */ | 374 /* push to output */ |
376 node->next = filter_root; | 375 node->next = TT.filter_root; |
377 filter_root = node; | 376 TT.filter_root = node; |
378 } | 377 } |
379 node = next; | 378 node = next; |
380 } | 379 } |
381 /* end of input - push opstack to output */ | 380 /* end of input - push opstack to output */ |
382 /* pop opstack to output till empty */ | 381 /* pop opstack to output till empty */ |
383 op_node = op_stack; | 382 op_node = op_stack; |
384 while (op_node) { | 383 while (op_node) { |
385 op_stack = op_node->next; | 384 op_stack = op_node->next; |
386 op_node->next = filter_root; | 385 op_node->next = TT.filter_root; |
387 filter_root = op_node; | 386 TT.filter_root = op_node; |
388 op_node = op_stack; | 387 op_node = op_stack; |
389 } | 388 } |
390 } | 389 } |
391 | 390 |
392 void find_main(void) | 391 void find_main(void) |