This repository was archived by the owner on Jan 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 313
Expand file tree
/
Copy pathFSharpCommandLineBuilder.fs
More file actions
106 lines (91 loc) · 4.55 KB
/
FSharpCommandLineBuilder.fs
File metadata and controls
106 lines (91 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace Microsoft.FSharp.Build
open System
open System.Text
open Microsoft.Build.Framework
open Microsoft.Build.Utilities
open Internal.Utilities
[<assembly: System.Runtime.InteropServices.ComVisible(false)>]
[<assembly: System.CLSCompliant(true)>]
do()
type FSharpCommandLineBuilder () =
// In addition to generating a command-line that will be handed to cmd.exe, we also generate
// an array of individual arguments. The former needs to be quoted (and cmd.exe will strip the
// quotes while parsing), whereas the latter is not. See bug 4357 for background; this helper
// class gets us out of the business of unparsing-then-reparsing arguments.
let builder = new CommandLineBuilder()
let mutable args = [] // in reverse order
let mutable srcs = [] // in reverse order
/// Return a list of the arguments (with no quoting for the cmd.exe shell)
member x.CapturedArguments() = List.rev args
/// Return a list of the sources (with no quoting for the cmd.exe shell)
member x.CapturedFilenames() = List.rev srcs
/// Return a full command line (with quoting for the cmd.exe shell)
override x.ToString() = builder.ToString()
member x.AppendFileNamesIfNotNull(filenames:ITaskItem array, sep:string) =
builder.AppendFileNamesIfNotNull(filenames, sep)
// do not update "args", not used
for item in filenames do
let tmp = new CommandLineBuilder()
tmp.AppendSwitchUnquotedIfNotNull("", item.ItemSpec) // we don't want to quote the filename, this is a way to get that
let s = tmp.ToString()
if s <> String.Empty then
srcs <- tmp.ToString() :: srcs
member x.AppendSwitchIfNotNull(switch:string, values:string array, sep:string) =
builder.AppendSwitchIfNotNull(switch, values, sep)
let tmp = new CommandLineBuilder()
tmp.AppendSwitchUnquotedIfNotNull(switch, values, sep)
let s = tmp.ToString()
if s <> String.Empty then
args <- s :: args
member x.AppendSwitchIfNotNull(switch:string, value:string, ?metadataNames:string array) =
let metadataNames = defaultArg metadataNames [||]
builder.AppendSwitchIfNotNull(switch, value)
let tmp = new CommandLineBuilder()
tmp.AppendSwitchUnquotedIfNotNull(switch, value)
let providedMetaData =
metadataNames
|> Array.filter (String.IsNullOrWhiteSpace >> not)
if providedMetaData.Length > 0 then
tmp.AppendTextUnquoted ","
tmp.AppendTextUnquoted (providedMetaData|> String.concat ",")
let s = tmp.ToString()
if s <> String.Empty then
args <- s :: args
member x.AppendSwitchUnquotedIfNotNull(switch:string, value:string) =
assert(switch = "") // we only call this method for "OtherFlags"
// Unfortunately we still need to mimic what cmd.exe does, but only for "OtherFlags".
let ParseCommandLineArgs(commandLine:string) = // returns list in reverse order
let mutable args = []
let mutable i = 0 // index into commandLine
let len = commandLine.Length
while i < len do
// skip whitespace
while i < len && System.Char.IsWhiteSpace(commandLine, i) do
i <- i + 1
if i < len then
// parse an argument
let sb = new StringBuilder()
let mutable finished = false
let mutable insideQuote = false
while i < len && not finished do
match commandLine.[i] with
| '"' -> insideQuote <- not insideQuote; i <- i + 1
| c when not insideQuote && System.Char.IsWhiteSpace(c) -> finished <- true
| c -> sb.Append(c) |> ignore; i <- i + 1
args <- sb.ToString() :: args
args
builder.AppendSwitchUnquotedIfNotNull(switch, value)
let tmp = new CommandLineBuilder()
tmp.AppendSwitchUnquotedIfNotNull(switch, value)
let s = tmp.ToString()
if s <> String.Empty then
args <- ParseCommandLineArgs(s) @ args
member x.AppendSwitch(switch:string) =
builder.AppendSwitch(switch)
args <- switch :: args
member internal x.GetCapturedArguments() =
[|
yield! x.CapturedArguments()
yield! x.CapturedFilenames()
|]