xref: /original-bsd/usr.bin/find/find.c (revision c41723e9)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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	5.4 (Berkeley) 12/27/91";
13 #endif /* not lint */
14 
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/errno.h>
18 #include <fts.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "find.h"
23 
24 /*
25  * find_formplan --
26  *	process the command line and create a "plan" corresponding to the
27  *	command arguments.
28  */
29 PLAN *
30 find_formplan(argv)
31 	char **argv;
32 {
33 	PLAN *plan, *tail, *new;
34 
35 	/*
36 	 * for each argument in the command line, determine what kind of node
37 	 * it is, create the appropriate node type and add the new plan node
38 	 * to the end of the existing plan.  The resulting plan is a linked
39 	 * list of plan nodes.  For example, the string:
40 	 *
41 	 *	% find . -name foo -newer bar -print
42 	 *
43 	 * results in the plan:
44 	 *
45 	 *	[-name foo]--> [-newer bar]--> [-print]
46 	 *
47 	 * in this diagram, `[-name foo]' represents the plan node generated
48 	 * by c_name() with an argument of foo and `-->' represents the
49 	 * plan->next pointer.
50 	 */
51 	for (plan = NULL; *argv;) {
52 		if (!(new = find_create(&argv)))
53 			continue;
54 		if (plan == NULL)
55 			tail = plan = new;
56 		else {
57 			tail->next = new;
58 			tail = new;
59 		}
60 	}
61 
62 	/*
63 	 * if the user didn't specify one of -print, -ok or -exec, then -print
64 	 * is assumed so we add a -print node on the end.  It is possible that
65 	 * the user might want the -print someplace else on the command line,
66 	 * but there's no way to know that.
67 	 */
68 	if (!isoutput) {
69 		new = c_print();
70 		if (plan == NULL)
71 			tail = plan = new;
72 		else {
73 			tail->next = new;
74 			tail = new;
75 		}
76 	}
77 
78 	/*
79 	 * the command line has been completely processed into a search plan
80 	 * except for the (, ), !, and -o operators.  Rearrange the plan so
81 	 * that the portions of the plan which are affected by the operators
82 	 * are moved into operator nodes themselves.  For example:
83 	 *
84 	 *	[!]--> [-name foo]--> [-print]
85 	 *
86 	 * becomes
87 	 *
88 	 *	[! [-name foo] ]--> [-print]
89 	 *
90 	 * and
91 	 *
92 	 *	[(]--> [-depth]--> [-name foo]--> [)]--> [-print]
93 	 *
94 	 * becomes
95 	 *
96 	 *	[expr [-depth]-->[-name foo] ]--> [-print]
97 	 *
98 	 * operators are handled in order of precedence.
99 	 */
100 
101 	plan = paren_squish(plan);		/* ()'s */
102 	plan = not_squish(plan);		/* !'s */
103 	plan = or_squish(plan);			/* -o's */
104 	return(plan);
105 }
106 
107 FTS *tree;			/* pointer to top of FTS hierarchy */
108 
109 /*
110  * find_execute --
111  *	take a search plan and an array of search paths and executes the plan
112  *	over all FTSENT's returned for the given search paths.
113  */
114 void
115 find_execute(plan, paths)
116 	PLAN *plan;		/* search plan */
117 	char **paths;		/* array of pathnames to traverse */
118 {
119 	register FTSENT *entry;
120 	PLAN *p;
121 
122 	if (!(tree = fts_open(paths, ftsoptions, (int (*)())NULL)))
123 		err("ftsopen: %s", strerror(errno));
124 
125 	while (entry = fts_read(tree)) {
126 		switch(entry->fts_info) {
127 		case FTS_D:
128 			if (isdepth)
129 				continue;
130 			break;
131 		case FTS_DP:
132 			if (!isdepth)
133 				continue;
134 			break;
135 		case FTS_DNR:
136 		case FTS_ERR:
137 		case FTS_NS:
138 			(void)fprintf(stderr, "find: %s: %s\n",
139 			    entry->fts_path, strerror(errno));
140 			continue;
141 		case FTS_SL:
142 			if (entry->fts_level == FTS_ROOTLEVEL) {
143 				(void)fts_set(tree, entry, FTS_FOLLOW);
144 				continue;
145 			}
146 			break;
147 		}
148 
149 #define	BADCH	" \t\n\\'\""
150 		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
151 			(void)fprintf(stderr,
152 			    "find: illegal path: %s\n", entry->fts_path);
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 	(void)fts_close(tree);
164 }
165