📄 fileman.cpp
字号:
/* FILEMAN.CPP - File manager
*/
#include "Common.hpp"
#include <io.h>
#include <sys\stat.h>
#include <direct.h>
#include <i86.h>
#include <ASSERT.H>
#include "GrEngine.hpp"
#include "CPU.hpp"
#include "FileMan.hpp"
#include "GUI.hpp"
#include "SPC700.hpp"
char romdir [80] = "..", sramdir [80] = "..", instdir [80] = "", sshotdir [80] = "";
char exedir [80];
byte gameres = 1, guires = 4;
byte addsubmethod = 0;
byte soundkhz = 8, soundchannels = 0xFF;
boolean stereosound = false;
byte pcontrol[4] = { 0, 1, 3, 3 };
boolean autobacktrack = true, disallowinst = false;
word backtracktime = 30, backtracknum = 3;
struct windowsettings ws [NUMWINDOWS];
extern struct filemap fm[FTAGS] = {
"CheatDesc", FCHEAT, FSTRINGALLOC, offsetof (cheatpatchset, desc), // 0
"AutoRegOn", FROMSETTING, FBYTE, offsetof (gamesettings, autoreg),
"FrameSkip", FROMSETTING, FBYTE, offsetof (gamesettings, frameskip),
"Regulate%", FROMSETTING, FBYTE, offsetof (gamesettings, regpercent),
"GrSpeedup", FROMSETTING, FBYTE, offsetof (gamesettings, grspeedup),
"65c816%", FROMSETTING, FBYTE, offsetof (gamesettings, cpupercent), // 5
"SPC700%", FROMSETTING, FBYTE, offsetof (gamesettings, spcpercent),
"SoundChs", FROMSETTING, FWORD, offsetof (gamesettings, soundch),
"BGs", FROMSETTING, FBYTE, offsetof (gamesettings, bgs),
"ForceROM", FROMSETTING, FBYTE, offsetof (gamesettings, forcerom),
"ForceCtry", FROMSETTING, FBYTE, offsetof (gamesettings, forcecountry), // 10
"Interl", FROMSETTING, FBYTE, offsetof (gamesettings, interleaved),
"EnableSPC", FROMSETTING, FBYTE, offsetof (gamesettings, emulatespc),
"SPCSkipM", FROMSETTING, FBYTE, offsetof (gamesettings, spcskipmethod),
"OpenWins", FROMSETTING, FWORD, offsetof (gamesettings, openwindows),
"NoFastROM", FROMSETTING, FBYTE, offsetof (gamesettings, ignorefastrom),
"GameRes", FGLOBAL, FBYTE, (dword) &gameres, // 15
"GUIRes", FGLOBAL, FBYTE, (dword) &guires,
"AddSubM", FGLOBAL, FBYTE, (dword) &addsubmethod,
"SoundKHz", FGLOBAL, FBYTE, (dword) &soundkhz,
"StereoSnd", FGLOBAL, FBYTE, (dword) &stereosound,
"P1Control", FGLOBAL, FBYTE, (dword) &pcontrol[0], // 20
"P2Control", FGLOBAL, FBYTE, (dword) &pcontrol[1],
"P3Control", FGLOBAL, FBYTE, (dword) &pcontrol[2],
"P4Control", FGLOBAL, FBYTE, (dword) &pcontrol[3],
"DisableIS", FGLOBAL, FBYTE, (dword) &disallowinst,
"WaitTrace", FGLOBAL, FBYTE, (dword) &waitretrace, // 25
"LeadingEd", FGLOBAL, FBYTE, (dword) &leadingedge,
"ROMDir", FGLOBAL, FSTRING, (dword) romdir,
"SRAMDir", FGLOBAL, FSTRING, (dword) sramdir,
"InstDir", FGLOBAL, FSTRING, (dword) instdir,
"SShotDir", FGLOBAL, FSTRING, (dword) sshotdir, // 30
"BackGrnd", FGLOBAL, FBYTE, (dword) &background,
"ESCQuits", FGLOBAL, FBYTE, (dword) &escquits,
"WindowSet", FGLOBAL, FBYTE, (dword) &set.window,
"TextSet", FGLOBAL, FBYTE, (dword) &set.text,
"CtrlSet", FGLOBAL, FBYTE, (dword) &set.control, // 35
"ChoiceSet", FGLOBAL, FBYTE, (dword) &set.choice,
"ButtonSet", FGLOBAL, FBYTE, (dword) &set.button,
"BtTextSet", FGLOBAL, FBYTE, (dword) &set.buttontext,
"TitleSet", FGLOBAL, FBYTE, (dword) &set.title,
"TtTextSet", FGLOBAL, FBYTE, (dword) &set.titletext, // 40
"FocusSet", FGLOBAL, FBYTE, (dword) &set.focus,
"FlashSet", FGLOBAL, FBYTE, (dword) &set.flash,
"JoyUp", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, up),
"JoyDown", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, down),
"JoyLeft", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, left), // 45
"JoyRight", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, right),
"JoyX", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, x),
"JoyY", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, y),
"JoyA", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, a),
"JoyB", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, b), // 50
"JoyL", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, l),
"JoyR", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, r),
"JoySelect", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, select),
"JoyStart", FJOYPADSETTING, FBYTE, offsetof (struct snesjoypad, start),
"WinPosX", FWINDOWPOS, FWORD, offsetof (struct windowsettings, x), // 55
"WinPosY", FWINDOWPOS, FWORD, offsetof (struct windowsettings, y),
"WinZOrder", FWINDOWPOS, FBYTE, offsetof (struct windowsettings, zorder),
"JoyMinX", FGLOBAL, FWORD, (dword) &joyminx,
"JoyMaxX", FGLOBAL, FWORD, (dword) &joymaxx,
"JoyMinY", FGLOBAL, FWORD, (dword) &joyminy, // 60
"JoyMaxY", FGLOBAL, FWORD, (dword) &joymaxy,
"JoyMidX", FGLOBAL, FWORD, (dword) &joymidx,
"JoyMidY", FGLOBAL, FWORD, (dword) &joymidy,
"JoyThresh", FGLOBAL, FWORD, (dword) &joythresh,
"BackNum", FGLOBAL, FWORD, (dword) &backtracknum, // 65
"FPUCopy", FGLOBAL, FBYTE, (dword) &fpucopy,
"Windowing", FROMSETTING, FBYTE, offsetof (gamesettings, windowing),
"IndirHDMA", FROMSETTING, FBYTE, offsetof (gamesettings, indirecthdma),
"AutoBackT", FGLOBAL, FBYTE, (dword) &autobacktrack,
"BackTTime", FGLOBAL, FWORD, (dword) &backtracktime,
"AskB4Exit", FGLOBAL, FBYTE, (dword) &confirmexit,
"ShowFPS", FGLOBAL, FBYTE, (dword) &showfps,
};
// Commands:
//
// New ROM "filename.ext"
// New Joypad n
// New Window n
// New Cheat bbaaaa=vv+...
//
// ; Statements starting with a semicolon are ignored.
struct gamesettings gsdefault = {
"[Defaults]", // char filename [13];
true, // boolean autoreg;
2, 100, // byte frameskip, regpercent;
false, // boolean grspeedup;
100, 100, // byte cpupercent, spcpercent;
0xFF, // word soundch;
31, // byte bgs;
0, 0, // byte forcerom, forcecountry;
false, // boolean interleaved;
false, // boolean emulatespc;
0, // byte spcskipmethod;
1, // word openwindows;
true, // boolean ignorefastrom
true, true// boolean windowing, indirecthdma
};
struct gamesettings *gs [MAXGAMEDATABASE] = {
&gsdefault // First entry (gs[0]) is the defaults.
};
struct gamesettings *curgs;
int curgsnum = 0;
int numgamesettings = 0;
int gsentries = 1;
boolean romloaded = false, romrunning = false;
void initfilemanager (char *argv0)
{
char temp[80];
curgs = gs[curgsnum];
strcpy (temp, argv0);
stripfilename (temp);
_fullpath (exedir, temp, 80);
debug0(exedir);
}
void uninitfilemanager (void)
{
int x, y;
for (x = 1; x < MAXGAMEDATABASE; x++) {
if (gs[x] == NULL) continue;
for (y = 0; y < gs[x]->patches; y++) {
free (gs[x]->cheat[y]->desc);
free (gs[x]->cheat[y]->patch);
free (gs[x]->cheat[y]);
}
free (gs[x]);
}
}
boolean exists (char *s)
{
if (access (s, 0) == 0)
return true;
else
return false;
}
boolean isadir (char *s)
{
static struct _stat buf;
// first checks whether the path is valid...
if (_stat (s, &buf) == -1) {
// no, so it might be an incomplete path. Decide based on the existance of an extention.
if (findlastch (s + findlastch(s, SLASH) + 1, '.') == -1) {
return true;
} else {
return false;
}
} else if (S_ISDIR(buf.st_mode))
return true;
return false;
}
void delstr (char *s, int p, int n)
{
for (s += p; *s != '\0'; s++) {
*s = s[n];
if (*s == '\0') break;
}
}
int findlastch (char *s, char ch)
{
int x;
for (x = strlen(s)-1; x >= 0; x--) {
if (s[x] == ch) {
return x;
}
}
return x;
}
int findfirstch (char *s, char ch)
{
int x;
for (x = 0; s[x] != '\0'; x++) {
if (s[x] == ch) {
return x;
}
}
return -1;
}
int countchar (char *s, char ch)
{
int n = 0;
while (*s != '\0') {
if (*s == ch) n++;
s++;
}
return n;
}
void trimspace (char *s)
{
int y, n;
for (y = 0; s[y] == ' ' || s[y] == 9; y++)
;
delstr (s, 0, y);
for (y = strlen(s)-1, n = 0; (s[y] == ' ' || s[y] == 9) && y >= 0; y--, n++)
;
delstr (s, y+1, n);
}
void trimfilespec (char *s)
{
trimspace (s);
if (countchar (s, SLASH) > 1 && s [strlen(s) - 1] == SLASH) {
s [strlen(s) - 1] = '\0';
}
}
void strippathname (char *name)
{
int x, p;
if (isadir (name)) {
name[0] = '\0';
return;
}
p = findlastch (name, SLASH);
x = findlastch (name, ':');
if (x > p) p = x;
delstr (name, 0, p + 1);
}
void stripfilename (char *name)
{
int x;
if (!isadir (name)) {
x = findlastch (name, SLASH);
if (name [x - 1] == ':' || x == 0) {
x++; // Don't delete backslash if file is in root.
}
delstr (name, x, strlen (name) - x);
} else {
x = strlen(name);
if (name[x-1] == SLASH)
name[x-1] = '\0';
}
}
void getabspath (char *path)
{ // absolute path reletive to executable directory
char tempcwd [80], temppath [80];
unsigned dummy;
getcwd (tempcwd, 80);
_dos_setdrive (exedir [0]-'A'+1, &dummy);
chdir (exedir);
_fullpath (temppath, path, 80);
strcpy (path, temppath);
_dos_setdrive (tempcwd [0]-'A'+1, &dummy);
chdir (tempcwd);
}
void combinepathfile (char *comb, char *path, char *fn)
{ // This function doesn't combine two paths... it just appends fn to path
int x = strlen (path);
strcpy (comb, path);
if (comb [x-1] != SLASH) {
comb [x] = SLASH;
x++;
}
strcpy (comb+x, fn);
}
void combinepaths (char *comb, char *path, char *offs)
{
char tempcwd [80], temppath [80];
unsigned dummy, originaldrive;
_dos_getdrive (&originaldrive); // Save current drive
path[0] = toupper(path[0]);
offs[0] = toupper(offs[0]);
if (offs[1] == ':')
_dos_setdrive (offs[0]-'A'+1, &dummy);
else if (path [1] == ':')
_dos_setdrive (path[0]-'A'+1, &dummy);
getcwd (tempcwd, 80); // save current directory
_fullpath (temppath, path, 80);
_dos_getdrive (&dummy);
if (dummy == temppath[0]-'A'+1)
chdir (path);
chdir (offs);
getcwd (comb, 80);
_dos_setdrive (tempcwd [0]-'A'+1, &dummy);
chdir (tempcwd); // restore current directory
_dos_setdrive (originaldrive, &dummy); // Restore current drive
}
#define ntohex(n) ((n) > 9 ? (n)+'A'-10 : (n)+'0')
#define ishexd(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z'))
#define hexton(c) ((c) >= 'A' ? (c)-'A'+10 : (c)-'0')
// ONLY WORKS ON UPPERCASE HEX!
int verifyspecformat (char *patchspec)
{ // Removes spaces...btw...and converts to uppercase.
// False=bad format, other=number of patches.
char *o_patchspec = patchspec;
int i, n;
strupr (patchspec);
debug0 ("Checking %s",patchspec);
while (*patchspec)
if (*patchspec == ' ')
for (i = 0; patchspec[i]; i++)
patchspec[i] = patchspec[i+1];
else
patchspec++;
patchspec = o_patchspec;
i = 0; n = 0;
for (;;) {
if (!((patchspec[i + 4] == '-') ^ (patchspec[i + 6] == '='))) {
debug0 ("Not game genie nor native format");
return false; // Must have a dash or equals, but not both
}
if (!ishexd(patchspec[i]) || !ishexd(patchspec[i+1]) || !ishexd(patchspec[i+2]) ||
!ishexd(patchspec[i+3]) || (!ishexd(patchspec[i+4]) && patchspec[i+4] != '-') ||
!ishexd(patchspec[i+5]) || (!ishexd(patchspec[i+6]) && patchspec[i+6] != '=') ||
!ishexd(patchspec[i+7]) || !ishexd(patchspec[i+8])) {
debug0 ("Digit problem in cheat");
return false; // Must all be hex digits
}
n++;
if (patchspec[i + 6] == '=' && ishexd(patchspec[i+9]) && ishexd(patchspec[i+10])) {
i += 2; // 2 More digits.
debug0 ("Word-sized cheat");
}
if (strlen (patchspec) - i < 10)
break;
if (patchspec[i+9] != '+') {
debug0 ("Multiple patches detected in cheat");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -