summaryrefslogtreecommitdiffstats
path: root/src/lib/quote_argv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/quote_argv.c')
-rw-r--r--src/lib/quote_argv.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/lib/quote_argv.c b/src/lib/quote_argv.c
new file mode 100644
index 0000000..b641ab3
--- /dev/null
+++ b/src/lib/quote_argv.c
@@ -0,0 +1,218 @@
+/* $Id: quote_argv.c 3235 2018-10-28 14:15:29Z bird $ */
+/** @file
+ * quote_argv - Correctly quote argv for spawn, windows specific.
+ */
+
+/*
+ * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "quote_argv.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef KBUILD_OS_WINDOWS
+# error "KBUILD_OS_WINDOWS not defined"
+#endif
+
+
+/**
+ * Checks if this is an Watcom option where we must just pass thru the string
+ * as-is.
+ *
+ * This is currnetly only used for -d (defining macros).
+ *
+ * @returns 1 if pass-thru, 0 if not.
+ * @param pszArg The argument to consider.
+ */
+static int isWatcomPassThruOption(const char *pszArg)
+{
+ char ch = *pszArg++;
+ if (ch != '-' && ch != '/')
+ return 0;
+ ch = *pszArg++;
+ switch (ch)
+ {
+ /* Example: -d+VAR="string-value" */
+ case 'd':
+ if (ch == '+')
+ ch = *pszArg++;
+ if (!isalpha(ch) && ch != '_')
+ return 0;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+/**
+ * Replaces arguments in need of quoting.
+ *
+ * For details on how MSC parses the command line, see "Parsing C Command-Line
+ * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
+ *
+ * @returns 0 on success, -1 if out of memory.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar
+ * OpenWatcom tools. They seem to follow some
+ * ancient or home made quoting convention.
+ * @param fFreeOrLeak Whether to free replaced argv members
+ * (non-zero), or just leak them (zero). This
+ * depends on which argv you're working on.
+ * Suggest doing the latter if it's main()'s argv.
+ */
+int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ {
+ char *const pszOrgOrg = argv[i];
+ const char *pszOrg = pszOrgOrg;
+ size_t cchOrg = strlen(pszOrg);
+ const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
+ const char *pszProblem = NULL;
+ if ( pszQuotes
+ || cchOrg == 0
+ || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL
+ || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
+ || ( !fWatcomBrainDamage
+ && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL)
+ || ( fWatcomBrainDamage
+ && (pszProblem = (const char *)memchr(pszOrg, '\\', cchOrg)) != NULL)
+ )
+ {
+ char ch;
+ int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
+ size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
+ char *pszNew = (char *)malloc(cchNew + 1 /*term*/);
+ if (!pszNew)
+ return -1;
+
+ argv[i] = pszNew;
+
+ /* Watcom does not grok stuff like "-i=c:\program files\watcom\h",
+ it think it's a source specification. In that case the quote
+ must follow the equal sign. */
+ if (fWatcomBrainDamage)
+ {
+ size_t cchUnquoted = 0;
+ if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
+ cchUnquoted = 1;
+ else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
+ {
+ const char *pszNeedQuoting;
+ if (isWatcomPassThruOption(pszOrg))
+ {
+ argv[i] = pszOrgOrg;
+ free(pszNew);
+ continue; /* No quoting needed, skip to the next argument. */
+ }
+
+ pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */
+ if ( pszNeedQuoting == NULL
+ || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
+ pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
+ else
+ pszNeedQuoting++;
+ cchUnquoted = pszNeedQuoting - pszOrg;
+ }
+ if (cchUnquoted)
+ {
+ memcpy(pszNew, pszOrg, cchUnquoted);
+ pszNew += cchUnquoted;
+ pszOrg += cchUnquoted;
+ cchOrg -= cchUnquoted;
+ }
+ }
+
+ *pszNew++ = '"';
+ if (fComplicated)
+ {
+ while ((ch = *pszOrg++) != '\0')
+ {
+ if (ch == '"')
+ {
+ *pszNew++ = '\\';
+ *pszNew++ = '"';
+ }
+ else if (ch == '\\')
+ {
+ /* Backslashes are a bit complicated, they depends on
+ whether a quotation mark follows them or not. They
+ only require escaping if one does. */
+ unsigned cSlashes = 1;
+ while ((ch = *pszOrg) == '\\')
+ {
+ pszOrg++;
+ cSlashes++;
+ }
+ if (ch == '"' || ch == '\0') /* We put a " at the EOS. */
+ {
+ while (cSlashes-- > 0)
+ {
+ *pszNew++ = '\\';
+ *pszNew++ = '\\';
+ }
+ }
+ else
+ while (cSlashes-- > 0)
+ *pszNew++ = '\\';
+ }
+ else
+ *pszNew++ = ch;
+ }
+ }
+ else
+ {
+ memcpy(pszNew, pszOrg, cchOrg);
+ pszNew += cchOrg;
+ }
+ *pszNew++ = '"';
+ *pszNew = '\0';
+
+ if (fFreeOrLeak)
+ free(pszOrgOrg);
+ }
+ }
+
+ /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
+ return 0;
+}
+