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

Source for file Getargs.php

Documentation is available at Getargs.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2004 The PHP Group                                     |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Bertrand Mansion <bmansion@mamasam.com>                      |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Getargs.php,v 1.23 2006/11/07 13:53:36 scottmattocks Exp $
  20.  
  21. require_once 'PEAR.php';
  22.  
  23. /**#@+
  24.  * Error Constants
  25.  */
  26. /**
  27.  * Wrong configuration
  28.  *
  29.  * This error will be TRIGGERed when a configuration error is found,
  30.  * it will also issue a WARNING.
  31.  */
  32. define('CONSOLE_GETARGS_ERROR_CONFIG'-1);
  33.  
  34. /**
  35.  * User made an error
  36.  *
  37.  * This error will be RETURNed when a bad parameter
  38.  * is found in the command line, for example an unknown parameter
  39.  * or a parameter with an invalid number of options.
  40.  */
  41. define('CONSOLE_GETARGS_ERROR_USER'-2);
  42.  
  43. /**
  44.  * Help text wanted
  45.  *
  46.  * This error will be RETURNed when the user asked to
  47.  * see the help by using <kbd>-h</kbd> or <kbd>--help</kbd> in the command line, you can then print
  48.  * the help ascii art text by using the {@link Console_Getargs::getHelp()} method
  49.  */
  50. define('CONSOLE_GETARGS_HELP'-3);
  51.  
  52. /**
  53.  * Option name for application "parameters"
  54.  *
  55.  * Parameters are the options an application needs to function.
  56.  * The two files passed to the diff command would be considered
  57.  * the parameters. These are different from other options in that
  58.  * they do not need an option name passed on the command line.
  59.  */
  60. define('CONSOLE_GETARGS_PARAMS''parameters');
  61. /**#@-*/
  62.  
  63. /**
  64.  * Command-line arguments parsing class
  65.  * 
  66.  * This implementation was freely inspired by a python module called
  67.  * getargs by Vinod Vijayarajan and a perl CPAN module called
  68.  * Getopt::Simple by Ron Savage
  69.  *
  70.  * This class implements a Command Line Parser that your cli applications
  71.  * can use to parse command line arguments found in $_SERVER['argv'] or a
  72.  * user defined array.
  73.  * 
  74.  * It gives more flexibility and error checking than Console_Getopt. It also
  75.  * performs some arguments validation and is capable to return a formatted
  76.  * help text to the user, based on the configuration it is given.
  77.  * 
  78.  * The class provides the following capabilities:
  79.  * - Each command line option can take an arbitrary number of arguments.
  80.  * - Makes the distinction between switches (options without arguments)
  81.  *   and options that require arguments.
  82.  * - Recognizes 'single-argument-options' and 'default-if-set' options.
  83.  * - Switches and options with arguments can be interleaved in the command
  84.  *   line.
  85.  * - You can specify the maximum and minimum number of arguments an option
  86.  *   can take. Use -1 if you don't want to specify an upper bound.
  87.  * - Specify the default arguments to an option
  88.  * - Short options can be more than one letter in length.
  89.  * - A given option may be invoked by multiple names (aliases).
  90.  * - Understands by default the --help, -h options
  91.  * - Can return a formatted help text
  92.  * - Arguments may be specified using the '=' syntax also.
  93.  * - Short option names may be concatenated (-dvw 100 == -d -v -w 100)
  94.  * - Can define a default option that will take any arguments added without
  95.  *   an option name
  96.  * - Can pass in a user defined array of arguments instead of using
  97.  *   $_SERVER['argv']
  98.  * 
  99.  * @todo      Implement the parsing of comma delimited arguments
  100.  * @todo      Implement method for turning assocative arrays into command
  101.  *             line arguments (ex. array('d' => true, 'v' => 2) -->
  102.  *                                 array('-d', '-v', 2))
  103.  *
  104.  * @author    Bertrand Mansion <bmansion@mamasam.com>
  105.  * @copyright 2004
  106.  * @license   http://www.php.net/license/3_0.txt PHP License 3.0
  107.  * @version   @VER@
  108.  * @package   Console_Getargs
  109.  */
  110. {
  111.     /**
  112.      * Factory creates a new {@link Console_Getargs_Options} object
  113.      *
  114.      * This method will return a new {@link Console_Getargs_Options}
  115.      * built using the given configuration options. If the configuration
  116.      * or the command line options contain errors, the returned object will
  117.      * in fact be a PEAR_Error explaining the cause of the error.
  118.      *
  119.      * Factory expects an array as parameter.
  120.      * The format for this array is:
  121.      * <pre>
  122.      * array(
  123.      *  longname => array('short'   => Short option name,
  124.      *                    'max'     => Maximum arguments for option,
  125.      *                    'min'     => Minimum arguments for option,
  126.      *                    'default' => Default option argument,
  127.      *                    'desc'    => Option description)
  128.      * )
  129.      * </pre>
  130.      * 
  131.      * If an option can be invoked by more than one name, they have to be defined
  132.      * by using | as a separator. For example: name1|name2
  133.      * This works both in long and short names.
  134.      *
  135.      * max/min are the most/least number of arguments an option accepts.
  136.      *
  137.      * The 'defaults' field is optional and is used to specify default
  138.      * arguments to an option. These will be assigned to the option if
  139.      * it is *not* used in the command line.
  140.      * Default arguments can be:
  141.      * - a single value for options that require a single argument,
  142.      * - an array of values for options with more than one possible arguments.
  143.      * Default argument(s) are mandatory for 'default-if-set' options.
  144.      *
  145.      * If max is 0 (option is just a switch), min is ignored.
  146.      * If max is -1, then the option can have an unlimited number of arguments
  147.      * greater or equal to min.
  148.      * 
  149.      * If max == min == 1, the option is treated as a single argument option.
  150.      * 
  151.      * If max >= 1 and min == 0, the option is treated as a
  152.      * 'default-if-set' option. This implies that it will get the default argument
  153.      * only if the option is used in the command line without any value.
  154.      * (Note: defaults *must* be specified for 'default-if-set' options)
  155.      *
  156.      * If the option is not in the command line, the defaults are
  157.      * *not* applied. If an argument for the option is specified on the command
  158.      * line, then the given argument is assigned to the option.
  159.      * Thus:
  160.      * - a --debug in the command line would cause debug = 'default argument'
  161.      * - a --debug 2 in the command line would result in debug = 2
  162.      *  if not used in the command line, debug will not be defined.
  163.      * 
  164.      * Example 1.
  165.      * <code>
  166.      * require_once 'Console_Getargs.php';
  167.      *
  168.      * $args =& Console_Getargs::factory($config);
  169.      * 
  170.      * if (PEAR::isError($args)) {
  171.      *  if ($args->getCode() === CONSOLE_GETARGS_ERROR_USER) {
  172.      *    echo Console_Getargs::getHelp($config, null, $args->getMessage())."\n";
  173.      *  } else if ($args->getCode() === CONSOLE_GETARGS_HELP) {
  174.      *    echo Console_Getargs::getHelp($config)."\n";
  175.      *  }
  176.      *  exit;
  177.      * }
  178.      * 
  179.      * echo 'Verbose: '.$args->getValue('verbose')."\n";
  180.      * if ($args->isDefined('bs')) {
  181.      *  echo 'Block-size: '.(is_array($args->getValue('bs')) ? implode(', ', $args->getValue('bs'))."\n" : $args->getValue('bs')."\n");
  182.      * } else {
  183.      *  echo "Block-size: undefined\n";
  184.      * }
  185.      * echo 'Files: '.($args->isDefined('file') ? implode(', ', $args->getValue('file'))."\n" : "undefined\n");
  186.      * if ($args->isDefined('n')) {
  187.      *  echo 'Nodes: '.(is_array($args->getValue('n')) ? implode(', ', $args->getValue('n'))."\n" : $args->getValue('n')."\n");
  188.      * } else {
  189.      *  echo "Nodes: undefined\n";
  190.      * }
  191.      * echo 'Log: '.$args->getValue('log')."\n";
  192.      * echo 'Debug: '.($args->isDefined('d') ? "YES\n" : "NO\n");
  193.      * 
  194.      * </code>
  195.      *
  196.      * If you don't want to require any option name for a set of arguments,
  197.      * or if you would like any "leftover" arguments assigned by default,
  198.      * you can create an option named CONSOLE_GETARGS_PARAMS that will
  199.      * grab any arguments that cannot be assigned to another option. The
  200.      * rules for CONSOLE_GETARGS_PARAMS are still the same. If you specify
  201.      * that two values must be passed then two values must be passed. See
  202.      * the example script for a complete example.
  203.      * 
  204.      * @param  array  $config     associative array with keys being the
  205.      *                             options long name
  206.      * @param  array  $arguments  numeric array of command line arguments
  207.      * @access public
  208.      * @return object|PEAR_Error a newly created Console_Getargs_Options
  209.      *                             object or a PEAR_Error object on error
  210.      */
  211.     function &factory($config = array()$arguments = NULL)
  212.     {
  213.         // Create the options object.
  214.         $obj =new Console_Getargs_Options();
  215.         
  216.         // Try to set up the arguments.
  217.         $err $obj->init($config$arguments);
  218.         if ($err !== true{
  219.             return $err;
  220.         }
  221.         
  222.         // Try to set up the options.
  223.         $err $obj->buildMaps();
  224.         if ($err !== true{
  225.             return $err;
  226.         }
  227.         
  228.         // Get the options and arguments from the command line.
  229.         $err $obj->parseArgs();
  230.         if ($err !== true{
  231.             return $err;
  232.         }
  233.         
  234.         // Set arguments for options that have defaults.
  235.         $err $obj->setDefaults();
  236.         if ($err !== true{
  237.             return $err;
  238.         }
  239.  
  240.         // Double check that all required options have been passed.
  241.         $err $obj->checkRequired();
  242.         if ($err !== true{
  243.             return $err;
  244.         }
  245.         
  246.         // All is good.
  247.         return $obj;
  248.     }
  249.     
  250.     /**
  251.      * Returns an ascii art version of the help
  252.      *
  253.      * This method uses the given configuration and parameters
  254.      * to create and format an help text for the options you defined
  255.      * in your config parameter. You can supply a header and a footer
  256.      * as well as the maximum length of a line. If you supplied
  257.      * descriptions for your options, they will be used as well.
  258.      *
  259.      * By default, it returns something like this:
  260.      * <pre>
  261.      * Usage: myscript.php [-dv --formats] <-fw --filters>
  262.      * 
  263.      * -f --files values(2)          Set the source and destination image files.
  264.      * -w --width=&lt;value&gt;      Set the new width of the image.
  265.      * -d --debug                    Switch to debug mode.
  266.      * --formats values(1-3)         Set the image destination format. (jpegbig,
  267.      *                               jpegsmall)
  268.      * -fi --filters values(1-...)   Set the filters to be applied to the image upon
  269.      *                               conversion. The filters will be used in the order
  270.      *                               they are set.
  271.      * -v --verbose (optional)value  Set the verbose level. (3)
  272.      * </pre>
  273.      *
  274.      * @access public
  275.      * @param  array  your args configuration
  276.      * @param  string the header for the help. If it is left null,
  277.      *                 a default header will be used, starting by Usage:
  278.      * @param  string the footer for the help. This could be used
  279.      *                 to supply a description of the error the user made
  280.      * @param  int    help lines max length
  281.      * @param  int    the indent for the options
  282.      * @return string the formatted help text
  283.      */
  284.     function getHelp($config$helpHeader = null$helpFooter ''$maxlength = 78$indent = 0)
  285.     {
  286.         // Start with an empty help message and build it piece by piece
  287.         $help '';
  288.         
  289.         // If no user defined header, build the default header.
  290.         if (!isset($helpHeader)) {
  291.             // Get the optional, required and "paramter" names for this config.
  292.             list($optional$required$paramsConsole_Getargs::getOptionalRequired($config);
  293.             // Start with the file name.
  294.             if (isset($_SERVER['SCRIPT_NAME'])) {
  295.                 $filename basename($_SERVER['SCRIPT_NAME']);
  296.             else {
  297.                 $filename $argv[0];
  298.             }
  299.             $helpHeader 'Usage: '$filename ' ';
  300.             // Add the optional arguments and required arguments.
  301.             $helpHeader.= $optional ' ' $required ' ';
  302.             // Add any parameters that are needed.
  303.             $helpHeader.= $params "\n\n";
  304.         }
  305.         
  306.         // Create an indent string to be prepended to each option row.
  307.         $indentStr str_repeat(' '(int)$indent);
  308.  
  309.         // Go through all of the short options to get a padding value.
  310.         $v array_values($config);
  311.         $shortlen = 0;
  312.         foreach ($v as $item{
  313.             if (isset($item['short'])) {
  314.                 $shortArr explode('|'$item['short']);
  315.  
  316.                 if (strlen($shortArr[0]$shortlen{
  317.                     $shortlen strlen($shortArr[0]);
  318.                 }
  319.             }
  320.         }
  321.  
  322.         // Add two to account for the extra characters we add automatically.
  323.         $shortlen += 2;
  324.  
  325.         // Build the list of options and definitions.
  326.         $i = 0;
  327.         foreach ($config as $long => $def{
  328.             
  329.             // Break the names up if there is more than one for an option.
  330.             $shortArr = array();
  331.             if (isset($def['short'])) {
  332.                 $shortArr explode('|'$def['short']);
  333.             }
  334.             $longArr explode('|'$long);
  335.             
  336.             // Column one is the option name displayed as "-short, --long [additional info]"
  337.             // Start with the indent string.
  338.             $col1[$i$indentStr;
  339.             // Add the short option name.
  340.             $col1[$i.= str_pad(!empty($shortArr'-' $shortArr[0' ' ''$shortlen);
  341.             // Add the long option name.
  342.             $col1[$i.= '--'.$longArr[0];
  343.             
  344.             // Get the min and max to show needed/optional values.
  345.             // Cast to int to avoid complications elsewhere.
  346.             $max = (int)$def['max'];
  347.             $min = isset($def['min']? (int)$def['min'$max;
  348.             
  349.             if ($max === 1 && $min === 1{
  350.                 // One value required.
  351.                 $col1[$i.= '=<value>';
  352.             else if ($max > 1{
  353.                 if ($min === $max{
  354.                     // More than one value needed.
  355.                     $col1[$i.= ' values('.$max.')';
  356.                 else if ($min === 0{
  357.                     // Argument takes optional value(s).
  358.                     $col1[$i.= ' values(optional)';
  359.                 else {
  360.                     // Argument takes a range of values.
  361.                     $col1[$i.= ' values('.$min.'-'.$max.')';
  362.                 }
  363.             else if ($max === 1 && $min === 0{
  364.                 // Argument can take at most one value.
  365.                 $col1[$i.= ' (optional)value';
  366.             else if ($max === -1{
  367.                 // Argument can take unlimited values.
  368.                 if ($min > 0{
  369.                     $col1[$i.= ' values('.$min.'-...)';
  370.                 else {
  371.                     $col1[$i.= ' (optional)values';
  372.                 }
  373.             }
  374.             
  375.             // Column two is the description if available.
  376.             if (isset($def['desc'])) {
  377.                 $col2[$i$def['desc'];
  378.             else {
  379.                 $col2[$i'';
  380.             }
  381.             // Add the default value(s) if there are any/
  382.             if (isset($def['default'])) {
  383.                 if (is_array($def['default'])) {
  384.                     $col2[$i.= ' ('.implode(', '$def['default']).')';
  385.                 else {
  386.                     $col2[$i.= ' ('.$def['default'].')';
  387.                 }
  388.             }
  389.             $i++;
  390.         }
  391.         
  392.         // Figure out the maximum length for column one.
  393.         $arglen = 0;
  394.         foreach ($col1 as $txt{
  395.             $length strlen($txt);
  396.             if ($length $arglen{
  397.                 $arglen $length;
  398.             }
  399.         }
  400.         
  401.         // The maximum length for each description line.
  402.         $desclen $maxlength $arglen;
  403.         $padding str_repeat(' '$arglen);
  404.         foreach ($col1 as $k => $txt{
  405.             // Wrap the descriptions.
  406.             if (strlen($col2[$k]$desclen{
  407.                 $desc wordwrap($col2[$k]$desclen"\n  ".$padding);
  408.             else {
  409.                 $desc $col2[$k];
  410.             }
  411.             // Push everything together.
  412.             $help .= str_pad($txt$arglen).'  '.$desc."\n";
  413.         }
  414.         
  415.         // Put it all together.
  416.         return $helpHeader.$help.$helpFooter;
  417.     }
  418.     
  419.     /**
  420.      * Parse the config array to determine which flags are
  421.      * optional and which are required.
  422.      *
  423.      * To make the help header more descriptive, the options
  424.      * are shown seperated into optional and required flags.
  425.      * When possible the short flag is used for readability.
  426.      * Optional items (including "parameters") are surrounded
  427.      * in square braces ([-vd]). Required flags are surrounded
  428.      * in angle brackets (<-wf>).
  429.      *
  430.      * This method may be called statically.
  431.      *
  432.      * @access  public
  433.      * @param   &$config The config array.
  434.      * @return  array 
  435.      * @author  Scott Mattocks
  436.      * @package Console_Getargs
  437.      */
  438.     function getOptionalRequired(&$config)
  439.     {
  440.         // Parse the config array and look for optional/required
  441.         // tags.
  442.         $optional         '';
  443.         $optionalHasShort = false;
  444.         $required         '';
  445.         $requiredHasShort = false;
  446.         
  447.         ksort($config);
  448.         foreach ($config as $long => $def{
  449.             
  450.             // We only really care about the first option name.
  451.             $long explode('|'$long);
  452.             $long reset($long);
  453.             
  454.             // Treat the "parameters" specially.
  455.             if ($long == CONSOLE_GETARGS_PARAMS{
  456.                 continue;
  457.             }
  458.             if (isset($def['short'])) {
  459.                 // We only really care about the first option name.
  460.                 $def['short'explode('|'$def['short']);
  461.                 $def['short'reset($def['short']);
  462.             }
  463.             
  464.             if (!isset($def['min']|| $def['min'== 0 || isset($def['default'])) {
  465.                 // This argument is optional.
  466.                 if (isset($def['short']&& strlen($def['short']== 1{
  467.                     $optional         $def['short'$optional;
  468.                     $optionalHasShort = true;
  469.                 else {
  470.                     $optional.= ' --' $long;
  471.                 }
  472.             else {
  473.                 // This argument is required.
  474.                 if (isset($def['short']&& strlen($def['short']== 1{
  475.                     $required         $def['short'$required;
  476.                     $requiredHasShort = true;
  477.                 else {
  478.                     $required.= ' --' $long;
  479.                 }
  480.             }
  481.         }
  482.         
  483.         // Check for "parameters" option.
  484.         $params '';
  485.         if (isset($config[CONSOLE_GETARGS_PARAMS])) {
  486.             for ($i = 1; $i <= max($config[CONSOLE_GETARGS_PARAMS]['max']$config[CONSOLE_GETARGS_PARAMS]['min']); ++$i{
  487.                 if ($config[CONSOLE_GETARGS_PARAMS]['max'== -1 ||
  488.                     ($i $config[CONSOLE_GETARGS_PARAMS]['min'&&
  489.                      $i <= $config[CONSOLE_GETARGS_PARAMS]['max']||
  490.                     isset($config[CONSOLE_GETARGS_PARAMS]['default'])) {
  491.                     // Parameter is optional.
  492.                     $params.= '[param' $i .'] ';
  493.                 else {
  494.                     // Parameter is required.
  495.                     $params.= 'param' $i ' ';
  496.                 }
  497.             }
  498.         }
  499.         // Add a leading - if needed.
  500.         if ($optionalHasShort{
  501.             $optional '-' $optional;
  502.         }
  503.         
  504.         if ($requiredHasShort{
  505.             $required '-' $required;
  506.         }
  507.         
  508.         // Add the extra characters if needed.
  509.         if (!empty($optional)) {
  510.             $optional '[' $optional ']';
  511.         }
  512.         if (!empty($required)) {
  513.             $required '<' $required '>';
  514.         }
  515.         
  516.         return array($optional$required$params);
  517.     }
  518. // end class Console_Getargs
  519.  
  520. /**
  521.  * This class implements a wrapper to the command line options and arguments.
  522.  *
  523.  * @author Bertrand Mansion <bmansion@mamasam.com>
  524.  * @package  Console_Getargs
  525.  */
  526. {
  527.     
  528.     /**
  529.      * Lookup to match short options name with long ones
  530.      * @var array 
  531.      * @access private
  532.      */
  533.     var $_shortLong = array();
  534.     
  535.     /**
  536.      * Lookup to match alias options name with long ones
  537.      * @var array 
  538.      * @access private
  539.      */
  540.     var $_aliasLong = array();
  541.     
  542.     /**
  543.      * Arguments set for the options
  544.      * @var array 
  545.      * @access private
  546.      */
  547.     var $_longLong = array();
  548.     
  549.     /**
  550.      * Configuration set at initialization time
  551.      * @var array 
  552.      * @access private
  553.      */
  554.     var $_config = array();
  555.     
  556.     /**
  557.      * A read/write copy of argv
  558.      * @var array 
  559.      * @access private
  560.      */
  561.     var $args = array();
  562.     
  563.     /**
  564.      * Initializes the Console_Getargs_Options object
  565.      * @param array configuration options
  566.      * @access private
  567.      * @throws CONSOLE_GETARGS_ERROR_CONFIG
  568.      * @return true|PEAR_Error
  569.      */
  570.     function init($config$arguments = NULL)
  571.     {
  572.         if (is_array($arguments)) {
  573.             // Use the user defined argument list.
  574.             $this->args $arguments;
  575.         else {
  576.             // Command line arguments must be available.
  577.             if (!isset($_SERVER['argv']|| !is_array($_SERVER['argv'])) {
  578.                 return PEAR::raiseError("Could not read argv"CONSOLE_GETARGS_ERROR_CONFIG,
  579.                                         PEAR_ERROR_TRIGGERE_USER_WARNING'Console_Getargs_Options::init()');
  580.             }
  581.             $this->args $_SERVER['argv'];
  582.         }
  583.         
  584.         // Drop the first argument if it doesn't begin with a '-'.
  585.         if (isset($this->args[0]{0}&& $this->args[0]{0!= '-'{
  586.             array_shift($this->args);
  587.         }
  588.         $this->_config $config;
  589.         return true;
  590.     }
  591.     
  592.     /**
  593.      * Makes the lookup arrays for alias and short name mapping with long names
  594.      * @access private
  595.      * @throws CONSOLE_GETARGS_ERROR_CONFIG
  596.      * @return true|PEAR_Error
  597.      */
  598.     function buildMaps()
  599.     {
  600.         foreach($this->_config as $long => $def{
  601.             
  602.             $longArr explode('|'$long);
  603.             $longname $longArr[0];
  604.             
  605.             if (count($longArr> 1{
  606.                 // The fisrt item in the list is "the option".
  607.                 // The rest are aliases.
  608.                 array_shift($longArr);
  609.                 foreach($longArr as $alias{
  610.                     // Watch out for duplicate aliases.
  611.                     if (isset($this->_aliasLong[$alias])) {
  612.                         return PEAR::raiseError('Duplicate alias for long option '.$aliasCONSOLE_GETARGS_ERROR_CONFIG,
  613.                                                 PEAR_ERROR_TRIGGERE_USER_WARNING'Console_Getargs_Options::buildMaps()');
  614.                         
  615.                     }
  616.                     $this->_aliasLong[$alias$longname;
  617.                 }
  618.                 // Add the real option name and defintion.
  619.                 $this->_config[$longname$def;
  620.                 // Get rid of the old version (name|alias1|...)
  621.                 unset($this->_config[$long]);
  622.             }
  623.             
  624.             // Add the (optional) short option names.
  625.             if (!empty($def['short'])) {
  626.                 // Short names
  627.                 $shortArr explode('|'$def['short']);
  628.                 $short $shortArr[0];
  629.                 if (count($shortArr> 1{
  630.                     // The first item is "the option".
  631.                     // The rest are aliases.
  632.                     array_shift($shortArr);
  633.                     foreach ($shortArr as $alias{
  634.                         // Watch out for duplicate aliases.
  635.                         if (isset($this->_shortLong[$alias])) {
  636.                             return PEAR::raiseError('Duplicate alias for short option '.$aliasCONSOLE_GETARGS_ERROR_CONFIG,
  637.                                                     PEAR_ERROR_TRIGGERE_USER_WARNING'Console_Getargs_Options::buildMaps()');
  638.                         }
  639.                         $this->_shortLong[$alias$longname;
  640.                     }
  641.                 }
  642.                 // Add the real short option name.
  643.                 $this->_shortLong[$short$longname;
  644.             }
  645.         }
  646.         return true;
  647.     }
  648.     
  649.     /**
  650.      * Parses the given options/arguments one by one
  651.      * @access private
  652.      * @throws CONSOLE_GETARGS_HELP
  653.      * @throws CONSOLE_GETARGS_ERROR_USER
  654.      * @return true|PEAR_Error
  655.      */
  656.     function parseArgs()
  657.     {
  658.         // Go through the options and parse the arguments for each.
  659.         for ($i = 0$count count($this->args)$i $count$i++{
  660.             $arg $this->args[$i];
  661.             if ($arg === '--help' || $arg === '-h'{
  662.                 // Asking for help breaks the loop.
  663.                 return PEAR::raiseError(nullCONSOLE_GETARGS_HELPPEAR_ERROR_RETURN);
  664.  
  665.             }
  666.             if ($arg === '--'{
  667.                 // '--' alone signals the start of "parameters"
  668.                 $err $this->parseArg(CONSOLE_GETARGS_PARAMStrue++$i);
  669.             elseif (strlen($arg> 1 && $arg{0== '-' && $arg{1== '-'{
  670.                 // Long name used (--option)
  671.                 $err $this->parseArg(substr($arg2)true$i);
  672.             else if (strlen($arg> 1 && $arg{0== '-'{
  673.                 // Short name used (-o)
  674.                 $err $this->parseArg(substr($arg1)false$i);
  675.                 if ($err === -1{
  676.                     break;
  677.                 }
  678.             elseif (isset($this->_config[CONSOLE_GETARGS_PARAMS])) {
  679.                 // No flags at all. Try the parameters option.
  680.                 $tempI &$i - 1;
  681.                 $err $this->parseArg(CONSOLE_GETARGS_PARAMStrue$tempI);
  682.             else {
  683.                 $err = PEAR::raiseError('Unknown argument '.$arg,
  684.                                         CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  685.                                         null'Console_Getargs_Options::parseArgs()');
  686.             }
  687.             if ($err !== true{
  688.                 return $err;
  689.             }
  690.         }
  691.         // Check to see if we need to reload the arguments
  692.         // due to concatenated short names.
  693.         if (isset($err&& $err === -1{
  694.             return $this->parseArgs();
  695.         }
  696.         
  697.         return true;
  698.     }
  699.     
  700.     /**
  701.      * Parses one option/argument
  702.      * @access private
  703.      * @throws CONSOLE_GETARGS_ERROR_USER
  704.      * @return true|PEAR_Error
  705.      */
  706.     function parseArg($arg$isLong&$pos)
  707.     {
  708.         // If the whole short option isn't in the shortLong array
  709.         // then break it into a bunch of switches.
  710.         if (!$isLong && !isset($this->_shortLong[$arg]&& strlen($arg> 1{
  711.             $newArgs = array();
  712.             for ($i = 0; $i strlen($arg)$i++{
  713.                 if (array_key_exists($arg{$i}$this->_shortLong)) {
  714.                     $newArgs['-' $arg{$i};
  715.                 else {
  716.                     $newArgs[$arg{$i};
  717.                 }
  718.             }
  719.             // Add the new args to the array.
  720.             array_splice($this->args$pos1$newArgs);
  721.             
  722.             // Reset the option values.
  723.             $this->_longLong = array();
  724.             
  725.             // Then reparse the arguments.
  726.             return -1;
  727.         }
  728.         
  729.         $opt '';
  730.         for ($i = 0; $i strlen($arg)$i++{
  731.             // Build the option name one char at a time looking for a match.
  732.             $opt .= $arg{$i};
  733.             if ($isLong === false && isset($this->_shortLong[$opt])) {
  734.                 // Found a match in the short option names.
  735.                 $cmp $opt;
  736.                 $long $this->_shortLong[$opt];
  737.             elseif ($isLong === true && isset($this->_config[$opt])) {
  738.                 // Found a match in the long option names.
  739.                 $long $cmp $opt;
  740.             elseif ($isLong === true && isset($this->_aliasLong[$opt])) {
  741.                 // Found a match in the long option names.
  742.                 $long $this->_aliasLong[$opt];
  743.                 $cmp $opt;
  744.             }
  745.             if ($arg{$i=== '='{
  746.                 // End of the option name when '=' is found.
  747.                 break;
  748.             }
  749.         }
  750.  
  751.         // If no option name is found, assume -- was passed.
  752.         if ($opt == ''{
  753.             $long CONSOLE_GETARGS_PARAMS;
  754.         }
  755.         
  756.         if (isset($long)) {
  757.             // A match was found.
  758.             if (strlen($argstrlen($cmp)) {
  759.                 // Seperate the argument from the option.
  760.                 // Ex: php test.php -f=image.png
  761.                 //     $cmp = 'f'
  762.                 //     $arg = 'f=image.png'
  763.                 $arg substr($argstrlen($cmp));
  764.                 // Now $arg = '=image.png'
  765.                 if ($arg{0=== '='{
  766.                     $arg substr($arg1);
  767.                     // Now $arg = 'image.png'
  768.                 }
  769.             else {
  770.                 // No argument passed for option.
  771.                 $arg '';
  772.             }
  773.             // Set the options value.
  774.             return $this->setValue($long$arg$pos);
  775.         }
  776.         return PEAR::raiseError('Unknown argument '.$opt,
  777.                                 CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  778.                                 null'Console_Getargs_Options::parseArg()');
  779.     }
  780.     
  781.     /**
  782.      * Set the option arguments
  783.      * @access private
  784.      * @throws CONSOLE_GETARGS_ERROR_CONFIG
  785.      * @throws CONSOLE_GETARGS_ERROR_USER
  786.      * @return true|PEAR_Error
  787.      */
  788.     function setValue($optname$value&$pos)
  789.     {
  790.         if (!isset($this->_config[$optname]['max'])) {
  791.             // Max must be set for every option even if it is zero or -1.
  792.             return PEAR::raiseError('No max parameter set for '.$optname,
  793.                                     CONSOLE_GETARGS_ERROR_CONFIGPEAR_ERROR_TRIGGER,
  794.                                     E_USER_WARNING'Console_Getargs_Options::setValue()');
  795.         }
  796.         
  797.         $max = (int)$this->_config[$optname]['max'];
  798.         $min = isset($this->_config[$optname]['min']? (int)$this->_config[$optname]['min']$max;
  799.  
  800.         // A value was passed after the option.
  801.         if ($value !== ''{
  802.             // Argument is like -v5
  803.             if ($min == 1 && $max > 0{
  804.                 // At least one argument is required for option.
  805.                 $this->updateValue($optname$value);
  806.                 return true;
  807.             }
  808.             if ($max === 0{
  809.                 // Argument passed but not expected.
  810.                 return PEAR::raiseError('Argument '.$optname.' does not take any value',
  811.                                         CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  812.                                         null'Console_Getargs_Options::setValue()');
  813.             }
  814.             // Not enough arguments passed for this option.
  815.             return PEAR::raiseError('Argument '.$optname.' expects more than one value',
  816.                                     CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  817.                                     null'Console_Getargs_Options::setValue()');
  818.         }
  819.         
  820.         if ($min === 1 && $max === 1{
  821.             // Argument requires 1 value
  822.             // If optname is "parameters" take a step back.
  823.             if ($optname == CONSOLE_GETARGS_PARAMS{
  824.                 $pos--;
  825.             }
  826.             if (isset($this->args[$pos+1]&& $this->isValue($this->args[$pos+1])) {
  827.                 // Set the option value and increment the position.
  828.                 $this->updateValue($optname$this->args[$pos+1]);
  829.                 $pos++;
  830.                 return true;
  831.             }
  832.             // What we thought was the argument was really the next option.
  833.             return PEAR::raiseError('Argument '.$optname.' expects one value',
  834.                                     CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  835.                                     null'Console_Getargs_Options::setValue()');
  836.             
  837.         else if ($max === 0{
  838.             // Argument is a switch
  839.             if (isset($this->args[$pos+1]&& $this->isValue($this->args[$pos+1])) {
  840.                 // What we thought was the next option was really an argument for this option.
  841.                 // First update the value
  842.                 $this->updateValue($optnametrue);                
  843.                 // Then try to assign values to parameters.
  844.                 if (isset($this->_config[CONSOLE_GETARGS_PARAMS])) {
  845.                     return $this->setValue(CONSOLE_GETARGS_PARAMS''++$pos);
  846.                 else {
  847.                     return PEAR::raiseError('Argument '.$optname.' does not take any value',
  848.                                             CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  849.                                             null'Console_Getargs_Options::setValue()');
  850.                 }
  851.             }
  852.             // Set the switch to on.
  853.             $this->updateValue($optnametrue);
  854.             return true;
  855.             
  856.         else if ($max >= 1 && $min === 0{
  857.             // Argument has a default-if-set value
  858.             if (!isset($this->_config[$optname]['default'])) {
  859.                 // A default value MUST be assigned when config is loaded.
  860.                 return PEAR::raiseError('No default value defined for '.$optname,
  861.                                         CONSOLE_GETARGS_ERROR_CONFIGPEAR_ERROR_TRIGGER,
  862.                                         E_USER_WARNING'Console_Getargs_Options::setValue()');
  863.             }
  864.             if (is_array($this->_config[$optname]['default'])) {
  865.                 // Default value cannot be an array.
  866.                 return PEAR::raiseError('Default value for '.$optname.' must be scalar',
  867.                                         CONSOLE_GETARGS_ERROR_CONFIGPEAR_ERROR_TRIGGER,
  868.                                         E_USER_WARNING'Console_Getargs_Options::setValue()');
  869.             }
  870.             
  871.             // If optname is "parameters" take a step back.
  872.             if ($optname == CONSOLE_GETARGS_PARAMS{
  873.                 $pos--;
  874.             }
  875.             
  876.             if (isset($this->args[$pos+1]&& $this->isValue($this->args[$pos+1])) {
  877.                 // Assign the option the value from the command line if there is one.
  878.                 $this->updateValue($optname$this->args[$pos+1]);
  879.                 $pos++;
  880.                 return true;
  881.             }
  882.             // Otherwise use the default value.
  883.             $this->updateValue($optname$this->_config[$optname]['default']);
  884.             return true;
  885.         }
  886.         
  887.         // Argument takes one or more values
  888.         $added = 0;
  889.         // If trying to assign values to parameters, must go back one position.
  890.         if ($optname == CONSOLE_GETARGS_PARAMS{
  891.             $pos max($pos - 1-1);
  892.         }
  893.         for ($i $pos + 1; $i <= count($this->args)$i++{
  894.             $paramFull $max <= count($this->getValue($optname)) && $max != -1;
  895.             if (isset($this->args[$i]&& $this->isValue($this->args[$i]&& !$paramFull{
  896.                 // Add the argument value until the next option is hit.
  897.                 $this->updateValue($optname$this->args[$i]);
  898.                 $added++;
  899.                 $pos++;
  900.                 // Only keep trying if we haven't filled up yet.
  901.                 // or there is no limit
  902.                 if (($added $max || $max < 0&& ($max < 0 || !$paramFull)) {
  903.                     continue;
  904.                 }
  905.             }
  906.             if ($min $added && !$paramFull{
  907.                 // There aren't enough arguments for this option.
  908.                 return PEAR::raiseError('Argument '.$optname.' expects at least '.$min.(($min > 1' values' ' value'),
  909.                                         CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  910.                                         null'Console_Getargs_Options::setValue()');
  911.             elseif ($max !== -1 && $paramFull{
  912.                 // Too many arguments for this option.
  913.                 // Try to add the extra options to parameters.
  914.                 if (isset($this->_config[CONSOLE_GETARGS_PARAMS]&& $optname != CONSOLE_GETARGS_PARAMS{
  915.                     return $this->setValue(CONSOLE_GETARGS_PARAMS''++$pos);
  916.                 elseif ($optname == CONSOLE_GETARGS_PARAMS && empty($this->args[$i])) {
  917.                     $pos += $added;
  918.                     break;
  919.                 else {
  920.                     return PEAR::raiseError('Argument '.$optname.' expects maximum '.$max.' values',
  921.                                             CONSOLE_GETARGS_ERROR_USERPEAR_ERROR_RETURN,
  922.                                             null'Console_Getargs_Options::setValue()');
  923.                 }
  924.             }
  925.             break;
  926.         }
  927.         // Everything went well.
  928.         return true;
  929.     }
  930.     
  931.     /**
  932.      * Checks whether the given parameter is an argument or an option
  933.      * @access private
  934.      * @return boolean 
  935.      */
  936.     function isValue($arg)
  937.     {
  938.         if ((strlen($arg> 1 && $arg{0== '-' && $arg{1== '-'||
  939.             (strlen($arg> 1 && $arg{0== '-')) {
  940.             // The next argument is really an option.
  941.             return false;
  942.         }
  943.         return true;
  944.     }
  945.     
  946.     /**
  947.      * Adds the argument to the option
  948.      *
  949.      * If the argument for the option is already set,
  950.      * the option arguments will be changed to an array
  951.      * @access private
  952.      * @return void 
  953.      */
  954.     function updateValue($optname$value)
  955.     {
  956.         if (isset($this->_longLong[$optname])) {
  957.             if (is_array($this->_longLong[$optname])) {
  958.                 // Add this value to the list of values for this option.
  959.                 $this->_longLong[$optname][$value;
  960.             else {
  961.                 // There is already one value set. Turn everything into a list of values.
  962.                 $prevValue $this->_longLong[$optname];
  963.                 $this->_longLong[$optname= array($prevValue);
  964.                 $this->_longLong[$optname][$value;
  965.             }
  966.         else {
  967.             // This is the first value for this option.
  968.             $this->_longLong[$optname$value;
  969.         }
  970.     }
  971.     
  972.     /**
  973.      * Sets the option default arguments when necessary
  974.      * @access private
  975.      * @return true 
  976.      */
  977.     function setDefaults()
  978.     {
  979.         foreach ($this->_config as $longname => $def{
  980.             // Add the default value only if the default is defined 
  981.             // and the option requires at least one argument.
  982.             if (isset($def['default']&& 
  983.                 ((isset($def['min']&& $def['min'!== 0||
  984.                 (!isset($def['min']isset($def['max']&& $def['max'!== 0)) &&
  985.                 !isset($this->_longLong[$longname])) {
  986.                 $this->_longLong[$longname$def['default'];
  987.             }
  988.         }
  989.         return true;
  990.     }
  991.     
  992.     /**
  993.      * Checks whether the given option is defined
  994.      *
  995.      * An option will be defined if an argument was assigned to it using
  996.      * the command line options. You can use the short, the long or
  997.      * an alias name as parameter.
  998.      *
  999.      * @access public
  1000.      * @param  string the name of the option to be checked
  1001.      * @return boolean true if the option is defined
  1002.      */
  1003.     function isDefined($optname)
  1004.     {
  1005.         $longname $this->getLongName($optname);
  1006.         if (isset($this->_longLong[$longname])) {
  1007.             return true;
  1008.         }
  1009.         return false;
  1010.     }
  1011.     
  1012.     /**
  1013.      * Returns the long version of the given parameter
  1014.      *
  1015.      * If the given name is not found, it will return the name that
  1016.      * was given, without further ensuring that the option
  1017.      * actually exists
  1018.      *
  1019.      * @access private
  1020.      * @param  string the name of the option
  1021.      * @return string long version of the option name
  1022.      */
  1023.     function getLongName($optname)
  1024.     {
  1025.         if (isset($this->_shortLong[$optname])) {
  1026.             // Short version was passed.
  1027.             $longname $this->_shortLong[$optname];
  1028.         else if (isset($this->_aliasLong[$optname])) {
  1029.             // An alias was passed.
  1030.             $longname $this->_aliasLong[$optname];
  1031.         else {
  1032.             // No further validation is done.
  1033.             $longname $optname;
  1034.         }
  1035.         return $longname;
  1036.     }
  1037.     
  1038.     /**
  1039.      * Returns the argument of the given option
  1040.      *
  1041.      * You can use the short, alias or long version of the option name.
  1042.      * This method will try to find the argument(s) of the given option name.
  1043.      * If it is not found it will return null. If the arg has more than
  1044.      * one argument, an array of arguments will be returned.
  1045.      *
  1046.      * @access public
  1047.      * @param  string the name of the option
  1048.      * @return array|string|nullargument(s) associated with the option
  1049.      */
  1050.     function getValue($optname)
  1051.     {
  1052.         if ($this->isDefined($optname)) {
  1053.             // Option is defined. Return its value
  1054.             $longname $this->getLongName($optname);
  1055.             return $this->_longLong[$longname];
  1056.         }
  1057.         // Option is not defined.
  1058.         return null;
  1059.     }
  1060.  
  1061.     /**
  1062.      * Returns all arguments that have been parsed and recognized
  1063.      *
  1064.      * The name of the options are stored in the keys of the array.
  1065.      * You may choose whether you want to use the long or the short
  1066.      * option names
  1067.      *
  1068.      * @access public
  1069.      * @param  string   option names to use for the keys (long or short)
  1070.      * @return array    values for all options
  1071.      */
  1072.     function getValues($optionNames 'long')
  1073.     {
  1074.         switch ($optionNames{
  1075.             case 'short':
  1076.                 $values = array();
  1077.                 foreach ($this->_shortLong as $short => $long{
  1078.                     if (isset($this->_longLong[$long])) {
  1079.                         $values[$short$this->_longLong[$long];
  1080.                     }
  1081.                 }
  1082.                 if (isset($this->_longLong['parameters'])) {
  1083.                     $values['parameters'$this->_longLong['parameters'];
  1084.                 }
  1085.                 return $values;
  1086.             case 'long':
  1087.             default:
  1088.                 return $this->_longLong;
  1089.         }
  1090.     }
  1091.  
  1092.     function checkRequired()
  1093.     {
  1094.         foreach ($this->_config as $optName => $opt{
  1095.             if (isset($opt['min']&& $opt['min'== 1 &&
  1096.                 $this->getValue($optName=== null
  1097.                 {
  1098.                 $err = PEAR::raiseError($optName ' is required'
  1099.                                         CONSOLE_GETARGS_ERROR_USER,
  1100.                                         PEAR_ERROR_RETURNnull,
  1101.                                         'Console_Getargs_Options::parseArgs()'
  1102.                                         );
  1103.                 return $err;
  1104.             }
  1105.         }        
  1106.         return true;
  1107.     }
  1108. // end class Console_Getargs_Options
  1109. /*
  1110.  * Local variables:
  1111.  * tab-width: 4
  1112.  * c-basic-offset: 4
  1113.  * End:
  1114.  */
  1115. ?>

Documentation generated on Mon, 11 Mar 2019 14:48:46 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.