]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/Console/Getopt.php
Merge branch '0.9.x' of gitorious.org:statusnet/mainline into 1.0.x
[quix0rs-gnu-social.git] / extlib / Console / Getopt.php
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 // +----------------------------------------------------------------------+
18 //
19 // $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $
20
21 require_once 'PEAR.php';
22
23 /**
24  * Command-line options parsing class.
25  *
26  * @author Andrei Zmievski <andrei@php.net>
27  *
28  */
29 class Console_Getopt {
30     /**
31      * Parses the command-line options.
32      *
33      * The first parameter to this function should be the list of command-line
34      * arguments without the leading reference to the running program.
35      *
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.
40      *
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 '=='.
45      *
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.
51      *
52      * Long and short options can be mixed.
53      *
54      * Most of the semantics of this function are based on GNU getopt_long().
55      *
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
59      *
60      * @return array two-element array containing the list of parsed options and
61      * the non-option arguments
62      *
63      * @access public
64      *
65      */
66     function getopt2($args, $short_options, $long_options = null)
67     {
68         return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
69     }
70
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)
77     {
78         return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
79     }
80
81     /**
82      * The actual implementation of the argument parsing code.
83      */
84     function doGetopt($version, $args, $short_options, $long_options = null)
85     {
86         // in case you pass directly readPHPArgv() as the first arg
87         if (PEAR::isError($args)) {
88             return $args;
89         }
90         if (empty($args)) {
91             return array(array(), array());
92         }
93         $opts     = array();
94         $non_opts = array();
95
96         settype($args, 'array');
97
98         if ($long_options) {
99             sort($long_options);
100         }
101
102         /*
103          * Preserve backwards compatibility with callers that relied on
104          * erroneous POSIX fix.
105          */
106         if ($version < 2) {
107             if (isset($args[0]{0}) && $args[0]{0} != '-') {
108                 array_shift($args);
109             }
110         }
111
112         reset($args);
113         while (list($i, $arg) = each($args)) {
114
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;
121             }
122
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;
138             }
139         }
140
141         return array($opts, $non_opts);
142     }
143
144     /**
145      * @access private
146      *
147      */
148     function _parseShortOption($arg, $short_options, &$opts, &$args)
149     {
150         for ($i = 0; $i < strlen($arg); $i++) {
151             $opt = $arg{$i};
152             $opt_arg = null;
153
154             /* Try to find the short option in the specifier string. */
155             if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
156             {
157                 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
158             }
159
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;
167                     }
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");
178                         }
179                     } else {
180                         return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
181                     }
182                 }
183             }
184
185             $opts[] = array($opt, $opt_arg);
186         }
187     }
188
189     /**
190      * @access private
191      *
192      */
193     function _isShortOpt($arg)
194     {
195         return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
196     }
197
198     /**
199      * @access private
200      *
201      */
202     function _isLongOpt($arg)
203     {
204         return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
205             preg_match('/[a-zA-Z]+$/', substr($arg, 2));
206     }
207
208     /**
209      * @access private
210      *
211      */
212     function _parseLongOption($arg, $long_options, &$opts, &$args)
213     {
214         @list($opt, $opt_arg) = explode('=', $arg, 2);
215         $opt_len = strlen($opt);
216
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);
221
222             /* Option doesn't match. Go on to the next one. */
223             if ($long_opt_name != $opt) {
224                 continue;
225             }
226
227             $opt_rest  = substr($long_opt, $opt_len);
228
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 = '';
235             }
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");
242             }
243
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");
250                     }
251                     if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
252                         return PEAR::raiseError("Console_Getopt: option requires an argument --$opt");
253                     }
254                 }
255             } else if ($opt_arg) {
256                 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
257             }
258
259             $opts[] = array('--' . $opt, $opt_arg);
260             return;
261         }
262
263         return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
264     }
265
266     /**
267     * Safely read the $argv PHP array across different PHP configurations.
268     * Will take care on register_globals and register_argc_argv ini directives
269     *
270     * @access public
271     * @return mixed the $argv PHP array or PEAR error if not registered
272     */
273     function readPHPArgv()
274     {
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?)");
280                 }
281                 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
282             }
283             return $_SERVER['argv'];
284         }
285         return $argv;
286     }
287
288 }
289
290 ?>