1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Runtime . CompilerServices ;
5+ using System . Runtime . InteropServices . ComTypes ;
6+ using System . Text ;
7+ using J4JSoftware . Logging ;
8+
9+ #pragma warning disable 8618
10+
11+ namespace J4JSoftware . CommandLine
12+ {
13+ public class Allocator : IAllocator
14+ {
15+ private readonly IElementTerminator _terminator ;
16+ private readonly IKeyPrefixer _prefixer ;
17+ private readonly IJ4JLogger _logger ;
18+
19+ public Allocator (
20+ IElementTerminator terminator ,
21+ IKeyPrefixer prefixer ,
22+ IJ4JLogger logger
23+ )
24+ {
25+ _terminator = terminator ;
26+ _prefixer = prefixer ;
27+
28+ _logger = logger ;
29+ _logger . SetLoggedType ( GetType ( ) ) ;
30+ }
31+
32+ public bool AllocateCommandLine ( string [ ] args , Options options , out List < string > ? unkeyed )
33+ {
34+ unkeyed = null ;
35+
36+ if ( ! AllocateCommandLine ( string . Join ( " " , args ) , options , out var temp ) )
37+ return false ;
38+
39+ unkeyed = temp ;
40+
41+ return true ;
42+ }
43+
44+ public bool AllocateCommandLine ( string cmdLine , Options options , out List < string > ? unkeyed )
45+ {
46+ unkeyed = null ;
47+ var unkeyedInternal = new List < string > ( ) ;
48+
49+ var accumulator = new StringBuilder ( ) ;
50+ Option ? curOption = null ;
51+ var charsProcessed = 0 ;
52+ var lastElementWasKey = false ;
53+
54+ for ( var idx = 0 ; idx < cmdLine . Length ; idx ++ )
55+ {
56+ accumulator . Append ( cmdLine [ idx ] ) ;
57+ charsProcessed ++ ;
58+
59+ var element = accumulator . ToString ( ) ;
60+
61+ // analyze the sequence as it currently stands to see if it includes
62+ // a prefixed key and/or has been terminated
63+ var maxPrefix = _prefixer . GetMaxPrefixLength ( element ) ;
64+ var maxTerminator = _terminator . GetMaxTerminatorLength ( element , maxPrefix > 0 ) ;
65+
66+ // keep adding characters unless we've encountered a termination
67+ // sequence or we've reached the end of the command line
68+ if ( maxTerminator <= 0 && charsProcessed < cmdLine . Length )
69+ continue ;
70+
71+ // extract the true element value from the prefix and terminator
72+ element = element [ maxPrefix ..^ maxTerminator ] ;
73+
74+ // key values are identified by the presence of known prefixes
75+ if ( maxPrefix > 0 )
76+ {
77+ // element is a key
78+
79+ // if the key (contained in element) isn't among the keys defined
80+ // in the options collection we have a problem
81+ if ( ! options . UsesCommandLineKey ( element ) )
82+ {
83+ _logger . Error < string > ( "Unknown key '{0}'" , element ) ;
84+ return false ;
85+ }
86+
87+ curOption = options [ element ] ;
88+
89+ curOption ! . CommandLineKeyUsed = element ;
90+
91+ lastElementWasKey = true ;
92+ }
93+ else
94+ {
95+ // element is parameter value
96+ if ( curOption == null || ! lastElementWasKey )
97+ unkeyedInternal . Add ( element ) ;
98+ else curOption . AddAllocatedValue ( element ) ;
99+
100+ lastElementWasKey = false ;
101+ }
102+
103+ // clear the accumulator so we can start processing the next character sequence
104+ accumulator . Clear ( ) ;
105+ }
106+
107+ unkeyed = unkeyedInternal ;
108+
109+ return true ;
110+ }
111+ }
112+ }
0 commit comments