xref: /original-bsd/usr.bin/find/find.c (revision 8c7fbc72)
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.7 (Berkeley) 05/01/93";
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 void
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 
125 	if (!(tree = fts_open(paths, ftsoptions, (int (*)())NULL)))
126 		err(1, "ftsopen");
127 
128 	while (entry = fts_read(tree)) {
129 		switch(entry->fts_info) {
130 		case FTS_D:
131 			if (isdepth)
132 				continue;
133 			break;
134 		case FTS_DP:
135 			if (!isdepth)
136 				continue;
137 			break;
138 		case FTS_DNR:
139 		case FTS_ERR:
140 		case FTS_NS:
141 			(void)fflush(stdout);
142 			warn("%s", entry->fts_path);
143 			continue;
144 		}
145 #define	BADCH	" \t\n\\'\""
146 		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
147 			(void)fflush(stdout);
148 			warnx("%s: illegal path", entry->fts_path);
149 			continue;
150 		}
151 
152 		/*
153 		 * call all the functions in the execution plan until one is
154 		 * false or all have been executed.  This is where we do all
155 		 * the work specified by the user on the command line.
156 		 */
157 		for (p = plan; p && (p->eval)(p, entry); p = p->next);
158 	}
159 	(void)fts_close(tree);
160 }
161