Skip to content

Commit 6768cfc

Browse files
authored
Merge pull request #1028 from ahoppen/ahoppen/split-windows-command-line
Add logic to split command line arguments on Windows
2 parents e56f735 + cfea672 commit 6768cfc

File tree

5 files changed

+470
-161
lines changed

5 files changed

+470
-161
lines changed

Sources/SKCore/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_library(SKCore STATIC
1111
FileBuildSettings.swift
1212
MainFilesProvider.swift
1313
PathPrefixMapping.swift
14+
SplitShellCommand.swift
1415
Toolchain.swift
1516
ToolchainRegistry.swift
1617
XCToolchainPlist.swift)

Sources/SKCore/CompilationDatabase.swift

Lines changed: 4 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,11 @@ extension CompilationDatabase.Command: Codable {
251251
if let arguments = try container.decodeIfPresent([String].self, forKey: .arguments) {
252252
self.commandLine = arguments
253253
} else if let command = try container.decodeIfPresent(String.self, forKey: .command) {
254+
#if os(Windows)
255+
self.commandLine = splitWindowsCommandLine(command, initialCommandName: true)
256+
#else
254257
self.commandLine = splitShellEscapedCommand(command)
258+
#endif
255259
} else {
256260
throw CompilationDatabaseDecodingError.missingCommandOrArguments
257261
}
@@ -265,123 +269,3 @@ extension CompilationDatabase.Command: Codable {
265269
try container.encodeIfPresent(output, forKey: .output)
266270
}
267271
}
268-
269-
/// Split and unescape a shell-escaped command line invocation.
270-
///
271-
/// Examples:
272-
///
273-
/// ```
274-
/// abc def -> ["abc", "def"]
275-
/// abc\ def -> ["abc def"]
276-
/// abc"\""def -> ["abc\"def"]
277-
/// abc'\"'def -> ["abc\\"def"]
278-
/// ```
279-
///
280-
/// See clang's `unescapeCommandLine()`.
281-
public func splitShellEscapedCommand(_ cmd: String) -> [String] {
282-
struct Parser {
283-
var content: Substring
284-
var i: Substring.UTF8View.Index
285-
var result: [String] = []
286-
287-
var ch: UInt8 { self.content.utf8[i] }
288-
var done: Bool { self.content.endIndex == i }
289-
290-
init(_ string: Substring) {
291-
self.content = string
292-
self.i = self.content.utf8.startIndex
293-
}
294-
295-
mutating func next() {
296-
i = content.utf8.index(after: i)
297-
}
298-
299-
mutating func next(expect c: UInt8) {
300-
assert(c == ch)
301-
next()
302-
}
303-
304-
mutating func parse() -> [String] {
305-
while !done {
306-
switch ch {
307-
case UInt8(ascii: " "): next()
308-
default: parseString()
309-
}
310-
}
311-
return result
312-
}
313-
314-
mutating func parseString() {
315-
var str = ""
316-
STRING: while !done {
317-
switch ch {
318-
case UInt8(ascii: " "): break STRING
319-
case UInt8(ascii: "\""): parseDoubleQuotedString(into: &str)
320-
case UInt8(ascii: "\'"): parseSingleQuotedString(into: &str)
321-
default: parsePlainString(into: &str)
322-
}
323-
}
324-
result.append(str)
325-
}
326-
327-
mutating func parseDoubleQuotedString(into str: inout String) {
328-
next(expect: UInt8(ascii: "\""))
329-
var start = i
330-
while !done {
331-
switch ch {
332-
case UInt8(ascii: "\""):
333-
str += content[start..<i]
334-
next()
335-
return
336-
case UInt8(ascii: "\\"):
337-
str += content[start..<i]
338-
next()
339-
start = i
340-
if !done { fallthrough }
341-
default:
342-
next()
343-
}
344-
}
345-
str += content[start..<i]
346-
}
347-
348-
mutating func parseSingleQuotedString(into str: inout String) {
349-
next(expect: UInt8(ascii: "\'"))
350-
let start = i
351-
while !done {
352-
switch ch {
353-
case UInt8(ascii: "\'"):
354-
str += content[start..<i]
355-
next()
356-
return
357-
default:
358-
next()
359-
}
360-
}
361-
str += content[start..<i]
362-
}
363-
364-
mutating func parsePlainString(into str: inout String) {
365-
var start = i
366-
while !done {
367-
let _ch = ch
368-
switch _ch {
369-
case UInt8(ascii: "\""), UInt8(ascii: "\'"), UInt8(ascii: " "):
370-
str += content[start..<i]
371-
return
372-
case UInt8(ascii: "\\"):
373-
str += content[start..<i]
374-
next()
375-
start = i
376-
if !done { fallthrough }
377-
default:
378-
next()
379-
}
380-
}
381-
str += content[start..<i]
382-
}
383-
}
384-
385-
var parser = Parser(cmd[...])
386-
return parser.parse()
387-
}

0 commit comments

Comments
 (0)