emergency release 2.2dev
[moodle.git] / lib / pear / Console / Getopt.php
blobb256d0eed3ca32fd5396fa44f07ea99ca940af42
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
4 // | PHP Version 5 |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2004 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 3.0 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available through the world-wide-web at the following url: |
11 // | http://www.php.net/license/3_0.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Author: Andrei Zmievski <andrei@php.net> |
17 // +----------------------------------------------------------------------+
19 // $Id$
21 require_once 'PEAR.php';
23 /**
24 * Command-line options parsing class.
26 * @author Andrei Zmievski <andrei@php.net>
29 class Console_Getopt {
30 /**
31 * Parses the command-line options.
33 * The first parameter to this function should be the list of command-line
34 * arguments without the leading reference to the running program.
36 * The second parameter is a string of allowed short options. Each of the
37 * option letters can be followed by a colon ':' to specify that the option
38 * requires an argument, or a double colon '::' to specify that the option
39 * takes an optional argument.
41 * The third argument is an optional array of allowed long options. The
42 * leading '--' should not be included in the option name. Options that
43 * require an argument should be followed by '=', and options that take an
44 * option argument should be followed by '=='.
46 * The return value is an array of two elements: the list of parsed
47 * options and the list of non-option command-line arguments. Each entry in
48 * the list of parsed options is a pair of elements - the first one
49 * specifies the option, and the second one specifies the option argument,
50 * if there was one.
52 * Long and short options can be mixed.
54 * Most of the semantics of this function are based on GNU getopt_long().
56 * @param array $args an array of command-line arguments
57 * @param string $short_options specifies the list of allowed short options
58 * @param array $long_options specifies the list of allowed long options
60 * @return array two-element array containing the list of parsed options and
61 * the non-option arguments
63 * @access public
66 function getopt2($args, $short_options, $long_options = null)
68 return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
71 /**
72 * This function expects $args to start with the script name (POSIX-style).
73 * Preserved for backwards compatibility.
74 * @see getopt2()
75 */
76 function getopt($args, $short_options, $long_options = null)
78 return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
81 /**
82 * The actual implementation of the argument parsing code.
84 function doGetopt($version, $args, $short_options, $long_options = null)
86 // in case you pass directly readPHPArgv() as the first arg
87 if (PEAR::isError($args)) {
88 return $args;
90 if (empty($args)) {
91 return array(array(), array());
93 $opts = array();
94 $non_opts = array();
96 settype($args, 'array');
98 if ($long_options) {
99 sort($long_options);
103 * Preserve backwards compatibility with callers that relied on
104 * erroneous POSIX fix.
106 if ($version < 2) {
107 if (isset($args[0]{0}) && $args[0]{0} != '-') {
108 array_shift($args);
112 reset($args);
113 while (list($i, $arg) = each($args)) {
115 /* The special element '--' means explicit end of
116 options. Treat the rest of the arguments as non-options
117 and end the loop. */
118 if ($arg == '--') {
119 $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
120 break;
123 if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
124 $non_opts = array_merge($non_opts, array_slice($args, $i));
125 break;
126 } elseif (strlen($arg) > 1 && $arg{1} == '-') {
127 $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
128 if (PEAR::isError($error))
129 return $error;
130 } elseif ($arg == '-') {
131 // - is stdin
132 $non_opts = array_merge($non_opts, array_slice($args, $i));
133 break;
134 } else {
135 $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
136 if (PEAR::isError($error))
137 return $error;
141 return array($opts, $non_opts);
145 * @access private
148 function _parseShortOption($arg, $short_options, &$opts, &$args)
150 for ($i = 0; $i < strlen($arg); $i++) {
151 $opt = $arg{$i};
152 $opt_arg = null;
154 /* Try to find the short option in the specifier string. */
155 if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
157 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
160 if (strlen($spec) > 1 && $spec{1} == ':') {
161 if (strlen($spec) > 2 && $spec{2} == ':') {
162 if ($i + 1 < strlen($arg)) {
163 /* Option takes an optional argument. Use the remainder of
164 the arg string if there is anything left. */
165 $opts[] = array($opt, substr($arg, $i + 1));
166 break;
168 } else {
169 /* Option requires an argument. Use the remainder of the arg
170 string if there is anything left. */
171 if ($i + 1 < strlen($arg)) {
172 $opts[] = array($opt, substr($arg, $i + 1));
173 break;
174 } else if (list(, $opt_arg) = each($args)) {
175 /* Else use the next argument. */;
176 if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
177 return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
179 } else {
180 return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
185 $opts[] = array($opt, $opt_arg);
190 * @access private
193 function _isShortOpt($arg)
195 return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
199 * @access private
202 function _isLongOpt($arg)
204 return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
205 preg_match('/[a-zA-Z]+$/', substr($arg, 2));
209 * @access private
212 function _parseLongOption($arg, $long_options, &$opts, &$args)
214 @list($opt, $opt_arg) = explode('=', $arg, 2);
215 $opt_len = strlen($opt);
217 for ($i = 0; $i < count($long_options); $i++) {
218 $long_opt = $long_options[$i];
219 $opt_start = substr($long_opt, 0, $opt_len);
220 $long_opt_name = str_replace('=', '', $long_opt);
222 /* Option doesn't match. Go on to the next one. */
223 if ($long_opt_name != $opt) {
224 continue;
227 $opt_rest = substr($long_opt, $opt_len);
229 /* Check that the options uniquely matches one of the allowed
230 options. */
231 if ($i + 1 < count($long_options)) {
232 $next_option_rest = substr($long_options[$i + 1], $opt_len);
233 } else {
234 $next_option_rest = '';
236 if ($opt_rest != '' && $opt{0} != '=' &&
237 $i + 1 < count($long_options) &&
238 $opt == substr($long_options[$i+1], 0, $opt_len) &&
239 $next_option_rest != '' &&
240 $next_option_rest{0} != '=') {
241 return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
244 if (substr($long_opt, -1) == '=') {
245 if (substr($long_opt, -2) != '==') {
246 /* Long option requires an argument.
247 Take the next argument if one wasn't specified. */;
248 if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
249 return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
251 if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
252 return PEAR::raiseError("Console_Getopt: option requires an argument --$opt");
255 } else if ($opt_arg) {
256 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
259 $opts[] = array('--' . $opt, $opt_arg);
260 return;
263 return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
267 * Safely read the $argv PHP array across different PHP configurations.
268 * Will take care on register_globals and register_argc_argv ini directives
270 * @access public
271 * @return mixed the $argv PHP array or PEAR error if not registered
273 function readPHPArgv()
275 global $argv;
276 if (!is_array($argv)) {
277 if (!@is_array($_SERVER['argv'])) {
278 if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
279 return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
281 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
283 return $_SERVER['argv'];
285 return $argv;