Console_CommandLine
[ class tree: Console_CommandLine ] [ index: Console_CommandLine ] [ all elements ]

Source for file CommandLine.php

Documentation is available at CommandLine.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * This file is part of the PEAR Console_CommandLine package.
  7.  *
  8.  * A full featured package for managing command-line options and arguments
  9.  * hightly inspired from python optparse module, it allows the developper to
  10.  * easily build complex command line interfaces.
  11.  *
  12.  * PHP version 5
  13.  *
  14.  * LICENSE: This source file is subject to the MIT license that is available
  15.  * through the world-wide-web at the following URI:
  16.  * http://opensource.org/licenses/mit-license.php
  17.  *
  18.  * @category  Console
  19.  * @package   Console_CommandLine
  20.  * @author    David JEAN LOUIS <izimobil@gmail.com>
  21.  * @copyright 2007 David JEAN LOUIS
  22.  * @license   http://opensource.org/licenses/mit-license.php MIT License
  23.  * @version   CVS: $Id: CommandLine.php,v 1.21 2008/12/06 11:45:13 izi Exp $
  24.  * @link      http://pear.php.net/package/Console_CommandLine
  25.  * @since     Class available since release 0.1.0
  26.  * @filesource
  27.  */
  28.  
  29. /**
  30.  * Required unconditionally
  31.  */
  32. require_once 'Console/CommandLine/Exception.php';
  33. require_once 'Console/CommandLine/Outputter/Default.php';
  34. require_once 'Console/CommandLine/Renderer/Default.php';
  35. require_once 'Console/CommandLine/MessageProvider/Default.php';
  36.  
  37. /**
  38.  * Main class for parsing command line options and arguments.
  39.  * 
  40.  * There are three ways to create parsers with this class:
  41.  * <code>
  42.  * // direct usage
  43.  * $parser = new Console_CommandLine();
  44.  *
  45.  * // with an xml definition file
  46.  * $parser = Console_CommandLine::fromXmlFile('path/to/file.xml');
  47.  *
  48.  * // with an xml definition string
  49.  * $validXmlString = '..your xml string...';
  50.  * $parser = Console_CommandLine::fromXmlString($validXmlString);
  51.  * </code>
  52.  *
  53.  * @category  Console
  54.  * @package   Console_CommandLine
  55.  * @author    David JEAN LOUIS <izimobil@gmail.com>
  56.  * @copyright 2007 David JEAN LOUIS
  57.  * @license   http://opensource.org/licenses/mit-license.php MIT License
  58.  * @version   Release: 1.0.5
  59.  * @link      http://pear.php.net/package/Console_CommandLine
  60.  * @since     File available since release 0.1.0
  61.  * @example   docs/examples/ex1.php
  62.  * @example   docs/examples/ex2.php
  63.  */
  64. {
  65.     // Public properties {{{
  66.  
  67.     /**
  68.      * Error messages.
  69.      *
  70.      * @var array $errors Error messages
  71.      * @todo move this to Console_CommandLine_MessageProvider
  72.      */
  73.     public static $errors = array(
  74.         'option_bad_name'                    => 'option name must be a valid php variable name (got: {$name})',
  75.         'argument_bad_name'                  => 'argument name must be a valid php variable name (got: {$name})',
  76.         'option_long_and_short_name_missing' => 'you must provide at least an option short name or long name for option "{$name}"',
  77.         'option_bad_short_name'              => 'option "{$name}" short name must be a dash followed by a letter (got: "{$short_name}")',
  78.         'option_bad_long_name'               => 'option "{$name}" long name must be 2 dashes followed by a word (got: "{$long_name}")',
  79.         'option_unregistered_action'         => 'unregistered action "{$action}" for option "{$name}".',
  80.         'option_bad_action'                  => 'invalid action for option "{$name}".',
  81.         'option_invalid_callback'            => 'you must provide a valid callback for option "{$name}"',
  82.         'action_class_does_not_exists'       => 'action "{$name}" class "{$class}" not found, make sure that your class is available before calling Console_CommandLine::registerAction()',
  83.         'invalid_xml_file'                   => 'XML definition file "{$file}" does not exists or is not readable',
  84.         'invalid_rng_file'                   => 'RNG file "{$file}" does not exists or is not readable'
  85.     );
  86.  
  87.     /**
  88.      * The name of the program, if not given it defaults to argv[0].
  89.      *
  90.      * @var string $name Name of your program
  91.      */
  92.     public $name;
  93.  
  94.     /**
  95.      * A description text that will be displayed in the help message.
  96.      *
  97.      * @var string $description Description of your program
  98.      */
  99.     public $description = '';
  100.  
  101.     /**
  102.      * A string that represents the version of the program, if this property is
  103.      * not empty and property add_version_option is not set to false, the
  104.      * command line parser will add a --version option, that will display the
  105.      * property content.
  106.      *
  107.      * @var    string $version 
  108.      * @access public
  109.      */
  110.     public $version = '';
  111.  
  112.     /**
  113.      * Boolean that determine if the command line parser should add the help
  114.      * (-h, --help) option automatically.
  115.      *
  116.      * @var bool $add_help_option Whether to add a help option or not
  117.      */
  118.     public $add_help_option = true;
  119.  
  120.     /**
  121.      * Boolean that determine if the command line parser should add the version
  122.      * (-v, --version) option automatically.
  123.      * Note that the version option is also generated only if the version
  124.      * property is not empty, it's up to you to provide a version string of
  125.      * course.
  126.      *
  127.      * @var bool $add_version_option Whether to add a version option or not
  128.      */
  129.     public $add_version_option = true;
  130.  
  131.     /**
  132.      * The command line parser renderer instance.
  133.      *
  134.      * @var    object that implements Console_CommandLine_Renderer interface
  135.      * @access protected
  136.      */
  137.     public $renderer = false;
  138.  
  139.     /**
  140.      * The command line parser outputter instance.
  141.      *
  142.      * @var Console_CommandLine_Outputter An outputter
  143.      */
  144.     public $outputter = false;
  145.  
  146.     /**
  147.      * The command line message provider instance.
  148.      *
  149.      * @var Console_CommandLine_MessageProvider A message provider instance
  150.      */
  151.     public $message_provider = false;
  152.  
  153.     /**
  154.      * Boolean that tells the parser to be POSIX compliant, POSIX demands the
  155.      * following behavior: the first non-option stops option processing.
  156.      *
  157.      * @var bool $force_posix Whether to force posix compliance or not
  158.      */
  159.     public $force_posix = false;
  160.  
  161.     /**
  162.      * An array of Console_CommandLine_Option objects.
  163.      *
  164.      * @var array $options The options array
  165.      */
  166.     public $options = array();
  167.  
  168.     /**
  169.      * An array of Console_CommandLine_Argument objects.
  170.      *
  171.      * @var array $args The arguments array
  172.      */
  173.     public $args = array();
  174.  
  175.     /**
  176.      * An array of Console_CommandLine_Command objects (sub commands).
  177.      *
  178.      * @var array $commands The commands array
  179.      */
  180.     public $commands = array();
  181.  
  182.     /**
  183.      * Parent, only relevant in Command objects but left here for interface
  184.      * convenience.
  185.      *
  186.      * @var Console_CommandLine The parent instance
  187.      * @todo move Console_CommandLine::parent to Console_CommandLine_Command
  188.      */
  189.     public $parent = false;
  190.  
  191.     /**
  192.      * Array of valid actions for an option, this array will also store user
  193.      * registered actions.
  194.      *
  195.      * The array format is:
  196.      * <pre>
  197.      * array(
  198.      *     <ActionName:string> => array(<ActionClass:string>, <builtin:bool>)
  199.      * )
  200.      * </pre>
  201.      *
  202.      * @var array $actions List of valid actions
  203.      */
  204.     public static $actions = array(
  205.         'StoreTrue'   => array('Console_CommandLine_Action_StoreTrue'true),
  206.         'StoreFalse'  => array('Console_CommandLine_Action_StoreFalse'true),
  207.         'StoreString' => array('Console_CommandLine_Action_StoreString'true),
  208.         'StoreInt'    => array('Console_CommandLine_Action_StoreInt'true),
  209.         'StoreFloat'  => array('Console_CommandLine_Action_StoreFloat'true),
  210.         'StoreArray'  => array('Console_CommandLine_Action_StoreArray'true),
  211.         'Callback'    => array('Console_CommandLine_Action_Callback'true),
  212.         'Counter'     => array('Console_CommandLine_Action_Counter'true),
  213.         'Help'        => array('Console_CommandLine_Action_Help'true),
  214.         'Version'     => array('Console_CommandLine_Action_Version'true),
  215.         'Password'    => array('Console_CommandLine_Action_Password'true),
  216.         'List'        => array('Console_CommandLine_Action_List'true),
  217.     );
  218.  
  219.     /**
  220.      * Array of options that must be dispatched at the end.
  221.      *
  222.      * @var array $_dispatchLater Options to be dispatched
  223.      */
  224.     private $_dispatchLater = array();
  225.  
  226.     // }}}
  227.     // __construct() {{{
  228.  
  229.     /**
  230.      * Constructor.
  231.      * Example:
  232.      *
  233.      * <code>
  234.      * $parser = new Console_CommandLine(array(
  235.      *     'name'               => 'yourprogram', // defaults to argv[0]
  236.      *     'description'        => 'Description of your program',
  237.      *     'version'            => '0.0.1', // your program version
  238.      *     'add_help_option'    => true, // or false to disable --version option
  239.      *     'add_version_option' => true, // or false to disable --help option
  240.      *     'force_posix'        => false // or true to force posix compliance
  241.      * ));
  242.      * </code>
  243.      *
  244.      * @param array $params An optional array of parameters
  245.      *
  246.      * @return void 
  247.      */
  248.     public function __construct(array $params = array()) 
  249.     {
  250.         if (isset($params['name'])) {
  251.             $this->name = $params['name'];
  252.         else if (isset($argv&& count($argv> 0{
  253.             $this->name = $argv[0];
  254.         else if (isset($_SERVER['argv']&& count($_SERVER['argv']> 0{
  255.             $this->name = $_SERVER['argv'][0];
  256.         else if (isset($_SERVER['SCRIPT_NAME'])) {
  257.             $this->name = basename($_SERVER['SCRIPT_NAME']);
  258.         }
  259.         if (isset($params['description'])) {
  260.             $this->description = $params['description'];
  261.         }
  262.         if (isset($params['version'])) {
  263.             $this->version = $params['version'];
  264.         }
  265.         if (isset($params['add_version_option'])) {
  266.             $this->add_version_option = $params['add_version_option'];
  267.         }
  268.         if (isset($params['add_help_option'])) {
  269.             $this->add_help_option = $params['add_help_option'];
  270.         }
  271.         if (isset($params['force_posix'])) {
  272.             $this->force_posix = $params['force_posix'];
  273.         else if (getenv('POSIXLY_CORRECT')) {
  274.             $this->force_posix = true;
  275.         }
  276.         // set default instances
  277.         $this->renderer         = new Console_CommandLine_Renderer_Default($this);
  278.         $this->outputter        = new Console_CommandLine_Outputter_Default();
  279.     }
  280.  
  281.     // }}}
  282.     // accept() {{{
  283.  
  284.     /**
  285.      * Method to allow Console_CommandLine to accept either:
  286.      *  + a custom renderer,
  287.      *  + a custom outputter,
  288.      *  + or a custom message provider
  289.      *
  290.      * @param mixed $instance The custom instance
  291.      *
  292.      * @return void 
  293.      * @throws Console_CommandLine_Exception if wrong argument passed
  294.      */
  295.     public function accept($instance
  296.     {
  297.         if ($instance instanceof Console_CommandLine_Renderer{
  298.             if (property_exists($instance'parser'&& !$instance->parser{
  299.                 $instance->parser = $this;
  300.             }
  301.             $this->renderer = $instance;
  302.         else if ($instance instanceof Console_CommandLine_Outputter{
  303.             $this->outputter = $instance;
  304.         else if ($instance instanceof Console_CommandLine_MessageProvider{
  305.             $this->message_provider = $instance;
  306.         else {
  307.             throw Console_CommandLine_Exception::factory(
  308.                 'INVALID_CUSTOM_INSTANCE',
  309.                 array()$this
  310.             );
  311.         }
  312.     }
  313.  
  314.     // }}}
  315.     // fromXmlFile() {{{
  316.  
  317.     /**
  318.      * Returns a command line parser instance built from an xml file.
  319.      *
  320.      * Example:
  321.      * <code>
  322.      * require_once 'Console/CommandLine.php';
  323.      * $parser = Console_CommandLine::fromXmlFile('path/to/file.xml');
  324.      * $result = $parser->parse();
  325.      * </code>
  326.      *
  327.      * @param string $file Path to the xml file
  328.      *
  329.      * @return Console_CommandLine The parser instance
  330.      */
  331.     public static function fromXmlFile($file
  332.     {
  333.         include_once 'Console/CommandLine/XmlParser.php';
  334.         return Console_CommandLine_XmlParser::parse($file);
  335.     }
  336.  
  337.     // }}}
  338.     // fromXmlString() {{{
  339.  
  340.     /**
  341.      * Returns a command line parser instance built from an xml string.
  342.      *
  343.      * Example:
  344.      * <code>
  345.      * require_once 'Console/CommandLine.php';
  346.      * $xmldata = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
  347.      * <command>
  348.      *   <description>Compress files</description>
  349.      *   <option name="quiet">
  350.      *     <short_name>-q</short_name>
  351.      *     <long_name>--quiet</long_name>
  352.      *     <description>be quiet when run</description>
  353.      *     <action>StoreTrue/action>
  354.      *   </option>
  355.      *   <argument name="files">
  356.      *     <description>a list of files</description>
  357.      *     <multiple>true</multiple>
  358.      *   </argument>
  359.      * </command>';
  360.      * $parser = Console_CommandLine::fromXmlString($xmldata);
  361.      * $result = $parser->parse();
  362.      * </code>
  363.      *
  364.      * @param string $string The xml data
  365.      *
  366.      * @return Console_CommandLine The parser instance
  367.      */
  368.     public static function fromXmlString($string
  369.     {
  370.         include_once 'Console/CommandLine/XmlParser.php';
  371.         return Console_CommandLine_XmlParser::parseString($string);
  372.     }
  373.  
  374.     // }}}
  375.     // addArgument() {{{
  376.  
  377.     /**
  378.      * Adds an argument to the command line parser and returns it.
  379.      *
  380.      * Adds an argument with the name $name and set its attributes with the
  381.      * array $params, then return the Console_CommandLine_Argument instance
  382.      * created.
  383.      * The method accepts another form: you can directly pass a
  384.      * Console_CommandLine_Argument object as the sole argument, this allows
  385.      * you to contruct the argument separately, in order to reuse it in
  386.      * different command line parsers or commands for example.
  387.      *
  388.      * Example:
  389.      * <code>
  390.      * $parser = new Console_CommandLine();
  391.      * // add an array argument
  392.      * $parser->addArgument('input_files', array('multiple'=>true));
  393.      * // add a simple argument
  394.      * $parser->addArgument('output_file');
  395.      * $result = $parser->parse();
  396.      * print_r($result->args['input_files']);
  397.      * print_r($result->args['output_file']);
  398.      * // will print:
  399.      * // array('file1', 'file2')
  400.      * // 'file3'
  401.      * // if the command line was:
  402.      * // myscript.php file1 file2 file3
  403.      * </code>
  404.      *
  405.      * In a terminal, the help will be displayed like this:
  406.      * <code>
  407.      * $ myscript.php install -h
  408.      * Usage: myscript.php <input_files...> <output_file>
  409.      * </code>
  410.      *
  411.      * @param mixed $name   A string containing the argument name or an
  412.      *                       instance of Console_CommandLine_Argument
  413.      * @param array $params An array containing the argument attributes
  414.      *
  415.      * @return Console_CommandLine_Argument the added argument
  416.      * @see Console_CommandLine_Argument
  417.      */
  418.     public function addArgument($name$params = array())
  419.     {
  420.         if ($name instanceof Console_CommandLine_Argument{
  421.             $argument $name;
  422.         else {
  423.             include_once 'Console/CommandLine/Argument.php';
  424.             $argument = new Console_CommandLine_Argument($name$params);
  425.         }
  426.         $argument->validate();
  427.         $this->args[$argument->name$argument;
  428.         return $argument;
  429.     }
  430.  
  431.     // }}}
  432.     // addCommand() {{{
  433.  
  434.     /**
  435.      * Adds a sub-command to the command line parser.
  436.      *
  437.      * Adds a command with the given $name to the parser and returns the
  438.      * Console_CommandLine_Command instance, you can then populate the command
  439.      * with options, configure it, etc... like you would do for the main parser
  440.      * because the class Console_CommandLine_Command inherits from
  441.      * Console_CommandLine.
  442.      *
  443.      * An example:
  444.      * <code>
  445.      * $parser = new Console_CommandLine();
  446.      * $install_cmd = $parser->addCommand('install');
  447.      * $install_cmd->addOption(
  448.      *     'verbose',
  449.      *     array(
  450.      *         'short_name'  => '-v',
  451.      *         'long_name'   => '--verbose',
  452.      *         'description' => 'be noisy when installing stuff',
  453.      *         'action'      => 'StoreTrue'
  454.      *      )
  455.      * );
  456.      * $parser->parse();
  457.      * </code>
  458.      * Then in a terminal:
  459.      * <code>
  460.      * $ myscript.php install -h
  461.      * Usage: myscript.php install [options]
  462.      *
  463.      * Options:
  464.      *   -h, --help     display this help message and exit
  465.      *   -v, --verbose  be noisy when installing stuff
  466.      *
  467.      * $ myscript.php install --verbose
  468.      * Installing whatever...
  469.      * $
  470.      * </code>
  471.      *
  472.      * @param mixed $name   A string containing the command name or an
  473.      *                       instance of Console_CommandLine_Command
  474.      * @param array $params An array containing the command attributes
  475.      *
  476.      * @return Console_CommandLine_Command the added subcommand
  477.      * @see    Console_CommandLine_Command
  478.      */
  479.     public function addCommand($name$params = array())
  480.     {
  481.         if ($name instanceof Console_CommandLine_Command{
  482.             $command $name;
  483.         else {
  484.             include_once 'Console/CommandLine/Command.php';
  485.             $params['name'$name;
  486.             $command        = new Console_CommandLine_Command($params);
  487.         }
  488.         $command->parent                = $this;
  489.         $this->commands[$command->name$command;
  490.         return $command;
  491.     }
  492.  
  493.     // }}}
  494.     // addOption() {{{
  495.  
  496.     /**
  497.      * Adds an option to the command line parser and returns it.
  498.      *
  499.      * Adds an option with the name $name and set its attributes with the
  500.      * array $params, then return the Console_CommandLine_Option instance
  501.      * created.
  502.      * The method accepts another form: you can directly pass a
  503.      * Console_CommandLine_Option object as the sole argument, this allows
  504.      * you to contruct the option separately, in order to reuse it in different
  505.      * command line parsers or commands for example.
  506.      *
  507.      * Example:
  508.      * <code>
  509.      * $parser = new Console_CommandLine();
  510.      * $parser->addOption('path', array(
  511.      *     'short_name'  => '-p',  // a short name
  512.      *     'long_name'   => '--path', // a long name
  513.      *     'description' => 'path to the dir', // a description msg
  514.      *     'action'      => 'StoreString',
  515.      *     'default'     => '/tmp' // a default value
  516.      * ));
  517.      * $parser->parse();
  518.      * </code>
  519.      *
  520.      * In a terminal, the help will be displayed like this:
  521.      * <code>
  522.      * $ myscript.php --help
  523.      * Usage: myscript.php [options]
  524.      *
  525.      * Options:
  526.      *   -h, --help  display this help message and exit
  527.      *   -p, --path  path to the dir
  528.      *
  529.      * </code>
  530.      *
  531.      * Various methods to specify an option, these 3 commands are equivalent:
  532.      * <code>
  533.      * $ myscript.php --path=some/path
  534.      * $ myscript.php -p some/path
  535.      * $ myscript.php -psome/path
  536.      * </code>
  537.      *
  538.      * @param mixed $name   A string containing the option name or an
  539.      *                       instance of Console_CommandLine_Option
  540.      * @param array $params An array containing the option attributes
  541.      *
  542.      * @return Console_CommandLine_Option The added option
  543.      * @see    Console_CommandLine_Option
  544.      */
  545.     public function addOption($name$params = array())
  546.     {
  547.         include_once 'Console/CommandLine/Option.php';
  548.         if ($name instanceof Console_CommandLine_Option{
  549.             $opt $name;
  550.         else {
  551.             $opt = new Console_CommandLine_Option($name$params);
  552.         }
  553.         $opt->validate();
  554.         $this->options[$opt->name$opt;
  555.         if (!empty($opt->choices&& $opt->add_list_option{
  556.             $this->addOption('list_' $opt->namearray(
  557.                 'long_name'     => '--list-' $opt->name,
  558.                 'description'   => $this->message_provider->get(
  559.                     'LIST_OPTION_MESSAGE',
  560.                     array('name' => $opt->name)
  561.                 ),
  562.                 'action'        => 'List',
  563.                 'action_params' => array('list' => $opt->choices),
  564.             ));
  565.         }
  566.         return $opt;
  567.     }
  568.  
  569.     // }}}
  570.     // displayError() {{{
  571.  
  572.     /**
  573.      * Displays an error to the user and exit with $exitCode.
  574.      *
  575.      * @param string $error    The error message
  576.      * @param int    $exitCode The exit code number
  577.      *
  578.      * @return void 
  579.      */
  580.     public function displayError($error$exitCode = 1)
  581.     {
  582.         $this->outputter->stderr($this->renderer->error($error));
  583.         exit($exitCode);
  584.     }
  585.  
  586.     // }}}
  587.     // displayUsage() {{{
  588.  
  589.     /**
  590.      * Displays the usage help message to the user and exit with $exitCode
  591.      *
  592.      * @param int $exitCode The exit code number
  593.      *
  594.      * @return void 
  595.      */
  596.     public function displayUsage($exitCode = 1)
  597.     {
  598.         $this->outputter->stderr($this->renderer->usage());
  599.         exit($exitCode);
  600.     }
  601.  
  602.     // }}}
  603.     // displayVersion() {{{
  604.  
  605.     /**
  606.      * Displays the program version to the user
  607.      *
  608.      * @return void 
  609.      */
  610.     public function displayVersion()
  611.     {
  612.         $this->outputter->stdout($this->renderer->version());
  613.         exit(0);
  614.     }
  615.  
  616.     // }}}
  617.     // findOption() {{{
  618.  
  619.     /**
  620.      * Finds the option that matches the given short_name (ex: -v), long_name
  621.      * (ex: --verbose) or name (ex: verbose).
  622.      *
  623.      * @param string $str The option identifier
  624.      *
  625.      * @return mixed A Console_CommandLine_Option instance or false
  626.      */
  627.     public function findOption($str)
  628.     {
  629.         $str trim($str);
  630.         if ($str === ''{
  631.             return false;
  632.         }
  633.         $matches = array();
  634.         foreach ($this->options as $opt{
  635.             if ($opt->short_name == $str || $opt->long_name == $str ||
  636.                 $opt->name == $str{
  637.                 // exact match
  638.                 return $opt;
  639.             }
  640.             if (substr($opt->long_name0strlen($str)) === $str{
  641.                 // abbreviated long option
  642.                 $matches[$opt;
  643.             }
  644.         }
  645.         if ($count count($matches)) {
  646.             if ($count > 1{
  647.                 $matches_str '';
  648.                 $padding     '';
  649.                 foreach ($matches as $opt{
  650.                     $matches_str .= $padding $opt->long_name;
  651.                     $padding      ', ';
  652.                 }
  653.                 throw Console_CommandLine_Exception::factory(
  654.                     'OPTION_AMBIGUOUS',
  655.                     array('name' => $str'matches' => $matches_str),
  656.                     $this
  657.                 );
  658.             }
  659.             return $matches[0];
  660.         }
  661.         return false;
  662.     }
  663.     // }}}
  664.     // registerAction() {{{
  665.  
  666.     /**
  667.      * Registers a custom action for the parser, an example:
  668.      *
  669.      * <code>
  670.      *
  671.      * // in this example we create a "range" action:
  672.      * // the user will be able to enter something like:
  673.      * // $ <program> -r 1,5
  674.      * // and in the result we will have:
  675.      * // $result->options['range']: array(1, 5)
  676.      *
  677.      * require_once 'Console/CommandLine.php';
  678.      * require_once 'Console/CommandLine/Action.php';
  679.      *
  680.      * class ActionRange extends Console_CommandLine_Action
  681.      * {
  682.      *     public function execute($value=false, $params=array())
  683.      *     {
  684.      *         $range = explode(',', str_replace(' ', '', $value));
  685.      *         if (count($range) != 2) {
  686.      *             throw new Exception(sprintf(
  687.      *                 'Option "%s" must be 2 integers separated by a comma',
  688.      *                 $this->option->name
  689.      *             ));
  690.      *         }
  691.      *         $this->setResult($range);
  692.      *     }
  693.      * }
  694.      * // then we can register our action
  695.      * Console_CommandLine::registerAction('Range', 'ActionRange');
  696.      * // and now our action is available !
  697.      * $parser = new Console_CommandLine();
  698.      * $parser->addOption('range', array(
  699.      *     'short_name'  => '-r',
  700.      *     'long_name'   => '--range',
  701.      *     'action'      => 'Range', // note our custom action
  702.      *     'description' => 'A range of two integers separated by a comma'
  703.      * ));
  704.      * // etc...
  705.      *
  706.      * </code>
  707.      *
  708.      * @param string $name  The name of the custom action
  709.      * @param string $class The class name of the custom action
  710.      *
  711.      * @return void 
  712.      */
  713.     public static function registerAction($name$class
  714.     {
  715.         if (!isset(self::$actions[$name])) {
  716.             if (!class_exists($class)) {
  717.                 self::triggerError('action_class_does_not_exists',
  718.                     E_USER_ERROR,
  719.                     array('{$name}' => $name'{$class}' => $class));
  720.             }
  721.             self::$actions[$name= array($classfalse);
  722.         }
  723.     }
  724.  
  725.     // }}}
  726.     // triggerError() {{{
  727.  
  728.     /**
  729.      * A wrapper for programming errors triggering.
  730.      *
  731.      * @param string $msgId  Identifier of the message
  732.      * @param int    $level  The php error level
  733.      * @param array  $params An array of search=>replaces entries
  734.      *
  735.      * @return void 
  736.      * @todo remove Console::triggerError() and use exceptions only
  737.      */
  738.     public static function triggerError($msgId$level$params=array()) 
  739.     {
  740.         if (isset(self::$errors[$msgId])) {
  741.             $msg = str_replace(array_keys($params),
  742.                 array_values($params)self::$errors[$msgId])
  743.             trigger_error($msg$level);
  744.         else {
  745.             trigger_error('unknown error'$level);
  746.         }
  747.     }
  748.  
  749.     // }}}
  750.     // parse() {{{
  751.  
  752.     /**
  753.      * Parses the command line arguments and returns a
  754.      * Console_CommandLine_Result instance.
  755.      *
  756.      * @param integer $userArgc Number of arguments (optional)
  757.      * @param array   $userArgv Array containing arguments (optional)
  758.      *
  759.      * @return Console_CommandLine_Result The result instance
  760.      * @throws Exception on user errors
  761.      */
  762.     public function parse($userArgc=null$userArgv=null)
  763.     {
  764.         $this->addBuiltinOptions();
  765.         if ($userArgc !== null && $userArgv !== null{
  766.             $argc $userArgc;
  767.             $argv $userArgv;
  768.         else {
  769.             list($argc$argv$this->getArgcArgv();
  770.         }
  771.         // build an empty result
  772.         include_once 'Console/CommandLine/Result.php';
  773.         $result = new Console_CommandLine_Result();
  774.         if (!($this instanceof Console_CommandLine_Command)) {
  775.             // remove script name if we're not in a subcommand
  776.             array_shift($argv);
  777.             $argc--;
  778.         }
  779.         // will contain aruments
  780.         $args = array();
  781.         foreach ($this->options as $name=>$option{
  782.             $result->options[$name$option->default;
  783.         }
  784.         // parse command line tokens
  785.         while ($argc--{
  786.             $token array_shift($argv);
  787.             try {
  788.                 if (isset($this->commands[$token])) {
  789.                     $result->command_name = $token;
  790.                     $result->command      = $this->commands[$token]->parse($argc,
  791.                         $argv);
  792.                     break;
  793.                 else {
  794.                     $this->parseToken($token$result$args$argc);
  795.                 }
  796.             catch (Exception $exc{
  797.                 throw $exc;
  798.             }
  799.         }
  800.         // minimum argument number check
  801.         $argnum = 0;
  802.         foreach ($this->args as $name=>$arg{
  803.             if (!$arg->optional{
  804.                 $argnum++;
  805.             }
  806.         }
  807.         if (count($args$argnum{
  808.             throw Console_CommandLine_Exception::factory(
  809.                 'ARGUMENT_REQUIRED',
  810.                 array('argnum' => $argnum'plural' => $argnum>1 ? 's'''),
  811.                 $this
  812.             );
  813.         }
  814.         // handle arguments
  815.         $c count($this->args);
  816.         foreach ($this->args as $name=>$arg{
  817.             $c--;
  818.             if ($arg->multiple{
  819.                 $result->args[$name$c array_splice($args0-$c$args;
  820.             else {
  821.                 $result->args[$namearray_shift($args);
  822.             }
  823.         }
  824.         // dispatch deferred options
  825.         foreach ($this->_dispatchLater as $optArray{
  826.             $optArray[0]->dispatchAction($optArray[1]$optArray[2]$this);
  827.         }
  828.         return $result;
  829.     }
  830.  
  831.     // }}}
  832.     // parseToken() {{{
  833.  
  834.     /**
  835.      * Parses the command line token and modifies *by reference* the $options
  836.      * and $args arrays.
  837.      *
  838.      * @param string $token  The command line token to parse
  839.      * @param object $result The Console_CommandLine_Result instance
  840.      * @param array  &$args  The argv array
  841.      * @param int    $argc   Number of lasting args
  842.      *
  843.      * @return void 
  844.      * @access protected
  845.      * @throws Exception on user errors
  846.      */
  847.     protected function parseToken($token$result&$args$argc)
  848.     {
  849.         static $lastopt  = false;
  850.         static $stopflag = false;
  851.         $last  $argc === 0;
  852.         $token = trim($token);
  853.         if (!$stopflag && $lastopt{
  854.             if (substr($token01== '-'{
  855.                 if ($lastopt->argument_optional{
  856.                     $this->_dispatchAction($lastopt''$result);
  857.                     if ($lastopt->action != 'StoreArray'{
  858.                         $lastopt = false;
  859.                     }
  860.                 else if (isset($result->options[$lastopt->name])) {
  861.                     // case of an option that expect a list of args
  862.                     $lastopt = false;
  863.                 else {
  864.                     throw Console_CommandLine_Exception::factory(
  865.                         'OPTION_VALUE_REQUIRED',
  866.                         array('name' => $lastopt->name),
  867.                         $this
  868.                     );
  869.                 }
  870.             else {
  871.                 // when a StoreArray option is positioned last, the behavior
  872.                 // is to consider that if there's already an element in the
  873.                 // array, and the commandline expects one or more args, we
  874.                 // leave last tokens to arguments
  875.                 if ($lastopt->action == 'StoreArray' && 
  876.                     !empty($result->options[$lastopt->name]&&
  877.                     count($this->args($argc count($args))) {
  878.                     $args[$token;
  879.                     return;
  880.                 }
  881.                 $this->_dispatchAction($lastopt$token$result);
  882.                 if ($lastopt->action != 'StoreArray'{
  883.                     $lastopt = false;
  884.                 }
  885.                 return;
  886.             }
  887.         }
  888.         if (!$stopflag && substr($token02== '--'{
  889.             // a long option
  890.             $optkv explode('='$token2);
  891.             if (trim($optkv[0]== '--'{
  892.                 // the special argument "--" forces in all cases the end of 
  893.                 // option scanning.
  894.                 $stopflag = true;
  895.                 return;
  896.             }
  897.             $opt $this->findOption($optkv[0]);
  898.             if (!$opt{
  899.                 throw Console_CommandLine_Exception::factory(
  900.                     'OPTION_UNKNOWN',
  901.                     array('name' => $optkv[0]),
  902.                     $this
  903.                 );
  904.             }
  905.             $value = isset($optkv[1]$optkv[1: false;
  906.             if (!$opt->expectsArgument(&& $value !== false{
  907.                 throw Console_CommandLine_Exception::factory(
  908.                     'OPTION_VALUE_UNEXPECTED',
  909.                     array('name' => $opt->name'value' => $value),
  910.                     $this
  911.                 );
  912.             }
  913.             if ($opt->expectsArgument(&& $value === false{
  914.                 // maybe the long option argument is separated by a space, if 
  915.                 // this is the case it will be the next arg
  916.                 if ($last && !$opt->argument_optional{
  917.                     throw Console_CommandLine_Exception::factory(
  918.                         'OPTION_VALUE_REQUIRED',
  919.                         array('name' => $opt->name),
  920.                         $this
  921.                     );
  922.                 }
  923.                 // we will have a value next time
  924.                 $lastopt $opt;
  925.                 return;
  926.             }
  927.             if ($opt->action == 'StoreArray'{
  928.                 $lastopt $opt;
  929.             }
  930.             $this->_dispatchAction($opt$value$result);
  931.         else if (!$stopflag && substr($token01== '-'{
  932.             // a short option
  933.             $optname substr($token02);
  934.             if ($optname == '-'{
  935.                 // special case of "-": try to read stdin
  936.                 $args[file_get_contents('php://stdin');
  937.                 return;
  938.             }
  939.             $opt $this->findOption($optname);
  940.             if (!$opt{
  941.                 throw Console_CommandLine_Exception::factory(
  942.                     'OPTION_UNKNOWN',
  943.                     array('name' => $optname),
  944.                     $this
  945.                 );
  946.             }
  947.             // parse other options or set the value
  948.             // in short: handle -f<value> and -f <value>
  949.             $next substr($token21);
  950.             // check if we must wait for a value
  951.             if ($next === false{
  952.                 if ($opt->expectsArgument()) {
  953.                     if ($last && !$opt->argument_optional{
  954.                         throw Console_CommandLine_Exception::factory(
  955.                             'OPTION_VALUE_REQUIRED',
  956.                             array('name' => $opt->name),
  957.                             $this
  958.                         );
  959.                     }
  960.                     // we will have a value next time
  961.                     $lastopt $opt;
  962.                     return;
  963.                 }
  964.                 $value = false;
  965.             else {
  966.                 if (!$opt->expectsArgument()) 
  967.                     if ($nextopt $this->findOption('-' $next)) {
  968.                         $this->_dispatchAction($optfalse$result);
  969.                         $this->parseToken('-' substr($token2)$result,
  970.                             $args$last);
  971.                         return;
  972.                     else {
  973.                         throw Console_CommandLine_Exception::factory(
  974.                             'OPTION_UNKNOWN',
  975.                             array('name' => $next),
  976.                             $this
  977.                         );
  978.                     }
  979.                 }
  980.                 if ($opt->action == 'StoreArray'{
  981.                     $lastopt $opt;
  982.                 }
  983.                 $value substr($token2);
  984.             }
  985.             $this->_dispatchAction($opt$value$result);
  986.         else {
  987.             // We have an argument.
  988.             // if we are in POSIX compliant mode, we must set the stop flag to 
  989.             // true in order to stop option parsing.
  990.             if (!$stopflag && $this->force_posix{
  991.                 $stopflag = true;
  992.             }
  993.             $args[$token;
  994.         }
  995.     }
  996.  
  997.     // }}}
  998.     // addBuiltinOptions() {{{
  999.  
  1000.     /**
  1001.      * Adds the builtin "Help" and "Version" options if needed.
  1002.      *
  1003.      * @return void 
  1004.      */
  1005.     public function addBuiltinOptions()
  1006.     {
  1007.         if ($this->add_help_option{
  1008.             $helpOptionParams = array(
  1009.                 'long_name'   => '--help',
  1010.                 'description' => 'show this help message and exit',
  1011.                 'action'      => 'Help'   
  1012.             );
  1013.             if (!$this->findOption('-h')) {
  1014.                 // short name is available, take it
  1015.                 $helpOptionParams['short_name''-h';
  1016.             }
  1017.             $this->addOption('help'$helpOptionParams);
  1018.         }
  1019.         if ($this->add_version_option && !empty($this->version)) {
  1020.             $versionOptionParams = array(
  1021.                 'long_name'   => '--version',
  1022.                 'description' => 'show the program version and exit',
  1023.                 'action'      => 'Version'   
  1024.             );
  1025.             if (!$this->findOption('-v')) {
  1026.                 // short name is available, take it
  1027.                 $versionOptionParams['short_name''-v';
  1028.             }
  1029.             $this->addOption('version'$versionOptionParams);
  1030.         }
  1031.     
  1032.  
  1033.     // }}}
  1034.     // getArgcArgv() {{{
  1035.  
  1036.     /**
  1037.      * Tries to return an array containing argc and argv, or trigger an error
  1038.      * if it fails to get them.
  1039.      *
  1040.      * @return array The argc/argv array
  1041.      * @throws Console_CommandLine_Exception
  1042.      */
  1043.     protected function getArgcArgv()
  1044.     {
  1045.         if (php_sapi_name(!= 'cli'{
  1046.             // we have a web request
  1047.             $argv = array($this->name);
  1048.             if (isset($_REQUEST)) {
  1049.                 foreach ($_REQUEST as $key => $value{
  1050.                     if (!is_array($value)) {
  1051.                         $value = array($value);
  1052.                     }
  1053.                     $opt $this->findOption($key);
  1054.                     if ($opt instanceof Console_CommandLine_Option{
  1055.                         // match a configured option
  1056.                         $argv[$opt->short_name ? 
  1057.                             $opt->short_name : $opt->long_name;
  1058.                         foreach ($value as $v{
  1059.                             if ($opt->expectsArgument()) {
  1060.                                 $argv[= isset($_GET[$key]urldecode($v$v;
  1061.                             else if ($v == '0' || $v == 'false'{
  1062.                                 array_pop($argv);
  1063.                             }
  1064.                         }
  1065.                     else if (isset($this->args[$key])) {
  1066.                         // match a configured argument
  1067.                         foreach ($value as $v{
  1068.                             $argv[= isset($_GET[$key]urldecode($v$v;
  1069.                         }
  1070.                     }
  1071.                 }
  1072.             }
  1073.             return array(count($argv)$argv);
  1074.         }
  1075.         if (isset($argc&& isset($argv)) {
  1076.             // case of register_argv_argc = 1
  1077.             return array($argc$argv);
  1078.         }
  1079.         if (isset($_SERVER['argc']&& isset($_SERVER['argv'])) {
  1080.             return array($_SERVER['argc']$_SERVER['argv']);
  1081.         }
  1082.         return array(0array());
  1083.     }
  1084.  
  1085.     // }}}
  1086.     // _dispatchAction() {{{
  1087.  
  1088.     /**
  1089.      * Dispatches the given option or store the option to dispatch it later.
  1090.      *
  1091.      * @param Console_CommandLine_Option $option The option instance
  1092.      * @param string                     $token  Command line token to parse
  1093.      * @param Console_CommandLine_Result $result The result instance
  1094.      *
  1095.      * @return void 
  1096.      */
  1097.     private function _dispatchAction($option$token$result)
  1098.     {
  1099.         if ($option->action == 'Password'{
  1100.             $this->_dispatchLater[= array($option$token$result);
  1101.         else {
  1102.             $option->dispatchAction($token$result$this);
  1103.         }
  1104.     }
  1105.     // }}}
  1106. }

Documentation generated on Mon, 11 Mar 2019 15:26:51 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.