PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/readline - readline_cli.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 222 365 60.8 %
Date: 2014-11-15 Functions: 15 17 88.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 15 Nov 2014 06:19:37 +0000 (8 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.