String (String s, QuoteFlag quoteFlag, String escapingCarets) { StringBuilder sb = new StringBuilder(); int lastPos = 0; Matcher m = WIN_CARET_SPECIAL.matcher(s); while (m.find()) { quoteFlag.update(s, lastPos, m.start()); appendQuoted(sb, s.substring(lastPos, m.start())); String specialText = m.group(); boolean isCaret = specialText.equals("^"); if (isCaret) specialText = escapingCarets + specialText; // only a caret is escaped using carets if (isCaret == quoteFlag.enabled) { // a caret must be always outside quotes: close a quote temporarily, put a caret, reopen a quote // rest special chars are always inside: quote and append them as usual appendQuoted(sb, specialText); // works for both cases } else { sb.append(specialText); } lastPos = m.end(); } quoteFlag.update(s, lastPos, s.length()); appendQuoted(sb, s.substring(lastPos)); // JDK ProcessBuilder implementation on Windows checks each argument to contain whitespaces and encloses it in // double quotes unless it's already quoted. Since our escaping logic is more complicated, we may end up with // something like [^^"foo bar"], which is not a quoted string, strictly speaking; it would require additional // quotes from the JDK's point of view, which in turn ruins the quoting and caret state inside the string. // // Here, we prepend and/or append a [""] token (2 quotes to preserve the parity), if necessary, to make the result // look like a properly quoted string: // // [^^"foo bar"] -> [""^^"foo bar"] # starts and ends with quotes // if (!isQuoted(sb, Q) && StringUtil.indexOfAny(sb, " \t") >= 0) { if (sb.charAt(0) != Q) sb.insert(0, QQ); if (sb.charAt(sb.length() - 1) != Q) sb.append(QQ); } return sb.toString(); }