Overview

Packages

  • Argv

Classes

  • Horde_Argv_AmbiguousOptionException
  • Horde_Argv_BadOptionException
  • Horde_Argv_Exception
  • Horde_Argv_HelpFormatter
  • Horde_Argv_IndentedHelpFormatter
  • Horde_Argv_Option
  • Horde_Argv_OptionConflictException
  • Horde_Argv_OptionContainer
  • Horde_Argv_OptionException
  • Horde_Argv_OptionGroup
  • Horde_Argv_OptionValueException
  • Horde_Argv_Parser
  • Horde_Argv_TitledHelpFormatter
  • Horde_Argv_Translation
  • Horde_Argv_Values
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Horde command-line argument parsing package.
  4:  *
  5:  * This package is ported from Python's Optik (http://optik.sourceforge.net/).
  6:  *
  7:  * @author   Chuck Hagenbuch <chuck@horde.org>
  8:  * @author   Mike Naberezny <mike@maintainable.com>
  9:  * @license  http://www.horde.org/licenses/bsd BSD
 10:  * @category Horde
 11:  * @package  Argv
 12:  */
 13: 
 14: /**
 15:  *  Class attributes:
 16:  *    standardOptionList : [Option]
 17:  *      list of standard options that will be accepted by all instances
 18:  *      of this parser class (intended to be overridden by subclasses).
 19:  *
 20:  *  Instance attributes:
 21:  *    usage : string
 22:  *      a usage string for your program.  Before it is displayed
 23:  *      to the user, "%prog" will be expanded to the name of
 24:  *      your program ($this->prog or os.path.basename(sys.argv[0])).
 25:  *    prog : string
 26:  *      the name of the current program (to override
 27:  *      os.path.basename(sys.argv[0])).
 28:  *    epilog : string
 29:  *      paragraph of help text to print after option help
 30:  *
 31:  *    optionGroups : [OptionGroup]
 32:  *      list of option groups in this parser (option groups are
 33:  *      irrelevant for parsing the command-line, but very useful
 34:  *      for generating help)
 35:  *
 36:  *    allowInterspersedArgs : bool = true
 37:  *      if true, positional arguments may be interspersed with options.
 38:  *      Assuming -a and -b each take a single argument, the command-line
 39:  *        -ablah foo bar -bboo baz
 40:  *      will be interpreted the same as
 41:  *        -ablah -bboo -- foo bar baz
 42:  *      If this flag were false, that command line would be interpreted as
 43:  *        -ablah -- foo bar -bboo baz
 44:  *      -- ie. we stop processing options as soon as we see the first
 45:  *      non-option argument.  (This is the tradition followed by
 46:  *      Python's getopt module, Perl's Getopt::Std, and other argument-
 47:  *      parsing libraries, but it is generally annoying to users.)
 48:  *
 49:  *    allowUnknownArgs : bool = false
 50:  *      if true, unrecognized arguments will be auto-created, instead
 51:  *      of throwing a BadOptionException.
 52:  *
 53:  *    ignoreUnknownArgs : bool = false
 54:  *      if true, unrecognized arguments will be silently skipped, instead of
 55:  *      throwing a BadOptionException.
 56:  *
 57:  *    rargs : [string]
 58:  *      the argument list currently being parsed.  Only set when
 59:  *      parseArgs() is active, and continually trimmed down as
 60:  *      we consume arguments.  Mainly there for the benefit of
 61:  *      callback options.
 62:  *    largs : [string]
 63:  *      the list of leftover arguments that we have skipped while
 64:  *      parsing options.  If allowInterspersedArgs is false, this
 65:  *      list is always empty.
 66:  *    values : Values
 67:  *      the set of option values currently being accumulated.  Only
 68:  *      set when parseArgs() is active.  Also mainly for callbacks.
 69:  *
 70:  * @category Horde
 71:  * @package  Argv
 72:  */
 73: class Horde_Argv_Parser extends Horde_Argv_OptionContainer
 74: {
 75:     public $standardOptionList = array();
 76: 
 77:     protected $_usage;
 78:     public $optionGroups = array();
 79: 
 80:     public function __construct($args = array())
 81:     {
 82:         $args = array_merge(array(
 83:             'usage' => null,
 84:             'optionList' => null,
 85:             'optionClass' => 'Horde_Argv_Option',
 86:             'version' => null,
 87:             'conflictHandler' => "error",
 88:             'description' => null,
 89:             'formatter' => null,
 90:             'addHelpOption' => true,
 91:             'prog' => null,
 92:             'epilog' => null,
 93:             'allowInterspersedArgs' => true,
 94:             'allowUnknownArgs' => false,
 95:             'ignoreUnknownArgs' => false,
 96:             ), $args);
 97: 
 98:         parent::__construct($args['optionClass'], $args['conflictHandler'], $args['description']);
 99:         $this->setUsage($args['usage']);
100:         $this->prog = $args['prog'];
101:         $this->version = $args['version'];
102:         $this->allowInterspersedArgs = $args['allowInterspersedArgs'];
103:         $this->allowUnknownArgs = $args['allowUnknownArgs'];
104:         $this->ignoreUnknownArgs = $args['ignoreUnknownArgs'];
105:         if (is_null($args['formatter'])) {
106:             $args['formatter'] = new Horde_Argv_IndentedHelpFormatter();
107:         }
108:         $this->formatter = $args['formatter'];
109:         $this->formatter->setParser($this);
110:         $this->epilog = $args['epilog'];
111: 
112:         // Populate the option list; initial sources are the
113:         // standardOptionList class attribute, the 'optionList'
114:         // argument, and (if applicable) the _addVersionOption() and
115:         // _addHelpOption() methods.
116:         $this->_populateOptionList($args['optionList'],
117:                                    $args['addHelpOption']);
118: 
119:         $this->_initParsingState();
120:     }
121: 
122:     /**
123:      *  Declare that you are done with this Horde_Argv_Parser.  This cleans up
124:      *  reference cycles so the Horde_Argv_Parser (and all objects referenced by
125:      *  it) can be garbage-collected promptly.  After calling destroy(), the
126:      *  Horde_Argv_Parser is unusable.
127:      */
128:     public function __destruct()
129:     {
130:         foreach ($this->optionGroups as &$group) {
131:             unset($group);
132:         }
133: 
134:         unset($this->optionList);
135:         unset($this->optionGroups);
136:         unset($this->formatter);
137:     }
138: 
139:     // -- Private methods -----------------------------------------------
140:     // (used by our OptionContainer's constructor)
141: 
142:     protected function _createOptionList()
143:     {
144:         $this->optionList = array();
145:         $this->optionGroups = array();
146:         $this->_createOptionMappings();
147:     }
148: 
149:     protected function _addHelpOption()
150:     {
151:         $this->addOption('-h', '--help', array('action' => 'help',
152:                                                'help' => Horde_Argv_Translation::t("show this help message and exit")));
153:     }
154: 
155:     protected function _addVersionOption()
156:     {
157:         $this->addOption('--version', array('action' => 'version',
158:                                             'help' => Horde_Argv_Translation::t("show program's version number and exit")));
159:     }
160: 
161:     protected function _populateOptionList($optionList, $add_help = true)
162:     {
163:         if ($this->standardOptionList)
164:             $this->addOptions($this->standardOptionList);
165:         if ($optionList)
166:             $this->addOptions($optionList);
167:         if ($this->version)
168:             $this->_addVersionOption();
169:         if ($add_help)
170:             $this->_addHelpOption();
171:     }
172: 
173:     protected function _initParsingState()
174:     {
175:         // These are set in parseArgs() for the convenience of callbacks.
176:         $this->rargs = null;
177:         $this->largs = null;
178:         $this->values = null;
179:     }
180: 
181:     // -- Simple modifier methods ---------------------------------------
182: 
183:     public function setUsage($usage)
184:     {
185:         if (is_null($usage))
186:             $this->_usage = '%prog ' . Horde_Argv_Translation::t("[options]");
187:         elseif ($usage == Horde_Argv_Option::SUPPRESS_USAGE)
188:             $this->_usage = null;
189:         else
190:             $this->_usage = $usage;
191:     }
192: 
193:     public function enableInterspersedArgs()
194:     {
195:         $this->allowInterspersedArgs = true;
196:     }
197: 
198:     public function disableInterspersedArgs()
199:     {
200:         $this->allowInterspersedArgs = false;
201:     }
202: 
203:     public function setDefault($dest, $value)
204:     {
205:         $this->defaults[$dest] = $value;
206:     }
207: 
208:     public function setDefaults($defaults)
209:     {
210:         $this->defaults = array_merge($this->defaults, $defaults);
211:     }
212: 
213:     protected function _getAllOptions()
214:     {
215:         $options = $this->optionList;
216:         foreach ($this->optionGroups as $group) {
217:             $options = array_merge($options, $group->optionList);
218:         }
219:         return $options;
220:     }
221: 
222:     public function getDefaultValues()
223:     {
224:         $defaults = $this->defaults;
225:         foreach ($this->_getAllOptions() as $option) {
226:             $default = isset($defaults[$option->dest]) ? $defaults[$option->dest] : null;
227:             if (is_string($default)) {
228:                 $opt_str = $option->getOptString();
229:                 $defaults[$option->dest] = $option->checkValue($opt_str, $default);
230:             }
231:         }
232: 
233:         return new Horde_Argv_Values($defaults);
234:     }
235: 
236: 
237:     // -- OptionGroup methods -------------------------------------------
238: 
239:     public function addOptionGroup()
240:     {
241:         // XXX lots of overlap with OptionContainer::addOption()
242:         $args = func_get_args();
243: 
244:         if (count($args) && is_string($args[0])) {
245:             $groupFactory = new ReflectionClass('Horde_Argv_OptionGroup');
246:             array_unshift($args, $this);
247:             $group = $groupFactory->newInstanceArgs($args);
248:         } elseif (count($args) == 1) {
249:             $group = $args[0];
250:             if (!$group instanceof Horde_Argv_OptionGroup)
251:                 throw new InvalidArgumentException("not an OptionGroup instance: " . var_export($group, true));
252:             if ($group->parser !== $this)
253:                 throw new InvalidArgumentException("invalid OptionGroup (wrong parser)");
254:         } else {
255:             throw new InvalidArgumentException('invalid arguments');
256:         }
257: 
258:         $this->optionGroups[] = $group;
259:         $this->defaults = array_merge($this->defaults, $group->defaults);
260:         return $group;
261:     }
262: 
263:     public function getOptionGroup($opt_str)
264:     {
265:         if (isset($this->shortOpt[$opt_str])) {
266:             $option = $this->shortOpt[$opt_str];
267:         } elseif (isset($this->longOpt[$opt_str])) {
268:             $option = $this->longOpt[$opt_str];
269:         } else {
270:             return null;
271:         }
272: 
273:         if ($option->container !== $this) {
274:             return $option->container;
275:         }
276: 
277:         return null;
278:     }
279: 
280:     // -- Option-parsing methods ----------------------------------------
281: 
282:     protected function _getArgs($args = null)
283:     {
284:         if (is_null($args)) {
285:             $args = $_SERVER['argv'];
286:             array_shift($args);
287:             return $args;
288:         } else {
289:             return $args;
290:         }
291:     }
292: 
293:     /**
294:      *  Parse the command-line options found in 'args' (default:
295:      *  sys.argv[1:]).  Any errors result in a call to 'parserError()', which
296:      *  by default prints the usage message to stderr and calls
297:      *  exit() with an error message.  On success returns a pair
298:      *  (values, args) where 'values' is an Values instance (with all
299:      *  your option values) and 'args' is the list of arguments left
300:      *  over after parsing options.
301:      */
302:     public function parseArgs($args = null, $values = null)
303:     {
304:         $rargs = $this->_getArgs($args);
305:         $largs = array();
306:         if (is_null($values))
307:             $values = $this->getDefaultValues();
308: 
309:         // Store the halves of the argument list as attributes for the
310:         // convenience of callbacks:
311:         //   rargs
312:         //     the rest of the command-line (the "r" stands for
313:         //     "remaining" or "right-hand")
314:         //   largs
315:         //     the leftover arguments -- ie. what's left after removing
316:         //     options and their arguments (the "l" stands for "leftover"
317:         //     or "left-hand")
318:         $this->rargs =& $rargs;
319:         $this->largs =& $largs;
320:         $this->values = $values;
321: 
322:         try {
323:             $this->_processArgs($largs, $rargs, $values);
324:         } catch (Horde_Argv_BadOptionException $e) {
325:             $this->parserError($e->getMessage());
326:         } catch (Horde_Argv_OptionValueException $e) {
327:             $this->parserError($e->getMessage());
328:         }
329: 
330:         $args = array_merge($largs, $rargs);
331:         return $this->checkValues($values, $args);
332:     }
333: 
334:     /**
335:      *  Check that the supplied option values and leftover arguments are
336:      *  valid.  Returns the option values and leftover arguments
337:      *  (possibly adjusted, possibly completely new -- whatever you
338:      *  like).  Default implementation just returns the passed-in
339:      *  values; subclasses may override as desired.
340:      */
341:     public function checkValues($values, $args)
342:     {
343:         return array($values, $args);
344:     }
345: 
346:     /**
347:      *  _process_args(largs : [string],
348:      *                rargs : [string],
349:      *                values : Values)
350:      *
351:      *  Process command-line arguments and populate 'values', consuming
352:      *  options and arguments from 'rargs'.  If 'allowInterspersedArgs' is
353:      *  false, stop at the first non-option argument.  If true, accumulate any
354:      *  interspersed non-option arguments in 'largs'.
355:      */
356:     protected function _processArgs(&$largs, &$rargs, &$values)
357:     {
358:         while ($rargs) {
359:             $arg = $rargs[0];
360:             // We handle bare "--" explicitly, and bare "-" is handled by the
361:             // standard arg handler since the short arg case ensures that the
362:             // len of the opt string is greater than 1.
363:             if ($arg == '--') {
364:                 array_shift($rargs);
365:                 return;
366:             } elseif (substr($arg, 0, 2) == '--') {
367:                 // process a single long option (possibly with value(s))
368:                 $this->_processLongOpt($rargs, $values);
369:             } elseif (substr($arg, 0, 1) == '-' && strlen($arg) > 1) {
370:                 // process a cluster of short options (possibly with
371:                 // value(s) for the last one only)
372:                 $this->_processShortOpts($rargs, $values);
373:             } elseif ($this->allowInterspersedArgs) {
374:                 $largs[] = $arg;
375:                 array_shift($rargs);
376:             } else {
377:                 // stop now, leave this arg in rargs
378:                 return;
379:             }
380:         }
381: 
382:         // Say this is the original argument list:
383:         // [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
384:         //                            ^
385:         // (we are about to process arg(i)).
386:         //
387:         // Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
388:         // [arg0, ..., arg(i-1)] (any options and their arguments will have
389:         // been removed from largs).
390:         //
391:         // The while loop will usually consume 1 or more arguments per pass.
392:         // If it consumes 1 (eg. arg is an option that takes no arguments),
393:         // then after _process_arg() is done the situation is:
394:         //
395:         //   largs = subset of [arg0, ..., arg(i)]
396:         //   rargs = [arg(i+1), ..., arg(N-1)]
397:         //
398:         // If allowInterspersedArgs is false, largs will always be
399:         // *empty* -- still a subset of [arg0, ..., arg(i-1)], but
400:         // not a very interesting subset!
401:     }
402: 
403:     /**
404:      *  opt : string) -> string
405:      *
406:      *    Determine which long option string 'opt' matches, ie. which one
407:      *    it is an unambiguous abbrevation for.  Raises BadOptionError if
408:      *    'opt' doesn't unambiguously match any long option string.
409:      */
410:     protected function _matchLongOpt($opt)
411:     {
412:         return self::matchAbbrev($opt, $this->longOpt);
413:     }
414: 
415:     /**
416:      *  (s : string, wordmap : {string : Option}) -> string
417:      *
418:      *  Return the string key in 'wordmap' for which 's' is an unambiguous
419:      *  abbreviation.  If 's' is found to be ambiguous or doesn't match any of
420:      *  'words', raise BadOptionError.
421:      */
422:     public static function matchAbbrev($s, $wordmap)
423:     {
424:         // Is there an exact match?
425:         if (array_key_exists($s, $wordmap)) {
426:             return $s;
427:         }
428: 
429:         // Isolate all words with s as a prefix.
430:         $possibilities = array();
431:         foreach (array_keys($wordmap) as $word) {
432:             if (strncmp($word, $s, strlen($s)) === 0) {
433:                 $possibilities[] = $word;
434:             }
435:         }
436: 
437:         // No exact match, so there had better be just one possibility.
438:         if (count($possibilities) == 1) {
439:             return $possibilities[0];
440:         } elseif (!$possibilities) {
441:             throw new Horde_Argv_BadOptionException($s);
442:         } else {
443:             // More than one possible completion: ambiguous prefix.
444:             sort($possibilities);
445:             throw new Horde_Argv_AmbiguousOptionException($s, $possibilities);
446:         }
447:     }
448: 
449:     protected function _processLongOpt(&$rargs, &$values)
450:     {
451:         $arg = array_shift($rargs);
452: 
453:         // Value explicitly attached to arg?  Pretend it's the next
454:         // argument.
455:         if (strpos($arg, '=') !== false) {
456:             list($opt, $next_arg) = explode('=', $arg, 2);
457:             array_unshift($rargs, $next_arg);
458:             $had_explicit_value = true;
459:         } else {
460:             $opt = $arg;
461:             $had_explicit_value = false;
462:         }
463: 
464:         try {
465:             $opt = $this->_matchLongOpt($opt);
466:             $option = $this->longOpt[$opt];
467:         } catch (Horde_Argv_BadOptionException $e) {
468:             if ($this->ignoreUnknownArgs) {
469:                 return;
470:             }
471:             if ($this->allowUnknownArgs) {
472:                 $option = $this->addOption($opt, array('default' => true, 'action' => 'append'));
473:             } else {
474:                 throw $e;
475:             }
476:         }
477: 
478:         if ($option->takesValue()) {
479:             $nargs = $option->nargs;
480:             if (count($rargs) < $nargs) {
481:                 if (!$option->hasDefault()) {
482:                     if ($nargs == 1) {
483:                         $this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires an argument"), $opt));
484:                     } else {
485:                         $this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires %d arguments"), $opt, $nargs));
486:                     }
487:                 }
488:             } elseif ($nargs == 1) {
489:                 $value = array_shift($rargs);
490:             } else {
491:                 $value = array_splice($rargs, 0, $nargs);
492:             }
493: 
494:         } elseif ($had_explicit_value) {
495:             $this->parserError(sprintf(Horde_Argv_Translation::t("%s option does not take a value"), $opt));
496: 
497:         } else {
498:             $value = null;
499:         }
500: 
501:         $option->process($opt, $value, $values, $this);
502:     }
503: 
504:     protected function _processShortOpts(&$rargs, &$values)
505:     {
506:         $arg = array_shift($rargs);
507:         $stop = false;
508:         $i = 1;
509:         for ($c = 1, $c_max = strlen($arg); $c < $c_max; $c++) {
510:             $ch = $arg[$c];
511:             $opt = '-' . $ch;
512:             $option = isset($this->shortOpt[$opt]) ? $this->shortOpt[$opt] : null;
513:             $i++; // we have consumed a character
514: 
515:             if (!$option) {
516:                 if ($this->allowUnknownArgs) {
517:                     $option = $this->addOption($opt, array('default' => true, 'action' => 'append'));
518:                 } else {
519:                     throw new Horde_Argv_BadOptionException($opt);
520:                 }
521:             }
522: 
523:             if ($option->takesValue()) {
524:                 // Any characters left in arg?  Pretend they're the
525:                 // next arg, and stop consuming characters of arg.
526:                 if ($i < strlen($arg)) {
527:                     array_unshift($rargs, substr($arg, $i));
528:                     $stop = true;
529:                 }
530: 
531:                 $nargs = $option->nargs;
532:                 if (count($rargs) < $nargs) {
533:                     if (!$option->hasDefault()) {
534:                         if ($nargs == 1) {
535:                             $this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires an argument"), $opt));
536:                         } else {
537:                             $this->parserError(sprintf(Horde_Argv_Translation::t("%s option requires %d arguments"), $opt, $nargs));
538:                         }
539:                     }
540:                 } elseif ($nargs == 1) {
541:                     $value = array_shift($rargs);
542:                 } else {
543:                     $value = array_splice($rargs, 0, $nargs);
544:                 }
545: 
546:             } else {
547:                 // option doesn't take a value
548:                 $value = null;
549:             }
550: 
551:             $option->process($opt, $value, $values, $this);
552: 
553:             if ($stop) { break; }
554:         }
555:     }
556: 
557:     // -- Feedback methods ----------------------------------------------
558: 
559:     public function getProgName()
560:     {
561:         if (is_null($this->prog))
562:             return basename($_SERVER['argv'][0]);
563:         else
564:             return $this->prog;
565:     }
566: 
567:     public function expandProgName($s)
568:     {
569:         return str_replace("%prog", $this->getProgName(), $s);
570:     }
571: 
572:     public function getDescription()
573:     {
574:         return $this->expandProgName($this->description);
575:     }
576: 
577:     public function parserExit($status = 0, $msg = null)
578:     {
579:         if ($msg)
580:             fwrite(STDERR, $msg);
581:         exit($status);
582:     }
583: 
584:     /**
585:      * Print a usage message incorporating $msg to stderr and exit.
586:      * If you override this in a subclass, it should not return -- it
587:      * should either exit or raise an exception.
588:      *
589:      * @param string $msg
590:      */
591:     public function parserError($msg)
592:     {
593:         $this->printUsage(STDERR);
594:         $this->parserExit(2, sprintf("%s: error: %s\n", $this->getProgName(), $msg));
595:     }
596: 
597:     public function getUsage($formatter = null)
598:     {
599:         if (is_null($formatter))
600:             $formatter = $this->formatter;
601:         if ($this->_usage)
602:             return $formatter->formatUsage($this->expandProgName($this->_usage));
603:         else
604:             return '';
605:     }
606: 
607:     /**
608:      *  (file : file = stdout)
609:      *
610:      *  Print the usage message for the current program ($this->_usage) to
611:      *  'file' (default stdout).  Any occurence of the string "%prog" in
612:      *  $this->_usage is replaced with the name of the current program
613:      *  (basename of sys.argv[0]).  Does nothing if $this->_usage is empty
614:      *  or not defined.
615:      */
616:     public function printUsage($file = null)
617:     {
618:         if (!$this->_usage)
619:             return;
620: 
621:         if (is_null($file))
622:             echo $this->getUsage();
623:         else
624:             fwrite($file, $this->getUsage());
625:     }
626: 
627:     public function getVersion()
628:     {
629:         if ($this->version)
630:             return $this->expandProgName($this->version);
631:         else
632:             return '';
633:     }
634: 
635:     /**
636:      * file : file = stdout
637:      *
638:      *    Print the version message for this program ($this->version) to
639:      *    'file' (default stdout).  As with printUsage(), any occurence
640:      *    of "%prog" in $this->version is replaced by the current program's
641:      *    name.  Does nothing if $this->version is empty or undefined.
642:      */
643:     public function printVersion($file = null)
644:     {
645:         if (!$this->version)
646:             return;
647: 
648:         if (is_null($file))
649:             echo $this->getVersion() . "\n";
650:         else
651:             fwrite($file, $this->getVersion() . "\n");
652:     }
653: 
654:     public function formatOptionHelp($formatter = null)
655:     {
656:         if (is_null($formatter))
657:             $formatter = $this->formatter;
658:         $formatter->storeOptionStrings($this);
659:         $result = array();
660:         $result[] = $formatter->formatHeading(Horde_Argv_Translation::t("Options"));
661:         $formatter->indent();
662:         if ($this->optionList) {
663:             $result[] = parent::formatOptionHelp($formatter);
664:             $result[] = "\n";
665:         }
666:         foreach ($this->optionGroups as $group) {
667:             $result[] = $group->formatHelp($formatter);
668:             $result[] = "\n";
669:         }
670:         $formatter->dedent();
671:         // Drop the last "\n", or the header if no options or option groups:
672:         array_pop($result);
673:         return implode('', $result);
674:     }
675: 
676:     public function formatEpilog($formatter)
677:     {
678:         return $formatter->formatEpilog($this->epilog);
679:     }
680: 
681:     public function formatHelp($formatter = null)
682:     {
683:         if (is_null($formatter))
684:             $formatter = $this->formatter;
685:         $result = array();
686:         if ($this->_usage)
687:             $result[] = $this->getUsage($formatter) . "\n";
688:         if ($this->description)
689:             $result[] = $this->formatDescription($formatter) . "\n";
690:         $result[] = $this->formatOptionHelp($formatter);
691:         $result[] = $this->formatEpilog($formatter);
692:         return implode('', $result);
693:     }
694: 
695:     /**
696:      *  file : file = stdout
697:      *
698:      *  Print an extended help message, listing all options and any
699:      *  help text provided with them, to 'file' (default stdout).
700:      */
701:     public function printHelp($file = null)
702:     {
703:         if (is_null($file))
704:             echo $this->formatHelp();
705:         else
706:             fwrite($file, $this->formatHelp());
707:     }
708: 
709: }
710: 
API documentation generated by ApiGen