comparison toys/pending/find.c @ 867:1700c6bfc8f5

find: Improve operator processing
author Felix Janda <felix.janda@posteo.de>
date Thu, 18 Apr 2013 22:37:09 +0200
parents 917d6e051b82
children c326f55c74bd
comparison
equal deleted inserted replaced
866:0fa773e2a4fe 867:1700c6bfc8f5
56 56
57 static struct filter_node *filter_root; 57 static struct filter_node *filter_root;
58 58
59 /* filter operation types */ 59 /* filter operation types */
60 #define OP_UNKNOWN 0 60 #define OP_UNKNOWN 0
61 #define OP_NOT 1 61 #define OP_OR 2
62 #define OP_OR 2 62 #define OP_AND 3
63 #define OP_AND 3 63 #define OP_NOT 4
64 64
65 #define LPAREN 4 65 #define LPAREN 1
66 #define RPAREN 5 66 #define RPAREN 5
67
68 #define MAX_OP 5
67 69
68 #define CHECK_NAME 7 70 #define CHECK_NAME 7
69 #define CHECK_MTIME 8 71 #define CHECK_MTIME 8
70 #define CHECK_TYPE 9 72 #define CHECK_TYPE 9
71 73
109 int result; 111 int result;
110 char *path; 112 char *path;
111 int plen = 0; 113 int plen = 0;
112 struct stat st_buf; 114 struct stat st_buf;
113 time_t node_time; 115 time_t node_time;
114 char terminator; 116 int op;
117 static int skip = 0;
115 118
116 /* if no filters, success */ 119 /* if no filters, success */
117 if (!filter) { 120 if (!filter) {
118 *fnext = NULL; 121 *fnext = NULL;
119 return 1; 122 return 1;
120 } 123 }
121 124 op = filter->op;
122 if (filter->op==OP_NOT) return !evaluate(filter->next, node, fnext); 125
123 126 if (op==OP_NOT) return !evaluate(filter->next, node, fnext);
124 if (filter->op==OP_OR) 127
125 return evaluate(filter->next, node, fnext) || evaluate(*fnext, node, fnext); 128 if (op==OP_OR || op==OP_AND) {
126 129 result = evaluate(filter->next, node, fnext);
127 if (filter->op==OP_AND) 130 if(!skip) {
128 return evaluate(filter->next, node, fnext) && evaluate(*fnext, node, fnext); 131 if (op==OP_OR) {
132 skip = result;
133 result = evaluate(*fnext, node, fnext) || result;
134 } else {
135 skip = !result;
136 result = evaluate(*fnext, node, fnext) && result;
137 }
138 skip = 0;
139 }
140 else result = evaluate(*fnext, node, fnext);
141 return result;
142 }
129 143
130 // we're down to single operations, mark our position 144 // we're down to single operations, mark our position
131 *fnext = filter->next; 145 *fnext = filter->next;
146 if(skip) return 0;
132 147
133 // TODO: Do a regex comparison 148 // TODO: Do a regex comparison
134 if (filter->op==CHECK_NAME) 149 if (op==CHECK_NAME)
135 return !strcmp(filter->data.name_regex, node->name); 150 return !strcmp(filter->data.name_regex, node->name);
136 151
137 if (filter->op==CHECK_MTIME) { 152 if (op==CHECK_MTIME) {
138 // do mtime check 153 // do mtime check
139 path = dirtree_path(node, &plen); 154 path = dirtree_path(node, &plen);
140 result = stat(path, &st_buf); 155 result = stat(path, &st_buf);
141 free(path); 156 free(path);
142 if (result<0) return 0; 157 if (result<0) return 0;
161 break; 176 break;
162 } 177 }
163 return result; 178 return result;
164 179
165 } 180 }
166 if (filter->op==CHECK_TYPE) { 181 if (op==CHECK_TYPE) {
167 path = dirtree_path(node, &plen); 182 path = dirtree_path(node, &plen);
168 result = lstat(path, &st_buf); 183 result = lstat(path, &st_buf);
169 free(path); 184 free(path);
170 if (result<0) return 0; 185 if (result<0) return 0;
171 return (st_buf.st_mode & S_IFMT) == filter->data.type; 186 return (st_buf.st_mode & S_IFMT) == filter->data.type;
172 } 187 }
173 188
174 189
175 if (filter->op==ACTION_PRINT || filter->op==ACTION_PRINT0) { 190 if (op==ACTION_PRINT || op==ACTION_PRINT0) {
176 terminator = (filter->op==ACTION_PRINT)*'\n'; 191 char terminator = (op==ACTION_PRINT)*'\n';
177 192
178 path = dirtree_path(node, &plen); 193 path = dirtree_path(node, &plen);
179 printf("%s%c", path, terminator); 194 printf("%s%c", path, terminator);
180 free(path); 195 free(path);
181 return 1; 196 return 1;
182 } 197 }
183 198
184 if (filter->op==ACTION_EXEC) return !do_exec(filter, node); 199 if (op==ACTION_EXEC) return !do_exec(filter, node);
185 200
186 error_msg("Ran out of operations in filter list!"); 201 error_msg("Ran out of operations in filter list!");
187 return 1; 202 return 1;
188 } 203 }
189 204
216 static void build_filter_list(void) 231 static void build_filter_list(void)
217 { 232 {
218 struct filter_node *node_list, *op_stack, *node, *op_node, *next; 233 struct filter_node *node_list, *op_stack, *node, *op_node, *next;
219 char *arg, **arg_array; 234 char *arg, **arg_array;
220 int i, j; 235 int i, j;
236 int prevop = 0;
221 237
222 /* part optargs here and build a filter list in prefix format */ 238 /* part optargs here and build a filter list in prefix format */
223 239
224 TT.dir = "."; 240 TT.dir = ".";
225 node_list = NULL; 241 node_list = NULL;
301 } 317 }
302 if (node->op == OP_UNKNOWN) { 318 if (node->op == OP_UNKNOWN) {
303 if (arg[0] == '-') error_exit("bad option '%s'", arg); 319 if (arg[0] == '-') error_exit("bad option '%s'", arg);
304 else TT.dir = arg; 320 else TT.dir = arg;
305 } else { 321 } else {
322 // add OP_AND where necessary
323 if (node_list) {
324 int o1 = node_list->op, o2 = node->op;
325 if ((o1>MAX_OP && o2>MAX_OP) ||
326 (o1==RPAREN && o2>=OP_NOT && o2!=RPAREN) ||
327 (o1>=OP_NOT && o1!=LPAREN && o2==LPAREN)) {
328 struct filter_node *n = (struct filter_node *)
329 xmalloc(sizeof(struct filter_node));
330 n->op = OP_AND;
331 n->next = node_list;
332 node_list = n;
333 }
334 }
306 /* push node */ 335 /* push node */
307 node->next = node_list;; 336 node->next = node_list;;
308 node_list = node; 337 node_list = node;
309 } 338 }
310 339
313 /* now convert from infix to prefix */ 342 /* now convert from infix to prefix */
314 filter_root = NULL; 343 filter_root = NULL;
315 op_stack = NULL; 344 op_stack = NULL;
316 node = node_list; 345 node = node_list;
317 while( node ) { 346 while( node ) {
347 int op = node->op;
318 next = node->next; 348 next = node->next;
319 switch( node->op ) { 349 if (op==LPAREN || op==RPAREN) {
320 case OP_AND: 350 free(node);
321 case OP_OR: 351 node = 0;
322 case OP_NOT: 352 }
323 case RPAREN: 353 if (op<=MAX_OP) {
324 /* push to opstack */ 354 if (prevop > op) {
325 node->next = op_stack; 355 /* pop opstack to output */
326 op_stack = node;
327 break;
328 case LPAREN:
329 free(node);
330 /* pop opstack to output (up to rparen) */
331 op_node = op_stack; 356 op_node = op_stack;
332 while (op_node && op_node->op != RPAREN) { 357 while (op_node) {
333 /* remove from op_stack */ 358 /* remove from op_stack */
334 op_stack = op_node->next; 359 op_stack = op_node->next;
335 /* push to output */ 360 /* push to output */
336 op_node->next = filter_root; 361 op_node->next = filter_root;
337 filter_root = op_node; 362 filter_root = op_node;
338 /* get next node */ 363 /* get next node */
339 op_node = op_stack; 364 op_node = op_stack;
340 } 365 }
341 /* rparen should be on op_stack */ 366 }
342 if (!op_stack) error_exit("need ')'"); 367 if (node) {
343 /* remove rparen from op_stack */ 368 /* push to opstack */
344 op_stack = op_stack->next; 369 node->next = op_stack;
345 free(op_node); 370 op_stack = node;
346 break; 371 }
347 default: 372 prevop = op*(op!=RPAREN);
373 }
374 else {
348 /* push to output */ 375 /* push to output */
349 node->next = filter_root; 376 node->next = filter_root;
350 filter_root = node; 377 filter_root = node;
351 break;
352 } 378 }
353 node = next; 379 node = next;
354 } 380 }
355 /* end of input - push opstack to output */ 381 /* end of input - push opstack to output */
356 /* pop opstack to output till empty */ 382 /* pop opstack to output till empty */
357 op_node = op_stack; 383 op_node = op_stack;
358 while (op_node) { 384 while (op_node) {
359 /*if (op_node->op == RPAREN || op_node->op == LPAREN) {
360 error_exit("Error: extra paren found\n");
361 }
362 */
363 op_stack = op_node->next; 385 op_stack = op_node->next;
364 op_node->next = filter_root; 386 op_node->next = filter_root;
365 filter_root = op_node; 387 filter_root = op_node;
366 op_node = op_stack; 388 op_node = op_stack;
367 } 389 }