summaryrefslogtreecommitdiff
path: root/sapi/cli
diff options
context:
space:
mode:
authorMark A. Hershberger <mah@debian.(none)>2009-03-25 00:34:59 -0400
committerMark A. Hershberger <mah@debian.(none)>2009-03-25 00:34:59 -0400
commitce7edc9b3c7370f32fec0bc7a8ec3e29ed9a5f61 (patch)
treeacdb9a8816483652a9db1a47db71df5df43707c5 /sapi/cli
parent10f5b47dc7c1cf2b9a00991629f43652710322d3 (diff)
downloadphp-ce7edc9b3c7370f32fec0bc7a8ec3e29ed9a5f61.tar.gz
Imported Upstream version 5.1.1upstream/5.1.1
Diffstat (limited to 'sapi/cli')
-rw-r--r--sapi/cli/CREDITS2
-rw-r--r--sapi/cli/Makefile.frag2
-rw-r--r--sapi/cli/config.m47
-rw-r--r--sapi/cli/config.w326
-rw-r--r--sapi/cli/getopt.c4
-rw-r--r--sapi/cli/php.1.in19
-rw-r--r--sapi/cli/php_cli.c141
-rw-r--r--sapi/cli/php_cli_readline.c445
-rw-r--r--sapi/cli/php_cli_readline.h25
-rw-r--r--sapi/cli/php_getopt.h5
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.
*/