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

Generated by: LCOV version 1.10

Generated at Tue, 04 Aug 2015 09:11:10 +0000 (10 hours ago)

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