]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/3rdParty/PhpShell/PHP/Shell.php
8012475e6ffe7d8e3f19511d52b325a09eb10fc1
[bacula/bacula] / gui / baculum / framework / 3rdParty / PhpShell / PHP / Shell.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4 /*
5 (c) 2006 Jan Kneschke <jan@kneschke.de>
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy of
8 this software and associated documentation files (the "Software"), to deal in
9 the Software without restriction, including without limitation the rights to
10 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is furnished to do
12 so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 */
25
26 /**
27 * A interactive PHP Shell
28 *
29 * The more I work with other languages like python and ruby I like their way how they
30 * work on problems. While PHP is very forgiving on errors, it is weak on the debugging
31 * side. It was missing a simple to use interactive shell for years. Python and Ruby have
32 * their ipython and iruby shell which give you a direct way to interact with the objects.
33 * No need to write a script and execute it afterwards.
34 *
35 * Starting the Shell:
36 *
37 * The package contains a shell wrapper for windows and unix:
38 * <pre>
39 * sh>  php-shell.sh
40 * win> php-shell
41 * </pre>
42 *
43 * Both are calling the wrapper script <code>php -q php-shell-cmd.php</code>
44 *
45 * Inline Help
46 *
47 * <pre>
48 * PHP-Shell - Version 0.2.0, with readline() support
49 * (c) 2006, Jan Kneschke <jan@kneschke.de>
50 *
51 * >> use '?' to open the inline help
52 *
53 * >> ?
54 * "inline help for the PHP-shell
55 *
56 *   >> ?
57 *     print this help
58 *   >> ? <topic>
59 *     get the doccomment for a class, method, property or function
60 *   >> p <var>
61 *     execute a verbose print (if implemented)
62 *   >> quit
63 *     leave shell
64 * "
65 * >> ? PHP_Shell
66 * </pre>
67 * Alternatives
68 *
69 * - http://david.acz.org/phpa/
70 * - http://www.hping.org/phpinteractive/
71 * - the embedded interactive php-shell: $ php -a
72 *
73 * @package PHP
74 */
75
76 /**
77 * PHP_Shell
78 *
79 * a interactive PHP Shell with tab-completion and history
80 * it can catch FATAL errors before executing the code
81 *
82 * Extensions are provided through three side-classes:
83 *
84 * - PHP_Shell_Commands
85 * - PHP_Shell_Options
86 * - PHP_Shell_Extensions
87 *
88 * @package PHP
89 */
90
91 require_once(dirname(__FILE__)."/Shell/Commands.php");
92 require_once(dirname(__FILE__)."/Shell/Options.php"); /* for the tab-complete */
93
94 class PHP_Shell {
95     /**
96     * current code-buffer
97     * @var string
98     */
99     protected $code;
100
101     /**
102     * set if readline support is enabled
103     * @var bool
104     */
105     protected $have_readline;
106
107     /**
108     * current version of the class
109     * @var string
110     */
111     protected $version = '0.3.1';
112
113     /**
114     *
115     */
116     protected $stdin;
117
118     protected $code_buffer;
119
120         public $has_semicolon=false;
121
122     /**
123     * init the shell and change if readline support is available
124     */
125     public function __construct() {
126         $this->code = '';
127
128         $this->stdin = null;
129
130         $this->have_readline = function_exists('readline');
131
132         if ($this->have_readline) {
133             readline_completion_function('__shell_readline_complete');
134         }
135
136         $this->use_readline = true;
137
138         $cmd = PHP_Shell_Commands::getInstance();
139
140         $cmd->registerCommand('#^quit$#', $this, 'cmdQuit', 'quit', 'leaves the shell');
141         $cmd->registerCommand('#^\?$#', $this, 'cmdHelp', '?', 'show this help');
142         $cmd->registerCommand('#^\?\s+license$#', $this, 'cmdLicense', '? license', 'show license of the shell');
143     }
144
145
146     /**
147     * parse the PHP code
148     *
149     * we parse before we eval() the code to
150     * - fetch fatal errors before they come up
151     * - know about where we have to wait for closing braces
152     *
153     * @return int 0 if a executable statement is in the code-buffer, non-zero otherwise
154     */
155     public function parse() {
156         ## remove empty lines
157         if (trim($this->code) == '') return 1;
158
159         $t = token_get_all('<?php '.$this->code.' ?>');
160
161         $need_semicolon = 1; /* do we need a semicolon to complete the statement ? */
162         $need_return = 1;    /* can we prepend a return to the eval-string ? */
163         $open_comment = 0;   /* a open multi-line comment */
164         $eval = '';          /* code to be eval()'ed later */
165         $braces = array();   /* to track if we need more closing braces */
166
167         $methods = array();  /* to track duplicate methods in a class declaration */
168         $ts = array();       /* tokens without whitespaces */
169
170         foreach ($t as $ndx => $token) {
171             if (is_array($token)) {
172                 $ignore = 0;
173
174                 switch($token[0]) {
175                 case T_WHITESPACE:
176                 case T_OPEN_TAG:
177                 case T_CLOSE_TAG:
178                     $ignore = 1;
179                     break;
180                 case T_FOREACH:
181                 case T_DO:
182                 case T_WHILE:
183                 case T_FOR:
184
185                 case T_IF:
186                 case T_RETURN:
187
188                 case T_CLASS:
189                 case T_FUNCTION:
190                 case T_INTERFACE:
191
192                 case T_PRINT:
193                 case T_ECHO:
194
195                 case T_COMMENT:
196                 case T_UNSET:
197
198                 case T_INCLUDE:
199                 case T_REQUIRE:
200                 case T_INCLUDE_ONCE:
201                 case T_REQUIRE_ONCE:
202                 case T_TRY:
203                 case T_SWITCH:
204                 case T_DEFAULT:
205                 case T_CASE:
206                 case T_BREAK:
207                 case T_DOC_COMMENT:
208                     $need_return = 0;
209                     break;
210                 case T_EMPTY:
211                 case T_ISSET:
212                 case T_EVAL:
213                 case T_EXIT:
214
215                 case T_VARIABLE:
216                 case T_STRING:
217                 case T_NEW:
218                 case T_EXTENDS:
219                 case T_IMPLEMENTS:
220                 case T_OBJECT_OPERATOR:
221                 case T_DOUBLE_COLON:
222                 case T_INSTANCEOF:
223
224                 case T_CATCH:
225                 case T_THROW:
226
227                 case T_ELSE:
228                 case T_AS:
229                 case T_LNUMBER:
230                 case T_DNUMBER:
231                 case T_CONSTANT_ENCAPSED_STRING:
232                 case T_ENCAPSED_AND_WHITESPACE:
233                 case T_CHARACTER:
234                 case T_ARRAY:
235                 case T_DOUBLE_ARROW:
236
237                 case T_CONST:
238                 case T_PUBLIC:
239                 case T_PROTECTED:
240                 case T_PRIVATE:
241                 case T_ABSTRACT:
242                 case T_STATIC:
243                 case T_VAR:
244
245                 case T_INC:
246                 case T_DEC:
247                 case T_SL:
248                 case T_SL_EQUAL:
249                 case T_SR:
250                 case T_SR_EQUAL:
251
252                 case T_IS_EQUAL:
253                 case T_IS_IDENTICAL:
254                 case T_IS_GREATER_OR_EQUAL:
255                 case T_IS_SMALLER_OR_EQUAL:
256
257                 case T_BOOLEAN_OR:
258                 case T_LOGICAL_OR:
259                 case T_BOOLEAN_AND:
260                 case T_LOGICAL_AND:
261                 case T_LOGICAL_XOR:
262                 case T_MINUS_EQUAL:
263                 case T_PLUS_EQUAL:
264                 case T_MUL_EQUAL:
265                 case T_DIV_EQUAL:
266                 case T_MOD_EQUAL:
267                 case T_XOR_EQUAL:
268                 case T_AND_EQUAL:
269                 case T_OR_EQUAL:
270
271                 case T_FUNC_C:
272                 case T_CLASS_C:
273                 case T_LINE:
274                 case T_FILE:
275
276                 case T_BOOL_CAST:
277                 case T_INT_CAST:
278                 case T_STRING_CAST:
279
280                     /* just go on */
281                     break;
282                 default:
283                     /* debug unknown tags*/
284                     error_log(sprintf("unknown tag: %d (%s): %s".PHP_EOL, $token[0], token_name($token[0]), $token[1]));
285
286                     break;
287                 }
288                 if (!$ignore) {
289                     $eval .= $token[1]." ";
290                     $ts[] = array("token" => $token[0], "value" => $token[1]);
291                 }
292             } else {
293                 $ts[] = array("token" => $token, "value" => '');
294
295                 $last = count($ts) - 1;
296
297                 switch ($token) {
298                 case '(':
299                     /* walk backwards through the tokens */
300
301                     if ($last >= 4 &&
302                         $ts[$last - 1]['token'] == T_STRING &&
303                         $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
304                         $ts[$last - 3]['token'] == ')' ) {
305                         /* func()->method()
306                         *
307                         * we can't know what func() is return, so we can't
308                         * say if the method() exists or not
309                         *
310                         */
311                     } else if ($last >= 3 &&
312                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
313                         $ts[0]['token'] != T_ABSTRACT && /* if we are not in a class definition */
314                         $ts[1]['token'] != T_CLASS && /* if we are not in a class definition */
315                         $ts[$last - 1]['token'] == T_STRING &&
316                         $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
317                         $ts[$last - 3]['token'] == T_VARIABLE ) {
318
319                         /* $object->method( */
320
321                         /* catch (Exception $e) does not set $e in $GLOBALS[] */
322                         $in_catch = 0;
323
324                         foreach ($ts as $v) {
325                             if ($v['token'] == T_CATCH) {
326                                 $in_catch = 1;
327                             }
328                         }
329
330                         if (!$in_catch) {
331                             /* $object has to exist and has to be a object */
332                             $objname = $ts[$last - 3]['value'];
333
334                             if (!isset($GLOBALS[ltrim($objname, '$')])) {
335                                 throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
336                             }
337                             $object = $GLOBALS[ltrim($objname, '$')];
338
339                             if (!is_object($object)) {
340                                 throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
341                             }
342
343                             $method = $ts[$last - 1]['value'];
344
345                             /* obj */
346
347                             if (!method_exists($object, $method)) {
348                                 throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'",
349                                     $objname, get_class($object), $method));
350                             }
351                         }
352                     } else if ($last >= 3 &&
353                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
354                         $ts[$last - 1]['token'] == T_VARIABLE &&
355                         $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
356                         $ts[$last - 3]['token'] == T_VARIABLE ) {
357
358                         /* $object->$method( */
359
360                         /* $object has to exist and has to be a object */
361                         $objname = $ts[$last - 3]['value'];
362
363                         if (!isset($GLOBALS[ltrim($objname, '$')])) {
364                             throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
365                         }
366                         $object = $GLOBALS[ltrim($objname, '$')];
367
368                         if (!is_object($object)) {
369                             throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
370                         }
371
372                         $methodname = $ts[$last - 1]['value'];
373
374                         if (!isset($GLOBALS[ltrim($methodname, '$')])) {
375                             throw new Exception(sprintf('Variable \'%s\' is not set', $methodname));
376                         }
377                         $method = $GLOBALS[ltrim($methodname, '$')];
378
379                         /* obj */
380
381                         if (!method_exists($object, $method)) {
382                             throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'",
383                                 $objname, get_class($object), $method));
384                         }
385
386                     } else if ($last >= 6 &&
387                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
388                         $ts[$last - 1]['token'] == T_STRING &&
389                         $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
390                         $ts[$last - 3]['token'] == ']' &&
391                             /* might be anything as index */
392                         $ts[$last - 5]['token'] == '[' &&
393                         $ts[$last - 6]['token'] == T_VARIABLE ) {
394
395                         /* $object[...]->method( */
396
397                         /* $object has to exist and has to be a object */
398                         $objname = $ts[$last - 6]['value'];
399
400                         if (!isset($GLOBALS[ltrim($objname, '$')])) {
401                             throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
402                         }
403                         $array = $GLOBALS[ltrim($objname, '$')];
404
405                         if (!is_array($array)) {
406                             throw new Exception(sprintf('Variable \'%s\' is not a array', $objname));
407                         }
408
409                         $andx = $ts[$last - 4]['value'];
410
411                         if (!isset($array[$andx])) {
412                             throw new Exception(sprintf('%s[\'%s\'] is not set', $objname, $andx));
413                         }
414
415                         $object = $array[$andx];
416
417                         if (!is_object($object)) {
418                             throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
419                         }
420
421                         $method = $ts[$last - 1]['value'];
422
423                         /* obj */
424
425                         if (!method_exists($object, $method)) {
426                             throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'",
427                                 $objname, get_class($object), $method));
428                         }
429
430                     } else if ($last >= 3 &&
431                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
432                         $ts[$last - 1]['token'] == T_STRING &&
433                         $ts[$last - 2]['token'] == T_DOUBLE_COLON &&
434                         $ts[$last - 3]['token'] == T_STRING ) {
435
436                         /* Class::method() */
437
438                         /* $object has to exist and has to be a object */
439                         $classname = $ts[$last - 3]['value'];
440
441                         if (!class_exists($classname)) {
442                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
443                         }
444
445                         $method = $ts[$last - 1]['value'];
446
447                         if (!in_array($method, get_class_methods($classname))) {
448                             throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'",
449                                 $classname, $method));
450                         }
451                     } else if ($last >= 3 &&
452                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
453                         $ts[$last - 1]['token'] == T_VARIABLE &&
454                         $ts[$last - 2]['token'] == T_DOUBLE_COLON &&
455                         $ts[$last - 3]['token'] == T_STRING ) {
456
457                         /* $var::method() */
458
459                         /* $object has to exist and has to be a object */
460                         $classname = $ts[$last - 3]['value'];
461
462                         if (!class_exists($classname)) {
463                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
464                         }
465
466                         $methodname = $ts[$last - 1]['value'];
467
468                         if (!isset($GLOBALS[ltrim($methodname, '$')])) {
469                             throw new Exception(sprintf('Variable \'%s\' is not set', $methodname));
470                         }
471                         $method = $GLOBALS[ltrim($methodname, '$')];
472
473                         if (!in_array($method, get_class_methods($classname))) {
474                             throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'",
475                                 $classname, $method));
476                         }
477
478                     } else if ($last >= 2 &&
479                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
480                         $ts[$last - 1]['token'] == T_STRING &&
481                         $ts[$last - 2]['token'] == T_NEW ) {
482
483                         /* new Class() */
484
485                         /* don't care about this in a class ... { ... } */
486
487                         $classname = $ts[$last - 1]['value'];
488
489                         if (!class_exists($classname)) {
490                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
491                         }
492
493                         $r = new ReflectionClass($classname);
494
495                         if ($r->isAbstract()) {
496                             throw new Exception(sprintf("Can't instantiate abstract Class '%s'", $classname));
497                         }
498
499                         if (!$r->isInstantiable()) {
500                             throw new Exception(sprintf('Class \'%s\' can\'t be instantiated. Is the class abstract ?', $classname));
501                         }
502
503                     } else if ($last >= 2 &&
504                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
505                         $ts[$last - 1]['token'] == T_STRING &&
506                         $ts[$last - 2]['token'] == T_FUNCTION ) {
507
508                         /* make sure we are not a in class definition */
509
510                         /* function a() */
511
512                         $func = $ts[$last - 1]['value'];
513
514                         if (function_exists($func)) {
515                             throw new Exception(sprintf('Function \'%s\' is already defined', $func));
516                         }
517                     } else if ($last >= 4 &&
518                         $ts[0]['token'] == T_CLASS &&
519                         $ts[1]['token'] == T_STRING &&
520                         $ts[$last - 1]['token'] == T_STRING &&
521                         $ts[$last - 2]['token'] == T_FUNCTION ) {
522
523                         /* make sure we are not a in class definition */
524
525                         /* class a { .. function a() ... } */
526
527                         $func = $ts[$last - 1]['value'];
528                         $classname = $ts[1]['value'];
529
530                         if (isset($methods[$func])) {
531                             throw new Exception(sprintf("Can't redeclare method '%s' in Class '%s'", $func, $classname));
532                         }
533
534                         $methods[$func] = 1;
535
536                     } else if ($last >= 1 &&
537                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
538                         $ts[0]['token'] != T_ABSTRACT && /* if we are not in a class definition */
539                         $ts[1]['token'] != T_CLASS && /* if we are not in a class definition */
540                         $ts[$last - 1]['token'] == T_STRING ) {
541                         /* func() */
542                         $funcname = $ts[$last - 1]['value'];
543
544                         if (!function_exists($funcname)) {
545                             throw new Exception(sprintf("Function %s() doesn't exist", $funcname));
546                         }
547                     } else if ($last >= 1 &&
548                         $ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
549                         $ts[$last - 1]['token'] == T_VARIABLE ) {
550
551                         /* $object has to exist and has to be a object */
552                         $funcname = $ts[$last - 1]['value'];
553
554                         if (!isset($GLOBALS[ltrim($funcname, '$')])) {
555                             throw new Exception(sprintf('Variable \'%s\' is not set', $funcname));
556                         }
557                         $func = $GLOBALS[ltrim($funcname, '$')];
558
559                         if (!function_exists($func)) {
560                             throw new Exception(sprintf("Function %s() doesn't exist", $func));
561                         }
562
563                     }
564
565                     array_push($braces, $token);
566                     break;
567                 case '{':
568                     $need_return = 0;
569
570                     if ($last >= 2 &&
571                         $ts[$last - 1]['token'] == T_STRING &&
572                         $ts[$last - 2]['token'] == T_CLASS ) {
573
574                         /* class name { */
575
576                         $classname = $ts[$last - 1]['value'];
577
578                         if (class_exists($classname, false)) {
579                             throw new Exception(sprintf("Class '%s' can't be redeclared", $classname));
580                         }
581                     } else if ($last >= 4 &&
582                         $ts[$last - 1]['token'] == T_STRING &&
583                         $ts[$last - 2]['token'] == T_EXTENDS &&
584                         $ts[$last - 3]['token'] == T_STRING &&
585                         $ts[$last - 4]['token'] == T_CLASS ) {
586
587                         /* class classname extends classname { */
588
589                         $classname = $ts[$last - 3]['value'];
590                         $extendsname = $ts[$last - 1]['value'];
591
592                         if (class_exists($classname, false)) {
593                             throw new Exception(sprintf("Class '%s' can't be redeclared",
594                                 $classname));
595                         }
596                         if (!class_exists($extendsname, true)) {
597                             throw new Exception(sprintf("Can't extend '%s' ... from not existing Class '%s'",
598                                 $classname, $extendsname));
599                         }
600                     } else if ($last >= 4 &&
601                         $ts[$last - 1]['token'] == T_STRING &&
602                         $ts[$last - 2]['token'] == T_IMPLEMENTS &&
603                         $ts[$last - 3]['token'] == T_STRING &&
604                         $ts[$last - 4]['token'] == T_CLASS ) {
605
606                         /* class name implements interface { */
607
608                         $classname = $ts[$last - 3]['value'];
609                         $implements = $ts[$last - 1]['value'];
610
611                         if (class_exists($classname, false)) {
612                             throw new Exception(sprintf("Class '%s' can't be redeclared",
613                                 $classname));
614                         }
615                         if (!interface_exists($implements, false)) {
616                             throw new Exception(sprintf("Can't implement not existing Interface '%s' for Class '%s'",
617                                 $implements, $classname));
618                         }
619                     }
620
621                     array_push($braces, $token);
622                     break;
623                 case '}':
624                     $need_return = 0;
625                 case ')':
626                     array_pop($braces);
627                     break;
628                 case '[':
629                     if ($ts[0]['token'] != T_CLASS && /* if we are not in a class definition */
630                         $ts[0]['token'] != T_ABSTRACT && /* if we are not in a class definition */
631                         $ts[1]['token'] != T_CLASS && /* if we are not in a class definition */
632                         $ts[$last - 1]['token'] == T_VARIABLE) {
633                         /* $a[] only works on array and string */
634
635                         /* $object has to exist and has to be a object */
636                         $objname = $ts[$last - 1]['value'];
637
638                         if (!isset($GLOBALS[ltrim($objname, '$')])) {
639                             throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
640                         }
641                         $obj = $GLOBALS[ltrim($objname, '$')];
642
643                         if (is_object($obj)) {
644                             throw new Exception(sprintf('Objects (%s) don\'t support array access operators', $objname));
645                         }
646                     }
647                     break;
648                 }
649
650                 $eval .= $token;
651             }
652         }
653
654         $last = count($ts) - 1;
655         if ($last >= 2 &&
656             $ts[$last - 0]['token'] == T_STRING &&
657             $ts[$last - 1]['token'] == T_DOUBLE_COLON &&
658             $ts[$last - 2]['token'] == T_STRING ) {
659
660             /* Class::constant */
661
662             /* $object has to exist and has to be a object */
663             $classname = $ts[$last - 2]['value'];
664
665             if (!class_exists($classname)) {
666                 throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
667             }
668
669             $constname = $ts[$last - 0]['value'];
670
671             $c = new ReflectionClass($classname);
672             if (!$c->hasConstant($constname)) {
673                 throw new Exception(sprintf("Class '%s' doesn't have a constant named '%s'",
674                     $classname, $constname));
675             }
676         } else if ($last == 0 &&
677             $ts[$last - 0]['token'] == T_VARIABLE ) {
678
679             /* $var */
680
681             $varname = $ts[$last - 0]['value'];
682
683             if (!isset($GLOBALS[ltrim($varname, '$')])) {
684                 throw new Exception(sprintf('Variable \'%s\' is not set', $varname));
685             }
686         }
687
688
689         $need_more = (count($braces) > 0) || $open_comment;
690
691         if ($need_more || ';' === $token) {
692                         $need_semicolon = 0;
693         }
694
695         if ($need_return) {
696             $eval = "return ".$eval;
697         }
698
699         /* add a traling ; if necessary */
700         if ($need_semicolon)
701                 {
702                         $this->has_semicolon = preg_match('/;\s*$/', $eval);
703                         $eval .= ';';
704                 }
705
706         if (!$need_more) {
707             $this->code = $eval;
708         }
709
710         return $need_more;
711     }
712
713     /**
714     * show the prompt and fetch a single line
715     *
716     * uses readline() if avaialbe
717     *
718     * @return string a input-line
719     */
720     public function readline() {
721         if (empty($this->code)) print PHP_EOL;
722
723         $prompt = (empty($this->code)) ? '>> ' : '.. ';
724
725         if (count($this->code_buffer) > 0) {
726             print $prompt;
727
728             $line = array_shift($this->code_buffer);
729
730             print $line.PHP_EOL;
731
732             return $line.PHP_EOL;
733         }
734
735         if ($this->have_readline) {
736             $l = readline($prompt);
737
738             readline_add_history($l);
739         } else {
740             print $prompt;
741
742             if (is_null($this->stdin)) {
743                 if (false === ($this->stdin = fopen("php://stdin", "r"))) {
744                     return false;
745                 }
746             }
747             $l = fgets($this->stdin);
748         }
749         return $l;
750     }
751
752     /**
753     * get the inline help
754     *
755     * @return string the inline help as string
756     */
757     public function cmdHelp($l) {
758         $o = 'Inline Help:'.PHP_EOL;
759
760         $cmds = PHP_Shell_Commands::getInstance()->getCommands();
761
762         $help = array();
763         foreach ($cmds as $cmd) {
764             $help[] = sprintf('  >> %s'.PHP_EOL.'    %s'.PHP_EOL,
765                 $cmd['command'],
766                 $cmd['description']
767             );
768         }
769
770         return var_export(implode("\n", $help), 1);
771     }
772
773     /**
774     * get the license string
775     *
776     * @return string the inline help as string
777     */
778     public function cmdLicense($l) {
779         $o = <<<EOF
780 (c) 2006 Jan Kneschke <jan@kneschke.de>
781
782 Permission is hereby granted, free of charge, to any person obtaining a copy of
783 this software and associated documentation files (the "Software"), to deal in
784 the Software without restriction, including without limitation the rights to
785 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
786 of the Software, and to permit persons to whom the Software is furnished to do
787 so, subject to the following conditions:
788
789 The above copyright notice and this permission notice shall be included in all
790 copies or substantial portions of the Software.
791
792 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
793 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
794 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
795 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
796 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
797 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
798 SOFTWARE.
799 EOF;
800
801         return var_export($o, 1);
802     }
803
804     /**
805     * handle the 'quit' command
806     *
807     * @return bool false to leave the input() call
808     * @see input
809     */
810     protected function cmdQuit($l) {
811         return false;
812     }
813
814     /**
815     * handle the input line
816     *
817     * read the input and handle the commands of the shell
818     *
819     * @return bool false on 'quit' or EOF, true otherwise
820     */
821     public function input() {
822         $l = $this->readline();
823
824         /* got EOF ? */
825         if (false === $l) return false;
826
827         $l = trim($l);
828
829         if (empty($this->code)) {
830             $this->verbose = 0;
831
832             $cmds = PHP_Shell_Commands::getInstance()->getCommands();
833
834             foreach ($cmds as $cmd) {
835                 if (preg_match($cmd['regex'], $l)) {
836                     $obj = $cmd['obj'];
837                     $func = $cmd['method'];
838
839                     if (false === ($l = $obj->$func($l))) {
840                         ## quit
841                         return false;
842                     }
843
844                     if (is_array($l)) {
845                         $this->code_buffer = $l;
846                         $l = '';
847                     }
848                     break;
849                 }
850             }
851         }
852
853         $this->appendCode($l);
854
855         return true;
856     }
857
858     /**
859     * get the code-buffer
860     *
861     * @return string the code-buffer
862     */
863     public function getCode() {
864                 return $this->code;
865         return $code;
866     }
867
868     /**
869     * reset the code-buffer
870     */
871     public function resetCode() {
872                 $this->has_semicolon=false;
873         $this->code = '';
874     }
875
876     /**
877     * append code to the code-buffer
878     *
879     * @param string $code input buffer
880     */
881     public function appendCode($code) {
882         if (strlen($code)) $code .= PHP_EOL;
883
884         $this->code .= $code;
885     }
886
887     /**
888     * check if readline support is enabled
889     *
890     * @return bool true if enabled, false otherwise
891     */
892     public function hasReadline() {
893         return $this->have_readline;
894     }
895
896     /**
897     * get version of the class
898     *
899     * @return string version-string
900     */
901     public function getVersion() {
902         return $this->version;
903     }
904 }
905
906 /**
907 * a readline completion callback
908 *
909 * @param string $str linebuffer
910 * @param integer $pos position in linebuffer
911 * @return array list of possible matches
912 */
913 function __shell_readline_complete($str, $pos) {
914     $in = readline_info('line_buffer');
915
916     /**
917     * parse the line-buffer backwards to see if we have a
918     * - constant
919     * - function
920     * - variable
921     */
922
923     $m = array();
924
925     if (preg_match('#\$([A-Za-z0-9_]+)->#', $in, $a)) {
926         /* check for $o->... */
927         $name = $a[1];
928
929         if (isset($GLOBALS[$name]) && is_object($GLOBALS[$name])) {
930             $c = get_class_methods($GLOBALS[$name]);
931
932             foreach ($c as $v) {
933                 $m[] = $v.'(';
934             }
935             $c = get_class_vars(get_class($GLOBALS[$name]));
936
937             foreach ($c as $k => $v) {
938                 $m[] = $k;
939             }
940
941             return $m;
942         }
943     } else if (preg_match('#\$([A-Za-z0-9_]+)\[([^\]]+)\]->#', $in, $a)) {
944         /* check for $o[...]->... */
945         $name = $a[1];
946
947         if (isset($GLOBALS[$name]) &&
948             is_array($GLOBALS[$name]) &&
949             isset($GLOBALS[$name][$a[2]])) {
950
951             $c = get_class_methods($GLOBALS[$name][$a[2]]);
952
953             foreach ($c as $v) {
954                 $m[] = $v.'(';
955             }
956             $c = get_class_vars(get_class($GLOBALS[$name][$a[2]]));
957
958             foreach ($c as $k => $v) {
959                 $m[] = $k;
960             }
961             return $m;
962         }
963
964     } else if (preg_match('#([A-Za-z0-9_]+)::#', $in, $a)) {
965         /* check for Class:: */
966         $name = $a[1];
967
968         if (class_exists($name, false)) {
969             $c = get_class_methods($name);
970
971             foreach ($c as $v) {
972                 $m[] = sprintf('%s::%s(', $name, $v);
973             }
974
975             $cl = new ReflectionClass($name);
976             $c = $cl->getConstants();
977
978             foreach ($c as $k => $v) {
979                 $m[] = sprintf('%s::%s', $name, $k);
980             }
981
982             return $m;
983         }
984     } else if (preg_match('#\$([a-zA-Z]?[a-zA-Z0-9_]*)$#', $in)) {
985         $m = array_keys($GLOBALS);
986
987         return $m;
988     } else if (preg_match('#new #', $in)) {
989         $c = get_declared_classes();
990
991         foreach ($c as $v) {
992             $m[] = $v.'(';
993         }
994
995         return $m;
996     } else if (preg_match('#^:set #', $in)) {
997         foreach (PHP_Shell_Options::getInstance()->getOptions() as $v) {
998             $m[] = $v;
999         }
1000
1001         return $m;
1002     }
1003
1004     $f = get_defined_functions();
1005
1006     foreach ($f['internal'] as $v) {
1007         $m[] = $v.'(';
1008     }
1009
1010     foreach ($f['user'] as $v) {
1011         $m[] = $v.'(';
1012     }
1013
1014     $c = get_declared_classes();
1015
1016     foreach ($c as $v) {
1017         $m[] = $v.'::';
1018     }
1019
1020     $c = get_defined_constants();
1021
1022     foreach ($c as $k => $v) {
1023         $m[] = $k;
1024     }
1025
1026     /* taken from http://de3.php.net/manual/en/reserved.php */
1027     $m[] = 'abstract';
1028     $m[] = 'and';
1029     $m[] = 'array(';
1030     $m[] = 'as';
1031     $m[] = 'break';
1032     $m[] = 'case';
1033     $m[] = 'catch';
1034     $m[] = 'class';
1035     $m[] = 'const';
1036     $m[] = 'continue';
1037     # $m[] = 'declare';
1038     $m[] = 'default';
1039     $m[] = 'die(';
1040     $m[] = 'do';
1041     $m[] = 'echo(';
1042     $m[] = 'else';
1043     $m[] = 'elseif';
1044     $m[] = 'empty(';
1045     # $m[] = 'enddeclare';
1046     $m[] = 'eval(';
1047     $m[] = 'exception';
1048     $m[] = 'extends';
1049     $m[] = 'exit(';
1050     $m[] = 'extends';
1051     $m[] = 'final';
1052     $m[] = 'for (';
1053     $m[] = 'foreach (';
1054     $m[] = 'function';
1055     $m[] = 'global';
1056     $m[] = 'if';
1057     $m[] = 'implements';
1058     $m[] = 'include "';
1059     $m[] = 'include_once "';
1060     $m[] = 'interface';
1061     $m[] = 'isset(';
1062     $m[] = 'list(';
1063     $m[] = 'new';
1064     $m[] = 'or';
1065     $m[] = 'print(';
1066     $m[] = 'private';
1067     $m[] = 'protected';
1068     $m[] = 'public';
1069     $m[] = 'require "';
1070     $m[] = 'require_once "';
1071     $m[] = 'return';
1072     $m[] = 'static';
1073     $m[] = 'switch (';
1074     $m[] = 'throw';
1075     $m[] = 'try';
1076     $m[] = 'unset(';
1077     # $m[] = 'use';
1078     $m[] = 'var';
1079     $m[] = 'while';
1080     $m[] = 'xor';
1081     $m[] = '__FILE__';
1082     $m[] = '__FUNCTION__';
1083     $m[] = '__CLASS__';
1084     $m[] = '__LINE__';
1085     $m[] = '__METHOD__';
1086
1087     # printf("%s ... %s\n", $str, $pos);
1088     return $m;
1089 }
1090
1091