8000 Created CommandLineParser. · kler/getopt-php@47e5f46 · GitHub
[go: up one dir, main page]

Skip to content

Commit 47e5f46

Browse files
committed
Created CommandLineParser.
< 10000 /div>
1 parent f34700c commit 47e5f46

File tree

6 files changed

+638
-454
lines changed

6 files changed

+638
-454
lines changed
Lines changed: 203 additions & 0 deletions
107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
<?php
2+
3+
namespace Ulrichsg\Getopt;
4+
5+
class CommandLineParser
6+
{
7+
/** @var Option[] */
8+
private $optionList;
9+
10+
private $options = array();
11+
private $operands = array();
12+
13+
public function __construct(array $optionList)
14+
{
15+
$this->optionList = $optionList;
16+
}
17+
18+
public function parse($arguments)
19+
{
20+
if (!is_array($arguments)) {
21+
$arguments = explode(' ', $arguments);
22+
}
23+
$operands = array();
24+
$numArgs = count($arguments);
25+
for ($i = 0; $i < $numArgs; ++$i) {
26+
$arg = trim($arguments[$i]);
27+
if (empty($arg)) {
28+
continue;
29+
}
30+
if ($arg == '--' || mb_substr($arg, 0, 1) != '-') {
31+
// no more options, treat the remaining arguments as operands
32+
$firstOperandIndex = $arg == '--' ? $i + 1 : $i;
33+
$operands = array_slice($arguments, $firstOperandIndex);
34+
break;
35+
}
36+
if (mb_substr($arg, 0, 2) == '--') {
37+
$this->addLongOption($arguments, $i);
38+
} else {
39+
$this->addShortOption($arguments, $i);
40+
}
41+
} // endfor
42+
43+
$this->addDefaultValues();
44+
45+
// remove '--' from operands array
46+
foreach ($operands as $operand) {
47+
if ($operand !== '--') {
48+
$this->operands[] = $operand;
49+
}
50+
}
51+
}
52+
53+
public function getOptions()
54+
{
55+
return $this->options;
56+
}
57+
58+
public function getOperands()
59+
{
60+
return $this->operands;
61+
}
62+
63+
private function addShortOption($arguments, &$i)
64+
{
65+
$numArgs = count($arguments);
66+
$option = mb_substr($arguments[$i], 1);
67+
if (mb_strlen($option) > 1) {
68+
// multiple options strung together
69+
$options = $this->splitString($option, 1);
70+
foreach ($options as $j => $ch) {
71+
if ($j < count($options) - 1
72+
|| !(
73+
$i < $numArgs - 1
74+
&& mb_substr($arguments[$i + 1], 0, 1) != '-'
75+
&& $this->optionHasArgument($ch)
76+
)
77+
) {
78+
$this->addOption($ch, null);
79+
} else { // e.g. `ls -sw 100`
80+
$value = $arguments[$i + 1];
81+
++$i;
82+
$this->addOption($ch, $value);
83+
}
84+
}
85+
} else {
86+
if ($i < $numArgs - 1
87+
&& mb_substr($arguments[$i + 1], 0, 1) != '-'
88+
&& $this->optionHasArgument($option)
89+
) {
90+
$value = $arguments[$i + 1];
91+
++$i;
92+
} else {
93+
$value = null;
94+
}
95+
$this->addOption($option, $value);
96+
}
97+
}
98+
99+
private function addLongOption($arguments, &$i)
100+
{
101+
$option = mb_substr($arguments[$i], 2);
102+
if (strpos($option, '=') === false) {
103+
if ($i < count($arguments) - 1
104+
&& mb_substr($arguments[$i + 1], 0, 1) != '-'
105+
&& $this->optionHasArgument($option)
106+
) {
+
$value = $arguments[$i + 1];
108+
++$i;
109+
} else {
110+
$value = null;
111+
}
112+
} else {
113+
list($option, $value) = explode('=', $option, 2);
114+
}
115+
$this->addOption($option, $value);
116+
}
117+
118+
/**
119+
* Add an option to the list of known options.
120+
*
121+
* @param string $string the option's name
122+
* @param string $value the option's value (or null)
123+
* @throws \UnexpectedValueException
124+
* @return void
125+
*/
126+
private function addOption($string, $value)
127+
{
128+
foreach ($this->optionList as $option) {
129+
if ($option->matches($string)) {
130+
if ($option->mode() == Getopt::REQUIRED_ARGUMENT && !mb_strlen($value)) {
131+
throw new \UnexpectedValueException("Option '$string' must have a value");
132+
}
133+
// for no-argument options, check if they are duplicate
134+
if ($option->mode() == Getopt::NO_ARGUMENT) {
135+
$oldValue = isset($this->options[$string]) ? $this->options[$string] : null;
136+
$value = is_null($oldValue) ? 1 : $oldValue + 1;
137+
}
138+
// for optional-argument options, set value to 1 if none was given
139+
$value = (mb_strlen($value) > 0) ? $value : 1;
140+
// add both long and short names (if they exist) to the option array to facilitate lookup
141+
if ($option->short()) {
142+
$this->options[$option->short()] = $value;
143+
}
144+
if ($option->long()) {
145+
$this->options[$option->long()] = $value;
146+
}
147+
return;
148+
}
149+
}
150+
throw new \UnexpectedValueException("Option '$string' is unknown");
151+
}
152+
153+
/**
154+
* If there are options with default values that were not overridden by the parsed option string,
155+
* add them to the list of known options.
156+
*/
157+
private function addDefaultValues()
158+
{
159+
foreach ($this->optionList as $option) {
160+
if ($option->hasDefaultValue()
161+
&& !isset($this->options[$option->short()])
162+
&& !isset($this->options[$option->long()])
163+
) {
164+
if ($option->short()) {
165+
$this->addOption($option->short(), $option->getDefaultValue());
166+
}
167+
if ($option->long()) {
168+
$this->addOption($option->long(), $option->getDefaultValue());
169+
}
170+
}
171+
}
172+
}
173+
174+
/**
175+
* Return true if the given option can take an argument, false if it can't or is unknown.
176+
*
177+
* @param string $name the option's name
178+
* @return boolean
179+
*/
180+
private function optionHasArgument($name)
181+
{
182+
foreach ($this->optionList as $option) {
183+
if ($option->matches($name)) {
184+
return $option->mode() != Getopt::NO_ARGUMENT;
185+
}
186+
}
187+
return false;
188+
}
189+
190+
/**
191+
* Split the string into individual characters,
192+
* @param string $string string to split
193+
* @return array
194+
*/
195+
private function splitString($string)
196+
{
197+
$result = array();
198+
for ($i = 0; $i < mb_strlen($string, "UTF-8"); ++$i) {
199+
$result[] = mb_substr($string, $i, 1, "UTF-8");
200+
}
201+
return $result;
202+
}
203+
}

0 commit comments

Comments
 (0)
0