277 lines
9.1 KiB
PHP
277 lines
9.1 KiB
PHP
<?php
|
|
/**
|
|
* Copyright 2010-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* This package is ported from Python's Optik (http://optik.sourceforge.net/).
|
|
*
|
|
* See the enclosed file LICENSE for license information (BSD). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/bsd.
|
|
*
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @author Mike Naberezny <mike@maintainable.com>
|
|
* @license http://www.horde.org/licenses/bsd BSD
|
|
* @category Horde
|
|
* @package Argv
|
|
*/
|
|
|
|
/**
|
|
* Abstract base class.
|
|
*
|
|
* Class attributes:
|
|
* standardOptionList : [Option]
|
|
* list of standard options that will be accepted by all instances
|
|
* of this parser class (intended to be overridden by subclasses).
|
|
*
|
|
* Instance attributes:
|
|
* optionList : [Option]
|
|
* the list of Option objects contained by this OptionContainer
|
|
* shortOpt : { string : Option }
|
|
* dictionary mapping short option strings, eg. "-f" or "-X",
|
|
* to the Option instances that implement them. If an Option
|
|
* has multiple short option strings, it will appears in this
|
|
* dictionary multiple times. [1]
|
|
* longOpt : { string : Option }
|
|
* dictionary mapping long option strings, eg. "--file" or
|
|
* "--exclude", to the Option instances that implement them.
|
|
* Again, a given Option can occur multiple times in this
|
|
* dictionary. [1]
|
|
* defaults : { string : any }
|
|
* dictionary mapping option destination names to default
|
|
* values for each destination [1]
|
|
*
|
|
* [1] These mappings are common to (shared by) all components of the
|
|
* controlling Horde_Argv_Parser, where they are initially created.
|
|
*
|
|
* @category Horde
|
|
* @package Argv
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @author Mike Naberezny <mike@maintainable.com>
|
|
* @copyright 2010-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/bsd BSD
|
|
*/
|
|
class Horde_Argv_OptionContainer
|
|
{
|
|
public $description = '';
|
|
public $optionList = array();
|
|
public $optionClass = 'Horde_Argv_Option';
|
|
public $defaults = array();
|
|
public $shortOpt = array();
|
|
public $longOpt = array();
|
|
public $conflictHandler;
|
|
|
|
/**
|
|
* Initialize the option list and related data structures.
|
|
* This method must be provided by subclasses, and it must
|
|
* initialize at least the following instance attributes:
|
|
* optionList, shortOpt, longOpt, defaults.
|
|
*/
|
|
public function __construct($optionClass, $conflictHandler, $description)
|
|
{
|
|
$this->_createOptionList();
|
|
|
|
$this->optionClass = $optionClass;
|
|
$this->setConflictHandler($conflictHandler);
|
|
$this->setDescription($description);
|
|
}
|
|
|
|
/**
|
|
* For use by Horde_Argv_Parser constructor -- create the master
|
|
* option mappings used by this Horde_Argv_Parser and all
|
|
* OptionGroups that it owns.
|
|
*/
|
|
protected function _createOptionMappings()
|
|
{
|
|
$this->shortOpt = array(); // single letter -> Option instance
|
|
$this->longOpt = array(); // long option -> Option instance
|
|
$this->defaults = array(); // maps option dest -> default value
|
|
}
|
|
|
|
/**
|
|
* For use by OptionGroup constructor -- use shared option
|
|
* mappings from the Horde_Argv_Parser that owns this OptionGroup.
|
|
*/
|
|
protected function _shareOptionMappings($parser)
|
|
{
|
|
$this->shortOpt =& $parser->shortOpt;
|
|
$this->longOpt =& $parser->longOpt;
|
|
$this->defaults = $parser->defaults;
|
|
}
|
|
|
|
public function setConflictHandler($handler)
|
|
{
|
|
if (!in_array($handler, array('error', 'resolve'))) {
|
|
throw new InvalidArgumentException('invalid conflictHandler ' . var_export($handler, true));
|
|
}
|
|
$this->conflictHandler = $handler;
|
|
}
|
|
|
|
public function setDescription($description)
|
|
{
|
|
$this->description = $description;
|
|
}
|
|
|
|
public function getDescription()
|
|
{
|
|
return $this->description;
|
|
}
|
|
|
|
// -- Option-adding methods -----------------------------------------
|
|
|
|
protected function _checkConflict($option)
|
|
{
|
|
$conflictOpts = array();
|
|
foreach ($option->shortOpts as $opt) {
|
|
if (isset($this->shortOpt[$opt])) {
|
|
$conflictOpts[$opt] = $this->shortOpt[$opt];
|
|
}
|
|
}
|
|
foreach ($option->longOpts as $opt) {
|
|
if (isset($this->longOpt[$opt])) {
|
|
$conflictOpts[$opt] = $this->longOpt[$opt];
|
|
}
|
|
}
|
|
|
|
if ($conflictOpts) {
|
|
$handler = $this->conflictHandler;
|
|
if ($handler == 'error') {
|
|
throw new Horde_Argv_OptionConflictException(sprintf(
|
|
'conflicting option string(s): %s',
|
|
implode(', ', array_keys($conflictOpts))), $option);
|
|
} elseif ($handler == 'resolve') {
|
|
foreach ($conflictOpts as $opt => $c_option) {
|
|
if (strncmp($opt, '--', 2) === 0) {
|
|
$key = array_search($opt, $c_option->longOpts);
|
|
if ($key !== false) {
|
|
unset($c_option->longOpts[$key]);
|
|
}
|
|
unset($this->longOpt[$opt]);
|
|
} else {
|
|
$key = array_search($opt, $c_option->shortOpts);
|
|
if ($key !== false) {
|
|
unset($c_option->shortOpts[$key]);
|
|
}
|
|
unset($this->shortOpt[$opt]);
|
|
}
|
|
|
|
if (! ($c_option->shortOpts || $c_option->longOpts)) {
|
|
$key = array_search($c_option, $c_option->container->optionList);
|
|
unset($c_option->container->optionList[$key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function addOption()
|
|
{
|
|
$opts = func_get_args();
|
|
|
|
if (count($opts) && is_string($opts[0])) {
|
|
$optionFactory = new ReflectionClass($this->optionClass);
|
|
$option = $optionFactory->newInstanceArgs($opts);
|
|
} elseif (count($opts) == 1) {
|
|
$option = $opts[0];
|
|
if (!$option instanceof Horde_Argv_Option)
|
|
throw new InvalidArgumentException('not an Option instance: ' . var_export($option, true));
|
|
} else {
|
|
throw new InvalidArgumentException('invalid arguments');
|
|
}
|
|
|
|
$this->_checkConflict($option);
|
|
|
|
$this->optionList[] = $option;
|
|
$option->container = $this;
|
|
foreach ($option->shortOpts as $opt) {
|
|
$this->shortOpt[$opt] = $option;
|
|
}
|
|
foreach ($option->longOpts as $opt) {
|
|
$this->longOpt[$opt] = $option;
|
|
}
|
|
|
|
if (!is_null($option->dest)) {
|
|
// option has a dest, we need a default
|
|
if ($option->default !== Horde_Argv_Option::$NO_DEFAULT) {
|
|
$this->defaults[$option->dest] = $option->default;
|
|
} elseif (!isset($this->defaults[$option->dest])) {
|
|
$this->defaults[$option->dest] = null;
|
|
}
|
|
}
|
|
|
|
return $option;
|
|
}
|
|
|
|
public function addOptions($optionList)
|
|
{
|
|
foreach ($optionList as $option) {
|
|
$this->addOption($option);
|
|
}
|
|
}
|
|
|
|
// -- Option query/removal methods ----------------------------------
|
|
|
|
public function getOption($opt_str)
|
|
{
|
|
if (isset($this->shortOpt[$opt_str])) {
|
|
return $this->shortOpt[$opt_str];
|
|
} elseif (isset($this->longOpt[$opt_str])) {
|
|
return $this->longOpt[$opt_str];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public function hasOption($opt_str)
|
|
{
|
|
return isset($this->shortOpt[$opt_str])
|
|
|| isset($this->longOpt[$opt_str]);
|
|
}
|
|
|
|
public function removeOption($opt_str)
|
|
{
|
|
$option = $this->getOption($opt_str);
|
|
if (is_null($option)) {
|
|
throw new InvalidArgumentException("no such option '$opt_str'");
|
|
}
|
|
|
|
foreach ($option->shortOpts as $opt) {
|
|
unset($this->shortOpt[$opt]);
|
|
}
|
|
foreach ($option->longOpts as $opt) {
|
|
unset($this->longOpt[$opt]);
|
|
}
|
|
$key = array_search($option, $option->container->optionList);
|
|
unset($option->container->optionList[$key]);
|
|
}
|
|
|
|
|
|
// -- Help-formatting methods ---------------------------------------
|
|
|
|
public function formatOptionHelp($formatter = null)
|
|
{
|
|
if (!$this->optionList)
|
|
return '';
|
|
$result = array();
|
|
foreach ($this->optionList as $option) {
|
|
if ($option->help != Horde_Argv_Option::SUPPRESS_HELP)
|
|
$result[] = $formatter->formatOption($option);
|
|
}
|
|
return implode('', $result);
|
|
}
|
|
|
|
public function formatDescription($formatter = null)
|
|
{
|
|
return $formatter->formatDescription($this->getDescription());
|
|
}
|
|
|
|
public function formatHelp($formatter = null)
|
|
{
|
|
$result = array();
|
|
if ($this->description)
|
|
$result[] = $this->formatDescription($formatter);
|
|
if ($this->optionList)
|
|
$result[] = $this->formatOptionHelp($formatter);
|
|
return implode("\n", $result);
|
|
}
|
|
|
|
}
|