/**
* @param array $argv
* @return OptionResult|Option[]
* @throws Exception\RequireValueException
* @throws Exception\InvalidOptionException
* @throws \Exception
*/
public function parse(array $argv)
{
$result = new OptionResult();
$argv = $this->preprocessingArguments($argv);
foreach ($this->specs as $spec) {
if ($spec->defaultValue !== null) {
$result->set($spec->getId(), $spec);
}
}
$len = count($argv);
for ($i = 0; $i < $len; ++$i) {
$arg = new Argument($argv[$i]);
// if looks like not an option, push it to argument list.
// TODO: we might want to support argument with preceding dash (?)
if (!$arg->isOption()) {
$result->addArgument($arg);
continue;
}
// if the option is with extra flags,
// split the string, and insert into the argv array
if ($arg->withExtraFlagOptions()) {
$extra = $arg->extractExtraFlagOptions();
array_splice($argv, $i + 1, 0, $extra);
$argv[$i] = $arg->arg;
// update argument to current argv list.
$len = count($argv);
// update argv list length
}
$next = null;
if ($i + 1 < count($argv)) {
$next = new Argument($argv[$i + 1]);
}
$spec = $this->specs->get($arg->getOptionName());
if (!$spec) {
throw new InvalidOptionException("Invalid option: " . $arg);
}
if ($spec->isRequired()) {
if (!$this->foundRequireValue($spec, $arg, $next)) {
throw new RequireValueException("Option {$arg->getOptionName()} requires a value. given '{$next}'");
}
$this->takeOptionValue($spec, $arg, $next);
if ($next && !$next->anyOfOptions($this->specs)) {
$i++;
}
$result->set($spec->getId(), $spec);
} elseif ($spec->isMultiple()) {
$this->pushOptionValue($spec, $arg, $next);
if ($next && $next->isOption()) {
$i++;
}
$result->set($spec->getId(), $spec);
} elseif ($spec->isOptional()) {
$this->takeOptionValue($spec, $arg, $next);
if (($spec->value || $spec->defaultValue) && $next && !$next->isOption()) {
$i++;
}
$result->set($spec->getId(), $spec);
} elseif ($spec->isIncremental()) {
$spec->increaseValue();
$result->set($spec->getId(), $spec);
} elseif ($spec->isFlag()) {
$spec->setValue(true);
$result->set($spec->getId(), $spec);
} else {
throw new Exception('Unknown attribute.');
}
}
return $result;
}