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