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

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