diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CommandLine.class.php b/CommandLine.class.php index 715100c..cbf3be6 100644 --- a/CommandLine.class.php +++ b/CommandLine.class.php @@ -1,871 +1,1019 @@ -setProgramName($programName); - $this->setDescription($mainDescription); - $this->setCommand($command); - $this->setVersion($version); - } - - /** - * Ajoute les options communes à la plupart des programmes - * - * Voici la liste des options générées : - * - Aide : --help ou -h - * - Version : --version ou -v (voir $shortForVersion) - * - * @param bool $shortForVersion L'option pour la version existe également au format "court" (-v) - * - * @return $this - */ - public function addDefaultArguments ($shortForVersion = true) { - if(!$this->existsOption(self::ARGUMENT_OPTION_HELP)) { - $this->addOption( - (new Argument\Option\Flag(self::ARGUMENT_OPTION_HELP, false, 'Affiche cette aide', 'help', 'h')) - ->setStoppingParse(true) - ); - } - - if (!$this->existsOption(self::ARGUMENT_OPTION_HELP) && !is_null($this->getVersion())) { - $this->addOption( - (new Argument\Option\Flag(self::ARGUMENT_OPTION_VERSION,false,'Affiche la version','version',$shortForVersion ? 'v' : null)) - ->setStoppingParse(true) - ); - } - - return $this; - } - /** - * Auto-lance les fonctions correspondantes aux options communes. - * - * @param stdClass $values Les valeurs du parsage - * @param boolean $exitAtEnd Terminer le script à la fin de la fonction correspondante ? - */ - public function treatDefaultArguments ($values, $exitAtEnd = true) { - if ($values->{self::ARGUMENT_OPTION_HELP} === true) { - $this->showHelp($exitAtEnd); - } - - if ($values->{self::ARGUMENT_OPTION_VERSION} === true) { - $this->showVersion($exitAtEnd); - } - } - - /** - * Traite la ligne de commande du script actuel pour en sortir les valeurs. - * - * @return stdClass Les valeurs extraites. - * @throws IException Quand toutes les solutions ne correspond pas - * @throws Exception Autre erreur - */ - public function parse () { - $argv = $_SERVER['argv']; - array_shift($argv); // Supprime le 1er paramètre : le nom du script PHP - - return $this->parseExplicit($argv); - } - /** - * Traite une ligne de commande pour en sortir les valeurs. - * - * @param string[] $argv La liste des arguments. - * - * @return stdClass Les valeurs extraites. - * @throws IException Quand toutes les solutions ne correspond pas - * @throws Exception Autre erreur - */ - public function parseExplicit ($argv) { - ksort($this->_solutions, SORT_NUMERIC); - foreach ($this->_solutions as $ordre => $solution) { - $argv_loop = $argv; - try { - $values = $solution->parseExplicit($argv_loop, $this->_optionsCommon); - } - catch (IException $e) { - if ($ordre >= ($this->getNextSolutionOrder() - 1)) { - throw $e; - } - - continue; - } - catch (Exception $e) { - throw $e; - } - - return $values; - } - - if (count($argv) > 0) { - throw new TooMuchValues($argv, 'Trop de valeurs'); - } - - return null; - } - - /** - * Affiche la version du programme - * - * @param boolean $exitAtEnd Terminer le script à la fin de la fonction ? - */ - public function showVersion ($exitAtEnd = true) { - echo $this->getVersion() . "\n"; - - if ($exitAtEnd) { - exit(0); - } - } - /** - * Affiche l'aide du programme. - * - * @param boolean $exitAtEnd Terminer le script à la fin de la fonction ? - */ - public function showHelp ($exitAtEnd = true) { - echo $this->generateHelp() . "\n"; - - if ($exitAtEnd) { - exit(0); - } - } - /** - * Génère l'aide du programme. - * - * @return string Le texte de l'aide. - */ - public function generateHelp () { - ksort($this->_solutions); - - $help = array(); - - $help[] = $this->getProgramName() . (is_null($this->getVersion()) ? '' : ', version ' . $this->getVersion()); - $help[] = $this->getDescription(); - $help[] = ''; - - foreach ($this->_solutions as $solution) { - $syntax = array( - $this->getCommand(), - count($this->_optionsCommon) > 0 || count($solution->getOptions()) > 0 ? '[OPTIONS]' : '', - ); - $syntax = array_merge($syntax, array_map(array(__CLASS__, '_getSyntaxOfArgument'), $solution->getArguments())); - - $help[] = implode(' ', $syntax); - - $help[] = self::TAB . 'Arguments :'; - $help = array_merge($help, self::_getArgumentsListing($solution->getArguments())); - $help[] = ''; - - $help[] = self::TAB . 'Options :'; - $help = array_merge($help, self::_getOptionsListing(array_merge($this->_optionsCommon, $solution->getOptions()))); - $help[] = ''; - } - $help[] = ''; - - return implode("\n", $help); - } - - /** - * La syntax d'un argument - * - * @param IArgumentValue $argument L'argument - * - * @return string La syntax de l'argument - * @see generateHelp() - */ - protected static function _getSyntaxOfArgument (IArgumentValue $argument) { - $syntax = ''; - - $min = $argument->getOccurMin(); - $max = $argument->getOccurMax(); - if (is_null($max)) { - $max = -1; - } - - if ($min == 0) { - $syntax .= '['; - } - - $syntax .= $argument->getName(); - for ($curr = 2; $curr <= $min; $curr++) { - $syntax .= ' ' . $argument->getName() . $curr; - } - - if ($max === -1 || $max > 1) { - if ($min < 2) { - $syntax .= ' [' . $argument->getName() . '2]'; - } - - $syntax .= ' ... [' . $argument->getName() . ($max === -1 ? 'N' : $max) . ']'; - } - - if ($min == 0) { - $syntax .= ']'; - } - - return $syntax; - } - /** - * Transforme une liste d'argument en un liste de leur descriptif complet (pour l'aide). - * - * @param IArgumentValue[] $arguments La liste des arguments - * - * @return string[] Les descriptifs complet des arguments - */ - protected static function _getArgumentsListing ($arguments) { - /* - * Calcul des différents padding - */ - // Initialisation - $pads = new stdClass; - $pads->name = 0; - $pads->occurMin = 0; - $pads->occurMax = 0; - $pads->valueDescription = 0; - - // Lecture des arguments - foreach ($arguments as $argument) { - $pads->name = max($pads->name, strlen($argument->getName())); - - $max = $argument->getOccurMax(); - $pads->occurMin = max($pads->occurMin, strlen($argument->getOccurMin())); - $pads->occurMax = max($pads->occurMax, strlen(is_null($max) ? 'N' : $max)); - - if ($argument instanceof IArgumentValueDescription) { - $pads->valueDescription = max($pads->valueDescription, strlen($argument->getValueDescription())); - } - } - - /* - * Génération des descriptifs - */ - $entries = array(); - foreach ($arguments as $argument) { - $label = str_pad($argument->getName(), $pads->name, ' ', STR_PAD_RIGHT); - - $max = $argument->getOccurMax(); - - $occur = ''; - $occur .= str_pad($argument->getOccurMin(), $pads->occurMin, ' ', STR_PAD_LEFT); - $occur .= ' => '; - $occur .= str_pad(is_null($max) ? 'N' : $max, $pads->occurMax, ' ', STR_PAD_RIGHT); - - $valueDescription = str_pad( - $argument instanceof IArgumentValueDescription ? $argument->getValueDescription() : '', - $pads->valueDescription, - ' ', - STR_PAD_RIGHT - ); - - $entries[] = self::TAB . self::TAB . implode(self::TAB, array( - $label, - $occur, - $valueDescription, - preg_replace( - /** @lang RegExp */ '@\r?\n@', - '$0' . self::TAB . self::TAB . implode(self::TAB, array( - str_pad('', $pads->name, ' '), - str_pad('', - $pads->occurMin + 4 + $pads->occurMax, - ' ' - ), - str_pad('', $pads->valueDescription, ' '), - '', - ) - ), - $argument->getDescription() - ), - ) - ); - } - - return $entries; - } - /** - * Transforme une liste d'options en un liste de leur descriptif complet (pour l'aide). - * - * @param IArgumentOption[] $options La liste des options - * - * @return string[] Les descriptifs complet des options - */ - protected static function _getOptionsListing ($options) { - /* - * Calcul des différents padding - */ - // Initialisation - $pads = new stdClass; - $pads->tagShort = 0; - $pads->tagLong = 0; - $pads->valueDescription = 0; - - // Lecture des arguments - foreach ($options as $option) { - $short = $option->getTagShort(); - if (!is_null($short)) { - $pads->tagShort = max($pads->tagShort, strlen($short)); - } - $pads->tagLong = max($pads->tagLong, strlen($option->getTagLong())); - - if ($option instanceof IArgumentValueDescription) { - $pads->valueDescription = max($pads->valueDescription, strlen($option->getValueDescription())); - } - } - - // Les tags ont une taille suplémentaire incompressible - $pads->tagShort += 1; - $pads->tagLong += 2; - - /* - * Génération des descriptifs - */ - $entries = array(); - foreach ($options as $option) { - $short = $option->getTagShort(); - - $label = ''; - $label .= str_pad(is_null($short) ? '' : '-' . $short, $pads->tagShort, ' ', STR_PAD_RIGHT); - $label .= ' '; - $label .= str_pad('--' . $option->getTagLong(), $pads->tagLong, ' ', STR_PAD_RIGHT); - $label .= $option->allowMultiple() ? ' *' : ($option->isStoppingParse() ? ' X' : ' '); - - $valueDescription = str_pad( - $option instanceof IArgumentValueDescription ? $option->getValueDescription() : '', - $pads->valueDescription, - ' ', - STR_PAD_RIGHT - ); - - $entries[] = self::TAB . self::TAB . implode(self::TAB, array( - $label, - $valueDescription, - preg_replace( - /** @lang RegExp */ '@\r?\n@', - '$0' . self::TAB . self::TAB . implode(self::TAB, array( - str_pad('', $pads->tagShort + 1 + $pads->tagLong - + 2, ' ' - ), - str_pad('', $pads->valueDescription, ' '), - '', - ) - ), - $option->getDescription() - ), - ) - ); - } - - return $entries; - } - - /** - * Le nom du programme. - * - * @return string Le nom. - * @see CommandLine::$_programName - */ - public function getProgramName () { - return $this->_programName; - } - /** - * Modifie le nom du programme. - * - * @param string $programName Le nouveau nom - * - * @return $this - * @see CommandLine::$_programName - */ - public function setProgramName ($programName) { - $this->_programName = $programName; - return $this; - } - - /** - * La commande de lancement du programme - * - * NULL = {@see CommandLine::$_programName Nom du programme} - * - * @return string|null La commande - * @see CommandLine::$_command - */ - public function getCommand () { - return $this->_command; - } - /** - * Modifie la commande de lancement du programme - * - * @param string|null $command La nouvelle commande - * - * @return $this - * @see CommandLine::$_command - */ - public function setCommand ($command) { - $this->_command = $command; - return $this; - } - - /** - * La description du programme - * - * @return string La description - * @see CommandLine::$_description - */ - public function getDescription () { - return $this->_description; - } - /** - * Modifie la description du programme. - * - * @param string $description La nouvelle description. - * - * @return $this - * @see CommandLine::$_description - */ - public function setDescription ($description) { - $this->_description = $description; - return $this; - } - - /** - * La version du programme - * - * @return string|null La version - * @see CommandLine::$_version - */ - public function getVersion () { - return $this->_version; - } - /** - * Modifie la version du programme. - * - * @param string|null $version La nouvelle version. - * - * @return $this - * @see CommandLine::$_version - */ - public function setVersion ($version) { - $this->_version = $version; - return $this; - } - - /** - * La liste des arguments "option" - * - * @return IArgumentOption[] La liste des options - * @see CommandLine::$_arguments_options - */ - public function getOptions () { - return $this->_arguments_options; - } - /** - * Modifie la liste des arguments "option" - * - * *Attention* : cette fonction _remplace_ la liste des options. - * Pour seulement en ajouter, utiliser {@see CommandLine::addOptions()} - * - * @param IArgumentOption[] $options La nouvelle liste d'options - * - * @return $this - * @see CommandLine::$_arguments_options - */ - public function setOptions ($options) { - self::_checkOptionList($options); - - $this->_arguments_options = $options; - return $this; - } - /** - * Ajoute des arguments "option" à ceux existants - * - * Pour ajouter une seule option, il est conseillé d'utiliser {@see CommandLine::addOption()} - * - * @param IArgumentOption[]|IArgumentOption $options La liste d'options à ajouter - * - * @return $this - * @see CommandLine::$_arguments_options - */ - public function addOptions ($options) { - if (!is_array($options) && $options instanceof IArgumentOption) { - $options = array($options); - } - self::_checkOptionList($options); - - $this->_arguments_options = array_merge($this->_arguments_options, $options); - return $this; - } - /** - * Ajoute un seul argument "option" à ceux existants - * - * Pour ajouter plusieurs options à la fois, il est conseillé d'utiliser {@see CommandLine::addOptions()} - * - * @param IArgumentOption $option L'options à ajouter - * - * @return $this - * @see CommandLine::$_arguments_options - */ - public function addOption ($option) { - return $this->addOptions(array($option)); - } - /** - * Est-ce que l'argument "option" existe déjà ? - * - * @param string $optionName Le nom de l'option - * - * @return bool True si l'option existe déjà, sinon False - */ - public function existsOption ($optionName) { - foreach ($this->_arguments_options as $option) { - if ($option->getName() == $optionName) { - return true; - } - } - - return false; - } - /** - * Est-ce que c'est un argument "option" ? - * - * @param mixed $argument L'argument à tester - * - * @return bool True si c'est bien un argument "option", sinon False - */ - public static function isOption ($argument) { - return $argument instanceof IArgumentOption; - } - /** - * Vérifie que la liste d'arguments "option" est valide - * - * Doit être un tableau et chaque élément doit implémenter {@see IArgumentOption} - * - * @param IArgumentOption[] $options Les options à vérifier - */ - protected static function _checkOptionList ($options) { - if (!is_array($options)) { - throw new InvalidArgumentException('La liste des options n\'est pas un tableau'); - } - foreach ($options as $key => $option) { - if (!self::isOption($option)) { - throw new InvalidArgumentException('L\'option ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentOption)'); - } - } - } - - /** - * La liste des arguments "value" - * - * @return IArgumentValue[] La liste des valeurs - * @see CommandLine::$_arguments_values - */ - public function getValues () { - return $this->_arguments_values; - } - /** - * Modifie la liste des arguments "value" - * - * *Attention* : cette fonction _remplace_ la liste des valeurs. - * Pour seulement en ajouter, utiliser {@see CommandLine::addValues()} - * - * @param IArgumentValue[] $values La nouvelle liste de valeurs - * - * @return $this - * @see CommandLine::$_arguments_values - */ - public function setValues ($values) { - self::_checkValueList($values); - - $this->_arguments_values = $values; - return $this; - } - /** - * Ajoute des arguments "value" à celles existantes - * - * Pour ajouter une seule valeur, il est conseillé d'utiliser {@see CommandLine::addValue()} - * - * @param IArgumentValue[]|IArgumentValue $values La liste des valeurs à ajouter - * - * @return $this - * @see CommandLine::$_arguments_values - */ - public function addValues ($values) { - if (!is_array($values) && $values instanceof IArgumentValue) { - $values = array($values); - } - self::_checkValueList($values); - - $this->_arguments_values = array_merge($this->_arguments_values, $values); - return $this; - } - /** - * Ajoute un seul argument "value" à celles existantes - * - * Pour ajouter plusieurs valeurs à la fois, il est conseillé d'utiliser {@see CommandLine::addValues()} - * - * @param IArgumentValue $value La valeur à ajouter - * - * @return $this - * @see CommandLine::$_arguments_values - */ - public function addValue ($value) { - return $this->addValues(array($value)); - } - /** - * Est-ce que l'argument "value" existe déjà ? - * - * @param string $valueName Le nom de la valeur - * - * @return bool True si la valeur existe déjà, sinon False - */ - public function existsValue ($valueName) { - foreach ($this->_arguments_values as $option) { - if ($option->getName() == $valueName) { - return true; - } - } - - return false; - } - /** - * Est-ce que c'est un argument "value" ? - * - * @param mixed $argument L'argument à tester - * - * @return bool True si c'est bien un argument "value", sinon False - */ - public static function isValue ($argument) { - return $argument instanceof IArgumentValue; - } - /** - * Vérifie que la liste d'arguments "value" est valide - * - * Doit être un tableau et chaque élément doit implémenter {@see IArgumentValue} - * - * @param IArgumentValue[] $values Les valeurs à vérifier - */ - protected static function _checkValueList ($values) { - if (!is_array($values)) { - throw new InvalidArgumentException('La liste des valeurs n\'est pas un tableau'); - } - foreach ($values as $key => $value) { - if (!self::isValue($value)) { - throw new InvalidArgumentException('La valeur ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentValue)'); - } - } - } - - /** - * La liste de tous les arguments ("value" et "option") - * - * @return IArgument[] La liste des arguments - */ - public function getArguments () { - return array_merge($this->getValues(), $this->getOptions()); - } - /** - * Modifie la liste de tous les arguments ("value" et "option") - * - * *Attention* : cette fonction _remplace_ la liste des arguments. - * Pour seulement en ajouter, utiliser {@see CommandLine::addArguments()} - * - * @param IArgumentValue[] $arguments La nouvelle liste d'arguments - * - * @return $this - */ - public function setArguments ($arguments) { - $this->setOptions(array()); - $this->setValues(array()); - - return $this->addArguments($arguments); - } - /** - * Ajoute des arguments "value" à celles existantes - * - * Pour ajouter un seul argument, il est conseillé d'utiliser {@see CommandLine::addArgument()} - * - * @param IArgument[]|IArgument $arguments La liste des arguments à ajouter - * - * @return $this - */ - public function addArguments ($arguments) { - if (!is_array($arguments) && $arguments instanceof IArgumentValue) { - $arguments = array($arguments); - } - self::_checkValueList($arguments); - - foreach ($arguments as $argument) { - $this->addArgument($argument); - } - - return $this; - } - /** - * Ajoute un seul argument ("value" ou "option") à ceux existants - * - * Pour ajouter plusieurs arguments à la fois, il est conseillé d'utiliser {@see CommandLine::addArguments()} - * - * @param IArgument $argument L'argument à ajouter - * - * @return $this - */ - public function addArgument ($argument) { - if (!self::isArgument($argument)) { - throw new InvalidArgumentException('L\'argument n\'est pas valide (n\'implémente pas IArgument)'); - } - - if (self::isOption($argument)) { - $this->addOption($argument); - } - elseif (self::isValue($argument)) { - $this->addValue($argument); - } - else { - $type = ''; - try { - $reflex = new ReflectionClass($argument); - foreach ($reflex->getInterfaces() as $interface) { - if ($interface->implementsInterface(IArgument::class)) { - $type = $interface->getName(); - break; - } - } - } - catch (ReflectionException $e) { - $type = ''; - } - - throw new InvalidArgumentException('L\'argument n\'est pas d\'un type géré : ' . $type); - } - - return $this; - } - /** - * Est-ce que l'argument ("value" ou "option") existe déjà ? - * - * @param string $argumentName Le nom de l'argument - * - * @return bool True si l'argument existe déjà, sinon False - */ - public function existsArgument ($argumentName) { - $arguments = $this->getArguments(); - foreach ($arguments as $argument) { - if ($argument->getName() == $argumentName) { - return true; - } - } - - return false; - } - /** - * Est-ce que c'est un argument ("value" ou "option") ? - * - * @param mixed $argument L'argument à tester - * - * @return bool True si c'est bien un argument, sinon False - */ - public static function isArgument ($argument) { - return $argument instanceof IArgument; - } - /** - * Vérifie que la liste d'arguments ("value" et "option") est valide - * - * Doit être un tableau et chaque élément doit implémenter {@see IArgument} - * - * @param IArgument[] $arguments Les arguments à vérifier - */ - protected static function _checkArgumentList ($arguments) { - if (!is_array($arguments)) { - throw new InvalidArgumentException('La liste des arguments n\'est pas un tableau'); - } - foreach ($arguments as $key => $argument) { - if (!self::isArgument($argument)) { - throw new InvalidArgumentException('L\'argument ' . $key . ' n\'est pas valide (n\'implémente pas IArgument)'); - } - } - } +setProgramName($programName); + $this->setDescription($mainDescription); + $this->setCommand($command); + $this->setVersion($version); + } + + /** + * La commande de lancement du programme + * + * NULL = {@see CommandLine::$_programName Nom du programme} + * + * @return string|null La commande + * @see CommandLine::$_command + */ + public function getCommand () { + return $this->_command; + } + /** + * Modifie la commande de lancement du programme + * + * @param string|null $command La nouvelle commande + * + * @return $this + * @see CommandLine::$_command + */ + public function setCommand ($command) { + $this->_command = $command; + return $this; + } + + /** + * Le nom du programme. + * + * @return string Le nom. + * @see CommandLine::$_programName + */ + public function getProgramName () { + return $this->_programName; + } + /** + * Modifie le nom du programme. + * + * @param string $programName Le nouveau nom + * + * @return $this + * @see CommandLine::$_programName + */ + public function setProgramName ($programName) { + $this->_programName = $programName; + return $this; + } + + /** + * La description du programme + * + * @return string La description + * @see CommandLine::$_description + */ + public function getDescription () { + return $this->_description; + } + /** + * Modifie la description du programme. + * + * @param string $description La nouvelle description. + * + * @return $this + * @see CommandLine::$_description + */ + public function setDescription ($description) { + $this->_description = $description; + return $this; + } + + /** + * La version du programme + * + * @return string|null La version + * @see CommandLine::$_version + */ + public function getVersion () { + return $this->_version; + } + /** + * Modifie la version du programme. + * + * @param string|null $version La nouvelle version. + * + * @return $this + * @see CommandLine::$_version + */ + public function setVersion ($version) { + $this->_version = $version; + return $this; + } + + /** + * La liste des arguments "value" + * + * @return IArgumentValue[] La liste des valeurs + * @see CommandLine::$_arguments_values + */ + public function getValues () { + return $this->_arguments_values; + } + /** + * Modifie la liste des arguments "value" + * + * *Attention* : cette fonction _remplace_ la liste des valeurs. + * Pour seulement en ajouter, utiliser {@see CommandLine::addValues()} + * + * @param IArgumentValue[] $values La nouvelle liste de valeurs + * + * @return $this + * @see CommandLine::$_arguments_values + */ + public function setValues ($values) { + self::_checkValueList($values); + + $this->_arguments_values = $values; + return $this; + } + /** + * Ajoute des arguments "value" à celles existantes + * + * Pour ajouter une seule valeur, il est conseillé d'utiliser {@see CommandLine::addValue()} + * + * @param IArgumentValue[]|IArgumentValue $values La liste des valeurs à ajouter + * + * @return $this + * @see CommandLine::$_arguments_values + */ + public function addValues ($values) { + if (!is_array($values) && $values instanceof IArgumentValue) { + $values = array($values); + } + self::_checkValueList($values); + + $this->_arguments_values = array_merge($this->_arguments_values, $values); + return $this; + } + /** + * Ajoute un seul argument "value" à celles existantes + * + * Pour ajouter plusieurs valeurs à la fois, il est conseillé d'utiliser {@see CommandLine::addValues()} + * + * @param IArgumentValue $value La valeur à ajouter + * + * @return $this + * @see CommandLine::$_arguments_values + */ + public function addValue ($value) { + return $this->addValues(array($value)); + } + /** + * Est-ce que l'argument "value" existe déjà ? + * + * @param string $valueName Le nom de la valeur + * + * @return bool True si la valeur existe déjà, sinon False + */ + public function existsValue ($valueName) { + foreach ($this->_arguments_values as $option) { + if ($option->getName() == $valueName) { + return true; + } + } + + return false; + } + /** + * Est-ce que c'est un argument "value" ? + * + * @param mixed $argument L'argument à tester + * + * @return bool True si c'est bien un argument "value", sinon False + */ + public static function isValue ($argument) { + return $argument instanceof IArgumentValue; + } + /** + * Vérifie que la liste d'arguments "value" est valide + * + * Doit être un tableau et chaque élément doit implémenter {@see IArgumentValue} + * + * @param IArgumentValue[] $values Les valeurs à vérifier + */ + protected static function _checkValueList ($values) { + if (!is_array($values)) { + throw new InvalidArgumentException('La liste des valeurs n\'est pas un tableau'); + } + foreach ($values as $key => $value) { + if (!self::isValue($value)) { + throw new InvalidArgumentException('La valeur ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentValue)'); + } + } + } + + /** + * La liste des arguments "option" + * + * @return IArgumentOption[] La liste des options + * @see CommandLine::$_arguments_options + */ + public function getOptions () { + return $this->_arguments_options; + } + /** + * Modifie la liste des arguments "option" + * + * *Attention* : cette fonction _remplace_ la liste des options. + * Pour seulement en ajouter, utiliser {@see CommandLine::addOptions()} + * + * @param IArgumentOption[] $options La nouvelle liste d'options + * + * @return $this + * @see CommandLine::$_arguments_options + */ + public function setOptions ($options) { + self::_checkOptionList($options); + + $this->_arguments_options = $options; + return $this; + } + /** + * Ajoute des arguments "option" à ceux existants + * + * Pour ajouter une seule option, il est conseillé d'utiliser {@see CommandLine::addOption()} + * + * @param IArgumentOption[]|IArgumentOption $options La liste d'options à ajouter + * + * @return $this + * @see CommandLine::$_arguments_options + */ + public function addOptions ($options) { + if (!is_array($options) && $options instanceof IArgumentOption) { + $options = array($options); + } + self::_checkOptionList($options); + + $this->_arguments_options = array_merge($this->_arguments_options, $options); + return $this; + } + /** + * Ajoute un seul argument "option" à ceux existants + * + * Pour ajouter plusieurs options à la fois, il est conseillé d'utiliser {@see CommandLine::addOptions()} + * + * @param IArgumentOption $option L'options à ajouter + * + * @return $this + * @see CommandLine::$_arguments_options + */ + public function addOption ($option) { + return $this->addOptions(array($option)); + } + /** + * Est-ce que l'argument "option" existe déjà ? + * + * @param string $optionName Le nom de l'option + * + * @return bool True si l'option existe déjà, sinon False + */ + public function existsOption ($optionName) { + foreach ($this->_arguments_options as $option) { + if ($option->getName() == $optionName) { + return true; + } + } + + return false; + } + /** + * Est-ce que c'est un argument "option" ? + * + * @param mixed $argument L'argument à tester + * + * @return bool True si c'est bien un argument "option", sinon False + */ + public static function isOption ($argument) { + return $argument instanceof IArgumentOption; + } + /** + * Vérifie que la liste d'arguments "option" est valide + * + * Doit être un tableau et chaque élément doit implémenter {@see IArgumentOption} + * + * @param IArgumentOption[] $options Les options à vérifier + */ + protected static function _checkOptionList ($options) { + if (!is_array($options)) { + throw new InvalidArgumentException('La liste des options n\'est pas un tableau'); + } + foreach ($options as $key => $option) { + if (!self::isOption($option)) { + throw new InvalidArgumentException('L\'option ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentOption)'); + } + } + } + + /** + * La liste de tous les arguments ("value" et "option") + * + * @return IArgument[] La liste des arguments + */ + public function getArguments () { + return array_merge($this->getValues(), $this->getOptions()); + } + /** + * Modifie la liste de tous les arguments ("value" et "option") + * + * *Attention* : cette fonction _remplace_ la liste des arguments. + * Pour seulement en ajouter, utiliser {@see CommandLine::addArguments()} + * + * @param IArgumentValue[] $arguments La nouvelle liste d'arguments + * + * @return $this + */ + public function setArguments ($arguments) { + $this->setOptions(array()); + $this->setValues(array()); + + return $this->addArguments($arguments); + } + /** + * Ajoute des arguments "value" à celles existantes + * + * Pour ajouter un seul argument, il est conseillé d'utiliser {@see CommandLine::addArgument()} + * + * @param IArgument[]|IArgument $arguments La liste des arguments à ajouter + * + * @return $this + */ + public function addArguments ($arguments) { + if (!is_array($arguments) && $arguments instanceof IArgumentValue) { + $arguments = array($arguments); + } + self::_checkValueList($arguments); + + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + + return $this; + } + /** + * Ajoute un seul argument ("value" ou "option") à ceux existants + * + * Pour ajouter plusieurs arguments à la fois, il est conseillé d'utiliser {@see CommandLine::addArguments()} + * + * @param IArgument $argument L'argument à ajouter + * + * @return $this + */ + public function addArgument ($argument) { + if (!self::isArgument($argument)) { + throw new InvalidArgumentException('L\'argument n\'est pas valide (n\'implémente pas IArgument)'); + } + + if (self::isOption($argument)) { + /** @var IArgumentOption $argument */ + $this->addOption($argument); + } + elseif (self::isValue($argument)) { + /** @var IArgumentValue $argument */ + $this->addValue($argument); + } + else { + $type = ''; + try { + $reflex = new ReflectionClass($argument); + foreach ($reflex->getInterfaces() as $interface) { + if ($interface->implementsInterface(IArgument::class)) { + $type = $interface->getName(); + break; + } + } + } + catch (ReflectionException $e) { + $type = ''; + } + + throw new InvalidArgumentException('L\'argument n\'est pas d\'un type géré : ' . $type); + } + + return $this; + } + /** + * Est-ce que l'argument ("value" ou "option") existe déjà ? + * + * @param string $argumentName Le nom de l'argument + * + * @return bool True si l'argument existe déjà, sinon False + */ + public function existsArgument ($argumentName) { + $arguments = $this->getArguments(); + foreach ($arguments as $argument) { + if ($argument->getName() == $argumentName) { + return true; + } + } + + return false; + } + /** + * Est-ce que c'est un argument ("value" ou "option") ? + * + * @param mixed $argument L'argument à tester + * + * @return bool True si c'est bien un argument, sinon False + */ + public static function isArgument ($argument) { + return $argument instanceof IArgument; + } + /** + * Vérifie que la liste d'arguments ("value" et "option") est valide + * + * Doit être un tableau et chaque élément doit implémenter {@see IArgument} + * + * @param IArgument[] $arguments Les arguments à vérifier + */ + protected static function _checkArgumentList ($arguments) { + if (!is_array($arguments)) { + throw new InvalidArgumentException('La liste des arguments n\'est pas un tableau'); + } + foreach ($arguments as $key => $argument) { + if (!self::isArgument($argument)) { + throw new InvalidArgumentException('L\'argument ' . $key . ' n\'est pas valide (n\'implémente pas IArgument)'); + } + } + } + + /** + * Ajoute les options communes à la plupart des programmes + * + * Voici la liste des options générées : + * - Aide : --help ou -h + * - Version : --version ou -v (voir $shortForVersion) + * + * @param bool $shortForVersion L'option pour la version existe également au format "court" (-v) + * + * @return $this + */ + public function addDefaultArguments ($shortForVersion = true) { + if (!$this->existsOption(self::ARGUMENT_OPTION_HELP)) { + $this->addOption( + (new Argument\Option\Flag(self::ARGUMENT_OPTION_HELP, false, 'Affiche cette aide', 'help', 'h')) + ->setStoppingParse(true) + ); + } + + if (!$this->existsOption(self::ARGUMENT_OPTION_HELP) && !is_null($this->getVersion())) { + $this->addOption( + (new Argument\Option\Flag(self::ARGUMENT_OPTION_VERSION, false, 'Affiche la version', 'version', $shortForVersion ? 'v' : null)) + ->setStoppingParse(true) + ); + } + + return $this; + } + /** + * Auto-lance les fonctions correspondantes aux options communes. + * + * @param stdClass $values Les valeurs du parsage + * @param boolean $exitAtEnd Terminer le script à la fin de la fonction correspondante ? + */ + public function treatDefaultArguments ($values, $exitAtEnd = true) { + if ($values->{self::ARGUMENT_OPTION_HELP} === true) { + $this->showHelp($exitAtEnd); + } + + if ($values->{self::ARGUMENT_OPTION_VERSION} === true) { + $this->showVersion($exitAtEnd); + } + } + + /** + * Affiche la version du programme + * + * @param boolean $exitAtEnd Terminer le script à la fin de la fonction ? + * + * @see CommandLine::getVersion() + */ + public function showVersion ($exitAtEnd = true) { + echo $this->getVersion() . "\n"; + + if ($exitAtEnd) { + exit(0); + } + } + /** + * Affiche l'aide du programme. + * + * @param boolean $exitAtEnd Terminer le script à la fin de la fonction ? + * + * @see CommandLine::generateHelp() + */ + public function showHelp ($exitAtEnd = true) { + echo $this->generateHelp() . "\n"; + + if ($exitAtEnd) { + exit(0); + } + } + /** + * Génère l'aide du programme. + * + * @return string Le texte de l'aide. + * + * @see CommandLine::showHelp() + */ + public function generateHelp () { + $help = array(); + + $help[] = $this->getProgramName() . (is_null($this->getVersion()) ? '' : ', version ' . $this->getVersion()); + $help[] = $this->getDescription(); + $help[] = ''; + + $syntax = array( + $this->getCommand(), + count($this->getOptions()) > 0 ? '[OPTIONS]' : '', + ); + $syntax = array_merge($syntax, array_map(array(__CLASS__, '_getSyntaxOfValue'), $this->getValues())); + + $help[] = implode(' ', $syntax); + + $help[] = 'Arguments :'; + $help = array_merge($help, self::_getValuesListing($this->getValues())); + $help[] = ''; + + $help[] = 'Options :'; + $help = array_merge($help, self::_getOptionsListing($this->getOptions())); + $help[] = ''; + + return implode("\n", $help); + } + + /** + * La syntax d'un argument "value" + * + * @param IArgumentValue $value L'argument + * + * @return string La syntax de l'argument + * @see generateHelp() + */ + protected static function _getSyntaxOfValue (IArgumentValue $value) { + $syntax = ''; + + $min = $value->getOccurMin(); + $max = $value->getOccurMax(); + if (is_null($max)) { + $max = -1; + } + + if ($min == 0) { + $syntax .= '['; + } + + $syntax .= $value->getName(); + for ($curr = 2; $curr <= $min; $curr++) { + $syntax .= ' ' . $value->getName() . $curr; + } + + if ($max === -1 || $max > 1) { + if ($min < 2) { + $syntax .= ' [' . $value->getName() . '2]'; + } + + $syntax .= ' ... [' . $value->getName() . ($max === -1 ? 'N' : $max) . ']'; + } + + if ($min == 0) { + $syntax .= ']'; + } + + return $syntax; + } + /** + * Genère l'aide d'une liste d'arguments "value" + * + * @param IArgumentValue[] $values La liste des valeurs + * + * @return string[] L'aide de chaque valeur + */ + protected static function _getValuesListing ($values) { + /* + * Calcul des différents padding + */ + // Initialisation + $pads = new stdClass; + $pads->name = 0; + $pads->occurMin = 0; + $pads->occurMax = 0; + $pads->valueDescription = 0; + + // Lecture des arguments + foreach ($values as $value) { + $pads->name = max($pads->name, strlen($value->getName())); + + $max = $value->getOccurMax(); + $pads->occurMin = max($pads->occurMin, strlen($value->getOccurMin())); + $pads->occurMax = max($pads->occurMax, strlen(is_null($max) ? 'N' : $max)); + + if ($value instanceof IArgumentValueDescription) { + $pads->valueDescription = max($pads->valueDescription, strlen($value->getValueDescription())); + } + } + + /* + * Génération des descriptifs + */ + $entries = array(); + foreach ($values as $value) { + $label = str_pad($value->getName(), $pads->name, ' ', STR_PAD_RIGHT); + + $max = $value->getOccurMax(); + + $occur = ''; + $occur .= str_pad($value->getOccurMin(), $pads->occurMin, ' ', STR_PAD_LEFT); + $occur .= ' => '; + $occur .= str_pad(is_null($max) ? 'N' : $max, $pads->occurMax, ' ', STR_PAD_RIGHT); + + $valueDescription = str_pad( + $value instanceof IArgumentValueDescription ? $value->getValueDescription() : '', + $pads->valueDescription, + ' ', + STR_PAD_RIGHT + ); + + $entries[] = self::TAB . implode(self::TAB, array( + $label, + $occur, + $valueDescription, + preg_replace( + /** @lang RegExp */ '@\r?\n@', + '$0' . self::TAB . implode(self::TAB, array( + str_pad('', $pads->name, ' '), + str_pad('', $pads->occurMin + 4 + $pads->occurMax, ' '), + str_pad('', $pads->valueDescription, ' '), + '', + ) + ), + $value->getDescription() + ), + ) + ); + } + + return $entries; + } + /** + * Genère l'aide d'une liste d'arguments "option" + * + * @param IArgumentOption[] $options La liste des options + * + * @return string[] L'aide de chaque option + */ + protected static function _getOptionsListing ($options) { + /* + * Calcul des différents padding + */ + // Initialisation + $pads = new stdClass; + $pads->tagShort = 0; + $pads->tagLong = 0; + $pads->valueDescription = 0; + + // Lecture des arguments + foreach ($options as $option) { + $short = $option->getTagShort(); + if (!is_null($short)) { + $pads->tagShort = max($pads->tagShort, strlen($short)); + } + $pads->tagLong = max($pads->tagLong, strlen($option->getTagLong())); + + if ($option instanceof IArgumentValueDescription) { + $pads->valueDescription = max($pads->valueDescription, strlen($option->getValueDescription())); + } + } + + // Les tags ont une taille suplémentaire incompressible + $pads->tagShort += 1; + $pads->tagLong += 2; + + /* + * Génération des descriptifs + */ + $entries = array(); + foreach ($options as $option) { + $short = $option->getTagShort(); + + $label = ''; + $label .= str_pad(is_null($short) ? '' : '-' . $short, $pads->tagShort, ' ', STR_PAD_RIGHT); + $label .= ' '; + $label .= str_pad('--' . $option->getTagLong(), $pads->tagLong, ' ', STR_PAD_RIGHT); + $label .= $option->allowMultiple() ? ' *' : ($option->isStoppingParse() ? ' X' : ' '); + + $valueDescription = str_pad( + $option instanceof IArgumentValueDescription ? $option->getValueDescription() : '', + $pads->valueDescription, + ' ', + STR_PAD_RIGHT + ); + + $entries[] = self::TAB . self::TAB . implode(self::TAB, array( + $label, + $valueDescription, + preg_replace( + /** @lang RegExp */ '@\r?\n@', + '$0' . self::TAB . self::TAB . implode(self::TAB, array( + str_pad('', $pads->tagShort + 1 + $pads->tagLong + 2, ' '), + str_pad('', $pads->valueDescription, ' '), + '', + ) + ), + $option->getDescription() + ), + ) + ); + } + + return $entries; + } + + /** + * Traite les arguments du script + * + * Revient à appeler {@see CommandLine::parseExplicit()} avec les arguments du script {@link https://www.php.net/manual/en/reserved.variables.argv.php $_SERVER['argv']} + * + * @return stdClass Les valeurs extraites + * @throws MissingArgument Quand un argument de la liste est manquant ou en quantité insuffisante + * @throws TooMuchValues Quand il reste des valeurs supplémentaires après le traitement de la liste d'arguments + */ + public function parse () { + $argv = $_SERVER['argv']; + array_shift($argv); // Supprime le 1er paramètre : le nom du script PHP + + return $this->parseExplicit($argv); + } + /** + * Traite une liste d'arguments. + * + * 1/ Vérifie que la liste d'arguments correspond à la syntaxe de la ligne de commande + * 2/ Extrait les valeurs voulues de la liste d'arguments + * + * @param string[] $argv La liste d'arguments + * + * @return stdClass Les valeurs extraites + * @throws MissingArgument Quand un argument de la liste est manquant ou en quantité insuffisante + * @throws TooMuchValues Quand il reste des valeurs supplémentaires après le traitement de la liste d'arguments + */ + public function parseExplicit ($argv) { + $stop = false; + $nb_args = count($argv); + + $out = $this->_parseOptions($argv, $this->getOptions(), $stop); + if ($stop) { + return $out; + } + + $values = array_values($this->getValues()); + /** + * @var int $ordre + * @var IArgumentValue $value + */ + foreach ($values as $ordre => $value) { + $min = $value->getOccurMin(); + self::_parseXTimes($argv, $out, $value, $min); + + $max = $value->getOccurMax(); + if (is_null($max) || $max > $min) { + $nbArgs = $this->_getNbArgumentRestant($ordre); + if ($nbArgs >= 0 && count($argv) > $nbArgs) { + $nbParse = count($argv) - $nbArgs; + if (!is_null($max)) { + $nbParse = min($nbParse, $max - $min); + } + + self::_parseXTimes($argv, $out, $value, $nbParse, $min); + } + } + } + + if (count($argv)) { + throw new TooMuchValues('Trop de paramètres : '.count($argv).' / '.$nb_args); + } + + // Valeurs par défaut + foreach ($this->getOptions() as $option) { + if (!isset($out->{$option->getVarName()})) { + $out->{$option->getVarName()} = $option->getDefault(); + } + } + foreach ($values as $value) { + if (!isset($out->{$value->getVarName()})) { + $out->{$value->getVarName()} = $value->getDefault(); + } + } + + return $out; + } + /** + * Calcule le nombre d'argument "value" restant à honorer. + * + * @param int $ordre_start L'ordre de la valeur en cours + * + * @return int Le nombre de valeurs restantes à traiter, ou -1 si un nombre "illimité" + */ + protected function _getNbArgumentRestant ($ordre_start) { + $nb = 0; + /** + * @var int $ordre + * @var IArgumentValue $argument + */ + foreach (array_values($this->getValues()) as $ordre => $argument) { + if ($ordre <= $ordre_start) { + continue; + } + + $max = $argument->getOccurMax(); + if (is_null($max)) { + return -1; + } + + $nb += $max; + } + + return $nb; + } + /** + * Parse des arguments "option" + * + * @param string[] $argv La liste des arguments du script + * @param IArgumentOption[] $options La liste des options + * @param boolean $stop Arrêt du parsage ? + * + * @return stdClass Les options extraites + * @throws IncorrectParse Si le parsage d'une des options échoue + */ + protected static function _parseOptions (&$argv, $options, &$stop) { + $values = new stdClass(); + $stop = false; + + foreach ($options as $option) { + do { + $argv_option = $argv; + + $find = false; + while (count($argv_option) > 0) { + $result = $option->parse($argv_option); + + if (!is_null($result)) { + if ($option->isStoppingParse()) { + $values = new stdClass(); + } + + self::_setValue($values, $option, $result, $option->allowMultiple() ? 2 : 1); + + if ($option->isStoppingParse()) { + $stop = true; + return $values; + } + + array_splice($argv, count($argv) - count($argv_option), $result->getConsume()); + $find = true; + break; + } + + array_shift($argv_option); + } + } while (count($argv_option) > 1 && (!$find || $option->allowMultiple())); + } + + return $values; + } + /** + * Parse un argument "value" X fois + * + * @param string[] $argv Liste des arguments du script + * @param stdClass $out Les valeurs de sortie + * @param IArgumentValue $value L'argument "value" à parser + * @param int $xTimes Le nombre de fois à parser + * @param int $offset L'offset pour le n° d'occurence + * + * @throws MissingArgument Si l'argument n'est pas en quantité suffisante + * @throws IncorrectParse Si l'argument échoue à se parser + */ + protected static function _parseXTimes (&$argv, &$out, $value, $xTimes, $offset = 0) { + if ($xTimes > count($argv)) { + throw new MissingArgument('L\'argument ' . $value->getName() . ' est en quantité insuffisante (' . count($argv) . ' / ' . $xTimes . ')'); + } + + for ($curr = 1; $curr <= $xTimes; $curr++) { + $result = $value->parse($argv); + if (is_null($result)) { + throw new MissingArgument('L\'occurence n° ' . ($offset + $curr) . ' de l\'argument ' . $value->getName() . ' ne correspond pas'); + } + + self::_setValue($out, $value, $result, $value->getOccurMax()); + $argv = array_slice($argv, $result->getConsume()); + } + } + /** + * Ajoute le résultat d'un argument "value" ou "option") aux valeurs de sortie + * + * @param stdClass $out Les valeurs de sortie, auxquelles ajouter la résultat + * @param IArgument $argument L'argument actuel + * @param ParseResult $result Le résultat du parsage de l'argument + * @param int|null $max Le nombre maximum de valeur autorisé + */ + protected static function _setValue (&$out, $argument, $result, $max) { + if (is_null($max) || $max > 1) { + if (!isset($out->{$argument->getVarName()})) { + $out->{$argument->getVarName()} = array(); + } + + $out->{$argument->getVarName()}[] = $result->getValue(); + } + else { + $out->{$argument->getVarName()} = $result->getValue(); + } + } } \ No newline at end of file diff --git a/Solution.class.php b/Solution.class.php deleted file mode 100644 index 06ca8f7..0000000 --- a/Solution.class.php +++ /dev/null @@ -1,279 +0,0 @@ -_arguments)) - throw new InvalidArgument($order, 'Cet ordre est déjà utilisé pour un autre argument'); - - $this->_arguments[$order] = $argument; - return $this; - } - /** - * Liste des arguments de la solution. - * - * @return IArgumentValue[] Les arguments. - */ - public function getArguments () { - ksort($this->_arguments); - return $this->_arguments; - } - /** - * Le prochain ordre disponible pour un argument - * - * @return int La prochaine position - */ - public function getNextOrder () { - $keys = array_keys($this->_arguments); - if(count($keys) < 1) - return 1; - - return max($keys) + 1; - } - - /** - * Ajoute une option - * - * @param IArgumentOption $option L'option - * - * @return $this - * - * @throws InvalidArgument Si les arguments secondaires (le cas échéant) sont invalides. - * - * @see $_options - */ - public function addOption (IArgumentOption $option) { - if(array_key_exists($option->getName(), $this->_options)) - throw new InvalidArgument($option, 'Il existe déjà une autre option avec le même nom'); - - $this->_options[$option->getName()] = $option; - - if($option instanceof IArgumentOptionSecondary) { - foreach($option->getOthersOptions() as $option_second) - $this->addOption($option_second); - } - - return $this; - } - /** - * Liste des options de la solution. - * - * @return IArgumentOption[] Les options. - */ - public function getOptions () { - return $this->_options; - } - - /** - * Traite la solution pour en sortir les valeurs. - * - * @param string[] $argv La liste des arguments - * @param IArgumentOption[] $common_options La liste des options communes - * - * @return stdClass Les valeurs extraites. - * @throws MissingArgument Quand un argument est manquant ou en quantité insuffisante - * @throws InvalidArgument Quand un argument n'arrive pas à parser sa valeur - * @throws TooMuchValues Quand la solution ne consumme pas la totalité des arguments - */ - public function parseExplicit ($argv, $common_options) { - $stop = false; - /** @var IArgumentOption[] $options */$options = array_merge($common_options, $this->getOptions()); - - $values = $this->_parseOptions($argv, $options, $stop); - if($stop) - return $values; - - $arguments = $this->getArguments(); - foreach($arguments as $ordre => $argument) { - $min = $argument->getOccurMin(); - self::_parseXTimes($argv, $values, $argument, $min); - - $max = $argument->getOccurMax(); - if(is_null($max) || $max > $min) { - $nbArgs = $this->_getNbArgumentRestant($ordre); - if($nbArgs >= 0 && count($argv) > $nbArgs) { - $nbParse = count($argv) - $nbArgs; - if(!is_null($max)) - $nbParse = min($nbParse, $max - $min); - - self::_parseXTimes($argv, $values, $argument, $nbParse, $min); - } - } - } - - if(count($argv)) - throw new TooMuchValues($argv, 'Trop de paramètres'); - - // Valeurs par défaut - foreach($options as $option) { - if(!isset($values->{$option->getVarName()})) - $values->{$option->getVarName()} = $option->getDefault(); - } - foreach($arguments as $argument) { - if(!isset($values->{$argument->getVarName()})) - $values->{$argument->getVarName()} = $argument->getDefault(); - } - - return $values; - } - /** - * Parse des options. - * - * @param string[] $argv La liste des arguments - * @param IArgumentOption[] $options La liste des options - * @param boolean $stop Arrêt du parsage ? - * - * @return stdClass Les options extraites - * @throws IncorrectParse Si le parsage d'une des options échoue - */ - protected static function _parseOptions (&$argv, $options, &$stop) { - $values = new stdClass(); - $stop = false; - - foreach($options as $option) { - do { - $argv_option = $argv; - - $find = false; - while(count($argv_option) > 0) { - $result = $option->parse($argv_option); - - if(!is_null($result)) { - if($option->isStoppingParse()) - $values = new stdClass(); - - self::_setValue($values, $option, $result, $option->allowMultiple() ? 2 : 1); - - if($option->isStoppingParse()) { - $stop = true; - return $values; - } - - array_splice($argv, count($argv) - count($argv_option), $result->getConsume()); - $find = true; - break; - } - - array_shift($argv_option); - } - } while(count($argv_option) > 1 && (!$find || $option->allowMultiple())); - } - - return $values; - } - - /** - * Parse un argument X fois - * - * @param string[] $argv Liste des arguments - * @param stdClass $values Les valeurs de sortie - * @param IArgumentValue $argument L'argument à parser - * @param int $xTimes Le nombre de fois à parser - * @param int $offset L'offset pour le n° d'occurence - * - * @throws MissingArgument Si l'argument n'est pas en quantité suffisante - * @throws IncorrectParse Si l'argument échoue à se parser - */ - protected static function _parseXTimes (&$argv, &$values, $argument, $xTimes, $offset = 0) { - if($xTimes > count($argv)) - throw new MissingArgument($argument, 'L\'argument est en quantité insuffisante (' . count($argv) . ' / ' . $xTimes . ')'); - - for($curr = 1; $curr <= $xTimes; $curr++) { - $result = $argument->parse($argv); - if(is_null($result)) - throw new MissingArgument($argument, 'L\'occurence n° ' . ($offset + $curr) . ' de l\'argument ne correspond pas'); - - self::_setValue($values, $argument, $result, $argument->getOccurMax()); - $argv = array_slice($argv, $result->getConsume()); - } - } - /** - * Ajoute le résultat d'un argument aux valeurs de sortie - * - * @param stdClass $values Les valeurs de sortie, auxquelles ajouter la résultat - * @param IArgument $argument L'argument actuel - * @param ParseResult $result Le résultat de l'argument - * @param int|null $max Le nombre max de valeur autorisé - */ - protected static function _setValue (&$values, $argument, $result, $max) { - if(is_null($max) || $max > 1) { - if(!isset($values->{$argument->getVarName()})) - $values->{$argument->getVarName()} = array(); - - $values->{$argument->getVarName()}[] = $result->getValue(); - } - else - $values->{$argument->getVarName()} = $result->getValue(); - } - /** - * Calcule le nombre d'argument restant à honorer. - * - * @param int $ordre_start L'ordre de l'argument en cours - * - * @return int Le nombre d'argument restant, ou -1 si un argument "illimité" - */ - protected function _getNbArgumentRestant ($ordre_start) { - $nb = 0; - foreach($this->getArguments() as $ordre => $argument) { - if($ordre <= $ordre_start) - continue; - - $max = $argument->getOccurMax(); - if(is_null($max)) - return -1; - - $nb += $max; - } - - return $nb; - } -} \ No newline at end of file