1 #Region "Microsoft.VisualBasic::fbbb4af951ee7f357716c975b2a40855, Microsoft.VisualBasic.Core\CommandLine\CommandLine.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Class CommandLine
35     
36     '         Properties: BoolFlags, cli, Count, EnvironmentVariables, IsNothing
37     '                     IsNullOrEmpty, IsReadOnly, Keys, Name, ParameterList
38     '                     Parameters, SingleValue, Tokens
39     
40     '         FunctionAssert, CheckMissingRequiredArguments, CheckMissingRequiredParameters, Contains, ContainsParameter
41     '                   GetBoolean, GetByte, GetBytes, GetChar, GetChars
42     '                   GetCommandsOverview, GetDateTime, GetDecimal, GetDictionary, GetDouble
43     '                   GetEnumerator, GetEnumerator1, GetFloat, GetFullDIRPath, GetFullFilePath
44     '                   GetGuid, GetInt16, GetInt32, GetInt64, GetObject
45     '                   GetOrdinal, GetString, GetValue, HavebFlag, IsNull
46     '                   IsTrue, OpenHandle, OpenStreamInput, OpenStreamOutput, ReadInput
47     '                   (+2 Overloads) Remove, ToArgumentVector, ToString
48     
49     '         Sub: (+2 Overloads) Add, Clear, CopyTo
50     
51     '         Operators: (+4 Overloads) -, ^, +, <, (+2 Overloads) <=
52     '                    >, (+2 Overloads) >=
53     
54     
55     ' /********************************************************************************/
56
57 #End Region
58
59 Imports System.IO
60 Imports System.Runtime.CompilerServices
61 Imports System.Text
62 Imports Microsoft.VisualBasic.CommandLine.Parsers
63 Imports Microsoft.VisualBasic.ComponentModel.Collection.Generic
64 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
65 Imports Microsoft.VisualBasic.Language
66 Imports Microsoft.VisualBasic.Language.Default
67 Imports Microsoft.VisualBasic.Language.UnixBash.FileSystem
68 Imports Microsoft.VisualBasic.Linq
69 Imports Microsoft.VisualBasic.Scripting
70 Imports Microsoft.VisualBasic.Scripting.Expressions
71 Imports Microsoft.VisualBasic.Serialization
72 Imports Microsoft.VisualBasic.Text
73
74 Namespace CommandLine
75
76     ''' <summary>
77     ''' A command line object that parse from the user input commandline string.
78     ''' (从用户所输入的命令行字符串之中解析出来的命令行对象,标准的命令行格式为:
79     ''' <example>&lt;EXE> &lt;CLI_Name> ["Parameter" "Value"]</example>)
80     ''' </summary>
81     ''' <remarks></remarks>
82     '''
83     Public Class CommandLine : Inherits BaseClass
84         Implements ICollection(Of NamedValue(Of String))
85         Implements INamedValue
86
87         Friend __arguments As New List(Of NamedValue(Of String))
88         ''' <summary>
89         ''' 原始的命令行字符串
90         ''' </summary>
91         Friend cliCommandArgvs As String
92
93         Dim _name As String
94
95         ''' <summary>
96         ''' The command name that parse from the input command line.
97         ''' (从输入的命令行中所解析出来的命令的名称)
98         ''' </summary>
99         ''' <value></value>
100         ''' <returns></returns>
101         ''' <remarks></remarks>
102         Public Property Name As String Implements INamedValue.Key
103             <MethodImpl(MethodImplOptions.AggressiveInlining)>
104             Get
105                 Return _name
106             End Get
107             Protected Friend Set(value As String)
108                 _name = value
109             End Set
110         End Property
111
112         ''' <summary>
113         ''' The command tokens that were parsed from the input commandline.
114         ''' (从所输入的命令行之中所解析出来的命令参数单元)
115         ''' </summary>
116         ''' <value></value>
117         ''' <returns></returns>
118         ''' <remarks></remarks>
119         Public Property Tokens As String()
120
121         ''' <summary>
122         ''' Listing all of the parameter value collection that parsed from the commandline string.
123         ''' </summary>
124         ''' <returns></returns>
125         Public ReadOnly Property ParameterList As NamedValue(Of String)()
126             <MethodImpl(MethodImplOptions.AggressiveInlining)>
127             Get
128                 Return __arguments.ToArray
129             End Get
130         End Property
131
132         ''' <summary>
133         ''' 得到当前的命令行对象之中的所有的参数的名称的列表
134         ''' </summary>
135         ''' <returns></returns>
136         Public ReadOnly Property Keys As String()
137             <MethodImpl(MethodImplOptions.AggressiveInlining)>
138             Get
139                 Return __arguments.Select(Function(v) v.Name).ToArray
140             End Get
141         End Property
142
143         ''' <summary>
144         ''' The parameters in the commandline without the first token of the command name.
145         ''' (将命令行解析为词元之后去掉命令的名称之后所剩下的所有的字符串列表)
146         ''' </summary>
147         ''' <value></value>
148         ''' <returns></returns>
149         ''' <remarks></remarks>
150         <DumpNode> Public ReadOnly Property Parameters As String()
151             <MethodImpl(MethodImplOptions.AggressiveInlining)>
152             Get
153                 Return Tokens.Skip(1).ToArray
154             End Get
155         End Property
156
157         ''' <summary>
158         ''' 对于参数而言,都是--或者-或者/或者\开头的,下一个单词为单引号或者非上面的字符开头的,例如/o &lt;path>
159         ''' 对于开关而言,与参数相同的其实符号,但是后面不跟参数而是其他的开关,通常开关用来进行简要表述一个逻辑值
160         ''' </summary>
161         ''' <returns></returns>
162         Public Property BoolFlags As String()
163
164         ''' <summary>
165         ''' 获取得到通过``/@set``参数所传入的环境变量
166         ''' </summary>
167         ''' <returns></returns>
168         Public ReadOnly Property EnvironmentVariables As Dictionary(Of StringString)
169             <MethodImpl(MethodImplOptions.AggressiveInlining)>
170             Get
171                 ' 在命令行之中没有任何其他的参数,但是存在一个/@set的话,这个标记会被当作为命令名称
172                 ' 则在读取环境变量的时候就会失败
173                 If Name.TextEquals("/@set"Then
174                     Return DictionaryParser.TryParse(Parameters(Scan0))
175                 Else
176                     Return GetDictionary("/@set")
177                 End If
178             End Get
179         End Property
180
181         ''' <summary>
182         ''' Get the original command line string.(获取所输入的命令行对象的原始的字符串)
183         ''' </summary>
184         ''' <value></value>
185         ''' <returns></returns>
186         ''' <remarks></remarks>
187         Public ReadOnly Property cli As String
188             <MethodImpl(MethodImplOptions.AggressiveInlining)>
189             Get
190                 Return cliCommandArgvs
191             End Get
192         End Property
193
194         ''' <summary>
195         ''' The parameter name is not case sensitive.
196         ''' (开关的名称是不区分大小写的,进行字符串插值脚本化处理的时候,是使用的<see cref="App.GetVariable"/>函数来获取环境变量值)
197         ''' </summary>
198         ''' <param name="paramName">
199         ''' The argument name in the commandline.
200         ''' 
201         ''' ##### 2018-09-10 
202         ''' 为了兼容VB的!字典取值语法,这个属性是会自动处理开关参数的前缀的
203         ''' 即会自动的将开关参数的/\--等前缀删除尝试进行取值
204         ''' 这个自动转换不会应用于逻辑开关参数上面
205         ''' </param>
206         ''' <value></value>
207         ''' <returns></returns>
208         ''' <remarks></remarks>
209         Default Public ReadOnly Property Item(paramName As StringAs DefaultString
210             Get
211                 Dim LQuery As NamedValue(Of String) =
212                     __arguments _
213                         .Where(Function(x)
214                                    Return String.Equals(x.Name, paramName, StringComparison.OrdinalIgnoreCase) OrElse
215                                           String.Equals(x.Name.Trim("\""/""-"), paramName, StringComparison.OrdinalIgnoreCase)
216                                End Function) _
217                         .FirstOrDefault
218                 ' 是值类型,不会出现空引用的情况
219                 Dim value As String = LQuery.Value
220
221                 If value.StringEmpty Then
222                     ' 2018-1-22
223                     '
224                     ' 如果是需要获取逻辑值的话,直接查找__arguments值列表是获取不到结果的
225                     ' 在这里使用IsTrue来判断,如果开关存在则返回TRUE字符串
226                     ' 否则返回空字符串表示不存在
227
228                     If HavebFlag(paramName) Then
229                         value = "TRUE"
230                     Else
231                         value = ""
232                     End If
233                 Else
234                     ' 尝试进行字符串插值,从而实现命令行部分脚本化
235
236                     ' 2017-3-13
237                     ' 对于Windows文件路径而言, 不推荐转义
238                     ' 因为Windows的文件路径分隔符为\,很容易引起误解,例如C:\tsv会被误转义为C:<TAB>sv而导致错误
239                     ' 所以在这里关闭escape参数选项
240                     value = value.Interpolate(__envir, escape:=False)
241                 End If
242
243                 Return New DefaultString(value)
244             End Get
245         End Property
246
247         ReadOnly __envir As Func(Of StringString) = AddressOf App.GetVariable
248
249         Public Property SingleValue As String
250
251         ''' <summary>
252         ''' See if the target logical flag argument is exists in the commandline?
253         ''' (查看命令行之中是否存在某一个逻辑开关)
254         ''' </summary>
255         ''' <param name="name"></param>
256         ''' <returns></returns>
257         Public Function HavebFlag(name As StringAs Boolean
258             If Me.BoolFlags.IsNullOrEmpty Then
259                 Return False
260             Else
261                 ' boolflags 已经全部都被转换为小写形式了
262                 Return Array.IndexOf(BoolFlags, name.ToLower) > -1
263             End If
264         End Function
265
266         ''' <summary>
267         ''' Returns the original cli command line argument string.(返回所传入的命令行的原始字符串)
268         ''' </summary>
269         ''' <returns></returns>
270         ''' <remarks></remarks>
271         ''' 
272         <MethodImpl(MethodImplOptions.AggressiveInlining)>
273         Public Overrides Function ToString() As String
274             Return CLICommandArgvs
275         End Function
276
277         ''' <summary>
278         ''' Get specific argument value as full directory path.
279         ''' </summary>
280         ''' <param name="name">parameter name</param>
281         ''' <returns></returns>
282         ''' 
283         <MethodImpl(MethodImplOptions.AggressiveInlining)>
284         Public Function GetFullDIRPath(name As StringAs String
285             Return FileIO.FileSystem.GetDirectoryInfo(Me(name)).FullName
286         End Function
287
288         ''' <summary>
289         ''' Get specific argument value as full file path.(这个函数还会同时修正file://协议的头部)
290         ''' </summary>
291         ''' <param name="name">parameter name</param>
292         ''' <returns></returns>
293         Public Function GetFullFilePath(name As StringAs String
294             Dim path$ = Me(name)
295             path = FixPath(path)
296             Return FileIO.FileSystem.GetFileInfo(path).FullName
297         End Function
298
299         ''' <summary>
300         ''' Gets the brief summary information of current cli command line object.
301         ''' (获取当前的命令行对象的参数摘要信息)
302         ''' </summary>
303         ''' <returns></returns>
304         ''' <remarks></remarks>
305         Public Function GetCommandsOverview() As String
306             Dim sb As New StringBuilder(vbCrLf, 1024)
307             Call sb.AppendLine($"Commandline arguments overviews{vbCrLf}Command Name  --  ""{Me.Name}""")
308             Call sb.AppendLine()
309             Call sb.AppendLine("---------------------------------------------------------")
310             Call sb.AppendLine()
311
312             If __arguments.Count = 0 Then
313                 Call sb.AppendLine("No parameter was define in this commandline.")
314                 Return sb.ToString
315             End If
316
317             Dim MaxSwitchName As Integer = (From item As NamedValue(Of String)
318                                             In __arguments
319                                             Select Len(item.Name)).Max
320             For Each sw As NamedValue(Of StringIn __arguments
321                 Call sb.AppendLine($"  {sw.Name}  {New String(" "c, MaxSwitchName - Len(sw.Name))}= ""{sw.Value}"";")
322             Next
323
324             Return sb.ToString
325         End Function
326
327         ''' <summary>
328         ''' Checking for the missing required parameter, this function will returns the missing parameter
329         ''' in the current cli command line object using a specific parameter name list.
330         ''' (检查<paramref name="list"></paramref>之中的所有参数是否存在,函数会返回不存在的参数名)
331         ''' </summary>
332         ''' <param name="list"></param>
333         ''' <returns></returns>
334         ''' <remarks></remarks>
335         Public Function CheckMissingRequiredParameters(list As IEnumerable(Of String)) As String()
336             Dim LQuery$() = LinqAPI.Exec(Of String) _
337  _
338                 () <= From p As String
339                       In list
340                       Where String.IsNullOrEmpty(Me(p))
341                       Select p
342
343             Return LQuery
344         End Function
345
346         ''' <summary>
347         ''' Gets a list of missing required argument name.
348         ''' </summary>
349         ''' <param name="args"></param>
350         ''' <returns></returns>
351         ''' 
352         <MethodImpl(MethodImplOptions.AggressiveInlining)>
353         Public Function CheckMissingRequiredArguments(ParamArray args As String()) As String()
354             Return CheckMissingRequiredParameters(list:=args)
355         End Function
356
357         ''' <summary>
358         ''' Does this cli command line object contains any parameter argument information.
359         ''' (查看本命令行参数对象之中是否存在有参数信息)
360         ''' </summary>
361         ''' <value></value>
362         ''' <returns></returns>
363         ''' <remarks></remarks>
364         Public ReadOnly Property IsNullOrEmpty As Boolean
365             <MethodImpl(MethodImplOptions.AggressiveInlining)>
366             Get
367                 Return Tokens.IsNullOrEmpty OrElse (Tokens.Length = 1 AndAlso String.IsNullOrEmpty(Tokens.First))
368             End Get
369         End Property
370
371         ''' <summary>
372         ''' <see cref="String.IsNullOrEmpty"/> of <see cref="Name"/> AndAlso <see cref="IsNullOrEmpty"/>
373         ''' </summary>
374         ''' <returns></returns>
375         Public ReadOnly Property IsNothing As Boolean
376             <MethodImpl(MethodImplOptions.AggressiveInlining)>
377             Get
378                 Return String.IsNullOrEmpty(Me.Name) AndAlso IsNullOrEmpty
379             End Get
380         End Property
381
382         ''' <summary>
383         ''' Does the specific argument exists in this commandline? argument name is not case sensitity.
384         ''' (参数名称字符串大小写不敏感)
385         ''' </summary>
386         ''' <param name="parameterName"></param>
387         ''' <returns></returns>
388         Public Function ContainsParameter(parameterName As String, trim As BooleanAs Boolean
389             Dim namer As String = If(trim, parameterName.TrimParamPrefix, parameterName)
390             Dim LQuery = LinqAPI.DefaultFirst(Of Integer) _
391  _
392                 () <= From para As NamedValue(Of String)
393                       In Me.__arguments  '  名称都是没有处理过的
394                       Where String.Equals(namer, para.Name, StringComparison.OrdinalIgnoreCase)
395                       Select 100
396
397             Return LQuery > 50
398         End Function
399
400         ''' <summary>
401         ''' Parsing the commandline string as object model
402         ''' </summary>
403         ''' <param name="CommandLine"></param>
404         ''' <returns></returns>
405         ''' 
406         <MethodImpl(MethodImplOptions.AggressiveInlining)>
407         Public Shared Widening Operator CType(CommandLine As StringAs CommandLine
408             Return TryParse(CommandLine)
409         End Operator
410
411         <MethodImpl(MethodImplOptions.AggressiveInlining)>
412         Public Shared Widening Operator CType(CLI As Func(Of String)) As CommandLine
413             Return TryParse(CLI())
414         End Operator
415
416         ''' <summary>
417         ''' Determined that the specific Boolean flag is exists or not? 
418         ''' if not then returns <paramref name="failure"/>, if exists such flag, then returns the <paramref name="name"/>.
419         ''' </summary>
420         ''' <param name="name">Boolean flag name</param>
421         ''' <param name="failure"></param>
422         ''' <returns></returns>
423         Public Function Assert(name As StringOptional failure As String = ""As String
424             If GetBoolean(name) Then
425                 Return name
426             Else
427                 Return failure
428             End If
429         End Function
430
431         ''' <summary>
432         ''' If the target parameter is not presents in the CLI, then this function will returns nothing.
433         ''' (键值对之间使用分号分隔)
434         ''' </summary>
435         ''' <param name="name$"></param>
436         ''' <returns></returns>
437         Public Function GetDictionary(name$, Optional default$ = NothingAs Dictionary(Of StringString)
438             Dim s$ = Me(name$)
439
440             If String.IsNullOrEmpty(s$) Then
441                 If [default].StringEmpty Then
442                     Return Nothing
443                 Else
444                     Return DictionaryParser.TryParse([default])
445                 End If
446             Else
447                 Return DictionaryParser.TryParse(s$)
448             End If
449         End Function
450
451         Public Function IsTrue(parameter$) As Boolean
452             If Me.HavebFlag(parameter) Then
453                 Return True
454             End If
455             Return Me(parameter).DefaultValue.ParseBoolean
456         End Function
457
458 #Region "Pipeline"
459
460         ''' <summary>About <paramref name="s"/>:
461         ''' 
462         ''' + 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. 
463         ''' + If the value is nothing, then this function will open the standard input as input.
464         ''' + If the file path is valid as input file, then a local file system pointer will be returned.
465         ''' 
466         ''' [管道函数] 假若参数名存在并且所指向的文件也存在,则返回本地文件的文件指针,否则返回标准输入的指针
467         ''' </summary>
468         ''' <param name="param"></param>
469         ''' <param name="s">
470         ''' + 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. 
471         ''' + If the value is nothing, then this function will open the standard input as input.
472         ''' + If the file path is valid as input file, then a local file system pointer will be returned.
473         ''' </param>
474         ''' <returns></returns>
475         Public Function OpenStreamInput(param As StringOptional ByRef s As String = NothingAs StreamReader
476             Dim path As String = Me(param)
477
478             If path.FileExists Then
479                 Return New StreamReader(New FileStream(path, FileMode.Open, access:=FileAccess.Read))
480             ElseIf Not String.IsNullOrEmpty(path) Then
481                 s = path
482                 Return Nothing
483             Else
484                 Return New StreamReader(Console.OpenStandardInput)
485             End If
486         End Function
487
488         ''' <summary>
489         ''' If the <see cref="StreamWriter.BaseStream"/> is <see cref="FileStream"/>, then it means not a ``std_out`` pointer.
490         ''' ([管道函数] 假若参数名存在,则返回本地文件的文件指针,否则返回标准输出的指针)
491         ''' </summary>
492         ''' <param name="param"></param>
493         ''' <returns></returns>
494         Public Function OpenStreamOutput(param$, Optional encoding As Encodings = Encodings.UTF8) As StreamWriter
495             Dim path$ = Me(param)
496
497             If path.StringEmpty Then
498                 Return New StreamWriter(Console.OpenStandardOutput, encoding.CodePage)
499             Else
500                 Return path.OpenWriter(encoding)
501             End If
502         End Function
503
504         ''' <summary>
505         ''' Read all of the text input from the file or ``std_in``
506         ''' </summary>
507         ''' <remarks>
508         ''' 这个函数会首先尝试使用<see cref="OpenStreamInput"/>打开本地文件和标准输出流
509         ''' 如果失败的话<see cref="OpenStreamInput"/>函数会返回空值,这个时候参数字符串将会直接被
510         ''' 返回作为结果,如果打开成功的话,会将得到的输入流之中的所有字符串读出来返回
511         ''' </remarks>
512         ''' <param name="param"></param>
513         ''' <returns></returns>
514         Public Function ReadInput(param As StringAs String
515             Dim s As String = Nothing
516             Dim read As StreamReader = OpenStreamInput(param, s)
517
518             If read Is Nothing Then
519                 Return s
520             Else
521                 Return read.ReadToEnd
522             End If
523         End Function
524 #End Region
525
526 #Region "IDataRecord Methods"
527
528         ''' <summary>
529         ''' Gets the value Of the specified column As a Boolean.
530         ''' (这个函数也同时包含有开关参数的,开关参数默认为逻辑值类型,当包含有开关参数的时候,其逻辑值为True,反之函数会检查参数列表,参数不存在则为空值字符串,则也为False)
531         ''' </summary>
532         ''' <param name="parameter">可以包含有开关参数</param>
533         ''' <returns></returns>
534         ''' 
535         <MethodImpl(MethodImplOptions.AggressiveInlining)>
536         Public Function GetBoolean(parameter As StringAs Boolean
537             Return Me.IsTrue(parameter)
538         End Function
539
540         ''' <summary>
541         ''' Gets the 8-bit unsigned Integer value Of the specified column.
542         ''' </summary>
543         ''' <param name="parameter"></param>
544         ''' <returns></returns>
545         ''' 
546         <MethodImpl(MethodImplOptions.AggressiveInlining)>
547         Public Function GetByte(parameter As StringAs Byte
548             Return CByte(Val(Me(parameter)))
549         End Function
550
551         ''' <summary>
552         ''' Reads a stream Of bytes from the specified column offset into the buffer As an array, starting at the given buffer offset.
553         ''' </summary>
554         ''' <returns></returns>
555         Public Function GetBytes(parameter As StringAs Byte()
556             Dim tokens As String() = Me(parameter).DefaultValue.Split(","c)
557             Return (From s As String In tokens Select CByte(Val(s))).ToArray
558         End Function
559
560         ''' <summary>
561         ''' Gets the character value Of the specified column.
562         ''' </summary>
563         ''' <returns></returns>
564         Public Function GetChar(parameter As StringAs Char
565             Dim s As String = Me(parameter)
566
567             If String.IsNullOrEmpty(s) Then
568                 Return ASCII.NUL
569             Else
570                 Return s.First
571             End If
572         End Function
573
574         ''' <summary>
575         ''' Reads a stream Of characters from the specified column offset into the buffer As an array, starting at the given buffer offset.
576         ''' </summary>
577         ''' <returns></returns>
578         ''' 
579         <MethodImpl(MethodImplOptions.AggressiveInlining)>
580         Public Function GetChars(parameter As StringAs Char()
581             Return Me(parameter)
582         End Function
583
584         ''' <summary>
585         ''' Gets the Date And time data value Of the specified field.
586         ''' </summary>
587         ''' <returns></returns>
588         ''' 
589         <MethodImpl(MethodImplOptions.AggressiveInlining)>
590         Public Function GetDateTime(parameter As StringAs DateTime
591             Return Me(parameter).DefaultValue.ParseDateTime
592         End Function
593
594         ''' <summary>
595         ''' Gets the fixed-position numeric value Of the specified field.
596         ''' </summary>
597         ''' <returns></returns>
598         ''' 
599         <MethodImpl(MethodImplOptions.AggressiveInlining)>
600         Public Function GetDecimal(parameter As StringAs Decimal
601             Return CDec(Val(Me(parameter).DefaultValue))
602         End Function
603
604         ''' <summary>
605         ''' Gets the Double-precision floating point number Of the specified field.
606         ''' </summary>
607         ''' <returns></returns>
608         ''' 
609         <MethodImpl(MethodImplOptions.AggressiveInlining)>
610         Public Function GetDouble(parameter As StringAs Double
611             Return Val(Me(parameter).DefaultValue)
612         End Function
613
614         ''' <summary>
615         ''' Gets the Single-precision floating point number Of the specified field.
616         ''' </summary>
617         ''' <returns></returns>
618         ''' 
619         <MethodImpl(MethodImplOptions.AggressiveInlining)>
620         Public Function GetFloat(parameter As StringAs Single
621             Return CSng(Val(Me(parameter).DefaultValue))
622         End Function
623
624         ''' <summary>
625         ''' Returns the GUID value Of the specified field.
626         ''' </summary>
627         ''' <returns></returns>
628         ''' 
629         <MethodImpl(MethodImplOptions.AggressiveInlining)>
630         Public Function GetGuid(parameter As StringAs Guid
631             Return Guid.Parse(Me(parameter))
632         End Function
633
634         ''' <summary>
635         ''' Gets the 16-bit signed Integer value Of the specified field.
636         ''' </summary>
637         ''' <returns></returns>
638         ''' 
639         <MethodImpl(MethodImplOptions.AggressiveInlining)>
640         Public Function GetInt16(parameter As StringAs Int16
641             Return CType(Val(Me(parameter).DefaultValue), Int16)
642         End Function
643
644         ''' <summary>
645         ''' Gets the 32-bit signed Integer value Of the specified field.
646         ''' </summary>
647         ''' <returns></returns>
648         ''' 
649         <MethodImpl(MethodImplOptions.AggressiveInlining)>
650         Public Function GetInt32(parameter As StringAs Int32
651             Return CInt(Val(Me(parameter).DefaultValue))
652         End Function
653
654         ''' <summary>
655         ''' Gets the 64-bit signed Integer value Of the specified field.
656         ''' </summary>
657         ''' <returns></returns>
658         ''' 
659         <MethodImpl(MethodImplOptions.AggressiveInlining)>
660         Public Function GetInt64(parameter As StringAs Int64
661             Return CLng(Val(Me(parameter).DefaultValue))
662         End Function
663
664         ''' <summary>
665         ''' Return the index Of the named field. If the name is not exists in the parameter list, then a -1 value will be return.
666         ''' </summary>
667         ''' <returns></returns>
668         Public Function GetOrdinal(parameter As StringAs Integer
669             Dim i% = LinqAPI.DefaultFirst(Of Integer)(-1) _
670  _
671                 <= From entry As NamedValue(Of String)
672                    In Me.__arguments
673                    Where String.Equals(parameter, entry.Name, StringComparison.OrdinalIgnoreCase)
674                    Select __arguments.IndexOf(entry)
675
676             Return i
677         End Function
678
679         ''' <summary>
680         ''' Gets the String value Of the specified field.
681         ''' </summary>
682         ''' <returns></returns>
683         ''' 
684         <MethodImpl(MethodImplOptions.AggressiveInlining)>
685         Public Function GetString(parameter As StringAs String
686             Return Me(parameter)
687         End Function
688
689         ''' <summary>
690         ''' Return whether the specified field Is Set To null.
691         ''' </summary>
692         ''' <returns></returns>
693         ''' 
694         <MethodImpl(MethodImplOptions.AggressiveInlining)>
695         Public Function IsNull(parameter As StringAs Boolean
696             Return Not Me.ContainsParameter(parameter, False)
697         End Function
698
699         ''' <summary>
700         '''
701         ''' </summary>
702         ''' <typeparam name="T"></typeparam>
703         ''' <param name="parameter">Command parameter name in the command line inputs.</param>
704         ''' <param name="__getObject"></param>
705         ''' <returns></returns>
706         Public Function GetObject(Of T)(parameter$, Optional __getObject As Func(Of String, T) = NothingAs T
707             Dim value$ = Me(parameter)
708             Dim obj = (__getObject Or StringParser(GetType(T)))(arg:=value)
709             Dim x As T = DirectCast(obj, T)
710             Return x
711         End Function
712
713         ''' <summary>
714         ''' If the given parameter is not exists in the user input arguments, then a developer specific default value will be return.
715         ''' </summary>
716         ''' <typeparam name="T"></typeparam>
717         ''' <param name="name">The optional argument parameter name</param>
718         ''' <param name="[default]">The default value for returns when the parameter is not exists in the user input.</param>
719         ''' <param name="__ctype">The custom string parser for the CLI argument value</param>
720         ''' <returns></returns>
721         Public Function GetValue(Of T)(name$, [default] As T, Optional __ctype As Func(Of String, T) = NothingAs T
722             If Not Me.ContainsParameter(name, FalseThen
723                 If GetType(T).Equals(GetType(Boolean)) Then
724                     If HavebFlag(name) Then
725                         Return DirectCast(DirectCast(GetBoolean(name), Object), T)
726                     End If
727                 End If
728
729                 Return [default]
730             End If
731
732             Dim str As String = Me(name).DefaultValue
733
734             If __ctype Is Nothing Then
735                 Dim value As Object = InputHandler.CTypeDynamic(str, GetType(T))
736                 Return DirectCast(value, T)
737             Else
738                 Return __ctype(str)
739             End If
740         End Function
741
742         ''' <summary>
743         ''' Open a file handle by using the parameter value
744         ''' </summary>
745         ''' <param name="name">The parameter name, and its argument value should be a valid file path</param>
746         ''' <param name="[default]">Default file path if the argument value is not exists</param>
747         ''' <returns></returns>
748         Public Function OpenHandle(name$, Optional default$ = ""As int
749             Dim file As String = Me(name)
750             If String.IsNullOrEmpty(file) Then
751                 file = [default]
752             End If
753             Return New int(FileHandles.OpenHandle(file))
754         End Function
755 #End Region
756
757 #Region "Implements IReadOnlyCollection(Of KeyValuePair(Of StringString))"
758
759         ''' <summary>
760         ''' 这个枚举函数也会将开关给包含进来,与<see cref="ToArgumentVector"/>方法所不同的是,这个函数里面的逻辑值开关的名称没有被修饰剪裁
761         ''' </summary>
762         ''' <returns></returns>
763         Public Iterator Function GetEnumerator() As IEnumerator(Of NamedValue(Of String)) Implements IEnumerable(Of NamedValue(Of String)).GetEnumerator
764             Dim source As New List(Of NamedValue(Of String))(Me.__arguments)
765
766             If Not Me.BoolFlags.IsNullOrEmpty Then
767                 source += From name As String
768                           In BoolFlags
769                           Select New NamedValue(Of String)(name, "true")
770             End If
771
772             For Each x As NamedValue(Of StringIn source
773                 Yield x
774             Next
775         End Function
776
777         Public Iterator Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
778             Yield GetEnumerator()
779         End Function
780
781         ''' <summary>
782         ''' Adds an item to the System.Collections.Generic.ICollection`1.
783         ''' </summary>
784         ''' <param name="item"></param>
785         ''' 
786         <MethodImpl(MethodImplOptions.AggressiveInlining)>
787         Public Sub Add(item As NamedValue(Of String)) Implements ICollection(Of NamedValue(Of String)).Add
788             Call __arguments.Add(item)
789         End Sub
790
791         ''' <summary>
792         ''' Add a parameter with name and its value.
793         ''' </summary>
794         ''' <param name="key"></param>
795         ''' <param name="value"></param>
796         Public Sub Add(key$, value$,
797                        Optional allowDuplicated As Boolean = False,
798                        <CallerMemberName> Optional stack$ = Nothing)
799
800             Dim item As New NamedValue(Of StringWith {
801                 .Name = key.ToLower,
802                 .Value = value,
803                 .Description = stack & "->" & NameOf(Add)
804             }
805
806             If Not allowDuplicated Then
807                 For i As Integer = 0 To __arguments.Count - 1
808                     With __arguments(i)
809                         If .Name.TextEquals(key) Then
810                             __arguments(i) = item
811                             Return
812                         End If
813                     End With
814                 Next
815
816                 ' 没有查找到需要被替换掉的下标,则直接在下面的代码之中进行添加
817             End If
818
819             __arguments += item
820         End Sub
821
822         ''' <summary>
823         ''' Clear the inner list buffer
824         ''' </summary>
825         ''' 
826         <MethodImpl(MethodImplOptions.AggressiveInlining)>
827         Public Sub Clear() Implements ICollection(Of NamedValue(Of String)).Clear
828             Call __arguments.Clear()
829         End Sub
830
831         ''' <summary>
832         ''' 只是通过比较名称来判断是否存在,值没有进行比较
833         ''' </summary>
834         ''' <param name="item"></param>
835         ''' <returns></returns>
836         Public Function Contains(item As NamedValue(Of String)) As Boolean Implements ICollection(Of NamedValue(Of String)).Contains
837             Dim LQuery% = LinqAPI.DefaultFirst(-1) _
838  _
839                 <= From obj As NamedValue(Of String)
840                    In Me.__arguments
841                    Where String.Equals(obj.Name, item.Name, StringComparison.OrdinalIgnoreCase)
842                    Select 100
843
844             Return LQuery > 50
845         End Function
846
847         <MethodImpl(MethodImplOptions.AggressiveInlining)>
848         Public Sub CopyTo(array() As NamedValue(Of String), arrayIndex As IntegerImplements ICollection(Of NamedValue(Of String)).CopyTo
849             Call __arguments.ToArray.CopyTo(array, arrayIndex)
850         End Sub
851
852         ''' <summary>
853         ''' Get the switch counts in this commandline object.(获取本命令行对象中的所定义的开关的数目)
854         ''' </summary>
855         ''' <value></value>
856         ''' <returns></returns>
857         ''' <remarks></remarks>
858         Public ReadOnly Property Count As Integer Implements ICollection(Of NamedValue(Of String)).Count
859             <MethodImpl(MethodImplOptions.AggressiveInlining)>
860             Get
861                 Return Me.__arguments.Count
862             End Get
863         End Property
864
865         Private ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of NamedValue(Of String)).IsReadOnly
866             <MethodImpl(MethodImplOptions.AggressiveInlining)>
867             Get
868                 Return True
869             End Get
870         End Property
871
872         ''' <summary>
873         ''' Removes a parameter by name
874         ''' </summary>
875         ''' <param name="paramName"></param>
876         ''' <returns></returns>
877         Public Function Remove(paramName As StringAs Boolean
878             Dim LQuery = LinqAPI.DefaultFirst(Of NamedValue(Of String)) _
879  _
880                 () <= From obj As NamedValue(Of String)
881                       In Me.__arguments
882                       Where String.Equals(obj.Name, paramName, StringComparison.OrdinalIgnoreCase)
883                       Select obj
884
885             If LQuery.IsEmpty Then
886                 Return False
887             Else
888                 Call __arguments.Remove(LQuery)
889                 Return True
890             End If
891         End Function
892
893         ''' <summary>
894         ''' Removes a parameter by <see cref="NamedValue(Of String).Name"/>
895         ''' </summary>
896         ''' <param name="item"></param>
897         ''' <returns></returns>
898         ''' 
899         <MethodImpl(MethodImplOptions.AggressiveInlining)>
900         Public Function Remove(item As NamedValue(Of String)) As Boolean Implements ICollection(Of NamedValue(Of String)).Remove
901             Return Remove(item.Name)
902         End Function
903 #End Region
904
905         ''' <summary>
906         ''' 将当前的这个命令行对象之中的所有的参数值都合并到一个向量之中返回.
907         ''' (``ToArray``拓展好像是有BUG的,所以请使用这个函数来获取所有的参数信息。
908         ''' 请注意,逻辑值开关的名称会被去掉前缀)
909         ''' </summary>
910         ''' <returns></returns>
911         Public Function ToArgumentVector() As NamedValue(Of String)()
912             Dim list As New List(Of NamedValue(Of String))
913
914             list += From arg As NamedValue(Of String)
915                     In __arguments.SafeQuery
916                     Select New NamedValue(Of StringWith {
917                         .Name = arg.Name,
918                         .Value = arg.Value
919                     }
920             list += From bs As String
921                     In BoolFlags.SafeQuery
922                     Select New NamedValue(Of StringWith {
923                         .Name = bs,
924                         .Value = "True"
925                     }
926
927             Return list
928         End Function
929
930         ''' <summary>
931         ''' Open a handle for a file system object.
932         ''' </summary>
933         ''' <param name="args"></param>
934         ''' <param name="fs"></param>
935         ''' <returns></returns>
936         Public Overloads Shared Operator +(args As CommandLine, fs$) As Integer
937             Dim path As String = args(fs)
938             Return FileHandles.OpenHandle(path)
939         End Operator
940
941         ''' <summary>
942         ''' Gets the CLI parameter value.
943         ''' </summary>
944         ''' <param name="args"></param>
945         ''' <param name="name"></param>
946         ''' <returns></returns>
947         Public Overloads Shared Operator <=(args As CommandLine, name$) As String
948             If args Is Nothing Then
949                 Return Nothing
950             Else
951                 Return args(name)
952             End If
953         End Operator
954
955         <MethodImpl(MethodImplOptions.AggressiveInlining)>
956         Public Shared Operator <=(opt As String, args As CommandLine) As CommandLine
957             Return TryParse(args(opt))
958         End Operator
959
960         Public Shared Operator ^(args As CommandLine, [default] As StringAs String
961             If args Is Nothing OrElse String.IsNullOrEmpty(args.CLICommandArgvs) Then
962                 Return [default]
963             Else
964                 Return args.CLICommandArgvs
965             End If
966         End Operator
967
968         Public Shared Operator >=(opt As String, args As CommandLine) As CommandLine
969             Throw New NotSupportedException
970         End Operator
971
972         ''' <summary>
973         ''' Try get parameter value.
974         ''' </summary>
975         ''' <param name="args"></param>
976         ''' <param name="name"></param>
977         ''' <returns></returns>
978         <MethodImpl(MethodImplOptions.AggressiveInlining)>
979         Public Overloads Shared Operator -(args As CommandLine, name As StringAs String
980             Return args(name)
981         End Operator
982
983         ''' <summary>
984         ''' Try get parameter value.
985         ''' </summary>
986         ''' <param name="args"></param>
987         ''' <returns></returns>
988         <MethodImpl(MethodImplOptions.AggressiveInlining)>
989         Public Overloads Shared Operator -(args As CommandLine, null As CommandLine) As CommandLine
990             Return args
991         End Operator
992
993         <MethodImpl(MethodImplOptions.AggressiveInlining)>
994         Public Overloads Shared Operator -(args As CommandLine, name As IEnumerable(Of String)) As String
995             Return args.GetValue(name.First, name.Last)
996         End Operator
997
998         <MethodImpl(MethodImplOptions.AggressiveInlining)>
999         Public Shared Operator -(args As CommandLine) As CommandLine
1000             Return args
1001         End Operator
1002
1003         <MethodImpl(MethodImplOptions.AggressiveInlining)>
1004         Public Shared Operator >(args As CommandLine, name As StringAs String
1005             Return args(name)
1006         End Operator
1007
1008         <MethodImpl(MethodImplOptions.AggressiveInlining)>
1009         Public Shared Operator <(args As CommandLine, name As StringAs String
1010             Return args(name)
1011         End Operator
1012
1013         Public Shared Operator >=(args As CommandLine, name As StringAs String
1014             Throw New NotSupportedException
1015         End Operator
1016     End Class
1017 End Namespace