Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Getargs.php
4
 *
5
 * @category  Extension
6
 * @package   Console_Getargs
7
 * @author    Bertrand Mansion <bmansion@mamasam.com>
8
 * @copyright 2004 Bertrand Mansion
9
 * @license   http://www.php.net/license/3_0.txt PHP License 3.0
10
 * @version   1.3.5
11
 * @link      http://pear.php.net/package/Console_Getargs
12
 */
13
 
14
/* vim: set expandtab tabstop=4 shiftwidth=4: */
15
// +----------------------------------------------------------------------+
16
// | PHP Version 4                                                        |
17
// +----------------------------------------------------------------------+
18
// | Copyright (c) 2004 The PHP Group                                     |
19
// +----------------------------------------------------------------------+
20
// | This source file is subject to version 3.0 of the PHP license,       |
21
// | that is bundled with this package in the file LICENSE, and is        |
22
// | available through the world-wide-web at the following url:           |
23
// | http://www.php.net/license/3_0.txt.                                  |
24
// | If you did not receive a copy of the PHP license and are unable to   |
25
// | obtain it through the world-wide-web, please send a note to          |
26
// | license@php.net so we can mail you a copy immediately.               |
27
// +----------------------------------------------------------------------+
28
// | Author: Bertrand Mansion <bmansion@mamasam.com>                      |
29
// +----------------------------------------------------------------------+
30
//
31
// $Id: Getargs.php 304313 2010-10-11 14:37:56Z jespino $
32
require_once 'PEAR.php';
33
/**#@+
34
 * Error Constants
35
*/
36
/**
37
 * Wrong configuration
38
 *
39
 * This error will be TRIGGERed when a configuration error is found,
40
 * it will also issue a WARNING.
41
 */
42
define('CONSOLE_GETARGS_ERROR_CONFIG', -1);
43
 
44
/**
45
 * User made an error
46
 *
47
 * This error will be RETURNed when a bad parameter
48
 * is found in the command line, for example an unknown parameter
49
 * or a parameter with an invalid number of options.
50
 */
51
define('CONSOLE_GETARGS_ERROR_USER', -2);
52
 
53
/**
54
 * Help text wanted
55
 *
56
 * This error will be RETURNed when the user asked to
57
 * see the help by using <kbd>-h</kbd> or <kbd>--help</kbd> in the command line, you can then print
58
 * the help ascii art text by using the {@link Console_Getargs::getHelp()} method
59
 */
60
define('CONSOLE_GETARGS_HELP', -3);
61
 
62
/**
63
 * Option name for application "parameters"
64
 *
65
 * Parameters are the options an application needs to function.
66
 * The two files passed to the diff command would be considered
67
 * the parameters. These are different from other options in that
68
 * they do not need an option name passed on the command line.
69
 */
70
define('CONSOLE_GETARGS_PARAMS', 'parameters');
71
/**#@-*/
72
 
73
/**
74
 * Command-line arguments parsing class
75
 *
76
 * This implementation was freely inspired by a python module called
77
 * getargs by Vinod Vijayarajan and a perl CPAN module called
78
 * Getopt::Simple by Ron Savage
79
 *
80
 * This class implements a Command Line Parser that your cli applications
81
 * can use to parse command line arguments found in $_SERVER['argv'] or a
82
 * user defined array.
83
 *
84
 * It gives more flexibility and error checking than Console_Getopt. It also
85
 * performs some arguments validation and is capable to return a formatted
86
 * help text to the user, based on the configuration it is given.
87
 *
88
 * The class provides the following capabilities:
89
 * - Each command line option can take an arbitrary number of arguments.
90
 * - Makes the distinction between switches (options without arguments)
91
 *   and options that require arguments.
92
 * - Recognizes 'single-argument-options' and 'default-if-set' options.
93
 * - Switches and options with arguments can be interleaved in the command
94
 *   line.
95
 * - You can specify the maximum and minimum number of arguments an option
96
 *   can take. Use -1 if you don't want to specify an upper bound.
97
 * - Specify the default arguments to an option
98
 * - Short options can be more than one letter in length.
99
 * - A given option may be invoked by multiple names (aliases).
100
 * - Understands by default the --help, -h options
101
 * - Can return a formatted help text
102
 * - Arguments may be specified using the '=' syntax also.
103
 * - Short option names may be concatenated (-dvw 100 == -d -v -w 100)
104
 * - Can define a default option that will take any arguments added without
105
 *   an option name
106
 * - Can pass in a user defined array of arguments instead of using
107
 *   $_SERVER['argv']
108
 *
109
 * @todo      Implement the parsing of comma delimited arguments
110
 * @todo      Implement method for turning assocative arrays into command
111
 *            line arguments (ex. array('d' => true, 'v' => 2) -->
112
 *            array('-d', '-v', 2))
113
 *
114
 * @category  Extension
115
 * @package   Console_Getargs
116
 * @author    Bertrand Mansion <bmansion@mamasam.com>
117
 * @copyright 2004 Bertrand Mansion
118
 * @license   http://www.php.net/license/3_0.txt PHP License 3.0
119
 * @version   1.3.5
120
 * @link      http://pear.php.net/package/Console_Getargs
121
 */
122
class Console_Getargs
123
{
124
    /**
125
     * Factory creates a new {@link Console_Getargs_Options} object
126
     *
127
     * This method will return a new {@link Console_Getargs_Options}
128
     * built using the given configuration options. If the configuration
129
     * or the command line options contain errors, the returned object will
130
     * in fact be a PEAR_Error explaining the cause of the error.
131
     *
132
     * Factory expects an array as parameter.
133
     * The format for this array is:
134
     * <pre>
135
     * array(
136
     *  longname => array('short'   => Short option name,
137
     *                    'max'     => Maximum arguments for option,
138
     *                    'min'     => Minimum arguments for option,
139
     *                    'default' => Default option argument,
140
     *                    'desc'    => Option description)
141
     * )
142
     * </pre>
143
     *
144
     * If an option can be invoked by more than one name, they have to be defined
145
     * by using | as a separator. For example: name1|name2
146
     * This works both in long and short names.
147
     *
148
     * max/min are the most/least number of arguments an option accepts.
149
     *
150
     * The 'defaults' field is optional and is used to specify default
151
     * arguments to an option. These will be assigned to the option if
152
     * it is *not* used in the command line.
153
     * Default arguments can be:
154
     * - a single value for options that require a single argument,
155
     * - an array of values for options with more than one possible arguments.
156
     * Default argument(s) are mandatory for 'default-if-set' options.
157
     *
158
     * If max is 0 (option is just a switch), min is ignored.
159
     * If max is -1, then the option can have an unlimited number of arguments
160
     * greater or equal to min.
161
     *
162
     * If max == min == 1, the option is treated as a single argument option.
163
     *
164
     * If max >= 1 and min == 0, the option is treated as a
165
     * 'default-if-set' option. This implies that it will get the default argument
166
     * only if the option is used in the command line without any value.
167
     * (Note: defaults *must* be specified for 'default-if-set' options)
168
     *
169
     * If the option is not in the command line, the defaults are
170
     * *not* applied. If an argument for the option is specified on the command
171
     * line, then the given argument is assigned to the option.
172
     * Thus:
173
     * - a --debug in the command line would cause debug = 'default argument'
174
     * - a --debug 2 in the command line would result in debug = 2
175
     *  if not used in the command line, debug will not be defined.
176
     *
177
     * Example 1.
178
     * <code>
179
     * require_once 'Console/Getargs.php';
180
     *
181
     * $args =& Console_Getargs::factory($config);
182
     *
183
     * if (PEAR::isError($args)) {
184
     *  if ($args->getCode() === CONSOLE_GETARGS_ERROR_USER) {
185
     *    echo Console_Getargs::getHelp($config, null, $args->getMessage())."\n";
186
     *  } else if ($args->getCode() === CONSOLE_GETARGS_HELP) {
187
     *    echo Console_Getargs::getHelp($config)."\n";
188
     *  }
189
     *  exit;
190
     * }
191
     *
192
     * echo 'Verbose: '.$args->getValue('verbose')."\n";
193
     * if ($args->isDefined('bs')) {
194
     *  echo 'Block-size: '.(is_array($args->getValue('bs')) ? implode(', ', $args->getValue('bs'))."\n" : $args->getValue('bs')."\n");
195
     * } else {
196
     *  echo "Block-size: undefined\n";
197
     * }
198
     * echo 'Files: '.($args->isDefined('file') ? implode(', ', $args->getValue('file'))."\n" : "undefined\n");
199
     * if ($args->isDefined('n')) {
200
     *  echo 'Nodes: '.(is_array($args->getValue('n')) ? implode(', ', $args->getValue('n'))."\n" : $args->getValue('n')."\n");
201
     * } else {
202
     *  echo "Nodes: undefined\n";
203
     * }
204
     * echo 'Log: '.$args->getValue('log')."\n";
205
     * echo 'Debug: '.($args->isDefined('d') ? "YES\n" : "NO\n");
206
     *
207
     * </code>
208
     *
209
     * If you don't want to require any option name for a set of arguments,
210
     * or if you would like any "leftover" arguments assigned by default,
211
     * you can create an option named CONSOLE_GETARGS_PARAMS that will
212
     * grab any arguments that cannot be assigned to another option. The
213
     * rules for CONSOLE_GETARGS_PARAMS are still the same. If you specify
214
     * that two values must be passed then two values must be passed. See
215
     * the example script for a complete example.
216
     *
217
     * @param array $config    associative array with keys being the
218
     * @param array $arguments numeric array of command line arguments
219
     *
220
     * @access public
221
     * @return object|PEAR_Error a newly created Console_Getargs_Options
222
     *                           object or a PEAR_Error object on error
223
     */
224
    function &factory($config = array(), $arguments = null)
225
    {
226
        // Create the options object.
227
        $obj = & new Console_Getargs_Options();
228
 
229
        // Try to set up the arguments.
230
        $err = $obj->init($config, $arguments);
231
        if ($err !== true) {
232
            return $err;
233
        }
234
 
235
        // Try to set up the options.
236
        $err = $obj->buildMaps();
237
        if ($err !== true) {
238
            return $err;
239
        }
240
 
241
        // Get the options and arguments from the command line.
242
        $err = $obj->parseArgs();
243
        if ($err !== true) {
244
            return $err;
245
        }
246
 
247
        // Set arguments for options that have defaults.
248
        $err = $obj->setDefaults();
249
        if ($err !== true) {
250
            return $err;
251
        }
252
 
253
        // Double check that all required options have been passed.
254
        $err = $obj->checkRequired();
255
        if ($err !== true) {
256
            return $err;
257
        }
258
 
259
        // All is good.
260
        return $obj;
261
    }
262
 
263
    /**
264
     * Returns an ascii art version of the help
265
     *
266
     * This method uses the given configuration and parameters
267
     * to create and format an help text for the options you defined
268
     * in your config parameter. You can supply a header and a footer
269
     * as well as the maximum length of a line. If you supplied
270
     * descriptions for your options, they will be used as well.
271
     *
272
     * By default, it returns something like this:
273
     * <pre>
274
     * Usage: myscript.php [-dv --formats] <-fw --filters>
275
     *
276
     * -f --files values(2)          Set the source and destination image files.
277
     * -w --width=&lt;value&gt;      Set the new width of the image.
278
     * -d --debug                    Switch to debug mode.
279
     * --formats values(1-3)         Set the image destination format. (jpegbig,
280
     *                               jpegsmall)
281
     * -fi --filters values(1-...)   Set the filters to be applied to the image upon
282
     *                               conversion. The filters will be used in the order
283
     *                               they are set.
284
     * -v --verbose (optional)value  Set the verbose level. (3)
285
     * </pre>
286
     *
287
     * @param array  $config     your args configuration
288
     * @param string $helpHeader the header for the help. If it is left null,
289
     *                           a default header will be used, starting by Usage:
290
     * @param string $helpFooter the footer for the help. This could be used
291
     *                           to supply a description of the error the user made
292
     * @param int    $maxlength  help lines max length
293
     * @param int    $indent     the indent for the options
294
     *
295
     * @access public
296
     * @return string the formatted help text
297
     */
298
    function getHelp($config, $helpHeader = null, $helpFooter = '', $maxlength = 78, $indent = 0)
299
    {
300
        // Start with an empty help message and build it piece by piece
301
        $help = '';
302
 
303
        // If no user defined header, build the default header.
304
        if (!isset($helpHeader)) {
305
            // Get the optional, required and "paramter" names for this config.
306
            list($optional, $required, $params) = Console_Getargs::getOptionalRequired($config);
307
            // Start with the file name.
308
            if (isset($_SERVER['SCRIPT_NAME'])) {
309
                $filename = basename($_SERVER['SCRIPT_NAME']);
310
            } else {
311
                $filename = $argv[0];
312
            }
313
            $helpHeader = 'Usage: ' . $filename . ' ';
314
            // Add the optional arguments and required arguments.
315
            $helpHeader.= $optional . ' ' . $required . ' ';
316
            // Add any parameters that are needed.
317
            $helpHeader.= $params . "\n\n";
318
        }
319
 
320
        // Create an indent string to be prepended to each option row.
321
        $indentStr = str_repeat(' ', (int)$indent);
322
 
323
        // Go through all of the short options to get a padding value.
324
        $v = array_values($config);
325
        $shortlen = 0;
326
        foreach ($v as $item) {
327
            if (isset($item['short'])) {
328
                $shortArr = explode('|', $item['short']);
329
 
330
                if (strlen($shortArr[0]) > $shortlen) {
331
                    $shortlen = strlen($shortArr[0]);
332
                }
333
            }
334
        }
335
 
336
        // Add two to account for the extra characters we add automatically.
337
        $shortlen+= 2;
338
 
339
        // Build the list of options and definitions.
340
        $i = 0;
341
        foreach ($config as $long => $def) {
342
 
343
            // Break the names up if there is more than one for an option.
344
            $shortArr = array();
345
            if (isset($def['short'])) {
346
                $shortArr = explode('|', $def['short']);
347
            }
348
            $longArr = explode('|', $long);
349
 
350
            // Column one is the option name displayed as "-short, --long [additional info]"
351
            // Start with the indent string.
352
            $col1[$i] = $indentStr;
353
            // Add the short option name.
354
            $col1[$i].= str_pad(!empty($shortArr) ? '-' . $shortArr[0] . ' ' : '', $shortlen);
355
            // Add the long option name.
356
            $col1[$i].= '--' . $longArr[0];
357
 
358
            // Get the min and max to show needed/optional values.
359
            // Cast to int to avoid complications elsewhere.
360
            $max = (int)$def['max'];
361
            $min = isset($def['min']) ? (int)$def['min'] : $max;
362
 
363
            if ($max === 1 && $min === 1) {
364
                // One value required.
365
                $col1[$i].= '=<value>';
366
            } else if ($max > 1) {
367
                if ($min === $max) {
368
                    // More than one value needed.
369
                    $col1[$i].= ' values(' . $max . ')';
370
                } else if ($min === 0) {
371
                    // Argument takes optional value(s).
372
                    $col1[$i].= ' values(optional)';
373
                } else {
374
                    // Argument takes a range of values.
375
                    $col1[$i].= ' values(' . $min . '-' . $max . ')';
376
                }
377
            } else if ($max === 1 && $min === 0) {
378
                // Argument can take at most one value.
379
                $col1[$i].= ' (optional)value';
380
            } else if ($max === - 1) {
381
                // Argument can take unlimited values.
382
                if ($min > 0) {
383
                    $col1[$i].= ' values(' . $min . '-...)';
384
                } else {
385
                    $col1[$i].= ' (optional)values';
386
                }
387
            }
388
 
389
            // Column two is the description if available.
390
            if (isset($def['desc'])) {
391
                $col2[$i] = $def['desc'];
392
            } else {
393
                $col2[$i] = '';
394
            }
395
            // Add the default value(s) if there are any/
396
            if (isset($def['default'])) {
397
                if (is_array($def['default'])) {
398
                    $col2[$i].= ' (' . implode(', ', $def['default']) . ')';
399
                } else {
400
                    $col2[$i].= ' (' . $def['default'] . ')';
401
                }
402
            }
403
            $i++;
404
        }
405
 
406
        // Figure out the maximum length for column one.
407
        $arglen = 0;
408
        foreach ($col1 as $txt) {
409
            $length = strlen($txt);
410
            if ($length > $arglen) {
411
                $arglen = $length;
412
            }
413
        }
414
 
415
        // The maximum length for each description line.
416
        $desclen = $maxlength - $arglen;
417
        $padding = str_repeat(' ', $arglen);
418
        foreach ($col1 as $k => $txt) {
419
            // Wrap the descriptions.
420
            if (strlen($col2[$k]) > $desclen) {
421
                $desc = wordwrap($col2[$k], $desclen, "\n  " . $padding);
422
            } else {
423
                $desc = $col2[$k];
424
            }
425
            // Push everything together.
426
            $help.= str_pad($txt, $arglen) . '  ' . $desc . "\n";
427
        }
428
 
429
        // Put it all together.
430
        return $helpHeader . $help . $helpFooter;
431
    }
432
 
433
    /**
434
     * Parse the config array to determine which flags are
435
     * optional and which are required.
436
     *
437
     * To make the help header more descriptive, the options
438
     * are shown seperated into optional and required flags.
439
     * When possible the short flag is used for readability.
440
     * Optional items (including "parameters") are surrounded
441
     * in square braces ([-vd]). Required flags are surrounded
442
     * in angle brackets (<-wf>).
443
     *
444
     * This method may be called statically.
445
     *
446
     * @param array &$config The config array.
447
     *
448
     * @access  public
449
     * @return  array
450
     * @author  Scott Mattocks
451
     * @package Console_Getargs
452
     */
453
    function getOptionalRequired(&$config)
454
    {
455
        // Parse the config array and look for optional/required
456
        // tags.
457
        $optional = '';
458
        $optionalHasShort = false;
459
        $required = '';
460
        $requiredHasShort = false;
461
 
462
        ksort($config);
463
        foreach ($config as $long => $def) {
464
 
465
            // We only really care about the first option name.
466
            $long = explode('|', $long);
467
            $long = reset($long);
468
 
469
            // Treat the "parameters" specially.
470
            if ($long == CONSOLE_GETARGS_PARAMS) {
471
                continue;
472
            }
473
            if (isset($def['short'])) {
474
                // We only really care about the first option name.
475
                $def['short'] = explode('|', $def['short']);
476
                $def['short'] = reset($def['short']);
477
            }
478
 
479
            if (!isset($def['min']) || $def['min'] == 0 || isset($def['default'])) {
480
                // This argument is optional.
481
                if (isset($def['short']) && strlen($def['short']) == 1) {
482
                    $optional = $def['short'] . $optional;
483
                    $optionalHasShort = true;
484
                } else {
485
                    $optional.= ' --' . $long;
486
                }
487
            } else {
488
                // This argument is required.
489
                if (isset($def['short']) && strlen($def['short']) == 1) {
490
                    $required = $def['short'] . $required;
491
                    $requiredHasShort = true;
492
                } else {
493
                    $required.= ' --' . $long;
494
                }
495
            }
496
        }
497
 
498
        // Check for "parameters" option.
499
        $params = '';
500
        if (isset($config[CONSOLE_GETARGS_PARAMS])) {
501
            for ($i = 1; $i <= max($config[CONSOLE_GETARGS_PARAMS]['max'], $config[CONSOLE_GETARGS_PARAMS]['min']); ++$i) {
502
                if ($config[CONSOLE_GETARGS_PARAMS]['max'] == - 1 || ($i > $config[CONSOLE_GETARGS_PARAMS]['min'] && $i <= $config[CONSOLE_GETARGS_PARAMS]['max']) || isset($config[CONSOLE_GETARGS_PARAMS]['default'])) {
503
                    // Parameter is optional.
504
                    $params.= '[param' . $i . '] ';
505
                } else {
506
                    // Parameter is required.
507
                    $params.= 'param' . $i . ' ';
508
                }
509
            }
510
        }
511
        // Add a leading - if needed.
512
        if ($optionalHasShort) {
513
            $optional = '-' . $optional;
514
        }
515
 
516
        if ($requiredHasShort) {
517
            $required = '-' . $required;
518
        }
519
 
520
        // Add the extra characters if needed.
521
        if (!empty($optional)) {
522
            $optional = '[' . $optional . ']';
523
        }
524
        if (!empty($required)) {
525
            $required = '<' . $required . '>';
526
        }
527
 
528
        return array($optional, $required, $params);
529
    }
530
} // end class Console_Getargs
531
 
532
/**
533
 * This class implements a wrapper to the command line options and arguments.
534
 *
535
 * @category Extension
536
 * @package  Console_Getargs
537
 * @author   Bertrand Mansion <bmansion@mamasam.com>
538
 * @license  http://www.php.net/license/3_0.txt PHP License 3.0
539
 * @link     http://pear.php.net/package/Console_Getargs
540
 */
541
class Console_Getargs_Options
542
{
543
 
544
    /**
545
     * Lookup to match short options name with long ones
546
     * @var    array
547
     * @access private
548
     */
549
    var $_shortLong = array();
550
 
551
    /**
552
     * Lookup to match alias options name with long ones
553
     * @var    array
554
     * @access private
555
     */
556
    var $_aliasLong = array();
557
 
558
    /**
559
     * Arguments set for the options
560
     * @var    array
561
     * @access private
562
     */
563
    var $_longLong = array();
564
 
565
    /**
566
     * If arguments have been defined on cmdline
567
     * @var    array
568
     * @access private
569
     */
570
    var $_defined = array();
571
 
572
    /**
573
     * Configuration set at initialization time
574
     * @var    array
575
     * @access private
576
     */
577
    var $_config = array();
578
 
579
    /**
580
     * A read/write copy of argv
581
     * @var    array
582
     * @access private
583
     */
584
    var $args = array();
585
 
586
    /**
587
     * Initializes the Console_Getargs_Options object
588
     *
589
     * @param array $config    configuration options
590
     * @param array $arguments arguments
591
     *
592
     * @access private
593
     * @throws CONSOLE_GETARGS_ERROR_CONFIG
594
     * @return true|PEAR_Error
595
     */
596
    function init($config, $arguments = null)
597
    {
598
        if (is_array($arguments)) {
599
            // Use the user defined argument list.
600
            $this->args = $arguments;
601
        } else {
602
            // Command line arguments must be available.
603
            if (!isset($_SERVER['argv']) || !is_array($_SERVER['argv'])) {
604
                return PEAR::raiseError("Could not read argv", CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::init()');
605
            }
606
            $this->args = $_SERVER['argv'];
607
        }
608
 
609
        // Drop the first argument if it doesn't begin with a '-'.
610
        if (isset($this->args[0] { 0 })
611
            && $this->args[0] { 0 } != '-'
612
        ) {
613
            array_shift($this->args);
614
        }
615
        $this->_config = $config;
616
        return true;
617
    }
618
 
619
    /**
620
     * Makes the lookup arrays for alias and short name mapping with long names
621
     *
622
     * @access private
623
     * @throws CONSOLE_GETARGS_ERROR_CONFIG
624
     * @return true|PEAR_Error
625
     */
626
    function buildMaps()
627
    {
628
        foreach ($this->_config as $long => $def) {
629
 
630
            $longArr = explode('|', $long);
631
            $longname = $longArr[0];
632
 
633
            if (count($longArr) > 1) {
634
                // The fisrt item in the list is "the option".
635
                // The rest are aliases.
636
                array_shift($longArr);
637
                foreach ($longArr as $alias) {
638
                    // Watch out for duplicate aliases.
639
                    if (isset($this->_aliasLong[$alias])) {
640
                        return PEAR::raiseError('Duplicate alias for long option ' . $alias, CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::buildMaps()');
641
                    }
642
                    $this->_aliasLong[$alias] = $longname;
643
                }
644
                // Add the real option name and defintion.
645
                $this->_config[$longname] = $def;
646
                // Get rid of the old version (name|alias1|...)
647
                unset($this->_config[$long]);
648
            }
649
 
650
            // Add the (optional) short option names.
651
            if (!empty($def['short'])) {
652
                // Short names
653
                $shortArr = explode('|', $def['short']);
654
                $short = $shortArr[0];
655
                if (count($shortArr) > 1) {
656
                    // The first item is "the option".
657
                    // The rest are aliases.
658
                    array_shift($shortArr);
659
                    foreach ($shortArr as $alias) {
660
                        // Watch out for duplicate aliases.
661
                        if (isset($this->_shortLong[$alias])) {
662
                            return PEAR::raiseError('Duplicate alias for short option ' . $alias, CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::buildMaps()');
663
                        }
664
                        $this->_shortLong[$alias] = $longname;
665
                    }
666
                }
667
                // Add the real short option name.
668
                $this->_shortLong[$short] = $longname;
669
            }
670
        }
671
        return true;
672
    }
673
 
674
    /**
675
     * Parses the given options/arguments one by one
676
     *
677
     * @access private
678
     * @throws CONSOLE_GETARGS_HELP
679
     * @throws CONSOLE_GETARGS_ERROR_USER
680
     * @return true|PEAR_Error
681
     */
682
    function parseArgs()
683
    {
684
        // Go through the options and parse the arguments for each.
685
        for ($i = 0, $count = count($this->args); $i < $count; $i++) {
686
            $arg = $this->args[$i];
687
            if ($arg === '--help' || $arg === '-h') {
688
                // Asking for help breaks the loop.
689
                return PEAR::raiseError(null, CONSOLE_GETARGS_HELP, PEAR_ERROR_RETURN);
690
 
691
            }
692
            if ($arg === '--') {
693
                // '--' alone signals the start of "parameters"
694
                $err = $this->parseArg(CONSOLE_GETARGS_PARAMS, true, ++$i);
695
            } elseif (strlen($arg) > 1 && $arg{0} == '-' && $arg{1} == '-') {
696
                // Long name used (--option)
697
                $err = $this->parseArg(substr($arg, 2), true, $i);
698
            } else if (strlen($arg) > 1 && $arg{0} == '-') {
699
                // Short name used (-o)
700
                $err = $this->parseArg(substr($arg, 1), false, $i);
701
                if ($err === - 1) {
702
                    break;
703
                }
704
            } elseif (isset($this->_config[CONSOLE_GETARGS_PARAMS])) {
705
                // No flags at all. Try the parameters option.
706
                $tempI = & $i - 1;
707
                $err = $this->parseArg(CONSOLE_GETARGS_PARAMS, true, $tempI);
708
            } else {
709
                $err = PEAR::raiseError('Unknown argument ' . $arg, CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::parseArgs()');
710
            }
711
            if ($err !== true) {
712
                return $err;
713
            }
714
        }
715
        // Check to see if we need to reload the arguments
716
        // due to concatenated short names.
717
        if (isset($err) && $err === - 1) {
718
            return $this->parseArgs();
719
        }
720
 
721
        return true;
722
    }
723
 
724
    /**
725
     * Parses one option/argument
726
     *
727
     * @access private
728
     * @throws CONSOLE_GETARGS_ERROR_USER
729
     * @return true|PEAR_Error
730
     */
731
    function parseArg($arg, $isLong, &$pos)
732
    {
733
        // If the whole short option isn't in the shortLong array
734
        // then break it into a bunch of switches.
735
        if (!$isLong && !isset($this->_shortLong[$arg]) && strlen($arg) > 1) {
736
            $newArgs = array();
737
            for ($i = 0; $i < strlen($arg); $i++) {
738
                if (array_key_exists($arg{$i}, $this->_shortLong)) {
739
                    $newArgs[] = '-' . $arg{$i};
740
                } else {
741
                    $newArgs[] = $arg{$i};
742
                }
743
            }
744
            // Add the new args to the array.
745
            array_splice($this->args, $pos, 1, $newArgs);
746
 
747
            // Reset the option values.
748
            $this->_longLong = array();
749
            $this->_defined = array();
750
 
751
            // Then reparse the arguments.
752
            return -1;
753
        }
754
 
755
        $opt = '';
756
        for ($i = 0; $i < strlen($arg); $i++) {
757
            // Build the option name one char at a time looking for a match.
758
            $opt.= $arg{$i};
759
            if ($isLong === false && isset($this->_shortLong[$opt])) {
760
                // Found a match in the short option names.
761
                $cmp = $opt;
762
                $long = $this->_shortLong[$opt];
763
            } elseif ($isLong === true && isset($this->_config[$opt])) {
764
                // Found a match in the long option names.
765
                $long = $cmp = $opt;
766
            } elseif ($isLong === true && isset($this->_aliasLong[$opt])) {
767
                // Found a match in the long option names.
768
                $long = $this->_aliasLong[$opt];
769
                $cmp = $opt;
770
            }
771
            if ($arg{$i} === '=') {
772
                // End of the option name when '=' is found.
773
                break;
774
            }
775
        }
776
 
777
        // If no option name is found, assume -- was passed.
778
        if ($opt == '') {
779
            $long = CONSOLE_GETARGS_PARAMS;
780
        }
781
 
782
        if (isset($long)) {
783
            // A match was found.
784
            if (strlen($arg) > strlen($cmp)) {
785
                // Seperate the argument from the option.
786
                // Ex: php test.php -f=image.png
787
                //     $cmp = 'f'
788
                //     $arg = 'f=image.png'
789
                $arg = substr($arg, strlen($cmp));
790
                // Now $arg = '=image.png'
791
                if ($arg{0} === '=') {
792
                    $arg = substr($arg, 1);
793
                    // Now $arg = 'image.png'
794
                }
795
            } else {
796
                // No argument passed for option.
797
                $arg = '';
798
            }
799
            // Set the options value.
800
            return $this->setValue($long, $arg, $pos);
801
        }
802
        return PEAR::raiseError('Unknown argument ' . $opt, CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::parseArg()');
803
    }
804
 
805
    /**
806
     * Set the option arguments
807
     *
808
     * @access private
809
     * @throws CONSOLE_GETARGS_ERROR_CONFIG
810
     * @throws CONSOLE_GETARGS_ERROR_USER
811
     * @return true|PEAR_Error
812
     */
813
    function setValue($optname, $value, &$pos)
814
    {
815
        if (!isset($this->_config[$optname]['max'])) {
816
            // Max must be set for every option even if it is zero or -1.
817
            return PEAR::raiseError('No max parameter set for ' . $optname, CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::setValue()');
818
        }
819
 
820
        $max = (int)$this->_config[$optname]['max'];
821
        $min = isset($this->_config[$optname]['min']) ? (int)$this->_config[$optname]['min'] : $max;
822
 
823
        // A value was passed after the option.
824
        if ($value !== '') {
825
            // Argument is like -v5
826
            if ($min == 1 && $max > 0) {
827
                // At least one argument is required for option.
828
                $this->updateValue($optname, $value);
829
                return true;
830
            }
831
            if ($max === 0) {
832
                // Argument passed but not expected.
833
                return PEAR::raiseError('Argument ' . $optname . ' does not take any value', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
834
            }
835
            // Not enough arguments passed for this option.
836
            return PEAR::raiseError('Argument ' . $optname . ' expects more than one value', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
837
        }
838
 
839
        if ($min === 1 && $max === 1) {
840
            // Argument requires 1 value
841
            // If optname is "parameters" take a step back.
842
            if ($optname == CONSOLE_GETARGS_PARAMS) {
843
                $pos--;
844
            }
845
            if (isset($this->args[$pos + 1]) && $this->isValue($this->args[$pos + 1])) {
846
                // Set the option value and increment the position.
847
                $this->updateValue($optname, $this->args[$pos + 1]);
848
                $pos++;
849
                return true;
850
            }
851
            // What we thought was the argument was really the next option.
852
            return PEAR::raiseError('Argument ' . $optname . ' expects one value', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
853
        } else if ($max === 0) {
854
            // Argument is a switch
855
            if (isset($this->args[$pos + 1]) && $this->isValue($this->args[$pos + 1])) {
856
                // What we thought was the next option was really an argument for this option.
857
                // First update the value
858
                $this->updateValue($optname, true);
859
                // Then try to assign values to parameters.
860
                if (isset($this->_config[CONSOLE_GETARGS_PARAMS])) {
861
                    return $this->setValue(CONSOLE_GETARGS_PARAMS, '', ++$pos);
862
                } else {
863
                    return PEAR::raiseError('Argument ' . $optname . ' does not take any value', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
864
                }
865
            }
866
            // Set the switch to on.
867
            $this->updateValue($optname, true);
868
            return true;
869
 
870
        } else if ($max >= 1 && $min === 0) {
871
            // Argument has a default-if-set value
872
            if (!isset($this->_config[$optname]['default'])) {
873
                // A default value MUST be assigned when config is loaded.
874
                return PEAR::raiseError('No default value defined for ' . $optname, CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::setValue()');
875
            }
876
            if (is_array($this->_config[$optname]['default'])) {
877
                // Default value cannot be an array.
878
                return PEAR::raiseError('Default value for ' . $optname . ' must be scalar', CONSOLE_GETARGS_ERROR_CONFIG, PEAR_ERROR_TRIGGER, E_USER_WARNING, 'Console_Getargs_Options::setValue()');
879
            }
880
 
881
            // If optname is "parameters" take a step back.
882
            if ($optname == CONSOLE_GETARGS_PARAMS) {
883
                $pos--;
884
            }
885
 
886
            if (isset($this->args[$pos + 1]) && $this->isValue($this->args[$pos + 1])) {
887
                // Assign the option the value from the command line if there is one.
888
                $this->updateValue($optname, $this->args[$pos + 1]);
889
                $pos++;
890
                return true;
891
            }
892
            // Otherwise use the default value.
893
            $this->updateValue($optname, $this->_config[$optname]['default']);
894
            return true;
895
        }
896
 
897
        // Argument takes one or more values
898
        $added = 0;
899
        // If trying to assign values to parameters, must go back one position.
900
        if ($optname == CONSOLE_GETARGS_PARAMS) {
901
            $pos = max($pos - 1, -1);
902
        }
903
        for ($i = $pos + 1; $i <= count($this->args); $i++) {
904
            $paramFull = $max <= count($this->getValue($optname)) && $max != - 1;
905
            if (isset($this->args[$i]) && $this->isValue($this->args[$i]) && !$paramFull) {
906
                // Add the argument value until the next option is hit.
907
                $this->updateValue($optname, $this->args[$i]);
908
                $added++;
909
                $pos++;
910
                // Only keep trying if we haven't filled up yet.
911
                // or there is no limit
912
                if (($added < $max || $max < 0) && ($max < 0 || !$paramFull)) {
913
                    continue;
914
                }
915
            }
916
            if ($min > $added && !$paramFull) {
917
                // There aren't enough arguments for this option.
918
                return PEAR::raiseError('Argument ' . $optname . ' expects at least ' . $min . (($min > 1) ? ' values' : ' value'), CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
919
            } elseif ($max !== - 1 && $paramFull) {
920
                // Too many arguments for this option.
921
                // Try to add the extra options to parameters.
922
                if (isset($this->_config[CONSOLE_GETARGS_PARAMS]) && $optname != CONSOLE_GETARGS_PARAMS) {
923
                    return $this->setValue(CONSOLE_GETARGS_PARAMS, '', ++$pos);
924
                } elseif ($optname == CONSOLE_GETARGS_PARAMS && empty($this->args[$i])) {
925
                    $pos+= $added;
926
                    break;
927
                } else {
928
                    return PEAR::raiseError('Argument ' . $optname . ' expects maximum ' . $max . ' values', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::setValue()');
929
                }
930
            }
931
            break;
932
        }
933
        // Everything went well.
934
        return true;
935
    }
936
 
937
    /**
938
     * Checks whether the given parameter is an argument or an option
939
     *
940
     * @access private
941
     * @return boolean
942
     */
943
    function isValue($arg)
944
    {
945
        if ((strlen($arg) > 1 && $arg{0} == '-' && $arg{1} == '-') || (strlen($arg) > 1 && $arg{0} == '-')) {
946
            // The next argument is really an option.
947
            return false;
948
        }
949
        return true;
950
    }
951
 
952
    /**
953
     * Adds the argument to the option
954
     *
955
     * If the argument for the option is already set,
956
     * the option arguments will be changed to an array
957
     *
958
     * @access private
959
     * @return void
960
     */
961
    function updateValue($optname, $value)
962
    {
963
        if (isset($this->_longLong[$optname])) {
964
            if (is_array($this->_longLong[$optname])) {
965
                // Add this value to the list of values for this option.
966
                $this->_longLong[$optname][] = $value;
967
            } else {
968
                // There is already one value set. Turn everything into a list of values.
969
                $prevValue = $this->_longLong[$optname];
970
                $this->_longLong[$optname] = array($prevValue);
971
                $this->_longLong[$optname][] = $value;
972
            }
973
        } else {
974
            // This is the first value for this option.
975
            $this->_longLong[$optname] = $value;
976
        }
977
        $this->_defined[$optname] = true;
978
    }
979
 
980
    /**
981
     * Sets the option default arguments when necessary
982
     *
983
     * @access private
984
     * @return true
985
     */
986
    function setDefaults()
987
    {
988
        foreach ($this->_config as $longname => $def) {
989
            // Add the default value only if the default is defined
990
            // and the option requires at least one argument.
991
            if (isset($def['default']) && ((isset($def['min']) && $def['min'] !== 0) || (!isset($def['min']) & isset($def['max']) && $def['max'] !== 0)) && !isset($this->_longLong[$longname])) {
992
                $this->_longLong[$longname] = $def['default'];
993
                $this->_defined[$longname] = false;
994
            }
995
        }
996
        return true;
997
    }
998
 
999
    /**
1000
     * Checks whether the given option is defined
1001
     *
1002
     * An option will be defined if an argument was assigned to it using
1003
     * the command line options. You can use the short, the long or
1004
     * an alias name as parameter.
1005
     *
1006
     * @param string $optname the name of the option to be checked
1007
     *
1008
     * @access public
1009
     * @return boolean true if the option is defined
1010
     */
1011
    function isDefined($optname)
1012
    {
1013
        $longname = $this->getLongName($optname);
1014
        return isset($this->_defined[$longname]) && $this->_defined[$longname];
1015
    }
1016
 
1017
    /**
1018
     * Returns the long version of the given parameter
1019
     *
1020
     * If the given name is not found, it will return the name that
1021
     * was given, without further ensuring that the option
1022
     * actually exists
1023
     *
1024
     * @param string $optname the name of the option
1025
     *
1026
     * @access private
1027
     * @return string long version of the option name
1028
     */
1029
    function getLongName($optname)
1030
    {
1031
        if (isset($this->_shortLong[$optname])) {
1032
            // Short version was passed.
1033
            $longname = $this->_shortLong[$optname];
1034
        } else if (isset($this->_aliasLong[$optname])) {
1035
            // An alias was passed.
1036
            $longname = $this->_aliasLong[$optname];
1037
        } else {
1038
            // No further validation is done.
1039
            $longname = $optname;
1040
        }
1041
        return $longname;
1042
    }
1043
 
1044
    /**
1045
     * Returns the argument of the given option
1046
     *
1047
     * You can use the short, alias or long version of the option name.
1048
     * This method will try to find the argument(s) of the given option name.
1049
     * If it is not found it will return null. If the arg has more than
1050
     * one argument, an array of arguments will be returned.
1051
     *
1052
     * @param string $optname the name of the option
1053
     *
1054
     * @access public
1055
     * @return array|string|null argument(s) associated with the option
1056
     */
1057
    function getValue($optname)
1058
    {
1059
        $longname = $this->getLongName($optname);
1060
        if (isset($this->_longLong[$longname])) {
1061
            // Option is defined. Return its value
1062
            return $this->_longLong[$longname];
1063
        }
1064
        // Option is not defined.
1065
        return null;
1066
    }
1067
 
1068
    /**
1069
     * Returns all arguments that have been parsed and recognized
1070
     *
1071
     * The name of the options are stored in the keys of the array.
1072
     * You may choose whether you want to use the long or the short
1073
     * option names
1074
     *
1075
     * @param string $optionNames option names to use for the keys (long or short)
1076
     *
1077
     * @access public
1078
     * @return array values for all options
1079
     */
1080
    function getValues($optionNames = 'long')
1081
    {
1082
        switch ($optionNames) {
1083
        case 'short':
1084
            $values = array();
1085
            foreach ($this->_shortLong as $short => $long) {
1086
                if (isset($this->_longLong[$long])) {
1087
                    $values[$short] = $this->_longLong[$long];
1088
                }
1089
            }
1090
            if (isset($this->_longLong['parameters'])) {
1091
                $values['parameters'] = $this->_longLong['parameters'];
1092
            }
1093
            return $values;
1094
        case 'long':
1095
        default:
1096
            return $this->_longLong;
1097
        }
1098
    }
1099
 
1100
    /**
1101
     * checkRequired
1102
     *
1103
     * @access public
1104
     * @return void
1105
     */
1106
    function checkRequired()
1107
    {
1108
        foreach ($this->_config as $optName => $opt) {
1109
            if (isset($opt['min']) && $opt['min'] == 1 && $this->getValue($optName) === null) {
1110
                $err = PEAR::raiseError($optName . ' is required', CONSOLE_GETARGS_ERROR_USER, PEAR_ERROR_RETURN, null, 'Console_Getargs_Options::parseArgs()');
1111
                return $err;
1112
            }
1113
        }
1114
        return true;
1115
    }
1116
} // end class Console_Getargs_Options
1117
/*
1118
 * Local variables:
1119
 * tab-width: 4
1120
 * c-basic-offset: 4
1121
 * End:
1122
*/
1123
?>