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