dojo = $dojo; $this->setFile($file); } public function getFile(){ return $this->file; } public function setFile($file){ $this->file = $file; } public function getFunctionDeclarations(){ $lines = $this->getCode(); $end = array(0, 0); $matches = preg_grep('%function%', $lines); $last_line = 0; foreach($matches as $line_number => $line){ if($line_number < $last_line){ continue; } if(preg_match('%(\bfunction\s+[a-zA-Z0-9_.$]+\b\s*\(|\b[a-zA-Z_.$][\w.$]*(?:\.[a-zA-Z_.$][\w.$]|\["[^"]+"\])*\s*=\s*(new\s*)?function\s*\()%', $line, $match)) { $declaration = new DojoFunctionDeclare($this); $declaration->setStart($line_number, strpos($line, $match[0])); $end = $declaration->build(); $last_line = $end[0]; $this->declarations[$declaration->getFunctionName()][] = $declaration; } } return $this->declarations; } /** * Searches the file for the format: (function(){})(); */ public function getExecutedFunctions(){ if ($this->executions) { return $this->executions; } $lines = $this->getCode(); $matches = preg_grep('%function%', $lines); $last_line = 0; foreach ($matches as $line_number => $line) { if ($line_number < $last_line) { continue; } if (preg_match('%(?:([a-zA-Z_.$][\w.$]*)\s*=\s*)?(?:new\s*)?\(\s*function\s*\(\s*\)\s*{%', $line, $match)) { $execution = new DojoExecutedFunction($this); $execution->setAnonymous(true); if ($match[1]) { $execution->setFunctionName($match[1]); } $execution->setStart($line_number, strpos($line, $match[0])); $end = $execution->build(); if ($end) { $last_line = $end[0]; $this->executions[] = $execution; } } } return $this->executions; } /** * Use this to find everywhere in the code a function is called. * * @param unknown_type $name */ public function getFunctionCalls($name){ if ($this->calls[$name]) { return $this->calls[$name]; } $this->calls[$name] = array(); $lines = $this->getCode(); $lines = preg_grep('%\b' . preg_quote($name) . '\s*\(%', $lines); foreach ($lines as $line_number => $line) { $position = strpos($line, $name); if ($line_number < $last_line_number || ($line_number == $last_line_number && $position < $last_position)) { continue; } $call = new DojoFunctionCall($this, $line_number, $position); list($last_line_number, $last_position) = $call->build(); $this->calls[$name][] = $call; } return $this->calls[$name]; } public function removeCodeFrom($lines){ $keys = array_keys($lines); $first = array_shift($keys); $last = array_pop($keys); for($i = $first; $i <= $last; $i++) { $line = $lines[$i]; if (preg_match('%function\s*\([^)]*\)\s*{%', $line, $match, PREG_OFFSET_CAPTURE)) { $declaration = new DojoFunctionDeclare($this, $i, $match[0][1]); list($i, ) = $declaration->build(); $lines = $declaration->removeCodeFrom($lines); } elseif (preg_match('%^.*(with|switch)\s*\([^(]*\)\s*{%', $line, $match)) { $with_lines = Text::chop($lines, $i, strlen($match[0]) - 1, null, null, true); list($end_line, $end_pos) = Text::findTermination($with_lines, '}', '{}()[]'); for ($j = $i; $j <= $end_line; $j++) { $line = $lines[$j]; if ($j == $i) { $lines[$j] = Text::blankOutAt($line, strlen($match[0]) - 1); } elseif ($j == $end_line) { $lines[$j] = Text::blankOutAt($line, 0, $end_pos); } else { $lines[$j] = Text::blankOut($line, $line); } } } } return $lines; } public function getAliases(){ if($this->aliases){ return $this->aliases; } return $this->aliases; } public function getObjects(){ if ($this->objects) { return $this->objects; } $lines = $this->getCode(); foreach ($lines as $line_number => $line) { if ($line_number < $end_line_number) { continue; } if (preg_match('%\b([a-zA-Z0-9_.$]+)\s*=\s*{%', $line, $match, PREG_OFFSET_CAPTURE)) { $object = new DojoObject($this, $line_number, $match[0][1] + strlen($match[0][0]) - 1); $object->setName($match[1][0]); list($end_line_number, $end_position) = $object->build(); $this->objects[] = $object; } } return $this->objects; } public function getSource(){ if ($this->source) { return $this->source; } $lines = preg_split("%\r?\n%", file_get_contents($this->dojo->getDir() . $this->file)); $lines[] = ''; $in_comment = false; foreach ($lines as $line_number => $line) { $pos = 0; $found = true; while ($found) { $found = false; if (!$in_comment) { if (preg_match('%/\*={5,}%', $line, $match, PREG_OFFSET_CAPTURE, $pos)) { $line = $lines[$line_number] = Text::blankOut($match[0][0], $line); $found = true; $in_comment = true; $pos = $match[0][1] + strlen($match[0][0]); } } elseif (preg_match('%={5,}\*/%', $line, $match, PREG_OFFSET_CAPTURE, $pos)) { $line = $lines[$line_number] = Text::blankOut($match[0][0], $line); $found = true; $in_comment = false; $pos = $match[0][1] + strlen($match[0][0]); } } } return $this->source = $lines; } /** * Removes comments and strings, preserving layout */ public function getCode(){ if ($this->code) { return $this->code; } $lines = $this->getSource(); $in_comment = false; foreach ($lines as $line_number => $line) { //print "$line_number $line\n"; if ($in_comment !== false) { if (preg_match('%^.*\*/%U', $line, $match)) { $line = Text::blankOut($match[0], $line); $in_comment = false; } else { $line = Text::blankOut($line, $line); } } $position = 0; $in_single_string = false; $in_double_string = false; $in_regex = false; for ($i = 0; $i < 100; $i++) { $matches = array(); if ($in_comment === false && $in_regex === false && $in_single_string === false && $in_double_string === false) { // Match the start of a line, the word return or case, or a character in: =([{,|&;:? // Followed by zero or more spaces // Followed by a forward slash // Not followed by another forward slash if (preg_match('%(?:^|\breturn\b|[=([{,|&;:?])\s*/(?!/)%', $line, $match, PREG_OFFSET_CAPTURE, $position)) { $matches[$match[0][1] + strlen($match[0][0]) - 1] = '/'; } if (preg_match('%(?:^|\b(?:case|return)\b|[=([{,|&;:?+])\s*(["\'])%', $line, $match, PREG_OFFSET_CAPTURE, $position)) { $matches[$match[0][1] + strlen($match[0][0]) - 1] = $match[1][0]; } if (($pos = strpos($line, '//', $position)) !== false) { $matches[$pos] = '//'; } if (($pos = strpos($line, '/*', $position)) !== false) { $matches[$pos] = '/*'; } } elseif ($in_regex !== false) { // A / not preceeded by a / or \ // Followed by 0 or more spaces // Followed by one of the characters: img.)]},|&;: or end of line if (preg_match('%(? $match) { if ($in_comment === false && $in_regex === false && $in_single_string === false && $in_double_string === false) { if ($match == '"') { $in_double_string = $position; break; } elseif ($match == "'") { $in_single_string = $position; break; } elseif ($match == '/') { $in_regex = $position; break; } elseif ($match == '//') { $line = Text::blankOutAt($line, $position); break; } elseif ($match == '/*') { $in_comment = $position; ++$position; break; } } elseif ($in_double_string !== false && $match == '"') { $line = Text::blankOutAt($line, $in_double_string + 1, $position - 1); $in_double_string = false; } elseif ($in_single_string !== false && $match == "'") { $line = Text::blankOutAt($line, $in_single_string + 1, $position - 1); $in_single_string = false; } elseif ($in_regex !== false && $match == '/') { $line = Text::blankOutAt($line, $in_regex + 1, $position - 1); $in_regex = false; } elseif ($in_comment !== false && $match == '*/') { $line = Text::blankOutAt($line, $in_comment + 2, $position - 1); $in_comment = false; } } ++$position; } if($i == 500){ die("\$i should not reach 500: $line"); } if ($in_comment !== false && !empty($line)) { $line = Text::blankOutAt($line, $in_comment); $in_comment = 0; } //print "$line_number $line\n"; $lines[$line_number] = $line; } return $this->code = $lines; } /** * After all calls are done, return what's left */ public function getExternalVariables(){ $lines = $this->getCode(); foreach ($this->objects as $pobject) { foreach ($pobject->declarations as $declaration) { $lines = Text::blankOutAtPositions($lines, $declaration->start[0], $declaration->start[1], $declaration->end[0], $declaration->end[1]); } } foreach($this->declarations as $declarations){ foreach ($declarations as $declaration) { $lines = Text::blankOutAtPositions($lines, $declaration->start[0], $declaration->start[1], $declaration->end[0], $declaration->end[1]); } } foreach($this->calls as $call_name => $calls){ foreach($calls as $call){ $lines = Text::blankOutAtPositions($lines, $call->start[0], $call->start[1], $call->end[0], $call->end[1]); } } foreach($this->executions as $execution){ $lines = Text::blankOutAtPositions($lines, $execution->start[0], $execution->start[1], $execution->end[0], $execution->end[1]); } $variables = array(); foreach (preg_grep('%=%', $lines) as $line_number => $line) { if (preg_match('%\b([a-zA-Z_.$][\w.$]*)\s*=(?!=)\s*(function\s*\()?%', $line, $match)) { $variables[] = $match[1]; } } return $variables; } /** * Remove items from the passed objects if they are inside of existing calls or declarations */ public function removeSwallowed(&$objects){ $swallowed = array(); foreach ($objects as $i => $object) { foreach ($this->objects as $pobject) { if (($object->start[0] > $pobject->start[0] || ($object->start[0] == $pobject->start[0] && $object->start[1] > $pobject->start[1])) && ($object->end[0] < $pobject->end[0] || ($object->end[0] == $pobject->end[0] && $object->end[1] < $pobject->end[1]))) { if ($objects[$i]) { $swallowed[] = $objects[$i]; } unset($objects[$i]); } foreach ($pobject->declarations as $declaration) { if (($object->start[0] > $declaration->start[0] || ($object->start[0] == $declaration->start[0] && $object->start[1] > $declaration->start[1])) && ($object->end[0] < $declaration->end[0] || ($object->end[0] == $declaration->end[0] && $object->end[1] < $declaration->end[1]))) { if ($objects[$i]) { $swallowed[] = $objects[$i]; } unset($objects[$i]); } } } foreach($this->declarations as $declarations){ foreach ($declarations as $declaration) { if(($object->start[0] > $declaration->start[0] || ($object->start[0] == $declaration->start[0] && $object->start[1] > $declaration->start[1])) && ($object->end[0] < $declaration->end[0] || ($object->end[0] == $declaration->end[0] && $object->end[1] < $declaration->end[1]))) { if ($objects[$i]) { $swallowed[] = $objects[$i]; } unset($objects[$i]); } } } foreach($this->calls as $call_name => $calls){ foreach($calls as $call){ if(($object->start[0] > $call->start[0] || ($object->start[0] == $call->start[0] && $object->start[1] > $call->start[1])) && ($object->end[0] < $call->end[0] || ($object->end[0] == $call->end[0] && $object->end[1] < $call->end[1]))) { if ($objects[$i]) { $swallowed[] = $objects[$i]; } unset($objects[$i]); } } } foreach($this->executions as $execution){ if(($object->start[0] > $execution->start[0] || ($object->start[0] == $execution->start[0] && $object->start[1] > $execution->start[1])) && ($object->end[0] < $execution->end[0] || ($object->end[0] == $execution->end[0] && $object->end[1] < $execution->end[1]))) { if ($objects[$i]) { $swallowed[] = $objects[$i]; } unset($objects[$i]); } } } return $swallowed; } public function getPackageName(){ $name = ''; if(file_exists('modules/' . $this->dojo->namespace . '.module')){ include_once('modules/' . $this->dojo->namespace . '.module'); $name = call_user_func($this->dojo->namespace . '_package_name', $this->dojo->namespace, $this->file); } if($name) return $name; return 'null'; } public function getResourceName(){ $name = ''; if(file_exists('modules/' . $this->dojo->namespace . '.module')){ include_once('modules/' . $this->dojo->namespace . '.module'); $name = call_user_func($this->dojo->namespace . '_resource_name', $this->dojo->namespace, $this->file); } if($name) return $name; return 'null'; } } ?>