operator.c revision 1591
117658Sjulian/*-
217658Sjulian * Copyright (c) 1990, 1993
317658Sjulian *	The Regents of the University of California.  All rights reserved.
417658Sjulian *
517658Sjulian * This code is derived from software contributed to Berkeley by
617658Sjulian * Cimarron D. Taylor of the University of California, Berkeley.
717658Sjulian *
817658Sjulian * Redistribution and use in source and binary forms, with or without
917658Sjulian * modification, are permitted provided that the following conditions
1017658Sjulian * are met:
1117658Sjulian * 1. Redistributions of source code must retain the above copyright
1217658Sjulian *    notice, this list of conditions and the following disclaimer.
1317658Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1417658Sjulian *    notice, this list of conditions and the following disclaimer in the
1517658Sjulian *    documentation and/or other materials provided with the distribution.
1617658Sjulian * 3. All advertising materials mentioning features or use of this software
1717658Sjulian *    must display the following acknowledgement:
1817658Sjulian *	This product includes software developed by the University of
1917658Sjulian *	California, Berkeley and its contributors.
2017658Sjulian * 4. Neither the name of the University nor the names of its contributors
2117658Sjulian *    may be used to endorse or promote products derived from this software
2217658Sjulian *    without specific prior written permission.
2317658Sjulian *
2417658Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2517658Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2617658Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2717658Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2817658Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2917658Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3017658Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3117658Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3217658Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3317658Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3417658Sjulian * SUCH DAMAGE.
3517658Sjulian */
3617658Sjulian
3717658Sjulian#ifndef lint
3817658Sjulianstatic char sccsid[] = "@(#)operator.c	8.1 (Berkeley) 6/6/93";
3926100Sfsmp#endif /* not lint */
4017658Sjulian
4117658Sjulian#include <sys/types.h>
4217658Sjulian
4317658Sjulian#include <err.h>
4417658Sjulian#include <fts.h>
4517658Sjulian#include <stdio.h>
4617658Sjulian
4717658Sjulian#include "find.h"
4817658Sjulian
4917658Sjulian/*
5017658Sjulian * yanknode --
5117658Sjulian *	destructively removes the top from the plan
5217658Sjulian */
5317658Sjulianstatic PLAN *
5417658Sjulianyanknode(planp)
5521776Sbde	PLAN **planp;		/* pointer to top of plan (modified) */
5617658Sjulian{
5717658Sjulian	PLAN *node;		/* top node removed from the plan */
5817658Sjulian
5917658Sjulian	if ((node = (*planp)) == NULL)
6017658Sjulian		return (NULL);
6117658Sjulian	(*planp) = (*planp)->next;
6217658Sjulian	node->next = NULL;
6317658Sjulian	return (node);
6417658Sjulian}
6517658Sjulian
6617658Sjulian/*
6717658Sjulian * yankexpr --
6817658Sjulian *	Removes one expression from the plan.  This is used mainly by
6917658Sjulian *	paren_squish.  In comments below, an expression is either a
7017658Sjulian *	simple node or a N_EXPR node containing a list of simple nodes.
7117658Sjulian */
7217658Sjulianstatic PLAN *
7317658Sjulianyankexpr(planp)
7417658Sjulian	PLAN **planp;		/* pointer to top of plan (modified) */
7517658Sjulian{
7617658Sjulian	register PLAN *next;	/* temp node holding subexpression results */
7717658Sjulian	PLAN *node;		/* pointer to returned node or expression */
7817658Sjulian	PLAN *tail;		/* pointer to tail of subplan */
7917658Sjulian	PLAN *subplan;		/* pointer to head of ( ) expression */
8017658Sjulian	int f_expr();
8117658Sjulian
8217658Sjulian	/* first pull the top node from the plan */
8317658Sjulian	if ((node = yanknode(planp)) == NULL)
8417658Sjulian		return (NULL);
8517658Sjulian
8617658Sjulian	/*
8717658Sjulian	 * If the node is an '(' then we recursively slurp up expressions
8817658Sjulian	 * until we find its associated ')'.  If it's a closing paren we
8917658Sjulian	 * just return it and unwind our recursion; all other nodes are
9017658Sjulian	 * complete expressions, so just return them.
9117658Sjulian	 */
9217658Sjulian	if (node->type == N_OPENPAREN)
9317658Sjulian		for (tail = subplan = NULL;;) {
9417658Sjulian			if ((next = yankexpr(planp)) == NULL)
9517658Sjulian				err(1, "(: missing closing ')'");
9617658Sjulian			/*
9717658Sjulian			 * If we find a closing ')' we store the collected
9817658Sjulian			 * subplan in our '(' node and convert the node to
9917658Sjulian			 * a N_EXPR.  The ')' we found is ignored.  Otherwise,
10017658Sjulian			 * we just continue to add whatever we get to our
10117658Sjulian			 * subplan.
10217658Sjulian			 */
10317658Sjulian			if (next->type == N_CLOSEPAREN) {
10417658Sjulian				if (subplan == NULL)
10517768Sjulian					errx(1, "(): empty inner expression");
10617768Sjulian				node->p_data[0] = subplan;
10717768Sjulian				node->type = N_EXPR;
10817768Sjulian				node->eval = f_expr;
10917768Sjulian				break;
11017768Sjulian			} else {
11117658Sjulian				if (subplan == NULL)
11217658Sjulian					tail = subplan = next;
11317658Sjulian				else {
11417658Sjulian					tail->next = next;
11517658Sjulian					tail = next;
11617658Sjulian				}
11717658Sjulian				tail->next = NULL;
11817658Sjulian			}
11917658Sjulian		}
12017658Sjulian	return (node);
12117658Sjulian}
12217658Sjulian
12317658Sjulian/*
12417658Sjulian * paren_squish --
12517658Sjulian *	replaces "parentheisized" plans in our search plan with "expr" nodes.
12617658Sjulian */
12717658SjulianPLAN *
12817658Sjulianparen_squish(plan)
12917658Sjulian	PLAN *plan;		/* plan with ( ) nodes */
13017658Sjulian{
13117658Sjulian	register PLAN *expr;	/* pointer to next expression */
13217658Sjulian	register PLAN *tail;	/* pointer to tail of result plan */
13317658Sjulian	PLAN *result;		/* pointer to head of result plan */
13417658Sjulian
13517658Sjulian	result = tail = NULL;
13617658Sjulian
13717658Sjulian	/*
13817658Sjulian	 * the basic idea is to have yankexpr do all our work and just
13917658Sjulian	 * collect it's results together.
14017658Sjulian	 */
14117658Sjulian	while ((expr = yankexpr(&plan)) != NULL) {
14217658Sjulian		/*
14317658Sjulian		 * if we find an unclaimed ')' it means there is a missing
14417658Sjulian		 * '(' someplace.
14517658Sjulian		 */
14617658Sjulian		if (expr->type == N_CLOSEPAREN)
14717658Sjulian			errx(1, "): no beginning '('");
14817658Sjulian
14917658Sjulian		/* add the expression to our result plan */
15017658Sjulian		if (result == NULL)
15117658Sjulian			tail = result = expr;
15217658Sjulian		else {
15317658Sjulian			tail->next = expr;
15417658Sjulian			tail = expr;
15517658Sjulian		}
15617658Sjulian		tail->next = NULL;
15717658Sjulian	}
15817658Sjulian	return (result);
15917658Sjulian}
16017658Sjulian
16117658Sjulian/*
16217658Sjulian * not_squish --
16318277Sbde *	compresses "!" expressions in our search plan.
16417658Sjulian */
16517658SjulianPLAN *
16617658Sjuliannot_squish(plan)
16717768Sjulian	PLAN *plan;		/* plan to process */
16817658Sjulian{
16925164Speter	register PLAN *next;	/* next node being processed */
17025164Speter	register PLAN *node;	/* temporary node used in N_NOT processing */
17125164Speter	register PLAN *tail;	/* pointer to tail of result plan */
17225164Speter	PLAN *result;		/* pointer to head of result plan */
17325164Speter
17425164Speter	tail = result = next = NULL;
17525164Speter
17625164Speter	while ((next = yanknode(&plan)) != NULL) {
17725164Speter		/*
17825164Speter		 * if we encounter a ( expression ) then look for nots in
17925164Speter		 * the expr subplan.
18025164Speter		 */
18125164Speter		if (next->type == N_EXPR)
18225164Speter			next->p_data[0] = not_squish(next->p_data[0]);
18325164Speter
18425164Speter		/*
18525164Speter		 * if we encounter a not, then snag the next node and place
18625164Speter		 * it in the not's subplan.  As an optimization we compress
18725164Speter		 * several not's to zero or one not.
18825164Speter		 */
18925164Speter		if (next->type == N_NOT) {
19017768Sjulian			int notlevel = 1;
19117768Sjulian
19217768Sjulian			node = yanknode(&plan);
19317658Sjulian			while (node->type == N_NOT) {
19417658Sjulian				++notlevel;
19517658Sjulian				node = yanknode(&plan);
19617658Sjulian			}
19717658Sjulian			if (node == NULL)
19817658Sjulian				errx(1, "!: no following expression");
19917658Sjulian			if (node->type == N_OR)
20017658Sjulian				errx(1, "!: nothing between ! and -o");
20117658Sjulian			if (notlevel % 2 != 1)
20217658Sjulian				next = node;
20317658Sjulian			else
20417658Sjulian				next->p_data[0] = node;
20517658Sjulian		}
20617658Sjulian
20717658Sjulian		/* add the node to our result plan */
20817658Sjulian		if (result == NULL)
20917658Sjulian			tail = result = next;
21017658Sjulian		else {
21117658Sjulian			tail->next = next;
21217658Sjulian			tail = next;
21317658Sjulian		}
21417658Sjulian		tail->next = NULL;
21517658Sjulian	}
21617658Sjulian	return (result);
21717658Sjulian}
21817658Sjulian
21917658Sjulian/*
22017658Sjulian * or_squish --
22117658Sjulian *	compresses -o expressions in our search plan.
22217658Sjulian */
22317658SjulianPLAN *
22417658Sjulianor_squish(plan)
22517658Sjulian	PLAN *plan;		/* plan with ors to be squished */
22617658Sjulian{
22717658Sjulian	register PLAN *next;	/* next node being processed */
22817658Sjulian	register PLAN *tail;	/* pointer to tail of result plan */
22917658Sjulian	PLAN *result;		/* pointer to head of result plan */
23017658Sjulian
23117658Sjulian	tail = result = next = NULL;
23217658Sjulian
23317658Sjulian	while ((next = yanknode(&plan)) != NULL) {
23417658Sjulian		/*
23517658Sjulian		 * if we encounter a ( expression ) then look for or's in
23617658Sjulian		 * the expr subplan.
23717658Sjulian		 */
23817658Sjulian		if (next->type == N_EXPR)
23917658Sjulian			next->p_data[0] = or_squish(next->p_data[0]);
24017658Sjulian
24117658Sjulian		/* if we encounter a not then look for not's in the subplan */
24217658Sjulian		if (next->type == N_NOT)
24317768Sjulian			next->p_data[0] = or_squish(next->p_data[0]);
24417768Sjulian
24517768Sjulian		/*
24617768Sjulian		 * if we encounter an or, then place our collected plan in the
24717768Sjulian		 * or's first subplan and then recursively collect the
24817768Sjulian		 * remaining stuff into the second subplan and return the or.
24917658Sjulian		 */
25017658Sjulian		if (next->type == N_OR) {
25117658Sjulian			if (result == NULL)
25217658Sjulian				errx(1, "-o: no expression before -o");
25317658Sjulian			next->p_data[0] = result;
25419274Sjulian			next->p_data[1] = or_squish(plan);
25519274Sjulian			if (next->p_data[1] == NULL)
25619274Sjulian				errx(1, "-o: no expression after -o");
25719274Sjulian			return (next);
25819274Sjulian		}
25919274Sjulian
26019274Sjulian		/* add the node to our result plan */
26117658Sjulian		if (result == NULL)
26217658Sjulian			tail = result = next;
26317658Sjulian		else {
26417658Sjulian			tail->next = next;
26517658Sjulian			tail = next;
26617658Sjulian		}
26717658Sjulian		tail->next = NULL;
26817658Sjulian	}
26917658Sjulian	return (result);
27017658Sjulian}
27117658Sjulian