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)