From 6e979aca9c56f45d600d1284ad25c7fb70d05197 Mon Sep 17 00:00:00 2001 From: merijnvdk Date: Fri, 15 Dec 2017 16:47:00 +0100 Subject: [PATCH] Initial load of rev 1354 into git Code copied from Web2All svn rev 1354 (modified) --- LICENSE.txt | 21 ++++ README.md | 13 +++ composer.json | 25 +++++ src/Web2All/Shell/Args.class.php | 169 +++++++++++++++++++++++++++++++ tests/Web2All/Shell/ArgsTest.php | 70 +++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 composer.json create mode 100644 src/Web2All/Shell/Args.class.php create mode 100644 tests/Web2All/Shell/ArgsTest.php diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..d82f2a5 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2007-2017 Web2All B.V. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f444bea --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Web2All shell + +This `web2all/shell` package requires the `web2all/framework` ([https://github.com/web2all/framework](https://github.com/web2all/framework)). It used to be proprietary software but now it has been released to the public domain under a MIT license. + +This pacckage is no longer actively maintained. Most likely it is only of interest if you own software created by Web2All B.V. which was built using these classes. + +## What does it do ## + +This package contains a (shell) commandline argument and switches parsing class. Poor mans implementation of something like perls `Getopt::Long`. + +## License ## + +Web2All framework is open-sourced software licensed under the MIT license ([https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT "license")). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f266a9b --- /dev/null +++ b/composer.json @@ -0,0 +1,25 @@ +{ + "name": "web2all/shell", + "description": "Web2All shell tooling (argument parsing)", + "keywords": ["web2all","shell","arg"], + "license": "MIT", + "authors": [ + { + "name": "Merijn van den Kroonenberg", + "homepage": "https://github.com/merijnvdk", + "role": "Developer" + } + ], + "require": { + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "autoload": { + "classmap": [ + "src/" + ] + } +} + diff --git a/src/Web2All/Shell/Args.class.php b/src/Web2All/Shell/Args.class.php new file mode 100644 index 0000000..77576db --- /dev/null +++ b/src/Web2All/Shell/Args.class.php @@ -0,0 +1,169 @@ +parseArguments($_SERVER['argv']); + } + } + + /** + * Parse argv into an array with key-value pairs + * + * @param array $argv + * @return array + */ + public function parseArguments($argv) { + $this->args = array(); + $this->params=array(); + $prev_arg=''; + $first=true; + foreach ($argv as $arg) { + // the first arg is the scriptname + if ($first){ + $first=false; + $this->scriptname=$arg; + } elseif (preg_match('/^--?([^=]+)=([^\s]*)$/',$arg,$reg)) { + // ok, we have something like --option=value + if($prev_arg && count($this->params)>0){ + // if we have params, append them to the last (previous) option + if($this->args[$prev_arg]===true){ + $this->args[$prev_arg]=implode(' ', $this->params); + }else{ + $this->args[$prev_arg].=' '.implode(' ', $this->params); + } + } + $this->args[$reg[1]] = $reg[2]; + $prev_arg=$reg[1]; + // as we still have options, reset the params as we expect them to be after the options + $this->params=array(); + } elseif(preg_match('/^--?([a-zA-Z0-9_+-]+)$/',$arg,$reg)) { + // we have something like --option or -option or --opt-ion+more + if($prev_arg && count($this->params)>0){ + // if we have params, append them to the last (previous) option + if($this->args[$prev_arg]===true){ + $this->args[$prev_arg]=implode(' ', $this->params); + }else{ + $this->args[$prev_arg].=' '.implode(' ', $this->params); + } + } + $this->args[$reg[1]] = true; + $prev_arg=$reg[1]; + // as we still have options, reset the params as we expect them to be after the options + $this->params=array(); + } else { + // not a param, so its a value (belonging to the last param) or an argument + if($prev_arg && $this->args[$prev_arg]===true){ + // okay, we had a previous option, and it was true, so it didn't have a value yet, + // so this value might be for that option + // But we will delay adding it, if another option follows, we will add this (and + // possibly more) as value to this option. Or we will do so when parsing ends. + + // because we do not know for sure if the option actually accepts values, this could also + // be a script param. So add it. + $this->params[]=$arg; + } elseif($prev_arg) { + // okay, we had a previous option, but it was not true...this means it already + // has a value. + // if there are no more other options, then the chance is high this is actually a script + // param, so add it there. It will be reset if we find another option. + $this->params[]=$arg; + }else{ + // there was no previous option, so it must be a script param + // if we get an option after this then thats weird and this param will be dropped. + $this->params[]=$arg; + } + } + + } + // ok we parsed all arguments, lets finish up + if($prev_arg && count($this->params)>0 && $this->args[$prev_arg]===true){ + // if we have params and options and the last option doesn't have a value yet, + // set its value to the first argument. But keep the first argument because we do not + // actually know if its an argument or belongs to the last option. + $this->args[$prev_arg]=$this->params[0]; + } + + return $this->args; + } + + /** + * Get a longopt value by name + * + * It would be better if this method was named getOpt, but its too late to change that + * + * @param string $name longopt name + * @return mixed false if the param is not present, true or string if it is present + */ + public function getArg($name) { + if(array_key_exists($name,$this->args)){ + return $this->args[$name]; + }else{ + return false; + } + } + + /** + * Get all script arguments/params + * + * Basically this are all params which appear after the last option. + * Possibly it includes the value of the last option. + * + * @return string[] + */ + public function getParams() { + return $this->params; + } + + /** + * Get the scriptname + * + * @return string + */ + public function getScriptname() { + return $this->scriptname; + } + +} +?> \ No newline at end of file diff --git a/tests/Web2All/Shell/ArgsTest.php b/tests/Web2All/Shell/ArgsTest.php new file mode 100644 index 0000000..42a1c1e --- /dev/null +++ b/tests/Web2All/Shell/ArgsTest.php @@ -0,0 +1,70 @@ +Factory->Web2All_Shell_Args(); + $opts = $args->parseArguments($argv); + $this->assertEquals($expected_opts, $opts, 'parsed options and switches'); + $params=$args->getParams(); + $this->assertEquals($expected_args, $params, 'parsed arguments'); + } + + /** + * Provide tasks + * + * @return array + */ + public function argumentProvider() + { + return array( +// test.php --test + array ( array ( 'test.php', '--test' ), array ( 'test' => true ), array ( ) ), +// test.php -t + array ( array ( 'test.php', '-t' ), array ( 't' => true ), array ( ) ), +// test.php -tp + array ( array ( 'test.php', '-tp' ), array ( 'tp' => true ), array ( ) ), +// test.php -t --test + array ( array ( 'test.php', '-t', '--test' ), array ( 't' => true, 'test' => true ), array ( ) ), +// test.php -a b + array ( array ( 'test.php', '-a', 'b' ), array ( 'a' => 'b' ), array ( 'b' ) ), +// test.php -a=b + array ( array ( 'test.php', '-a=b' ), array ( 'a' => 'b' ), array ( ) ), +// test.php -a "a b c" + array ( array ( 'test.php', '-a', 'a b c' ), array ( 'a' => 'a b c' ), array ( 'a b c' ) ), +// test.php --anoption "a b c" + array ( array ( 'test.php', '--anoption', 'a b c' ), array ( 'anoption' => 'a b c' ), array ( 'a b c' ) ), +// test.php arg1 + array ( array ( 'test.php', 'arg1' ), array ( ), array ( 'arg1' ) ), +// test.php arg1 arg2 + array ( array ( 'test.php', 'arg1', 'arg2' ), array ( ), array ( 'arg1', 'arg2' ) ), +// test.php arg1 arg2 arg3 + array ( array ( 'test.php', 'arg1', 'arg2', 'arg3' ), array ( ), array ( 'arg1', 'arg2', 'arg3' ) ), +// test.php --bool-opt1 --bool-opt2 --str-opt test --int-opt=1 arg1 arg2 arg3 + array ( array ( 'test.php', '--bool-opt1', '--bool-opt2', '--str-opt', 'test', '--int-opt=1', 'arg1', 'arg2', 'arg3' ), array ( 'bool-opt1' => true, 'bool-opt2' => true, 'str-opt' => 'test', 'int-opt' => '1' ), array ( 'arg1', 'arg2', 'arg3' ) ) + ); + } +} +?> \ No newline at end of file