Check-in [3c5482959c]
Not logged in
Overview

SHA1 Hash:3c5482959c058d62b032ad5819a738dd418a73cf
Date: 2007-09-22 19:43:55
User: drh
Comment:Merge in the w32 changes.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Added Makefile.w32 version [7035415b04]

@@ -1,1 +1,48 @@
+#!/usr/bin/make
+#
+#### The toplevel directory of the source tree.  Fossil can be built
+#    in a directory that is separate from the source tree.  Just change
+#    the following to point from the build directory to the src/ folder.
+#
+SRCDIR = ./src
+
+#### C Compiler and options for use in building executables that
+#    will run on the platform that is doing the build.  This is used
+#    to compile code-generator programs as part of the build process.
+#    See TCC below for the C compiler for building the finished binary.
+#
+BCC = gcc -g -O2
+
+#### The suffix to add to executable files.  ".exe" for windows.
+#    Nothing for unix.
+#
+E =
+
+#### C Compile and options for use in building executables that
+#    will run on the target platform.  This is usually the same
+#    as BCC, unless you are cross-compiling.  This C compiler builds
+#    the finished binary for fossil.  The BCC compiler above is used
+#    for building intermediate code-generator tools.
+#
+#TCC = gcc -O6
+#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
+#TCC = gcc -g -Os -Wall
+TCC = gcc -g -Os -Wall -DFOSSIL_I18N=0
+
+#### Extra arguments for linking the finished binary.  Fossil needs
+#    to link against the Z-Lib compression library.  There are no
+#    other dependencies.  We sometimes add the -static option here
+#    so that we can build a static executable that will run in a
+#    chroot jail.
+#
+#LIB = -lz
+LIB = -lz -lws2_32
+
+
+#### Tcl shell for use in running the fossil testsuite.
+#
+TCLSH = tclsh
 
+# You should not need to change anything below this line
+###############################################################################
+include $(SRCDIR)/main.mk

Modified src/add.c from [771768ca0d] to [7e200015f8].

@@ -50,11 +50,11 @@
     char *zName;
     char *zPath;
     Blob pathname;
     int isDir;
 
-    zName = mprintf("%s", g.argv[i]);
+    zName = mprintf("%/", g.argv[i]);
     isDir = file_isdir(zName);
     if( isDir==1 ) continue;
     if( isDir==0 ){
       fossil_fatal("not found: %s", zName);
     }
@@ -100,11 +100,11 @@
   for(i=2; i<g.argc; i++){
     char *zName;
     char *zPath;
     Blob pathname;
 
-    zName = mprintf("%s", g.argv[i]);
+    zName = mprintf("%/", g.argv[i]);
     file_tree_name(zName, &pathname);
     zPath = blob_str(&pathname);
     if( !db_exists(
              "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
       fossil_fatal("not in the repository: %s", zName);

Modified src/blob.c from [f2c016552c] to [70f1a3c914].

@@ -571,13 +571,24 @@
     }
     nName = file_simplify_name(zName, nName);
     for(i=1; i<nName; i++){
       if( zName[i]=='/' ){
         zName[i] = 0;
-        if( file_mkdir(zName, 1) ){
-          fossil_panic("unable to create directory %s", zName);
+#ifdef __MINGW32__
+        /*
+        ** On Windows, local path looks like: C:/develop/project/file.txt
+        ** The if stops us from trying to create a directory of a drive letter
+        ** C: in this example.
+        */
+        if( !(i==2 && zName[1]==':') ){
+#endif
+          if( file_mkdir(zName, 1) ){
+            fossil_panic("unable to create directory %s", zName);
+          }
+#ifdef __MINGW32__
         }
+#endif
         zName[i] = '/';
       }
     }
     out = fopen(zName, "wb");
     if( out==0 ){

Modified src/cgi.c from [f25a72aeb6] to [57f4d7daa3].

@@ -26,20 +26,26 @@
 ** dispensing QUERY_STRING parameters and cookies, the "mprintf()"
 ** formatting function and its cousins, and routines to encode and
 ** decode strings in HTML or HTTP.
 */
 #include "config.h"
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <time.h>
-#include <sys/times.h>
-#include <sys/time.h>
-#include <sys/wait.h>
+#ifdef __MINGW32__
+#  include <windows.h>           /* for Sleep once server works again */
+#  include <winsock2.h>          /* socket operations */
+#  define sleep Sleep            /* windows does not have sleep, but Sleep */
+#else
+#  include <sys/socket.h>
+#  include <netinet/in.h>
+#  include <arpa/inet.h>
+#  include <sys/times.h>
+#  include <sys/time.h>
+#  include <sys/wait.h>
+#  include <sys/select.h>
+#endif
+#include <time.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/select.h>
 #include <unistd.h>
 #include "cgi.h"
 
 #if INTERFACE
 /*
@@ -1076,10 +1082,14 @@
 ** As new connections arrive, fork a child and let child return
 ** out of this procedure call.  The child will handle the request.
 ** The parent never returns from this procedure.
 */
 void cgi_http_server(int iPort){
+#ifdef __MINGW32__
+  fprintf(stderr,"server not yet available in windows version of fossil\n");
+  exit(1);
+#else
   int listener;                /* The server socket */
   int connection;              /* A socket for each individual connection */
   fd_set readfds;              /* Set of file descriptors for select() */
   size_t lenaddr;              /* Length of the inaddr structure */
   int child;                   /* PID of the child process */
@@ -1142,10 +1152,11 @@
       nchildren--;
     }
   }
   /* NOT REACHED */
   exit(1);
+#endif
 }
 
 /*
 ** Name of days and months.
 */

Modified src/checkin.c from [08fa2df4cf] to [39235e7847].

@@ -162,18 +162,24 @@
   db_finalize(&q);
 }
 
 /*
 ** COMMAND: clean
-** Usage: %fossil clean
+** Usage: %fossil clean ?-all
 ** Delete all "extra" files in the source tree.  "Extra" files are
 ** files that are not officially part of the checkout.  See also
-** the "extra" command.
+** the "extra" command. This operation cannot be undone.
+**
+** You will be prompted before removing each file. If you are
+** sure you wish to remove all "extra" files you can specify the
+** optional -all flag.
 */
 void clean_cmd(void){
+  int allFlag;
   Blob path;
   Stmt q;
+  allFlag = find_option("all","a",0)!=0;
   db_must_be_within_tree();
   db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
   chdir(g.zLocalRoot);
   blob_zero(&path);
   vfile_scan(0, &path);
@@ -180,11 +186,23 @@
   db_prepare(&q,
       "SELECT %Q || x FROM sfile"
       " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
       " ORDER BY 1", g.zLocalRoot);
   while( db_step(&q)==SQLITE_ROW ){
-    unlink(db_column_text(&q, 0));
+    if( allFlag ){
+      unlink(db_column_text(&q, 0));
+      continue;
+    }
+
+    Blob ans;
+    char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ",
+      db_column_text(&q, 0));
+    blob_zero(&ans);
+    prompt_user(prompt, &ans);
+    if( blob_str(&ans)[0]=='y' ){
+      unlink(db_column_text(&q, 0));
+    }
   }
   db_finalize(&q);
 }
 
 /*
@@ -218,11 +236,11 @@
     zEditor = "ed";
   }
   zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
                    g.zLocalRoot);
   blob_write_to_file(&text, zFile);
-  zCmd = mprintf("%s %s", zEditor, zFile);
+  zCmd = mprintf("%s \"%s\"", zEditor, zFile);
   printf("%s\n", zCmd);
   if( system(zCmd) ){
     fossil_panic("editor aborted");
   }
   blob_reset(&text);

Modified src/db.c from [16bbdf5494] to [b9655281e8].

@@ -33,14 +33,16 @@
 **    (3)  A local checkout database named "FOSSIL" and located at the
 **         root of the local copy of the source tree.
 **
 */
 #include "config.h"
+#ifndef __MINGW32__
+#  include <pwd.h>
+#endif
 #include <sqlite3.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <pwd.h>
 #include <unistd.h>
 #include "db.h"
 
 #if INTERFACE
 /*
@@ -488,15 +490,31 @@
 ** Open the user database in "~/.fossil".  Create the database anew if
 ** it does not already exist.
 */
 void db_open_config(void){
   char *zDbName;
-  const char *zHome = getenv("HOME");
+  const char *zHome;
+#ifdef __MINGW32__
+  zHome = getenv("LOCALAPPDATA");
+  if( zHome==0 ){
+    zHome = getenv("APPDATA");
+    if( zHome==0 ){
+      zHome = getenv("HOMEPATH");
+    }
+  }
+#else
+  zHome = getenv("HOME");
+#endif
   if( zHome==0 ){
     db_err("cannot local home directory");
   }
+#ifdef __MINGW32__
+  /* . filenames give some window systems problems and many apps problems */
+  zDbName = mprintf("%s/_fossil", zHome);
+#else
   zDbName = mprintf("%s/.fossil", zHome);
+#endif
   if( g.configOpen ) return;
   if( file_size(zDbName)<1024*3 ){
     db_init_database(zDbName, zConfigSchema, (char*)0);
   }
   db_open_or_attach(zDbName, "configdb");
@@ -534,15 +552,19 @@
 ** it is attached to the open database connection too.
 */
 int db_open_local(void){
   int n;
   char zPwd[2000];
+  char *zPwdConv;
   if( g.localOpen) return 1;
   if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
     db_err("pwd too big: max %d", sizeof(zPwd)-20);
   }
   n = strlen(zPwd);
+  zPwdConv = mprintf("%/", zPwd);
+  strncpy(zPwd, zPwdConv, 2000-20);
+  free(zPwdConv);
   while( n>0 ){
     if( access(zPwd, W_OK) ) break;
     strcpy(&zPwd[n], "/_FOSSIL_");
     if( isValidLocalDb(zPwd) ){
       /* Found a valid _FOSSIL_ file */

Modified src/file.c from [43aa6bdf65] to [0453cec099].

@@ -105,11 +105,15 @@
   if( rc==2 ){
     if( !forceFlag ) return 1;
     unlink(zName);
   }
   if( rc!=1 ){
+#ifdef __MINGW32__
+    return mkdir(zName);
+#else
     return mkdir(zName, 0755);
+#endif
   }
   return 0;
 }
 
 /*
@@ -188,11 +192,11 @@
     if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
       fprintf(stderr, "pwd too big: max %d\n", sizeof(zPwd)-20);
       exit(1);
     }
     blob_zero(pOut);
-    blob_appendf(pOut, "%s/%s", zPwd, zOrigName);
+    blob_appendf(pOut, "%//%/", zPwd, zOrigName);
   }
   blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut)));
 }
 
 /*

Modified src/http.c from [43986095c4] to [54410d4f2b].

@@ -23,22 +23,55 @@
 **
 ** This file contains code that implements the client-side HTTP protocol
 */
 #include "config.h"
 #include "http.h"
+#ifdef __MINGW32__
+#  include <windows.h>
+#  include <winsock2.h>
+#else
+#  include <arpa/inet.h>
+#  include <sys/socket.h>
+#  include <netdb.h>
+#  include <netinet/in.h>
+#endif
 #include <assert.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
+#include <sys/types.h>
 #include <signal.h>
 
 /*
 ** Persistent information about the HTTP connection.
 */
-static FILE *pSocket = 0;   /* The socket on which we talk to the server */
+
+#ifdef __MINGW32__
+static WSADATA ws_info;
+static int pSocket = 0;     /* The socket on which we talk to the server on */
+#else
+static FILE *pSocket = 0;   /* The socket filehandle on which we talk to the server */
+#endif
+
+/*
+** Winsock must be initialize before use.  This helper method allows us to
+** always call ws_init in our code regardless of platform but only actually
+** initialize winsock on the windows platform.
+*/
+static void ws_init(){
+#ifdef __MINGW32__
+  if (WSAStartup(MAKEWORD(2,0), &ws_info) != 0){
+    fossil_panic("can't initialize winsock");
+  }
+#endif
+}
+
+/*
+** Like ws_init, winsock must also be cleaned up after.
+*/
+static void ws_cleanup(){
+#ifdef __MINGW32__
+  WSACleanup();
+#endif
+}
 
 /*
 ** Open a socket connection to the server.  Return 0 on success and
 ** non-zero if an error occurs.
 */
@@ -45,11 +78,14 @@
 static int http_open_socket(void){
   static struct sockaddr_in addr;  /* The server address */
   static int addrIsInit = 0;       /* True once addr is initialized */
   int s;
 
+  ws_init();
+
   if( !addrIsInit ){
+
     addr.sin_family = AF_INET;
     addr.sin_port = htons(g.urlPort);
     *(int*)&addr.sin_addr = inet_addr(g.urlName);
     if( -1 == *(int*)&addr.sin_addr ){
 #ifndef FOSSIL_STATIC_LINK
@@ -76,13 +112,64 @@
     fossil_panic("cannot create a socket");
   }
   if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){
     fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort);
   }
+#ifdef __MINGW32__
+  pSocket = s;
+#else
   pSocket = fdopen(s,"r+");
   signal(SIGPIPE, SIG_IGN);
+#endif
   return 0;
+}
+
+/*
+** Read the socket until a newline '\n' is found.  Return the number
+** of characters read. pSockId contains the socket handel.  pOut
+** contains a pointer to the buffer to write to.  pOutSize contains
+** the maximum size of the line that pOut can handle.
+*/
+static int socket_recv_line(int pSockId, char* pOut, int pOutSize){
+  int received=0;
+  char letter;
+  memset(pOut,0,pOutSize);
+  for(; received<pOutSize-1;received++){
+    if( recv(pSockId,(char*)&letter,1,0)>0 ){
+      pOut[received]=letter;
+      if( letter=='\n' ){
+        break;
+      }
+    }else{
+      break;
+    }
+  }
+  return received;
+}
+
+/*
+** Initialize a blob to the data on an input socket.  return
+** the number of bytes read into the blob.  Any prior content
+** of the blob is discarded, not freed.
+**
+** The function was placed here in http.c due to it's socket
+** nature and we did not want to introduce socket headers into
+** the socket netural blob.c file.
+*/
+int socket_read_blob(Blob *pBlob, int pSockId, int nToRead){
+  int i=0,read=0;
+  char rbuf[50];
+  blob_zero(pBlob);
+  while ( i<nToRead ){
+    read = recv(pSockId, rbuf, 50, 0);
+    i += read;
+    if( read<0 ){
+      return 0;
+    }
+    blob_append(pBlob, rbuf, read);
+  }
+  return blob_size(pBlob);
 }
 
 /*
 ** Make a single attempt to talk to the server.  Return TRUE on success
 ** and FALSE on a failure.
@@ -93,40 +180,78 @@
 **
 ** If an error occurs, this routine return false, resets pReply and
 ** closes the persistent connection, if any.
 */
 static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){
-  int rc;
-  int closeConnection;
+  int closeConnection=1;   /* default to closing the connection */
+  int rc;
   int iLength;
   int iHttpVersion;
   int i;
   int nRead;
   char zLine[2000];
 
   if( pSocket==0 && http_open_socket() ){
     return 0;
   }
+  iLength = -1;
+#ifdef __MINGW32__
+  /*
+  ** Use recv/send on the windows platform as winsock does not allow
+  ** sockets to be used as FILE handles, thus fdopen, fwrite, fgets
+  ** does not function on windows for sockets.
+  */
+  rc = send(pSocket, blob_buffer(pHeader), blob_size(pHeader), 0);
+  if( rc!=blob_size(pHeader) ) goto write_err;
+  rc = send(pSocket, blob_buffer(pPayload), blob_size(pPayload), 0);
+  if( rc!=blob_size(pPayload) ) goto write_err;
+
+  /* Read the response */
+  while( socket_recv_line(pSocket, zLine, 2000) ){
+    for( i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++ ){}
+    if( i==0 ) break;
+    zLine[i] = 0;
+    if( strncasecmp(zLine, "http/1.", 7)==0 ){
+      if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
+      if( rc!=200 ) goto write_err;
+      if( iHttpVersion==0 ){
+        closeConnection = 1;
+      }else{
+        closeConnection = 0;
+      }
+    } else if( strncasecmp(zLine, "content-length:", 15)==0 ){
+      iLength = atoi(&zLine[16]);
+    }else if( strncasecmp(zLine, "connection:", 11)==0 ){
+      for(i=12; isspace(zLine[i]); i++){}
+      if( zLine[i]=='c' || zLine[i]=='C' ){
+        closeConnection = 1;
+      }else if( zLine[i]=='k' || zLine[i]=='K' ){
+        closeConnection = 0;
+      }
+    }
+  }
+  if( iLength<0 ) goto write_err;
+  nRead = socket_read_blob(pReply, pSocket, iLength);
+#else
   rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket);
   if( rc!=blob_size(pHeader) ) goto write_err;
   rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket);
   if( rc!=blob_size(pPayload) ) goto write_err;
   if( fflush(pSocket) ) goto write_err;
   if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err;
   if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
   if( rc!=200 ) goto write_err;
   if( iHttpVersion==0 ){
-    closeConnection = 1;
+    closeConnection = 1;   /* Connection: close */
   }else{
-    closeConnection = 0;
-  }
-  iLength = -1;
+    closeConnection = 0;   /* Connection: keep-alive */
+  }
   while( fgets(zLine, sizeof(zLine), pSocket) ){
     for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
     if( i==0 ) break;
     zLine[i] = 0;
-    if( strncasecmp(zLine, "content-length:",15)==0 ){
+    if( strncasecmp(zLine,"content-length:",15)==0 ){
       iLength = atoi(&zLine[16]);
     }else if( strncasecmp(zLine, "connection:", 11)==0 ){
       for(i=12; isspace(zLine[i]); i++){}
       if( zLine[i]=='c' || zLine[i]=='C' ){
         closeConnection = 1;   /* Connection: close */
@@ -135,10 +260,11 @@
       }
     }
   }
   if( iLength<0 ) goto write_err;
   nRead = blob_read_from_channel(pReply, pSocket, iLength);
+#endif
   if( nRead!=iLength ){
     blob_reset(pReply);
     goto write_err;
   }
   if( closeConnection ){
@@ -260,9 +386,21 @@
 /*
 ** Make sure the socket to the HTTP server is closed
 */
 void http_close(void){
   if( pSocket ){
+#ifdef __MINGW32__
+    closesocket(pSocket);
+#else
     fclose(pSocket);
+#endif
     pSocket = 0;
   }
+  /*
+  ** This is counter productive. Each time we open a connection we initialize
+  ** winsock and then when closing we cleanup. It would be better to
+  ** initialize winsock once at application start when we know we are going to
+  ** use the socket interface and then cleanup once at application exit when
+  ** we are all done with all socket operations.
+  */
+  ws_cleanup();
 }

Modified src/login.c from [4e89d2580b] to [d1ac22275c].

@@ -44,10 +44,14 @@
 ** logs and downloading diffs of very version of the archive that
 ** has ever existed, and things like that.
 */
 #include "config.h"
 #include "login.h"
+#ifdef __MINGW32__
+#  include <windows.h>           /* for Sleep */
+#  define sleep Sleep            /* windows does not have sleep, but Sleep */
+#endif
 #include <time.h>
 
 /*
 ** Return the name of the login cookie
 */

Modified src/printf.c from [48f1118d8e] to [63619c9ec6].

@@ -49,10 +49,11 @@
 #define etPOINTER    15 /* The %p conversion */
 #define etHTMLIZE    16 /* Make text safe for HTML */
 #define etHTTPIZE    17 /* Make text safe for HTTP.  "/" encoded as %2f */
 #define etURLIZE     18 /* Make text safe for HTTP.  "/" not encoded */
 #define etFOSSILIZE  19 /* The fossil header encoding format. */
+#define etPATH       20 /* Path type */
 
 
 /*
 ** An "etByte" is an 8-bit unsigned value.
 */
@@ -109,10 +110,11 @@
   {  'G',  0, 1, etGENERIC,    14, 0 },
   {  'i', 10, 1, etRADIX,      0,  0 },
   {  'n',  0, 0, etSIZE,       0,  0 },
   {  '%',  0, 0, etPERCENT,    0,  0 },
   {  'p', 16, 0, etPOINTER,    0,  1 },
+  {  '/',  0, 0, etPATH,       0,  0 },
 };
 #define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
 
 /*
 ** "*val" is a double such that 0.1 <= *val < 10.0
@@ -541,10 +543,26 @@
         }else{
           length =1;
         }
         bufpt = buf;
         break;
+      case etPATH: {
+        int i;
+        char *e = va_arg(ap,char*);
+        if( e==0 ){e="";}
+        length = strlen(e);
+        zExtra = bufpt = malloc(length+1);
+        for( i=0; i<length; i++ ){
+          if( e[i]=='\\' ){
+            bufpt[i]='/';
+          }else{
+            bufpt[i]=e[i];
+          }
+        }
+        bufpt[length]='\0';
+        break;
+      }
       case etSTRING:
       case etDYNSTRING:
         bufpt = va_arg(ap,char*);
         if( bufpt==0 ){
           bufpt = "";

Modified src/user.c from [7f6b214713] to [2a5d91addf].

@@ -44,10 +44,50 @@
     }
     if( z[i]<' ' ) z[i] = ' ';
   }
   blob_append(pBlob, z, -1);
 }
+
+#ifdef __MINGW32__
+/*
+** getpass for Windows
+*/
+static char *getpass(const char *prompt){
+  static char pwd[64];
+  size_t i;
+
+  fputs(prompt,stderr);
+  fflush(stderr);
+  for(i=0; i<sizeof(pwd)-1; ++i){
+    pwd[i] = _getch();
+    if(pwd[i]=='\r' || pwd[i]=='\n'){
+      break;
+    }
+    /* BS or DEL */
+    else if(i>0 && (pwd[i]==8 || pwd[i]==127)){
+      i -= 2;
+      continue;
+    }
+    /* CTRL-C */
+    else if(pwd[i]==3) {
+      i=0;
+      break;
+    }
+    /* ESC */
+    else if(pwd[i]==27){
+      i=0;
+      break;
+    }
+    else{
+      fputc('*',stderr);
+    }
+  }
+  pwd[i]='\0';
+  fputs("\n", stderr);
+  return pwd;
+}
+#endif
 
 /*
 ** Do a single prompt for a passphrase.  Store the results in the blob.
 */
 static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){

Added win32.txt version [f8b38cdb44]

@@ -1,1 +1,84 @@
+Notes: Porting fossil to win32
+======================================================================
+
+Setting up my build environment:
+----------------------------------------------------------------------
+
+  Install:
+    MinGW 5.1.3
+    MSYS  1.0.10
+
+  Download/compile/install zlib (configure --prefix=/mingw)
+  Download/compile/install tclsh (configure --prefix=/) (for tests)
+
+  All commands were issued in the MSYS shell, not a cmd.exe
+
+Outstanding Issues:
+----------------------------------------------------------------------
+
+* server is totally non-functional - #if/#end'd out of the code
+
+Commands status:
+----------------------------------------------------------------------
+
+add               OK
+cgi               Not tested
+changes           OK
+checkout          BAD #1
+clean             OK
+clone             OK
+close             OK
+commit            OK
+config            OK
+deconstruct       OK
+del               OK
+descendents       OK
+diff              OK
+extra             OK
+help              OK
+http              Not Tested
+info              OK
+leaves            OK
+ls                OK
+merge             OK
+new               OK
+open              OK
+pull              OK
+push              OK
+rebuild           OK (didn't have a corrupt file to try on though)
+redo              BAD #3
+rm                OK
+server            BAD #4
+status            OK
+sync              OK
+timeline          OK
+tkdiff            OK
+undo              OK
+update            OK
+user capabilities OK
+user default      OK
+user list         OK
+user new          OK
+user password     OK
+
+#1 Have a repo where I removed a file. I did a fossil checkout 123abc,
+   which is the last version that had the file. The file does not
+   appear. fossil checkout --force 123abc does things, but still the
+   file does not appear.
+
+   Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and
+   the file appears.
+
+   Is that normal operation?
+
+#3 In test1/ I edited a file, test2/ I updated, type file.txt changes
+   were there. I then did fossil undo file.txt. The changes were gone
+   and fossil status said I had edited file.txt. A fossil redo did not
+   print anything to the screen and the changes for file.txt are not
+   in the file. fossil status still reports that the file was edited.
+   There was no commit/update or any other command inbetween these
+   actions.
 
+#4 There were various difficulties in this function beyond simple socket
+   problems. The major one being fork. This will probably be the last
+   command to be functional in fossil on windows.