[php-src] master: ext/readline: Refactor CLI readline completion generators

From: Date: Fri, 09 Oct 2026 13:57:44 +0000
Subject: [php-src] master: ext/readline: Refactor CLI readline completion generators
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142115@lists.php.net to get a copy of this message
Author: Weilin Du (LamentXU123) Committer: GitHub (web-flow) Pusher: LamentXU123 Date: 2026-10-09T21:57:40+08:00 Commit: https://github.com/php/php-src/commit/ea9454d35281856801433760c392b294059741ce Raw diff: https://github.com/php/php-src/commit/ea9454d35281856801433760c392b294059741ce.diff ext/readline: Refactor CLI readline completion generators Replace strcpy() with length-aware memcpy() and check malloc() failures. Changed paths: M ext/readline/readline_cli.c Diff: diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 973aea106112..3f435b82c784 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -412,7 +412,15 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ } /* }}} */ -static char *cli_completion_generator_ht(const char *text, size_t textlen, int *state, HashTable *ht, void **pData) /* {{{ */ +typedef enum { + CLI_COMPLETION_VARIABLE, + CLI_COMPLETION_INI, + CLI_COMPLETION_FUNCTION, + CLI_COMPLETION_CONSTANT, + CLI_COMPLETION_CLASS, +} cli_completion_type; + +static char *cli_completion_generator_ht(const char *text, size_t textlen, int *state, HashTable *ht, cli_completion_type type) /* {{{ */ { zend_string *name; zend_ulong number; @@ -421,14 +429,48 @@ static char *cli_completion_generator_ht(const char *text, size_t textlen, int * zend_hash_internal_pointer_reset(ht); (*state)++; } - while(zend_hash_has_more_elements(ht) == SUCCESS) { + while (zend_hash_has_more_elements(ht) == SUCCESS) { zend_hash_get_current_key(ht, &name, &number); if (!textlen || !strncmp(ZSTR_VAL(name), text, textlen)) { - if (pData) { - *pData = zend_hash_get_current_data_ptr(ht); + char prefix = '\0'; + char append_character = '\0'; + + switch (type) { + case CLI_COMPLETION_VARIABLE: + prefix = '$'; + break; + case CLI_COMPLETION_INI: + prefix = '#'; + append_character = '='; + break; + case CLI_COMPLETION_FUNCTION: { + zend_function *func = zend_hash_get_current_data_ptr(ht); + name = func->common.function_name; + append_character = '('; + break; + } + case CLI_COMPLETION_CLASS: { + zend_class_entry *ce = zend_hash_get_current_data_ptr(ht); + name = ce->name; + break; + } + case CLI_COMPLETION_CONSTANT: + break; } + zend_hash_move_forward(ht); - return ZSTR_VAL(name); + /* The line editing library takes ownership of the candidate. */ + size_t prefix_len = prefix ? 1 : 0; + char *retval = malloc(prefix_len + ZSTR_LEN(name) + 1); + if (!retval) { + return NULL; + } + if (prefix) { + retval[0] = prefix; + } + memcpy(retval + prefix_len, ZSTR_VAL(name), ZSTR_LEN(name) + 1); + rl_completion_append_character = append_character; + return retval; } if (zend_hash_move_forward(ht) == FAILURE) { break; @@ -438,71 +480,6 @@ static char *cli_completion_generator_ht(const char *text, size_t textlen, int * return NULL; } /* }}} */ -static char *cli_completion_generator_var(const char *text, size_t textlen, int *state) /* {{{ */ -{ - char *retval, *tmp; - zend_array *symbol_table = &EG(symbol_table); - - tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, symbol_table, NULL); - 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, size_t textlen, int *state) /* {{{ */ -{ - char *retval, *tmp; - - tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(ini_directives), NULL); - 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, size_t textlen, int *state, HashTable *ht) /* {{{ */ -{ - zend_function *func; - char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&func); - if (retval) { - rl_completion_append_character = '('; - retval = strdup(ZSTR_VAL(func->common.function_name)); - } - - return retval; -} /* }}} */ - -static char *cli_completion_generator_class(const char *text, size_t textlen, int *state) /* {{{ */ -{ - zend_class_entry *ce; - char *retval = cli_completion_generator_ht(text, textlen, state, EG(class_table), (void**)&ce); - if (retval) { - rl_completion_append_character = '\0'; - retval = strdup(ZSTR_VAL(ce->name)); - } - - return retval; -} /* }}} */ - -static char *cli_completion_generator_define(const char *text, size_t textlen, int *state, HashTable *ht) /* {{{ */ -{ - zend_class_entry **pce; - char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&pce); - 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) /* {{{ */ @@ -523,9 +500,9 @@ static char *cli_completion_generator(const char *text, int index) /* {{{ */ cli_completion_state = 0; } if (text[0] == '$') { - retval = cli_completion_generator_var(text, textlen, &cli_completion_state); + retval = cli_completion_generator_ht(text + 1, textlen - 1, &cli_completion_state, &EG(symbol_table), CLI_COMPLETION_VARIABLE); } else if (text[0] == '#' && text[1] != '[') { - retval = cli_completion_generator_ini(text, textlen, &cli_completion_state); + retval = cli_completion_generator_ht(text + 1, textlen - 1, &cli_completion_state, EG(ini_directives), CLI_COMPLETION_INI); } else { char *lc_text; const char *class_name_end; @@ -552,21 +529,21 @@ static char *cli_completion_generator(const char *text, int index) /* {{{ */ switch (cli_completion_state) { case 0: case 1: - retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, ce ? &ce->function_table : EG(function_table)); + retval = cli_completion_generator_ht(lc_text, textlen, &cli_completion_state, ce ? &ce->function_table : EG(function_table), CLI_COMPLETION_FUNCTION); if (retval) { break; } ZEND_FALLTHROUGH; case 2: case 3: - retval = cli_completion_generator_define(constant_text, textlen, &cli_completion_state, ce ? &ce->constants_table : EG(zend_constants)); + retval = cli_completion_generator_ht(constant_text, textlen, &cli_completion_state, ce ? &ce->constants_table : EG(zend_constants), CLI_COMPLETION_CONSTANT); if (retval || ce) { break; } ZEND_FALLTHROUGH; case 4: case 5: - retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state); + retval = cli_completion_generator_ht(lc_text, textlen, &cli_completion_state, EG(class_table), CLI_COMPLETION_CLASS); break; default: break;

« previous php.cvs (#142115) next »