1 /*-
2 * Copyright (c) 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Cimarron D. Taylor of the University of California, Berkeley.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)find.c 8.5 (Berkeley) 08/05/94";
13 #endif /* not lint */
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #include <err.h>
19 #include <errno.h>
20 #include <fts.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "find.h"
26
27 /*
28 * find_formplan --
29 * process the command line and create a "plan" corresponding to the
30 * command arguments.
31 */
32 PLAN *
find_formplan(argv)33 find_formplan(argv)
34 char **argv;
35 {
36 PLAN *plan, *tail, *new;
37
38 /*
39 * for each argument in the command line, determine what kind of node
40 * it is, create the appropriate node type and add the new plan node
41 * to the end of the existing plan. The resulting plan is a linked
42 * list of plan nodes. For example, the string:
43 *
44 * % find . -name foo -newer bar -print
45 *
46 * results in the plan:
47 *
48 * [-name foo]--> [-newer bar]--> [-print]
49 *
50 * in this diagram, `[-name foo]' represents the plan node generated
51 * by c_name() with an argument of foo and `-->' represents the
52 * plan->next pointer.
53 */
54 for (plan = tail = NULL; *argv;) {
55 if (!(new = find_create(&argv)))
56 continue;
57 if (plan == NULL)
58 tail = plan = new;
59 else {
60 tail->next = new;
61 tail = new;
62 }
63 }
64
65 /*
66 * if the user didn't specify one of -print, -ok or -exec, then -print
67 * is assumed so we bracket the current expression with parens, if
68 * necessary, and add a -print node on the end.
69 */
70 if (!isoutput) {
71 if (plan == NULL) {
72 new = c_print();
73 tail = plan = new;
74 } else {
75 new = c_openparen();
76 new->next = plan;
77 plan = new;
78 new = c_closeparen();
79 tail->next = new;
80 tail = new;
81 new = c_print();
82 tail->next = new;
83 tail = new;
84 }
85 }
86
87 /*
88 * the command line has been completely processed into a search plan
89 * except for the (, ), !, and -o operators. Rearrange the plan so
90 * that the portions of the plan which are affected by the operators
91 * are moved into operator nodes themselves. For example:
92 *
93 * [!]--> [-name foo]--> [-print]
94 *
95 * becomes
96 *
97 * [! [-name foo] ]--> [-print]
98 *
99 * and
100 *
101 * [(]--> [-depth]--> [-name foo]--> [)]--> [-print]
102 *
103 * becomes
104 *
105 * [expr [-depth]-->[-name foo] ]--> [-print]
106 *
107 * operators are handled in order of precedence.
108 */
109
110 plan = paren_squish(plan); /* ()'s */
111 plan = not_squish(plan); /* !'s */
112 plan = or_squish(plan); /* -o's */
113 return (plan);
114 }
115
116 FTS *tree; /* pointer to top of FTS hierarchy */
117
118 /*
119 * find_execute --
120 * take a search plan and an array of search paths and executes the plan
121 * over all FTSENT's returned for the given search paths.
122 */
123 int
find_execute(plan,paths)124 find_execute(plan, paths)
125 PLAN *plan; /* search plan */
126 char **paths; /* array of pathnames to traverse */
127 {
128 register FTSENT *entry;
129 PLAN *p;
130 int rval;
131
132 if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL)
133 err(1, "ftsopen");
134
135 for (rval = 0; (entry = fts_read(tree)) != NULL;) {
136 switch (entry->fts_info) {
137 case FTS_D:
138 if (isdepth)
139 continue;
140 break;
141 case FTS_DP:
142 if (!isdepth)
143 continue;
144 break;
145 case FTS_DNR:
146 case FTS_ERR:
147 case FTS_NS:
148 (void)fflush(stdout);
149 warnx("%s: %s",
150 entry->fts_path, strerror(entry->fts_errno));
151 rval = 1;
152 continue;
153 #ifdef FTS_W
154 case FTS_W:
155 continue;
156 #endif /* FTS_W */
157 }
158 #define BADCH " \t\n\\'\""
159 if (isxargs && strpbrk(entry->fts_path, BADCH)) {
160 (void)fflush(stdout);
161 warnx("%s: illegal path", entry->fts_path);
162 rval = 1;
163 continue;
164 }
165
166 /*
167 * Call all the functions in the execution plan until one is
168 * false or all have been executed. This is where we do all
169 * the work specified by the user on the command line.
170 */
171 for (p = plan; p && (p->eval)(p, entry); p = p->next);
172 }
173 if (errno)
174 err(1, "fts_read");
175 return (rval);
176 }
177