24#ifndef HAVE_RL_COMPLETION_MATCHES
25#define rl_completion_matches completion_matches
38#include <unixlib/local.h>
42#include <editline/readline.h>
44#include <readline/readline.h>
45#include <readline/history.h>
56#if defined(COMPILE_DL_READLINE) && !defined(PHP_WIN32)
61#define RTLD_DEFAULT NULL
64#define DEFAULT_PROMPT "\\b \\> "
68static char php_last_char =
'\0';
69static FILE *pager_pipe =
NULL;
71static size_t readline_shell_write(
const char *str,
size_t str_length)
82 return fwrite(str, 1,
MIN(str_length, 16384), pager_pipe);
89static size_t readline_shell_ub_write(
const char *str,
size_t str_length)
94 php_last_char = str[str_length-1];
100static void cli_readline_init_globals(zend_cli_readline_globals *rg)
104 rg->prompt_str =
NULL;
131 bool unicode_warned =
false;
134 if (*prompt_spec ==
'\\') {
135 switch (prompt_spec[1]) {
137 smart_str_appendc(&
retval,
'\\');
141 smart_str_appendc(&
retval,
'\n');
145 smart_str_appendc(&
retval,
'\t');
149 smart_str_appendc(&
retval,
'\033');
159 smart_str_appends(&
retval, block);
167 smart_str_appendc(&
retval,
'`');
171 smart_str_appendc(&
retval,
'\\');
174 }
else if (*prompt_spec ==
'`') {
175 char *prompt_end =
strstr(prompt_spec + 1,
"`");
179 code =
estrndup(prompt_spec + 1, prompt_end - prompt_spec - 1);
187 prompt_spec = prompt_end;
190 if (!(*prompt_spec & 0x80)) {
191 smart_str_appendc(&
retval, *prompt_spec);
193 if (!unicode_warned) {
195 "prompt contains unsupported unicode characters");
196 unicode_warned =
true;
198 smart_str_appendc(&
retval,
'?');
201 }
while (++prompt_spec && *prompt_spec);
209 int valid_end = 1, last_valid_end;
210 int brackets_count = 0;
214 char *heredoc_tag =
NULL;
217 for (i = 0; i <
len; ++i) {
226 if (brackets_count > 0) {
229 valid_end = brackets_count ? 0 : 1;
236 if (brace_count > 0) {
242 valid_end = brace_count == 0 && brackets_count == 0;
256 if (code[i+1] ==
'[') {
263 if (code[i+1] ==
'/') {
268 if (code[i+1] ==
'*') {
269 last_valid_end = valid_end;
278 if (code[i+1] ==
'>') {
287 if (i + 2 <
len && code[i+1] ==
'<' && code[i+2] ==
'<') {
300 if (code[i] ==
'\\') {
303 if (code[i] ==
'\'') {
312 if (code[i] ==
'\\') {
315 if (code[i] ==
'"') {
324 if (code[i] ==
'\n') {
329 if (code[i-1] ==
'*' && code[i] ==
'/') {
331 valid_end = last_valid_end;
352 heredoc_tag = code+i;
360 if (!
strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) {
361 unsigned char c = code[i + 1];
362 char *
p = code + i - heredoc_len;
364 if ((c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'_' || c >= 0x80)
break;
365 while (*
p ==
' ' || *
p ==
'\t')
p--;
366 if (*
p !=
'\n')
break;
371 if ((
CG(short_tags) && !
strncmp(code+i-1,
"<?", 2))
372 || (i > 3 && !
strncmp(code+i-4,
"<?php", 5))
383 *
prompt = cli_get_prompt(
"php",
'(');
384 }
else if (brackets_count) {
385 *
prompt = cli_get_prompt(
"php",
'{');
387 *
prompt = cli_get_prompt(
"php",
'>');
392 *
prompt = cli_get_prompt(
"php",
'\'');
396 *
prompt = cli_get_prompt(
"php",
'"');
399 *
prompt = cli_get_prompt(
"/* ",
'>');
402 *
prompt = cli_get_prompt(
"<<<",
'>');
405 *
prompt = cli_get_prompt(
" ",
'>');
409 if (!valid_end || brackets_count) {
417static char *cli_completion_generator_ht(
const char *
text,
size_t textlen,
int *
state,
HashTable *
ht,
void **pData)
423 zend_hash_internal_pointer_reset(
ht);
426 while(zend_hash_has_more_elements(
ht) ==
SUCCESS) {
427 zend_hash_get_current_key(
ht, &
name, &number);
432 zend_hash_move_forward(
ht);
435 if (zend_hash_move_forward(
ht) ==
FAILURE) {
443static char *cli_completion_generator_var(
const char *
text,
size_t textlen,
int *
state)
448 tmp =
retval = cli_completion_generator_ht(
text + 1, textlen - 1,
state, symbol_table,
NULL);
453 rl_completion_append_character =
'\0';
458static char *cli_completion_generator_ini(
const char *
text,
size_t textlen,
int *
state)
467 rl_completion_append_character =
'=';
472static char *cli_completion_generator_func(
const char *
text,
size_t textlen,
int *
state,
HashTable *
ht)
477 rl_completion_append_character =
'(';
484static char *cli_completion_generator_class(
const char *
text,
size_t textlen,
int *
state)
487 char *
retval = cli_completion_generator_ht(
text, textlen,
state,
EG(class_table), (
void**)&ce);
489 rl_completion_append_character =
'\0';
496static char *cli_completion_generator_define(
const char *
text,
size_t textlen,
int *
state,
HashTable *
ht)
499 char *
retval = cli_completion_generator_ht(
text, textlen,
state,
ht, (
void**)&pce);
501 rl_completion_append_character =
'\0';
508static int cli_completion_state;
510static char *cli_completion_generator(
const char *
text,
int index)
525 cli_completion_state = 0;
527 if (
text[0] ==
'$') {
528 retval = cli_completion_generator_var(
text, textlen, &cli_completion_state);
529 }
else if (
text[0] ==
'#' &&
text[1] !=
'[') {
530 retval = cli_completion_generator_ini(
text, textlen, &cli_completion_state);
532 char *lc_text, *class_name_end;
537 if (class_name_end) {
538 size_t class_name_len = class_name_end -
text;
539 class_name = zend_string_alloc(class_name_len, 0);
546 textlen -= (class_name_len + 2);
551 switch (cli_completion_state) {
554 retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, ce ? &ce->
function_table :
EG(function_table));
568 retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state);
579 char *tmp = malloc(
len);
590static char **cli_code_completion(
const char *
text,
int start,
int end)
596static int readline_shell_run(
void)
603 int history_lines_to_write = 0;
605 if (
PG(auto_prepend_file) &&
PG(auto_prepend_file)[0]) {
614 const char *histfile_env_name =
"PHP_HISTFILE";
615 if (
getenv(histfile_env_name)) {
621 spprintf(&history_file, MAX_PATH,
"%s/.php_history",
getenv(
"USERPROFILE"));
629 rl_attempted_completion_function = cli_code_completion;
632 rl_special_prefixes =
"$";
634 read_history(history_file);
650 if (
line[0] ==
'#' &&
line[1] !=
'[') {
655 cmd = zend_string_init(&
line[1], param - &
line[1] - 1, 0);
663 prompt = cli_get_prompt(
"php",
'>');
679 history_lines_to_write += 1;
685 if (!cli_is_valid_code(code,
pos, &
prompt)) {
689 if (history_lines_to_write) {
691 write_history(history_file);
693 append_history(history_lines_to_write, history_file);
695 history_lines_to_write = 0;
704 if (!pager_pipe && php_last_char !=
'\0' && php_last_char !=
'\n') {
717 php_last_char =
'\0';
722 return EG(exit_status);
728#define GET_SHELL_CB(cb) \
730 get_cli_shell_callbacks get_callbacks; \
731 HMODULE hMod = GetModuleHandle("php.exe"); \
733 if (strlen(sapi_module.name) >= 3 && 0 == strncmp("cli", sapi_module.name, 3)) { \
734 get_callbacks = (get_cli_shell_callbacks)GetProcAddress(hMod, "php_cli_get_shell_callbacks"); \
735 if (get_callbacks) { \
736 (cb) = get_callbacks(); \
748#define GET_SHELL_CB(cb) \
751 cli_shell_callbacks_t *(*get_callbacks)(void); \
752 get_callbacks = dlsym(RTLD_DEFAULT, "php_cli_get_shell_callbacks"); \
753 if (get_callbacks) { \
754 (cb) = get_callbacks(); \
771 cb->cli_shell_write = readline_shell_write;
772 cb->cli_shell_ub_write = readline_shell_ub_write;
773 cb->cli_shell_run = readline_shell_run;
787 cb->cli_shell_write =
NULL;
788 cb->cli_shell_ub_write =
NULL;
getenv(?string $name=null, bool $local_only=false)
fwrite($stream, string $data, ?int $length=null)
strstr(string $haystack, string $needle, bool $before_needle=false)
PHPAPI size_t php_write(void *buf, size_t size)
php_info_print_table_start()
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
#define PHP_MSHUTDOWN_FUNCTION
#define PHP_MINIT_FUNCTION
#define PHP_MINFO_FUNCTION
unsigned const char * end
unsigned const char * pos
unsigned const char * text
#define PHP_INI_STAGE_RUNTIME
#define STD_PHP_INI_ENTRY
readline(?string $prompt=null)
#define rl_completion_matches
char ** php_readline_completion_cb(const char *text, int start, int end)
HashTable constants_table
ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count,...)
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor)
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
#define estrndup(s, length)
#define erealloc(ptr, size)
strncmp(string $string1, string $string2, int $length)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle)
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severity)
ZEND_API zend_class_entry * zend_lookup_class(zend_string *name)
ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *retval_ptr, const char *string_name)
union _zend_function zend_function
#define zend_hash_get_current_data_ptr(ht)
ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, int force_change)
#define UNREGISTER_INI_ENTRIES()
#define REGISTER_INI_ENTRIES()
#define DISPLAY_INI_ENTRIES()
struct _zend_file_handle zend_file_handle
struct _zend_string zend_string
ZEND_API char *ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length)
ZEND_API char *ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length)
struct _zend_array zend_array
struct _zend_class_entry zend_class_entry
ZEND_API void zend_stream_init_filename(zend_file_handle *handle, const char *filename)
struct _zend_array HashTable
#define VCWD_POPEN(command, type)