Sick of trying to remember those cryptic short filenames?
Sick of trying to remember the syntax of LREDIR or $_hdimage?
Sick of forgetting to include the builtins in your PATH?

Ever wanted to run a DOS app without typing a _single_ DOS command?

Don't delay - try the attached patch today!

Here are the steps for success (tm):

1. Get a copy of 1.1.5.7 or CVS
2. Apply the attached patch
3. make && make install
4. Make sure "unix -c" is put at the end of your autoexec.bat
   (as opposed to the default, "unix -e", which tries to execute
    your commands literally)

Now, you can run your favourite DOS apps like this:

   xdosemu "/home/clarence/games/commander keen/keen1.exe"

And it will automatically:

1. mount / if the specified program is not available from an
   already-redirected drive
2. "cd" to the correct directory
3. and execute the program automagically, all without _any_ typing in DOS

In the process, I "ported" over some more builtins i.e. I just cut and
paste them (except for com_dossetcurrentdir()).

Also, while I was at it, I made a cosmetic change to GetRedirectionRoot()
in mfs.c - maybe it's just me but returning "TRUE" for failure and "FALSE"
for success is just a little bit misleading :P

Thanks go to Stas Sergeev for his help on callbacks and builtins, and
Bart Oldeman for his explanation of make_unmake_dos_mangled_path()
which must have changed at least 3 times during the writing of this patch :P

Enjoy!
Clarence, uncharacteristically writing an ad :)

--
KolourPaint - http://sf.net/projects/kolourpaint
LibMSWrite - http://sf.net/projects/libmswrite


"Documentation is code duplication" -- David Greenaway
diff -ur -x'*.d' -x'*.o' 1157pr/src/dosext/mfs/lfn.h 1157/src/dosext/mfs/lfn.h
--- 1157pr/src/dosext/mfs/lfn.h	1970-01-01 10:00:00.000000000 +1000
+++ 1157/src/dosext/mfs/lfn.h	2003-09-14 15:26:56.000000000 +1000
@@ -0,0 +1,10 @@
+/* 
+ * All modifications in this file to the original code are
+ * (C) Copyright 1992, ..., 2003 the "DOSEMU-Development-Team".
+ *
+ * for details see file COPYING in the DOSEMU distribution
+ */
+
+void make_unmake_dos_mangled_path(char *dest, char *fpath,
+                                         int current_drive, int alias);
+
diff -ur -x'*.d' -x'*.o' 1157pr/src/dosext/mfs/lfn.c 1157/src/dosext/mfs/lfn.c
--- 1157pr/src/dosext/mfs/lfn.c	2003-09-14 12:44:30.000000000 +1000
+++ 1157/src/dosext/mfs/lfn.c	2003-09-19 18:29:14.000000000 +1000
@@ -24,6 +24,7 @@
 #include "mfs.h"
 #include "mangle.h"
 #include "bios.h"
+#include "lfn.h"
 
 #define EOS '\0'
 #define BACKSLASH '\\'
@@ -78,7 +79,7 @@
 	  alias=1: mangle, alias=0: don't mangle
    output: dest = DOS path
 */
-static void make_unmake_dos_mangled_path(char *dest, char *fpath,
+void make_unmake_dos_mangled_path(char *dest, char *fpath,
 					 int current_drive, int alias)
 {
 	char *src;
diff -ur -x'*.d' -x'*.o' 1157pr/src/dosext/mfs/mfs.c 1157/src/dosext/mfs/mfs.c
--- 1157pr/src/dosext/mfs/mfs.c	2003-09-14 12:44:30.000000000 +1000
+++ 1157/src/dosext/mfs/mfs.c	2003-09-14 17:04:07.000000000 +1000
@@ -264,18 +264,6 @@
 #define SFT_FDEVICE 0x0080
 #define SFT_FEOF 0x0040
 
-/* #define MAX_PATH_LENGTH 57 */
-/* 2001/01/05 Manfred Scherer
- * With the value 57 I can create pathlength until 54.
- * In native DOS I can create pathlength until 63.
- * With the value 66 it should be possible to create
- * paths with length 63.
- * I've tested it on my own system, and I found the value 66
- * is right for me.
- */
-
-#define MAX_PATH_LENGTH 66
-
 struct file_fd
 {
   char *name;
@@ -2417,12 +2405,12 @@
 int
 GetRedirectionRoot(int dsk, char **resourceName,int *ro_flag)
 {
-  if (!drives[dsk].root) return (TRUE);
+  if (!drives[dsk].root) return 1;
   *resourceName = malloc(MAXPATHLEN + 1);
-  if (*resourceName == NULL) return (TRUE);
+  if (*resourceName == NULL) return 1;
   strcpy(*resourceName, drives[dsk].root );
   *ro_flag=drives[dsk].read_only;
-  return (FALSE);
+  return 0;
 
 }
 
diff -ur -x'*.d' -x'*.o' 1157pr/src/dosext/mfs/mfs.h 1157/src/dosext/mfs/mfs.h
--- 1157pr/src/dosext/mfs/mfs.h	2003-09-14 12:44:30.000000000 +1000
+++ 1157/src/dosext/mfs/mfs.h	2003-09-14 17:06:49.000000000 +1000
@@ -14,7 +14,6 @@
 #include <sys/stat.h>
 #include <dirent.h>
 
-#ifdef DOSEMU
 /* definitions to make mach emu code compatible with dosemu */
 #include "emu.h"
 
@@ -67,7 +66,6 @@
 #define SETHIGH(x,y) 	(*(x) = (*(x) & ~0xff00) | ((MASK8(y))<<8))
 #define SETLOW(x,y) 	(*(x) = (*(x) & ~0xff) | (MASK8(y)))
 #define SETWORD(x,y)	(*(x) = (*(x) & ~0xffff) | (MASK16(y)))
-#endif
 
 /*
  * Copyright (c) 1991 Carnegie Mellon University
@@ -471,6 +469,20 @@
 #define CANCEL_REDIRECTION 4
 #define EXTENDED_GET_REDIRECTION 5
 
+
+/* #define MAX_PATH_LENGTH 57 */
+/* 2001/01/05 Manfred Scherer
+ * With the value 57 I can create pathlength until 54.
+ * In native DOS I can create pathlength until 63.
+ * With the value 66 it should be possible to create
+ * paths with length 63.
+ * I've tested it on my own system, and I found the value 66
+ * is right for me.
+ */
+
+#define MAX_PATH_LENGTH 66
+
+
 extern int build_ufs_path_(char *ufs, const char *path, int drive,
                            int lowercase);
 extern boolean_t find_file(char *fpath, struct stat *st, int drive);
diff -ur -x'*.d' -x'*.o' 1157pr/src/plugin/commands/builtins.c 1157/src/plugin/commands/builtins.c
--- 1157pr/src/plugin/commands/builtins.c	2003-09-14 12:44:22.000000000 +1000
+++ 1157/src/plugin/commands/builtins.c	2003-09-14 16:06:13.000000000 +1000
@@ -377,6 +377,37 @@
    return(argcx);
 }
 
+int com_dosgetdrive(void)
+{
+        HI(ax) = 0x19;
+        call_msdos();    /* call MSDOS */
+        return LO(ax);  /* 0=A, 1=B, ... */
+}
+
+int com_dossetdrive(int drive)
+{
+        HI(ax) = 0x0e;
+        LO(dx) = drive; /* 0=A, 1=B, ... */
+        call_msdos();    /* call MSDOS */
+        return LO(ax);  /* number of available logical drives */
+}
+
+int com_dossetcurrentdir(char *path)
+{
+        /*struct com_starter_seg  *ctcb = owntcb->params;*/
+        char *s = com_strdup(path);
+
+        com_errno = 8;
+        if (!s) return -1;
+        HI(ax) = 0x3b;
+        LWORD(ds) = FP_SEG32 (s) /*COM_SEG*/;
+        LWORD(edx) = FP_OFF32 (s) /*COM_OFFS_OF(s)*/;
+        call_msdos();    /* call MSDOS */
+        com_strfree(s);
+        if (LWORD(eflags) & CF) return -1;
+        return 0;
+}
+
 struct REGPACK regs_to_regpack(struct vm86_regs *regs)
 {
 	struct REGPACK regpack;
diff -ur -x'*.d' -x'*.o' 1157pr/src/plugin/commands/builtins.h 1157/src/plugin/commands/builtins.h
--- 1157pr/src/plugin/commands/builtins.h	2003-09-14 12:44:22.000000000 +1000
+++ 1157/src/plugin/commands/builtins.h	2003-09-14 15:47:59.000000000 +1000
@@ -63,6 +63,9 @@
 char * com_strdup(char *s);
 unsigned short get_dos_ver(void);
 void com_strfree(char *s);
+int com_dosgetdrive(void);
+int com_dossetdrive(int drive);
+int com_dossetcurrentdir(char *path);
 void com_intr(int intno, struct REGPACK *regpack);
 int com_int86x(int intno, union com_REGS *inregs,
 		union com_REGS *outregs, struct SREGS *segregs);
diff -ur -x'*.d' -x'*.o' 1157pr/src/plugin/commands/unix.c 1157/src/plugin/commands/unix.c
--- 1157pr/src/plugin/commands/unix.c	2003-09-14 12:44:22.000000000 +1000
+++ 1157/src/plugin/commands/unix.c	2003-09-19 19:22:39.000000000 +1000
@@ -13,6 +13,7 @@
  ************************************************/
 
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -22,6 +23,9 @@
 #include "memory.h"
 #include "doshelpers.h"
 #include "builtins.h"
+#include "redirect.h"
+#include "../../dosext/mfs/lfn.h"
+#include "../../dosext/mfs/mfs.h"
 
 #include "msetenv.h"
 #include "unix.h"
@@ -41,7 +45,7 @@
 static int usage (void);
 static int send_command (char **argv);
 #if CAN_EXECUTE_DOS
-static int do_execute_dos (int argc, char **argv);
+static int do_execute_dos (int argc, char **argv, int isLiteralCommand);
 #endif
 static int do_set_dosenv (int agrc, char **argv);
 
@@ -61,7 +65,11 @@
     case 'e':
     case 'E':
       /* EXECUTE dos command*/
-      return do_execute_dos (argc-2, argv+2);
+      return do_execute_dos (argc-2, argv+2, 1/*literal DOS cmd*/);
+    case 'c':
+    case 'C':
+      /* EXECUTE dos program*/
+      return do_execute_dos (argc-2, argv+2, 0/*not literal DOS cmd - is Linux path*/);
 #endif
     case 's':
     case 'S':
@@ -83,8 +91,11 @@
   printf ("Run Linux commands from DOSEMU\n\n");
 #if CAN_EXECUTE_DOS
   printf ("UNIX -e [ENVVAR]\n");
-  printf ("  Execute the DOS command given in the Linux environment variable \"ENVVAR\"\n");
-  printf ("  and then exit DOSEMU.\n");
+  printf ("  Execute the DOS command given in the Linux environment variable \"ENVVAR\".\n");
+  printf ("  If not given, use the argument to the -E flag of DOSEMU\n\n");
+  printf ("UNIX -c [ENVVAR]\n");
+  printf ("  Execute the DOS program whose Linux path is given in the Linux environment\n");
+  printf ("  variable \"ENVVAR\".\n");
   printf ("  If not given, use the argument to the -E flag of DOSEMU\n\n");
 #endif
   printf ("UNIX -s ENVVAR\n");
@@ -92,7 +103,7 @@
   printf ("UNIX command [arg1 ...]\n");
   printf ("  Execute the Linux command with the arguments given.\n\n");
   printf ("UNIX\n");
-  printf ("  show this help screen\n\n\n");
+  printf ("  show this help screen\n\n");
   printf ("Note: Use UNIX only to run Linux commands that terminates without user\n");
   printf ("      interaction. Otherwise it will start and wait forever!\n");
 
@@ -126,7 +137,169 @@
 }
 
 #if CAN_EXECUTE_DOS
-static int do_execute_dos (int argc, char **argv)
+
+static char *makeEndInBackslash (char *s)
+{
+  int len = strlen (s);
+  if (len && s [len - 1] != '/')
+    strcpy (s + len, "/");
+  return s;
+}
+
+/*
+ * Return the drive from which <linux_path_resolved> is accessible.
+ * If there is no such redirection, it returns the next available drive * -1.
+ * If there are no available drives (from >= 2 aka "C:"), it returns -26.
+ * If an error occurs, it returns -27.
+ *
+ * In addition, if a drive is available, <linux_path_resolved> is modified
+ * to have the drive's uncannonicalized linux root as its prefix.  This is
+ * necessary as make_unmake_dos_mangled_path() will not work with a resolved
+ * path if the drive was LREDIR'ed by the user to a unresolved path.
+ */
+static int findDrive (char *linux_path_resolved)
+{
+  int freeDrive = -26;
+
+  j_printf ("findDrive (linux_path='%s')\n", linux_path_resolved);
+
+  int drive;
+  for (drive = 0; drive < 26; drive++) {
+    char *drive_linux_root = NULL;
+    int drive_ro;
+    char drive_linux_root_resolved [PATH_MAX];
+
+    if (GetRedirectionRoot (drive, &drive_linux_root, &drive_ro) == 0/*success*/) {
+      if (!realpath (drive_linux_root, drive_linux_root_resolved)) {
+        fprintf (stderr, "ERROR: Cannot canonicalize drive root path (%s)\n", strerror (errno));
+        return -27;
+      }
+
+      /* make sure drive root ends in / */
+      makeEndInBackslash (drive_linux_root_resolved);
+      
+      j_printf ("CMP: drive=%i drive_linux_root='%s' (resolved='%s')\n",
+                 drive, drive_linux_root, drive_linux_root_resolved);
+
+      /* TODO: handle case insensitive filesystems (e.g. VFAT)
+       *     - can we just strlwr() both paths before comparing them? */
+      if (strstr (linux_path_resolved, drive_linux_root_resolved) == linux_path_resolved) {
+        char old_linux_path_resolved [PATH_MAX];
+        
+        j_printf ("\tFound drive!\n");
+        strcpy (old_linux_path_resolved, linux_path_resolved);
+        snprintf (linux_path_resolved, PATH_MAX, "%s%s",
+                  drive_linux_root/*unresolved*/,
+                  old_linux_path_resolved + strlen (drive_linux_root_resolved));
+        j_printf ("\t\tModified root; linux path='%s'\n", linux_path_resolved);
+        
+        free (drive_linux_root);
+        return drive;
+      }
+      
+      free (drive_linux_root);
+    } else {
+      if (drive >= 2 && freeDrive == -26) {
+        freeDrive = -drive;
+      }
+    }
+  }
+
+  j_printf ("findDrive() returning free drive: %i\n", -freeDrive);
+  return freeDrive;
+}
+
+/*
+ * Given a <linux_path>, change to its corresponding drive and directory
+ * in DOS (redirecting a new drive if neccessary).  The DOS command is
+ * returned through <linux_path>.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+static int setupDOSCommand (char *linux_path)
+{
+  char linux_path_resolved[PATH_MAX];
+  char dos_path [MAX_PATH_LENGTH];
+  int drive;
+ 
+  char *b;
+
+  
+  if (!realpath (linux_path, linux_path_resolved)) {
+    fprintf (stderr, "ERROR: Cannot canonicalize path (%s)\n", strerror (errno));
+    return (1);
+  }
+
+  
+  drive = findDrive (linux_path_resolved);
+  if (drive < 0) {
+    drive = -drive;
+    
+    if (drive >= 26) {
+      if (drive == 26) {
+        fprintf (stderr, "ERROR: Cannot find a free DOS drive to use for LREDIR\n");
+      }
+      
+      return (1);
+    }
+
+    /* try mounting / on this DOS drive
+       (this won't work nice with "long" Linux paths > approx. 66
+        but at least programs that try to access ..\DATA\BLAH.DAT
+        will work)
+     */
+
+    j_printf ("Redirecting %c: to /\n", drive + 'A');
+    if (RedirectDisk (drive, LINUX_RESOURCE "/", 0/*rw*/) != 0/*success*/) {
+      fprintf (stderr, "ERROR: Could not redirect %c: to /\n", drive + 'A');
+      return (1);
+    }
+  }
+  
+  
+  /* switch to the drive */
+  j_printf ("Switching to drive %i (%c:)\n", drive, drive + 'A');
+  com_dossetdrive (drive);
+  if (com_dosgetdrive () != drive) {
+    fprintf (stderr, "ERROR: Could not change to %c:\n", drive + 'A');
+     
+    if (com_dossetdrive (com_dosgetdrive ()) < 26)
+      fprintf (stderr, "Try 'LASTDRIVE=Z' in CONFIG.SYS.\n");
+
+    return (1);
+  }
+
+  
+  make_unmake_dos_mangled_path (dos_path, linux_path_resolved,
+                                drive, 1/*alias*/);
+  j_printf ("DOS path: '%s' (from linux '%s')\n",
+            dos_path, linux_path_resolved);
+
+  
+  /* switch to the directory */
+  if (strlen (dos_path) >= 3 && (b = strrchr (dos_path, '\\')) != NULL) {
+    char *dos_dir = dos_path + 2;
+    *b++ = 0;
+    
+    j_printf ("Changing to directory '%s'\n", dos_dir);
+    if (com_dossetcurrentdir (dos_dir)) {
+      fprintf (stderr, "ERROR: Could not change to directory: %s\n", dos_dir);
+      return (1);
+    }
+  } else {
+    fprintf (stderr, "INTERNAL ERROR: no backslash in DOS path\n");
+    return (1);
+  }
+  
+
+  /* return the 8.3 EXE name */
+  strcpy (linux_path/*arg as return value*/, b);
+  
+  
+  return (0);
+}
+
+static int do_execute_dos (int argc, char **argv, int isLiteralCommand)
 {
   char *data = lowmem_alloc(256);
   struct REGPACK preg = REGPACK_INIT;
@@ -148,16 +321,23 @@
   if (! preg.r_ax) {
     /* SUCCESSFUL */
 
-    printf ("About to Execute : %s\n", data);
-
-
-	if (system (data)) {
-		/* SYSTEM failed ... */
-		fprintf (stderr, "SYSTEM failed ....(%d)\n", errno);
-		return (1);
-	}
+    if (!isLiteralCommand && setupDOSCommand (data))
+        return (1);
+    
+    if (*data) {
+      printf ("About to Execute : %s\n", data);
+
+      if (system (data)) {
+        /* SYSTEM failed ... */
+        fprintf (stderr, "SYSTEM failed ....(%d)\n", errno);
+        return (1);
+      }
  
-	return (0);
+      return (0);
+    } else {
+      /* empty string */
+      return (1);
+    }
   }
   else {
     /* UNSUCCESSFUL */
diff -ur -x'*.d' -x'*.o' 1157pr/src/plugin/coopthreads/coopthreads.c 1157/src/plugin/coopthreads/coopthreads.c
--- 1157pr/src/plugin/coopthreads/coopthreads.c	2003-09-14 12:44:22.000000000 +1000
+++ 1157/src/plugin/coopthreads/coopthreads.c	2003-09-14 16:02:42.000000000 +1000
@@ -994,21 +994,6 @@
 	return 0;
 }
 
-int com_dosgetdrive(void)
-{
-	HI(ax) = 0x19;
-	call_msdos();    /* call MSDOS */
-	return LO(ax);	/* 0=A, 1=B, ... */
-}
-
-int com_dossetdrive(int drive)
-{
-	HI(ax) = 0x0e;
-	LO(dx) = drive;	/* 0=A, 1=B, ... */
-	call_msdos();    /* call MSDOS */
-	return LO(ax);	/* number of available logical drives */
-}
-
 int com_dosgetcurrentdir(int drive, char *buf)
 {
 	struct com_starter_seg  *ctcb = owntcb->params;
@@ -1031,22 +1016,6 @@
 	return 0;
 }
 
-int com_dossetcurrentdir(char *path)
-{
-	struct com_starter_seg  *ctcb = owntcb->params;
-	char *s = com_strdup(path);
-
-	com_errno = 8;
-	if (!s) return -1;
-	HI(ax) = 0x3b;
-	LWORD(ds) = COM_SEG;
-	LWORD(edx) = COM_OFFS_OF(s);
-	call_msdos();    /* call MSDOS */
-	com_strfree(s);
-	if (LWORD(eflags) & CF) return -1;
-	return 0;
-}
-
 int com_dosgetsetfilestamp(int fd, int ftime)
 {
 	if (ftime) {

Reply via email to