99
1010namespace Toolkit \Cli ;
1111
12+ use Toolkit \Cli \Helper \FlagHelper ;
1213use Toolkit \Cli \Util \LineParser ;
1314use function array_flip ;
1415use function array_merge ;
1516use function current ;
1617use function escapeshellarg ;
1718use function explode ;
18- use function is_bool ;
1919use function is_int ;
20- use function is_numeric ;
2120use function next ;
2221use function preg_match ;
2322use function str_split ;
24- use function stripos ;
2523use function strpos ;
2624use function substr ;
2725use function trim ;
3331 */
3432class Flags
3533{
36- // These words will be as a Boolean value
37- private const TRUE_WORDS = '|on|yes|true| ' ;
38-
39- private const FALSE_WORDS = '|off|no|false| ' ;
40-
4134 /**
4235 * @param array $argv
4336 *
@@ -134,26 +127,26 @@ public static function parseArgv(array $params, array $config = []): array
134127 // Special short style
135128 // posix: -abc will expand: -a -b -c
136129 // unix: -abc will expand: -a=bc
137- 'shortStyle ' => 'posix ' ,
130+ 'shortStyle ' => 'posix ' ,
138131 ], $ config );
139132
140133 $ args = $ sOpts = $ lOpts = [];
141134 // config
142135 $ boolOpts = array_flip ((array )$ config ['boolOpts ' ]);
143136 $ arrayOpts = array_flip ((array )$ config ['arrayOpts ' ]);
144137
145- // each() will deprecated at 7.2. so,there use current and next instead it.
146- // while (list(,$p) = each($params)) {
138+ $ optParseEnd = false ;
147139 while (false !== ($ p = current ($ params ))) {
148140 next ($ params );
149141
150- // empty string
151- if ($ p === '' ) {
142+ // option parse end, collect remaining arguments.
143+ if ($ optParseEnd ) {
144+ self ::collectArgs ($ args , $ p );
152145 continue ;
153146 }
154147
155148 // is options and not equals '-' '--'
156- if ($ p [0 ] === '- ' && '' !== trim ($ p , '- ' )) {
149+ if ($ p && $ p [0 ] === '- ' && '' !== trim ($ p , '- ' )) {
157150 $ value = true ;
158151 $ isLong = false ;
159152 $ option = substr ($ p , 1 );
@@ -177,7 +170,7 @@ public static function parseArgv(array $params, array $config = []): array
177170 $ nxt = current ($ params );
178171
179172 // next elem is value. fix: allow empty string ''
180- if ($ value === true && !isset ($ boolOpts [$ option ]) && self :: nextIsValue ($ nxt )) {
173+ if ($ value === true && !isset ($ boolOpts [$ option ]) && FlagHelper:: isOptionValue ($ nxt )) {
181174 // list(,$val) = each($params);
182175 $ value = $ nxt ;
183176 next ($ params );
@@ -190,7 +183,7 @@ public static function parseArgv(array $params, array $config = []): array
190183 continue ;
191184 }
192185
193- $ value = self ::filterBool ($ value );
186+ $ value = FlagHelper ::filterBool ($ value );
194187 $ isArray = isset ($ arrayOpts [$ option ]);
195188
196189 if ($ isLong ) {
@@ -208,21 +201,16 @@ public static function parseArgv(array $params, array $config = []): array
208201 continue ;
209202 }
210203
204+ // stop parse options:
205+ // - found '--' will stop parse options
206+ if ($ p === '-- ' ) {
207+ $ optParseEnd = true ;
208+ continue ;
209+ }
210+
211211 // parse arguments:
212212 // - param doesn't belong to any option, define it is args
213-
214- // value specified inline (<arg>=<value>)
215- if (strpos ($ p , '= ' ) !== false ) {
216- [$ name , $ value ] = explode ('= ' , $ p , 2 );
217-
218- if (self ::isValidArgName ($ name )) {
219- $ args [$ name ] = self ::filterBool ($ value );
220- } else {
221- $ args [] = $ p ;
222- }
223- } else {
224- $ args [] = $ p ;
225- }
213+ self ::collectArgs ($ args , $ p );
226214 }
227215
228216 if ($ config ['mergeOpts ' ]) {
@@ -232,6 +220,26 @@ public static function parseArgv(array $params, array $config = []): array
232220 return [$ args , $ sOpts , $ lOpts ];
233221 }
234222
223+ /**
224+ * @param array $args
225+ * @param string $p
226+ */
227+ private static function collectArgs (array &$ args , string $ p ): void
228+ {
229+ // value specified inline (<arg>=<value>)
230+ if (strpos ($ p , '= ' ) !== false ) {
231+ [$ name , $ value ] = explode ('= ' , $ p , 2 );
232+
233+ if (FlagHelper::isValidName ($ name )) {
234+ $ args [$ name ] = FlagHelper::filterBool ($ value );
235+ } else {
236+ $ args [] = $ p ;
237+ }
238+ } else {
239+ $ args [] = $ p ;
240+ }
241+ }
242+
235243 /**
236244 * parse custom array params
237245 * ```php
@@ -295,79 +303,6 @@ public static function parseString(string $string, array $config = []): array
295303 return self ::parseArgv ($ flags , $ config );
296304 }
297305
298- /**
299- * @param string|bool $val
300- * @param bool $enable
301- *
302- * @return bool|int|mixed
303- */
304- public static function filterBool ($ val , bool $ enable = true )
305- {
306- if ($ enable ) {
307- if (is_bool ($ val ) || is_numeric ($ val )) {
308- return $ val ;
309- }
310-
311- // check it is a bool value.
312- if (false !== stripos (self ::TRUE_WORDS , "| $ val| " )) {
313- return true ;
314- }
315-
316- if (false !== stripos (self ::FALSE_WORDS , "| $ val| " )) {
317- return false ;
318- }
319- }
320-
321- return $ val ;
322- }
323-
324- /**
325- * check next is option value
326- *
327- * @param mixed $val
328- *
329- * @return bool
330- */
331- public static function nextIsValue ($ val ): bool
332- {
333- // current() fetch error, will return FALSE
334- if ($ val === false ) {
335- return false ;
336- }
337-
338- // if is: '', 0
339- if (!$ val ) {
340- return true ;
341- }
342-
343- // is not option name.
344- if ($ val [0 ] !== '- ' ) {
345- // ensure is option value.
346- if (false === strpos ($ val , '= ' )) {
347- return true ;
348- }
349-
350- // is string value, but contains '='
351- [$ name ,] = explode ('= ' , $ val , 2 );
352-
353- // named argument OR invlaid: 'some = string'
354- return false === self ::isValidArgName ($ name );
355- }
356-
357- // is option name.
358- return false ;
359- }
360-
361- /**
362- * @param string $name
363- *
364- * @return bool
365- */
366- public static function isValidArgName (string $ name ): bool
367- {
368- return preg_match ('#^\w+$# ' , $ name ) === 1 ;
369- }
370-
371306 /**
372307 * Escapes a token through escapeshellarg if it contains unsafe chars.
373308 *
0 commit comments