Просмотр исходного кода

dos: Added MS-DOS support via djgpp.

Ryan C. Gordon 2 недель назад
Родитель
Сommit
f674b2dc15
6 измененных файлов с 207 добавлено и 6 удалено
  1. 8 1
      CMakeLists.txt
  2. 1 1
      src/physfs.h
  3. 2 2
      src/physfs_internal.h
  4. 178 0
      src/physfs_platform_dos.c
  5. 15 2
      src/physfs_platform_posix.c
  6. 3 0
      src/physfs_platforms.h

+ 8 - 1
CMakeLists.txt

@@ -85,6 +85,7 @@ set(PHYSFS_SRCS
     src/physfs_unicode.c
     src/physfs_unicode.c
     src/physfs_platform_cafe.c
     src/physfs_platform_cafe.c
     src/physfs_platform_ctr.c
     src/physfs_platform_ctr.c
+    src/physfs_platform_dos.c
     src/physfs_platform_posix.c
     src/physfs_platform_posix.c
     src/physfs_platform_unix.c
     src/physfs_platform_unix.c
     src/physfs_platform_windows.c
     src/physfs_platform_windows.c
@@ -218,7 +219,10 @@ if(PHYSFS_BUILD_STATIC)
     list(APPEND PHYSFS_INSTALL_TARGETS "physfs-static")
     list(APPEND PHYSFS_INSTALL_TARGETS "physfs-static")
 endif()
 endif()
 
 
-option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
+if (NOT DOS)
+    option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
+endif()
+
 if(PHYSFS_BUILD_SHARED)
 if(PHYSFS_BUILD_SHARED)
     add_library(physfs-shared SHARED ${PHYSFS_SRCS})
     add_library(physfs-shared SHARED ${PHYSFS_SRCS})
     add_library(PhysFS::PhysFS-shared ALIAS physfs-shared)
     add_library(PhysFS::PhysFS-shared ALIAS physfs-shared)
@@ -258,6 +262,9 @@ if(PHYSFS_BUILD_TEST)
     add_executable(test_physfs test/test_physfs.c)
     add_executable(test_physfs test/test_physfs.c)
     target_link_libraries(test_physfs PRIVATE PhysFS::PhysFS)
     target_link_libraries(test_physfs PRIVATE PhysFS::PhysFS)
     sdl_add_warning_options(test_physfs WARNING_AS_ERROR ${PHYSFS_WERROR})
     sdl_add_warning_options(test_physfs WARNING_AS_ERROR ${PHYSFS_WERROR})
+    if(DOS)
+        set_target_properties(test_physfs PROPERTIES OUTPUT_NAME "TESTPHYS")   # 8.3 file names!
+    endif()
 
 
     find_path(READLINE_H readline/readline.h)
     find_path(READLINE_H readline/readline.h)
     find_path(HISTORY_H readline/history.h)
     find_path(HISTORY_H readline/history.h)

+ 1 - 1
src/physfs.h

@@ -233,7 +233,7 @@ extern "C" {
 #define PHYSFS_DECL __declspec(dllexport)
 #define PHYSFS_DECL __declspec(dllexport)
 #elif defined(__SUNPRO_C)
 #elif defined(__SUNPRO_C)
 #define PHYSFS_DECL __global
 #define PHYSFS_DECL __global
-#elif ((__GNUC__ >= 3) && (!defined(__EMX__)) && (!defined(sun)))
+#elif ((__GNUC__ >= 3) && (!defined(__EMX__)) && (!defined(DJGPP)) && (!defined(sun)))
 #define PHYSFS_DECL __attribute__((visibility("default")))
 #define PHYSFS_DECL __attribute__((visibility("default")))
 #else
 #else
 #define PHYSFS_DECL
 #define PHYSFS_DECL

+ 2 - 2
src/physfs_internal.h

@@ -69,7 +69,7 @@ extern "C" {
    All file-private symbols need to be marked "static".
    All file-private symbols need to be marked "static".
    Everything shared between PhysicsFS sources needs to be in this
    Everything shared between PhysicsFS sources needs to be in this
    file between the visibility pragma blocks. */
    file between the visibility pragma blocks. */
-#if !defined(_WIN32) && (PHYSFS_MINIMUM_GCC_VERSION(4,0) || defined(__clang__))
+#if !defined(_WIN32) && !defined(DJGPP) && (PHYSFS_MINIMUM_GCC_VERSION(4,0) || defined(__clang__))
 #define PHYSFS_HAVE_PRAGMA_VISIBILITY 1
 #define PHYSFS_HAVE_PRAGMA_VISIBILITY 1
 #endif
 #endif
 
 
@@ -477,7 +477,7 @@ void __PHYSFS_DirTreeDeinit(__PHYSFS_DirTree *dt);
  *  Obviously, this isn't a function. If you need more than one char for this,
  *  Obviously, this isn't a function. If you need more than one char for this,
  *  you'll need to pull some old pieces of PhysicsFS out of revision control.
  *  you'll need to pull some old pieces of PhysicsFS out of revision control.
  */
  */
-#if defined(PHYSFS_PLATFORM_WINDOWS) || defined(PHYSFS_PLATFORM_OS2)
+#if defined(PHYSFS_PLATFORM_DOS) || defined(PHYSFS_PLATFORM_WINDOWS) || defined(PHYSFS_PLATFORM_OS2)
 #define __PHYSFS_platformDirSeparator '\\'
 #define __PHYSFS_platformDirSeparator '\\'
 #else
 #else
 #define __PHYSFS_STANDARD_DIRSEP 1
 #define __PHYSFS_STANDARD_DIRSEP 1

+ 178 - 0
src/physfs_platform_dos.c

@@ -0,0 +1,178 @@
+/*
+ * MS-DOS support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_DOS
+
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/farptr.h>
+#include <dpmi.h>
+#include <go32.h>
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(const char *argv0)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+void __PHYSFS_platformDeinit(void)
+{
+    /* no-op */
+} /* __PHYSFS_platformDeinit */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if (defined PHYSFS_NO_CDROM_SUPPORT)
+    /* no-op. */
+#else
+    /* MSCDEX API calls go through interrupt 0x2F with AH=0x15: https://www.phatcode.net/res/220/files/mscdex21.txt */
+    __dpmi_regs regs;
+    regs.x.ax = 0x1500;  /* get number of CD drive letters */
+    regs.x.bx = 0x0000;
+    __dpmi_int(0x2F, &regs);
+
+    const int num_drives = (int) regs.x.bx;  /* if zero, no drives or no MSCDEX installed. */
+    if (num_drives > 0) {
+        regs.x.ax = 0x150D;  /* get CD drive letters */
+        regs.x.es = __tb >> 4;     /* the transfer buffer is at least 2k large, if all possible drives were CD-ROMs, we'd need 26 bytes. */
+        regs.x.bx = __tb & 0x0f;
+        __dpmi_int(0x2F, &regs);
+        char drives[26];
+        dosmemget(__tb, num_drives, drives);
+        for (int i = 0; i < num_drives; i++) {
+            const char path[] = { 'A' + drives[i], ':', '\\', '\0' };
+            DIR *dirp = opendir(path);  /* if we can open the drive's root dir, there's a filesystem there. */
+            if (dirp) {
+                closedir(dirp);
+                cb(data, path);
+            }
+        }
+    }
+#endif
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    /* As of MS-DOS 3.0, you can get the full path to the EXE from the very end of the
+        environment table, which is discovered through the PSP:
+        https://en.wikipedia.org/wiki/Program_Segment_Prefix
+
+       An EXE is launched with the PSP's segment in DS, but we'll use a DOS API to obtain it
+        later, since we don't control startup. https://stanislavs.org/helppc/int_21-62.html
+
+       The table pointed to by the word at offset 0x2C in the PSP is just a collection
+        of ASCIZ strings, with a blank string signifying the end. The EXE path is
+        after that.
+
+       https://stackoverflow.com/questions/60928997/how-to-get-environment-variables-in-a-dos-assembly-program
+     */
+    __dpmi_regs regs;
+    regs.x.ax = 0x6200;  /* get number of CD drive letters */
+    regs.x.bx = 0x0000;
+    __dpmi_int(0x21, &regs);
+
+    /* https://www.delorie.com/djgpp/doc/ug/dpmi/farptr-intro.html.en */
+    const unsigned long pspseg = (unsigned long) regs.x.bx;
+    const unsigned long envsel = (unsigned long) _farpeekw(_dos_ds, (pspseg * 16) + 0x2C);
+
+    int zero_count = 0;
+    int offset;
+    for (offset = 0; (offset < 0xFFFF) && (zero_count < 2); offset++) {
+        const char ch = (char) _farpeekb(envsel, offset);
+        if (ch == 0) {
+            zero_count++;
+        } else {
+            zero_count = 0;
+        }
+    }
+
+    if (zero_count != 2) {
+        return NULL;  /* uhoh */
+    }
+
+    /* there's a Uint16 here that represents number of extension strings. In practice it's always 1 and that one string is the path we need. */
+    offset += 2;
+
+    int slen = 0;
+    for (unsigned long i = offset; _farpeekb(envsel, i) != 0; i++) {
+        slen++;
+    }
+
+    slen++;  /* count the null terminator. */
+
+    char *lastbackslash = NULL;
+    char *retval = (char *) allocator.Malloc(slen);
+    if (retval) {
+        int i = 0;
+        do {
+            const char ch = (char) _farpeekb(envsel, offset + i);
+            retval[i] = ch;
+            if (ch == '\\') {
+                lastbackslash = &retval[i];
+            }
+            i++;
+        } while (i < slen);
+    }
+
+    if (lastbackslash) {
+        lastbackslash[1] = '\0';  /* chop off exe name, just leave path */
+    }
+
+    return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcUserDir(void)
+{
+    return __PHYSFS_platformCalcBaseDir(NULL);  /* !!! FIXME: ? */
+}
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    return __PHYSFS_platformCalcBaseDir(NULL);  /* !!! FIXME: ? */
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+    return (void *) 0x1;
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    return (void *) 0x1;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    return (mutex == ((void *) 0x1));
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* PHYSFS_PLATFORM_DOS */
+
+/* end of physfs_platform_dos.c ... */
+

+ 15 - 2
src/physfs_platform_posix.c

@@ -19,7 +19,10 @@
 #include <dirent.h>
 #include <dirent.h>
 #include <errno.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fcntl.h>
+
+#ifndef PHYSFS_PLATFORM_DOS
 #include <pthread.h>
 #include <pthread.h>
+#endif
 
 
 #include "physfs_internal.h"
 #include "physfs_internal.h"
 
 
@@ -31,7 +34,6 @@ static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
         case 0: return PHYSFS_ERR_OK;
         case 0: return PHYSFS_ERR_OK;
         case EACCES: return PHYSFS_ERR_PERMISSION;
         case EACCES: return PHYSFS_ERR_PERMISSION;
         case EPERM: return PHYSFS_ERR_PERMISSION;
         case EPERM: return PHYSFS_ERR_PERMISSION;
-        case EDQUOT: return PHYSFS_ERR_NO_SPACE;
         case EIO: return PHYSFS_ERR_IO;
         case EIO: return PHYSFS_ERR_IO;
         case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
         case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
         case EMLINK: return PHYSFS_ERR_NO_SPACE;
         case EMLINK: return PHYSFS_ERR_NO_SPACE;
@@ -41,10 +43,13 @@ static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
         case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
         case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
         case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
         case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
         case EROFS: return PHYSFS_ERR_READ_ONLY;
         case EROFS: return PHYSFS_ERR_READ_ONLY;
-        case ETXTBSY: return PHYSFS_ERR_BUSY;
         case EBUSY: return PHYSFS_ERR_BUSY;
         case EBUSY: return PHYSFS_ERR_BUSY;
         case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
         case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
         case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
         case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
+        #ifndef PHYSFS_PLATFORM_DOS  /* djgpp doesn't have these. */
+        case EDQUOT: return PHYSFS_ERR_NO_SPACE;
+        case ETXTBSY: return PHYSFS_ERR_BUSY;
+        #endif
         default: return PHYSFS_ERR_OS_ERROR;
         default: return PHYSFS_ERR_OS_ERROR;
     } /* switch */
     } /* switch */
 } /* errcodeFromErrnoError */
 } /* errcodeFromErrnoError */
@@ -56,6 +61,7 @@ static inline PHYSFS_ErrorCode errcodeFromErrno(void)
 } /* errcodeFromErrno */
 } /* errcodeFromErrno */
 
 
 
 
+#ifndef PHYSFS_PLATFORM_DOS
 static char *getUserDirByUID(void)
 static char *getUserDirByUID(void)
 {
 {
     uid_t uid = getuid();
     uid_t uid = getuid();
@@ -114,6 +120,7 @@ char *__PHYSFS_platformCalcUserDir(void)
 
 
     return retval;
     return retval;
 } /* __PHYSFS_platformCalcUserDir */
 } /* __PHYSFS_platformCalcUserDir */
+#endif
 
 
 
 
 PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
 PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
@@ -176,6 +183,10 @@ static void *doOpen(const char *filename, int mode)
     /* O_APPEND doesn't actually behave as we'd like. */
     /* O_APPEND doesn't actually behave as we'd like. */
     mode &= ~O_APPEND;
     mode &= ~O_APPEND;
 
 
+#ifdef PHYSFS_PLATFORM_DOS
+    mode |= O_BINARY;
+#endif
+
 #ifdef O_CLOEXEC
 #ifdef O_CLOEXEC
     /* Add O_CLOEXEC if defined */
     /* Add O_CLOEXEC if defined */
     mode |= O_CLOEXEC;
     mode |= O_CLOEXEC;
@@ -367,6 +378,7 @@ int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
 } /* __PHYSFS_platformStat */
 } /* __PHYSFS_platformStat */
 
 
 
 
+#ifndef PHYSFS_PLATFORM_DOS
 typedef struct
 typedef struct
 {
 {
     pthread_mutex_t mutex;
     pthread_mutex_t mutex;
@@ -442,6 +454,7 @@ void __PHYSFS_platformReleaseMutex(void *mutex)
         } /* if */
         } /* if */
     } /* if */
     } /* if */
 } /* __PHYSFS_platformReleaseMutex */
 } /* __PHYSFS_platformReleaseMutex */
+#endif  /* !PHYSFS_PLATFORM_DOS */
 
 
 #endif  /* PHYSFS_PLATFORM_POSIX */
 #endif  /* PHYSFS_PLATFORM_POSIX */
 
 

+ 3 - 0
src/physfs_platforms.h

@@ -15,6 +15,9 @@
 #if defined(TARGET_EXTENSION) && (defined(TARGET_PLAYDATE) || defined(TARGET_SIMULATOR))
 #if defined(TARGET_EXTENSION) && (defined(TARGET_PLAYDATE) || defined(TARGET_SIMULATOR))
 #  define PHYSFS_PLATFORM_PLAYDATE 1
 #  define PHYSFS_PLATFORM_PLAYDATE 1
 #  define PHYSFS_NO_CRUNTIME_MALLOC 1
 #  define PHYSFS_NO_CRUNTIME_MALLOC 1
+#elif (defined DJGPP)
+#  define PHYSFS_PLATFORM_DOS 1
+#  define PHYSFS_PLATFORM_POSIX 1  /* close enough with djgpp */
 #elif (defined __LIBRETRO__)
 #elif (defined __LIBRETRO__)
 #  define PHYSFS_PLATFORM_LIBRETRO 1
 #  define PHYSFS_PLATFORM_LIBRETRO 1
 #  define PHYSFS_NO_CDROM_SUPPORT 1
 #  define PHYSFS_NO_CDROM_SUPPORT 1