2015-05-21 17:39:11 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Zend Framework (http://framework.zend.com/)
|
|
|
|
*
|
|
|
|
* @link http://github.com/zendframework/zf2 for the canonical source repository
|
|
|
|
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
|
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Todaymade\Daux\Generator;
|
|
|
|
|
|
|
|
use InvalidArgumentException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Getopt is a class to parse options for command-line
|
|
|
|
* applications.
|
|
|
|
*
|
|
|
|
* Terminology:
|
|
|
|
* Argument: an element of the argv array. This may be part of an option,
|
|
|
|
* or it may be a non-option command-line argument.
|
|
|
|
* Flag: the letter or word set off by a '-' or '--'. Example: in '--output filename',
|
|
|
|
* '--output' is the flag.
|
|
|
|
* Parameter: the additional argument that is associated with the option.
|
|
|
|
* Example: in '--output filename', the 'filename' is the parameter.
|
|
|
|
* Option: the combination of a flag and its parameter, if any.
|
|
|
|
* Example: in '--output filename', the whole thing is the option.
|
|
|
|
*
|
|
|
|
* The following features are supported:
|
|
|
|
*
|
|
|
|
* - Short flags like '-a'. Short flags are preceded by a single
|
|
|
|
* dash. Short flags may be clustered e.g. '-abc', which is the
|
|
|
|
* same as '-a' '-b' '-c'.
|
|
|
|
* - Long flags like '--verbose'. Long flags are preceded by a
|
|
|
|
* double dash. Long flags may not be clustered.
|
|
|
|
* - Options may have a parameter, e.g. '--output filename'.
|
|
|
|
* - Parameters for long flags may also be set off with an equals sign,
|
|
|
|
* e.g. '--output=filename'.
|
|
|
|
* - Parameters for long flags may be checked as string, word, or integer.
|
|
|
|
* - Automatic generation of a helpful usage message.
|
|
|
|
* - Signal end of options with '--'; subsequent arguments are treated
|
|
|
|
* as non-option arguments, even if they begin with '-'.
|
|
|
|
* - Raise exception Zend\Console\* in several cases
|
|
|
|
* when invalid flags or parameters are given. Usage message is
|
|
|
|
* returned in the exception object.
|
|
|
|
*
|
|
|
|
* The format for specifying options uses a PHP associative array.
|
|
|
|
* The key is has the format of a list of pipe-separated flag names,
|
|
|
|
* followed by an optional '=' to indicate a required parameter or
|
|
|
|
* '-' to indicate an optional parameter. Following that, the type
|
|
|
|
* of parameter may be specified as 's' for string, 'w' for word,
|
|
|
|
* or 'i' for integer.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
* - 'user|username|u=s' this means '--user' or '--username' or '-u'
|
|
|
|
* are synonyms, and the option requires a string parameter.
|
|
|
|
* - 'p=i' this means '-p' requires an integer parameter. No synonyms.
|
|
|
|
* - 'verbose|v-i' this means '--verbose' or '-v' are synonyms, and
|
|
|
|
* they take an optional integer parameter.
|
|
|
|
* - 'help|h' this means '--help' or '-h' are synonyms, and
|
|
|
|
* they take no parameter.
|
|
|
|
*
|
|
|
|
* The values in the associative array are strings that are used as
|
|
|
|
* brief descriptions of the options when printing a usage message.
|
|
|
|
*
|
|
|
|
* The simpler format for specifying options used by PHP's getopt()
|
|
|
|
* function is also supported. This is similar to GNU getopt and shell
|
|
|
|
* getopt format.
|
|
|
|
*
|
|
|
|
* Example: 'abc:' means options '-a', '-b', and '-c'
|
|
|
|
* are legal, and the latter requires a string parameter.
|
|
|
|
*/
|
|
|
|
class Getopt
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Constant tokens for various symbols used in the mode_zend
|
|
|
|
* rule format.
|
|
|
|
*/
|
|
|
|
const PARAM_REQUIRED = '=';
|
|
|
|
const PARAM_OPTIONAL = '-';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores the command-line arguments for the calling application.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $argv = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores the name of the calling application.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $progname = '';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores the list of legal options for this application.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $rules = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores alternate spellings of legal options.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $ruleMap = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores options given by the user in the current invocation
|
|
|
|
* of the application, as well as parameters given in options.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $options = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* State of the options: parsed or not yet parsed?
|
|
|
|
*
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $parsed = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The constructor takes one to three parameters.
|
|
|
|
*
|
|
|
|
* The first parameter is $rules, which may be a string for
|
|
|
|
* gnu-style format, or a structured array for Zend-style format.
|
|
|
|
*
|
|
|
|
* @param array $rules
|
|
|
|
* @throws InvalidArgumentException
|
|
|
|
*/
|
|
|
|
public function __construct($rules, $argv = null)
|
|
|
|
{
|
|
|
|
$this->argv = $argv?: $_SERVER['argv'];
|
|
|
|
|
|
|
|
$this->progname = $this->argv[0];
|
|
|
|
$this->addRules($rules);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a list of options that have been seen in the current argv.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getOptions()
|
|
|
|
{
|
|
|
|
$this->parse();
|
|
|
|
return $this->options;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the state of the option seen on the command line of the
|
|
|
|
* current application invocation.
|
|
|
|
*
|
|
|
|
* This function returns true, or the parameter value to the option, if any.
|
|
|
|
* If the option was not given, this function returns false.
|
|
|
|
*
|
|
|
|
* @param string $flag
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function getOption($flag)
|
|
|
|
{
|
|
|
|
$this->parse();
|
|
|
|
|
|
|
|
$flag = strtolower($flag);
|
|
|
|
|
|
|
|
if (isset($this->ruleMap[$flag])) {
|
|
|
|
$flag = $this->ruleMap[$flag];
|
|
|
|
if (isset($this->options[$flag])) {
|
|
|
|
return $this->options[$flag];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a useful option reference, formatted for display in an
|
|
|
|
* error message.
|
|
|
|
*
|
|
|
|
* Note that this usage information is provided in most Exceptions
|
|
|
|
* generated by this class.
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getUsageMessage()
|
|
|
|
{
|
|
|
|
$usage = "Usage: {$this->progname} [ options ]\n";
|
|
|
|
$maxLen = 20;
|
|
|
|
$lines = array();
|
|
|
|
foreach ($this->rules as $rule) {
|
|
|
|
if (isset($rule['isFreeformFlag'])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$flags = array();
|
|
|
|
if (is_array($rule['alias'])) {
|
|
|
|
foreach ($rule['alias'] as $flag) {
|
|
|
|
$flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$linepart['name'] = implode('|', $flags);
|
|
|
|
if (isset($rule['param']) && $rule['param'] != 'none') {
|
|
|
|
$linepart['name'] .= '=""';
|
|
|
|
switch ($rule['param']) {
|
|
|
|
case 'optional':
|
|
|
|
$linepart['name'] .= " (optional)";
|
|
|
|
break;
|
|
|
|
case 'required':
|
|
|
|
$linepart['name'] .= " (required)";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strlen($linepart['name']) > $maxLen) {
|
|
|
|
$maxLen = strlen($linepart['name']);
|
|
|
|
}
|
|
|
|
$linepart['help'] = '';
|
|
|
|
if (isset($rule['help'])) {
|
|
|
|
$linepart['help'] .= $rule['help'];
|
|
|
|
}
|
|
|
|
$lines[] = $linepart;
|
|
|
|
}
|
|
|
|
foreach ($lines as $linepart) {
|
|
|
|
$usage .= sprintf(
|
|
|
|
"%s %s\n",
|
|
|
|
str_pad($linepart['name'], $maxLen),
|
|
|
|
$linepart['help']
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return $usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse command-line arguments and find both long and short
|
|
|
|
* options.
|
|
|
|
*
|
|
|
|
* Also find option parameters, and remaining arguments after
|
|
|
|
* all options have been parsed.
|
|
|
|
*
|
|
|
|
* @return self
|
|
|
|
*/
|
|
|
|
public function parse()
|
|
|
|
{
|
|
|
|
if ($this->parsed === true) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in_array('--help', $this->argv)) {
|
|
|
|
echo $this->getUsageMessage();
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->options = array();
|
|
|
|
|
|
|
|
$long = [];
|
|
|
|
$short = '';
|
|
|
|
foreach ($this->rules as $rule) {
|
2015-05-22 14:48:09 +02:00
|
|
|
foreach ($rule['alias'] as $alias) {
|
2015-05-21 17:39:11 +02:00
|
|
|
$prepared = $alias;
|
|
|
|
if ($rule['param'] == 'optional') {
|
|
|
|
$prepared .= '::';
|
|
|
|
} elseif ($rule['param'] == 'required') {
|
|
|
|
$prepared .= ':';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen($alias) == 1) {
|
|
|
|
$short .= $prepared;
|
|
|
|
} else {
|
|
|
|
$long[] = $prepared;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = getopt($short, $long);
|
|
|
|
|
|
|
|
foreach ($result as $key => $value) {
|
|
|
|
$this->options[$this->ruleMap[$key]] = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->parsed = true;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define legal options using the Zend-style format.
|
|
|
|
*
|
|
|
|
* @param array $rules
|
|
|
|
* @throws InvalidArgumentException
|
|
|
|
*/
|
|
|
|
protected function addRules($rules)
|
|
|
|
{
|
|
|
|
foreach ($rules as $ruleCode => $helpMessage) {
|
|
|
|
// this may have to translate the long parm type if there
|
|
|
|
// are any complaints that =string will not work (even though that use
|
|
|
|
// case is not documented)
|
|
|
|
if (in_array(substr($ruleCode, -2, 1), array('-', '='))) {
|
|
|
|
$flagList = substr($ruleCode, 0, -2);
|
|
|
|
$delimiter = substr($ruleCode, -2, 1);
|
|
|
|
} else {
|
|
|
|
$flagList = $ruleCode;
|
|
|
|
$delimiter = $paramType = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$flagList = strtolower($flagList);
|
|
|
|
|
|
|
|
$flags = explode('|', $flagList);
|
|
|
|
$rule = array();
|
|
|
|
$mainFlag = $flags[0];
|
|
|
|
foreach ($flags as $flag) {
|
|
|
|
if (empty($flag)) {
|
|
|
|
throw new InvalidArgumentException("Blank flag not allowed in rule \"$ruleCode\".");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($this->ruleMap[$flag]) || (strlen($flag) != 1 && isset($this->rules[$flag]))) {
|
|
|
|
throw new InvalidArgumentException("Option \"-$flag\" is being defined more than once.");
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->ruleMap[$flag] = $mainFlag;
|
|
|
|
$rule['alias'][] = $flag;
|
|
|
|
}
|
|
|
|
$rule['param'] = 'none';
|
|
|
|
if (isset($delimiter)) {
|
|
|
|
$rule['param'] = $delimiter == self::PARAM_REQUIRED? 'required' : 'optional';
|
|
|
|
}
|
|
|
|
|
|
|
|
$rule['help'] = $helpMessage;
|
|
|
|
$this->rules[$mainFlag] = $rule;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|