Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder4.news.weretis.net!nuzba.szn.dk!pnx.dk!eternal-september.org!feeder.eternal-september.org!mx05.eternal-september.org!.POSTED!not-for-mail From: Steven Simpson Newsgroups: comp.lang.java.programmer Subject: Re: exec problem is JDK 1.7.0_21 Date: Tue, 23 Apr 2013 19:56:20 +0100 Organization: A noiseless patient Spider Lines: 140 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Injection-Info: mx05.eternal-september.org; posting-host="847c23adf71594bde0de355f9bb56936"; logging-data="8169"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19ZBPbyUuM72yoa7K0QqI0uSE+nKRl3QfI=" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130329 Thunderbird/17.0.5 In-Reply-To: Cancel-Lock: sha1:nyvYXLW675PKc7YLSnPfL10iHi0= Xref: csiph.com comp.lang.java.programmer:23593 On 23/04/13 10:48, Steven Simpson wrote: > Does that work correctly for anything to be thrown at CommandLineToArgvW? No, you idiot. If the argument is: C:\foo bar\ ...quotes are needed around it to escape the space: "C:\foo bar\" ...but a quote at the end will be misinterpreted as a literal quote, and result in: C:\foo bar" ...if it's allowed at all. The documentation was not clear on whether quotes needed to be around the whole argument, or could be used within: C:\foo" "bar But then you have to watch for: C:\foo\ bar\ ...which has to be escaped as something like these: C:\foo"\ "bar\ "C:\foo\ bar"\ The simplest option might be to do as before, but just put the 'final' quote immediately before any trailing backslashes: import java.util.*; import java.util.regex.*; public final class WindowsArgumentGenerator { private WindowsArgumentGenerator() { } private static final Pattern slashSequence = Pattern.compile("(\\\\*)\""); private static final Pattern spaces = Pattern.compile("\\s"); private static boolean needsQuotes(CharSequence s) { return spaces.matcher(s).find(); } public static String generateWindowsArgument(List args) { StringBuilder out = new StringBuilder(); String sep = ""; for (final CharSequence arg : args) { out.append(sep); sep = " "; final boolean quoted = needsQuotes(arg); if (quoted) out.append('"'); final int startOffset = out.length(); Matcher m = slashSequence.matcher(arg); int lastEnd = 0; while (m.find()) { out.append(arg.subSequence(lastEnd, m.start())); lastEnd = m.end(); final String slashes = m.group(1); /* Double the slashes and add one, then add the * quote. */ out.append(slashes) .append(slashes) .append('\\') .append("\""); } out.append(arg.subSequence(lastEnd, arg.length())); if (quoted) { int i = out.length(); while (i > startOffset && out.charAt(i - 1) == '\\') i--; out.insert(i, '"'); } } return out.toString(); } public static void main(String[] args) throws Exception { for (int i = 0; i < args.length; i++) System.out.printf("argv[%d]=[%s]%n", i, args[i]); System.out.println(generateWindowsArgument(Arrays.asList(args))); } } Trying it out (in bash): $ java WindowsArgumentGenerator 'hello world' argv[0]=[hello world] "hello world" $ java WindowsArgumentGenerator '"hello world"' argv[0]=["hello world"] "\"hello world\"" $ java WindowsArgumentGenerator '"hello" "world"' argv[0]=["hello" "world"] "\"hello\" \"world\"" $ java WindowsArgumentGenerator 'hello" " world' argv[0]=[hello" " world] "hello\" \" world" $ java WindowsArgumentGenerator 'hello' '""' 'world' argv[0]=[hello] argv[1]=[""] argv[2]=[world] hello \"\" world $ java WindowsArgumentGenerator 'c:\program files\' 'world' argv[0]=[c:\program files\] argv[1]=[world] "c:\program files"\ world $ java WindowsArgumentGenerator 'c:\program files\\' 'world' argv[0]=[c:\program files\\] argv[1]=[world] "c:\program files"\\ world $ java WindowsArgumentGenerator 'c:\program files\\\' 'world' argv[0]=[c:\program files\\\] argv[1]=[world] "c:\program files"\\\ world -- ss at comp dot lancs dot ac dot uk