Fossil SCM
Merge the unicode-cmdline branch into trunk.
Commit
f668ff44c04174dd04bae5f594aa1fd7852f67af
Parent
ffcdfadbda404d9…
9 files changed
+13
-19
+51
-28
+149
-22
+5
+9
-18
+37
-30
+2
+5
+1
-1
+13
-19
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -130,11 +130,11 @@ | ||
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | /* |
| 133 | 133 | ** A reallocation function that assumes that aData came from malloc(). |
| 134 | 134 | ** This function attempts to resize the buffer of the blob to hold |
| 135 | -** newSize bytes. | |
| 135 | +** newSize bytes. | |
| 136 | 136 | ** |
| 137 | 137 | ** No attempt is made to recover from an out-of-memory error. |
| 138 | 138 | ** If an OOM error occurs, an error message is printed on stderr |
| 139 | 139 | ** and the program exits. |
| 140 | 140 | */ |
| @@ -368,11 +368,11 @@ | ||
| 368 | 368 | ((B)->nUsed==sizeof(S)-1 && memcmp((B)->aData,S,sizeof(S)-1)==0) |
| 369 | 369 | #endif |
| 370 | 370 | |
| 371 | 371 | |
| 372 | 372 | /* |
| 373 | -** Attempt to resize a blob so that its internal buffer is | |
| 373 | +** Attempt to resize a blob so that its internal buffer is | |
| 374 | 374 | ** nByte in size. The blob is truncated if necessary. |
| 375 | 375 | */ |
| 376 | 376 | void blob_resize(Blob *pBlob, unsigned int newSize){ |
| 377 | 377 | pBlob->xRealloc(pBlob, newSize+1); |
| 378 | 378 | pBlob->nUsed = newSize; |
| @@ -453,11 +453,11 @@ | ||
| 453 | 453 | int blob_tell(Blob *p){ |
| 454 | 454 | return p->iCursor; |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | 457 | /* |
| 458 | -** Extract a single line of text from pFrom beginning at the current | |
| 458 | +** Extract a single line of text from pFrom beginning at the current | |
| 459 | 459 | ** cursor location and use that line of text to initialize pTo. |
| 460 | 460 | ** pTo will include the terminating \n. Return the number of bytes |
| 461 | 461 | ** in the line including the \n at the end. 0 is returned at |
| 462 | 462 | ** end-of-file. |
| 463 | 463 | ** |
| @@ -669,11 +669,11 @@ | ||
| 669 | 669 | void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){ |
| 670 | 670 | vxprintf(pBlob, zFormat, ap); |
| 671 | 671 | } |
| 672 | 672 | |
| 673 | 673 | /* |
| 674 | -** Initalize a blob to the data on an input channel. Return | |
| 674 | +** Initalize a blob to the data on an input channel. Return | |
| 675 | 675 | ** the number of bytes read into the blob. Any prior content |
| 676 | 676 | ** of the blob is discarded, not freed. |
| 677 | 677 | */ |
| 678 | 678 | int blob_read_from_channel(Blob *pBlob, FILE *in, int nToRead){ |
| 679 | 679 | size_t n; |
| @@ -767,22 +767,16 @@ | ||
| 767 | 767 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 768 | 768 | FILE *out; |
| 769 | 769 | int wrote; |
| 770 | 770 | |
| 771 | 771 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 772 | - int n; | |
| 772 | + int n = blob_size(pBlob); | |
| 773 | 773 | #if defined(_WIN32) |
| 774 | - if( _isatty(fileno(stdout)) ){ | |
| 775 | - char *z; | |
| 776 | - z = fossil_utf8_to_console(blob_str(pBlob)); | |
| 777 | - n = strlen(z); | |
| 778 | - fwrite(z, 1, n, stdout); | |
| 779 | - free(z); | |
| 774 | + if( fossil_utf8_to_console(blob_buffer(pBlob), n, 0) >= 0 ){ | |
| 780 | 775 | return n; |
| 781 | 776 | } |
| 782 | 777 | #endif |
| 783 | - n = blob_size(pBlob); | |
| 784 | 778 | fwrite(blob_buffer(pBlob), 1, n, stdout); |
| 785 | 779 | return n; |
| 786 | 780 | }else{ |
| 787 | 781 | int i, nName; |
| 788 | 782 | char *zName, zBuf[1000]; |
| @@ -833,12 +827,12 @@ | ||
| 833 | 827 | return wrote; |
| 834 | 828 | } |
| 835 | 829 | |
| 836 | 830 | /* |
| 837 | 831 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 838 | -** pOut to be the same blob. | |
| 839 | -** | |
| 832 | +** pOut to be the same blob. | |
| 833 | +** | |
| 840 | 834 | ** pOut must either be the same as pIn or else uninitialized. |
| 841 | 835 | */ |
| 842 | 836 | void blob_compress(Blob *pIn, Blob *pOut){ |
| 843 | 837 | unsigned int nIn = blob_size(pIn); |
| 844 | 838 | unsigned int nOut = 13 + nIn + (nIn+999)/1000; |
| @@ -871,13 +865,13 @@ | ||
| 871 | 865 | blob_compress(&f, &f); |
| 872 | 866 | blob_write_to_file(&f, g.argv[3]); |
| 873 | 867 | } |
| 874 | 868 | |
| 875 | 869 | /* |
| 876 | -** Compress the concatenation of a blobs pIn1 and pIn2. Store the result | |
| 877 | -** in pOut. | |
| 878 | -** | |
| 870 | +** Compress the concatenation of a blobs pIn1 and pIn2. Store the result | |
| 871 | +** in pOut. | |
| 872 | +** | |
| 879 | 873 | ** pOut must be either uninitialized or must be the same as either pIn1 or |
| 880 | 874 | ** pIn2. |
| 881 | 875 | */ |
| 882 | 876 | void blob_compress2(Blob *pIn1, Blob *pIn2, Blob *pOut){ |
| 883 | 877 | unsigned int nIn = blob_size(pIn1) + blob_size(pIn2); |
| @@ -944,11 +938,11 @@ | ||
| 944 | 938 | inBuf = (unsigned char*)blob_buffer(pIn); |
| 945 | 939 | nOut = (inBuf[0]<<24) + (inBuf[1]<<16) + (inBuf[2]<<8) + inBuf[3]; |
| 946 | 940 | blob_zero(&temp); |
| 947 | 941 | blob_resize(&temp, nOut+1); |
| 948 | 942 | nOut2 = (long int)nOut; |
| 949 | - rc = uncompress((unsigned char*)blob_buffer(&temp), &nOut2, | |
| 943 | + rc = uncompress((unsigned char*)blob_buffer(&temp), &nOut2, | |
| 950 | 944 | &inBuf[4], nIn - 4); |
| 951 | 945 | if( rc!=Z_OK ){ |
| 952 | 946 | blob_reset(&temp); |
| 953 | 947 | return 1; |
| 954 | 948 | } |
| @@ -1062,11 +1056,11 @@ | ||
| 1062 | 1056 | ** |
| 1063 | 1057 | ** Returns the number of bytes read/copied, which may be less than |
| 1064 | 1058 | ** nLen (if end-of-blob is encountered). |
| 1065 | 1059 | ** |
| 1066 | 1060 | ** Updates pIn's cursor. |
| 1067 | -** | |
| 1061 | +** | |
| 1068 | 1062 | ** Returns 0 if pIn contains no data. |
| 1069 | 1063 | */ |
| 1070 | 1064 | unsigned int blob_read(Blob *pIn, void * pDest, unsigned int nLen ){ |
| 1071 | 1065 | if( !pIn->aData || (pIn->iCursor >= pIn->nUsed) ){ |
| 1072 | 1066 | return 0; |
| 1073 | 1067 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -130,11 +130,11 @@ | |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | ** A reallocation function that assumes that aData came from malloc(). |
| 134 | ** This function attempts to resize the buffer of the blob to hold |
| 135 | ** newSize bytes. |
| 136 | ** |
| 137 | ** No attempt is made to recover from an out-of-memory error. |
| 138 | ** If an OOM error occurs, an error message is printed on stderr |
| 139 | ** and the program exits. |
| 140 | */ |
| @@ -368,11 +368,11 @@ | |
| 368 | ((B)->nUsed==sizeof(S)-1 && memcmp((B)->aData,S,sizeof(S)-1)==0) |
| 369 | #endif |
| 370 | |
| 371 | |
| 372 | /* |
| 373 | ** Attempt to resize a blob so that its internal buffer is |
| 374 | ** nByte in size. The blob is truncated if necessary. |
| 375 | */ |
| 376 | void blob_resize(Blob *pBlob, unsigned int newSize){ |
| 377 | pBlob->xRealloc(pBlob, newSize+1); |
| 378 | pBlob->nUsed = newSize; |
| @@ -453,11 +453,11 @@ | |
| 453 | int blob_tell(Blob *p){ |
| 454 | return p->iCursor; |
| 455 | } |
| 456 | |
| 457 | /* |
| 458 | ** Extract a single line of text from pFrom beginning at the current |
| 459 | ** cursor location and use that line of text to initialize pTo. |
| 460 | ** pTo will include the terminating \n. Return the number of bytes |
| 461 | ** in the line including the \n at the end. 0 is returned at |
| 462 | ** end-of-file. |
| 463 | ** |
| @@ -669,11 +669,11 @@ | |
| 669 | void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){ |
| 670 | vxprintf(pBlob, zFormat, ap); |
| 671 | } |
| 672 | |
| 673 | /* |
| 674 | ** Initalize a blob to the data on an input channel. Return |
| 675 | ** the number of bytes read into the blob. Any prior content |
| 676 | ** of the blob is discarded, not freed. |
| 677 | */ |
| 678 | int blob_read_from_channel(Blob *pBlob, FILE *in, int nToRead){ |
| 679 | size_t n; |
| @@ -767,22 +767,16 @@ | |
| 767 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 768 | FILE *out; |
| 769 | int wrote; |
| 770 | |
| 771 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 772 | int n; |
| 773 | #if defined(_WIN32) |
| 774 | if( _isatty(fileno(stdout)) ){ |
| 775 | char *z; |
| 776 | z = fossil_utf8_to_console(blob_str(pBlob)); |
| 777 | n = strlen(z); |
| 778 | fwrite(z, 1, n, stdout); |
| 779 | free(z); |
| 780 | return n; |
| 781 | } |
| 782 | #endif |
| 783 | n = blob_size(pBlob); |
| 784 | fwrite(blob_buffer(pBlob), 1, n, stdout); |
| 785 | return n; |
| 786 | }else{ |
| 787 | int i, nName; |
| 788 | char *zName, zBuf[1000]; |
| @@ -833,12 +827,12 @@ | |
| 833 | return wrote; |
| 834 | } |
| 835 | |
| 836 | /* |
| 837 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 838 | ** pOut to be the same blob. |
| 839 | ** |
| 840 | ** pOut must either be the same as pIn or else uninitialized. |
| 841 | */ |
| 842 | void blob_compress(Blob *pIn, Blob *pOut){ |
| 843 | unsigned int nIn = blob_size(pIn); |
| 844 | unsigned int nOut = 13 + nIn + (nIn+999)/1000; |
| @@ -871,13 +865,13 @@ | |
| 871 | blob_compress(&f, &f); |
| 872 | blob_write_to_file(&f, g.argv[3]); |
| 873 | } |
| 874 | |
| 875 | /* |
| 876 | ** Compress the concatenation of a blobs pIn1 and pIn2. Store the result |
| 877 | ** in pOut. |
| 878 | ** |
| 879 | ** pOut must be either uninitialized or must be the same as either pIn1 or |
| 880 | ** pIn2. |
| 881 | */ |
| 882 | void blob_compress2(Blob *pIn1, Blob *pIn2, Blob *pOut){ |
| 883 | unsigned int nIn = blob_size(pIn1) + blob_size(pIn2); |
| @@ -944,11 +938,11 @@ | |
| 944 | inBuf = (unsigned char*)blob_buffer(pIn); |
| 945 | nOut = (inBuf[0]<<24) + (inBuf[1]<<16) + (inBuf[2]<<8) + inBuf[3]; |
| 946 | blob_zero(&temp); |
| 947 | blob_resize(&temp, nOut+1); |
| 948 | nOut2 = (long int)nOut; |
| 949 | rc = uncompress((unsigned char*)blob_buffer(&temp), &nOut2, |
| 950 | &inBuf[4], nIn - 4); |
| 951 | if( rc!=Z_OK ){ |
| 952 | blob_reset(&temp); |
| 953 | return 1; |
| 954 | } |
| @@ -1062,11 +1056,11 @@ | |
| 1062 | ** |
| 1063 | ** Returns the number of bytes read/copied, which may be less than |
| 1064 | ** nLen (if end-of-blob is encountered). |
| 1065 | ** |
| 1066 | ** Updates pIn's cursor. |
| 1067 | ** |
| 1068 | ** Returns 0 if pIn contains no data. |
| 1069 | */ |
| 1070 | unsigned int blob_read(Blob *pIn, void * pDest, unsigned int nLen ){ |
| 1071 | if( !pIn->aData || (pIn->iCursor >= pIn->nUsed) ){ |
| 1072 | return 0; |
| 1073 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -130,11 +130,11 @@ | |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | ** A reallocation function that assumes that aData came from malloc(). |
| 134 | ** This function attempts to resize the buffer of the blob to hold |
| 135 | ** newSize bytes. |
| 136 | ** |
| 137 | ** No attempt is made to recover from an out-of-memory error. |
| 138 | ** If an OOM error occurs, an error message is printed on stderr |
| 139 | ** and the program exits. |
| 140 | */ |
| @@ -368,11 +368,11 @@ | |
| 368 | ((B)->nUsed==sizeof(S)-1 && memcmp((B)->aData,S,sizeof(S)-1)==0) |
| 369 | #endif |
| 370 | |
| 371 | |
| 372 | /* |
| 373 | ** Attempt to resize a blob so that its internal buffer is |
| 374 | ** nByte in size. The blob is truncated if necessary. |
| 375 | */ |
| 376 | void blob_resize(Blob *pBlob, unsigned int newSize){ |
| 377 | pBlob->xRealloc(pBlob, newSize+1); |
| 378 | pBlob->nUsed = newSize; |
| @@ -453,11 +453,11 @@ | |
| 453 | int blob_tell(Blob *p){ |
| 454 | return p->iCursor; |
| 455 | } |
| 456 | |
| 457 | /* |
| 458 | ** Extract a single line of text from pFrom beginning at the current |
| 459 | ** cursor location and use that line of text to initialize pTo. |
| 460 | ** pTo will include the terminating \n. Return the number of bytes |
| 461 | ** in the line including the \n at the end. 0 is returned at |
| 462 | ** end-of-file. |
| 463 | ** |
| @@ -669,11 +669,11 @@ | |
| 669 | void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){ |
| 670 | vxprintf(pBlob, zFormat, ap); |
| 671 | } |
| 672 | |
| 673 | /* |
| 674 | ** Initalize a blob to the data on an input channel. Return |
| 675 | ** the number of bytes read into the blob. Any prior content |
| 676 | ** of the blob is discarded, not freed. |
| 677 | */ |
| 678 | int blob_read_from_channel(Blob *pBlob, FILE *in, int nToRead){ |
| 679 | size_t n; |
| @@ -767,22 +767,16 @@ | |
| 767 | int blob_write_to_file(Blob *pBlob, const char *zFilename){ |
| 768 | FILE *out; |
| 769 | int wrote; |
| 770 | |
| 771 | if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){ |
| 772 | int n = blob_size(pBlob); |
| 773 | #if defined(_WIN32) |
| 774 | if( fossil_utf8_to_console(blob_buffer(pBlob), n, 0) >= 0 ){ |
| 775 | return n; |
| 776 | } |
| 777 | #endif |
| 778 | fwrite(blob_buffer(pBlob), 1, n, stdout); |
| 779 | return n; |
| 780 | }else{ |
| 781 | int i, nName; |
| 782 | char *zName, zBuf[1000]; |
| @@ -833,12 +827,12 @@ | |
| 827 | return wrote; |
| 828 | } |
| 829 | |
| 830 | /* |
| 831 | ** Compress a blob pIn. Store the result in pOut. It is ok for pIn and |
| 832 | ** pOut to be the same blob. |
| 833 | ** |
| 834 | ** pOut must either be the same as pIn or else uninitialized. |
| 835 | */ |
| 836 | void blob_compress(Blob *pIn, Blob *pOut){ |
| 837 | unsigned int nIn = blob_size(pIn); |
| 838 | unsigned int nOut = 13 + nIn + (nIn+999)/1000; |
| @@ -871,13 +865,13 @@ | |
| 865 | blob_compress(&f, &f); |
| 866 | blob_write_to_file(&f, g.argv[3]); |
| 867 | } |
| 868 | |
| 869 | /* |
| 870 | ** Compress the concatenation of a blobs pIn1 and pIn2. Store the result |
| 871 | ** in pOut. |
| 872 | ** |
| 873 | ** pOut must be either uninitialized or must be the same as either pIn1 or |
| 874 | ** pIn2. |
| 875 | */ |
| 876 | void blob_compress2(Blob *pIn1, Blob *pIn2, Blob *pOut){ |
| 877 | unsigned int nIn = blob_size(pIn1) + blob_size(pIn2); |
| @@ -944,11 +938,11 @@ | |
| 938 | inBuf = (unsigned char*)blob_buffer(pIn); |
| 939 | nOut = (inBuf[0]<<24) + (inBuf[1]<<16) + (inBuf[2]<<8) + inBuf[3]; |
| 940 | blob_zero(&temp); |
| 941 | blob_resize(&temp, nOut+1); |
| 942 | nOut2 = (long int)nOut; |
| 943 | rc = uncompress((unsigned char*)blob_buffer(&temp), &nOut2, |
| 944 | &inBuf[4], nIn - 4); |
| 945 | if( rc!=Z_OK ){ |
| 946 | blob_reset(&temp); |
| 947 | return 1; |
| 948 | } |
| @@ -1062,11 +1056,11 @@ | |
| 1056 | ** |
| 1057 | ** Returns the number of bytes read/copied, which may be less than |
| 1058 | ** nLen (if end-of-blob is encountered). |
| 1059 | ** |
| 1060 | ** Updates pIn's cursor. |
| 1061 | ** |
| 1062 | ** Returns 0 if pIn contains no data. |
| 1063 | */ |
| 1064 | unsigned int blob_read(Blob *pIn, void * pDest, unsigned int nLen ){ |
| 1065 | if( !pIn->aData || (pIn->iCursor >= pIn->nUsed) ){ |
| 1066 | return 0; |
| 1067 |
+51
-28
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -114,11 +114,11 @@ | ||
| 114 | 114 | |
| 115 | 115 | /* |
| 116 | 116 | ** Same as file_size(), but takes into account symlinks. |
| 117 | 117 | */ |
| 118 | 118 | i64 file_wd_size(const char *zFilename){ |
| 119 | - return getStat(zFilename, 1) ? -1 : fileStat.st_size; | |
| 119 | + return getStat(zFilename, 1) ? -1 : fileStat.st_size; | |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | /* |
| 123 | 123 | ** Return the modification time for a file. Return -1 if the file |
| 124 | 124 | ** does not exist. If zFilename is NULL return the size of the most |
| @@ -134,11 +134,11 @@ | ||
| 134 | 134 | i64 file_wd_mtime(const char *zFilename){ |
| 135 | 135 | return getStat(zFilename, 1) ? -1 : fileStat.st_mtime; |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | /* |
| 139 | -** Return TRUE if the named file is an ordinary file or symlink | |
| 139 | +** Return TRUE if the named file is an ordinary file or symlink | |
| 140 | 140 | ** and symlinks are allowed. |
| 141 | 141 | ** Return false for directories, devices, fifos, etc. |
| 142 | 142 | */ |
| 143 | 143 | int file_wd_isfile_or_link(const char *zFilename){ |
| 144 | 144 | return getStat(zFilename, 1) ? 0 : S_ISREG(fileStat.st_mode) || |
| @@ -191,14 +191,14 @@ | ||
| 191 | 191 | } |
| 192 | 192 | } |
| 193 | 193 | if( zName!=zBuf ) free(zName); |
| 194 | 194 | |
| 195 | 195 | if( symlink(zTargetFile, zName)!=0 ){ |
| 196 | - fossil_fatal_recursive("unable to create symlink \"%s\"", zName); | |
| 196 | + fossil_fatal_recursive("unable to create symlink \"%s\"", zName); | |
| 197 | 197 | } |
| 198 | 198 | }else |
| 199 | -#endif | |
| 199 | +#endif | |
| 200 | 200 | { |
| 201 | 201 | Blob content; |
| 202 | 202 | blob_set(&content, zTargetFile); |
| 203 | 203 | blob_write_to_file(&content, zLinkFile); |
| 204 | 204 | blob_reset(&content); |
| @@ -230,11 +230,11 @@ | ||
| 230 | 230 | if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 ) |
| 231 | 231 | return PERM_EXE; |
| 232 | 232 | else |
| 233 | 233 | return PERM_REG; |
| 234 | 234 | #else |
| 235 | - if( S_ISREG(fileStat.st_mode) && | |
| 235 | + if( S_ISREG(fileStat.st_mode) && | |
| 236 | 236 | ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0 ) |
| 237 | 237 | return PERM_EXE; |
| 238 | 238 | else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) ) |
| 239 | 239 | return PERM_LNK; |
| 240 | 240 | else |
| @@ -405,11 +405,11 @@ | ||
| 405 | 405 | #endif |
| 406 | 406 | } |
| 407 | 407 | |
| 408 | 408 | /* |
| 409 | 409 | ** Create the directory named in the argument, if it does not already |
| 410 | -** exist. If forceFlag is 1, delete any prior non-directory object | |
| 410 | +** exist. If forceFlag is 1, delete any prior non-directory object | |
| 411 | 411 | ** with the same name. |
| 412 | 412 | ** |
| 413 | 413 | ** Return the number of errors. |
| 414 | 414 | */ |
| 415 | 415 | int file_mkdir(const char *zName, int forceFlag){ |
| @@ -719,11 +719,11 @@ | ||
| 719 | 719 | } |
| 720 | 720 | } |
| 721 | 721 | return 1; |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | -/* | |
| 724 | +/* | |
| 725 | 725 | ** Return a pointer to the first character in a pathname past the |
| 726 | 726 | ** drive letter. This routine is a no-op on unix. |
| 727 | 727 | */ |
| 728 | 728 | char *file_without_drive_letter(char *zIn){ |
| 729 | 729 | #ifdef _WIN32 |
| @@ -947,19 +947,19 @@ | ||
| 947 | 947 | |
| 948 | 948 | azDirs[1] = fossil_getenv("TEMP"); |
| 949 | 949 | azDirs[2] = fossil_getenv("TMP"); |
| 950 | 950 | #endif |
| 951 | 951 | |
| 952 | - | |
| 952 | + | |
| 953 | 953 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 954 | 954 | if( azDirs[i]==0 ) continue; |
| 955 | 955 | if( !file_isdir(azDirs[i]) ) continue; |
| 956 | 956 | zDir = azDirs[i]; |
| 957 | 957 | break; |
| 958 | 958 | } |
| 959 | 959 | |
| 960 | - /* Check that the output buffer is large enough for the temporary file | |
| 960 | + /* Check that the output buffer is large enough for the temporary file | |
| 961 | 961 | ** name. If it is not, return SQLITE_ERROR. |
| 962 | 962 | */ |
| 963 | 963 | if( (strlen(zDir) + 17) >= (size_t)nBuf ){ |
| 964 | 964 | fossil_fatal("insufficient space for temporary filename"); |
| 965 | 965 | } |
| @@ -1035,21 +1035,21 @@ | ||
| 1035 | 1035 | ** Since everything is always UTF8 on unix, these routines are no-ops |
| 1036 | 1036 | ** there. |
| 1037 | 1037 | */ |
| 1038 | 1038 | |
| 1039 | 1039 | /* |
| 1040 | -** Translate MBCS to UTF8. Return a pointer to the translated text. | |
| 1040 | +** Translate MBCS to UTF8. Return a pointer to the translated text. | |
| 1041 | 1041 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| 1042 | 1042 | ** returned pointer when done. |
| 1043 | 1043 | */ |
| 1044 | 1044 | char *fossil_mbcs_to_utf8(const char *zMbcs){ |
| 1045 | 1045 | #ifdef _WIN32 |
| 1046 | 1046 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 1047 | 1047 | return sqlite3_win32_mbcs_to_utf8(zMbcs); |
| 1048 | 1048 | #else |
| 1049 | 1049 | return (char*)zMbcs; /* No-op on unix */ |
| 1050 | -#endif | |
| 1050 | +#endif | |
| 1051 | 1051 | } |
| 1052 | 1052 | |
| 1053 | 1053 | /* |
| 1054 | 1054 | ** Translate Unicode to UTF8. Return a pointer to the translated text. |
| 1055 | 1055 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| @@ -1078,11 +1078,11 @@ | ||
| 1078 | 1078 | #ifdef _WIN32 |
| 1079 | 1079 | extern char *sqlite3_win32_utf8_to_mbcs(const char*); |
| 1080 | 1080 | return sqlite3_win32_utf8_to_mbcs(zUtf8); |
| 1081 | 1081 | #else |
| 1082 | 1082 | return (char*)zUtf8; /* No-op on unix */ |
| 1083 | -#endif | |
| 1083 | +#endif | |
| 1084 | 1084 | } |
| 1085 | 1085 | |
| 1086 | 1086 | /* |
| 1087 | 1087 | ** Translate UTF8 to unicode for use in system calls. Return a pointer to the |
| 1088 | 1088 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| @@ -1116,48 +1116,71 @@ | ||
| 1116 | 1116 | #endif |
| 1117 | 1117 | return zValue; |
| 1118 | 1118 | } |
| 1119 | 1119 | |
| 1120 | 1120 | /* |
| 1121 | -** Translate UTF8 to MBCS for display on the console. Return a pointer to the | |
| 1122 | -** translated text.. Call fossil_mbcs_free() to deallocate any memory | |
| 1123 | -** used to store the returned pointer when done. | |
| 1121 | +** Display UTF8 on the console. Return the number of | |
| 1122 | +** Characters written. If stdout or stderr is redirected | |
| 1123 | +** to a file, -1 is returned and nothing is written | |
| 1124 | +** to the console. | |
| 1124 | 1125 | */ |
| 1125 | -char *fossil_utf8_to_console(const char *zUtf8){ | |
| 1126 | +int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){ | |
| 1126 | 1127 | #ifdef _WIN32 |
| 1127 | - int nChar, nByte; | |
| 1128 | - WCHAR *zUnicode; /* Unicode version of zUtf8 */ | |
| 1128 | + int nChar; | |
| 1129 | + wchar_t *zUnicode; /* Unicode version of zUtf8 */ | |
| 1130 | +#ifdef UNICODE | |
| 1131 | + DWORD dummy; | |
| 1132 | +#else | |
| 1129 | 1133 | char *zConsole; /* Console version of zUtf8 */ |
| 1130 | 1134 | int codepage; /* Console code page */ |
| 1135 | +#endif | |
| 1136 | + | |
| 1137 | + static int istty[2] = { -1, -1 }; | |
| 1138 | + if( istty[toStdErr] == -1 ){ | |
| 1139 | + istty[toStdErr] = _isatty(toStdErr + 1) != 0; | |
| 1140 | + } | |
| 1141 | + if( !istty[toStdErr] ){ | |
| 1142 | + /* stdout/stderr is not a console. */ | |
| 1143 | + return -1; | |
| 1144 | + } | |
| 1131 | 1145 | |
| 1132 | - nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); | |
| 1133 | - zUnicode = malloc( nChar*sizeof(zUnicode[0]) ); | |
| 1146 | + nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, NULL, 0); | |
| 1147 | + zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) ); | |
| 1134 | 1148 | if( zUnicode==0 ){ |
| 1135 | 1149 | return 0; |
| 1136 | 1150 | } |
| 1137 | - nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); | |
| 1151 | + nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, zUnicode, nChar); | |
| 1138 | 1152 | if( nChar==0 ){ |
| 1139 | 1153 | free(zUnicode); |
| 1140 | 1154 | return 0; |
| 1141 | 1155 | } |
| 1156 | + zUnicode[nChar] = '\0'; | |
| 1157 | +#ifdef UNICODE | |
| 1158 | + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode, nChar, &dummy, 0); | |
| 1159 | +#else /* !UNICODE */ | |
| 1142 | 1160 | codepage = GetConsoleCP(); |
| 1143 | - nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, 0, 0, 0, 0); | |
| 1144 | - zConsole = malloc( nByte ); | |
| 1161 | + nByte = WideCharToMultiByte(codepage, 0, zUnicode, nChar, 0, 0, 0, 0); | |
| 1162 | + zConsole = malloc( nByte + 1); | |
| 1145 | 1163 | if( zConsole==0 ){ |
| 1146 | 1164 | free(zUnicode); |
| 1147 | 1165 | return 0; |
| 1148 | 1166 | } |
| 1149 | - nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, zConsole, nByte, 0, 0); | |
| 1167 | + nByte = WideCharToMultiByte(codepage, 0, zUnicode, nChar, zConsole, nByte, 0, 0); | |
| 1168 | + zConsole[nByte] = '\0'; | |
| 1150 | 1169 | free(zUnicode); |
| 1151 | 1170 | if( nByte == 0 ){ |
| 1152 | 1171 | free(zConsole); |
| 1153 | 1172 | zConsole = 0; |
| 1173 | + return 0; | |
| 1154 | 1174 | } |
| 1155 | - return zConsole; | |
| 1175 | + fwrite(zConsole, 1, nByte, toStdErr ? stderr : stdout); | |
| 1176 | + fflush(toStdErr ? stderr : stdout); | |
| 1177 | +#endif /* UNICODE */ | |
| 1178 | + return nChar; | |
| 1156 | 1179 | #else |
| 1157 | - return (char*)zUtf8; /* No-op on unix */ | |
| 1158 | -#endif | |
| 1180 | + return -1; /* No-op on unix */ | |
| 1181 | +#endif | |
| 1159 | 1182 | } |
| 1160 | 1183 | |
| 1161 | 1184 | /* |
| 1162 | 1185 | ** Translate MBCS to UTF8. Return a pointer. Call fossil_mbcs_free() |
| 1163 | 1186 | ** to deallocate any memory used to store the returned pointer when done. |
| @@ -1166,11 +1189,11 @@ | ||
| 1166 | 1189 | #ifdef _WIN32 |
| 1167 | 1190 | extern void sqlite3_free(void*); |
| 1168 | 1191 | sqlite3_free(zOld); |
| 1169 | 1192 | #else |
| 1170 | 1193 | /* No-op on unix */ |
| 1171 | -#endif | |
| 1194 | +#endif | |
| 1172 | 1195 | } |
| 1173 | 1196 | |
| 1174 | 1197 | /* |
| 1175 | 1198 | ** Like fopen() but always takes a UTF8 argument. |
| 1176 | 1199 | */ |
| 1177 | 1200 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -114,11 +114,11 @@ | |
| 114 | |
| 115 | /* |
| 116 | ** Same as file_size(), but takes into account symlinks. |
| 117 | */ |
| 118 | i64 file_wd_size(const char *zFilename){ |
| 119 | return getStat(zFilename, 1) ? -1 : fileStat.st_size; |
| 120 | } |
| 121 | |
| 122 | /* |
| 123 | ** Return the modification time for a file. Return -1 if the file |
| 124 | ** does not exist. If zFilename is NULL return the size of the most |
| @@ -134,11 +134,11 @@ | |
| 134 | i64 file_wd_mtime(const char *zFilename){ |
| 135 | return getStat(zFilename, 1) ? -1 : fileStat.st_mtime; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ** Return TRUE if the named file is an ordinary file or symlink |
| 140 | ** and symlinks are allowed. |
| 141 | ** Return false for directories, devices, fifos, etc. |
| 142 | */ |
| 143 | int file_wd_isfile_or_link(const char *zFilename){ |
| 144 | return getStat(zFilename, 1) ? 0 : S_ISREG(fileStat.st_mode) || |
| @@ -191,14 +191,14 @@ | |
| 191 | } |
| 192 | } |
| 193 | if( zName!=zBuf ) free(zName); |
| 194 | |
| 195 | if( symlink(zTargetFile, zName)!=0 ){ |
| 196 | fossil_fatal_recursive("unable to create symlink \"%s\"", zName); |
| 197 | } |
| 198 | }else |
| 199 | #endif |
| 200 | { |
| 201 | Blob content; |
| 202 | blob_set(&content, zTargetFile); |
| 203 | blob_write_to_file(&content, zLinkFile); |
| 204 | blob_reset(&content); |
| @@ -230,11 +230,11 @@ | |
| 230 | if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 ) |
| 231 | return PERM_EXE; |
| 232 | else |
| 233 | return PERM_REG; |
| 234 | #else |
| 235 | if( S_ISREG(fileStat.st_mode) && |
| 236 | ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0 ) |
| 237 | return PERM_EXE; |
| 238 | else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) ) |
| 239 | return PERM_LNK; |
| 240 | else |
| @@ -405,11 +405,11 @@ | |
| 405 | #endif |
| 406 | } |
| 407 | |
| 408 | /* |
| 409 | ** Create the directory named in the argument, if it does not already |
| 410 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 411 | ** with the same name. |
| 412 | ** |
| 413 | ** Return the number of errors. |
| 414 | */ |
| 415 | int file_mkdir(const char *zName, int forceFlag){ |
| @@ -719,11 +719,11 @@ | |
| 719 | } |
| 720 | } |
| 721 | return 1; |
| 722 | } |
| 723 | |
| 724 | /* |
| 725 | ** Return a pointer to the first character in a pathname past the |
| 726 | ** drive letter. This routine is a no-op on unix. |
| 727 | */ |
| 728 | char *file_without_drive_letter(char *zIn){ |
| 729 | #ifdef _WIN32 |
| @@ -947,19 +947,19 @@ | |
| 947 | |
| 948 | azDirs[1] = fossil_getenv("TEMP"); |
| 949 | azDirs[2] = fossil_getenv("TMP"); |
| 950 | #endif |
| 951 | |
| 952 | |
| 953 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 954 | if( azDirs[i]==0 ) continue; |
| 955 | if( !file_isdir(azDirs[i]) ) continue; |
| 956 | zDir = azDirs[i]; |
| 957 | break; |
| 958 | } |
| 959 | |
| 960 | /* Check that the output buffer is large enough for the temporary file |
| 961 | ** name. If it is not, return SQLITE_ERROR. |
| 962 | */ |
| 963 | if( (strlen(zDir) + 17) >= (size_t)nBuf ){ |
| 964 | fossil_fatal("insufficient space for temporary filename"); |
| 965 | } |
| @@ -1035,21 +1035,21 @@ | |
| 1035 | ** Since everything is always UTF8 on unix, these routines are no-ops |
| 1036 | ** there. |
| 1037 | */ |
| 1038 | |
| 1039 | /* |
| 1040 | ** Translate MBCS to UTF8. Return a pointer to the translated text. |
| 1041 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| 1042 | ** returned pointer when done. |
| 1043 | */ |
| 1044 | char *fossil_mbcs_to_utf8(const char *zMbcs){ |
| 1045 | #ifdef _WIN32 |
| 1046 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 1047 | return sqlite3_win32_mbcs_to_utf8(zMbcs); |
| 1048 | #else |
| 1049 | return (char*)zMbcs; /* No-op on unix */ |
| 1050 | #endif |
| 1051 | } |
| 1052 | |
| 1053 | /* |
| 1054 | ** Translate Unicode to UTF8. Return a pointer to the translated text. |
| 1055 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| @@ -1078,11 +1078,11 @@ | |
| 1078 | #ifdef _WIN32 |
| 1079 | extern char *sqlite3_win32_utf8_to_mbcs(const char*); |
| 1080 | return sqlite3_win32_utf8_to_mbcs(zUtf8); |
| 1081 | #else |
| 1082 | return (char*)zUtf8; /* No-op on unix */ |
| 1083 | #endif |
| 1084 | } |
| 1085 | |
| 1086 | /* |
| 1087 | ** Translate UTF8 to unicode for use in system calls. Return a pointer to the |
| 1088 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| @@ -1116,48 +1116,71 @@ | |
| 1116 | #endif |
| 1117 | return zValue; |
| 1118 | } |
| 1119 | |
| 1120 | /* |
| 1121 | ** Translate UTF8 to MBCS for display on the console. Return a pointer to the |
| 1122 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| 1123 | ** used to store the returned pointer when done. |
| 1124 | */ |
| 1125 | char *fossil_utf8_to_console(const char *zUtf8){ |
| 1126 | #ifdef _WIN32 |
| 1127 | int nChar, nByte; |
| 1128 | WCHAR *zUnicode; /* Unicode version of zUtf8 */ |
| 1129 | char *zConsole; /* Console version of zUtf8 */ |
| 1130 | int codepage; /* Console code page */ |
| 1131 | |
| 1132 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); |
| 1133 | zUnicode = malloc( nChar*sizeof(zUnicode[0]) ); |
| 1134 | if( zUnicode==0 ){ |
| 1135 | return 0; |
| 1136 | } |
| 1137 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); |
| 1138 | if( nChar==0 ){ |
| 1139 | free(zUnicode); |
| 1140 | return 0; |
| 1141 | } |
| 1142 | codepage = GetConsoleCP(); |
| 1143 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, 0, 0, 0, 0); |
| 1144 | zConsole = malloc( nByte ); |
| 1145 | if( zConsole==0 ){ |
| 1146 | free(zUnicode); |
| 1147 | return 0; |
| 1148 | } |
| 1149 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, zConsole, nByte, 0, 0); |
| 1150 | free(zUnicode); |
| 1151 | if( nByte == 0 ){ |
| 1152 | free(zConsole); |
| 1153 | zConsole = 0; |
| 1154 | } |
| 1155 | return zConsole; |
| 1156 | #else |
| 1157 | return (char*)zUtf8; /* No-op on unix */ |
| 1158 | #endif |
| 1159 | } |
| 1160 | |
| 1161 | /* |
| 1162 | ** Translate MBCS to UTF8. Return a pointer. Call fossil_mbcs_free() |
| 1163 | ** to deallocate any memory used to store the returned pointer when done. |
| @@ -1166,11 +1189,11 @@ | |
| 1166 | #ifdef _WIN32 |
| 1167 | extern void sqlite3_free(void*); |
| 1168 | sqlite3_free(zOld); |
| 1169 | #else |
| 1170 | /* No-op on unix */ |
| 1171 | #endif |
| 1172 | } |
| 1173 | |
| 1174 | /* |
| 1175 | ** Like fopen() but always takes a UTF8 argument. |
| 1176 | */ |
| 1177 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -114,11 +114,11 @@ | |
| 114 | |
| 115 | /* |
| 116 | ** Same as file_size(), but takes into account symlinks. |
| 117 | */ |
| 118 | i64 file_wd_size(const char *zFilename){ |
| 119 | return getStat(zFilename, 1) ? -1 : fileStat.st_size; |
| 120 | } |
| 121 | |
| 122 | /* |
| 123 | ** Return the modification time for a file. Return -1 if the file |
| 124 | ** does not exist. If zFilename is NULL return the size of the most |
| @@ -134,11 +134,11 @@ | |
| 134 | i64 file_wd_mtime(const char *zFilename){ |
| 135 | return getStat(zFilename, 1) ? -1 : fileStat.st_mtime; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ** Return TRUE if the named file is an ordinary file or symlink |
| 140 | ** and symlinks are allowed. |
| 141 | ** Return false for directories, devices, fifos, etc. |
| 142 | */ |
| 143 | int file_wd_isfile_or_link(const char *zFilename){ |
| 144 | return getStat(zFilename, 1) ? 0 : S_ISREG(fileStat.st_mode) || |
| @@ -191,14 +191,14 @@ | |
| 191 | } |
| 192 | } |
| 193 | if( zName!=zBuf ) free(zName); |
| 194 | |
| 195 | if( symlink(zTargetFile, zName)!=0 ){ |
| 196 | fossil_fatal_recursive("unable to create symlink \"%s\"", zName); |
| 197 | } |
| 198 | }else |
| 199 | #endif |
| 200 | { |
| 201 | Blob content; |
| 202 | blob_set(&content, zTargetFile); |
| 203 | blob_write_to_file(&content, zLinkFile); |
| 204 | blob_reset(&content); |
| @@ -230,11 +230,11 @@ | |
| 230 | if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 ) |
| 231 | return PERM_EXE; |
| 232 | else |
| 233 | return PERM_REG; |
| 234 | #else |
| 235 | if( S_ISREG(fileStat.st_mode) && |
| 236 | ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0 ) |
| 237 | return PERM_EXE; |
| 238 | else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) ) |
| 239 | return PERM_LNK; |
| 240 | else |
| @@ -405,11 +405,11 @@ | |
| 405 | #endif |
| 406 | } |
| 407 | |
| 408 | /* |
| 409 | ** Create the directory named in the argument, if it does not already |
| 410 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 411 | ** with the same name. |
| 412 | ** |
| 413 | ** Return the number of errors. |
| 414 | */ |
| 415 | int file_mkdir(const char *zName, int forceFlag){ |
| @@ -719,11 +719,11 @@ | |
| 719 | } |
| 720 | } |
| 721 | return 1; |
| 722 | } |
| 723 | |
| 724 | /* |
| 725 | ** Return a pointer to the first character in a pathname past the |
| 726 | ** drive letter. This routine is a no-op on unix. |
| 727 | */ |
| 728 | char *file_without_drive_letter(char *zIn){ |
| 729 | #ifdef _WIN32 |
| @@ -947,19 +947,19 @@ | |
| 947 | |
| 948 | azDirs[1] = fossil_getenv("TEMP"); |
| 949 | azDirs[2] = fossil_getenv("TMP"); |
| 950 | #endif |
| 951 | |
| 952 | |
| 953 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 954 | if( azDirs[i]==0 ) continue; |
| 955 | if( !file_isdir(azDirs[i]) ) continue; |
| 956 | zDir = azDirs[i]; |
| 957 | break; |
| 958 | } |
| 959 | |
| 960 | /* Check that the output buffer is large enough for the temporary file |
| 961 | ** name. If it is not, return SQLITE_ERROR. |
| 962 | */ |
| 963 | if( (strlen(zDir) + 17) >= (size_t)nBuf ){ |
| 964 | fossil_fatal("insufficient space for temporary filename"); |
| 965 | } |
| @@ -1035,21 +1035,21 @@ | |
| 1035 | ** Since everything is always UTF8 on unix, these routines are no-ops |
| 1036 | ** there. |
| 1037 | */ |
| 1038 | |
| 1039 | /* |
| 1040 | ** Translate MBCS to UTF8. Return a pointer to the translated text. |
| 1041 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| 1042 | ** returned pointer when done. |
| 1043 | */ |
| 1044 | char *fossil_mbcs_to_utf8(const char *zMbcs){ |
| 1045 | #ifdef _WIN32 |
| 1046 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 1047 | return sqlite3_win32_mbcs_to_utf8(zMbcs); |
| 1048 | #else |
| 1049 | return (char*)zMbcs; /* No-op on unix */ |
| 1050 | #endif |
| 1051 | } |
| 1052 | |
| 1053 | /* |
| 1054 | ** Translate Unicode to UTF8. Return a pointer to the translated text. |
| 1055 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| @@ -1078,11 +1078,11 @@ | |
| 1078 | #ifdef _WIN32 |
| 1079 | extern char *sqlite3_win32_utf8_to_mbcs(const char*); |
| 1080 | return sqlite3_win32_utf8_to_mbcs(zUtf8); |
| 1081 | #else |
| 1082 | return (char*)zUtf8; /* No-op on unix */ |
| 1083 | #endif |
| 1084 | } |
| 1085 | |
| 1086 | /* |
| 1087 | ** Translate UTF8 to unicode for use in system calls. Return a pointer to the |
| 1088 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| @@ -1116,48 +1116,71 @@ | |
| 1116 | #endif |
| 1117 | return zValue; |
| 1118 | } |
| 1119 | |
| 1120 | /* |
| 1121 | ** Display UTF8 on the console. Return the number of |
| 1122 | ** Characters written. If stdout or stderr is redirected |
| 1123 | ** to a file, -1 is returned and nothing is written |
| 1124 | ** to the console. |
| 1125 | */ |
| 1126 | int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){ |
| 1127 | #ifdef _WIN32 |
| 1128 | int nChar; |
| 1129 | wchar_t *zUnicode; /* Unicode version of zUtf8 */ |
| 1130 | #ifdef UNICODE |
| 1131 | DWORD dummy; |
| 1132 | #else |
| 1133 | char *zConsole; /* Console version of zUtf8 */ |
| 1134 | int codepage; /* Console code page */ |
| 1135 | #endif |
| 1136 | |
| 1137 | static int istty[2] = { -1, -1 }; |
| 1138 | if( istty[toStdErr] == -1 ){ |
| 1139 | istty[toStdErr] = _isatty(toStdErr + 1) != 0; |
| 1140 | } |
| 1141 | if( !istty[toStdErr] ){ |
| 1142 | /* stdout/stderr is not a console. */ |
| 1143 | return -1; |
| 1144 | } |
| 1145 | |
| 1146 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, NULL, 0); |
| 1147 | zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) ); |
| 1148 | if( zUnicode==0 ){ |
| 1149 | return 0; |
| 1150 | } |
| 1151 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, nByte, zUnicode, nChar); |
| 1152 | if( nChar==0 ){ |
| 1153 | free(zUnicode); |
| 1154 | return 0; |
| 1155 | } |
| 1156 | zUnicode[nChar] = '\0'; |
| 1157 | #ifdef UNICODE |
| 1158 | WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode, nChar, &dummy, 0); |
| 1159 | #else /* !UNICODE */ |
| 1160 | codepage = GetConsoleCP(); |
| 1161 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, nChar, 0, 0, 0, 0); |
| 1162 | zConsole = malloc( nByte + 1); |
| 1163 | if( zConsole==0 ){ |
| 1164 | free(zUnicode); |
| 1165 | return 0; |
| 1166 | } |
| 1167 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, nChar, zConsole, nByte, 0, 0); |
| 1168 | zConsole[nByte] = '\0'; |
| 1169 | free(zUnicode); |
| 1170 | if( nByte == 0 ){ |
| 1171 | free(zConsole); |
| 1172 | zConsole = 0; |
| 1173 | return 0; |
| 1174 | } |
| 1175 | fwrite(zConsole, 1, nByte, toStdErr ? stderr : stdout); |
| 1176 | fflush(toStdErr ? stderr : stdout); |
| 1177 | #endif /* UNICODE */ |
| 1178 | return nChar; |
| 1179 | #else |
| 1180 | return -1; /* No-op on unix */ |
| 1181 | #endif |
| 1182 | } |
| 1183 | |
| 1184 | /* |
| 1185 | ** Translate MBCS to UTF8. Return a pointer. Call fossil_mbcs_free() |
| 1186 | ** to deallocate any memory used to store the returned pointer when done. |
| @@ -1166,11 +1189,11 @@ | |
| 1189 | #ifdef _WIN32 |
| 1190 | extern void sqlite3_free(void*); |
| 1191 | sqlite3_free(zOld); |
| 1192 | #else |
| 1193 | /* No-op on unix */ |
| 1194 | #endif |
| 1195 | } |
| 1196 | |
| 1197 | /* |
| 1198 | ** Like fopen() but always takes a UTF8 argument. |
| 1199 | */ |
| 1200 |
+149
-22
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -157,11 +157,11 @@ | ||
| 157 | 157 | char *urlPasswd; /* Password for http: */ |
| 158 | 158 | char *urlCanonical; /* Canonical representation of the URL */ |
| 159 | 159 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 160 | 160 | char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */ |
| 161 | 161 | int dontKeepUrl; /* Do not persist the URL */ |
| 162 | - | |
| 162 | + | |
| 163 | 163 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 164 | 164 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */ |
| 165 | 165 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 166 | 166 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 167 | 167 | int userUid; /* Integer user id */ |
| @@ -168,11 +168,11 @@ | ||
| 168 | 168 | |
| 169 | 169 | /* Information used to populate the RCVFROM table */ |
| 170 | 170 | int rcvid; /* The rcvid. 0 if not yet defined. */ |
| 171 | 171 | char *zIpAddr; /* The remote IP address */ |
| 172 | 172 | char *zNonce; /* The nonce used for login */ |
| 173 | - | |
| 173 | + | |
| 174 | 174 | /* permissions used by the server */ |
| 175 | 175 | struct FossilUserPerms perm; |
| 176 | 176 | |
| 177 | 177 | #ifdef FOSSIL_ENABLE_TCL |
| 178 | 178 | /* all Tcl related context necessary for integration */ |
| @@ -195,11 +195,11 @@ | ||
| 195 | 195 | const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */ |
| 196 | 196 | char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */ |
| 197 | 197 | const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ |
| 198 | 198 | const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ |
| 199 | 199 | int anAuxCols[MX_AUX]; /* Number of columns for option() values */ |
| 200 | - | |
| 200 | + | |
| 201 | 201 | int allowSymlinks; /* Cached "allow-symlinks" option */ |
| 202 | 202 | |
| 203 | 203 | #ifdef FOSSIL_ENABLE_JSON |
| 204 | 204 | struct FossilJsonBits { |
| 205 | 205 | int isJsonMode; /* True if running in JSON mode, else |
| @@ -262,11 +262,11 @@ | ||
| 262 | 262 | #endif |
| 263 | 263 | |
| 264 | 264 | Global g; |
| 265 | 265 | |
| 266 | 266 | /* |
| 267 | -** The table of web pages supported by this application is generated | |
| 267 | +** The table of web pages supported by this application is generated | |
| 268 | 268 | ** automatically by the "mkindex" program and written into a file |
| 269 | 269 | ** named "page_index.h". We include that file here to get access |
| 270 | 270 | ** to the table. |
| 271 | 271 | */ |
| 272 | 272 | #include "page_index.h" |
| @@ -329,30 +329,147 @@ | ||
| 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 from mbcs to UTF-8. Then | |
| 453 | +** Convert all arguments from mbcs (or unicode) to UTF-8. Then | |
| 337 | 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 |
| 343 | 460 | ** (c) If the line begins with "-" and contains a space, it is broken |
| 344 | 461 | ** into two arguments at the space. |
| 345 | 462 | */ |
| 346 | -static void expand_args_option(int argc, char **argv){ | |
| 463 | +static void expand_args_option(int argc, void *argv){ | |
| 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,13 +476,18 @@ | ||
| 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); |
| 484 | +#ifdef UNICODE | |
| 485 | + for(i=1; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]); | |
| 486 | +#else | |
| 366 | 487 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_mbcs_to_utf8(g.argv[i]); |
| 488 | +#endif | |
| 367 | 489 | #endif |
| 368 | 490 | for(i=1; i<g.argc-1; i++){ |
| 369 | 491 | z = g.argv[i]; |
| 370 | 492 | if( z[0]!='-' ) continue; |
| 371 | 493 | z++; |
| @@ -390,21 +512,21 @@ | ||
| 390 | 512 | } |
| 391 | 513 | z = blob_str(&file); |
| 392 | 514 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 393 | 515 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| 394 | 516 | for(j=0; j<i; j++) newArgv[j] = g.argv[j]; |
| 395 | - | |
| 517 | + | |
| 396 | 518 | blob_rewind(&file); |
| 397 | 519 | while( (n = blob_line(&file, &line))>0 ){ |
| 398 | 520 | if( n<=1 ) continue; |
| 399 | 521 | z = blob_buffer(&line); |
| 400 | 522 | z[n-1] = 0; |
| 401 | 523 | if (foundBom == -1) { |
| 402 | 524 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 403 | 525 | foundBom = memcmp(z, bom, 3)==0; |
| 404 | 526 | if( foundBom ) { |
| 405 | - z += 3; n -= 3; | |
| 527 | + z += 3; n -= 3; | |
| 406 | 528 | } |
| 407 | 529 | } |
| 408 | 530 | if((n>1) && ('\r'==z[n-2])){ |
| 409 | 531 | if(n==2) continue /*empty line*/; |
| 410 | 532 | z[n-2] = 0; |
| @@ -430,11 +552,16 @@ | ||
| 430 | 552 | } |
| 431 | 553 | |
| 432 | 554 | /* |
| 433 | 555 | ** This procedure runs first. |
| 434 | 556 | */ |
| 435 | -int main(int argc, char **argv){ | |
| 557 | +#if defined(_WIN32) && defined(UNICODE) | |
| 558 | +int wmain(int argc, wchar_t **argv) | |
| 559 | +#else | |
| 560 | +int main(int argc, char **argv) | |
| 561 | +#endif | |
| 562 | +{ | |
| 436 | 563 | const char *zCmdName = "unknown"; |
| 437 | 564 | int idx; |
| 438 | 565 | int rc; |
| 439 | 566 | |
| 440 | 567 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| @@ -726,12 +853,12 @@ | ||
| 726 | 853 | #else |
| 727 | 854 | /* On unix, evaluate the command directly. |
| 728 | 855 | */ |
| 729 | 856 | if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd); |
| 730 | 857 | rc = system(zOrigCmd); |
| 731 | -#endif | |
| 732 | - return rc; | |
| 858 | +#endif | |
| 859 | + return rc; | |
| 733 | 860 | } |
| 734 | 861 | |
| 735 | 862 | /* |
| 736 | 863 | ** Turn off any NL to CRNL translation on the stream given as an |
| 737 | 864 | ** argument. This is a no-op on unix but is necessary on windows. |
| @@ -1194,11 +1321,11 @@ | ||
| 1194 | 1321 | ** * Environment variables are set up according to the CGI standard. |
| 1195 | 1322 | ** |
| 1196 | 1323 | ** If the repository is known, it has already been opened. If unknown, |
| 1197 | 1324 | ** then g.zRepositoryName holds the directory that contains the repository |
| 1198 | 1325 | ** and the actual repository is taken from the first element of PATH_INFO. |
| 1199 | -** | |
| 1326 | +** | |
| 1200 | 1327 | ** Process the webpage specified by the PATH_INFO or REQUEST_URI |
| 1201 | 1328 | ** environment variable. |
| 1202 | 1329 | */ |
| 1203 | 1330 | static void process_one_web_page(const char *zNotFound){ |
| 1204 | 1331 | const char *zPathInfo; |
| @@ -1267,11 +1394,11 @@ | ||
| 1267 | 1394 | cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); |
| 1268 | 1395 | zPathInfo += i; |
| 1269 | 1396 | cgi_replace_parameter("SCRIPT_NAME", zNewScript); |
| 1270 | 1397 | db_open_repository(zRepo); |
| 1271 | 1398 | if( g.fHttpTrace ){ |
| 1272 | - fprintf(stderr, | |
| 1399 | + fprintf(stderr, | |
| 1273 | 1400 | "# repository: [%s]\n" |
| 1274 | 1401 | "# new PATH_INFO = [%s]\n" |
| 1275 | 1402 | "# new SCRIPT_NAME = [%s]\n", |
| 1276 | 1403 | zRepo, zPathInfo, zNewScript); |
| 1277 | 1404 | } |
| @@ -1282,11 +1409,11 @@ | ||
| 1282 | 1409 | */ |
| 1283 | 1410 | if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){ |
| 1284 | 1411 | zPathInfo = "/xfer"; |
| 1285 | 1412 | } |
| 1286 | 1413 | set_base_url(); |
| 1287 | - if( zPathInfo==0 || zPathInfo[0]==0 | |
| 1414 | + if( zPathInfo==0 || zPathInfo[0]==0 | |
| 1288 | 1415 | || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ |
| 1289 | 1416 | #ifdef FOSSIL_ENABLE_JSON |
| 1290 | 1417 | if(g.json.isJsonMode){ |
| 1291 | 1418 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1292 | 1419 | fossil_exit(0); |
| @@ -1312,11 +1439,11 @@ | ||
| 1312 | 1439 | ** that accepts the login credentials of the current repository. A |
| 1313 | 1440 | ** subrepository is identified by a CONFIG table entry "subrepo:NAME" |
| 1314 | 1441 | ** where NAME is the first component of the path. The value of the |
| 1315 | 1442 | ** the CONFIG entries is the string "USER:FILENAME" where USER is the |
| 1316 | 1443 | ** USER name to log in as in the subrepository and FILENAME is the |
| 1317 | - ** repository filename. | |
| 1444 | + ** repository filename. | |
| 1318 | 1445 | */ |
| 1319 | 1446 | zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", |
| 1320 | 1447 | g.zPath); |
| 1321 | 1448 | if( zAltRepo ){ |
| 1322 | 1449 | int nHost; |
| @@ -1514,11 +1641,11 @@ | ||
| 1514 | 1641 | |
| 1515 | 1642 | /* If the CGI program contains one or more lines of the form |
| 1516 | 1643 | ** |
| 1517 | 1644 | ** redirect: repository-filename http://hostname/path/%s |
| 1518 | 1645 | ** |
| 1519 | -** then control jumps here. Search each repository for an artifact ID | |
| 1646 | +** then control jumps here. Search each repository for an artifact ID | |
| 1520 | 1647 | ** that matches the "name" CGI parameter and for the first match, |
| 1521 | 1648 | ** redirect to the corresponding URL with the "name" CGI parameter |
| 1522 | 1649 | ** inserted. Paint an error page if no match is found. |
| 1523 | 1650 | ** |
| 1524 | 1651 | ** If there is a line of the form: |
| @@ -1530,11 +1657,11 @@ | ||
| 1530 | 1657 | */ |
| 1531 | 1658 | void redirect_web_page(int nRedirect, char **azRedirect){ |
| 1532 | 1659 | int i; /* Loop counter */ |
| 1533 | 1660 | const char *zNotFound = 0; /* Not found URL */ |
| 1534 | 1661 | const char *zName = P("name"); |
| 1535 | - set_base_url(); | |
| 1662 | + set_base_url(); | |
| 1536 | 1663 | if( zName==0 ){ |
| 1537 | 1664 | zName = P("SCRIPT_NAME"); |
| 1538 | 1665 | if( zName && zName[0]=='/' ) zName++; |
| 1539 | 1666 | } |
| 1540 | 1667 | if( zName && validate16(zName, strlen(zName)) ){ |
| @@ -1603,11 +1730,11 @@ | ||
| 1603 | 1730 | ** |
| 1604 | 1731 | ** Usage: %fossil http REPOSITORY ?OPTIONS? |
| 1605 | 1732 | ** |
| 1606 | 1733 | ** Handle a single HTTP request appearing on stdin. The resulting webpage |
| 1607 | 1734 | ** is delivered on stdout. This method is used to launch an HTTP request |
| 1608 | -** handler from inetd, for example. The argument is the name of the | |
| 1735 | +** handler from inetd, for example. The argument is the name of the | |
| 1609 | 1736 | ** repository. |
| 1610 | 1737 | ** |
| 1611 | 1738 | ** If REPOSITORY is a directory that contains one or more repositories |
| 1612 | 1739 | ** with names of the form "*.fossil" then the first element of the URL |
| 1613 | 1740 | ** pathname selects among the various repositories. If the pathname does |
| @@ -1742,11 +1869,11 @@ | ||
| 1742 | 1869 | ** See also: cgi, http, winsrv |
| 1743 | 1870 | */ |
| 1744 | 1871 | void cmd_webserver(void){ |
| 1745 | 1872 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1746 | 1873 | const char *zPort; /* Value of the --port option */ |
| 1747 | - char *zBrowser; /* Name of web browser program */ | |
| 1874 | + const char *zBrowser; /* Name of web browser program */ | |
| 1748 | 1875 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1749 | 1876 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1750 | 1877 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1751 | 1878 | int flags = 0; /* Server flags */ |
| 1752 | 1879 | |
| @@ -1779,11 +1906,11 @@ | ||
| 1779 | 1906 | /* Unix implementation */ |
| 1780 | 1907 | if( isUiCmd ){ |
| 1781 | 1908 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1782 | 1909 | zBrowser = db_get("web-browser", 0); |
| 1783 | 1910 | if( zBrowser==0 ){ |
| 1784 | - static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1911 | + static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; | |
| 1785 | 1912 | int i; |
| 1786 | 1913 | zBrowser = "echo"; |
| 1787 | 1914 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1788 | 1915 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1789 | 1916 | zBrowser = azBrowserProg[i]; |
| 1790 | 1917 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -157,11 +157,11 @@ | |
| 157 | char *urlPasswd; /* Password for http: */ |
| 158 | char *urlCanonical; /* Canonical representation of the URL */ |
| 159 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 160 | char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */ |
| 161 | int dontKeepUrl; /* Do not persist the URL */ |
| 162 | |
| 163 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 164 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */ |
| 165 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 166 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 167 | int userUid; /* Integer user id */ |
| @@ -168,11 +168,11 @@ | |
| 168 | |
| 169 | /* Information used to populate the RCVFROM table */ |
| 170 | int rcvid; /* The rcvid. 0 if not yet defined. */ |
| 171 | char *zIpAddr; /* The remote IP address */ |
| 172 | char *zNonce; /* The nonce used for login */ |
| 173 | |
| 174 | /* permissions used by the server */ |
| 175 | struct FossilUserPerms perm; |
| 176 | |
| 177 | #ifdef FOSSIL_ENABLE_TCL |
| 178 | /* all Tcl related context necessary for integration */ |
| @@ -195,11 +195,11 @@ | |
| 195 | const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */ |
| 196 | char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */ |
| 197 | const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ |
| 198 | const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ |
| 199 | int anAuxCols[MX_AUX]; /* Number of columns for option() values */ |
| 200 | |
| 201 | int allowSymlinks; /* Cached "allow-symlinks" option */ |
| 202 | |
| 203 | #ifdef FOSSIL_ENABLE_JSON |
| 204 | struct FossilJsonBits { |
| 205 | int isJsonMode; /* True if running in JSON mode, else |
| @@ -262,11 +262,11 @@ | |
| 262 | #endif |
| 263 | |
| 264 | Global g; |
| 265 | |
| 266 | /* |
| 267 | ** The table of web pages supported by this application is generated |
| 268 | ** automatically by the "mkindex" program and written into a file |
| 269 | ** named "page_index.h". We include that file here to get access |
| 270 | ** to the table. |
| 271 | */ |
| 272 | #include "page_index.h" |
| @@ -329,30 +329,147 @@ | |
| 329 | free(g.zErrMsg); |
| 330 | if(g.db){ |
| 331 | db_close(0); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* |
| 336 | ** Convert all arguments from mbcs to UTF-8. Then |
| 337 | ** search g.argv for arguments "--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 |
| 343 | ** (c) If the line begins with "-" and contains a space, it is broken |
| 344 | ** into two arguments at the space. |
| 345 | */ |
| 346 | static void expand_args_option(int argc, char **argv){ |
| 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,13 +476,18 @@ | |
| 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 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_mbcs_to_utf8(g.argv[i]); |
| 367 | #endif |
| 368 | for(i=1; i<g.argc-1; i++){ |
| 369 | z = g.argv[i]; |
| 370 | if( z[0]!='-' ) continue; |
| 371 | z++; |
| @@ -390,21 +512,21 @@ | |
| 390 | } |
| 391 | z = blob_str(&file); |
| 392 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 393 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| 394 | for(j=0; j<i; j++) newArgv[j] = g.argv[j]; |
| 395 | |
| 396 | blob_rewind(&file); |
| 397 | while( (n = blob_line(&file, &line))>0 ){ |
| 398 | if( n<=1 ) continue; |
| 399 | z = blob_buffer(&line); |
| 400 | z[n-1] = 0; |
| 401 | if (foundBom == -1) { |
| 402 | static const char bom[] = { 0xEF, 0xBB, 0xBF }; |
| 403 | foundBom = memcmp(z, bom, 3)==0; |
| 404 | if( foundBom ) { |
| 405 | z += 3; n -= 3; |
| 406 | } |
| 407 | } |
| 408 | if((n>1) && ('\r'==z[n-2])){ |
| 409 | if(n==2) continue /*empty line*/; |
| 410 | z[n-2] = 0; |
| @@ -430,11 +552,16 @@ | |
| 430 | } |
| 431 | |
| 432 | /* |
| 433 | ** This procedure runs first. |
| 434 | */ |
| 435 | int main(int argc, char **argv){ |
| 436 | const char *zCmdName = "unknown"; |
| 437 | int idx; |
| 438 | int rc; |
| 439 | |
| 440 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| @@ -726,12 +853,12 @@ | |
| 726 | #else |
| 727 | /* On unix, evaluate the command directly. |
| 728 | */ |
| 729 | if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd); |
| 730 | rc = system(zOrigCmd); |
| 731 | #endif |
| 732 | return rc; |
| 733 | } |
| 734 | |
| 735 | /* |
| 736 | ** Turn off any NL to CRNL translation on the stream given as an |
| 737 | ** argument. This is a no-op on unix but is necessary on windows. |
| @@ -1194,11 +1321,11 @@ | |
| 1194 | ** * Environment variables are set up according to the CGI standard. |
| 1195 | ** |
| 1196 | ** If the repository is known, it has already been opened. If unknown, |
| 1197 | ** then g.zRepositoryName holds the directory that contains the repository |
| 1198 | ** and the actual repository is taken from the first element of PATH_INFO. |
| 1199 | ** |
| 1200 | ** Process the webpage specified by the PATH_INFO or REQUEST_URI |
| 1201 | ** environment variable. |
| 1202 | */ |
| 1203 | static void process_one_web_page(const char *zNotFound){ |
| 1204 | const char *zPathInfo; |
| @@ -1267,11 +1394,11 @@ | |
| 1267 | cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); |
| 1268 | zPathInfo += i; |
| 1269 | cgi_replace_parameter("SCRIPT_NAME", zNewScript); |
| 1270 | db_open_repository(zRepo); |
| 1271 | if( g.fHttpTrace ){ |
| 1272 | fprintf(stderr, |
| 1273 | "# repository: [%s]\n" |
| 1274 | "# new PATH_INFO = [%s]\n" |
| 1275 | "# new SCRIPT_NAME = [%s]\n", |
| 1276 | zRepo, zPathInfo, zNewScript); |
| 1277 | } |
| @@ -1282,11 +1409,11 @@ | |
| 1282 | */ |
| 1283 | if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){ |
| 1284 | zPathInfo = "/xfer"; |
| 1285 | } |
| 1286 | set_base_url(); |
| 1287 | if( zPathInfo==0 || zPathInfo[0]==0 |
| 1288 | || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ |
| 1289 | #ifdef FOSSIL_ENABLE_JSON |
| 1290 | if(g.json.isJsonMode){ |
| 1291 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1292 | fossil_exit(0); |
| @@ -1312,11 +1439,11 @@ | |
| 1312 | ** that accepts the login credentials of the current repository. A |
| 1313 | ** subrepository is identified by a CONFIG table entry "subrepo:NAME" |
| 1314 | ** where NAME is the first component of the path. The value of the |
| 1315 | ** the CONFIG entries is the string "USER:FILENAME" where USER is the |
| 1316 | ** USER name to log in as in the subrepository and FILENAME is the |
| 1317 | ** repository filename. |
| 1318 | */ |
| 1319 | zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", |
| 1320 | g.zPath); |
| 1321 | if( zAltRepo ){ |
| 1322 | int nHost; |
| @@ -1514,11 +1641,11 @@ | |
| 1514 | |
| 1515 | /* If the CGI program contains one or more lines of the form |
| 1516 | ** |
| 1517 | ** redirect: repository-filename http://hostname/path/%s |
| 1518 | ** |
| 1519 | ** then control jumps here. Search each repository for an artifact ID |
| 1520 | ** that matches the "name" CGI parameter and for the first match, |
| 1521 | ** redirect to the corresponding URL with the "name" CGI parameter |
| 1522 | ** inserted. Paint an error page if no match is found. |
| 1523 | ** |
| 1524 | ** If there is a line of the form: |
| @@ -1530,11 +1657,11 @@ | |
| 1530 | */ |
| 1531 | void redirect_web_page(int nRedirect, char **azRedirect){ |
| 1532 | int i; /* Loop counter */ |
| 1533 | const char *zNotFound = 0; /* Not found URL */ |
| 1534 | const char *zName = P("name"); |
| 1535 | set_base_url(); |
| 1536 | if( zName==0 ){ |
| 1537 | zName = P("SCRIPT_NAME"); |
| 1538 | if( zName && zName[0]=='/' ) zName++; |
| 1539 | } |
| 1540 | if( zName && validate16(zName, strlen(zName)) ){ |
| @@ -1603,11 +1730,11 @@ | |
| 1603 | ** |
| 1604 | ** Usage: %fossil http REPOSITORY ?OPTIONS? |
| 1605 | ** |
| 1606 | ** Handle a single HTTP request appearing on stdin. The resulting webpage |
| 1607 | ** is delivered on stdout. This method is used to launch an HTTP request |
| 1608 | ** handler from inetd, for example. The argument is the name of the |
| 1609 | ** repository. |
| 1610 | ** |
| 1611 | ** If REPOSITORY is a directory that contains one or more repositories |
| 1612 | ** with names of the form "*.fossil" then the first element of the URL |
| 1613 | ** pathname selects among the various repositories. If the pathname does |
| @@ -1742,11 +1869,11 @@ | |
| 1742 | ** See also: cgi, http, winsrv |
| 1743 | */ |
| 1744 | void cmd_webserver(void){ |
| 1745 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 1746 | const char *zPort; /* Value of the --port option */ |
| 1747 | char *zBrowser; /* Name of web browser program */ |
| 1748 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1749 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1750 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1751 | int flags = 0; /* Server flags */ |
| 1752 | |
| @@ -1779,11 +1906,11 @@ | |
| 1779 | /* Unix implementation */ |
| 1780 | if( isUiCmd ){ |
| 1781 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| 1782 | zBrowser = db_get("web-browser", 0); |
| 1783 | if( zBrowser==0 ){ |
| 1784 | static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; |
| 1785 | int i; |
| 1786 | zBrowser = "echo"; |
| 1787 | for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ |
| 1788 | if( binaryOnPath(azBrowserProg[i]) ){ |
| 1789 | zBrowser = azBrowserProg[i]; |
| 1790 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -157,11 +157,11 @@ | |
| 157 | char *urlPasswd; /* Password for http: */ |
| 158 | char *urlCanonical; /* Canonical representation of the URL */ |
| 159 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 160 | char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */ |
| 161 | int dontKeepUrl; /* Do not persist the URL */ |
| 162 | |
| 163 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 164 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */ |
| 165 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 166 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 167 | int userUid; /* Integer user id */ |
| @@ -168,11 +168,11 @@ | |
| 168 | |
| 169 | /* Information used to populate the RCVFROM table */ |
| 170 | int rcvid; /* The rcvid. 0 if not yet defined. */ |
| 171 | char *zIpAddr; /* The remote IP address */ |
| 172 | char *zNonce; /* The nonce used for login */ |
| 173 | |
| 174 | /* permissions used by the server */ |
| 175 | struct FossilUserPerms perm; |
| 176 | |
| 177 | #ifdef FOSSIL_ENABLE_TCL |
| 178 | /* all Tcl related context necessary for integration */ |
| @@ -195,11 +195,11 @@ | |
| 195 | const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */ |
| 196 | char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */ |
| 197 | const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ |
| 198 | const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ |
| 199 | int anAuxCols[MX_AUX]; /* Number of columns for option() values */ |
| 200 | |
| 201 | int allowSymlinks; /* Cached "allow-symlinks" option */ |
| 202 | |
| 203 | #ifdef FOSSIL_ENABLE_JSON |
| 204 | struct FossilJsonBits { |
| 205 | int isJsonMode; /* True if running in JSON mode, else |
| @@ -262,11 +262,11 @@ | |
| 262 | #endif |
| 263 | |
| 264 | Global g; |
| 265 | |
| 266 | /* |
| 267 | ** The table of web pages supported by this application is generated |
| 268 | ** automatically by the "mkindex" program and written into a file |
| 269 | ** named "page_index.h". We include that file here to get access |
| 270 | ** to the table. |
| 271 | */ |
| 272 | #include "page_index.h" |
| @@ -329,30 +329,147 @@ | |
| 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 |
| 460 | ** (c) If the line begins with "-" and contains a space, it is broken |
| 461 | ** into two arguments at the space. |
| 462 | */ |
| 463 | static void expand_args_option(int argc, void *argv){ |
| 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,13 +476,18 @@ | |
| 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 |
| 487 | for(i=1; i<g.argc; i++) g.argv[i] = fossil_mbcs_to_utf8(g.argv[i]); |
| 488 | #endif |
| 489 | #endif |
| 490 | for(i=1; i<g.argc-1; i++){ |
| 491 | z = g.argv[i]; |
| 492 | if( z[0]!='-' ) continue; |
| 493 | z++; |
| @@ -390,21 +512,21 @@ | |
| 512 | } |
| 513 | z = blob_str(&file); |
| 514 | for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; |
| 515 | newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); |
| 516 | for(j=0; j<i; j++) newArgv[j] = g.argv[j]; |
| 517 | |
| 518 | blob_rewind(&file); |
| 519 | while( (n = blob_line(&file, &line))>0 ){ |
| 520 | if( n<=1 ) continue; |
| 521 | z = blob_buffer(&line); |
| 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; |
| @@ -430,11 +552,16 @@ | |
| 552 | } |
| 553 | |
| 554 | /* |
| 555 | ** This procedure runs first. |
| 556 | */ |
| 557 | #if defined(_WIN32) && defined(UNICODE) |
| 558 | int wmain(int argc, wchar_t **argv) |
| 559 | #else |
| 560 | int main(int argc, char **argv) |
| 561 | #endif |
| 562 | { |
| 563 | const char *zCmdName = "unknown"; |
| 564 | int idx; |
| 565 | int rc; |
| 566 | |
| 567 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| @@ -726,12 +853,12 @@ | |
| 853 | #else |
| 854 | /* On unix, evaluate the command directly. |
| 855 | */ |
| 856 | if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd); |
| 857 | rc = system(zOrigCmd); |
| 858 | #endif |
| 859 | return rc; |
| 860 | } |
| 861 | |
| 862 | /* |
| 863 | ** Turn off any NL to CRNL translation on the stream given as an |
| 864 | ** argument. This is a no-op on unix but is necessary on windows. |
| @@ -1194,11 +1321,11 @@ | |
| 1321 | ** * Environment variables are set up according to the CGI standard. |
| 1322 | ** |
| 1323 | ** If the repository is known, it has already been opened. If unknown, |
| 1324 | ** then g.zRepositoryName holds the directory that contains the repository |
| 1325 | ** and the actual repository is taken from the first element of PATH_INFO. |
| 1326 | ** |
| 1327 | ** Process the webpage specified by the PATH_INFO or REQUEST_URI |
| 1328 | ** environment variable. |
| 1329 | */ |
| 1330 | static void process_one_web_page(const char *zNotFound){ |
| 1331 | const char *zPathInfo; |
| @@ -1267,11 +1394,11 @@ | |
| 1394 | cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); |
| 1395 | zPathInfo += i; |
| 1396 | cgi_replace_parameter("SCRIPT_NAME", zNewScript); |
| 1397 | db_open_repository(zRepo); |
| 1398 | if( g.fHttpTrace ){ |
| 1399 | fprintf(stderr, |
| 1400 | "# repository: [%s]\n" |
| 1401 | "# new PATH_INFO = [%s]\n" |
| 1402 | "# new SCRIPT_NAME = [%s]\n", |
| 1403 | zRepo, zPathInfo, zNewScript); |
| 1404 | } |
| @@ -1282,11 +1409,11 @@ | |
| 1409 | */ |
| 1410 | if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){ |
| 1411 | zPathInfo = "/xfer"; |
| 1412 | } |
| 1413 | set_base_url(); |
| 1414 | if( zPathInfo==0 || zPathInfo[0]==0 |
| 1415 | || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ |
| 1416 | #ifdef FOSSIL_ENABLE_JSON |
| 1417 | if(g.json.isJsonMode){ |
| 1418 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1419 | fossil_exit(0); |
| @@ -1312,11 +1439,11 @@ | |
| 1439 | ** that accepts the login credentials of the current repository. A |
| 1440 | ** subrepository is identified by a CONFIG table entry "subrepo:NAME" |
| 1441 | ** where NAME is the first component of the path. The value of the |
| 1442 | ** the CONFIG entries is the string "USER:FILENAME" where USER is the |
| 1443 | ** USER name to log in as in the subrepository and FILENAME is the |
| 1444 | ** repository filename. |
| 1445 | */ |
| 1446 | zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'", |
| 1447 | g.zPath); |
| 1448 | if( zAltRepo ){ |
| 1449 | int nHost; |
| @@ -1514,11 +1641,11 @@ | |
| 1641 | |
| 1642 | /* If the CGI program contains one or more lines of the form |
| 1643 | ** |
| 1644 | ** redirect: repository-filename http://hostname/path/%s |
| 1645 | ** |
| 1646 | ** then control jumps here. Search each repository for an artifact ID |
| 1647 | ** that matches the "name" CGI parameter and for the first match, |
| 1648 | ** redirect to the corresponding URL with the "name" CGI parameter |
| 1649 | ** inserted. Paint an error page if no match is found. |
| 1650 | ** |
| 1651 | ** If there is a line of the form: |
| @@ -1530,11 +1657,11 @@ | |
| 1657 | */ |
| 1658 | void redirect_web_page(int nRedirect, char **azRedirect){ |
| 1659 | int i; /* Loop counter */ |
| 1660 | const char *zNotFound = 0; /* Not found URL */ |
| 1661 | const char *zName = P("name"); |
| 1662 | set_base_url(); |
| 1663 | if( zName==0 ){ |
| 1664 | zName = P("SCRIPT_NAME"); |
| 1665 | if( zName && zName[0]=='/' ) zName++; |
| 1666 | } |
| 1667 | if( zName && validate16(zName, strlen(zName)) ){ |
| @@ -1603,11 +1730,11 @@ | |
| 1730 | ** |
| 1731 | ** Usage: %fossil http REPOSITORY ?OPTIONS? |
| 1732 | ** |
| 1733 | ** Handle a single HTTP request appearing on stdin. The resulting webpage |
| 1734 | ** is delivered on stdout. This method is used to launch an HTTP request |
| 1735 | ** handler from inetd, for example. The argument is the name of the |
| 1736 | ** repository. |
| 1737 | ** |
| 1738 | ** If REPOSITORY is a directory that contains one or more repositories |
| 1739 | ** with names of the form "*.fossil" then the first element of the URL |
| 1740 | ** pathname selects among the various repositories. If the pathname does |
| @@ -1742,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 | |
| @@ -1779,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 |
+5
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -473,10 +473,15 @@ | ||
| 473 | 473 | # With JSON support |
| 474 | 474 | ifdef FOSSIL_ENABLE_JSON |
| 475 | 475 | TCC += -DFOSSIL_ENABLE_JSON=1 |
| 476 | 476 | RCC += -DFOSSIL_ENABLE_JSON=1 |
| 477 | 477 | endif |
| 478 | + | |
| 479 | +# Fix buggy MinGW command line parsing | |
| 480 | +ifdef MINGW_BROKEN_MAINARGS | |
| 481 | +TCC += -DMINGW_BROKEN_MAINARGS | |
| 482 | +endif | |
| 478 | 483 | |
| 479 | 484 | #### We add the -static option here so that we can build a static |
| 480 | 485 | # executable that will run in a chroot jail. |
| 481 | 486 | # |
| 482 | 487 | LIB = -static |
| 483 | 488 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -473,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 | #### We add the -static option here so that we can build a static |
| 480 | # executable that will run in a chroot jail. |
| 481 | # |
| 482 | LIB = -static |
| 483 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -473,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 |
+9
-18
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -243,11 +243,11 @@ | ||
| 243 | 243 | blob_append(pBlob,"%",1); |
| 244 | 244 | count++; |
| 245 | 245 | break; |
| 246 | 246 | } |
| 247 | 247 | /* Find out what flags are present */ |
| 248 | - flag_leftjustify = flag_plussign = flag_blanksign = | |
| 248 | + flag_leftjustify = flag_plussign = flag_blanksign = | |
| 249 | 249 | flag_alternateform = flag_altform2 = flag_zeropad = 0; |
| 250 | 250 | done = 0; |
| 251 | 251 | do{ |
| 252 | 252 | switch( c ){ |
| 253 | 253 | case '-': flag_leftjustify = 1; break; |
| @@ -814,25 +814,16 @@ | ||
| 814 | 814 | ** if the output is going to the screen. If output is redirected into |
| 815 | 815 | ** a file, no translation occurs. No translation ever occurs on unix. |
| 816 | 816 | */ |
| 817 | 817 | void fossil_puts(const char *z, int toStdErr){ |
| 818 | 818 | #if defined(_WIN32) |
| 819 | - static int once = 1; | |
| 820 | - static int istty[2]; | |
| 821 | - char *zToFree = 0; | |
| 822 | - if( once ){ | |
| 823 | - istty[0] = _isatty(fileno(stdout)); | |
| 824 | - istty[1] = _isatty(fileno(stderr)); | |
| 825 | - once = 0; | |
| 826 | - } | |
| 827 | - assert( toStdErr==0 || toStdErr==1 ); | |
| 828 | - if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); | |
| 829 | - fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); | |
| 830 | - free(zToFree); | |
| 831 | -#else | |
| 832 | - fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); | |
| 833 | -#endif | |
| 819 | + if( fossil_utf8_to_console(z, strlen(z), toStdErr) >= 0 ){ | |
| 820 | + return; | |
| 821 | + } | |
| 822 | +#endif | |
| 823 | + assert( toStdErr==0 || toStdErr==1 ); | |
| 824 | + fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); | |
| 834 | 825 | fflush(toStdErr ? stderr : stdout); |
| 835 | 826 | } |
| 836 | 827 | |
| 837 | 828 | /* |
| 838 | 829 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| @@ -863,11 +854,11 @@ | ||
| 863 | 854 | return -1; |
| 864 | 855 | }else if( zB==0 ){ |
| 865 | 856 | return +1; |
| 866 | 857 | }else{ |
| 867 | 858 | int a, b; |
| 868 | - do{ | |
| 859 | + do{ | |
| 869 | 860 | a = *zA++; |
| 870 | 861 | b = *zB++; |
| 871 | 862 | }while( a==b && a!=0 ); |
| 872 | 863 | return ((unsigned char)a) - (unsigned char)b; |
| 873 | 864 | } |
| @@ -878,11 +869,11 @@ | ||
| 878 | 869 | return -1; |
| 879 | 870 | }else if( zB==0 ){ |
| 880 | 871 | return +1; |
| 881 | 872 | }else if( nByte>0 ){ |
| 882 | 873 | int a, b; |
| 883 | - do{ | |
| 874 | + do{ | |
| 884 | 875 | a = *zA++; |
| 885 | 876 | b = *zB++; |
| 886 | 877 | }while( a==b && a!=0 && (--nByte)>0 ); |
| 887 | 878 | return ((unsigned char)a) - (unsigned char)b; |
| 888 | 879 | }else{ |
| 889 | 880 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -243,11 +243,11 @@ | |
| 243 | blob_append(pBlob,"%",1); |
| 244 | count++; |
| 245 | break; |
| 246 | } |
| 247 | /* Find out what flags are present */ |
| 248 | flag_leftjustify = flag_plussign = flag_blanksign = |
| 249 | flag_alternateform = flag_altform2 = flag_zeropad = 0; |
| 250 | done = 0; |
| 251 | do{ |
| 252 | switch( c ){ |
| 253 | case '-': flag_leftjustify = 1; break; |
| @@ -814,25 +814,16 @@ | |
| 814 | ** if the output is going to the screen. If output is redirected into |
| 815 | ** a file, no translation occurs. No translation ever occurs on unix. |
| 816 | */ |
| 817 | void fossil_puts(const char *z, int toStdErr){ |
| 818 | #if defined(_WIN32) |
| 819 | static int once = 1; |
| 820 | static int istty[2]; |
| 821 | char *zToFree = 0; |
| 822 | if( once ){ |
| 823 | istty[0] = _isatty(fileno(stdout)); |
| 824 | istty[1] = _isatty(fileno(stderr)); |
| 825 | once = 0; |
| 826 | } |
| 827 | assert( toStdErr==0 || toStdErr==1 ); |
| 828 | if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); |
| 829 | fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); |
| 830 | free(zToFree); |
| 831 | #else |
| 832 | fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); |
| 833 | #endif |
| 834 | fflush(toStdErr ? stderr : stdout); |
| 835 | } |
| 836 | |
| 837 | /* |
| 838 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| @@ -863,11 +854,11 @@ | |
| 863 | return -1; |
| 864 | }else if( zB==0 ){ |
| 865 | return +1; |
| 866 | }else{ |
| 867 | int a, b; |
| 868 | do{ |
| 869 | a = *zA++; |
| 870 | b = *zB++; |
| 871 | }while( a==b && a!=0 ); |
| 872 | return ((unsigned char)a) - (unsigned char)b; |
| 873 | } |
| @@ -878,11 +869,11 @@ | |
| 878 | return -1; |
| 879 | }else if( zB==0 ){ |
| 880 | return +1; |
| 881 | }else if( nByte>0 ){ |
| 882 | int a, b; |
| 883 | do{ |
| 884 | a = *zA++; |
| 885 | b = *zB++; |
| 886 | }while( a==b && a!=0 && (--nByte)>0 ); |
| 887 | return ((unsigned char)a) - (unsigned char)b; |
| 888 | }else{ |
| 889 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -243,11 +243,11 @@ | |
| 243 | blob_append(pBlob,"%",1); |
| 244 | count++; |
| 245 | break; |
| 246 | } |
| 247 | /* Find out what flags are present */ |
| 248 | flag_leftjustify = flag_plussign = flag_blanksign = |
| 249 | flag_alternateform = flag_altform2 = flag_zeropad = 0; |
| 250 | done = 0; |
| 251 | do{ |
| 252 | switch( c ){ |
| 253 | case '-': flag_leftjustify = 1; break; |
| @@ -814,25 +814,16 @@ | |
| 814 | ** if the output is going to the screen. If output is redirected into |
| 815 | ** a file, no translation occurs. No translation ever occurs on unix. |
| 816 | */ |
| 817 | void fossil_puts(const char *z, int toStdErr){ |
| 818 | #if defined(_WIN32) |
| 819 | if( fossil_utf8_to_console(z, strlen(z), toStdErr) >= 0 ){ |
| 820 | return; |
| 821 | } |
| 822 | #endif |
| 823 | assert( toStdErr==0 || toStdErr==1 ); |
| 824 | fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); |
| 825 | fflush(toStdErr ? stderr : stdout); |
| 826 | } |
| 827 | |
| 828 | /* |
| 829 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| @@ -863,11 +854,11 @@ | |
| 854 | return -1; |
| 855 | }else if( zB==0 ){ |
| 856 | return +1; |
| 857 | }else{ |
| 858 | int a, b; |
| 859 | do{ |
| 860 | a = *zA++; |
| 861 | b = *zB++; |
| 862 | }while( a==b && a!=0 ); |
| 863 | return ((unsigned char)a) - (unsigned char)b; |
| 864 | } |
| @@ -878,11 +869,11 @@ | |
| 869 | return -1; |
| 870 | }else if( zB==0 ){ |
| 871 | return +1; |
| 872 | }else if( nByte>0 ){ |
| 873 | int a, b; |
| 874 | do{ |
| 875 | a = *zA++; |
| 876 | b = *zB++; |
| 877 | }while( a==b && a!=0 && (--nByte)>0 ); |
| 878 | return ((unsigned char)a) - (unsigned char)b; |
| 879 | }else{ |
| 880 |
+37
-30
| --- src/winhttp.c | ||
| +++ src/winhttp.c | ||
| @@ -109,11 +109,11 @@ | ||
| 109 | 109 | wanted -= got; |
| 110 | 110 | } |
| 111 | 111 | fclose(out); |
| 112 | 112 | out = 0; |
| 113 | 113 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 114 | - fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, | |
| 114 | + fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, | |
| 115 | 115 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 116 | 116 | ); |
| 117 | 117 | fossil_system(zCmd); |
| 118 | 118 | in = fossil_fopen(zReplyFName, "rb"); |
| 119 | 119 | if( in ){ |
| @@ -129,10 +129,15 @@ | ||
| 129 | 129 | file_delete(zRequestFName); |
| 130 | 130 | file_delete(zReplyFName); |
| 131 | 131 | free(p); |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | +#if !defined(UNICODE) | |
| 135 | +# define fossil_unicode_to_utf8 fossil_mbcs_to_utf8 | |
| 136 | +# define fossil_utf8_to_unicode fossil_utf8_to_mbcs | |
| 137 | +#endif | |
| 138 | + | |
| 134 | 139 | /* |
| 135 | 140 | ** Start a listening socket and process incoming HTTP requests on |
| 136 | 141 | ** that socket. |
| 137 | 142 | */ |
| 138 | 143 | void win32_http_server( |
| @@ -146,11 +151,11 @@ | ||
| 146 | 151 | SOCKET s = INVALID_SOCKET; |
| 147 | 152 | SOCKADDR_IN addr; |
| 148 | 153 | int idCnt = 0; |
| 149 | 154 | int iPort = mnPort; |
| 150 | 155 | Blob options; |
| 151 | - char zTmpPath[MAX_PATH]; | |
| 156 | + TCHAR zTmpPath[MAX_PATH]; | |
| 152 | 157 | |
| 153 | 158 | if( zStopper ) file_delete(zStopper); |
| 154 | 159 | blob_zero(&options); |
| 155 | 160 | if( zNotFound ){ |
| 156 | 161 | blob_appendf(&options, " --notfound %s", zNotFound); |
| @@ -194,11 +199,11 @@ | ||
| 194 | 199 | } |
| 195 | 200 | } |
| 196 | 201 | if( !GetTempPath(MAX_PATH, zTmpPath) ){ |
| 197 | 202 | fossil_fatal("unable to get path to the temporary directory."); |
| 198 | 203 | } |
| 199 | - zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_mbcs_to_utf8(zTmpPath), iPort); | |
| 204 | + zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_unicode_to_utf8(zTmpPath), iPort); | |
| 200 | 205 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 201 | 206 | if( zBrowser ){ |
| 202 | 207 | zBrowser = mprintf(zBrowser, iPort); |
| 203 | 208 | fossil_print("Launch webbrowser: %s\n", zBrowser); |
| 204 | 209 | fossil_system(zBrowser); |
| @@ -214,11 +219,11 @@ | ||
| 214 | 219 | int len = sizeof(client_addr); |
| 215 | 220 | int wsaError; |
| 216 | 221 | |
| 217 | 222 | client = accept(s, (struct sockaddr*)&client_addr, &len); |
| 218 | 223 | if( client==INVALID_SOCKET ){ |
| 219 | - /* If the service control handler has closed the listener socket, | |
| 224 | + /* If the service control handler has closed the listener socket, | |
| 220 | 225 | ** cleanup and return, otherwise report a fatal error. */ |
| 221 | 226 | wsaError = WSAGetLastError(); |
| 222 | 227 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| 223 | 228 | WSACleanup(); |
| 224 | 229 | return; |
| @@ -249,11 +254,11 @@ | ||
| 249 | 254 | struct HttpService { |
| 250 | 255 | int port; /* Port on which the http server should run */ |
| 251 | 256 | const char *zNotFound; /* The --notfound option, or NULL */ |
| 252 | 257 | int flags; /* One or more HTTP_SERVER_ flags */ |
| 253 | 258 | int isRunningAsService; /* Are we running as a service ? */ |
| 254 | - const char *zServiceName; /* Name of the service */ | |
| 259 | + const TCHAR *zServiceName;/* Name of the service */ | |
| 255 | 260 | SOCKET s; /* Socket on which the http server listens */ |
| 256 | 261 | }; |
| 257 | 262 | |
| 258 | 263 | /* |
| 259 | 264 | ** Variables used for running as windows service. |
| @@ -298,11 +303,11 @@ | ||
| 298 | 303 | 0, |
| 299 | 304 | NULL |
| 300 | 305 | ); |
| 301 | 306 | } |
| 302 | 307 | if( nMsg ){ |
| 303 | - zMsg = fossil_mbcs_to_utf8(tmp); | |
| 308 | + zMsg = fossil_unicode_to_utf8(tmp); | |
| 304 | 309 | }else{ |
| 305 | 310 | fossil_fatal("unable to get system error message."); |
| 306 | 311 | } |
| 307 | 312 | if( tmp ){ |
| 308 | 313 | LocalFree((HLOCAL) tmp); |
| @@ -326,11 +331,11 @@ | ||
| 326 | 331 | } |
| 327 | 332 | ssStatus.dwCurrentState = dwCurrentState; |
| 328 | 333 | ssStatus.dwWin32ExitCode = dwWin32ExitCode; |
| 329 | 334 | ssStatus.dwWaitHint = dwWaitHint; |
| 330 | 335 | |
| 331 | - if( (dwCurrentState==SERVICE_RUNNING) || | |
| 336 | + if( (dwCurrentState==SERVICE_RUNNING) || | |
| 332 | 337 | (dwCurrentState==SERVICE_STOPPED) ){ |
| 333 | 338 | ssStatus.dwCheckPoint = 0; |
| 334 | 339 | }else{ |
| 335 | 340 | ssStatus.dwCheckPoint++; |
| 336 | 341 | } |
| @@ -384,11 +389,11 @@ | ||
| 384 | 389 | if( argc>0 ){ |
| 385 | 390 | hsData.zServiceName = argv[0]; |
| 386 | 391 | } |
| 387 | 392 | |
| 388 | 393 | /* Register the service control handler function */ |
| 389 | - sshStatusHandle = RegisterServiceCtrlHandler("", win32_http_service_ctrl); | |
| 394 | + sshStatusHandle = RegisterServiceCtrlHandler(TEXT(""), win32_http_service_ctrl); | |
| 390 | 395 | if( !sshStatusHandle ){ |
| 391 | 396 | win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0); |
| 392 | 397 | return; |
| 393 | 398 | } |
| 394 | 399 | |
| @@ -429,12 +434,12 @@ | ||
| 429 | 434 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 430 | 435 | int flags /* One or more HTTP_SERVER_ flags */ |
| 431 | 436 | ){ |
| 432 | 437 | /* Define the service table. */ |
| 433 | 438 | SERVICE_TABLE_ENTRY ServiceTable[] = |
| 434 | - {{"", (LPSERVICE_MAIN_FUNCTION)win32_http_service_main}, {NULL, NULL}}; | |
| 435 | - | |
| 439 | + {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)win32_http_service_main}, {NULL, NULL}}; | |
| 440 | + | |
| 436 | 441 | /* Initialize the HttpService structure. */ |
| 437 | 442 | hsData.port = nPort; |
| 438 | 443 | hsData.zNotFound = zNotFound; |
| 439 | 444 | hsData.flags = flags; |
| 440 | 445 | |
| @@ -447,11 +452,12 @@ | ||
| 447 | 452 | } |
| 448 | 453 | } |
| 449 | 454 | return 0; |
| 450 | 455 | } |
| 451 | 456 | |
| 452 | -/* | |
| 457 | +#ifdef _WIN32 | |
| 458 | +/* dupe ifdef needed for mkindex | |
| 453 | 459 | ** COMMAND: winsrv* |
| 454 | 460 | ** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS? |
| 455 | 461 | ** |
| 456 | 462 | ** Where METHOD is one of: create delete show start stop. |
| 457 | 463 | ** |
| @@ -459,11 +465,11 @@ | ||
| 459 | 465 | ** (for example) Fossil to be running in the background when no user |
| 460 | 466 | ** is logged in. |
| 461 | 467 | ** |
| 462 | 468 | ** In the following description of the methods, "Fossil-DSCM" will be |
| 463 | 469 | ** used as the default SERVICE-NAME: |
| 464 | -** | |
| 470 | +** | |
| 465 | 471 | ** fossil winsrv create ?SERVICE-NAME? ?OPTIONS? |
| 466 | 472 | ** |
| 467 | 473 | ** Creates a service. Available options include: |
| 468 | 474 | ** |
| 469 | 475 | ** -D|--display DISPLAY-NAME |
| @@ -565,11 +571,11 @@ | ||
| 565 | 571 | |
| 566 | 572 | if( strncmp(zMethod, "create", n)==0 ){ |
| 567 | 573 | SC_HANDLE hScm; |
| 568 | 574 | SC_HANDLE hSvc; |
| 569 | 575 | SERVICE_DESCRIPTION |
| 570 | - svcDescr = {"Fossil - Distributed Software Configuration Management"}; | |
| 576 | + svcDescr = {TEXT("Fossil - Distributed Software Configuration Management")}; | |
| 571 | 577 | char *zErrFmt = "unable to create service '%s': %s"; |
| 572 | 578 | DWORD dwStartType = SERVICE_DEMAND_START; |
| 573 | 579 | const char *zDisplay = find_option("display", "D", 1); |
| 574 | 580 | const char *zStart = find_option("start", "S", 1); |
| 575 | 581 | const char *zUsername = find_option("username", "U", 1); |
| @@ -624,22 +630,22 @@ | ||
| 624 | 630 | /* Create the service. */ |
| 625 | 631 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 626 | 632 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 627 | 633 | hSvc = CreateService( |
| 628 | 634 | hScm, /* Handle to the SCM */ |
| 629 | - fossil_utf8_to_mbcs(zSvcName), /* Name of the service */ | |
| 630 | - fossil_utf8_to_mbcs(zDisplay), /* Display name */ | |
| 635 | + fossil_utf8_to_unicode(zSvcName), /* Name of the service */ | |
| 636 | + fossil_utf8_to_unicode(zDisplay), /* Display name */ | |
| 631 | 637 | SERVICE_ALL_ACCESS, /* Desired access */ |
| 632 | 638 | SERVICE_WIN32_OWN_PROCESS, /* Service type */ |
| 633 | 639 | dwStartType, /* Start type */ |
| 634 | 640 | SERVICE_ERROR_NORMAL, /* Error control */ |
| 635 | - fossil_utf8_to_mbcs(blob_str(&binPath)), /* Binary path */ | |
| 641 | + fossil_utf8_to_unicode(blob_str(&binPath)), /* Binary path */ | |
| 636 | 642 | NULL, /* Load ordering group */ |
| 637 | 643 | NULL, /* Tag value */ |
| 638 | 644 | NULL, /* Service dependencies */ |
| 639 | - fossil_utf8_to_mbcs(zUsername), /* Service account */ | |
| 640 | - fossil_utf8_to_mbcs(zPassword) /* Account password */ | |
| 645 | + fossil_utf8_to_unicode(zUsername), /* Service account */ | |
| 646 | + fossil_utf8_to_unicode(zPassword) /* Account password */ | |
| 641 | 647 | ); |
| 642 | 648 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 643 | 649 | /* Set the service description. */ |
| 644 | 650 | ChangeServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, &svcDescr); |
| 645 | 651 | fossil_print("Service '%s' successfully created.\n", zSvcName); |
| @@ -658,11 +664,11 @@ | ||
| 658 | 664 | }else if( g.argc>4 ){ |
| 659 | 665 | fossil_fatal("to much arguments for delete method."); |
| 660 | 666 | } |
| 661 | 667 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 662 | 668 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 663 | - hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); | |
| 669 | + hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); | |
| 664 | 670 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 665 | 671 | QueryServiceStatus(hSvc, &sstat); |
| 666 | 672 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 667 | 673 | fossil_print("Stopping service '%s'", zSvcName); |
| 668 | 674 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -695,28 +701,28 @@ | ||
| 695 | 701 | SERVICE_STATUS sstat; |
| 696 | 702 | LPQUERY_SERVICE_CONFIG pSvcConfig; |
| 697 | 703 | LPSERVICE_DESCRIPTION pSvcDescr; |
| 698 | 704 | BOOL bStatus; |
| 699 | 705 | DWORD nRequired; |
| 700 | - char *zErrFmt = "unable to show service '%s': %s"; | |
| 701 | - static const char *zSvcTypes[] = { | |
| 706 | + const char *zErrFmt = "unable to show service '%s': %s"; | |
| 707 | + static const char *const zSvcTypes[] = { | |
| 702 | 708 | "Driver service", |
| 703 | 709 | "File system driver service", |
| 704 | 710 | "Service runs in its own process", |
| 705 | 711 | "Service shares a process with other services", |
| 706 | 712 | "Service can interact with the desktop" |
| 707 | 713 | }; |
| 708 | 714 | const char *zSvcType = ""; |
| 709 | - static char *zSvcStartTypes[] = { | |
| 715 | + static const char *const zSvcStartTypes[] = { | |
| 710 | 716 | "Started by the system loader", |
| 711 | 717 | "Started by the IoInitSystem function", |
| 712 | 718 | "Started automatically by the service control manager", |
| 713 | 719 | "Started manually", |
| 714 | 720 | "Service cannot be started" |
| 715 | 721 | }; |
| 716 | 722 | const char *zSvcStartType = ""; |
| 717 | - static const char *zSvcStates[] = { | |
| 723 | + static const char *const zSvcStates[] = { | |
| 718 | 724 | "Stopped", "Starting", "Stopping", "Running", |
| 719 | 725 | "Continue pending", "Pause pending", "Paused" |
| 720 | 726 | }; |
| 721 | 727 | const char *zSvcState = ""; |
| 722 | 728 | |
| @@ -726,11 +732,11 @@ | ||
| 726 | 732 | }else if( g.argc>4 ){ |
| 727 | 733 | fossil_fatal("to much arguments for show method."); |
| 728 | 734 | } |
| 729 | 735 | hScm = OpenSCManager(NULL, NULL, GENERIC_READ); |
| 730 | 736 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 731 | - hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), GENERIC_READ); | |
| 737 | + hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), GENERIC_READ); | |
| 732 | 738 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 733 | 739 | /* Get the service configuration */ |
| 734 | 740 | bStatus = QueryServiceConfig(hSvc, NULL, 0, &nRequired); |
| 735 | 741 | if( !bStatus && GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){ |
| 736 | 742 | fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| @@ -778,19 +784,19 @@ | ||
| 778 | 784 | case SERVICE_PAUSED: zSvcState = zSvcStates[6]; break; |
| 779 | 785 | } |
| 780 | 786 | /* Print service information to terminal */ |
| 781 | 787 | fossil_print("Service name .......: %s\n", zSvcName); |
| 782 | 788 | fossil_print("Display name .......: %s\n", |
| 783 | - fossil_mbcs_to_utf8(pSvcConfig->lpDisplayName)); | |
| 789 | + fossil_unicode_to_utf8(pSvcConfig->lpDisplayName)); | |
| 784 | 790 | fossil_print("Service description : %s\n", |
| 785 | - fossil_mbcs_to_utf8(pSvcDescr->lpDescription)); | |
| 791 | + fossil_unicode_to_utf8(pSvcDescr->lpDescription)); | |
| 786 | 792 | fossil_print("Service type .......: %s.\n", zSvcType); |
| 787 | 793 | fossil_print("Service start type .: %s.\n", zSvcStartType); |
| 788 | 794 | fossil_print("Binary path name ...: %s\n", |
| 789 | - fossil_mbcs_to_utf8(pSvcConfig->lpBinaryPathName)); | |
| 795 | + fossil_unicode_to_utf8(pSvcConfig->lpBinaryPathName)); | |
| 790 | 796 | fossil_print("Service username ...: %s\n", |
| 791 | - fossil_mbcs_to_utf8(pSvcConfig->lpServiceStartName)); | |
| 797 | + fossil_unicode_to_utf8(pSvcConfig->lpServiceStartName)); | |
| 792 | 798 | fossil_print("Current state ......: %s.\n", zSvcState); |
| 793 | 799 | /* Cleanup */ |
| 794 | 800 | fossil_free(pSvcConfig); |
| 795 | 801 | fossil_free(pSvcDescr); |
| 796 | 802 | CloseServiceHandle(hSvc); |
| @@ -808,11 +814,11 @@ | ||
| 808 | 814 | }else if( g.argc>4 ){ |
| 809 | 815 | fossil_fatal("to much arguments for start method."); |
| 810 | 816 | } |
| 811 | 817 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 812 | 818 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 813 | - hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); | |
| 819 | + hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); | |
| 814 | 820 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 815 | 821 | QueryServiceStatus(hSvc, &sstat); |
| 816 | 822 | if( sstat.dwCurrentState!=SERVICE_RUNNING ){ |
| 817 | 823 | fossil_print("Starting service '%s'", zSvcName); |
| 818 | 824 | if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ |
| @@ -844,11 +850,11 @@ | ||
| 844 | 850 | }else if( g.argc>4 ){ |
| 845 | 851 | fossil_fatal("to much arguments for stop method."); |
| 846 | 852 | } |
| 847 | 853 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 848 | 854 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 849 | - hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); | |
| 855 | + hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); | |
| 850 | 856 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 851 | 857 | QueryServiceStatus(hSvc, &sstat); |
| 852 | 858 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 853 | 859 | fossil_print("Stopping service '%s'", zSvcName); |
| 854 | 860 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -872,7 +878,8 @@ | ||
| 872 | 878 | fossil_fatal("METHOD should be one of:" |
| 873 | 879 | " create delete show start stop"); |
| 874 | 880 | } |
| 875 | 881 | return; |
| 876 | 882 | } |
| 883 | +#endif /* _WIN32 */ | |
| 877 | 884 | |
| 878 | 885 | #endif /* _WIN32 -- This code is for win32 only */ |
| 879 | 886 | |
| 880 | 887 | ADDED test/cmdline.test |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -109,11 +109,11 @@ | |
| 109 | wanted -= got; |
| 110 | } |
| 111 | fclose(out); |
| 112 | out = 0; |
| 113 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 114 | fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, |
| 115 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 116 | ); |
| 117 | fossil_system(zCmd); |
| 118 | in = fossil_fopen(zReplyFName, "rb"); |
| 119 | if( in ){ |
| @@ -129,10 +129,15 @@ | |
| 129 | file_delete(zRequestFName); |
| 130 | file_delete(zReplyFName); |
| 131 | free(p); |
| 132 | } |
| 133 | |
| 134 | /* |
| 135 | ** Start a listening socket and process incoming HTTP requests on |
| 136 | ** that socket. |
| 137 | */ |
| 138 | void win32_http_server( |
| @@ -146,11 +151,11 @@ | |
| 146 | SOCKET s = INVALID_SOCKET; |
| 147 | SOCKADDR_IN addr; |
| 148 | int idCnt = 0; |
| 149 | int iPort = mnPort; |
| 150 | Blob options; |
| 151 | char zTmpPath[MAX_PATH]; |
| 152 | |
| 153 | if( zStopper ) file_delete(zStopper); |
| 154 | blob_zero(&options); |
| 155 | if( zNotFound ){ |
| 156 | blob_appendf(&options, " --notfound %s", zNotFound); |
| @@ -194,11 +199,11 @@ | |
| 194 | } |
| 195 | } |
| 196 | if( !GetTempPath(MAX_PATH, zTmpPath) ){ |
| 197 | fossil_fatal("unable to get path to the temporary directory."); |
| 198 | } |
| 199 | zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_mbcs_to_utf8(zTmpPath), iPort); |
| 200 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 201 | if( zBrowser ){ |
| 202 | zBrowser = mprintf(zBrowser, iPort); |
| 203 | fossil_print("Launch webbrowser: %s\n", zBrowser); |
| 204 | fossil_system(zBrowser); |
| @@ -214,11 +219,11 @@ | |
| 214 | int len = sizeof(client_addr); |
| 215 | int wsaError; |
| 216 | |
| 217 | client = accept(s, (struct sockaddr*)&client_addr, &len); |
| 218 | if( client==INVALID_SOCKET ){ |
| 219 | /* If the service control handler has closed the listener socket, |
| 220 | ** cleanup and return, otherwise report a fatal error. */ |
| 221 | wsaError = WSAGetLastError(); |
| 222 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| 223 | WSACleanup(); |
| 224 | return; |
| @@ -249,11 +254,11 @@ | |
| 249 | struct HttpService { |
| 250 | int port; /* Port on which the http server should run */ |
| 251 | const char *zNotFound; /* The --notfound option, or NULL */ |
| 252 | int flags; /* One or more HTTP_SERVER_ flags */ |
| 253 | int isRunningAsService; /* Are we running as a service ? */ |
| 254 | const char *zServiceName; /* Name of the service */ |
| 255 | SOCKET s; /* Socket on which the http server listens */ |
| 256 | }; |
| 257 | |
| 258 | /* |
| 259 | ** Variables used for running as windows service. |
| @@ -298,11 +303,11 @@ | |
| 298 | 0, |
| 299 | NULL |
| 300 | ); |
| 301 | } |
| 302 | if( nMsg ){ |
| 303 | zMsg = fossil_mbcs_to_utf8(tmp); |
| 304 | }else{ |
| 305 | fossil_fatal("unable to get system error message."); |
| 306 | } |
| 307 | if( tmp ){ |
| 308 | LocalFree((HLOCAL) tmp); |
| @@ -326,11 +331,11 @@ | |
| 326 | } |
| 327 | ssStatus.dwCurrentState = dwCurrentState; |
| 328 | ssStatus.dwWin32ExitCode = dwWin32ExitCode; |
| 329 | ssStatus.dwWaitHint = dwWaitHint; |
| 330 | |
| 331 | if( (dwCurrentState==SERVICE_RUNNING) || |
| 332 | (dwCurrentState==SERVICE_STOPPED) ){ |
| 333 | ssStatus.dwCheckPoint = 0; |
| 334 | }else{ |
| 335 | ssStatus.dwCheckPoint++; |
| 336 | } |
| @@ -384,11 +389,11 @@ | |
| 384 | if( argc>0 ){ |
| 385 | hsData.zServiceName = argv[0]; |
| 386 | } |
| 387 | |
| 388 | /* Register the service control handler function */ |
| 389 | sshStatusHandle = RegisterServiceCtrlHandler("", win32_http_service_ctrl); |
| 390 | if( !sshStatusHandle ){ |
| 391 | win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0); |
| 392 | return; |
| 393 | } |
| 394 | |
| @@ -429,12 +434,12 @@ | |
| 429 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 430 | int flags /* One or more HTTP_SERVER_ flags */ |
| 431 | ){ |
| 432 | /* Define the service table. */ |
| 433 | SERVICE_TABLE_ENTRY ServiceTable[] = |
| 434 | {{"", (LPSERVICE_MAIN_FUNCTION)win32_http_service_main}, {NULL, NULL}}; |
| 435 | |
| 436 | /* Initialize the HttpService structure. */ |
| 437 | hsData.port = nPort; |
| 438 | hsData.zNotFound = zNotFound; |
| 439 | hsData.flags = flags; |
| 440 | |
| @@ -447,11 +452,12 @@ | |
| 447 | } |
| 448 | } |
| 449 | return 0; |
| 450 | } |
| 451 | |
| 452 | /* |
| 453 | ** COMMAND: winsrv* |
| 454 | ** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS? |
| 455 | ** |
| 456 | ** Where METHOD is one of: create delete show start stop. |
| 457 | ** |
| @@ -459,11 +465,11 @@ | |
| 459 | ** (for example) Fossil to be running in the background when no user |
| 460 | ** is logged in. |
| 461 | ** |
| 462 | ** In the following description of the methods, "Fossil-DSCM" will be |
| 463 | ** used as the default SERVICE-NAME: |
| 464 | ** |
| 465 | ** fossil winsrv create ?SERVICE-NAME? ?OPTIONS? |
| 466 | ** |
| 467 | ** Creates a service. Available options include: |
| 468 | ** |
| 469 | ** -D|--display DISPLAY-NAME |
| @@ -565,11 +571,11 @@ | |
| 565 | |
| 566 | if( strncmp(zMethod, "create", n)==0 ){ |
| 567 | SC_HANDLE hScm; |
| 568 | SC_HANDLE hSvc; |
| 569 | SERVICE_DESCRIPTION |
| 570 | svcDescr = {"Fossil - Distributed Software Configuration Management"}; |
| 571 | char *zErrFmt = "unable to create service '%s': %s"; |
| 572 | DWORD dwStartType = SERVICE_DEMAND_START; |
| 573 | const char *zDisplay = find_option("display", "D", 1); |
| 574 | const char *zStart = find_option("start", "S", 1); |
| 575 | const char *zUsername = find_option("username", "U", 1); |
| @@ -624,22 +630,22 @@ | |
| 624 | /* Create the service. */ |
| 625 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 626 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 627 | hSvc = CreateService( |
| 628 | hScm, /* Handle to the SCM */ |
| 629 | fossil_utf8_to_mbcs(zSvcName), /* Name of the service */ |
| 630 | fossil_utf8_to_mbcs(zDisplay), /* Display name */ |
| 631 | SERVICE_ALL_ACCESS, /* Desired access */ |
| 632 | SERVICE_WIN32_OWN_PROCESS, /* Service type */ |
| 633 | dwStartType, /* Start type */ |
| 634 | SERVICE_ERROR_NORMAL, /* Error control */ |
| 635 | fossil_utf8_to_mbcs(blob_str(&binPath)), /* Binary path */ |
| 636 | NULL, /* Load ordering group */ |
| 637 | NULL, /* Tag value */ |
| 638 | NULL, /* Service dependencies */ |
| 639 | fossil_utf8_to_mbcs(zUsername), /* Service account */ |
| 640 | fossil_utf8_to_mbcs(zPassword) /* Account password */ |
| 641 | ); |
| 642 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 643 | /* Set the service description. */ |
| 644 | ChangeServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, &svcDescr); |
| 645 | fossil_print("Service '%s' successfully created.\n", zSvcName); |
| @@ -658,11 +664,11 @@ | |
| 658 | }else if( g.argc>4 ){ |
| 659 | fossil_fatal("to much arguments for delete method."); |
| 660 | } |
| 661 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 662 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 663 | hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); |
| 664 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 665 | QueryServiceStatus(hSvc, &sstat); |
| 666 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 667 | fossil_print("Stopping service '%s'", zSvcName); |
| 668 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -695,28 +701,28 @@ | |
| 695 | SERVICE_STATUS sstat; |
| 696 | LPQUERY_SERVICE_CONFIG pSvcConfig; |
| 697 | LPSERVICE_DESCRIPTION pSvcDescr; |
| 698 | BOOL bStatus; |
| 699 | DWORD nRequired; |
| 700 | char *zErrFmt = "unable to show service '%s': %s"; |
| 701 | static const char *zSvcTypes[] = { |
| 702 | "Driver service", |
| 703 | "File system driver service", |
| 704 | "Service runs in its own process", |
| 705 | "Service shares a process with other services", |
| 706 | "Service can interact with the desktop" |
| 707 | }; |
| 708 | const char *zSvcType = ""; |
| 709 | static char *zSvcStartTypes[] = { |
| 710 | "Started by the system loader", |
| 711 | "Started by the IoInitSystem function", |
| 712 | "Started automatically by the service control manager", |
| 713 | "Started manually", |
| 714 | "Service cannot be started" |
| 715 | }; |
| 716 | const char *zSvcStartType = ""; |
| 717 | static const char *zSvcStates[] = { |
| 718 | "Stopped", "Starting", "Stopping", "Running", |
| 719 | "Continue pending", "Pause pending", "Paused" |
| 720 | }; |
| 721 | const char *zSvcState = ""; |
| 722 | |
| @@ -726,11 +732,11 @@ | |
| 726 | }else if( g.argc>4 ){ |
| 727 | fossil_fatal("to much arguments for show method."); |
| 728 | } |
| 729 | hScm = OpenSCManager(NULL, NULL, GENERIC_READ); |
| 730 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 731 | hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), GENERIC_READ); |
| 732 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 733 | /* Get the service configuration */ |
| 734 | bStatus = QueryServiceConfig(hSvc, NULL, 0, &nRequired); |
| 735 | if( !bStatus && GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){ |
| 736 | fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| @@ -778,19 +784,19 @@ | |
| 778 | case SERVICE_PAUSED: zSvcState = zSvcStates[6]; break; |
| 779 | } |
| 780 | /* Print service information to terminal */ |
| 781 | fossil_print("Service name .......: %s\n", zSvcName); |
| 782 | fossil_print("Display name .......: %s\n", |
| 783 | fossil_mbcs_to_utf8(pSvcConfig->lpDisplayName)); |
| 784 | fossil_print("Service description : %s\n", |
| 785 | fossil_mbcs_to_utf8(pSvcDescr->lpDescription)); |
| 786 | fossil_print("Service type .......: %s.\n", zSvcType); |
| 787 | fossil_print("Service start type .: %s.\n", zSvcStartType); |
| 788 | fossil_print("Binary path name ...: %s\n", |
| 789 | fossil_mbcs_to_utf8(pSvcConfig->lpBinaryPathName)); |
| 790 | fossil_print("Service username ...: %s\n", |
| 791 | fossil_mbcs_to_utf8(pSvcConfig->lpServiceStartName)); |
| 792 | fossil_print("Current state ......: %s.\n", zSvcState); |
| 793 | /* Cleanup */ |
| 794 | fossil_free(pSvcConfig); |
| 795 | fossil_free(pSvcDescr); |
| 796 | CloseServiceHandle(hSvc); |
| @@ -808,11 +814,11 @@ | |
| 808 | }else if( g.argc>4 ){ |
| 809 | fossil_fatal("to much arguments for start method."); |
| 810 | } |
| 811 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 812 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 813 | hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); |
| 814 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 815 | QueryServiceStatus(hSvc, &sstat); |
| 816 | if( sstat.dwCurrentState!=SERVICE_RUNNING ){ |
| 817 | fossil_print("Starting service '%s'", zSvcName); |
| 818 | if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ |
| @@ -844,11 +850,11 @@ | |
| 844 | }else if( g.argc>4 ){ |
| 845 | fossil_fatal("to much arguments for stop method."); |
| 846 | } |
| 847 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 848 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 849 | hSvc = OpenService(hScm, fossil_utf8_to_mbcs(zSvcName), SERVICE_ALL_ACCESS); |
| 850 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 851 | QueryServiceStatus(hSvc, &sstat); |
| 852 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 853 | fossil_print("Stopping service '%s'", zSvcName); |
| 854 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -872,7 +878,8 @@ | |
| 872 | fossil_fatal("METHOD should be one of:" |
| 873 | " create delete show start stop"); |
| 874 | } |
| 875 | return; |
| 876 | } |
| 877 | |
| 878 | #endif /* _WIN32 -- This code is for win32 only */ |
| 879 | |
| 880 | DDED test/cmdline.test |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -109,11 +109,11 @@ | |
| 109 | wanted -= got; |
| 110 | } |
| 111 | fclose(out); |
| 112 | out = 0; |
| 113 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 114 | fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, |
| 115 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 116 | ); |
| 117 | fossil_system(zCmd); |
| 118 | in = fossil_fopen(zReplyFName, "rb"); |
| 119 | if( in ){ |
| @@ -129,10 +129,15 @@ | |
| 129 | file_delete(zRequestFName); |
| 130 | file_delete(zReplyFName); |
| 131 | free(p); |
| 132 | } |
| 133 | |
| 134 | #if !defined(UNICODE) |
| 135 | # define fossil_unicode_to_utf8 fossil_mbcs_to_utf8 |
| 136 | # define fossil_utf8_to_unicode fossil_utf8_to_mbcs |
| 137 | #endif |
| 138 | |
| 139 | /* |
| 140 | ** Start a listening socket and process incoming HTTP requests on |
| 141 | ** that socket. |
| 142 | */ |
| 143 | void win32_http_server( |
| @@ -146,11 +151,11 @@ | |
| 151 | SOCKET s = INVALID_SOCKET; |
| 152 | SOCKADDR_IN addr; |
| 153 | int idCnt = 0; |
| 154 | int iPort = mnPort; |
| 155 | Blob options; |
| 156 | TCHAR zTmpPath[MAX_PATH]; |
| 157 | |
| 158 | if( zStopper ) file_delete(zStopper); |
| 159 | blob_zero(&options); |
| 160 | if( zNotFound ){ |
| 161 | blob_appendf(&options, " --notfound %s", zNotFound); |
| @@ -194,11 +199,11 @@ | |
| 199 | } |
| 200 | } |
| 201 | if( !GetTempPath(MAX_PATH, zTmpPath) ){ |
| 202 | fossil_fatal("unable to get path to the temporary directory."); |
| 203 | } |
| 204 | zTempPrefix = mprintf("%sfossil_server_P%d_", fossil_unicode_to_utf8(zTmpPath), iPort); |
| 205 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 206 | if( zBrowser ){ |
| 207 | zBrowser = mprintf(zBrowser, iPort); |
| 208 | fossil_print("Launch webbrowser: %s\n", zBrowser); |
| 209 | fossil_system(zBrowser); |
| @@ -214,11 +219,11 @@ | |
| 219 | int len = sizeof(client_addr); |
| 220 | int wsaError; |
| 221 | |
| 222 | client = accept(s, (struct sockaddr*)&client_addr, &len); |
| 223 | if( client==INVALID_SOCKET ){ |
| 224 | /* If the service control handler has closed the listener socket, |
| 225 | ** cleanup and return, otherwise report a fatal error. */ |
| 226 | wsaError = WSAGetLastError(); |
| 227 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| 228 | WSACleanup(); |
| 229 | return; |
| @@ -249,11 +254,11 @@ | |
| 254 | struct HttpService { |
| 255 | int port; /* Port on which the http server should run */ |
| 256 | const char *zNotFound; /* The --notfound option, or NULL */ |
| 257 | int flags; /* One or more HTTP_SERVER_ flags */ |
| 258 | int isRunningAsService; /* Are we running as a service ? */ |
| 259 | const TCHAR *zServiceName;/* Name of the service */ |
| 260 | SOCKET s; /* Socket on which the http server listens */ |
| 261 | }; |
| 262 | |
| 263 | /* |
| 264 | ** Variables used for running as windows service. |
| @@ -298,11 +303,11 @@ | |
| 303 | 0, |
| 304 | NULL |
| 305 | ); |
| 306 | } |
| 307 | if( nMsg ){ |
| 308 | zMsg = fossil_unicode_to_utf8(tmp); |
| 309 | }else{ |
| 310 | fossil_fatal("unable to get system error message."); |
| 311 | } |
| 312 | if( tmp ){ |
| 313 | LocalFree((HLOCAL) tmp); |
| @@ -326,11 +331,11 @@ | |
| 331 | } |
| 332 | ssStatus.dwCurrentState = dwCurrentState; |
| 333 | ssStatus.dwWin32ExitCode = dwWin32ExitCode; |
| 334 | ssStatus.dwWaitHint = dwWaitHint; |
| 335 | |
| 336 | if( (dwCurrentState==SERVICE_RUNNING) || |
| 337 | (dwCurrentState==SERVICE_STOPPED) ){ |
| 338 | ssStatus.dwCheckPoint = 0; |
| 339 | }else{ |
| 340 | ssStatus.dwCheckPoint++; |
| 341 | } |
| @@ -384,11 +389,11 @@ | |
| 389 | if( argc>0 ){ |
| 390 | hsData.zServiceName = argv[0]; |
| 391 | } |
| 392 | |
| 393 | /* Register the service control handler function */ |
| 394 | sshStatusHandle = RegisterServiceCtrlHandler(TEXT(""), win32_http_service_ctrl); |
| 395 | if( !sshStatusHandle ){ |
| 396 | win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0); |
| 397 | return; |
| 398 | } |
| 399 | |
| @@ -429,12 +434,12 @@ | |
| 434 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 435 | int flags /* One or more HTTP_SERVER_ flags */ |
| 436 | ){ |
| 437 | /* Define the service table. */ |
| 438 | SERVICE_TABLE_ENTRY ServiceTable[] = |
| 439 | {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)win32_http_service_main}, {NULL, NULL}}; |
| 440 | |
| 441 | /* Initialize the HttpService structure. */ |
| 442 | hsData.port = nPort; |
| 443 | hsData.zNotFound = zNotFound; |
| 444 | hsData.flags = flags; |
| 445 | |
| @@ -447,11 +452,12 @@ | |
| 452 | } |
| 453 | } |
| 454 | return 0; |
| 455 | } |
| 456 | |
| 457 | #ifdef _WIN32 |
| 458 | /* dupe ifdef needed for mkindex |
| 459 | ** COMMAND: winsrv* |
| 460 | ** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS? |
| 461 | ** |
| 462 | ** Where METHOD is one of: create delete show start stop. |
| 463 | ** |
| @@ -459,11 +465,11 @@ | |
| 465 | ** (for example) Fossil to be running in the background when no user |
| 466 | ** is logged in. |
| 467 | ** |
| 468 | ** In the following description of the methods, "Fossil-DSCM" will be |
| 469 | ** used as the default SERVICE-NAME: |
| 470 | ** |
| 471 | ** fossil winsrv create ?SERVICE-NAME? ?OPTIONS? |
| 472 | ** |
| 473 | ** Creates a service. Available options include: |
| 474 | ** |
| 475 | ** -D|--display DISPLAY-NAME |
| @@ -565,11 +571,11 @@ | |
| 571 | |
| 572 | if( strncmp(zMethod, "create", n)==0 ){ |
| 573 | SC_HANDLE hScm; |
| 574 | SC_HANDLE hSvc; |
| 575 | SERVICE_DESCRIPTION |
| 576 | svcDescr = {TEXT("Fossil - Distributed Software Configuration Management")}; |
| 577 | char *zErrFmt = "unable to create service '%s': %s"; |
| 578 | DWORD dwStartType = SERVICE_DEMAND_START; |
| 579 | const char *zDisplay = find_option("display", "D", 1); |
| 580 | const char *zStart = find_option("start", "S", 1); |
| 581 | const char *zUsername = find_option("username", "U", 1); |
| @@ -624,22 +630,22 @@ | |
| 630 | /* Create the service. */ |
| 631 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 632 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 633 | hSvc = CreateService( |
| 634 | hScm, /* Handle to the SCM */ |
| 635 | fossil_utf8_to_unicode(zSvcName), /* Name of the service */ |
| 636 | fossil_utf8_to_unicode(zDisplay), /* Display name */ |
| 637 | SERVICE_ALL_ACCESS, /* Desired access */ |
| 638 | SERVICE_WIN32_OWN_PROCESS, /* Service type */ |
| 639 | dwStartType, /* Start type */ |
| 640 | SERVICE_ERROR_NORMAL, /* Error control */ |
| 641 | fossil_utf8_to_unicode(blob_str(&binPath)), /* Binary path */ |
| 642 | NULL, /* Load ordering group */ |
| 643 | NULL, /* Tag value */ |
| 644 | NULL, /* Service dependencies */ |
| 645 | fossil_utf8_to_unicode(zUsername), /* Service account */ |
| 646 | fossil_utf8_to_unicode(zPassword) /* Account password */ |
| 647 | ); |
| 648 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 649 | /* Set the service description. */ |
| 650 | ChangeServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, &svcDescr); |
| 651 | fossil_print("Service '%s' successfully created.\n", zSvcName); |
| @@ -658,11 +664,11 @@ | |
| 664 | }else if( g.argc>4 ){ |
| 665 | fossil_fatal("to much arguments for delete method."); |
| 666 | } |
| 667 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 668 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 669 | hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); |
| 670 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 671 | QueryServiceStatus(hSvc, &sstat); |
| 672 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 673 | fossil_print("Stopping service '%s'", zSvcName); |
| 674 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -695,28 +701,28 @@ | |
| 701 | SERVICE_STATUS sstat; |
| 702 | LPQUERY_SERVICE_CONFIG pSvcConfig; |
| 703 | LPSERVICE_DESCRIPTION pSvcDescr; |
| 704 | BOOL bStatus; |
| 705 | DWORD nRequired; |
| 706 | const char *zErrFmt = "unable to show service '%s': %s"; |
| 707 | static const char *const zSvcTypes[] = { |
| 708 | "Driver service", |
| 709 | "File system driver service", |
| 710 | "Service runs in its own process", |
| 711 | "Service shares a process with other services", |
| 712 | "Service can interact with the desktop" |
| 713 | }; |
| 714 | const char *zSvcType = ""; |
| 715 | static const char *const zSvcStartTypes[] = { |
| 716 | "Started by the system loader", |
| 717 | "Started by the IoInitSystem function", |
| 718 | "Started automatically by the service control manager", |
| 719 | "Started manually", |
| 720 | "Service cannot be started" |
| 721 | }; |
| 722 | const char *zSvcStartType = ""; |
| 723 | static const char *const zSvcStates[] = { |
| 724 | "Stopped", "Starting", "Stopping", "Running", |
| 725 | "Continue pending", "Pause pending", "Paused" |
| 726 | }; |
| 727 | const char *zSvcState = ""; |
| 728 | |
| @@ -726,11 +732,11 @@ | |
| 732 | }else if( g.argc>4 ){ |
| 733 | fossil_fatal("to much arguments for show method."); |
| 734 | } |
| 735 | hScm = OpenSCManager(NULL, NULL, GENERIC_READ); |
| 736 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 737 | hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), GENERIC_READ); |
| 738 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 739 | /* Get the service configuration */ |
| 740 | bStatus = QueryServiceConfig(hSvc, NULL, 0, &nRequired); |
| 741 | if( !bStatus && GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){ |
| 742 | fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| @@ -778,19 +784,19 @@ | |
| 784 | case SERVICE_PAUSED: zSvcState = zSvcStates[6]; break; |
| 785 | } |
| 786 | /* Print service information to terminal */ |
| 787 | fossil_print("Service name .......: %s\n", zSvcName); |
| 788 | fossil_print("Display name .......: %s\n", |
| 789 | fossil_unicode_to_utf8(pSvcConfig->lpDisplayName)); |
| 790 | fossil_print("Service description : %s\n", |
| 791 | fossil_unicode_to_utf8(pSvcDescr->lpDescription)); |
| 792 | fossil_print("Service type .......: %s.\n", zSvcType); |
| 793 | fossil_print("Service start type .: %s.\n", zSvcStartType); |
| 794 | fossil_print("Binary path name ...: %s\n", |
| 795 | fossil_unicode_to_utf8(pSvcConfig->lpBinaryPathName)); |
| 796 | fossil_print("Service username ...: %s\n", |
| 797 | fossil_unicode_to_utf8(pSvcConfig->lpServiceStartName)); |
| 798 | fossil_print("Current state ......: %s.\n", zSvcState); |
| 799 | /* Cleanup */ |
| 800 | fossil_free(pSvcConfig); |
| 801 | fossil_free(pSvcDescr); |
| 802 | CloseServiceHandle(hSvc); |
| @@ -808,11 +814,11 @@ | |
| 814 | }else if( g.argc>4 ){ |
| 815 | fossil_fatal("to much arguments for start method."); |
| 816 | } |
| 817 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 818 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 819 | hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); |
| 820 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 821 | QueryServiceStatus(hSvc, &sstat); |
| 822 | if( sstat.dwCurrentState!=SERVICE_RUNNING ){ |
| 823 | fossil_print("Starting service '%s'", zSvcName); |
| 824 | if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ |
| @@ -844,11 +850,11 @@ | |
| 850 | }else if( g.argc>4 ){ |
| 851 | fossil_fatal("to much arguments for stop method."); |
| 852 | } |
| 853 | hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); |
| 854 | if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 855 | hSvc = OpenService(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); |
| 856 | if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); |
| 857 | QueryServiceStatus(hSvc, &sstat); |
| 858 | if( sstat.dwCurrentState!=SERVICE_STOPPED ){ |
| 859 | fossil_print("Stopping service '%s'", zSvcName); |
| 860 | if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){ |
| @@ -872,7 +878,8 @@ | |
| 878 | fossil_fatal("METHOD should be one of:" |
| 879 | " create delete show start stop"); |
| 880 | } |
| 881 | return; |
| 882 | } |
| 883 | #endif /* _WIN32 */ |
| 884 | |
| 885 | #endif /* _WIN32 -- This code is for win32 only */ |
| 886 | |
| 887 | 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 |
+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 |
+1
-1
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -32,11 +32,11 @@ | ||
| 32 | 32 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 33 | 33 | ZLIB = zlib.lib |
| 34 | 34 | |
| 35 | 35 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 36 | 36 | |
| 37 | -CFLAGS = -nologo -MT -O2 | |
| 37 | +CFLAGS = -nologo -MT -O2 -DUNICODE -D_UNICODE | |
| 38 | 38 | BCC = $(CC) $(CFLAGS) |
| 39 | 39 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) |
| 40 | 40 | LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB) |
| 41 | 41 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 42 | 42 | |
| 43 | 43 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -32,11 +32,11 @@ | |
| 32 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 33 | ZLIB = zlib.lib |
| 34 | |
| 35 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 36 | |
| 37 | CFLAGS = -nologo -MT -O2 |
| 38 | BCC = $(CC) $(CFLAGS) |
| 39 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) |
| 40 | LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB) |
| 41 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 42 | |
| 43 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -32,11 +32,11 @@ | |
| 32 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 33 | ZLIB = zlib.lib |
| 34 | |
| 35 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 36 | |
| 37 | CFLAGS = -nologo -MT -O2 -DUNICODE -D_UNICODE |
| 38 | BCC = $(CC) $(CFLAGS) |
| 39 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) |
| 40 | LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB) |
| 41 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 42 | |
| 43 |