xref: /minix3/usr.bin/find/operator.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: operator.c,v 1.10 2014/10/18 08:33:30 snj Exp $	*/
2319e7a6dSDavid van Moolenbroek 
3319e7a6dSDavid van Moolenbroek /*-
4319e7a6dSDavid van Moolenbroek  * Copyright (c) 1990, 1993
5319e7a6dSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
6319e7a6dSDavid van Moolenbroek  *
7319e7a6dSDavid van Moolenbroek  * This code is derived from software contributed to Berkeley by
8319e7a6dSDavid van Moolenbroek  * Cimarron D. Taylor of the University of California, Berkeley.
9319e7a6dSDavid van Moolenbroek  *
10319e7a6dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
11319e7a6dSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
12319e7a6dSDavid van Moolenbroek  * are met:
13319e7a6dSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
14319e7a6dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
15319e7a6dSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
16319e7a6dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
17319e7a6dSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
18319e7a6dSDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
19319e7a6dSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
20319e7a6dSDavid van Moolenbroek  *    without specific prior written permission.
21319e7a6dSDavid van Moolenbroek  *
22319e7a6dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23319e7a6dSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24319e7a6dSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25319e7a6dSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26319e7a6dSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27319e7a6dSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28319e7a6dSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29319e7a6dSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30319e7a6dSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31319e7a6dSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32319e7a6dSDavid van Moolenbroek  * SUCH DAMAGE.
33319e7a6dSDavid van Moolenbroek  */
34319e7a6dSDavid van Moolenbroek 
35319e7a6dSDavid van Moolenbroek #include <sys/cdefs.h>
36319e7a6dSDavid van Moolenbroek #ifndef lint
37319e7a6dSDavid van Moolenbroek #if 0
38319e7a6dSDavid van Moolenbroek static char sccsid[] = "from: @(#)operator.c	8.1 (Berkeley) 6/6/93";
39319e7a6dSDavid van Moolenbroek #else
40*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: operator.c,v 1.10 2014/10/18 08:33:30 snj Exp $");
41319e7a6dSDavid van Moolenbroek #endif
42319e7a6dSDavid van Moolenbroek #endif /* not lint */
43319e7a6dSDavid van Moolenbroek 
44319e7a6dSDavid van Moolenbroek #include <sys/types.h>
45319e7a6dSDavid van Moolenbroek 
46319e7a6dSDavid van Moolenbroek #include <err.h>
47319e7a6dSDavid van Moolenbroek #include <fts.h>
48319e7a6dSDavid van Moolenbroek #include <stdio.h>
49319e7a6dSDavid van Moolenbroek 
50319e7a6dSDavid van Moolenbroek #include "find.h"
51319e7a6dSDavid van Moolenbroek 
52319e7a6dSDavid van Moolenbroek static PLAN *yanknode(PLAN **);
53319e7a6dSDavid van Moolenbroek static PLAN *yankexpr(PLAN **);
54319e7a6dSDavid van Moolenbroek 
55319e7a6dSDavid van Moolenbroek /*
56319e7a6dSDavid van Moolenbroek  * yanknode --
57319e7a6dSDavid van Moolenbroek  *	destructively removes the top from the plan
58319e7a6dSDavid van Moolenbroek  */
59319e7a6dSDavid van Moolenbroek static PLAN *
yanknode(PLAN ** planp)60319e7a6dSDavid van Moolenbroek yanknode(PLAN **planp)		/* pointer to top of plan (modified) */
61319e7a6dSDavid van Moolenbroek {
62319e7a6dSDavid van Moolenbroek 	PLAN *node;		/* top node removed from the plan */
63319e7a6dSDavid van Moolenbroek 
64319e7a6dSDavid van Moolenbroek 	if ((node = (*planp)) == NULL)
65319e7a6dSDavid van Moolenbroek 		return (NULL);
66319e7a6dSDavid van Moolenbroek 	(*planp) = (*planp)->next;
67319e7a6dSDavid van Moolenbroek 	node->next = NULL;
68319e7a6dSDavid van Moolenbroek 	return (node);
69319e7a6dSDavid van Moolenbroek }
70319e7a6dSDavid van Moolenbroek 
71319e7a6dSDavid van Moolenbroek /*
72319e7a6dSDavid van Moolenbroek  * yankexpr --
73319e7a6dSDavid van Moolenbroek  *	Removes one expression from the plan.  This is used mainly by
74319e7a6dSDavid van Moolenbroek  *	paren_squish.  In comments below, an expression is either a
75319e7a6dSDavid van Moolenbroek  *	simple node or a N_EXPR node containing a list of simple nodes.
76319e7a6dSDavid van Moolenbroek  */
77319e7a6dSDavid van Moolenbroek static PLAN *
yankexpr(PLAN ** planp)78319e7a6dSDavid van Moolenbroek yankexpr(PLAN **planp)		/* pointer to top of plan (modified) */
79319e7a6dSDavid van Moolenbroek {
80319e7a6dSDavid van Moolenbroek 	PLAN *next;		/* temp node holding subexpression results */
81319e7a6dSDavid van Moolenbroek 	PLAN *node;		/* pointer to returned node or expression */
82319e7a6dSDavid van Moolenbroek 	PLAN *tail;		/* pointer to tail of subplan */
83319e7a6dSDavid van Moolenbroek 	PLAN *subplan;		/* pointer to head of ( ) expression */
84319e7a6dSDavid van Moolenbroek 
85319e7a6dSDavid van Moolenbroek 	/* first pull the top node from the plan */
86319e7a6dSDavid van Moolenbroek 	if ((node = yanknode(planp)) == NULL)
87319e7a6dSDavid van Moolenbroek 		return (NULL);
88319e7a6dSDavid van Moolenbroek 
89319e7a6dSDavid van Moolenbroek 	/*
90319e7a6dSDavid van Moolenbroek 	 * If the node is an '(' then we recursively slurp up expressions
91319e7a6dSDavid van Moolenbroek 	 * until we find its associated ')'.  If it's a closing paren we
92319e7a6dSDavid van Moolenbroek 	 * just return it and unwind our recursion; all other nodes are
93319e7a6dSDavid van Moolenbroek 	 * complete expressions, so just return them.
94319e7a6dSDavid van Moolenbroek 	 */
95319e7a6dSDavid van Moolenbroek 	if (node->type == N_OPENPAREN)
96319e7a6dSDavid van Moolenbroek 		for (tail = subplan = NULL;;) {
97319e7a6dSDavid van Moolenbroek 			if ((next = yankexpr(planp)) == NULL)
98319e7a6dSDavid van Moolenbroek 				err(1, "(: missing closing ')'");
99319e7a6dSDavid van Moolenbroek 			/*
100319e7a6dSDavid van Moolenbroek 			 * If we find a closing ')' we store the collected
101319e7a6dSDavid van Moolenbroek 			 * subplan in our '(' node and convert the node to
102319e7a6dSDavid van Moolenbroek 			 * a N_EXPR.  The ')' we found is ignored.  Otherwise,
103319e7a6dSDavid van Moolenbroek 			 * we just continue to add whatever we get to our
104319e7a6dSDavid van Moolenbroek 			 * subplan.
105319e7a6dSDavid van Moolenbroek 			 */
106319e7a6dSDavid van Moolenbroek 			if (next->type == N_CLOSEPAREN) {
107319e7a6dSDavid van Moolenbroek 				if (subplan == NULL)
108319e7a6dSDavid van Moolenbroek 					errx(1, "(): empty inner expression");
109319e7a6dSDavid van Moolenbroek 				node->p_data[0] = subplan;
110319e7a6dSDavid van Moolenbroek 				node->type = N_EXPR;
111319e7a6dSDavid van Moolenbroek 				node->eval = f_expr;
112319e7a6dSDavid van Moolenbroek 				break;
113319e7a6dSDavid van Moolenbroek 			} else {
114319e7a6dSDavid van Moolenbroek 				if (subplan == NULL)
115319e7a6dSDavid van Moolenbroek 					tail = subplan = next;
116319e7a6dSDavid van Moolenbroek 				else {
117319e7a6dSDavid van Moolenbroek 					tail->next = next;
118319e7a6dSDavid van Moolenbroek 					tail = next;
119319e7a6dSDavid van Moolenbroek 				}
120319e7a6dSDavid van Moolenbroek 				tail->next = NULL;
121319e7a6dSDavid van Moolenbroek 			}
122319e7a6dSDavid van Moolenbroek 		}
123319e7a6dSDavid van Moolenbroek 	return (node);
124319e7a6dSDavid van Moolenbroek }
125319e7a6dSDavid van Moolenbroek 
126319e7a6dSDavid van Moolenbroek /*
127319e7a6dSDavid van Moolenbroek  * paren_squish --
128319e7a6dSDavid van Moolenbroek  *	replaces "parentheisized" plans in our search plan with "expr" nodes.
129319e7a6dSDavid van Moolenbroek  */
130319e7a6dSDavid van Moolenbroek PLAN *
paren_squish(PLAN * plan)131319e7a6dSDavid van Moolenbroek paren_squish(PLAN *plan)	/* plan with ( ) nodes */
132319e7a6dSDavid van Moolenbroek {
133319e7a6dSDavid van Moolenbroek 	PLAN *expr;		/* pointer to next expression */
134319e7a6dSDavid van Moolenbroek 	PLAN *tail;		/* pointer to tail of result plan */
135319e7a6dSDavid van Moolenbroek 	PLAN *result;		/* pointer to head of result plan */
136319e7a6dSDavid van Moolenbroek 
137319e7a6dSDavid van Moolenbroek 	result = tail = NULL;
138319e7a6dSDavid van Moolenbroek 
139319e7a6dSDavid van Moolenbroek 	/*
140319e7a6dSDavid van Moolenbroek 	 * the basic idea is to have yankexpr do all our work and just
141*0a6a1f1dSLionel Sambuc 	 * collect its results together.
142319e7a6dSDavid van Moolenbroek 	 */
143319e7a6dSDavid van Moolenbroek 	while ((expr = yankexpr(&plan)) != NULL) {
144319e7a6dSDavid van Moolenbroek 		/*
145319e7a6dSDavid van Moolenbroek 		 * if we find an unclaimed ')' it means there is a missing
146319e7a6dSDavid van Moolenbroek 		 * '(' someplace.
147319e7a6dSDavid van Moolenbroek 		 */
148319e7a6dSDavid van Moolenbroek 		if (expr->type == N_CLOSEPAREN)
149319e7a6dSDavid van Moolenbroek 			errx(1, "): no beginning '('");
150319e7a6dSDavid van Moolenbroek 
151319e7a6dSDavid van Moolenbroek 		/* add the expression to our result plan */
152319e7a6dSDavid van Moolenbroek 		if (result == NULL)
153319e7a6dSDavid van Moolenbroek 			tail = result = expr;
154319e7a6dSDavid van Moolenbroek 		else {
155319e7a6dSDavid van Moolenbroek 			tail->next = expr;
156319e7a6dSDavid van Moolenbroek 			tail = expr;
157319e7a6dSDavid van Moolenbroek 		}
158319e7a6dSDavid van Moolenbroek 		tail->next = NULL;
159319e7a6dSDavid van Moolenbroek 	}
160319e7a6dSDavid van Moolenbroek 	return (result);
161319e7a6dSDavid van Moolenbroek }
162319e7a6dSDavid van Moolenbroek 
163319e7a6dSDavid van Moolenbroek /*
164319e7a6dSDavid van Moolenbroek  * not_squish --
165319e7a6dSDavid van Moolenbroek  *	compresses "!" expressions in our search plan.
166319e7a6dSDavid van Moolenbroek  */
167319e7a6dSDavid van Moolenbroek PLAN *
not_squish(PLAN * plan)168319e7a6dSDavid van Moolenbroek not_squish(PLAN *plan)		/* plan to process */
169319e7a6dSDavid van Moolenbroek {
170319e7a6dSDavid van Moolenbroek 	PLAN *next;		/* next node being processed */
171319e7a6dSDavid van Moolenbroek 	PLAN *node;		/* temporary node used in N_NOT processing */
172319e7a6dSDavid van Moolenbroek 	PLAN *tail;		/* pointer to tail of result plan */
173319e7a6dSDavid van Moolenbroek 	PLAN *result;		/* pointer to head of result plan */
174319e7a6dSDavid van Moolenbroek 
175319e7a6dSDavid van Moolenbroek 	tail = result = next = NULL;
176319e7a6dSDavid van Moolenbroek 
177319e7a6dSDavid van Moolenbroek 	while ((next = yanknode(&plan)) != NULL) {
178319e7a6dSDavid van Moolenbroek 		/*
179319e7a6dSDavid van Moolenbroek 		 * if we encounter a ( expression ) then look for nots in
180319e7a6dSDavid van Moolenbroek 		 * the expr subplan.
181319e7a6dSDavid van Moolenbroek 		 */
182319e7a6dSDavid van Moolenbroek 		if (next->type == N_EXPR)
183319e7a6dSDavid van Moolenbroek 			next->p_data[0] = not_squish(next->p_data[0]);
184319e7a6dSDavid van Moolenbroek 
185319e7a6dSDavid van Moolenbroek 		/*
186319e7a6dSDavid van Moolenbroek 		 * if we encounter a not, then snag the next node and place
187319e7a6dSDavid van Moolenbroek 		 * it in the not's subplan.  As an optimization we compress
188319e7a6dSDavid van Moolenbroek 		 * several not's to zero or one not.
189319e7a6dSDavid van Moolenbroek 		 */
190319e7a6dSDavid van Moolenbroek 		if (next->type == N_NOT) {
191319e7a6dSDavid van Moolenbroek 			int notlevel = 1;
192319e7a6dSDavid van Moolenbroek 
193319e7a6dSDavid van Moolenbroek 			node = yanknode(&plan);
194319e7a6dSDavid van Moolenbroek 			while (node != NULL && node->type == N_NOT) {
195319e7a6dSDavid van Moolenbroek 				++notlevel;
196319e7a6dSDavid van Moolenbroek 				node = yanknode(&plan);
197319e7a6dSDavid van Moolenbroek 			}
198319e7a6dSDavid van Moolenbroek 			if (node == NULL)
199319e7a6dSDavid van Moolenbroek 				errx(1, "!: no following expression");
200319e7a6dSDavid van Moolenbroek 			if (node->type == N_OR)
201319e7a6dSDavid van Moolenbroek 				errx(1, "!: nothing between ! and -o");
202319e7a6dSDavid van Moolenbroek 			if (node->type == N_EXPR)
203319e7a6dSDavid van Moolenbroek 				node = not_squish(node);
204319e7a6dSDavid van Moolenbroek 			if (notlevel % 2 != 1)
205319e7a6dSDavid van Moolenbroek 				next = node;
206319e7a6dSDavid van Moolenbroek 			else
207319e7a6dSDavid van Moolenbroek 				next->p_data[0] = node;
208319e7a6dSDavid van Moolenbroek 		}
209319e7a6dSDavid van Moolenbroek 
210319e7a6dSDavid van Moolenbroek 		/* add the node to our result plan */
211319e7a6dSDavid van Moolenbroek 		if (result == NULL)
212319e7a6dSDavid van Moolenbroek 			tail = result = next;
213319e7a6dSDavid van Moolenbroek 		else {
214319e7a6dSDavid van Moolenbroek 			tail->next = next;
215319e7a6dSDavid van Moolenbroek 			tail = next;
216319e7a6dSDavid van Moolenbroek 		}
217319e7a6dSDavid van Moolenbroek 		tail->next = NULL;
218319e7a6dSDavid van Moolenbroek 	}
219319e7a6dSDavid van Moolenbroek 	return (result);
220319e7a6dSDavid van Moolenbroek }
221319e7a6dSDavid van Moolenbroek 
222319e7a6dSDavid van Moolenbroek /*
223319e7a6dSDavid van Moolenbroek  * or_squish --
224319e7a6dSDavid van Moolenbroek  *	compresses -o expressions in our search plan.
225319e7a6dSDavid van Moolenbroek  */
226319e7a6dSDavid van Moolenbroek PLAN *
or_squish(PLAN * plan)227319e7a6dSDavid van Moolenbroek or_squish(PLAN *plan)		/* plan with ors to be squished */
228319e7a6dSDavid van Moolenbroek {
229319e7a6dSDavid van Moolenbroek 	PLAN *next;		/* next node being processed */
230319e7a6dSDavid van Moolenbroek 	PLAN *tail;		/* pointer to tail of result plan */
231319e7a6dSDavid van Moolenbroek 	PLAN *result;		/* pointer to head of result plan */
232319e7a6dSDavid van Moolenbroek 
233319e7a6dSDavid van Moolenbroek 	tail = result = next = NULL;
234319e7a6dSDavid van Moolenbroek 
235319e7a6dSDavid van Moolenbroek 	while ((next = yanknode(&plan)) != NULL) {
236319e7a6dSDavid van Moolenbroek 		/*
237319e7a6dSDavid van Moolenbroek 		 * if we encounter a ( expression ) then look for or's in
238319e7a6dSDavid van Moolenbroek 		 * the expr subplan.
239319e7a6dSDavid van Moolenbroek 		 */
240319e7a6dSDavid van Moolenbroek 		if (next->type == N_EXPR)
241319e7a6dSDavid van Moolenbroek 			next->p_data[0] = or_squish(next->p_data[0]);
242319e7a6dSDavid van Moolenbroek 
243319e7a6dSDavid van Moolenbroek 		/* if we encounter a not then look for not's in the subplan */
244319e7a6dSDavid van Moolenbroek 		if (next->type == N_NOT)
245319e7a6dSDavid van Moolenbroek 			next->p_data[0] = or_squish(next->p_data[0]);
246319e7a6dSDavid van Moolenbroek 
247319e7a6dSDavid van Moolenbroek 		/*
248319e7a6dSDavid van Moolenbroek 		 * if we encounter an or, then place our collected plan in the
249319e7a6dSDavid van Moolenbroek 		 * or's first subplan and then recursively collect the
250319e7a6dSDavid van Moolenbroek 		 * remaining stuff into the second subplan and return the or.
251319e7a6dSDavid van Moolenbroek 		 */
252319e7a6dSDavid van Moolenbroek 		if (next->type == N_OR) {
253319e7a6dSDavid van Moolenbroek 			if (result == NULL)
254319e7a6dSDavid van Moolenbroek 				errx(1, "-o: no expression before -o");
255319e7a6dSDavid van Moolenbroek 			next->p_data[0] = result;
256319e7a6dSDavid van Moolenbroek 			next->p_data[1] = or_squish(plan);
257319e7a6dSDavid van Moolenbroek 			if (next->p_data[1] == NULL)
258319e7a6dSDavid van Moolenbroek 				errx(1, "-o: no expression after -o");
259319e7a6dSDavid van Moolenbroek 			return (next);
260319e7a6dSDavid van Moolenbroek 		}
261319e7a6dSDavid van Moolenbroek 
262319e7a6dSDavid van Moolenbroek 		/* add the node to our result plan */
263319e7a6dSDavid van Moolenbroek 		if (result == NULL)
264319e7a6dSDavid van Moolenbroek 			tail = result = next;
265319e7a6dSDavid van Moolenbroek 		else {
266319e7a6dSDavid van Moolenbroek 			tail->next = next;
267319e7a6dSDavid van Moolenbroek 			tail = next;
268319e7a6dSDavid van Moolenbroek 		}
269319e7a6dSDavid van Moolenbroek 		tail->next = NULL;
270319e7a6dSDavid van Moolenbroek 	}
271319e7a6dSDavid van Moolenbroek 	return (result);
272319e7a6dSDavid van Moolenbroek }
273