From becedd5bd29dd1ea3c21426568e6412d6b9a404e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 30 Dec 2024 08:27:31 +0000 Subject: win32: code shrink quote_arg() Alter quote_arg() to perform a single pass over the string in the case where no change is required. Based on a proposal by @avih in GitHub PR #317. Saves 16 bytes. --- win32/process.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/win32/process.c b/win32/process.c index a70b9484e..e7c9ca187 100644 --- a/win32/process.c +++ b/win32/process.c @@ -109,38 +109,34 @@ parse_interpreter(const char *cmd, interp_t *interp) char * FAST_FUNC quote_arg(const char *arg) { - char *r = xmalloc(2 * strlen(arg) + 3); // max-esc, enclosing DQ, \0 - char *d = r; - int nbs = 0; // n consecutive BS right before current char + char *d, *r = xmalloc(2 * strlen(arg) + 3); // max-esc, quotes, \0 + size_t nbs = 0; // consecutive backslashes before current char + int quoted = !*arg; - /* empty arguments and those containing tab/space must be quoted */ - if (!*arg || strpbrk(arg, " \t")) { - *d++ = '"'; - } + for (d = r; *arg; *d++ = *arg++) { + if (*arg == ' ' || *arg == '\t') + quoted = 1; + + if (*arg == '\\' || *arg == '"') + *d++ = '\\'; + else + d -= nbs; // undo nbs escapes, if any (not followed by DQ) - while (*arg) { - switch (*arg) { - case '\\': + if (*arg == '\\') ++nbs; - break; - case '"': // double consecutive-BS, plus one to escape the DQ - for (++nbs; nbs; --nbs) - *d++ = '\\'; - break; - default: // reset count if followed by not-DQ + else nbs = 0; - } - *d++ = *arg++; } - if (*r == '"') { - while (nbs--) // double consecutive-BS before the closing DQ - *d++ = '\\'; - *d++ = '"'; + if (quoted) { + memmove(r + 1, r, d++ - r); + *r = *d++ = '"'; + } else { + d -= nbs; } - *d++ = '\0'; - return xrealloc(r, d - r); + *d = 0; + return r; } char * FAST_FUNC -- cgit v1.2.3-55-g6feb