home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / PHP / CompatInfo / Cli.php next >
Encoding:
PHP Script  |  2008-07-02  |  51.6 KB  |  1,528 lines

  1. <?php
  2. /**
  3.  * CLI Script to Check Compatibility of chunk of PHP code
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * LICENSE: This source file is subject to version 3.01 of the PHP license
  8.  * that is available through the world-wide-web at the following URI:
  9.  * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
  10.  * the PHP License and are unable to obtain it through the web, please
  11.  * send a note to license@php.net so we can mail you a copy immediately.
  12.  *
  13.  * @category PHP
  14.  * @package  PHP_CompatInfo
  15.  * @author   Davey Shafik <davey@php.net>
  16.  * @author   Laurent Laville <pear@laurent-laville.org>
  17.  * @license  http://www.php.net/license/3_01.txt  PHP License 3.01
  18.  * @version  CVS: $Id: Cli.php,v 1.61 2008/04/10 22:19:34 farell Exp $
  19.  * @link     http://pear.php.net/package/PHP_CompatInfo
  20.  * @since    File available since Release 0.8.0
  21.  */
  22.  
  23. require_once 'PHP/CompatInfo.php';
  24. require_once 'Console/Getargs.php';
  25. require_once 'Console/Table.php';
  26.  
  27. /**
  28.  * CLI Script to Check Compatibility of chunk of PHP code
  29.  *
  30.  * <code>
  31.  * <?php
  32.  *     require_once 'PHP/CompatInfo/Cli.php';
  33.  *     $cli = new PHP_CompatInfo_Cli;
  34.  *     $cli->run();
  35.  * ?>
  36.  * </code>
  37.  *
  38.  * @example docs/examples/cliCustom.php Example of using PHP_CompatInfo_Cli
  39.  *
  40.  * @category  PHP
  41.  * @package   PHP_CompatInfo
  42.  * @author    Davey Shafik <davey@php.net>
  43.  * @author    Laurent Laville <pear@laurent-laville.org>
  44.  * @copyright 2003 Davey Shafik and Synaptic Media. All Rights Reserved.
  45.  * @license   http://www.php.net/license/3_01.txt  PHP License 3.01
  46.  * @version   Release: 1.7.0
  47.  * @link      http://pear.php.net/package/PHP_CompatInfo
  48.  * @since     Class available since Release 0.8.0
  49.  */
  50.  
  51. class PHP_CompatInfo_Cli extends PHP_CompatInfo
  52. {
  53.     /**
  54.      * @var    array    Current CLI Flags
  55.      * @since  0.8.0
  56.      */
  57.     var $opts = array();
  58.  
  59.     /**
  60.      * @var    string   error message
  61.      * @since  0.8.0
  62.      */
  63.     var $error;
  64.  
  65.     /**
  66.      * @var    string   String to be Processed
  67.      * @since  1.6.0
  68.      */
  69.     var $string;
  70.  
  71.     /**
  72.      * @var    string   File to be Processed
  73.      * @since  0.8.0
  74.      */
  75.     var $file;
  76.  
  77.     /**
  78.      * @var    string   Directory to be Processed
  79.      * @since  0.8.0
  80.      */
  81.     var $dir;
  82.  
  83.     /**
  84.      * @var    object   Console_Getargs instance
  85.      * @since  1.4.0
  86.      */
  87.     var $args;
  88.  
  89.     /**
  90.      * @var    array    Current parser options
  91.      * @since  1.4.0
  92.      */
  93.     var $options = array();
  94.  
  95.     /**
  96.      * @var    integer  Output level detail
  97.      * @since  1.7.0b3
  98.      */
  99.     var $_output_level;
  100.  
  101.  
  102.     /**
  103.      * ZE2 Constructor
  104.      *
  105.      * @since  0.8.0
  106.      */
  107.     function __construct()
  108.     {
  109.         $this->opts = array(
  110.             'dir' =>
  111.                 array('short' => 'd',
  112.                       'desc'  => 'Parse DIR to get its compatibility info',
  113.                       'default' => '',
  114.                       'min'   => 0 , 'max' => 1),
  115.             'file' =>
  116.                 array('short' => 'f',
  117.                       'desc' => 'Parse FILE to get its compatibility info',
  118.                       'default' => '',
  119.                       'min'   => 0 , 'max' => 1),
  120.             'string' =>
  121.                 array('short' => 's',
  122.                       'desc' => 'Parse STRING to get its compatibility info',
  123.                       'default' => '',
  124.                       'min'   => 0 , 'max' => 1),
  125.             'verbose' =>
  126.                 array('short'   => 'v',
  127.                       'desc'    => 'Set the verbose level',
  128.                       'default' => 1,
  129.                       'min'     => 0 , 'max' => 1),
  130.             'no-recurse' =>
  131.                 array('short' => 'n',
  132.                       'desc'  => 'Do not recursively parse files when using --dir',
  133.                       'max'   => 0),
  134.             'ignore-files' =>
  135.                 array('short'   => 'if',
  136.                       'desc'    => 'Data file name which contains a list of '
  137.                                  . 'file to ignore',
  138.                       'default' => 'files.txt',
  139.                       'min'     => 0 , 'max' => 1),
  140.             'ignore-dirs' =>
  141.                 array('short'   => 'id',
  142.                       'desc'    => 'Data file name which contains a list of '
  143.                                  . 'directory to ignore',
  144.                       'default' => 'dirs.txt',
  145.                       'min'     => 0 , 'max' => 1),
  146.             'ignore-functions' =>
  147.                 array('short'   => 'in',
  148.                       'desc'    => 'Data file name which contains a list of '
  149.                                  . 'php function to ignore',
  150.                       'default' => 'functions.txt',
  151.                       'min'     => 0 , 'max' => 1),
  152.             'ignore-constants' =>
  153.                 array('short'   => 'ic',
  154.                       'desc'    => 'Data file name which contains a list of '
  155.                                  . 'php constant to ignore',
  156.                       'default' => 'constants.txt',
  157.                       'min'     => 0 , 'max' => 1),
  158.             'ignore-extensions' =>
  159.                 array('short'   => 'ie',
  160.                       'desc'    => 'Data file name which contains a list of '
  161.                                  . 'php extension to ignore',
  162.                       'default' => 'extensions.txt',
  163.                       'min'     => 0 , 'max' => 1),
  164.             'ignore-versions' =>
  165.                 array('short'   => 'iv',
  166.                       'desc'    => 'PHP versions - functions to exclude '
  167.                                  . 'when parsing source code',
  168.                       'default' => '5.0.0',
  169.                       'min'     => 0 , 'max' => 2),
  170.             'ignore-functions-match' =>
  171.                 array('short'   => 'inm',
  172.                       'desc'    => 'Data file name which contains a list of '
  173.                                  . 'php function pattern to ignore',
  174.                       'default' => 'functions-match.txt',
  175.                       'min'     => 0 , 'max' => 1),
  176.             'ignore-extensions-match' =>
  177.                 array('short'   => 'iem',
  178.                       'desc'    => 'Data file name which contains a list of '
  179.                                  . 'php extension pattern to ignore',
  180.                       'default' => 'extensions-match.txt',
  181.                       'min'     => 0 , 'max' => 1),
  182.             'ignore-constants-match' =>
  183.                 array('short'   => 'icm',
  184.                       'desc'    => 'Data file name which contains a list of '
  185.                                  . 'php constant pattern to ignore',
  186.                       'default' => 'constants-match.txt',
  187.                       'min'     => 0 , 'max' => 1),
  188.             'file-ext' =>
  189.                 array('short'   => 'fe',
  190.                       'desc'    => 'A comma separated list of file extensions '
  191.                                  . 'to parse (only valid if parsing a directory)',
  192.                       'default' => 'php, php4, inc, phtml',
  193.                       'min'     => 0 , 'max' => 1),
  194.             'report' =>
  195.                 array('short' => 'r',
  196.                       'desc' => 'Print either "xml" or "cli" report',
  197.                       'default' => 'cli',
  198.                       'min'   => 0 , 'max' => 1),
  199.             'output-level' =>
  200.                 array('short' => 'o',
  201.                       'desc' => 'Print Path/File + Version with additional data',
  202.                       'default' => 15,
  203.                       'min'   => 0 , 'max' => 1),
  204.             'summarize' =>
  205.                 array('short' => 'S',
  206.                       'desc' => 'Print only summary when parsing directory',
  207.                       'max'   => 0),
  208.             'version' =>
  209.                 array('short' => 'V',
  210.                       'desc'  => 'Print version information',
  211.                       'max'   => 0),
  212.             'help' =>
  213.                 array('short' => 'h',
  214.                       'desc'  => 'Show this help',
  215.                       'max'   => 0),
  216.         );
  217.         $this->args = & Console_Getargs::factory($this->opts);
  218.         if (PEAR::isError($this->args)) {
  219.             if ($this->args->getCode() === CONSOLE_GETARGS_HELP) {
  220.                 $this->error = '';
  221.             } else {
  222.                 $this->error = $this->args->getMessage();
  223.             }
  224.             return;
  225.         }
  226.  
  227.         // version
  228.         $V = $this->args->getValue('V');
  229.         if (isset($V)) {
  230.             $this->error = 'PHP_CompatInfo (cli) version 1.7.0'
  231.                          . ' (http://pear.php.net/package/PHP_CompatInfo)';
  232.             return;
  233.         }
  234.  
  235.         // debug
  236.         $this->options['debug'] = false;
  237.         if ($this->args->isDefined('v')) {
  238.             $v = $this->args->getValue('v');
  239.             if ($v > 3) {
  240.                 $this->options['debug'] = true;
  241.             }
  242.         }
  243.  
  244.         // no-recurse
  245.         if ($this->args->isDefined('n')) {
  246.             $this->options['recurse_dir'] = false;
  247.         }
  248.  
  249.         // dir
  250.         if ($this->args->isDefined('d')) {
  251.             $d = $this->args->getValue('d');
  252.             if (file_exists($d)) {
  253.                 if ($d{strlen($d)-1} == '/' || $d{strlen($d)-1} == '\\') {
  254.                     $d = substr($d, 0, -1);
  255.                 }
  256.                 $this->dir = str_replace('\\', '/', realpath($d));
  257.             } else {
  258.                 $this->error = 'Failed opening directory "' . $d
  259.                      . '". Please check your spelling and try again.';
  260.                 return;
  261.             }
  262.         }
  263.  
  264.         // file
  265.         if ($this->args->isDefined('f')) {
  266.             $f = $this->args->getValue('f');
  267.             if (file_exists($f)) {
  268.                 $this->file = $f;
  269.             } else {
  270.                 $this->error = 'Failed opening file "' . $f
  271.                      . '". Please check your spelling and try again.';
  272.                 return;
  273.             }
  274.         }
  275.  
  276.         // string
  277.         if ($this->args->isDefined('s')) {
  278.             $s = $this->args->getValue('s');
  279.             if (!empty($s)) {
  280.                 $this->string = sprintf("<?php %s ?>", $s);
  281.             } else {
  282.                 $this->error = 'Failed opening string "' . $s
  283.                      . '". Please check your spelling and try again.';
  284.                 return;
  285.             }
  286.         }
  287.  
  288.         // ignore-files
  289.         $if = $this->args->getValue('if');
  290.         if (isset($if)) {
  291.             if (file_exists($if)) {
  292.                 $options                       = $this->_parseParamFile($if);
  293.                 $this->options['ignore_files'] = $options['std'];
  294.             } else {
  295.                 $this->error = 'Failed opening file "' . $if
  296.                      . '" (ignore-files option). '
  297.                      . 'Please check your spelling and try again.';
  298.                 return;
  299.             }
  300.         }
  301.  
  302.         // ignore-dirs
  303.         $id = $this->args->getValue('id');
  304.         if (isset($id)) {
  305.             if (file_exists($id)) {
  306.                 $options                      = $this->_parseParamFile($id);
  307.                 $this->options['ignore_dirs'] = $options['std'];
  308.             } else {
  309.                 $this->error = 'Failed opening file "' . $id
  310.                      . '" (ignore-dirs option). '
  311.                      . 'Please check your spelling and try again.';
  312.                 return;
  313.             }
  314.         }
  315.  
  316.         // ignore-functions
  317.         $in = $this->args->getValue('in');
  318.         if (isset($in)) {
  319.             if (file_exists($in)) {
  320.                 $options                           = $this->_parseParamFile($in);
  321.                 $this->options['ignore_functions'] = $options['std'];
  322.             } else {
  323.                 $this->error = 'Failed opening file "' . $in
  324.                      . '" (ignore-functions option). '
  325.                      . 'Please check your spelling and try again.';
  326.                 return;
  327.             }
  328.         }
  329.  
  330.         // ignore-constants
  331.         $ic = $this->args->getValue('ic');
  332.         if (isset($ic)) {
  333.             if (file_exists($ic)) {
  334.                 $options                           = $this->_parseParamFile($ic);
  335.                 $this->options['ignore_constants'] = $options['std'];
  336.             } else {
  337.                 $this->error = 'Failed opening file "' . $ic
  338.                      . '" (ignore-constants option). '
  339.                      . 'Please check your spelling and try again.';
  340.                 return;
  341.             }
  342.         }
  343.  
  344.         // ignore-extensions
  345.         $ie = $this->args->getValue('ie');
  346.         if (isset($ie)) {
  347.             if (file_exists($ie)) {
  348.                 $options                            = $this->_parseParamFile($ie);
  349.                 $this->options['ignore_extensions'] = $options['std'];
  350.             } else {
  351.                 $this->error = 'Failed opening file "' . $ie
  352.                      . '" (ignore-extensions option). '
  353.                      . 'Please check your spelling and try again.';
  354.                 return;
  355.             }
  356.         }
  357.  
  358.         // ignore-versions
  359.         $iv = $this->args->getValue('iv');
  360.         if (isset($iv)) {
  361.             if (!is_array($iv)) {
  362.                 $iv = array($iv);
  363.             }
  364.             $this->options['ignore_versions'] = $iv;
  365.         }
  366.  
  367.         // ignore-functions-match
  368.         $inm = $this->args->getValue('inm');
  369.         if (isset($inm)) {
  370.             if (file_exists($inm)) {
  371.                 $patterns = $this->_parseParamFile($inm, true);
  372.                 if (count($patterns['std']) > 0
  373.                     && count($patterns['reg']) > 0) {
  374.                     $this->error = 'Mixed "function_exists" and '
  375.                          . '"preg_match" conditions are not allowed. '
  376.                          . 'Please check your spelling and try again.';
  377.                     return;
  378.  
  379.                 } elseif (count($patterns['std']) > 0) {
  380.                     $this->options['ignore_functions_match']
  381.                         = array('function_exists', $patterns['std']);
  382.                 } elseif (count($patterns['reg']) > 0) {
  383.                     $this->options['ignore_functions_match']
  384.                         = array('preg_match', $patterns['reg']);
  385.                 }
  386.             } else {
  387.                 $this->error = 'Failed opening file "' . $inm
  388.                      . '" (ignore-functions-match option). '
  389.                      . 'Please check your spelling and try again.';
  390.                 return;
  391.             }
  392.         }
  393.  
  394.         // ignore-extensions-match
  395.         $iem = $this->args->getValue('iem');
  396.         if (isset($iem)) {
  397.             if (file_exists($iem)) {
  398.                 $patterns = $this->_parseParamFile($iem, true);
  399.                 if (count($patterns['std']) > 0
  400.                     && count($patterns['reg']) > 0) {
  401.                     $this->error = 'Mixed "extension_loaded" and '
  402.                          . '"preg_match" conditions are not allowed. '
  403.                          . 'Please check your spelling and try again.';
  404.                     return;
  405.  
  406.                 } elseif (count($patterns['std']) > 0) {
  407.                     $this->options['ignore_extensions_match']
  408.                         = array('extension_loaded', $patterns['std']);
  409.                 } elseif (count($patterns['reg']) > 0) {
  410.                     $this->options['ignore_extensions_match']
  411.                         = array('preg_match', $patterns['reg']);
  412.                 }
  413.             } else {
  414.                 $this->error = 'Failed opening file "' . $iem
  415.                      . '" (ignore-extensions-match option). '
  416.                      . 'Please check your spelling and try again.';
  417.                 return;
  418.             }
  419.         }
  420.  
  421.         // ignore-constants-match
  422.         $icm = $this->args->getValue('icm');
  423.         if (isset($icm)) {
  424.             if (file_exists($icm)) {
  425.                 $patterns = $this->_parseParamFile($icm, true);
  426.                 if (count($patterns['std']) > 0
  427.                     && count($patterns['reg']) > 0) {
  428.                     $this->error = 'Mixed "defined" and '
  429.                          . '"preg_match" conditions are not allowed. '
  430.                          . 'Please check your spelling and try again.';
  431.                     return;
  432.  
  433.                 } elseif (count($patterns['std']) > 0) {
  434.                     $this->options['ignore_constants_match']
  435.                         = array('defined', $patterns['std']);
  436.                 } elseif (count($patterns['reg']) > 0) {
  437.                     $this->options['ignore_constants_match']
  438.                         = array('preg_match', $patterns['reg']);
  439.                 }
  440.             } else {
  441.                 $this->error = 'Failed opening file "' . $icm
  442.                      . '" (ignore-constants-match option). '
  443.                      . 'Please check your spelling and try again.';
  444.                 return;
  445.             }
  446.         }
  447.  
  448.         // file-ext
  449.         if ($this->args->isDefined('d') && $this->args->isDefined('fe')) {
  450.             $fe = $this->args->getValue('fe');
  451.             if (is_string($fe)) {
  452.                 $this->options['file_ext'] = explode(',', $fe);
  453.             } else {
  454.                 $this->error = 'No valid file extensions provided "'
  455.                      . '". Please check your spelling and try again.';
  456.                 return;
  457.             }
  458.         }
  459.  
  460.         // output-level
  461.         if ($this->args->isDefined('o')) {
  462.             $this->_output_level = $this->args->getValue('o');
  463.         } else {
  464.             $this->_output_level = 15; // default = full detail
  465.         }
  466.  
  467.         // file or directory options are minimum required to work
  468.         if (!$this->args->isDefined('f')
  469.             && !$this->args->isDefined('d')
  470.             && !$this->args->isDefined('s')) {
  471.             $this->error = 'ERROR: You must supply at least '
  472.                 . 'one string, file or directory to process';
  473.         }
  474.     }
  475.  
  476.     /**
  477.      * ZE1 PHP4 Compatible Constructor
  478.      *
  479.      * @since  0.8.0
  480.      */
  481.     function PHP_CompatInfo_Cli()
  482.     {
  483.         $this->__construct();
  484.     }
  485.  
  486.     /**
  487.      * Run the CLI Script
  488.      *
  489.      * @return void
  490.      * @access public
  491.      * @since  0.8.0
  492.      */
  493.     function run()
  494.     {
  495.         if (isset($this->error)) {
  496.             if (strpos($this->error, 'PHP_CompatInfo') === false) {
  497.                 $this->_printUsage($this->error);
  498.             } else {
  499.                 // when Version asked, do not print help usage
  500.                 echo $this->error;
  501.             }
  502.         } else {
  503.             if (isset($this->dir)) {
  504.                 $this->_parseDir();
  505.             } elseif (isset($this->file)) {
  506.                 $this->_parseFile();
  507.             } elseif (isset($this->string)) {
  508.                 $this->_parseString();
  509.             }
  510.         }
  511.     }
  512.  
  513.     /**
  514.      * Parse content of parameter files
  515.      *
  516.      * Parse content of parameter files used by switches
  517.      * <ul>
  518.      * <li>ignore-files
  519.      * <li>ignore-dirs
  520.      * <li>ignore-functions
  521.      * <li>ignore-constants
  522.      * <li>ignore-extensions
  523.      * <li>ignore-functions-match
  524.      * <li>ignore-extensions-match
  525.      * <li>ignore-constants-match
  526.      * </ul>
  527.      *
  528.      * @param string $fn          Parameter file name
  529.      * @param bool   $withPattern TRUE if the file may contain regular expression
  530.      *
  531.      * @return array
  532.      * @access private
  533.      * @since  version 1.7.0b4 (2008-04-03)
  534.      */
  535.     function _parseParamFile($fn, $withPattern = false)
  536.     {
  537.         $lines    = file($fn);
  538.         $patterns = array('std' => array(), 'reg' => array());
  539.         foreach ($lines as $line) {
  540.             $line = rtrim($line);  // remove line ending
  541.             if (strlen($line) == 0) {
  542.                 continue;  // skip empty lines
  543.             }
  544.             if ($line{0} == ';') {
  545.                 continue;  // skip this pattern: consider as comment line
  546.             }
  547.             if ($line{0} == '=') {
  548.                 list($p, $s)       = explode('=', $line);
  549.                 $patterns['reg'][] = '/'.$s.'/';
  550.             } else {
  551.                 if ($withPattern === true) {
  552.                     $patterns['std'][] = '/'.$line.'/';
  553.                 } else {
  554.                     $patterns['std'][] = $line;
  555.                 }
  556.             }
  557.         }
  558.         return $patterns;
  559.     }
  560.  
  561.     /**
  562.      * Parse Directory Input
  563.      *
  564.      * @return void
  565.      * @access private
  566.      * @since  0.8.0
  567.      */
  568.     function _parseDir()
  569.     {
  570.         $info = $this->parseDir($this->dir, $this->options);
  571.         if ($info === false) {
  572.             $err = 'No valid files into directory "' . $this->dir
  573.                . '". Please check your spelling and try again.';
  574.             $this->_printUsage($err);
  575.             return;
  576.         }
  577.         $o = $this->_output_level;
  578.         if ($this->args->isDefined('r')) {
  579.             $r = $this->args->getValue('r');
  580.             if ($r == 'xml') {
  581.                 $this->_printXMLReport($info);
  582.                 return;
  583.             }
  584.         }
  585.  
  586.         $table = new Console_Table();
  587.         $hdr   = array('Path', 'Version');
  588.         $f     = 1;
  589.         if ($o & 1) {
  590.             $hdr[] = 'C';
  591.             $f++;
  592.         }
  593.         if ($o & 2) {
  594.             $hdr[]   = 'Extensions';
  595.             $filter2 = array(&$this, '_splitExtname');
  596.             $table->addFilter($f+1, $filter2);
  597.             $f++;
  598.         }
  599.         if ($o & 4) {
  600.             if ($o & 8) {
  601.                 $hdr[] = 'Constants/Tokens';
  602.             } else {
  603.                 $hdr[] = 'Constants';
  604.             }
  605.             $f++;
  606.         } else {
  607.             if ($o & 8) {
  608.                 $hdr[] = 'Tokens';
  609.                 $f++;
  610.             }
  611.         }
  612.         $table->setHeaders($hdr);
  613.         $filter0 = array(&$this, '_splitFilename');
  614.         $table->addFilter(0, $filter0);
  615.         if ($o > 3) {
  616.             $filter3 = array(&$this, '_splitConstant');
  617.             $table->addFilter($f, $filter3);
  618.         }
  619.  
  620.         $ext   = implode("\r\n", $info['extensions']);
  621.         $const = implode("\r\n", array_merge($info['constants'], $info['tokens']));
  622.         $ds    = DIRECTORY_SEPARATOR;
  623.         $dir   = str_replace(array('\\', '/'), $ds, $this->dir);
  624.  
  625.         $data = array($dir . $ds . '*');
  626.         if (empty($info['max_version'])) {
  627.             $data[] = $info['version'];
  628.         } else {
  629.             $data[] = implode("\r\n", array($info['version'], $info['max_version']));
  630.         }
  631.  
  632.         if ($o & 1) {
  633.             $data[] = $info['cond_code'][0];
  634.         }
  635.         if ($o & 2) {
  636.             $data[] = $ext;
  637.         }
  638.         if ($o & 4) {
  639.             if ($o & 8) {
  640.                 $data[] = $const;
  641.             } else {
  642.                 $data[] = implode("\r\n", $info['constants']);
  643.             }
  644.         } else {
  645.             if ($o & 8) {
  646.                 $data[] = implode("\r\n", $info['tokens']);
  647.             }
  648.         }
  649.  
  650.         $table->addRow($data);
  651.  
  652.         // summarize : print only summary for directory without files details
  653.         if ($this->args->isDefined('S') === false) {
  654.  
  655.             unset($info['max_version']);
  656.             unset($info['version']);
  657.             unset($info['extensions']);
  658.             unset($info['constants']);
  659.             unset($info['tokens']);
  660.             unset($info['cond_code']);
  661.  
  662.             $ignored = $info['ignored_files'];
  663.  
  664.             unset($info['ignored_files']);
  665.             unset($info['ignored_functions']);
  666.             unset($info['ignored_extensions']);
  667.             unset($info['ignored_constants']);
  668.  
  669.             foreach ($info as $file => $info) {
  670.                 if ($info === false) {
  671.                     continue;  // skip this (invalid) file
  672.                 }
  673.                 $ext   = implode("\r\n", $info['extensions']);
  674.                 $const = implode("\r\n", array_merge($info['constants'],
  675.                                                      $info['tokens']));
  676.  
  677.                 $file = str_replace(array('\\', '/'), $ds, $file);
  678.                 $table->addSeparator();
  679.  
  680.                 $data = array($file);
  681.                 if (empty($info['max_version'])) {
  682.                     $data[] = $info['version'];
  683.                 } else {
  684.                     $data[] = implode("\r\n",
  685.                                       array($info['version'], $info['max_version']));
  686.                 }
  687.  
  688.                 if ($o & 1) {
  689.                     $data[] = $info['cond_code'][0];
  690.                 }
  691.                 if ($o & 2) {
  692.                     $data[] = $ext;
  693.                 }
  694.                 if ($o & 4) {
  695.                     if ($o & 8) {
  696.                         $data[] = $const;
  697.                     } else {
  698.                         $data[] = implode("\r\n", $info['constants']);
  699.                     }
  700.                 } else {
  701.                     if ($o & 8) {
  702.                         $data[] = implode("\r\n", $info['tokens']);
  703.                     }
  704.                 }
  705.  
  706.                 $table->addRow($data);
  707.             }
  708.         }
  709.         $output = $table->getTable();
  710.  
  711.         // verbose level
  712.         $v = $this->args->getValue('v');
  713.  
  714.         // command line resume
  715.         if ($v & 1) {
  716.             $output .= "\nCommand Line resume :\n\n";
  717.  
  718.             $table = new Console_Table();
  719.             $table->setHeaders(array('Option', 'Value'));
  720.  
  721.             $filter0 = array(&$this, '_splitOption');
  722.             $table->addFilter(0, $filter0);
  723.             $filter1 = array(&$this, '_splitValue');
  724.             $table->addFilter(1, $filter1);
  725.  
  726.             $opts = $this->args->getValues();
  727.             if (is_array($opts)) {
  728.                 foreach ($opts as $key => $raw) {
  729.                     if (is_array($raw)) {
  730.                         $raw = implode(', ', $raw);
  731.                     }
  732.                     $contents = array($key, $raw);
  733.                     $table->addRow($contents);
  734.                 }
  735.             }
  736.  
  737.             $output .= $table->getTable();
  738.         }
  739.  
  740.         // parser options resume
  741.         if ($v & 2) {
  742.             $output .= "\nParser options :\n\n";
  743.  
  744.             $table = new Console_Table();
  745.             $table->setHeaders(array('Option', 'Value'));
  746.  
  747.             $filter0 = array(&$this, '_splitOption');
  748.             $table->addFilter(0, $filter0);
  749.             $filter1 = array(&$this, '_splitValue');
  750.             $table->addFilter(1, $filter1);
  751.  
  752.             $opts = $this->options;
  753.             if (is_array($opts)) {
  754.                 foreach ($opts as $key => $raw) {
  755.                     if ($key == 'debug' || $key == 'recurse_dir') {
  756.                         $raw = ($raw === true) ? 'TRUE' : 'FALSE';
  757.                     }
  758.                     if (substr($key, -6) == '_match') {
  759.                         $val = array_values($raw[1]);
  760.                         array_unshift($val, $raw[0]);
  761.                         $raw = implode("\r\n", $val);
  762.                     } else {
  763.                         if (is_array($raw)) {
  764.                             $raw = implode("\r\n", $raw);
  765.                         }
  766.                     }
  767.                     $contents = array($key, $raw);
  768.                     $table->addRow($contents);
  769.                 }
  770.             }
  771.  
  772.             $output .= $table->getTable();
  773.         }
  774.  
  775.         echo $output;
  776.     }
  777.  
  778.     /**
  779.      * Parse File Input
  780.      *
  781.      * @return void
  782.      * @access private
  783.      * @since  0.8.0
  784.      */
  785.     function _parseFile()
  786.     {
  787.         $info = $this->parseFile($this->file, $this->options);
  788.         if ($info === false) {
  789.             $err = 'Failed opening file "' . $this->file
  790.                . '". Please check your spelling and try again.';
  791.             $this->_printUsage($err);
  792.             return;
  793.         }
  794.         $o = $this->_output_level;
  795.         if ($this->args->isDefined('r')) {
  796.             $r = $this->args->getValue('r');
  797.             if ($r == 'xml') {
  798.                 $this->_printXMLReport($info);
  799.                 return;
  800.             }
  801.         }
  802.  
  803.         $table = new Console_Table();
  804.         $hdr   = array('File', 'Version');
  805.         $f     = 1;
  806.         if ($o & 1) {
  807.             $hdr[] = 'C';
  808.             $f++;
  809.         }
  810.         if ($o & 2) {
  811.             $hdr[]   = 'Extensions';
  812.             $filter2 = array(&$this, '_splitExtname');
  813.             $table->addFilter($f+1, $filter2);
  814.             $f++;
  815.         }
  816.         if ($o & 4) {
  817.             if ($o & 8) {
  818.                 $hdr[] = 'Constants/Tokens';
  819.             } else {
  820.                 $hdr[] = 'Constants';
  821.             }
  822.             $f++;
  823.         } else {
  824.             if ($o & 8) {
  825.                 $hdr[] = 'Tokens';
  826.                 $f++;
  827.             }
  828.         }
  829.         $table->setHeaders($hdr);
  830.         $filter0 = array(&$this, '_splitFilename');
  831.         $table->addFilter(0, $filter0);
  832.         if ($o > 3) {
  833.             $filter3 = array(&$this, '_splitConstant');
  834.             $table->addFilter($f, $filter3);
  835.         }
  836.  
  837.         $ext   = implode("\r\n", $info['extensions']);
  838.         $const = implode("\r\n", array_merge($info['constants'], $info['tokens']));
  839.         $data  = array($this->file);
  840.         if (empty($info['max_version'])) {
  841.             $data[] = $info['version'];
  842.         } else {
  843.             $data[] = implode("\r\n", array($info['version'], $info['max_version']));
  844.         }
  845.  
  846.         if ($o & 1) {
  847.             $data[] = $info['cond_code'][0];
  848.         }
  849.         if ($o & 2) {
  850.             $data[] = $ext;
  851.         }
  852.         if ($o & 4) {
  853.             if ($o & 8) {
  854.                 $data[] = $const;
  855.             } else {
  856.                 $data[] = implode("\r\n", $info['constants']);
  857.             }
  858.         } else {
  859.             if ($o & 8) {
  860.                 $data[] = implode("\r\n", $info['tokens']);
  861.             }
  862.         }
  863.  
  864.         $table->addRow($data);
  865.  
  866.         $output = $table->getTable();
  867.  
  868.         // verbose level
  869.         $v = $this->args->getValue('v');
  870.  
  871.         // command line resume
  872.         if ($v & 1) {
  873.             $output .= "\nCommand Line resume :\n\n";
  874.  
  875.             $table = new Console_Table();
  876.             $table->setHeaders(array('Option', 'Value'));
  877.  
  878.             $filter0 = array(&$this, '_splitOption');
  879.             $table->addFilter(0, $filter0);
  880.             $filter1 = array(&$this, '_splitValue');
  881.             $table->addFilter(1, $filter1);
  882.  
  883.             $opts = $this->args->getValues();
  884.             if (is_array($opts)) {
  885.                 foreach ($opts as $key => $raw) {
  886.                     if (is_array($raw)) {
  887.                         $raw = implode(', ', $raw);
  888.                     }
  889.                     $contents = array($key, $raw);
  890.                     $table->addRow($contents);
  891.                 }
  892.             }
  893.  
  894.             $output .= $table->getTable();
  895.         }
  896.  
  897.         // parser options resume
  898.         if ($v & 2) {
  899.             $output .= "\nParser options :\n\n";
  900.  
  901.             $table = new Console_Table();
  902.             $table->setHeaders(array('Option', 'Value'));
  903.  
  904.             $filter0 = array(&$this, '_splitOption');
  905.             $table->addFilter(0, $filter0);
  906.             $filter1 = array(&$this, '_splitValue');
  907.             $table->addFilter(1, $filter1);
  908.  
  909.             $opts = $this->options;
  910.             if (is_array($opts)) {
  911.                 foreach ($opts as $key => $raw) {
  912.                     if ($key == 'debug' || $key == 'recurse_dir') {
  913.                         $raw = ($raw === true) ? 'TRUE' : 'FALSE';
  914.                     }
  915.                     if (substr($key, -6) == '_match') {
  916.                         $val = array_values($raw[1]);
  917.                         array_unshift($val, $raw[0]);
  918.                         $raw = implode("\r\n", $val);
  919.                     } else {
  920.                         if (is_array($raw)) {
  921.                             $raw = implode("\r\n", $raw);
  922.                         }
  923.                     }
  924.                     $contents = array($key, $raw);
  925.                     $table->addRow($contents);
  926.                 }
  927.             }
  928.  
  929.             $output .= $table->getTable();
  930.         }
  931.  
  932.         // extra information
  933.         if ($v & 4) {
  934.             $output .= "\nDebug:\n\n";
  935.  
  936.             $table = new Console_Table();
  937.             $table->setHeaders(array('Version', 'Function', 'Extension', 'PECL'));
  938.  
  939.             unset($info['max_version']);
  940.             unset($info['version']);
  941.             unset($info['extensions']);
  942.             unset($info['constants']);
  943.             unset($info['tokens']);
  944.             unset($info['cond_code']);
  945.             unset($info['ignored_functions']);
  946.             unset($info['ignored_extensions']);
  947.             unset($info['ignored_constants']);
  948.  
  949.             foreach ($info as $version => $functions) {
  950.                 foreach ($functions as $func) {
  951.                     $table->addRow(array($version,
  952.                         $func['function'], $func['extension'],
  953.                         (isset($func['pecl']) ?
  954.                         (($func['pecl'] === true) ? 'yes' : 'no') : '')));
  955.                 }
  956.             }
  957.  
  958.             $output .= $table->getTable();
  959.         }
  960.  
  961.         echo $output;
  962.     }
  963.  
  964.     /**
  965.      * Parse String Input
  966.      *
  967.      * @return void
  968.      * @access private
  969.      * @since  1.6.0
  970.      */
  971.     function _parseString()
  972.     {
  973.         $info = $this->parseString($this->string, $this->options);
  974.         if ($info === false) {
  975.             $err = 'Failed opening string "' . $this->string
  976.                . '". Please check your spelling and try again.';
  977.             $this->_printUsage($err);
  978.             return;
  979.         }
  980.         $table = new Console_Table();
  981.         $table->setHeaders(array('Version', 'Extensions', 'Constants/Tokens'));
  982.  
  983.         $ext   = implode("\r\n", $info['extensions']);
  984.         $const = implode("\r\n", $info['constants']);
  985.         $data  = array();
  986.         if (empty($info['max_version'])) {
  987.             $data[] = $info['version'];
  988.         } else {
  989.             $data[] = implode("\r\n", array($info['version'], $info['max_version']));
  990.         }
  991.         $data[] = $ext;
  992.         $data[] = $const;
  993.  
  994.         $table->addRow($data);
  995.  
  996.         $output = $table->getTable();
  997.  
  998.         // verbose level
  999.         $v = $this->args->getValue('v');
  1000.  
  1001.         // command line resume
  1002.         if ($v & 1) {
  1003.             $output .= "\nCommand Line resume :\n\n";
  1004.  
  1005.             $table = new Console_Table();
  1006.             $table->setHeaders(array('Option', 'Value'));
  1007.  
  1008.             $filter0 = array(&$this, '_splitOption');
  1009.             $table->addFilter(0, $filter0);
  1010.             $filter1 = array(&$this, '_splitValue');
  1011.             $table->addFilter(1, $filter1);
  1012.  
  1013.             $opts = $this->args->getValues();
  1014.             if (is_array($opts)) {
  1015.                 foreach ($opts as $key => $raw) {
  1016.                     if (is_array($raw)) {
  1017.                         $raw = implode(', ', $raw);
  1018.                     }
  1019.                     $contents = array($key, $raw);
  1020.                     $table->addRow($contents);
  1021.                 }
  1022.             }
  1023.  
  1024.             $output .= $table->getTable();
  1025.         }
  1026.  
  1027.         // parser options resume
  1028.         if ($v & 2) {
  1029.             $output .= "\nParser options :\n\n";
  1030.  
  1031.             $table = new Console_Table();
  1032.             $table->setHeaders(array('Option', 'Value'));
  1033.  
  1034.             $filter0 = array(&$this, '_splitOption');
  1035.             $table->addFilter(0, $filter0);
  1036.             $filter1 = array(&$this, '_splitValue');
  1037.             $table->addFilter(1, $filter1);
  1038.  
  1039.             $opts = $this->options;
  1040.             if (is_array($opts)) {
  1041.                 foreach ($opts as $key => $raw) {
  1042.                     if ($key == 'debug') {
  1043.                         $raw = ($raw === true) ? 'TRUE' : 'FALSE';
  1044.                     }
  1045.                     if (substr($key, -6) == '_match') {
  1046.                         $val = array_values($raw[1]);
  1047.                         array_unshift($val, $raw[0]);
  1048.                         $raw = implode("\r\n", $val);
  1049.                     } else {
  1050.                         if (is_array($raw)) {
  1051.                             $raw = implode("\r\n", $raw);
  1052.                         }
  1053.                     }
  1054.                     $contents = array($key, $raw);
  1055.                     $table->addRow($contents);
  1056.                 }
  1057.             }
  1058.  
  1059.             $output .= $table->getTable();
  1060.         }
  1061.  
  1062.         // extra information
  1063.         if ($v & 4) {
  1064.             $output .= "\nDebug:\n\n";
  1065.  
  1066.             $table = new Console_Table();
  1067.             $table->setHeaders(array('Version', 'Function', 'Extension', 'PECL'));
  1068.  
  1069.             unset($info['max_version']);
  1070.             unset($info['version']);
  1071.             unset($info['extensions']);
  1072.             unset($info['constants']);
  1073.             unset($info['tokens']);
  1074.             unset($info['cond_code']);
  1075.             unset($info['ignored_functions']);
  1076.             unset($info['ignored_extensions']);
  1077.             unset($info['ignored_constants']);
  1078.  
  1079.             foreach ($info as $version => $functions) {
  1080.                 foreach ($functions as $func) {
  1081.                     $table->addRow(array($version,
  1082.                         $func['function'], $func['extension'],
  1083.                         (isset($func['pecl']) ?
  1084.                         (($func['pecl'] === true) ? 'yes' : 'no') : '')));
  1085.                 }
  1086.             }
  1087.  
  1088.             $output .= $table->getTable();
  1089.         }
  1090.  
  1091.         echo $output;
  1092.     }
  1093.  
  1094.     /**
  1095.      * The Console_Table filter callback limits table output to 80 columns,
  1096.      * and Path column to 29 characters
  1097.      * (27 + 1 blank margin left + 1 blank margin right).
  1098.      *
  1099.      * @param string $data Content of filename column (0)
  1100.      *
  1101.      * @return string
  1102.      * @access private
  1103.      * @since  1.3.0
  1104.      */
  1105.     function _splitFilename($data)
  1106.     {
  1107.         if (strlen($data) <= 27) {
  1108.             $str = str_pad($data, 27);
  1109.         } else {
  1110.             $str = '...' . substr($data, (strlen($data) - 24));
  1111.         }
  1112.         return $str;
  1113.     }
  1114.  
  1115.     /**
  1116.      * The Console_Table filter callback limits table output to 80 columns,
  1117.      * and Extensions column to 12 characters
  1118.      * (10 + 1 blank margin left + 1 blank margin right).
  1119.      *
  1120.      * @param string $data Content of extensions column
  1121.      *
  1122.      * @return string
  1123.      * @access private
  1124.      * @since  1.7.0
  1125.      */
  1126.     function _splitExtname($data)
  1127.     {
  1128.         $szlim = ($this->_output_level & 12) ? 10 : 35;
  1129.         if ($this->_output_level & 1) {
  1130.             $szlim = $szlim - 4;
  1131.         }
  1132.         $extArr = explode("\r\n", $data);
  1133.         $str    = '';
  1134.         foreach ($extArr as $ext) {
  1135.             if (strlen($ext) <= $szlim) {
  1136.                 $str .= str_pad($ext, $szlim);
  1137.             } else {
  1138.                 $str .= '...' . substr($ext, (strlen($ext) - ($szlim - 3)));
  1139.             }
  1140.             $str .= "\r\n";
  1141.         }
  1142.         $str = rtrim($str, "\r\n");
  1143.         return $str;
  1144.     }
  1145.  
  1146.     /**
  1147.      * The Console_Table filter callback limits table output to 80 columns,
  1148.      * and Constants/Tokens column to 20 characters
  1149.      * (18 + 1 blank margin left + 1 blank margin right)
  1150.      *
  1151.      * @param string $data Content of constants/tokens column
  1152.      *
  1153.      * @return string
  1154.      * @access private
  1155.      * @since  1.7.0
  1156.      */
  1157.     function _splitConstant($data)
  1158.     {
  1159.         $szlim = ($this->_output_level & 2) ? 22 : 35;
  1160.         if ($this->_output_level & 1) {
  1161.             $szlim = $szlim - 4;
  1162.         }
  1163.         $cstArr = explode("\r\n", $data);
  1164.         $str    = '';
  1165.         foreach ($cstArr as $cst) {
  1166.             if (strlen($cst) <= $szlim) {
  1167.                 $str .= str_pad($cst, $szlim);
  1168.             } else {
  1169.                 $str .= '...' . substr($cst, (strlen($cst) - ($szlim - 3)));
  1170.             }
  1171.             $str .= "\r\n";
  1172.         }
  1173.         $str = rtrim($str, "\r\n");
  1174.         return $str;
  1175.     }
  1176.  
  1177.     /**
  1178.      * The Console_Table filter callback limits table output to 80 columns,
  1179.      * and Command line Option column to 25 characters
  1180.      * (23 + 1 blank margin left + 1 blank margin right).
  1181.      *
  1182.      * @param string $data Content of option column (0)
  1183.      *
  1184.      * @return string
  1185.      * @access private
  1186.      * @since  1.7.0
  1187.      */
  1188.     function _splitOption($data)
  1189.     {
  1190.         if (strlen($data) <= 23) {
  1191.             $str = str_pad($data, 23);
  1192.         } else {
  1193.             $str = '...' . substr($data, (strlen($data) - 20));
  1194.         }
  1195.         return $str;
  1196.     }
  1197.  
  1198.     /**
  1199.      * The Console_Table filter callback limits table output to 80 columns,
  1200.      * and Command line Value column to 51 characters
  1201.      * (49 + 1 blank margin left + 1 blank margin right)
  1202.      *
  1203.      * @param string $data Content of value column (1)
  1204.      *
  1205.      * @return string
  1206.      * @access private
  1207.      * @since  1.7.0
  1208.      */
  1209.     function _splitValue($data)
  1210.     {
  1211.         $cstArr = explode("\r\n", $data);
  1212.         $str    = '';
  1213.         foreach ($cstArr as $cst) {
  1214.             if (strlen($cst) <= 49) {
  1215.                 $str .= str_pad($cst, 49);
  1216.             } else {
  1217.                 $str .= '...' . substr($cst, (strlen($cst) - 46));
  1218.             }
  1219.             $str .= "\r\n";
  1220.         }
  1221.         $str = rtrim($str, "\r\n");
  1222.         return $str;
  1223.     }
  1224.  
  1225.     /**
  1226.      * Show full help information
  1227.      *
  1228.      * @param string $footer (optional) page footer content
  1229.      *
  1230.      * @return void
  1231.      * @access private
  1232.      * @since  0.8.0
  1233.      */
  1234.     function _printUsage($footer = '')
  1235.     {
  1236.         $header = 'Usage: '
  1237.             . basename($_SERVER['SCRIPT_NAME']) . " [options]\n\n";
  1238.         echo Console_Getargs::getHelp($this->opts, $header,
  1239.             "\n$footer\n", 78, 2)."\n";
  1240.     }
  1241.  
  1242.     /**
  1243.      * Print XML report
  1244.      *
  1245.      * @param array $info File or directory parsing data
  1246.      *
  1247.      * @return void
  1248.      * @access private
  1249.      * @since  1.6.0
  1250.      */
  1251.     function _printXMLReport($info)
  1252.     {
  1253.         include_once 'XML/Util.php';
  1254.  
  1255.         ob_start();
  1256.  
  1257.         echo XML_Util::getXMLDeclaration("1.0", "UTF-8");
  1258.         echo PHP_EOL;
  1259.         echo XML_Util::createStartElement('pci',
  1260.                                           array('version' => '1.7.0'));
  1261.         echo PHP_EOL;
  1262.         $o = $this->_output_level;
  1263.  
  1264.         if (isset($this->dir)) {
  1265.             // parsing a directory
  1266.  
  1267.             // print <dir> tag
  1268.             $tag = array('qname' => 'dir',
  1269.                          'content' => $this->dir);
  1270.             echo XML_Util::createTagFromArray($tag);
  1271.             echo PHP_EOL;
  1272.  
  1273.             // print global <version> tag
  1274.             if (empty($info['max_version'])) {
  1275.                 $attr = array();
  1276.             } else {
  1277.                 $attr = array('max' => $info['max_version']);
  1278.             }
  1279.             $tag = array('qname' => 'version',
  1280.                          'attributes' => $attr,
  1281.                          'content' => $info['version']);
  1282.             echo XML_Util::createTagFromArray($tag);
  1283.             echo PHP_EOL;
  1284.  
  1285.             // print global <conditions> tag group
  1286.             if ($o & 1) {
  1287.                 $this->_printTagList($info['cond_code'], 'condition');
  1288.             }
  1289.             // print global <extensions> tag group
  1290.             if ($o & 2) {
  1291.                 $this->_printTagList($info['extensions'], 'extension');
  1292.             }
  1293.             // print global <constants> tag group
  1294.             if ($o & 4) {
  1295.                 $this->_printTagList($info['constants'], 'constant');
  1296.             }
  1297.             // print global <tokens> tag group
  1298.             if ($o & 8) {
  1299.                 $this->_printTagList($info['tokens'], 'token');
  1300.             }
  1301.  
  1302.             // print global <ignored> tag group
  1303.             echo XML_Util::createStartElement('ignored');
  1304.             echo PHP_EOL;
  1305.             // with children groups <files>, <functions>, <extensions>, <constants>
  1306.             $ignored = array('file' => $info['ignored_files'],
  1307.                              'function' => $info['ignored_functions'],
  1308.                              'extension' => $info['ignored_extensions'],
  1309.                              'constant' => $info['ignored_constants']);
  1310.             foreach ($ignored as $tag => $data) {
  1311.                 $this->_printTagList($data, $tag);
  1312.             }
  1313.             echo XML_Util::createEndElement('ignored');
  1314.             echo PHP_EOL;
  1315.  
  1316.             // remove summary data
  1317.             unset($info['ignored_files']);
  1318.             unset($info['ignored_functions']);
  1319.             unset($info['ignored_extensions']);
  1320.             unset($info['ignored_constants']);
  1321.             unset($info['max_version']);
  1322.             unset($info['version']);
  1323.             unset($info['extensions']);
  1324.             unset($info['constants']);
  1325.             unset($info['tokens']);
  1326.             unset($info['cond_code']);
  1327.  
  1328.             $files = $info;
  1329.         } else {
  1330.             // parsing a single file
  1331.             $files = array($this->file => $info);
  1332.         }
  1333.  
  1334.         // print <files> tag group
  1335.         echo XML_Util::createStartElement('files', array('count' => count($files)));
  1336.         echo PHP_EOL;
  1337.  
  1338.         foreach ($files as $file => $info) {
  1339.             // print local <file> tag
  1340.             echo XML_Util::createStartElement('file', array('name' => $file));
  1341.             echo PHP_EOL;
  1342.  
  1343.             // print local <version> tag
  1344.             if (empty($info['max_version'])) {
  1345.                 $attr = array();
  1346.             } else {
  1347.                 $attr = array('max' => $info['max_version']);
  1348.             }
  1349.             $tag = array('qname' => 'version',
  1350.                          'attributes' => $attr,
  1351.                          'content' => $info['version']);
  1352.             echo XML_Util::createTagFromArray($tag);
  1353.             echo PHP_EOL;
  1354.  
  1355.             // print local <conditions> tag group
  1356.             if ($o & 1) {
  1357.                 $this->_printTagList($info['cond_code'], 'condition');
  1358.             }
  1359.             // print local <extensions> tag group
  1360.             if ($o & 2) {
  1361.                 $this->_printTagList($info['extensions'], 'extension');
  1362.             }
  1363.             // print local <constants> tag group
  1364.             if ($o & 4) {
  1365.                 $this->_printTagList($info['constants'], 'constant');
  1366.             }
  1367.             // print local <tokens> tag group
  1368.             if ($o & 8) {
  1369.                 $this->_printTagList($info['tokens'], 'token');
  1370.             }
  1371.  
  1372.             // print local <ignored> tag group
  1373.             echo XML_Util::createStartElement('ignored');
  1374.             echo PHP_EOL;
  1375.             // with children groups <functions>, <extensions>, <constants>
  1376.             $ignored = array('function' => $info['ignored_functions'],
  1377.                              'extension' => $info['ignored_extensions'],
  1378.                              'constant' => $info['ignored_constants']);
  1379.             foreach ($ignored as $tag => $data) {
  1380.                 $this->_printTagList($data, $tag);
  1381.             }
  1382.             echo XML_Util::createEndElement('ignored');
  1383.             echo PHP_EOL;
  1384.  
  1385.             // verbose level
  1386.             $v = $this->args->getValue('v');
  1387.  
  1388.             // extra information only if verbose mode >= 4
  1389.             if ($v & 4) {
  1390.                 unset($info['ignored_files']);
  1391.                 unset($info['ignored_functions']);
  1392.                 unset($info['ignored_extensions']);
  1393.                 unset($info['ignored_constants']);
  1394.                 unset($info['max_version']);
  1395.                 unset($info['version']);
  1396.                 unset($info['constants']);
  1397.                 unset($info['tokens']);
  1398.                 unset($info['extensions']);
  1399.                 unset($info['cond_code']);
  1400.  
  1401.                 // print local <functions> tag group
  1402.                 $this->_printTagList($info, 'function');
  1403.             }
  1404.  
  1405.             echo XML_Util::createEndElement('file');
  1406.             echo PHP_EOL;
  1407.         }
  1408.         echo XML_Util::createEndElement('files');
  1409.         echo PHP_EOL;
  1410.         echo XML_Util::createEndElement('pci');
  1411.         echo PHP_EOL;
  1412.  
  1413.         $result = ob_get_clean();
  1414.  
  1415.         // try to see if we can improve XML render
  1416.         $beautifier = 'XML/Beautifier.php';
  1417.         if (PHP_CompatInfo_Cli::isIncludable($beautifier)) {
  1418.             include_once $beautifier;
  1419.             $options = array('indent' => ' ');
  1420.             $fmt     = new XML_Beautifier($options);
  1421.             $result  = $fmt->formatString($result);
  1422.         }
  1423.         echo $result;
  1424.     }
  1425.  
  1426.     /**
  1427.      * Print a group of same tag in the XML report.
  1428.      *
  1429.      * Groups list are : extension(s), constant(s), token(s)
  1430.      *
  1431.      * @param array  $dataSrc Data source
  1432.      * @param string $tagName Name of the XML tag
  1433.      *
  1434.      * @return void
  1435.      * @access private
  1436.      * @since  version 1.7.0b4 (2008-04-03)
  1437.      */
  1438.     function _printTagList($dataSrc, $tagName)
  1439.     {
  1440.         if ($tagName == 'function') {
  1441.             $c = 0;
  1442.             foreach ($dataSrc as $version => $functions) {
  1443.                 $c += count($functions);
  1444.             }
  1445.             $attributes = array('count' => $c);
  1446.         } elseif ($tagName == 'condition') {
  1447.             if ($this->options['debug'] === true) {
  1448.                 $c = 0;
  1449.                 foreach ($dataSrc[1] as $cond => $elements) {
  1450.                     $c += count($elements);
  1451.                 }
  1452.                 $attributes = array('count' => $c, 'level' => $dataSrc[0]);
  1453.             } else {
  1454.                 $attributes = array('level' => $dataSrc[0]);
  1455.             }
  1456.         } else {
  1457.             $attributes = array('count' => count($dataSrc));
  1458.         }
  1459.  
  1460.         echo XML_Util::createStartElement($tagName.'s', $attributes);
  1461.         echo PHP_EOL;
  1462.  
  1463.         if ($tagName == 'function') {
  1464.             foreach ($dataSrc as $version => $functions) {
  1465.                 foreach ($functions as $data) {
  1466.                     $attr = array('version' => $version);
  1467.                     if (!empty($data['extension'])) {
  1468.                         $attr['extension'] = $data['extension'];
  1469.                         $attr['pecl']      = $data['pecl'] === true ?
  1470.                                                 'true' : 'false';
  1471.                     }
  1472.                     $tag = array('qname' => $tagName,
  1473.                                  'attributes' => $attr,
  1474.                                  'content' => $data['function']);
  1475.                     echo XML_Util::createTagFromArray($tag);
  1476.                     echo PHP_EOL;
  1477.                 }
  1478.             }
  1479.         } elseif ($tagName == 'condition') {
  1480.             if ($this->options['debug'] == true) {
  1481.                 foreach ($dataSrc[1] as $cond => $elements) {
  1482.                     $cond = ($cond == 0) ? 1 : ($cond * 2);
  1483.                     foreach ($elements as $data) {
  1484.                         $tag = array('qname' => $tagName,
  1485.                                      'attributes' => array('level' => $cond),
  1486.                                      'content' => $data);
  1487.                         echo XML_Util::createTagFromArray($tag);
  1488.                         echo PHP_EOL;
  1489.                     }
  1490.                 }
  1491.             }
  1492.         } else {
  1493.             foreach ($dataSrc as $data) {
  1494.                 $tag = array('qname' => $tagName,
  1495.                              'attributes' => array(),
  1496.                              'content' => $data);
  1497.                 echo XML_Util::createTagFromArray($tag);
  1498.                 echo PHP_EOL;
  1499.             }
  1500.         }
  1501.  
  1502.         echo XML_Util::createEndElement($tagName.'s');
  1503.         echo PHP_EOL;
  1504.     }
  1505.  
  1506.     /**
  1507.      * Returns whether or not a file is in the include path.
  1508.      *
  1509.      * @param string $file Path to filename to check if includable
  1510.      *
  1511.      * @static
  1512.      * @access public
  1513.      * @return boolean TRUE if the file is in the include path, FALSE otherwise
  1514.      * @since  version 1.7.0b4 (2008-04-03)
  1515.      */
  1516.     function isIncludable($file)
  1517.     {
  1518.         foreach (explode(PATH_SEPARATOR, get_include_path()) as $ip) {
  1519.             if (file_exists($ip . DIRECTORY_SEPARATOR . $file)
  1520.                 && is_readable($ip . DIRECTORY_SEPARATOR . $file)
  1521.                 ) {
  1522.                 return true;
  1523.             }
  1524.         }
  1525.         return false;
  1526.     }
  1527. }
  1528. ?>