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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/sapi/cli - php_cli_readline.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 195
Code covered: 62.1 % Executed lines: 121
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 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: php_cli_readline.c 272370 2008-12-31 11:15:49Z sebastian $ */
      21                 : 
      22                 : #include "php.h"
      23                 : 
      24                 : #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE)
      25                 : 
      26                 : #ifndef HAVE_RL_COMPLETION_MATCHES
      27                 : #define rl_completion_matches completion_matches
      28                 : #endif
      29                 : 
      30                 : #include "php_globals.h"
      31                 : #include "php_variables.h"
      32                 : #include "zend_hash.h"
      33                 : #include "zend_modules.h"
      34                 : 
      35                 : #include "SAPI.h"
      36                 : 
      37                 : #if HAVE_SETLOCALE
      38                 : #include <locale.h>
      39                 : #endif
      40                 : #include "zend.h"
      41                 : #include "zend_extensions.h"
      42                 : #include "php_ini.h"
      43                 : #include "php_globals.h"
      44                 : #include "php_main.h"
      45                 : #include "fopen_wrappers.h"
      46                 : #include "ext/standard/php_standard.h"
      47                 : 
      48                 : #ifdef __riscos__
      49                 : #include <unixlib/local.h>
      50                 : #endif
      51                 : 
      52                 : #include <readline/readline.h>
      53                 : #if !HAVE_LIBEDIT
      54                 : #include <readline/history.h>
      55                 : #endif
      56                 : 
      57                 : #include "zend_compile.h"
      58                 : #include "zend_execute.h"
      59                 : #include "zend_highlight.h"
      60                 : #include "zend_indent.h"
      61                 : 
      62                 : typedef enum {
      63                 :         body,
      64                 :         sstring,
      65                 :         dstring,
      66                 :         sstring_esc,
      67                 :         dstring_esc,
      68                 :         comment_line,
      69                 :         comment_block,
      70                 :         heredoc_start,
      71                 :         heredoc,
      72                 :         outside,
      73                 : } php_code_type;
      74                 : 
      75                 : int cli_is_valid_code(char *code, int len, char **prompt TSRMLS_DC) /* {{{ */
      76              18 : {
      77              18 :         int valid_end = 1, last_valid_end;
      78              18 :         int brackets_count = 0;
      79              18 :         int brace_count = 0;
      80                 :         int i;
      81              18 :         php_code_type code_type = body;
      82                 :         char *heredoc_tag;
      83                 :         int heredoc_len;
      84                 : 
      85             558 :         for (i = 0; i < len; ++i) {
      86             540 :                 switch(code_type) {
      87                 :                         default:
      88             297 :                                 switch(code[i]) {
      89                 :                                         case '{':
      90               6 :                                                 brackets_count++;
      91               6 :                                                 valid_end = 0;
      92               6 :                                                 break;
      93                 :                                         case '}':
      94               2 :                                                 if (brackets_count > 0) {
      95               2 :                                                         brackets_count--;
      96                 :                                                 }
      97               2 :                                                 valid_end = brackets_count ? 0 : 1;
      98               2 :                                                 break;
      99                 :                                         case '(':
     100               7 :                                                 brace_count++;
     101               7 :                                                 valid_end = 0;
     102               7 :                                                 break;
     103                 :                                         case ')':
     104               7 :                                                 if (brace_count > 0) {
     105               7 :                                                         brace_count--;
     106                 :                                                 }
     107               7 :                                                 valid_end = 0;
     108               7 :                                                 break;
     109                 :                                         case ';':
     110               8 :                                                 valid_end = brace_count == 0 && brackets_count == 0;
     111               8 :                                                 break;
     112                 :                                         case ' ':
     113                 :                                         case '\r':
     114                 :                                         case '\n':
     115                 :                                         case '\t':
     116              59 :                                                 break;
     117                 :                                         case '\'':
     118               4 :                                                 code_type = sstring;
     119               4 :                                                 break;
     120                 :                                         case '"':
     121               5 :                                                 code_type = dstring;
     122               5 :                                                 break;
     123                 :                                         case '#':
     124               0 :                                                 code_type = comment_line;
     125               0 :                                                 break;
     126                 :                                         case '/':
     127               0 :                                                 if (code[i+1] == '/') {
     128               0 :                                                         i++;
     129               0 :                                                         code_type = comment_line;
     130               0 :                                                         break;
     131                 :                                                 }
     132               0 :                                                 if (code[i+1] == '*') {
     133               0 :                                                         last_valid_end = valid_end;
     134               0 :                                                         valid_end = 0;
     135               0 :                                                         code_type = comment_block;
     136               0 :                                                         i++;
     137               0 :                                                         break;
     138                 :                                                 }
     139               0 :                                                 valid_end = 0;
     140               0 :                                                 break;
     141                 :                                         case '%':
     142               0 :                                                 if (!CG(asp_tags)) {
     143               0 :                                                         valid_end = 0;
     144               0 :                                                         break;
     145                 :                                                 }
     146                 :                                                 /* no break */
     147                 :                                         case '?':
     148               0 :                                                 if (code[i+1] == '>') {
     149               0 :                                                         i++;
     150               0 :                                                         code_type = outside;
     151               0 :                                                         break;
     152                 :                                                 }
     153               0 :                                                 valid_end = 0;
     154               0 :                                                 break;
     155                 :                                         case '<':
     156               6 :                                                 valid_end = 0;
     157               6 :                                                 if (i + 2 < len && code[i+1] == '<' && code[i+2] == '<') {
     158               6 :                                                         i += 2;
     159               6 :                                                         code_type = heredoc_start;
     160               6 :                                                         heredoc_len = 0;
     161                 :                                                 }
     162               6 :                                                 break;
     163                 :                                         default:
     164             193 :                                                 valid_end = 0;
     165                 :                                                 break;
     166                 :                                 }
     167             297 :                                 break;
     168                 :                         case sstring:
     169              56 :                                 if (code[i] == '\\') {
     170               0 :                                         code_type = sstring_esc;
     171                 :                                 } else {
     172              56 :                                         if (code[i] == '\'') {
     173               2 :                                                 code_type = body;
     174                 :                                         }
     175                 :                                 }
     176              56 :                                 break;
     177                 :                         case sstring_esc:
     178               0 :                                 code_type = sstring;
     179               0 :                                 break;
     180                 :                         case dstring:
     181              61 :                                 if (code[i] == '\\') {
     182               0 :                                         code_type = dstring_esc;
     183                 :                                 } else {
     184              61 :                                         if (code[i] == '"') {
     185               5 :                                                 code_type = body;
     186                 :                                         }
     187                 :                                 }
     188              61 :                                 break;
     189                 :                         case dstring_esc:
     190               0 :                                 code_type = dstring;
     191               0 :                                 break;
     192                 :                         case comment_line:
     193               0 :                                 if (code[i] == '\n') {
     194               0 :                                         code_type = body;
     195                 :                                 }
     196               0 :                                 break;
     197                 :                         case comment_block:
     198               0 :                                 if (code[i-1] == '*' && code[i] == '/') {
     199               0 :                                         code_type = body;
     200               0 :                                         valid_end = last_valid_end;
     201                 :                                 }
     202               0 :                                 break;
     203                 :                         case heredoc_start:
     204              48 :                                 switch(code[i]) {
     205                 :                                         case ' ':
     206                 :                                         case '\t':
     207               0 :                                                 break;
     208                 :                                         case '\r':
     209                 :                                         case '\n':
     210               6 :                                                 code_type = heredoc;
     211               6 :                                                 break;
     212                 :                                         default:
     213              42 :                                                 if (!heredoc_len) {
     214               6 :                                                         heredoc_tag = code+i;
     215                 :                                                 }
     216              42 :                                                 heredoc_len++;
     217                 :                                                 break;
     218                 :                                 }
     219              48 :                                 break;
     220                 :                         case heredoc:
     221              78 :                                 if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') {
     222               0 :                                         code_type = body;
     223              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') {
     224               1 :                                         code_type = body;
     225               1 :                                         valid_end = 1;
     226                 :                                 }
     227              78 :                                 break;
     228                 :                         case outside:
     229               0 :                                 if ((CG(short_tags) && !strncmp(code+i-1, "<?", 2))
     230                 :                                 ||  (CG(asp_tags) && !strncmp(code+i-1, "<%", 2))
     231                 :                                 ||  (i > 3 && !strncmp(code+i-4, "<?php", 5))
     232                 :                                 ) {
     233               0 :                                         code_type = body;
     234                 :                                 }
     235                 :                                 break;
     236                 :                 }
     237                 :         }
     238                 : 
     239              18 :         switch (code_type) {
     240                 :                 default:
     241              11 :                         if (brace_count) {
     242               0 :                                 *prompt = "php ( ";
     243              11 :                         } else if (brackets_count) {
     244               4 :                                 *prompt = "php { ";
     245                 :                         } else {
     246               7 :                                 *prompt = "php > ";
     247                 :                         }
     248              11 :                         break;
     249                 :                 case sstring:
     250                 :                 case sstring_esc:
     251               2 :                         *prompt = "php ' ";
     252               2 :                         break;
     253                 :                 case dstring:
     254                 :                 case dstring_esc:
     255               0 :                         *prompt = "php \" ";
     256               0 :                         break;
     257                 :                 case comment_block:
     258               0 :                         *prompt = "/*  > ";
     259               0 :                         break;
     260                 :                 case heredoc:
     261               5 :                         *prompt = "<<< > ";
     262               5 :                         break;
     263                 :                 case outside:
     264               0 :                         *prompt = "    > ";
     265                 :                         break;
     266                 :         }
     267                 : 
     268              18 :         if (!valid_end || brackets_count) {
     269              11 :                 return 0;
     270                 :         } else {
     271               7 :                 return 1;
     272                 :         }
     273                 : }
     274                 : /* }}} */
     275                 : 
     276                 : static char *cli_completion_generator_ht(const char *text, int textlen, int *state, HashTable *ht, void **pData TSRMLS_DC) /* {{{ */
     277               4 : {
     278                 :         char *name;
     279                 :         ulong number;
     280                 : 
     281               4 :         if (!(*state % 2)) {
     282               3 :                 zend_hash_internal_pointer_reset(ht);
     283               3 :                 (*state)++;
     284                 :         }
     285            4328 :         while(zend_hash_has_more_elements(ht) == SUCCESS) {
     286            4321 :                 zend_hash_get_current_key(ht, &name, &number, 0);
     287            4321 :                 if (!textlen || !strncmp(name, text, textlen)) {
     288               1 :                         if (pData) {
     289               1 :                                 zend_hash_get_current_data(ht, pData);
     290                 :                         }
     291               1 :                         zend_hash_move_forward(ht);
     292               1 :                         return name;
     293                 :                 }
     294            4320 :                 if (zend_hash_move_forward(ht) == FAILURE) {
     295               0 :                         break;
     296                 :                 }
     297                 :         }
     298               3 :         (*state)++;
     299               3 :         return NULL;
     300                 : } /* }}} */
     301                 : 
     302                 : static char *cli_completion_generator_var(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */
     303               0 : {
     304                 :         char *retval, *tmp;
     305                 : 
     306               0 :         tmp = retval = cli_completion_generator_ht(text + 1, textlen - 1, state, EG(active_symbol_table), NULL TSRMLS_CC);
     307               0 :         if (retval) {
     308               0 :                 retval = malloc(strlen(tmp) + 2);
     309               0 :                 retval[0] = '$';
     310               0 :                 strcpy(&retval[1], tmp);
     311               0 :                 rl_completion_append_character = '\0';
     312                 :         }
     313               0 :         return retval;
     314                 : } /* }}} */
     315                 : 
     316                 : static char *cli_completion_generator_func(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */
     317               2 : {
     318                 :         zend_function *func;
     319               2 :         char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&func TSRMLS_CC);
     320               2 :         if (retval) {
     321               1 :                 rl_completion_append_character = '(';
     322               1 :                 retval = strdup(func->common.function_name);
     323                 :         }
     324                 :         
     325               2 :         return retval;
     326                 : } /* }}} */
     327                 : 
     328                 : static char *cli_completion_generator_class(const char *text, int textlen, int *state TSRMLS_DC) /* {{{ */
     329               1 : {
     330                 :         zend_class_entry **pce;
     331               1 :         char *retval = cli_completion_generator_ht(text, textlen, state, EG(class_table), (void**)&pce TSRMLS_CC);
     332               1 :         if (retval) {
     333               0 :                 rl_completion_append_character = '\0';
     334               0 :                 retval = strdup((*pce)->name);
     335                 :         }
     336                 :         
     337               1 :         return retval;
     338                 : } /* }}} */
     339                 : 
     340                 : static char *cli_completion_generator_define(const char *text, int textlen, int *state, HashTable *ht TSRMLS_DC) /* {{{ */
     341               1 : {
     342                 :         zend_class_entry **pce;
     343               1 :         char *retval = cli_completion_generator_ht(text, textlen, state, ht, (void**)&pce TSRMLS_CC);
     344               1 :         if (retval) {
     345               0 :                 rl_completion_append_character = '\0';
     346               0 :                 retval = strdup(retval);
     347                 :         }
     348                 :         
     349               1 :         return retval;
     350                 : } /* }}} */
     351                 : 
     352                 : static int cli_completion_state;
     353                 : 
     354                 : static char *cli_completion_generator(const char *text, int index) /* {{{ */
     355               2 : {
     356                 : /*
     357                 : TODO:
     358                 : - constants
     359                 : - maybe array keys
     360                 : - language constructs and other things outside a hashtable (echo, try, function, class, ...)
     361                 : - object/class members
     362                 : 
     363                 : - future: respect scope ("php > function foo() { $[tab]" should only expand to local variables...)
     364                 : */
     365               2 :         char *retval = NULL;
     366               2 :         int textlen = strlen(text);
     367                 :         TSRMLS_FETCH();
     368                 : 
     369               2 :         if (!index) {
     370               1 :                 cli_completion_state = 0;
     371                 :         }
     372               2 :         if (text[0] == '$') {
     373               0 :                 retval = cli_completion_generator_var(text, textlen, &cli_completion_state TSRMLS_CC);
     374                 :         } else {
     375                 :                 char *lc_text, *class_name, *class_name_end;
     376                 :                 int class_name_len;
     377               2 :                 zend_class_entry **pce = NULL;
     378                 :                 
     379               2 :                 class_name_end = strstr(text, "::");
     380               2 :                 if (class_name_end) {
     381               0 :                         class_name_len = class_name_end - text;
     382               0 :                         class_name = zend_str_tolower_dup(text, class_name_len);
     383               0 :                         class_name[class_name_len] = '\0'; /* not done automatically */
     384               0 :                         if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC)==FAILURE) {
     385               0 :                                 efree(class_name);
     386               0 :                                 return NULL;
     387                 :                         }
     388               0 :                         lc_text = zend_str_tolower_dup(class_name_end + 2, textlen - 2 - class_name_len);
     389               0 :                         textlen -= (class_name_len + 2);
     390                 :                 } else {
     391               2 :                         lc_text = zend_str_tolower_dup(text, textlen);
     392                 :                 }
     393                 : 
     394               2 :                 switch (cli_completion_state) {
     395                 :                         case 0:
     396                 :                         case 1:
     397               2 :                                 retval = cli_completion_generator_func(lc_text, textlen, &cli_completion_state, pce ? &(*pce)->function_table : EG(function_table) TSRMLS_CC);
     398               2 :                                 if (retval) {
     399               1 :                                         break;
     400                 :                                 }
     401                 :                         case 2:
     402                 :                         case 3:
     403               1 :                                 retval = cli_completion_generator_define(text, textlen, &cli_completion_state, pce ? &(*pce)->constants_table : EG(zend_constants) TSRMLS_CC);
     404               1 :                                 if (retval || pce) {
     405                 :                                         break;
     406                 :                                 }
     407                 :                         case 4:
     408                 :                         case 5:
     409               1 :                                 retval = cli_completion_generator_class(lc_text, textlen, &cli_completion_state TSRMLS_CC);
     410                 :                                 break;
     411                 :                         default:
     412                 :                                 break;
     413                 :                 }
     414               2 :                 efree(lc_text);
     415               2 :                 if (class_name_end) {
     416               0 :                         efree(class_name);
     417                 :                 }
     418               2 :                 if (pce && retval) {
     419               0 :                         int len = class_name_len + 2 + strlen(retval) + 1;
     420               0 :                         char *tmp = malloc(len);
     421                 :                         
     422               0 :                         snprintf(tmp, len, "%s::%s", (*pce)->name, retval);
     423               0 :                         free(retval);
     424               0 :                         retval = tmp;
     425                 :                 }
     426                 :         }
     427                 :         
     428               2 :         return retval;
     429                 : } /* }}} */
     430                 : 
     431                 : char **cli_code_completion(const char *text, int start, int end) /* {{{ */
     432               1 : {
     433               1 :         return rl_completion_matches(text, cli_completion_generator);
     434                 : }
     435                 : /* }}} */
     436                 : 
     437                 : #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
     438                 : 
     439                 : /*
     440                 :  * Local variables:
     441                 :  * tab-width: 4
     442                 :  * c-basic-offset: 4
     443                 :  * End:
     444                 :  * vim600: sw=4 ts=4 fdm=marker
     445                 :  * vim<600: sw=4 ts=4
     446                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:17 +0000 (3 days ago)

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