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.

drh 2021-06-22 17:28 trunk
Commit be6aa9e637f4e46227be7722d0c0177d836470675d107ada2f36fdd91dde81f4
1 file changed +74
+74
--- src/util.c
+++ src/util.c
@@ -28,16 +28,21 @@
2828
/*
2929
** For the fossil_timer_xxx() family of functions...
3030
*/
3131
#ifdef _WIN32
3232
# include <windows.h>
33
+# include <wchar.h>
34
+# include <process.h>
3335
#else
3436
# include <sys/time.h>
3537
# include <sys/resource.h>
3638
# include <unistd.h>
3739
# include <fcntl.h>
3840
# include <errno.h>
41
+# include <spawn.h>
42
+# include <sys/types.h>
43
+# include <wait.h>
3944
#endif
4045
4146
4247
/*
4348
** Exit. Take care to close the database first.
@@ -362,10 +367,79 @@
362367
fflush(stdout);
363368
rc = fossil_system(zLine);
364369
printf("result: %d\n", rc);
365370
}
366371
}
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
+}
367441
368442
/*
369443
** Like strcmp() except that it accepts NULL pointers. NULL sorts before
370444
** all non-NULL string pointers. Also, this strcmp() is a binary comparison
371445
** that does not consider locale.
372446
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button