Fossil SCM

Reformat the windows command-line parser to following the Fossil style. Use the alternative command-line parser on all windows builds, not just for MinGW builds, to simplify the logic and so that the alternative parser code is testing more heavily.

drh 2012-09-09 22:06 UTC mingw-broken-cmdline
Commit f575af97b2221e9e822cab27b8e153c70bcd01f8
1 file changed +116 -129
+116 -129
--- src/main.c
+++ src/main.c
@@ -330,131 +330,125 @@
330330
if(g.db){
331331
db_close(0);
332332
}
333333
}
334334
335
+#if defined(_WIN32)
335336
/*
336
- *-------------------------------------------------------------------------
337
- *
338
- * setargv --
339
- *
340
- * Parse the Windows command line string into argc/argv. Done here
341
- * because we don't trust the builtin argument parser in crt0. Windows
342
- * applications are responsible for breaking their command line into
343
- * arguments.
344
- *
345
- * 2N backslashes + quote -> N backslashes + begin quoted string
346
- * 2N + 1 backslashes + quote -> literal
347
- * N backslashes + non-quote -> literal
348
- * quote + quote in a quoted string -> single quote
349
- * quote + quote not in quoted string -> empty string
350
- * quote -> begin quoted string
351
- *
352
- * Results:
353
- * Fills argcPtr with the number of arguments and argvPtr with the array
354
- * of arguments.
355
- *
356
- * Side effects:
357
- * Memory allocated.
358
- *
359
- *--------------------------------------------------------------------------
360
- */
361
-
362
-#ifdef MINGW_BROKEN_MAINARGS
337
+** Parse the command-line arguments passed to windows. We do this
338
+** ourselves to work around bugs in the command-line parsing of MinGW.
339
+** It is possible (in theory) to only use this routine when compiling
340
+** with MinGW and to use built-in command-line parsing for MSVC and
341
+** MinGW-64. However, the code is here, it is efficient, and works, and
342
+** by using it in all cases we do a better job of testing it. If you suspect
343
+** a bug in this code, test your theory by invoking "fossil test-echo".
344
+**
345
+** This routine is copied from TCL with some reformatting.
346
+** The original comment text follows:
347
+**
348
+** Parse the Windows command line string into argc/argv. Done here
349
+** because we don't trust the builtin argument parser in crt0. Windows
350
+** applications are responsible for breaking their command line into
351
+** arguments.
352
+**
353
+** 2N backslashes + quote -> N backslashes + begin quoted string
354
+** 2N + 1 backslashes + quote -> literal
355
+** N backslashes + non-quote -> literal
356
+** quote + quote in a quoted string -> single quote
357
+** quote + quote not in quoted string -> empty string
358
+** quote -> begin quoted string
359
+**
360
+** Results:
361
+** Fills argcPtr with the number of arguments and argvPtr with the array
362
+** of arguments.
363
+*/
363364
#include <tchar.h>
364
-
365
-static void
366
-setargv(
367
- int *argcPtr, /* Filled with number of argument strings. */
368
- void *argvPtr) /* Filled with argument strings (malloc'd). */
369
-{
370
- TCHAR *cmdLine, *p, *arg, *argSpace;
371
- TCHAR **argv;
372
- int argc, size, inquote, copy, slashes;
373
-
374
- cmdLine = GetCommandLine();
375
-
376
- /*
377
- * Precompute an overly pessimistic guess at the number of arguments in
378
- * the command line by counting non-space spans.
379
- */
380
-
381
- size = 2;
382
- for (p = cmdLine; *p != TEXT('\0'); p++) {
383
- if ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
384
- size++;
385
- while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
386
- p++;
387
- }
388
- if (*p == TEXT('\0')) {
389
- break;
390
- }
391
- }
392
- }
393
-
394
- argSpace = fossil_malloc(size * sizeof(char *)
395
- + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR));
396
- argv = (TCHAR **) argSpace;
397
- argSpace += size * (sizeof(char *)/sizeof(TCHAR));
398
- size--;
399
-
400
- p = cmdLine;
401
- for (argc = 0; argc < size; argc++) {
402
- argv[argc] = arg = argSpace;
403
- while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
404
- p++;
405
- }
406
- if (*p == TEXT('\0')) {
407
- break;
408
- }
409
-
410
- inquote = 0;
411
- slashes = 0;
412
- while (1) {
413
- copy = 1;
414
- while (*p == TEXT('\\')) {
415
- slashes++;
416
- p++;
417
- }
418
- if (*p == TEXT('"')) {
419
- if ((slashes & 1) == 0) {
420
- copy = 0;
421
- if ((inquote) && (p[1] == TEXT('"'))) {
422
- p++;
423
- copy = 1;
424
- } else {
425
- inquote = !inquote;
426
- }
427
- }
428
- slashes >>= 1;
429
- }
430
-
431
- while (slashes) {
432
- *arg = TEXT('\\');
433
- arg++;
434
- slashes--;
435
- }
436
-
437
- if ((*p == TEXT('\0')) || (!inquote &&
438
- ((*p == TEXT(' ')) || (*p == TEXT('\t'))))) { /* INTL: ISO space. */
439
- break;
440
- }
441
- if (copy != 0) {
442
- *arg = *p;
443
- arg++;
444
- }
445
- p++;
446
- }
447
- *arg = '\0';
448
- argSpace = arg + 1;
449
- }
450
- argv[argc] = NULL;
451
-
452
- *argcPtr = argc;
453
- *((TCHAR ***)argvPtr) = argv;
454
-}
455
-#endif /* MINGW_BROKEN_MAINARGS */
365
+#define tchar_isspace(X) ((X)==TEXT(' ') || (X)==TEXT('\t'))
366
+static void parse_windows_command_line(
367
+ int *argcPtr, /* Filled with number of argument strings. */
368
+ void *argvPtr /* Filled with argument strings (malloc'd). */
369
+){
370
+ TCHAR *cmdLine, *p, *arg, *argSpace;
371
+ TCHAR **argv;
372
+ int argc, size, inquote, copy, slashes;
373
+
374
+ cmdLine = GetCommandLine();
375
+
376
+ /*
377
+ ** Precompute an overly pessimistic guess at the number of arguments in
378
+ ** the command line by counting non-space spans.
379
+ */
380
+ size = 2;
381
+ for(p=cmdLine; *p!=TEXT('\0'); p++){
382
+ if( tchar_isspace(*p) ){
383
+ size++;
384
+ while( tchar_isspace(*p) ){
385
+ p++;
386
+ }
387
+ if( *p==TEXT('\0') ){
388
+ break;
389
+ }
390
+ }
391
+ }
392
+
393
+ argSpace = fossil_malloc(size * sizeof(char*)
394
+ + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR));
395
+ argv = (TCHAR**)argSpace;
396
+ argSpace += size*(sizeof(char*)/sizeof(TCHAR));
397
+ size--;
398
+
399
+ p = cmdLine;
400
+ for(argc=0; argc<size; argc++){
401
+ argv[argc] = arg = argSpace;
402
+ while( tchar_isspace(*p) ){
403
+ p++;
404
+ }
405
+ if (*p == TEXT('\0')) {
406
+ break;
407
+ }
408
+ inquote = 0;
409
+ slashes = 0;
410
+ while(1){
411
+ copy = 1;
412
+ while( *p==TEXT('\\') ){
413
+ slashes++;
414
+ p++;
415
+ }
416
+ if( *p==TEXT('"') ){
417
+ if( (slashes&1)==0 ){
418
+ copy = 0;
419
+ if( inquote && p[1]==TEXT('"') ){
420
+ p++;
421
+ copy = 1;
422
+ }else{
423
+ inquote = !inquote;
424
+ }
425
+ }
426
+ slashes >>= 1;
427
+ }
428
+ while( slashes ){
429
+ *arg = TEXT('\\');
430
+ arg++;
431
+ slashes--;
432
+ }
433
+ if( *p==TEXT('\0') || (!inquote && tchar_isspace(*p)) ){
434
+ break;
435
+ }
436
+ if( copy!=0 ){
437
+ *arg = *p;
438
+ arg++;
439
+ }
440
+ p++;
441
+ }
442
+ *arg = '\0';
443
+ argSpace = arg + 1;
444
+ }
445
+ argv[argc] = NULL;
446
+ *argcPtr = argc;
447
+ *((TCHAR ***)argvPtr) = argv;
448
+}
449
+#endif /* defined(_WIN32) */
456450
457451
458452
/*
459453
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
460454
** search g.argv for arguments "--args FILENAME". If found, then
@@ -482,13 +476,11 @@
482476
#endif
483477
484478
g.argc = argc;
485479
g.argv = argv;
486480
#ifdef _WIN32
487
-#ifdef MINGW_BROKEN_MAINARGS
488
- setargv(&g.argc, &g.argv);
489
-#endif
481
+ parse_windows_command_line(&g.argc, &g.argv);
490482
GetModuleFileNameW(NULL, buf, MAX_PATH);
491483
g.argv[0] = fossil_unicode_to_utf8(buf);
492484
#ifdef UNICODE
493485
for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]);
494486
#else
@@ -530,11 +522,11 @@
530522
z[n-1] = 0;
531523
if (foundBom == -1) {
532524
static const char bom[] = { 0xEF, 0xBB, 0xBF };
533525
foundBom = memcmp(z, bom, 3)==0;
534526
if( foundBom ) {
535
- z += 3; n -= 3;
527
+ z += 3; n -= 3;
536528
}
537529
}
538530
if((n>1) && ('\r'==z[n-2])){
539531
if(n==2) continue /*empty line*/;
540532
z[n-2] = 0;
@@ -560,16 +552,11 @@
560552
}
561553
562554
/*
563555
** This procedure runs first.
564556
*/
565
-#if defined(_WIN32) && defined(UNICODE) && !defined(MINGW_BROKEN_MAINARGS)
566
-int wmain(int argc, wchar_t **argv)
567
-#else
568
-int main(int argc, char **argv)
569
-#endif
570
-{
557
+int main(int argc, char **argv){
571558
const char *zCmdName = "unknown";
572559
int idx;
573560
int rc;
574561
575562
sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
576563
--- src/main.c
+++ src/main.c
@@ -330,131 +330,125 @@
330 if(g.db){
331 db_close(0);
332 }
333 }
334
 
335 /*
336 *-------------------------------------------------------------------------
337 *
338 * setargv --
339 *
340 * Parse the Windows command line string into argc/argv. Done here
341 * because we don't trust the builtin argument parser in crt0. Windows
342 * applications are responsible for breaking their command line into
343 * arguments.
344 *
345 * 2N backslashes + quote -> N backslashes + begin quoted string
346 * 2N + 1 backslashes + quote -> literal
347 * N backslashes + non-quote -> literal
348 * quote + quote in a quoted string -> single quote
349 * quote + quote not in quoted string -> empty string
350 * quote -> begin quoted string
351 *
352 * Results:
353 * Fills argcPtr with the number of arguments and argvPtr with the array
354 * of arguments.
355 *
356 * Side effects:
357 * Memory allocated.
358 *
359 *--------------------------------------------------------------------------
360 */
361
362 #ifdef MINGW_BROKEN_MAINARGS
363 #include <tchar.h>
364
365 static void
366 setargv(
367 int *argcPtr, /* Filled with number of argument strings. */
368 void *argvPtr) /* Filled with argument strings (malloc'd). */
369 {
370 TCHAR *cmdLine, *p, *arg, *argSpace;
371 TCHAR **argv;
372 int argc, size, inquote, copy, slashes;
373
374 cmdLine = GetCommandLine();
375
376 /*
377 * Precompute an overly pessimistic guess at the number of arguments in
378 * the command line by counting non-space spans.
379 */
380
381 size = 2;
382 for (p = cmdLine; *p != TEXT('\0'); p++) {
383 if ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
384 size++;
385 while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
386 p++;
387 }
388 if (*p == TEXT('\0')) {
389 break;
390 }
391 }
392 }
393
394 argSpace = fossil_malloc(size * sizeof(char *)
395 + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR));
396 argv = (TCHAR **) argSpace;
397 argSpace += size * (sizeof(char *)/sizeof(TCHAR));
398 size--;
399
400 p = cmdLine;
401 for (argc = 0; argc < size; argc++) {
402 argv[argc] = arg = argSpace;
403 while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */
404 p++;
405 }
406 if (*p == TEXT('\0')) {
407 break;
408 }
409
410 inquote = 0;
411 slashes = 0;
412 while (1) {
413 copy = 1;
414 while (*p == TEXT('\\')) {
415 slashes++;
416 p++;
417 }
418 if (*p == TEXT('"')) {
419 if ((slashes & 1) == 0) {
420 copy = 0;
421 if ((inquote) && (p[1] == TEXT('"'))) {
422 p++;
423 copy = 1;
424 } else {
425 inquote = !inquote;
426 }
427 }
428 slashes >>= 1;
429 }
430
431 while (slashes) {
432 *arg = TEXT('\\');
433 arg++;
434 slashes--;
435 }
436
437 if ((*p == TEXT('\0')) || (!inquote &&
438 ((*p == TEXT(' ')) || (*p == TEXT('\t'))))) { /* INTL: ISO space. */
439 break;
440 }
441 if (copy != 0) {
442 *arg = *p;
443 arg++;
444 }
445 p++;
446 }
447 *arg = '\0';
448 argSpace = arg + 1;
449 }
450 argv[argc] = NULL;
451
452 *argcPtr = argc;
453 *((TCHAR ***)argvPtr) = argv;
454 }
455 #endif /* MINGW_BROKEN_MAINARGS */
456
457
458 /*
459 ** Convert all arguments from mbcs (or unicode) to UTF-8. Then
460 ** search g.argv for arguments "--args FILENAME". If found, then
@@ -482,13 +476,11 @@
482 #endif
483
484 g.argc = argc;
485 g.argv = argv;
486 #ifdef _WIN32
487 #ifdef MINGW_BROKEN_MAINARGS
488 setargv(&g.argc, &g.argv);
489 #endif
490 GetModuleFileNameW(NULL, buf, MAX_PATH);
491 g.argv[0] = fossil_unicode_to_utf8(buf);
492 #ifdef UNICODE
493 for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]);
494 #else
@@ -530,11 +522,11 @@
530 z[n-1] = 0;
531 if (foundBom == -1) {
532 static const char bom[] = { 0xEF, 0xBB, 0xBF };
533 foundBom = memcmp(z, bom, 3)==0;
534 if( foundBom ) {
535 z += 3; n -= 3;
536 }
537 }
538 if((n>1) && ('\r'==z[n-2])){
539 if(n==2) continue /*empty line*/;
540 z[n-2] = 0;
@@ -560,16 +552,11 @@
560 }
561
562 /*
563 ** This procedure runs first.
564 */
565 #if defined(_WIN32) && defined(UNICODE) && !defined(MINGW_BROKEN_MAINARGS)
566 int wmain(int argc, wchar_t **argv)
567 #else
568 int main(int argc, char **argv)
569 #endif
570 {
571 const char *zCmdName = "unknown";
572 int idx;
573 int rc;
574
575 sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
576
--- src/main.c
+++ src/main.c
@@ -330,131 +330,125 @@
330 if(g.db){
331 db_close(0);
332 }
333 }
334
335 #if defined(_WIN32)
336 /*
337 ** Parse the command-line arguments passed to windows. We do this
338 ** ourselves to work around bugs in the command-line parsing of MinGW.
339 ** It is possible (in theory) to only use this routine when compiling
340 ** with MinGW and to use built-in command-line parsing for MSVC and
341 ** MinGW-64. However, the code is here, it is efficient, and works, and
342 ** by using it in all cases we do a better job of testing it. If you suspect
343 ** a bug in this code, test your theory by invoking "fossil test-echo".
344 **
345 ** This routine is copied from TCL with some reformatting.
346 ** The original comment text follows:
347 **
348 ** Parse the Windows command line string into argc/argv. Done here
349 ** because we don't trust the builtin argument parser in crt0. Windows
350 ** applications are responsible for breaking their command line into
351 ** arguments.
352 **
353 ** 2N backslashes + quote -> N backslashes + begin quoted string
354 ** 2N + 1 backslashes + quote -> literal
355 ** N backslashes + non-quote -> literal
356 ** quote + quote in a quoted string -> single quote
357 ** quote + quote not in quoted string -> empty string
358 ** quote -> begin quoted string
359 **
360 ** Results:
361 ** Fills argcPtr with the number of arguments and argvPtr with the array
362 ** of arguments.
363 */
364 #include <tchar.h>
365 #define tchar_isspace(X) ((X)==TEXT(' ') || (X)==TEXT('\t'))
366 static void parse_windows_command_line(
367 int *argcPtr, /* Filled with number of argument strings. */
368 void *argvPtr /* Filled with argument strings (malloc'd). */
369 ){
370 TCHAR *cmdLine, *p, *arg, *argSpace;
371 TCHAR **argv;
372 int argc, size, inquote, copy, slashes;
373
374 cmdLine = GetCommandLine();
375
376 /*
377 ** Precompute an overly pessimistic guess at the number of arguments in
378 ** the command line by counting non-space spans.
379 */
380 size = 2;
381 for(p=cmdLine; *p!=TEXT('\0'); p++){
382 if( tchar_isspace(*p) ){
383 size++;
384 while( tchar_isspace(*p) ){
385 p++;
386 }
387 if( *p==TEXT('\0') ){
388 break;
389 }
390 }
391 }
392
393 argSpace = fossil_malloc(size * sizeof(char*)
394 + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR));
395 argv = (TCHAR**)argSpace;
396 argSpace += size*(sizeof(char*)/sizeof(TCHAR));
397 size--;
398
399 p = cmdLine;
400 for(argc=0; argc<size; argc++){
401 argv[argc] = arg = argSpace;
402 while( tchar_isspace(*p) ){
403 p++;
404 }
405 if (*p == TEXT('\0')) {
406 break;
407 }
408 inquote = 0;
409 slashes = 0;
410 while(1){
411 copy = 1;
412 while( *p==TEXT('\\') ){
413 slashes++;
414 p++;
415 }
416 if( *p==TEXT('"') ){
417 if( (slashes&1)==0 ){
418 copy = 0;
419 if( inquote && p[1]==TEXT('"') ){
420 p++;
421 copy = 1;
422 }else{
423 inquote = !inquote;
424 }
425 }
426 slashes >>= 1;
427 }
428 while( slashes ){
429 *arg = TEXT('\\');
430 arg++;
431 slashes--;
432 }
433 if( *p==TEXT('\0') || (!inquote && tchar_isspace(*p)) ){
434 break;
435 }
436 if( copy!=0 ){
437 *arg = *p;
438 arg++;
439 }
440 p++;
441 }
442 *arg = '\0';
443 argSpace = arg + 1;
444 }
445 argv[argc] = NULL;
446 *argcPtr = argc;
447 *((TCHAR ***)argvPtr) = argv;
448 }
449 #endif /* defined(_WIN32) */
 
 
 
 
 
 
 
450
451
452 /*
453 ** Convert all arguments from mbcs (or unicode) to UTF-8. Then
454 ** search g.argv for arguments "--args FILENAME". If found, then
@@ -482,13 +476,11 @@
476 #endif
477
478 g.argc = argc;
479 g.argv = argv;
480 #ifdef _WIN32
481 parse_windows_command_line(&g.argc, &g.argv);
 
 
482 GetModuleFileNameW(NULL, buf, MAX_PATH);
483 g.argv[0] = fossil_unicode_to_utf8(buf);
484 #ifdef UNICODE
485 for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]);
486 #else
@@ -530,11 +522,11 @@
522 z[n-1] = 0;
523 if (foundBom == -1) {
524 static const char bom[] = { 0xEF, 0xBB, 0xBF };
525 foundBom = memcmp(z, bom, 3)==0;
526 if( foundBom ) {
527 z += 3; n -= 3;
528 }
529 }
530 if((n>1) && ('\r'==z[n-2])){
531 if(n==2) continue /*empty line*/;
532 z[n-2] = 0;
@@ -560,16 +552,11 @@
552 }
553
554 /*
555 ** This procedure runs first.
556 */
557 int main(int argc, char **argv){
 
 
 
 
 
558 const char *zCmdName = "unknown";
559 int idx;
560 int rc;
561
562 sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
563

Keyboard Shortcuts

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