Annotation of embedaddon/php/ext/readline/readline_cli.c, revision 1.1
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: Marcus Boerger <helly@php.net> |
! 16: | Johannes Schlueter <johannes@php.net> |
! 17: +----------------------------------------------------------------------+
! 18: */
! 19:
! 20: /* $Id$ */
! 21:
! 22: #include "php.h"
! 23:
! 24: #ifndef HAVE_RL_COMPLETION_MATCHES
! 25: #define rl_completion_matches completion_matches
! 26: #endif
! 27:
! 28: #include "php_globals.h"
! 29: #include "php_variables.h"
! 30: #include "zend_hash.h"
! 31: #include "zend_modules.h"
! 32:
! 33: #include "SAPI.h"
! 34:
! 35: #if HAVE_SETLOCALE
! 36: #include <locale.h>
! 37: #endif
! 38: #include "zend.h"
! 39: #include "zend_extensions.h"
! 40: #include "php_ini.h"
! 41: #include "php_globals.h"
! 42: #include "php_main.h"
! 43: #include "fopen_wrappers.h"
! 44: #include "ext/standard/php_standard.h"
! 45: #include "ext/standard/php_smart_str.h"
! 46:
! 47: #ifdef __riscos__
! 48: #include <unixlib/local.h>
! 49: #endif
! 50:
! 51: #if HAVE_LIBEDIT
! 52: #include <editline/readline.h>
! 53: #else
! 54: #include <readline/readline.h>
! 55: #include <readline/history.h>
! 56: #endif
! 57:
! 58: #include "zend_compile.h"
! 59: #include "zend_execute.h"
! 60: #include "zend_highlight.h"
! 61: #include "zend_indent.h"
! 62: #include "zend_exceptions.h"
! 63:
! 64: #include "sapi/cli/cli.h"
! 65: #include "readline_cli.h"
! 66:
! 67: #ifdef COMPILE_DL_READLINE
! 68: #include <dlfcn.h>
! 69: #endif
! 70:
! 71: #ifndef RTLD_DEFAULT
! 72: #define RTLD_DEFAULT NULL
! 73: #endif
! 74:
! 75: #define DEFAULT_PROMPT "\\b \\> "
! 76:
! 77: ZEND_DECLARE_MODULE_GLOBALS(cli_readline);
! 78:
! 79: static char php_last_char = '\0';
! 80: static FILE *pager_pipe = NULL;
! 81:
! 82: static size_t readline_shell_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */
! 83: {
! 84: if (CLIR_G(prompt_str)) {
! 85: smart_str_appendl(CLIR_G(prompt_str), str, str_length);
! 86: return str_length;
! 87: }
! 88:
! 89: if (CLIR_G(pager) && *CLIR_G(pager) && !pager_pipe) {
! 90: pager_pipe = VCWD_POPEN(CLIR_G(pager), "w");
! 91: }
! 92: if (pager_pipe) {
! 93: return fwrite(str, 1, MIN(str_length, 16384), pager_pipe);
! 94: }
! 95:
! 96: return -1;
! 97: }
! 98: /* }}} */
! 99:
! 100: static int readline_shell_ub_write(const char *str, uint str_length TSRMLS_DC) /* {{{ */
! 101: {
! 102: php_last_char = str[str_length-1];
! 103: return -1;
! 104: }
! 105: /* }}} */
! 106:
! 107: static void cli_readline_init_globals(zend_cli_readline_globals *rg TSRMLS_DC)
! 108: {
! 109: rg->pager = NULL;
! 110: rg->prompt = NULL;
! 111: rg->prompt_str = NULL;
! 112: }
! 113:
! 114: PHP_INI_BEGIN()
! 115: STD_PHP_INI_ENTRY("cli.pager", "", PHP_INI_ALL, OnUpdateString, pager, zend_cli_readline_globals, cli_readline_globals)
! 116: STD_PHP_INI_ENTRY("cli.prompt", DEFAULT_PROMPT, PHP_INI_ALL, OnUpdateString, prompt, zend_cli_readline_globals, cli_readline_globals)
! 117: PHP_INI_END()
! 118:
! 119:
! 120:
! 121: typedef enum {
! 122: body,
! 123: sstring,
! 124: dstring,
! 125: sstring_esc,
! 126: dstring_esc,
! 127: comment_line,
! 128: comment_block,
! 129: heredoc_start,
! 130: heredoc,
! 131: outside,
! 132: } php_code_type;
! 133:
! 134: static char *cli_get_prompt(char *block, char prompt TSRMLS_DC) /* {{{ */
! 135: {
! 136: smart_str retval = {0};
! 137: char *prompt_spec = CLIR_G(prompt) ? CLIR_G(prompt) : DEFAULT_PROMPT;
! 138:
! 139: do {
! 140: if (*prompt_spec == '\\') {
! 141: switch (prompt_spec[1]) {
! 142: case '\\':
! 143: smart_str_appendc(&retval, '\\');
! 144: prompt_spec++;
! 145: break;
! 146: case 'n':
! 147: smart_str_appendc(&retval, '\n');
! 148: prompt_spec++;
! 149: break;
! 150: case 't':
! 151: smart_str_appendc(&retval, '\t');
! 152: prompt_spec++;
! 153: break;
! 154: case 'e':
! 155: smart_str_appendc(&retval, '\033');
! 156: prompt_spec++;
! 157: break;
! 158:
! 159:
! 160: case 'v':
! 161: smart_str_appends(&retval, PHP_VERSION);
! 162: prompt_spec++;
! 163: break;
! 164: case 'b':
! 165: smart_str_appends(&retval, block);
! 166: prompt_spec++;
! 167: break;
! 168: case '>':
! 169: smart_str_appendc(&retval, prompt);
! 170: prompt_spec++;
! 171: break;
! 172: case '`':
! 173: smart_str_appendc(&retval, '`');
! 174: prompt_spec++;
! 175: break;
! 176: default:
! 177: smart_str_appendc(&retval, '\\');
! 178: break;
! 179: }
! 180: } else if (*prompt_spec == '`') {
! 181: char *prompt_end = strstr(prompt_spec + 1, "`");
! 182: char *code;
! 183:
! 184: if (prompt_end) {
! 185: code = estrndup(prompt_spec + 1, prompt_end - prompt_spec - 1);
! 186:
! 187: CLIR_G(prompt_str) = &retval;
! 188: zend_try {
! 189: zend_eval_stringl(code, prompt_end - prompt_spec - 1, NULL, "php prompt code" TSRMLS_CC);
! 190: } zend_end_try();
! 191: CLIR_G(prompt_str) = NULL;
! 192: efree(code);
! 193: prompt_spec = prompt_end;
! 194: }
! 195: } else {
! 196: smart_str_appendc(&retval, *prompt_spec);
! 197: }
! 198: } while (++prompt_spec && *prompt_spec);
! 199: smart_str_0(&retval);
! 200: return retval.c;
! 201: }
! 202: /* }}} */
! 203:
! 204: static int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */
! 205: {
! 206: int valid_end = 1, last_valid_end;
! 207: int brackets_count = 0;
! 208: int brace_count = 0;
! 209: int i;
! 210: php_code_type code_type = body;
! 211: char *heredoc_tag;
! 212: int heredoc_len;
! 213:
! 214: for (i = 0; i < len; ++i) {
! 215: switch(code_type) {
! 216: default:
! 217: switch(code[i]) {
! 218: case '{':
! 219: brackets_count++;
! 220: valid_end = 0;
! 221: break;
! 222: case '}':
! 223: if (brackets_count > 0) {
! 224: brackets_count--;
! 225: }
! 226: valid_end = brackets_count ? 0 : 1;
! 227: break;
! 228: case '(':
! 229: brace_count++;
! 230: valid_end = 0;
! 231: break;
! 232: case ')':
! 233: if (brace_count > 0) {
! 234: brace_count--;
! 235: }
! 236: valid_end = 0;
! 237: break;
! 238: case ';':
! 239: valid_end = brace_count == 0 && brackets_count == 0;
! 240: break;
! 241: case ' ':
! 242: case '\r':
! 243: case '\n':
! 244: case '\t':
! 245: break;
! 246: case '\'':
! 247: code_type = sstring;
! 248: break;
! 249: case '"':
! 250: code_type = dstring;
! 251: break;
! 252: case '#':
! 253: code_type = comment_line;
! 254: break;
! 255: case '/':
! 256: if (code[i+1] == '/') {
! 257: i++;
! 258: code_type = comment_line;
! 259: break;
! 260: }
! 261: if (code[i+1] == '*') {
! 262: last_valid_end = valid_end;
! 263: valid_end = 0;
! 264: code_type = comment_block;
! 265: i++;
! 266: break;
! 267: }
! 268: valid_end = 0;
! 269: break;
! 270: case '%':
! 271: if (!CG(asp_tags)) {
! 272: valid_end = 0;
! 273: break;
! 274: }
! 275: /* no break */
! 276: case '?':
! 277: if (code[i+1] == '>') {
! 278: i++;
! 279: code_type = outside;
! 280: break;
! 281: }
! 282: valid_end = 0;
! 283: break;
! 284: case '<':
! 285: valid_end = 0;
! 286: if (i + 2 < len && code[i+1] == '<' && code[i+2] == '<') {
! 287: i += 2;
! 288: code_type = heredoc_start;
! 289: heredoc_len = 0;
! 290: }
! 291: break;
! 292: default:
! 293: valid_end = 0;
! 294: break;
! 295: }
! 296: break;
! 297: case sstring:
! 298: if (code[i] == '\\') {
! 299: code_type = sstring_esc;
! 300: } else {
! 301: if (code[i] == '\'') {
! 302: code_type = body;
! 303: }
! 304: }
! 305: break;
! 306: case sstring_esc:
! 307: code_type = sstring;
! 308: break;
! 309: case dstring:
! 310: if (code[i] == '\\') {
! 311: code_type = dstring_esc;
! 312: } else {
! 313: if (code[i] == '"') {
! 314: code_type = body;
! 315: }
! 316: }
! 317: break;
! 318: case dstring_esc:
! 319: code_type = dstring;
! 320: break;
! 321: case comment_line:
! 322: if (code[i] == '\n') {
! 323: code_type = body;
! 324: }
! 325: break;
! 326: case comment_block:
! 327: if (code[i-1] == '*' && code[i] == '/') {
! 328: code_type = body;
! 329: valid_end = last_valid_end;
! 330: }
! 331: break;
! 332: case heredoc_start:
! 333: switch(code[i]) {
! 334: case ' ':
! 335: case '\t':
! 336: case '\'':
! 337: break;
! 338: case '\r':
! 339: case '\n':
! 340: code_type = heredoc;
! 341: break;
! 342: default:
! 343: if (!heredoc_len) {
! 344: heredoc_tag = code+i;
! 345: }
! 346: heredoc_len++;
! 347: break;
! 348: }
! 349: break;
! 350: case heredoc:
! 351: if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') {
! 352: code_type = body;
! 353: } else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') {
! 354: code_type = body;
! 355: valid_end = 1;
! 356: }
! 357: break;
! 358: case outside:
! 359: if ((CG(short_tags) && !strncmp(code+i-1, "<?", 2))
! 360: || (CG(asp_tags) && !strncmp(code+i-1, "<%", 2))
! 361: || (i > 3 && !strncmp(code+i-4, "<?php", 5))
! 362: ) {
! 363: code_type = body;
! 364: }
! 365: break;
! 366: }
! 367: }
! 368:
! 369: switch (code_type) {
! 370: default:
! 371: if (brace_count) {
! 372: *prompt = cli_get_prompt("php", '(' TSRMLS_CC);
! 373: } else if (brackets_count) {
! 374: *prompt = cli_get_prompt("php", '{' TSRMLS_CC);
! 375: } else {
! 376: *prompt = cli_get_prompt("php", '>' TSRMLS_CC);
! 377: }
! 378: break;
! 379: case sstring:
! 380: case sstring_esc:
! 381: *prompt = cli_get_prompt("php", '\'' TSRMLS_CC);
! 382: break;
! 383: case dstring:
! 384: case dstring_esc:
! 385: *prompt = cli_get_prompt("php", '"' TSRMLS_CC);
! 386: break;
! 387: case comment_block:
! 388: *prompt = cli_get_prompt("/* ", '>' TSRMLS_CC);
! 389: break;
! 390: case heredoc:
! 391: *prompt = cli_get_prompt("<<<", '>' TSRMLS_CC);
! 392: break;
! 393: case outside:
! 394: *prompt = cli_get_prompt(" ", '>' TSRMLS_CC);
! 395: break;
! 396: }
! 397:
! 398: if (!valid_end || brackets_count) {
! 399: return 0;
! 400: } else {
! 401: return 1;
! 402: }
! 403: }
! 404: /* }}} */
! 405:
! 406: static char *cli_completion_generator_ht(const char *text, int textlen, int *state, HashTable *ht, void **pData TSRMLS_DC) /* {{{ */
! 407: {
! 408: char *name;
! 409: ulong number;
! 410:
! 411: if (!(*state % 2)) {
! 412: zend_hash_internal_pointer_reset(ht);
! 413: (*state)++;
! 414: }
! 415: while(zend_hash_has_more_elements(ht) == SUCCESS) {
! 416: zend_hash_get_current_key(ht, &name, &number, 0);
! 417: if (!textlen || !strncmp(name, text, textlen)) {
! 418: if (pData) {
! 419: zend_hash_get_current_data(ht, pData);
! 420: }
! 421: zend_hash_move_forward(ht);
! 422: return name;
! 423: }
! 424: if (zend_hash_move_forward(ht) == FAILURE) {
! 425: break;
! 426: }
! 427: }
! 428: (*state)++;
! 429: return NULL;
! 430: } /* }}} */
! 431:
! 432: static char *cli_completion_generator_var(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */
! 433: {
! 434: char *retval, *tmp;
! 435:
! 436: tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(active_symbol_table), NULL TSRMLS_CC);
! 437: if (retval) {
! 438: retval = malloc(strlen(tmp) + 2);
! 439: retval[0] = '$';
! 440: strcpy(&retval[1], tmp);
! 441: rl_completion_append_character = '\0';
! 442: }
! 443: return retval;
! 444: } /* }}} */
! 445:
! 446: static char *cli_completion_generator_ini(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */
! 447: {
! 448: char *retval, *tmp;
! 449:
! 450: tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(ini_directives), NULL TSRMLS_CC);
! 451: if (retval) {
! 452: retval = malloc(strlen(tmp) + 2);
! 453: retval[0] = '#';
! 454: strcpy(&retval[1], tmp);
! 455: rl_completion_append_character = '=';
! 456: }
! 457: return retval;
! 458: } /* }}} */
! 459:
! 460: static char *cli_completion_generator_func(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */
! 461: {
! 462: zend_function *func;
! 463: char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&func TSRMLS_CC);
! 464: if (retval) {
! 465: rl_completion_append_character = '(';
! 466: retval = strdup(func->common.function_name);
! 467: }
! 468:
! 469: return retval;
! 470: } /* }}} */
! 471:
! 472: static char *cli_completion_generator_class(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */
! 473: {
! 474: zend_class_entry **pce;
! 475: char *retval = cli_completion_generator_ht(text, textlen, state, EG(class_table), (void**)&pce TSRMLS_CC);
! 476: if (retval) {
! 477: rl_completion_append_character = '\0';
! 478: retval = strdup((*pce)->name);
! 479: }
! 480:
! 481: return retval;
! 482: } /* }}} */
! 483:
! 484: static char *cli_completion_generator_define(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */
! 485: {
! 486: zend_class_entry **pce;
! 487: char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&pce TSRMLS_CC);
! 488: if (retval) {
! 489: rl_completion_append_character = '\0';
! 490: retval = strdup(retval);
! 491: }
! 492:
! 493: return retval;
! 494: } /* }}} */
! 495:
! 496: static int cli_completion_state;
! 497:
! 498: static char *cli_completion_generator(const char *text, int index) /* {{{ */
! 499: {
! 500: /*
! 501: TODO:
! 502: - constants
! 503: - maybe array keys
! 504: - language constructs and other things outside a hashtable (echo, try, function, class, ...)
! 505: - object/class members
! 506:
! 507: - future: respect scope ("php > function foo() { $[tab]" should only expand to local variables...)
! 508: */
! 509: char *retval = NULL;
! 510: int textlen = strlen(text);
! 511: TSRMLS_FETCH();
! 512:
! 513: if (!index) {
! 514: cli_completion_state = 0;
! 515: }
! 516: if (text[0] == '$') {
! 517: retval = cli_completion_generator_var(text, textlen, &cli_completion_state TSRMLS_CC);
! 518: } else if (text[0] == '#') {
! 519: retval = cli_completion_generator_ini(text, textlen, &cli_completion_state TSRMLS_CC);
! 520: } else {
! 521: char *lc_text, *class_name, *class_name_end;
! 522: int class_name_len;
! 523: zend_class_entry **pce = NULL;
! 524:
! 525: class_name_end = strstr(text, "::");
! 526: if (class_name_end) {
! 527: class_name_len = class_name_end - text;
! 528: class_name = zend_str_tolower_dup(text, class_name_len);
! 529: class_name[class_name_len] = '\0'; /* not done automatically */
! 530: if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) {
! 531: efree(class_name);
! 532: return NULL;
! 533: }
! 534: lc_text = zend_str_tolower_dup(class_name_end + 2, textlen - 2 - class_name_len);
! 535: textlen -= (class_name_len + 2);
! 536: } else {
! 537: lc_text = zend_str_tolower_dup(text, textlen);
! 538: }
! 539:
! 540: switch (cli_completion_state) {
! 541: case 0:
! 542: case 1:
! 543: retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, pce ? &(*pce)->function_table : EG(function_table) TSRMLS_CC);
! 544: if (retval) {
! 545: break;
! 546: }
! 547: case 2:
! 548: case 3:
! 549: retval = cli_completion_generator_define(text, textlen, &cli_completion_state, pce ? &(*pce)->constants_table : EG(zend_constants) TSRMLS_CC);
! 550: if (retval || pce) {
! 551: break;
! 552: }
! 553: case 4:
! 554: case 5:
! 555: retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state TSRMLS_CC);
! 556: break;
! 557: default:
! 558: break;
! 559: }
! 560: efree(lc_text);
! 561: if (class_name_end) {
! 562: efree(class_name);
! 563: }
! 564: if (pce && retval) {
! 565: int len = class_name_len + 2 + strlen(retval) + 1;
! 566: char *tmp = malloc(len);
! 567:
! 568: snprintf(tmp, len, "%s::%s", (*pce)->name, retval);
! 569: free(retval);
! 570: retval = tmp;
! 571: }
! 572: }
! 573:
! 574: return retval;
! 575: } /* }}} */
! 576:
! 577: static char **cli_code_completion(const char *text, int start, int end) /* {{{ */
! 578: {
! 579: return rl_completion_matches(text, cli_completion_generator);
! 580: }
! 581: /* }}} */
! 582:
! 583: static int readline_shell_run(TSRMLS_D) /* {{{ */
! 584: {
! 585: char *line;
! 586: size_t size = 4096, pos = 0, len;
! 587: char *code = emalloc(size);
! 588: char *prompt = cli_get_prompt("php", '>' TSRMLS_CC);
! 589: char *history_file;
! 590:
! 591: if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
! 592: zend_file_handle *prepend_file_p;
! 593: zend_file_handle prepend_file = {0};
! 594:
! 595: prepend_file.filename = PG(auto_prepend_file);
! 596: prepend_file.opened_path = NULL;
! 597: prepend_file.free_filename = 0;
! 598: prepend_file.type = ZEND_HANDLE_FILENAME;
! 599: prepend_file_p = &prepend_file;
! 600:
! 601: zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p);
! 602: }
! 603:
! 604: history_file = tilde_expand("~/.php_history");
! 605: rl_attempted_completion_function = cli_code_completion;
! 606: rl_special_prefixes = "$";
! 607: read_history(history_file);
! 608:
! 609: EG(exit_status) = 0;
! 610: while ((line = readline(prompt)) != NULL) {
! 611: if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
! 612: free(line);
! 613: break;
! 614: }
! 615:
! 616: if (!pos && !*line) {
! 617: free(line);
! 618: continue;
! 619: }
! 620:
! 621: len = strlen(line);
! 622:
! 623: if (line[0] == '#') {
! 624: char *param = strstr(&line[1], "=");
! 625: if (param) {
! 626: char *cmd;
! 627: uint cmd_len;
! 628: param++;
! 629: cmd_len = param - &line[1] - 1;
! 630: cmd = estrndup(&line[1], cmd_len);
! 631:
! 632: zend_alter_ini_entry_ex(cmd, cmd_len + 1, param, strlen(param), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
! 633: efree(cmd);
! 634: add_history(line);
! 635:
! 636: efree(prompt);
! 637: /* TODO: This might be wrong! */
! 638: prompt = cli_get_prompt("php", '>' TSRMLS_CC);
! 639: continue;
! 640: }
! 641: }
! 642:
! 643: if (pos + len + 2 > size) {
! 644: size = pos + len + 2;
! 645: code = erealloc(code, size);
! 646: }
! 647: memcpy(&code[pos], line, len);
! 648: pos += len;
! 649: code[pos] = '\n';
! 650: code[++pos] = '\0';
! 651:
! 652: if (*line) {
! 653: add_history(line);
! 654: }
! 655:
! 656: free(line);
! 657: efree(prompt);
! 658:
! 659: if (!cli_is_valid_code(code, pos, &prompt TSRMLS_CC)) {
! 660: continue;
! 661: }
! 662:
! 663: zend_try {
! 664: zend_eval_stringl(code, pos, NULL, "php shell code" TSRMLS_CC);
! 665: } zend_end_try();
! 666:
! 667: pos = 0;
! 668:
! 669: if (!pager_pipe && php_last_char != '\0' && php_last_char != '\n') {
! 670: readline_shell_write("\n", 1 TSRMLS_CC);
! 671: }
! 672:
! 673: if (EG(exception)) {
! 674: zend_exception_error(EG(exception), E_WARNING TSRMLS_CC);
! 675: }
! 676:
! 677: if (pager_pipe) {
! 678: fclose(pager_pipe);
! 679: pager_pipe = NULL;
! 680: }
! 681:
! 682: php_last_char = '\0';
! 683: }
! 684: write_history(history_file);
! 685: free(history_file);
! 686: efree(code);
! 687: efree(prompt);
! 688: return EG(exit_status);
! 689: }
! 690: /* }}} */
! 691:
! 692: /*
! 693: #ifdef COMPILE_DL_READLINE
! 694: This dlsym() is always used as even the CGI SAPI is linked against "CLI"-only
! 695: extensions. If that is being changed dlsym() should only be used when building
! 696: this extension sharedto offer compatibility.
! 697: */
! 698: #define GET_SHELL_CB(cb) \
! 699: do { \
! 700: (cb) = NULL; \
! 701: cli_shell_callbacks_t *(*get_callbacks)(); \
! 702: get_callbacks = dlsym(RTLD_DEFAULT, "php_cli_get_shell_callbacks"); \
! 703: if (get_callbacks) { \
! 704: (cb) = get_callbacks(); \
! 705: } \
! 706: } while(0)
! 707: /*#else
! 708: #define GET_SHELL_CB(cb) (cb) = php_cli_get_shell_callbacks()
! 709: #endif*/
! 710:
! 711: PHP_MINIT_FUNCTION(cli_readline)
! 712: {
! 713: cli_shell_callbacks_t *cb;
! 714:
! 715: ZEND_INIT_MODULE_GLOBALS(cli_readline, cli_readline_init_globals, NULL);
! 716: REGISTER_INI_ENTRIES();
! 717:
! 718: #if HAVE_LIBEDIT
! 719: REGISTER_STRING_CONSTANT("READLINE_LIB", "libedit", CONST_CS|CONST_PERSISTENT);
! 720: #else
! 721: REGISTER_STRING_CONSTANT("READLINE_LIB", "readline", CONST_CS|CONST_PERSISTENT);
! 722: #endif
! 723:
! 724: GET_SHELL_CB(cb);
! 725: if (cb) {
! 726: cb->cli_shell_write = readline_shell_write;
! 727: cb->cli_shell_ub_write = readline_shell_ub_write;
! 728: cb->cli_shell_run = readline_shell_run;
! 729: }
! 730:
! 731: return SUCCESS;
! 732: }
! 733:
! 734: PHP_MSHUTDOWN_FUNCTION(cli_readline)
! 735: {
! 736: cli_shell_callbacks_t *cb;
! 737:
! 738: UNREGISTER_INI_ENTRIES();
! 739:
! 740: GET_SHELL_CB(cb);
! 741: if (cb) {
! 742: cb->cli_shell_write = NULL;
! 743: cb->cli_shell_ub_write = NULL;
! 744: cb->cli_shell_run = NULL;
! 745: }
! 746:
! 747: return SUCCESS;
! 748: }
! 749:
! 750: PHP_MINFO_FUNCTION(cli_readline)
! 751: {
! 752: php_info_print_table_start();
! 753: php_info_print_table_header(2, "Readline Support", "enabled");
! 754: php_info_print_table_row(2, "Readline library", (rl_library_version ? rl_library_version : "Unknown"));
! 755: php_info_print_table_end();
! 756:
! 757: DISPLAY_INI_ENTRIES();
! 758: }
! 759:
! 760: /*
! 761: * Local variables:
! 762: * tab-width: 4
! 763: * c-basic-offset: 4
! 764: * End:
! 765: * vim600: sw=4 ts=4 fdm=marker
! 766: * vim<600: sw=4 ts=4
! 767: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>