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