1 /*- 2 * Copyright (c) 1990 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 char copyright[] = 13 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)find.c 4.36 (Berkeley) 03/10/91"; 19 #endif /* not lint */ 20 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <sys/errno.h> 24 #include <time.h> 25 #include <fts.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include "find.h" 30 31 FTS *tree; /* pointer to top of FTS hierarchy */ 32 time_t now; /* time find was run */ 33 /* options for the ftsopen(3) call */ 34 int ftsoptions = FTS_NOSTAT|FTS_PHYSICAL; 35 int isdeprecated; /* using deprecated syntax */ 36 int isdepth; /* do directories on post-order visit */ 37 int isoutput; /* user specified output operator */ 38 int isrelative; /* can do -exec/ok on relative path */ 39 40 main(argc, argv) 41 int argc; 42 char **argv; 43 { 44 PLAN *plan; 45 char **p, **paths; 46 PLAN *find_formplan(); 47 time_t time(); 48 void newsyntax(), oldsyntax(); 49 50 (void)time(&now); /* initialize the time-of-day */ 51 52 if (argc < 2) 53 usage(); 54 55 paths = argv; 56 57 /* 58 * if arguments start with an option, treat it like new syntax; 59 * otherwise, if has a "-option" anywhere (which isn't an argument 60 * to another command) treat it as old syntax. 61 */ 62 if (argv[1][0] != '-') 63 for (p = argv + 1; *p; ++p) { 64 if (!strcmp(*p, "exec") || !strcmp(*p, "ok")) { 65 while (p[1] && strcmp(*++p, ";")); 66 continue; 67 } 68 if (**p == '-') { 69 isdeprecated = 1; 70 oldsyntax(&argv); 71 break; 72 } 73 } 74 if (!isdeprecated) 75 newsyntax(argc, &argv); 76 77 plan = find_formplan(argv); /* execution plan */ 78 find_execute(plan, paths); 79 } 80 81 /* 82 * find_formplan -- 83 * process the command line and create a "plan" corresponding to the 84 * command arguments. 85 */ 86 PLAN * 87 find_formplan(argv) 88 char **argv; 89 { 90 PLAN *plan, *tail, *new; 91 PLAN *c_print(), *find_create(), *not_squish(), *or_squish(); 92 PLAN *paren_squish(); 93 94 /* 95 * for each argument in the command line, determine what kind of node 96 * it is, create the appropriate node type and add the new plan node 97 * to the end of the existing plan. The resulting plan is a linked 98 * list of plan nodes. For example, the string: 99 * 100 * % find . -name foo -newer bar -print 101 * 102 * results in the plan: 103 * 104 * [-name foo]--> [-newer bar]--> [-print] 105 * 106 * in this diagram, `[-name foo]' represents the plan node generated 107 * by c_name() with an argument of foo and `-->' represents the 108 * plan->next pointer. 109 */ 110 for (plan = NULL; *argv;) { 111 if (!(new = find_create(&argv))) 112 continue; 113 if (plan == NULL) 114 tail = plan = new; 115 else { 116 tail->next = new; 117 tail = new; 118 } 119 } 120 121 /* 122 * if the user didn't specify one of -print, -ok or -exec, then -print 123 * is assumed so we add a -print node on the end. It is possible that 124 * the user might want the -print someplace else on the command line, 125 * but there's no way to know that. 126 */ 127 if (!isoutput) { 128 new = c_print(); 129 if (plan == NULL) 130 tail = plan = new; 131 else { 132 tail->next = new; 133 tail = new; 134 } 135 } 136 137 /* 138 * the command line has been completely processed into a search plan 139 * except for the (, ), !, and -o operators. Rearrange the plan so 140 * that the portions of the plan which are affected by the operators 141 * are moved into operator nodes themselves. For example: 142 * 143 * [!]--> [-name foo]--> [-print] 144 * 145 * becomes 146 * 147 * [! [-name foo] ]--> [-print] 148 * 149 * and 150 * 151 * [(]--> [-depth]--> [-name foo]--> [)]--> [-print] 152 * 153 * becomes 154 * 155 * [expr [-depth]-->[-name foo] ]--> [-print] 156 * 157 * operators are handled in order of precedence. 158 */ 159 160 plan = paren_squish(plan); /* ()'s */ 161 plan = not_squish(plan); /* !'s */ 162 plan = or_squish(plan); /* -o's */ 163 return(plan); 164 } 165 166 /* 167 * find_execute -- 168 * take a search plan and an array of search paths and executes the plan 169 * over all FTSENT's returned for the given search paths. 170 */ 171 find_execute(plan, paths) 172 PLAN *plan; /* search plan */ 173 char **paths; /* array of pathnames to traverse */ 174 { 175 register FTSENT *entry; 176 PLAN *p; 177 178 if (!(tree = fts_open(paths, ftsoptions, (int (*)())NULL))) { 179 error("ftsopen", errno); 180 exit(1); 181 } 182 183 while (entry = fts_read(tree)) { 184 switch(entry->fts_info) { 185 case FTS_D: 186 if (isdepth) 187 continue; 188 break; 189 case FTS_DP: 190 if (!isdepth) 191 continue; 192 break; 193 case FTS_DNR: 194 case FTS_ERR: 195 case FTS_NS: 196 error(entry->fts_path, errno); 197 continue; 198 } 199 200 /* 201 * call all the functions in the execution plan until one is 202 * false or all have been executed. This is where we do all 203 * the work specified by the user on the command line. 204 */ 205 for (p = plan; p && (p->eval)(p, entry); p = p->next); 206 } 207 (void)fts_close(tree); 208 } 209