Modified: php/php-src/trunk/NEWS =================================================================== --- php/php-src/trunk/NEWS 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/NEWS 2011-02-19 16:04:30 UTC (rev 308482) @@ -112,6 +112,7 @@ . Added "cli.prompt" php.ini setting to configure the shell prompt. . Added shortcut #inisetting=value to change ini settings at run-time. . Changed shell not to terminate on fatal errors. + . Interactive shell works with shared readline extension. FR #53878. - Improved FastCGI SAPI: (Dmitry) . Added apache compatible functions: apache_child_terminate(), Modified: php/php-src/trunk/ext/readline/config.m4 =================================================================== --- php/php-src/trunk/ext/readline/config.m4 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/ext/readline/config.m4 2011-02-19 16:04:30 UTC (rev 308482) @@ -98,6 +98,6 @@ if test "$PHP_READLINE" != "no" || test "$PHP_LIBEDIT" != "no"; then AC_CHECK_FUNCS([rl_completion_matches]) - PHP_NEW_EXTENSION(readline, readline.c, $ext_shared, cli) + PHP_NEW_EXTENSION(readline, readline.c readline_cli.c, $ext_shared, cli) PHP_SUBST(READLINE_SHARED_LIBADD) fi Modified: php/php-src/trunk/ext/readline/readline.c =================================================================== --- php/php-src/trunk/ext/readline/readline.c 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/ext/readline/readline.c 2011-02-19 16:04:30 UTC (rev 308482) @@ -26,6 +26,7 @@ #include "php.h" #include "php_readline.h" +#include "readline_cli.h" #if HAVE_LIBREADLINE || HAVE_LIBEDIT @@ -66,7 +67,9 @@ static zval _readline_array; PHP_MINIT_FUNCTION(readline); +PHP_MSHUTDOWN_FUNCTION(readline); PHP_RSHUTDOWN_FUNCTION(readline); +PHP_MINFO_FUNCTION(readline); /* }}} */ @@ -151,11 +154,11 @@ "readline", php_readline_functions, PHP_MINIT(readline), + PHP_MSHUTDOWN(readline), NULL, - NULL, PHP_RSHUTDOWN(readline), - NULL, - NO_VERSION_YET, + PHP_MINFO(readline), + PHP_VERSION, STANDARD_MODULE_PROPERTIES }; @@ -166,9 +169,14 @@ PHP_MINIT_FUNCTION(readline) { using_history(); - return SUCCESS; + return PHP_MINIT(cli_readline)(INIT_FUNC_ARGS_PASSTHRU); } +PHP_MSHUTDOWN_FUNCTION(readline) +{ + return PHP_MSHUTDOWN(cli_readline)(SHUTDOWN_FUNC_ARGS_PASSTHRU); +} + PHP_RSHUTDOWN_FUNCTION(readline) { if (_readline_completion) { @@ -186,6 +194,11 @@ return SUCCESS; } +PHP_MINFO_FUNCTION(readline) +{ + return PHP_MINFO(cli_readline)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU); +} + /* }}} */ /* {{{ proto string readline([string prompt]) Copied: php/php-src/trunk/ext/readline/readline_cli.c (from rev 307861, php/php-src/trunk/sapi/cli/php_cli_readline.c) =================================================================== --- php/php-src/trunk/ext/readline/readline_cli.c (rev 0) +++ php/php-src/trunk/ext/readline/readline_cli.c 2011-02-19 16:04:30 UTC (rev 308482) @@ -0,0 +1,752 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2011 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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 | + | Johannes Schlueter | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php.h" + +#ifndef HAVE_RL_COMPLETION_MATCHES +#define rl_completion_matches completion_matches +#endif + +#include "php_globals.h" +#include "php_variables.h" +#include "zend_hash.h" +#include "zend_modules.h" + +#include "SAPI.h" + +#if HAVE_SETLOCALE +#include +#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" +#include "ext/standard/php_smart_str.h" + +#ifdef __riscos__ +#include +#endif + +#if HAVE_LIBEDIT +#include +#else +#include +#include +#endif + +#include "zend_compile.h" +#include "zend_execute.h" +#include "zend_highlight.h" +#include "zend_indent.h" +#include "zend_exceptions.h" + +#include "sapi/cli/cli.h" +#include "readline_cli.h" + +#ifdef COMPILE_DL_READLINE +#include +#endif + +#define DEFAULT_PROMPT "\\b \\> " + +ZEND_DECLARE_MODULE_GLOBALS(cli_readline); + +static char php_last_char = '\0'; +static FILE *pager_pipe = NULL; + +static size_t readline_shell_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ +{ + if (CLIR_G(prompt_str)) { + smart_str_appendl(CLIR_G(prompt_str), str, str_length); + return str_length; + } + + if (CLIR_G(pager) && *CLIR_G(pager) && !pager_pipe) { + pager_pipe = VCWD_POPEN(CLIR_G(pager), "w"); + } + if (pager_pipe) { + return fwrite(str, 1, MIN(str_length, 16384), pager_pipe); + } + + return -1; +} +/* }}} */ + +static int readline_shell_ub_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ +{ + php_last_char = str[str_length-1]; + return -1; +} +/* }}} */ + +static void cli_readline_init_globals(zend_cli_readline_globals *rg TSRMLS_DC) +{ + rg->pager = NULL; + rg->prompt = NULL; + rg->prompt_str = NULL; +} + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("cli.pager", "", PHP_INI_ALL, OnUpdateString, pager, zend_cli_readline_globals, cli_readline_globals) + STD_PHP_INI_ENTRY("cli.prompt", DEFAULT_PROMPT, PHP_INI_ALL, OnUpdateString, prompt, zend_cli_readline_globals, cli_readline_globals) +PHP_INI_END() + + + +typedef enum { + body, + sstring, + dstring, + sstring_esc, + dstring_esc, + comment_line, + comment_block, + heredoc_start, + heredoc, + outside, +} php_code_type; + +static char *cli_get_prompt(char *block, char prompt TSRMLS_DC) /* {{{ */ +{ + smart_str retval = {0}; + char *prompt_spec = CLIR_G(prompt) ? CLIR_G(prompt) : DEFAULT_PROMPT; + + do { + if (*prompt_spec == '\\') { + switch (prompt_spec[1]) { + case '\\': + smart_str_appendc(&retval, '\\'); + prompt_spec++; + break; + case 'n': + smart_str_appendc(&retval, '\n'); + prompt_spec++; + break; + case 't': + smart_str_appendc(&retval, '\t'); + prompt_spec++; + break; + case 'e': + smart_str_appendc(&retval, '\033'); + prompt_spec++; + break; + + + case 'v': + smart_str_appends(&retval, PHP_VERSION); + prompt_spec++; + break; + case 'b': + smart_str_appends(&retval, block); + prompt_spec++; + break; + case '>': + smart_str_appendc(&retval, prompt); + prompt_spec++; + break; + case '`': + smart_str_appendc(&retval, '`'); + prompt_spec++; + break; + default: + smart_str_appendc(&retval, '\\'); + break; + } + } else if (*prompt_spec == '`') { + char *prompt_end = strstr(prompt_spec + 1, "`"); + char *code; + + if (prompt_end) { + code = estrndup(prompt_spec + 1, prompt_end - prompt_spec - 1); + + CLIR_G(prompt_str) = &retval; + zend_try { + zend_eval_stringl(code, prompt_end - prompt_spec - 1, NULL, "php prompt code" TSRMLS_CC); + } zend_end_try(); + CLIR_G(prompt_str) = NULL; + efree(code); + prompt_spec = prompt_end; + } + } else { + smart_str_appendc(&retval, *prompt_spec); + } + } while (++prompt_spec && *prompt_spec); + smart_str_0(&retval); + return retval.c; +} +/* }}} */ + +static 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': + case '\'': + 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, " 3 && !strncmp(code+i-4, "' TSRMLS_CC); + } + break; + case sstring: + case sstring_esc: + *prompt = cli_get_prompt("php", '\'' TSRMLS_CC); + break; + case dstring: + case dstring_esc: + *prompt = cli_get_prompt("php", '"' TSRMLS_CC); + break; + case comment_block: + *prompt = cli_get_prompt("/* ", '>' TSRMLS_CC); + break; + case heredoc: + *prompt = cli_get_prompt("<<<", '>' TSRMLS_CC); + break; + case outside: + *prompt = cli_get_prompt(" ", '>' TSRMLS_CC); + 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_ini(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */ +{ + char *retval, *tmp; + + tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(ini_directives), NULL TSRMLS_CC); + if (retval) { + retval = malloc(strlen(tmp) + 2); + retval[0] = '#'; + strcpy(&retval[1], tmp); + rl_completion_append_character = '='; + } + 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 = NULL; + 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 if (text[0] == '#') { + retval = cli_completion_generator_ini(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) { + int len = class_name_len + 2 + strlen(retval) + 1; + char *tmp = malloc(len); + + snprintf(tmp, len, "%s::%s", (*pce)->name, retval); + free(retval); + retval = tmp; + } + } + + return retval; +} /* }}} */ + +static char **cli_code_completion(const char *text, int start, int end) /* {{{ */ +{ + return rl_completion_matches(text, cli_completion_generator); +} +/* }}} */ + +static int readline_shell_run(TSRMLS_D) /* {{{ */ +{ + char *line; + size_t size = 4096, pos = 0, len; + char *code = emalloc(size); + char *prompt = cli_get_prompt("php", '>' TSRMLS_CC); + char *history_file; + + if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) { + zend_file_handle *prepend_file_p; + zend_file_handle prepend_file = {0}; + + prepend_file.filename = PG(auto_prepend_file); + prepend_file.opened_path = NULL; + prepend_file.free_filename = 0; + prepend_file.type = ZEND_HANDLE_FILENAME; + prepend_file_p = &prepend_file; + + zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p); + } + + 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 (line[0] == '#') { + char *param = strstr(&line[1], "="); + if (param) { + char *cmd; + uint cmd_len; + param++; + cmd_len = param - &line[1] - 1; + cmd = estrndup(&line[1], cmd_len); + + zend_alter_ini_entry_ex(cmd, cmd_len + 1, param, strlen(param), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); + efree(cmd); + add_history(line); + + efree(prompt); + /* TODO: This might be wrong! */ + prompt = cli_get_prompt("php", '>' TSRMLS_CC); + continue; + } + } + + 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); + efree(prompt); + + if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) { + continue; + } + + zend_try { + zend_eval_stringl(code, pos, NULL, "php shell code" TSRMLS_CC); + } zend_end_try(); + + pos = 0; + + if (!pager_pipe && php_last_char != '\0' && php_last_char != '\n') { + readline_shell_write("\n", 1 TSRMLS_CC); + } + + if (EG(exception)) { + zend_exception_error(EG(exception), E_WARNING TSRMLS_CC); + } + + if (pager_pipe) { + fclose(pager_pipe); + pager_pipe = NULL; + } + + php_last_char = '\0'; + } + write_history(history_file); + free(history_file); + efree(code); + efree(prompt); + return EG(exit_status); +} +/* }}} */ + +/* +#ifdef COMPILE_DL_READLINE +This dlsym() is always used as even the CGI SAPI is linked against "CLI"-only +extensions. If that is being changed dlsym() should only be used when building +this extension sharedto offer compatibility. +*/ +#define GET_SHELL_CB(cb) \ + do { \ + (cb) = NULL; \ + cli_shell_callbacks_t *(*get_callbacks)(); \ + get_callbacks = dlsym(RTLD_DEFAULT, "php_cli_get_shell_callbacks"); \ + if (get_callbacks) { \ + (cb) = get_callbacks(); \ + } \ + } while(0) +/*#else +#define GET_SHELL_CB(cb) (cb) = php_cli_get_shell_callbacks() +#endif*/ + +PHP_MINIT_FUNCTION(cli_readline) +{ + cli_shell_callbacks_t *cb; + + ZEND_INIT_MODULE_GLOBALS(cli_readline, cli_readline_init_globals, NULL); + REGISTER_INI_ENTRIES(); + + GET_SHELL_CB(cb); + if (cb) { + cb->cli_shell_write = readline_shell_write; + cb->cli_shell_ub_write = readline_shell_ub_write; + cb->cli_shell_run = readline_shell_run; + } + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(cli_readline) +{ + cli_shell_callbacks_t *cb; + + UNREGISTER_INI_ENTRIES(); + + GET_SHELL_CB(cb); + if (cb) { + cb->cli_shell_write = NULL; + cb->cli_shell_ub_write = NULL; + cb->cli_shell_run = NULL; + } + + return SUCCESS; +} + +PHP_MINFO_FUNCTION(cli_readline) +{ + DISPLAY_INI_ENTRIES(); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ Copied: php/php-src/trunk/ext/readline/readline_cli.h (from rev 307861, php/php-src/trunk/sapi/cli/php_cli_readline.h) =================================================================== --- php/php-src/trunk/ext/readline/readline_cli.h (rev 0) +++ php/php-src/trunk/ext/readline/readline_cli.h 2011-02-19 16:04:30 UTC (rev 308482) @@ -0,0 +1,43 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2011 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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 | + | Johannes Schlueter | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php.h" +#include "ext/standard/php_smart_str.h" + +ZEND_BEGIN_MODULE_GLOBALS(cli_readline) + char *pager; + char *prompt; + smart_str *prompt_str; +ZEND_END_MODULE_GLOBALS(cli_readline) + +#ifdef ZTS +# define CLIR_G(v) TSRMG(cli_readline_globals_id, zend_cli_readline_globals *, v) +#else +# define CLIR_G(v) (cli_readline_globals.v) +#endif + +extern PHP_MINIT_FUNCTION(cli_readline); +extern PHP_MSHUTDOWN_FUNCTION(cli_readline); +extern PHP_MINFO_FUNCTION(cli_readline); + +ZEND_EXTERN_MODULE_GLOBALS(cli_readline) + + Added: php/php-src/trunk/sapi/cli/cli.h =================================================================== --- php/php-src/trunk/sapi/cli/cli.h (rev 0) +++ php/php-src/trunk/sapi/cli/cli.h 2011-02-19 16:04:30 UTC (rev 308482) @@ -0,0 +1,52 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: Johannes Schlueter | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef CLI_H +#define CLI_H + +#ifdef PHP_WIN32 +# define PHP_CLI_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHP_CLI_API __attribute__ ((visibility("default"))) +#else +# define PHP_CLI_API +#endif + + +extern PHP_CLI_API size_t sapi_cli_single_write(const char *str, uint str_length TSRMLS_DC); + +typedef struct { + size_t (*cli_shell_write)(const char *str, uint str_length TSRMLS_DC); + int (*cli_shell_ub_write)(const char *str, uint str_length TSRMLS_DC); + int (*cli_shell_run)(TSRMLS_D); +} cli_shell_callbacks_t; + +extern PHP_CLI_API cli_shell_callbacks_t *php_cli_get_shell_callbacks(); + +#endif /* CLI_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ Property changes on: php/php-src/trunk/sapi/cli/cli.h ___________________________________________________________________ Added: svn:keywords + Id Rev Revision Added: svn:eol-style + native Modified: php/php-src/trunk/sapi/cli/config.m4 =================================================================== --- php/php-src/trunk/sapi/cli/config.m4 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/sapi/cli/config.m4 2011-02-19 16:04:30 UTC (rev 308482) @@ -14,7 +14,7 @@ SAPI_CLI_PATH=sapi/cli/php dnl Select SAPI - PHP_SELECT_SAPI(cli, program, php_cli.c php_cli_readline.c,, '$(SAPI_CLI_PATH)') + PHP_SELECT_SAPI(cli, program, php_cli.c,, '$(SAPI_CLI_PATH)') case $host_alias in *aix*) Modified: php/php-src/trunk/sapi/cli/config.w32 =================================================================== --- php/php-src/trunk/sapi/cli/config.w32 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/sapi/cli/config.w32 2011-02-19 16:04:30 UTC (rev 308482) @@ -6,7 +6,7 @@ ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no'); if (PHP_CLI == "yes") { - SAPI('cli', 'php_cli.c php_cli_readline.c', 'php.exe'); + SAPI('cli', 'php_cli.c', 'php.exe'); if (PHP_CRT_DEBUG == "yes") { ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP"); } @@ -14,7 +14,7 @@ } if (PHP_CLI_WIN32 == "yes") { - SAPI('cli_win32', 'cli_win32.c php_cli_readline.c', 'php-win.exe'); + SAPI('cli_win32', 'cli_win32.c', 'php-win.exe'); ADD_FLAG("LDFLAGS_CLI_WIN32", "/stack:8388608"); } Modified: php/php-src/trunk/sapi/cli/php_cli.c =================================================================== --- php/php-src/trunk/sapi/cli/php_cli.c 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/sapi/cli/php_cli.c 2011-02-19 16:04:30 UTC (rev 308482) @@ -61,6 +61,7 @@ #include "php_main.h" #include "fopen_wrappers.h" #include "ext/standard/php_standard.h" +#include "cli.h" #ifdef PHP_WIN32 #include #include @@ -75,16 +76,6 @@ #include #endif -#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) -#if HAVE_LIBEDIT -#include -#else -#include -#include -#endif -#include "php_cli_readline.h" -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ - #include "zend_compile.h" #include "zend_execute.h" #include "zend_highlight.h" @@ -121,6 +112,12 @@ #define PHP_MODE_REFLECTION_ZEND_EXTENSION 12 #define PHP_MODE_SHOW_INI_CONFIG 13 +cli_shell_callbacks_t cli_shell_callbacks = { NULL, NULL, NULL }; +PHP_CLI_API cli_shell_callbacks_t *php_cli_get_shell_callbacks() +{ + return &cli_shell_callbacks; +} + const char HARDCODED_INI[] = "html_errors=0\n" "register_argc_argv=1\n" @@ -131,10 +128,6 @@ 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'; -static FILE *pager_pipe = NULL; -#endif static const opt_struct OPTIONS[] = { {'a', 0, "interactive"}, @@ -256,26 +249,20 @@ return ret != -1; } -static inline size_t sapi_cli_single_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ +PHP_CLI_API size_t sapi_cli_single_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */ { #ifdef PHP_WRITE_STDOUT long ret; #endif -#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) - if (CLIR_G(prompt_str)) { - smart_str_appendl(CLIR_G(prompt_str), str, str_length); - return str_length; + if (cli_shell_callbacks.cli_shell_write) { + size_t shell_wrote; + shell_wrote = cli_shell_callbacks.cli_shell_write(str, str_length TSRMLS_CC); + if (shell_wrote > -1) { + return shell_wrote; + } } - if (CLIR_G(pager) && *CLIR_G(pager) && !pager_pipe) { - pager_pipe = VCWD_POPEN(CLIR_G(pager), "w"); - } - if (pager_pipe) { - return fwrite(str, 1, MIN(str_length, 16384), pager_pipe); - } -#endif - #ifdef PHP_WRITE_STDOUT do { ret = write(STDOUT_FILENO, str, str_length); @@ -301,13 +288,18 @@ 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 + if (cli_shell_callbacks.cli_shell_ub_write) { + int ub_wrote; + ub_wrote = cli_shell_callbacks.cli_shell_ub_write(str, str_length TSRMLS_CC); + if (ub_wrote > -1) { + return ub_wrote; + } + } + while (remaining > 0) { ret = sapi_cli_single_write(ptr, remaining TSRMLS_CC); @@ -419,11 +411,7 @@ static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */ { -#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) - if (php_module_startup(sapi_module, &cli_readline_module_entry, 1)==FAILURE) { -#else if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { -#endif return FAILURE; } return SUCCESS; @@ -1142,117 +1130,13 @@ 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 = cli_get_prompt("php", '>' TSRMLS_CC); - char *history_file; - - if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) { - zend_file_handle *prepend_file_p; - zend_file_handle prepend_file = {0}; - - prepend_file.filename = PG(auto_prepend_file); - prepend_file.opened_path = NULL; - prepend_file.free_filename = 0; - prepend_file.type = ZEND_HANDLE_FILENAME; - prepend_file_p = &prepend_file; - - zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p); - } - - 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 (line[0] == '#') { - char *param = strstr(&line[1], "="); - if (param) { - char *cmd; - uint cmd_len; - param++; - cmd_len = param - &line[1] - 1; - cmd = estrndup(&line[1], cmd_len); - - zend_alter_ini_entry_ex(cmd, cmd_len + 1, param, strlen(param), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); - efree(cmd); - add_history(line); - - efree(prompt); - /* TODO: This might be wrong! */ - prompt = cli_get_prompt("php", '>' TSRMLS_CC); - continue; - } - } - - 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); - efree(prompt); - - if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) { - continue; - } - - zend_try { - zend_eval_stringl(code, pos, NULL, "php shell code" TSRMLS_CC); - } zend_end_try(); - - pos = 0; - - if (!pager_pipe && php_last_char != '\0' && php_last_char != '\n') { - sapi_cli_single_write("\n", 1 TSRMLS_CC); - } - - if (EG(exception)) { - zend_exception_error(EG(exception), E_WARNING TSRMLS_CC); - } - - if (pager_pipe) { - fclose(pager_pipe); - pager_pipe = NULL; - } - - php_last_char = '\0'; - } - write_history(history_file); - free(history_file); - efree(code); - efree(prompt); + if (interactive && cli_shell_callbacks.cli_shell_run) { + exit_status = cli_shell_callbacks.cli_shell_run(); + } else { + php_execute_script(&file_handle TSRMLS_CC); exit_status = EG(exit_status); - break; } -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ - php_execute_script(&file_handle TSRMLS_CC); - exit_status = EG(exit_status); + break; case PHP_MODE_LINT: exit_status = php_lint_script(&file_handle TSRMLS_CC); Deleted: php/php-src/trunk/sapi/cli/php_cli_readline.c =================================================================== --- php/php-src/trunk/sapi/cli/php_cli_readline.c 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/sapi/cli/php_cli_readline.c 2011-02-19 16:04:30 UTC (rev 308482) @@ -1,584 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 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_01.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 | - | Johannes Schlueter | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php.h" - -#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) - -#ifndef HAVE_RL_COMPLETION_MATCHES -#define rl_completion_matches completion_matches -#endif - -#include "php_globals.h" -#include "php_variables.h" -#include "zend_hash.h" -#include "zend_modules.h" - -#include "SAPI.h" - -#if HAVE_SETLOCALE -#include -#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" -#include "ext/standard/php_smart_str.h" - -#ifdef __riscos__ -#include -#endif - -#if HAVE_LIBEDIT -#include -#else -#include -#include -#endif - -#include "zend_compile.h" -#include "zend_execute.h" -#include "zend_highlight.h" -#include "zend_indent.h" - -#include "php_cli_readline.h" - -#define DEFAULT_PROMPT "\\b \\> " - -ZEND_DECLARE_MODULE_GLOBALS(cli_readline); - -static void cli_readline_init_globals(zend_cli_readline_globals *rg TSRMLS_DC) -{ - rg->pager = NULL; - rg->prompt = NULL; - rg->prompt_str = NULL; -} - -PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("cli.pager", "", PHP_INI_ALL, OnUpdateString, pager, zend_cli_readline_globals, cli_readline_globals) - STD_PHP_INI_ENTRY("cli.prompt", DEFAULT_PROMPT, PHP_INI_ALL, OnUpdateString, prompt, zend_cli_readline_globals, cli_readline_globals) -PHP_INI_END() - -static PHP_MINIT_FUNCTION(cli_readline) -{ - ZEND_INIT_MODULE_GLOBALS(cli_readline, cli_readline_init_globals, NULL); - REGISTER_INI_ENTRIES(); - return SUCCESS; -} - -static PHP_MSHUTDOWN_FUNCTION(cli_readline) -{ - UNREGISTER_INI_ENTRIES(); - return SUCCESS; -} - -static PHP_MINFO_FUNCTION(cli_readline) -{ - DISPLAY_INI_ENTRIES(); -} - -zend_module_entry cli_readline_module_entry = { - STANDARD_MODULE_HEADER, - "cli-readline", - NULL, - PHP_MINIT(cli_readline), - PHP_MSHUTDOWN(cli_readline), - NULL, - NULL, - PHP_MINFO(cli_readline), - PHP_VERSION, - STANDARD_MODULE_PROPERTIES -}; - -typedef enum { - body, - sstring, - dstring, - sstring_esc, - dstring_esc, - comment_line, - comment_block, - heredoc_start, - heredoc, - outside, -} php_code_type; - -char *cli_get_prompt(char *block, char prompt TSRMLS_DC) /* {{{ */ -{ - smart_str retval = {0}; - char *prompt_spec = CLIR_G(prompt) ? CLIR_G(prompt) : DEFAULT_PROMPT; - - do { - if (*prompt_spec == '\\') { - switch (prompt_spec[1]) { - case '\\': - smart_str_appendc(&retval, '\\'); - prompt_spec++; - break; - case 'n': - smart_str_appendc(&retval, '\n'); - prompt_spec++; - break; - case 't': - smart_str_appendc(&retval, '\t'); - prompt_spec++; - break; - case 'e': - smart_str_appendc(&retval, '\033'); - prompt_spec++; - break; - - - case 'v': - smart_str_appends(&retval, PHP_VERSION); - prompt_spec++; - break; - case 'b': - smart_str_appends(&retval, block); - prompt_spec++; - break; - case '>': - smart_str_appendc(&retval, prompt); - prompt_spec++; - break; - case '`': - smart_str_appendc(&retval, '`'); - prompt_spec++; - break; - default: - smart_str_appendc(&retval, '\\'); - break; - } - } else if (*prompt_spec == '`') { - char *prompt_end = strstr(prompt_spec + 1, "`"); - char *code; - - if (prompt_end) { - code = estrndup(prompt_spec + 1, prompt_end - prompt_spec - 1); - - CLIR_G(prompt_str) = &retval; - zend_try { - zend_eval_stringl(code, prompt_end - prompt_spec - 1, NULL, "php prompt code" TSRMLS_CC); - } zend_end_try(); - CLIR_G(prompt_str) = NULL; - efree(code); - prompt_spec = prompt_end; - } - } else { - smart_str_appendc(&retval, *prompt_spec); - } - } while (++prompt_spec && *prompt_spec); - smart_str_0(&retval); - return retval.c; -} - -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': - case '\'': - 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, " 3 && !strncmp(code+i-4, "' TSRMLS_CC); - } - break; - case sstring: - case sstring_esc: - *prompt = cli_get_prompt("php", '\'' TSRMLS_CC); - break; - case dstring: - case dstring_esc: - *prompt = cli_get_prompt("php", '"' TSRMLS_CC); - break; - case comment_block: - *prompt = cli_get_prompt("/* ", '>' TSRMLS_CC); - break; - case heredoc: - *prompt = cli_get_prompt("<<<", '>' TSRMLS_CC); - break; - case outside: - *prompt = cli_get_prompt(" ", '>' TSRMLS_CC); - 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_ini(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */ -{ - char *retval, *tmp; - - tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(ini_directives), NULL TSRMLS_CC); - if (retval) { - retval = malloc(strlen(tmp) + 2); - retval[0] = '#'; - strcpy(&retval[1], tmp); - rl_completion_append_character = '='; - } - 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 = NULL; - 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 if (text[0] == '#') { - retval = cli_completion_generator_ini(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) { - int len = class_name_len + 2 + strlen(retval) + 1; - char *tmp = malloc(len); - - snprintf(tmp, len, "%s::%s", (*pce)->name, retval); - free(retval); - retval = tmp; - } - } - - return retval; -} /* }}} */ - -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 - */ Deleted: php/php-src/trunk/sapi/cli/php_cli_readline.h =================================================================== --- php/php-src/trunk/sapi/cli/php_cli_readline.h 2011-02-19 15:19:08 UTC (rev 308481) +++ php/php-src/trunk/sapi/cli/php_cli_readline.h 2011-02-19 16:04:30 UTC (rev 308482) @@ -1,44 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 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_01.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 | - | Johannes Schlueter | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php.h" -#include "ext/standard/php_smart_str.h" - -ZEND_BEGIN_MODULE_GLOBALS(cli_readline) - char *pager; - char *prompt; - smart_str *prompt_str; -ZEND_END_MODULE_GLOBALS(cli_readline) - -#ifdef ZTS -# define CLIR_G(v) TSRMG(cli_readline_globals_id, zend_cli_readline_globals *, v) -#else -# define CLIR_G(v) (cli_readline_globals.v) -#endif - -ZEND_EXTERN_MODULE_GLOBALS(cli_readline) - -extern zend_module_entry cli_readline_module_entry; - -char *cli_get_prompt(char *block, char prompt TSRMLS_DC); -int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC); - -char **cli_code_completion(const char *text, int start, int end);