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