VirtualBox

source: kBuild/trunk/src/lib/quote_argv.c@ 2838

Last change on this file since 2838 was 2838, checked in by bird, 9 years ago

kWorker: A little more hacking.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/* $Id: quote_argv.c 2838 2016-08-25 21:46:25Z bird $ */
2/** @file
3 * quote_argv - Correctly quote argv for spawn, windows specific.
4 */
5
6/*
7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "quote_argv.h"
30#include <stdlib.h>
31#include <string.h>
32#include <ctype.h>
33
34#ifndef KBUILD_OS_WINDOWS
35# error "KBUILD_OS_WINDOWS not defined"
36#endif
37
38
39/**
40 * Checks if this is an Watcom option where we must just pass thru the string
41 * as-is.
42 *
43 * This is currnetly only used for -d (defining macros).
44 *
45 * @returns 1 if pass-thru, 0 if not.
46 * @param pszArg The argument to consider.
47 */
48static int isWatcomPassThruOption(const char *pszArg)
49{
50 char ch = *pszArg++;
51 if (ch != '-' && ch != '/')
52 return 0;
53 ch = *pszArg++;
54 switch (ch)
55 {
56 /* Example: -d+VAR="string-value" */
57 case 'd':
58 if (ch == '+')
59 ch = *pszArg++;
60 if (!isalpha(ch) && ch != '_')
61 return 0;
62 return 1;
63
64 default:
65 return 0;
66 }
67}
68
69
70/**
71 * Replaces arguments in need of quoting.
72 *
73 * For details on how MSC parses the command line, see "Parsing C Command-Line
74 * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
75 *
76 * @param argc The argument count.
77 * @param argv The argument vector.
78 * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar
79 * OpenWatcom tools. They seem to follow some
80 * ancient or home made quoting convention.
81 * @param fFreeOrLeak Whether to free replaced argv members
82 * (non-zero), or just leak them (zero). This
83 * depends on which argv you're working on.
84 * Suggest doing the latter if it's main()'s argv.
85 */
86void quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
87{
88 int i;
89 for (i = 0; i < argc; i++)
90 {
91 char *const pszOrgOrg = argv[i];
92 const char *pszOrg = pszOrgOrg;
93 size_t cchOrg = strlen(pszOrg);
94 const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
95 const char *pszProblem = NULL;
96 if ( pszQuotes
97 || cchOrg == 0
98 || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL
99 || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
100 || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
101 || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
102 || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL
103 || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL
104 || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL
105 || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL
106 || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL
107 || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
108 || ( !fWatcomBrainDamage
109 && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL)
110 )
111 {
112 char ch;
113 int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
114 size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
115 char *pszNew = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/);
116
117 argv[i] = pszNew;
118
119 /* Watcom does not grok stuff like "-i=c:\program files\watcom\h",
120 it think it's a source specification. In that case the quote
121 must follow the equal sign. */
122 if (fWatcomBrainDamage)
123 {
124 size_t cchUnquoted = 0;
125 if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
126 cchUnquoted = 1;
127 else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
128 {
129 if (isWatcomPassThruOption(pszOrg))
130 cchUnquoted = strlen(pszOrg) + 1;
131 else
132 {
133 const char *pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */
134 if ( pszNeedQuoting == NULL
135 || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
136 pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
137 else
138 pszNeedQuoting++;
139 cchUnquoted = pszNeedQuoting - pszOrg;
140 }
141 }
142 if (cchUnquoted)
143 {
144 memcpy(pszNew, pszOrg, cchUnquoted);
145 pszNew += cchUnquoted;
146 pszOrg += cchUnquoted;
147 cchOrg -= cchUnquoted;
148 }
149 }
150
151 *pszNew++ = '"';
152 if (fComplicated)
153 {
154 while ((ch = *pszOrg++) != '\0')
155 {
156 if (ch == '"')
157 {
158 *pszNew++ = '\\';
159 *pszNew++ = '"';
160 }
161 else if (ch == '\\')
162 {
163 /* Backslashes are a bit complicated, they depends on
164 whether a quotation mark follows them or not. They
165 only require escaping if one does. */
166 unsigned cSlashes = 1;
167 while ((ch = *pszOrg) == '\\')
168 {
169 pszOrg++;
170 cSlashes++;
171 }
172 if (ch == '"' || ch == '\0') /* We put a " at the EOS. */
173 {
174 while (cSlashes-- > 0)
175 {
176 *pszNew++ = '\\';
177 *pszNew++ = '\\';
178 }
179 }
180 else
181 while (cSlashes-- > 0)
182 *pszNew++ = '\\';
183 }
184 else
185 *pszNew++ = ch;
186 }
187 }
188 else
189 {
190 memcpy(pszNew, pszOrg, cchOrg);
191 pszNew += cchOrg;
192 }
193 *pszNew++ = '"';
194 *pszNew = '\0';
195
196 if (fFreeOrLeak)
197 free(pszOrgOrg);
198 }
199 }
200
201 /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
202}
203
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette