Added support for ERRORLEVEL.
Most errors reported via FormatMessage().
COPY command now works correctly if output specifier is a directory.

diff --git a/programs/wcmd/ChangeLog b/programs/wcmd/ChangeLog
index eccc8c2..4fc945b 100644
--- a/programs/wcmd/ChangeLog
+++ b/programs/wcmd/ChangeLog
@@ -1,3 +1,20 @@
+v0.14 - 1 August 2000
+Errorlevel support added
+Most errors reported via FormatMessage()
+COPY command now works correctly if output specifier is a directory.
+
+v0.13 - 30 July 2000
+By Jason Edmeades (jason@the-edmeades.fsnet.co.uk)
+-Enhanced 'if' support
+-Use of PATHEXT env var (NT) - eg. run file with non-normal extension
+  if allowed through pathext
+-Better searching of path for these files
+-Support of .cmd as extension for batch (NT allows this)
+-Support for %* as a batch option
+-Lookup in registry for filetype to see how it should be launched 
+  (HKEY_CLASSES_ROOT, then its name, getting shell->open->command and
+  launching the appropriate program).
+
 v0.12 - 4 July 1999
 FOR and IF commands added.
 MOVE command added, but no wildcard support.
diff --git a/programs/wcmd/README b/programs/wcmd/README
index 9496ba1..995c10b 100644
--- a/programs/wcmd/README
+++ b/programs/wcmd/README
@@ -22,18 +22,18 @@
 always clear. The Wine attributes API calls map to the Unix stat() function
 which cannot handle the other attributes available in DOS.
 - Date/timestamps of files in the DIR listing are shown using the current
-locale. As there is AFAIK no way to set the locale, they will always appear in
-US format.
+locale, which is set using the Unix LANG environment variable. By default the
+US date-time format is used. Set eg "LANG=en_GB" for DD/MM/YY dates and 24-hour
+times.
 - Line editing and command recall doesn't work due to missing functionality in
 Wine.
 - File sizes in the DIR function are all given in 32 bits, though totals and
 free space are computed to 64 bits.
-- DIR/S fails if there is no matching file in the starting directory, ie
-"DIR C:\TEMP\*.c /S" doesn't work if there is no file matching *.c in C:\TEMP
-but one does exist in a lower directory.
+- DIR/S only works if no file specification is given, ie "DIR C:\TEMP /S" works
+but "DIR C:\TEMP\*.C" doesn't work if a matching file exists in a lower
+directory.
 - Copy, rename, move, need the source and destination to be specified fully
 with an absolute or relative path but no wildcards or partial filenames.
-- The IF ERRORLEVEL construct is not implemented.
 - Redirection is implemented as a command line is parsed. This means that ">"
 and "<" symbols cannot appear in command arguments even within quotes.
 - In many cases parsing and syntax checking is less rigorous than DOS. Thus an
diff --git a/programs/wcmd/batch.c b/programs/wcmd/batch.c
index 6bb9c22..acfbc1e 100644
--- a/programs/wcmd/batch.c
+++ b/programs/wcmd/batch.c
@@ -16,7 +16,7 @@
 extern int echo_mode;
 extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
 extern BATCH_CONTEXT *context;
-
+extern DWORD errorlevel;
 
 
 /****************************************************************************
@@ -43,7 +43,8 @@
   if (strstr (string, ".bat") == NULL) strcat (string, ".bat");
   h = CreateFile (string, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
   if (h == INVALID_HANDLE_VALUE) {
-    WCMD_output ("File %s not found\n", string);
+    SetLastError (ERROR_FILE_NOT_FOUND);
+    WCMD_print_error ();
     return;
   }
 
@@ -223,7 +224,7 @@
   }
 }
 
-/**************************************************************************** 
+/****************************************************************************
  * WCMD_fgets
  *
  * Get one line from a batch file. We can't use the native f* functions because
@@ -244,7 +245,7 @@
     if (*s == '\n') bytes = 0;
     else if (*s != '\r') {
       s++;
-    n--;
+      n--;
     }
     *s = '\0';
   } while ((bytes == 1) && (n > 1));
diff --git a/programs/wcmd/builtins.c b/programs/wcmd/builtins.c
index cdc18a6..1ccac73 100644
--- a/programs/wcmd/builtins.c
+++ b/programs/wcmd/builtins.c
@@ -29,6 +29,7 @@
 extern int echo_mode, verify_mode;
 extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
 extern BATCH_CONTEXT *context;
+extern DWORD errorlevel;
 
 
 
@@ -61,7 +62,6 @@
  *
  * Copy a file or wildcarded set.
  * FIXME: No wildcard support
- * FIXME: Needs output file to be fully specified (can't just enter directory)
  */
 
 void WCMD_copy () {
@@ -71,13 +71,22 @@
 HANDLE hff;
 BOOL force, status;
 static char *overwrite = "Overwrite file (Y/N)?";
-char string[8], outpath[MAX_PATH];
+char string[8], outpath[MAX_PATH], inpath[MAX_PATH], *infile;
 
   if ((strchr(param1,'*') != NULL) && (strchr(param1,'%') != NULL)) {
     WCMD_output ("Wildcards not yet supported\n");
     return;
   }
   GetFullPathName (param2, sizeof(outpath), outpath, NULL);
+  hff = FindFirstFile (outpath, &fd);
+  if (hff != INVALID_HANDLE_VALUE) {
+    if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      GetFullPathName (param1, sizeof(inpath), inpath, &infile);
+      strcat (outpath, "\\");
+      strcat (outpath, infile);
+    }
+    FindClose (hff);
+  }
   force = (strstr (quals, "/Y") != NULL);
   if (!force) {
     hff = FindFirstFile (outpath, &fd);
@@ -236,7 +245,9 @@
   }
 }
 
-/*
+/*****************************************************************************
+ * WCMD_Execute
+ *
  *	Execute a command after substituting variable text for the supplied parameter
  */
 
@@ -283,10 +294,10 @@
   else {
     for (i=0; i<=WCMD_EXIT; i++) {
       if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
-      	  param1, -1, inbuilt[i], -1) == 2) {
-        LoadString (0, i, buffer, sizeof(buffer));
-        WCMD_output (buffer);
-        return;
+	  param1, -1, inbuilt[i], -1) == 2) {
+	LoadString (hinst, i, buffer, sizeof(buffer));
+	WCMD_output (buffer);
+	return;
       }
     }
     WCMD_output ("No help available for %s\n", param1);
@@ -322,7 +333,6 @@
  * WCMD_if
  *
  * Batch file conditional.
- * FIXME: The "errorlevel" version is not supported.
  * FIXME: Much more syntax checking needed!
  */
 
@@ -340,7 +350,7 @@
     lstrcpy (condition, param1);
   }
   if (!lstrcmpi (condition, "errorlevel")) {
-    WCMD_output (nyi);
+    if (errorlevel >= atoi(WCMD_parameter (p, 1+negate, NULL))) test = 1;
     return;
   }
   else if (!lstrcmpi (condition, "exist")) {
@@ -421,17 +431,11 @@
 void WCMD_rename () {
 
 int status;
-static char *dirmsg = "Input file is a directory. Use the MOVE command\n\n";
 
   if ((strchr(param1,'*') != NULL) || (strchr(param1,'%') != NULL)) {
     WCMD_output ("Wildcards not yet supported\n");
     return;
   }
-  status = GetFileAttributes (param1);
-  if ((status != -1) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
-    WCMD_output (dirmsg);
-    return;
-  }
   status = MoveFile (param1, param2);
   if (!status) WCMD_print_error ();
 }
diff --git a/programs/wcmd/directory.c b/programs/wcmd/directory.c
index 6d264ee..2799e1d 100644
--- a/programs/wcmd/directory.c
+++ b/programs/wcmd/directory.c
@@ -29,6 +29,7 @@
 extern char anykey[];
 extern int echo_mode;
 extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
+extern DWORD errorlevel;
 
 int file_total, dir_total, line_count, page_mode, recurse;
 __int64 byte_total;
@@ -52,7 +53,11 @@
   page_mode = (strstr(quals, "/P") != NULL);
   recurse = (strstr(quals, "/S") != NULL);
   if (param1[0] == '\0') strcpy (param1, ".");
-  GetFullPathName (param1, sizeof(path), path, NULL);
+  status = GetFullPathName (param1, sizeof(path), path, NULL);
+  if (!status) {
+    WCMD_print_error();
+    return;
+  }
   lstrcpyn (drive, path, 3);
   status = WCMD_volume (0, drive);
   if (!status) {
@@ -121,7 +126,8 @@
   fd = malloc (sizeof(WIN32_FIND_DATA));
   hff = FindFirstFile (search_path, fd);
   if (hff == INVALID_HANDLE_VALUE) {
-    WCMD_output ("File Not Found\n");
+    SetLastError (ERROR_FILE_NOT_FOUND);
+    WCMD_print_error ();
     free (fd);
     return;
   }
diff --git a/programs/wcmd/wcmdmain.c b/programs/wcmd/wcmdmain.c
index 1e6825d..8325868 100644
--- a/programs/wcmd/wcmdmain.c
+++ b/programs/wcmd/wcmdmain.c
@@ -20,10 +20,12 @@
 		"PROMPT", "REM", "REN", "RENAME", "RD", "RMDIR", "SET", "SHIFT",
 		"TIME", "TYPE", "VERIFY", "VER", "VOL", "EXIT"};
 
+HINSTANCE hinst;
+DWORD errorlevel;
 int echo_mode = 1, verify_mode = 0;
 char nyi[] = "Not Yet Implemented\n\n";
 char newline[] = "\n";
-char version_string[] = "WCMD Version 0.12\n\n";
+char version_string[] = "WCMD Version 0.14\n\n";
 char anykey[] = "Press any key to continue: ";
 char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
 BATCH_CONTEXT *context = NULL;
@@ -376,6 +378,8 @@
   if (!status) {
     WCMD_print_error ();
   }
+  GetExitCodeProcess (pe.hProcess, &errorlevel);
+  if (errorlevel == STILL_ACTIVE) errorlevel = 0;
 }
 
 /******************************************************************************
@@ -459,30 +463,25 @@
 /****************************************************************************
  * WCMD_print_error
  *
- * Print the message for GetLastError - not much use yet as Wine doesn't have
- * the messages available, so we show meaningful messages for the most likely.
+ * Print the message for GetLastError
  */
 
 void WCMD_print_error () {
 LPVOID lpMsgBuf;
 DWORD error_code;
+int status;
 
   error_code = GetLastError ();
-  switch (error_code) {
-    case ERROR_FILE_NOT_FOUND:
-      WCMD_output ("File Not Found\n");
-      break;
-    case ERROR_PATH_NOT_FOUND:
-      WCMD_output ("Path Not Found\n");
-      break;
-    default:
-      FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-    			NULL, error_code,
-			MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
-			(LPTSTR) &lpMsgBuf, 0, NULL);
-      WCMD_output (lpMsgBuf);
-      LocalFree ((HLOCAL)lpMsgBuf);
+  status = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+    			NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
+  if (!status) {
+    WCMD_output ("FIXME: Cannot display message for error %d, status %d\n",
+			error_code, GetLastError());
+    return;
   }
+  WCMD_output (lpMsgBuf);
+  LocalFree ((HLOCAL)lpMsgBuf);
+  WCMD_output (newline);
   return;
 }
 
@@ -568,7 +567,10 @@
 
 
 
-/*	Remove leading spaces from a string. Return a pointer to the first
+/***************************************************************************
+ * WCMD_strtrim_leading_spaces
+ *
+ *	Remove leading spaces from a string. Return a pointer to the first
  *	non-space character. Does not modify the input string
  */
 
@@ -581,7 +583,10 @@
   return ptr;
 }
 
-/*	Remove trailing spaces from a string. This routine modifies the input
+/*************************************************************************
+ * WCMD_strtrim_trailing_spaces
+ *
+ *	Remove trailing spaces from a string. This routine modifies the input
  *	string by placing a null after the last non-space character
  */
 
diff --git a/programs/wcmd/wcmdrc.rc b/programs/wcmd/wcmdrc.rc
index 16ffa26..33343e0 100644
--- a/programs/wcmd/wcmdrc.rc
+++ b/programs/wcmd/wcmdrc.rc
@@ -64,11 +64,10 @@
  \
 Syntax:	IF [NOT] EXIST filename command \
 	IF [NOT] string1==string2 command \
+	IF [NOT] ERRORLEVEL number command \
  \
 In the second form of the command, string1 and string2 must be in double \
-quotes. The comparison is not case-sensitive.\
- \
-The form IF [NOT] ERRORLEVEL number is not implemented in Wcmd.\n"
+quotes. The comparison is not case-sensitive.\n"
 
   WCMD_LABEL,  "Help about LABEL\n"
   WCMD_MD,     "Help about MD\n"