PageRenderTime 35ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/lint_php_lib.php

https://github.com/pceres/lint_php
PHP | 1956 lines | 1128 code | 576 blank | 252 comment | 152 complexity | f503f44fa344666e269960047fdebfeb MD5 | raw file
  1. <?php
  2. /*
  3. lint_php_lib: a PHP script that computes McCabe's cyclomatic complexity of a generic PHP source code
  4. Copyright (C) 2007 Pasquale Ceres
  5. Version 0.13
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  18. function lint($text,$verbosity) {
  19. /*
  20. input:
  21. $text : text to analyse
  22. $verbosity : [0,1,2] debug level (0 no debug info, 2 max verbosity
  23. es.:
  24. result = lint($text,0);
  25. cyclomatic complexity increase for each token:
  26. if : number of logical conditions (es. if ($a && $b) {} determines an increment of two)
  27. elseif : number of logical conditions
  28. else : 0
  29. case : 1
  30. default : 1
  31. while : number of logical conditions
  32. for : 1
  33. foreach : 1
  34. try : 1
  35. */
  36. // configurations
  37. $only_code = 0; // [0,1] 0 -> also show line numbers
  38. $max_lines = 10000; // max number of lines to show
  39. $parameters = Array();
  40. $parameters['list_begin_end_tokens'] = Array('if','else','elseif','try','catch','while','do','for','foreach');
  41. $parameters['list_mid_tokens'] = Array('else','elseif','catch');
  42. // check input
  43. if (empty($text))
  44. {
  45. die('Insert some text!');
  46. }
  47. if (!in_array($verbosity,range(0,2)))
  48. {
  49. stampa('0: no debug info');
  50. stampa('1: show some debug info');
  51. stampa('2: show all debug info');
  52. stampa(' ');
  53. die('Wrong value for "verbosity"!');
  54. }
  55. // parse input (treat the text as one file)
  56. $list_files = Array($text);
  57. // iterate for each file
  58. $list_result = Array();
  59. for($i_file = 0; $i_file<count($list_files); $i_file++)
  60. {
  61. $text = $list_files[$i_file];
  62. // just print file content
  63. if ($verbosity)
  64. {
  65. stampa(sprintf('%3d)',$i_file));
  66. }
  67. if ($verbosity)
  68. {
  69. stampa(sprintf('Text Reading...'));
  70. }
  71. $temp_result = read_phptext($text);
  72. $list_lines_in = $temp_result[0];
  73. $list_numlines_in = $temp_result[1];
  74. if ($verbosity >= 2)
  75. {
  76. show_lines($list_lines_in,$list_numlines_in,array_fill(0,count($list_numlines_in),0),$only_code,$max_lines);
  77. }
  78. // all text but php code is filtered out:
  79. //
  80. // $a=1; /* comment1 */ echo($a) // comment 2
  81. // becomes
  82. // $a=1;
  83. // echo($a)
  84. //
  85. if ($verbosity)
  86. {
  87. stampa('Code Filtering...');
  88. }
  89. $temp_result = filter_text($list_lines_in,$list_numlines_in);
  90. $list_lines_code = $temp_result[0];
  91. $list_numlines_code = $temp_result[1];
  92. if ($verbosity >= 2)
  93. {
  94. show_lines($list_lines_code,$list_numlines_code,array_fill(0,count($list_numlines_code),0),$only_code,$max_lines);
  95. }
  96. // every line is split into separate tokens (the separator is ";"):
  97. //
  98. // $a=1;echo($a)
  99. // becomes
  100. // $a=1;
  101. // echo($a)
  102. //
  103. if ($verbosity)
  104. {
  105. stampa('Code Splitting...');
  106. }
  107. $temp_result = parse_mfile($list_lines_code,$list_numlines_code,$parameters['list_begin_end_tokens']);
  108. $list_lines_split = $temp_result[0];
  109. $list_numlines_split = $temp_result[1];
  110. if ($verbosity >= 2)
  111. {
  112. show_lines($list_lines_split,$list_numlines_split,array_fill(0,count($list_numlines_split),0),$only_code,$max_lines);
  113. }
  114. // each line is reassembled, trying to have one instruction for each line, without blank spaces, and no
  115. // simple instructions (for example: if (true) disp('true') --> if (true) {disp('true')})
  116. if ($verbosity)
  117. {
  118. stampa('Code Reassembling...');
  119. }
  120. $temp_result = reassemble_mfile($list_lines_split,$list_numlines_split,$parameters);
  121. $list_lines_out = $temp_result[0];
  122. $list_numlines_out = $temp_result[1];
  123. if ($verbosity >= 2)
  124. {
  125. show_lines($list_lines_out,$list_numlines_out,array_fill(0,count($list_numlines_out)),$only_code,$max_lines);
  126. }
  127. if ($verbosity)
  128. {
  129. stampa('Code Indenting...');
  130. }
  131. $temp_result = indent_mfile($list_lines_out,$list_numlines_out);
  132. $list_indent_out = $temp_result[0];
  133. $lista_functions = $temp_result[1];
  134. $lista_function_names = $temp_result[2];
  135. $list_lines_out = $temp_result[3];
  136. $indent_mccount = $temp_result[4];
  137. $temp_result = check_unused_functions($lista_functions, $lista_function_names);
  138. $lista_functions = $temp_result[0];
  139. $is_script = $temp_result[1];
  140. if ($verbosity >= 2)
  141. {
  142. show_lines($list_lines_out, $list_numlines_out, $list_indent_out, $only_code, $max_lines, $indent_mccount);
  143. }
  144. $res_lint = show_functions($lista_functions, $verbosity);
  145. $result = Array();
  146. $result['lines_in'] = Array('lines' => $list_lines_in, 'numlines' => $list_numlines_in);
  147. $result['lines_split'] = Array('lines' => $list_lines_split, 'numlines' => $list_numlines_split);
  148. $result['lines_out'] = Array('lines' => $list_lines_out, 'numlines' => $list_numlines_out, 'list_indent_out' => $list_indent_out, 'indent_mccount' => $indent_mccount);
  149. $result['lista_functions'] = $lista_functions;
  150. $result['res_lint'] = $res_lint;
  151. $list_result[$i_file] = $result;
  152. } // end for $i_file
  153. // end
  154. return $list_result;
  155. } // end function lint()
  156. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. function read_phptext($text) {
  158. $list_lines_in = Array();
  159. $list_numlines_in = Array();
  160. $ks = preg_split("/\r?\n/",$text);
  161. foreach($ks as $line_number => $tline)
  162. {
  163. $riga_in = $line_number+1;
  164. array_push($list_lines_in,$tline);
  165. array_push($list_numlines_in,$riga_in);
  166. } // end while
  167. // end
  168. return Array($list_lines_in, $list_numlines_in);
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  171. function show_lines($list_lines,$list_numlines,$list_indent,$only_code,$max_lines,$indent_mccount = Array()) {
  172. stampa('------------------------------------------------------------------------------');
  173. for ($i=0;$i<min(count($list_lines),$max_lines);$i++)
  174. {
  175. $line = $list_lines[$i];
  176. $numline = $list_numlines[$i];
  177. $indent = $list_indent[$i];
  178. $num_spaces = $indent*4;
  179. $indent_str = str_repeat('--->',$indent); // indent string (to be added at the left of the line)
  180. if (count('indent_mccount') > 0)
  181. {
  182. $mc_count = $indent_mccount[$i];
  183. if ($mc_count > 0)
  184. {
  185. $ks_mccount = sprintf('(->%1d) - ', $mc_count);
  186. }
  187. else
  188. {
  189. $ks_mccount = ' - ';
  190. }
  191. }
  192. else
  193. {
  194. $ks_mccount = '';
  195. }
  196. if ($only_code)
  197. {
  198. stampa(sprintf('%s%s%s',$ks_mccount,$indent_str,$line));
  199. }
  200. else
  201. {
  202. stampa(sprintf('%3d - %s%s%s',$numline,$ks_mccount,$indent_str,$line));
  203. }
  204. } // end for $i
  205. // end
  206. stampa(' ');
  207. } // end function show_lines
  208. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  209. function filter_text($list_lines_in,$list_numlines_in) {
  210. /*
  211. Drop all text but php code (strings, comments, etc.)
  212. */
  213. $list_lines_out = Array();
  214. $list_numlines_out = Array();
  215. $enlined_lines = '';
  216. $rem_state = Array('rem_state' => 0); // out of php code
  217. for($i=0;$i < count($list_lines_in); $i++)
  218. {
  219. $line = rtrim(strtolower($list_lines_in[$i]));
  220. $numline = $list_numlines_in[$i];
  221. // drop all text but PHP code
  222. $temp_result = pre_split_work($line,$rem_state);
  223. $line_filtered = $temp_result[0];
  224. $rem_state = $temp_result[1];
  225. $new_lines_out = $line_filtered;
  226. $new_numlines_out = $numline;
  227. if (strlen($new_lines_out) > 0)
  228. {
  229. $list_lines_out[count($list_lines_out)] = $new_lines_out;
  230. $list_numlines_out[count($list_numlines_out)] = $new_numlines_out;
  231. }
  232. // echo "|$line|$line_filtered|{$rem_state['rem_state']}<br>\n";
  233. } // end for $i
  234. return Array($list_lines_out,$list_numlines_out);
  235. } // end function filter_text
  236. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. function parse_mfile($list_lines_in,$list_numlines_in,$list_begin_end_tokens) {
  238. $list_lines_out = Array();
  239. $list_numlines_out = Array();
  240. $enlined_lines = '';
  241. $rem_state = Array('rem_state' => 0); // out of php code
  242. for($i=0;$i < count($list_lines_in); $i++)
  243. {
  244. $line = $list_lines_in[$i];
  245. $numline = $list_numlines_in[$i];
  246. if (isset($list_lines_in[$i+1]))
  247. {
  248. $nextline = $list_lines_in[$i+1];
  249. }
  250. else
  251. {
  252. $nextline = ' ';
  253. }
  254. $first_char = $nextline[0]; // first char of the next line
  255. $line_current = $line;
  256. // condition to enqueue current line, or to stop enqueueing and analyse enqueued text
  257. $enqueue_to_next_line = (in_array($first_char,Array('?',':'))); // if the first char of next line is ? or :, just enline, as well
  258. if ($enqueue_to_next_line)
  259. {
  260. // enqueue to the next line, and empty current one
  261. $list_lines_in[$i+1] = $line_current.' '.$list_lines_in[$i+1]; // add current line to the next one
  262. $list_numlines_in[$i+1] = $numline; // change next line number: it will start with current line number
  263. $line_current = '';
  264. $stop_enqueue = false;
  265. }
  266. else
  267. {
  268. // check the last character of current line
  269. $last_char = $line_current[strlen($line_current)-1]; // last char of the line
  270. $stop_enqueue = (in_array($last_char,Array(';','}',')','{'))); // if the last char isn't ; or } or ), just enline
  271. // if line ends by :, and it is a case statement, stop enqueueing
  272. preg_match("/(case|default)/",$line_current,$z);
  273. if (($last_char === ':') && (count($z) > 0))
  274. {
  275. $stop_enqueue = 1;
  276. }
  277. }
  278. $enlined_lines .= $line_current;
  279. $flg_analyse_line = ($i == count($list_lines_in)-1) || ($stop_enqueue);
  280. // if the enlines text has to be analysed, do that
  281. if ($flg_analyse_line)
  282. {
  283. // echo "analyzing:|$enlined_lines|<br>";
  284. if (strlen($enlined_lines) > 0)
  285. {
  286. // perform here enqueued line transformations:
  287. // resolve ternary statements into if-then-else
  288. $enlined_lines = preg_replace('/([^\?]+)\?([^:]+):([^;]+);/','if ($1), {$2;} else {$3;}',$enlined_lines);
  289. // split enlined text into several atomic lines
  290. $temp_result = split_line($enlined_lines,$numline,$list_begin_end_tokens);
  291. $new_lines_out = $temp_result[0];
  292. $new_numlines_out = $temp_result[1];
  293. if (count($new_lines_out) > 0)
  294. {
  295. $list_lines_out = array_merge($list_lines_out,$new_lines_out);
  296. $list_numlines_out = array_merge($list_numlines_out,$new_numlines_out);
  297. }
  298. }
  299. // reset the enlined text buffer
  300. $enlined_lines = '';
  301. } // end if
  302. } // end for $i
  303. // end
  304. return Array($list_lines_out,$list_numlines_out);
  305. } // end function parse_mfile
  306. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. function pre_split_work($line, $rem_state) {
  308. /*
  309. This function takes the input line, and tryes to filter out all text but PHP code.
  310. Strings are substituted by a ' ' default string.
  311. Since comments and string can spread over different lines, a state has to be passed to tell the
  312. function whether the input line is inside a comment or a string that began in previous lines.
  313. */
  314. $list_string_tag = Array('"','\''); // opening and closing multiline string tag
  315. $list_string_tag_id = Array(2 ,3 ); // associated rem_state
  316. // echo "(".$rem_state['rem_state'].")|$line|<br>";
  317. switch ($rem_state['rem_state'])
  318. {
  319. case 0: // out of php: HTML code or inside comments (/*...*/)
  320. $temp_result = pre_split_work_rem($line, $rem_state); // manage the line in a rem state
  321. $line = $temp_result[0];
  322. $rem_state = $temp_result[1];
  323. break; // case 0
  324. case 1: // php code
  325. $temp_result = pre_split_work_phpcode($line, $rem_state, $list_string_tag, $list_string_tag_id);
  326. $line = $temp_result[0];
  327. $rem_state = $temp_result[1];
  328. break; // case 1
  329. // Multiline string delimited by " or ' ( depending on $list_string_tag and $list_string_tag_id)
  330. // It is mandatory that $list_string_tag_id contains the value used by the switch/case's just below
  331. case 2:
  332. case 3:
  333. $temp_result = pre_split_work_multilinestring($line, $rem_state, $list_string_tag, $list_string_tag_id);
  334. $line = $temp_result[0];
  335. $rem_state = $temp_result[1];
  336. break; // case 2,3
  337. case 4: // heredoc string inside php code
  338. $temp_result = pre_split_work_heredoc($line,$rem_state);
  339. $line = $temp_result[0];
  340. $rem_state = $temp_result[1];
  341. break; // case 4
  342. default:
  343. die(sprintf('Unmanaged rem_state (%d)!',$rem_state['rem_state']));
  344. break;
  345. } // end switch($rem_state['rem_state'])
  346. // end
  347. $line = drop_strings($line);
  348. // substitute commas with spaces inside input parameter text of functions
  349. if (preg_match('/\s*function/',$line)) // if the line starts with "function" token...
  350. {
  351. $lista_pat = Array('function\s*\[[^\]]*\]','function\s*[^\(]*\([^\)]*\)');
  352. for ($i_pat = 0;$i_pat < count($lista_pat); $i_pat++)
  353. {
  354. $pat = "/".$lista_pat[$i_pat]."/i";
  355. preg_match($pat,$line,$z);
  356. if (!empty($z))
  357. {
  358. // delete semicolon deriving from enclosed remarcs inside function parameters
  359. // (es. function foo($bar1 /*note */,$bar2) --> foo($bar1;, $bar2) --> foo($bar1 $bar2) )
  360. $z[0]=str_replace(';','',$z[0]);
  361. // substitute commas with spaces (es. function foo($bar1,$bar2) --> foo($bar1 $bar2) )
  362. $z=str_replace(',',' ',$z[0]);
  363. $line = preg_replace($pat,$z,$line);
  364. }
  365. }
  366. }
  367. // if a simple instruction (not inclosed in brackets {}) follows an intermediate token (else, catch, etc.), then
  368. // insert a semicolon (ex: "else echo('1')" --> "else; echo('1')"
  369. $line = preg_replace('/(else|catch)[\s]+/i',"\\1;",$line);
  370. $line = trim($line);
  371. $line_elaborata = $line;
  372. return Array($line_elaborata,$rem_state);
  373. } // end function pre_split_work
  374. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  375. function pre_split_work_heredoc(&$line,&$rem_state) {
  376. /*
  377. This function manages the $line when in a heredoc string state ($rem_state['rem_state'] = 4)
  378. */
  379. // search for heredoc string closing tag
  380. $string_tag = '^'.$rem_state['heredoc_close_tag'].';?$';
  381. if ( preg_match("/$string_tag/",$line) )
  382. {
  383. $rem_state['rem_state'] = 1; // back to PHP code
  384. unset($rem_state['heredoc_close_tag']);
  385. }
  386. $line = '';
  387. return Array($line,$rem_state);
  388. } // end function pre_split_work_heredoc
  389. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  390. function pre_split_work_multilinestring(&$line,&$rem_state,$list_string_tag,$list_string_tag_id) {
  391. /*
  392. This function manages the $line when in a multiline string state ($rem_state['rem_state'] = 2 or 3)
  393. */
  394. // determine the string delimiter that originated the multiline string
  395. $string_tag = $list_string_tag[array_search($rem_state['rem_state'], $list_string_tag_id)];
  396. // drop escapes (hopefully inside strings!)
  397. $line2 = drop_escapes($line);
  398. // search for string closing tag
  399. preg_match_all("/$string_tag/",$line2,$z);
  400. //if (count($z[0]) % 2 == 1 ) // an odd number means the multiline string closes
  401. if ( count($z[0]) > 0 ) // if you find at least one tag, manage it
  402. {
  403. // pointer next to first string_tag
  404. $ind = strfind($line2,$string_tag)+1;
  405. $rem_state['rem_state'] = 1; // back to PHP code
  406. $temp_result = pre_split_work(substr($line2,$ind), $rem_state);
  407. $line3 = $temp_result[0];
  408. $rem_state = $temp_result[1];
  409. $line = $line3;
  410. }
  411. else
  412. {
  413. $line = '';
  414. }
  415. return Array($line,$rem_state);
  416. } // end function pre_split_work_multilinestring
  417. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  418. function pre_split_work_phpcode(&$line,&$rem_state,$list_string_tag,$list_string_tag_id) {
  419. /*
  420. This function manages the $line when in a php state ($rem_state['rem_state'] = 1)
  421. */
  422. // drop escapes (hopefully inside strings!)
  423. $line = drop_escapes($line);
  424. // in PHP code, you can drop strings
  425. $line = drop_strings($line);
  426. // search for rem closing tags
  427. $tag = '?>';
  428. $rem_state_restart_tag = '<?php'; // tag to search in following text to exit the out-of-php-code state (0)
  429. $ind = strfind($line,$tag);
  430. if ($ind === False)
  431. {
  432. $tag = '/*';
  433. $rem_state_restart_tag = '*/'; // tag to search in following text to exit the out-of-php-code state (0)
  434. $ind = strfind($line,$tag);
  435. }
  436. // verify if a potential rem closing tag is inside a string
  437. if ( ($ind > 0) && (strlen($line) > 0) )
  438. {
  439. $line = drop_strings(substr($line,0,$ind)).substr($line,$ind);
  440. $ind = strfind($line,$tag);
  441. preg_match_all("/'/",substr($line,0,$ind),$z);
  442. if ( count($z[0]) % 2 == 1 )
  443. {
  444. $ind = False; // if so, don't consider it
  445. }
  446. }
  447. // if a rem tag ("<?php" or "/*") was found, change the state
  448. if ($ind !== False)
  449. {
  450. $line2 = substr($line,0,$ind);
  451. $rem_state['rem_state'] = 0;
  452. $rem_state['rem_state_restart_tag'] = $rem_state_restart_tag; // save the restart tag: only its occurrence will restart php code
  453. $temp_result = pre_split_work(substr($line,$ind+strlen($tag)), $rem_state);
  454. $line3 = $temp_result[0];
  455. $rem_state = $temp_result[1];
  456. // $line = $line2.';'.$line3;
  457. $line = $line2.' '.$line3; // join code before and after a /*...*/ comment by a blank space
  458. }
  459. // search for multiline unclosed string
  460. $line2 = drop_strings($line);
  461. for ($i_tag = 0;$i_tag < count($list_string_tag);$i_tag++)
  462. {
  463. $string_tag = $list_string_tag[$i_tag];
  464. $string_tag_id = $list_string_tag_id[$i_tag];
  465. preg_match_all("/$string_tag/",$line2,$z);
  466. if ( count($z[0]) % 2 == 1 )
  467. {
  468. $line = $line2." ".$string_tag;
  469. $rem_state['rem_state'] = $string_tag_id;
  470. break;
  471. }
  472. }
  473. // search for heredoc string opening tag
  474. $string_tag = '<<<([a-zA-Z_][a-zA-Z0-9_]+)$';
  475. preg_match_all("/$string_tag/",$line,$z);
  476. if ( isset($z[1][0]) && (count($z[1][0]) > 0) )
  477. {
  478. $heredoc_close_tag = $z[1][0];
  479. preg_match("/$string_tag/",$line,$z,PREG_OFFSET_CAPTURE);
  480. $pos = $z[0][1];
  481. $line2 = drop_strings(substr($line,0,$pos));
  482. $line = $line2.' " ";';
  483. $rem_state['rem_state'] = max($list_string_tag_id)+1;
  484. $rem_state['heredoc_close_tag'] = $heredoc_close_tag;
  485. }
  486. return Array($line,$rem_state);
  487. } // end function pre_split_work_phpcode
  488. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  489. function pre_split_work_rem(&$line,&$rem_state) {
  490. /*
  491. This function manages the $line when in a rem state ($rem_state['rem_state'] = 0)
  492. */
  493. // retrieve the rem opening tag (previously saved when the rem state was set, otherwise "<?php")
  494. if (empty($rem_state['rem_state_restart_tag']))
  495. {
  496. $tag = '<?php';
  497. }
  498. else
  499. {
  500. $tag = $rem_state['rem_state_restart_tag'];
  501. }
  502. // search for rem opening tags (previously saved when the rem state was set)
  503. $ind = strfind($line,$tag);
  504. if ($ind===False)
  505. {
  506. $line = '';
  507. }
  508. else
  509. {
  510. $line = substr($line,$ind+strlen($tag));
  511. $rem_state['rem_state'] = 1;
  512. $temp_result = pre_split_work($line,$rem_state);
  513. $line = $temp_result[0];
  514. $rem_state = $temp_result[1];
  515. }
  516. return Array($line,$rem_state);
  517. } // end function pre_split_work_rem
  518. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. function drop_comments($line) {
  520. $ind_rem = strpos($line,'#');
  521. if ($ind_rem !== False)
  522. {
  523. $line = trim(substr($line,0,$ind_rem)); // drop comments
  524. }
  525. $ind_rem = strpos($line,'//');
  526. if ($ind_rem !== False)
  527. {
  528. $line = trim(substr($line,0,$ind_rem)); // drop comments
  529. }
  530. return $line;
  531. } // function drop_comments($line)
  532. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  533. function drop_escapes($line) {
  534. /*
  535. This function substitutes or drops special escape sequences (typical inside strings),
  536. such as "\'", "\\"
  537. */
  538. $list_tag_replace = Array(
  539. Array("/\\\\\\\\/","_"), // substitute \\ by _ (must be first, to prevent "\\" to be transformed into "\_ )
  540. Array("/\\\'/","_"), // substitute \' by _
  541. Array("/\\\\\"/","_") // substitute \" by _
  542. );
  543. for ($i_tag = 0; $i_tag < count($list_tag_replace); $i_tag++)
  544. {
  545. $tag_old = $list_tag_replace[$i_tag][0];
  546. $tag_new = $list_tag_replace[$i_tag][1];
  547. $line2='';
  548. while (strlen($line)!=strlen($line2))
  549. {
  550. $line2 = $line;
  551. $line = preg_replace($tag_old,$tag_new,$line2,1);
  552. }
  553. // echo "$i_tag($tag_old|$tag_new)$line|$line2|<br>\n";
  554. }
  555. // $line = preg_replace("/''/i","'_'",$line); // substitute repeated single quotes with '_'
  556. // $line = preg_replace('/""/i','"_"',$line); // substitute repeated double quotes with "_"
  557. return $line;
  558. } // end function drop_escapes($line)
  559. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  560. function drop_strings($line) {
  561. $line = drop_escapes($line);
  562. // sostituisci stringhe con "_"
  563. $string_tag = '^[^\'"]*([\'"])';
  564. preg_match("/$string_tag/",$line,$z);
  565. $ancora = 1;
  566. while ( (count($z) > 0) && ($ancora) )
  567. {
  568. $string_delimiter = $z[1];
  569. $string_tag2 = $string_delimiter.'([^'.$string_delimiter.']*)'.$string_delimiter;
  570. $line2 = preg_replace("/$string_tag2/",'@_@',$line,1);
  571. if ( $line2 === $line )
  572. {
  573. $ancora = 0;
  574. }
  575. else
  576. {
  577. $line = $line2;
  578. preg_match("/$string_tag/",$line,$z);
  579. }
  580. }
  581. $line = preg_replace('/@_@/','"_"',$line);
  582. $line = drop_comments($line);
  583. return $line;
  584. } // end function drop_strings($line)
  585. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  586. function split_line($line,$numline,$list_begin_end_tokens) {
  587. $new_lines_out = Array();
  588. $new_numlines_out = Array();
  589. $split_tags = Array(';','{','}'); // tags that cause the line to be split
  590. $drop_tags = Array(';'); // tags that, alone in a line, are dropped
  591. $line = trim($line);
  592. if (!empty($line))
  593. {
  594. $pieces = explode_lines(Array($line),$split_tags,$list_begin_end_tokens);
  595. for ($i_pieces = 0; $i_pieces < count($pieces); $i_pieces++)
  596. {
  597. $piece = trim($pieces[$i_pieces]);
  598. // add the slice, if it isn't empty, and it is not a tag to be dropped
  599. if (!empty($piece) && !in_array($piece,$drop_tags))
  600. {
  601. array_push($new_lines_out,$piece);
  602. array_push($new_numlines_out,$numline);
  603. }
  604. }
  605. } // end if
  606. return Array($new_lines_out, $new_numlines_out);
  607. } // end function split_line
  608. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  609. function explode_lines($pieces,$list_sep,$list_begin_end_tokens) {
  610. for ($i_sep = 0; $i_sep < count($list_sep); $i_sep++)
  611. {
  612. $sep = $list_sep[$i_sep];
  613. $temp_pieces = Array();
  614. for ($i_pieces = 0; $i_pieces < count($pieces); $i_pieces++)
  615. {
  616. $piece = $pieces[$i_pieces];
  617. $temp = fcn_explode($piece,$sep,1);
  618. $temp_pieces = array_merge($temp_pieces,$temp);
  619. }
  620. $pieces = $temp_pieces;
  621. } // end for
  622. // check if a single line "if" is in the line, and split it (es.: "if (!$slpos) $slpos = 18;" is split into
  623. // "if (!$slpos)" and "$slpos = 18;"
  624. if (count($list_begin_end_tokens))
  625. {
  626. // prepare the regexp format
  627. $ks_format = '';
  628. foreach ($list_begin_end_tokens as $token)
  629. {
  630. $ks_format .= "$token|";
  631. }
  632. $ks_format = substr($ks_format,0,-1);
  633. $ks_format = "/^[\s;]($ks_format)\s+\((.*)\)\s+([^\{;]+);/";
  634. // check each piece for the format
  635. $temp_pieces = Array();
  636. for ($i_piece = 0; $i_piece < count($pieces); $i_piece++)
  637. {
  638. $line_temp = $pieces[$i_piece];
  639. preg_match($ks_format," $line_temp",$z); // add a leading space, to match pieces that begin with the token
  640. if (!empty($z))
  641. {
  642. $ks_token_start = $z[1]; // "if"
  643. $ks_condition = $z[2]; // "!$slpos"
  644. $ks_action1 = $z[3]; // "$slpos = 18"
  645. $line1 = "$ks_token_start ($ks_condition)";
  646. $line2 = "$ks_action1;";
  647. array_push($temp_pieces,$line1);
  648. array_push($temp_pieces,$line2);
  649. }
  650. else
  651. {
  652. array_push($temp_pieces,$line_temp);
  653. }
  654. } // end for
  655. } // end if
  656. $pieces = $temp_pieces;
  657. return $pieces;
  658. } // end function explode_lines
  659. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  660. function reassemble_mfile($list_lines_in,$list_numlines_in,$parameters) {
  661. $list_lines_out = Array();
  662. $list_numlines_out = Array();
  663. $list_open = Array('(');
  664. $list_close = Array(')');
  665. $list_begin_end_tokens = $parameters['list_begin_end_tokens'];
  666. $list_mid_tokens = $parameters['list_mid_tokens'];
  667. $parenthesys_flag = 0;
  668. $newline = 1;
  669. $num_open = 0;
  670. $num_close = 0;
  671. $line_step = 100;
  672. // prepare the regexp format
  673. $ks_format = '';
  674. foreach ($list_begin_end_tokens as $token)
  675. {
  676. $ks_format .= "$token|";
  677. }
  678. $ks_format = substr($ks_format,0,-1);
  679. for ($i=0;$i<count($list_lines_in);$i++) {
  680. $line = $list_lines_in[$i];
  681. $numline = $list_numlines_in[$i];
  682. if (strpos($line,"...")!==false)
  683. {
  684. $line = str_replace('...','',$line);
  685. }
  686. // if an elseif (or similar) follows, don't go to new line
  687. if ($newline)
  688. {
  689. for ($i_mid = 0;$i_mid < count($list_mid_tokens);$i_mid++)
  690. {
  691. $mid_token = $list_mid_tokens[$i_mid];
  692. if (strpos($line,$mid_token)!==false)
  693. {
  694. $newline = 0;
  695. }
  696. }
  697. }
  698. // if an open brace parenthesis { is at the beginning of the line, then move it at the end of the previous line
  699. if ( (strpos($line,'{') !== false) && (strpos($line,'{') === 0) )
  700. {
  701. $newline = 0;
  702. }
  703. // if previous token manages complex instructions ({...}, parenthesys_flag=1), and a simple instruction follows,
  704. // surrond it by braces (making it a complex instruction)
  705. if ($newline)
  706. {
  707. // a command should not be embraced if an opening parenthesis is found
  708. $embrace_line = (strcmp($line,'{') !== 0);
  709. if ( $parenthesys_flag && $embrace_line )
  710. {
  711. // no embracing if next command is a complex one, as well: better not embracing
  712. // es.: if ($a==1) $b=1; else if ($a==2) $b=2; else $b=3;
  713. preg_match("/^\s*($ks_format)/",$line,$z);
  714. if (count($z) > 0)
  715. {
  716. // Add a virtual empty atomic instruction, just before the complex instruction that starts here
  717. // the indentation will be at the wrong level for the latter, but following instructions will be indented
  718. // correctly
  719. $add_line = Array('{/*multiline atomic instruction without curly braces: dropped*/}',$line);
  720. }
  721. else
  722. {
  723. // Add an open curly brace to the previous line ...
  724. $list_lines_out[count($list_lines_out)-1] = $list_lines_out[count($list_lines_out)-1].',{';
  725. // ... and a new line with a close curly brace after the current line
  726. $add_line = Array($line,'}');
  727. }
  728. }
  729. else
  730. {
  731. $add_line = Array($line);
  732. }
  733. $add_numline = array_fill(0,count($add_line),$numline);
  734. $list_lines_out = array_merge($list_lines_out,$add_line);
  735. $list_numlines_out = array_merge($list_numlines_out,$add_numline);
  736. }
  737. else
  738. {
  739. $list_lines_out[count($list_lines_out)-1] = $list_lines_out[count($list_lines_out)-1].','.$line;
  740. }
  741. // count open and close brackets
  742. for ($i_open = 0;$i_open<count($list_open);$i_open++)
  743. {
  744. $num_open = $num_open+count(explode($list_open[$i_open],$line))-1;
  745. $num_close = $num_close+count(explode($list_close[$i_open],$line))-1;
  746. }
  747. // determine whether line terminates correctly (and you can go to a new line), or it is incomplete (and it continues
  748. // in the following line)
  749. $is_complete = (empty($line) || (!in_array(substr($line,-1,1),Array('|','&'))) );
  750. if ( ($num_open == $num_close) && $is_complete )
  751. {
  752. $newline = 1;
  753. }
  754. else
  755. {
  756. $newline = 0;
  757. }
  758. // verify that a { is present in following line, or treat the following instruction as a simple instruction
  759. $parenthesys_flag = 0;
  760. for ($i_tok = 0; $i_tok < count($list_begin_end_tokens); $i_tok++)
  761. {
  762. $tok = $list_begin_end_tokens[$i_tok];
  763. if ( (strpos($line,$tok) === 0) && (preg_match('/' . $tok . '[^{]*{/',$line)==0) )
  764. {
  765. $parenthesys_flag = 1;
  766. }
  767. }
  768. // a 'while' after 'do' isn't followed by a complex instruction
  769. if ($parenthesys_flag && (preg_match('/^while.*;$/',$line)>0) )
  770. {
  771. $parenthesys_flag = 0;
  772. }
  773. } // end for
  774. // end
  775. return Array($list_lines_out,$list_numlines_out);
  776. } // end function reassemble_mfile
  777. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  778. function fcn_explode($line,$sep,$flag_keep_sep) {
  779. $ind = fcn_strpos($line,$sep); // all positions where separator is found
  780. if ($ind === False)
  781. {
  782. $piece = normalizza_riga($line);
  783. $pieces = Array($piece);
  784. }
  785. else
  786. {
  787. $ind = array_merge($ind,Array(strlen($line)));
  788. $lsep = strlen($sep);
  789. if ($flag_keep_sep)
  790. {
  791. $first_piece = substr($line,0,$ind[0]+strlen($sep));
  792. }
  793. else
  794. {
  795. $first_piece = substr($line,0,$ind[0]);
  796. }
  797. $pieces = Array(normalizza_riga($first_piece));
  798. for ($i=1;$i<count($ind);$i++)
  799. {
  800. if ($flag_keep_sep)
  801. {
  802. $piece = substr($line,$ind[$i-1]+$lsep,$ind[$i]-$ind[$i-1]);
  803. }
  804. else
  805. {
  806. $piece = substr($line,$ind[$i-1]+$lsep,$ind[$i]-$ind[$i-1]-$lsep);
  807. }
  808. $piece = normalizza_riga($piece);
  809. if (!empty($piece))
  810. {
  811. array_push($pieces,$piece);
  812. }
  813. } // end for
  814. // end
  815. } // end if
  816. // end
  817. return $pieces;
  818. } // end function fcn_explode
  819. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  820. function indent_mfile($list_lines_in,$list_numlines_in) {
  821. $list_indent = Array();
  822. $list_inc0 = Array('for' ,'foreach' ,'if' ,'try' ,'switch' ,'while' ,'do' );
  823. $list_mid0 = Array(Array('') ,Array('') ,Array('},elseif' ,'},else') ,Array('},catch') ,Array('},case' ,'},default') ,Array('') ,Array('') );
  824. $list_dec0 = Array('}' ,'}' ,'}' ,'}' ,'}' ,'}' ,'}' );
  825. // add a space to tokens to be searched for
  826. $token_append_string = ' ';
  827. for ($i_inc = 0; $i_inc < count($list_inc0); $i_inc++)
  828. {
  829. $list_inc[$i_inc] = $list_inc0[$i_inc].$token_append_string;
  830. $list_mid_ = $list_mid0[$i_inc];
  831. $list_mid[$i_inc] = Array();
  832. for ($i_mid = 0; $i_mid < count($list_mid_); $i_mid++)
  833. {
  834. $list_mid[$i_inc][$i_mid] = $list_mid_[$i_mid].$token_append_string;
  835. }
  836. $list_dec[$i_inc] = $list_dec0[$i_inc].$token_append_string;
  837. }
  838. $indent_tokens['list_inc0'] = $list_inc0;
  839. $indent_tokens['list_mid0'] = $list_mid0;
  840. $indent_tokens['list_dec0'] = $list_dec0;
  841. $indent_tokens['list_inc'] = $list_inc;
  842. $indent_tokens['list_mid'] = $list_mid;
  843. $indent_tokens['list_dec'] = $list_dec;
  844. $indent = 0;
  845. $indent_next = 0;
  846. $token = Array();
  847. $list_token = Array($token);
  848. $list_tokens = Array();
  849. $function_info = get_function_info('');
  850. $lista_functions = Array();
  851. $lista_function_names = Array();
  852. $stati = Array('line_modified' => '');
  853. for ($i = 0; $i < count($list_lines_in); $i++)
  854. {
  855. $line = $list_lines_in[$i].' ';
  856. $numline = $list_numlines_in[$i];
  857. $temp_result = indent_line($line, $numline, $indent, $indent_tokens, $token, $list_tokens, $function_info, $list_token, $lista_functions, $lista_function_names, $stati);
  858. $token = $temp_result[0];
  859. $token_next = $temp_result[1];
  860. $indent = $temp_result[2];
  861. $indent_next = $temp_result[3];
  862. $list_token = $temp_result[4];
  863. $list_tokens = $temp_result[5];
  864. $function_info = $temp_result[6];
  865. $lista_functions = $temp_result[7];
  866. $lista_function_names = $temp_result[8];
  867. $stati = $temp_result[9];
  868. $mc_inc = $temp_result[10];
  869. // echo "$numline-->$indent-$mc_inc<br>"; // !!!
  870. // var_dump($function_info['function']);echo "<br>";
  871. // if the line has to be changed
  872. if (!empty($stati['line_modified']))
  873. {
  874. $list_lines_in[$i] = $stati['line_modified'];
  875. $stati['line_modified'] = '';
  876. }
  877. $list_mc_count_in[$i] = $mc_inc;
  878. $list_indent[$i] = $indent;
  879. $indent = $indent+$indent_next;
  880. } // end for
  881. // end
  882. $function_info = function_checks($function_info,$list_tokens);
  883. array_push($lista_functions, $function_info);
  884. return Array($list_indent, $lista_functions, $lista_function_names, $list_lines_in, $list_mc_count_in);
  885. } // end function indent_mfile
  886. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  887. function indent_line($line, $numline, $indent, $indent_tokens, $token, $list_tokens, $function_info, $list_token, $lista_functions, $lista_function_names, $stati) {
  888. // insert a space before open braces
  889. $line = preg_replace('/([^[:space:]]){/',"\\1 {",$line);
  890. $mc_inc = 0; // by default each line doesn't increment the McCabe cyclomatic complexity counter
  891. $list_inc0 = $indent_tokens['list_inc0'];
  892. $list_mid0 = $indent_tokens['list_mid0'];
  893. $list_dec0 = $indent_tokens['list_dec0'];
  894. $list_inc = $indent_tokens['list_inc'];
  895. $list_mid = $indent_tokens['list_mid'];
  896. $list_dec = $indent_tokens['list_dec'];
  897. $token_next = Array();
  898. $indent_next = 0;
  899. // if indent counter is zero (top level), and I find a }, it means that the current function closes here
  900. if ( ($indent == 0) && ($line === '} ') )
  901. {
  902. $close_function = true;
  903. }
  904. else
  905. {
  906. $close_function = false;
  907. }
  908. // a 'do' structure was just closed --> request the substitution of 'while' with 'while_do'
  909. if (array_key_exists('subst_line',$stati) && (!empty($stati['subst_line'])))
  910. {
  911. $line = preg_replace('/' . $stati['subst_line'][0] . '/',$stati['subst_line'][1],$line);
  912. $stati['line_modified'] = $line;
  913. $stati['subst_line'] = Array();
  914. }
  915. else
  916. {
  917. // a new complex instruction starts?
  918. for ($i_inc = 0; $i_inc < count($list_inc0); $i_inc++)
  919. {
  920. if (preg_match('/^'.$list_inc0[$i_inc].'[^[:alnum:]]?/',$line))
  921. {
  922. $token_next['inc'] = $list_inc0[$i_inc];
  923. $token_next['mid'] = $list_mid0[$i_inc];
  924. $token_next['dec'] = $list_dec0[$i_inc];
  925. $indent_next = 1;
  926. break;
  927. } // end if
  928. } // end for
  929. if (array_key_exists('dec',$token))
  930. {
  931. // if you're inside a complex instruction, delimited by braces, for which closing tags exist
  932. // (ex. '}', and other intermediate (ex. 'else', 'elseif')...
  933. // var_dump($token);echo "<br>"; // !!!
  934. // stampa("1($indent,$indent_next)"); // !!!
  935. // search intermediate token (ex. else)
  936. $temp_result = manage_mid_token($line,$token,$indent,$indent_next);
  937. $indent = $temp_result[0];
  938. $indent_next = $temp_result[1];
  939. // stampa("2($indent,$indent_next)"); // !!!
  940. // search closing token (ex. })
  941. $temp_result = manage_dec_token($line, $numline, $token, $list_token, $indent, $indent_next, $function_info, $stati);
  942. $indent = $temp_result[0];
  943. $indent_next = $temp_result[1];
  944. $token = $temp_result[2];
  945. $list_token = $temp_result[3];
  946. $function_info = $temp_result[4];
  947. $stati = $temp_result[5];
  948. // var_dump($token);echo "<br>"; // !!!
  949. // stampa("3($indent,$indent_next)"); // !!!
  950. } // end if
  951. } // end if
  952. // end
  953. // current function finishes, a new starts (included the root function, for scripts not inside function tags)
  954. if ( (preg_match('/^(private |public |protected )*function /',$line)) || ($close_function) )
  955. {
  956. // first verify the tokens found in previous function...
  957. $function_info = function_checks($function_info,$list_tokens);
  958. array_push($lista_functions, $function_info);
  959. // ...then start new function
  960. $function_info = get_function_info($line);
  961. $list_tokens = Array();
  962. array_push($lista_function_names, $function_info['function']);
  963. }
  964. else
  965. {
  966. // verify whether any of the tokens is an input or output parameter
  967. preg_match_all('/[[:alnum:]_$]+/',$line,$temp_ereg_result);
  968. if (empty($line_tokens))
  969. {
  970. $line_tokens = $temp_ereg_result[0];
  971. }
  972. else
  973. {
  974. $line_tokens = array_merge($line_tokens, $temp_ereg_result[0]);
  975. }
  976. $list_tokens = array_unique(array_merge($list_tokens, $line_tokens));
  977. $mc_inc = lint_check($line,$line_tokens);
  978. $function_info['mc_count'] = $function_info['mc_count']+$mc_inc;
  979. } // end if
  980. // end
  981. if (array_key_exists('inc',$token_next))
  982. {
  983. $token = $token_next;
  984. array_push($list_token, $token_next);
  985. }
  986. return Array($token, $token_next, $indent, $indent_next, $list_token, $list_tokens, $function_info, $lista_functions, $lista_function_names, $stati, $mc_inc);
  987. } // end function indent_line
  988. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  989. function lint_check($line, $line_tokens) {
  990. $list_tok = Array('if' ,'elseif','while_do','while','try' ,'case' ,'default','for' ,'foreach' );
  991. $num_tok = Array(1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 );
  992. $mc_inc = 0;
  993. for ($i_token = 0; $i_token < count($line_tokens); $i_token++)
  994. {
  995. $token = $line_tokens[$i_token];
  996. $ind = array_search($token,$list_tok);
  997. if ($ind !== false)
  998. {
  999. $mc_inc = 1;
  1000. if ($i_token >= count($num_tok))
  1001. {
  1002. stampa($line);
  1003. die('error!');
  1004. }
  1005. if ($num_tok[$i_token])
  1006. {
  1007. preg_match_all('/(&&)+/',$line,$and1);
  1008. preg_match_all('/[^[:alnum:]_]and[^[:alnum:]_]?/',$line,$and2);
  1009. $ands = count($and1[0])+count($and2[0]);
  1010. preg_match_all('/(\|\|)+/',$line,$or1);
  1011. preg_match_all('/[^[:alnum:]_]or[^[:alnum:]_]?/',$line,$or2);
  1012. $ors = count($or1[0])+count($or2[0]);
  1013. //echo "$line --> $token (and: $ands - or: $ors)<br>";
  1014. $mc_inc = $mc_inc+$ands+$ors;
  1015. }
  1016. break;
  1017. } // end if
  1018. // end
  1019. } // end for
  1020. // end
  1021. return $mc_inc;
  1022. } // end function lint_check
  1023. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1024. function manage_mid_token($line,$token,$indent,$indent_next) {
  1025. $ancora=1;
  1026. $i_mid=0;
  1027. $ind_mid = null;
  1028. while ($ancora)
  1029. {
  1030. $needle = $token['mid'][$i_mid];
  1031. if (!empty($needle) && preg_match('/' . addcslashes($needle, '/') . '/',$line))
  1032. {
  1033. $ancora=0;
  1034. $ind_mid = $i_mid;
  1035. // echo "1|$needle|$line|<br>"; // !!!
  1036. // var_dump($ind_mid === null); // !!!
  1037. }
  1038. else
  1039. {
  1040. $i_mid = $i_mid+1;
  1041. $ancora = $i_mid < count($token['mid']);
  1042. // echo "2<br>"; // !!!
  1043. }
  1044. } // end while
  1045. // end
  1046. // if you find a mid token (ex. else, elseif, ecc.) decrement current line indentation (but increment again at next line)
  1047. if ($ind_mid !== null)
  1048. {
  1049. $indent = $indent-1;
  1050. $indent_next = 1;
  1051. } // end if
  1052. return Array($indent,$indent_next);
  1053. } // end function manage_mid_token
  1054. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1055. function manage_dec_token($line, $numline, $token, $list_token, $indent, $indent_next, $function_info, $stati) {
  1056. $stati['subst_line'] = Array(); // by default don't require any line substitution
  1057. $ind_dec = fcn_strpos($line,$token['dec'].' ');
  1058. if ($ind_dec!==false)
  1059. {
  1060. // if current structure is a do, request the substitution of the closing 'while' token with 'while_do'
  1061. if (strcmp($token['inc'],'do') === 0)
  1062. {
  1063. $stati['subst_line'] = Array('^while([^[:alnum:]]?)',"while_do\\1");
  1064. } // end if
  1065. $indent = $indent-1;
  1066. $indent_next = 0;
  1067. $list_token = array_splice($list_token,0,-1);
  1068. if (empty($list_token))
  1069. {
  1070. $msg = sprintf('Errore nella linea %d',$numline);
  1071. if (!empty($function_info))
  1072. {
  1073. $function_info['final_end'] = 1;
  1074. stampa($msg);
  1075. }
  1076. else
  1077. {
  1078. die($msg);
  1079. }
  1080. }
  1081. else
  1082. {
  1083. $token = $list_token[count($list_token)-1];
  1084. }
  1085. } // end if
  1086. // end
  1087. return Array($indent, $indent_next, $token, $list_token, $function_info, $stati);
  1088. } // end function manage_dec_token
  1089. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1090. function function_checks($function_info,$list_tokens) {
  1091. $function_info['list_tokens'] = $list_tokens;
  1092. $list_tokens = array_merge($list_tokens,Array('varargin','varargout'));
  1093. // unused input arguments
  1094. $lista_param = $function_info['list_args_in'];
  1095. $tipo_param = 'Input';
  1096. $unused_var = Array();
  1097. foreach ($lista_param as $id => $param)
  1098. {
  1099. if (!in_array($param,$list_tokens))
  1100. {
  1101. array_push($unused_var,$param);
  1102. }
  1103. }
  1104. $function_info['unused_inputs'] = $unused_var;
  1105. // unused output arguments
  1106. $lista_param = $function_info['list_args_out'];
  1107. $tipo_param = 'Output';
  1108. $unused_var = Array();
  1109. foreach ($lista_param as $id => $param)
  1110. {
  1111. if (!in_array($param,$list_tokens))
  1112. {
  1113. array_push($unused_var,$param);
  1114. }
  1115. }
  1116. $function_info['unused_outputs'] = $unused_var;
  1117. return $function_info;
  1118. } // end function_checks
  1119. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1120. function get_function_info($line) {
  1121. if (empty($line) || ($line == '} '))
  1122. {
  1123. $function_info = Array('function' => '');
  1124. $function_info['args_in'] = '';
  1125. $function_info['args_out'] = '';
  1126. $function_info['list_args_in'] = Array();
  1127. $function_info['list_args_out'] = Array();
  1128. $function_info['mc_count'] = 1;
  1129. return $function_info;
  1130. }
  1131. $list = Array(
  1132. 'function[[:space:]]+()&?[[:space:]]*([^\(=]*)[[:space:]]*\([[:space:]]*([^\)]*)',
  1133. 'function[[:space:]]+([^=]*)=[[:space:]]+&?[[:space:]]*([^\(]*)[[:space:]]*\([[:space:]]*([^\)]*)'
  1134. );
  1135. $ancora = 1;
  1136. $i = 0;
  1137. while ($ancora)
  1138. {
  1139. $pat = $list[$i];
  1140. // echo "$i - $pat<br>";
  1141. $function_info = Array();
  1142. $temp = preg_match('/' . addcslashes($pat, '/') . '/',$line,$temp_function_info);
  1143. $function_info['args_out'] = $temp_function_info[1];
  1144. $function_info['function'] = $temp_function_info[2];
  1145. $function_info['args_in'] = $temp_function_info[3];
  1146. $i = $i+1;
  1147. $ancora = ( empty($function_info['function']) && ($i < count($list)) );
  1148. }
  1149. if (!array_key_exists('args_out',$function_info))
  1150. {
  1151. $function_info['args_out'] = '';
  1152. }
  1153. if (!array_key_exists('function',$function_info))
  1154. {
  1155. $function_info['function'] = '';
  1156. }
  1157. if (!array_key_exists('args_in',$function_info))
  1158. {
  1159. $function_info['args_in'] = '';
  1160. }
  1161. if (empty($function_info['function']))
  1162. {
  1163. stampa('Problema nel parsing della funzione:');
  1164. var_dump($function_info);
  1165. die($line);
  1166. }
  1167. $flag_keep_sep = 0;
  1168. if (!empty($function_info['args_out']))
  1169. {
  1170. $function_info['list_args_out'] = explode_lines(Array($function_info['args_out']),Array(',',' '),Array());
  1171. }
  1172. else
  1173. {
  1174. $function_info['list_args_out'] = Array();
  1175. }
  1176. if (!empty($function_info['args_in']))
  1177. {
  1178. // drop "&" for referenced arguments
  1179. $function_info['args_in'] = preg_replace('/&/','',$function_info['args_in']);
  1180. // drop default values ("... $a=NULL ..." --> "... $a ..." )
  1181. $function_info['args_in'] = preg_replace('/=[[:space:]]*[^[:space:]]+[[:space:]]*/', ' ',$function_info['args_in']);
  1182. // split input arguments
  1183. $function_info['list_args_in'] = explode_lines(Array($function_info['args_in']),Array(',',' '),Array());
  1184. }
  1185. else
  1186. {
  1187. $function_info['list_args_in'] = Array();
  1188. }
  1189. $function_info['mc_count'] = 1;
  1190. return $function_info;
  1191. } // end function get_function_info
  1192. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1193. function check_unused_functions($lista_functions, $lista_function_names) {
  1194. if (count($lista_functions) == 1)
  1195. {
  1196. $is_script = 1;
  1197. }
  1198. else
  1199. {
  1200. $is_script = 0;
  1201. }
  1202. $unused_fcns = $lista_function_names;
  1203. for ($i_fcn = 0; $i_fcn < count($lista_function_names); $i_fcn++)
  1204. {
  1205. $function_info = $lista_functions[$i_fcn];
  1206. $fcn_tokens = $function_info['list_tokens'];
  1207. $unused_fcns = array_diff($unused_fcns, $fcn_tokens);
  1208. }
  1209. for ($i_fcn = 0; $i_fcn < count($lista_functions); $i_fcn++)
  1210. {
  1211. $function_info = $lista_functions[$i_fcn];
  1212. $fcn_name = $function_info['function'];
  1213. if ( (in_array($fcn_name, $unused_fcns)) && (!empty($fcn_name)) )
  1214. {
  1215. $unused_flag = 1;
  1216. }
  1217. else
  1218. {
  1219. $unused_flag = 0;
  1220. }
  1221. // echo("$fcn_name : $unused_flag<br>"); // !!!
  1222. $function_info['unused_flag'] = $unused_flag;
  1223. $lista_functions[$i_fcn] = $function_info;
  1224. }
  1225. return Array($lista_functions, $is_script);
  1226. } // end function check_unused_functions
  1227. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1228. function normalizza_riga($riga) {
  1229. // elimina commenti
  1230. $ind = strpos($riga,'#');
  1231. if ($ind !== False)
  1232. {
  1233. $riga = substr($riga,0,$ind);
  1234. }
  1235. // drop blank spaces ad the beginning and the end of the line
  1236. $riga = trim($riga);
  1237. return $riga;
  1238. } // end function normalizza_riga
  1239. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  1240. function show_functions($lista_functions, $verbosity) {
  1241. $result = Array();
  1242. $ks_space = str_repeat(' ',8);
  1243. if ($verbosity)
  1244. {
  1245. stampa(' ');
  1246. }
  1247. // List of function for which unused-check is not possible
  1248. // For instance, class constructors and destructors (and all class magic functions) are declared as __construct and
  1249. // __destruct, but the actual use is issued by the "new" or "unset" token
  1250. $list_fcn_unused_skip = Array('__construct', '__destruct', '__call', '__callStatic', '__get', '__set', '__isset',
  1251. '__unset', '__sleep', '__wakeup', '__toString', '__invoke', '__set_state', '__clone');
  1252. for ($i_fcn = 0; $i_fcn < count($lista_functions); $i_fcn++)
  1253. {
  1254. $function_info = $lista_functions[$i_fcn];
  1255. $fcn_name = $function_info['function'];
  1256. $fcn_mc_count = $function_info['mc_count'];
  1257. $fcn_unused_inputs = $function_info['unused_inputs'];
  1258. $fcn_unused_outputs = $function_info['unused_outputs'];
  1259. $fcn_unused_flag = $function_info['unused_flag'];
  1260. // echo "$i_fcn<br><br>"; // !!!
  1261. // var_dump($function_info);
  1262. // echo "<br><br>";
  1263. // check unused output
  1264. if (!empty($fcn_unused_outputs))
  1265. {
  1266. for ($i = 0; $i < count($fcn_unused_outputs); $i++)
  1267. {
  1268. $result = print_msg($result,sprintf("%sFunction return value '%s' appears to never be set.",$ks_space,$fcn_unused_outputs[$i]),$verbosity);
  1269. }
  1270. }
  1271. // McCabe cyclomatic complexity
  1272. if (empty($fcn_name))
  1273. {
  1274. $fcn_msg = '';
  1275. if ($fcn_mc_count > 1)
  1276. {
  1277. $show_line = true;
  1278. }
  1279. else
  1280. {
  1281. $show_line = false;
  1282. }
  1283. }
  1284. else
  1285. {
  1286. $fcn_msg = sprintf("of '%s' ",$fcn_name);
  1287. $show_line = true;
  1288. }
  1289. if ($show_line)
  1290. {
  1291. $result = print_msg($result,sprintf('The McCabe complexity %sis %d.', $fcn_msg, $fcn_mc_count), $verbosity);
  1292. }
  1293. // check declared but unused functions
  1294. $flg_fcn_unused = !in_array($fcn_name,$list_fcn_unused_skip); // check if the unused-check is possible
  1295. if ($flg_fcn_unused)
  1296. {
  1297. $result = manage_unused_function($fcn_name, $fcn_unused_flag, $result, $verbosity);
  1298. }
  1299. // check unused input
  1300. if (!empty($fcn_unused_inputs))
  1301. {
  1302. for ($i = 0; $i < count($fcn_unused_inputs); $i++)
  1303. {
  1304. $result = print_msg($result,sprintf("%sInput variable '%s' appears never to be used.",$ks_space,$fcn_unused_inputs[$i]),$verbosity);
  1305. }
  1306. }
  1307. } // end for
  1308. // end
  1309. return $result;
  1310. } // end function show_functions
  1311. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1312. function manage_unused_function($fcn_name, $fcn_unused_flag, $result, $verbosity) {
  1313. $ks_space = str_repeat(' ',8);
  1314. if ($fcn_unused_flag)
  1315. {
  1316. // unused functions
  1317. $result = print_msg($result, sprintf("%sFunction '%s' appears never to be used.", $ks_space, $fcn_name), $verbosity);
  1318. } // end if
  1319. // end
  1320. return $result;
  1321. } // end function manage_unused_function
  1322. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1323. function print_msg($result, $msg, $verbosity) {
  1324. array_push($result, $msg);
  1325. if ($verbosity)
  1326. {
  1327. $ks = " $msg<br>";
  1328. stampa($ks);
  1329. }
  1330. return $result;
  1331. } // end function print_msg
  1332. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1333. function stampa($ks) {
  1334. $ks = htmlentities($ks);
  1335. echo("$ks<br>\n");
  1336. }
  1337. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1338. function strfind($line,$tag) {
  1339. $ind = strpos($line,$tag);
  1340. if ($ind !== False)
  1341. {
  1342. // $z1 = htmlentities($line);
  1343. // $z2 = htmlentities($tag);
  1344. // echo "'$z2' trovato in '$z1' in posizione $ind!<br>\n";
  1345. }
  1346. return $ind;
  1347. }
  1348. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1349. function fcn_strpos($line,$sep) {
  1350. $temp = preg_split("/$sep/", $line, -1, PREG_SPLIT_OFFSET_CAPTURE);
  1351. $ind = false;
  1352. $first = true;
  1353. for ($id = 1;$id < count($temp); $id++)
  1354. {
  1355. $substr = $temp[$id];
  1356. $val = $substr[1]-strlen($sep);
  1357. if ($first)
  1358. {
  1359. $first = false;
  1360. $ind = Array($val);
  1361. }
  1362. else
  1363. {
  1364. array_push($ind,$val);
  1365. }
  1366. }
  1367. return $ind;
  1368. } // end function fcn_strpos
  1369. ?>