MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / cbm_build_cmdline

Function cbm_build_cmdline

src/foundation/compat_fs.c:589–684  ·  view source on GitHub ↗

Build a properly-quoted Windows command line from an argv array. * Returns a heap-allocated wide string, or NULL on allocation failure. * Quoting follows the MSVC CRT convention: arguments containing spaces, * tabs, or double-quotes are wrapped in double-quotes, with backslashes * before a closing quote doubled and the quote itself escaped. Argument * bytes are treated as UTF-8 and converted

Source from the content-addressed store, hash-verified

587 * so non-ASCII arguments (e.g. a non-ASCII %USERPROFILE%) survive intact.
588 * Declared in compat_fs_internal.h so the test suite can drive it. */
589wchar_t *cbm_build_cmdline(const char *const *argv) {
590 /* First pass: compute required buffer size. */
591 size_t total = 1; /* NUL terminator */
592 for (int i = 0; argv[i]; i++) {
593 const char *arg = argv[i];
594 bool needs_quote = (arg[0] == '\0');
595 for (const char *p = arg; *p; p++) {
596 if (*p == ' ' || *p == '\t' || *p == '"') {
597 needs_quote = true;
598 }
599 }
600 if (i > 0) {
601 total++; /* space separator */
602 }
603 if (needs_quote) {
604 total += 2; /* opening and closing quote */
605 size_t backslashes = 0;
606 for (const char *p = arg; *p; p++) {
607 if (*p == '\\') {
608 backslashes++;
609 } else if (*p == '"') {
610 total += backslashes + 1; /* double backslashes + escape backslash */
611 backslashes = 0;
612 } else {
613 backslashes = 0;
614 }
615 total++;
616 }
617 /* Trailing backslashes before closing quote must be doubled. */
618 total += backslashes;
619 } else {
620 total += strlen(arg);
621 }
622 }
623
624 /* Build the quoted command line in UTF-8 first, then widen it as a
625 * whole via cbm_utf8_to_wide. Every character the quoting logic acts
626 * on (space, tab, '"', '\\') is ASCII and, by UTF-8's design, never
627 * appears inside a multibyte sequence, so operating on raw bytes here
628 * is safe and keeps multibyte argument bytes intact for conversion. */
629 char *buf = (char *)malloc(total);
630 if (!buf) {
631 return NULL;
632 }
633
634 /* Second pass: write the command line bytes. */
635 char *w = buf;
636 for (int i = 0; argv[i]; i++) {
637 const char *arg = argv[i];
638 bool needs_quote = (arg[0] == '\0');
639 for (const char *p = arg; *p; p++) {
640 if (*p == ' ' || *p == '\t' || *p == '"') {
641 needs_quote = true;
642 break;
643 }
644 }
645 if (i > 0) {
646 *w++ = ' ';

Callers 2

cbm_exec_no_shellFunction · 0.85
test_security.cFile · 0.85

Calls 1

cbm_utf8_to_wideFunction · 0.85

Tested by

no test coverage detected