1*043fbe51Sderaadt /* $OpenBSD: operator.c,v 1.10 2009/10/27 23:59:38 deraadt Exp $ */
21258a77dSderaadt
3df930be7Sderaadt /*-
4df930be7Sderaadt * Copyright (c) 1990, 1993
5df930be7Sderaadt * The Regents of the University of California. All rights reserved.
6df930be7Sderaadt *
7df930be7Sderaadt * This code is derived from software contributed to Berkeley by
8df930be7Sderaadt * Cimarron D. Taylor of the University of California, Berkeley.
9df930be7Sderaadt *
10df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
11df930be7Sderaadt * modification, are permitted provided that the following conditions
12df930be7Sderaadt * are met:
13df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
15df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
16df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
17df930be7Sderaadt * documentation and/or other materials provided with the distribution.
18f75387cbSmillert * 3. Neither the name of the University nor the names of its contributors
19df930be7Sderaadt * may be used to endorse or promote products derived from this software
20df930be7Sderaadt * without specific prior written permission.
21df930be7Sderaadt *
22df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32df930be7Sderaadt * SUCH DAMAGE.
33df930be7Sderaadt */
34df930be7Sderaadt
35df930be7Sderaadt #include <sys/types.h>
36efc2f9d4Smillert #include <sys/stat.h>
37df930be7Sderaadt
38df930be7Sderaadt #include <err.h>
39df930be7Sderaadt #include <fts.h>
40df930be7Sderaadt #include <stdio.h>
41df930be7Sderaadt
42df930be7Sderaadt #include "find.h"
43ac3c97abSderaadt #include "extern.h"
44df930be7Sderaadt
45df930be7Sderaadt /*
46df930be7Sderaadt * yanknode --
47df930be7Sderaadt * destructively removes the top from the plan
48df930be7Sderaadt */
49df930be7Sderaadt static PLAN *
yanknode(PLAN ** planp)50ac3c97abSderaadt yanknode(PLAN **planp) /* pointer to top of plan (modified) */
51df930be7Sderaadt {
52df930be7Sderaadt PLAN *node; /* top node removed from the plan */
53df930be7Sderaadt
54df930be7Sderaadt if ((node = (*planp)) == NULL)
55df930be7Sderaadt return (NULL);
56df930be7Sderaadt (*planp) = (*planp)->next;
57df930be7Sderaadt node->next = NULL;
58df930be7Sderaadt return (node);
59df930be7Sderaadt }
60df930be7Sderaadt
61df930be7Sderaadt /*
62df930be7Sderaadt * yankexpr --
63df930be7Sderaadt * Removes one expression from the plan. This is used mainly by
64df930be7Sderaadt * paren_squish. In comments below, an expression is either a
65df930be7Sderaadt * simple node or a N_EXPR node containing a list of simple nodes.
66df930be7Sderaadt */
67df930be7Sderaadt static PLAN *
yankexpr(PLAN ** planp)68ac3c97abSderaadt yankexpr(PLAN **planp) /* pointer to top of plan (modified) */
69df930be7Sderaadt {
70c0932ef1Smpech PLAN *next; /* temp node holding subexpression results */
71df930be7Sderaadt PLAN *node; /* pointer to returned node or expression */
72df930be7Sderaadt PLAN *tail; /* pointer to tail of subplan */
73df930be7Sderaadt PLAN *subplan; /* pointer to head of ( ) expression */
74ac3c97abSderaadt extern int f_expr(PLAN *, FTSENT *);
75df930be7Sderaadt
76df930be7Sderaadt /* first pull the top node from the plan */
77df930be7Sderaadt if ((node = yanknode(planp)) == NULL)
78df930be7Sderaadt return (NULL);
79df930be7Sderaadt
80df930be7Sderaadt /*
81df930be7Sderaadt * If the node is an '(' then we recursively slurp up expressions
82df930be7Sderaadt * until we find its associated ')'. If it's a closing paren we
83df930be7Sderaadt * just return it and unwind our recursion; all other nodes are
84df930be7Sderaadt * complete expressions, so just return them.
85df930be7Sderaadt */
86df930be7Sderaadt if (node->type == N_OPENPAREN)
87df930be7Sderaadt for (tail = subplan = NULL;;) {
88df930be7Sderaadt if ((next = yankexpr(planp)) == NULL)
898bf98a1fStom errx(1, "(: missing closing ')'");
90df930be7Sderaadt /*
91df930be7Sderaadt * If we find a closing ')' we store the collected
92df930be7Sderaadt * subplan in our '(' node and convert the node to
93df930be7Sderaadt * a N_EXPR. The ')' we found is ignored. Otherwise,
94df930be7Sderaadt * we just continue to add whatever we get to our
95df930be7Sderaadt * subplan.
96df930be7Sderaadt */
97df930be7Sderaadt if (next->type == N_CLOSEPAREN) {
98df930be7Sderaadt if (subplan == NULL)
99df930be7Sderaadt errx(1, "(): empty inner expression");
100df930be7Sderaadt node->p_data[0] = subplan;
101df930be7Sderaadt node->type = N_EXPR;
102df930be7Sderaadt node->eval = f_expr;
103df930be7Sderaadt break;
104df930be7Sderaadt } else {
105df930be7Sderaadt if (subplan == NULL)
106df930be7Sderaadt tail = subplan = next;
107df930be7Sderaadt else {
108df930be7Sderaadt tail->next = next;
109df930be7Sderaadt tail = next;
110df930be7Sderaadt }
111df930be7Sderaadt tail->next = NULL;
112df930be7Sderaadt }
113df930be7Sderaadt }
114df930be7Sderaadt return (node);
115df930be7Sderaadt }
116df930be7Sderaadt
117df930be7Sderaadt /*
118df930be7Sderaadt * paren_squish --
119df930be7Sderaadt * replaces "parentheisized" plans in our search plan with "expr" nodes.
120df930be7Sderaadt */
121df930be7Sderaadt PLAN *
paren_squish(PLAN * plan)122ac3c97abSderaadt paren_squish(PLAN *plan) /* plan with ( ) nodes */
123df930be7Sderaadt {
124c0932ef1Smpech PLAN *expr; /* pointer to next expression */
125c0932ef1Smpech PLAN *tail; /* pointer to tail of result plan */
126df930be7Sderaadt PLAN *result; /* pointer to head of result plan */
127df930be7Sderaadt
128df930be7Sderaadt result = tail = NULL;
129df930be7Sderaadt
130df930be7Sderaadt /*
131df930be7Sderaadt * the basic idea is to have yankexpr do all our work and just
132df930be7Sderaadt * collect it's results together.
133df930be7Sderaadt */
134df930be7Sderaadt while ((expr = yankexpr(&plan)) != NULL) {
135df930be7Sderaadt /*
136df930be7Sderaadt * if we find an unclaimed ')' it means there is a missing
137df930be7Sderaadt * '(' someplace.
138df930be7Sderaadt */
139df930be7Sderaadt if (expr->type == N_CLOSEPAREN)
140df930be7Sderaadt errx(1, "): no beginning '('");
141df930be7Sderaadt
142df930be7Sderaadt /* add the expression to our result plan */
143df930be7Sderaadt if (result == NULL)
144df930be7Sderaadt tail = result = expr;
145df930be7Sderaadt else {
146df930be7Sderaadt tail->next = expr;
147df930be7Sderaadt tail = expr;
148df930be7Sderaadt }
149df930be7Sderaadt tail->next = NULL;
150df930be7Sderaadt }
151df930be7Sderaadt return (result);
152df930be7Sderaadt }
153df930be7Sderaadt
154df930be7Sderaadt /*
155df930be7Sderaadt * not_squish --
156df930be7Sderaadt * compresses "!" expressions in our search plan.
157df930be7Sderaadt */
158df930be7Sderaadt PLAN *
not_squish(PLAN * plan)159ac3c97abSderaadt not_squish(PLAN *plan) /* plan to process */
160df930be7Sderaadt {
161c0932ef1Smpech PLAN *next; /* next node being processed */
162c0932ef1Smpech PLAN *node; /* temporary node used in N_NOT processing */
163c0932ef1Smpech PLAN *tail; /* pointer to tail of result plan */
164df930be7Sderaadt PLAN *result; /* pointer to head of result plan */
165df930be7Sderaadt
166df930be7Sderaadt tail = result = next = NULL;
167df930be7Sderaadt
168df930be7Sderaadt while ((next = yanknode(&plan)) != NULL) {
169df930be7Sderaadt /*
170df930be7Sderaadt * if we encounter a ( expression ) then look for nots in
171df930be7Sderaadt * the expr subplan.
172df930be7Sderaadt */
173df930be7Sderaadt if (next->type == N_EXPR)
174df930be7Sderaadt next->p_data[0] = not_squish(next->p_data[0]);
175df930be7Sderaadt
176df930be7Sderaadt /*
177df930be7Sderaadt * if we encounter a not, then snag the next node and place
178df930be7Sderaadt * it in the not's subplan. As an optimization we compress
179df930be7Sderaadt * several not's to zero or one not.
180df930be7Sderaadt */
181df930be7Sderaadt if (next->type == N_NOT) {
182df930be7Sderaadt int notlevel = 1;
183df930be7Sderaadt
184df930be7Sderaadt node = yanknode(&plan);
1854eb1a0d5Sderaadt while (node != NULL && node->type == N_NOT) {
186df930be7Sderaadt ++notlevel;
187df930be7Sderaadt node = yanknode(&plan);
188df930be7Sderaadt }
189df930be7Sderaadt if (node == NULL)
190df930be7Sderaadt errx(1, "!: no following expression");
191df930be7Sderaadt if (node->type == N_OR)
192df930be7Sderaadt errx(1, "!: nothing between ! and -o");
193435af6efSmillert if (node->type == N_EXPR)
194435af6efSmillert node = not_squish(node);
195df930be7Sderaadt if (notlevel % 2 != 1)
196df930be7Sderaadt next = node;
197df930be7Sderaadt else
198df930be7Sderaadt next->p_data[0] = node;
199df930be7Sderaadt }
200df930be7Sderaadt
201df930be7Sderaadt /* add the node to our result plan */
202df930be7Sderaadt if (result == NULL)
203df930be7Sderaadt tail = result = next;
204df930be7Sderaadt else {
205df930be7Sderaadt tail->next = next;
206df930be7Sderaadt tail = next;
207df930be7Sderaadt }
208df930be7Sderaadt tail->next = NULL;
209df930be7Sderaadt }
210df930be7Sderaadt return (result);
211df930be7Sderaadt }
212df930be7Sderaadt
213df930be7Sderaadt /*
214df930be7Sderaadt * or_squish --
215df930be7Sderaadt * compresses -o expressions in our search plan.
216df930be7Sderaadt */
217df930be7Sderaadt PLAN *
or_squish(PLAN * plan)218ac3c97abSderaadt or_squish(PLAN *plan) /* plan with ors to be squished */
219df930be7Sderaadt {
220c0932ef1Smpech PLAN *next; /* next node being processed */
221c0932ef1Smpech PLAN *tail; /* pointer to tail of result plan */
222df930be7Sderaadt PLAN *result; /* pointer to head of result plan */
223df930be7Sderaadt
224df930be7Sderaadt tail = result = next = NULL;
225df930be7Sderaadt
226df930be7Sderaadt while ((next = yanknode(&plan)) != NULL) {
227df930be7Sderaadt /*
228df930be7Sderaadt * if we encounter a ( expression ) then look for or's in
229df930be7Sderaadt * the expr subplan.
230df930be7Sderaadt */
231df930be7Sderaadt if (next->type == N_EXPR)
232df930be7Sderaadt next->p_data[0] = or_squish(next->p_data[0]);
233df930be7Sderaadt
234df930be7Sderaadt /* if we encounter a not then look for not's in the subplan */
235df930be7Sderaadt if (next->type == N_NOT)
236df930be7Sderaadt next->p_data[0] = or_squish(next->p_data[0]);
237df930be7Sderaadt
238df930be7Sderaadt /*
239df930be7Sderaadt * if we encounter an or, then place our collected plan in the
240df930be7Sderaadt * or's first subplan and then recursively collect the
241df930be7Sderaadt * remaining stuff into the second subplan and return the or.
242df930be7Sderaadt */
243df930be7Sderaadt if (next->type == N_OR) {
244df930be7Sderaadt if (result == NULL)
245df930be7Sderaadt errx(1, "-o: no expression before -o");
246df930be7Sderaadt next->p_data[0] = result;
247df930be7Sderaadt next->p_data[1] = or_squish(plan);
248df930be7Sderaadt if (next->p_data[1] == NULL)
249df930be7Sderaadt errx(1, "-o: no expression after -o");
250df930be7Sderaadt return (next);
251df930be7Sderaadt }
252df930be7Sderaadt
253df930be7Sderaadt /* add the node to our result plan */
254df930be7Sderaadt if (result == NULL)
255df930be7Sderaadt tail = result = next;
256df930be7Sderaadt else {
257df930be7Sderaadt tail->next = next;
258df930be7Sderaadt tail = next;
259df930be7Sderaadt }
260df930be7Sderaadt tail->next = NULL;
261df930be7Sderaadt }
262df930be7Sderaadt return (result);
263df930be7Sderaadt }
264