@@ -83,7 +83,7 @@ internal void BindParameters(Collection<CommandParameterInternal> parameters)
8383 if ( parameter . ParameterNameSpecified )
8484 {
8585 Diagnostics . Assert ( ! parameter . ParameterText . Contains ( ' ' ) , "Parameters cannot have whitespace" ) ;
86- PossiblyGlobArg ( parameter . ParameterText , parameter , StringConstantType . BareWord ) ;
86+ PossiblyGlobArg ( parameter . ParameterText , parameter , usedQuotes : false ) ;
8787
8888 if ( parameter . SpaceAfterParameter )
8989 {
@@ -108,30 +108,22 @@ internal void BindParameters(Collection<CommandParameterInternal> parameters)
108108 // windbg -k com:port=\\devbox\pipe\debug,pipe,resets=0,reconnect
109109 // The parser produced an array of strings but marked the parameter so we
110110 // can properly reconstruct the correct command line.
111- StringConstantType stringConstantType = StringConstantType . BareWord ;
111+ bool usedQuotes = false ;
112112 ArrayLiteralAst arrayLiteralAst = null ;
113113 switch ( parameter ? . ArgumentAst )
114114 {
115115 case StringConstantExpressionAst sce :
116- stringConstantType = sce . StringConstantType ;
116+ usedQuotes = sce . StringConstantType != StringConstantType . BareWord ;
117117 break ;
118118 case ExpandableStringExpressionAst ese :
119- stringConstantType = ese . StringConstantType ;
119+ usedQuotes = ese . StringConstantType != StringConstantType . BareWord ;
120120 break ;
121121 case ArrayLiteralAst ala :
122122 arrayLiteralAst = ala ;
123123 break ;
124124 }
125125
126- // Prior to PSNativePSPathResolution experimental feature, a single quote worked the same as a double quote
127- // so if the feature is not enabled, we treat any quotes as double quotes. When this feature is no longer
128- // experimental, this code here needs to be removed.
129- if ( ! ExperimentalFeature . IsEnabled ( "PSNativePSPathResolution" ) && stringConstantType == StringConstantType . SingleQuoted )
130- {
131- stringConstantType = StringConstantType . DoubleQuoted ;
132- }
133-
134- AppendOneNativeArgument ( Context , parameter , argValue , arrayLiteralAst , sawVerbatimArgumentMarker , stringConstantType ) ;
126+ AppendOneNativeArgument ( Context , parameter , argValue , arrayLiteralAst , sawVerbatimArgumentMarker , usedQuotes ) ;
135127 }
136128 }
137129 }
@@ -225,8 +217,8 @@ internal NativeArgumentPassingStyle ArgumentPassingStyle
225217 /// <param name="obj">The object to append.</param>
226218 /// <param name="argArrayAst">If the argument was an array literal, the Ast, otherwise null.</param>
227219 /// <param name="sawVerbatimArgumentMarker">True if the argument occurs after --%.</param>
228- /// <param name="stringConstantType">Bare, SingleQuoted, or DoubleQuoted .</param>
229- private void AppendOneNativeArgument ( ExecutionContext context , CommandParameterInternal parameter , object obj , ArrayLiteralAst argArrayAst , bool sawVerbatimArgumentMarker , StringConstantType stringConstantType )
220+ /// <param name="usedQuotes">True if the argument was a quoted string (single or double) .</param>
221+ private void AppendOneNativeArgument ( ExecutionContext context , CommandParameterInternal parameter , object obj , ArrayLiteralAst argArrayAst , bool sawVerbatimArgumentMarker , bool usedQuotes )
230222 {
231223 IEnumerator list = LanguagePrimitives . GetEnumerator ( obj ) ;
232224
@@ -291,20 +283,11 @@ private void AppendOneNativeArgument(ExecutionContext context, CommandParameterI
291283 if ( NeedQuotes ( arg ) )
292284 {
293285 _arguments . Append ( '"' ) ;
294-
295- if ( stringConstantType == StringConstantType . DoubleQuoted )
296- {
297- _arguments . Append ( ResolvePath ( arg , Context ) ) ;
298- AddToArgumentList ( parameter , ResolvePath ( arg , Context ) ) ;
299- }
300- else
301- {
302- _arguments . Append ( arg ) ;
303- AddToArgumentList ( parameter , arg ) ;
304- }
286+ AddToArgumentList ( parameter , arg ) ;
305287
306288 // need to escape all trailing backslashes so the native command receives it correctly
307289 // according to http://www.daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULESDOC
290+ _arguments . Append ( arg ) ;
308291 for ( int i = arg . Length - 1 ; i >= 0 && arg [ i ] == '\\ ' ; i -- )
309292 {
310293 _arguments . Append ( '\\ ' ) ;
@@ -319,14 +302,14 @@ private void AppendOneNativeArgument(ExecutionContext context, CommandParameterI
319302 // We have a literal array, so take the extent, break it on spaces and add them to the argument list.
320303 foreach ( string element in argArrayAst . Extent . Text . Split ( ' ' , StringSplitOptions . RemoveEmptyEntries ) )
321304 {
322- PossiblyGlobArg ( element , parameter , stringConstantType ) ;
305+ PossiblyGlobArg ( element , parameter , usedQuotes ) ;
323306 }
324307
325308 break ;
326309 }
327310 else
328311 {
329- PossiblyGlobArg ( arg , parameter , stringConstantType ) ;
312+ PossiblyGlobArg ( arg , parameter , usedQuotes ) ;
330313 }
331314 }
332315 }
@@ -346,173 +329,98 @@ private void AppendOneNativeArgument(ExecutionContext context, CommandParameterI
346329 /// </summary>
347330 /// <param name="arg">The argument that possibly needs expansion.</param>
348331 /// <param name="parameter">The parameter associated with the operation.</param>
349- /// <param name="stringConstantType">Bare, SingleQuoted, or DoubleQuoted .</param>
350- private void PossiblyGlobArg ( string arg , CommandParameterInternal parameter , StringConstantType stringConstantType )
332+ /// <param name="usedQuotes">True if the argument was a quoted string (single or double) .</param>
333+ private void PossiblyGlobArg ( string arg , CommandParameterInternal parameter , bool usedQuotes )
351334 {
352335 var argExpanded = false ;
353336
354337#if UNIX
355338 // On UNIX systems, we expand arguments containing wildcard expressions against
356339 // the file system just like bash, etc.
357-
358- if ( stringConstantType == StringConstantType . BareWord )
340+ if ( ! usedQuotes && WildcardPattern . ContainsWildcardCharacters ( arg ) )
359341 {
360- if ( WildcardPattern . ContainsWildcardCharacters ( arg ) )
342+ // See if the current working directory is a filesystem provider location
343+ // We won't do the expansion if it isn't since native commands can only access the file system.
344+ var cwdinfo = Context . EngineSessionState . CurrentLocation ;
345+
346+ // If it's a filesystem location then expand the wildcards
347+ if ( cwdinfo . Provider . Name . Equals ( FileSystemProvider . ProviderName , StringComparison . OrdinalIgnoreCase ) )
361348 {
362- // See if the current working directory is a filesystem provider location
363- // We won't do the expansion if it isn't since native commands can only access the file system.
364- var cwdinfo = Context . EngineSessionState . CurrentLocation ;
349+ // On UNIX, paths starting with ~ or absolute paths are not normalized
350+ bool normalizePath = arg . Length == 0 || ! ( arg [ 0 ] == '~' || arg [ 0 ] == '/' ) ;
365351
366- // If it's a filesystem location then expand the wildcards
367- if ( cwdinfo . Provider . Name . Equals ( FileSystemProvider . ProviderName , StringComparison . OrdinalIgnoreCase ) )
352+ // See if there are any matching paths otherwise just add the pattern as the argument
353+ Collection < PSObject > paths = null ;
354+ try
368355 {
369- // On UNIX, paths starting with ~ or absolute paths are not normalized
370- bool normalizePath = arg . Length == 0 || ! ( arg [ 0 ] == '~' || arg [ 0 ] == '/' ) ;
371-
372- // See if there are any matching paths otherwise just add the pattern as the argument
373- Collection < PSObject > paths = null ;
374- try
375- {
376- paths = Context . EngineSessionState . InvokeProvider . ChildItem . Get ( arg , false ) ;
377- }
378- catch
379- {
380- // Fallthrough will append the pattern unchanged.
381- }
356+ paths = Context . EngineSessionState . InvokeProvider . ChildItem . Get ( arg , false ) ;
357+ }
358+ catch
359+ {
360+ // Fallthrough will append the pattern unchanged.
361+ }
382362
383- // Expand paths, but only from the file system.
384- if ( paths ? . Count > 0 && paths . All ( static p => p . BaseObject is FileSystemInfo ) )
363+ // Expand paths, but only from the file system.
364+ if ( paths ? . Count > 0 && paths . All ( p => p . BaseObject is FileSystemInfo ) )
365+ {
366+ var sep = string . Empty ;
367+ foreach ( var path in paths )
385368 {
386- var sep = string . Empty ;
387- foreach ( var path in paths )
369+ _arguments . Append ( sep ) ;
370+ sep = " " ;
371+ var expandedPath = ( path . BaseObject as FileSystemInfo ) . FullName ;
372+ if ( normalizePath )
388373 {
389- _arguments . Append ( sep ) ;
390- sep = " " ;
391- var expandedPath = ( path . BaseObject as FileSystemInfo ) . FullName ;
392- if ( normalizePath )
393- {
394- expandedPath =
395- Context . SessionState . Path . NormalizeRelativePath ( expandedPath , cwdinfo . ProviderPath ) ;
396- }
397- // If the path contains spaces, then add quotes around it.
398- if ( NeedQuotes ( expandedPath ) )
399- {
400- _arguments . Append ( '"' ) ;
401- _arguments . Append ( expandedPath ) ;
402- _arguments . Append ( '"' ) ;
403- AddToArgumentList ( parameter , expandedPath ) ;
404- }
405- else
406- {
407- _arguments . Append ( expandedPath ) ;
408- AddToArgumentList ( parameter , expandedPath ) ;
409- }
410-
411- argExpanded = true ;
374+ expandedPath =
375+ Context . SessionState . Path . NormalizeRelativePath ( expandedPath , cwdinfo . ProviderPath ) ;
376+ }
377+ // If the path contains spaces, then add quotes around it.
378+ if ( NeedQuotes ( expandedPath ) )
379+ {
380+ _arguments . Append ( '"' ) ;
381+ _arguments . Append ( expandedPath ) ;
382+ _arguments . Append ( '"' ) ;
412383 }
384+ else
385+ {
386+ _arguments . Append ( expandedPath ) ;
387+ }
388+
389+ AddToArgumentList ( parameter , expandedPath ) ;
390+ argExpanded = true ;
413391 }
414392 }
415393 }
416- else
394+ }
395+ else if ( ! usedQuotes )
396+ {
397+ // Even if there are no wildcards, we still need to possibly
398+ // expand ~ into the filesystem provider home directory path
399+ ProviderInfo fileSystemProvider = Context . EngineSessionState . GetSingleProvider ( FileSystemProvider . ProviderName ) ;
400+ string home = fileSystemProvider . Home ;
401+ if ( string . Equals ( arg , "~" ) )
417402 {
418- // Even if there are no wildcards, we still need to possibly
419- // expand ~ into the filesystem provider home directory path
420- ProviderInfo fileSystemProvider = Context . EngineSessionState . GetSingleProvider ( FileSystemProvider . ProviderName ) ;
421- string home = fileSystemProvider . Home ;
422- if ( string . Equals ( arg , "~" ) )
423- {
424- _arguments . Append ( home ) ;
425- AddToArgumentList ( parameter , home ) ;
426- argExpanded = true ;
427- }
428- else if ( arg . StartsWith ( "~/" , StringComparison . OrdinalIgnoreCase ) )
429- {
430- string replacementString = string . Concat ( home , arg . AsSpan ( 1 ) ) ;
431- _arguments . Append ( replacementString ) ;
432- AddToArgumentList ( parameter , replacementString ) ;
433- argExpanded = true ;
434- }
403+ _arguments . Append ( home ) ;
404+ AddToArgumentList ( parameter , home ) ;
405+ argExpanded = true ;
406+ }
407+ else if ( arg . StartsWith ( "~/" , StringComparison . OrdinalIgnoreCase ) )
408+ {
409+ var replacementString = string . Concat ( home , arg . AsSpan ( 1 ) ) ;
410+ _arguments . Append ( replacementString ) ;
411+ AddToArgumentList ( parameter , replacementString ) ;
412+ argExpanded = true ;
435413 }
436414 }
437415#endif // UNIX
438416
439- if ( stringConstantType != StringConstantType . SingleQuoted )
440- {
441- arg = ResolvePath ( arg , Context ) ;
442- }
443-
444417 if ( ! argExpanded )
445418 {
446419 _arguments . Append ( arg ) ;
447420 AddToArgumentList ( parameter , arg ) ;
448421 }
449422 }
450423
451- /// <summary>
452- /// Check if string is prefixed by psdrive, if so, expand it if filesystem path.
453- /// </summary>
454- /// <param name="path">The potential PSPath to resolve.</param>
455- /// <param name="context">The current ExecutionContext.</param>
456- /// <returns>Resolved PSPath if applicable otherwise the original path</returns>
457- internal static string ResolvePath ( string path , ExecutionContext context )
458- {
459- if ( ExperimentalFeature . IsEnabled ( "PSNativePSPathResolution" ) )
460- {
461- #if ! UNIX
462- // on Windows, we need to expand ~ to point to user's home path
463- if ( string . Equals ( path , "~" , StringComparison . Ordinal ) || path . StartsWith ( TildeDirectorySeparator , StringComparison . Ordinal ) || path . StartsWith ( TildeAltDirectorySeparator , StringComparison . Ordinal ) )
464- {
465- try
466- {
467- ProviderInfo fileSystemProvider = context . EngineSessionState . GetSingleProvider ( FileSystemProvider . ProviderName ) ;
468- return new StringBuilder ( fileSystemProvider . Home )
469- . Append ( path . AsSpan ( 1 ) )
470- . Replace ( Path . AltDirectorySeparatorChar , Path . DirectorySeparatorChar )
471- . ToString ( ) ;
472- }
473- catch
474- {
475- return path ;
476- }
477- }
478-
479- // check if the driveName is an actual disk drive on Windows, if so, no expansion
480- if ( path . Length >= 2 && path [ 1 ] == ':' )
481- {
482- foreach ( var drive in DriveInfo . GetDrives ( ) )
483- {
484- if ( drive . Name . StartsWith ( new string ( path [ 0 ] , 1 ) , StringComparison . OrdinalIgnoreCase ) )
485- {
486- return path ;
487- }
488- }
489- }
490- #endif
491-
492- if ( path . Contains ( ':' ) )
493- {
494- LocationGlobber globber = new LocationGlobber ( context . SessionState ) ;
495- try
496- {
497- ProviderInfo providerInfo ;
498-
499- // replace the argument with resolved path if it's a filesystem path
500- string pspath = globber . GetProviderPath ( path , out providerInfo ) ;
501- if ( string . Equals ( providerInfo . Name , FileSystemProvider . ProviderName , StringComparison . OrdinalIgnoreCase ) )
502- {
503- path = pspath ;
504- }
505- }
506- catch
507- {
508- // if it's not a provider path, do nothing
509- }
510- }
511- }
512-
513- return path ;
514- }
515-
516424 /// <summary>
517425 /// Check to see if the string contains spaces and therefore must be quoted.
518426 /// </summary>
@@ -567,8 +475,6 @@ private static string GetEnumerableArgSeparator(ArrayLiteralAst arrayLiteralAst,
567475 /// The native command to bind to.
568476 /// </summary>
569477 private readonly NativeCommand _nativeCommand ;
570- private static readonly string TildeDirectorySeparator = $ "~{ Path . DirectorySeparatorChar } ";
571- private static readonly string TildeAltDirectorySeparator = $ "~{ Path . AltDirectorySeparatorChar } ";
572478
573479 #endregion private members
574480 }
0 commit comments