xref: /original-bsd/usr.bin/find/find.c (revision deff14a8)
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 *
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
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