package.xml 0000664 0001750 0001750 00000127232 13102315277 011307 0 ustar jan jan
Horde_Argvpear.horde.orgArgvHorde command-line argument parsing packageClasses for parsing command line arguments with various actions, providing help, grouping options, and more.Jan Schneiderjanjan@horde.orgyesChuck Hagenbuchchuckchuck@horde.orgnoMike Nabereznymnaberezmike@maintainable.comno2017-05-032.1.01.1.0stablestableBSD-2-Clause
* [jan] Colorize output.
* [jan] Add Horde_Argv_HelpFormatter#highlightHeading() and Horde_Argv_HelpFormatter#highlightOption().
5.3.08.0.0alpha18.0.0alpha11.7.0Horde_Clipear.horde.org2.2.03.0.0alpha13.0.0alpha1Horde_Exceptionpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Translationpear.horde.org2.2.03.0.0alpha13.0.0alpha1Horde_Utilpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Testpear.horde.org2.1.03.0.0alpha13.0.0alpha10.1.00.1.0betabeta2010-10-22BSD-2-Clause
* Initial release, ported from Optik (http://optik.sourceforge.net/)
1.0.0alpha11.0.0alphaalpha2011-03-08BSD-2-Clause
* First alpha release for Horde 4.
1.0.0beta11.0.0betabeta2011-03-16BSD-2-Clause
* First beta release for Horde 4.
1.0.0RC11.0.0betabeta2011-03-22BSD-2-Clause
* First release candidate for Horde 4.
1.0.0RC21.0.0betabeta2011-03-29BSD-2-Clause
* Second release candidate for Horde 4.
1.0.01.0.0stablestable2011-04-06BSD-2-Clause
* First stable release for Horde 4.
1.0.11.0.0stablestable2011-05-18BSD-2-Clause
* [jan] Updated Spanish translation.
1.0.21.0.0stablestable2011-06-01BSD-2-Clause
* [jan] Updated Slovak translation.
1.0.31.0.0stablestable2011-07-05BSD-2-Clause
* [jan] Update Lithuanian translation.
1.0.41.0.0stablestable2011-07-27BSD-2-Clause
* [jan] Update Latvian translation.
1.0.51.0.0stablestable2011-11-22BSD-2-Clause
* [jan] Update Estonian translation.
* [jan] Fix tests to work with PHPUnit 3.6.
2.0.0alpha11.0.0alphastable2012-07-05BSD-2-Clause
* First alpha release for Horde 5.
2.0.0beta11.0.0betastable2012-07-19BSD-2-Clause
* First beta release for Horde 5.
2.0.01.0.0stablestable2012-10-30BSD-2-Clause
* First stable release for Horde 5.
2.0.11.0.0stablestable2012-11-06BSD-2-Clause
* [jan] Update Dutch translation (Arjen de Korte <build+horde@de-korte.org>).
2.0.21.0.0stablestable2012-11-19BSD-2-Clause
* [mms] Use new Horde_Test layout.
2.0.31.0.0stablestable2013-01-09BSD-2-Clause
* [jan] Update Basque translation (Ibon Igartua <ibon.igartua@ehu.es>).
2.0.41.0.0stablestable2013-01-29BSD-2-Clause
* [jan] Update French translation (Paul De Vlieger <paul.de_vlieger@moniut.univ-bpclermont.fr>).
2.0.51.0.0stablestable2013-03-05BSD-2-Clause
* [jan] Add extensive documention.
2.0.61.0.0stablestable2013-04-04BSD-2-Clause
* [jan] Fix documentation formatting.
2.0.71.0.0stablestable2013-04-04BSD-2-Clause
* [jan] Re-release of broken package.
2.0.81.0.0stablestable2014-04-03BSD-2-Clause
* [jan] Update Ukrainian translation.
2.0.91.0.0stablestable2014-05-21BSD-2-Clause
* [jan] Update Hungarian translation (Andras Galos <galosa@netinform.hu>).
2.0.101.0.0stablestable2015-01-08BSD-2-Clause
* [jan] Support loading translations from Composer-installed package.
* [jan] Improve PSR-2 compatibility.
2.0.111.0.0stablestable2015-04-28BSD-2-Clause
* [jan] Fix issues with certain locales like Turkish.
2.0.121.0.0stablestable2016-02-01BSD-2-Clause
* [jan] Mark PHP 7 as supported.
2.1.01.1.0stablestable2017-05-03BSD-2-Clause
* [jan] Colorize output.
* [jan] Add Horde_Argv_HelpFormatter#highlightHeading() and Horde_Argv_HelpFormatter#highlightOption().
Horde_Argv-2.1.0/doc/Horde/Argv/ADVANCED 0000664 0001750 0001750 00000037603 13102315276 015444 0 ustar jan jan ============
Horde_Argv
============
.. contents:: Contents
.. section-numbering::
----------------
Advanced Usage
----------------
This is reference documentation. If you haven't read the `Basic Usage`_ tutorial document yet, do so now.
.. _`Basic Usage`: Basic Usage
Creating and populating the parser
==================================
There are several ways to populate the parser with options. One way is to pass a list of ``Horde_Argv_Option``s to the ``Horde_Argv_Parser`` constructor:
::
$parser = new Horde_Argv_Parser(array('optionList' => array(
new Horde_Argv_Option(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')),
new Horde_Argv_Option(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose'))
)));
For long option lists, it's often more convenient/readable to create the list separately:
::
$option_list = array(
new Horde_Argv_Option(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')),
// ... 17 other options ...
new Horde_Argv_Option(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose'))
);
$parser = new Horde_Argv_Parser(array('optionList' => $option_list));
Or, you can use the ``addOption()`` method of ``Horde_Argv_Parser`` to add options one at a time:
::
$parser = new Horde_Argv_Parser();
$parser->addOption(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')
);
$parser->addOption(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose')
);
This method makes it easier to track down exceptions raised by the ``Horde_Argv_Option`` constructor, which are common because of the complicated interdependencies among the various keyword arguments -- if you get it wrong, *Horde_Argv* throws an ``InvalidArgumentException``.
``addOption()`` can be called in one of two ways:
* pass it an ``Horde_Argv_Option`` instance
* pass it any combination of positional and keyword arguments that are acceptable to ``new Horde_Argv_Option()`` (ie., to the ``Horde_Argv_Option`` constructor), and it will create the ``Horde_Argv_Option`` instance for you (shown above)
Defining options
================
Each ``Horde_Argv_Option`` instance represents a set of synonymous command-line options, ie. options that have the same meaning and effect, but different spellings. You can specify any number of short or long option strings, but you must specify at least one option string.
To define an option with only a short option string:
::
new Horde_Argv_Option('-f', ...)
And to define an option with only a long option string:
::
new Horde_Argv_Option('--foo', ...)
The ... represents a set of keyword arguments that define option attributes, i.e. attributes of the ``Horde_Argv_Option`` object. Just which keyword args you must supply for a given ``Horde_Argv_Option`` is fairly complicated (see the various ``_check*()`` methods in the ``Horde_Argv_Option`` class if you don't believe me). If you get it wrong, *Horde_Argv* throws an ``InvalidArgumentException`` explaining your mistake.
The most important attribute of an option is its action, ie. what to do when we encounter this option on the command-line. The possible actions are:
:``store``: store this option's argument [default]
:``store_const``: store a constant value
:``store_true``: store a ``TRUE`` value
:``store_false``: store a ``FALSE`` value
:``append``: append this option's argument to a list
:``count``: increment a counter by one
:``callback``: call a specified function
:``help``: print a usage message including all options and the
documentation for them
(If you don't supply an action, the default is ``store``. For this action, you may also supply ``type`` and ``dest`` option attributes; see below.)
As you can see, most actions involve storing or updating a value somewhere. *Horde_Argv* always creates an instance of ``Horde_Argv_Values`` (referred to as options) specifically for this purpose. Option arguments (and various other values) are stored as attributes of this object, according to the ``dest`` (destination) option attribute.
For example, when you call
::
$parser->parseArgs();
one of the first things *Horde_Argv* does is create the options object:
::
$options = new Horde_Argv_Values();
If one of the options in this parser is defined with
::
new Horde_Argv_Option('-f', '--file', array('action' => 'store', 'type' => 'string', 'dest' => 'filename'))
and the command-line being parsed includes any of the following:
::
-ffoo
-f foo
--file=foo
--file foo
then *Horde_Argv*, on seeing the "-f" or "--file" option, will do the equivalent of this:
::
$options->filename = 'foo';
Clearly, the ``type`` and ``dest`` arguments are almost as important as ``action``. ``action`` is the only attribute that is meaningful for all options, though, so it is the most important.
Option actions
==============
The various option actions all have slightly different requirements and effects. Most actions have several relevant option attributes which you may specify to guide *Horde_Argv*'s behaviour; a few have required attributes, which you must specify for any option using that action.
* ``store`` [relevant: ``type``, ``dest``, ``nargs``, ``choices``]
The option must be followed by an argument, which is converted to a value according to ``type`` and stored in ``dest``. If ``nargs`` > 1, multiple arguments will be consumed from the command line; all will be converted according to ``type`` and stored to ``dest`` as an array. See the "Option types" section below.
If ``choices`` is supplied (an array of strings), the ``type`` defaults to ``choice``.
If ``type`` is not supplied, it defaults to ``string``.
If ``dest`` is not supplied, *Horde_Argv* derives a destination from the first long option strings (e.g., "--foo-bar" implies "foo_bar"). If there are no long option strings, *Horde_Argv* derives a destination from the first short option string (e.g., "-f" implies "f").
Example:
::
$parser->addOption('-f');
$parser->addOption('-p', array('type' => 'float', 'nargs' => 3, 'dest' => 'point'));
Given the following command line:
``-f foo.txt -p 1 -3.5 4 -fbar.txt``
*Horde_Argv* will set
::
$options->f = 'foo.txt';
$options->point = array(1.0, -3.5, 4.0);
$options->f = 'bar.txt';
* ``store_const`` [required: ``const``; relevant: ``dest``]
The value ``const`` is stored in ``dest``.
Example:
::
$parser->addOption('-q', '--quiet', array('action' => 'store_const', 'const' => 0, 'dest' => 'verbose'));
$parser->addOption('-v', '--verbose', array('action' => 'store_const', 'const' => 1, 'dest' => 'verbose'));
$parser->addOption('--noisy', array('action' => 'store_const', 'const' => 2, 'dest' => 'verbose'));
If "--noisy" is seen, *Horde_Argv* will set
::
$options->verbose = 2;
* ``store_true`` [relevant: ``dest``]
A special case of ``store_const`` that stores a ``TRUE`` value to ``dest``.
* ``store_false`` [relevant: ``dest``]
Like ``store_true``, but stores a ``FALSE`` value.
Example:
::
$parser->addOption(null, '--clobber', array('action' => 'store_true', 'dest' => 'clobber'));
$parser->addOption(null, '--no-clobber', array('action' => 'store_false', 'dest' => 'clobber'));
* ``append`` [relevant: ``type``, ``dest``, ``nargs``, ``choices``]
The option must be followed by an argument, which is appended to the array in ``dest``. If no default value for ``dest`` is supplied, an empty array is automatically created when *Horde_Argv* first encounters this option on the command-line. If ``nargs`` > 1, multiple arguments are consumed, and an array of length ``nargs`` is appended to ``dest``.
The defaults for ``type`` and ``dest`` are the same as for the ``store`` action.
Example:
::
$parser->addOption('-t', '--tracks', array('action' => 'append', 'type' => 'int'));
If "-t3" is seen on the command-line, *Horde_Argv* does the equivalent of:
::
$options->tracks = array();
$options->tracks[] = intval('3');
If, a little later on, "--tracks=4" is seen, it does:
::
$options->tracks[] = intval('4');
* ``count`` [relevant: ``dest``]
Increment the integer stored at ``dest``. ``dest`` is set to zero before being incremented the first time (unless you supply a default value).
Example:
::
$parser->addOption('-v', array('action' => 'count', 'dest' => 'verbosity'));
The first time "-v" is seen on the command line, *Horde_Argv* does the equivalent of:
::
$options->verbosity = 0;
$options->verbosity += 1;
Every subsequent occurrence of "-v" results in
::
$options->verbosity += 1;
* ``callback`` [required: ``callback``; relevant: ``type``, ``nargs``, ``callback_args``, ``callback_kwargs``]
Call the function specified by ``callback``. The signature of this function should be
::
func(Horde_Argv_Option $option,
string $opt,
mixed $value,
Horde_Argv_Parser $parser,
array $args,
array $kwargs)
See Option Callbacks for more detail.
* ``help`` [relevant: none]
Prints a complete help message for all the options in the current option parser. The help message is constructed from the ``usage`` string passed to ``Horde_Argv_Parser``'s constructor and the ``help`` string passed to every option.
If no help string is supplied for an option, it will still be listed in the help message. To omit an option entirely, use the special value ``Horde_Argv_Option::SUPPRESS_HELP``.
Example:
::
$parser = new Horde_Argv_Parser();
$parser->addOption('-h', '--help',
array('action' => 'help'));
$parser->addOption('-v',
array('action' => 'store_true', 'dest' => 'verbose',
'help' => 'Be moderately verbose'));
$parser->addOption('--file',
array('dest' => 'filename',
'help' => 'Input file to read data from'));
$parser->addOption('--secret',
array('help' => Horde_Argv_Option::SUPPRESS_HELP));
If *Horde_Argv* sees either "-h" or "--help" on the command line, it will print something like the following help message to stdout (assuming $_SERVER['argv'][0] is "foo.php"):
::
usage: foo.py [options]
options:
-h, --help Show this help message and exit
-v Be moderately verbose
--file=FILENAME Input file to read data from
After printing the help message, *Horde_Argv* terminates your process with ``exit(0)``.
* ``version`` [relevant: none]
Prints the version number supplied to the ``Horde_Argv_Parser`` to stdout and exits. The version number is actually formatted and printed by the ``printVersion()`` method of ``Horde_Argv_Parser``. Generally only relevant if the version argument is supplied to the ``Horde_Argv_Parser`` constructor.
Option types
============
*Horde_Argv* has six built-in option types: ``string``, ``int``, ``long``, ``choice``, ``float`` and ``complex``. If you need to add new option types, see `Extending Horde_Argv`_.
.. _`Extending Horde_Argv`: Extending Horde_Argv
Arguments to string options are not checked or converted in any way: the text on the command line is stored in the destination (or passed to the callback) as-is.
Integer arguments are passed to ``intval()`` to convert them to PHP integers. If ``intval()`` fails, so will *Horde_Argv*, although with a more useful error message. (Internally, *Horde_Argv* throws ``Horde_Argv_OptionValueException`` from ``Horde_Argv_Option#checkBuiltin()``; ``Horde_Argv_Parser`` catches this exception higher up and terminates your program with a useful error message.)
Likewise, float arguments are passed to ``floatval()`` for conversion, long arguments also to ``intval()``, and complex arguments are not handled yet. Apart from that, they are handled identically to integer arguments.
``choice`` options are a subtype of ``string`` options. The ``choices`` option attribute (an array of strings) defines the set of allowed option arguments. ``Horde_Argv_Option#checkChoice()`` compares user-supplied option arguments against this master list and throws ``Horde_Argv_OptionValueException`` if an invalid string is given.
Querying and manipulating your option parser
============================================
Sometimes, it's useful to poke around your option parser and see what's there. ``Horde_Argv_Parser`` provides a couple of methods to help you out:
:``boolean hasOption(string $opt_str)``: Given an option string such as
"-q" or "--verbose", returns ``true`` if the ``Horde_Argv_Parser`` has an option
with that option string.
:``Horde_Argv_Option getOption(string $opt_str)``: Returns the
``Horde_Argv_Option`` instance that implements the supplied option string, or
``null`` if no options implement it.
:``removeOption(string $opt_str)``: If the ``Horde_Argv_Parser``
has an option corresponding to ``$opt_str``, that option is removed. If that
option provided any other option strings, all of those option strings become
invalid. If ``$opt_str`` does not occur in any option belonging to this
``Horde_Argv_Parser``, throws ``InvalidArgumentException``.
Conflicts between options
=========================
If you're not careful, it's easy to define conflicting options:
::
$parser->addOption('-n', '--dry-run', ...);
[...]
$parser->addOption('-n', '--noisy', ...);
(This is even easier to do if you've defined your own ``Horde_Argv_Parser`` subclass with some standard options.)
Every time you add an option, *Horde_Argv* checks for conflicts with existing options. If it finds any, it invokes the current conflict-handling mechanism. You can set the conflict-handling mechanism either in the constructor:
::
$parser = new Horde_Argv_Parser(..., array('conflictHandler' => '...'));
or with a separate call:
::
$parser->setConflictHandler('...');
The available conflict-handling mechanisms are:
:``error`` (default): assume option conflicts are a programming error and throws
``Horde_Argv_OptionConflictException``
:``resolve``: resolve option conflicts intelligently (see below)
Here's an example: first, define an ``Horde_Argv_Parser`` that resolves conflicts intelligently:
::
$parser = new Horde_Argv_Parser(array('conflictHandler' => 'resolve'));
Now add all of our options:
::
$parser->addOption('-n', '--dry-run', ..., array('help' => 'original dry-run option'));
[...]
$parser->addOption('-n', '--noisy', ..., array('help' => 'be noisy'));
At this point, *Horde_Argv* detects that a previously-added option is already using the "-n" option string. Since ``conflictHandler`` is "resolve", it resolves the situation by removing "-n" from the earlier option's list of option strings. Now, "--dry-run" is the only way for the user to activate that option. If the user asks for help, the help message will reflect that, e.g.:
::
options:
--dry-run original dry-run option
[...]
-n, --noisy be noisy
Note that it's possible to whittle away the option strings for a previously-added option until there are none left, and the user has no way of invoking that option from the command-line. In that case, *Horde_Argv* removes that option completely, so it doesn't show up in help text or anywhere else. E.g. if we carry on with our existing ``Horde_Argv_Parser``:
::
$parser->addOption('--dry-run', ..., array('help' => 'new dry-run option'));
At this point, the first "-n/--dry-run" option is no longer accessible, so *Horde_Argv* removes it. If the user asks for help, they'll get something like this:
::
options:
[...]
-n, --noisy be noisy
--dry-run new dry-run option
Horde_Argv-2.1.0/doc/Horde/Argv/CALLBACKS 0000664 0001750 0001750 00000026216 13102315276 015554 0 ustar jan jan ============
Horde_Argv
============
------------------
Option Callbacks
------------------
When *Horde_Argv*'s built-in actions and types aren't quite enough for your needs, you have two choices: extend *Horde_Argv* or define a callback option. Extending *Horde_Argv* is more general, but overkill for a lot of simple cases. Quite often a simple callback is all you need.
You define a callback in two steps:
* define the option itself using the callback action
* write the callback; this is a function (or method) that takes at least four arguments, as described below
Defining a callback option
==========================
As always, the easiest way to define a callback option is by using the ``addOption()`` method of your ``Horde_Argv_Parser`` object. The only option attribute you must specify is callback, the function to call:
::
$parser->addOption('-c', array('action' => 'callback', 'callback' => 'my_callback'));
Note that you supply a ``callable`` here -- so you must have already defined a function ``my_callback()`` when you define the ``callback`` option. In this simple case, *Horde_Argv* knows nothing about the arguments the "-c" option expects to take. Usually, this means that the option doesn't take any arguments -- the mere presence of "-c" on the command-line is all it needs to know. In some circumstances, though, you might want your callback to consume an arbitrary number of command-line arguments. This is where writing callbacks gets tricky; it's covered later in this document.
*Horde_Argv* always passes four particular arguments to your callback, and it will only pass additional arguments if you specify them via ``callback_args`` and ``callback_kwargs``. Thus, the minimal callback function signature is:
::
function my_callback($option, $opt, $value, $parser)
The four arguments to a callback are described below.
There are several other option attributes that you can supply when you define an option attribute:
:``type``: has its usual meaning: as with the ``store`` or ``append``
actions, it instructs *Horde_Argv* to consume one argument and convert it to
``type``. Rather than storing the converted value(s) anywhere, though,
*Horde_Argv* passes it to your callback function.
:``nargs``: also has its usual meaning: if it is supplied and > 1,
*Horde_Argv* will consume ``nargs`` arguments, each of which must be convertible
to ``type``. It then passes an array of converted values to your callback.
:``callback_args``: an array of extra positional arguments to pass to the
callback
:``callback_kwargs``: a hash of extra keyword arguments to pass to the callback
How callbacks are called
========================
All callbacks are called as follows:
::
func(Horde_Argv_Option $option,
string $opt,
mixed $value,
Horde_Argv_Parser $parser,
array $args,
array $kwargs)
where
:``$option``: is the ``Horde_Argv_Option`` instance that's calling the callback
:``$opt``: is the option string seen on the command-line that's triggering the
callback. (If an abbreviated long option was used, ``$opt`` will be the full,
canonical option string -- e.g. if the user puts "--foo" on the command-line as
an abbreviation for "--foobar", then ``$opt`` will be "--foobar".)
:``$value``: is the argument to this option seen on the command-line.
*Horde_Argv* will only expect an argument if ``type`` is set; the type of
``$value`` will be the type implied by the option's type (see "Option types"
below). If ``type`` for this option is ``null`` (no argument expected), then
``$value`` will be ``null``. If ``nargs`` > 1, ``$value`` will be an array of
values of the appropriate type.
:``$parser``: is the ``Horde_Argv_Parser`` instance driving the whole thing,
mainly useful because you can access some other interesting data through it, as
instance attributes:
: ``$parser->largs`` : the current list of leftover arguments, ie. arguments that have been consumed but are neither options nor option arguments. Feel free to modify ``$parser->largs``, e.g. by adding more arguments to it. (This list will become ``$args``, the second return value of ``parseArgs()``.)
: ``$parser->rargs`` : the current list of remaining arguments, ie. with ``$opt`` and ``$value`` (if applicable) removed, and only the arguments following them still there. Feel free to modify ``$parser->rargs``, e.g. by consuming more arguments.
: ``$parser->values`` : the object where option values are by default stored (an instance of ``Horde_Argv_Values``). This lets callbacks use the same mechanism as the rest of *Horde_Argv* for storing option values; you don't need to mess around with globals or closures. You can also access or modify the value(s) of any options already encountered on the command-line.
:``$args``: is a tuple of arbitrary positional arguments supplied via the
``callback_args`` option attribute.
:``$kwargs``: is a dictionary of arbitrary keyword arguments supplied via
``callback_kwargs``.
Error handling
==============
The callback function should throw ``Horde_Argv_OptionValueException`` if there are any problems with the option or its argument(s). *Horde_Argv* catches this and terminates the program, printing the error message you supply to stderr. Your message should be clear, concise, accurate, and mention the option at fault. Otherwise, the user will have a hard time figuring out what he did wrong.
Examples part 1: no arguments
=============================
Here's an example of a callback option that takes no arguments, and simply records that the option was seen:
::
function record_foo_seen($option, $opt, $value, $parser)
{
$parser->saw_foo = true;
}
$parser->addOption(
'--foo',
arry('action' => 'callback', 'callback' => 'record_foo_seen')
);
Of course, you could do that with the ``store_true`` action. Here's a slightly more interesting example: record the fact that "-a" is seen, but blow up if it comes after "-b" in the command-line.
::
$check_order = function($option, $opt, $value, $parser)
{
if ($parser->values->b) {
throw new Horde_Argv_OptionValueException("can't use -a after -b");
}
$parser->values->a = 1;
}
[...]
$parser->addOption(
'-a',
array('action' => 'callback', 'callback' => $check_order)
);
$parser->addOption('-b', array('action' => 'store_true', 'dest' => 'b'));
If you want to re-use this callback for several similar options (set a flag, but blow up if "-b" has already been seen), it needs a bit of work: the error message and the flag that it sets must be generalized.
::
function check_order($option, $opt, $value, $parser)
{
if ($parser->values->b) {
throw new Horde_Argv_OptionValueException(sprintf("can't use %s after -b", $opt));
}
$parser->values->{$option->dest} = 1;
}
[...]
$parser->addOption(
'-a',
array('action' => 'callback', 'callback' => 'check_order', 'dest' => 'a')
);
$parser->addOption(
'-b',
array('action' => 'store_true', 'dest' => 'b')
);
$parser->addOption(
'-c',
array('action' => 'callback', 'callback' => 'check_order', 'dest' => 'c')
);
Of course, you could put any condition in there -- you're not limited to checking the values of already-defined options. For example, if you have options that should not be called when the moon is full, all you have to do is this:
::
function check_moon($option, $opt, $value, $parser)
{
if (is_moon_full()) {
throw new Horde_Argv_OptionValueException(sprintf('%s option invalid when moon is full', $opt));
}
$parser->values->{$option->dest} = 1;
}
[...]
$parser->addOption(
'--foo',
array('action' => 'callback', 'callback' => 'check_moon', 'dest' => 'foo')
);
(The definition of ``is_moon_full()`` is left as an exercise for the reader.)
Examples part 2: fixed arguments
================================
Things get slightly more interesting when you define callback options that take a fixed number of arguments. Specifying that a callback option takes arguments is similar to defining a ``store`` or ``append`` option: if you define ``type``, then the option takes one argument that must be convertible to that type; if you further define ``nargs``, then the option takes ``nargs`` arguments.
Here's an example that just emulates the standard ``store`` action:
::
function store_value($option, $opt, $value, $parser)
{
$parser->values->{$option->dest} = $value;
}
[...]
$parser->addOption(
'--foo',
array('action' => 'callback', 'callback' => 'store_value',
'type' => 'int', 'nargs' => 3, 'dest' => 'foo')
);
Note that *Horde_Argv* takes care of consuming 3 arguments and converting them to integers for you; all you have to do is store them. (Or whatever: obviously you don't need a callback for this example. Use your imagination!)
Examples part 3: variable arguments
===================================
Things get hairy when you want an option to take a variable number of arguments. For this case, you must write a callback, as *Horde_Argv* doesn't provide any built-in capabilities for it. And you have to deal with certain intricacies of conventional Unix command-line parsing that *Horde_Argv* normally handles for you. In particular, callbacks have to worry about bare "--" and "-" arguments; the convention is:
* bare "--", if not the argument to some option, causes command-line processing to halt and the "--" itself is lost
* bare "-" similarly causes command-line processing to halt, but the "-" itself is kept
* either "--" or "-" can be option arguments
If you want an option that takes a variable number of arguments, there are several subtle, tricky issues to worry about. The exact implementation you choose will be based on which trade-offs you're willing to make for your application (which is why *Horde_Argv* doesn't support this sort of thing directly).
Nevertheless, here's a stab at a callback for an option with variable arguments:
::
function vararg_callback($option, $opt, $value, $parser)
{
$done = 0;
$value = array();
$rargs = $parser->rargs;
while ($rargs) {
$arg = $rargs[0];
// Stop if we hit an $arg like '--foo', '-a', '-fx', '--file=f',
// etc. Note that this also stops on '-3' or '-3.0', so if
// your option takes numeric values, you will need to handle
// this.
if ((substr($arg, 0, 2) == '--' && strlen($arg) > 2) ||
($arg[0] == '-' && strlen($arg) > 1 && $arg[1] != '-')) {
break;
} else {
$value[] = $arg;
}
array_shift($rargs);
}
$parser->values->{$option->dest} = $value;
}
[...]
$parser->addOption(
'-c', '--callback',
array('action' => 'callback', 'callback' => 'vararg_callback')
);
The main weakness with this particular implementation is that negative numbers in the arguments following "-c" will be interpreted as further options, rather than as arguments to "-c". Fixing this is left as an exercise for the reader.
Horde_Argv-2.1.0/doc/Horde/Argv/COPYING 0000664 0001750 0001750 00000002430 13102315276 015375 0 ustar jan jan Copyright 1999-2017 Horde LLC. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HORDE PROJECT
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Horde_Argv-2.1.0/doc/Horde/Argv/DOCS_ORIGIN 0000664 0001750 0001750 00000001423 13102315276 016065 0 ustar jan jan ======================
Documentation origin
======================
Some of the Horde component documentation is maintained in the Horde
wiki. The following list indicates the source locations for some of
the files in this directory.
:`doc/Horde/Argv/README`_: README
:`doc/Horde/Argv/ADVANCED`_: ADVANCED
:`doc/Horde/Argv/EXTEND`_: EXTEND
:`doc/Horde/Argv/CALLBACKS`_: CALLBACKS
.. _doc/Horde/Argv/README: http://wiki.horde.org/Doc/Dev/HordeArgv?actionID=export&format=rst
.. _doc/Horde/Argv/ADVANCED: http://wiki.horde.org/Doc/Dev/HordeArgvAdvanced?actionID=export&format=rst
.. _doc/Horde/Argv/EXTEND: http://wiki.horde.org/Doc/Dev/HordeArgvExtend?actionID=export&format=rst
.. _doc/Horde/Argv/CALLBACKS: http://wiki.horde.org/Doc/Dev/HordeArgvCallbacks?actionID=export&format=rst
Horde_Argv-2.1.0/doc/Horde/Argv/EXTEND 0000664 0001750 0001750 00000021156 13102315276 015262 0 ustar jan jan ============
Horde_Argv
============
----------------------
Extending Horde_Argv
----------------------
Since the two major controlling factors in how *Horde_Argv* interprets command-line options are the action and type of each option, the most likely direction of extension is to add new actions and new types.
Adding new types
================
To add new types, you need to define your own subclass of the ``Horde_Argv_Option class``. This class has a couple of properties that define *Horde_Argv*'s types: ``$TYPES`` and ``$TYPE_CHECKER``.
``$TYPES`` is a tuple of type names; in your subclass, simply define a new tuple ``$TYPES`` that builds on the standard one.
``$TYPE_CHECKER`` is a dictionary mapping type names to type-checking functions. A type-checking function has the following signature:
::
foo check_foo(Horde_Argv_Option $option, string $opt, string $value)
You can name it whatever you like, and make it return any type you like (e.g. the hypothetical type foo). The value returned by a type-checking function will wind up in the ``Horde_Argv_Values`` instance returned by ``Horde_Argv_Parser->parseArgs()``, or be passed to callbacks as the ``$value`` parameter.
Your type-checking function should throw ``Horde_Argv_OptionValueException`` if it encounters any problems. ``Horde_Argv_OptionValueException`` takes a single string argument, which is passed as-is to ``Horde_Argv_Parser``'s ``parserError()`` method, which in turn prepends the program name and the string ``"error:"`` and prints everything to stderr before terminating the process.
Here's a silly example that demonstrates adding an imaginary ``MyComplex`` option type to parse complex numbers on the command line.
You need to define your type-checker, since it's referred to in the ``$TYPE_CHECKER`` class attribute of your ``Horde_Argv_Option`` subclass:
::
class MyOption extends Horde_Argv_Option
{
public function __construct()
{
$this->TYPES[] = 'complex';
$this->TYPE_CHECKER['complex'] = 'checkComplex';
}
public function checkComplex($option, $opt, $value)
{
try {
return new MyComplex(value);
} catch (Exception $e) {
throw new Horde_Argv_OptionValueException(
sprintf('option %s: invalid complex value: %s', (opt, value))
);
}
}
}
That's it! Now you can write a script that uses the new option type just like any other *Horde_Argv*-based script, except you have to instruct your ``Horde_Argv_Parser`` to use ``MyOption`` instead of ``Horde_Argv_Option``:
::
$parser = new Horde_Argv_Parser(array('optionClass' => 'MyOption'));
$parser->addOption('-c', array('type' => 'complex'));
Alternately, you can build your own option list and pass it to ``Horde_Argv_Parser``; if you don't use ``addOption()`` in the above way, you don't need to tell ``Horde_Argv_Parser`` which option class to use:
::
$option_list = array(
new MyOption(
'-c',
array('action' => 'store', 'type' => 'complex', 'dest' => 'c')
)
);
parser = new Horde_Argv_Parser(array('optionList' => $option_list));
Adding new actions
==================
Adding new actions is a bit trickier, because you have to understand that *Horde_Argv* has a couple of classifications for actions:
:"store" actions: actions that result in *Horde_Argv* storing a value to a
property of the current ``Horde_Argv_Values`` instance; these options require a
``dest`` attribute to be supplied to the ``Horde_Argv_Option`` constructor
:"typed" actions: actions that take a value from the command line and expect it
to be of a certain type; or rather, a string that can be converted to a certain
type. These options require a type attribute to the ``Horde_Argv_Option``
constructor.
These are overlapping sets: some default "store" actions are ``store``, ``store_const``, ``append``, and ``count``, while the default "typed" actions are ``store``, ``append``, and ``callback``.
When you add an action, you need to decide if it's a "store" action, a "typed" action, neither, or both. Three class properties of ``Horde_Argv_Option`` (or your ``Horde_Argv_Option`` subclass) control this:
:``$ACTIONS``: all actions must be listed in ``$ACTIONS``
:``$STORE_ACTIONS``: "store" actions are additionally listed here
:``$TYPED_ACTIONS``: "typed" actions are additionally listed here
In order to actually implement your new action, you must override ``Horde_Argv_Option``'s ``takeAction()`` method and add a case that recognizes your action.
For example, let's add an ``extend`` action. This is similar to the standard ``append`` action, but instead of taking a single value from the command-line and appending it to an existing list, extend will take multiple values in a single comma-delimited string, and extend an existing list with them. That is, if ``"--names"`` is an ``extend`` option of type ``string``, the command line
::
--names=foo,bar --names blah --names ding,dong
would result in a list
::
array('foo', 'bar', 'blah', 'ding', 'dong')
Again we define a subclass of ``Horde_Argv_Option``:
::
class MyOption extends Horde_Argv_Option
{
public function __construct()
{
$this->ACTIONS[] = 'extend';
$this->STORE_ACTIONS[] = 'extend';
$this->TYPED_ACTIONS[] = 'extend';
}
public function takeAction($action, $dest, $opt, $value, $values, $parser)
{
if ($action == 'extend') {
$lvalue = explode(',', $value);
$values->dest = array_merge($values->ensureValue('dest', array()),
$lvalue);
} else {
parent::takeAction($action, $dest, $opt, $value, $values, $parser);
}
}
}
Features of note:
* ``extend`` both expects a value on the command-line and stores that value somewhere, so it goes in both ``$STORE_ACTIONS`` and ``$TYPED_ACTIONS``
* ``MyOption::takeAction()`` implements just this one new action, and passes control back to ``Horde_Argv_Option::takeAction()`` for the standard *Horde_Argv* actions
* ``$values`` is an instance of the ``Horde_Argv_Values`` class, which provides the very useful ``ensureValue()`` method. ``ensureValue()`` is essentially a getter with a safety valve; it is called as
``$values->ensureValue($attr, $value)``
If the ``$attr`` property of ``$values`` doesn't exist or is ``null``, then ``ensureValue()`` first sets it to ``$value``, and then returns ``$value``. This is very handy for actions like ``extend``, ``append``, and ``count``, all of which accumulate data in a variable and expect that variable to be of a certain type (an array for the first two, an integer for the latter). Using ``ensureValue()`` means that scripts using your action don't have to worry about setting a default value for the option destinations in question; they can just leave the default as ``null`` and ``ensureValue()`` will take care of getting it right when it's needed.
Other reasons to extend Horde_Argv
==================================
Adding new types and new actions are the big, obvious reasons why you might want to extend *Horde_Argv*. I can think of at least two other areas to play with.
First, the simple one: ``Horde_Argv_Parser`` tries to be helpful by calling ``exit()`` when appropriate, i.e. when there's an error on the command line or when the user requests help. In the former case, the traditional course of letting the script crash with a traceback is unacceptable; it will make users think there's a bug in your script when they make a command-line error. In the latter case, there's generally not much point in carrying on after printing a help message.
If this behaviour bothers you, it shouldn't be too hard to "fix" it. You'll have to
1. subclass ``Horde_Argv_Parser`` and override ``parserError()``
2. subclass ``Horde_Argv_Option`` and override ``takeAction()`` -- you'll need to provide your own handling of the ``help`` action that doesn't call ``exit()``
The second, much more complex, possibility is to override the command-line syntax implemented by *Horde_Argv*. In this case, you'd leave the whole machinery of option actions and types alone, but rewrite the code that processes ``argv``. You'll need to subclass ``Horde_Argv_Parser`` in any case; depending on how radical a rewrite you want, you'll probably need to override one or all of ``parseArgs()``, ``_processLongOpt()``, and ``_processShortOpts()``.
Both of these are left as an exercise for the reader. I have not tried to implement either myself, since I'm quite happy with *Horde_Argv*'s default behaviour (naturally).
Happy hacking, and don't forget: Use the Source, Luke.
Horde_Argv-2.1.0/doc/Horde/Argv/README 0000664 0001750 0001750 00000033113 13102315276 015224 0 ustar jan jan ============
Horde_Argv
============
.. contents:: Contents
.. section-numbering::
*Horde_Argv* is a library for parsing command line arguments with various actions, providing help, grouping options, and more. It is ported from Python's Optik (http://optik.sourceforge.net/).
-------------
Basic Usage
-------------
While *Horde_Argv* is quite flexible and powerful, you don't have to jump through hoops or read reams of documentation to get started. This document aims to demonstrate some simple usage patterns that will get you started using *Horde_Argv* in your scripts.
To parse a command line with *Horde_Argv*, you must create an ``Horde_Argv_Parser`` instance and define some options. You'll have to import the ``Horde_Argv_Parser`` classes in any script that uses *Horde_Argv*, but it is suggested that you use an autoloader instead:
::
require_once 'Horde/Autoloader/Default.php';
Early on in the main program, create a parser:
::
$parser = new Horde_Argv_Parser();
Then you can start defining options. The basic syntax is:
::
$parser->addOption('opt_str', ..., array('attr' => 'value', ...));
That is, each option has one or more option strings, such as "-f" or "--file", and several option attributes that tell *Horde_Argv* what to expect and what to do when it encounters that option on the command line.
Typically, each option will have one short option string and one long option string, e.g.:
::
$parser->addOption('-f', '--file', ...);
You're free to define as many short option strings and as many long option strings as you like, as long as there is at least one option string overall.
Once all of your options are defined, instruct *Horde_Argv* to parse your program's command line:
::
list($values, $args) = $parser->parseArgs();
(You can pass an argument list to ``parseArgs()`` if you like, but that's rarely necessary: by default it uses $_SERVER['argv'].)
``parseArgs()`` returns two values:
* $values is a ``Horde_Argv_Values`` object containing values for all of your options -- e.g. if "--file" takes a single string argument, then $values->file (or $values['file']) will be the filename supplied by the user, or NULL if the user did not supply that option.
* $args is the list of arguments left over after parsing options.
This tutorial document only covers the four most important option attributes: "action", "type", "dest" (destination), and "help". Of these, "action" is the most fundamental.
Option actions
==============
Actions tell *Horde_Argv* what to do when it encounters an option on the command line. There is a fixed set of actions hard-coded into *Horde_Argv*; adding new actions is an advanced topic covered in `Extending Horde_Argv`_. Most actions tell *Horde_Argv* to store a value in some variable -- for example, take a string from the command line and store it in an attribute of options.
.. _`Extending Horde_Argv`: Extending Horde_Argv
If you don't specify an option action, *Horde_Argv* defaults to "store".
The store action
****************
The most common option action is store, which tells *Horde_Argv* to take the next argument (or the remainder of the current argument), ensure that it is of the correct type, and store it to your chosen destination.
For example:
::
$parser->addOption(
'-f', '--file',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')
);
Now let's make up a fake command line and ask *Horde_Argv* to parse it:
::
$args = array('-f', 'foo.txt');
list($values, $args) = $parser->parseArgs(args);
When *Horde_Argv* sees the "-f", it consumes the next argument, "foo.txt", and stores it in $values->filename, where values is the first return value from ``parseArgs()``. So, after this call to ``parseArgs()``, ``$values->filename`` is "foo.txt".
Some other option types supported by *Horde_Argv* are "int" and "float". Here's an option that expects an integer argument:
::
$parser->addOption('-n', array('type' => 'int', 'dest' => 'num'));
Note that I didn't supply a long option, which is perfectly acceptable. I also didn't specify the action, since the default is "store".
Let's parse another fake command-line. This time, we'll jam the option argument right up against the option -- "-n42" (one argument) is equivalent to "-n 42" (two arguments).
::
list($values, $args) = $parser->parseArgs(array('-n42'));
echo $values->num;
will print "42".
Trying out the "float" type is left as an exercise for the reader.
If you don't specify a type, *Horde_Argv* assumes "string". Combined with the fact that the default action is "store", that means our first example can be a lot shorter:
::
$parser->addOption('-f', '--file', array('dest' => 'filename'))
If you don't supply a destination, *Horde_Argv* figures out a sensible default from the option strings: if the first long option string is "--foo-bar", then the default destination is "foo_bar". If there are no long option strings, *Horde_Argv* looks at the first short option: the default destination for "-f" is "f".
Adding types is covered in "Extending *Horde_Argv*".
Handling flag (boolean) options
*******************************
Flag options -- set a variable to TRUE or FALSE when a particular option is seen -- are quite common. *Horde_Argv* supports them with two separate actions, "store_true" and "store_false". For example, you might have a verbose flag that is turned on with "-v" and off with "-q":
::
$parser->addOption('-v', array('action' => 'store_true', 'dest' => 'verbose'));
$parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose'));
Here we have two different options with the same destination, which is perfectly OK. (It just means you have to be a bit careful when setting default values -- see Default values, below.)
When *Horde_Argv* sees "-v" on the command line, it sets the verbose attribute of the special "option values" object to a TRUE value; when it sees "-q", it sets verbose to a FALSE value.
Other actions
*************
Some other actions supported by *Horde_Argv* are:
:"store_const": store a constant value
:"append": append this option's argument to a list
:"count": increment a counter by one
:"callback": call a specified function
These are covered in the `Advanced Usage`_ and `Option Callbacks`_ documents.
.. _`Advanced Usage`: Advanced Usage
.. _`Option Callbacks`: Option Callbacks
Default values
==============
All of the above examples involve setting some variable (the "destination") when certain command-line options are seen. What happens if those options are never seen? Since we didn't supply any defaults, they are all set to NULL. Usually, this is just fine, but sometimes you want more control. To address that need, *Horde_Argv* lets you supply a default value for each destination, which is assigned before the command-line is parsed.
First, consider the verbose/quiet example. If we want *Horde_Argv* to set verbose to TRUE unless "-q" is seen, then we can do this:
::
$parser->addOption('-v', array('action' => 'store_true', 'dest' => 'verbose', $default => true));
$parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose'));
Oddly enough, this is exactly equivalent:
::
$parser->addOption('-v', array('action' => 'store_true', 'dest' => 'verbose'));
$parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose', $default => true));
Those are equivalent because you're supplying a default value for the option's destination, and these two options happen to have the same destination (the verbose variable).
Consider this:
::
$parser->addOption('-v', array('action' => 'store_true', 'dest' => 'verbose', $default => false));
$parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose', $default => true));
Again, the default value for verbose will be TRUE: the last default value supplied for any particular destination attribute is the one that counts.
A clearer way to specify default values is the ``setDefaults()`` method of ``Horde_Argv_Parser``, which you can call at any time before calling ``parseArgs()``:
::
$parser->setDefaults(array('verbose' => true));
$parser->addOption(...);
list($values, $args) = $parser->parseArgs();
As before, the last value specified for a given option destination is the one that counts. For clarity, try to use one method or the other of setting default values, not both.
Generating help
===============
There is one more feature that you will use in every script: *Horde_Argv*'s ability to generate help messages. All you have to do is supply a help value for each option. Let's create a new parser and populate it with user-friendly (documented) options:
::
$usage = 'usage: %prog [options] arg1 arg2';
$parser = new Horde_Argv_Parser(array('usage' => $usage));
$parser->addOption(
'-v', '--verbose',
array('action' => 'store_true', 'dest' => 'verbose', $default => 1,
'help' => 'make lots of noise [default]')
);
$parser->addOption(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose',
'help' => 'be vewwy quiet (I'm hunting wabbits)')
);
$parser->addOption(
'-f', '--filename',
array('metavar' => 'FILE', 'help' => 'write output to FILE')
);
$parser->addOption(
'-m', '--mode',
array('default' => 'intermediate',
'help' => 'interaction mode: one of "novice", "intermediate" [default], "expert"')
);
If *Horde_Argv* encounters either '-h' or '--help' on the command-line, or if you just call ``$parser->printHelp()``, it prints the following to stdout:
::
usage: [options] arg1 arg2
options:
-h, --help show this help message and exit
-v, --verbose make lots of noise [default]
-q, --quiet be vewwy quiet (I'm hunting wabbits)
-fFILE, --filename=FILE
write output to FILE
-mMODE, --mode=MODE interaction mode: one of 'novice', 'intermediate'
[default], 'expert'
There's a lot going on here to help *Horde_Argv* generate the best possible help message:
* the script defines its own usage message:
``$usage = 'usage: %prog [options] arg1 arg2';``
*Horde_Argv* expands "%prog" in the usage string to the name of the current script, i.e. basename($_SERVER['argv'][0]). The expanded string is then printed before the detailed option help.
If you don't supply a usage string, *Horde_Argv* uses a bland but sensible default: "usage: %prog [options]", which is fine if your script doesn't take any positional arguments.
* every option defines a help string, and doesn't worry about line-wrapping -- *Horde_Argv* takes care of wrapping lines and making the help output look good.
* options that take a value indicate this fact in their automatically-generated help message, e.g. for the "mode" option:
``-mMODE, --mode=MODE``
Here, "MODE" is called the meta-variable: it stands for the argument that the user is expected to supply to -m/--mode. By default, *Horde_Argv* converts the destination variable name to uppercase and uses that for the meta-variable. Sometimes, that's not what you want -- for example, the --filename option explicitly sets $metavar = "FILE", resulting in this automatically-generated option description:
``-fFILE, --filename=FILE``
This is important for more than just saving space, though: the manually written help text uses the meta-variable "FILE", to clue the user in that there's a connection between the formal syntax "-fFILE" and the informal semantic description "write output to FILE". This is a simple but effective way to make your help text a lot clearer and more useful for end users.
Print a version number
======================
Similar to the brief usage string, *Horde_Argv* can also print a version string for your program. You have to supply the string, as the version argument to ``Horde_Argv_Parser``:
::
$parser = new Horde_Argv_Parser(array('usage' => '%prog [-f] [-q]', 'version' => '%prog 1.0'));
Note that "%prog" is expanded just like it is in usage. Apart from that, version can contain anything you like. When you supply it, *Horde_Argv* automatically adds a "--version" option to your parser. If it encounters this option on the command line, it expands your version string (by replacing "%prog"), prints it to stdout, and exits.
For example, if your script is called "/usr/bin/foo", a user might do:
::
$ /usr/bin/foo --version
foo 1.0
Error-handling
==============
The one thing you need to know for basic usage is how *Horde_Argv* behaves when it encounters an error on the command-line -- e.g. "-n4x" where the "-n" option takes an integer. *Horde_Argv* prints your usage message to stderr, followed by a useful and human-readable error message. Then it terminates with a non-zero exit status by calling ``exit()``.
If you don't like this, subclass ``Horde_Argv_Parser`` and override the ``parserError()`` method. See Extending *Horde_Argv*.
Putting it all together
=======================
Here's what a *Horde_Argv*-based scripts usually look like:
::
require_once 'Horde/Autoloader/Default.php';
[...]
$usage = 'usage: %prog [options] arg';
$parser = new Horde_Argv_Parser(array('usage' => $usage));
$parser->addOption(
'-f', '--file',
array('type' => 'string', 'dest' => 'filename',
'help' => 'read data from FILENAME')
);
$parser->addOption(
'-v', '--verbose',
array('action' => 'store_true', 'dest' => 'verbose')
);
$parser->addOption(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose')
);
[... more options ...]
list($values, $args) = $parser->parseArgs();
if (count($args) != 1) {
$parser->parserError('incorrect number of arguments');
}
if ($values->verbose) {
printf('reading %s...%n', $values->filename);
}
[... go to work ...]
Horde_Argv-2.1.0/doc/Horde/Argv/UPGRADING 0000664 0001750 0001750 00000000652 13102315276 015611 0 ustar jan jan ======================
Upgrading Horde_Argv
======================
:Contact: dev@lists.horde.org
.. contents:: Contents
.. section-numbering::
This lists the API changes between releases of the package.
Upgrading to 2.1.0
==================
- Horde_Argv_HelpFormatter
- highlightHeading(), highlightOption()
These methods have been added.
- __construct()
The $color parameter has been added.
Horde_Argv-2.1.0/lib/Horde/Argv/AmbiguousOptionException.php 0000664 0001750 0001750 00000002215 13102315276 022060 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Raised if an ambiguous option is seen on the command line.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_AmbiguousOptionException extends Horde_Argv_BadOptionException
{
public function __construct($opt_str, $possibilities)
{
// Have to skip the BadOptionException constructor or the string gets double-prefixed.
Horde_Argv_OptionException::__construct(sprintf('ambiguous option: %s (%s?)', $opt_str, implode(', ', $possibilities)));
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/BadOptionException.php 0000664 0001750 0001750 00000001730 13102315276 020614 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Raised if an invalid option is seen on the command line.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_BadOptionException extends Horde_Argv_OptionException
{
public function __construct($opt_str)
{
parent::__construct(sprintf('no such option: %s', $opt_str));
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/Exception.php 0000664 0001750 0001750 00000001504 13102315276 017013 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Exception handler for the Horde_Argv library.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_Exception extends Horde_Exception_Wrapped
{
}
Horde_Argv-2.1.0/lib/Horde/Argv/HelpFormatter.php 0000664 0001750 0001750 00000024702 13102315276 017636 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Provides HelpFormatter, used by Horde_Argv_Parser to generate formatted
* help text.
*
* Abstract base class for formatting option help. Horde_Argv_Parser
* instances should use one of the HelpFormatter subclasses for
* formatting help; by default IndentedHelpFormatter is used.
*
* Instance attributes:
* parser : Horde_Argv_Parser
* the controlling Horde_Argv_Parser instance
* _color : Horde_Cli_Color @since Horde_Argv 2.1.0
* a color formatter
* indent_increment : int
* the number of columns to indent per nesting level
* max_help_position : int
* the maximum starting column for option help text
* help_position : int
* the calculated starting column for option help text;
* initially the same as the maximum
* width : int
* total number of columns for output (automatically detected by default)
* level : int
* current indentation level
* current_indent : int
* current indentation level (in columns)
* help_width : int
* number of columns available for option help text (calculated)
* default_tag : str
* text to replace with each option's default value, "%default"
* by default. Set to false value to disable default value expansion.
* option_strings : { Option : str }
* maps Option instances to the snippet of help text explaining
* the syntax of that option, e.g. "-h, --help" or
* "-fFILE, --file=FILE"
* _short_opt_fmt : str
* format string controlling how short options with values are
* printed in help text. Must be either "%s%s" ("-fFILE") or
* "%s %s" ("-f FILE"), because those are the two syntaxes that
* Horde_Argv supports.
* _long_opt_fmt : str
* similar but for long options; must be either "%s %s" ("--file FILE")
* or "%s=%s" ("--file=FILE").
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
abstract class Horde_Argv_HelpFormatter
{
const NO_DEFAULT_VALUE = 'none';
public $parser = null;
public function __construct(
$indent_increment, $max_help_position, $width = null,
$short_first = false, $color = null
)
{
if (is_null($color)) {
$color = new Horde_Cli_Color();
}
$this->_color = $color;
$this->indent_increment = $indent_increment;
$this->help_position = $this->max_help_position = $max_help_position;
if (is_null($width)) {
$cli = new Horde_Cli();
$width = $cli->getWidth() - 2;
}
$this->width = $width;
$this->current_indent = 0;
$this->level = 0;
$this->help_width = null; // computed later
$this->short_first = $short_first;
$this->default_tag = '%default';
$this->option_strings = array();
$this->_short_opt_fmt = '%s %s';
$this->_long_opt_fmt = '%s=%s';
}
public function setParser($parser)
{
$this->parser = $parser;
}
public function setShortOptDelimiter($delim)
{
if (!in_array($delim, array('', ' '))) {
throw new InvalidArgumentException('invalid metavar delimiter for short options: ' . $delim);
}
$this->_short_opt_fmt = "%s$delim%s";
}
public function setLongOptDelimiter($delim)
{
if (!in_array($delim, array('=', ' '))) {
throw new InvalidArgumentException('invalid metavar delimiter for long options: ' . $delim);
}
$this->_long_opt_fmt = "%s$delim%s";
}
public function indent()
{
$this->current_indent += $this->indent_increment;
$this->level += 1;
}
public function dedent()
{
$this->current_indent -= $this->indent_increment;
assert($this->current_indent >= 0); // Indent decreased below 0
$this->level -= 1;
}
abstract public function formatUsage($usage);
abstract public function formatHeading($heading);
/**
* Highlights with the heading color.
*
* @since Horde_Argv 2.1.0
*
* @param string $heading A heading text.
*
* @retun string The colored text.
*/
public function highlightHeading($heading)
{
return $this->_color->brown($heading);
}
/**
* Format a paragraph of free-form text for inclusion in the
* help output at the current indentation level.
*/
protected function _formatText($text)
{
$text_width = $this->width - $this->current_indent;
$indent = str_repeat(' ', $this->current_indent);
return wordwrap($indent . $text, $text_width, "\n" . $indent, true);
}
public function formatDescription($description)
{
if ($description) {
return $this->_formatText($description) . "\n";
} else {
return '';
}
}
public function formatEpilog($epilog)
{
if ($epilog) {
return "\n" . $this->_formatText($epilog) . "\n";
} else {
return '';
}
}
public function expandDefault($option)
{
if (is_null($this->parser) || !$this->default_tag) {
return $option->help;
}
$default_value = isset($this->parser->defaults[$option->dest]) ? $this->parser->defaults[$option->dest] : null;
if ($default_value == Horde_Argv_Option::$NO_DEFAULT || !$default_value) {
$default_value = self::NO_DEFAULT_VALUE;
}
return str_replace($this->default_tag, (string)$default_value, $option->help);
}
/**
* The help for each option consists of two parts:
* * the opt strings and metavars
* eg. ("-x", or "-fFILENAME, --file=FILENAME")
* * the user-supplied help string
* eg. ("turn on expert mode", "read data from FILENAME")
*
* If possible, we write both of these on the same line:
* -x turn on expert mode
*
* But if the opt string list is too long, we put the help
* string on a second line, indented to the same column it would
* start in if it fit on the first line.
* -fFILENAME, --file=FILENAME
* read data from FILENAME
*/
public function formatOption($option)
{
$result = array();
$opts = isset($this->option_strings[(string)$option])
? $this->option_strings[(string)$option]
: null;
$opt_width = $this->help_position - $this->current_indent - 2;
if (strlen($opts) > $opt_width) {
$opts = sprintf(
'%' . $this->current_indent . "s%s\n",
'',
$opts
);
$indent_first = $this->help_position;
} else {
// start help on same line as opts
$opts = sprintf(
'%' . $this->current_indent . 's%-' . $opt_width . 's ',
'',
$opts
);
$indent_first = 0;
}
$opts = $this->highlightOption($opts);
$result[] = $opts;
if ($option->help) {
$help_text = $this->expandDefault($option);
$help_lines = explode("\n", wordwrap($help_text, $this->help_width, "\n", true));
$result[] = sprintf(
'%' . $indent_first . "s%s\n", '', $help_lines[0]
);
for ($i = 1, $i_max = count($help_lines); $i < $i_max; $i++) {
$result[] = sprintf(
'%' . $this->help_position . "s%s\n", '', $help_lines[$i]
);
}
} elseif (substr($opts, -1) != "\n") {
$result[] = "\n";
}
return implode('', $result);
}
/**
* Highlights with the option color.
*
* @since Horde_Argv 2.1.0
*
* @param string $option An option text.
*
* @retun string The colored text.
*/
public function highlightOption($option)
{
return $this->_color->green($option);
}
public function storeOptionStrings($parser)
{
$this->indent();
$max_len = 0;
foreach ($parser->optionList as $opt) {
$strings = $this->formatOptionStrings($opt);
$this->option_strings[(string)$opt] = $strings;
$max_len = max(
$max_len,
strlen($strings) + $this->current_indent
);
}
$this->indent();
foreach ($parser->optionGroups as $group) {
foreach ($group->optionList as $opt) {
$strings = $this->formatOptionStrings($opt);
$this->option_strings[(string)$opt] = $strings;
$max_len = max(
$max_len,
strlen($strings)
+ $this->current_indent
);
}
}
$this->dedent();
$this->dedent();
$this->help_position = min($max_len + 2, $this->max_help_position);
$this->help_width = $this->width - $this->help_position;
}
/**
* Return a comma-separated list of option strings & metavariables.
*/
public function formatOptionStrings($option)
{
if ($option->takesValue()) {
$metavar = $option->metavar ? $option->metavar : Horde_String::upper($option->dest);
$short_opts = array();
foreach ($option->shortOpts as $sopt) {
$short_opts[] = sprintf($this->_short_opt_fmt, $sopt, $metavar);
}
$long_opts = array();
foreach ($option->longOpts as $lopt) {
$long_opts[] = sprintf($this->_long_opt_fmt, $lopt, $metavar);
}
} else {
$short_opts = $option->shortOpts;
$long_opts = $option->longOpts;
}
if ($this->short_first) {
$opts = array_merge($short_opts, $long_opts);
} else {
$opts = array_merge($long_opts, $short_opts);
}
return implode(', ', $opts);
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/IndentedHelpFormatter.php 0000664 0001750 0001750 00000002760 13102315276 021311 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Format help with indented section bodies.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_IndentedHelpFormatter extends Horde_Argv_HelpFormatter
{
public function __construct(
$indent_increment = 2, $max_help_position = 24, $width = null,
$short_first = true, $color = null
)
{
parent::__construct(
$indent_increment, $max_help_position, $width, $short_first, $color
);
}
public function formatUsage($usage)
{
return sprintf(
$this->highlightHeading(Horde_Argv_Translation::t("Usage:"))
. " %s\n",
$usage
);
}
public function formatHeading($heading)
{
return $this->highlightHeading(sprintf(
'%' . $this->current_indent . "s%s:\n", '', $heading
));
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/Option.php 0000664 0001750 0001750 00000046567 13102315276 016347 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Defines the Option class and some standard value-checking functions.
*
* Instance attributes:
* shortOpts : [string]
* longOpts : [string]
*
* action : string
* type : string
* dest : string
* default : any
* nargs : int
* const : any
* choices : [string]
* callback : function
* callbackArgs : (any*)
* help : string
* metavar : string
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_Option
{
const SUPPRESS_HELP = 'SUPPRESS HELP';
const SUPPRESS_USAGE = 'SUPPRESS USAGE';
/**
* Not supplying a default is different from a default of None,
* so we need an explicit 'not supplied' value.
*/
public static $NO_DEFAULT = array('NO', 'DEFAULT');
public static function parseNumber($value)
{
if (!strlen($value)) {
return false;
}
// Values to check against or compute with.
$first = substr($value, 0, 1);
$prefix = substr($value, 0, 2);
$suffix = substr($value, 2);
// Hex
if ($prefix == '0x' || $prefix == '0X') {
if (strspn($suffix, '0123456789abcdefABCDEF') != strlen($suffix)) {
return false;
}
return hexdec($value);
}
// Binary
if ($prefix == '0b' || $prefix == '0B') {
if (strspn($suffix, '01') != strlen($suffix)) {
return false;
}
return bindec($value);
}
// Octal
if ($first == '0') {
$suffix = substr($value, 1);
if (strspn($suffix, '01234567') != strlen($suffix)) {
return false;
}
return octdec($suffix);
}
// Base 10
if (!is_numeric($value)) {
return false;
}
return intval($value);
}
public function checkBuiltin($opt, $value)
{
switch ($this->type) {
case 'int':
case 'long':
$number = self::parseNumber($value);
if ($number === false) {
$message = $this->type == 'int'
? Horde_Argv_Translation::t("option %s: invalid integer value: '%s'")
: Horde_Argv_Translation::t("option %s: invalid long integer value: '%s'");
throw new Horde_Argv_OptionValueException(
sprintf($message, $opt, $value));
}
return $number;
case 'float':
if (!is_numeric($value)) {
throw new Horde_Argv_OptionValueException(
sprintf(Horde_Argv_Translation::t("option %s: invalid floating-point value: '%s'"),
$opt, $value));
}
return floatval($value);
}
}
public function checkChoice($opt, $value)
{
if (in_array($value, $this->choices)) {
return $value;
} else {
$choices = array();
foreach ($this->choices as $choice) {
$choices[] = (string)$choice;
}
$choices = "'" . implode("', '", $choices) . "'";
throw new Horde_Argv_OptionValueException(sprintf(
Horde_Argv_Translation::t("option %s: invalid choice: '%s' (choose from %s)"),
$opt, $value, $choices));
}
}
/**
* The list of instance attributes that may be set through keyword args to
* the constructor.
*/
public $ATTRS = array(
'action',
'type',
'dest',
'default',
'nargs',
'const',
'choices',
'callback',
'callbackArgs',
'help',
'metavar',
);
/**
* The set of actions allowed by option parsers. Explicitly listed here so
* the constructor can validate its arguments.
*/
public $ACTIONS = array(
'store',
'store_const',
'store_true',
'store_false',
'append',
'append_const',
'count',
'callback',
'help',
'version',
);
/**
* The set of actions that involve storing a value somewhere;
* also listed just for constructor argument validation. (If
* the action is one of these, there must be a destination.)
*/
public $STORE_ACTIONS = array(
'store',
'store_const',
'store_true',
'store_false',
'append',
'append_const',
'count',
);
/**
* The set of actions for which it makes sense to supply a value type,
* ie. which may consume an argument from the command line.
*/
public $TYPED_ACTIONS = array(
'store',
'append',
'callback',
);
/**
* The set of actions which *require* a value type, ie. that always consume
* an argument from the command line.
*/
public $ALWAYS_TYPED_ACTIONS = array('store', 'append');
/**
* The set of actions which take a 'const' attribute.
*/
public $CONST_ACTIONS = array('store_const', 'append_const');
/**
* The set of known types for option parsers.
*
* Again, listed here for constructor argument validation.
*/
public $TYPES = array('string', 'int', 'long', 'float', 'complex', 'choice');
/**
* Dictionary of argument checking functions, which convert and validate
* option arguments according to the option type.
*
* Signature of checking functions is:
*
*
* mixed function(Horde_Argv_Option $option, string $opt, string $value)
*
*
* where
* - $option is the Horde_Argv_Option instance calling the checker
* - $opt is the actual option seen on the command-line (eg. '-a', '--file')
* - $value is the option argument seen on the command-line
*
* The return value should be in the appropriate PHP type
* for $option->type -- eg. an integer if $option->type == 'int'.
*
* If no checker is defined for a type, arguments will be unchecked and
* remain strings.
*/
public $TYPE_CHECKER = array('int' => 'checkBuiltin',
'long' => 'checkBuiltin',
'float' => 'checkBuiltin',
'complex' => 'checkBuiltin',
'choice' => 'checkChoice',
);
/**
* A list of unbound method objects.
*
* They are called by the constructor, in order, after all attributes are
* initialized. The list is created and filled in later, after all the
* methods are actually defined. (I just put it here because I like to
* define and document all class attributes in the same place.) Subclasses
* that add another _check_*() method should define their own CHECK_METHODS
* list that adds their check method to those from this class.
*/
public $CHECK_METHODS = array('_checkAction',
'_checkType',
'_checkChoice',
'_checkDest',
'_checkConst',
'_checkNargs',
'_checkCallback',
);
// -- Constructor/initialization methods ----------------------------
public $shortOpts = array();
public $longOpts = array();
public $dest;
public $default;
/**
* Constructor.
*/
public function __construct()
{
// The last argument to this function is an $attrs hash, if it
// is present and an array. All other arguments are $opts.
$opts = func_get_args();
$num = func_num_args();
if ($num == 0 || $num == 1 || !is_array($opts[$num - 1])) {
$attrs = array();
} else {
$attrs = array_pop($opts);
}
// Set shortOpts, longOpts attrs from 'opts' tuple.
// Have to be set now, in case no option strings are supplied.
$this->shortOpts = array();
$this->longOpts = array();
$opts = $this->_checkOptStrings($opts);
$this->_setOptStrings($opts);
// Set all other attrs (action, type, etc.) from 'attrs' dict
$this->_setAttrs($attrs);
// Check all the attributes we just set. There are lots of
// complicated interdependencies, but luckily they can be farmed
// out to the _check*() methods listed in CHECK_METHODS -- which
// could be handy for subclasses! The one thing these all share
// is that they raise OptionError if they discover a problem.
foreach ($this->CHECK_METHODS as $checker) {
call_user_func(array($this, $checker));
}
}
protected function _checkOptStrings($opts)
{
// Filter out None because early versions of Optik had exactly
// one short option and one long option, either of which
// could be None.
$opts = array_filter($opts);
if (!$opts) {
throw new InvalidArgumentException('at least one option string must be supplied');
}
return $opts;
}
protected function _setOptStrings($opts)
{
foreach ($opts as &$opt) {
$opt = (string)$opt;
if (strlen($opt) < 2) {
throw new Horde_Argv_OptionException(sprintf("invalid option string '%s': must be at least two characters long", $opt), $this);
} elseif (strlen($opt) == 2) {
if (!($opt[0] == '-' && $opt[1] != '-')) {
throw new Horde_Argv_OptionException(sprintf(
"invalid short option string '%s': " .
"must be of the form -x, (x any non-dash char)", $opt), $this);
}
$this->shortOpts[] = $opt;
} else {
if (!(substr($opt, 0, 2) == '--' && $opt[2] != '-')) {
throw new Horde_Argv_OptionException(sprintf(
"invalid long option string '%s': " .
"must start with --, followed by non-dash", $opt), $this);
}
$this->longOpts[] = $opt;
}
}
}
protected function _setAttrs($attrs)
{
foreach ($this->ATTRS as $attr) {
if (array_key_exists($attr, $attrs)) {
$this->$attr = $attrs[$attr];
unset($attrs[$attr]);
} else {
if ($attr == 'default') {
$this->$attr = self::$NO_DEFAULT;
} else {
$this->$attr = null;
}
}
}
if ($attrs) {
$attrs = array_keys($attrs);
sort($attrs);
throw new Horde_Argv_OptionException(sprintf(
'invalid keyword arguments: %s', implode(', ', $attrs)), $this);
}
}
// -- Constructor validation methods --------------------------------
public function _checkAction()
{
if (is_null($this->action)) {
$this->action = 'store';
} elseif (!in_array($this->action, $this->ACTIONS)) {
throw new Horde_Argv_OptionException(sprintf("invalid action: '%s'", $this->action), $this);
}
}
public function _checkType()
{
if (is_null($this->type)) {
if (in_array($this->action, $this->ALWAYS_TYPED_ACTIONS)) {
if (!is_null($this->choices)) {
// The 'choices' attribute implies 'choice' type.
$this->type = 'choice';
} else {
// No type given? 'string' is the most sensible default.
$this->type = 'string';
}
}
} else {
if ($this->type == 'str') {
$this->type = 'string';
}
if (!in_array($this->type, $this->TYPES)) {
throw new Horde_Argv_OptionException(sprintf("invalid option type: '%s'", $this->type), $this);
}
if (!in_array($this->action, $this->TYPED_ACTIONS)) {
throw new Horde_Argv_OptionException(sprintf(
"must not supply a type for action '%s'", $this->action), $this);
}
}
}
public function _checkChoice()
{
if ($this->type == 'choice') {
if (is_null($this->choices)) {
throw new Horde_Argv_OptionException(
"must supply a list of choices for type 'choice'", $this);
} elseif (!(is_array($this->choices) || $this->choices instanceof Iterator)) {
throw new Horde_Argv_OptionException(sprintf(
"choices must be a list of strings ('%s' supplied)",
gettype($this->choices)), $this);
}
} elseif (!is_null($this->choices)) {
throw new Horde_Argv_OptionException(sprintf(
"must not supply choices for type '%s'", $this->type), $this);
}
}
public function _checkDest()
{
// No destination given, and we need one for this action. The
// $this->type check is for callbacks that take a value.
$takes_value = (in_array($this->action, $this->STORE_ACTIONS) ||
!is_null($this->type));
if (is_null($this->dest) && $takes_value) {
// Glean a destination from the first long option string,
// or from the first short option string if no long options.
if ($this->longOpts) {
// eg. '--foo-bar' -> 'foo_bar'
$this->dest = str_replace('-', '_', substr($this->longOpts[0], 2));
} else {
$this->dest = $this->shortOpts[0][1];
}
}
}
public function _checkConst()
{
if (!in_array($this->action, $this->CONST_ACTIONS) && !is_null($this->const)) {
throw new Horde_Argv_OptionException(sprintf(
"'const' must not be supplied for action '%s'", $this->action),
$this);
}
}
public function _checkNargs()
{
if (in_array($this->action, $this->TYPED_ACTIONS)) {
if (is_null($this->nargs)) {
$this->nargs = 1;
}
} elseif (!is_null($this->nargs)) {
throw new Horde_Argv_OptionException(sprintf(
"'nargs' must not be supplied for action '%s'", $this->action),
$this);
}
}
public function _checkCallback()
{
if ($this->action == 'callback') {
if (!is_callable($this->callback)) {
$callback_name = is_array($this->callback) ?
is_object($this->callback[0]) ? get_class($this->callback[0] . '#' . $this->callback[1]) : implode('#', $this->callback) :
$this->callback;
throw new Horde_Argv_OptionException(sprintf(
"callback not callable: '%s'", $callback_name), $this);
}
if (!is_null($this->callbackArgs) && !is_array($this->callbackArgs)) {
throw new Horde_Argv_OptionException(sprintf(
"callbackArgs, if supplied, must be an array: not '%s'",
$this->callbackArgs), $this);
}
} else {
if (!is_null($this->callback)) {
$callback_name = is_array($this->callback) ?
is_object($this->callback[0]) ? get_class($this->callback[0] . '#' . $this->callback[1]) : implode('#', $this->callback) :
$this->callback;
throw new Horde_Argv_OptionException(sprintf(
"callback supplied ('%s') for non-callback option",
$callback_name), $this);
}
if (!is_null($this->callbackArgs)) {
throw new Horde_Argv_OptionException(
'callbackArgs supplied for non-callback option', $this);
}
}
}
// -- Miscellaneous methods -----------------------------------------
public function __toString()
{
return implode('/', array_merge($this->shortOpts, $this->longOpts));
}
public function takesValue()
{
return !is_null($this->type);
}
public function hasDefault()
{
return $this->default !== self::$NO_DEFAULT;
}
public function getOptString()
{
if ($this->longOpts) {
return $this->longOpts[0];
} else {
return $this->shortOpts[0];
}
}
// -- Processing methods --------------------------------------------
public function checkValue($opt, $value)
{
if (!isset($this->TYPE_CHECKER[$this->type])) {
return $value;
}
$checker = $this->TYPE_CHECKER[$this->type];
return call_user_func(array($this, $checker), $opt, $value);
}
public function convertValue($opt, $value)
{
if (!is_null($value)) {
if ($this->nargs == 1) {
return $this->checkValue($opt, $value);
} else {
$return = array();
foreach ($value as $v) {
$return[] = $this->checkValue($opt, $v);
}
return $return;
}
}
}
public function process($opt, $value, $values, $parser)
{
// First, convert the value(s) to the right type. Howl if any
// value(s) are bogus.
$value = $this->convertValue($opt, $value);
// And then take whatever action is expected of us.
// This is a separate method to make life easier for
// subclasses to add new actions.
return $this->takeAction(
$this->action, $this->dest, $opt, $value, $values, $parser);
}
public function takeAction($action, $dest, $opt, $value, $values, $parser)
{
if ($action == 'store') {
$values->$dest = $value;
} elseif ($action == 'store_const') {
$values->$dest = $this->const;
} elseif ($action == 'store_true') {
$values->$dest = true;
} elseif ($action == 'store_false') {
$values->$dest = false;
} elseif ($action == 'append') {
$values->{$dest}[] = $value;
} elseif ($action == 'append_const') {
$values->{$dest}[] = $this->const;
} elseif ($action == 'count') {
$values->ensureValue($dest, 0);
$values->$dest++;
} elseif ($action == 'callback') {
call_user_func($this->callback, $this, $opt, $value, $parser, $this->callbackArgs);
} elseif ($action == 'help') {
$parser->printHelp();
$parser->parserExit();
} elseif ($action == 'version') {
$parser->printVersion();
$parser->parserExit();
} else {
throw new RuntimeException('unknown action ' . $this->action);
}
return 1;
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/OptionConflictException.php 0000664 0001750 0001750 00000001546 13102315276 021674 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Raised if conflicting options are added to a Horde_Argv_Parser.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_OptionConflictException extends Horde_Argv_OptionException
{}
Horde_Argv-2.1.0/lib/Horde/Argv/OptionContainer.php 0000664 0001750 0001750 00000022106 13102315276 020171 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Abstract base class.
*
* Class attributes:
* standardOptionList : [Option]
* list of standard options that will be accepted by all instances
* of this parser class (intended to be overridden by subclasses).
*
* Instance attributes:
* optionList : [Option]
* the list of Option objects contained by this OptionContainer
* shortOpt : { string : Option }
* dictionary mapping short option strings, eg. "-f" or "-X",
* to the Option instances that implement them. If an Option
* has multiple short option strings, it will appears in this
* dictionary multiple times. [1]
* longOpt : { string : Option }
* dictionary mapping long option strings, eg. "--file" or
* "--exclude", to the Option instances that implement them.
* Again, a given Option can occur multiple times in this
* dictionary. [1]
* defaults : { string : any }
* dictionary mapping option destination names to default
* values for each destination [1]
*
* [1] These mappings are common to (shared by) all components of the
* controlling Horde_Argv_Parser, where they are initially created.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_OptionContainer
{
public $description = '';
public $optionList = array();
public $optionClass = 'Horde_Argv_Option';
public $defaults = array();
public $shortOpt = array();
public $longOpt = array();
public $conflictHandler;
/**
* Initialize the option list and related data structures.
* This method must be provided by subclasses, and it must
* initialize at least the following instance attributes:
* optionList, shortOpt, longOpt, defaults.
*/
public function __construct($optionClass, $conflictHandler, $description)
{
$this->_createOptionList();
$this->optionClass = $optionClass;
$this->setConflictHandler($conflictHandler);
$this->setDescription($description);
}
/**
* For use by Horde_Argv_Parser constructor -- create the master
* option mappings used by this Horde_Argv_Parser and all
* OptionGroups that it owns.
*/
protected function _createOptionMappings()
{
$this->shortOpt = array(); // single letter -> Option instance
$this->longOpt = array(); // long option -> Option instance
$this->defaults = array(); // maps option dest -> default value
}
/**
* For use by OptionGroup constructor -- use shared option
* mappings from the Horde_Argv_Parser that owns this OptionGroup.
*/
protected function _shareOptionMappings($parser)
{
$this->shortOpt =& $parser->shortOpt;
$this->longOpt =& $parser->longOpt;
$this->defaults = $parser->defaults;
}
public function setConflictHandler($handler)
{
if (!in_array($handler, array('error', 'resolve'))) {
throw new InvalidArgumentException('invalid conflictHandler ' . var_export($handler, true));
}
$this->conflictHandler = $handler;
}
public function setDescription($description)
{
$this->description = $description;
}
public function getDescription()
{
return $this->description;
}
// -- Option-adding methods -----------------------------------------
protected function _checkConflict($option)
{
$conflictOpts = array();
foreach ($option->shortOpts as $opt) {
if (isset($this->shortOpt[$opt])) {
$conflictOpts[$opt] = $this->shortOpt[$opt];
}
}
foreach ($option->longOpts as $opt) {
if (isset($this->longOpt[$opt])) {
$conflictOpts[$opt] = $this->longOpt[$opt];
}
}
if ($conflictOpts) {
$handler = $this->conflictHandler;
if ($handler == 'error') {
throw new Horde_Argv_OptionConflictException(sprintf(
'conflicting option string(s): %s',
implode(', ', array_keys($conflictOpts))), $option);
} elseif ($handler == 'resolve') {
foreach ($conflictOpts as $opt => $c_option) {
if (strncmp($opt, '--', 2) === 0) {
$key = array_search($opt, $c_option->longOpts);
if ($key !== false) {
unset($c_option->longOpts[$key]);
}
unset($this->longOpt[$opt]);
} else {
$key = array_search($opt, $c_option->shortOpts);
if ($key !== false) {
unset($c_option->shortOpts[$key]);
}
unset($this->shortOpt[$opt]);
}
if (! ($c_option->shortOpts || $c_option->longOpts)) {
$key = array_search($c_option, $c_option->container->optionList);
unset($c_option->container->optionList[$key]);
}
}
}
}
}
public function addOption()
{
$opts = func_get_args();
if (count($opts) && is_string($opts[0])) {
$optionFactory = new ReflectionClass($this->optionClass);
$option = $optionFactory->newInstanceArgs($opts);
} elseif (count($opts) == 1) {
$option = $opts[0];
if (!$option instanceof Horde_Argv_Option)
throw new InvalidArgumentException('not an Option instance: ' . var_export($option, true));
} else {
throw new InvalidArgumentException('invalid arguments');
}
$this->_checkConflict($option);
$this->optionList[] = $option;
$option->container = $this;
foreach ($option->shortOpts as $opt) {
$this->shortOpt[$opt] = $option;
}
foreach ($option->longOpts as $opt) {
$this->longOpt[$opt] = $option;
}
if (!is_null($option->dest)) {
// option has a dest, we need a default
if ($option->default !== Horde_Argv_Option::$NO_DEFAULT) {
$this->defaults[$option->dest] = $option->default;
} elseif (!isset($this->defaults[$option->dest])) {
$this->defaults[$option->dest] = null;
}
}
return $option;
}
public function addOptions($optionList)
{
foreach ($optionList as $option) {
$this->addOption($option);
}
}
// -- Option query/removal methods ----------------------------------
public function getOption($opt_str)
{
if (isset($this->shortOpt[$opt_str])) {
return $this->shortOpt[$opt_str];
} elseif (isset($this->longOpt[$opt_str])) {
return $this->longOpt[$opt_str];
} else {
return null;
}
}
public function hasOption($opt_str)
{
return isset($this->shortOpt[$opt_str])
|| isset($this->longOpt[$opt_str]);
}
public function removeOption($opt_str)
{
$option = $this->getOption($opt_str);
if (is_null($option)) {
throw new InvalidArgumentException("no such option '$opt_str'");
}
foreach ($option->shortOpts as $opt) {
unset($this->shortOpt[$opt]);
}
foreach ($option->longOpts as $opt) {
unset($this->longOpt[$opt]);
}
$key = array_search($option, $option->container->optionList);
unset($option->container->optionList[$key]);
}
// -- Help-formatting methods ---------------------------------------
public function formatOptionHelp($formatter = null)
{
if (!$this->optionList)
return '';
$result = array();
foreach ($this->optionList as $option) {
if ($option->help != Horde_Argv_Option::SUPPRESS_HELP)
$result[] = $formatter->formatOption($option);
}
return implode('', $result);
}
public function formatDescription($formatter = null)
{
return $formatter->formatDescription($this->getDescription());
}
public function formatHelp($formatter = null)
{
$result = array();
if ($this->description)
$result[] = $this->formatDescription($formatter);
if ($this->optionList)
$result[] = $this->formatOptionHelp($formatter);
return implode("\n", $result);
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/OptionException.php 0000664 0001750 0001750 00000002215 13102315276 020204 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Raised if an Option instance is created with invalid or
* inconsistent arguments.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_OptionException extends Horde_Argv_Exception
{
public function __construct($msg, $option = null)
{
$this->optionId = (string)$option;
if ($this->optionId) {
parent::__construct(sprintf('option %s: %s', $this->optionId, $msg));
} else {
parent::__construct($msg);
}
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/OptionGroup.php 0000664 0001750 0001750 00000003471 13102315276 017347 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* An option group allows to group a number of options under a common header
* and description.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_OptionGroup extends Horde_Argv_OptionContainer
{
protected $_title;
public function __construct($parser, $title, $description = null)
{
$this->parser = $parser;
parent::__construct($parser->optionClass, $parser->conflictHandler, $description);
$this->_title = $title;
}
protected function _createOptionList()
{
$this->optionList = array();
$this->_shareOptionMappings($this->parser);
}
public function setTitle($title)
{
$this->_title = $title;
}
public function __destruct()
{
unset($this->optionList);
}
// -- Help-formatting methods ---------------------------------------
public function formatHelp($formatter = null)
{
if (is_null($formatter))
return '';
$result = $formatter->formatHeading($this->_title);
$formatter->indent();
$result .= parent::formatHelp($formatter);
$formatter->dedent();
return $result;
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/OptionValueException.php 0000664 0001750 0001750 00000001543 13102315276 021204 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Raised if an invalid option value is encountered on the command
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_OptionValueException extends Horde_Argv_OptionException
{}
Horde_Argv-2.1.0/lib/Horde/Argv/Parser.php 0000664 0001750 0001750 00000057041 13102315276 016320 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Horde command-line argument parsing package.
*
* Class attributes:
* standardOptionList : [Option]
* list of standard options that will be accepted by all instances
* of this parser class (intended to be overridden by subclasses).
*
* Instance attributes:
* usage : string
* a usage string for your program. Before it is displayed
* to the user, "%prog" will be expanded to the name of
* your program ($this->prog or os.path.basename(sys.argv[0])).
* prog : string
* the name of the current program (to override
* os.path.basename(sys.argv[0])).
* epilog : string
* paragraph of help text to print after option help
*
* optionGroups : [OptionGroup]
* list of option groups in this parser (option groups are
* irrelevant for parsing the command-line, but very useful
* for generating help)
*
* allowInterspersedArgs : bool = true
* if true, positional arguments may be interspersed with options.
* Assuming -a and -b each take a single argument, the command-line
* -ablah foo bar -bboo baz
* will be interpreted the same as
* -ablah -bboo -- foo bar baz
* If this flag were false, that command line would be interpreted as
* -ablah -- foo bar -bboo baz
* -- ie. we stop processing options as soon as we see the first
* non-option argument. (This is the tradition followed by
* Python's getopt module, Perl's Getopt::Std, and other argument-
* parsing libraries, but it is generally annoying to users.)
*
* allowUnknownArgs : bool = false
* if true, unrecognized arguments will be auto-created, instead
* of throwing a BadOptionException.
*
* ignoreUnknownArgs : bool = false
* if true, unrecognized arguments will be silently skipped, instead of
* throwing a BadOptionException.
*
* rargs : [string]
* the argument list currently being parsed. Only set when
* parseArgs() is active, and continually trimmed down as
* we consume arguments. Mainly there for the benefit of
* callback options.
* largs : [string]
* the list of leftover arguments that we have skipped while
* parsing options. If allowInterspersedArgs is false, this
* list is always empty.
* values : Values
* the set of option values currently being accumulated. Only
* set when parseArgs() is active. Also mainly for callbacks.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_Parser extends Horde_Argv_OptionContainer
{
public $standardOptionList = array();
protected $_usage;
public $optionGroups = array();
public function __construct($args = array())
{
$args = array_merge(array(
'usage' => null,
'optionList' => null,
'optionClass' => 'Horde_Argv_Option',
'version' => null,
'conflictHandler' => "error",
'description' => null,
'formatter' => null,
'addHelpOption' => true,
'prog' => null,
'epilog' => null,
'allowInterspersedArgs' => true,
'allowUnknownArgs' => false,
'ignoreUnknownArgs' => false,
), $args);
parent::__construct($args['optionClass'], $args['conflictHandler'], $args['description']);
$this->setUsage($args['usage']);
$this->prog = $args['prog'];
$this->version = $args['version'];
$this->allowInterspersedArgs = $args['allowInterspersedArgs'];
$this->allowUnknownArgs = $args['allowUnknownArgs'];
$this->ignoreUnknownArgs = $args['ignoreUnknownArgs'];
if (is_null($args['formatter'])) {
$args['formatter'] = new Horde_Argv_IndentedHelpFormatter();
}
$this->formatter = $args['formatter'];
$this->formatter->setParser($this);
$this->epilog = $args['epilog'];
// Populate the option list; initial sources are the
// standardOptionList class attribute, the 'optionList'
// argument, and (if applicable) the _addVersionOption() and
// _addHelpOption() methods.
$this->_populateOptionList($args['optionList'],
$args['addHelpOption']);
$this->_initParsingState();
}
// -- Private methods -----------------------------------------------
// (used by our OptionContainer's constructor)
protected function _createOptionList()
{
$this->optionList = array();
$this->optionGroups = array();
$this->_createOptionMappings();
}
protected function _addHelpOption()
{
$this->addOption('-h', '--help', array('action' => 'help',
'help' => Horde_Argv_Translation::t("show this help message and exit")));
}
protected function _addVersionOption()
{
$this->addOption('--version', array('action' => 'version',
'help' => Horde_Argv_Translation::t("show program's version number and exit")));
}
protected function _populateOptionList($optionList, $add_help = true)
{
if ($this->standardOptionList)
$this->addOptions($this->standardOptionList);
if ($optionList)
$this->addOptions($optionList);
if ($this->version)
$this->_addVersionOption();
if ($add_help)
$this->_addHelpOption();
}
protected function _initParsingState()
{
// These are set in parseArgs() for the convenience of callbacks.
$this->rargs = null;
$this->largs = null;
$this->values = null;
}
// -- Simple modifier methods ---------------------------------------
public function setUsage($usage)
{
if (is_null($usage))
$this->_usage = '%prog ' . Horde_Argv_Translation::t("[options]");
elseif ($usage == Horde_Argv_Option::SUPPRESS_USAGE)
$this->_usage = null;
else
$this->_usage = $usage;
}
public function enableInterspersedArgs()
{
$this->allowInterspersedArgs = true;
}
public function disableInterspersedArgs()
{
$this->allowInterspersedArgs = false;
}
public function setDefault($dest, $value)
{
$this->defaults[$dest] = $value;
}
public function setDefaults($defaults)
{
$this->defaults = array_merge($this->defaults, $defaults);
}
protected function _getAllOptions()
{
$options = $this->optionList;
foreach ($this->optionGroups as $group) {
$options = array_merge($options, $group->optionList);
}
return $options;
}
public function getDefaultValues()
{
$defaults = $this->defaults;
foreach ($this->_getAllOptions() as $option) {
$default = isset($defaults[$option->dest]) ? $defaults[$option->dest] : null;
if (is_string($default)) {
$opt_str = $option->getOptString();
$defaults[$option->dest] = $option->checkValue($opt_str, $default);
}
}
return new Horde_Argv_Values($defaults);
}
// -- OptionGroup methods -------------------------------------------
public function addOptionGroup()
{
// XXX lots of overlap with OptionContainer::addOption()
$args = func_get_args();
if (count($args) && is_string($args[0])) {
$groupFactory = new ReflectionClass('Horde_Argv_OptionGroup');
array_unshift($args, $this);
$group = $groupFactory->newInstanceArgs($args);
} elseif (count($args) == 1) {
$group = $args[0];
if (!$group instanceof Horde_Argv_OptionGroup)
throw new InvalidArgumentException("not an OptionGroup instance: " . var_export($group, true));
if ($group->parser !== $this)
throw new InvalidArgumentException("invalid OptionGroup (wrong parser)");
} else {
throw new InvalidArgumentException('invalid arguments');
}
$this->optionGroups[] = $group;
$this->defaults = array_merge($this->defaults, $group->defaults);
return $group;
}
public function getOptionGroup($opt_str)
{
if (isset($this->shortOpt[$opt_str])) {
$option = $this->shortOpt[$opt_str];
} elseif (isset($this->longOpt[$opt_str])) {
$option = $this->longOpt[$opt_str];
} else {
return null;
}
if ($option->container !== $this) {
return $option->container;
}
return null;
}
// -- Option-parsing methods ----------------------------------------
protected function _getArgs($args = null)
{
if (is_null($args)) {
$args = $_SERVER['argv'];
array_shift($args);
return $args;
} else {
return $args;
}
}
/**
* Parse the command-line options found in 'args' (default:
* sys.argv[1:]). Any errors result in a call to 'parserError()', which
* by default prints the usage message to stderr and calls
* exit() with an error message. On success returns a pair
* (values, args) where 'values' is an Values instance (with all
* your option values) and 'args' is the list of arguments left
* over after parsing options.
*/
public function parseArgs($args = null, $values = null)
{
$rargs = $this->_getArgs($args);
$largs = array();
if (is_null($values))
$values = $this->getDefaultValues();
// Store the halves of the argument list as attributes for the
// convenience of callbacks:
// rargs
// the rest of the command-line (the "r" stands for
// "remaining" or "right-hand")
// largs
// the leftover arguments -- ie. what's left after removing
// options and their arguments (the "l" stands for "leftover"
// or "left-hand")
$this->rargs =& $rargs;
$this->largs =& $largs;
$this->values = $values;
try {
$this->_processArgs($largs, $rargs, $values);
} catch (Horde_Argv_BadOptionException $e) {
$this->parserError($e->getMessage());
} catch (Horde_Argv_OptionValueException $e) {
$this->parserError($e->getMessage());
}
$args = array_merge($largs, $rargs);
return $this->checkValues($values, $args);
}
/**
* Check that the supplied option values and leftover arguments are
* valid. Returns the option values and leftover arguments
* (possibly adjusted, possibly completely new -- whatever you
* like). Default implementation just returns the passed-in
* values; subclasses may override as desired.
*/
public function checkValues($values, $args)
{
return array($values, $args);
}
/**
* _process_args(largs : [string],
* rargs : [string],
* values : Values)
*
* Process command-line arguments and populate 'values', consuming
* options and arguments from 'rargs'. If 'allowInterspersedArgs' is
* false, stop at the first non-option argument. If true, accumulate any
* interspersed non-option arguments in 'largs'.
*/
protected function _processArgs(&$largs, &$rargs, &$values)
{
while ($rargs) {
$arg = $rargs[0];
// We handle bare "--" explicitly, and bare "-" is handled by the
// standard arg handler since the short arg case ensures that the
// len of the opt string is greater than 1.
if ($arg == '--') {
array_shift($rargs);
return;
} elseif (substr($arg, 0, 2) == '--') {
// process a single long option (possibly with value(s))
$this->_processLongOpt($rargs, $values);
} elseif (substr($arg, 0, 1) == '-' && strlen($arg) > 1) {
// process a cluster of short options (possibly with
// value(s) for the last one only)
$this->_processShortOpts($rargs, $values);
} elseif ($this->allowInterspersedArgs) {
$largs[] = $arg;
array_shift($rargs);
} else {
// stop now, leave this arg in rargs
return;
}
}
// Say this is the original argument list:
// [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
// ^
// (we are about to process arg(i)).
//
// Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
// [arg0, ..., arg(i-1)] (any options and their arguments will have
// been removed from largs).
//
// The while loop will usually consume 1 or more arguments per pass.
// If it consumes 1 (eg. arg is an option that takes no arguments),
// then after _process_arg() is done the situation is:
//
// largs = subset of [arg0, ..., arg(i)]
// rargs = [arg(i+1), ..., arg(N-1)]
//
// If allowInterspersedArgs is false, largs will always be
// *empty* -- still a subset of [arg0, ..., arg(i-1)], but
// not a very interesting subset!
}
/**
* opt : string) -> string
*
* Determine which long option string 'opt' matches, ie. which one
* it is an unambiguous abbrevation for. Raises BadOptionError if
* 'opt' doesn't unambiguously match any long option string.
*/
protected function _matchLongOpt($opt)
{
return self::matchAbbrev($opt, $this->longOpt);
}
/**
* (s : string, wordmap : {string : Option}) -> string
*
* Return the string key in 'wordmap' for which 's' is an unambiguous
* abbreviation. If 's' is found to be ambiguous or doesn't match any of
* 'words', raise BadOptionError.
*/
public static function matchAbbrev($s, $wordmap)
{
// Is there an exact match?
if (array_key_exists($s, $wordmap)) {
return $s;
}
// Isolate all words with s as a prefix.
$possibilities = array();
foreach (array_keys($wordmap) as $word) {
if (strncmp($word, $s, strlen($s)) === 0) {
$possibilities[] = $word;
}
}
// No exact match, so there had better be just one possibility.
if (count($possibilities) == 1) {
return $possibilities[0];
} elseif (!$possibilities) {
throw new Horde_Argv_BadOptionException($s);
} else {
// More than one possible completion: ambiguous prefix.
sort($possibilities);
throw new Horde_Argv_AmbiguousOptionException($s, $possibilities);
}
}
protected function _processLongOpt(&$rargs, &$values)
{
$arg = array_shift($rargs);
// Value explicitly attached to arg? Pretend it's the next
// argument.
if (strpos($arg, '=') !== false) {
list($opt, $next_arg) = explode('=', $arg, 2);
array_unshift($rargs, $next_arg);
$had_explicit_value = true;
} else {
$opt = $arg;
$had_explicit_value = false;
}
try {
$opt = $this->_matchLongOpt($opt);
$option = $this->longOpt[$opt];
} catch (Horde_Argv_BadOptionException $e) {
if ($this->ignoreUnknownArgs) {
return;
}
if ($this->allowUnknownArgs) {
$option = $this->addOption($opt, array('default' => true, 'action' => 'append'));
} else {
throw $e;
}
}
if ($option->takesValue()) {
$nargs = $option->nargs;
if (count($rargs) < $nargs) {
if (!$option->hasDefault()) {
if ($nargs == 1) {
$this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires an argument"), $opt));
} else {
$this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires %d arguments"), $opt, $nargs));
}
}
} elseif ($nargs == 1) {
$value = array_shift($rargs);
} else {
$value = array_splice($rargs, 0, $nargs);
}
} elseif ($had_explicit_value) {
$this->parserError(sprintf(Horde_Argv_Translation::t("%s option does not take a value"), $opt));
} else {
$value = null;
}
$option->process($opt, $value, $values, $this);
}
protected function _processShortOpts(&$rargs, &$values)
{
$arg = array_shift($rargs);
$stop = false;
$i = 1;
for ($c = 1, $c_max = strlen($arg); $c < $c_max; $c++) {
$ch = $arg[$c];
$opt = '-' . $ch;
$option = isset($this->shortOpt[$opt]) ? $this->shortOpt[$opt] : null;
$i++; // we have consumed a character
if (!$option) {
if ($this->allowUnknownArgs) {
$option = $this->addOption($opt, array('default' => true, 'action' => 'append'));
} else {
throw new Horde_Argv_BadOptionException($opt);
}
}
if ($option->takesValue()) {
// Any characters left in arg? Pretend they're the
// next arg, and stop consuming characters of arg.
if ($i < strlen($arg)) {
array_unshift($rargs, substr($arg, $i));
$stop = true;
}
$nargs = $option->nargs;
if (count($rargs) < $nargs) {
if (!$option->hasDefault()) {
if ($nargs == 1) {
$this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires an argument"), $opt));
} else {
$this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires %d arguments"), $opt, $nargs));
}
}
} elseif ($nargs == 1) {
$value = array_shift($rargs);
} else {
$value = array_splice($rargs, 0, $nargs);
}
} else {
// option doesn't take a value
$value = null;
}
$option->process($opt, $value, $values, $this);
if ($stop) { break; }
}
}
// -- Feedback methods ----------------------------------------------
public function getProgName()
{
if (is_null($this->prog))
return basename($_SERVER['argv'][0]);
else
return $this->prog;
}
public function expandProgName($s)
{
return str_replace("%prog", $this->getProgName(), $s);
}
public function getDescription()
{
return $this->expandProgName($this->description);
}
public function parserExit($status = 0, $msg = null)
{
if ($msg)
fwrite(STDERR, $msg);
exit($status);
}
/**
* Print a usage message incorporating $msg to stderr and exit.
* If you override this in a subclass, it should not return -- it
* should either exit or raise an exception.
*
* @param string $msg
*/
public function parserError($msg)
{
$this->printUsage(STDERR);
$this->parserExit(2, sprintf("%s: error: %s\n", $this->getProgName(), $msg));
}
public function getUsage($formatter = null)
{
if (is_null($formatter))
$formatter = $this->formatter;
if ($this->_usage)
return $formatter->formatUsage($this->expandProgName($this->_usage));
else
return '';
}
/**
* (file : file = stdout)
*
* Print the usage message for the current program ($this->_usage) to
* 'file' (default stdout). Any occurence of the string "%prog" in
* $this->_usage is replaced with the name of the current program
* (basename of sys.argv[0]). Does nothing if $this->_usage is empty
* or not defined.
*/
public function printUsage($file = null)
{
if (!$this->_usage)
return;
if (is_null($file))
echo $this->getUsage();
else
fwrite($file, $this->getUsage());
}
public function getVersion()
{
if ($this->version)
return $this->expandProgName($this->version);
else
return '';
}
/**
* file : file = stdout
*
* Print the version message for this program ($this->version) to
* 'file' (default stdout). As with printUsage(), any occurence
* of "%prog" in $this->version is replaced by the current program's
* name. Does nothing if $this->version is empty or undefined.
*/
public function printVersion($file = null)
{
if (!$this->version)
return;
if (is_null($file))
echo $this->getVersion() . "\n";
else
fwrite($file, $this->getVersion() . "\n");
}
public function formatOptionHelp($formatter = null)
{
if (is_null($formatter))
$formatter = $this->formatter;
$formatter->storeOptionStrings($this);
$result = array();
$result[] = $formatter->formatHeading(Horde_Argv_Translation::t("Options"));
$formatter->indent();
if ($this->optionList) {
$result[] = parent::formatOptionHelp($formatter);
$result[] = "\n";
}
foreach ($this->optionGroups as $group) {
$result[] = $group->formatHelp($formatter);
$result[] = "\n";
}
$formatter->dedent();
// Drop the last "\n", or the header if no options or option groups:
array_pop($result);
return implode('', $result);
}
public function formatEpilog($formatter)
{
return $formatter->formatEpilog($this->epilog);
}
public function formatHelp($formatter = null)
{
if (is_null($formatter))
$formatter = $this->formatter;
$result = array();
if ($this->_usage)
$result[] = $this->getUsage($formatter) . "\n";
if ($this->description)
$result[] = $this->formatDescription($formatter) . "\n";
$result[] = $this->formatOptionHelp($formatter);
$result[] = $this->formatEpilog($formatter);
return implode('', $result);
}
/**
* file : file = stdout
*
* Print an extended help message, listing all options and any
* help text provided with them, to 'file' (default stdout).
*/
public function printHelp($file = null)
{
if (is_null($file))
echo $this->formatHelp();
else
fwrite($file, $this->formatHelp());
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/TitledHelpFormatter.php 0000664 0001750 0001750 00000003074 13102315276 021003 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Format help with underlined section headers.
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_TitledHelpFormatter extends Horde_Argv_HelpFormatter
{
public function __construct(
$indent_increment = 0, $max_help_position = 24, $width = null,
$short_first = false, $color = null
)
{
parent::__construct(
$indent_increment, $max_help_position, $width, $short_first, $color
);
}
public function formatUsage($usage)
{
return sprintf(
"%s %s\n",
$this->formatHeading(Horde_Argv_Translation::t("Usage")),
$usage
);
}
public function formatHeading($heading)
{
$prefix = array('=', '-');
return $this->highlightHeading(sprintf(
"%s\n%s\n",
$heading,
str_repeat($prefix[$this->level], strlen($heading))
));
}
}
Horde_Argv-2.1.0/lib/Horde/Argv/Translation.php 0000664 0001750 0001750 00000001713 13102315276 017355 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/bsd BSD
*/
/**
* Horde_Argv_Translation is the translation wrapper class for Horde_Argv.
*
* @author Jan Schneider
* @package Argv
* @category Horde
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_Translation extends Horde_Translation_Autodetect
{
/**
* The translation domain
*
* @var string
*/
protected static $_domain = 'Horde_Argv';
/**
* The absolute PEAR path to the translations for the default gettext handler.
*
* @var string
*/
protected static $_pearDirectory = '@data_dir@';
}
Horde_Argv-2.1.0/lib/Horde/Argv/Values.php 0000664 0001750 0001750 00000003612 13102315276 016316 0 ustar jan jan
* @author Mike Naberezny
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Argv
*/
/**
* Result hash for Horde_Argv_Parser
*
* @category Horde
* @package Argv
* @author Chuck Hagenbuch
* @author Mike Naberezny
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/bsd BSD
*/
class Horde_Argv_Values implements IteratorAggregate, ArrayAccess, Countable
{
public function __construct($defaults = array())
{
foreach ($defaults as $attr => $val) {
$this->$attr = $val;
}
}
public function __toString()
{
$str = array();
foreach ($this as $attr => $val) {
$str[] = $attr . ': ' . (string)$val;
}
return implode(', ', $str);
}
public function offsetExists($attr)
{
return isset($this->$attr) && !is_null($this->$attr);
}
public function offsetGet($attr)
{
return $this->$attr;
}
public function offsetSet($attr, $val)
{
$this->$attr = $val;
}
public function offsetUnset($attr)
{
unset($this->$attr);
}
public function getIterator()
{
return new ArrayIterator(get_object_vars($this));
}
public function count()
{
return count(get_object_vars($this));
}
public function ensureValue($attr, $value)
{
if (is_null($this->$attr)) {
$this->$attr = $value;
}
return $this->$attr;
}
}
Horde_Argv-2.1.0/locale/ar/LC_MESSAGES/Horde_Argv.mo 0000664 0001750 0001750 00000000732 13102315276 017643 0 ustar jan jan Þ• 4 L ` a i A p ² ¿ Options Usage: Project-Id-Version: Horde_Argv
Report-Msgid-Bugs-To: dev@lists.horde.org
POT-Creation-Date: 2010-10-13 01:27+0200
PO-Revision-Date: 2010-10-13 01:27+0200
Last-Translator: Automatically generated
Language-Team: i18n@lists.horde.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
خيارات ØØ¬Ù… الاستخدام: Horde_Argv-2.1.0/locale/ar/LC_MESSAGES/Horde_Argv.po 0000664 0001750 0001750 00000003575 13102315276 017656 0 ustar jan jan # Arabic translations for Horde_Argv module.
# Copyright 2010-2017 Horde LLC (http://www.horde.org/)
# This file is distributed under the same license as the Horde_Argv module.
# Automatically generated, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde_Argv\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2010-10-13 01:27+0200\n"
"PO-Revision-Date: 2010-10-13 01:27+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: lib/Horde/Argv/Parser.php:507
#, php-format
msgid "%s option does not take a value"
msgstr ""
#: lib/Horde/Argv/Parser.php:497 lib/Horde/Argv/Parser.php:549
#, php-format
msgid "%s option requires %d arguments"
msgstr ""
#: lib/Horde/Argv/Parser.php:495 lib/Horde/Argv/Parser.php:547
#, php-format
msgid "%s option requires an argument"
msgstr ""
#: lib/Horde/Argv/Parser.php:672
msgid "Options"
msgstr "خيارات"
#: lib/Horde/Argv/TitledHelpFormatter.php:29
#, fuzzy
msgid "Usage"
msgstr "ØØ¬Ù… الاستخدام:"
#: lib/Horde/Argv/IndentedHelpFormatter.php:29
msgid "Usage:"
msgstr "ØØ¬Ù… الاستخدام:"
#: lib/Horde/Argv/Parser.php:199
#, fuzzy
msgid "[options]"
msgstr "خيارات"
#: lib/Horde/Argv/Option.php:129
#, php-format
msgid "option %s: invalid choice: '%s' (choose from %s)"
msgstr ""
#: lib/Horde/Argv/Option.php:111
#, php-format
msgid "option %s: invalid floating-point value: '%s'"
msgstr ""
#: lib/Horde/Argv/Option.php:101
#, php-format
msgid "option %s: invalid integer value: '%s'"
msgstr ""
#: lib/Horde/Argv/Option.php:102
#, php-format
msgid "option %s: invalid long integer value: '%s'"
msgstr ""
#: lib/Horde/Argv/Parser.php:171
msgid "show program's version number and exit"
msgstr ""
#: lib/Horde/Argv/Parser.php:165
msgid "show this help message and exit"
msgstr ""
Horde_Argv-2.1.0/locale/bg/LC_MESSAGES/Horde_Argv.mo 0000664 0001750 0001750 00000000724 13102315276 017632 0 ustar jan jan Þ• 4 L ` a i A p
² ½ Options Usage: Project-Id-Version: Horde_Argv
Report-Msgid-Bugs-To: dev@lists.horde.org
POT-Creation-Date: 2010-10-13 01:27+0200
PO-Revision-Date: 2010-10-13 01:27+0200
Last-Translator: Automatically generated
Language-Team: i18n@lists.horde.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Опции Използване:: Horde_Argv-2.1.0/locale/bg/LC_MESSAGES/Horde_Argv.po 0000664 0001750 0001750 00000003703 13102315276 017635 0 ustar jan jan # Bulgarian translations for Horde_Argv module.
# Copyright 2010-2017 Horde LLC (http://www.horde.org/)
# This file is distributed under the same license as the Horde_Argv module.
# Automatically generated, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde_Argv\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2010-10-13 01:27+0200\n"
"PO-Revision-Date: 2010-10-13 01:27+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: lib/Horde/Argv/Parser.php:507
#, php-format
msgid "%s option does not take a value"
msgstr ""
#: lib/Horde/Argv/Parser.php:497 lib/Horde/Argv/Parser.php:549
#, php-format
msgid "%s option requires %d arguments"
msgstr ""
#: lib/Horde/Argv/Parser.php:495 lib/Horde/Argv/Parser.php:547
#, php-format
msgid "%s option requires an argument"
msgstr ""
#: lib/Horde/Argv/Parser.php:672
msgid "Options"
msgstr "Опции"
#: lib/Horde/Argv/TitledHelpFormatter.php:29
#, fuzzy
msgid "Usage"
msgstr "Използване::"
#: lib/Horde/Argv/IndentedHelpFormatter.php:29
msgid "Usage:"
msgstr "Използване::"
#: lib/Horde/Argv/Parser.php:199
#, fuzzy
msgid "[options]"
msgstr "Опции"
#: lib/Horde/Argv/Option.php:129
#, php-format
msgid "option %s: invalid choice: '%s' (choose from %s)"
msgstr ""
#: lib/Horde/Argv/Option.php:111
#, php-format
msgid "option %s: invalid floating-point value: '%s'"
msgstr ""
#: lib/Horde/Argv/Option.php:101
#, php-format
msgid "option %s: invalid integer value: '%s'"
msgstr ""
#: lib/Horde/Argv/Option.php:102
#, php-format
msgid "option %s: invalid long integer value: '%s'"
msgstr ""
#: lib/Horde/Argv/Parser.php:171
msgid "show program's version number and exit"
msgstr ""
#: lib/Horde/Argv/Parser.php:165
#, fuzzy
msgid "show this help message and exit"
msgstr " help Покажи това помощно Ñъобщение."
Horde_Argv-2.1.0/locale/bs/LC_MESSAGES/Horde_Argv.mo 0000664 0001750 0001750 00000000642 13102315276 017645 0 ustar jan jan Þ• , <