diff options
| author | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:34:59 -0400 |
|---|---|---|
| committer | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:34:59 -0400 |
| commit | ce7edc9b3c7370f32fec0bc7a8ec3e29ed9a5f61 (patch) | |
| tree | acdb9a8816483652a9db1a47db71df5df43707c5 /sapi/cli | |
| parent | 10f5b47dc7c1cf2b9a00991629f43652710322d3 (diff) | |
| download | php-ce7edc9b3c7370f32fec0bc7a8ec3e29ed9a5f61.tar.gz | |
Imported Upstream version 5.1.1upstream/5.1.1
Diffstat (limited to 'sapi/cli')
| -rw-r--r-- | sapi/cli/CREDITS | 2 | ||||
| -rw-r--r-- | sapi/cli/Makefile.frag | 2 | ||||
| -rw-r--r-- | sapi/cli/config.m4 | 7 | ||||
| -rw-r--r-- | sapi/cli/config.w32 | 6 | ||||
| -rw-r--r-- | sapi/cli/getopt.c | 4 | ||||
| -rw-r--r-- | sapi/cli/php.1.in | 19 | ||||
| -rw-r--r-- | sapi/cli/php_cli.c | 141 | ||||
| -rw-r--r-- | sapi/cli/php_cli_readline.c | 445 | ||||
| -rw-r--r-- | sapi/cli/php_cli_readline.h | 25 | ||||
| -rw-r--r-- | sapi/cli/php_getopt.h | 5 |
10 files changed, 612 insertions, 44 deletions
diff --git a/sapi/cli/CREDITS b/sapi/cli/CREDITS index fac101d74..5f3b0fbe3 100644 --- a/sapi/cli/CREDITS +++ b/sapi/cli/CREDITS @@ -1,2 +1,2 @@ CLI -Edin Kadribasic, Marcus Boerger +Edin Kadribasic, Marcus Boerger, Johannes Schlueter diff --git a/sapi/cli/Makefile.frag b/sapi/cli/Makefile.frag index 5db4c68ba..6903ca1fc 100644 --- a/sapi/cli/Makefile.frag +++ b/sapi/cli/Makefile.frag @@ -8,4 +8,4 @@ install-cli: $(SAPI_CLI_PATH) @$(INSTALL_CLI) @echo "Installing PHP CLI man page: $(INSTALL_ROOT)$(mandir)/man1/" @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 - @$(INSTALL_DATA) $(builddir)/php.1 $(INSTALL_ROOT)$(mandir)/man1/php.1 + @$(INSTALL_DATA) $(builddir)/php.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)php$(program_suffix).1 diff --git a/sapi/cli/config.m4 b/sapi/cli/config.m4 index 123df11d7..bf23060b9 100644 --- a/sapi/cli/config.m4 +++ b/sapi/cli/config.m4 @@ -1,12 +1,12 @@ dnl -dnl $Id: config.m4,v 1.18.2.2 2005/06/20 11:48:25 sniper Exp $ +dnl $Id: config.m4,v 1.22 2005/07/07 05:54:43 dmitry Exp $ dnl AC_MSG_CHECKING(for CLI build) AC_ARG_ENABLE(cli, [ --disable-cli Disable building CLI version of PHP - (this forces --without-pear).], + (this forces --without-pear)], [ PHP_SAPI_CLI=$enableval ],[ @@ -19,6 +19,9 @@ if test "$PHP_SAPI_CLI" != "no"; then PHP_SUBST(SAPI_CLI_PATH) case $host_alias in + *aix*) + BUILD_CLI="echo '\#! .' > php.sym && echo >>php.sym && nm -BCpg \`echo \$(PHP_GLOBAL_OBJS) \$(PHP_CLI_OBJS) | sed 's/\([A-Za-z0-9_]*\)\.lo/.libs\/\1.o/g'\` | \$(AWK) '{ if (((\$\$2 == \"T\") || (\$\$2 == \"D\") || (\$\$2 == \"B\")) && (substr(\$\$3,1,1) != \".\")) { print \$\$3 } }' | sort -u >> php.sym && \$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) -Wl,-brtl -Wl,-bE:php.sym \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_CLI_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CLI_PATH)" + ;; *darwin*) BUILD_CLI="\$(CC) \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(NATIVE_RPATHS) \$(PHP_GLOBAL_OBJS:.lo=.o) \$(PHP_CLI_OBJS:.lo=.o) \$(PHP_FRAMEWORKS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CLI_PATH)" ;; diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32 index 53cb29618..98898fd7e 100644 --- a/sapi/cli/config.w32 +++ b/sapi/cli/config.w32 @@ -1,18 +1,18 @@ // vim:ft=javascript -// $Id: config.w32,v 1.3 2004/01/14 03:14:17 wez Exp $ +// $Id: config.w32,v 1.4 2005/05/14 19:33:18 helly Exp $ ARG_ENABLE('cli', 'Build CLI version of PHP', 'yes'); ARG_ENABLE('crt-debug', 'Extra CRT debugging', 'no'); ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no'); if (PHP_CLI == "yes") { - SAPI('cli', 'getopt.c php_cli.c', 'php.exe'); + SAPI('cli', 'getopt.c php_cli.c php_cli_readline.c', 'php.exe'); if (PHP_CRT_DEBUG == "yes") { ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP"); } } if (PHP_CLI_WIN32 == "yes") { - SAPI('cli_win32', 'getopt.c cli_win32.c', 'php-win.exe'); + SAPI('cli_win32', 'getopt.c cli_win32.c php_cli_readline.c', 'php-win.exe'); } diff --git a/sapi/cli/getopt.c b/sapi/cli/getopt.c index 601cb9f96..24d1c8bf0 100644 --- a/sapi/cli/getopt.c +++ b/sapi/cli/getopt.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | + | Copyright (c) 1997-2005 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: getopt.c,v 1.7 2004/01/08 08:18:09 andi Exp $ */ +/* $Id: getopt.c,v 1.8 2005/08/03 11:12:18 sniper Exp $ */ #include <stdio.h> #include <string.h> diff --git a/sapi/cli/php.1.in b/sapi/cli/php.1.in index c6380e296..33613464a 100644 --- a/sapi/cli/php.1.in +++ b/sapi/cli/php.1.in @@ -1,7 +1,7 @@ ./" +----------------------------------------------------------------------+ ./" | PHP Version 5 | ./" +----------------------------------------------------------------------+ -./" | Copyright (c) 1997-2004 The PHP Group | +./" | Copyright (c) 1997-2005 The PHP Group | ./" +----------------------------------------------------------------------+ ./" | This source file is subject to version 3.0 of the PHP license, | ./" | that is bundled with this package in the file LICENSE, and is | @@ -14,7 +14,7 @@ ./" | Author: Marcus Boerger <helly@php.net> | ./" +----------------------------------------------------------------------+ ./" -./" $Id: php.1.in,v 1.7.2.1 2005/04/30 04:12:43 sniper Exp $ +./" $Id: php.1.in,v 1.12 2005/08/03 11:12:18 sniper Exp $ ./" .TH PHP 1 "Feb 2003" "The PHP Group" "Scripting Language" .SH NAME @@ -24,7 +24,7 @@ PHP Command Line Interface 'CLI' .SH SYNOPSIS .B php [options] [ -.B \-f ] +.B \-f\fP ] .IR file [[\-\-] .IR args.\|.\|. ] @@ -60,9 +60,10 @@ PHP Command Line Interface 'CLI' [options] \-\- [ .IR args.\|.\|. ] .LP +\fBphp \fP[options] \fB\-a\fP +.LP .SH DESCRIPTION -.B PHP -is a widely\-used general\-purpose scripting language that is especially suited for +\fBPHP\fP is a widely\-used general\-purpose scripting language that is especially suited for Web development and can be embedded into HTML. This is the command line interface that enables you to the following: .P @@ -108,7 +109,9 @@ executed. .TP .PD 1 .B \-a -Run interactively +Run PHP interactively. This lets you enter snippets of PHP code that directly +get executed. When readline support is enabled you can edit the lines and also +have history support. .TP .PD 0 .B \-\-php\-ini \fIpath\fP|\fIfile\fP @@ -376,11 +379,11 @@ contributors all around the world. .SH VERSION INFORMATION This manpage describes \fBphp\fP, version @PHP_VERSION@. .SH COPYRIGHT -Copyright \(co 1997\-2004 The PHP Group +Copyright \(co 1997\-2005 The PHP Group .LP This source file is subject to version 3.0 of the PHP license, that is bundled with this package in the file LICENSE, and is -available at through the world-wide-web at +available through the world-wide-web at .PD 0 .P .B http://www.php.net/license/3_0.txt diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index 6ef52f105..7355e4931 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | + | Copyright (c) 1997-2005 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -14,12 +14,13 @@ +----------------------------------------------------------------------+ | Author: Edin Kadribasic <edink@php.net> | | Marcus Boerger <helly@php.net> | + | Johannes Schlueter <johannes@php.net> | | Parts based on CGI SAPI Module by | | Rasmus Lerdorf, Stig Bakken and Zeev Suraski | +----------------------------------------------------------------------+ */ -/* $Id: php_cli.c,v 1.113.2.2 2005/03/22 15:09:20 tony2001 Exp $ */ +/* $Id: php_cli.c,v 1.129.2.6 2005/11/17 08:37:31 sniper Exp $ */ #include "php.h" #include "php_globals.h" @@ -69,12 +70,19 @@ #include <unixlib/local.h> #endif +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) +#include <readline/readline.h> +#if !HAVE_LIBEDIT +#include <readline/history.h> +#endif +#include "php_cli_readline.h" +#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ + #include "zend_compile.h" #include "zend_execute.h" #include "zend_highlight.h" #include "zend_indent.h" - #include "php_getopt.h" #ifndef O_BINARY @@ -91,6 +99,9 @@ static char *php_optarg = NULL; static int php_optind = 1; +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) +static char php_last_char = '\0'; +#endif static const opt_struct OPTIONS[] = { {'a', 0, "interactive"}, @@ -200,6 +211,13 @@ static int sapi_cli_ub_write(const char *str, uint str_length TSRMLS_DC) uint remaining = str_length; size_t ret; +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) + if (!str_length) { + return 0; + } + php_last_char = str[str_length-1]; +#endif + while (remaining > 0) { ret = sapi_cli_single_write(ptr, remaining); @@ -345,6 +363,7 @@ static sapi_module_struct cli_sapi_module = { sapi_cli_register_variables, /* register server variables */ sapi_cli_log_message, /* Log message */ + NULL, /* Get request time */ STANDARD_SAPI_MODULE_PROPERTIES }; @@ -368,8 +387,13 @@ static void php_cli_usage(char *argv0) " %s [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]\n" " %s [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]\n" " %s [options] -- [args...]\n" + " %s [options] -a\n" "\n" +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) + " -a Run as interactive shell\n" +#else " -a Run interactively\n" +#endif " -c <path>|<file> Look for php.ini file in this directory\n" " -n No php.ini file will be used\n" " -d foo[=bar] Define INI entry foo with value 'bar'\n" @@ -393,11 +417,11 @@ static void php_cli_usage(char *argv0) " args... Arguments passed to script. Use -- args when first argument\n" " starts with - or script is read from stdin\n" "\n" - , prog, prog, prog, prog, prog); + , prog, prog, prog, prog, prog, prog); } /* }}} */ -static void define_command_line_ini_entry(char *arg) +static void define_command_line_ini_entry(char *arg TSRMLS_DC) { char *name, *value; @@ -409,7 +433,14 @@ static void define_command_line_ini_entry(char *arg) } else { value = "1"; } - zend_alter_ini_entry(name, strlen(name)+1, value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); + + if (!strcasecmp(name, "extension")) { /* load function module */ + zval extension, zval; + ZVAL_STRING(&extension, value, 0); + php_dl(&extension, MODULE_PERSISTENT, &zval, 1 TSRMLS_CC); + } else { + zend_alter_ini_entry(name, strlen(name)+1, value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); + } } @@ -457,21 +488,21 @@ static void cli_register_file_handles(TSRMLS_D) ic.value = *zin; ic.flags = CONST_CS; - ic.name = zend_strndup(ZEND_STRS("STDIN")); + ic.name = zend_strndup(ZEND_STRL("STDIN")); ic.name_len = sizeof("STDIN"); ic.module_number = 0; zend_register_constant(&ic TSRMLS_CC); oc.value = *zout; oc.flags = CONST_CS; - oc.name = zend_strndup(ZEND_STRS("STDOUT")); + oc.name = zend_strndup(ZEND_STRL("STDOUT")); oc.name_len = sizeof("STDOUT"); oc.module_number = 0; zend_register_constant(&oc TSRMLS_CC); ec.value = *zerr; ec.flags = CONST_CS; - ec.name = zend_strndup(ZEND_STRS("STDERR")); + ec.name = zend_strndup(ZEND_STRL("STDERR")); ec.name_len = sizeof("STDERR"); ec.module_number = 0; zend_register_constant(&ec TSRMLS_CC); @@ -492,7 +523,7 @@ static int cli_seek_file_begin(zend_file_handle *file_handle, char *script_file, *lineno = 1; if (!(file_handle->handle.fp = VCWD_FOPEN(script_file, "rb"))) { - php_printf("Could not open input file: %s.\n", script_file); + php_printf("Could not open input file: %s\n", script_file); return FAILURE; } file_handle->filename = script_file; @@ -656,18 +687,18 @@ int main(int argc, char *argv[]) switch (c) { case 'd': /* define ini entries on command line */ - define_command_line_ini_entry(php_optarg); + define_command_line_ini_entry(php_optarg TSRMLS_CC); break; case 'h': /* help & quit */ case '?': - php_output_startup(); - php_output_activate(TSRMLS_C); + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } php_cli_usage(argv[0]); php_end_ob_buffers(1 TSRMLS_CC); - exit_status=1; - goto err; - + exit_status=0; + goto out; case 'i': /* php info & quit */ if (php_request_startup(TSRMLS_C)==FAILURE) { @@ -675,32 +706,33 @@ int main(int argc, char *argv[]) } php_print_info(0xFFFFFFFF TSRMLS_CC); php_end_ob_buffers(1 TSRMLS_CC); - exit_status=1; + exit_status=0; goto out; case 'm': /* list compiled in modules */ - php_output_startup(); - php_output_activate(TSRMLS_C); + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } php_printf("[PHP Modules]\n"); print_modules(TSRMLS_C); php_printf("\n[Zend Modules]\n"); print_extensions(TSRMLS_C); php_printf("\n"); php_end_ob_buffers(1 TSRMLS_CC); - exit_status=1; - goto err; + exit_status=0; + goto out; case 'v': /* show php version & quit */ if (php_request_startup(TSRMLS_C)==FAILURE) { goto err; } #if ZEND_DEBUG - php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2005 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #else - php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2005 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #endif php_end_ob_buffers(1 TSRMLS_CC); - exit_status=1; + exit_status=0; goto out; default: @@ -943,6 +975,67 @@ int main(int argc, char *argv[]) if (strcmp(file_handle.filename, "-")) { cli_register_file_handles(TSRMLS_C); } + +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) + if (interactive) { + char *line; + size_t size = 4096, pos = 0, len; + char *code = emalloc(size); + char *prompt = "php > "; + char *history_file; + + history_file = tilde_expand("~/.php_history"); + rl_attempted_completion_function = cli_code_completion; + rl_special_prefixes = "$"; + read_history(history_file); + + EG(exit_status) = 0; + while ((line = readline(prompt)) != NULL) { + if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) { + free(line); + break; + } + + if (!pos && !*line) { + free(line); + continue; + } + + len = strlen(line); + if (pos + len + 2 > size) { + size = pos + len + 2; + code = erealloc(code, size); + } + memcpy(&code[pos], line, len); + pos += len; + code[pos] = '\n'; + code[++pos] = '\0'; + + if (*line) { + add_history(line); + } + + free(line); + + if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) { + continue; + } + + zend_eval_string(code, NULL, "php shell code" TSRMLS_CC); + pos = 0; + + if (php_last_char != '\0' && php_last_char != '\n') { + sapi_cli_single_write("\n", 1); + } + php_last_char = '\0'; + } + write_history(history_file); + free(history_file); + efree(code); + exit_status = EG(exit_status); + break; + } +#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ php_execute_script(&file_handle TSRMLS_CC); exit_status = EG(exit_status); break; diff --git a/sapi/cli/php_cli_readline.c b/sapi/cli/php_cli_readline.c new file mode 100644 index 000000000..97b2d0faf --- /dev/null +++ b/sapi/cli/php_cli_readline.c @@ -0,0 +1,445 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2005 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Marcus Boerger <helly@php.net> | + | Johannes Schlueter <johannes@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: php_cli_readline.c,v 1.3.2.3 2005/11/17 08:37:31 sniper Exp $ */ + +#include "php.h" + +#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) + +#include "php_globals.h" +#include "php_variables.h" +#include "zend_hash.h" +#include "zend_modules.h" + +#include "SAPI.h" + +#if HAVE_SETLOCALE +#include <locale.h> +#endif +#include "zend.h" +#include "zend_extensions.h" +#include "php_ini.h" +#include "php_globals.h" +#include "php_main.h" +#include "fopen_wrappers.h" +#include "ext/standard/php_standard.h" + +#ifdef __riscos__ +#include <unixlib/local.h> +#endif + +#include <readline/readline.h> +#if !HAVE_LIBEDIT +#include <readline/history.h> +#endif + +#include "zend_compile.h" +#include "zend_execute.h" +#include "zend_highlight.h" +#include "zend_indent.h" + +/* {{{ cli_is_valid_code + */ +typedef enum { + body, + sstring, + dstring, + sstring_esc, + dstring_esc, + comment_line, + comment_block, + heredoc_start, + heredoc, + outside, +} php_code_type; + +int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) +{ + int valid_end = 1, last_valid_end; + int brackets_count = 0; + int brace_count = 0; + int i; + php_code_type code_type = body; + char *heredoc_tag; + int heredoc_len; + + for (i = 0; i < len; ++i) { + switch(code_type) { + default: + switch(code[i]) { + case '{': + brackets_count++; + valid_end = 0; + break; + case '}': + if (brackets_count > 0) { + brackets_count--; + } + valid_end = brackets_count ? 0 : 1; + break; + case '(': + brace_count++; + valid_end = 0; + break; + case ')': + if (brace_count > 0) { + brace_count--; + } + valid_end = 0; + break; + case ';': + valid_end = brace_count == 0 && brackets_count == 0; + break; + case ' ': + case '\r': + case '\n': + case '\t': + break; + case '\'': + code_type = sstring; + break; + case '"': + code_type = dstring; + break; + case '#': + code_type = comment_line; + break; + case '/': + if (code[i+1] == '/') { + i++; + code_type = comment_line; + break; + } + if (code[i+1] == '*') { + last_valid_end = valid_end; + valid_end = 0; + code_type = comment_block; + i++; + break; + } + valid_end = 0; + break; + case '%': + if (!CG(asp_tags)) { + valid_end = 0; + break; + } + /* no break */ + case '?': + if (code[i+1] == '>') { + i++; + code_type = outside; + break; + } + valid_end = 0; + break; + case '<': + valid_end = 0; + if (i + 2 < len && code[i+1] == '<' && code[i+2] == '<') { + i += 2; + code_type = heredoc_start; + heredoc_len = 0; + } + break; + default: + valid_end = 0; + break; + } + break; + case sstring: + if (code[i] == '\\') { + code_type = sstring_esc; + } else { + if (code[i] == '\'') { + code_type = body; + } + } + break; + case sstring_esc: + code_type = sstring; + break; + case dstring: + if (code[i] == '\\') { + code_type = dstring_esc; + } else { + if (code[i] == '"') { + code_type = body; + } + } + break; + case dstring_esc: + code_type = dstring; + break; + case comment_line: + if (code[i] == '\n') { + code_type = body; + } + break; + case comment_block: + if (code[i-1] == '*' && code[i] == '/') { + code_type = body; + valid_end = last_valid_end; + } + break; + case heredoc_start: + switch(code[i]) { + case ' ': + case '\t': + break; + case '\r': + case '\n': + code_type = heredoc; + break; + default: + if (!heredoc_len) { + heredoc_tag = code+i; + } + heredoc_len++; + break; + } + break; + case heredoc: + if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') { + code_type = body; + } else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') { + code_type = body; + valid_end = 1; + } + break; + case outside: + if ((CG(short_tags) && !strncmp(code+i-1, "<?", 2)) + || (CG(asp_tags) && !strncmp(code+i-1, "<%", 2)) + || (i > 3 && !strncmp(code+i-4, "<?php", 5)) + ) { + code_type = body; + } + break; + } + } + + switch (code_type) { + default: + if (brace_count) { + *prompt = "php ( "; + } else if (brackets_count) { + *prompt = "php { "; + } else { + *prompt = "php > "; + } + break; + case sstring: + case sstring_esc: + *prompt = "php ' "; + break; + case dstring: + case dstring_esc: + *prompt = "php \" "; + break; + case comment_block: + *prompt = "/* > "; + break; + case heredoc: + *prompt = "<<< > "; + break; + case outside: + *prompt = " > "; + break; + } + + if (!valid_end || brackets_count) { + return 0; + } else { + return 1; + } +} +/* }}} */ + +static char *cli_completion_generator_ht(const char *text, int textlen, int *state, HashTable *ht, void **pData TSRMLS_DC) /* {{{ */ +{ + char *name; + ulong number; + + if (!(*state % 2)) { + zend_hash_internal_pointer_reset(ht); + (*state)++; + } + while(zend_hash_has_more_elements(ht) == SUCCESS) { + zend_hash_get_current_key(ht, &name, &number, 0); + if (!textlen || !strncmp(name, text, textlen)) { + if (pData) { + zend_hash_get_current_data(ht, pData); + } + zend_hash_move_forward(ht); + return name; + } + if (zend_hash_move_forward(ht) == FAILURE) { + break; + } + } + (*state)++; + return NULL; +} /* }}} */ + +static char *cli_completion_generator_var(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */ +{ + char *retval, *tmp; + + tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(active_symbol_table), NULL TSRMLS_CC); + if (retval) { + retval = malloc(strlen(tmp) + 2); + retval[0] = '$'; + strcpy(&retval[1], tmp); + rl_completion_append_character = '\0'; + } + return retval; +} /* }}} */ + +static char *cli_completion_generator_func(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */ +{ + zend_function *func; + char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&func TSRMLS_CC); + if (retval) { + rl_completion_append_character = '('; + retval = strdup(func->common.function_name); + } + + return retval; +} /* }}} */ + +static char *cli_completion_generator_class(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */ +{ + zend_class_entry **pce; + char *retval = cli_completion_generator_ht(text, textlen, state, EG(class_table), (void**)&pce TSRMLS_CC); + if (retval) { + rl_completion_append_character = '\0'; + retval = strdup((*pce)->name); + } + + return retval; +} /* }}} */ + +static char *cli_completion_generator_define(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */ +{ + zend_class_entry **pce; + char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&pce TSRMLS_CC); + if (retval) { + rl_completion_append_character = '\0'; + retval = strdup(retval); + } + + return retval; +} /* }}} */ + +static int cli_completion_state; + +static char *cli_completion_generator(const char *text, int index) /* {{{ */ +{ +/* +TODO: +- constants +- maybe array keys +- language constructs and other things outside a hashtable (echo, try, function, class, ...) +- object/class members + +- future: respect scope ("php > function foo() { $[tab]" should only expand to local variables...) +*/ + char *retval; + int textlen = strlen(text); + TSRMLS_FETCH(); + + if (!index) { + cli_completion_state = 0; + } + if (text[0] == '$') { + retval = cli_completion_generator_var(text, textlen, &cli_completion_state TSRMLS_CC); + } else { + char *lc_text, *class_name, *class_name_end; + int class_name_len; + zend_class_entry **pce = NULL; + + class_name_end = strstr(text, "::"); + if (class_name_end) { + class_name_len = class_name_end - text; + class_name = zend_str_tolower_dup(text, class_name_len); + class_name[class_name_len] = '\0'; /* not done automatically */ + if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) { + efree(class_name); + return NULL; + } + lc_text = zend_str_tolower_dup(class_name_end + 2, textlen - 2 - class_name_len); + textlen -= (class_name_len + 2); + } else { + lc_text = zend_str_tolower_dup(text, textlen); + } + + switch (cli_completion_state) { + case 0: + case 1: + retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, pce ? &(*pce)->function_table : EG(function_table) TSRMLS_CC); + if (retval) { + break; + } + case 2: + case 3: + retval = cli_completion_generator_define(text, textlen, &cli_completion_state, pce ? &(*pce)->constants_table : EG(zend_constants) TSRMLS_CC); + if (retval || pce) { + break; + } + case 4: + case 5: + retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state TSRMLS_CC); + break; + default: + break; + } + efree(lc_text); + if (class_name_end) { + efree(class_name); + } + if (pce && retval) { + char *tmp = malloc(class_name_len + 2 + strlen(retval) + 1); + + sprintf(tmp, "%s::%s", (*pce)->name, retval); + free(retval); + retval = tmp; + } + } + + return retval; +} /* }}} */ + +/* {{{ cli_code_completion + */ +char **cli_code_completion(const char *text, int start, int end) +{ + return rl_completion_matches(text, cli_completion_generator); +} +/* }}} */ + +#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/sapi/cli/php_cli_readline.h b/sapi/cli/php_cli_readline.h new file mode 100644 index 000000000..f840765ba --- /dev/null +++ b/sapi/cli/php_cli_readline.h @@ -0,0 +1,25 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2005 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: php_cli_readline.h,v 1.2 2005/08/03 11:12:18 sniper Exp $ */ + +#include "php.h" + +int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC); + +char **cli_code_completion(const char *text, int start, int end); diff --git a/sapi/cli/php_getopt.h b/sapi/cli/php_getopt.h index 334bb2c79..14f9ca5e8 100644 --- a/sapi/cli/php_getopt.h +++ b/sapi/cli/php_getopt.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2004 The PHP Group | + | Copyright (c) 1997-2005 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_getopt.h,v 1.5.2.1 2005/03/11 11:04:03 hyanantha Exp $ */ +/* $Id: php_getopt.h,v 1.7 2005/08/03 11:12:18 sniper Exp $ */ #include "php.h" @@ -27,7 +27,6 @@ As NetWare LibC has optind and optarg macros defined in unistd.h our local varia #undef optarg #undef optind #endif - /* Define structure for one recognized option (both single char and long name). * If short_open is '-' this is the last option. */ |
