xref: /PHP-7.0/ext/readline/readline.c (revision 478f119a)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2017 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;
63 
64 #endif
65 
66 static zval _readline_completion;
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_READLINE_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 	ZVAL_UNDEF(&_readline_completion);
178 #if HAVE_RL_CALLBACK_READ_CHAR
179 	ZVAL_UNDEF(&_prepped_callback);
180 #endif
181    	return PHP_MINIT(cli_readline)(INIT_FUNC_ARGS_PASSTHRU);
182 }
183 
PHP_MSHUTDOWN_FUNCTION(readline)184 PHP_MSHUTDOWN_FUNCTION(readline)
185 {
186 	return PHP_MSHUTDOWN(cli_readline)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
187 }
188 
PHP_RSHUTDOWN_FUNCTION(readline)189 PHP_RSHUTDOWN_FUNCTION(readline)
190 {
191 	zval_ptr_dtor(&_readline_completion);
192 	ZVAL_UNDEF(&_readline_completion);
193 #if HAVE_RL_CALLBACK_READ_CHAR
194 	if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
195 		rl_callback_handler_remove();
196 		zval_ptr_dtor(&_prepped_callback);
197 		ZVAL_UNDEF(&_prepped_callback);
198 	}
199 #endif
200 
201 	return SUCCESS;
202 }
203 
PHP_MINFO_FUNCTION(readline)204 PHP_MINFO_FUNCTION(readline)
205 {
206 	PHP_MINFO(cli_readline)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
207 }
208 
209 /* }}} */
210 
211 /* {{{ proto string readline([string prompt])
212    Reads a line */
PHP_FUNCTION(readline)213 PHP_FUNCTION(readline)
214 {
215 	char *prompt = NULL;
216 	size_t prompt_len;
217 	char *result;
218 
219 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &prompt, &prompt_len)) {
220 		RETURN_FALSE;
221 	}
222 
223 	result = readline(prompt);
224 
225 	if (! result) {
226 		RETURN_FALSE;
227 	} else {
228 		RETVAL_STRING(result);
229 		free(result);
230 	}
231 }
232 
233 /* }}} */
234 
235 #define SAFE_STRING(s) ((s)?(char*)(s):"")
236 
237 /* {{{ proto mixed readline_info([string varname [, string newvalue]])
238    Gets/sets various internal readline variables. */
PHP_FUNCTION(readline_info)239 PHP_FUNCTION(readline_info)
240 {
241 	char *what = NULL;
242 	zval *value = NULL;
243 	size_t what_len, oldval;
244 	char *oldstr;
245 
246 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sz", &what, &what_len, &value) == FAILURE) {
247 		return;
248 	}
249 
250 	if (!what) {
251 		array_init(return_value);
252 		add_assoc_string(return_value,"line_buffer",SAFE_STRING(rl_line_buffer));
253 		add_assoc_long(return_value,"point",rl_point);
254 		add_assoc_long(return_value,"end",rl_end);
255 #ifdef HAVE_LIBREADLINE
256 		add_assoc_long(return_value,"mark",rl_mark);
257 		add_assoc_long(return_value,"done",rl_done);
258 		add_assoc_long(return_value,"pending_input",rl_pending_input);
259 		add_assoc_string(return_value,"prompt",SAFE_STRING(rl_prompt));
260 		add_assoc_string(return_value,"terminal_name",(char *)SAFE_STRING(rl_terminal_name));
261 #endif
262 #if HAVE_ERASE_EMPTY_LINE
263 		add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line);
264 #endif
265 		add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version));
266 		add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name));
267 		add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over);
268 	} else {
269 		if (!strcasecmp(what,"line_buffer")) {
270 			oldstr = rl_line_buffer;
271 			if (value) {
272 				/* XXX if (rl_line_buffer) free(rl_line_buffer); */
273 				convert_to_string_ex(value);
274 				rl_line_buffer = strdup(Z_STRVAL_P(value));
275 			}
276 			RETVAL_STRING(SAFE_STRING(oldstr));
277 		} else if (!strcasecmp(what, "point")) {
278 			RETVAL_LONG(rl_point);
279 		} else if (!strcasecmp(what, "end")) {
280 			RETVAL_LONG(rl_end);
281 #ifdef HAVE_LIBREADLINE
282 		} else if (!strcasecmp(what, "mark")) {
283 			RETVAL_LONG(rl_mark);
284 		} else if (!strcasecmp(what, "done")) {
285 			oldval = rl_done;
286 			if (value) {
287 				convert_to_long_ex(value);
288 				rl_done = Z_LVAL_P(value);
289 			}
290 			RETVAL_LONG(oldval);
291 		} else if (!strcasecmp(what, "pending_input")) {
292 			oldval = rl_pending_input;
293 			if (value) {
294 				convert_to_string_ex(value);
295 				rl_pending_input = Z_STRVAL_P(value)[0];
296 			}
297 			RETVAL_LONG(oldval);
298 		} else if (!strcasecmp(what, "prompt")) {
299 			RETVAL_STRING(SAFE_STRING(rl_prompt));
300 		} else if (!strcasecmp(what, "terminal_name")) {
301 			RETVAL_STRING((char *)SAFE_STRING(rl_terminal_name));
302 #endif
303 #if HAVE_ERASE_EMPTY_LINE
304 		} else if (!strcasecmp(what, "erase_empty_line")) {
305 			oldval = rl_erase_empty_line;
306 			if (value) {
307 				convert_to_long_ex(value);
308 				rl_erase_empty_line = Z_LVAL_P(value);
309 			}
310 			RETVAL_LONG(oldval);
311 #endif
312 		} else if (!strcasecmp(what,"library_version")) {
313 			RETVAL_STRING((char *)SAFE_STRING(rl_library_version));
314 		} else if (!strcasecmp(what, "readline_name")) {
315 			oldstr = (char*)rl_readline_name;
316 			if (value) {
317 				/* XXX if (rl_readline_name) free(rl_readline_name); */
318 				convert_to_string_ex(value);
319 				rl_readline_name = strdup(Z_STRVAL_P(value));;
320 			}
321 			RETVAL_STRING(SAFE_STRING(oldstr));
322 		} else if (!strcasecmp(what, "attempted_completion_over")) {
323 			oldval = rl_attempted_completion_over;
324 			if (value) {
325 				convert_to_long_ex(value);
326 				rl_attempted_completion_over = Z_LVAL_P(value);
327 			}
328 			RETVAL_LONG(oldval);
329 		}
330 	}
331 }
332 
333 /* }}} */
334 /* {{{ proto bool readline_add_history(string prompt)
335    Adds a line to the history */
PHP_FUNCTION(readline_add_history)336 PHP_FUNCTION(readline_add_history)
337 {
338 	char *arg;
339 	size_t arg_len;
340 
341 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
342 		return;
343 	}
344 
345 	add_history(arg);
346 
347 	RETURN_TRUE;
348 }
349 
350 /* }}} */
351 /* {{{ proto bool readline_clear_history(void)
352    Clears the history */
PHP_FUNCTION(readline_clear_history)353 PHP_FUNCTION(readline_clear_history)
354 {
355 	if (zend_parse_parameters_none() == FAILURE) {
356 		return;
357 	}
358 
359 #if HAVE_LIBEDIT
360 	/* clear_history is the only function where rl_initialize
361 	   is not call to ensure correct allocation */
362 	using_history();
363 #endif
364 	clear_history();
365 
366 	RETURN_TRUE;
367 }
368 
369 /* }}} */
370 /* {{{ proto array readline_list_history(void)
371    Lists the history */
372 #ifndef HAVE_LIBEDIT
PHP_FUNCTION(readline_list_history)373 PHP_FUNCTION(readline_list_history)
374 {
375 	HIST_ENTRY **history;
376 
377 	if (zend_parse_parameters_none() == FAILURE) {
378 		return;
379 	}
380 
381 	history = history_list();
382 
383 	array_init(return_value);
384 
385 	if (history) {
386 		int i;
387 		for (i = 0; history[i]; i++) {
388 			add_next_index_string(return_value,history[i]->line);
389 		}
390 	}
391 }
392 #endif
393 /* }}} */
394 /* {{{ proto bool readline_read_history([string filename])
395    Reads the history */
PHP_FUNCTION(readline_read_history)396 PHP_FUNCTION(readline_read_history)
397 {
398 	char *arg = NULL;
399 	size_t arg_len;
400 
401 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p", &arg, &arg_len) == FAILURE) {
402 		return;
403 	}
404 
405 	if (arg && php_check_open_basedir(arg)) {
406 		RETURN_FALSE;
407 	}
408 
409 	/* XXX from & to NYI */
410 	if (read_history(arg)) {
411 		/* If filename is NULL, then read from `~/.history' */
412 		RETURN_FALSE;
413 	} else {
414 		RETURN_TRUE;
415 	}
416 }
417 
418 /* }}} */
419 /* {{{ proto bool readline_write_history([string filename])
420    Writes the history */
PHP_FUNCTION(readline_write_history)421 PHP_FUNCTION(readline_write_history)
422 {
423 	char *arg = NULL;
424 	size_t arg_len;
425 
426 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p", &arg, &arg_len) == FAILURE) {
427 		return;
428 	}
429 
430 	if (arg && php_check_open_basedir(arg)) {
431 		RETURN_FALSE;
432 	}
433 
434 	if (write_history(arg)) {
435 		RETURN_FALSE;
436 	} else {
437 		RETURN_TRUE;
438 	}
439 }
440 
441 /* }}} */
442 /* {{{ proto bool readline_completion_function(string funcname)
443    Readline completion function? */
444 
_readline_command_generator(const char * text,int state)445 static char *_readline_command_generator(const char *text, int state)
446 {
447 	HashTable  *myht = Z_ARRVAL(_readline_array);
448 	zval *entry;
449 
450 	if (!state) {
451 		zend_hash_internal_pointer_reset(myht);
452 	}
453 
454 	while ((entry = zend_hash_get_current_data(myht)) != NULL) {
455 		zend_hash_move_forward(myht);
456 
457 		convert_to_string_ex(entry);
458 		if (strncmp (Z_STRVAL_P(entry), text, strlen(text)) == 0) {
459 			return (strdup(Z_STRVAL_P(entry)));
460 		}
461 	}
462 
463 	return NULL;
464 }
465 
_readline_string_zval(zval * ret,const char * str)466 static void _readline_string_zval(zval *ret, const char *str)
467 {
468 	if (str) {
469 		ZVAL_STRING(ret, (char*)str);
470 	} else {
471 		ZVAL_NULL(ret);
472 	}
473 }
474 
_readline_long_zval(zval * ret,long l)475 static void _readline_long_zval(zval *ret, long l)
476 {
477 	ZVAL_LONG(ret, l);
478 }
479 
_readline_completion_cb(const char * text,int start,int end)480 static char **_readline_completion_cb(const char *text, int start, int end)
481 {
482 	zval params[3];
483 	int i;
484 	char **matches = NULL;
485 
486 	_readline_string_zval(&params[0], text);
487 	_readline_long_zval(&params[1], start);
488 	_readline_long_zval(&params[2], end);
489 
490 	if (call_user_function(CG(function_table), NULL, &_readline_completion, &_readline_array, 3, params) == SUCCESS) {
491 		if (Z_TYPE(_readline_array) == IS_ARRAY) {
492 			if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
493 				matches = rl_completion_matches(text,_readline_command_generator);
494 			} else {
495 				matches = malloc(sizeof(char *) * 2);
496 				if (!matches) {
497 					return NULL;
498 				}
499 				matches[0] = strdup("");
500 				matches[1] = '\0';
501 			}
502 		}
503 	}
504 
505 	for (i = 0; i < 3; i++) {
506 		zval_ptr_dtor(&params[i]);
507 	}
508 	zval_ptr_dtor(&_readline_array);
509 
510 	return matches;
511 }
512 
PHP_FUNCTION(readline_completion_function)513 PHP_FUNCTION(readline_completion_function)
514 {
515 	zval *arg = NULL;
516 	zend_string *name = NULL;
517 
518 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg)) {
519 		RETURN_FALSE;
520 	}
521 
522 	if (!zend_is_callable(arg, 0, &name)) {
523 		php_error_docref(NULL, E_WARNING, "%s is not callable", ZSTR_VAL(name));
524 		zend_string_release(name);
525 		RETURN_FALSE;
526 	}
527 	zend_string_release(name);
528 
529 	zval_ptr_dtor(&_readline_completion);
530 	ZVAL_COPY(&_readline_completion, arg);
531 
532 	rl_attempted_completion_function = _readline_completion_cb;
533 	if (rl_attempted_completion_function == NULL) {
534 		RETURN_FALSE;
535 	}
536 	RETURN_TRUE;
537 }
538 
539 /* }}} */
540 
541 #if HAVE_RL_CALLBACK_READ_CHAR
542 
php_rl_callback_handler(char * the_line)543 static void php_rl_callback_handler(char *the_line)
544 {
545 	zval params[1];
546 	zval dummy;
547 
548 	ZVAL_NULL(&dummy);
549 
550 	_readline_string_zval(&params[0], the_line);
551 
552 	call_user_function(CG(function_table), NULL, &_prepped_callback, &dummy, 1, params);
553 
554 	zval_ptr_dtor(&params[0]);
555 	zval_ptr_dtor(&dummy);
556 }
557 
558 /* {{{ proto void readline_callback_handler_install(string prompt, mixed callback)
559    Initializes the readline callback interface and terminal, prints the prompt and returns immediately */
PHP_FUNCTION(readline_callback_handler_install)560 PHP_FUNCTION(readline_callback_handler_install)
561 {
562 	zval *callback;
563 	zend_string *name = NULL;
564 	char *prompt;
565 	size_t prompt_len;
566 
567 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &prompt, &prompt_len, &callback)) {
568 		return;
569 	}
570 
571 	if (!zend_is_callable(callback, 0, &name)) {
572 		php_error_docref(NULL, E_WARNING, "%s is not callable", ZSTR_VAL(name));
573 		zend_string_release(name);
574 		RETURN_FALSE;
575 	}
576 	zend_string_release(name);
577 
578 	if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
579 		rl_callback_handler_remove();
580 		zval_ptr_dtor(&_prepped_callback);
581 	}
582 
583 	ZVAL_COPY(&_prepped_callback, callback);
584 
585 	rl_callback_handler_install(prompt, php_rl_callback_handler);
586 
587 	RETURN_TRUE;
588 }
589 /* }}} */
590 
591 /* {{{ proto void readline_callback_read_char()
592    Informs the readline callback interface that a character is ready for input */
PHP_FUNCTION(readline_callback_read_char)593 PHP_FUNCTION(readline_callback_read_char)
594 {
595 	if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
596 		rl_callback_read_char();
597 	}
598 }
599 /* }}} */
600 
601 /* {{{ proto bool readline_callback_handler_remove()
602    Removes a previously installed callback handler and restores terminal settings */
PHP_FUNCTION(readline_callback_handler_remove)603 PHP_FUNCTION(readline_callback_handler_remove)
604 {
605 	if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
606 		rl_callback_handler_remove();
607 		zval_ptr_dtor(&_prepped_callback);
608 		ZVAL_UNDEF(&_prepped_callback);
609 		RETURN_TRUE;
610 	}
611 	RETURN_FALSE;
612 }
613 /* }}} */
614 
615 /* {{{ proto void readline_redisplay(void)
616    Ask readline to redraw the display */
PHP_FUNCTION(readline_redisplay)617 PHP_FUNCTION(readline_redisplay)
618 {
619 #if HAVE_LIBEDIT
620 	/* seems libedit doesn't take care of rl_initialize in rl_redisplay
621 	 * see bug #72538 */
622 	using_history();
623 #endif
624 	rl_redisplay();
625 }
626 /* }}} */
627 
628 #endif
629 
630 #if HAVE_RL_ON_NEW_LINE
631 /* {{{ proto void readline_on_new_line(void)
632    Inform readline that the cursor has moved to a new line */
PHP_FUNCTION(readline_on_new_line)633 PHP_FUNCTION(readline_on_new_line)
634 {
635 	rl_on_new_line();
636 }
637 /* }}} */
638 
639 #endif
640 
641 
642 #endif /* HAVE_LIBREADLINE */
643 
644 /*
645  * Local variables:
646  * tab-width: 4
647  * c-basic-offset: 4
648  * End:
649  */
650