Fossil SCM
Merge the latest trunk changes and the mingw-broken-cmdline branch into unicode-cmdline.
Commit
b19ef490fdbe5822c893ae12ea8de463575a33e1
Parent
af4287ac3a314b4…
15 files changed
+24
-2
+125
-7
+125
-7
+125
-7
+7
+7
+12
+12
+12
+27
+3
-3
+2
+2
+5
+5
+24
-2
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -451,10 +451,32 @@ | ||
| 451 | 451 | } |
| 452 | 452 | } |
| 453 | 453 | manifest_destroy(pFrom); |
| 454 | 454 | manifest_destroy(pTo); |
| 455 | 455 | } |
| 456 | + | |
| 457 | +/* | |
| 458 | +** Return the name of the external diff command, or return NULL if | |
| 459 | +** no external diff command is defined. | |
| 460 | +*/ | |
| 461 | +const char *diff_command_external(int guiDiff){ | |
| 462 | + char *zDefault; | |
| 463 | + const char *zName; | |
| 464 | + | |
| 465 | + if( guiDiff ){ | |
| 466 | +#if defined(_WIN32) | |
| 467 | + zDefault = "WinDiff.exe"; | |
| 468 | +#else | |
| 469 | + zDefault = 0; | |
| 470 | +#endif | |
| 471 | + zName = "gdiff-command"; | |
| 472 | + }else{ | |
| 473 | + zDefault = 0; | |
| 474 | + zName = "diff-command"; | |
| 475 | + } | |
| 476 | + return db_get(zName, zDefault); | |
| 477 | +} | |
| 456 | 478 | |
| 457 | 479 | /* |
| 458 | 480 | ** COMMAND: diff |
| 459 | 481 | ** COMMAND: gdiff |
| 460 | 482 | ** |
| @@ -522,11 +544,11 @@ | ||
| 522 | 544 | } |
| 523 | 545 | if( zTo==0 ){ |
| 524 | 546 | db_must_be_within_tree(); |
| 525 | 547 | verify_all_options(); |
| 526 | 548 | if( !isInternDiff ){ |
| 527 | - zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); | |
| 549 | + zDiffCmd = diff_command_external(isGDiff); | |
| 528 | 550 | } |
| 529 | 551 | if( g.argc>=3 ){ |
| 530 | 552 | for(f=2; f<g.argc; ++f){ |
| 531 | 553 | diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]); |
| 532 | 554 | } |
| @@ -537,11 +559,11 @@ | ||
| 537 | 559 | fossil_fatal("must use --from if --to is present"); |
| 538 | 560 | }else{ |
| 539 | 561 | db_find_and_open_repository(0, 0); |
| 540 | 562 | verify_all_options(); |
| 541 | 563 | if( !isInternDiff ){ |
| 542 | - zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); | |
| 564 | + zDiffCmd = diff_command_external(isGDiff); | |
| 543 | 565 | } |
| 544 | 566 | if( g.argc>=3 ){ |
| 545 | 567 | for(f=2; f<g.argc; ++f){ |
| 546 | 568 | diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]); |
| 547 | 569 | } |
| 548 | 570 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -451,10 +451,32 @@ | |
| 451 | } |
| 452 | } |
| 453 | manifest_destroy(pFrom); |
| 454 | manifest_destroy(pTo); |
| 455 | } |
| 456 | |
| 457 | /* |
| 458 | ** COMMAND: diff |
| 459 | ** COMMAND: gdiff |
| 460 | ** |
| @@ -522,11 +544,11 @@ | |
| 522 | } |
| 523 | if( zTo==0 ){ |
| 524 | db_must_be_within_tree(); |
| 525 | verify_all_options(); |
| 526 | if( !isInternDiff ){ |
| 527 | zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); |
| 528 | } |
| 529 | if( g.argc>=3 ){ |
| 530 | for(f=2; f<g.argc; ++f){ |
| 531 | diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]); |
| 532 | } |
| @@ -537,11 +559,11 @@ | |
| 537 | fossil_fatal("must use --from if --to is present"); |
| 538 | }else{ |
| 539 | db_find_and_open_repository(0, 0); |
| 540 | verify_all_options(); |
| 541 | if( !isInternDiff ){ |
| 542 | zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); |
| 543 | } |
| 544 | if( g.argc>=3 ){ |
| 545 | for(f=2; f<g.argc; ++f){ |
| 546 | diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]); |
| 547 | } |
| 548 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -451,10 +451,32 @@ | |
| 451 | } |
| 452 | } |
| 453 | manifest_destroy(pFrom); |
| 454 | manifest_destroy(pTo); |
| 455 | } |
| 456 | |
| 457 | /* |
| 458 | ** Return the name of the external diff command, or return NULL if |
| 459 | ** no external diff command is defined. |
| 460 | */ |
| 461 | const char *diff_command_external(int guiDiff){ |
| 462 | char *zDefault; |
| 463 | const char *zName; |
| 464 | |
| 465 | if( guiDiff ){ |
| 466 | #if defined(_WIN32) |
| 467 | zDefault = "WinDiff.exe"; |
| 468 | #else |
| 469 | zDefault = 0; |
| 470 | #endif |
| 471 | zName = "gdiff-command"; |
| 472 | }else{ |
| 473 | zDefault = 0; |
| 474 | zName = "diff-command"; |
| 475 | } |
| 476 | return db_get(zName, zDefault); |
| 477 | } |
| 478 | |
| 479 | /* |
| 480 | ** COMMAND: diff |
| 481 | ** COMMAND: gdiff |
| 482 | ** |
| @@ -522,11 +544,11 @@ | |
| 544 | } |
| 545 | if( zTo==0 ){ |
| 546 | db_must_be_within_tree(); |
| 547 | verify_all_options(); |
| 548 | if( !isInternDiff ){ |
| 549 | zDiffCmd = diff_command_external(isGDiff); |
| 550 | } |
| 551 | if( g.argc>=3 ){ |
| 552 | for(f=2; f<g.argc; ++f){ |
| 553 | diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]); |
| 554 | } |
| @@ -537,11 +559,11 @@ | |
| 559 | fossil_fatal("must use --from if --to is present"); |
| 560 | }else{ |
| 561 | db_find_and_open_repository(0, 0); |
| 562 | verify_all_options(); |
| 563 | if( !isInternDiff ){ |
| 564 | zDiffCmd = diff_command_external(isGDiff); |
| 565 | } |
| 566 | if( g.argc>=3 ){ |
| 567 | for(f=2; f<g.argc; ++f){ |
| 568 | diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]); |
| 569 | } |
| 570 |
+125
-7
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -329,14 +329,131 @@ | ||
| 329 | 329 | free(g.zErrMsg); |
| 330 | 330 | if(g.db){ |
| 331 | 331 | db_close(0); |
| 332 | 332 | } |
| 333 | 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 | + | |
| 334 | 451 | |
| 335 | 452 | /* |
| 336 | -** Convert all arguments to UTF-8. Then search g.argv for for arguments | |
| 337 | -** "--args FILENAME". If found, then | |
| 453 | +** Convert all arguments from mbcs (or unicode) to UTF-8. Then | |
| 454 | +** search g.argv for arguments "--args FILENAME". If found, then | |
| 338 | 455 | ** (1) remove the two arguments from g.argv |
| 339 | 456 | ** (2) Read the file FILENAME |
| 340 | 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | 458 | ** (a) Ignore blank lines in the file |
| 342 | 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | ||
| 347 | 464 | Blob file = empty_blob; /* Content of the file */ |
| 348 | 465 | Blob line = empty_blob; /* One line of the file */ |
| 349 | 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | 467 | unsigned int i, j, k; /* Loop counters */ |
| 351 | 468 | int n; /* Number of bytes in one line */ |
| 352 | - char *z; /* General use string pointer */ | |
| 353 | - char **newArgv; /* New expanded g.argv under construction */ | |
| 469 | + char *z; /* General use string pointer */ | |
| 470 | + char **newArgv; /* New expanded g.argv under construction */ | |
| 354 | 471 | char const * zFileName; /* input file name */ |
| 355 | 472 | FILE * zInFile; /* input FILE */ |
| 356 | 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | 474 | #ifdef _WIN32 |
| 358 | 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | ||
| 359 | 476 | #endif |
| 360 | 477 | |
| 361 | 478 | g.argc = argc; |
| 362 | 479 | g.argv = argv; |
| 363 | 480 | #ifdef _WIN32 |
| 481 | + parse_windows_command_line(&g.argc, &g.argv); | |
| 364 | 482 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | 483 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | 484 | #ifdef UNICODE |
| 367 | 485 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | 486 | #else |
| @@ -404,11 +522,11 @@ | ||
| 404 | 522 | z[n-1] = 0; |
| 405 | 523 | if (foundBom == -1) { |
| 406 | 524 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | 525 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | 526 | if( foundBom ) { |
| 409 | - z += 3; n -= 3; | |
| 527 | + z += 3; n -= 3; | |
| 410 | 528 | } |
| 411 | 529 | } |
| 412 | 530 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | 531 | if(n==2) continue /*empty line*/; |
| 414 | 532 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | ||
| 1751 | 1869 | ** See also: cgi, http, winsrv |
| 1752 | 1870 | */ |
| 1753 | 1871 | void cmd_webserver(void){ |
| 1754 | 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | 1873 | const char *zPort; /* Value of the --port option */ |
| 1756 | - char *zBrowser; /* Name of web browser program */ | |
| 1874 | + const char *zBrowser; /* Name of web browser program */ | |
| 1757 | 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | 1878 | int flags = 0; /* Server flags */ |
| 1761 | 1879 | |
| @@ -1788,11 +1906,11 @@ | ||
| 1788 | 1906 | /* Unix implementation */ |
| 1789 | 1907 | if( isUiCmd ){ |
| 1790 | 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | 1909 | zBrowser = db_get("web-browser", 0); |
| 1792 | 1910 | if( zBrowser==0 ){ |
| 1793 | - static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1911 | + static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1794 | 1912 | int i; |
| 1795 | 1913 | zBrowser = "echo"; |
| 1796 | 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | 1916 | zBrowser = azBrowserProg[i]; |
| 1799 | 1917 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 330 | if(g.db){ |
| 331 | db_close(0); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* |
| 336 | ** Convert all arguments to UTF-8. Then search g.argv for for arguments |
| 337 | ** "--args FILENAME". If found, then |
| 338 | ** (1) remove the two arguments from g.argv |
| 339 | ** (2) Read the file FILENAME |
| 340 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | ** (a) Ignore blank lines in the file |
| 342 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 347 | Blob file = empty_blob; /* Content of the file */ |
| 348 | Blob line = empty_blob; /* One line of the file */ |
| 349 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | unsigned int i, j, k; /* Loop counters */ |
| 351 | int n; /* Number of bytes in one line */ |
| 352 | char *z; /* General use string pointer */ |
| 353 | char **newArgv; /* New expanded g.argv under construction */ |
| 354 | char const * zFileName; /* input file name */ |
| 355 | FILE * zInFile; /* input FILE */ |
| 356 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | #ifdef _WIN32 |
| 358 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | |
| 359 | #endif |
| 360 | |
| 361 | g.argc = argc; |
| 362 | g.argv = argv; |
| 363 | #ifdef _WIN32 |
| 364 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | #ifdef UNICODE |
| 367 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | #else |
| @@ -404,11 +522,11 @@ | |
| 404 | z[n-1] = 0; |
| 405 | if (foundBom == -1) { |
| 406 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | if( foundBom ) { |
| 409 | z += 3; n -= 3; |
| 410 | } |
| 411 | } |
| 412 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | if(n==2) continue /*empty line*/; |
| 414 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | |
| 1751 | ** See also: cgi, http, winsrv |
| 1752 | */ |
| 1753 | void cmd_webserver(void){ |
| 1754 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | const char *zPort; /* Value of the --port option */ |
| 1756 | char *zBrowser; /* Name of web browser program */ |
| 1757 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | int flags = 0; /* Server flags */ |
| 1761 | |
| @@ -1788,11 +1906,11 @@ | |
| 1788 | /* Unix implementation */ |
| 1789 | if( isUiCmd ){ |
| 1790 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | zBrowser = db_get("web-browser", 0); |
| 1792 | if( zBrowser==0 ){ |
| 1793 | static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1794 | int i; |
| 1795 | zBrowser = "echo"; |
| 1796 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | zBrowser = azBrowserProg[i]; |
| 1799 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 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 |
| 455 | ** (1) remove the two arguments from g.argv |
| 456 | ** (2) Read the file FILENAME |
| 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 458 | ** (a) Ignore blank lines in the file |
| 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 464 | Blob file = empty_blob; /* Content of the file */ |
| 465 | Blob line = empty_blob; /* One line of the file */ |
| 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 467 | unsigned int i, j, k; /* Loop counters */ |
| 468 | int n; /* Number of bytes in one line */ |
| 469 | char *z; /* General use string pointer */ |
| 470 | char **newArgv; /* New expanded g.argv under construction */ |
| 471 | char const * zFileName; /* input file name */ |
| 472 | FILE * zInFile; /* input FILE */ |
| 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 474 | #ifdef _WIN32 |
| 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +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 |
| @@ -404,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; |
| @@ -1751,11 +1869,11 @@ | |
| 1869 | ** See also: cgi, http, winsrv |
| 1870 | */ |
| 1871 | void cmd_webserver(void){ |
| 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1873 | const char *zPort; /* Value of the --port option */ |
| 1874 | const char *zBrowser; /* Name of web browser program */ |
| 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1878 | int flags = 0; /* Server flags */ |
| 1879 | |
| @@ -1788,11 +1906,11 @@ | |
| 1906 | /* Unix implementation */ |
| 1907 | if( isUiCmd ){ |
| 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1909 | zBrowser = db_get("web-browser", 0); |
| 1910 | if( zBrowser==0 ){ |
| 1911 | static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1912 | int i; |
| 1913 | zBrowser = "echo"; |
| 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1916 | zBrowser = azBrowserProg[i]; |
| 1917 |
+125
-7
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -329,14 +329,131 @@ | ||
| 329 | 329 | free(g.zErrMsg); |
| 330 | 330 | if(g.db){ |
| 331 | 331 | db_close(0); |
| 332 | 332 | } |
| 333 | 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 | + | |
| 334 | 451 | |
| 335 | 452 | /* |
| 336 | -** Convert all arguments to UTF-8. Then search g.argv for for arguments | |
| 337 | -** "--args FILENAME". If found, then | |
| 453 | +** Convert all arguments from mbcs (or unicode) to UTF-8. Then | |
| 454 | +** search g.argv for arguments "--args FILENAME". If found, then | |
| 338 | 455 | ** (1) remove the two arguments from g.argv |
| 339 | 456 | ** (2) Read the file FILENAME |
| 340 | 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | 458 | ** (a) Ignore blank lines in the file |
| 342 | 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | ||
| 347 | 464 | Blob file = empty_blob; /* Content of the file */ |
| 348 | 465 | Blob line = empty_blob; /* One line of the file */ |
| 349 | 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | 467 | unsigned int i, j, k; /* Loop counters */ |
| 351 | 468 | int n; /* Number of bytes in one line */ |
| 352 | - char *z; /* General use string pointer */ | |
| 353 | - char **newArgv; /* New expanded g.argv under construction */ | |
| 469 | + char *z; /* General use string pointer */ | |
| 470 | + char **newArgv; /* New expanded g.argv under construction */ | |
| 354 | 471 | char const * zFileName; /* input file name */ |
| 355 | 472 | FILE * zInFile; /* input FILE */ |
| 356 | 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | 474 | #ifdef _WIN32 |
| 358 | 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | ||
| 359 | 476 | #endif |
| 360 | 477 | |
| 361 | 478 | g.argc = argc; |
| 362 | 479 | g.argv = argv; |
| 363 | 480 | #ifdef _WIN32 |
| 481 | + parse_windows_command_line(&g.argc, &g.argv); | |
| 364 | 482 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | 483 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | 484 | #ifdef UNICODE |
| 367 | 485 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | 486 | #else |
| @@ -404,11 +522,11 @@ | ||
| 404 | 522 | z[n-1] = 0; |
| 405 | 523 | if (foundBom == -1) { |
| 406 | 524 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | 525 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | 526 | if( foundBom ) { |
| 409 | - z += 3; n -= 3; | |
| 527 | + z += 3; n -= 3; | |
| 410 | 528 | } |
| 411 | 529 | } |
| 412 | 530 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | 531 | if(n==2) continue /*empty line*/; |
| 414 | 532 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | ||
| 1751 | 1869 | ** See also: cgi, http, winsrv |
| 1752 | 1870 | */ |
| 1753 | 1871 | void cmd_webserver(void){ |
| 1754 | 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | 1873 | const char *zPort; /* Value of the --port option */ |
| 1756 | - char *zBrowser; /* Name of web browser program */ | |
| 1874 | + const char *zBrowser; /* Name of web browser program */ | |
| 1757 | 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | 1878 | int flags = 0; /* Server flags */ |
| 1761 | 1879 | |
| @@ -1788,11 +1906,11 @@ | ||
| 1788 | 1906 | /* Unix implementation */ |
| 1789 | 1907 | if( isUiCmd ){ |
| 1790 | 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | 1909 | zBrowser = db_get("web-browser", 0); |
| 1792 | 1910 | if( zBrowser==0 ){ |
| 1793 | - static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1911 | + static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1794 | 1912 | int i; |
| 1795 | 1913 | zBrowser = "echo"; |
| 1796 | 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | 1916 | zBrowser = azBrowserProg[i]; |
| 1799 | 1917 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 330 | if(g.db){ |
| 331 | db_close(0); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* |
| 336 | ** Convert all arguments to UTF-8. Then search g.argv for for arguments |
| 337 | ** "--args FILENAME". If found, then |
| 338 | ** (1) remove the two arguments from g.argv |
| 339 | ** (2) Read the file FILENAME |
| 340 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | ** (a) Ignore blank lines in the file |
| 342 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 347 | Blob file = empty_blob; /* Content of the file */ |
| 348 | Blob line = empty_blob; /* One line of the file */ |
| 349 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | unsigned int i, j, k; /* Loop counters */ |
| 351 | int n; /* Number of bytes in one line */ |
| 352 | char *z; /* General use string pointer */ |
| 353 | char **newArgv; /* New expanded g.argv under construction */ |
| 354 | char const * zFileName; /* input file name */ |
| 355 | FILE * zInFile; /* input FILE */ |
| 356 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | #ifdef _WIN32 |
| 358 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | |
| 359 | #endif |
| 360 | |
| 361 | g.argc = argc; |
| 362 | g.argv = argv; |
| 363 | #ifdef _WIN32 |
| 364 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | #ifdef UNICODE |
| 367 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | #else |
| @@ -404,11 +522,11 @@ | |
| 404 | z[n-1] = 0; |
| 405 | if (foundBom == -1) { |
| 406 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | if( foundBom ) { |
| 409 | z += 3; n -= 3; |
| 410 | } |
| 411 | } |
| 412 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | if(n==2) continue /*empty line*/; |
| 414 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | |
| 1751 | ** See also: cgi, http, winsrv |
| 1752 | */ |
| 1753 | void cmd_webserver(void){ |
| 1754 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | const char *zPort; /* Value of the --port option */ |
| 1756 | char *zBrowser; /* Name of web browser program */ |
| 1757 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | int flags = 0; /* Server flags */ |
| 1761 | |
| @@ -1788,11 +1906,11 @@ | |
| 1788 | /* Unix implementation */ |
| 1789 | if( isUiCmd ){ |
| 1790 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | zBrowser = db_get("web-browser", 0); |
| 1792 | if( zBrowser==0 ){ |
| 1793 | static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1794 | int i; |
| 1795 | zBrowser = "echo"; |
| 1796 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | zBrowser = azBrowserProg[i]; |
| 1799 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 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 |
| 455 | ** (1) remove the two arguments from g.argv |
| 456 | ** (2) Read the file FILENAME |
| 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 458 | ** (a) Ignore blank lines in the file |
| 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 464 | Blob file = empty_blob; /* Content of the file */ |
| 465 | Blob line = empty_blob; /* One line of the file */ |
| 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 467 | unsigned int i, j, k; /* Loop counters */ |
| 468 | int n; /* Number of bytes in one line */ |
| 469 | char *z; /* General use string pointer */ |
| 470 | char **newArgv; /* New expanded g.argv under construction */ |
| 471 | char const * zFileName; /* input file name */ |
| 472 | FILE * zInFile; /* input FILE */ |
| 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 474 | #ifdef _WIN32 |
| 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +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 |
| @@ -404,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; |
| @@ -1751,11 +1869,11 @@ | |
| 1869 | ** See also: cgi, http, winsrv |
| 1870 | */ |
| 1871 | void cmd_webserver(void){ |
| 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1873 | const char *zPort; /* Value of the --port option */ |
| 1874 | const char *zBrowser; /* Name of web browser program */ |
| 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1878 | int flags = 0; /* Server flags */ |
| 1879 | |
| @@ -1788,11 +1906,11 @@ | |
| 1906 | /* Unix implementation */ |
| 1907 | if( isUiCmd ){ |
| 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1909 | zBrowser = db_get("web-browser", 0); |
| 1910 | if( zBrowser==0 ){ |
| 1911 | static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1912 | int i; |
| 1913 | zBrowser = "echo"; |
| 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1916 | zBrowser = azBrowserProg[i]; |
| 1917 |
+125
-7
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -329,14 +329,131 @@ | ||
| 329 | 329 | free(g.zErrMsg); |
| 330 | 330 | if(g.db){ |
| 331 | 331 | db_close(0); |
| 332 | 332 | } |
| 333 | 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 | + | |
| 334 | 451 | |
| 335 | 452 | /* |
| 336 | -** Convert all arguments to UTF-8. Then search g.argv for for arguments | |
| 337 | -** "--args FILENAME". If found, then | |
| 453 | +** Convert all arguments from mbcs (or unicode) to UTF-8. Then | |
| 454 | +** search g.argv for arguments "--args FILENAME". If found, then | |
| 338 | 455 | ** (1) remove the two arguments from g.argv |
| 339 | 456 | ** (2) Read the file FILENAME |
| 340 | 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | 458 | ** (a) Ignore blank lines in the file |
| 342 | 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | ||
| 347 | 464 | Blob file = empty_blob; /* Content of the file */ |
| 348 | 465 | Blob line = empty_blob; /* One line of the file */ |
| 349 | 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | 467 | unsigned int i, j, k; /* Loop counters */ |
| 351 | 468 | int n; /* Number of bytes in one line */ |
| 352 | - char *z; /* General use string pointer */ | |
| 353 | - char **newArgv; /* New expanded g.argv under construction */ | |
| 469 | + char *z; /* General use string pointer */ | |
| 470 | + char **newArgv; /* New expanded g.argv under construction */ | |
| 354 | 471 | char const * zFileName; /* input file name */ |
| 355 | 472 | FILE * zInFile; /* input FILE */ |
| 356 | 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | 474 | #ifdef _WIN32 |
| 358 | 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | ||
| 359 | 476 | #endif |
| 360 | 477 | |
| 361 | 478 | g.argc = argc; |
| 362 | 479 | g.argv = argv; |
| 363 | 480 | #ifdef _WIN32 |
| 481 | + parse_windows_command_line(&g.argc, &g.argv); | |
| 364 | 482 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | 483 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | 484 | #ifdef UNICODE |
| 367 | 485 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | 486 | #else |
| @@ -404,11 +522,11 @@ | ||
| 404 | 522 | z[n-1] = 0; |
| 405 | 523 | if (foundBom == -1) { |
| 406 | 524 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | 525 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | 526 | if( foundBom ) { |
| 409 | - z += 3; n -= 3; | |
| 527 | + z += 3; n -= 3; | |
| 410 | 528 | } |
| 411 | 529 | } |
| 412 | 530 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | 531 | if(n==2) continue /*empty line*/; |
| 414 | 532 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | ||
| 1751 | 1869 | ** See also: cgi, http, winsrv |
| 1752 | 1870 | */ |
| 1753 | 1871 | void cmd_webserver(void){ |
| 1754 | 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | 1873 | const char *zPort; /* Value of the --port option */ |
| 1756 | - char *zBrowser; /* Name of web browser program */ | |
| 1874 | + const char *zBrowser; /* Name of web browser program */ | |
| 1757 | 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | 1878 | int flags = 0; /* Server flags */ |
| 1761 | 1879 | |
| @@ -1788,11 +1906,11 @@ | ||
| 1788 | 1906 | /* Unix implementation */ |
| 1789 | 1907 | if( isUiCmd ){ |
| 1790 | 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | 1909 | zBrowser = db_get("web-browser", 0); |
| 1792 | 1910 | if( zBrowser==0 ){ |
| 1793 | - static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1911 | + static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1794 | 1912 | int i; |
| 1795 | 1913 | zBrowser = "echo"; |
| 1796 | 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | 1916 | zBrowser = azBrowserProg[i]; |
| 1799 | 1917 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 330 | if(g.db){ |
| 331 | db_close(0); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* |
| 336 | ** Convert all arguments to UTF-8. Then search g.argv for for arguments |
| 337 | ** "--args FILENAME". If found, then |
| 338 | ** (1) remove the two arguments from g.argv |
| 339 | ** (2) Read the file FILENAME |
| 340 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 341 | ** (a) Ignore blank lines in the file |
| 342 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 347 | Blob file = empty_blob; /* Content of the file */ |
| 348 | Blob line = empty_blob; /* One line of the file */ |
| 349 | unsigned int nLine; /* Number of lines in the file*/ |
| 350 | unsigned int i, j, k; /* Loop counters */ |
| 351 | int n; /* Number of bytes in one line */ |
| 352 | char *z; /* General use string pointer */ |
| 353 | char **newArgv; /* New expanded g.argv under construction */ |
| 354 | char const * zFileName; /* input file name */ |
| 355 | FILE * zInFile; /* input FILE */ |
| 356 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 357 | #ifdef _WIN32 |
| 358 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +476,11 @@ | |
| 359 | #endif |
| 360 | |
| 361 | g.argc = argc; |
| 362 | g.argv = argv; |
| 363 | #ifdef _WIN32 |
| 364 | GetModuleFileNameW(NULL, buf, MAX_PATH); |
| 365 | g.argv[0] = fossil_unicode_to_utf8(buf); |
| 366 | #ifdef UNICODE |
| 367 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); |
| 368 | #else |
| @@ -404,11 +522,11 @@ | |
| 404 | z[n-1] = 0; |
| 405 | if (foundBom == -1) { |
| 406 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 407 | foundBom = memcmp(z, bom, 3)==0; |
| 408 | if( foundBom ) { |
| 409 | z += 3; n -= 3; |
| 410 | } |
| 411 | } |
| 412 | if((n>1) && ('\r'==z[n-2])){ |
| 413 | if(n==2) continue /*empty line*/; |
| 414 | z[n-2] = 0; |
| @@ -1751,11 +1869,11 @@ | |
| 1751 | ** See also: cgi, http, winsrv |
| 1752 | */ |
| 1753 | void cmd_webserver(void){ |
| 1754 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1755 | const char *zPort; /* Value of the --port option */ |
| 1756 | char *zBrowser; /* Name of web browser program */ |
| 1757 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1758 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1759 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1760 | int flags = 0; /* Server flags */ |
| 1761 | |
| @@ -1788,11 +1906,11 @@ | |
| 1788 | /* Unix implementation */ |
| 1789 | if( isUiCmd ){ |
| 1790 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1791 | zBrowser = db_get("web-browser", 0); |
| 1792 | if( zBrowser==0 ){ |
| 1793 | static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1794 | int i; |
| 1795 | zBrowser = "echo"; |
| 1796 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1797 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1798 | zBrowser = azBrowserProg[i]; |
| 1799 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -329,14 +329,131 @@ | |
| 329 | free(g.zErrMsg); |
| 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 |
| 455 | ** (1) remove the two arguments from g.argv |
| 456 | ** (2) Read the file FILENAME |
| 457 | ** (3) Use the contents of FILE to replace the two removed arguments: |
| 458 | ** (a) Ignore blank lines in the file |
| 459 | ** (b) Each non-empty line of the file is an argument, except |
| @@ -347,12 +464,12 @@ | |
| 464 | Blob file = empty_blob; /* Content of the file */ |
| 465 | Blob line = empty_blob; /* One line of the file */ |
| 466 | unsigned int nLine; /* Number of lines in the file*/ |
| 467 | unsigned int i, j, k; /* Loop counters */ |
| 468 | int n; /* Number of bytes in one line */ |
| 469 | char *z; /* General use string pointer */ |
| 470 | char **newArgv; /* New expanded g.argv under construction */ |
| 471 | char const * zFileName; /* input file name */ |
| 472 | FILE * zInFile; /* input FILE */ |
| 473 | int foundBom = -1; /* -1= not searched yet, 0 = no; 1=yes */ |
| 474 | #ifdef _WIN32 |
| 475 | wchar_t buf[MAX_PATH]; |
| @@ -359,10 +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 |
| @@ -404,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; |
| @@ -1751,11 +1869,11 @@ | |
| 1869 | ** See also: cgi, http, winsrv |
| 1870 | */ |
| 1871 | void cmd_webserver(void){ |
| 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1873 | const char *zPort; /* Value of the --port option */ |
| 1874 | const char *zBrowser; /* Name of web browser program */ |
| 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1878 | int flags = 0; /* Server flags */ |
| 1879 | |
| @@ -1788,11 +1906,11 @@ | |
| 1906 | /* Unix implementation */ |
| 1907 | if( isUiCmd ){ |
| 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1909 | zBrowser = db_get("web-browser", 0); |
| 1910 | if( zBrowser==0 ){ |
| 1911 | static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1912 | int i; |
| 1913 | zBrowser = "echo"; |
| 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1916 | zBrowser = azBrowserProg[i]; |
| 1917 |
+7
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -1088,5 +1088,12 @@ | ||
| 1088 | 1088 | |
| 1089 | 1089 | |
| 1090 | 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | 1092 | |
| 1093 | +# | |
| 1094 | +# The list of all the targets that do not correspond to real files. This stops | |
| 1095 | +# 'make' from getting confused when someone makes an error in a rule. | |
| 1096 | +# | |
| 1097 | + | |
| 1098 | +.PHONY: all install test clean | |
| 1099 | + | |
| 1093 | 1100 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -1088,5 +1088,12 @@ | |
| 1088 | |
| 1089 | |
| 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | |
| 1093 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -1088,5 +1088,12 @@ | |
| 1088 | |
| 1089 | |
| 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | |
| 1093 | # |
| 1094 | # The list of all the targets that do not correspond to real files. This stops |
| 1095 | # 'make' from getting confused when someone makes an error in a rule. |
| 1096 | # |
| 1097 | |
| 1098 | .PHONY: all install test clean |
| 1099 | |
| 1100 |
+7
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -1088,5 +1088,12 @@ | ||
| 1088 | 1088 | |
| 1089 | 1089 | |
| 1090 | 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | 1092 | |
| 1093 | +# | |
| 1094 | +# The list of all the targets that do not correspond to real files. This stops | |
| 1095 | +# 'make' from getting confused when someone makes an error in a rule. | |
| 1096 | +# | |
| 1097 | + | |
| 1098 | +.PHONY: all install test clean | |
| 1099 | + | |
| 1093 | 1100 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -1088,5 +1088,12 @@ | |
| 1088 | |
| 1089 | |
| 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | |
| 1093 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -1088,5 +1088,12 @@ | |
| 1088 | |
| 1089 | |
| 1090 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1091 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 1092 | |
| 1093 | # |
| 1094 | # The list of all the targets that do not correspond to real files. This stops |
| 1095 | # 'make' from getting confused when someone makes an error in a rule. |
| 1096 | # |
| 1097 | |
| 1098 | .PHONY: all install test clean |
| 1099 | |
| 1100 |
+12
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -303,10 +303,17 @@ | ||
| 303 | 303 | |
| 304 | 304 | set opt {} |
| 305 | 305 | writeln { |
| 306 | 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | + | |
| 309 | +# | |
| 310 | +# The list of all the targets that do not correspond to real files. This stops | |
| 311 | +# 'make' from getting confused when someone makes an error in a rule. | |
| 312 | +# | |
| 313 | + | |
| 314 | +.PHONY: all install test clean | |
| 308 | 315 | } |
| 309 | 316 | |
| 310 | 317 | close $output_file |
| 311 | 318 | # |
| 312 | 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | ||
| 466 | 473 | # With JSON support |
| 467 | 474 | ifdef FOSSIL_ENABLE_JSON |
| 468 | 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | 477 | endif |
| 478 | + | |
| 479 | +# Fix buggy MinGW command line parsing | |
| 480 | +ifdef MINGW_BROKEN_MAINARGS | |
| 481 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 482 | +endif | |
| 471 | 483 | |
| 472 | 484 | #### We add the -static option here so that we can build a static |
| 473 | 485 | # executable that will run in a chroot jail. |
| 474 | 486 | # |
| 475 | 487 | LIB = -static |
| 476 | 488 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | } |
| 309 | |
| 310 | close $output_file |
| 311 | # |
| 312 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 466 | # With JSON support |
| 467 | ifdef FOSSIL_ENABLE_JSON |
| 468 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | endif |
| 471 | |
| 472 | #### We add the -static option here so that we can build a static |
| 473 | # executable that will run in a chroot jail. |
| 474 | # |
| 475 | LIB = -static |
| 476 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | |
| 309 | # |
| 310 | # The list of all the targets that do not correspond to real files. This stops |
| 311 | # 'make' from getting confused when someone makes an error in a rule. |
| 312 | # |
| 313 | |
| 314 | .PHONY: all install test clean |
| 315 | } |
| 316 | |
| 317 | close $output_file |
| 318 | # |
| 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 473 | # With JSON support |
| 474 | ifdef FOSSIL_ENABLE_JSON |
| 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 477 | endif |
| 478 | |
| 479 | # Fix buggy MinGW command line parsing |
| 480 | ifdef MINGW_BROKEN_MAINARGS |
| 481 | TCC += -DMINGW_BROKEN_MAINARGS |
| 482 | endif |
| 483 | |
| 484 | #### We add the -static option here so that we can build a static |
| 485 | # executable that will run in a chroot jail. |
| 486 | # |
| 487 | LIB = -static |
| 488 |
+12
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -303,10 +303,17 @@ | ||
| 303 | 303 | |
| 304 | 304 | set opt {} |
| 305 | 305 | writeln { |
| 306 | 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | + | |
| 309 | +# | |
| 310 | +# The list of all the targets that do not correspond to real files. This stops | |
| 311 | +# 'make' from getting confused when someone makes an error in a rule. | |
| 312 | +# | |
| 313 | + | |
| 314 | +.PHONY: all install test clean | |
| 308 | 315 | } |
| 309 | 316 | |
| 310 | 317 | close $output_file |
| 311 | 318 | # |
| 312 | 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | ||
| 466 | 473 | # With JSON support |
| 467 | 474 | ifdef FOSSIL_ENABLE_JSON |
| 468 | 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | 477 | endif |
| 478 | + | |
| 479 | +# Fix buggy MinGW command line parsing | |
| 480 | +ifdef MINGW_BROKEN_MAINARGS | |
| 481 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 482 | +endif | |
| 471 | 483 | |
| 472 | 484 | #### We add the -static option here so that we can build a static |
| 473 | 485 | # executable that will run in a chroot jail. |
| 474 | 486 | # |
| 475 | 487 | LIB = -static |
| 476 | 488 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | } |
| 309 | |
| 310 | close $output_file |
| 311 | # |
| 312 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 466 | # With JSON support |
| 467 | ifdef FOSSIL_ENABLE_JSON |
| 468 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | endif |
| 471 | |
| 472 | #### We add the -static option here so that we can build a static |
| 473 | # executable that will run in a chroot jail. |
| 474 | # |
| 475 | LIB = -static |
| 476 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | |
| 309 | # |
| 310 | # The list of all the targets that do not correspond to real files. This stops |
| 311 | # 'make' from getting confused when someone makes an error in a rule. |
| 312 | # |
| 313 | |
| 314 | .PHONY: all install test clean |
| 315 | } |
| 316 | |
| 317 | close $output_file |
| 318 | # |
| 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 473 | # With JSON support |
| 474 | ifdef FOSSIL_ENABLE_JSON |
| 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 477 | endif |
| 478 | |
| 479 | # Fix buggy MinGW command line parsing |
| 480 | ifdef MINGW_BROKEN_MAINARGS |
| 481 | TCC += -DMINGW_BROKEN_MAINARGS |
| 482 | endif |
| 483 | |
| 484 | #### We add the -static option here so that we can build a static |
| 485 | # executable that will run in a chroot jail. |
| 486 | # |
| 487 | LIB = -static |
| 488 |
+12
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -303,10 +303,17 @@ | ||
| 303 | 303 | |
| 304 | 304 | set opt {} |
| 305 | 305 | writeln { |
| 306 | 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | + | |
| 309 | +# | |
| 310 | +# The list of all the targets that do not correspond to real files. This stops | |
| 311 | +# 'make' from getting confused when someone makes an error in a rule. | |
| 312 | +# | |
| 313 | + | |
| 314 | +.PHONY: all install test clean | |
| 308 | 315 | } |
| 309 | 316 | |
| 310 | 317 | close $output_file |
| 311 | 318 | # |
| 312 | 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | ||
| 466 | 473 | # With JSON support |
| 467 | 474 | ifdef FOSSIL_ENABLE_JSON |
| 468 | 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | 477 | endif |
| 478 | + | |
| 479 | +# Fix buggy MinGW command line parsing | |
| 480 | +ifdef MINGW_BROKEN_MAINARGS | |
| 481 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 482 | +endif | |
| 471 | 483 | |
| 472 | 484 | #### We add the -static option here so that we can build a static |
| 473 | 485 | # executable that will run in a chroot jail. |
| 474 | 486 | # |
| 475 | 487 | LIB = -static |
| 476 | 488 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | } |
| 309 | |
| 310 | close $output_file |
| 311 | # |
| 312 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 466 | # With JSON support |
| 467 | ifdef FOSSIL_ENABLE_JSON |
| 468 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 469 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 470 | endif |
| 471 | |
| 472 | #### We add the -static option here so that we can build a static |
| 473 | # executable that will run in a chroot jail. |
| 474 | # |
| 475 | LIB = -static |
| 476 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -303,10 +303,17 @@ | |
| 303 | |
| 304 | set opt {} |
| 305 | writeln { |
| 306 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 307 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE |
| 308 | |
| 309 | # |
| 310 | # The list of all the targets that do not correspond to real files. This stops |
| 311 | # 'make' from getting confused when someone makes an error in a rule. |
| 312 | # |
| 313 | |
| 314 | .PHONY: all install test clean |
| 315 | } |
| 316 | |
| 317 | close $output_file |
| 318 | # |
| 319 | # End of the main.mk output |
| @@ -466,10 +473,15 @@ | |
| 473 | # With JSON support |
| 474 | ifdef FOSSIL_ENABLE_JSON |
| 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 477 | endif |
| 478 | |
| 479 | # Fix buggy MinGW command line parsing |
| 480 | ifdef MINGW_BROKEN_MAINARGS |
| 481 | TCC += -DMINGW_BROKEN_MAINARGS |
| 482 | endif |
| 483 | |
| 484 | #### We add the -static option here so that we can build a static |
| 485 | # executable that will run in a chroot jail. |
| 486 | # |
| 487 | LIB = -static |
| 488 |
+27
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -1614,10 +1614,33 @@ | ||
| 1614 | 1614 | @ take effect. </p> |
| 1615 | 1615 | style_footer(); |
| 1616 | 1616 | db_end_transaction(0); |
| 1617 | 1617 | } |
| 1618 | 1618 | |
| 1619 | +/* | |
| 1620 | +** Prevent the RAW SQL feature from being used to ATTACH a different | |
| 1621 | +** database and query it. | |
| 1622 | +** | |
| 1623 | +** Actually, the RAW SQL feature only does a single statement per request. | |
| 1624 | +** So it is not possible to ATTACH and then do a separate query. This | |
| 1625 | +** routine is not strictly necessary, therefore. But it does not hurt | |
| 1626 | +** to be paranoid. | |
| 1627 | +*/ | |
| 1628 | +int raw_sql_query_authorizer( | |
| 1629 | + void *pError, | |
| 1630 | + int code, | |
| 1631 | + const char *zArg1, | |
| 1632 | + const char *zArg2, | |
| 1633 | + const char *zArg3, | |
| 1634 | + const char *zArg4 | |
| 1635 | +){ | |
| 1636 | + if( code==SQLITE_ATTACH ){ | |
| 1637 | + return SQLITE_DENY; | |
| 1638 | + } | |
| 1639 | + return SQLITE_OK; | |
| 1640 | +} | |
| 1641 | + | |
| 1619 | 1642 | |
| 1620 | 1643 | /* |
| 1621 | 1644 | ** WEBPAGE: admin_sql |
| 1622 | 1645 | ** |
| 1623 | 1646 | ** Run raw SQL commands against the database file using the web interface. |
| @@ -1632,10 +1655,13 @@ | ||
| 1632 | 1655 | db_begin_transaction(); |
| 1633 | 1656 | style_header("Raw SQL Commands"); |
| 1634 | 1657 | @ <p><b>Caution:</b> There are no restrictions on the SQL that can be |
| 1635 | 1658 | @ run by this page. You can do serious and irrepairable damage to the |
| 1636 | 1659 | @ repository. Proceed with extreme caution.</p> |
| 1660 | + @ | |
| 1661 | + @ <p>Only a the first statement in the entry box will be run. | |
| 1662 | + @ Any subsequent statements will be silently ignored.</p> | |
| 1637 | 1663 | @ |
| 1638 | 1664 | @ <p>Database names:<ul><li>repository → %s(db_name("repository")) |
| 1639 | 1665 | if( g.configOpen ){ |
| 1640 | 1666 | @ <li>config → %s(db_name("configdb")) |
| 1641 | 1667 | } |
| @@ -1671,10 +1697,11 @@ | ||
| 1671 | 1697 | int nCol; |
| 1672 | 1698 | int nRow = 0; |
| 1673 | 1699 | int i; |
| 1674 | 1700 | @ <hr /> |
| 1675 | 1701 | login_verify_csrf_secret(); |
| 1702 | + sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); | |
| 1676 | 1703 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1677 | 1704 | if( rc!=SQLITE_OK ){ |
| 1678 | 1705 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| 1679 | 1706 | sqlite3_finalize(pStmt); |
| 1680 | 1707 | }else if( pStmt==0 ){ |
| 1681 | 1708 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1614,10 +1614,33 @@ | |
| 1614 | @ take effect. </p> |
| 1615 | style_footer(); |
| 1616 | db_end_transaction(0); |
| 1617 | } |
| 1618 | |
| 1619 | |
| 1620 | /* |
| 1621 | ** WEBPAGE: admin_sql |
| 1622 | ** |
| 1623 | ** Run raw SQL commands against the database file using the web interface. |
| @@ -1632,10 +1655,13 @@ | |
| 1632 | db_begin_transaction(); |
| 1633 | style_header("Raw SQL Commands"); |
| 1634 | @ <p><b>Caution:</b> There are no restrictions on the SQL that can be |
| 1635 | @ run by this page. You can do serious and irrepairable damage to the |
| 1636 | @ repository. Proceed with extreme caution.</p> |
| 1637 | @ |
| 1638 | @ <p>Database names:<ul><li>repository → %s(db_name("repository")) |
| 1639 | if( g.configOpen ){ |
| 1640 | @ <li>config → %s(db_name("configdb")) |
| 1641 | } |
| @@ -1671,10 +1697,11 @@ | |
| 1671 | int nCol; |
| 1672 | int nRow = 0; |
| 1673 | int i; |
| 1674 | @ <hr /> |
| 1675 | login_verify_csrf_secret(); |
| 1676 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1677 | if( rc!=SQLITE_OK ){ |
| 1678 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| 1679 | sqlite3_finalize(pStmt); |
| 1680 | }else if( pStmt==0 ){ |
| 1681 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1614,10 +1614,33 @@ | |
| 1614 | @ take effect. </p> |
| 1615 | style_footer(); |
| 1616 | db_end_transaction(0); |
| 1617 | } |
| 1618 | |
| 1619 | /* |
| 1620 | ** Prevent the RAW SQL feature from being used to ATTACH a different |
| 1621 | ** database and query it. |
| 1622 | ** |
| 1623 | ** Actually, the RAW SQL feature only does a single statement per request. |
| 1624 | ** So it is not possible to ATTACH and then do a separate query. This |
| 1625 | ** routine is not strictly necessary, therefore. But it does not hurt |
| 1626 | ** to be paranoid. |
| 1627 | */ |
| 1628 | int raw_sql_query_authorizer( |
| 1629 | void *pError, |
| 1630 | int code, |
| 1631 | const char *zArg1, |
| 1632 | const char *zArg2, |
| 1633 | const char *zArg3, |
| 1634 | const char *zArg4 |
| 1635 | ){ |
| 1636 | if( code==SQLITE_ATTACH ){ |
| 1637 | return SQLITE_DENY; |
| 1638 | } |
| 1639 | return SQLITE_OK; |
| 1640 | } |
| 1641 | |
| 1642 | |
| 1643 | /* |
| 1644 | ** WEBPAGE: admin_sql |
| 1645 | ** |
| 1646 | ** Run raw SQL commands against the database file using the web interface. |
| @@ -1632,10 +1655,13 @@ | |
| 1655 | db_begin_transaction(); |
| 1656 | style_header("Raw SQL Commands"); |
| 1657 | @ <p><b>Caution:</b> There are no restrictions on the SQL that can be |
| 1658 | @ run by this page. You can do serious and irrepairable damage to the |
| 1659 | @ repository. Proceed with extreme caution.</p> |
| 1660 | @ |
| 1661 | @ <p>Only a the first statement in the entry box will be run. |
| 1662 | @ Any subsequent statements will be silently ignored.</p> |
| 1663 | @ |
| 1664 | @ <p>Database names:<ul><li>repository → %s(db_name("repository")) |
| 1665 | if( g.configOpen ){ |
| 1666 | @ <li>config → %s(db_name("configdb")) |
| 1667 | } |
| @@ -1671,10 +1697,11 @@ | |
| 1697 | int nCol; |
| 1698 | int nRow = 0; |
| 1699 | int i; |
| 1700 | @ <hr /> |
| 1701 | login_verify_csrf_secret(); |
| 1702 | sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); |
| 1703 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1704 | if( rc!=SQLITE_OK ){ |
| 1705 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| 1706 | sqlite3_finalize(pStmt); |
| 1707 | }else if( pStmt==0 ){ |
| 1708 |
+3
-3
| --- src/stash.c | ||
| +++ src/stash.c | ||
| @@ -549,20 +549,20 @@ | ||
| 549 | 549 | "(SELECT origname FROM stashfile WHERE stashid=%d)", |
| 550 | 550 | stashid); |
| 551 | 551 | undo_finish(); |
| 552 | 552 | }else |
| 553 | 553 | if( memcmp(zCmd, "diff", nCmd)==0 ){ |
| 554 | - const char *zDiffCmd = db_get("diff-command", 0); | |
| 554 | + const char *zDiffCmd = diff_command_external(0); | |
| 555 | 555 | u64 diffFlags = diff_options(); |
| 556 | 556 | if( g.argc>4 ) usage("diff STASHID"); |
| 557 | 557 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 558 | 558 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 559 | 559 | }else |
| 560 | 560 | if( memcmp(zCmd, "gdiff", nCmd)==0 ){ |
| 561 | - const char *zDiffCmd = db_get("gdiff-command", 0); | |
| 561 | + const char *zDiffCmd = diff_command_external(1); | |
| 562 | 562 | u64 diffFlags = diff_options(); |
| 563 | - if( g.argc>4 ) usage("diff STASHID"); | |
| 563 | + if( g.argc>4 ) usage("gdiff STASHID"); | |
| 564 | 564 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 565 | 565 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 566 | 566 | }else |
| 567 | 567 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 568 | 568 | g.argv[1] = "help"; |
| 569 | 569 | |
| 570 | 570 | ADDED test/cmdline.test |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -549,20 +549,20 @@ | |
| 549 | "(SELECT origname FROM stashfile WHERE stashid=%d)", |
| 550 | stashid); |
| 551 | undo_finish(); |
| 552 | }else |
| 553 | if( memcmp(zCmd, "diff", nCmd)==0 ){ |
| 554 | const char *zDiffCmd = db_get("diff-command", 0); |
| 555 | u64 diffFlags = diff_options(); |
| 556 | if( g.argc>4 ) usage("diff STASHID"); |
| 557 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 558 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 559 | }else |
| 560 | if( memcmp(zCmd, "gdiff", nCmd)==0 ){ |
| 561 | const char *zDiffCmd = db_get("gdiff-command", 0); |
| 562 | u64 diffFlags = diff_options(); |
| 563 | if( g.argc>4 ) usage("diff STASHID"); |
| 564 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 565 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 566 | }else |
| 567 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 568 | g.argv[1] = "help"; |
| 569 | |
| 570 | DDED test/cmdline.test |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -549,20 +549,20 @@ | |
| 549 | "(SELECT origname FROM stashfile WHERE stashid=%d)", |
| 550 | stashid); |
| 551 | undo_finish(); |
| 552 | }else |
| 553 | if( memcmp(zCmd, "diff", nCmd)==0 ){ |
| 554 | const char *zDiffCmd = diff_command_external(0); |
| 555 | u64 diffFlags = diff_options(); |
| 556 | if( g.argc>4 ) usage("diff STASHID"); |
| 557 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 558 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 559 | }else |
| 560 | if( memcmp(zCmd, "gdiff", nCmd)==0 ){ |
| 561 | const char *zDiffCmd = diff_command_external(1); |
| 562 | u64 diffFlags = diff_options(); |
| 563 | if( g.argc>4 ) usage("gdiff STASHID"); |
| 564 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 565 | stash_diff(stashid, zDiffCmd, diffFlags); |
| 566 | }else |
| 567 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 568 | g.argv[1] = "help"; |
| 569 | |
| 570 | DDED test/cmdline.test |
+2
| --- a/test/cmdline.test | ||
| +++ b/test/cmdline.test | ||
| @@ -0,0 +1,2 @@ | ||
| 1 | +# | |
| 2 | +# Copyright |
| --- a/test/cmdline.test | |
| +++ b/test/cmdline.test | |
| @@ -0,0 +1,2 @@ | |
| --- a/test/cmdline.test | |
| +++ b/test/cmdline.test | |
| @@ -0,0 +1,2 @@ | |
| 1 | # |
| 2 | # Copyright |
+2
| --- a/test/cmdline.test | ||
| +++ b/test/cmdline.test | ||
| @@ -0,0 +1,2 @@ | ||
| 1 | +# | |
| 2 | +# Copyright |
| --- a/test/cmdline.test | |
| +++ b/test/cmdline.test | |
| @@ -0,0 +1,2 @@ | |
| --- a/test/cmdline.test | |
| +++ b/test/cmdline.test | |
| @@ -0,0 +1,2 @@ | |
| 1 | # |
| 2 | # Copyright |
+5
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -145,10 +145,15 @@ | ||
| 145 | 145 | # With JSON support |
| 146 | 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | 149 | endif |
| 150 | + | |
| 151 | +# Fix buggy MinGW command line parsing | |
| 152 | +ifdef MINGW_BROKEN_MAINARGS | |
| 153 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 154 | +endif | |
| 150 | 155 | |
| 151 | 156 | #### We add the -static option here so that we can build a static |
| 152 | 157 | # executable that will run in a chroot jail. |
| 153 | 158 | # |
| 154 | 159 | LIB = -static |
| 155 | 160 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -145,10 +145,15 @@ | |
| 145 | # With JSON support |
| 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | endif |
| 150 | |
| 151 | #### We add the -static option here so that we can build a static |
| 152 | # executable that will run in a chroot jail. |
| 153 | # |
| 154 | LIB = -static |
| 155 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -145,10 +145,15 @@ | |
| 145 | # With JSON support |
| 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | endif |
| 150 | |
| 151 | # Fix buggy MinGW command line parsing |
| 152 | ifdef MINGW_BROKEN_MAINARGS |
| 153 | TCC += -DMINGW_BROKEN_MAINARGS |
| 154 | endif |
| 155 | |
| 156 | #### We add the -static option here so that we can build a static |
| 157 | # executable that will run in a chroot jail. |
| 158 | # |
| 159 | LIB = -static |
| 160 |
+5
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -145,10 +145,15 @@ | ||
| 145 | 145 | # With JSON support |
| 146 | 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | 149 | endif |
| 150 | + | |
| 151 | +# Fix buggy MinGW command line parsing | |
| 152 | +ifdef MINGW_BROKEN_MAINARGS | |
| 153 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 154 | +endif | |
| 150 | 155 | |
| 151 | 156 | #### We add the -static option here so that we can build a static |
| 152 | 157 | # executable that will run in a chroot jail. |
| 153 | 158 | # |
| 154 | 159 | LIB = -static |
| 155 | 160 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -145,10 +145,15 @@ | |
| 145 | # With JSON support |
| 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | endif |
| 150 | |
| 151 | #### We add the -static option here so that we can build a static |
| 152 | # executable that will run in a chroot jail. |
| 153 | # |
| 154 | LIB = -static |
| 155 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -145,10 +145,15 @@ | |
| 145 | # With JSON support |
| 146 | ifdef FOSSIL_ENABLE_JSON |
| 147 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 148 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 149 | endif |
| 150 | |
| 151 | # Fix buggy MinGW command line parsing |
| 152 | ifdef MINGW_BROKEN_MAINARGS |
| 153 | TCC += -DMINGW_BROKEN_MAINARGS |
| 154 | endif |
| 155 | |
| 156 | #### We add the -static option here so that we can build a static |
| 157 | # executable that will run in a chroot jail. |
| 158 | # |
| 159 | LIB = -static |
| 160 |