|
| 1 | +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. |
| 2 | + |
| 3 | +namespaceMicrosoft.FSharp.Build |
| 4 | + |
| 5 | +openSystem |
| 6 | +openSystem.Text |
| 7 | +openMicrosoft.Build.Framework |
| 8 | +openMicrosoft.Build.Utilities |
| 9 | +openInternal.Utilities |
| 10 | + |
| 11 | +[<assembly: System.Runtime.InteropServices.ComVisible(false)>] |
| 12 | +[<assembly: System.CLSCompliant(true)>] |
| 13 | +do() |
| 14 | + |
| 15 | +typeFSharpCommandLineBuilder()= |
| 16 | + |
| 17 | +// In addition to generating a command-line that will be handed to cmd.exe, we also generate |
| 18 | +// an array of individual arguments. The former needs to be quoted (and cmd.exe will strip the |
| 19 | +// quotes while parsing), whereas the latter is not. See bug 4357 for background; this helper |
| 20 | +// class gets us out of the business of unparsing-then-reparsing arguments. |
| 21 | + |
| 22 | +letbuilder=new CommandLineBuilder() |
| 23 | +let mutableargs=[]// in reverse order |
| 24 | +let mutablesrcs=[]// in reverse order |
| 25 | + |
| 26 | +/// Return a list of the arguments (with no quoting for the cmd.exe shell) |
| 27 | +memberx.CapturedArguments()= List.rev args |
| 28 | + |
| 29 | +/// Return a list of the sources (with no quoting for the cmd.exe shell) |
| 30 | +memberx.CapturedFilenames()= List.rev srcs |
| 31 | + |
| 32 | +/// Return a full command line (with quoting for the cmd.exe shell) |
| 33 | +overridex.ToString()= builder.ToString() |
| 34 | + |
| 35 | +memberx.AppendFileNamesIfNotNull(filenames:ITaskItem array,sep:string)= |
| 36 | + builder.AppendFileNamesIfNotNull(filenames, sep) |
| 37 | +// do not update "args", not used |
| 38 | +for itemin filenamesdo |
| 39 | +lettmp=new CommandLineBuilder() |
| 40 | + tmp.AppendSwitchUnquotedIfNotNull("", item.ItemSpec)// we don't want to quote the filename, this is a way to get that |
| 41 | +lets= tmp.ToString() |
| 42 | +if s<> String.Emptythen |
| 43 | + srcs<- tmp.ToString():: srcs |
| 44 | + |
| 45 | +memberx.AppendSwitchIfNotNull(switch:string,values:string array,sep:string)= |
| 46 | + builder.AppendSwitchIfNotNull(switch, values, sep) |
| 47 | +lettmp=new CommandLineBuilder() |
| 48 | + tmp.AppendSwitchUnquotedIfNotNull(switch, values, sep) |
| 49 | +lets= tmp.ToString() |
| 50 | +if s<> String.Emptythen |
| 51 | + args<- s:: args |
| 52 | + |
| 53 | +memberx.AppendSwitchIfNotNull(switch:string,value:string,?metadataNames:string array)= |
| 54 | +letmetadataNames= defaultArg metadataNames[||] |
| 55 | + builder.AppendSwitchIfNotNull(switch, value) |
| 56 | +lettmp=new CommandLineBuilder() |
| 57 | + tmp.AppendSwitchUnquotedIfNotNull(switch, value) |
| 58 | +letprovidedMetaData= |
| 59 | + metadataNames |
| 60 | +|> Array.filter(String.IsNullOrWhiteSpace>>not) |
| 61 | +if providedMetaData.Length>0then |
| 62 | + tmp.AppendTextUnquoted"," |
| 63 | + tmp.AppendTextUnquoted(providedMetaData|> String.concat",") |
| 64 | +lets= tmp.ToString() |
| 65 | +if s<> String.Emptythen |
| 66 | + args<- s:: args |
| 67 | + |
| 68 | +memberx.AppendSwitchUnquotedIfNotNull(switch:string,value:string)= |
| 69 | +assert(switch="")// we only call this method for "OtherFlags" |
| 70 | +// Unfortunately we still need to mimic what cmd.exe does, but only for "OtherFlags". |
| 71 | +letParseCommandLineArgs(commandLine:string)=// returns list in reverse order |
| 72 | +let mutableargs=[] |
| 73 | +let mutablei=0// index into commandLine |
| 74 | +letlen= commandLine.Length |
| 75 | +while i< lendo |
| 76 | +// skip whitespace |
| 77 | +while i< len&& System.Char.IsWhiteSpace(commandLine, i)do |
| 78 | + i<- i+1 |
| 79 | +if i< lenthen |
| 80 | +// parse an argument |
| 81 | +letsb=new StringBuilder() |
| 82 | +let mutablefinished=false |
| 83 | +let mutableinsideQuote=false |
| 84 | +while i< len&¬ finisheddo |
| 85 | +match commandLine.[i]with |
| 86 | +|'"'-> insideQuote<-not insideQuote; i<- i+1 |
| 87 | +| cwhennot insideQuote&& System.Char.IsWhiteSpace(c)-> finished<-true |
| 88 | +| c-> sb.Append(c)|> ignore; i<- i+1 |
| 89 | + args<- sb.ToString():: args |
| 90 | + args |
| 91 | + builder.AppendSwitchUnquotedIfNotNull(switch, value) |
| 92 | +lettmp=new CommandLineBuilder() |
| 93 | + tmp.AppendSwitchUnquotedIfNotNull(switch, value) |
| 94 | +lets= tmp.ToString() |
| 95 | +if s<> String.Emptythen |
| 96 | + args<- ParseCommandLineArgs(s)@ args |
| 97 | + |
| 98 | +memberx.AppendSwitch(switch:string)= |
| 99 | + builder.AppendSwitch(switch) |
| 100 | + args<- switch:: args |
| 101 | + |
| 102 | +memberinternalx.GetCapturedArguments()= |
| 103 | +[| |
| 104 | +yield! x.CapturedArguments() |
| 105 | +yield! x.CapturedFilenames() |
| 106 | +|] |