/** * @param array * @param array * @param array * @return int * */ public function _exec(array $argv, array $envp, array $redirections) { $descriptors = $this->descriptors; foreach ($redirections as $n => $redirection) { if (is_array($redirection)) { if (($handle = @fopen($redirection[1], $redirection[0])) === FALSE) { throw new Error('cannot open file ' . $redirection[1]); } $descriptors[$n] = $handle; } else { assert(is_int($redirection)); if (!isset($descriptors[$redirection])) { throw new Error('bad file descriptor ' . $redirection); } $descriptors[$n] = $descriptors[$redirection]; } } // BREAK if ($argv[0] === 'break') { $n = 1; if (isset($argv[1])) { $n = intval($argv[1]); } throw new BuiltinBreak($n); // COLON } else { if ($argv[0] === ':') { $this->variables['?'] = 0; } else { if ($argv[0] === 'continue') { $n = 1; if (isset($argv[1])) { $n = intval($argv[1]); } throw new BuiltinContinue($n); // DOT } else { if ($argv[0] === '.') { if (!(isset($argv[1]) && ($contents = file_get_contents($argv[1])) !== FALSE)) { if (!isset($argv[1])) { throw new Error('.: no file given'); } else { throw new Error('.: cannot read file'); } } $saved_can_read = $this->can_read; $this->can_read = FALSE; $saved_tokens = $this->tokens; $this->tokens = $this->tokenize($contents); $saved_descriptors = $this->descriptors; $this->descriptors = $descriptors; try { $this->interpretMoreCommands(); } catch (BuiltinReturn $r) { $this->variables['?'] = $r->getExitStatus(); } $this->can_read = $saved_can_read; $this->tokens = $saved_tokens; $this->descriptors = $saved_descriptors; // EVAL } else { if ($argv[0] === 'eval') { $newtokens = $this->tokenize(implode(' ', array_slice($argv, 1))); if (end($newtokens) === ';') { array_pop($newtokens); } $this->tokens = array_merge(array(';'), $newtokens, $this->tokens); // EXEC } else { if ($argv[0] === 'exec') { if (count($argv) > 1) { fwrite($descriptors[2], "exec: only file descriptors handling implemented\n"); $this->variables['?'] = 255; } else { $this->descriptors = $descriptors; $this->variables['?'] = 0; } // EXIT } else { if ($argv[0] === 'exit') { $n = 0; if (isset($argv[1])) { $n = intval($argv[1]); } throw new BuiltinExit($n); // EXPORT } else { if ($argv[0] === 'export') { if (isset($argv[1]) && $argv[1] === '-p') { foreach ($this->exported as $exported => $_) { if (isset($this->variables[$exported])) { fprintf($descriptors[1], "export %s='%s'\n", $exported, $this->variables[$exported]); } else { fprintf($descriptors[1], "export %s\n", $exported); } } } else { foreach (array_slice($argv, 1) as $variable) { if (strpos($variable, '=') !== FALSE) { list($variable, $value) = explode('=', $variable, 2); $this->variables[$variable] = $value; } $this->exported[$variable] = TRUE; } } $this->variables['?'] = 0; // READONLY } else { if ($argv[0] === 'readonly') { fwrite($descriptors[2], "readonly: currently not supported\n"); $this->variables['?'] = 255; // RETURN } else { if ($argv[0] === 'return') { $n = 0; if (isset($argv[1])) { $n = intval($argv[1]); } throw new BuiltinReturn($n); // SET } else { if ($argv[0] === 'set') { fwrite($descriptors[2], "set: currently not supported\n"); $this->variables['?'] = 255; // SHIFT } else { if ($argv[0] === 'shift') { $n = 1; if (isset($argv[1])) { $n = intval($argv[1]); } for ($i = 1, $c = count($this->argv); $i < $c; ++$i) { unset($this->variables[$i]); } foreach (array_slice($this->argv, count($this->argv) - $this->variables['#'] + $n) as $i => $arg) { $this->variables[$i + 1] = $arg; } $this->variables['#'] = $this->variables['#'] - $n; $this->variables['?'] = 0; // TIMES } else { if ($argv[0] === 'times') { fwrite($descriptors[2], "times: currently not supported\n"); $this->variables['?'] = 255; // TRAP } else { if ($argv[0] === 'trap') { fwrite($descriptors[2], "trap: currently not supported\n"); $this->variables['?'] = 255; // UNSET } else { if ($argv[0] === 'unset') { if (count($argv) < 2) { fwrite($descriptors[2], "unset: [-fv] name...\n"); $this->variables['?'] = 255; } else { if ($argv[1] === '-f') { foreach (array_slice($argv, 2) as $function) { unset($this->functions[$function]); } } else { $variables = array_slice($argv, 1); if ($argv[1] === '-v') { $variables = array_slice($argv, 2); } foreach ($variables as $variable) { unset($this->variables[$variable]); } } $this->variables['?'] = 0; } // FUNCTION? } else { if (isset($this->functions[$argv[0]])) { $saved_argv = $this->argv; $this->argv = $argv; $saved_envp = $this->envp; $this->envp = $envp; $saved_variables = $this->variables; $this->variables = array(); $this->variables['#'] = count($argv) - 1; foreach ($argv as $k => $v) { $this->variables[$k] = $v; } $saved_can_read = $this->can_read; $this->can_read = FALSE; $saved_tokens = $this->tokens; $this->tokens = $this->functions[$argv[0]]; $this->interpretMoreCommands(); $saved_variables['?'] = isset($this->variables['?']) ? $this->variables['?'] : 0; $this->argv = $saved_argv; $this->envp = $saved_envp; $this->variables = $saved_variables; $this->can_read = $saved_can_read; $this->tokens = $saved_tokens; return $this->variables['?']; // EXTERNAL EXECUTOR } else { $this->variables['?'] = $this->executor->exec($argv, $envp, $descriptors); if ($this->variables['?'] === 127 && $this->interactive) { fwrite($this->stderr, "sh: " . $argv[0] . " not found\r\n"); } return $this->variables['?']; } } } } } } } } } } } } } } } } }