mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-28 07:45:22 +00:00
dos: Use INT 0x21, operation 0x62 to calculate basepath.
Previously this captured argv[0] and pushed it through searchpath(). It's probably better to go right to the source to find this info, though.
This commit is contained in:
@@ -22,9 +22,10 @@
|
||||
|
||||
#ifdef SDL_FILESYSTEM_DOS
|
||||
|
||||
#include <dir.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../../core/dos/SDL_dos.h"
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
// System dependent filesystem routines
|
||||
|
||||
@@ -32,33 +33,75 @@
|
||||
|
||||
char *SDL_SYS_GetBasePath(void)
|
||||
{
|
||||
extern const char *SDL_argv0; // from src/main/dos/SDL_sysmain_runapp.c
|
||||
char *searched = searchpath(SDL_argv0);
|
||||
if (!searched) {
|
||||
SDL_SetError("argv[0] not found by searchpath");
|
||||
return NULL;
|
||||
}
|
||||
/* 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
|
||||
|
||||
char *fullpath = SDL_strdup(searched);
|
||||
if (!fullpath) {
|
||||
return NULL;
|
||||
}
|
||||
An EXE is launched with the PSP's segment in DS, but we'll use a DOS API to obtain it
|
||||
later, in case we don't control startup. https://stanislavs.org/helppc/int_21-62.html
|
||||
|
||||
// I don't know if this is a good idea. Drop DOS path separators, use Unix style instead.
|
||||
char *ptr;
|
||||
for (ptr = fullpath; *ptr; ptr++) {
|
||||
if (*ptr == '\\') {
|
||||
*ptr = '/';
|
||||
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 PSP address */
|
||||
regs.x.bx = 0x0000;
|
||||
__dpmi_int(0x21, ®s);
|
||||
|
||||
const Uint32 pspseg = (Uint32) regs.x.bx;
|
||||
const Uint32 envsel = (Uint32) DOS_PeekUint16((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;
|
||||
}
|
||||
}
|
||||
|
||||
// drop the .exe name.
|
||||
ptr = SDL_strrchr(fullpath, '/');
|
||||
if (ptr) {
|
||||
ptr[1] = '\0';
|
||||
if (zero_count != 2) {
|
||||
return NULL; // uhoh
|
||||
} else if (_farpeekw(envsel, offset) < 1) { // 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.
|
||||
return NULL; // uhoh
|
||||
}
|
||||
|
||||
return fullpath;
|
||||
offset += 2;
|
||||
|
||||
int slen = 0;
|
||||
for (unsigned long i = (unsigned long) offset; _farpeekb(envsel, i) != 0; i++) {
|
||||
slen++;
|
||||
}
|
||||
|
||||
slen++; /* count the null terminator. */
|
||||
|
||||
char *lastbackslash = NULL;
|
||||
char *retval = (char *) SDL_malloc(slen);
|
||||
if (retval) {
|
||||
for (int i = 0; i < slen; i++) {
|
||||
const char ch = (char) _farpeekb(envsel, offset + i);
|
||||
if (ch == '\\') {
|
||||
retval[i] = '/'; // I don't know if this is a good idea. Drop DOS path separators, use Unix style instead.
|
||||
lastbackslash = &retval[i];
|
||||
} else {
|
||||
retval[i] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastbackslash) {
|
||||
lastbackslash[1] = '\0'; /* chop off exe name, just leave path */
|
||||
} else { // uh...should have been a full path...?!
|
||||
SDL_free(retval);
|
||||
retval = NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
char *SDL_SYS_GetPrefPath(const char *org, const char *app)
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#include <crt0.h>
|
||||
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY | _CRT0_FLAG_NONMOVE_SBRK;
|
||||
|
||||
const char *SDL_argv0 = NULL;
|
||||
|
||||
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved)
|
||||
{
|
||||
(void)reserved;
|
||||
@@ -43,8 +41,6 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserve
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_argv0 = argv ? argv[0] : NULL;
|
||||
|
||||
return SDL_CallMainFunction(argc, argv, mainFunction);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user