~chroot64bit/zivios/gentoo-experimental

« back to all changes in this revision

Viewing changes to application/library/Zend/Console/Getopt.php

  • Committer: Mustafa A. Hashmi
  • Date: 2008-12-04 13:32:21 UTC
  • Revision ID: mhashmi@zivios.org-20081204133221-0nd1trunwevijj38
Inclusion of new installation framework with ties to zend layout and dojo layout

Show diffs side-by-side

added added

removed removed

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