Moving the UnitTest directory out of the docs/ folder and into the root of the framework
[isso.git] / docs / tools / function_finder.php
1 <?php
2 /*=====================================================================*\
3 || ################################################################### ||
4 || # Function Finder [#]version[#]
5 || # --------------------------------------------------------------- # ||
6 || # Copyright ©2002-[#]year[#] by Iris Studios, Inc. All Rights Reserved. # ||
7 || # This file may not be reproduced in any way without permission. # ||
8 || ################################################################### ||
9 \*=====================================================================*/
10
11 $path = '/Server/htdocs/sportal/';
12 $filelist = fetch_flat_listing($path);
13
14 foreach ($filelist AS $filename)
15 {
16 $fpath = $path . $filename;
17 $file = file_get_contents($fpath);
18 $templist = fetch_methods($file);
19
20 $elements['methods']['classes'] = array_merge($elements['methods']['classes'], $templist['methods']['classes']);
21 $elements['methods']['functions'] = array_merge($elements['methods']['functions'], $templist['methods']['functions']);
22 $elements['limiters']["$fpath"] = $templist['limiters'];
23
24 $perfile["$fpath"] = $templist['methods'];
25 }
26
27 foreach ($elements['methods']['functions'] AS $name)
28 {
29 $count['functions']["$name"] = 0;
30 }
31
32 foreach ($elements['methods']['classes'] AS $name => $methods)
33 {
34 foreach ($methods AS $method)
35 {
36 $count['classes']["$name"]["$method"] = 0;
37 }
38 }
39
40 foreach ($filelist AS $filename)
41 {
42 $fpath = $path . $filename;
43
44 $file = file_get_contents($fpath);
45 $count = fetch_calls($file, $elements['methods'], $elements['limiters']["$fpath"], $count);
46 }
47
48 print_r($count);
49
50 // ###################################################################
51 // ###################################################################
52 // ###################################################################
53
54 function fetch_listing($path, $basepath = '', $unset = 1)
55 {
56 static $filelist;
57
58 if ($unset)
59 {
60 $filelist = array();
61 }
62
63 if (substr($path, (strlen($path) - 1), 1) != '/')
64 {
65 $path .= '/';
66 }
67
68 if ($handle = opendir($path))
69 {
70 while (($file = readdir($handle)) !== false)
71 {
72 if (substr($file, 0, 1) != '.' AND $file != 'CVS')
73 {
74 if (is_dir($path . $file))
75 {
76 $filelist["$basepath"][] = "$file/";
77 fetch_listing("$path$file", "$basepath$file/", 0);
78 }
79 else
80 {
81 $filelist["$basepath"][] = $file;
82 }
83 }
84 }
85 closedir($handle);
86 }
87 return $filelist;
88 }
89
90 // ###################################################################
91
92 function fetch_flat_listing($path)
93 {
94 $filelist = fetch_listing($path);
95
96 foreach ($filelist AS $basepath => $files)
97 {
98 foreach ($files AS $file)
99 {
100 if (substr($file, (strlen($file) - 1), 1) != '/' AND preg_match('#\.php$#', $file) AND !strpos($basepath, '3rdparty') AND !strpos($basepath, 'phpdoc') AND !strpos($basepath, 'jpgraph'))
101 {
102 $flatlist[] = "./$basepath$file";
103 }
104 }
105 }
106 return $flatlist;
107 }
108
109 // ###################################################################
110
111 function fetch_calls($file, $methodlist, $limiters, $count)
112 {
113 static $objects, $extends;
114
115 // strip comments
116 $file = preg_replace('#/\*(.*?)\*/#s', '', $file);
117
118 // tokens
119 $tokens = token_get_all($file);
120
121 // valid tokens
122 static $validtokens, $othertokens;
123 if (!is_array($validtokens))
124 {
125 $validtokens = array('T_EXTENDS', 'T_FUNCTION', 'T_VARIABLE', 'T_STRING', 'T_NEW', 'T_DOUBLE_COLON', 'T_PAAMAYIM_NEKUDOTAYIM', 'T_OBJECT_OPERATOR');
126 $othertokens = array('(', ')', ';');
127 }
128
129 // good tokens
130 $gt = array();
131
132 // actual function calls
133 $elements = array();
134
135 // remove invalid tokens
136 $i = 0;
137 foreach ($tokens AS $id => $bit)
138 {
139 unset($tokens["$id"]);
140 if (is_array($bit))
141 {
142 if (in_array($token_name = token_name($bit[0]), $validtokens))
143 {
144 $gt["$i"] = $bit;
145 $gt["$i"][2] = $token_name;
146 $gt["$i"][3] = $id;
147 $i++;
148 }
149 }
150 else
151 {
152 if (in_array($bit, $othertokens))
153 {
154 $gt["$i"][0] = '-1';
155 $gt["$i"][1] = $bit;
156 if ($bit == '(' OR $bit == ')')
157 {
158 $gt["$i"][2] = 'P_' . ($bit == '(' ? 'OPEN' : 'CLOSE');
159 }
160 else
161 {
162 $gt["$i"][2] = 'SC';
163 }
164 $gt["$i"][3] = $id;
165 $i++;
166 }
167 }
168 }
169
170 // get what we're looking for
171 $triggers = array('new' => array(), 'popen' => array());
172 foreach ($methodlist['classes'] AS $name => $methods)
173 {
174 $triggers['new'][] = $name;
175 $triggers['popen'] = array_merge($triggers['popen'], $methods);
176 }
177 $triggers['popen'] = array_merge($triggers['popen'], $methodlist['functions']);
178
179 // find a list of all the defined objects
180 foreach ($gt AS $id => $bit)
181 {
182 $prevbit = $gt[ $id - 1 ];
183 $nextbit = $gt[ $id + 1 ];
184
185 if ($bit[2] == 'T_NEW')
186 {
187 if ($prevbit[2] == 'T_VARIABLE' AND $nextbit[2] == 'T_STRING' AND in_array($nextbit[1], $triggers['new']))
188 {
189 $objects["$prevbit[1]"] = $nextbit[1];
190 }
191 }
192 if ($bit[2] == 'T_EXTENDS')
193 {
194 if ($prevbit[2] == 'T_STRING' AND $nextbit[2] == 'T_STRING' AND in_array($prevbit[1], $triggers['new']) AND in_array($prevbit[1], $triggers['new']))
195 {
196 $extends["$prevbit[1]"] = $nextbit[1];
197 }
198 }
199 }
200
201 // process tokens
202 $incall = false;
203 $root = 0;
204 $stack = array();
205 $functlist = array();
206 foreach ($gt AS $id => $bit)
207 {
208 $token = $bit[2];
209 $prevbit = $gt[ $id - 1 ];
210 $nextbit = $gt[ $id + 1 ];
211
212 // handle object calls
213 if ($token == 'T_DOUBLE_COLON' OR $token == 'T_PAAMAYIM_NEKUDOTAYIM' OR $token == 'T_OBJECT_OPERATOR')
214 {
215 $classname = null;
216
217 // find classname
218 if (isset($objects["$prevbit[1]"]))
219 {
220 $classname = $objects["$prevbit[1]"];
221 }
222 else if (in_array($prevbit[1], $triggers['new']))
223 {
224 $classname = $prevbit[1];
225 }
226 // we've got an extension!
227 else if ($prevbit[1] == 'parent')
228 {
229 // find a class that the call could be in
230 foreach ($limiters AS $class => $limits)
231 {
232 if ($bit[3] > $limits[0] AND $bit[3] < $limits[1])
233 {
234 $refclass = $class;
235 }
236 }
237
238 // get the parent of that object
239 if (isset($methodlist['classes']["$refclass"]))
240 {
241 $tempclassname = $extends["$refclass"];
242 if (isset($methodlist['classes']["$tempclassname"]))
243 {
244 $classname = $tempclassname;
245 }
246 }
247 }
248 // we've got an inner-object call
249 else if ($prevbit[1] == '$this')
250 {
251 // find a class that the call could be in
252 foreach ($limiters AS $class => $limits)
253 {
254 if ($bit[3] > $limits[0] AND $bit[3] < $limits[1])
255 {
256 $refclass = $class;
257 }
258 }
259
260 if (isset($methodlist['classes']["$refclass"]))
261 {
262 $classname = $refclass;
263 }
264 }
265
266 // object name validation
267 if ($classname)
268 {
269 // method call validation
270 if (in_array($nextbit[1], $methodlist['classes']["$classname"]))
271 {
272 $count['classes']["$classname"]["$nextbit[1]"]++;
273 }
274 }
275 }
276 // initial
277 else if ($token == 'T_STRING' AND $nextbit[2] == 'P_OPEN' AND $prevbit[2] != 'T_FUNCTION' AND $prevbit[2] != 'T_DOUBLE_COLON' AND $prevbit[2] != 'T_PAAMAYIM_NEKUDOTAYIM' AND $prevbit[2] != 'T_OBJECT_OPERATOR' AND !in_array($bit[1], $triggers['new']))
278 {
279 $incall = true;
280 $root = $id;
281 $functlist["$id"] = $bit[1];
282 }
283 // parens in call
284 else if ($token == 'P_OPEN' AND $incall)
285 {
286 array_push($stack, $id);
287 }
288 // close parens in call
289 else if ($token == 'P_CLOSE' AND $incall)
290 {
291 // find the most recent function
292 $end = array_pop($stack) - 1;
293
294 // see if we can increment a function
295 if (in_array($functlist["$end"], $methodlist['functions']))
296 {
297 $count['functions'][ $functlist["$end"] ]++;
298 }
299
300 // we're done with all functions and the semi colon is next
301 if (count($stack) == 0 AND $nextbit[2] == 'SC')
302 {
303 $incall = false;
304 }
305 }
306 }
307
308 return $count;
309 }
310
311 // ###################################################################
312
313 function fetch_methods($file)
314 {
315 // strip comments
316 $file = preg_replace('#/\*(.*?)\*/#s', '', $file);
317
318 // tokens
319 $tokens = token_get_all($file);
320
321 // valid tokens
322 static $validtokens, $othertokensopen, $othertokensclose, $othertokens;
323 if (!is_array($validtokens))
324 {
325 $validtokens = array('T_CLASS', 'T_FUNCTION', 'T_STRING');
326 $othertokensopen = array('{', '${', 'T_CURLY_OPEN', 'T_DOLLAR_OPEN_CURLY_BRACES');
327 $othertokensclose = array('}');
328 $othertokens = array_merge($othertokensopen, $othertokensclose);
329 }
330
331 // good tokens
332 $gt = array();
333
334 // actual named items
335 $elements = array();
336
337 // remove invalid tokens
338 $i = 0;
339 foreach ($tokens AS $id => $bit)
340 {
341 unset($tokens["$id"]);
342 if (is_array($bit))
343 {
344 // if we have a T_CLASS, T_FUNCTION, or T_STRING
345 if (in_array($token_name = token_name($bit[0]), $validtokens))
346 {
347 $gt["$i"] = $bit;
348 $gt["$i"][2] = $token_name;
349 $gt["$i"][3] = $id;
350 $i++;
351 }
352 // special open {
353 else if (in_array($token_name = token_name($bit[0]), $othertokens))
354 {
355 $gt["$i"][0] = '-1';
356 $gt["$i"][1] = $bit[1];
357 $gt["$i"][2] = 'B_' . (in_array($token_name, $othertokensopen) ? 'OPEN' : 'CLOSE');
358 $gt["$i"][3] = $id;
359 $i++;
360 }
361 }
362 // if we have an opening or closing brace
363 else if (in_array($bit, $othertokens))
364 {
365 // make up some token information
366 $gt["$i"][0] = '-1';
367 $gt["$i"][1] = $bit;
368 $gt["$i"][2] = 'B_' . (in_array($bit, $othertokensopen) ? 'OPEN' : 'CLOSE');
369 $gt["$i"][3] = $id;
370 $i++;
371 }
372 }
373
374 // process tokens
375 $elements = array('classes' => array(), 'functions' => array());
376
377 $inclass = false;
378 $infunction = false;
379 $class = '';
380 $stack = array();
381 foreach ($gt AS $id => $bit)
382 {
383 $token = $bit[2];
384 $nextbit = $gt[ $id + 1 ];
385
386 if ($token == 'T_CLASS')
387 {
388 $inclass = true;
389 $class = $nextbit[1];
390
391 $elements['classes']["$class"] = array();
392
393 $limiters["$class"][0] = $bit[3];
394 }
395 else if ($token == 'T_FUNCTION')
396 {
397 $infunction = true;
398
399 if ($inclass)
400 {
401 $elements['classes']["$class"][] = $nextbit[1];
402 }
403 else
404 {
405 $elements['functions'][] = $nextbit[1];
406 }
407 }
408 else if ($token == 'B_OPEN')
409 {
410 array_push($stack, $id);
411 }
412 else if ($token == 'B_CLOSE')
413 {
414 array_pop($stack);
415
416 // breaking out of a method
417 if ($inclass AND $infunction)
418 {
419 if (count($stack) < 2)
420 {
421 $infunction = false;
422 }
423 }
424 // breaking out of a class
425 else if ($inclass AND !$infunction)
426 {
427 if (count($stack) < 1)
428 {
429 $inclass = false;
430 $limiters["$class"][1] = $bit[3];
431 }
432 }
433 // breaking out of a function
434 else if (!$inclass AND $infunction)
435 {
436 if (count($stack) == 0)
437 {
438 $infunction = false;
439 }
440 }
441 }
442 $lastbit = $bit;
443 }
444
445 return array('methods' => $elements, 'limiters' => $limiters);
446 }
447
448 /*=====================================================================*\
449 || ###################################################################
450 || # $HeadURL$
451 || # $Id$
452 || ###################################################################
453 \*=====================================================================*/
454 ?>