Changes On Branch unicode-cmdline
Not logged in

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