support --long-opt=arg
[pharext/pharext] / src / pharext / CliArgs.php
index fb9a7ec5895ab02d31ef765b3cba31a81d1f2d7e..99992bd321cca327e2b2e6e72300dd97c9b0c941 100644 (file)
@@ -51,7 +51,7 @@ class CliArgs implements \ArrayAccess
         * Original option spec
         * @var array
         */
-       private $orig;
+       private $orig = [];
        
        /**
         * Compiled spec
@@ -79,15 +79,32 @@ class CliArgs implements \ArrayAccess
         * @return pharext\CliArgs self
         */
        public function compile(array $spec = null) {
-               $this->orig = $spec;
-               $this->spec = [];
+               $this->orig = array_merge($this->orig, $spec);
                foreach ((array) $spec as $arg) {
-                       $this->spec["-".$arg[0]] = $arg;
+                       if (isset($arg[0])) { 
+                               $this->spec["-".$arg[0]] = $arg;
+                       }
                        $this->spec["--".$arg[1]] = $arg;
                }
                return $this;
        }
        
+       /**
+        * Get original spec
+        * @return array
+        */
+       public function getSpec() {
+               return $this->orig;
+       }
+       
+       /**
+        * Get compiled spec
+        * @return array
+        */
+       public function getCompiledSpec() {
+               return $this->spec;
+       }
+       
        /**
         * Parse command line arguments according to the compiled spec.
         * 
@@ -103,23 +120,30 @@ class CliArgs implements \ArrayAccess
                for ($i = 0; $i < $argc; ++$i) {
                        $o = $argv[$i];
                        
-                       if ($o{0} === '-' && strlen($o) > 1 && $o{1} !== '-') {
+                       if ($o{0} === '-' && strlen($o) > 2 && $o{1} !== '-') {
                                // multiple short opts, .e.g -vps
                                $argc += strlen($o) - 2;
                                array_splice($argv, $i, 1, array_map(function($s) {
                                        return "-$s";
                                }, str_split(substr($o, 1))));
                                $o = $argv[$i];
+                       } elseif ($o{0} === '-' && strlen($o) > 2 && $o{1} === '-' && 0 < ($eq = strpos($o, "="))) {
+                               $argc++;
+                               array_splice($argv, $i, 1, [
+                                       substr($o, 0, $eq++),
+                                       substr($o, $eq)
+                               ]);
+                               $o = $argv[$i];
                        }
 
                        if (!isset($this->spec[$o])) {
-                               yield sprintf("Unknown option %s", $argv[$i]);
+                               yield sprintf("Unknown option %s", $o);
                        } elseif (!$this->optAcceptsArg($o)) {
                                $this[$o] = true;
                        } elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) {
                                $this[$o] = $argv[++$i];
-                       } elseif ($this->optNeedsArg($o)) {
-                               yield sprintf("Option --%s needs an argument", $this->optLongName($o));
+                       } elseif ($this->optRequiresArg($o)) {
+                               yield sprintf("Option --%s requires an argument", $this->optLongName($o));
                        } else {
                                // OPTARG
                                $this[$o] = $this->optDefaultArg($o);
@@ -149,48 +173,6 @@ class CliArgs implements \ArrayAccess
                }
        }
        
-       /**
-        * Output command line help message
-        * @param string $prog
-        */
-       public function help($prog) {
-               printf("\nUsage:\n\n  $ %s", $prog);
-               $flags = [];
-               $required = [];
-               $optional = [];
-               foreach ($this->orig as $spec) {
-                       if ($spec[3] & self::REQARG) {
-                               if ($spec[3] & self::REQUIRED) {
-                                       $required[] = $spec;
-                               } else {
-                                       $optional[] = $spec;
-                               }
-                       } else {
-                               $flags[] = $spec;
-                       }
-               }
-               
-               if ($flags) {
-                       printf(" [-%s]", implode("|-", array_column($flags, 0)));
-               }
-               foreach ($required as $req) {
-                       printf(" -%s <arg>", $req[0]);
-               }
-               if ($optional) {
-                       printf(" [-%s <arg>]", implode("|-", array_column($optional, 0)));
-               } 
-               printf("\n\n");
-               foreach ($this->orig as $spec) {
-                       printf("    -%s|--%s %s", $spec[0], $spec[1], ($spec[3] & self::REQARG) ? "<arg>  " : (($spec[3] & self::OPTARG) ? "[<arg>]" : "       "));
-                       printf("%s%s %s", str_repeat(" ", 16-strlen($spec[1])), $spec[2], ($spec[3] & self::REQUIRED) ? "(REQUIRED)" : "");
-                       if (isset($spec[4])) {
-                               printf(" [%s]", $spec[4]);
-                       }
-                       printf("\n");
-               }
-               printf("\n");
-       }
-       
        /**
         * Retreive the default argument of an option
         * @param string $o
@@ -217,14 +199,26 @@ class CliArgs implements \ArrayAccess
                return "";
        }
 
+       /**
+        * Retrieve option's flags
+        * @param string $o
+        * @return int
+        */
+       private function optFlags($o) {
+               $o = $this->opt($o);
+               if (isset($this->spec[$o])) {
+                       return $this->spec[$o][3];
+               }
+               return null;
+       }
+       
        /**
         * Check whether an option is flagged for halting argument processing
         * @param string $o
         * @return boolean
         */
        private function optHalts($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::HALT;
+               return $this->optFlags($o) & self::HALT;
        }
        
        /**
@@ -232,9 +226,8 @@ class CliArgs implements \ArrayAccess
         * @param string $o
         * @return boolean
         */
-       private function optNeedsArg($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::REQARG;
+       private function optRequiresArg($o) {
+               return $this->optFlags($o) & self::REQARG;
        }
        
        /**
@@ -243,8 +236,7 @@ class CliArgs implements \ArrayAccess
         * @return boolean
         */
        private function optAcceptsArg($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & 0xf00;
+               return $this->optFlags($o) & 0xf00;
        }
        
        /**
@@ -253,8 +245,7 @@ class CliArgs implements \ArrayAccess
         * @return boolean
         */
        private function optIsMulti($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::MULTI;
+               return $this->optFlags($o) & self::MULTI;
        }
        
        /**
@@ -313,12 +304,18 @@ class CliArgs implements \ArrayAccess
                return $this->offsetGet($o);
        }
        function offsetSet($o, $v) {
+               $osn = $this->optShortName($o);
+               $oln = $this->optLongName($o);
                if ($this->optIsMulti($o)) {
-                       $this->args["-".$this->optShortName($o)][] = $v;
-                       $this->args["--".$this->optLongName($o)][] = $v;
+                       if (isset($osn)) {
+                               $this->args["-$osn"][] = $v;
+                       }
+                       $this->args["--$oln"][] = $v;
                } else {
-                       $this->args["-".$this->optShortName($o)] = $v;
-                       $this->args["--".$this->optLongName($o)] = $v;
+                       if (isset($osn)) {
+                               $this->args["-$osn"] = $v;
+                       }
+                       $this->args["--$oln"] = $v;
                }
        }
        function __set($o, $v) {