Append one argv element to the command line using the Microsoft C runtime * quoting rules (see MS "Parsing C Command-Line Arguments"). CreateProcess takes * a SINGLE string that the child re-parses back into argv, so any element with a * space, tab or double-quote must be wrapped in quotes and its embedded quotes / * preceding backslashes escaped. Without this a JSON argument like * {"repo_pa
| 235 | * non-zero at JSON-arg parse, misattributed to the last-marked file). POSIX is |
| 236 | * unaffected: the POSIX spawn path passes the argv array straight to execv. */ |
| 237 | static size_t cbm_cmdline_append_arg(char *buf, size_t cap, size_t pos, const char *arg, bool first, |
| 238 | bool *ovf) { |
| 239 | if (!first) { |
| 240 | pos = cbm_cmdline_put(buf, cap, pos, ' ', ovf); |
| 241 | } |
| 242 | pos = cbm_cmdline_put(buf, cap, pos, '"', ovf); |
| 243 | for (const char *p = arg; *p;) { |
| 244 | size_t nbs = 0; |
| 245 | while (*p == '\\') { |
| 246 | nbs++; |
| 247 | p++; |
| 248 | } |
| 249 | if (*p == '\0') { |
| 250 | /* Trailing backslashes precede the closing quote: double them so the |
| 251 | * quote stays a delimiter, not an escaped literal. */ |
| 252 | for (size_t k = 0; k < nbs * 2; k++) { |
| 253 | pos = cbm_cmdline_put(buf, cap, pos, '\\', ovf); |
| 254 | } |
| 255 | break; |
| 256 | } |
| 257 | if (*p == '"') { |
| 258 | /* N backslashes then a quote -> 2N+1 backslashes then an escaped quote. */ |
| 259 | for (size_t k = 0; k < nbs * 2 + 1; k++) { |
| 260 | pos = cbm_cmdline_put(buf, cap, pos, '\\', ovf); |
| 261 | } |
| 262 | pos = cbm_cmdline_put(buf, cap, pos, '"', ovf); |
| 263 | p++; |
| 264 | } else { |
| 265 | for (size_t k = 0; k < nbs; k++) { |
| 266 | pos = cbm_cmdline_put(buf, cap, pos, '\\', ovf); |
| 267 | } |
| 268 | pos = cbm_cmdline_put(buf, cap, pos, *p, ovf); |
| 269 | p++; |
| 270 | } |
| 271 | } |
| 272 | pos = cbm_cmdline_put(buf, cap, pos, '"', ovf); |
| 273 | return pos; |
| 274 | } |
| 275 | |
| 276 | /* Build a full Windows CreateProcess command line from a NULL-terminated argv, |
| 277 | * applying the MS C runtime quoting rules so the child re-parses byte-identical |
no test coverage detected