helly Sat May 14 15:33:18 2005 EDT Added files: /php-src/sapi/cli php_cli_readline.c php_cli_readline.h
Modified files: /php-src configure.in /php-src/sapi/cli config.w32 php_cli.c Log: - Add command completion to CLI's -a mode
http://cvs.php.net/diff.php/php-src/configure.in?r1=1.553&r2=1.554&ty=u Index: php-src/configure.in diff -u php-src/configure.in:1.553 php-src/configure.in:1.554 --- php-src/configure.in:1.553 Fri May 6 22:51:50 2005 +++ php-src/configure.in Sat May 14 15:33:17 2005 @@ -1,4 +1,4 @@ -dnl ## $Id: configure.in,v 1.553 2005/05/07 02:51:50 sniper Exp $ -*- autoconf -*- +dnl ## $Id: configure.in,v 1.554 2005/05/14 19:33:17 helly Exp $ -*- autoconf -*- dnl ## Process this file with autoconf to produce a configure script. divert(1) @@ -1054,7 +1054,7 @@ if test "$PHP_SAPI_CLI" != "no"; then PHP_CLI_TARGET="\$(SAPI_CLI_PATH)" PHP_INSTALL_CLI_TARGET="install-cli" - PHP_ADD_SOURCES(sapi/cli, php_cli.c getopt.c,, cli) + PHP_ADD_SOURCES(sapi/cli, php_cli.c php_cli_readline.c getopt.c,, cli) fi PHP_SUBST(PHP_CLI_TARGET) http://cvs.php.net/diff.php/php-src/sapi/cli/config.w32?r1=1.3&r2=1.4&ty=u Index: php-src/sapi/cli/config.w32 diff -u php-src/sapi/cli/config.w32:1.3 php-src/sapi/cli/config.w32:1.4 --- php-src/sapi/cli/config.w32:1.3 Tue Jan 13 22:14:17 2004 +++ php-src/sapi/cli/config.w32 Sat May 14 15:33:18 2005 @@ -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'); } http://cvs.php.net/diff.php/php-src/sapi/cli/php_cli.c?r1=1.123&r2=1.124&ty=u Index: php-src/sapi/cli/php_cli.c diff -u php-src/sapi/cli/php_cli.c:1.123 php-src/sapi/cli/php_cli.c:1.124 --- php-src/sapi/cli/php_cli.c:1.123 Sat May 7 08:24:18 2005 +++ php-src/sapi/cli/php_cli.c Sat May 14 15:33:18 2005 @@ -14,12 +14,13 @@ +----------------------------------------------------------------------+ | Author: Edin Kadribasic <[EMAIL PROTECTED]> | | Marcus Boerger <[EMAIL PROTECTED]> | + | Johannes Schlueter <[EMAIL PROTECTED]> | | Parts based on CGI SAPI Module by | | Rasmus Lerdorf, Stig Bakken and Zeev Suraski | +----------------------------------------------------------------------+ */ -/* $Id: php_cli.c,v 1.123 2005/05/07 12:24:18 helly Exp $ */ +/* $Id: php_cli.c,v 1.124 2005/05/14 19:33:18 helly Exp $ */ #include "php.h" #include "php_globals.h" @@ -74,7 +75,7 @@ #if !HAVE_LIBEDIT #include <readline/history.h> #endif -#endif +#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ #include "zend_compile.h" #include "zend_execute.h" @@ -83,6 +84,7 @@ #include "php_getopt.h" +#include "php_cli_readline.h" #ifndef O_BINARY #define O_BINARY 0 @@ -539,216 +541,6 @@ } /* }}} */ -#if HAVE_LIBREADLINE || HAVE_LIBEDIT - -/* {{{ cli_is_valid_code - */ -typedef enum { - body, - sstring, - dstring, - sstring_esc, - dstring_esc, - comment_line, - comment_block, - heredoc_start, - heredoc, - outside, -} php_code_type; - -static int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) -{ - int valid_end = 1; - 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 '\n': - case '\t': - break; - case '\'': - code_type = sstring; - break; - case '"': - code_type = dstring; - break; - case '/': - if (code[i+1] == '/') { - i++; - code_type = comment_line; - break; - } - if (code[i+1] == '*') { - 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; - } - 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_type = body; - } - 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; - } -} -/* }}} */ - -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ - /* {{{ main */ #ifdef PHP_CLI_WIN32_NO_CONSOLE @@ -1185,11 +977,11 @@ char *history_file; history_file = tilde_expand("~/.php_history"); + rl_attempted_completion_function = cli_code_completion; + /*rl_completion_append_character = '(';*/ + rl_special_prefixes = "$"; read_history(history_file); - /* it would be nicer to implement this correct */ - rl_bind_key ('\t', rl_insert); - EG(exit_status) = 0; while ((line = readline(pos ? prompt : "php > ")) != NULL) { if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) { http://cvs.php.net/co.php/php-src/sapi/cli/php_cli_readline.c?r=1.1&p=1 Index: php-src/sapi/cli/php_cli_readline.c +++ php-src/sapi/cli/php_cli_readline.c /* +----------------------------------------------------------------------+ | 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 | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Marcus Boerger <[EMAIL PROTECTED]> | | Johannes Schlueter <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ /* $Id: php_cli_readline.c,v 1.1 2005/05/14 19:33:18 helly Exp $ */ #include "php.h" #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 #if HAVE_LIBREADLINE || HAVE_LIBEDIT #include <readline/readline.h> #if !HAVE_LIBEDIT #include <readline/history.h> #endif #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ #include "zend_compile.h" #include "zend_execute.h" #include "zend_highlight.h" #include "zend_indent.h" #if HAVE_LIBREADLINE || HAVE_LIBEDIT /* {{{ 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; 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 '\n': case '\t': break; case '\'': code_type = sstring; break; case '"': code_type = dstring; break; case '/': if (code[i+1] == '/') { i++; code_type = comment_line; break; } if (code[i+1] == '*') { 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; } 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_type = body; } 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) + 1); 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(lc_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 */ http://cvs.php.net/co.php/php-src/sapi/cli/php_cli_readline.h?r=1.1&p=1 Index: php-src/sapi/cli/php_cli_readline.h +++ php-src/sapi/cli/php_cli_readline.h /* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2004 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 | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Marcus Boerger <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ /* $Id: php_cli_readline.h,v 1.1 2005/05/14 19:33:18 helly 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);
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php