File indexing completed on 2024-05-12 06:02:21

0001 <?php
0002 /**
0003  * Zend_Console_Getopt is a class to parse options for command-line
0004  * applications.
0005  *
0006  * LICENSE
0007  *
0008  * This source file is subject to the new BSD license that is bundled
0009  * with this package in the file LICENSE.txt.
0010  * It is also available through the world-wide-web at this URL:
0011  * http://framework.zend.com/license/new-bsd
0012  * If you did not receive a copy of the license and are unable to
0013  * obtain it through the world-wide-web, please send an email
0014  * to license@zend.com so we can send you a copy immediately.
0015  *
0016  * @category   Zend
0017  * @package    Zend_Console_Getopt
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * Zend_Console_Getopt is a class to parse options for command-line
0025  * applications.
0026  *
0027  * Terminology:
0028  * Argument: an element of the argv array.  This may be part of an option,
0029  *   or it may be a non-option command-line argument.
0030  * Flag: the letter or word set off by a '-' or '--'.  Example: in '--output filename',
0031  *   '--output' is the flag.
0032  * Parameter: the additional argument that is associated with the option.
0033  *   Example: in '--output filename', the 'filename' is the parameter.
0034  * Option: the combination of a flag and its parameter, if any.
0035  *   Example: in '--output filename', the whole thing is the option.
0036  *
0037  * The following features are supported:
0038  *
0039  * - Short flags like '-a'.  Short flags are preceded by a single
0040  *   dash.  Short flags may be clustered e.g. '-abc', which is the
0041  *   same as '-a' '-b' '-c'.
0042  * - Long flags like '--verbose'.  Long flags are preceded by a
0043  *   double dash.  Long flags may not be clustered.
0044  * - Options may have a parameter, e.g. '--output filename'.
0045  * - Parameters for long flags may also be set off with an equals sign,
0046  *   e.g. '--output=filename'.
0047  * - Parameters for long flags may be checked as string, word, or integer.
0048  * - Automatic generation of a helpful usage message.
0049  * - Signal end of options with '--'; subsequent arguments are treated
0050  *   as non-option arguments, even if they begin with '-'.
0051  * - Raise exception Zend_Console_Getopt_Exception in several cases
0052  *   when invalid flags or parameters are given.  Usage message is
0053  *   returned in the exception object.
0054  *
0055  * The format for specifying options uses a PHP associative array.
0056  * The key is has the format of a list of pipe-separated flag names,
0057  * followed by an optional '=' to indicate a required parameter or
0058  * '-' to indicate an optional parameter.  Following that, the type
0059  * of parameter may be specified as 's' for string, 'w' for word,
0060  * or 'i' for integer.
0061  *
0062  * Examples:
0063  * - 'user|username|u=s'  this means '--user' or '--username' or '-u'
0064  *   are synonyms, and the option requires a string parameter.
0065  * - 'p=i'  this means '-p' requires an integer parameter.  No synonyms.
0066  * - 'verbose|v-i'  this means '--verbose' or '-v' are synonyms, and
0067  *   they take an optional integer parameter.
0068  * - 'help|h'  this means '--help' or '-h' are synonyms, and
0069  *   they take no parameter.
0070  *
0071  * The values in the associative array are strings that are used as
0072  * brief descriptions of the options when printing a usage message.
0073  *
0074  * The simpler format for specifying options used by PHP's getopt()
0075  * function is also supported.  This is similar to GNU getopt and shell
0076  * getopt format.
0077  *
0078  * Example:  'abc:' means options '-a', '-b', and '-c'
0079  * are legal, and the latter requires a string parameter.
0080  *
0081  * @category   Zend
0082  * @package    Zend_Console_Getopt
0083  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0084  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0085  * @version    Release: @package_version@
0086  * @since      Class available since Release 0.6.0
0087  *
0088  * @todo  Handle params with multiple values, e.g. --colors=red,green,blue
0089  *        Set value of parameter to the array of values.  Allow user to specify
0090  *        the separator with Zend_Console_Getopt::CONFIG_PARAMETER_SEPARATOR.
0091  *        If this config value is null or empty string, do not split values
0092  *        into arrays.  Default separator is comma (',').
0093  *
0094  * @todo  Handle params with multiple values specified with separate options
0095  *        e.g. --colors red --colors green --colors blue should give one
0096  *        option with an array(red, green, blue).
0097  *        Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_PARAMETERS.
0098  *        Default is that subsequent options overwrite the parameter value.
0099  *
0100  * @todo  Handle flags occurring multiple times, e.g. -v -v -v
0101  *        Set value of the option's parameter to the integer count of instances
0102  *        instead of a boolean.
0103  *        Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_FLAGS.
0104  *        Default is that the value is simply boolean true regardless of
0105  *        how many instances of the flag appear.
0106  *
0107  * @todo  Handle flags that implicitly print usage message, e.g. --help
0108  *
0109  * @todo  Handle freeform options, e.g. --set-variable
0110  *        Enable with Zend_Console_Getopt::CONFIG_FREEFORM_FLAGS
0111  *        All flag-like syntax is recognized, no flag generates an exception.
0112  *
0113  * @todo  Handle numeric options, e.g. -1, -2, -3, -1000
0114  *        Enable with Zend_Console_Getopt::CONFIG_NUMERIC_FLAGS
0115  *        The rule must specify a named flag and the '#' symbol as the
0116  *        parameter type. e.g.,  'lines=#'
0117  *
0118  * @todo  Enable user to specify header and footer content in the help message.
0119  *
0120  * @todo  Feature request to handle option interdependencies.
0121  *        e.g. if -b is specified, -a must be specified or else the
0122  *        usage is invalid.
0123  *
0124  * @todo  Feature request to implement callbacks.
0125  *        e.g. if -a is specified, run function 'handleOptionA'().
0126  */
0127 class Zend_Console_Getopt
0128 {
0129 
0130     /**
0131      * The options for a given application can be in multiple formats.
0132      * modeGnu is for traditional 'ab:c:' style getopt format.
0133      * modeZend is for a more structured format.
0134      */
0135     const MODE_ZEND                         = 'zend';
0136     const MODE_GNU                          = 'gnu';
0137 
0138     /**
0139      * Constant tokens for various symbols used in the mode_zend
0140      * rule format.
0141      */
0142     const PARAM_REQUIRED                    = '=';
0143     const PARAM_OPTIONAL                    = '-';
0144     const TYPE_STRING                       = 's';
0145     const TYPE_WORD                         = 'w';
0146     const TYPE_INTEGER                      = 'i';
0147 
0148     /**
0149      * These are constants for optional behavior of this class.
0150      * ruleMode is either 'zend' or 'gnu' or a user-defined mode.
0151      * dashDash is true if '--' signifies the end of command-line options.
0152      * ignoreCase is true if '--opt' and '--OPT' are implicitly synonyms.
0153      * parseAll is true if all options on the command line should be parsed, regardless of
0154      * whether an argument appears before them.
0155      */
0156     const CONFIG_RULEMODE                   = 'ruleMode';
0157     const CONFIG_DASHDASH                   = 'dashDash';
0158     const CONFIG_IGNORECASE                 = 'ignoreCase';
0159     const CONFIG_PARSEALL                   = 'parseAll';
0160 
0161     /**
0162      * Defaults for getopt configuration are:
0163      * ruleMode is 'zend' format,
0164      * dashDash (--) token is enabled,
0165      * ignoreCase is not enabled,
0166      * parseAll is enabled.
0167      */
0168     protected $_getoptConfig = array(
0169         self::CONFIG_RULEMODE   => self::MODE_ZEND,
0170         self::CONFIG_DASHDASH   => true,
0171         self::CONFIG_IGNORECASE => false,
0172         self::CONFIG_PARSEALL   => true,
0173     );
0174 
0175     /**
0176      * Stores the command-line arguments for the calling application.
0177      *
0178      * @var array
0179      */
0180     protected $_argv = array();
0181 
0182     /**
0183      * Stores the name of the calling application.
0184      *
0185      * @var string
0186      */
0187     protected $_progname = '';
0188 
0189     /**
0190      * Stores the list of legal options for this application.
0191      *
0192      * @var array
0193      */
0194     protected $_rules = array();
0195 
0196     /**
0197      * Stores alternate spellings of legal options.
0198      *
0199      * @var array
0200      */
0201     protected $_ruleMap = array();
0202 
0203     /**
0204      * Stores options given by the user in the current invocation
0205      * of the application, as well as parameters given in options.
0206      *
0207      * @var array
0208      */
0209     protected $_options = array();
0210 
0211     /**
0212      * Stores the command-line arguments other than options.
0213      *
0214      * @var array
0215      */
0216     protected $_remainingArgs = array();
0217 
0218     /**
0219      * State of the options: parsed or not yet parsed?
0220      *
0221      * @var boolean
0222      */
0223     protected $_parsed = false;
0224 
0225     /**
0226      * The constructor takes one to three parameters.
0227      *
0228      * The first parameter is $rules, which may be a string for
0229      * gnu-style format, or a structured array for Zend-style format.
0230      *
0231      * The second parameter is $argv, and it is optional.  If not
0232      * specified, $argv is inferred from the global argv.
0233      *
0234      * The third parameter is an array of configuration parameters
0235      * to control the behavior of this instance of Getopt; it is optional.
0236      *
0237      * @param  array $rules
0238      * @param  array $argv
0239      * @param  array $getoptConfig
0240      * @return void
0241      */
0242     public function __construct($rules, $argv = null, $getoptConfig = array())
0243     {
0244         if (!isset($_SERVER['argv'])) {
0245             // require_once 'Zend/Console/Getopt/Exception.php';
0246             if (ini_get('register_argc_argv') == false) {
0247                 throw new Zend_Console_Getopt_Exception(
0248                     "argv is not available, because ini option 'register_argc_argv' is set Off"
0249                 );
0250             } else {
0251                 throw new Zend_Console_Getopt_Exception(
0252                     '$_SERVER["argv"] is not set, but Zend_Console_Getopt cannot work without this information.'
0253                 );
0254             }
0255         }
0256 
0257         $this->_progname = $_SERVER['argv'][0];
0258         $this->setOptions($getoptConfig);
0259         $this->addRules($rules);
0260         if (!is_array($argv)) {
0261             $argv = array_slice($_SERVER['argv'], 1);
0262         }
0263         if (isset($argv)) {
0264             $this->addArguments((array)$argv);
0265         }
0266     }
0267 
0268     /**
0269      * Return the state of the option seen on the command line of the
0270      * current application invocation.  This function returns true, or the
0271      * parameter to the option, if any.  If the option was not given,
0272      * this function returns null.
0273      *
0274      * The magic __get method works in the context of naming the option
0275      * as a virtual member of this class.
0276      *
0277      * @param  string $key
0278      * @return string
0279      */
0280     public function __get($key)
0281     {
0282         return $this->getOption($key);
0283     }
0284 
0285     /**
0286      * Test whether a given option has been seen.
0287      *
0288      * @param  string $key
0289      * @return boolean
0290      */
0291     public function __isset($key)
0292     {
0293         $this->parse();
0294         if (isset($this->_ruleMap[$key])) {
0295             $key = $this->_ruleMap[$key];
0296             return isset($this->_options[$key]);
0297         }
0298         return false;
0299     }
0300 
0301     /**
0302      * Set the value for a given option.
0303      *
0304      * @param  string $key
0305      * @param  string $value
0306      * @return void
0307      */
0308     public function __set($key, $value)
0309     {
0310         $this->parse();
0311         if (isset($this->_ruleMap[$key])) {
0312             $key = $this->_ruleMap[$key];
0313             $this->_options[$key] = $value;
0314         }
0315     }
0316 
0317     /**
0318      * Return the current set of options and parameters seen as a string.
0319      *
0320      * @return string
0321      */
0322     public function __toString()
0323     {
0324         return $this->toString();
0325     }
0326 
0327     /**
0328      * Unset an option.
0329      *
0330      * @param  string $key
0331      * @return void
0332      */
0333     public function __unset($key)
0334     {
0335         $this->parse();
0336         if (isset($this->_ruleMap[$key])) {
0337             $key = $this->_ruleMap[$key];
0338             unset($this->_options[$key]);
0339         }
0340     }
0341 
0342     /**
0343      * Define additional command-line arguments.
0344      * These are appended to those defined when the constructor was called.
0345      *
0346      * @param  array $argv
0347      * @throws Zend_Console_Getopt_Exception When not given an array as parameter
0348      * @return Zend_Console_Getopt Provides a fluent interface
0349      */
0350     public function addArguments($argv)
0351     {
0352         if(!is_array($argv)) {
0353             // require_once 'Zend/Console/Getopt/Exception.php';
0354             throw new Zend_Console_Getopt_Exception(
0355                 "Parameter #1 to addArguments should be an array");
0356         }
0357         $this->_argv = array_merge($this->_argv, $argv);
0358         $this->_parsed = false;
0359         return $this;
0360     }
0361 
0362     /**
0363      * Define full set of command-line arguments.
0364      * These replace any currently defined.
0365      *
0366      * @param  array $argv
0367      * @throws Zend_Console_Getopt_Exception When not given an array as parameter
0368      * @return Zend_Console_Getopt Provides a fluent interface
0369      */
0370     public function setArguments($argv)
0371     {
0372         if(!is_array($argv)) {
0373             // require_once 'Zend/Console/Getopt/Exception.php';
0374             throw new Zend_Console_Getopt_Exception(
0375                 "Parameter #1 to setArguments should be an array");
0376         }
0377         $this->_argv = $argv;
0378         $this->_parsed = false;
0379         return $this;
0380     }
0381 
0382     /**
0383      * Define multiple configuration options from an associative array.
0384      * These are not program options, but properties to configure
0385      * the behavior of Zend_Console_Getopt.
0386      *
0387      * @param  array $getoptConfig
0388      * @return Zend_Console_Getopt Provides a fluent interface
0389      */
0390     public function setOptions($getoptConfig)
0391     {
0392         if (isset($getoptConfig)) {
0393             foreach ($getoptConfig as $key => $value) {
0394                 $this->setOption($key, $value);
0395             }
0396         }
0397         return $this;
0398     }
0399 
0400     /**
0401      * Define one configuration option as a key/value pair.
0402      * These are not program options, but properties to configure
0403      * the behavior of Zend_Console_Getopt.
0404      *
0405      * @param  string $configKey
0406      * @param  string $configValue
0407      * @return Zend_Console_Getopt Provides a fluent interface
0408      */
0409     public function setOption($configKey, $configValue)
0410     {
0411         if ($configKey !== null) {
0412             $this->_getoptConfig[$configKey] = $configValue;
0413         }
0414         return $this;
0415     }
0416 
0417     /**
0418      * Define additional option rules.
0419      * These are appended to the rules defined when the constructor was called.
0420      *
0421      * @param  array $rules
0422      * @return Zend_Console_Getopt Provides a fluent interface
0423      */
0424     public function addRules($rules)
0425     {
0426         $ruleMode = $this->_getoptConfig['ruleMode'];
0427         switch ($this->_getoptConfig['ruleMode']) {
0428             case self::MODE_ZEND:
0429                 if (is_array($rules)) {
0430                     $this->_addRulesModeZend($rules);
0431                     break;
0432                 }
0433                 // intentional fallthrough
0434             case self::MODE_GNU:
0435                 $this->_addRulesModeGnu($rules);
0436                 break;
0437             default:
0438                 /**
0439                  * Call addRulesModeFoo() for ruleMode 'foo'.
0440                  * The developer should subclass Getopt and
0441                  * provide this method.
0442                  */
0443                 $method = '_addRulesMode' . ucfirst($ruleMode);
0444                 $this->$method($rules);
0445         }
0446         $this->_parsed = false;
0447         return $this;
0448     }
0449 
0450     /**
0451      * Return the current set of options and parameters seen as a string.
0452      *
0453      * @return string
0454      */
0455     public function toString()
0456     {
0457         $this->parse();
0458         $s = array();
0459         foreach ($this->_options as $flag => $value) {
0460             $s[] = $flag . '=' . ($value === true ? 'true' : $value);
0461         }
0462         return implode(' ', $s);
0463     }
0464 
0465     /**
0466      * Return the current set of options and parameters seen
0467      * as an array of canonical options and parameters.
0468      *
0469      * Clusters have been expanded, and option aliases
0470      * have been mapped to their primary option names.
0471      *
0472      * @return array
0473      */
0474     public function toArray()
0475     {
0476         $this->parse();
0477         $s = array();
0478         foreach ($this->_options as $flag => $value) {
0479             $s[] = $flag;
0480             if ($value !== true) {
0481                 $s[] = $value;
0482             }
0483         }
0484         return $s;
0485     }
0486 
0487     /**
0488      * Return the current set of options and parameters seen in Json format.
0489      *
0490      * @return string
0491      */
0492     public function toJson()
0493     {
0494         $this->parse();
0495         $j = array();
0496         foreach ($this->_options as $flag => $value) {
0497             $j['options'][] = array(
0498                 'option' => array(
0499                     'flag' => $flag,
0500                     'parameter' => $value
0501                 )
0502             );
0503         }
0504 
0505         /**
0506          * @see Zend_Json
0507          */
0508         // require_once 'Zend/Json.php';
0509         $json = Zend_Json::encode($j);
0510 
0511         return $json;
0512     }
0513 
0514     /**
0515      * Return the current set of options and parameters seen in XML format.
0516      *
0517      * @return string
0518      */
0519     public function toXml()
0520     {
0521         $this->parse();
0522         $doc = new DomDocument('1.0', 'utf-8');
0523         $optionsNode = $doc->createElement('options');
0524         $doc->appendChild($optionsNode);
0525         foreach ($this->_options as $flag => $value) {
0526             $optionNode = $doc->createElement('option');
0527             $optionNode->setAttribute('flag', utf8_encode($flag));
0528             if ($value !== true) {
0529                 $optionNode->setAttribute('parameter', utf8_encode($value));
0530             }
0531             $optionsNode->appendChild($optionNode);
0532         }
0533         $xml = $doc->saveXML();
0534         return $xml;
0535     }
0536 
0537     /**
0538      * Return a list of options that have been seen in the current argv.
0539      *
0540      * @return array
0541      */
0542     public function getOptions()
0543     {
0544         $this->parse();
0545         return array_keys($this->_options);
0546     }
0547 
0548     /**
0549      * Return the state of the option seen on the command line of the
0550      * current application invocation.
0551      *
0552      * This function returns true, or the parameter value to the option, if any.
0553      * If the option was not given, this function returns null.
0554      *
0555      * @param  string $flag
0556      * @return mixed
0557      */
0558     public function getOption($flag)
0559     {
0560         $this->parse();
0561         if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
0562             $flag = strtolower($flag);
0563         }
0564         if (isset($this->_ruleMap[$flag])) {
0565             $flag = $this->_ruleMap[$flag];
0566             if (isset($this->_options[$flag])) {
0567                 return $this->_options[$flag];
0568             }
0569         }
0570         return null;
0571     }
0572 
0573     /**
0574      * Return the arguments from the command-line following all options found.
0575      *
0576      * @return array
0577      */
0578     public function getRemainingArgs()
0579     {
0580         $this->parse();
0581         return $this->_remainingArgs;
0582     }
0583 
0584     /**
0585      * Return a useful option reference, formatted for display in an
0586      * error message.
0587      *
0588      * Note that this usage information is provided in most Exceptions
0589      * generated by this class.
0590      *
0591      * @return string
0592      */
0593     public function getUsageMessage()
0594     {
0595         $usage = "Usage: {$this->_progname} [ options ]\n";
0596         $maxLen = 20;
0597         $lines = array();
0598         foreach ($this->_rules as $rule) {
0599             $flags = array();
0600             if (is_array($rule['alias'])) {
0601                 foreach ($rule['alias'] as $flag) {
0602                     $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag;
0603                 }
0604             }
0605             $linepart['name'] = implode('|', $flags);
0606             if (isset($rule['param']) && $rule['param'] != 'none') {
0607                 $linepart['name'] .= ' ';
0608                 switch ($rule['param']) {
0609                     case 'optional':
0610                         $linepart['name'] .= "[ <{$rule['paramType']}> ]";
0611                         break;
0612                     case 'required':
0613                         $linepart['name'] .= "<{$rule['paramType']}>";
0614                         break;
0615                 }
0616             }
0617             if (strlen($linepart['name']) > $maxLen) {
0618                 $maxLen = strlen($linepart['name']);
0619             }
0620             $linepart['help'] = '';
0621             if (isset($rule['help'])) {
0622                 $linepart['help'] .= $rule['help'];
0623             }
0624             $lines[] = $linepart;
0625         }
0626         foreach ($lines as $linepart) {
0627             $usage .= sprintf("%s %s\n",
0628             str_pad($linepart['name'], $maxLen),
0629             $linepart['help']);
0630         }
0631         return $usage;
0632     }
0633 
0634     /**
0635      * Define aliases for options.
0636      *
0637      * The parameter $aliasMap is an associative array
0638      * mapping option name (short or long) to an alias.
0639      *
0640      * @param  array $aliasMap
0641      * @throws Zend_Console_Getopt_Exception
0642      * @return Zend_Console_Getopt Provides a fluent interface
0643      */
0644     public function setAliases($aliasMap)
0645     {
0646         foreach ($aliasMap as $flag => $alias)
0647         {
0648             if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
0649                 $flag = strtolower($flag);
0650                 $alias = strtolower($alias);
0651             }
0652             if (!isset($this->_ruleMap[$flag])) {
0653                 continue;
0654             }
0655             $flag = $this->_ruleMap[$flag];
0656             if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) {
0657                 $o = (strlen($alias) == 1 ? '-' : '--') . $alias;
0658                 // require_once 'Zend/Console/Getopt/Exception.php';
0659                 throw new Zend_Console_Getopt_Exception(
0660                     "Option \"$o\" is being defined more than once.");
0661             }
0662             $this->_rules[$flag]['alias'][] = $alias;
0663             $this->_ruleMap[$alias] = $flag;
0664         }
0665         return $this;
0666     }
0667 
0668     /**
0669      * Define help messages for options.
0670      *
0671      * The parameter $help_map is an associative array
0672      * mapping option name (short or long) to the help string.
0673      *
0674      * @param  array $helpMap
0675      * @return Zend_Console_Getopt Provides a fluent interface
0676      */
0677     public function setHelp($helpMap)
0678     {
0679         foreach ($helpMap as $flag => $help)
0680         {
0681             if (!isset($this->_ruleMap[$flag])) {
0682                 continue;
0683             }
0684             $flag = $this->_ruleMap[$flag];
0685             $this->_rules[$flag]['help'] = $help;
0686         }
0687         return $this;
0688     }
0689 
0690     /**
0691      * Parse command-line arguments and find both long and short
0692      * options.
0693      *
0694      * Also find option parameters, and remaining arguments after
0695      * all options have been parsed.
0696      *
0697      * @return Zend_Console_Getopt|null Provides a fluent interface
0698      */
0699     public function parse()
0700     {
0701         if ($this->_parsed === true) {
0702             return;
0703         }
0704         $argv = $this->_argv;
0705         $this->_options = array();
0706         $this->_remainingArgs = array();
0707         while (count($argv) > 0) {
0708             if ($argv[0] == '--') {
0709                 array_shift($argv);
0710                 if ($this->_getoptConfig[self::CONFIG_DASHDASH]) {
0711                     $this->_remainingArgs = array_merge($this->_remainingArgs, $argv);
0712                     break;
0713                 }
0714             }
0715             if (substr($argv[0], 0, 2) == '--') {
0716                 $this->_parseLongOption($argv);
0717             } else if (substr($argv[0], 0, 1) == '-' && ('-' != $argv[0] || count($argv) >1))  {
0718                 $this->_parseShortOptionCluster($argv);
0719             } else if($this->_getoptConfig[self::CONFIG_PARSEALL]) {
0720                 $this->_remainingArgs[] = array_shift($argv);
0721             } else {
0722                 /*
0723                  * We should put all other arguments in _remainingArgs and stop parsing
0724                  * since CONFIG_PARSEALL is false.
0725                  */
0726                 $this->_remainingArgs = array_merge($this->_remainingArgs, $argv);
0727                 break;
0728             }
0729         }
0730         $this->_parsed = true;
0731         return $this;
0732     }
0733 
0734     /**
0735      * @throws Zend_Console_Getopt_Exception
0736      */
0737     public function checkRequiredArguments()
0738     {
0739         foreach ($this->_rules as $name => $rule) {
0740             if ($rule['param'] === 'required') {
0741                 $defined = false;
0742                 foreach ($rule['alias'] as $alias) {
0743                     $defined = $defined === true ? true : array_key_exists($alias, $this->_options);
0744                 }
0745                 if ($defined === false) {
0746                     // require_once 'Zend/Console/Getopt/Exception.php';
0747                     throw new Zend_Console_Getopt_Exception(
0748                         'Option "$alias" requires a parameter.',
0749                         $this->getUsageMessage()
0750                     );
0751                 }
0752             }
0753         }
0754     }
0755 
0756     /**
0757      * Parse command-line arguments for a single long option.
0758      * A long option is preceded by a double '--' character.
0759      * Long options may not be clustered.
0760      *
0761      * @param  mixed &$argv
0762      * @return void
0763      */
0764     protected function _parseLongOption(&$argv)
0765     {
0766         $optionWithParam = ltrim(array_shift($argv), '-');
0767         $l = explode('=', $optionWithParam, 2);
0768         $flag = array_shift($l);
0769         $param = array_shift($l);
0770         if (isset($param)) {
0771             array_unshift($argv, $param);
0772         }
0773         $this->_parseSingleOption($flag, $argv);
0774     }
0775 
0776     /**
0777      * Parse command-line arguments for short options.
0778      * Short options are those preceded by a single '-' character.
0779      * Short options may be clustered.
0780      *
0781      * @param  mixed &$argv
0782      * @return void
0783      */
0784     protected function _parseShortOptionCluster(&$argv)
0785     {
0786         $flagCluster = ltrim(array_shift($argv), '-');
0787         foreach (str_split($flagCluster) as $flag) {
0788             $this->_parseSingleOption($flag, $argv);
0789         }
0790     }
0791 
0792     /**
0793      * Parse command-line arguments for a single option.
0794      *
0795      * @param  string $flag
0796      * @param  mixed  $argv
0797      * @throws Zend_Console_Getopt_Exception
0798      * @return void
0799      */
0800     protected function _parseSingleOption($flag, &$argv)
0801     {
0802         if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
0803             $flag = strtolower($flag);
0804         }
0805         if (!isset($this->_ruleMap[$flag])) {
0806             // require_once 'Zend/Console/Getopt/Exception.php';
0807             throw new Zend_Console_Getopt_Exception(
0808                 "Option \"$flag\" is not recognized.",
0809                 $this->getUsageMessage());
0810         }
0811         $realFlag = $this->_ruleMap[$flag];
0812         switch ($this->_rules[$realFlag]['param']) {
0813             case 'required':
0814                 if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
0815                     $param = array_shift($argv);
0816                     $this->_checkParameterType($realFlag, $param);
0817                 } else {
0818                     // require_once 'Zend/Console/Getopt/Exception.php';
0819                     throw new Zend_Console_Getopt_Exception(
0820                         "Option \"$flag\" requires a parameter.",
0821                         $this->getUsageMessage());
0822                 }
0823                 break;
0824             case 'optional':
0825                 if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
0826                     $param = array_shift($argv);
0827                     $this->_checkParameterType($realFlag, $param);
0828                 } else {
0829                     $param = true;
0830                 }
0831                 break;
0832             default:
0833                 $param = true;
0834         }
0835         $this->_options[$realFlag] = $param;
0836     }
0837 
0838     /**
0839      * Return true if the parameter is in a valid format for
0840      * the option $flag.
0841      * Throw an exception in most other cases.
0842      *
0843      * @param  string $flag
0844      * @param  string $param
0845      * @throws Zend_Console_Getopt_Exception
0846      * @return bool
0847      */
0848     protected function _checkParameterType($flag, $param)
0849     {
0850         $type = 'string';
0851         if (isset($this->_rules[$flag]['paramType'])) {
0852             $type = $this->_rules[$flag]['paramType'];
0853         }
0854         switch ($type) {
0855             case 'word':
0856                 if (preg_match('/\W/', $param)) {
0857                     // require_once 'Zend/Console/Getopt/Exception.php';
0858                     throw new Zend_Console_Getopt_Exception(
0859                         "Option \"$flag\" requires a single-word parameter, but was given \"$param\".",
0860                         $this->getUsageMessage());
0861                 }
0862                 break;
0863             case 'integer':
0864                 if (preg_match('/\D/', $param)) {
0865                     // require_once 'Zend/Console/Getopt/Exception.php';
0866                     throw new Zend_Console_Getopt_Exception(
0867                         "Option \"$flag\" requires an integer parameter, but was given \"$param\".",
0868                         $this->getUsageMessage());
0869                 }
0870                 break;
0871             case 'string':
0872             default:
0873                 break;
0874         }
0875         return true;
0876     }
0877 
0878     /**
0879      * Define legal options using the gnu-style format.
0880      *
0881      * @param  string $rules
0882      * @return void
0883      */
0884     protected function _addRulesModeGnu($rules)
0885     {
0886         $ruleArray = array();
0887 
0888         /**
0889          * Options may be single alphanumeric characters.
0890          * Options may have a ':' which indicates a required string parameter.
0891          * No long options or option aliases are supported in GNU style.
0892          */
0893         preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray);
0894         foreach ($ruleArray[1] as $rule) {
0895             $r = array();
0896             $flag = substr($rule, 0, 1);
0897             if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
0898                 $flag = strtolower($flag);
0899             }
0900             $r['alias'][] = $flag;
0901             if (substr($rule, 1, 1) == ':') {
0902                 $r['param'] = 'required';
0903                 $r['paramType'] = 'string';
0904             } else {
0905                 $r['param'] = 'none';
0906             }
0907             $this->_rules[$flag] = $r;
0908             $this->_ruleMap[$flag] = $flag;
0909         }
0910     }
0911 
0912     /**
0913      * Define legal options using the Zend-style format.
0914      *
0915      * @param  array $rules
0916      * @throws Zend_Console_Getopt_Exception
0917      * @return void
0918      */
0919     protected function _addRulesModeZend($rules)
0920     {
0921         foreach ($rules as $ruleCode => $helpMessage)
0922         {
0923             // this may have to translate the long parm type if there
0924             // are any complaints that =string will not work (even though that use
0925             // case is not documented)
0926             if (in_array(substr($ruleCode, -2, 1), array('-', '='))) {
0927                 $flagList  = substr($ruleCode, 0, -2);
0928                 $delimiter = substr($ruleCode, -2, 1);
0929                 $paramType = substr($ruleCode, -1);
0930             } else {
0931                 $flagList = $ruleCode;
0932                 $delimiter = $paramType = null;
0933             }
0934             if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
0935                 $flagList = strtolower($flagList);
0936             }
0937             $flags = explode('|', $flagList);
0938             $rule = array();
0939             $mainFlag = $flags[0];
0940             foreach ($flags as $flag) {
0941                 if (empty($flag)) {
0942                     // require_once 'Zend/Console/Getopt/Exception.php';
0943                     throw new Zend_Console_Getopt_Exception(
0944                         "Blank flag not allowed in rule \"$ruleCode\".");
0945                 }
0946                 if (strlen($flag) == 1) {
0947                     if (isset($this->_ruleMap[$flag])) {
0948                         // require_once 'Zend/Console/Getopt/Exception.php';
0949                         throw new Zend_Console_Getopt_Exception(
0950                             "Option \"-$flag\" is being defined more than once.");
0951                     }
0952                     $this->_ruleMap[$flag] = $mainFlag;
0953                     $rule['alias'][] = $flag;
0954                 } else {
0955                     if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) {
0956                         // require_once 'Zend/Console/Getopt/Exception.php';
0957                         throw new Zend_Console_Getopt_Exception(
0958                             "Option \"--$flag\" is being defined more than once.");
0959                     }
0960                     $this->_ruleMap[$flag] = $mainFlag;
0961                     $rule['alias'][] = $flag;
0962                 }
0963             }
0964             if (isset($delimiter)) {
0965                 switch ($delimiter) {
0966                     case self::PARAM_REQUIRED:
0967                         $rule['param'] = 'required';
0968                         break;
0969                     case self::PARAM_OPTIONAL:
0970                     default:
0971                         $rule['param'] = 'optional';
0972                 }
0973                 switch (substr($paramType, 0, 1)) {
0974                     case self::TYPE_WORD:
0975                         $rule['paramType'] = 'word';
0976                         break;
0977                     case self::TYPE_INTEGER:
0978                         $rule['paramType'] = 'integer';
0979                         break;
0980                     case self::TYPE_STRING:
0981                     default:
0982                         $rule['paramType'] = 'string';
0983                 }
0984             } else {
0985                 $rule['param'] = 'none';
0986             }
0987             $rule['help'] = $helpMessage;
0988             $this->_rules[$mainFlag] = $rule;
0989         }
0990     }
0991 
0992 }