1cbeaa4a0SAndreas Gohr<?php 2cbeaa4a0SAndreas Gohr 3cbeaa4a0SAndreas Gohrnamespace splitbrain\phpcli; 4cbeaa4a0SAndreas Gohr 5cbeaa4a0SAndreas Gohr/** 6cbeaa4a0SAndreas Gohr * Class Options 7cbeaa4a0SAndreas Gohr * 8cbeaa4a0SAndreas Gohr * Parses command line options passed to the CLI script. Allows CLI scripts to easily register all accepted options and 9cbeaa4a0SAndreas Gohr * commands and even generates a help text from this setup. 10cbeaa4a0SAndreas Gohr * 11cbeaa4a0SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 12cbeaa4a0SAndreas Gohr * @license MIT 13cbeaa4a0SAndreas Gohr */ 14cbeaa4a0SAndreas Gohrclass Options 15cbeaa4a0SAndreas Gohr{ 16cbeaa4a0SAndreas Gohr /** @var array keeps the list of options to parse */ 17cbeaa4a0SAndreas Gohr protected $setup; 18cbeaa4a0SAndreas Gohr 19cbeaa4a0SAndreas Gohr /** @var array store parsed options */ 20cbeaa4a0SAndreas Gohr protected $options = array(); 21cbeaa4a0SAndreas Gohr 22cbeaa4a0SAndreas Gohr /** @var string current parsed command if any */ 23cbeaa4a0SAndreas Gohr protected $command = ''; 24cbeaa4a0SAndreas Gohr 25cbeaa4a0SAndreas Gohr /** @var array passed non-option arguments */ 26cbeaa4a0SAndreas Gohr protected $args = array(); 27cbeaa4a0SAndreas Gohr 28cbeaa4a0SAndreas Gohr /** @var string the executed script */ 29cbeaa4a0SAndreas Gohr protected $bin; 30cbeaa4a0SAndreas Gohr 31cbeaa4a0SAndreas Gohr /** @var Colors for colored help output */ 32cbeaa4a0SAndreas Gohr protected $colors; 33cbeaa4a0SAndreas Gohr 34cbeaa4a0SAndreas Gohr /** 35cbeaa4a0SAndreas Gohr * Constructor 36cbeaa4a0SAndreas Gohr * 37cbeaa4a0SAndreas Gohr * @param Colors $colors optional configured color object 38cbeaa4a0SAndreas Gohr * @throws Exception when arguments can't be read 39cbeaa4a0SAndreas Gohr */ 40cbeaa4a0SAndreas Gohr public function __construct(Colors $colors = null) 41cbeaa4a0SAndreas Gohr { 42cbeaa4a0SAndreas Gohr if (!is_null($colors)) { 43cbeaa4a0SAndreas Gohr $this->colors = $colors; 44cbeaa4a0SAndreas Gohr } else { 45cbeaa4a0SAndreas Gohr $this->colors = new Colors(); 46cbeaa4a0SAndreas Gohr } 47cbeaa4a0SAndreas Gohr 48cbeaa4a0SAndreas Gohr $this->setup = array( 49cbeaa4a0SAndreas Gohr '' => array( 50cbeaa4a0SAndreas Gohr 'opts' => array(), 51cbeaa4a0SAndreas Gohr 'args' => array(), 52cbeaa4a0SAndreas Gohr 'help' => '' 53cbeaa4a0SAndreas Gohr ) 54cbeaa4a0SAndreas Gohr ); // default command 55cbeaa4a0SAndreas Gohr 56cbeaa4a0SAndreas Gohr $this->args = $this->readPHPArgv(); 57cbeaa4a0SAndreas Gohr $this->bin = basename(array_shift($this->args)); 58cbeaa4a0SAndreas Gohr 59cbeaa4a0SAndreas Gohr $this->options = array(); 60cbeaa4a0SAndreas Gohr } 61ab0a8902SAndreas Gohr 62ab0a8902SAndreas Gohr /** 63ab0a8902SAndreas Gohr * Gets the bin value 64ab0a8902SAndreas Gohr */ 65ab0a8902SAndreas Gohr public function getBin() 66ab0a8902SAndreas Gohr { 67ab0a8902SAndreas Gohr return $this->bin; 68ab0a8902SAndreas Gohr } 69cbeaa4a0SAndreas Gohr 70cbeaa4a0SAndreas Gohr /** 71cbeaa4a0SAndreas Gohr * Sets the help text for the tool itself 72cbeaa4a0SAndreas Gohr * 73cbeaa4a0SAndreas Gohr * @param string $help 74cbeaa4a0SAndreas Gohr */ 75cbeaa4a0SAndreas Gohr public function setHelp($help) 76cbeaa4a0SAndreas Gohr { 77cbeaa4a0SAndreas Gohr $this->setup['']['help'] = $help; 78cbeaa4a0SAndreas Gohr } 79cbeaa4a0SAndreas Gohr 80cbeaa4a0SAndreas Gohr /** 81cbeaa4a0SAndreas Gohr * Register the names of arguments for help generation and number checking 82cbeaa4a0SAndreas Gohr * 83cbeaa4a0SAndreas Gohr * This has to be called in the order arguments are expected 84cbeaa4a0SAndreas Gohr * 85cbeaa4a0SAndreas Gohr * @param string $arg argument name (just for help) 86cbeaa4a0SAndreas Gohr * @param string $help help text 87cbeaa4a0SAndreas Gohr * @param bool $required is this a required argument 88cbeaa4a0SAndreas Gohr * @param string $command if theses apply to a sub command only 89cbeaa4a0SAndreas Gohr * @throws Exception 90cbeaa4a0SAndreas Gohr */ 91cbeaa4a0SAndreas Gohr public function registerArgument($arg, $help, $required = true, $command = '') 92cbeaa4a0SAndreas Gohr { 93cbeaa4a0SAndreas Gohr if (!isset($this->setup[$command])) { 94cbeaa4a0SAndreas Gohr throw new Exception("Command $command not registered"); 95cbeaa4a0SAndreas Gohr } 96cbeaa4a0SAndreas Gohr 97cbeaa4a0SAndreas Gohr $this->setup[$command]['args'][] = array( 98cbeaa4a0SAndreas Gohr 'name' => $arg, 99cbeaa4a0SAndreas Gohr 'help' => $help, 100cbeaa4a0SAndreas Gohr 'required' => $required 101cbeaa4a0SAndreas Gohr ); 102cbeaa4a0SAndreas Gohr } 103cbeaa4a0SAndreas Gohr 104cbeaa4a0SAndreas Gohr /** 105cbeaa4a0SAndreas Gohr * This registers a sub command 106cbeaa4a0SAndreas Gohr * 107cbeaa4a0SAndreas Gohr * Sub commands have their own options and use their own function (not main()). 108cbeaa4a0SAndreas Gohr * 109cbeaa4a0SAndreas Gohr * @param string $command 110cbeaa4a0SAndreas Gohr * @param string $help 111cbeaa4a0SAndreas Gohr * @throws Exception 112cbeaa4a0SAndreas Gohr */ 113cbeaa4a0SAndreas Gohr public function registerCommand($command, $help) 114cbeaa4a0SAndreas Gohr { 115cbeaa4a0SAndreas Gohr if (isset($this->setup[$command])) { 116cbeaa4a0SAndreas Gohr throw new Exception("Command $command already registered"); 117cbeaa4a0SAndreas Gohr } 118cbeaa4a0SAndreas Gohr 119cbeaa4a0SAndreas Gohr $this->setup[$command] = array( 120cbeaa4a0SAndreas Gohr 'opts' => array(), 121cbeaa4a0SAndreas Gohr 'args' => array(), 122cbeaa4a0SAndreas Gohr 'help' => $help 123cbeaa4a0SAndreas Gohr ); 124cbeaa4a0SAndreas Gohr 125cbeaa4a0SAndreas Gohr } 126cbeaa4a0SAndreas Gohr 127cbeaa4a0SAndreas Gohr /** 128cbeaa4a0SAndreas Gohr * Register an option for option parsing and help generation 129cbeaa4a0SAndreas Gohr * 130cbeaa4a0SAndreas Gohr * @param string $long multi character option (specified with --) 131cbeaa4a0SAndreas Gohr * @param string $help help text for this option 132cbeaa4a0SAndreas Gohr * @param string|null $short one character option (specified with -) 133cbeaa4a0SAndreas Gohr * @param bool|string $needsarg does this option require an argument? give it a name here 134cbeaa4a0SAndreas Gohr * @param string $command what command does this option apply to 135cbeaa4a0SAndreas Gohr * @throws Exception 136cbeaa4a0SAndreas Gohr */ 137cbeaa4a0SAndreas Gohr public function registerOption($long, $help, $short = null, $needsarg = false, $command = '') 138cbeaa4a0SAndreas Gohr { 139cbeaa4a0SAndreas Gohr if (!isset($this->setup[$command])) { 140cbeaa4a0SAndreas Gohr throw new Exception("Command $command not registered"); 141cbeaa4a0SAndreas Gohr } 142cbeaa4a0SAndreas Gohr 143cbeaa4a0SAndreas Gohr $this->setup[$command]['opts'][$long] = array( 144cbeaa4a0SAndreas Gohr 'needsarg' => $needsarg, 145cbeaa4a0SAndreas Gohr 'help' => $help, 146cbeaa4a0SAndreas Gohr 'short' => $short 147cbeaa4a0SAndreas Gohr ); 148cbeaa4a0SAndreas Gohr 149cbeaa4a0SAndreas Gohr if ($short) { 150cbeaa4a0SAndreas Gohr if (strlen($short) > 1) { 151cbeaa4a0SAndreas Gohr throw new Exception("Short options should be exactly one ASCII character"); 152cbeaa4a0SAndreas Gohr } 153cbeaa4a0SAndreas Gohr 154cbeaa4a0SAndreas Gohr $this->setup[$command]['short'][$short] = $long; 155cbeaa4a0SAndreas Gohr } 156cbeaa4a0SAndreas Gohr } 157cbeaa4a0SAndreas Gohr 158cbeaa4a0SAndreas Gohr /** 159cbeaa4a0SAndreas Gohr * Checks the actual number of arguments against the required number 160cbeaa4a0SAndreas Gohr * 161cbeaa4a0SAndreas Gohr * Throws an exception if arguments are missing. 162cbeaa4a0SAndreas Gohr * 163cbeaa4a0SAndreas Gohr * This is run from CLI automatically and usually does not need to be called directly 164cbeaa4a0SAndreas Gohr * 165cbeaa4a0SAndreas Gohr * @throws Exception 166cbeaa4a0SAndreas Gohr */ 167cbeaa4a0SAndreas Gohr public function checkArguments() 168cbeaa4a0SAndreas Gohr { 169cbeaa4a0SAndreas Gohr $argc = count($this->args); 170cbeaa4a0SAndreas Gohr 171cbeaa4a0SAndreas Gohr $req = 0; 172cbeaa4a0SAndreas Gohr foreach ($this->setup[$this->command]['args'] as $arg) { 173cbeaa4a0SAndreas Gohr if (!$arg['required']) { 174cbeaa4a0SAndreas Gohr break; 175cbeaa4a0SAndreas Gohr } // last required arguments seen 176cbeaa4a0SAndreas Gohr $req++; 177cbeaa4a0SAndreas Gohr } 178cbeaa4a0SAndreas Gohr 179cbeaa4a0SAndreas Gohr if ($req > $argc) { 180cbeaa4a0SAndreas Gohr throw new Exception("Not enough arguments", Exception::E_OPT_ARG_REQUIRED); 181cbeaa4a0SAndreas Gohr } 182cbeaa4a0SAndreas Gohr } 183cbeaa4a0SAndreas Gohr 184cbeaa4a0SAndreas Gohr /** 185cbeaa4a0SAndreas Gohr * Parses the given arguments for known options and command 186cbeaa4a0SAndreas Gohr * 187cbeaa4a0SAndreas Gohr * The given $args array should NOT contain the executed file as first item anymore! The $args 188cbeaa4a0SAndreas Gohr * array is stripped from any options and possible command. All found otions can be accessed via the 189cbeaa4a0SAndreas Gohr * getOpt() function 190cbeaa4a0SAndreas Gohr * 191cbeaa4a0SAndreas Gohr * Note that command options will overwrite any global options with the same name 192cbeaa4a0SAndreas Gohr * 193cbeaa4a0SAndreas Gohr * This is run from CLI automatically and usually does not need to be called directly 194cbeaa4a0SAndreas Gohr * 195cbeaa4a0SAndreas Gohr * @throws Exception 196cbeaa4a0SAndreas Gohr */ 197cbeaa4a0SAndreas Gohr public function parseOptions() 198cbeaa4a0SAndreas Gohr { 199cbeaa4a0SAndreas Gohr $non_opts = array(); 200cbeaa4a0SAndreas Gohr 201cbeaa4a0SAndreas Gohr $argc = count($this->args); 202cbeaa4a0SAndreas Gohr for ($i = 0; $i < $argc; $i++) { 203cbeaa4a0SAndreas Gohr $arg = $this->args[$i]; 204cbeaa4a0SAndreas Gohr 205cbeaa4a0SAndreas Gohr // The special element '--' means explicit end of options. Treat the rest of the arguments as non-options 206cbeaa4a0SAndreas Gohr // and end the loop. 207cbeaa4a0SAndreas Gohr if ($arg == '--') { 208cbeaa4a0SAndreas Gohr $non_opts = array_merge($non_opts, array_slice($this->args, $i + 1)); 209cbeaa4a0SAndreas Gohr break; 210cbeaa4a0SAndreas Gohr } 211cbeaa4a0SAndreas Gohr 212cbeaa4a0SAndreas Gohr // '-' is stdin - a normal argument 213cbeaa4a0SAndreas Gohr if ($arg == '-') { 214cbeaa4a0SAndreas Gohr $non_opts = array_merge($non_opts, array_slice($this->args, $i)); 215cbeaa4a0SAndreas Gohr break; 216cbeaa4a0SAndreas Gohr } 217cbeaa4a0SAndreas Gohr 218cbeaa4a0SAndreas Gohr // first non-option 219*64604f4eSAndreas Gohr if ($arg[0] != '-') { 220cbeaa4a0SAndreas Gohr $non_opts = array_merge($non_opts, array_slice($this->args, $i)); 221cbeaa4a0SAndreas Gohr break; 222cbeaa4a0SAndreas Gohr } 223cbeaa4a0SAndreas Gohr 224cbeaa4a0SAndreas Gohr // long option 225*64604f4eSAndreas Gohr if (strlen($arg) > 1 && $arg[1] === '-') { 226cbeaa4a0SAndreas Gohr $arg = explode('=', substr($arg, 2), 2); 227cbeaa4a0SAndreas Gohr $opt = array_shift($arg); 228cbeaa4a0SAndreas Gohr $val = array_shift($arg); 229cbeaa4a0SAndreas Gohr 230cbeaa4a0SAndreas Gohr if (!isset($this->setup[$this->command]['opts'][$opt])) { 231cbeaa4a0SAndreas Gohr throw new Exception("No such option '$opt'", Exception::E_UNKNOWN_OPT); 232cbeaa4a0SAndreas Gohr } 233cbeaa4a0SAndreas Gohr 234cbeaa4a0SAndreas Gohr // argument required? 235cbeaa4a0SAndreas Gohr if ($this->setup[$this->command]['opts'][$opt]['needsarg']) { 236cbeaa4a0SAndreas Gohr if (is_null($val) && $i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) { 237cbeaa4a0SAndreas Gohr $val = $this->args[++$i]; 238cbeaa4a0SAndreas Gohr } 239cbeaa4a0SAndreas Gohr if (is_null($val)) { 240cbeaa4a0SAndreas Gohr throw new Exception("Option $opt requires an argument", 241cbeaa4a0SAndreas Gohr Exception::E_OPT_ARG_REQUIRED); 242cbeaa4a0SAndreas Gohr } 243cbeaa4a0SAndreas Gohr $this->options[$opt] = $val; 244cbeaa4a0SAndreas Gohr } else { 245cbeaa4a0SAndreas Gohr $this->options[$opt] = true; 246cbeaa4a0SAndreas Gohr } 247cbeaa4a0SAndreas Gohr 248cbeaa4a0SAndreas Gohr continue; 249cbeaa4a0SAndreas Gohr } 250cbeaa4a0SAndreas Gohr 251cbeaa4a0SAndreas Gohr // short option 252cbeaa4a0SAndreas Gohr $opt = substr($arg, 1); 253cbeaa4a0SAndreas Gohr if (!isset($this->setup[$this->command]['short'][$opt])) { 254cbeaa4a0SAndreas Gohr throw new Exception("No such option $arg", Exception::E_UNKNOWN_OPT); 255cbeaa4a0SAndreas Gohr } else { 256cbeaa4a0SAndreas Gohr $opt = $this->setup[$this->command]['short'][$opt]; // store it under long name 257cbeaa4a0SAndreas Gohr } 258cbeaa4a0SAndreas Gohr 259cbeaa4a0SAndreas Gohr // argument required? 260cbeaa4a0SAndreas Gohr if ($this->setup[$this->command]['opts'][$opt]['needsarg']) { 261cbeaa4a0SAndreas Gohr $val = null; 262cbeaa4a0SAndreas Gohr if ($i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) { 263cbeaa4a0SAndreas Gohr $val = $this->args[++$i]; 264cbeaa4a0SAndreas Gohr } 265cbeaa4a0SAndreas Gohr if (is_null($val)) { 266cbeaa4a0SAndreas Gohr throw new Exception("Option $arg requires an argument", 267cbeaa4a0SAndreas Gohr Exception::E_OPT_ARG_REQUIRED); 268cbeaa4a0SAndreas Gohr } 269cbeaa4a0SAndreas Gohr $this->options[$opt] = $val; 270cbeaa4a0SAndreas Gohr } else { 271cbeaa4a0SAndreas Gohr $this->options[$opt] = true; 272cbeaa4a0SAndreas Gohr } 273cbeaa4a0SAndreas Gohr } 274cbeaa4a0SAndreas Gohr 275cbeaa4a0SAndreas Gohr // parsing is now done, update args array 276cbeaa4a0SAndreas Gohr $this->args = $non_opts; 277cbeaa4a0SAndreas Gohr 278cbeaa4a0SAndreas Gohr // if not done yet, check if first argument is a command and reexecute argument parsing if it is 279cbeaa4a0SAndreas Gohr if (!$this->command && $this->args && isset($this->setup[$this->args[0]])) { 280cbeaa4a0SAndreas Gohr // it is a command! 281cbeaa4a0SAndreas Gohr $this->command = array_shift($this->args); 282cbeaa4a0SAndreas Gohr $this->parseOptions(); // second pass 283cbeaa4a0SAndreas Gohr } 284cbeaa4a0SAndreas Gohr } 285cbeaa4a0SAndreas Gohr 286cbeaa4a0SAndreas Gohr /** 287cbeaa4a0SAndreas Gohr * Get the value of the given option 288cbeaa4a0SAndreas Gohr * 289cbeaa4a0SAndreas Gohr * Please note that all options are accessed by their long option names regardless of how they were 290cbeaa4a0SAndreas Gohr * specified on commandline. 291cbeaa4a0SAndreas Gohr * 292cbeaa4a0SAndreas Gohr * Can only be used after parseOptions() has been run 293cbeaa4a0SAndreas Gohr * 294cbeaa4a0SAndreas Gohr * @param mixed $option 295cbeaa4a0SAndreas Gohr * @param bool|string $default what to return if the option was not set 29643d3f077SAndreas Gohr * @return bool|string|string[] 297cbeaa4a0SAndreas Gohr */ 298cbeaa4a0SAndreas Gohr public function getOpt($option = null, $default = false) 299cbeaa4a0SAndreas Gohr { 300cbeaa4a0SAndreas Gohr if ($option === null) { 301cbeaa4a0SAndreas Gohr return $this->options; 302cbeaa4a0SAndreas Gohr } 303cbeaa4a0SAndreas Gohr 304cbeaa4a0SAndreas Gohr if (isset($this->options[$option])) { 305cbeaa4a0SAndreas Gohr return $this->options[$option]; 306cbeaa4a0SAndreas Gohr } 307cbeaa4a0SAndreas Gohr return $default; 308cbeaa4a0SAndreas Gohr } 309cbeaa4a0SAndreas Gohr 310cbeaa4a0SAndreas Gohr /** 311cbeaa4a0SAndreas Gohr * Return the found command if any 312cbeaa4a0SAndreas Gohr * 313cbeaa4a0SAndreas Gohr * @return string 314cbeaa4a0SAndreas Gohr */ 315cbeaa4a0SAndreas Gohr public function getCmd() 316cbeaa4a0SAndreas Gohr { 317cbeaa4a0SAndreas Gohr return $this->command; 318cbeaa4a0SAndreas Gohr } 319cbeaa4a0SAndreas Gohr 320cbeaa4a0SAndreas Gohr /** 321cbeaa4a0SAndreas Gohr * Get all the arguments passed to the script 322cbeaa4a0SAndreas Gohr * 323cbeaa4a0SAndreas Gohr * This will not contain any recognized options or the script name itself 324cbeaa4a0SAndreas Gohr * 325cbeaa4a0SAndreas Gohr * @return array 326cbeaa4a0SAndreas Gohr */ 327cbeaa4a0SAndreas Gohr public function getArgs() 328cbeaa4a0SAndreas Gohr { 329cbeaa4a0SAndreas Gohr return $this->args; 330cbeaa4a0SAndreas Gohr } 331cbeaa4a0SAndreas Gohr 332cbeaa4a0SAndreas Gohr /** 333cbeaa4a0SAndreas Gohr * Builds a help screen from the available options. You may want to call it from -h or on error 334cbeaa4a0SAndreas Gohr * 335cbeaa4a0SAndreas Gohr * @return string 33643d3f077SAndreas Gohr * 33743d3f077SAndreas Gohr * @throws Exception 338cbeaa4a0SAndreas Gohr */ 339cbeaa4a0SAndreas Gohr public function help() 340cbeaa4a0SAndreas Gohr { 341cbeaa4a0SAndreas Gohr $tf = new TableFormatter($this->colors); 342cbeaa4a0SAndreas Gohr $text = ''; 343cbeaa4a0SAndreas Gohr 344cbeaa4a0SAndreas Gohr $hascommands = (count($this->setup) > 1); 345cbeaa4a0SAndreas Gohr foreach ($this->setup as $command => $config) { 346cbeaa4a0SAndreas Gohr $hasopts = (bool)$this->setup[$command]['opts']; 347cbeaa4a0SAndreas Gohr $hasargs = (bool)$this->setup[$command]['args']; 348cbeaa4a0SAndreas Gohr 349cbeaa4a0SAndreas Gohr // usage or command syntax line 350cbeaa4a0SAndreas Gohr if (!$command) { 351cbeaa4a0SAndreas Gohr $text .= $this->colors->wrap('USAGE:', Colors::C_BROWN); 352cbeaa4a0SAndreas Gohr $text .= "\n"; 353cbeaa4a0SAndreas Gohr $text .= ' ' . $this->bin; 354cbeaa4a0SAndreas Gohr $mv = 2; 355cbeaa4a0SAndreas Gohr } else { 356cbeaa4a0SAndreas Gohr $text .= "\n"; 357cbeaa4a0SAndreas Gohr $text .= $this->colors->wrap(' ' . $command, Colors::C_PURPLE); 358cbeaa4a0SAndreas Gohr $mv = 4; 359cbeaa4a0SAndreas Gohr } 360cbeaa4a0SAndreas Gohr 361cbeaa4a0SAndreas Gohr if ($hasopts) { 362cbeaa4a0SAndreas Gohr $text .= ' ' . $this->colors->wrap('<OPTIONS>', Colors::C_GREEN); 363cbeaa4a0SAndreas Gohr } 364cbeaa4a0SAndreas Gohr 365cbeaa4a0SAndreas Gohr if (!$command && $hascommands) { 366cbeaa4a0SAndreas Gohr $text .= ' ' . $this->colors->wrap('<COMMAND> ...', Colors::C_PURPLE); 367cbeaa4a0SAndreas Gohr } 368cbeaa4a0SAndreas Gohr 369cbeaa4a0SAndreas Gohr foreach ($this->setup[$command]['args'] as $arg) { 370cbeaa4a0SAndreas Gohr $out = $this->colors->wrap('<' . $arg['name'] . '>', Colors::C_CYAN); 371cbeaa4a0SAndreas Gohr 372cbeaa4a0SAndreas Gohr if (!$arg['required']) { 373cbeaa4a0SAndreas Gohr $out = '[' . $out . ']'; 374cbeaa4a0SAndreas Gohr } 375cbeaa4a0SAndreas Gohr $text .= ' ' . $out; 376cbeaa4a0SAndreas Gohr } 377cbeaa4a0SAndreas Gohr $text .= "\n"; 378cbeaa4a0SAndreas Gohr 379cbeaa4a0SAndreas Gohr // usage or command intro 380cbeaa4a0SAndreas Gohr if ($this->setup[$command]['help']) { 381cbeaa4a0SAndreas Gohr $text .= "\n"; 382cbeaa4a0SAndreas Gohr $text .= $tf->format( 383cbeaa4a0SAndreas Gohr array($mv, '*'), 384cbeaa4a0SAndreas Gohr array('', $this->setup[$command]['help'] . "\n") 385cbeaa4a0SAndreas Gohr ); 386cbeaa4a0SAndreas Gohr } 387cbeaa4a0SAndreas Gohr 388cbeaa4a0SAndreas Gohr // option description 389cbeaa4a0SAndreas Gohr if ($hasopts) { 390cbeaa4a0SAndreas Gohr if (!$command) { 391cbeaa4a0SAndreas Gohr $text .= "\n"; 392cbeaa4a0SAndreas Gohr $text .= $this->colors->wrap('OPTIONS:', Colors::C_BROWN); 393cbeaa4a0SAndreas Gohr } 394cbeaa4a0SAndreas Gohr $text .= "\n"; 395cbeaa4a0SAndreas Gohr foreach ($this->setup[$command]['opts'] as $long => $opt) { 396cbeaa4a0SAndreas Gohr 397cbeaa4a0SAndreas Gohr $name = ''; 398cbeaa4a0SAndreas Gohr if ($opt['short']) { 399cbeaa4a0SAndreas Gohr $name .= '-' . $opt['short']; 400cbeaa4a0SAndreas Gohr if ($opt['needsarg']) { 401cbeaa4a0SAndreas Gohr $name .= ' <' . $opt['needsarg'] . '>'; 402cbeaa4a0SAndreas Gohr } 403cbeaa4a0SAndreas Gohr $name .= ', '; 404cbeaa4a0SAndreas Gohr } 405cbeaa4a0SAndreas Gohr $name .= "--$long"; 406cbeaa4a0SAndreas Gohr if ($opt['needsarg']) { 407cbeaa4a0SAndreas Gohr $name .= ' <' . $opt['needsarg'] . '>'; 408cbeaa4a0SAndreas Gohr } 409cbeaa4a0SAndreas Gohr 410cbeaa4a0SAndreas Gohr $text .= $tf->format( 411cbeaa4a0SAndreas Gohr array($mv, '30%', '*'), 412cbeaa4a0SAndreas Gohr array('', $name, $opt['help']), 413cbeaa4a0SAndreas Gohr array('', 'green', '') 414cbeaa4a0SAndreas Gohr ); 415cbeaa4a0SAndreas Gohr $text .= "\n"; 416cbeaa4a0SAndreas Gohr } 417cbeaa4a0SAndreas Gohr } 418cbeaa4a0SAndreas Gohr 419cbeaa4a0SAndreas Gohr // argument description 420cbeaa4a0SAndreas Gohr if ($hasargs) { 421cbeaa4a0SAndreas Gohr if (!$command) { 422cbeaa4a0SAndreas Gohr $text .= "\n"; 423cbeaa4a0SAndreas Gohr $text .= $this->colors->wrap('ARGUMENTS:', Colors::C_BROWN); 424cbeaa4a0SAndreas Gohr } 425cbeaa4a0SAndreas Gohr $text .= "\n"; 426cbeaa4a0SAndreas Gohr foreach ($this->setup[$command]['args'] as $arg) { 427cbeaa4a0SAndreas Gohr $name = '<' . $arg['name'] . '>'; 428cbeaa4a0SAndreas Gohr 429cbeaa4a0SAndreas Gohr $text .= $tf->format( 430cbeaa4a0SAndreas Gohr array($mv, '30%', '*'), 431cbeaa4a0SAndreas Gohr array('', $name, $arg['help']), 432cbeaa4a0SAndreas Gohr array('', 'cyan', '') 433cbeaa4a0SAndreas Gohr ); 434cbeaa4a0SAndreas Gohr } 435cbeaa4a0SAndreas Gohr } 436cbeaa4a0SAndreas Gohr 437cbeaa4a0SAndreas Gohr // head line and intro for following command documentation 438cbeaa4a0SAndreas Gohr if (!$command && $hascommands) { 439cbeaa4a0SAndreas Gohr $text .= "\n"; 440cbeaa4a0SAndreas Gohr $text .= $this->colors->wrap('COMMANDS:', Colors::C_BROWN); 441cbeaa4a0SAndreas Gohr $text .= "\n"; 442cbeaa4a0SAndreas Gohr $text .= $tf->format( 443cbeaa4a0SAndreas Gohr array($mv, '*'), 444cbeaa4a0SAndreas Gohr array('', 'This tool accepts a command as first parameter as outlined below:') 445cbeaa4a0SAndreas Gohr ); 446cbeaa4a0SAndreas Gohr $text .= "\n"; 447cbeaa4a0SAndreas Gohr } 448cbeaa4a0SAndreas Gohr } 449cbeaa4a0SAndreas Gohr 450cbeaa4a0SAndreas Gohr return $text; 451cbeaa4a0SAndreas Gohr } 452cbeaa4a0SAndreas Gohr 453cbeaa4a0SAndreas Gohr /** 454cbeaa4a0SAndreas Gohr * Safely read the $argv PHP array across different PHP configurations. 455cbeaa4a0SAndreas Gohr * Will take care on register_globals and register_argc_argv ini directives 456cbeaa4a0SAndreas Gohr * 457cbeaa4a0SAndreas Gohr * @throws Exception 458cbeaa4a0SAndreas Gohr * @return array the $argv PHP array or PEAR error if not registered 459cbeaa4a0SAndreas Gohr */ 460cbeaa4a0SAndreas Gohr private function readPHPArgv() 461cbeaa4a0SAndreas Gohr { 462cbeaa4a0SAndreas Gohr global $argv; 463cbeaa4a0SAndreas Gohr if (!is_array($argv)) { 464cbeaa4a0SAndreas Gohr if (!@is_array($_SERVER['argv'])) { 465cbeaa4a0SAndreas Gohr if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { 466cbeaa4a0SAndreas Gohr throw new Exception( 467cbeaa4a0SAndreas Gohr "Could not read cmd args (register_argc_argv=Off?)", 468cbeaa4a0SAndreas Gohr Exception::E_ARG_READ 469cbeaa4a0SAndreas Gohr ); 470cbeaa4a0SAndreas Gohr } 471cbeaa4a0SAndreas Gohr return $GLOBALS['HTTP_SERVER_VARS']['argv']; 472cbeaa4a0SAndreas Gohr } 473cbeaa4a0SAndreas Gohr return $_SERVER['argv']; 474cbeaa4a0SAndreas Gohr } 475cbeaa4a0SAndreas Gohr return $argv; 476cbeaa4a0SAndreas Gohr } 477cbeaa4a0SAndreas Gohr} 478cbeaa4a0SAndreas Gohr 479