Return a newly-allocated argv-like array, by parsing and splitting the input 'str'. 'extra_argc' is the number of additional elements to allocate in the array (on top of the number of args required to split 'str'). Store into *argc the number of arguments found (plus 1 for the program name). Example: int argc; char **argv = build_argv ("A=B uname -k', 3, &argc); R
| 363 | and the complexity of keeping track of the storage that may have been |
| 364 | allocated via multiple calls to build_argv is not worth the hassle. */ |
| 365 | static char ** |
| 366 | build_argv (char const *str, int extra_argc, int *argc) |
| 367 | { |
| 368 | bool dq = false, sq = false; |
| 369 | struct splitbuf ss; |
| 370 | ss.argv = xnmalloc (extra_argc + 2, 2 * sizeof *ss.argv); |
| 371 | ss.argc = 1; |
| 372 | ss.half_alloc = extra_argc + 2; |
| 373 | ss.extra_argc = extra_argc; |
| 374 | ss.sep = true; |
| 375 | ss.argv[ss.argc] = NULL; |
| 376 | |
| 377 | /* In the following loop, |
| 378 | 'break' causes the character 'newc' to be added to *dest, |
| 379 | 'continue' skips the character. */ |
| 380 | while (*str) |
| 381 | { |
| 382 | char newc = *str; /* Default: add the next character. */ |
| 383 | |
| 384 | switch (*str) |
| 385 | { |
| 386 | case '\'': |
| 387 | if (dq) |
| 388 | break; |
| 389 | sq = !sq; |
| 390 | check_start_new_arg (&ss); |
| 391 | ++str; |
| 392 | continue; |
| 393 | |
| 394 | case '"': |
| 395 | if (sq) |
| 396 | break; |
| 397 | dq = !dq; |
| 398 | check_start_new_arg (&ss); |
| 399 | ++str; |
| 400 | continue; |
| 401 | |
| 402 | case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': |
| 403 | /* Start a new argument if outside quotes. */ |
| 404 | if (sq || dq) |
| 405 | break; |
| 406 | ss.sep = true; |
| 407 | str += strspn (str, C_ISSPACE_CHARS); |
| 408 | continue; |
| 409 | |
| 410 | case '#': |
| 411 | if (!ss.sep) |
| 412 | break; |
| 413 | goto eos; /* '#' as first char terminates the string. */ |
| 414 | |
| 415 | case '\\': |
| 416 | /* Backslash inside single-quotes is not special, except \\ |
| 417 | and \'. */ |
| 418 | if (sq && str[1] != '\\' && str[1] != '\'') |
| 419 | break; |
| 420 | |
| 421 | /* Skip the backslash and examine the next character. */ |
| 422 | newc = *++str; |
no test coverage detected