All of lore.kernel.org
 help / color / mirror / Atom feed
From: Clarence Dang <dang@kde.org>
To: linux-msdos@vger.kernel.org
Subject: [PATCH] Never type another DOS command!
Date: Sun, 21 Sep 2003 01:46:54 +1000	[thread overview]
Message-ID: <200309210146.54606.dang@kde.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1654 bytes --]


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

[-- Attachment #2: dosemu_exec2.diff --]
[-- Type: text/x-diff, Size: 15008 bytes --]

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	other threads:[~2003-09-20 15:46 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200309210146.54606.dang@kde.org \
    --to=dang@kde.org \
    --cc=linux-msdos@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.