Fossil SCM
There is a fossil_spawn() implementation for windows here, using _wspawnvp(). But it does not work. Apparently _wspawnvp() does not preserve the argument boundaries.
Commit
be6aa9e637f4e46227be7722d0c0177d836470675d107ada2f36fdd91dde81f4
Parent
775860ad2e5fab7…
1 file changed
+74
+74
| --- src/util.c | ||
| +++ src/util.c | ||
| @@ -28,16 +28,21 @@ | ||
| 28 | 28 | /* |
| 29 | 29 | ** For the fossil_timer_xxx() family of functions... |
| 30 | 30 | */ |
| 31 | 31 | #ifdef _WIN32 |
| 32 | 32 | # include <windows.h> |
| 33 | +# include <wchar.h> | |
| 34 | +# include <process.h> | |
| 33 | 35 | #else |
| 34 | 36 | # include <sys/time.h> |
| 35 | 37 | # include <sys/resource.h> |
| 36 | 38 | # include <unistd.h> |
| 37 | 39 | # include <fcntl.h> |
| 38 | 40 | # include <errno.h> |
| 41 | +# include <spawn.h> | |
| 42 | +# include <sys/types.h> | |
| 43 | +# include <wait.h> | |
| 39 | 44 | #endif |
| 40 | 45 | |
| 41 | 46 | |
| 42 | 47 | /* |
| 43 | 48 | ** Exit. Take care to close the database first. |
| @@ -362,10 +367,79 @@ | ||
| 362 | 367 | fflush(stdout); |
| 363 | 368 | rc = fossil_system(zLine); |
| 364 | 369 | printf("result: %d\n", rc); |
| 365 | 370 | } |
| 366 | 371 | } |
| 372 | + | |
| 373 | +/* | |
| 374 | +** A cross-platform "spawn" type function: search for zProgram in PATH, | |
| 375 | +** passing the given argument list through without interpretation. Due | |
| 376 | +** to Windows platform limitations — see the definition of WinMain() — | |
| 377 | +** this is an ideal we can achieve only on POSIX platforms. | |
| 378 | +*/ | |
| 379 | +int fossil_spawn(const char* zProgram, char *const*azArgv){ | |
| 380 | + extern char **environ; | |
| 381 | + int status = -1; | |
| 382 | +#ifdef _WIN32 | |
| 383 | + int nArg, i; | |
| 384 | + wchar_t **azWide; | |
| 385 | + for(nArg=0; azArgv[nArg]; nArg++){} | |
| 386 | + azWide = fossil_malloc( sizeof(azWide[0])+(nArg+1) ); | |
| 387 | + for(i=0; i<nArg; i++){ | |
| 388 | + azWide[i] = fossil_utf8_to_unicode(azArgv[i]); | |
| 389 | + } | |
| 390 | + azWide[i] = 0; | |
| 391 | + status = (int)_wspawnvp(_P_WAIT, azWide[0], azWide); | |
| 392 | + for(i=0; i<nArg; i++){ | |
| 393 | + fossil_unicode_free(azWide[i]); | |
| 394 | + } | |
| 395 | + fossil_free(azWide); | |
| 396 | +#else | |
| 397 | + pid_t pid; | |
| 398 | + if( posix_spawnp(&pid, zProgram, NULL, NULL, azArgv, environ)==0 ){ | |
| 399 | + waitpid(pid, &status, 0); | |
| 400 | + }else{ | |
| 401 | + fossil_fatal("posix_spawn(%s, ...) failed: %s", | |
| 402 | + zProgram, strerror(errno)); | |
| 403 | + } | |
| 404 | +#endif | |
| 405 | + return status; | |
| 406 | +} | |
| 407 | + | |
| 408 | +/* | |
| 409 | +** COMMAND: test-fossil-spawn | |
| 410 | +** | |
| 411 | +** Calls test-echo, passing each argument as-given. Used by the test | |
| 412 | +** suite to verify that this platform can pass problematic arguments | |
| 413 | +** (quotes, spaces, shell-specific escaping characters...) through | |
| 414 | +** fossil_spawn() without mangling or reinterpretation. | |
| 415 | +** | |
| 416 | +** To an outsider, this function has the same effect as test-echo, | |
| 417 | +** but the way it achieves that exercises a different subset of | |
| 418 | +** Fossil's functionality. | |
| 419 | +*/ | |
| 420 | +void test_fossil_spawn_cmd(void){ | |
| 421 | + int i, j=0, rc; | |
| 422 | + char **azArgv = fossil_malloc(sizeof(char*) * (g.argc + 1)); | |
| 423 | + azArgv[j++] = g.nameOfExe; | |
| 424 | + azArgv[j++] = "test-echo"; | |
| 425 | + if( find_option("hex",0,0) ){ | |
| 426 | + azArgv[j++] = "--hex"; | |
| 427 | + } | |
| 428 | + for( i=2; i<g.argc; ++i ){ | |
| 429 | + azArgv[j++] = g.argv[i]; | |
| 430 | + } | |
| 431 | + azArgv[j] = 0; | |
| 432 | + fossil_print("Calling with %d arguments\n", j); | |
| 433 | + for(i=0; i<j; i++){ | |
| 434 | + fossil_print("calling-argv[%d] = [%s]\n", i, azArgv[i]); | |
| 435 | + } | |
| 436 | + fossil_print("vvvvv------- the call -------vvvvv\n"); | |
| 437 | + rc = fossil_spawn(g.nameOfExe, azArgv); | |
| 438 | + fossil_print("^^^^^------- finished -------^^^^^\n"); | |
| 439 | + fossil_print("result code: %d\n", rc); | |
| 440 | +} | |
| 367 | 441 | |
| 368 | 442 | /* |
| 369 | 443 | ** Like strcmp() except that it accepts NULL pointers. NULL sorts before |
| 370 | 444 | ** all non-NULL string pointers. Also, this strcmp() is a binary comparison |
| 371 | 445 | ** that does not consider locale. |
| 372 | 446 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -28,16 +28,21 @@ | |
| 28 | /* |
| 29 | ** For the fossil_timer_xxx() family of functions... |
| 30 | */ |
| 31 | #ifdef _WIN32 |
| 32 | # include <windows.h> |
| 33 | #else |
| 34 | # include <sys/time.h> |
| 35 | # include <sys/resource.h> |
| 36 | # include <unistd.h> |
| 37 | # include <fcntl.h> |
| 38 | # include <errno.h> |
| 39 | #endif |
| 40 | |
| 41 | |
| 42 | /* |
| 43 | ** Exit. Take care to close the database first. |
| @@ -362,10 +367,79 @@ | |
| 362 | fflush(stdout); |
| 363 | rc = fossil_system(zLine); |
| 364 | printf("result: %d\n", rc); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | /* |
| 369 | ** Like strcmp() except that it accepts NULL pointers. NULL sorts before |
| 370 | ** all non-NULL string pointers. Also, this strcmp() is a binary comparison |
| 371 | ** that does not consider locale. |
| 372 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -28,16 +28,21 @@ | |
| 28 | /* |
| 29 | ** For the fossil_timer_xxx() family of functions... |
| 30 | */ |
| 31 | #ifdef _WIN32 |
| 32 | # include <windows.h> |
| 33 | # include <wchar.h> |
| 34 | # include <process.h> |
| 35 | #else |
| 36 | # include <sys/time.h> |
| 37 | # include <sys/resource.h> |
| 38 | # include <unistd.h> |
| 39 | # include <fcntl.h> |
| 40 | # include <errno.h> |
| 41 | # include <spawn.h> |
| 42 | # include <sys/types.h> |
| 43 | # include <wait.h> |
| 44 | #endif |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | ** Exit. Take care to close the database first. |
| @@ -362,10 +367,79 @@ | |
| 367 | fflush(stdout); |
| 368 | rc = fossil_system(zLine); |
| 369 | printf("result: %d\n", rc); |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | /* |
| 374 | ** A cross-platform "spawn" type function: search for zProgram in PATH, |
| 375 | ** passing the given argument list through without interpretation. Due |
| 376 | ** to Windows platform limitations — see the definition of WinMain() — |
| 377 | ** this is an ideal we can achieve only on POSIX platforms. |
| 378 | */ |
| 379 | int fossil_spawn(const char* zProgram, char *const*azArgv){ |
| 380 | extern char **environ; |
| 381 | int status = -1; |
| 382 | #ifdef _WIN32 |
| 383 | int nArg, i; |
| 384 | wchar_t **azWide; |
| 385 | for(nArg=0; azArgv[nArg]; nArg++){} |
| 386 | azWide = fossil_malloc( sizeof(azWide[0])+(nArg+1) ); |
| 387 | for(i=0; i<nArg; i++){ |
| 388 | azWide[i] = fossil_utf8_to_unicode(azArgv[i]); |
| 389 | } |
| 390 | azWide[i] = 0; |
| 391 | status = (int)_wspawnvp(_P_WAIT, azWide[0], azWide); |
| 392 | for(i=0; i<nArg; i++){ |
| 393 | fossil_unicode_free(azWide[i]); |
| 394 | } |
| 395 | fossil_free(azWide); |
| 396 | #else |
| 397 | pid_t pid; |
| 398 | if( posix_spawnp(&pid, zProgram, NULL, NULL, azArgv, environ)==0 ){ |
| 399 | waitpid(pid, &status, 0); |
| 400 | }else{ |
| 401 | fossil_fatal("posix_spawn(%s, ...) failed: %s", |
| 402 | zProgram, strerror(errno)); |
| 403 | } |
| 404 | #endif |
| 405 | return status; |
| 406 | } |
| 407 | |
| 408 | /* |
| 409 | ** COMMAND: test-fossil-spawn |
| 410 | ** |
| 411 | ** Calls test-echo, passing each argument as-given. Used by the test |
| 412 | ** suite to verify that this platform can pass problematic arguments |
| 413 | ** (quotes, spaces, shell-specific escaping characters...) through |
| 414 | ** fossil_spawn() without mangling or reinterpretation. |
| 415 | ** |
| 416 | ** To an outsider, this function has the same effect as test-echo, |
| 417 | ** but the way it achieves that exercises a different subset of |
| 418 | ** Fossil's functionality. |
| 419 | */ |
| 420 | void test_fossil_spawn_cmd(void){ |
| 421 | int i, j=0, rc; |
| 422 | char **azArgv = fossil_malloc(sizeof(char*) * (g.argc + 1)); |
| 423 | azArgv[j++] = g.nameOfExe; |
| 424 | azArgv[j++] = "test-echo"; |
| 425 | if( find_option("hex",0,0) ){ |
| 426 | azArgv[j++] = "--hex"; |
| 427 | } |
| 428 | for( i=2; i<g.argc; ++i ){ |
| 429 | azArgv[j++] = g.argv[i]; |
| 430 | } |
| 431 | azArgv[j] = 0; |
| 432 | fossil_print("Calling with %d arguments\n", j); |
| 433 | for(i=0; i<j; i++){ |
| 434 | fossil_print("calling-argv[%d] = [%s]\n", i, azArgv[i]); |
| 435 | } |
| 436 | fossil_print("vvvvv------- the call -------vvvvv\n"); |
| 437 | rc = fossil_spawn(g.nameOfExe, azArgv); |
| 438 | fossil_print("^^^^^------- finished -------^^^^^\n"); |
| 439 | fossil_print("result code: %d\n", rc); |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | ** Like strcmp() except that it accepts NULL pointers. NULL sorts before |
| 444 | ** all non-NULL string pointers. Also, this strcmp() is a binary comparison |
| 445 | ** that does not consider locale. |
| 446 |