Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch unicode-cmdline Excluding Merge-Ins
This is equivalent to a diff from ffcdfadbda to b19ef490fd
2012-09-11
| ||
12:16 | Merge the unicode-cmdline branch into trunk. check-in: f668ff44c0 user: drh tags: trunk | |
11:57 | Merge the latest trunk changes and the mingw-broken-cmdline branch into unicode-cmdline. Closed-Leaf check-in: b19ef490fd user: drh tags: unicode-cmdline | |
2012-09-10
| ||
18:15 | add .PHONY target to makefile, this makes "make test" work even though there already is a directory named "test" check-in: ffcdfadbda user: jan.nijtmans tags: trunk | |
08:21 | Add some test cases Closed-Leaf check-in: d43165418c user: jan.nijtmans tags: mingw-broken-cmdline | |
2012-09-08
| ||
13:13 | Fix a harmless compiler warning. check-in: c42408e15b user: drh tags: trunk | |
2012-09-07
| ||
07:55 | merge trunk check-in: af4287ac3a user: jan.nijtmans tags: unicode-cmdline | |
Changes to src/blob.c.
128 128 fputs(zErrMsg, stderr); 129 129 fossil_exit(1); 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 */ 141 141 void blobReallocMalloc(Blob *pBlob, unsigned int newSize){ 142 142 if( newSize==0 ){ ................................................................................ 366 366 #if INTERFACE 367 367 # define blob_eq(B,S) \ 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; 379 379 pBlob->aData[newSize] = 0; 380 380 } ................................................................................ 451 451 ** Return the current offset into the blob 452 452 */ 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 ** 464 464 ** The cursor of pFrom is left pointing at the first byte past the 465 465 ** \n that terminated the line. ................................................................................ 667 667 va_end(ap); 668 668 } 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; 680 680 blob_zero(pBlob); 681 681 if( nToRead<0 ){ ................................................................................ 765 765 ** Return the number of bytes written. 766 766 */ 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]; 789 783 790 784 nName = strlen(zFilename); ................................................................................ 831 825 blob_size(pBlob), zFilename); 832 826 } 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; 845 839 unsigned long int nOut2; 846 840 unsigned char *outBuf; ................................................................................ 869 863 if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE"); 870 864 blob_read_from_file(&f, g.argv[2]); 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); 884 878 unsigned int nOut = 13 + nIn + (nIn+999)/1000; 885 879 unsigned char *outBuf; ................................................................................ 942 936 return 0; 943 937 } 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 } 955 949 blob_resize(&temp, nOut2); 956 950 if( pOut==pIn ) blob_reset(pOut); ................................................................................ 1060 1054 ** bytes from pIn, starting at position pIn->iCursor, and copies them 1061 1055 ** to pDest (which must be valid memory at least nLen bytes long). 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 } else if( (pIn->iCursor + nLen) > (unsigned int)pIn->nUsed ){ 1074 1068 nLen = (unsigned int) (pIn->nUsed - pIn->iCursor);
Changes to src/file.c.
112 112 return getStat(zFilename, 0) ? -1 : fileStat.st_size; 113 113 } 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 125 125 ** recently stat-ed file. 126 126 */ ................................................................................ 132 132 ** Same as file_mtime(), but takes into account symlinks. 133 133 */ 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) || 145 145 S_ISLNK(fileStat.st_mode); 146 146 } ................................................................................ 189 189 } 190 190 zName[i] = '/'; 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); 205 205 } 206 206 } ................................................................................ 228 228 # define S_IXUSR _S_IEXEC 229 229 # endif 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 241 241 return PERM_REG; 242 242 #endif ................................................................................ 403 403 #else 404 404 unlink(zFilename); 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){ 416 416 int rc = file_wd_isdir(zName); 417 417 if( rc==2 ){ ................................................................................ 717 717 if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0; 718 718 } 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 730 730 if( fossil_isalpha(zIn[0]) && zIn[1]==':' ) zIn += 2; 731 731 #endif ................................................................................ 945 945 azDirs[0] = fossil_unicode_to_utf8(zTmpPath); 946 946 } 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 } 966 966 967 967 do{ ................................................................................ 1033 1033 /************************************************************************** 1034 1034 ** The following routines translate between MBCS and UTF8 on windows. 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 1056 1056 ** returned pointer when done. 1057 1057 */ ................................................................................ 1076 1076 */ 1077 1077 char *fossil_utf8_to_mbcs(const char *zUtf8){ 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 1089 1089 ** used to store the returned pointer when done. 1090 1090 */ ................................................................................ 1114 1114 #else 1115 1115 char *zValue = getenv(zName); 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. 1164 1187 */ 1165 1188 void fossil_mbcs_free(void *zOld){ 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 FILE *fossil_fopen(const char *zName, const char *zMode){ 1178 1201 #ifdef _WIN32
Changes to src/main.c.
155 155 char *urlPath; /* Pathname for http: */ 156 156 char *urlUser; /* User id for http: */ 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 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 */ 179 179 struct TclContext tcl; 180 180 #endif ................................................................................ 193 193 /* Storage for the aux() and/or option() SQL function arguments */ 194 194 int nAux; /* Number of distinct aux() or option() values */ 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 206 206 false. This changes how errors are 207 207 reported. In JSON mode we try to ................................................................................ 260 260 #define CGIDEBUG(X) if( g.fDebug ) cgi_debug X 261 261 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" 273 273 274 274 /* ................................................................................ 328 328 #endif 329 329 free(g.zErrMsg); 330 330 if(g.db){ 331 331 db_close(0); 332 332 } 333 333 } 334 334 335 +#if defined(_WIN32) 335 336 /* 336 -** Convert all arguments from mbcs to UTF-8. Then 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 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 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++; 372 494 if( z[0]=='-' ) z++; 373 495 if( z[0]==0 ) return; /* Stop searching at "--" */ ................................................................................ 388 510 } 389 511 zInFile = NULL; 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; 411 533 } 412 534 if (!foundBom) { ................................................................................ 428 550 g.argc = j; 429 551 g.argv = newArgv; 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); 441 568 memset(&g, 0, sizeof(g)); 442 569 g.now = time(0); ................................................................................ 724 851 fossil_mbcs_free(zUnicode); 725 852 free(zNewCmd); 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. 738 865 */ 739 866 void fossil_binary_mode(FILE *p){ ................................................................................ 1192 1319 ** Preconditions: 1193 1320 ** 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; 1205 1332 char *zPath = NULL; 1206 1333 int idx; ................................................................................ 1265 1392 } 1266 1393 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo); 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 } 1278 1405 } 1279 1406 ................................................................................ 1280 1407 /* Find the page that the user has requested, construct and deliver that 1281 1408 ** page. 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); 1293 1420 } 1294 1421 #endif ................................................................................ 1310 1437 1311 1438 /* Look for sub-repositories. A sub-repository is another repository 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; 1323 1450 int jj; 1324 1451 char *zUser = zAltRepo; ................................................................................ 1512 1639 } 1513 1640 } 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: 1525 1652 ** 1526 1653 ** redirect: * URL ................................................................................ 1528 1655 ** Then a redirect is made to URL if no match is found. Otherwise a 1529 1656 ** very primative error message is returned. 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)) ){ 1541 1668 for(i=0; i<nRedirect; i++){ 1542 1669 if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ ................................................................................ 1601 1728 ** 1602 1729 ** COMMAND: http* 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 1614 1741 ** not select a valid repository and the --notfound option is available, 1615 1742 ** then the server redirects (HTTP code 302) to the URL of --notfound. ................................................................................ 1740 1867 ** --th-trace trace TH1 execution (for debugging purposes) 1741 1868 ** 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 1753 1880 #if defined(_WIN32) 1754 1881 const char *zStopperFile; /* Name of file used to terminate server */ ................................................................................ 1777 1904 } 1778 1905 #if !defined(_WIN32) 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 break; 1791 1918 }
Changes to src/makemake.tcl.
471 471 endif 472 472 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 484 489 # OpenSSL: Add the necessary libraries required, if enabled.
Changes to src/printf.c.
241 241 if( (c=(*++fmt))==0 ){ 242 242 errorflag = 1; 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; 254 254 case '+': flag_plussign = 1; break; 255 255 case ' ': flag_blanksign = 1; break; ................................................................................ 812 812 ** 813 813 ** On windows, transform the output into the current terminal encoding 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; 819 + if( fossil_utf8_to_console(z, strlen(z), toStdErr) >= 0 ){ 820 + return; 826 821 } 822 +#endif 827 823 assert( toStdErr==0 || toStdErr==1 ); 828 - if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); 829 824 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 825 fflush(toStdErr ? stderr : stdout); 835 826 } 836 827 837 828 /* 838 829 ** Write output for user consumption. If g.cgiOutput is enabled, then 839 830 ** send the output as part of the CGI reply. If g.cgiOutput is false, 840 831 ** then write on standard output. ................................................................................ 861 852 if( zA==0 ){ 862 853 if( zB==0 ) return 0; 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 } 874 865 } 875 866 int fossil_strncmp(const char *zA, const char *zB, int nByte){ ................................................................................ 876 867 if( zA==0 ){ 877 868 if( zB==0 ) return 0; 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 return 0; 890 881 }
Changes to src/winhttp.c.
107 107 break; 108 108 } 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 ){ 120 120 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ 121 121 send(p->s, zHdr, got, 0); ................................................................................ 127 127 if( in ) fclose(in); 128 128 closesocket(p->s); 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( 139 144 int mnPort, int mxPort, /* Range of allowed TCP port numbers */ 140 145 const char *zBrowser, /* Command to launch browser. (Or NULL) */ ................................................................................ 144 149 ){ 145 150 WSADATA wd; 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); 157 162 } 158 163 if( g.useLocalauth ){ ................................................................................ 192 197 fossil_fatal("unable to open listening socket on any" 193 198 " port in the range %d..%d", mnPort, mxPort); 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); 205 210 } 206 211 fossil_print("Type Ctrl-C to stop the HTTP server\n"); ................................................................................ 212 217 SOCKADDR_IN client_addr; 213 218 HttpRequest *p; 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; 225 230 }else{ 226 231 closesocket(s); ................................................................................ 247 252 */ 248 253 typedef struct HttpService HttpService; 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. 260 265 */ 261 266 static HttpService hsData = {8080, NULL, 0, 0, NULL, INVALID_SOCKET}; ................................................................................ 296 301 0, 297 302 (LPTSTR) &tmp, 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); 309 314 } 310 315 return zMsg; ................................................................................ 324 329 }else{ 325 330 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; 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 } 337 342 SetServiceStatus(sshStatusHandle, &ssStatus); 338 343 return ; ................................................................................ 382 387 /* Update the service information. */ 383 388 hsData.isRunningAsService = 1; 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 395 400 /* Set service specific data and report that the service is starting. */ 396 401 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ................................................................................ 427 432 int win32_http_service( 428 433 int nPort, /* TCP port number */ 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 441 446 /* Try to start the control dispatcher thread for the service. */ 442 447 if( !StartServiceCtrlDispatcher(ServiceTable) ){ ................................................................................ 445 450 }else{ 446 451 fossil_fatal("error from StartServiceCtrlDispatcher()"); 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 ** 458 464 ** The winsrv command manages Fossil as a Windows service. This allows 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 470 476 ** 471 477 ** Sets the display name of the service. This name is shown ................................................................................ 563 569 zMethod = g.argv[2]; 564 570 n = strlen(zMethod); 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); 576 582 const char *zPassword = find_option("password", "W", 1); 577 583 const char *zPort = find_option("port", "P", 1); ................................................................................ 622 628 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1); 623 629 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName); 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); 646 652 CloseServiceHandle(hSvc); 647 653 CloseServiceHandle(hScm); ................................................................................ 656 662 if( g.argc==4 ){ 657 663 zSvcName = g.argv[3]; 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 ){ 669 675 if( !ControlService(hSvc, SERVICE_CONTROL_STOP, &sstat) ){ 670 676 fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); ................................................................................ 693 699 SC_HANDLE hScm; 694 700 SC_HANDLE hSvc; 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 723 729 verify_all_options(); 724 730 if( g.argc==4 ){ 725 731 zSvcName = g.argv[3]; 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()); 737 743 } 738 744 pSvcConfig = fossil_malloc(nRequired); ................................................................................ 776 782 case SERVICE_CONTINUE_PENDING: zSvcState = zSvcStates[4]; break; 777 783 case SERVICE_PAUSE_PENDING: zSvcState = zSvcStates[5]; break; 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); 797 803 CloseServiceHandle(hScm); 798 804 }else ................................................................................ 806 812 if( g.argc==4 ){ 807 813 zSvcName = g.argv[3]; 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 ){ 819 825 if( !StartService(hSvc, 0, NULL) ){ 820 826 fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); ................................................................................ 842 848 if( g.argc==4 ){ 843 849 zSvcName = g.argv[3]; 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 ){ 855 861 if( !ControlService(hSvc, SERVICE_CONTROL_STOP, &sstat) ){ 856 862 fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg()); ................................................................................ 870 876 }else 871 877 { 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 */
Added test/cmdline.test.
1 +# 2 +# Copyright (c) 2011 D. Richard Hipp 3 +# 4 +# This program is free software; you can redistribute it and/or 5 +# modify it under the terms of the Simplified BSD License (also 6 +# known as the "2-Clause License" or "FreeBSD License".) 7 +# 8 +# This program is distributed in the hope that it will be useful, 9 +# but without any warranty; without even the implied warranty of 10 +# merchantability or fitness for a particular purpose. 11 +# 12 +# Author contact information: 13 +# drh@hwaci.com 14 +# http://www.hwaci.com/drh/ 15 +# 16 +############################################################################ 17 +# 18 +# Test command line parsing 19 +# 20 + 21 +proc cmd-line {testname args} { 22 + set i 1 23 + foreach {cmdline result} $args { 24 + fossil test-echo {*}$cmdline 25 + test cmd-line-$testname.$i {[lrange [split $::RESULT \n] 2 end]=="\{argv\[2\] = \[$result\]\}"} 26 + incr i 27 + } 28 +} 29 +cmd-line 100 abc abc {"abc"} abc 30 +cmd-line 101 * {*} *.* {*.*}
Changes to win/Makefile.mingw.
143 143 endif 144 144 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 156 161 # OpenSSL: Add the necessary libraries required, if enabled.
Changes to win/Makefile.msc.
30 30 #ZLIB = zdll.lib 31 31 ZINCDIR = $(MSCDIR)\extra\include 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 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT3 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 44 44