// This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // For more information, please refer to <http://unlicense.org/> package com.facebook.buck.util; /** * Helps quote arguments when launching a process on Windows. * * <p>Unix's process spawning syscall accepts an array of arguments, but Windows' equivalent accepts * a single string and splits the strings according to some different rules. */ class WindowsCreateProcessEscape { private WindowsCreateProcessEscape() {} /** Same as {@link #quote(String)} except appends to a {@code StringBuilder}. */ public static void quote(StringBuilder buf, String arg) { if (!mightNeedQuotes(arg)) { buf.append(arg); return; } buf.append('"'); // The length of the current run of backslashes. int nPending = 0; for (int i = 0; i < arg.length(); i++) { char c = arg.charAt(i); if (c == '\\') { nPending++; } else { if (c == '"') { // Escape all the backslashes we've collected up till now. for (int j = 0; j < nPending; j++) { buf.append('\\'); } // Escape the quote. buf.append('\\'); } nPending = 0; } buf.append(c); } // Escape all the backslashes that appear before the final closing quote. for (int j = 0; j < nPending; j++) { buf.append('\\'); } buf.append('"'); } /** * Given a string X, this function returns a string that, when passed through the Windows * implementation of Java's {@link Runtime#exec(String[])} or {@link java.lang.ProcessBuilder}, * will appear to the spawned process as X. * * @param arg The argument to quote. * @return The quote version of 'arg'. */ public static String quote(String arg) { StringBuilder buf = new StringBuilder(2 + arg.length() * 2); quote(buf, arg); return buf.toString(); } private static boolean mightNeedQuotes(String arg) { if (arg.length() == 0) { return true; } for (int i = 0; i < arg.length(); i++) { char c = arg.charAt(i); if (c == '"' || c == ' ' || c == '\t') { return true; } } return false; } }