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: 221 350 63.1 %
Date: 2016-08-24 Functions: 15 17 88.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:28 +0000 (30 hours ago)

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