OSDN Git Service

Добавление Мест размещения и регионов (подразделений)
[invent/invent.git] / 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     public function __construct(array $argv = null, InputDefinition $definition = null)
47     {
48         if (null === $argv) {
49             $argv = $_SERVER['argv'];
50         }
51
52         // strip the application name
53         array_shift($argv);
54
55         $this->tokens = $argv;
56
57         parent::__construct($definition);
58     }
59
60     protected function setTokens(array $tokens)
61     {
62         $this->tokens = $tokens;
63     }
64
65     /**
66      * {@inheritdoc}
67      */
68     protected function parse()
69     {
70         $parseOptions = true;
71         $this->parsed = $this->tokens;
72         while (null !== $token = array_shift($this->parsed)) {
73             if ($parseOptions && '' == $token) {
74                 $this->parseArgument($token);
75             } elseif ($parseOptions && '--' == $token) {
76                 $parseOptions = false;
77             } elseif ($parseOptions && 0 === strpos($token, '--')) {
78                 $this->parseLongOption($token);
79             } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
80                 $this->parseShortOption($token);
81             } else {
82                 $this->parseArgument($token);
83             }
84         }
85     }
86
87     /**
88      * Parses a short option.
89      */
90     private function parseShortOption(string $token)
91     {
92         $name = substr($token, 1);
93
94         if (\strlen($name) > 1) {
95             if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
96                 // an option with a value (with no space)
97                 $this->addShortOption($name[0], substr($name, 1));
98             } else {
99                 $this->parseShortOptionSet($name);
100             }
101         } else {
102             $this->addShortOption($name, null);
103         }
104     }
105
106     /**
107      * Parses a short option set.
108      *
109      * @throws RuntimeException When option given doesn't exist
110      */
111     private function parseShortOptionSet(string $name)
112     {
113         $len = \strlen($name);
114         for ($i = 0; $i < $len; ++$i) {
115             if (!$this->definition->hasShortcut($name[$i])) {
116                 $encoding = mb_detect_encoding($name, null, true);
117                 throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
118             }
119
120             $option = $this->definition->getOptionForShortcut($name[$i]);
121             if ($option->acceptValue()) {
122                 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
123
124                 break;
125             } else {
126                 $this->addLongOption($option->getName(), null);
127             }
128         }
129     }
130
131     /**
132      * Parses a long option.
133      */
134     private function parseLongOption(string $token)
135     {
136         $name = substr($token, 2);
137
138         if (false !== $pos = strpos($name, '=')) {
139             if (0 === \strlen($value = substr($name, $pos + 1))) {
140                 array_unshift($this->parsed, $value);
141             }
142             $this->addLongOption(substr($name, 0, $pos), $value);
143         } else {
144             $this->addLongOption($name, null);
145         }
146     }
147
148     /**
149      * Parses an argument.
150      *
151      * @throws RuntimeException When too many arguments are given
152      */
153     private function parseArgument(string $token)
154     {
155         $c = \count($this->arguments);
156
157         // if input is expecting another argument, add it
158         if ($this->definition->hasArgument($c)) {
159             $arg = $this->definition->getArgument($c);
160             $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
161
162         // if last argument isArray(), append token to last argument
163         } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
164             $arg = $this->definition->getArgument($c - 1);
165             $this->arguments[$arg->getName()][] = $token;
166
167         // unexpected argument
168         } else {
169             $all = $this->definition->getArguments();
170             if (\count($all)) {
171                 throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
172             }
173
174             throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
175         }
176     }
177
178     /**
179      * Adds a short option value.
180      *
181      * @throws RuntimeException When option given doesn't exist
182      */
183     private function addShortOption(string $shortcut, $value)
184     {
185         if (!$this->definition->hasShortcut($shortcut)) {
186             throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
187         }
188
189         $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
190     }
191
192     /**
193      * Adds a long option value.
194      *
195      * @throws RuntimeException When option given doesn't exist
196      */
197     private function addLongOption(string $name, $value)
198     {
199         if (!$this->definition->hasOption($name)) {
200             throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
201         }
202
203         $option = $this->definition->getOption($name);
204
205         if (null !== $value && !$option->acceptValue()) {
206             throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
207         }
208
209         if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {
210             // if option accepts an optional or mandatory argument
211             // let's see if there is one provided
212             $next = array_shift($this->parsed);
213             if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
214                 $value = $next;
215             } else {
216                 array_unshift($this->parsed, $next);
217             }
218         }
219
220         if (null === $value) {
221             if ($option->isValueRequired()) {
222                 throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
223             }
224
225             if (!$option->isArray() && !$option->isValueOptional()) {
226                 $value = true;
227             }
228         }
229
230         if ($option->isArray()) {
231             $this->options[$name][] = $value;
232         } else {
233             $this->options[$name] = $value;
234         }
235     }
236
237     /**
238      * {@inheritdoc}
239      */
240     public function getFirstArgument()
241     {
242         $isOption = false;
243         foreach ($this->tokens as $i => $token) {
244             if ($token && '-' === $token[0]) {
245                 if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) {
246                     continue;
247                 }
248
249                 // If it's a long option, consider that everything after "--" is the option name.
250                 // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
251                 $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
252                 if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
253                     // noop
254                 } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
255                     $isOption = true;
256                 }
257
258                 continue;
259             }
260
261             if ($isOption) {
262                 $isOption = false;
263                 continue;
264             }
265
266             return $token;
267         }
268
269         return null;
270     }
271
272     /**
273      * {@inheritdoc}
274      */
275     public function hasParameterOption($values, bool $onlyParams = false)
276     {
277         $values = (array) $values;
278
279         foreach ($this->tokens as $token) {
280             if ($onlyParams && '--' === $token) {
281                 return false;
282             }
283             foreach ($values as $value) {
284                 // Options with values:
285                 //   For long options, test for '--option=' at beginning
286                 //   For short options, test for '-o' at beginning
287                 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
288                 if ($token === $value || '' !== $leading && 0 === strpos($token, $leading)) {
289                     return true;
290                 }
291             }
292         }
293
294         return false;
295     }
296
297     /**
298      * {@inheritdoc}
299      */
300     public function getParameterOption($values, $default = false, bool $onlyParams = false)
301     {
302         $values = (array) $values;
303         $tokens = $this->tokens;
304
305         while (0 < \count($tokens)) {
306             $token = array_shift($tokens);
307             if ($onlyParams && '--' === $token) {
308                 return $default;
309             }
310
311             foreach ($values as $value) {
312                 if ($token === $value) {
313                     return array_shift($tokens);
314                 }
315                 // Options with values:
316                 //   For long options, test for '--option=' at beginning
317                 //   For short options, test for '-o' at beginning
318                 $leading = 0 === strpos($value, '--') ? $value.'=' : $value;
319                 if ('' !== $leading && 0 === strpos($token, $leading)) {
320                     return substr($token, \strlen($leading));
321                 }
322             }
323         }
324
325         return $default;
326     }
327
328     /**
329      * Returns a stringified representation of the args passed to the command.
330      *
331      * @return string
332      */
333     public function __toString()
334     {
335         $tokens = array_map(function ($token) {
336             if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
337                 return $match[1].$this->escapeToken($match[2]);
338             }
339
340             if ($token && '-' !== $token[0]) {
341                 return $this->escapeToken($token);
342             }
343
344             return $token;
345         }, $this->tokens);
346
347         return implode(' ', $tokens);
348     }
349 }