History

w32: improve quoting when spawning cross-compiler

The previous code had few issues: - Didn't quote an empty string. - Didn't quote if the string contains tabs. - Didn't take into account existing backslashes at the string. E.g. previously broken (in POSIX sh, like cygwin or busybox-w32): - tcc -m 32 test.c -D 'CSTR="foo'$'\t''bar"' (wrongly rejected by tcc). - tcc -m 32 test.c -D 'CSTR="foo\"bar"' (incorrect CSTR at test.c). Both issues are fixed with the new code, and presumably any others. The empty/tabs issues could be fixed within the current code, but the backslashes issue is not worth shoehorning it, so this is a rewrite.

Avi Halachmi (:avih) committed 1 year ago

Commit 1cf33fe1 parent a6ef3181 file · +31 −14Browse files

Unified · Split

tcctools.c+31−14
@@ -497,21 +497,38 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option) · 496 unmodified lines
497497 #ifdef _WIN32
498498 #include <process.h>
499499
500−/* quote quotes in string and quote string if it contains spaces */
501−static char *quote_win32(const char *s0)
500+/* - Empty argument or with space/tab (not newline) requires quoting.
501+ * - Double-quotes at the value require '\'-escape, retardless of quoting.
502+ * - Consecutive (or 1) backslashes at the value all need '\'-escape only if
503+ * followed by [escaped] double quote, else taken literally, e.g. <x\\y\>
504+ * remains literal without quoting or esc, but <x\\"y\> becomes <x\\\\\"y\>.
505+ * - This "before double quote" rule applies also before delimiting quoting,
506+ * e.g. <x\y \"z\> becomes <"x\y \\\"z\\"> (quoting required because space).
507+ *
508+ * https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
509+ */
510+static char *quote_win32(const char *s)
502511 {
503− const char *s;
504− char *p, *q;
505− int a = 0, b = 0, c;
506− for (s = s0; !!(c = *s); ++s)
507− a += c == '"', b |= c == ' ';
508− q = p = tcc_malloc(s - s0 + a + b + b + 1);
509− *q = '"', q += b;
510− for (s = s0; !!(c = *s); *q++ = c, ++s)
511− if (c == '"')
512− *q++ = '\\';
513− *q = '"', q += b, *q = '\0';
514− return p;
512+ char *o, *r = tcc_malloc(2 * strlen(s) + 3); /* max-esc, quotes, \0 */
513+ int cbs = 0, quoted = !*s; /* consecutive backslashes before current */
514+
515+ for (o = r; *s; *o++ = *s++) {
516+ quoted |= *s == ' ' || *s == '\t';
517+ if (*s == '\\' || *s == '"')
518+ *o++ = '\\';
519+ else
520+ o -= cbs; /* undo cbs escpaes, if any (not followed by DQ) */
521+ cbs = *s == '\\' ? cbs + 1 : 0;
522+ }
523+ if (quoted) {
524+ memmove(r + 1, r, o++ - r);
525+ *r = *o++ = '"';
526+ } else {
527+ o -= cbs;
528+ }
529+
530+ *o = 0;
531+ return r; /* don't bother with realloc(r, o-r+1) */
515532 }
516533
517534 static int execvp_win32(const char *prog, char **argv)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t