xref: /original-bsd/usr.bin/find/find.c (revision e58c8952)
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.3 (Berkeley) 04/01/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 add a -print node on the end.  It is possible that
68 	 * the user might want the -print someplace else on the command line,
69 	 * but there's no way to know that.
70 	 */
71 	if (!isoutput) {
72 		new = c_print();
73 		if (plan == NULL)
74 			tail = plan = new;
75 		else {
76 			tail->next = new;
77 			tail = new;
78 		}
79 	}
80 
81 	/*
82 	 * the command line has been completely processed into a search plan
83 	 * except for the (, ), !, and -o operators.  Rearrange the plan so
84 	 * that the portions of the plan which are affected by the operators
85 	 * are moved into operator nodes themselves.  For example:
86 	 *
87 	 *	[!]--> [-name foo]--> [-print]
88 	 *
89 	 * becomes
90 	 *
91 	 *	[! [-name foo] ]--> [-print]
92 	 *
93 	 * and
94 	 *
95 	 *	[(]--> [-depth]--> [-name foo]--> [)]--> [-print]
96 	 *
97 	 * becomes
98 	 *
99 	 *	[expr [-depth]-->[-name foo] ]--> [-print]
100 	 *
101 	 * operators are handled in order of precedence.
102 	 */
103 
104 	plan = paren_squish(plan);		/* ()'s */
105 	plan = not_squish(plan);		/* !'s */
106 	plan = or_squish(plan);			/* -o's */
107 	return (plan);
108 }
109 
110 FTS *tree;			/* pointer to top of FTS hierarchy */
111 
112 /*
113  * find_execute --
114  *	take a search plan and an array of search paths and executes the plan
115  *	over all FTSENT's returned for the given search paths.
116  */
117 int
118 find_execute(plan, paths)
119 	PLAN *plan;		/* search plan */
120 	char **paths;		/* array of pathnames to traverse */
121 {
122 	register FTSENT *entry;
123 	PLAN *p;
124 	int rval;
125 
126 	if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL)
127 		err(1, "ftsopen");
128 
129 	for (rval = 0; (entry = fts_read(tree)) != NULL;) {
130 		switch (entry->fts_info) {
131 		case FTS_D:
132 			if (isdepth)
133 				continue;
134 			break;
135 		case FTS_DP:
136 			if (!isdepth)
137 				continue;
138 			break;
139 		case FTS_DNR:
140 		case FTS_ERR:
141 		case FTS_NS:
142 			(void)fflush(stdout);
143 			warnx("%s: %s",
144 			    entry->fts_path, strerror(entry->fts_errno));
145 			rval = 1;
146 			continue;
147 		}
148 #define	BADCH	" \t\n\\'\""
149 		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
150 			(void)fflush(stdout);
151 			warnx("%s: illegal path", entry->fts_path);
152 			rval = 1;
153 			continue;
154 		}
155 
156 		/*
157 		 * Call all the functions in the execution plan until one is
158 		 * false or all have been executed.  This is where we do all
159 		 * the work specified by the user on the command line.
160 		 */
161 		for (p = plan; p && (p->eval)(p, entry); p = p->next);
162 	}
163 	if (errno)
164 		err(1, "fts_read");
165 	return (rval);
166 }
167