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) {