]> granicus.if.org Git - php/commitdiff
- missing files
authorPierre Joye <pajoye@php.net>
Tue, 22 Feb 2011 12:59:50 +0000 (12:59 +0000)
committerPierre Joye <pajoye@php.net>
Tue, 22 Feb 2011 12:59:50 +0000 (12:59 +0000)
sapi/cli/php_cli_readline.c [new file with mode: 0644]
sapi/cli/php_cli_readline.h [new file with mode: 0644]

diff --git a/sapi/cli/php_cli_readline.c b/sapi/cli/php_cli_readline.c
new file mode 100644 (file)
index 0000000..62d1185
--- /dev/null
@@ -0,0 +1,448 @@
+/*\r
+   +----------------------------------------------------------------------+\r
+   | PHP Version 5                                                        |\r
+   +----------------------------------------------------------------------+\r
+   | Copyright (c) 1997-2011 The PHP Group                                |\r
+   +----------------------------------------------------------------------+\r
+   | This source file is subject to version 3.01 of the PHP license,      |\r
+   | that is bundled with this package in the file LICENSE, and is        |\r
+   | available through the world-wide-web at the following url:           |\r
+   | http://www.php.net/license/3_01.txt                                  |\r
+   | If you did not receive a copy of the PHP license and are unable to   |\r
+   | obtain it through the world-wide-web, please send a note to          |\r
+   | license@php.net so we can mail you a copy immediately.               |\r
+   +----------------------------------------------------------------------+\r
+   | Author: Marcus Boerger <helly@php.net>                               |\r
+   |         Johannes Schlueter <johannes@php.net>                        |\r
+   +----------------------------------------------------------------------+\r
+*/\r
+\r
+/* $Id: php_cli_readline.c 306939 2011-01-01 02:19:59Z felipe $ */\r
+\r
+#include "php.h"\r
+\r
+#if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE)\r
+\r
+#ifndef HAVE_RL_COMPLETION_MATCHES\r
+#define rl_completion_matches completion_matches\r
+#endif\r
+\r
+#include "php_globals.h"\r
+#include "php_variables.h"\r
+#include "zend_hash.h"\r
+#include "zend_modules.h"\r
+\r
+#include "SAPI.h"\r
+\r
+#if HAVE_SETLOCALE\r
+#include <locale.h>\r
+#endif\r
+#include "zend.h"\r
+#include "zend_extensions.h"\r
+#include "php_ini.h"\r
+#include "php_globals.h"\r
+#include "php_main.h"\r
+#include "fopen_wrappers.h"\r
+#include "ext/standard/php_standard.h"\r
+\r
+#ifdef __riscos__\r
+#include <unixlib/local.h>\r
+#endif\r
+\r
+#if HAVE_LIBEDIT\r
+#include <editline/readline.h>\r
+#else\r
+#include <readline/readline.h>\r
+#include <readline/history.h>\r
+#endif\r
+\r
+#include "zend_compile.h"\r
+#include "zend_execute.h"\r
+#include "zend_highlight.h"\r
+#include "zend_indent.h"\r
+\r
+typedef enum {\r
+       body,\r
+       sstring,\r
+       dstring,\r
+       sstring_esc,\r
+       dstring_esc,\r
+       comment_line,\r
+       comment_block,\r
+       heredoc_start,\r
+       heredoc,\r
+       outside,\r
+} php_code_type;\r
+\r
+int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */\r
+{\r
+       int valid_end = 1, last_valid_end;\r
+       int brackets_count = 0;\r
+       int brace_count = 0;\r
+       int i;\r
+       php_code_type code_type = body;\r
+       char *heredoc_tag;\r
+       int heredoc_len;\r
+\r
+       for (i = 0; i < len; ++i) {\r
+               switch(code_type) {\r
+                       default:\r
+                               switch(code[i]) {\r
+                                       case '{':\r
+                                               brackets_count++;\r
+                                               valid_end = 0;\r
+                                               break;\r
+                                       case '}':\r
+                                               if (brackets_count > 0) {\r
+                                                       brackets_count--;\r
+                                               }\r
+                                               valid_end = brackets_count ? 0 : 1;\r
+                                               break;\r
+                                       case '(':\r
+                                               brace_count++;\r
+                                               valid_end = 0;\r
+                                               break;\r
+                                       case ')':\r
+                                               if (brace_count > 0) {\r
+                                                       brace_count--;\r
+                                               }\r
+                                               valid_end = 0;\r
+                                               break;\r
+                                       case ';':\r
+                                               valid_end = brace_count == 0 && brackets_count == 0;\r
+                                               break;\r
+                                       case ' ':\r
+                                       case '\r':\r
+                                       case '\n':\r
+                                       case '\t':\r
+                                               break;\r
+                                       case '\'':\r
+                                               code_type = sstring;\r
+                                               break;\r
+                                       case '"':\r
+                                               code_type = dstring;\r
+                                               break;\r
+                                       case '#':\r
+                                               code_type = comment_line;\r
+                                               break;\r
+                                       case '/':\r
+                                               if (code[i+1] == '/') {\r
+                                                       i++;\r
+                                                       code_type = comment_line;\r
+                                                       break;\r
+                                               }\r
+                                               if (code[i+1] == '*') {\r
+                                                       last_valid_end = valid_end;\r
+                                                       valid_end = 0;\r
+                                                       code_type = comment_block;\r
+                                                       i++;\r
+                                                       break;\r
+                                               }\r
+                                               valid_end = 0;\r
+                                               break;\r
+                                       case '%':\r
+                                               if (!CG(asp_tags)) {\r
+                                                       valid_end = 0;\r
+                                                       break;\r
+                                               }\r
+                                               /* no break */\r
+                                       case '?':\r
+                                               if (code[i+1] == '>') {\r
+                                                       i++;\r
+                                                       code_type = outside;\r
+                                                       break;\r
+                                               }\r
+                                               valid_end = 0;\r
+                                               break;\r
+                                       case '<':\r
+                                               valid_end = 0;\r
+                                               if (i + 2 < len && code[i+1] == '<' && code[i+2] == '<') {\r
+                                                       i += 2;\r
+                                                       code_type = heredoc_start;\r
+                                                       heredoc_len = 0;\r
+                                               }\r
+                                               break;\r
+                                       default:\r
+                                               valid_end = 0;\r
+                                               break;\r
+                               }\r
+                               break;\r
+                       case sstring:\r
+                               if (code[i] == '\\') {\r
+                                       code_type = sstring_esc;\r
+                               } else {\r
+                                       if (code[i] == '\'') {\r
+                                               code_type = body;\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case sstring_esc:\r
+                               code_type = sstring;\r
+                               break;\r
+                       case dstring:\r
+                               if (code[i] == '\\') {\r
+                                       code_type = dstring_esc;\r
+                               } else {\r
+                                       if (code[i] == '"') {\r
+                                               code_type = body;\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case dstring_esc:\r
+                               code_type = dstring;\r
+                               break;\r
+                       case comment_line:\r
+                               if (code[i] == '\n') {\r
+                                       code_type = body;\r
+                               }\r
+                               break;\r
+                       case comment_block:\r
+                               if (code[i-1] == '*' && code[i] == '/') {\r
+                                       code_type = body;\r
+                                       valid_end = last_valid_end;\r
+                               }\r
+                               break;\r
+                       case heredoc_start:\r
+                               switch(code[i]) {\r
+                                       case ' ':\r
+                                       case '\t':\r
+                                               break;\r
+                                       case '\r':\r
+                                       case '\n':\r
+                                               code_type = heredoc;\r
+                                               break;\r
+                                       default:\r
+                                               if (!heredoc_len) {\r
+                                                       heredoc_tag = code+i;\r
+                                               }\r
+                                               heredoc_len++;\r
+                                               break;\r
+                               }\r
+                               break;\r
+                       case heredoc:\r
+                               if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') {\r
+                                       code_type = body;\r
+                               } else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') {\r
+                                       code_type = body;\r
+                                       valid_end = 1;\r
+                               }\r
+                               break;\r
+                       case outside:\r
+                               if ((CG(short_tags) && !strncmp(code+i-1, "<?", 2))\r
+                               ||  (CG(asp_tags) && !strncmp(code+i-1, "<%", 2))\r
+                               ||  (i > 3 && !strncmp(code+i-4, "<?php", 5))\r
+                               ) {\r
+                                       code_type = body;\r
+                               }\r
+                               break;\r
+               }\r
+       }\r
+\r
+       switch (code_type) {\r
+               default:\r
+                       if (brace_count) {\r
+                               *prompt = "php ( ";\r
+                       } else if (brackets_count) {\r
+                               *prompt = "php { ";\r
+                       } else {\r
+                               *prompt = "php > ";\r
+                       }\r
+                       break;\r
+               case sstring:\r
+               case sstring_esc:\r
+                       *prompt = "php ' ";\r
+                       break;\r
+               case dstring:\r
+               case dstring_esc:\r
+                       *prompt = "php \" ";\r
+                       break;\r
+               case comment_block:\r
+                       *prompt = "/*  > ";\r
+                       break;\r
+               case heredoc:\r
+                       *prompt = "<<< > ";\r
+                       break;\r
+               case outside:\r
+                       *prompt = "    > ";\r
+                       break;\r
+       }\r
+\r
+       if (!valid_end || brackets_count) {\r
+               return 0;\r
+       } else {\r
+               return 1;\r
+       }\r
+}\r
+/* }}} */\r
+\r
+static char *cli_completion_generator_ht(const char *text, int textlen, int *state, HashTable *ht, void **pData TSRMLS_DC) /* {{{ */\r
+{\r
+       char *name;\r
+       ulong number;\r
+\r
+       if (!(*state % 2)) {\r
+               zend_hash_internal_pointer_reset(ht);\r
+               (*state)++;\r
+       }\r
+       while(zend_hash_has_more_elements(ht) == SUCCESS) {\r
+               zend_hash_get_current_key(ht, &name, &number, 0);\r
+               if (!textlen || !strncmp(name, text, textlen)) {\r
+                       if (pData) {\r
+                               zend_hash_get_current_data(ht, pData);\r
+                       }\r
+                       zend_hash_move_forward(ht);\r
+                       return name;\r
+               }\r
+               if (zend_hash_move_forward(ht) == FAILURE) {\r
+                       break;\r
+               }\r
+       }\r
+       (*state)++;\r
+       return NULL;\r
+} /* }}} */\r
+\r
+static char *cli_completion_generator_var(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */\r
+{\r
+       char *retval, *tmp;\r
+\r
+       tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(active_symbol_table), NULL TSRMLS_CC);\r
+       if (retval) {\r
+               retval = malloc(strlen(tmp) + 2);\r
+               retval[0] = '$';\r
+               strcpy(&retval[1], tmp);\r
+               rl_completion_append_character = '\0';\r
+       }\r
+       return retval;\r
+} /* }}} */\r
+\r
+static char *cli_completion_generator_func(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */\r
+{\r
+       zend_function *func;\r
+       char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&func TSRMLS_CC);\r
+       if (retval) {\r
+               rl_completion_append_character = '(';\r
+               retval = strdup(func->common.function_name);\r
+       }\r
+       \r
+       return retval;\r
+} /* }}} */\r
+\r
+static char *cli_completion_generator_class(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */\r
+{\r
+       zend_class_entry **pce;\r
+       char *retval = cli_completion_generator_ht(text, textlen, state, EG(class_table), (void**)&pce TSRMLS_CC);\r
+       if (retval) {\r
+               rl_completion_append_character = '\0';\r
+               retval = strdup((*pce)->name);\r
+       }\r
+       \r
+       return retval;\r
+} /* }}} */\r
+\r
+static char *cli_completion_generator_define(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */\r
+{\r
+       zend_class_entry **pce;\r
+       char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&pce TSRMLS_CC);\r
+       if (retval) {\r
+               rl_completion_append_character = '\0';\r
+               retval = strdup(retval);\r
+       }\r
+       \r
+       return retval;\r
+} /* }}} */\r
+\r
+static int cli_completion_state;\r
+\r
+static char *cli_completion_generator(const char *text, int index) /* {{{ */\r
+{\r
+/*\r
+TODO:\r
+- constants\r
+- maybe array keys\r
+- language constructs and other things outside a hashtable (echo, try, function, class, ...)\r
+- object/class members\r
+\r
+- future: respect scope ("php > function foo() { $[tab]" should only expand to local variables...)\r
+*/\r
+       char *retval = NULL;\r
+       int textlen = strlen(text);\r
+       TSRMLS_FETCH();\r
+\r
+       if (!index) {\r
+               cli_completion_state = 0;\r
+       }\r
+       if (text[0] == '$') {\r
+               retval = cli_completion_generator_var(text, textlen, &cli_completion_state TSRMLS_CC);\r
+       } else {\r
+               char *lc_text, *class_name, *class_name_end;\r
+               int class_name_len;\r
+               zend_class_entry **pce = NULL;\r
+               \r
+               class_name_end = strstr(text, "::");\r
+               if (class_name_end) {\r
+                       class_name_len = class_name_end - text;\r
+                       class_name = zend_str_tolower_dup(text, class_name_len);\r
+                       class_name[class_name_len] = '\0'; /* not done automatically */\r
+                       if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) {\r
+                               efree(class_name);\r
+                               return NULL;\r
+                       }\r
+                       lc_text = zend_str_tolower_dup(class_name_end + 2, textlen - 2 - class_name_len);\r
+                       textlen -= (class_name_len + 2);\r
+               } else {\r
+                       lc_text = zend_str_tolower_dup(text, textlen);\r
+               }\r
+\r
+               switch (cli_completion_state) {\r
+                       case 0:\r
+                       case 1:\r
+                               retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, pce ? &(*pce)->function_table : EG(function_table) TSRMLS_CC);\r
+                               if (retval) {\r
+                                       break;\r
+                               }\r
+                       case 2:\r
+                       case 3:\r
+                               retval = cli_completion_generator_define(text, textlen, &cli_completion_state, pce ? &(*pce)->constants_table : EG(zend_constants) TSRMLS_CC);\r
+                               if (retval || pce) {\r
+                                       break;\r
+                               }\r
+                       case 4:\r
+                       case 5:\r
+                               retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state TSRMLS_CC);\r
+                               break;\r
+                       default:\r
+                               break;\r
+               }\r
+               efree(lc_text);\r
+               if (class_name_end) {\r
+                       efree(class_name);\r
+               }\r
+               if (pce && retval) {\r
+                       int len = class_name_len + 2 + strlen(retval) + 1;\r
+                       char *tmp = malloc(len);\r
+                       \r
+                       snprintf(tmp, len, "%s::%s", (*pce)->name, retval);\r
+                       free(retval);\r
+                       retval = tmp;\r
+               }\r
+       }\r
+       \r
+       return retval;\r
+} /* }}} */\r
+\r
+char **cli_code_completion(const char *text, int start, int end) /* {{{ */\r
+{\r
+       return rl_completion_matches(text, cli_completion_generator);\r
+}\r
+/* }}} */\r
+\r
+#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */\r
+\r
+/*\r
+ * Local variables:\r
+ * tab-width: 4\r
+ * c-basic-offset: 4\r
+ * End:\r
+ * vim600: sw=4 ts=4 fdm=marker\r
+ * vim<600: sw=4 ts=4\r
+ */\r
diff --git a/sapi/cli/php_cli_readline.h b/sapi/cli/php_cli_readline.h
new file mode 100644 (file)
index 0000000..1661a95
--- /dev/null
@@ -0,0 +1,25 @@
+/*\r
+   +----------------------------------------------------------------------+\r
+   | PHP Version 5                                                        |\r
+   +----------------------------------------------------------------------+\r
+   | Copyright (c) 1997-2011 The PHP Group                                |\r
+   +----------------------------------------------------------------------+\r
+   | This source file is subject to version 3.01 of the PHP license,      |\r
+   | that is bundled with this package in the file LICENSE, and is        |\r
+   | available through the world-wide-web at the following url:           |\r
+   | http://www.php.net/license/3_01.txt                                  |\r
+   | If you did not receive a copy of the PHP license and are unable to   |\r
+   | obtain it through the world-wide-web, please send a note to          |\r
+   | license@php.net so we can mail you a copy immediately.               |\r
+   +----------------------------------------------------------------------+\r
+   | Author: Marcus Boerger <helly@php.net>                               |\r
+   +----------------------------------------------------------------------+\r
+*/\r
+\r
+/* $Id: php_cli_readline.h 306939 2011-01-01 02:19:59Z felipe $ */\r
+\r
+#include "php.h"\r
+\r
+int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC);\r
+\r
+char **cli_code_completion(const char *text, int start, int end);\r