php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
readline.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Thies C. Arntzen <thies@thieso.net> |
14 +----------------------------------------------------------------------+
15*/
16
17/* {{{ includes & prototypes */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include "php.h"
24#include "php_readline.h"
25#include "readline_cli.h"
26#include "readline_arginfo.h"
27
28#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
29
30#ifndef HAVE_RL_COMPLETION_MATCHES
31#define rl_completion_matches completion_matches
32#endif
33
34#ifdef HAVE_LIBEDIT
35#include <editline/readline.h>
36#else
37#include <readline/readline.h>
38#include <readline/history.h>
39#endif
40
41#ifdef HAVE_RL_CALLBACK_READ_CHAR
42
43static zval _prepped_callback;
44
45#endif
46
47static zval _readline_completion;
48static zval _readline_array;
49
54
55/* }}} */
56
57/* {{{ module stuff */
58zend_module_entry readline_module_entry = {
60 "readline",
61 ext_functions,
64 NULL,
67 PHP_READLINE_VERSION,
69};
70
71#ifdef COMPILE_DL_READLINE
73#endif
74
76{
77#ifdef HAVE_LIBREADLINE
78 /* libedit don't need this call which set the tty in cooked mode */
79 using_history();
80#endif
81 ZVAL_UNDEF(&_readline_completion);
82#ifdef HAVE_RL_CALLBACK_READ_CHAR
83 ZVAL_UNDEF(&_prepped_callback);
84#endif
85
86 register_readline_symbols(module_number);
87
88 return PHP_MINIT(cli_readline)(INIT_FUNC_ARGS_PASSTHRU);
89}
90
92{
93 return PHP_MSHUTDOWN(cli_readline)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
94}
95
97{
98 zval_ptr_dtor(&_readline_completion);
99 ZVAL_UNDEF(&_readline_completion);
100#ifdef HAVE_RL_CALLBACK_READ_CHAR
101 if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
102 rl_callback_handler_remove();
103 zval_ptr_dtor(&_prepped_callback);
104 ZVAL_UNDEF(&_prepped_callback);
105 }
106#endif
107
108 return SUCCESS;
109}
110
112{
114}
115
116/* }}} */
117
118/* {{{ Reads a line */
120{
121 char *prompt = NULL;
122 size_t prompt_len;
123 char *result;
124
125 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &prompt, &prompt_len)) {
127 }
128
130
131 if (! result) {
133 } else {
135 free(result);
136 }
137}
138
139/* }}} */
140
141#define SAFE_STRING(s) ((s)?(char*)(s):"")
142
143/* {{{ Gets/sets various internal readline variables. */
145{
146 zend_string *what = NULL;
147 zval *value = NULL;
148 size_t oldval;
149 char *oldstr;
150
151 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!z!", &what, &value) == FAILURE) {
153 }
154
155 if (!what) {
157 add_assoc_string(return_value,"line_buffer",SAFE_STRING(rl_line_buffer));
158 add_assoc_long(return_value,"point",rl_point);
159#ifndef PHP_WIN32
160 add_assoc_long(return_value,"end",rl_end);
161#endif
162#ifdef HAVE_LIBREADLINE
163 add_assoc_long(return_value,"mark",rl_mark);
164 add_assoc_long(return_value,"done",rl_done);
165 add_assoc_long(return_value,"pending_input",rl_pending_input);
166 add_assoc_string(return_value,"prompt",SAFE_STRING(rl_prompt));
167 add_assoc_string(return_value,"terminal_name",(char *)SAFE_STRING(rl_terminal_name));
168 add_assoc_str(return_value, "completion_append_character",
169 rl_completion_append_character == 0
171 : ZSTR_CHAR(rl_completion_append_character));
172 add_assoc_bool(return_value,"completion_suppress_append",rl_completion_suppress_append);
173#endif
174#ifdef HAVE_ERASE_EMPTY_LINE
175 add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line);
176#endif
177#ifndef PHP_WIN32
178 add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version));
179#endif
180 add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name));
181 add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over);
182 } else {
183 if (zend_string_equals_literal_ci(what,"line_buffer")) {
184 oldstr = strdup(rl_line_buffer ? rl_line_buffer : "");
185 if (value) {
186 if (!try_convert_to_string(value)) {
188 }
189#if !defined(PHP_WIN32) && !defined(HAVE_LIBEDIT)
190 if (!rl_line_buffer) {
191 rl_line_buffer = malloc(Z_STRLEN_P(value) + 1);
192 } else if (strlen(oldstr) < Z_STRLEN_P(value)) {
193 rl_extend_line_buffer(Z_STRLEN_P(value) + 1);
194 free(oldstr);
195 oldstr = strdup(rl_line_buffer ? rl_line_buffer : "");
196 }
197 memcpy(rl_line_buffer, Z_STRVAL_P(value), Z_STRLEN_P(value) + 1);
198#else
199 char *tmp = strdup(Z_STRVAL_P(value));
200 if (tmp) {
201 if (rl_line_buffer) {
202 free(rl_line_buffer);
203 }
204 rl_line_buffer = tmp;
205 }
206#endif
207#if !defined(PHP_WIN32)
208 rl_end = Z_STRLEN_P(value);
209#endif
210 }
211 RETVAL_STRING(SAFE_STRING(oldstr));
212 free(oldstr);
213 } else if (zend_string_equals_literal_ci(what, "point")) {
214 RETVAL_LONG(rl_point);
215#ifndef PHP_WIN32
216 } else if (zend_string_equals_literal_ci(what, "end")) {
217 RETVAL_LONG(rl_end);
218#endif
219#ifdef HAVE_LIBREADLINE
220 } else if (zend_string_equals_literal_ci(what, "mark")) {
221 RETVAL_LONG(rl_mark);
222 } else if (zend_string_equals_literal_ci(what, "done")) {
223 oldval = rl_done;
224 if (value) {
225 rl_done = zval_get_long(value);
226 }
227 RETVAL_LONG(oldval);
228 } else if (zend_string_equals_literal_ci(what, "pending_input")) {
229 oldval = rl_pending_input;
230 if (value) {
231 if (!try_convert_to_string(value)) {
233 }
234 rl_pending_input = Z_STRVAL_P(value)[0];
235 }
236 RETVAL_LONG(oldval);
237 } else if (zend_string_equals_literal_ci(what, "prompt")) {
238 RETVAL_STRING(SAFE_STRING(rl_prompt));
239 } else if (zend_string_equals_literal_ci(what, "terminal_name")) {
240 RETVAL_STRING((char *)SAFE_STRING(rl_terminal_name));
241 } else if (zend_string_equals_literal_ci(what, "completion_suppress_append")) {
242 oldval = rl_completion_suppress_append;
243 if (value) {
244 rl_completion_suppress_append = zend_is_true(value);
245 }
246 RETVAL_BOOL(oldval);
247 } else if (zend_string_equals_literal_ci(what, "completion_append_character")) {
248 oldval = rl_completion_append_character;
249 if (value) {
250 if (!try_convert_to_string(value)) {
252 }
253 rl_completion_append_character = (int)Z_STRVAL_P(value)[0];
254 }
256 oldval == 0 ? ZSTR_EMPTY_ALLOC() : ZSTR_CHAR(oldval));
257#endif
258#ifdef HAVE_ERASE_EMPTY_LINE
259 } else if (zend_string_equals_literal_ci(what, "erase_empty_line")) {
260 oldval = rl_erase_empty_line;
261 if (value) {
262 rl_erase_empty_line = zval_get_long(value);
263 }
264 RETVAL_LONG(oldval);
265#endif
266#ifndef PHP_WIN32
267 } else if (zend_string_equals_literal_ci(what,"library_version")) {
268 RETVAL_STRING((char *)SAFE_STRING(rl_library_version));
269#endif
270 } else if (zend_string_equals_literal_ci(what, "readline_name")) {
271 oldstr = (char*)rl_readline_name;
272 if (value) {
273 /* XXX if (rl_readline_name) free(rl_readline_name); */
274 if (!try_convert_to_string(value)) {
276 }
277 rl_readline_name = strdup(Z_STRVAL_P(value));
278 }
279 RETVAL_STRING(SAFE_STRING(oldstr));
280 } else if (zend_string_equals_literal_ci(what, "attempted_completion_over")) {
281 oldval = rl_attempted_completion_over;
282 if (value) {
283 rl_attempted_completion_over = zval_get_long(value);
284 }
285 RETVAL_LONG(oldval);
286 }
287 }
288}
289
290/* }}} */
291/* {{{ Adds a line to the history */
293{
294 char *arg;
295 size_t arg_len;
296
297 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
299 }
300
301 add_history(arg);
302
304}
305
306/* }}} */
307/* {{{ Clears the history */
309{
312 }
313
314#ifdef HAVE_LIBEDIT
315 /* clear_history is the only function where rl_initialize
316 is not call to ensure correct allocation */
317 using_history();
318#endif
319 clear_history();
320
322}
323
324/* }}} */
325
326#ifdef HAVE_HISTORY_LIST
327/* {{{ Lists the history */
329{
330 HIST_ENTRY **history;
331
334 }
335
337
338#if defined(HAVE_LIBEDIT) && defined(PHP_WIN32) /* Winedit on Windows */
339 history = history_list();
340
341 if (history) {
342 int i, n = history_length();
343 for (i = 0; i < n; i++) {
345 }
346 }
347
348#elif defined(HAVE_LIBEDIT) /* libedit */
349 {
350 HISTORY_STATE *hs;
351 int i;
352
353 using_history();
354 hs = history_get_history_state();
355 if (hs && hs->length) {
356 history = history_list();
357 if (history) {
358 for (i = 0; i < hs->length; i++) {
360 }
361 }
362 }
363 free(hs);
364 }
365
366#else /* readline */
367 history = history_list();
368
369 if (history) {
370 int i;
371 for (i = 0; history[i]; i++) {
373 }
374 }
375#endif
376}
377/* }}} */
378#endif
379
380/* {{{ Reads the history */
382{
383 char *arg = NULL;
384 size_t arg_len;
385
386 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!", &arg, &arg_len) == FAILURE) {
388 }
389
392 }
393
394 /* XXX from & to NYI */
395 if (read_history(arg)) {
396 /* If filename is NULL, then read from `~/.history' */
398 } else {
400 }
401}
402
403/* }}} */
404/* {{{ Writes the history */
406{
407 char *arg = NULL;
408 size_t arg_len;
409
410 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!", &arg, &arg_len) == FAILURE) {
412 }
413
416 }
417
418 if (write_history(arg)) {
420 } else {
422 }
423}
424
425/* }}} */
426/* {{{ Readline completion function? */
427
428static char *_readline_command_generator(const char *text, int state)
429{
430 HashTable *myht = Z_ARRVAL(_readline_array);
431 zval *entry;
432
433 if (!state) {
434 zend_hash_internal_pointer_reset(myht);
435 }
436
437 while ((entry = zend_hash_get_current_data(myht)) != NULL) {
438 zend_hash_move_forward(myht);
439
440 convert_to_string(entry);
441 if (strncmp (Z_STRVAL_P(entry), text, strlen(text)) == 0) {
442 return (strdup(Z_STRVAL_P(entry)));
443 }
444 }
445
446 return NULL;
447}
448
449static void _readline_string_zval(zval *ret, const char *str)
450{
451 if (str) {
452 ZVAL_STRING(ret, (char*)str);
453 } else {
454 ZVAL_NULL(ret);
455 }
456}
457
458char **php_readline_completion_cb(const char *text, int start, int end)
459{
460 zval params[3];
461 char **matches = NULL;
462
463 _readline_string_zval(&params[0], text);
464 ZVAL_LONG(&params[1], start);
465 ZVAL_LONG(&params[2], end);
466
467 if (call_user_function(NULL, NULL, &_readline_completion, &_readline_array, 3, params) == SUCCESS) {
468 if (Z_TYPE(_readline_array) == IS_ARRAY) {
469 SEPARATE_ARRAY(&_readline_array);
470 if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
471 matches = rl_completion_matches(text,_readline_command_generator);
472 } else {
473 /* libedit will read matches[2] */
474 matches = calloc(3, sizeof(char *));
475 if (!matches) {
476 return NULL;
477 }
478 matches[0] = strdup("");
479 }
480 }
481 }
482
483 zval_ptr_dtor(&params[0]);
484 zval_ptr_dtor(&_readline_array);
485
486 return matches;
487}
488
490{
491 zend_fcall_info fci;
493
494 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fcc)) {
496 }
497
498 zval_ptr_dtor(&_readline_completion);
499 ZVAL_COPY(&_readline_completion, &fci.function_name);
500
501 /* NOTE: The rl_attempted_completion_function variable (and others) are part of the readline library, not php */
502 rl_attempted_completion_function = php_readline_completion_cb;
503 if (rl_attempted_completion_function == NULL) {
505 }
507}
508
509/* }}} */
510
511#ifdef HAVE_RL_CALLBACK_READ_CHAR
512
513static void php_rl_callback_handler(char *the_line)
514{
515 zval params[1];
516 zval dummy;
517
518 ZVAL_NULL(&dummy);
519
520 _readline_string_zval(&params[0], the_line);
521
522 call_user_function(NULL, NULL, &_prepped_callback, &dummy, 1, params);
523
524 zval_ptr_dtor(&params[0]);
525 zval_ptr_dtor(&dummy);
526}
527
528/* {{{ Initializes the readline callback interface and terminal, prints the prompt and returns immediately */
530{
531 char *prompt;
532 zend_fcall_info fci;
534 size_t prompt_len;
535
536 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &prompt, &prompt_len, &fci, &fcc)) {
538 }
539
540 if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
541 rl_callback_handler_remove();
542 zval_ptr_dtor(&_prepped_callback);
543 }
544
545 ZVAL_COPY(&_prepped_callback, &fci.function_name);
546
547 rl_callback_handler_install(prompt, php_rl_callback_handler);
548
550}
551/* }}} */
552
553/* {{{ Informs the readline callback interface that a character is ready for input */
555{
558 }
559
560 if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
561 rl_callback_read_char();
562 }
563}
564/* }}} */
565
566/* {{{ Removes a previously installed callback handler and restores terminal settings */
568{
571 }
572
573 if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
574 rl_callback_handler_remove();
575 zval_ptr_dtor(&_prepped_callback);
576 ZVAL_UNDEF(&_prepped_callback);
578 }
580}
581/* }}} */
582
583/* {{{ Ask readline to redraw the display */
585{
588 }
589
590#ifdef HAVE_LIBEDIT
591 /* seems libedit doesn't take care of rl_initialize in rl_redisplay
592 * see bug #72538 */
593 using_history();
594#endif
595 rl_redisplay();
596}
597/* }}} */
598
599#endif
600
601#ifdef HAVE_RL_ON_NEW_LINE
602/* {{{ Inform readline that the cursor has moved to a new line */
604{
607 }
608
609 rl_on_new_line();
610}
611/* }}} */
612
613#endif
614
615
616#endif /* HAVE_LIBREADLINE */
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
buf start
Definition ffi.c:4687
PHPAPI int php_check_open_basedir(const char *path)
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINFO
Definition php.h:396
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_MSHUTDOWN
Definition php.h:393
#define PHP_MINFO_FUNCTION
Definition php.h:404
#define PHP_RSHUTDOWN
Definition php.h:395
#define PHP_RSHUTDOWN_FUNCTION
Definition php.h:403
#define PHP_MINIT
Definition php.h:392
int line
Definition php_ffi.h:54
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * text
Definition php_ffi.h:53
readline(?string $prompt=null)
readline_clear_history()
readline_redisplay()
readline_info(?string $var_name=null, $value=null)
readline_callback_handler_install(string $prompt, callable $callback)
readline_completion_function(callable $callback)
readline_add_history(string $prompt)
readline_callback_handler_remove()
readline_on_new_line()
readline_callback_read_char()
readline_read_history(?string $filename=null)
readline_list_history()
readline_write_history(?string $filename=null)
#define rl_completion_matches
char ** php_readline_completion_cb(const char *text, int start, int end)
char * prompt
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API zend_result add_next_index_string(zval *arg, const char *str)
Definition zend_API.c:2186
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
struct _zend_fcall_info_cache zend_fcall_info_cache
#define RETVAL_INTERNED_STR(s)
Definition zend_API.h:1014
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETVAL_STRING(s)
Definition zend_API.h:1017
#define ZVAL_STRING(z, s)
Definition zend_API.h:956
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define zend_parse_parameters_none()
Definition zend_API.h:353
struct _zend_fcall_info zend_fcall_info
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETVAL_BOOL(b)
Definition zend_API.h:1009
#define call_user_function(function_table, object, function_name, retval_ptr, param_count, params)
Definition zend_API.h:687
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define RETURN_TRUE
Definition zend_API.h:1059
#define array_init(arg)
Definition zend_API.h:537
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
struct _zend_string zend_string
#define STANDARD_MODULE_HEADER
#define SHUTDOWN_FUNC_ARGS_PASSTHRU
#define INIT_FUNC_ARGS_PASSTHRU
#define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define convert_to_string(op)
#define ZSTR_EMPTY_ALLOC()
#define zend_string_equals_literal_ci(str, c)
#define ZSTR_CHAR(c)
#define ZVAL_UNDEF(z)
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
@ FAILURE
Definition zend_types.h:61
#define ZVAL_COPY(z, v)
#define SEPARATE_ARRAY(zv)
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_ARRVAL(zval)
Definition zend_types.h:986
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval * return_value
bool result
zval * ret
value