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

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