xref: /PHP-5.5/ext/readline/readline.c (revision a620b790)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Thies C. Arntzen <thies@thieso.net>                          |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 /* {{{ includes & prototypes */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "php.h"
28 #include "php_readline.h"
29 #include "readline_cli.h"
30 
31 #if HAVE_LIBREADLINE || HAVE_LIBEDIT
32 
33 #ifndef HAVE_RL_COMPLETION_MATCHES
34 #define rl_completion_matches completion_matches
35 #endif
36 
37 #ifdef HAVE_LIBEDIT
38 #include <editline/readline.h>
39 #else
40 #include <readline/readline.h>
41 #include <readline/history.h>
42 #endif
43 
44 PHP_FUNCTION(readline);
45 PHP_FUNCTION(readline_add_history);
46 PHP_FUNCTION(readline_info);
47 PHP_FUNCTION(readline_clear_history);
48 #ifndef HAVE_LIBEDIT
49 PHP_FUNCTION(readline_list_history);
50 #endif
51 PHP_FUNCTION(readline_read_history);
52 PHP_FUNCTION(readline_write_history);
53 PHP_FUNCTION(readline_completion_function);
54 
55 #if HAVE_RL_CALLBACK_READ_CHAR
56 PHP_FUNCTION(readline_callback_handler_install);
57 PHP_FUNCTION(readline_callback_read_char);
58 PHP_FUNCTION(readline_callback_handler_remove);
59 PHP_FUNCTION(readline_redisplay);
60 PHP_FUNCTION(readline_on_new_line);
61 
62 static zval *_prepped_callback = NULL;
63 
64 #endif
65 
66 static zval *_readline_completion = NULL;
67 static zval _readline_array;
68 
69 PHP_MINIT_FUNCTION(readline);
70 PHP_MSHUTDOWN_FUNCTION(readline);
71 PHP_RSHUTDOWN_FUNCTION(readline);
72 PHP_MINFO_FUNCTION(readline);
73 
74 /* }}} */
75 
76 /* {{{ arginfo */
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline, 0, 0, 0)
78 	ZEND_ARG_INFO(0, prompt)
79 ZEND_END_ARG_INFO()
80 
81 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_info, 0, 0, 0)
82 	ZEND_ARG_INFO(0, varname)
83 	ZEND_ARG_INFO(0, newvalue)
84 ZEND_END_ARG_INFO()
85 
86 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_add_history, 0, 0, 1)
87 	ZEND_ARG_INFO(0, prompt)
88 ZEND_END_ARG_INFO()
89 
90 ZEND_BEGIN_ARG_INFO(arginfo_readline_clear_history, 0)
91 ZEND_END_ARG_INFO()
92 
93 #ifndef HAVE_LIBEDIT
94 ZEND_BEGIN_ARG_INFO(arginfo_readline_list_history, 0)
95 ZEND_END_ARG_INFO()
96 #endif
97 
98 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_read_history, 0, 0, 0)
99 	ZEND_ARG_INFO(0, filename)
100 ZEND_END_ARG_INFO()
101 
102 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_write_history, 0, 0, 0)
103 	ZEND_ARG_INFO(0, filename)
104 ZEND_END_ARG_INFO()
105 
106 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_completion_function, 0, 0, 1)
107 	ZEND_ARG_INFO(0, funcname)
108 ZEND_END_ARG_INFO()
109 
110 #if HAVE_RL_CALLBACK_READ_CHAR
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_callback_handler_install, 0, 0, 2)
112 	ZEND_ARG_INFO(0, prompt)
113 	ZEND_ARG_INFO(0, callback)
114 ZEND_END_ARG_INFO()
115 
116 ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_read_char, 0)
117 ZEND_END_ARG_INFO()
118 
119 ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_handler_remove, 0)
120 ZEND_END_ARG_INFO()
121 
122 ZEND_BEGIN_ARG_INFO(arginfo_readline_redisplay, 0)
123 ZEND_END_ARG_INFO()
124 
125 ZEND_BEGIN_ARG_INFO(arginfo_readline_on_new_line, 0)
126 ZEND_END_ARG_INFO()
127 #endif
128 /* }}} */
129 
130 /* {{{ module stuff */
131 static const zend_function_entry php_readline_functions[] = {
132 	PHP_FE(readline,	   		        arginfo_readline)
133 	PHP_FE(readline_info,  	            arginfo_readline_info)
134 	PHP_FE(readline_add_history, 		arginfo_readline_add_history)
135 	PHP_FE(readline_clear_history, 		arginfo_readline_clear_history)
136 #ifndef HAVE_LIBEDIT
137 	PHP_FE(readline_list_history, 		arginfo_readline_list_history)
138 #endif
139 	PHP_FE(readline_read_history, 		arginfo_readline_read_history)
140 	PHP_FE(readline_write_history, 		arginfo_readline_write_history)
141 	PHP_FE(readline_completion_function,arginfo_readline_completion_function)
142 #if HAVE_RL_CALLBACK_READ_CHAR
143 	PHP_FE(readline_callback_handler_install, arginfo_readline_callback_handler_install)
144 	PHP_FE(readline_callback_read_char,			arginfo_readline_callback_read_char)
145 	PHP_FE(readline_callback_handler_remove,	arginfo_readline_callback_handler_remove)
146 	PHP_FE(readline_redisplay, arginfo_readline_redisplay)
147 #endif
148 #if HAVE_RL_ON_NEW_LINE
149 	PHP_FE(readline_on_new_line, arginfo_readline_on_new_line)
150 #endif
151 	PHP_FE_END
152 };
153 
154 zend_module_entry readline_module_entry = {
155 	STANDARD_MODULE_HEADER,
156 	"readline",
157 	php_readline_functions,
158 	PHP_MINIT(readline),
159 	PHP_MSHUTDOWN(readline),
160 	NULL,
161 	PHP_RSHUTDOWN(readline),
162 	PHP_MINFO(readline),
163 	PHP_VERSION,
164 	STANDARD_MODULE_PROPERTIES
165 };
166 
167 #ifdef COMPILE_DL_READLINE
168 ZEND_GET_MODULE(readline)
169 #endif
170 
PHP_MINIT_FUNCTION(readline)171 PHP_MINIT_FUNCTION(readline)
172 {
173 #if HAVE_LIBREADLINE
174 		/* libedit don't need this call which set the tty in cooked mode */
175 		using_history();
176 #endif
177     	return PHP_MINIT(cli_readline)(INIT_FUNC_ARGS_PASSTHRU);
178 }
179 
PHP_MSHUTDOWN_FUNCTION(readline)180 PHP_MSHUTDOWN_FUNCTION(readline)
181 {
182 	return PHP_MSHUTDOWN(cli_readline)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
183 }
184 
PHP_RSHUTDOWN_FUNCTION(readline)185 PHP_RSHUTDOWN_FUNCTION(readline)
186 {
187 	if (_readline_completion) {
188 		zval_dtor(_readline_completion);
189 		FREE_ZVAL(_readline_completion);
190 	}
191 #if HAVE_RL_CALLBACK_READ_CHAR
192 	if (_prepped_callback) {
193 		rl_callback_handler_remove();
194 		zval_ptr_dtor(&_prepped_callback);
195 		_prepped_callback = 0;
196 	}
197 #endif
198 
199 	return SUCCESS;
200 }
201 
PHP_MINFO_FUNCTION(readline)202 PHP_MINFO_FUNCTION(readline)
203 {
204 	PHP_MINFO(cli_readline)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
205 }
206 
207 /* }}} */
208 
209 /* {{{ proto string readline([string prompt])
210    Reads a line */
PHP_FUNCTION(readline)211 PHP_FUNCTION(readline)
212 {
213 	char *prompt = NULL;
214 	int prompt_len;
215 	char *result;
216 
217 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &prompt, &prompt_len)) {
218 		RETURN_FALSE;
219 	}
220 
221 	result = readline(prompt);
222 
223 	if (! result) {
224 		RETURN_FALSE;
225 	} else {
226 		RETVAL_STRING(result,1);
227 		free(result);
228 	}
229 }
230 
231 /* }}} */
232 
233 #define SAFE_STRING(s) ((s)?(char*)(s):"")
234 
235 /* {{{ proto mixed readline_info([string varname [, string newvalue]])
236    Gets/sets various internal readline variables. */
PHP_FUNCTION(readline_info)237 PHP_FUNCTION(readline_info)
238 {
239 	char *what = NULL;
240 	zval **value = NULL;
241 	int what_len, oldval;
242 	char *oldstr;
243 
244 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sZ", &what, &what_len, &value) == FAILURE) {
245 		return;
246 	}
247 
248 	if (!what) {
249 		array_init(return_value);
250 		add_assoc_string(return_value,"line_buffer",SAFE_STRING(rl_line_buffer),1);
251 		add_assoc_long(return_value,"point",rl_point);
252 		add_assoc_long(return_value,"end",rl_end);
253 #ifdef HAVE_LIBREADLINE
254 		add_assoc_long(return_value,"mark",rl_mark);
255 		add_assoc_long(return_value,"done",rl_done);
256 		add_assoc_long(return_value,"pending_input",rl_pending_input);
257 		add_assoc_string(return_value,"prompt",SAFE_STRING(rl_prompt),1);
258 		add_assoc_string(return_value,"terminal_name",(char *)SAFE_STRING(rl_terminal_name),1);
259 #endif
260 #if HAVE_ERASE_EMPTY_LINE
261 		add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line);
262 #endif
263 		add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version),1);
264 		add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name),1);
265 		add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over);
266 	} else {
267 		if (!strcasecmp(what,"line_buffer")) {
268 			oldstr = rl_line_buffer;
269 			if (value) {
270 				/* XXX if (rl_line_buffer) free(rl_line_buffer); */
271 				convert_to_string_ex(value);
272 				rl_line_buffer = strdup(Z_STRVAL_PP(value));
273 			}
274 			RETVAL_STRING(SAFE_STRING(oldstr),1);
275 		} else if (!strcasecmp(what, "point")) {
276 			RETVAL_LONG(rl_point);
277 		} else if (!strcasecmp(what, "end")) {
278 			RETVAL_LONG(rl_end);
279 #ifdef HAVE_LIBREADLINE
280 		} else if (!strcasecmp(what, "mark")) {
281 			RETVAL_LONG(rl_mark);
282 		} else if (!strcasecmp(what, "done")) {
283 			oldval = rl_done;
284 			if (value) {
285 				convert_to_long_ex(value);
286 				rl_done = Z_LVAL_PP(value);
287 			}
288 			RETVAL_LONG(oldval);
289 		} else if (!strcasecmp(what, "pending_input")) {
290 			oldval = rl_pending_input;
291 			if (value) {
292 				convert_to_string_ex(value);
293 				rl_pending_input = Z_STRVAL_PP(value)[0];
294 			}
295 			RETVAL_LONG(oldval);
296 		} else if (!strcasecmp(what, "prompt")) {
297 			RETVAL_STRING(SAFE_STRING(rl_prompt),1);
298 		} else if (!strcasecmp(what, "terminal_name")) {
299 			RETVAL_STRING((char *)SAFE_STRING(rl_terminal_name),1);
300 #endif
301 #if HAVE_ERASE_EMPTY_LINE
302 		} else if (!strcasecmp(what, "erase_empty_line")) {
303 			oldval = rl_erase_empty_line;
304 			if (value) {
305 				convert_to_long_ex(value);
306 				rl_erase_empty_line = Z_LVAL_PP(value);
307 			}
308 			RETVAL_LONG(oldval);
309 #endif
310 		} else if (!strcasecmp(what,"library_version")) {
311 			RETVAL_STRING((char *)SAFE_STRING(rl_library_version),1);
312 		} else if (!strcasecmp(what, "readline_name")) {
313 			oldstr = (char*)rl_readline_name;
314 			if (value) {
315 				/* XXX if (rl_readline_name) free(rl_readline_name); */
316 				convert_to_string_ex(value);
317 				rl_readline_name = strdup(Z_STRVAL_PP(value));;
318 			}
319 			RETVAL_STRING(SAFE_STRING(oldstr),1);
320 		} else if (!strcasecmp(what, "attempted_completion_over")) {
321 			oldval = rl_attempted_completion_over;
322 			if (value) {
323 				convert_to_long_ex(value);
324 				rl_attempted_completion_over = Z_LVAL_PP(value);
325 			}
326 			RETVAL_LONG(oldval);
327 		}
328 	}
329 }
330 
331 /* }}} */
332 /* {{{ proto bool readline_add_history(string prompt)
333    Adds a line to the history */
PHP_FUNCTION(readline_add_history)334 PHP_FUNCTION(readline_add_history)
335 {
336 	char *arg;
337 	int arg_len;
338 
339 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
340 		return;
341 	}
342 
343 	add_history(arg);
344 
345 	RETURN_TRUE;
346 }
347 
348 /* }}} */
349 /* {{{ proto bool readline_clear_history(void)
350    Clears the history */
PHP_FUNCTION(readline_clear_history)351 PHP_FUNCTION(readline_clear_history)
352 {
353 	if (zend_parse_parameters_none() == FAILURE) {
354 		return;
355 	}
356 
357 #if HAVE_LIBEDIT
358 	/* clear_history is the only function where rl_initialize
359 	   is not call to ensure correct allocation */
360 	using_history();
361 #endif
362 	clear_history();
363 
364 	RETURN_TRUE;
365 }
366 
367 /* }}} */
368 /* {{{ proto array readline_list_history(void)
369    Lists the history */
370 #ifndef HAVE_LIBEDIT
PHP_FUNCTION(readline_list_history)371 PHP_FUNCTION(readline_list_history)
372 {
373 	HIST_ENTRY **history;
374 
375 	if (zend_parse_parameters_none() == FAILURE) {
376 		return;
377 	}
378 
379 	history = history_list();
380 
381 	array_init(return_value);
382 
383 	if (history) {
384 		int i;
385 		for (i = 0; history[i]; i++) {
386 			add_next_index_string(return_value,history[i]->line,1);
387 		}
388 	}
389 }
390 #endif
391 /* }}} */
392 /* {{{ proto bool readline_read_history([string filename])
393    Reads the history */
PHP_FUNCTION(readline_read_history)394 PHP_FUNCTION(readline_read_history)
395 {
396 	char *arg = NULL;
397 	int arg_len;
398 
399 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|p", &arg, &arg_len) == FAILURE) {
400 		return;
401 	}
402 
403 	if (arg && php_check_open_basedir(arg TSRMLS_CC)) {
404 		RETURN_FALSE;
405 	}
406 
407 	/* XXX from & to NYI */
408 	if (read_history(arg)) {
409 		/* If filename is NULL, then read from `~/.history' */
410 		RETURN_FALSE;
411 	} else {
412 		RETURN_TRUE;
413 	}
414 }
415 
416 /* }}} */
417 /* {{{ proto bool readline_write_history([string filename])
418    Writes the history */
PHP_FUNCTION(readline_write_history)419 PHP_FUNCTION(readline_write_history)
420 {
421 	char *arg = NULL;
422 	int arg_len;
423 
424 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|p", &arg, &arg_len) == FAILURE) {
425 		return;
426 	}
427 
428 	if (arg && php_check_open_basedir(arg TSRMLS_CC)) {
429 		RETURN_FALSE;
430 	}
431 
432 	if (write_history(arg)) {
433 		RETURN_FALSE;
434 	} else {
435 		RETURN_TRUE;
436 	}
437 }
438 
439 /* }}} */
440 /* {{{ proto bool readline_completion_function(string funcname)
441    Readline completion function? */
442 
_readline_command_generator(const char * text,int state)443 static char *_readline_command_generator(const char *text, int state)
444 {
445 	HashTable  *myht = Z_ARRVAL(_readline_array);
446 	zval **entry;
447 
448 	if (!state) {
449 		zend_hash_internal_pointer_reset(myht);
450 	}
451 
452 	while (zend_hash_get_current_data(myht, (void **)&entry) == SUCCESS) {
453 		zend_hash_move_forward(myht);
454 
455 		convert_to_string_ex(entry);
456 		if (strncmp (Z_STRVAL_PP(entry), text, strlen(text)) == 0) {
457 			return (strdup(Z_STRVAL_PP(entry)));
458 		}
459 	}
460 
461 	return NULL;
462 }
463 
_readline_string_zval(const char * str)464 static zval *_readline_string_zval(const char *str)
465 {
466 	zval *ret;
467 	int len;
468 
469 	MAKE_STD_ZVAL(ret);
470 
471 	if (str) {
472 		len = strlen(str);
473 		ZVAL_STRINGL(ret, (char*)str, len, 1);
474 	} else {
475 		ZVAL_NULL(ret);
476 	}
477 
478 	return ret;
479 }
480 
_readline_long_zval(long l)481 static zval *_readline_long_zval(long l)
482 {
483 	zval *ret;
484 	MAKE_STD_ZVAL(ret);
485 
486 	Z_TYPE_P(ret) = IS_LONG;
487 	Z_LVAL_P(ret) = l;
488 	return ret;
489 }
490 
_readline_completion_cb(const char * text,int start,int end)491 static char **_readline_completion_cb(const char *text, int start, int end)
492 {
493 	zval *params[3];
494 	int i;
495 	char **matches = NULL;
496 	TSRMLS_FETCH();
497 
498 	params[0]=_readline_string_zval(text);
499 	params[1]=_readline_long_zval(start);
500 	params[2]=_readline_long_zval(end);
501 
502 	if (call_user_function(CG(function_table), NULL, _readline_completion, &_readline_array, 3, params TSRMLS_CC) == SUCCESS) {
503 		if (Z_TYPE(_readline_array) == IS_ARRAY) {
504 			if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
505 				matches = rl_completion_matches(text,_readline_command_generator);
506 			} else {
507 				matches = malloc(sizeof(char *) * 2);
508 				if (!matches) {
509 					return NULL;
510 				}
511 				matches[0] = strdup("");
512 				matches[1] = '\0';
513 			}
514 		}
515 	}
516 
517 	for (i = 0; i < 3; i++) {
518 		zval_ptr_dtor(&params[i]);
519 	}
520 	zval_dtor(&_readline_array);
521 
522 	return matches;
523 }
524 
PHP_FUNCTION(readline_completion_function)525 PHP_FUNCTION(readline_completion_function)
526 {
527 	zval *arg = NULL;
528 	char *name = NULL;
529 
530 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg)) {
531 		RETURN_FALSE;
532 	}
533 
534 	if (!zend_is_callable(arg, 0, &name TSRMLS_CC)) {
535 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not callable", name);
536 		efree(name);
537 		RETURN_FALSE;
538 	}
539 	efree(name);
540 
541 	if (_readline_completion) {
542 		zval_dtor(_readline_completion);
543 		FREE_ZVAL(_readline_completion);
544 	}
545 
546 	MAKE_STD_ZVAL(_readline_completion);
547 	*_readline_completion = *arg;
548 	zval_copy_ctor(_readline_completion);
549 
550 	rl_attempted_completion_function = _readline_completion_cb;
551 	if (rl_attempted_completion_function == NULL) {
552 		efree(name);
553 		RETURN_FALSE;
554 	}
555 	RETURN_TRUE;
556 }
557 
558 /* }}} */
559 
560 #if HAVE_RL_CALLBACK_READ_CHAR
561 
php_rl_callback_handler(char * the_line)562 static void php_rl_callback_handler(char *the_line)
563 {
564 	zval *params[1];
565 	zval dummy;
566 	TSRMLS_FETCH();
567 
568 	ZVAL_NULL(&dummy);
569 
570 	params[0] = _readline_string_zval(the_line);
571 
572 	call_user_function(CG(function_table), NULL, _prepped_callback, &dummy, 1, params TSRMLS_CC);
573 
574 	zval_ptr_dtor(&params[0]);
575 	zval_dtor(&dummy);
576 }
577 
578 /* {{{ proto void readline_callback_handler_install(string prompt, mixed callback)
579    Initializes the readline callback interface and terminal, prints the prompt and returns immediately */
PHP_FUNCTION(readline_callback_handler_install)580 PHP_FUNCTION(readline_callback_handler_install)
581 {
582 	zval *callback;
583 	char *name = NULL;
584 	char *prompt;
585 	int prompt_len;
586 
587 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &prompt, &prompt_len, &callback)) {
588 		return;
589 	}
590 
591 	if (!zend_is_callable(callback, 0, &name TSRMLS_CC)) {
592 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not callable", name);
593 		efree(name);
594 		RETURN_FALSE;
595 	}
596 	efree(name);
597 
598 	if (_prepped_callback) {
599 		rl_callback_handler_remove();
600 		zval_dtor(_prepped_callback);
601 		FREE_ZVAL(_prepped_callback);
602 	}
603 
604 	ALLOC_ZVAL(_prepped_callback);
605 	MAKE_COPY_ZVAL(&callback, _prepped_callback);
606 
607 	rl_callback_handler_install(prompt, php_rl_callback_handler);
608 
609 	RETURN_TRUE;
610 }
611 /* }}} */
612 
613 /* {{{ proto void readline_callback_read_char()
614    Informs the readline callback interface that a character is ready for input */
PHP_FUNCTION(readline_callback_read_char)615 PHP_FUNCTION(readline_callback_read_char)
616 {
617 	if (_prepped_callback) {
618 		rl_callback_read_char();
619 	}
620 }
621 /* }}} */
622 
623 /* {{{ proto bool readline_callback_handler_remove()
624    Removes a previously installed callback handler and restores terminal settings */
PHP_FUNCTION(readline_callback_handler_remove)625 PHP_FUNCTION(readline_callback_handler_remove)
626 {
627 	if (_prepped_callback) {
628 		rl_callback_handler_remove();
629 		zval_dtor(_prepped_callback);
630 		FREE_ZVAL(_prepped_callback);
631 		_prepped_callback = 0;
632 		RETURN_TRUE;
633 	}
634 	RETURN_FALSE;
635 }
636 /* }}} */
637 
638 /* {{{ proto void readline_redisplay(void)
639    Ask readline to redraw the display */
PHP_FUNCTION(readline_redisplay)640 PHP_FUNCTION(readline_redisplay)
641 {
642 	rl_redisplay();
643 }
644 /* }}} */
645 
646 #endif
647 
648 #if HAVE_RL_ON_NEW_LINE
649 /* {{{ proto void readline_on_new_line(void)
650    Inform readline that the cursor has moved to a new line */
PHP_FUNCTION(readline_on_new_line)651 PHP_FUNCTION(readline_on_new_line)
652 {
653 	rl_on_new_line();
654 }
655 /* }}} */
656 
657 #endif
658 
659 
660 #endif /* HAVE_LIBREADLINE */
661 
662 /*
663  * Local variables:
664  * tab-width: 4
665  * c-basic-offset: 4
666  * End:
667  */
668