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

Function cbm_build_cmdline

src/foundation/compat_fs.c:454–549  ·  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

452 * so non-ASCII arguments (e.g. a non-ASCII %USERPROFILE%) survive intact.
453 * Declared in compat_fs_internal.h so the test suite can drive it. */
454wchar_t *cbm_build_cmdline(const char *const *argv) {
455 /* First pass: compute required buffer size. */
456 size_t total = 1; /* NUL terminator */
457 for (int i = 0; argv[i]; i++) {
458 const char *arg = argv[i];
459 bool needs_quote = (arg[0] == '\0');
460 for (const char *p = arg; *p; p++) {
461 if (*p == ' ' || *p == '\t' || *p == '"') {
462 needs_quote = true;
463 }
464 }
465 if (i > 0) {
466 total++; /* space separator */
467 }
468 if (needs_quote) {
469 total += 2; /* opening and closing quote */
470 size_t backslashes = 0;
471 for (const char *p = arg; *p; p++) {
472 if (*p == '\\') {
473 backslashes++;
474 } else if (*p == '"') {
475 total += backslashes + 1; /* double backslashes + escape backslash */
476 backslashes = 0;
477 } else {
478 backslashes = 0;
479 }
480 total++;
481 }
482 /* Trailing backslashes before closing quote must be doubled. */
483 total += backslashes;
484 } else {
485 total += strlen(arg);
486 }
487 }
488
489 /* Build the quoted command line in UTF-8 first, then widen it as a
490 * whole via cbm_utf8_to_wide. Every character the quoting logic acts
491 * on (space, tab, '"', '\\') is ASCII and, by UTF-8's design, never
492 * appears inside a multibyte sequence, so operating on raw bytes here
493 * is safe and keeps multibyte argument bytes intact for conversion. */
494 char *buf = (char *)malloc(total);
495 if (!buf) {
496 return NULL;
497 }
498
499 /* Second pass: write the command line bytes. */
500 char *w = buf;
501 for (int i = 0; argv[i]; i++) {
502 const char *arg = argv[i];
503 bool needs_quote = (arg[0] == '\0');
504 for (const char *p = arg; *p; p++) {
505 if (*p == ' ' || *p == '\t' || *p == '"') {
506 needs_quote = true;
507 break;
508 }
509 }
510 if (i > 0) {
511 *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