f6e40cfc68ec099251d32b336e2741f53189905f
[yaffs-website] / vendor / symfony / console / Input / ArgvInput.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Console\Input;
13
14 use Symfony\Component\Console\Exception\RuntimeException;
15
16 /**
17  * ArgvInput represents an input coming from the CLI arguments.
18  *
19  * Usage:
20  *
21  *     $input = new ArgvInput();
22  *
23  * By default, the `$_SERVER['argv']` array is used for the input values.
24  *
25  * This can be overridden by explicitly passing the input values in the constructor:
26  *
27  *     $input = new ArgvInput($_SERVER['argv']);
28  *
29  * If you pass it yourself, don't forget that the first element of the array
30  * is the name of the running application.
31  *
32  * When passing an argument to the constructor, be sure that it respects
33  * the same rules as the argv one. It's almost always better to use the
34  * `StringInput` when you want to provide your own input.
35  *
36  * @author Fabien Potencier <fabien@symfony.com>
37  *
38  * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
39  * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
40  */
41 class ArgvInput extends Input
42 {
43     private $tokens;
44     private $parsed;
45
46     /**
47      * Constructor.
48      *
49      * @param array|null           $argv       An array of parameters from the CLI (in the argv format)
50      * @param InputDefinition|null $definition A InputDefinition instance
51      */
52     public function __construct(array $argv = null, InputDefinition $definition = null)
53     {
54         if (null === $argv) {
55             $argv = $_SERVER['argv'];
56         }
57
58         // strip the application name
59         array_shift($argv);
60
61         $this->tokens = $argv;
62
63         parent::__construct($definition);
64     }
65
66     protected function setTokens(array $tokens)
67     {
68         $this->tokens = $tokens;
69     }
70
71     /**
72      * {@inheritdoc}
73      */
74     protected function parse()
75     {
76         $parseOptions = true;
77         $this->parsed = $this->tokens;
78         while (null !== $token = array_shift($this->parsed)) {
79             if ($parseOptions && '' == $token) {
80                 $this->parseArgument($token);
81             } elseif ($parseOptions && '--' == $token) {
82                 $parseOptions = false;
83             } elseif ($parseOptions && 0 === strpos($token, '--')) {
84                 $this->parseLongOption($token);
85             } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
86                 $this->parseShortOption($token);
87             } else {
88                 $this->parseArgument($token);
89             }
90         }
91     }
92
93     /**
94      * Parses a short option.
95      *
96      * @param string $token The current token
97      */
98     private function parseShortOption($token)
99     {
100         $name = substr($token, 1);
101
102         if (strlen($name) > 1) {
103             if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
104                 // an option with a value (with no space)
105                 $this->addShortOption($name[0], substr($name, 1));
106             } else {
107                 $this->parseShortOptionSet($name);
108             }
109         } else {
110             $this->addShortOption($name, null);
111         }
112     }
113
114     /**
115      * Parses a short option set.
116      *
117      * @param string $name The current token
118      *
119      * @throws RuntimeException When option given doesn't exist
120      */
121     private function parseShortOptionSet($name)
122     {
123         $len = strlen($name);
124         for ($i = 0; $i < $len; ++$i) {
125             if (!$this->definition->hasShortcut($name[$i])) {
126                 throw new RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
127             }
128
129             $option = $this->definition->getOptionForShortcut($name[$i]);
130             if ($option->acceptValue()) {
131                 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
132
133                 break;
134             } else {
135                 $this->addLongOption($option->getName(), null);
136             }
137         }
138     }
139
140     /**
141      * Parses a long option.
142      *
143      * @param string $token The current token
144      */
145     private function parseLongOption($token)
146     {
147         $name = substr($token, 2);
148
149         if (false !== $pos = strpos($name, '=')) {
150             if (0 === strlen($value = substr($name, $pos + 1))) {
151                 array_unshift($this->parsed, null);
152             }
153             $this->addLongOption(substr($name, 0, $pos), $value);
154         } else {
155             $this->addLongOption($name, null);
156         }
157     }
158
159     /**
160      * Parses an argument.
161      *
162      * @param string $token The current token
163      *
164      * @throws RuntimeException When too many arguments are given
165      */
166     private function parseArgument($token)
167     {
168         $c = count($this->arguments);
169
170         // if input is expecting another argument, add it
171         if ($this->definition->hasArgument($c)) {
172             $arg = $this->definition->getArgument($c);
173             $this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token;
174
175         // if last argument isArray(), append token to last argument
176         } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
177             $arg = $this->definition->getArgument($c - 1);
178             $this->arguments[$arg->getName()][] = $token;
179
180         // unexpected argument
181         } else {
182             $all = $this->definition->getArguments();
183             if (count($all)) {
184                 throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
185             }
186
187             throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
188         }
189     }
190
191     /**
192      * Adds a short option value.
193      *
194      * @param string $shortcut The short option key
195      * @param mixed  $value    The value for the option
196      *
197      * @throws RuntimeException When option given doesn't exist
198      */
199     private function addShortOption($shortcut, $value)
200     {
201         if (!$this->definition->hasShortcut($shortcut)) {
202             throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
203         }
204
205         $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
206     }
207
208     /**
209      * Adds a long option value.
210      *
211      * @param string $name  The long option key
212      * @param mixed  $value The value for the option
213      *
214      * @throws RuntimeException When option given doesn't exist
215      */
216     private function addLongOption($name, $value)
217     {
218         if (!$this->definition->hasOption($name)) {
219             throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
220         }
221
222         $option = $this->definition->getOption($name);
223
224         // Convert empty values to null
225         if (!isset($value[0])) {
226             $value = null;
227         }
228
229         if (null !== $value && !$option->acceptValue()) {
230             throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
231         }
232
233         if (null === $value && $option->acceptValue() && count($this->parsed)) {
234             // if option accepts an optional or mandatory argument
235             // let's see if there is one provided
236             $next = array_shift($this->parsed);
237             if (isset($next[0]) && '-' !== $next[0]) {
238                 $value = $next;
239             } elseif (empty($next)) {
240                 $value = null;
241             } else {
242                 array_unshift($this->parsed, $next);
243             }
244         }
245
246         if (null === $value) {
247             if ($option->isValueRequired()) {
248                 throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
249             }
250
251             if (!$option->isArray()) {
252                 $value = $option->isValueOptional() ? $option->getDefault() : true;
253             }
254         }
255
256         if ($option->isArray()) {
257             $this->options[$name][] = $value;
258         } else {
259             $this->options[$name] = $value;
260         }
261     }
262
263     /**
264      * {@inheritdoc}
265      */
266     public function getFirstArgument()
267     {
268         foreach ($this->tokens as $token) {
269             if ($token && '-' === $token[0]) {
270                 continue;
271             }
272
273             return $token;
274         }
275     }
276
277     /**
278      * {@inheritdoc}
279      */
280     public function hasParameterOption($values)
281     {
282         $values = (array) $values;
283
284         foreach ($this->tokens as $token) {
285             foreach ($values as $value) {
286                 if ($token === $value || 0 === strpos($token, $value.'=')) {
287                     return true;
288                 }
289             }
290         }
291
292         return false;
293     }
294
295     /**
296      * {@inheritdoc}
297      */
298     public function getParameterOption($values, $default = false)
299     {
300         $values = (array) $values;
301         $tokens = $this->tokens;
302
303         while (0 < count($tokens)) {
304             $token = array_shift($tokens);
305
306             foreach ($values as $value) {
307                 if ($token === $value || 0 === strpos($token, $value.'=')) {
308                     if (false !== $pos = strpos($token, '=')) {
309                         return substr($token, $pos + 1);
310                     }
311
312                     return array_shift($tokens);
313                 }
314             }
315         }
316
317         return $default;
318     }
319
320     /**
321      * Returns a stringified representation of the args passed to the command.
322      *
323      * @return string
324      */
325     public function __toString()
326     {
327         $self = $this;
328         $tokens = array_map(function ($token) use ($self) {
329             if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
330                 return $match[1].$self->escapeToken($match[2]);
331             }
332
333             if ($token && $token[0] !== '-') {
334                 return $self->escapeToken($token);
335             }
336
337             return $token;
338         }, $this->tokens);
339
340         return implode(' ', $tokens);
341     }
342 }