1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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 /* {{{ includes & prototypes */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_readline.h"
27 #include "readline_cli.h"
28
29 #if HAVE_LIBREADLINE || HAVE_LIBEDIT
30
31 #ifndef HAVE_RL_COMPLETION_MATCHES
32 #define rl_completion_matches completion_matches
33 #endif
34
35 #ifdef HAVE_LIBEDIT
36 #include <editline/readline.h>
37 #else
38 #include <readline/readline.h>
39 #include <readline/history.h>
40 #endif
41
42 PHP_FUNCTION(readline);
43 PHP_FUNCTION(readline_add_history);
44 PHP_FUNCTION(readline_info);
45 PHP_FUNCTION(readline_clear_history);
46 #ifndef HAVE_LIBEDIT
47 PHP_FUNCTION(readline_list_history);
48 #endif
49 PHP_FUNCTION(readline_read_history);
50 PHP_FUNCTION(readline_write_history);
51 PHP_FUNCTION(readline_completion_function);
52
53 #if HAVE_RL_CALLBACK_READ_CHAR
54 PHP_FUNCTION(readline_callback_handler_install);
55 PHP_FUNCTION(readline_callback_read_char);
56 PHP_FUNCTION(readline_callback_handler_remove);
57 PHP_FUNCTION(readline_redisplay);
58 PHP_FUNCTION(readline_on_new_line);
59
60 static zval _prepped_callback;
61
62 #endif
63
64 static zval _readline_completion;
65 static zval _readline_array;
66
67 PHP_MINIT_FUNCTION(readline);
68 PHP_MSHUTDOWN_FUNCTION(readline);
69 PHP_RSHUTDOWN_FUNCTION(readline);
70 PHP_MINFO_FUNCTION(readline);
71
72 /* }}} */
73
74 /* {{{ arginfo */
75 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline, 0, 0, 0)
76 ZEND_ARG_INFO(0, prompt)
77 ZEND_END_ARG_INFO()
78
79 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_info, 0, 0, 0)
80 ZEND_ARG_INFO(0, varname)
81 ZEND_ARG_INFO(0, newvalue)
82 ZEND_END_ARG_INFO()
83
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_add_history, 0, 0, 1)
85 ZEND_ARG_INFO(0, prompt)
86 ZEND_END_ARG_INFO()
87
88 ZEND_BEGIN_ARG_INFO(arginfo_readline_clear_history, 0)
89 ZEND_END_ARG_INFO()
90
91 #ifndef HAVE_LIBEDIT
92 ZEND_BEGIN_ARG_INFO(arginfo_readline_list_history, 0)
93 ZEND_END_ARG_INFO()
94 #endif
95
96 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_read_history, 0, 0, 0)
97 ZEND_ARG_INFO(0, filename)
98 ZEND_END_ARG_INFO()
99
100 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_write_history, 0, 0, 0)
101 ZEND_ARG_INFO(0, filename)
102 ZEND_END_ARG_INFO()
103
104 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_completion_function, 0, 0, 1)
105 ZEND_ARG_INFO(0, funcname)
106 ZEND_END_ARG_INFO()
107
108 #if HAVE_RL_CALLBACK_READ_CHAR
109 ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_callback_handler_install, 0, 0, 2)
110 ZEND_ARG_INFO(0, prompt)
111 ZEND_ARG_INFO(0, callback)
112 ZEND_END_ARG_INFO()
113
114 ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_read_char, 0)
115 ZEND_END_ARG_INFO()
116
117 ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_handler_remove, 0)
118 ZEND_END_ARG_INFO()
119
120 ZEND_BEGIN_ARG_INFO(arginfo_readline_redisplay, 0)
121 ZEND_END_ARG_INFO()
122
123 #if HAVE_RL_ON_NEW_LINE
124 ZEND_BEGIN_ARG_INFO(arginfo_readline_on_new_line, 0)
125 ZEND_END_ARG_INFO()
126 #endif
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 #ifndef PHP_WIN32
255 add_assoc_long(return_value,"end",rl_end);
256 #endif
257 #ifdef HAVE_LIBREADLINE
258 add_assoc_long(return_value,"mark",rl_mark);
259 add_assoc_long(return_value,"done",rl_done);
260 add_assoc_long(return_value,"pending_input",rl_pending_input);
261 add_assoc_string(return_value,"prompt",SAFE_STRING(rl_prompt));
262 add_assoc_string(return_value,"terminal_name",(char *)SAFE_STRING(rl_terminal_name));
263 add_assoc_str(return_value, "completion_append_character",
264 rl_completion_append_character == 0
265 ? ZSTR_EMPTY_ALLOC()
266 : ZSTR_CHAR(rl_completion_append_character));
267 add_assoc_bool(return_value,"completion_suppress_append",rl_completion_suppress_append);
268 #endif
269 #if HAVE_ERASE_EMPTY_LINE
270 add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line);
271 #endif
272 #ifndef PHP_WIN32
273 add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version));
274 #endif
275 add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name));
276 add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over);
277 } else {
278 if (!strcasecmp(what,"line_buffer")) {
279 oldstr = rl_line_buffer;
280 if (value) {
281 /* XXX if (rl_line_buffer) free(rl_line_buffer); */
282 convert_to_string_ex(value);
283 rl_line_buffer = strdup(Z_STRVAL_P(value));
284 }
285 RETVAL_STRING(SAFE_STRING(oldstr));
286 } else if (!strcasecmp(what, "point")) {
287 RETVAL_LONG(rl_point);
288 #ifndef PHP_WIN32
289 } else if (!strcasecmp(what, "end")) {
290 RETVAL_LONG(rl_end);
291 #endif
292 #ifdef HAVE_LIBREADLINE
293 } else if (!strcasecmp(what, "mark")) {
294 RETVAL_LONG(rl_mark);
295 } else if (!strcasecmp(what, "done")) {
296 oldval = rl_done;
297 if (value) {
298 convert_to_long_ex(value);
299 rl_done = Z_LVAL_P(value);
300 }
301 RETVAL_LONG(oldval);
302 } else if (!strcasecmp(what, "pending_input")) {
303 oldval = rl_pending_input;
304 if (value) {
305 convert_to_string_ex(value);
306 rl_pending_input = Z_STRVAL_P(value)[0];
307 }
308 RETVAL_LONG(oldval);
309 } else if (!strcasecmp(what, "prompt")) {
310 RETVAL_STRING(SAFE_STRING(rl_prompt));
311 } else if (!strcasecmp(what, "terminal_name")) {
312 RETVAL_STRING((char *)SAFE_STRING(rl_terminal_name));
313 } else if (!strcasecmp(what, "completion_suppress_append")) {
314 oldval = rl_completion_suppress_append;
315 if (value) {
316 rl_completion_suppress_append = zend_is_true(value);
317 }
318 RETVAL_BOOL(oldval);
319 } else if (!strcasecmp(what, "completion_append_character")) {
320 oldval = rl_completion_append_character;
321 if (value) {
322 convert_to_string_ex(value)
323 rl_completion_append_character = (int)Z_STRVAL_P(value)[0];
324 }
325 RETVAL_INTERNED_STR(
326 oldval == 0 ? ZSTR_EMPTY_ALLOC() : ZSTR_CHAR(oldval));
327 #endif
328 #if HAVE_ERASE_EMPTY_LINE
329 } else if (!strcasecmp(what, "erase_empty_line")) {
330 oldval = rl_erase_empty_line;
331 if (value) {
332 convert_to_long_ex(value);
333 rl_erase_empty_line = Z_LVAL_P(value);
334 }
335 RETVAL_LONG(oldval);
336 #endif
337 #ifndef PHP_WIN32
338 } else if (!strcasecmp(what,"library_version")) {
339 RETVAL_STRING((char *)SAFE_STRING(rl_library_version));
340 #endif
341 } else if (!strcasecmp(what, "readline_name")) {
342 oldstr = (char*)rl_readline_name;
343 if (value) {
344 /* XXX if (rl_readline_name) free(rl_readline_name); */
345 convert_to_string_ex(value);
346 rl_readline_name = strdup(Z_STRVAL_P(value));
347 }
348 RETVAL_STRING(SAFE_STRING(oldstr));
349 } else if (!strcasecmp(what, "attempted_completion_over")) {
350 oldval = rl_attempted_completion_over;
351 if (value) {
352 convert_to_long_ex(value);
353 rl_attempted_completion_over = Z_LVAL_P(value);
354 }
355 RETVAL_LONG(oldval);
356 }
357 }
358 }
359
360 /* }}} */
361 /* {{{ proto bool readline_add_history(string prompt)
362 Adds a line to the history */
PHP_FUNCTION(readline_add_history)363 PHP_FUNCTION(readline_add_history)
364 {
365 char *arg;
366 size_t arg_len;
367
368 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
369 return;
370 }
371
372 add_history(arg);
373
374 RETURN_TRUE;
375 }
376
377 /* }}} */
378 /* {{{ proto bool readline_clear_history(void)
379 Clears the history */
PHP_FUNCTION(readline_clear_history)380 PHP_FUNCTION(readline_clear_history)
381 {
382 if (zend_parse_parameters_none() == FAILURE) {
383 return;
384 }
385
386 #if HAVE_LIBEDIT
387 /* clear_history is the only function where rl_initialize
388 is not call to ensure correct allocation */
389 using_history();
390 #endif
391 clear_history();
392
393 RETURN_TRUE;
394 }
395
396 /* }}} */
397 /* {{{ proto array readline_list_history(void)
398 Lists the history */
399 #ifndef HAVE_LIBEDIT
PHP_FUNCTION(readline_list_history)400 PHP_FUNCTION(readline_list_history)
401 {
402 HIST_ENTRY **history;
403
404 if (zend_parse_parameters_none() == FAILURE) {
405 return;
406 }
407
408 history = history_list();
409
410 array_init(return_value);
411
412 if (history) {
413 int i;
414 for (i = 0; history[i]; i++) {
415 add_next_index_string(return_value,history[i]->line);
416 }
417 }
418 }
419 #endif
420 /* }}} */
421 /* {{{ proto bool readline_read_history([string filename])
422 Reads the history */
PHP_FUNCTION(readline_read_history)423 PHP_FUNCTION(readline_read_history)
424 {
425 char *arg = NULL;
426 size_t arg_len;
427
428 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p", &arg, &arg_len) == FAILURE) {
429 return;
430 }
431
432 if (arg && php_check_open_basedir(arg)) {
433 RETURN_FALSE;
434 }
435
436 /* XXX from & to NYI */
437 if (read_history(arg)) {
438 /* If filename is NULL, then read from `~/.history' */
439 RETURN_FALSE;
440 } else {
441 RETURN_TRUE;
442 }
443 }
444
445 /* }}} */
446 /* {{{ proto bool readline_write_history([string filename])
447 Writes the history */
PHP_FUNCTION(readline_write_history)448 PHP_FUNCTION(readline_write_history)
449 {
450 char *arg = NULL;
451 size_t arg_len;
452
453 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p", &arg, &arg_len) == FAILURE) {
454 return;
455 }
456
457 if (arg && php_check_open_basedir(arg)) {
458 RETURN_FALSE;
459 }
460
461 if (write_history(arg)) {
462 RETURN_FALSE;
463 } else {
464 RETURN_TRUE;
465 }
466 }
467
468 /* }}} */
469 /* {{{ proto bool readline_completion_function(string funcname)
470 Readline completion function? */
471
_readline_command_generator(const char * text,int state)472 static char *_readline_command_generator(const char *text, int state)
473 {
474 HashTable *myht = Z_ARRVAL(_readline_array);
475 zval *entry;
476
477 if (!state) {
478 zend_hash_internal_pointer_reset(myht);
479 }
480
481 while ((entry = zend_hash_get_current_data(myht)) != NULL) {
482 zend_hash_move_forward(myht);
483
484 convert_to_string_ex(entry);
485 if (strncmp (Z_STRVAL_P(entry), text, strlen(text)) == 0) {
486 return (strdup(Z_STRVAL_P(entry)));
487 }
488 }
489
490 return NULL;
491 }
492
_readline_string_zval(zval * ret,const char * str)493 static void _readline_string_zval(zval *ret, const char *str)
494 {
495 if (str) {
496 ZVAL_STRING(ret, (char*)str);
497 } else {
498 ZVAL_NULL(ret);
499 }
500 }
501
_readline_long_zval(zval * ret,long l)502 static void _readline_long_zval(zval *ret, long l)
503 {
504 ZVAL_LONG(ret, l);
505 }
506
_readline_completion_cb(const char * text,int start,int end)507 static char **_readline_completion_cb(const char *text, int start, int end)
508 {
509 zval params[3];
510 char **matches = NULL;
511
512 _readline_string_zval(¶ms[0], text);
513 _readline_long_zval(¶ms[1], start);
514 _readline_long_zval(¶ms[2], end);
515
516 if (call_user_function(CG(function_table), NULL, &_readline_completion, &_readline_array, 3, params) == SUCCESS) {
517 if (Z_TYPE(_readline_array) == IS_ARRAY) {
518 if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
519 matches = rl_completion_matches(text,_readline_command_generator);
520 } else {
521 matches = malloc(sizeof(char *) * 2);
522 if (!matches) {
523 return NULL;
524 }
525 matches[0] = strdup("");
526 matches[1] = NULL;
527 }
528 }
529 }
530
531 zval_ptr_dtor(¶ms[0]);
532 zval_ptr_dtor(&_readline_array);
533
534 return matches;
535 }
536
PHP_FUNCTION(readline_completion_function)537 PHP_FUNCTION(readline_completion_function)
538 {
539 zval *arg;
540
541 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg)) {
542 RETURN_FALSE;
543 }
544
545 if (!zend_is_callable(arg, 0, NULL)) {
546 zend_string *name = zend_get_callable_name(arg);
547 php_error_docref(NULL, E_WARNING, "%s is not callable", ZSTR_VAL(name));
548 zend_string_release_ex(name, 0);
549 RETURN_FALSE;
550 }
551
552 zval_ptr_dtor(&_readline_completion);
553 ZVAL_COPY(&_readline_completion, arg);
554
555 rl_attempted_completion_function = _readline_completion_cb;
556 if (rl_attempted_completion_function == NULL) {
557 RETURN_FALSE;
558 }
559 RETURN_TRUE;
560 }
561
562 /* }}} */
563
564 #if HAVE_RL_CALLBACK_READ_CHAR
565
php_rl_callback_handler(char * the_line)566 static void php_rl_callback_handler(char *the_line)
567 {
568 zval params[1];
569 zval dummy;
570
571 ZVAL_NULL(&dummy);
572
573 _readline_string_zval(¶ms[0], the_line);
574
575 call_user_function(CG(function_table), NULL, &_prepped_callback, &dummy, 1, params);
576
577 zval_ptr_dtor(¶ms[0]);
578 zval_ptr_dtor(&dummy);
579 }
580
581 /* {{{ proto void readline_callback_handler_install(string prompt, mixed callback)
582 Initializes the readline callback interface and terminal, prints the prompt and returns immediately */
PHP_FUNCTION(readline_callback_handler_install)583 PHP_FUNCTION(readline_callback_handler_install)
584 {
585 zval *callback;
586 char *prompt;
587 size_t prompt_len;
588
589 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &prompt, &prompt_len, &callback)) {
590 return;
591 }
592
593 if (!zend_is_callable(callback, 0, NULL)) {
594 zend_string *name = zend_get_callable_name(callback);
595 php_error_docref(NULL, E_WARNING, "%s is not callable", ZSTR_VAL(name));
596 zend_string_release_ex(name, 0);
597 RETURN_FALSE;
598 }
599
600 if (Z_TYPE(_prepped_callback) != IS_UNDEF) {
601 rl_callback_handler_remove();
602 zval_ptr_dtor(&_prepped_callback);
603 }
604
605 ZVAL_COPY(&_prepped_callback, 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 (Z_TYPE(_prepped_callback) != IS_UNDEF) {
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 (Z_TYPE(_prepped_callback) != IS_UNDEF) {
628 rl_callback_handler_remove();
629 zval_ptr_dtor(&_prepped_callback);
630 ZVAL_UNDEF(&_prepped_callback);
631 RETURN_TRUE;
632 }
633 RETURN_FALSE;
634 }
635 /* }}} */
636
637 /* {{{ proto void readline_redisplay(void)
638 Ask readline to redraw the display */
PHP_FUNCTION(readline_redisplay)639 PHP_FUNCTION(readline_redisplay)
640 {
641 #if HAVE_LIBEDIT
642 /* seems libedit doesn't take care of rl_initialize in rl_redisplay
643 * see bug #72538 */
644 using_history();
645 #endif
646 rl_redisplay();
647 }
648 /* }}} */
649
650 #endif
651
652 #if HAVE_RL_ON_NEW_LINE
653 /* {{{ proto void readline_on_new_line(void)
654 Inform readline that the cursor has moved to a new line */
PHP_FUNCTION(readline_on_new_line)655 PHP_FUNCTION(readline_on_new_line)
656 {
657 rl_on_new_line();
658 }
659 /* }}} */
660
661 #endif
662
663
664 #endif /* HAVE_LIBREADLINE */
665
666 /*
667 * Local variables:
668 * tab-width: 4
669 * c-basic-offset: 4
670 * End:
671 */
672