root/lang/php/misc/phsh

Revision 11597, 5.0 kB (checked in by bto, 4 years ago)

ライブラリとして呼ばれた場合は実行しないようにした

  • Property svn:executable set to *
Line 
1#!/usr/bin/env php
2<?php
3// disable E_STRICT
4if (defined('E_STRICT')) {
5    ini_set('error_reporting', ini_get('error_reporting')&~E_STRICT);
6}
7
8require_once 'Console/Getopt.php';
9
10
11class PHSH
12{
13    var $options = array();
14
15    function phsh()
16    {
17        $this->initialize();
18    }
19
20    function initialize()
21    {
22        $this->options = array(
23            'help'         => false,
24            'history_file' => "{$_ENV['HOME']}/.phsh_history",
25            'login'        => false,
26            'login_file'   => "{$_ENV['HOME']}/.phsh_login",
27            'rc_file'      => "{$_ENV['HOME']}/.phshrc");
28    }
29
30    function &addHistory(&$line)
31    {
32        static $last_line = '';
33
34        if ($line != $last_line) {
35            readline_add_history($line);
36            readline_write_history($this->options['history_file']);
37            $last_line = $line;
38        }
39
40        return $line;
41    }
42
43    function executeShell($command_line = null)
44    {
45        $pid = pcntl_fork();
46        if ($pid == 0) {
47            $path = '/bin/sh';
48            $args = array();
49            if ($command_line) {
50                $args = array('-c', $command_line);
51            }
52            exit(pcntl_exec($path, $args));
53        }
54        return pcntl_waitpid($pid, $status);
55    }
56
57    function getProgramName()
58    {
59        $argv = Console_Getopt::readPHPArgv();
60        return basename($argv[0]);
61    }
62
63    function isCallable(&$line)
64    {
65        $regex = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
66        return preg_match($regex, $line, $matches) && !is_callable($matches[0]);
67    }
68
69    function main()
70    {
71        if (PEAR::isError($this->parseOptions())) {
72            fwrite(STDERR, "Invalid options\n");
73            $this->usage(1);
74        }
75
76        if ($this->options['help']) {
77            $this->usage();
78        }
79
80        readline_completion_function('__phshCompletion');
81
82        return $this->mainLoop();
83    }
84
85    function mainLoop()
86    {
87        if ($this->options['login'] && file_exists($this->options['login_file'])) {
88            include($this->options['login_file']);
89        }
90
91        if (file_exists($this->options['rc_file'])) {
92            include($this->options['rc_file']);
93        }
94
95        readline_read_history($this->options['history_file']);
96        $__phsh = array();
97        @ob_flush();
98
99        while (true) {
100            $__phsh['line'] = $this->modifyCommandLine($this->addHistory(
101                readline('<?php ')));
102            if ($__phsh['line']) {
103                $this->printResult(eval($__phsh['line']));
104            }
105            @ob_flush();
106        }
107    }
108
109    function &modifyCommandLine(&$line)
110    {
111        $new_line = trim($line);
112        if (!$new_line) {
113            return $new_line;
114        }
115
116        if ($new_line[0] == '#') {
117            $this->executeShell(trim(substr($new_line, 1)));
118            $new_line = '';
119        } else if (substr($new_line, -2) == '?>') {
120            $new_line = 'exit;';
121        } else if ($this->isCallable($new_line)) {
122            $new_line = "{$new_line}; return;";
123        } else {
124            $new_line = "return {$new_line};";
125        }
126
127        return $new_line;
128    }
129
130    function &parseOptions()
131    {
132        $console_getopt = new Console_Getopt;
133        $longoptions = array('help', 'login');
134        $options = array();
135        $shortoptions = 'hl';
136
137        $result = $console_getopt->getopt(
138            $console_getopt->readPHPArgv(), $shortoptions, $longoptions);
139        if (PEAR::isError($result)) {
140            return $result;
141        }
142
143        $program_name = $this->getProgramName();
144        if ($program_name[0] == '-') {
145            $options['login'] = true;
146        }
147
148        foreach ($result[0] as $option) {
149            switch ($option[0]) {
150            case 'h':
151            case '--help':
152                $options['help'] = true;
153                break;
154            case 'l':
155            case '--login':
156                $options['login'] = true;
157                break;
158            }
159        }
160
161        $this->options = array_merge($this->options, $options);
162        return $this->options;
163    }
164
165    function printResult($result)
166    {
167        var_dump($result);
168        return true;
169    }
170
171    function usage($status = 0)
172    {
173        $program_name = $this->getProgramName();
174        $message = <<< EOS
175Usage: {$program_name} [options]
176    -h, --help         show this message
177    -l, --login        works as a login shell
178EOS;
179        fwrite(STDERR, $message."\n");
180        exit($status);
181    }
182
183    /******************
184     *                *
185     * static methods *
186     *                *
187     ******************/
188    function completion($line, $pos, $cursor)
189    {
190        $functions = get_defined_functions();
191        return array_merge(
192            $functions['internal'], $functions['user'],
193            array_keys(get_defined_constants()));
194    }
195}
196
197function __phshCompletion($line, $position, $cursor)
198{
199    return PHSH::completion($line, $position, $cursor);
200}
201
202// immediately return while required as a library
203if (debug_backtrace()) {
204    return;
205}
206
207$phsh = new PHSH;
208return $phsh->main();
Note: See TracBrowser for help on using the browser.