microsoft-visualbasic-runtime/CommandLine/CommandLine.vb

1038 lines
42 KiB
VB.net
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#Region "Microsoft.VisualBasic::7b47855e89a8f5f044bdf74ac27b35cf, Microsoft.VisualBasic.Core\CommandLine\CommandLine.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.
' /********************************************************************************/
' Summaries:
' Class CommandLine
'
' Properties: BoolFlags, cli, Count, EnvironmentVariables, IsNothing
' IsNullOrEmpty, IsReadOnly, Keys, Name, ParameterList
' Parameters, SingleValue, Tokens
'
' Function: Assert, CheckMissingRequiredArguments, CheckMissingRequiredParameters, Contains, ContainsParameter
' GetBoolean, GetByte, GetBytes, GetChar, GetChars
' GetCommandsOverview, GetDateTime, GetDecimal, GetDictionary, GetDouble
' GetEnumerator, GetEnumerator1, GetFloat, GetFullDIRPath, GetFullFilePath
' GetGuid, GetInt16, GetInt32, GetInt64, GetObject
' GetOrdinal, GetString, GetValue, HavebFlag, IsNull
' IsTrue, OpenHandle, OpenStreamInput, OpenStreamOutput, ReadInput
' (+2 Overloads) Remove, ToArgumentVector, ToString, TrimNamePrefix
'
' Sub: (+2 Overloads) Add, Clear, CopyTo
'
' Operators: (+4 Overloads) -, ^, +, <, (+2 Overloads) <=
' >, (+2 Overloads) >=
'
'
' /********************************************************************************/
#End Region
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Text
Imports Microsoft.VisualBasic.CommandLine.Parsers
Imports Microsoft.VisualBasic.ComponentModel.Collection.Generic
Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
Imports Microsoft.VisualBasic.Language
Imports Microsoft.VisualBasic.Language.Default
Imports Microsoft.VisualBasic.Linq
Imports Microsoft.VisualBasic.Scripting
Imports Microsoft.VisualBasic.Scripting.Expressions
Imports Microsoft.VisualBasic.Serialization
Imports Microsoft.VisualBasic.Text
Namespace CommandLine
' file path: C://path/to/file
' standard input: std_in://
' standard output: std_out://
' memory mapping file: memory://file/uri
''' <summary>
''' A command line object that parse from the user input commandline string.
''' (从用户所输入的命令行字符串之中解析出来的命令行对象,标准的命令行格式为:
''' <example>&lt;EXE> &lt;CLI_Name> ["Parameter" "Value"]</example>)
''' </summary>
''' <remarks></remarks>
'''
Public Class CommandLine
Implements ICollection(Of NamedValue(Of String))
Implements INamedValue
Friend arguments As New List(Of NamedValue(Of String))
''' <summary>
''' 原始的命令行字符串
''' </summary>
Friend cliCommandArgvs As String
Dim _name As String
''' <summary>
''' The command name that parse from the input command line.
''' (从输入的命令行中所解析出来的命令的名称)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Name As String Implements INamedValue.Key
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return _name
End Get
Protected Friend Set(value As String)
_name = value
End Set
End Property
''' <summary>
''' The command tokens that were parsed from the input commandline.
''' (从所输入的命令行之中所解析出来的命令参数单元)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Tokens As String()
''' <summary>
''' Listing all of the parameter value collection that parsed from the commandline string.
''' </summary>
''' <returns></returns>
Public ReadOnly Property ParameterList As NamedValue(Of String)()
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return arguments.ToArray
End Get
End Property
''' <summary>
''' 得到当前的命令行对象之中的所有的参数的名称的列表
''' </summary>
''' <returns></returns>
Public ReadOnly Property Keys As String()
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return arguments.Select(Function(v) v.Name).ToArray
End Get
End Property
''' <summary>
''' The parameters in the commandline without the first token of the command name.
''' (将命令行解析为词元之后去掉命令的名称之后所剩下的所有的字符串列表)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<DumpNode> Public ReadOnly Property Parameters As String()
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return Tokens.Skip(1).ToArray
End Get
End Property
''' <summary>
''' 对于参数而言,都是--或者-或者/或者\开头的,下一个单词为单引号或者非上面的字符开头的,例如/o &lt;path>
''' 对于开关而言,与参数相同的其实符号,但是后面不跟参数而是其他的开关,通常开关用来进行简要表述一个逻辑值
''' </summary>
''' <returns></returns>
Public Property BoolFlags As String()
''' <summary>
''' 获取得到通过``/@set``参数所传入的环境变量
''' </summary>
''' <returns></returns>
Public ReadOnly Property EnvironmentVariables As Dictionary(Of String, String)
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
' 在命令行之中没有任何其他的参数,但是存在一个/@set的话这个标记会被当作为命令名称
' 则在读取环境变量的时候就会失败
If Name.TextEquals("/@set") Then
Return DictionaryParser.TryParse(Parameters(Scan0))
Else
Return GetDictionary("/@set")
End If
End Get
End Property
''' <summary>
''' Get the original command line string.(获取所输入的命令行对象的原始的字符串)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property cli As String
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return cliCommandArgvs
End Get
End Property
''' <summary>
''' The parameter name is not case sensitive.
''' (开关的名称是不区分大小写的,进行字符串插值脚本化处理的时候,是使用的<see cref="App.GetVariable"/>函数来获取环境变量值)
''' </summary>
''' <param name="paramName">
''' The argument name in the commandline.
'''
''' ##### 2018-09-10
''' 为了兼容VB的!字典取值语法,这个属性是会自动处理开关参数的前缀的
''' 即会自动的将开关参数的/\--等前缀删除尝试进行取值
''' 这个自动转换不会应用于逻辑开关参数上面
''' </param>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Default Public ReadOnly Property Item(paramName As String) As DefaultString
Get
Dim LQuery As NamedValue(Of String) = arguments _
.Where(Function(a)
Return a.Name.TextEquals(paramName) OrElse
a.Name.DoCall(AddressOf TrimNamePrefix) _
.TextEquals(paramName)
End Function) _
.FirstOrDefault
' 是值类型,不会出现空引用的情况
Dim value As String = LQuery.Value
If value.StringEmpty Then
' 2018-1-22
'
' 如果是需要获取逻辑值的话直接查找__arguments值列表是获取不到结果的
' 在这里使用IsTrue来判断如果开关存在则返回TRUE字符串
' 否则返回空字符串表示不存在
If HavebFlag(paramName) Then
value = "TRUE"
Else
value = ""
End If
Else
' 尝试进行字符串插值,从而实现命令行部分脚本化
' 2017-3-13
' 对于Windows文件路径而言 不推荐转义
' 因为Windows的文件路径分隔符为\很容易引起误解例如C:\tsv会被误转义为C:<TAB>sv而导致错误
' 所以在这里关闭escape参数选项
value = value.Interpolate(environment, escape:=False)
End If
Return New DefaultString(value)
End Get
End Property
ReadOnly environment As Func(Of String, String) = AddressOf App.GetVariable
Public Property SingleValue As String
''' <summary>
''' See if the target logical flag argument is exists in the commandline?
''' (查看命令行之中是否存在某一个逻辑开关)
''' </summary>
''' <param name="name"></param>
''' <returns></returns>
Public Function HavebFlag(name As String) As Boolean
If Me.BoolFlags.IsNullOrEmpty Then
Return False
Else
' boolflags 已经全部都被转换为小写形式了
Return Array.IndexOf(BoolFlags, name.ToLower) > -1
End If
End Function
''' <summary>
''' Returns the original cli command line argument string.(返回所传入的命令行的原始字符串)
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Overrides Function ToString() As String
Return cliCommandArgvs
End Function
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Function TrimNamePrefix(argName As String) As String
Return argName.Trim("\", "/", "-")
End Function
''' <summary>
''' Get specific argument value as full directory path.
''' </summary>
''' <param name="name">parameter name</param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetFullDIRPath(name As String) As String
Return FileIO.FileSystem.GetDirectoryInfo(Me(name)).FullName
End Function
''' <summary>
''' Get specific argument value as full file path.(这个函数还会同时修正file://协议的头部)
''' </summary>
''' <param name="name">parameter name</param>
''' <returns></returns>
Public Function GetFullFilePath(name As String) As String
Dim path$ = Me(name)
path = FixPath(path)
Return FileIO.FileSystem.GetFileInfo(path).FullName
End Function
''' <summary>
''' Gets the brief summary information of current cli command line object.
''' (获取当前的命令行对象的参数摘要信息)
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function GetCommandsOverview() As String
Dim sb As New StringBuilder(vbCrLf, 1024)
Call sb.AppendLine($"Commandline arguments overviews{vbCrLf}Command Name -- ""{Me.Name}""")
Call sb.AppendLine()
Call sb.AppendLine("---------------------------------------------------------")
Call sb.AppendLine()
If arguments.Count = 0 Then
Call sb.AppendLine("No parameter was define in this commandline.")
Return sb.ToString
End If
Dim MaxSwitchName As Integer = (From item As NamedValue(Of String)
In arguments
Select Len(item.Name)).Max
For Each sw As NamedValue(Of String) In arguments
Call sb.AppendLine($" {sw.Name} {New String(" "c, MaxSwitchName - Len(sw.Name))}= ""{sw.Value}"";")
Next
Return sb.ToString
End Function
''' <summary>
''' Checking for the missing required parameter, this function will returns the missing parameter
''' in the current cli command line object using a specific parameter name list.
''' (检查<paramref name="list"></paramref>之中的所有参数是否存在,函数会返回不存在的参数名)
''' </summary>
''' <param name="list"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function CheckMissingRequiredParameters(list As IEnumerable(Of String)) As String()
Dim LQuery$() = LinqAPI.Exec(Of String) _
_
() <= From p As String
In list
Where String.IsNullOrEmpty(Me(p))
Select p
Return LQuery
End Function
''' <summary>
''' Gets a list of missing required argument name.
''' </summary>
''' <param name="args"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function CheckMissingRequiredArguments(ParamArray args As String()) As String()
Return CheckMissingRequiredParameters(list:=args)
End Function
''' <summary>
''' Does this cli command line object contains any parameter argument information.
''' (查看本命令行参数对象之中是否存在有参数信息)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property IsNullOrEmpty As Boolean
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return Tokens.IsNullOrEmpty OrElse (Tokens.Length = 1 AndAlso String.IsNullOrEmpty(Tokens.First))
End Get
End Property
''' <summary>
''' <see cref="String.IsNullOrEmpty"/> of <see cref="Name"/> AndAlso <see cref="IsNullOrEmpty"/>
''' </summary>
''' <returns></returns>
Public ReadOnly Property IsNothing As Boolean
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return String.IsNullOrEmpty(Me.Name) AndAlso IsNullOrEmpty
End Get
End Property
''' <summary>
''' Does the specific argument exists in this commandline? argument name is not case sensitity.
''' (参数名称字符串大小写不敏感)
''' </summary>
''' <param name="parameterName"></param>
''' <returns></returns>
Public Function ContainsParameter(parameterName As String, Optional trim As Boolean = False) As Boolean
Dim namer As String = If(trim, parameterName.TrimParamPrefix, parameterName)
Dim LQuery = LinqAPI.DefaultFirst(Of Integer) _
_
() <= From para As NamedValue(Of String)
In Me.arguments ' 名称都是没有处理过的
Where String.Equals(namer, para.Name, StringComparison.OrdinalIgnoreCase)
Select 100
Return LQuery > 50
End Function
''' <summary>
''' Parsing the commandline string as object model
''' </summary>
''' <param name="CommandLine"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Widening Operator CType(CommandLine As String) As CommandLine
Return TryParse(CommandLine)
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Widening Operator CType(CLI As Func(Of String)) As CommandLine
Return TryParse(CLI())
End Operator
''' <summary>
''' Determined that the specific Boolean flag is exists or not?
''' if not then returns <paramref name="failure"/>, if exists such flag, then returns the <paramref name="name"/>.
''' </summary>
''' <param name="name">Boolean flag name</param>
''' <param name="failure"></param>
''' <returns></returns>
Public Function Assert(name As String, Optional failure As String = "") As String
If GetBoolean(name) Then
Return name
Else
Return failure
End If
End Function
''' <summary>
''' If the target parameter is not presents in the CLI, then this function will returns nothing.
''' (键值对之间使用分号分隔)
''' </summary>
''' <param name="name$"></param>
''' <returns></returns>
Public Function GetDictionary(name$, Optional default$ = Nothing) As Dictionary(Of String, String)
Dim s$ = Me(name$)
If String.IsNullOrEmpty(s$) Then
If [default].StringEmpty Then
Return Nothing
Else
Return DictionaryParser.TryParse([default])
End If
Else
Return DictionaryParser.TryParse(s$)
End If
End Function
Public Function IsTrue(parameter$) As Boolean
If Me.HavebFlag(parameter) Then
Return True
End If
Return Me(parameter).DefaultValue.ParseBoolean
End Function
#Region "Pipeline"
''' <summary>About <paramref name="s"/>:
'''
''' + If the file path is not a value path, then is the value is not null, the argument value will be returned from this parameter.
''' + If the value is nothing, then this function will open the standard input as input.
''' + If the file path is valid as input file, then a local file system pointer will be returned.
'''
''' [管道函数] 假若参数名存在并且所指向的文件也存在,则返回本地文件的文件指针,否则返回标准输入的指针
''' </summary>
''' <param name="param"></param>
''' <param name="s">
''' + If the file path is not a value path, then is the value is not null, the argument value will be returned from this parameter.
''' + If the value is nothing, then this function will open the standard input as input.
''' + If the file path is valid as input file, then a local file system pointer will be returned.
''' </param>
''' <returns></returns>
Public Function OpenStreamInput(param As String, Optional ByRef s As String = Nothing) As StreamReader
Dim path As String = Me(param)
Dim type As FileTypes = StreamExtensions.FileType(path)
Select Case type
Case FileTypes.MemoryFile, FileTypes.PipelineFile
Return New StreamReader(StreamExtensions.OpenForRead(path))
Case Else
If path.FileExists Then
Return New StreamReader(New FileStream(path, FileMode.Open, access:=FileAccess.Read))
ElseIf Not String.IsNullOrEmpty(path) Then
s = path
Return Nothing
Else
Return New StreamReader(Console.OpenStandardInput)
End If
End Select
End Function
''' <summary>
''' If the <see cref="StreamWriter.BaseStream"/> is <see cref="FileStream"/>, then it means not a ``std_out`` pointer.
''' ([管道函数] 假若参数名存在,则返回本地文件的文件指针,否则返回标准输出的指针)
''' </summary>
''' <param name="param"></param>
''' <returns></returns>
Public Function OpenStreamOutput(param$, Optional encoding As Encodings = Encodings.UTF8, Optional size& = 512 * 1024 * 1024) As StreamWriter
Dim path$ = Me(param)
Dim type As FileTypes = StreamExtensions.FileType(path)
Select Case type
Case FileTypes.MemoryFile, FileTypes.PipelineFile
Return New StreamWriter(StreamExtensions.OpenForWrite(path, size))
Case Else
If path.StringEmpty Then
Return New StreamWriter(Console.OpenStandardOutput, encoding.CodePage)
Else
Return path.OpenWriter(encoding)
End If
End Select
End Function
''' <summary>
''' Read all of the text input from the file or ``std_in``
''' </summary>
''' <remarks>
''' 这个函数会首先尝试使用<see cref="OpenStreamInput"/>打开本地文件和标准输出流
''' 如果失败的话<see cref="OpenStreamInput"/>函数会返回空值,这个时候参数字符串将会直接被
''' 返回作为结果,如果打开成功的话,会将得到的输入流之中的所有字符串读出来返回
''' </remarks>
''' <param name="param"></param>
''' <returns></returns>
Public Function ReadInput(param As String) As String
Dim s As String = Nothing
Dim read As StreamReader = OpenStreamInput(param, s)
If read Is Nothing Then
Return s
Else
Return read.ReadToEnd
End If
End Function
#End Region
#Region "IDataRecord Methods"
''' <summary>
''' Gets the value Of the specified column As a Boolean.
''' (这个函数也同时包含有开关参数的开关参数默认为逻辑值类型当包含有开关参数的时候其逻辑值为True反之函数会检查参数列表参数不存在则为空值字符串则也为False)
''' </summary>
''' <param name="parameter">可以包含有开关参数</param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetBoolean(parameter As String) As Boolean
Return Me.IsTrue(parameter)
End Function
''' <summary>
''' Gets the 8-bit unsigned Integer value Of the specified column.
''' </summary>
''' <param name="parameter"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetByte(parameter As String) As Byte
Return CByte(Val(Me(parameter)))
End Function
''' <summary>
''' Reads a stream Of bytes from the specified column offset into the buffer As an array, starting at the given buffer offset.
''' </summary>
''' <returns></returns>
Public Function GetBytes(parameter As String) As Byte()
Dim tokens As String() = Me(parameter).DefaultValue.Split(","c)
Return (From s As String In tokens Select CByte(Val(s))).ToArray
End Function
''' <summary>
''' Gets the character value Of the specified column.
''' </summary>
''' <returns></returns>
Public Function GetChar(parameter As String) As Char
Dim s As String = Me(parameter)
If String.IsNullOrEmpty(s) Then
Return ASCII.NUL
Else
Return s.First
End If
End Function
''' <summary>
''' Reads a stream Of characters from the specified column offset into the buffer As an array, starting at the given buffer offset.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetChars(parameter As String) As Char()
Return Me(parameter)
End Function
''' <summary>
''' Gets the Date And time data value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetDateTime(parameter As String) As DateTime
Return Me(parameter).DefaultValue.ParseDateTime
End Function
''' <summary>
''' Gets the fixed-position numeric value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetDecimal(parameter As String) As Decimal
Return CDec(Val(Me(parameter).DefaultValue))
End Function
''' <summary>
''' Gets the Double-precision floating point number Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetDouble(parameter As String) As Double
Return Val(Me(parameter).DefaultValue)
End Function
''' <summary>
''' Gets the Single-precision floating point number Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetFloat(parameter As String) As Single
Return CSng(Val(Me(parameter).DefaultValue))
End Function
''' <summary>
''' Returns the GUID value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetGuid(parameter As String) As Guid
Return Guid.Parse(Me(parameter))
End Function
''' <summary>
''' Gets the 16-bit signed Integer value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetInt16(parameter As String) As Int16
Return CType(Val(Me(parameter).DefaultValue), Int16)
End Function
''' <summary>
''' Gets the 32-bit signed Integer value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetInt32(parameter As String) As Int32
Return CInt(Val(Me(parameter).DefaultValue))
End Function
''' <summary>
''' Gets the 64-bit signed Integer value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetInt64(parameter As String) As Int64
Return CLng(Val(Me(parameter).DefaultValue))
End Function
''' <summary>
''' Return the index Of the named field. If the name is not exists in the parameter list, then a -1 value will be return.
''' </summary>
''' <returns></returns>
Public Function GetOrdinal(parameter As String) As Integer
Dim i% = LinqAPI.DefaultFirst(Of Integer)(-1) _
_
<= From entry As NamedValue(Of String)
In Me.arguments
Where String.Equals(parameter, entry.Name, StringComparison.OrdinalIgnoreCase)
Select arguments.IndexOf(entry)
Return i
End Function
''' <summary>
''' Gets the String value Of the specified field.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function GetString(parameter As String) As String
Return Me(parameter)
End Function
''' <summary>
''' Return whether the specified field Is Set To null.
''' </summary>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function IsNull(parameter As String) As Boolean
Return Not Me.ContainsParameter(parameter, False)
End Function
''' <summary>
'''
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="parameter">Command parameter name in the command line inputs.</param>
''' <param name="__getObject"></param>
''' <returns></returns>
Public Function GetObject(Of T)(parameter$, Optional __getObject As Func(Of String, T) = Nothing) As T
Dim value$ = Me(parameter)
Dim obj = (__getObject Or StringParser(GetType(T)))(arg:=value)
Dim x As T = DirectCast(obj, T)
Return x
End Function
''' <summary>
''' If the given parameter is not exists in the user input arguments, then a developer specific default value will be return.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="name">The optional argument parameter name</param>
''' <param name="[default]">The default value for returns when the parameter is not exists in the user input.</param>
''' <param name="cast">The custom string parser for the CLI argument value</param>
''' <returns></returns>
Public Function GetValue(Of T)(name$, [default] As T, Optional cast As Func(Of String, T) = Nothing) As T
If Not Me.ContainsParameter(name, False) Then
If GetType(T).Equals(GetType(Boolean)) Then
If HavebFlag(name) Then
Return DirectCast(DirectCast(GetBoolean(name), Object), T)
End If
End If
Return [default]
End If
Dim str As String = Me(name).DefaultValue
If cast Is Nothing Then
Dim value As Object = InputHandler.CTypeDynamic(str, GetType(T))
Return DirectCast(value, T)
Else
Return cast(str)
End If
End Function
''' <summary>
''' Open a file handle by using the parameter value
''' </summary>
''' <param name="name">The parameter name, and its argument value should be a valid file path</param>
''' <param name="[default]">Default file path if the argument value is not exists</param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function OpenHandle(name$, Optional default$ = "", Optional encoding As Encodings = Encodings.UTF8) As i32
Return My.File.OpenHandle(Me(name) Or [default].AsDefault, encoding)
End Function
#End Region
#Region "Implements IReadOnlyCollection(Of KeyValuePair(Of String, String))"
''' <summary>
''' 这个枚举函数也会将开关给包含进来,与<see cref="ToArgumentVector"/>方法所不同的是,这个函数里面的逻辑值开关的名称没有被修饰剪裁
''' </summary>
''' <returns></returns>
Public Iterator Function GetEnumerator() As IEnumerator(Of NamedValue(Of String)) Implements IEnumerable(Of NamedValue(Of String)).GetEnumerator
Dim source As New List(Of NamedValue(Of String))(Me.arguments)
If Not Me.BoolFlags.IsNullOrEmpty Then
source += From name As String
In BoolFlags
Select New NamedValue(Of String)(name, "true")
End If
For Each x As NamedValue(Of String) In source
Yield x
Next
End Function
Public Iterator Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Yield GetEnumerator()
End Function
''' <summary>
''' Adds an item to the System.Collections.Generic.ICollection`1.
''' </summary>
''' <param name="item"></param>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Sub Add(item As NamedValue(Of String)) Implements ICollection(Of NamedValue(Of String)).Add
Call arguments.Add(item)
End Sub
''' <summary>
''' Add a parameter with name and its value.
''' </summary>
''' <param name="key"></param>
''' <param name="value"></param>
Public Sub Add(key$, value$,
Optional allowDuplicated As Boolean = False,
<CallerMemberName> Optional stack$ = Nothing)
Dim item As New NamedValue(Of String) With {
.Name = key.ToLower,
.Value = value,
.Description = stack & "->" & NameOf(Add)
}
If Not allowDuplicated Then
For i As Integer = 0 To arguments.Count - 1
With arguments(i)
If .Name.TextEquals(key) Then
arguments(i) = item
Return
End If
End With
Next
' 没有查找到需要被替换掉的下标,则直接在下面的代码之中进行添加
End If
arguments += item
End Sub
''' <summary>
''' Clear the inner list buffer
''' </summary>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Sub Clear() Implements ICollection(Of NamedValue(Of String)).Clear
Call arguments.Clear()
End Sub
''' <summary>
''' 只是通过比较名称来判断是否存在,值没有进行比较
''' </summary>
''' <param name="item"></param>
''' <returns></returns>
Public Function Contains(item As NamedValue(Of String)) As Boolean Implements ICollection(Of NamedValue(Of String)).Contains
Dim LQuery% = LinqAPI.DefaultFirst(-1) _
_
<= From obj As NamedValue(Of String)
In Me.arguments
Where String.Equals(obj.Name, item.Name, StringComparison.OrdinalIgnoreCase)
Select 100
Return LQuery > 50
End Function
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Sub CopyTo(array() As NamedValue(Of String), arrayIndex As Integer) Implements ICollection(Of NamedValue(Of String)).CopyTo
Call arguments.ToArray.CopyTo(array, arrayIndex)
End Sub
''' <summary>
''' Get the switch counts in this commandline object.(获取本命令行对象中的所定义的开关的数目)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Count As Integer Implements ICollection(Of NamedValue(Of String)).Count
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return Me.arguments.Count
End Get
End Property
Private ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of NamedValue(Of String)).IsReadOnly
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return True
End Get
End Property
''' <summary>
''' Removes a parameter by name
''' </summary>
''' <param name="paramName"></param>
''' <returns></returns>
Public Function Remove(paramName As String) As Boolean
Dim LQuery = LinqAPI.DefaultFirst(Of NamedValue(Of String)) _
_
() <= From obj As NamedValue(Of String)
In Me.arguments
Where String.Equals(obj.Name, paramName, StringComparison.OrdinalIgnoreCase)
Select obj
If LQuery.IsEmpty Then
Return False
Else
Call arguments.Remove(LQuery)
Return True
End If
End Function
''' <summary>
''' Removes a parameter by <see cref="NamedValue(Of String).Name"/>
''' </summary>
''' <param name="item"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function Remove(item As NamedValue(Of String)) As Boolean Implements ICollection(Of NamedValue(Of String)).Remove
Return Remove(item.Name)
End Function
#End Region
''' <summary>
''' 将当前的这个命令行对象之中的所有的参数值都合并到一个向量之中返回.
''' (``ToArray``拓展好像是有BUG的所以请使用这个函数来获取所有的参数信息。
''' 请注意,逻辑值开关的名称会被去掉前缀)
''' </summary>
''' <returns></returns>
Public Function ToArgumentVector() As NamedValue(Of String)()
Dim list As New List(Of NamedValue(Of String))
list += From arg As NamedValue(Of String)
In arguments.SafeQuery
Select New NamedValue(Of String) With {
.Name = arg.Name,
.Value = arg.Value
}
list += From bs As String
In BoolFlags.SafeQuery
Select New NamedValue(Of String) With {
.Name = bs,
.Value = "True"
}
Return list
End Function
''' <summary>
''' Open a handle for a file system object.
''' </summary>
''' <param name="args"></param>
''' <param name="fs"></param>
''' <returns></returns>
Public Overloads Shared Operator +(args As CommandLine, fs$) As Integer
Dim path As String = args(fs)
Return My.File.OpenHandle(path)
End Operator
''' <summary>
''' Gets the CLI parameter value.
''' </summary>
''' <param name="args"></param>
''' <param name="name"></param>
''' <returns></returns>
Public Overloads Shared Operator <=(args As CommandLine, name$) As String
If args Is Nothing Then
Return Nothing
Else
Return args(name)
End If
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Operator <=(opt As String, args As CommandLine) As CommandLine
Return TryParse(args(opt))
End Operator
Public Shared Operator ^(args As CommandLine, [default] As String) As String
If args Is Nothing OrElse String.IsNullOrEmpty(args.cliCommandArgvs) Then
Return [default]
Else
Return args.cliCommandArgvs
End If
End Operator
Public Shared Operator >=(opt As String, args As CommandLine) As CommandLine
Throw New NotSupportedException
End Operator
''' <summary>
''' Try get parameter value.
''' </summary>
''' <param name="args"></param>
''' <param name="name"></param>
''' <returns></returns>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Overloads Shared Operator -(args As CommandLine, name As String) As String
Return args(name)
End Operator
''' <summary>
''' Try get parameter value.
''' </summary>
''' <param name="args"></param>
''' <returns></returns>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Overloads Shared Operator -(args As CommandLine, null As CommandLine) As CommandLine
Return args
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Overloads Shared Operator -(args As CommandLine, name As IEnumerable(Of String)) As String
Return args.GetValue(name.First, name.Last)
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Operator -(args As CommandLine) As CommandLine
Return args
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Operator >(args As CommandLine, name As String) As String
Return args(name)
End Operator
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Shared Operator <(args As CommandLine, name As String) As String
Return args(name)
End Operator
Public Shared Operator >=(args As CommandLine, name As String) As String
Throw New NotSupportedException
End Operator
End Class
End Namespace