func quote()

in Sources/TSCBasic/misc.swift [25:82]


    func quote(argument: String) -> String {
        if !argument.contains(where: { " \t\n\"".contains($0) }) {
            return argument
        }

        // To escape the command line, we surround the argument with quotes.
        // However, the complication comes due to how the Windows command line
        // parser treats backslashes (\) and quotes (").
        //
        // - \ is normally treated as a literal backslash
        //      e.g. alpha\beta\gamma => alpha\beta\gamma
        // - The sequence \" is treated as a literal "
        //      e.g. alpha\"beta => alpha"beta
        //
        // But then what if we are given a path that ends with a \?
        //
        // Surrounding alpha\beta\ with " would be "alpha\beta\" which would be
        // an unterminated string since it ends on a literal quote. To allow
        // this case the parser treats:
        //
        //  - \\" as \ followed by the " metacharacter
        //  - \\\" as \ followed by a literal "
        //
        // In general:
        //  - 2n \ followed by " => n \ followed by the " metacharacter
        //  - 2n + 1 \ followed by " => n \ followed by a literal "

        var quoted = "\""
        var unquoted = argument.unicodeScalars

        while !unquoted.isEmpty {
            guard let firstNonBS = unquoted.firstIndex(where: { $0 != "\\" }) else {
                // String ends with a backslash (e.g. first\second\), escape all
                // the backslashes then add the metacharacter ".
                let count = unquoted.count
                quoted.append(String(repeating: "\\", count: 2 * count))
                break
            }

            let count = unquoted.distance(from: unquoted.startIndex, to: firstNonBS)
            if unquoted[firstNonBS] == "\"" {
                // This is a string of \ followed by a " (e.g. first\"second).
                // Escape the backslashes and the quote.
                quoted.append(String(repeating: "\\", count: 2 * count + 1))
            } else {
                // These are just literal backslashes
                quoted.append(String(repeating: "\\", count: count))
            }

            quoted.append(String(unquoted[firstNonBS]))

            // Drop the backslashes and the following character
            unquoted.removeFirst(count + 1)
        }
        quoted.append("\"")

        return quoted
    }