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