|
1 <?php |
|
2 /** |
|
3 * Zend_Console_Getopt is a class to parse options for command-line |
|
4 * applications. |
|
5 * |
|
6 * LICENSE |
|
7 * |
|
8 * This source file is subject to the new BSD license that is bundled |
|
9 * with this package in the file LICENSE.txt. |
|
10 * It is also available through the world-wide-web at this URL: |
|
11 * http://framework.zend.com/license/new-bsd |
|
12 * If you did not receive a copy of the license and are unable to |
|
13 * obtain it through the world-wide-web, please send an email |
|
14 * to license@zend.com so we can send you a copy immediately. |
|
15 * |
|
16 * @category Zend |
|
17 * @package Zend_Console_Getopt |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Getopt.php 22191 2010-05-17 21:50:14Z jan $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * Zend_Console_Getopt is a class to parse options for command-line |
|
25 * applications. |
|
26 * |
|
27 * Terminology: |
|
28 * Argument: an element of the argv array. This may be part of an option, |
|
29 * or it may be a non-option command-line argument. |
|
30 * Flag: the letter or word set off by a '-' or '--'. Example: in '--output filename', |
|
31 * '--output' is the flag. |
|
32 * Parameter: the additional argument that is associated with the option. |
|
33 * Example: in '--output filename', the 'filename' is the parameter. |
|
34 * Option: the combination of a flag and its parameter, if any. |
|
35 * Example: in '--output filename', the whole thing is the option. |
|
36 * |
|
37 * The following features are supported: |
|
38 * |
|
39 * - Short flags like '-a'. Short flags are preceded by a single |
|
40 * dash. Short flags may be clustered e.g. '-abc', which is the |
|
41 * same as '-a' '-b' '-c'. |
|
42 * - Long flags like '--verbose'. Long flags are preceded by a |
|
43 * double dash. Long flags may not be clustered. |
|
44 * - Options may have a parameter, e.g. '--output filename'. |
|
45 * - Parameters for long flags may also be set off with an equals sign, |
|
46 * e.g. '--output=filename'. |
|
47 * - Parameters for long flags may be checked as string, word, or integer. |
|
48 * - Automatic generation of a helpful usage message. |
|
49 * - Signal end of options with '--'; subsequent arguments are treated |
|
50 * as non-option arguments, even if they begin with '-'. |
|
51 * - Raise exception Zend_Console_Getopt_Exception in several cases |
|
52 * when invalid flags or parameters are given. Usage message is |
|
53 * returned in the exception object. |
|
54 * |
|
55 * The format for specifying options uses a PHP associative array. |
|
56 * The key is has the format of a list of pipe-separated flag names, |
|
57 * followed by an optional '=' to indicate a required parameter or |
|
58 * '-' to indicate an optional parameter. Following that, the type |
|
59 * of parameter may be specified as 's' for string, 'w' for word, |
|
60 * or 'i' for integer. |
|
61 * |
|
62 * Examples: |
|
63 * - 'user|username|u=s' this means '--user' or '--username' or '-u' |
|
64 * are synonyms, and the option requires a string parameter. |
|
65 * - 'p=i' this means '-p' requires an integer parameter. No synonyms. |
|
66 * - 'verbose|v-i' this means '--verbose' or '-v' are synonyms, and |
|
67 * they take an optional integer parameter. |
|
68 * - 'help|h' this means '--help' or '-h' are synonyms, and |
|
69 * they take no parameter. |
|
70 * |
|
71 * The values in the associative array are strings that are used as |
|
72 * brief descriptions of the options when printing a usage message. |
|
73 * |
|
74 * The simpler format for specifying options used by PHP's getopt() |
|
75 * function is also supported. This is similar to GNU getopt and shell |
|
76 * getopt format. |
|
77 * |
|
78 * Example: 'abc:' means options '-a', '-b', and '-c' |
|
79 * are legal, and the latter requires a string parameter. |
|
80 * |
|
81 * @category Zend |
|
82 * @package Zend_Console_Getopt |
|
83 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
84 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
85 * @version Release: @package_version@ |
|
86 * @since Class available since Release 0.6.0 |
|
87 * |
|
88 * @todo Handle params with multiple values, e.g. --colors=red,green,blue |
|
89 * Set value of parameter to the array of values. Allow user to specify |
|
90 * the separator with Zend_Console_Getopt::CONFIG_PARAMETER_SEPARATOR. |
|
91 * If this config value is null or empty string, do not split values |
|
92 * into arrays. Default separator is comma (','). |
|
93 * |
|
94 * @todo Handle params with multiple values specified with separate options |
|
95 * e.g. --colors red --colors green --colors blue should give one |
|
96 * option with an array(red, green, blue). |
|
97 * Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_PARAMETERS. |
|
98 * Default is that subsequent options overwrite the parameter value. |
|
99 * |
|
100 * @todo Handle flags occurring multiple times, e.g. -v -v -v |
|
101 * Set value of the option's parameter to the integer count of instances |
|
102 * instead of a boolean. |
|
103 * Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_FLAGS. |
|
104 * Default is that the value is simply boolean true regardless of |
|
105 * how many instances of the flag appear. |
|
106 * |
|
107 * @todo Handle flags that implicitly print usage message, e.g. --help |
|
108 * |
|
109 * @todo Handle freeform options, e.g. --set-variable |
|
110 * Enable with Zend_Console_Getopt::CONFIG_FREEFORM_FLAGS |
|
111 * All flag-like syntax is recognized, no flag generates an exception. |
|
112 * |
|
113 * @todo Handle numeric options, e.g. -1, -2, -3, -1000 |
|
114 * Enable with Zend_Console_Getopt::CONFIG_NUMERIC_FLAGS |
|
115 * The rule must specify a named flag and the '#' symbol as the |
|
116 * parameter type. e.g., 'lines=#' |
|
117 * |
|
118 * @todo Enable user to specify header and footer content in the help message. |
|
119 * |
|
120 * @todo Feature request to handle option interdependencies. |
|
121 * e.g. if -b is specified, -a must be specified or else the |
|
122 * usage is invalid. |
|
123 * |
|
124 * @todo Feature request to implement callbacks. |
|
125 * e.g. if -a is specified, run function 'handleOptionA'(). |
|
126 */ |
|
127 class Zend_Console_Getopt |
|
128 { |
|
129 |
|
130 /** |
|
131 * The options for a given application can be in multiple formats. |
|
132 * modeGnu is for traditional 'ab:c:' style getopt format. |
|
133 * modeZend is for a more structured format. |
|
134 */ |
|
135 const MODE_ZEND = 'zend'; |
|
136 const MODE_GNU = 'gnu'; |
|
137 |
|
138 /** |
|
139 * Constant tokens for various symbols used in the mode_zend |
|
140 * rule format. |
|
141 */ |
|
142 const PARAM_REQUIRED = '='; |
|
143 const PARAM_OPTIONAL = '-'; |
|
144 const TYPE_STRING = 's'; |
|
145 const TYPE_WORD = 'w'; |
|
146 const TYPE_INTEGER = 'i'; |
|
147 |
|
148 /** |
|
149 * These are constants for optional behavior of this class. |
|
150 * ruleMode is either 'zend' or 'gnu' or a user-defined mode. |
|
151 * dashDash is true if '--' signifies the end of command-line options. |
|
152 * ignoreCase is true if '--opt' and '--OPT' are implicitly synonyms. |
|
153 * parseAll is true if all options on the command line should be parsed, regardless of |
|
154 * whether an argument appears before them. |
|
155 */ |
|
156 const CONFIG_RULEMODE = 'ruleMode'; |
|
157 const CONFIG_DASHDASH = 'dashDash'; |
|
158 const CONFIG_IGNORECASE = 'ignoreCase'; |
|
159 const CONFIG_PARSEALL = 'parseAll'; |
|
160 |
|
161 /** |
|
162 * Defaults for getopt configuration are: |
|
163 * ruleMode is 'zend' format, |
|
164 * dashDash (--) token is enabled, |
|
165 * ignoreCase is not enabled, |
|
166 * parseAll is enabled. |
|
167 */ |
|
168 protected $_getoptConfig = array( |
|
169 self::CONFIG_RULEMODE => self::MODE_ZEND, |
|
170 self::CONFIG_DASHDASH => true, |
|
171 self::CONFIG_IGNORECASE => false, |
|
172 self::CONFIG_PARSEALL => true, |
|
173 ); |
|
174 |
|
175 /** |
|
176 * Stores the command-line arguments for the calling applicaion. |
|
177 * |
|
178 * @var array |
|
179 */ |
|
180 protected $_argv = array(); |
|
181 |
|
182 /** |
|
183 * Stores the name of the calling applicaion. |
|
184 * |
|
185 * @var string |
|
186 */ |
|
187 protected $_progname = ''; |
|
188 |
|
189 /** |
|
190 * Stores the list of legal options for this application. |
|
191 * |
|
192 * @var array |
|
193 */ |
|
194 protected $_rules = array(); |
|
195 |
|
196 /** |
|
197 * Stores alternate spellings of legal options. |
|
198 * |
|
199 * @var array |
|
200 */ |
|
201 protected $_ruleMap = array(); |
|
202 |
|
203 /** |
|
204 * Stores options given by the user in the current invocation |
|
205 * of the application, as well as parameters given in options. |
|
206 * |
|
207 * @var array |
|
208 */ |
|
209 protected $_options = array(); |
|
210 |
|
211 /** |
|
212 * Stores the command-line arguments other than options. |
|
213 * |
|
214 * @var array |
|
215 */ |
|
216 protected $_remainingArgs = array(); |
|
217 |
|
218 /** |
|
219 * State of the options: parsed or not yet parsed? |
|
220 * |
|
221 * @var boolean |
|
222 */ |
|
223 protected $_parsed = false; |
|
224 |
|
225 /** |
|
226 * The constructor takes one to three parameters. |
|
227 * |
|
228 * The first parameter is $rules, which may be a string for |
|
229 * gnu-style format, or a structured array for Zend-style format. |
|
230 * |
|
231 * The second parameter is $argv, and it is optional. If not |
|
232 * specified, $argv is inferred from the global argv. |
|
233 * |
|
234 * The third parameter is an array of configuration parameters |
|
235 * to control the behavior of this instance of Getopt; it is optional. |
|
236 * |
|
237 * @param array $rules |
|
238 * @param array $argv |
|
239 * @param array $getoptConfig |
|
240 * @return void |
|
241 */ |
|
242 public function __construct($rules, $argv = null, $getoptConfig = array()) |
|
243 { |
|
244 if (!isset($_SERVER['argv'])) { |
|
245 require_once 'Zend/Console/Getopt/Exception.php'; |
|
246 if (ini_get('register_argc_argv') == false) { |
|
247 throw new Zend_Console_Getopt_Exception( |
|
248 "argv is not available, because ini option 'register_argc_argv' is set Off" |
|
249 ); |
|
250 } else { |
|
251 throw new Zend_Console_Getopt_Exception( |
|
252 '$_SERVER["argv"] is not set, but Zend_Console_Getopt cannot work without this information.' |
|
253 ); |
|
254 } |
|
255 } |
|
256 |
|
257 $this->_progname = $_SERVER['argv'][0]; |
|
258 $this->setOptions($getoptConfig); |
|
259 $this->addRules($rules); |
|
260 if (!is_array($argv)) { |
|
261 $argv = array_slice($_SERVER['argv'], 1); |
|
262 } |
|
263 if (isset($argv)) { |
|
264 $this->addArguments((array)$argv); |
|
265 } |
|
266 } |
|
267 |
|
268 /** |
|
269 * Return the state of the option seen on the command line of the |
|
270 * current application invocation. This function returns true, or the |
|
271 * parameter to the option, if any. If the option was not given, |
|
272 * this function returns null. |
|
273 * |
|
274 * The magic __get method works in the context of naming the option |
|
275 * as a virtual member of this class. |
|
276 * |
|
277 * @param string $key |
|
278 * @return string |
|
279 */ |
|
280 public function __get($key) |
|
281 { |
|
282 return $this->getOption($key); |
|
283 } |
|
284 |
|
285 /** |
|
286 * Test whether a given option has been seen. |
|
287 * |
|
288 * @param string $key |
|
289 * @return boolean |
|
290 */ |
|
291 public function __isset($key) |
|
292 { |
|
293 $this->parse(); |
|
294 if (isset($this->_ruleMap[$key])) { |
|
295 $key = $this->_ruleMap[$key]; |
|
296 return isset($this->_options[$key]); |
|
297 } |
|
298 return false; |
|
299 } |
|
300 |
|
301 /** |
|
302 * Set the value for a given option. |
|
303 * |
|
304 * @param string $key |
|
305 * @param string $value |
|
306 * @return void |
|
307 */ |
|
308 public function __set($key, $value) |
|
309 { |
|
310 $this->parse(); |
|
311 if (isset($this->_ruleMap[$key])) { |
|
312 $key = $this->_ruleMap[$key]; |
|
313 $this->_options[$key] = $value; |
|
314 } |
|
315 } |
|
316 |
|
317 /** |
|
318 * Return the current set of options and parameters seen as a string. |
|
319 * |
|
320 * @return string |
|
321 */ |
|
322 public function __toString() |
|
323 { |
|
324 return $this->toString(); |
|
325 } |
|
326 |
|
327 /** |
|
328 * Unset an option. |
|
329 * |
|
330 * @param string $key |
|
331 * @return void |
|
332 */ |
|
333 public function __unset($key) |
|
334 { |
|
335 $this->parse(); |
|
336 if (isset($this->_ruleMap[$key])) { |
|
337 $key = $this->_ruleMap[$key]; |
|
338 unset($this->_options[$key]); |
|
339 } |
|
340 } |
|
341 |
|
342 /** |
|
343 * Define additional command-line arguments. |
|
344 * These are appended to those defined when the constructor was called. |
|
345 * |
|
346 * @param array $argv |
|
347 * @throws Zend_Console_Getopt_Exception When not given an array as parameter |
|
348 * @return Zend_Console_Getopt Provides a fluent interface |
|
349 */ |
|
350 public function addArguments($argv) |
|
351 { |
|
352 if(!is_array($argv)) { |
|
353 require_once 'Zend/Console/Getopt/Exception.php'; |
|
354 throw new Zend_Console_Getopt_Exception( |
|
355 "Parameter #1 to addArguments should be an array"); |
|
356 } |
|
357 $this->_argv = array_merge($this->_argv, $argv); |
|
358 $this->_parsed = false; |
|
359 return $this; |
|
360 } |
|
361 |
|
362 /** |
|
363 * Define full set of command-line arguments. |
|
364 * These replace any currently defined. |
|
365 * |
|
366 * @param array $argv |
|
367 * @throws Zend_Console_Getopt_Exception When not given an array as parameter |
|
368 * @return Zend_Console_Getopt Provides a fluent interface |
|
369 */ |
|
370 public function setArguments($argv) |
|
371 { |
|
372 if(!is_array($argv)) { |
|
373 require_once 'Zend/Console/Getopt/Exception.php'; |
|
374 throw new Zend_Console_Getopt_Exception( |
|
375 "Parameter #1 to setArguments should be an array"); |
|
376 } |
|
377 $this->_argv = $argv; |
|
378 $this->_parsed = false; |
|
379 return $this; |
|
380 } |
|
381 |
|
382 /** |
|
383 * Define multiple configuration options from an associative array. |
|
384 * These are not program options, but properties to configure |
|
385 * the behavior of Zend_Console_Getopt. |
|
386 * |
|
387 * @param array $getoptConfig |
|
388 * @return Zend_Console_Getopt Provides a fluent interface |
|
389 */ |
|
390 public function setOptions($getoptConfig) |
|
391 { |
|
392 if (isset($getoptConfig)) { |
|
393 foreach ($getoptConfig as $key => $value) { |
|
394 $this->setOption($key, $value); |
|
395 } |
|
396 } |
|
397 return $this; |
|
398 } |
|
399 |
|
400 /** |
|
401 * Define one configuration option as a key/value pair. |
|
402 * These are not program options, but properties to configure |
|
403 * the behavior of Zend_Console_Getopt. |
|
404 * |
|
405 * @param string $configKey |
|
406 * @param string $configValue |
|
407 * @return Zend_Console_Getopt Provides a fluent interface |
|
408 */ |
|
409 public function setOption($configKey, $configValue) |
|
410 { |
|
411 if ($configKey !== null) { |
|
412 $this->_getoptConfig[$configKey] = $configValue; |
|
413 } |
|
414 return $this; |
|
415 } |
|
416 |
|
417 /** |
|
418 * Define additional option rules. |
|
419 * These are appended to the rules defined when the constructor was called. |
|
420 * |
|
421 * @param array $rules |
|
422 * @return Zend_Console_Getopt Provides a fluent interface |
|
423 */ |
|
424 public function addRules($rules) |
|
425 { |
|
426 $ruleMode = $this->_getoptConfig['ruleMode']; |
|
427 switch ($this->_getoptConfig['ruleMode']) { |
|
428 case self::MODE_ZEND: |
|
429 if (is_array($rules)) { |
|
430 $this->_addRulesModeZend($rules); |
|
431 break; |
|
432 } |
|
433 // intentional fallthrough |
|
434 case self::MODE_GNU: |
|
435 $this->_addRulesModeGnu($rules); |
|
436 break; |
|
437 default: |
|
438 /** |
|
439 * Call addRulesModeFoo() for ruleMode 'foo'. |
|
440 * The developer should subclass Getopt and |
|
441 * provide this method. |
|
442 */ |
|
443 $method = '_addRulesMode' . ucfirst($ruleMode); |
|
444 $this->$method($rules); |
|
445 } |
|
446 $this->_parsed = false; |
|
447 return $this; |
|
448 } |
|
449 |
|
450 /** |
|
451 * Return the current set of options and parameters seen as a string. |
|
452 * |
|
453 * @return string |
|
454 */ |
|
455 public function toString() |
|
456 { |
|
457 $this->parse(); |
|
458 $s = array(); |
|
459 foreach ($this->_options as $flag => $value) { |
|
460 $s[] = $flag . '=' . ($value === true ? 'true' : $value); |
|
461 } |
|
462 return implode(' ', $s); |
|
463 } |
|
464 |
|
465 /** |
|
466 * Return the current set of options and parameters seen |
|
467 * as an array of canonical options and parameters. |
|
468 * |
|
469 * Clusters have been expanded, and option aliases |
|
470 * have been mapped to their primary option names. |
|
471 * |
|
472 * @return array |
|
473 */ |
|
474 public function toArray() |
|
475 { |
|
476 $this->parse(); |
|
477 $s = array(); |
|
478 foreach ($this->_options as $flag => $value) { |
|
479 $s[] = $flag; |
|
480 if ($value !== true) { |
|
481 $s[] = $value; |
|
482 } |
|
483 } |
|
484 return $s; |
|
485 } |
|
486 |
|
487 /** |
|
488 * Return the current set of options and parameters seen in Json format. |
|
489 * |
|
490 * @return string |
|
491 */ |
|
492 public function toJson() |
|
493 { |
|
494 $this->parse(); |
|
495 $j = array(); |
|
496 foreach ($this->_options as $flag => $value) { |
|
497 $j['options'][] = array( |
|
498 'option' => array( |
|
499 'flag' => $flag, |
|
500 'parameter' => $value |
|
501 ) |
|
502 ); |
|
503 } |
|
504 |
|
505 /** |
|
506 * @see Zend_Json |
|
507 */ |
|
508 require_once 'Zend/Json.php'; |
|
509 $json = Zend_Json::encode($j); |
|
510 |
|
511 return $json; |
|
512 } |
|
513 |
|
514 /** |
|
515 * Return the current set of options and parameters seen in XML format. |
|
516 * |
|
517 * @return string |
|
518 */ |
|
519 public function toXml() |
|
520 { |
|
521 $this->parse(); |
|
522 $doc = new DomDocument('1.0', 'utf-8'); |
|
523 $optionsNode = $doc->createElement('options'); |
|
524 $doc->appendChild($optionsNode); |
|
525 foreach ($this->_options as $flag => $value) { |
|
526 $optionNode = $doc->createElement('option'); |
|
527 $optionNode->setAttribute('flag', utf8_encode($flag)); |
|
528 if ($value !== true) { |
|
529 $optionNode->setAttribute('parameter', utf8_encode($value)); |
|
530 } |
|
531 $optionsNode->appendChild($optionNode); |
|
532 } |
|
533 $xml = $doc->saveXML(); |
|
534 return $xml; |
|
535 } |
|
536 |
|
537 /** |
|
538 * Return a list of options that have been seen in the current argv. |
|
539 * |
|
540 * @return array |
|
541 */ |
|
542 public function getOptions() |
|
543 { |
|
544 $this->parse(); |
|
545 return array_keys($this->_options); |
|
546 } |
|
547 |
|
548 /** |
|
549 * Return the state of the option seen on the command line of the |
|
550 * current application invocation. |
|
551 * |
|
552 * This function returns true, or the parameter value to the option, if any. |
|
553 * If the option was not given, this function returns false. |
|
554 * |
|
555 * @param string $flag |
|
556 * @return mixed |
|
557 */ |
|
558 public function getOption($flag) |
|
559 { |
|
560 $this->parse(); |
|
561 if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { |
|
562 $flag = strtolower($flag); |
|
563 } |
|
564 if (isset($this->_ruleMap[$flag])) { |
|
565 $flag = $this->_ruleMap[$flag]; |
|
566 if (isset($this->_options[$flag])) { |
|
567 return $this->_options[$flag]; |
|
568 } |
|
569 } |
|
570 return null; |
|
571 } |
|
572 |
|
573 /** |
|
574 * Return the arguments from the command-line following all options found. |
|
575 * |
|
576 * @return array |
|
577 */ |
|
578 public function getRemainingArgs() |
|
579 { |
|
580 $this->parse(); |
|
581 return $this->_remainingArgs; |
|
582 } |
|
583 |
|
584 /** |
|
585 * Return a useful option reference, formatted for display in an |
|
586 * error message. |
|
587 * |
|
588 * Note that this usage information is provided in most Exceptions |
|
589 * generated by this class. |
|
590 * |
|
591 * @return string |
|
592 */ |
|
593 public function getUsageMessage() |
|
594 { |
|
595 $usage = "Usage: {$this->_progname} [ options ]\n"; |
|
596 $maxLen = 20; |
|
597 $lines = array(); |
|
598 foreach ($this->_rules as $rule) { |
|
599 $flags = array(); |
|
600 if (is_array($rule['alias'])) { |
|
601 foreach ($rule['alias'] as $flag) { |
|
602 $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag; |
|
603 } |
|
604 } |
|
605 $linepart['name'] = implode('|', $flags); |
|
606 if (isset($rule['param']) && $rule['param'] != 'none') { |
|
607 $linepart['name'] .= ' '; |
|
608 switch ($rule['param']) { |
|
609 case 'optional': |
|
610 $linepart['name'] .= "[ <{$rule['paramType']}> ]"; |
|
611 break; |
|
612 case 'required': |
|
613 $linepart['name'] .= "<{$rule['paramType']}>"; |
|
614 break; |
|
615 } |
|
616 } |
|
617 if (strlen($linepart['name']) > $maxLen) { |
|
618 $maxLen = strlen($linepart['name']); |
|
619 } |
|
620 $linepart['help'] = ''; |
|
621 if (isset($rule['help'])) { |
|
622 $linepart['help'] .= $rule['help']; |
|
623 } |
|
624 $lines[] = $linepart; |
|
625 } |
|
626 foreach ($lines as $linepart) { |
|
627 $usage .= sprintf("%s %s\n", |
|
628 str_pad($linepart['name'], $maxLen), |
|
629 $linepart['help']); |
|
630 } |
|
631 return $usage; |
|
632 } |
|
633 |
|
634 /** |
|
635 * Define aliases for options. |
|
636 * |
|
637 * The parameter $aliasMap is an associative array |
|
638 * mapping option name (short or long) to an alias. |
|
639 * |
|
640 * @param array $aliasMap |
|
641 * @throws Zend_Console_Getopt_Exception |
|
642 * @return Zend_Console_Getopt Provides a fluent interface |
|
643 */ |
|
644 public function setAliases($aliasMap) |
|
645 { |
|
646 foreach ($aliasMap as $flag => $alias) |
|
647 { |
|
648 if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { |
|
649 $flag = strtolower($flag); |
|
650 $alias = strtolower($alias); |
|
651 } |
|
652 if (!isset($this->_ruleMap[$flag])) { |
|
653 continue; |
|
654 } |
|
655 $flag = $this->_ruleMap[$flag]; |
|
656 if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) { |
|
657 $o = (strlen($alias) == 1 ? '-' : '--') . $alias; |
|
658 require_once 'Zend/Console/Getopt/Exception.php'; |
|
659 throw new Zend_Console_Getopt_Exception( |
|
660 "Option \"$o\" is being defined more than once."); |
|
661 } |
|
662 $this->_rules[$flag]['alias'][] = $alias; |
|
663 $this->_ruleMap[$alias] = $flag; |
|
664 } |
|
665 return $this; |
|
666 } |
|
667 |
|
668 /** |
|
669 * Define help messages for options. |
|
670 * |
|
671 * The parameter $help_map is an associative array |
|
672 * mapping option name (short or long) to the help string. |
|
673 * |
|
674 * @param array $helpMap |
|
675 * @return Zend_Console_Getopt Provides a fluent interface |
|
676 */ |
|
677 public function setHelp($helpMap) |
|
678 { |
|
679 foreach ($helpMap as $flag => $help) |
|
680 { |
|
681 if (!isset($this->_ruleMap[$flag])) { |
|
682 continue; |
|
683 } |
|
684 $flag = $this->_ruleMap[$flag]; |
|
685 $this->_rules[$flag]['help'] = $help; |
|
686 } |
|
687 return $this; |
|
688 } |
|
689 |
|
690 /** |
|
691 * Parse command-line arguments and find both long and short |
|
692 * options. |
|
693 * |
|
694 * Also find option parameters, and remaining arguments after |
|
695 * all options have been parsed. |
|
696 * |
|
697 * @return Zend_Console_Getopt|null Provides a fluent interface |
|
698 */ |
|
699 public function parse() |
|
700 { |
|
701 if ($this->_parsed === true) { |
|
702 return; |
|
703 } |
|
704 $argv = $this->_argv; |
|
705 $this->_options = array(); |
|
706 $this->_remainingArgs = array(); |
|
707 while (count($argv) > 0) { |
|
708 if ($argv[0] == '--') { |
|
709 array_shift($argv); |
|
710 if ($this->_getoptConfig[self::CONFIG_DASHDASH]) { |
|
711 $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); |
|
712 break; |
|
713 } |
|
714 } |
|
715 if (substr($argv[0], 0, 2) == '--') { |
|
716 $this->_parseLongOption($argv); |
|
717 } else if (substr($argv[0], 0, 1) == '-' && ('-' != $argv[0] || count($argv) >1)) { |
|
718 $this->_parseShortOptionCluster($argv); |
|
719 } else if($this->_getoptConfig[self::CONFIG_PARSEALL]) { |
|
720 $this->_remainingArgs[] = array_shift($argv); |
|
721 } else { |
|
722 /* |
|
723 * We should put all other arguments in _remainingArgs and stop parsing |
|
724 * since CONFIG_PARSEALL is false. |
|
725 */ |
|
726 $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); |
|
727 break; |
|
728 } |
|
729 } |
|
730 $this->_parsed = true; |
|
731 return $this; |
|
732 } |
|
733 |
|
734 /** |
|
735 * Parse command-line arguments for a single long option. |
|
736 * A long option is preceded by a double '--' character. |
|
737 * Long options may not be clustered. |
|
738 * |
|
739 * @param mixed &$argv |
|
740 * @return void |
|
741 */ |
|
742 protected function _parseLongOption(&$argv) |
|
743 { |
|
744 $optionWithParam = ltrim(array_shift($argv), '-'); |
|
745 $l = explode('=', $optionWithParam, 2); |
|
746 $flag = array_shift($l); |
|
747 $param = array_shift($l); |
|
748 if (isset($param)) { |
|
749 array_unshift($argv, $param); |
|
750 } |
|
751 $this->_parseSingleOption($flag, $argv); |
|
752 } |
|
753 |
|
754 /** |
|
755 * Parse command-line arguments for short options. |
|
756 * Short options are those preceded by a single '-' character. |
|
757 * Short options may be clustered. |
|
758 * |
|
759 * @param mixed &$argv |
|
760 * @return void |
|
761 */ |
|
762 protected function _parseShortOptionCluster(&$argv) |
|
763 { |
|
764 $flagCluster = ltrim(array_shift($argv), '-'); |
|
765 foreach (str_split($flagCluster) as $flag) { |
|
766 $this->_parseSingleOption($flag, $argv); |
|
767 } |
|
768 } |
|
769 |
|
770 /** |
|
771 * Parse command-line arguments for a single option. |
|
772 * |
|
773 * @param string $flag |
|
774 * @param mixed $argv |
|
775 * @throws Zend_Console_Getopt_Exception |
|
776 * @return void |
|
777 */ |
|
778 protected function _parseSingleOption($flag, &$argv) |
|
779 { |
|
780 if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { |
|
781 $flag = strtolower($flag); |
|
782 } |
|
783 if (!isset($this->_ruleMap[$flag])) { |
|
784 require_once 'Zend/Console/Getopt/Exception.php'; |
|
785 throw new Zend_Console_Getopt_Exception( |
|
786 "Option \"$flag\" is not recognized.", |
|
787 $this->getUsageMessage()); |
|
788 } |
|
789 $realFlag = $this->_ruleMap[$flag]; |
|
790 switch ($this->_rules[$realFlag]['param']) { |
|
791 case 'required': |
|
792 if (count($argv) > 0) { |
|
793 $param = array_shift($argv); |
|
794 $this->_checkParameterType($realFlag, $param); |
|
795 } else { |
|
796 require_once 'Zend/Console/Getopt/Exception.php'; |
|
797 throw new Zend_Console_Getopt_Exception( |
|
798 "Option \"$flag\" requires a parameter.", |
|
799 $this->getUsageMessage()); |
|
800 } |
|
801 break; |
|
802 case 'optional': |
|
803 if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') { |
|
804 $param = array_shift($argv); |
|
805 $this->_checkParameterType($realFlag, $param); |
|
806 } else { |
|
807 $param = true; |
|
808 } |
|
809 break; |
|
810 default: |
|
811 $param = true; |
|
812 } |
|
813 $this->_options[$realFlag] = $param; |
|
814 } |
|
815 |
|
816 /** |
|
817 * Return true if the parameter is in a valid format for |
|
818 * the option $flag. |
|
819 * Throw an exception in most other cases. |
|
820 * |
|
821 * @param string $flag |
|
822 * @param string $param |
|
823 * @throws Zend_Console_Getopt_Exception |
|
824 * @return bool |
|
825 */ |
|
826 protected function _checkParameterType($flag, $param) |
|
827 { |
|
828 $type = 'string'; |
|
829 if (isset($this->_rules[$flag]['paramType'])) { |
|
830 $type = $this->_rules[$flag]['paramType']; |
|
831 } |
|
832 switch ($type) { |
|
833 case 'word': |
|
834 if (preg_match('/\W/', $param)) { |
|
835 require_once 'Zend/Console/Getopt/Exception.php'; |
|
836 throw new Zend_Console_Getopt_Exception( |
|
837 "Option \"$flag\" requires a single-word parameter, but was given \"$param\".", |
|
838 $this->getUsageMessage()); |
|
839 } |
|
840 break; |
|
841 case 'integer': |
|
842 if (preg_match('/\D/', $param)) { |
|
843 require_once 'Zend/Console/Getopt/Exception.php'; |
|
844 throw new Zend_Console_Getopt_Exception( |
|
845 "Option \"$flag\" requires an integer parameter, but was given \"$param\".", |
|
846 $this->getUsageMessage()); |
|
847 } |
|
848 break; |
|
849 case 'string': |
|
850 default: |
|
851 break; |
|
852 } |
|
853 return true; |
|
854 } |
|
855 |
|
856 /** |
|
857 * Define legal options using the gnu-style format. |
|
858 * |
|
859 * @param string $rules |
|
860 * @return void |
|
861 */ |
|
862 protected function _addRulesModeGnu($rules) |
|
863 { |
|
864 $ruleArray = array(); |
|
865 |
|
866 /** |
|
867 * Options may be single alphanumeric characters. |
|
868 * Options may have a ':' which indicates a required string parameter. |
|
869 * No long options or option aliases are supported in GNU style. |
|
870 */ |
|
871 preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray); |
|
872 foreach ($ruleArray[1] as $rule) { |
|
873 $r = array(); |
|
874 $flag = substr($rule, 0, 1); |
|
875 if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { |
|
876 $flag = strtolower($flag); |
|
877 } |
|
878 $r['alias'][] = $flag; |
|
879 if (substr($rule, 1, 1) == ':') { |
|
880 $r['param'] = 'required'; |
|
881 $r['paramType'] = 'string'; |
|
882 } else { |
|
883 $r['param'] = 'none'; |
|
884 } |
|
885 $this->_rules[$flag] = $r; |
|
886 $this->_ruleMap[$flag] = $flag; |
|
887 } |
|
888 } |
|
889 |
|
890 /** |
|
891 * Define legal options using the Zend-style format. |
|
892 * |
|
893 * @param array $rules |
|
894 * @throws Zend_Console_Getopt_Exception |
|
895 * @return void |
|
896 */ |
|
897 protected function _addRulesModeZend($rules) |
|
898 { |
|
899 foreach ($rules as $ruleCode => $helpMessage) |
|
900 { |
|
901 // this may have to translate the long parm type if there |
|
902 // are any complaints that =string will not work (even though that use |
|
903 // case is not documented) |
|
904 if (in_array(substr($ruleCode, -2, 1), array('-', '='))) { |
|
905 $flagList = substr($ruleCode, 0, -2); |
|
906 $delimiter = substr($ruleCode, -2, 1); |
|
907 $paramType = substr($ruleCode, -1); |
|
908 } else { |
|
909 $flagList = $ruleCode; |
|
910 $delimiter = $paramType = null; |
|
911 } |
|
912 if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { |
|
913 $flagList = strtolower($flagList); |
|
914 } |
|
915 $flags = explode('|', $flagList); |
|
916 $rule = array(); |
|
917 $mainFlag = $flags[0]; |
|
918 foreach ($flags as $flag) { |
|
919 if (empty($flag)) { |
|
920 require_once 'Zend/Console/Getopt/Exception.php'; |
|
921 throw new Zend_Console_Getopt_Exception( |
|
922 "Blank flag not allowed in rule \"$ruleCode\"."); |
|
923 } |
|
924 if (strlen($flag) == 1) { |
|
925 if (isset($this->_ruleMap[$flag])) { |
|
926 require_once 'Zend/Console/Getopt/Exception.php'; |
|
927 throw new Zend_Console_Getopt_Exception( |
|
928 "Option \"-$flag\" is being defined more than once."); |
|
929 } |
|
930 $this->_ruleMap[$flag] = $mainFlag; |
|
931 $rule['alias'][] = $flag; |
|
932 } else { |
|
933 if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) { |
|
934 require_once 'Zend/Console/Getopt/Exception.php'; |
|
935 throw new Zend_Console_Getopt_Exception( |
|
936 "Option \"--$flag\" is being defined more than once."); |
|
937 } |
|
938 $this->_ruleMap[$flag] = $mainFlag; |
|
939 $rule['alias'][] = $flag; |
|
940 } |
|
941 } |
|
942 if (isset($delimiter)) { |
|
943 switch ($delimiter) { |
|
944 case self::PARAM_REQUIRED: |
|
945 $rule['param'] = 'required'; |
|
946 break; |
|
947 case self::PARAM_OPTIONAL: |
|
948 default: |
|
949 $rule['param'] = 'optional'; |
|
950 } |
|
951 switch (substr($paramType, 0, 1)) { |
|
952 case self::TYPE_WORD: |
|
953 $rule['paramType'] = 'word'; |
|
954 break; |
|
955 case self::TYPE_INTEGER: |
|
956 $rule['paramType'] = 'integer'; |
|
957 break; |
|
958 case self::TYPE_STRING: |
|
959 default: |
|
960 $rule['paramType'] = 'string'; |
|
961 } |
|
962 } else { |
|
963 $rule['param'] = 'none'; |
|
964 } |
|
965 $rule['help'] = $helpMessage; |
|
966 $this->_rules[$mainFlag] = $rule; |
|
967 } |
|
968 } |
|
969 |
|
970 } |