1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Console Getopt |
5
|
|
|
* |
6
|
|
|
* All rights reserved. |
7
|
|
|
* Redistribution and use in source and binary forms, with or without modification, |
8
|
|
|
* are permitted provided that the following conditions are met: |
9
|
|
|
* + Redistributions of source code must retain the above copyright notice, |
10
|
|
|
* this list of conditions and the following disclaimer. |
11
|
|
|
* + Redistributions in binary form must reproduce the above copyright notice, |
12
|
|
|
* this list of conditions and the following disclaimer in the documentation and/or |
13
|
|
|
* other materials provided with the distribution. |
14
|
|
|
* + The names of its contributors may not be used to endorse or promote |
15
|
|
|
* products derived from this software without specific prior written permission. |
16
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
20
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
21
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
22
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
23
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
24
|
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
25
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
26
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27
|
|
|
* |
28
|
|
|
* @category Console |
29
|
|
|
* @package Console_GetoptPlus |
30
|
|
|
* @author Michel Corne <[email protected]> |
31
|
|
|
* @copyright 2008 Michel Corne |
32
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License |
33
|
|
|
* @version SVN: $Id: Getopt.php 48 2008-01-10 15:32:56Z mcorne $ |
34
|
|
|
* @link http://pear.php.net/package/Console_GetoptPlus |
35
|
|
|
*/ |
36
|
|
|
|
37
|
|
|
require_once 'Console/GetoptPlus/Exception.php'; |
38
|
|
|
require_once XOOPS_ROOT_PATH . '/modules/extgallery/class/pear/PEAR.php'; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Parsing of a command line. |
42
|
|
|
* |
43
|
|
|
* See more examples in docs/examples. |
44
|
|
|
* |
45
|
|
|
* Code Example 1: |
46
|
|
|
* <code> |
47
|
|
|
* require_once 'Console/GetoptPlus.php'; |
48
|
|
|
* |
49
|
|
|
* try { |
50
|
|
|
* $shortOptions = "b:c::"; |
51
|
|
|
* $longOptions = array("foo", "bar="); |
52
|
|
|
* $options = Console_Getoptplus::getopt($config, $shortOptions, $longOptions); |
53
|
|
|
* // some processing here... |
54
|
|
|
* print_r($options); |
55
|
|
|
* } |
56
|
|
|
* catch(Console_GetoptPlus_Exception $e) { |
57
|
|
|
* $error = array($e->getCode(), $e->getMessage()); |
58
|
|
|
* print_r($error); |
59
|
|
|
* } |
60
|
|
|
* </code> |
61
|
|
|
* |
62
|
|
|
* Code Example 2: |
63
|
|
|
* <code> |
64
|
|
|
* require_once 'Console/GetoptPlus/Getopt.php'; |
65
|
|
|
* |
66
|
|
|
* try { |
67
|
|
|
* $shortOptions = "b:c::"; |
68
|
|
|
* $longOptions = array("foo", "bar="); |
69
|
|
|
* $options = Console_GetoptPlus_Getopt::getopt($config, $shortOptions, $longOptions); |
70
|
|
|
* // some processing here... |
71
|
|
|
* print_r($options); |
72
|
|
|
* } |
73
|
|
|
* catch(Console_GetoptPlus_Exception $e) { |
74
|
|
|
* $error = array($e->getCode(), $e->getMessage()); |
75
|
|
|
* print_r($error); |
76
|
|
|
* } |
77
|
|
|
* </code> |
78
|
|
|
* |
79
|
|
|
* Run: |
80
|
|
|
* <pre> |
81
|
|
|
* #xyz --foo -b car -c |
82
|
|
|
* #xyz --foo -b car -c param1 |
83
|
|
|
* #xyz --foo -b car -cbus param1 |
84
|
|
|
* #xyz --foo -b car -c=bus param1 |
85
|
|
|
* #xyz --bar car param1 param2 |
86
|
|
|
* #xyz --bar car -- param1 param2 |
87
|
|
|
* #xyz --bar=car param1 param2 |
88
|
|
|
* </pre> |
89
|
|
|
* |
90
|
|
|
* @category Console |
91
|
|
|
* @package Console_GetoptPlus |
92
|
|
|
* @author Michel Corne <[email protected]> |
93
|
|
|
* @copyright 2008 Michel Corne |
94
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License |
95
|
|
|
* @version Release: |
96
|
|
|
* @package _version@ |
97
|
|
|
* @link http://pear.php.net/package/Console_GetoptPlus |
98
|
|
|
* @see Console_Getopt |
99
|
|
|
*/ |
100
|
|
|
class Console_GetoptPlus_Getopt |
|
|
|
|
101
|
|
|
{ |
102
|
|
|
/** |
103
|
|
|
* The list of ambigous option names |
104
|
|
|
* |
105
|
|
|
* @var array |
106
|
|
|
* @access private |
107
|
|
|
*/ |
108
|
|
|
private $ambigous; |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* The command arguments |
112
|
|
|
* |
113
|
|
|
* @var array |
114
|
|
|
* @access private |
115
|
|
|
*/ |
116
|
|
|
private $args; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* The long option names |
120
|
|
|
* |
121
|
|
|
* @var array |
122
|
|
|
* @access private |
123
|
|
|
*/ |
124
|
|
|
private $longOptionsDef; |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* The parsed options |
128
|
|
|
* |
129
|
|
|
* @var array |
130
|
|
|
* @access private |
131
|
|
|
*/ |
132
|
|
|
private $options; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* The option shortcut names |
136
|
|
|
* |
137
|
|
|
* @var array |
138
|
|
|
* @access private |
139
|
|
|
*/ |
140
|
|
|
private $shortcuts; |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* The short option names and their definition |
144
|
|
|
* |
145
|
|
|
* @var array |
146
|
|
|
* @access private |
147
|
|
|
*/ |
148
|
|
|
private $shortOptionsDef; |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* The option types |
152
|
|
|
* |
153
|
|
|
* @var array |
154
|
|
|
* @access private |
155
|
|
|
*/ |
156
|
|
|
private $type = array(// / |
157
|
|
|
false => 'noarg', |
158
|
|
|
'=' => 'mandatory', ':' => 'mandatory', |
159
|
|
|
'==' => 'optional', '::' => 'optional', |
160
|
|
|
); |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Creates the option shorcut names |
164
|
|
|
* |
165
|
|
|
* @param array $longOptionsDef the long option names |
166
|
|
|
* @param string $ambiguity directive to handle option names ambiguity |
167
|
|
|
* @return array the option shorcuts and the ambigous options |
168
|
|
|
* @access public |
169
|
|
|
*/ |
170
|
|
|
public function createShorcuts($longOptionsDef, $ambiguity) |
171
|
|
|
{ |
172
|
|
|
$shortcuts = array(); |
173
|
|
|
$ambigous = array(); |
174
|
|
|
|
175
|
|
|
if ($ambiguity == 'shortcuts') { |
176
|
|
|
foreach(array_keys($longOptionsDef) as $name) { |
177
|
|
|
// splits the option name in characters to build the name |
178
|
|
|
// substring combinations, e.g. foo => f, fo, foo |
179
|
|
|
$subName = ''; |
180
|
|
|
foreach(str_split($name) as $char) { |
181
|
|
|
$subName .= $char; |
182
|
|
|
|
183
|
|
|
if (isset($ambigous[$subName])) { |
184
|
|
|
// adds the shortcut to the list of ambigous shortcuts |
185
|
|
|
$ambigous[$subName][] = $name; |
186
|
|
|
} else if (isset($shortcuts[$subName])) { |
187
|
|
|
// there is already a shortcut, adds the previous one |
188
|
|
|
// and the current one in the list of ambigous shortcuts |
189
|
|
|
$ambigous[$subName] = array($shortcuts[$subName], $name); |
190
|
|
|
unset($shortcuts[$subName]); |
191
|
|
|
} else { |
192
|
|
|
// creates the shorcut entry |
193
|
|
|
$shortcuts[$subName] = $name; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
// checks if some options are ambigous, e.g. --foo --foobar |
198
|
|
|
$names = array_intersect_key($longOptionsDef, $ambigous) and |
|
|
|
|
199
|
|
|
self::exception('ambigous', key($names)); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
return array($shortcuts, $ambigous); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Parses the command line |
207
|
|
|
* |
208
|
|
|
* See getopt() for a complete description. |
209
|
|
|
* |
210
|
|
|
* @param numeric $version the getopt version: 1 or 2 |
|
|
|
|
211
|
|
|
* @param array $args the arguments |
212
|
|
|
* @param string $shortOptions the short options definition, e.g. "ab:c::" |
213
|
|
|
* @param array $longOptions the long options definition |
214
|
|
|
* @param string $ambiguity directive to handle option names ambiguity |
215
|
|
|
* @return array the parsed options, their arguments and parameters |
216
|
|
|
* @access public |
217
|
|
|
* @static |
218
|
|
|
*/ |
219
|
|
|
public static function doGetopt($version = null, $args = array(), |
220
|
|
|
$shortOptions = '', $longOptions = array(), $ambiguity = '') |
221
|
|
|
{ |
222
|
|
|
$getopt = new self; |
223
|
|
|
|
224
|
|
|
return $getopt->process($args, $shortOptions, $longOptions, |
225
|
|
|
$ambiguity, $version); |
|
|
|
|
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Wraps the exception call |
230
|
|
|
* |
231
|
|
|
* @return void |
232
|
|
|
* @access private |
233
|
|
|
* @throws Console_GetoptPlus_Exception Exception |
234
|
|
|
* @static |
235
|
|
|
*/ |
236
|
|
|
private static function exception() |
237
|
|
|
{ |
238
|
|
|
$error = func_get_args(); |
239
|
|
|
throw new Console_GetoptPlus_Exception($error); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Parses the command line |
244
|
|
|
* |
245
|
|
|
* See the definition/example in the class Doc Block. |
246
|
|
|
* |
247
|
|
|
* Example: returning an index array |
248
|
|
|
* <code> |
249
|
|
|
* array( |
250
|
|
|
* [0] => array("foo" => null, "bar" => "car", "c" => null), |
251
|
|
|
* [1] => array([0] => "param1", [1] => "param2") |
252
|
|
|
* ); |
253
|
|
|
* </code> |
254
|
|
|
* |
255
|
|
|
* @param array $args the arguments |
256
|
|
|
* @param string $shortOptions the short options definition, e.g. "ab:c::" |
257
|
|
|
* <ul> |
258
|
|
|
* <li>":" : the option requires an argument</li> |
259
|
|
|
* <li>"::" : the option accepts an optional argument</li> |
260
|
|
|
* <li>otherwise the option accepts no argument</li> |
261
|
|
|
* </ul> |
262
|
|
|
* @param array $longOptions the long options definition, |
263
|
|
|
* e.g. array("art", "bar=", "car==) |
264
|
|
|
* <ul> |
265
|
|
|
* <li>"=" : the option requires an argument</li> |
266
|
|
|
* <li>"==" : the option accepts an optional argument</li> |
267
|
|
|
* <li>otherwise the option accepts no argument</li> |
268
|
|
|
* </ul> |
269
|
|
|
* @param string $ambiguity directive to handle option names ambiguity, |
270
|
|
|
* e.g. "--foo" and "--foobar": |
271
|
|
|
* <ul> |
272
|
|
|
* <li>"loose": allowed if "--foo" does not |
273
|
|
|
* accept an argument, this is the default |
274
|
|
|
* behaviour</li> |
275
|
|
|
* <li>"strict": no ambiguity allowed</li> |
276
|
|
|
* <li>"shortcuts": implies "strict", the use of |
277
|
|
|
* partial option names is allowed, |
278
|
|
|
* e.g. "--f" or "--fo" instead of "--foo"</li> |
279
|
|
|
* </ul> |
280
|
|
|
* @return array the parsed options, their arguments and parameters |
281
|
|
|
* @access public |
282
|
|
|
* @static |
283
|
|
|
*/ |
284
|
|
|
public static function getopt($args = array(), $shortOptions = '', |
285
|
|
|
$longOptions = array(), $ambiguity = '') |
286
|
|
|
{ |
287
|
|
|
return self::doGetopt(1, $args, $shortOptions, $longOptions, $ambiguity); |
|
|
|
|
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Parses the command line |
292
|
|
|
* |
293
|
|
|
* See getopt() for a complete description. |
294
|
|
|
* |
295
|
|
|
* @param array $args the arguments |
296
|
|
|
* @param string $shortOptions the short options definition, e.g. "ab:c::" |
297
|
|
|
* @param array $longOptions the long options definition |
298
|
|
|
* @param string $ambiguity directive to handle option names ambiguity |
299
|
|
|
* @return array the parsed options, their arguments and parameters |
300
|
|
|
* @access public |
301
|
|
|
* @static |
302
|
|
|
*/ |
303
|
|
|
public static function getopt2($args = array(), $shortOptions = '', |
304
|
|
|
$longOptions = array(), $ambiguity = '') |
305
|
|
|
{ |
306
|
|
|
return self::doGetopt(2, $args, $shortOptions, $longOptions, $ambiguity); |
|
|
|
|
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Checks if the argument is an option |
311
|
|
|
* |
312
|
|
|
* @param string $argument the argument, e.g. "-f" or "--foo" |
313
|
|
|
* @return boolean true if an option, false otherwise |
314
|
|
|
* @access public |
315
|
|
|
*/ |
316
|
|
|
public function isOption($argument) |
317
|
|
|
{ |
318
|
|
|
return (bool)preg_match('~^(-\w|--\w+)$~', $argument); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Parses a long option |
323
|
|
|
* |
324
|
|
|
* @param string $argument the option and argument (excluding the "--" prefix), |
325
|
|
|
* e.g. "file=foo.php", "file foo.php", "bar" |
326
|
|
|
* @return void |
327
|
|
|
* @access public |
328
|
|
|
*/ |
329
|
|
|
public function parseLongOption($argument) |
330
|
|
|
{ |
331
|
|
|
$option = explode('=', $argument, 2); |
332
|
|
|
$name = current($option); |
333
|
|
|
$arg = next($option) or $arg = null; |
|
|
|
|
334
|
|
|
// verifies the option is valid |
335
|
|
|
isset($this->ambigous[$name]) and self::exception('ambigous', $name); |
|
|
|
|
336
|
|
|
isset($this->shortcuts[$name]) and $name = $this->shortcuts[$name] or |
|
|
|
|
337
|
|
|
isset($this->longOptionsDef[$name]) or self::exception('unrecognized', $name); |
|
|
|
|
338
|
|
|
|
339
|
|
|
if ($this->longOptionsDef[$name] == 'mandatory') { |
340
|
|
|
// the option requires an argument, e.g. --file=foo.php |
341
|
|
|
// tries the next argument if necessary, e.g. --file foo.php |
342
|
|
|
is_null($arg) and list(, $arg) = each($this->args); |
|
|
|
|
343
|
|
|
is_null($arg) and self::exception('mandatory', $name); |
|
|
|
|
344
|
|
|
// verifies the argument is not an option itself |
345
|
|
|
$this->isOption($arg) and self::exception('mandatory', $name); |
|
|
|
|
346
|
|
|
} else if ($this->longOptionsDef[$name] == 'noarg' and !is_null($arg)) { |
|
|
|
|
347
|
|
|
// the option may not take an optional argument |
348
|
|
|
self::exception('noargument', $name); |
349
|
|
|
} |
350
|
|
|
// capture the option and its argument |
351
|
|
|
$this->options[] = array('--' . $name, $arg); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Parses the long option names and types |
356
|
|
|
* |
357
|
|
|
* @param array $options the long options, e.g. array("foo", "bar=") |
358
|
|
|
* @return array the options name and type, |
359
|
|
|
* e.g. array("foo"=>"noarg", "bar"=>"mandatory") |
360
|
|
|
* @access public |
361
|
|
|
*/ |
362
|
|
|
public function parseLongOptionsDef($options) |
363
|
|
|
{ |
364
|
|
|
// converts to an array if there is only one option |
365
|
|
|
settype($options, 'array'); |
366
|
|
|
|
367
|
|
|
$longOptionsDef = array(); |
368
|
|
|
foreach($options as $option) { |
369
|
|
|
if ($option = trim($option)) { |
370
|
|
|
// extracts the option name and type: |
371
|
|
|
// optional argument (==), mandatory (=), or none (null) |
|
|
|
|
372
|
|
|
// verifies the option syntax is correct |
373
|
|
|
preg_match("~^(\w+)(==|=)?$~", $option, $match) or |
|
|
|
|
374
|
|
|
self::exception('invalid', $option); |
375
|
|
|
$name = next($match); |
376
|
|
|
$type = next($match); |
377
|
|
|
// verifies the option is not a duplicate |
378
|
|
|
isset($longOptionsDef[$name]) and self::exception('duplicate', $name); |
|
|
|
|
379
|
|
|
// captures the option name and type |
380
|
|
|
$longOptionsDef[$name] = $this->type[$type]; |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
return $longOptionsDef; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* Parses a short option |
389
|
|
|
* |
390
|
|
|
* @param string $argument the option and argument (excluding the "-" prefix), |
391
|
|
|
* e.g. "zfoo.php", "z foo.php", "z". |
392
|
|
|
* @return void |
393
|
|
|
* @access public |
394
|
|
|
*/ |
395
|
|
|
public function parseShortOption($argument) |
396
|
|
|
{ |
397
|
|
|
for ($i = 0; $i < strlen($argument); $i++) { |
398
|
|
|
$name = $argument{$i}; |
399
|
|
|
$arg = null; |
400
|
|
|
// verifies the option is valid |
401
|
|
|
isset($this->shortOptionsDef[$name]) or self::exception('unrecognized', $name); |
|
|
|
|
402
|
|
|
|
403
|
|
|
if ($this->shortOptionsDef[$name] == 'optional') { |
404
|
|
|
// the option may take an optional argument, e.g. -zfoo.php or -z |
405
|
|
|
if (($arg = substr($argument, $i + 1)) !== false) { |
406
|
|
|
// the remainder of the string is the option argument |
407
|
|
|
$this->options[] = array($name, $arg); |
408
|
|
|
return; |
409
|
|
|
} |
410
|
|
|
} else if ($this->shortOptionsDef[$name] == 'mandatory') { |
411
|
|
|
// the option requires an argument, -zfoo.php or -z foo.php |
412
|
|
|
if (($arg = substr($argument, $i + 1)) === false) { |
413
|
|
|
// nothing left to use as the option argument |
414
|
|
|
// the next argument is expected to be the option argument |
415
|
|
|
// verifies there is one and it is not an option itself |
416
|
|
|
list(, $arg) = each($this->args); |
417
|
|
|
(is_null($arg) or $this->isOption($arg)) and |
|
|
|
|
418
|
|
|
self::exception('mandatory', $name); |
419
|
|
|
} |
420
|
|
|
$this->options[] = array($name, $arg); |
421
|
|
|
return; |
422
|
|
|
} |
423
|
|
|
// else: the option is not expecting an argument, e.g. -h |
424
|
|
|
// TODO: verify that if followed by a non option which is interpreted |
425
|
|
|
// as the end of options, there is indeed no option after until |
426
|
|
|
// possibly -- or - |
427
|
|
|
// capture the option and its argument |
428
|
|
|
$this->options[] = array($name, $arg); |
429
|
|
|
} |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
/** |
433
|
|
|
* Parses the short option names and types |
434
|
|
|
* |
435
|
|
|
* @param string $options the short options, e.g. array("ab:c::) |
436
|
|
|
* @return array the options name and type, |
437
|
|
|
* e.g. array("a"=>"noarg", "b"=>"mandatory", "c"=>"optional") |
438
|
|
|
* @access public |
439
|
|
|
*/ |
440
|
|
|
public function parseShortOptionsDef($options) |
441
|
|
|
{ |
442
|
|
|
// expecting a string for a the short options definition |
443
|
|
|
is_array($options) and self::exception('string'); |
|
|
|
|
444
|
|
|
// trims and extracts the options name and type |
445
|
|
|
// optional argument (::), mandatory (:), or none (null) |
|
|
|
|
446
|
|
|
$options = trim($options); |
447
|
|
|
preg_match_all("~(\w)(::|:)?~", $options, $matches, PREG_SET_ORDER); |
448
|
|
|
|
449
|
|
|
$check = ''; |
450
|
|
|
$shortOptionsDef = array(); |
451
|
|
|
foreach($matches as $match) { |
|
|
|
|
452
|
|
|
$check .= current($match); |
453
|
|
|
$name = next($match); |
454
|
|
|
$type = next($match); |
455
|
|
|
// verifies the option is not a duplicate |
456
|
|
|
isset($shortOptionsDef[$name]) and self::exception('duplicate', $name); |
|
|
|
|
457
|
|
|
// captures the option name and type |
458
|
|
|
$shortOptionsDef[$name] = $this->type[$type]; |
459
|
|
|
} |
460
|
|
|
// checks there is no syntax error the short options definition |
461
|
|
|
$check == $options or self::exception('syntax', $name); |
|
|
|
|
462
|
|
|
|
463
|
|
|
return $shortOptionsDef; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* Parses the command line |
468
|
|
|
* |
469
|
|
|
* See getopt() for a complete description. |
470
|
|
|
* |
471
|
|
|
* @param array $args the arguments |
472
|
|
|
* @param string $shortOptions the short options definition, e.g. "ab:c::" |
473
|
|
|
* @param array $longOptions the long options definition, e.g. array("foo", "bar=") |
474
|
|
|
* @param string $ambiguity directive to handle option names ambiguity |
475
|
|
|
* @param numeric $version the getopt version: 1 or 2 |
|
|
|
|
476
|
|
|
* @return array the parsed options, their arguments and parameters |
477
|
|
|
* @access public |
478
|
|
|
*/ |
479
|
|
|
public function process($args = array(), $shortOptions, $longOptions, |
480
|
|
|
$ambiguity = '', $version = 2) |
481
|
|
|
{ |
482
|
|
|
settype($args, 'array'); |
483
|
|
|
in_array($ambiguity, array('loose', 'strict', 'shortcuts')) or |
|
|
|
|
484
|
|
|
$ambiguity = 'loose'; |
485
|
|
|
|
486
|
|
|
if ($version < 2) { |
487
|
|
|
// preserve backwards compatibility with callers |
488
|
|
|
// that relied on erroneous POSIX fix |
489
|
|
|
// note: ported from Console/Getopt |
490
|
|
|
isset($args[0]) and substr($args[0], 0, 1) != '-' and array_shift($args); |
|
|
|
|
491
|
|
|
settype($args, 'array'); |
492
|
|
|
} |
493
|
|
|
$this->args = $args; |
494
|
|
|
// parses the options definitions, create shorcuts or check ambiguities |
495
|
|
|
$this->shortOptionsDef = $this->parseShortOptionsDef($shortOptions); |
496
|
|
|
$this->longOptionsDef = $this->parseLongOptionsDef($longOptions); |
497
|
|
|
list($this->shortcuts, $this->ambigous) = $this->createShorcuts($this->longOptionsDef, $ambiguity); |
498
|
|
|
$this->verifyNoAmbiguity($this->longOptionsDef, $ambiguity); |
499
|
|
|
|
500
|
|
|
$this->options = array(); |
501
|
|
|
$parameters = array(); |
502
|
|
|
while (list($i, $arg) = each($this->args)) { |
503
|
|
|
if ($arg == '--') { |
504
|
|
|
// end of options |
505
|
|
|
// the remaining arguments are parameters excluding this one |
506
|
|
|
$parameters = array_slice($this->args, $i + 1); |
507
|
|
|
break; |
508
|
|
|
} else if ($arg == '-') { |
509
|
|
|
// the stdin flag |
510
|
|
|
// the remaining arguments are parameters including this one |
511
|
|
|
$parameters = array_slice($this->args, $i); |
512
|
|
|
break; |
513
|
|
|
} else if (substr($arg, 0, 2) == '--') { |
514
|
|
|
// a long option, e.g. --foo |
515
|
|
|
if ($this->longOptionsDef) { |
|
|
|
|
516
|
|
|
$this->parseLongOption(substr($arg, 2)); |
517
|
|
|
} else { |
518
|
|
|
// not expecting long options, the remaining arguments are |
519
|
|
|
// parameters including this one stripped off of -- |
520
|
|
|
$parameters = array_slice($this->args, $i); |
521
|
|
|
$parameters[0] = substr($parameters[0], 2); |
522
|
|
|
break; |
523
|
|
|
} |
524
|
|
|
} else if ($arg{0} == '-') { |
525
|
|
|
// a short option, e.g. -h |
526
|
|
|
$this->parseShortOption(substr($arg, 1)); |
527
|
|
|
} else { |
528
|
|
|
// the first non option |
529
|
|
|
// the remaining arguments are parameters including this one |
530
|
|
|
$parameters = array_slice($this->args, $i); |
531
|
|
|
break; |
532
|
|
|
} |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
return array($this->options, $parameters); |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* Reads the command arguments |
540
|
|
|
* |
541
|
|
|
* @return array the arguments |
542
|
|
|
* @access public |
543
|
|
|
* @static |
544
|
|
|
*/ |
545
|
|
|
public static function readPHPArgv() |
|
|
|
|
546
|
|
|
{ |
547
|
|
|
global $argv; |
|
|
|
|
548
|
|
|
|
549
|
|
|
is_array($args = $argv) or |
|
|
|
|
550
|
|
|
is_array($args = $_SERVER['argv']) or |
|
|
|
|
551
|
|
|
is_array($args = $GLOBALS['HTTP_SERVER_VARS']['argv']) or |
|
|
|
|
552
|
|
|
self::exception('noargs'); |
553
|
|
|
|
554
|
|
|
return $args; |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
/** |
558
|
|
|
* Verifies there is no ambiguity with option names |
559
|
|
|
* |
560
|
|
|
* @param array $longOptionsDef the long options names and their types |
561
|
|
|
* @param string $ambiguity directive to handle option names ambiguity, |
562
|
|
|
* See getopt() for a complete description |
563
|
|
|
* @return boolean no ambiguity if true, false otherwise |
564
|
|
|
* @access public |
565
|
|
|
*/ |
566
|
|
|
public function verifyNoAmbiguity($longOptionsDef, $ambiguity) |
567
|
|
|
{ |
568
|
|
|
settype($longOptionsDef, 'array'); |
569
|
|
|
|
570
|
|
|
foreach($longOptionsDef as $name => $type) { |
571
|
|
|
foreach($longOptionsDef as $name2 => $type2) { |
572
|
|
|
if ($name != $name2) { |
573
|
|
|
if ($ambiguity == 'loose' and $type == 'noarg') { |
|
|
|
|
574
|
|
|
// according to Getopt.php, CVS v 1.4 2007/06/12, |
575
|
|
|
// _parseLongOption(), line #236, the possible |
|
|
|
|
576
|
|
|
// ambiguity of a long option name with another one is |
577
|
|
|
// ignored if this option does not expect an argument! |
578
|
|
|
continue; |
579
|
|
|
} |
580
|
|
|
// checks options are not ambigous, e.g. --foo --foobar |
581
|
|
|
strpos($name2, $name) === false or self::exception('ambigous', $name); |
|
|
|
|
582
|
|
|
} |
583
|
|
|
// else: there is no ambiguity between an option and itself! |
584
|
|
|
} |
585
|
|
|
} |
586
|
|
|
|
587
|
|
|
return true; |
588
|
|
|
} |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
?> |
|
|
|
|
592
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.