shadowbrokers-exploits/windows/Resources/Dsz/Scripts/Include/_CommandLine.dsi
2017-04-14 11:45:07 +02:00

553 lines
18 KiB
Text

#----------------------------------------------------
# _CommandLine
# This file provides utility functions for handling
# command lines
#----------------------------------------------------
@include "_Arrays.dsi";
@include "_Paths.dsi";
#---------------------------------------------------------------------------------------------------#
# _DisplayHelp
# Shows the script's commandline help using the default path to the file
#---------------------------------------------------------------------------------------------------#
sub _DisplayHelp( ) {
return _DisplayHelp( "" );
}
#---------------------------------------------------------------------------------------------------#
# _DisplayHelp
# Shows the script's commandline help using the specified path to the file
#
# Params
# IN STRING $Filename
# the path to the command definition
#---------------------------------------------------------------------------------------------------#
sub _DisplayHelp( IN STRING $filename ) {
string $fullpath;
if( __FindCommandFile( $filename, $fullpath ) ) {
string %description;
if( __ParseCommandDescription( $fullpath, %description ) ) {
return __DisplayHelp( %_sgEnv{"script_name"}, %description );
}
}
return false;
}
#---------------------------------------------------------------------------------------------------#
# _ParseCommandLine
# Parses the specified commandline
#
# Params
# IN INT $argc
# the number of the parameters
# IN STRING $argv
# the parameters themselves
# REF STRING %parameters
# the destination for the data
#---------------------------------------------------------------------------------------------------#
sub _ParseCommandLine( IN INT $argc, IN STRING $argv, REF STRING %parameters ) {
return _ParseCommandLine( $argc, $argv, "", %parameters, false );
}
sub _ParseCommandLine( IN INT $argc, IN STRING $argv, REF STRING %parameters, IN BOOL $stripQuotes) {
return _ParseCommandLine( $argc, $argv, "", %parameters, $stripQuotes );
}
#---------------------------------------------------------------------------------------------------#
# _ParseCommandLine
# Parses the specified commandline
#
# Params
# IN INT $argc
# the number of the parameters
# IN STRING $argv
# the parameters themselves
# IN STRING $filename
# the path to the script command description
# REF STRING %parameters
# the destination for the data
#---------------------------------------------------------------------------------------------------#
sub _ParseCommandLine( IN INT $argc, IN STRING $argv, IN STRING $filename, REF STRING %parameters, IN BOOL $stripQuotes ) {
string %description;
string $fullpath;
if( !__FindCommandFile( $filename, $fullpath ) ) {
return false;
}
if( !__ParseCommandDescription( $fullpath, %description ) ) {
return false;
}
# always
%parameters{'script'} = $argv[0];
if( $argc >= 2 && ($argv[1] == "?" || $argv[1] == "/?" || $argv[1] == "-?" || $argv[1] == "+?" || $argv[1] == "/help" || $argv[1] == "-help" || $argv[1] == "+help" ) ) {
__DisplayHelp( $argv[0], %description );
return false;
}
string $option;
for( int $i = 1; $i < $argc; $i++ ) {
string $match;
if( RegexMatch("^[+-](.+)", $argv[$i], $match ) ) {
if( sizeof( $match ) == 1 ) {
if( defined( $option ) ) {
if( !__FullOption( %description, %parameters, $option ) ) {
return __PrintError("Incomplete '$option'",$argv[0], %description );
}
if( !defined( %parameters{$option} ) ) {
%parameters{$option} = "true";
}
}
if( !__ValidOption( %description, $match ) ) {
return __PrintError( "Invalid option '$match'", $argv[0], %description );
}
if( defined( %parameters{$match} ) ) {
return __PrintError( "Only one use of '$argv[$i]' allowed", $argv[0], %description );
}
$option = $match;
} else {
return __PrintError( "Invalid option", $argv[0], %description );
}
} else if( !defined( $option ) ) {
return __PrintError( "Missing required option", $argv[0], %description );
} else {
string $arg = $argv[$i];
if ($stripQuotes) {
RegExSub('"(.*)"', '\$1', $arg);
}
if( !__ValidArgument( %description, $option, sizeof( %parameters{$option} ), $arg ) ) {
return __PrintError( "Invalid argument '$argv[$i]'", $argv[0], %description );
}
_AppendString( %parameters{$option}, $arg );
}
}
if( defined( $option ) && !__FullOption( %description, %parameters, $option ) ) {
return __PrintError( "Incomplete '$option'", $argv[0], %description );
}
if( defined( $option ) && !defined( %parameters{$option} ) ) {
%parameters{$option} = "true";
}
return __AllRequiredOptionsUsed( %description, %parameters );
}
#---------------------------------------------------------------------------------------------------#
# __FindCommandFile
# Finds the command file using the given filename / relative path
#
# Params
# IN STRING $filename
# path to the file
# OUT STRING $fullpath
# outputs the full path
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __FindCommandFile( IN STRING $filename, OUT STRING $fullpath ) {
if( $filename == "" ) {
# get all the characters of the filename before '.dss', but drop off any that are part of the path
if( !RegexMatch("([^\\\\/]*)\\.dss", %_sgEnv{'script_name'}, $filename ) && defined( $filename ) ) {
return false;
}
$filename = "$filename.txt";
}
if( _IsFullPath( $filename ) ) {
$fullpath = $filename;
} else {
$fullpath = "%_sgEnv{'script_path'}/$filename";
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __ParseCommandDescription
# Parses the specified description file
#
# Params
# IN STRING $filename
# where to look
# REF STRING %parameters
# output of of the options
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __ParseCommandDescription( IN STRING $filename, REF STRING %parameters ) {
string $lines;
if (!ReadFile("$filename", $lines)) {
echo "Unable to open $filename";
%parameters{'undefined'} = "true";
return true;
}
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $option = -1;
for( int $i=0; $i < sizeof($lines); $i++ ) {
# skip comments
string $match;
if( RegexMatch( "^[\t ]*(#.*){0,1}\$", $lines[$i] ) ) {
# blank line or comment
continue;
} else if( RegExMatch( "^[\t ]+([^\t ].*)\$", $lines[$i], $match ) && defined( $match ) && sizeof( $match ) == 1 ) {
# help line
if( $option == -1 ) {
# we haven't found one yet
echo "Invalid file format";
return false;
}
string $key = "$optionKey$option$helpKey";
_AppendString( %parameters{$key}, $match );
} else if( RegExMatch( "^([\\[<])-([^\t ]+) *(.*)([\\]>])[\t ]*\$", $lines[$i], $match ) && defined( $match ) && sizeof( $match ) == 4 ) {
$option++;
if( $match[0] == "[" && $match[3] == "]" ) {
%parameters{"$optionKey$option$required"} = "false";
} else if( $match[0] == "<" && $match[3] == ">" ) {
%parameters{"$optionKey$option$required"} = "true";
} else {
echo "Invalid file format";
return false;
}
%parameters{"$optionKey$option$name"} = $match[1];
int $argument = 0;
string $args = $match[2];
bool $mustBeOptional = false;
while( $args != "" ) {
if( RegexMatch( "^[\t ]*([\\[<])([^\t ]+)([\\]>])[\t ]*(.*)\$", $args, $match ) && defined( $match ) && sizeof( $match ) == 4 ) {
if( $match[0] == "[" && $match[2] == "]" ) {
%parameters{"$optionKey$option$argumentKey$argument$required"} = "false";
$mustBeOptional = true;
} else if( $match[0] == "<" && $match[2] == ">" && !$mustBeOptional ) {
%parameters{"$optionKey$option$argumentKey$argument$required"} = "true";
} else {
echo "Invalid file format: Mismatched argument tags";
return false;
}
%parameters{"$optionKey$option$argumentKey$argument$name"} = $match[1];
$args = $match[3];
$argument++;
} else if( RegexMatch( "^[\t ]*\$", $args ) ) {
break;
} else {
echo "Invalid file format: Couldn't parse '$args'";
return false;
}
}
} else {
#invalid line
echo "Invalid line";
return false;
}
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __DisplayHelp
# Actually does the display help stuff
#
# Params
# IN STRING $script
# the name of the script
# IN STRING %description
# the commandline model
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __DisplayHelp( IN STRING $script, IN STRING %description ) {
if( defined( %description{'undefined'} ) && <bool>%description{'undefined'} ) {
echo 'script "$script" -args "[options]"';
return true;
}
echo 'script "$script" -args "..."';
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $index = 0;
while( defined( %description{ "$optionKey$index$name" } ) ) {
string $arguments = "";
int $arg = 0;
while( defined( %description{ "$optionKey$index$argumentKey$arg$name" } ) ) {
if( <bool>%description{ "$optionKey$index$argumentKey$arg$required" } ) {
StrCat( $arguments, ' <%description{ "$optionKey$index$argumentKey$arg$name" }>');
} else {
StrCat( $arguments, ' [%description{ "$optionKey$index$argumentKey$arg$name" }]');
}
$arg++;
}
# build up arguments
if( <bool>%description{ "$optionKey$index$required" } ) {
echo ' <-%description{ "$optionKey$index$name" }$arguments>';
} else {
echo ' [-%description{ "$optionKey$index$name" }$arguments]';
}
if( defined( %description{ "$optionKey$index$helpKey" } ) ) {
for( int $i = 0; $i < sizeof( %description{ "$optionKey$index$helpKey" } ); $i++ ) {
echo ' %description{ "$optionKey$index$helpKey" }[$i]';
}
}
$index++;
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __ValidOption
# Verifies that the provided option is an option available according to the description file
#
# Params
# REF STRING %description
# the command line model
# IN STRING $option
# the specified option
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __ValidOption( REF STRING %description, IN STRING $option ) {
# not defined, always true
if( defined( %description{'undefined'} ) && <bool>%description{'undefined'} ) {
return true;
}
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $num = 0;
while( defined( %description{ "$optionKey$num$name" } ) ) {
if( %description{ "$optionKey$num$name" } == $option ) {
return true;
}
$num++;
}
return false;
}
#---------------------------------------------------------------------------------------------------#
# __ValidArgument
# Returns whether the given argument (and its location) are valid
#
# Params
# REF STRING %description
# the commandline model
# IN STRING $option
# the specific option to which the argument belongs
# IN INT $index
# the index of the argument within the option
# IN STRING $argument
# the argument provided
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __ValidArgument( REF STRING %description, IN STRING $option, IN INT $index, IN STRING $argument ) {
# not defined, always true
if( defined( %description{'undefined'} ) && <bool>%description{'undefined'} ) {
return true;
}
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $num = 0;
while( defined( %description{ "$optionKey$num$name" } ) ) {
if( %description{ "$optionKey$num$name" } == $option ) {
# now that I have the option, I can do the argument, too
if( !defined( %description{ "$optionKey$num$argumentKey$index$name" } ) ) {
return false;
}
string $str = %description{ "$optionKey$num$argumentKey$index$name" };
if( RegexMatch( "[^\\|]+\\|[^\\|].+", $str ) ) {
# we have a list of enumerated values
while( $str != "" ) {
string $match;
if( !(RegexMatch("[\t ]*([^\\|]+)[\t ]*\\|[\t ]*([^\\|].*)", $str, $match) && defined( $match ) && sizeof( $match ) == 2 ) ) {
return $str == $argument;
}
$str = $match[1];
if( $argument == $match[0] ) {
return true;
}
}
return false;
}
return true;
}
$num++;
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __FullOption
# Determines if the specified option has all the parameters it needs
#
# Params
# REF STRING %description
# the commandline model
# REF STRING %parameters
# the parameter output struct
# IN STRING $option
# the specified option
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __FullOption( REF STRING %description, REF STRING %parameters, IN STRING $option ) {
# not defined, always has enough
if( defined( %description{'undefined'} ) && <bool>%description{'undefined'} ) {
return true;
}
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $num = 0;
while( defined( %description{ "$optionKey$num$name" } ) ) {
if( %description{ "$optionKey$num$name" } != $option ) {
$num++;
continue;
}
int $num2 = 0;
int $min = 0;
int $max = 0;
while( defined( %description{ "$optionKey$num$argumentKey$num2$name" } ) ) {
$max++;
if( <bool>%description{ "$optionKey$num$argumentKey$num2$required" } ) {
$min++;
}
$num2++;
}
return ( sizeof( %parameters{$option} ) >= $min && sizeof( %parameters{$option} ) <= $max );
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __AllRequiredOptionsUsed
# Returns true if the commandline model has been sufficiently used to qualify as a valid commandline
#
# Params
# REF STRING %description
# the commandline model
# REF STRING %parameters
# the output data model
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __AllRequiredOptionsUsed( REF STRING %description, REF STRING %parameters ) {
# not defined, always true
if( defined( %description{'undefined'} ) && <bool>%description{'undefined'} ) {
return true;
}
string $optionKey, $argumentKey, $helpKey, $required, $name, $value;
__GetKeys( $optionKey, $argumentKey, $helpKey, $required, $name, $value );
int $num = 0;
while( defined( %description{ "$optionKey$num$name" } ) ) {
if( <bool>%description{ "$optionKey$num$required" } ) {
# must be present in %parameters
if( !
defined( %parameters{ %description{ "$optionKey$num$name" } } ) ||
sizeof( %parameters{ %description{ "$optionKey$num$name" } } ) == 0
) {
echo "Missing option \"%description{ '$optionKey$num$name' }\"";
return false;
}
}
$num++;
}
return true;
}
#---------------------------------------------------------------------------------------------------#
# __PrintError
# Prints an error with some spacing around it
#
# Params
# IN STRING $error
# the error message
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __PrintError( IN STRING $error ) {
echo "";
echo "* ";
echo "* $error";
echo "* ";
echo "";
}
#---------------------------------------------------------------------------------------------------#
# __PrintError
# Prints an error with some spacing around it and shows the command's help
#
# Params
# IN STRING $error
# the error message
# IN STRING $cmd
# the name of the script
# IN STRING %description
# the command's description
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __PrintError( IN STRING $error, IN STRING $cmd, IN STRING %description ) {
__PrintError( $error );
__DisplayHelp( $cmd, %description );
return false;
}
#---------------------------------------------------------------------------------------------------#
# __GetKeys
# This function returns the keys used in several functions to manipulate the hash.
# Putting them all here allows for easy changes.
#
# Params
# OUT STRING $optionKey
# the prefix used to designate an option
# OUT STRING $argumentKey
# the prefix used to designate an argument
# OUT STRING $helpKey
# the prefix used to designate help information
# OUT STRING $required
# the prefix used to designate a required option
# OUT STRING $name
# the prefix used to designate an name
# OUT STRING $value
# the prefix used to designate an value
#
# NOTE: Not intended to be called outside this file
#---------------------------------------------------------------------------------------------------#
sub __GetKeys( OUT STRING $optionKey, OUT STRING $argumentKey, OUT STRING $helpKey, OUT STRING $required, OUT STRING $name, OUT STRING $value ) {
$optionKey = "opt_";
$argumentKey = "arg_";
$helpKey = "help_";
$required = "req_";
$name = "name_";
$value = "value_";
return true;
}