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