Cleaned up handling of various file paths throughtout the codebase.

Basically, directories are now guaranteed to always end in the path
separator.  Ensuring this makes certain sections of code work faster,
and guaranteeing it allows higher layers of code to not worry about it.

Added 'cfgdir' commandline argument, to specify the default directory
for Distella-like Stella-compatible config files.

Implemented 'loadconfig' debugger prompt command.  It's currently
working great with several test config files provided by Omega of
AtariAge.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2125 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-09-06 00:17:51 +00:00
parent 871d851e4d
commit 2d08d4e459
17 changed files with 198 additions and 74 deletions

View File

@ -1648,7 +1648,7 @@ GLuint FBSurfaceGL::genShader(ShaderType type)
// These shader files are stored in 'BASEDIR/shaders/'
char* buffer = NULL;
const string& filename =
myFB.myOSystem->baseDir() + BSPF_PATH_SEPARATOR + "shaders" +
myFB.myOSystem->baseDir() + "shaders" +
BSPF_PATH_SEPARATOR + fFile;
ifstream in(filename.c_str());
if(in && in.is_open())

View File

@ -26,9 +26,9 @@
#include "CartDebug.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
const Settings& settings)
CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
: DebuggerSystem(dbg, console),
myOSystem(osystem),
myRWPortAddress(0),
myLabelLength(5) // longest pre-defined label
{
@ -36,6 +36,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
addRamArea(0x80, 128, 0, 0);
// Add extended RAM
const RamAreaList& areas = console.cartridge().ramAreas();
for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i)
addRamArea(i->start, i->size, i->roffset, i->woffset);
@ -65,7 +66,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
// Add settings for Distella
DiStella::settings.gfx_format =
settings.getInt("gfxformat") == 16 ? kBASE_16 : kBASE_2;
myOSystem.settings().getInt("gfxformat") == 16 ? kBASE_16 : kBASE_2;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -346,7 +347,8 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end)
bool CartDebug::addDirective(CartDebug::DisasmType type,
uInt16 start, uInt16 end, int bank)
{
#define PRINT_TAG(d) \
cerr << (d.type == CartDebug::CODE ? "CODE" : \
@ -360,10 +362,13 @@ bool CartDebug::addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 en
PRINT_TAG((*d)); \
cerr << endl;
BankInfo& info = (myDebugger.cpuDebug().pc() & 0x1000) ?
myBankInfo[getBank()] : myBankInfo[myBankInfo.size()-1];
if(bank < 0) // Do we want the current bank or ZP RAM?
bank = (myDebugger.cpuDebug().pc() & 0x1000) ? getBank() : myBankInfo.size()-1;
bank = BSPF_min(bank, bankCount() - 1);
BankInfo& info = myBankInfo[bank];
DirectiveList& list = info.directiveList;
DirectiveTag tag;
tag.type = type;
tag.start = start;
@ -642,13 +647,118 @@ string CartDebug::loadSymbolFile(const string& f)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::loadConfigFile(const string& f)
string CartDebug::loadConfigFile(string file)
{
return "NOT YET IMPLEMENTED";
FilesystemNode node(file);
if(file == "") // Use config file based on ROM name
{
file = myOSystem.romFile();
string::size_type spos;
if((spos = file.find_last_of('.')) != string::npos )
file.replace(spos, file.size(), ".cfg");
else
file += ".cfg";
FilesystemNode usercfg(file);
if(usercfg.exists())
{
node = usercfg;
}
else // Use global config file based on properties cart name
{
const string& globalfile = myOSystem.cfgDir() +
myConsole.properties().get(Cartridge_Name) + ".cfg";
FilesystemNode globalcfg(globalfile);
if(globalcfg.exists())
node = globalcfg;
}
}
if(node.exists() && !node.isDirectory())
{
ifstream in(node.getPath().c_str());
if(!in.is_open())
return "Unable to read directives from " + node.getPath();
int currentbank = 0;
while(!in.eof())
{
// Skip leading space
int c = in.peek();
while(c == ' ' && c == '\t')
{
in.get();
c = in.peek();
}
string line;
c = in.peek();
if(c == '/') // Comment, swallow line and continue
{
getline(in, line);
continue;
}
else if(c == '[')
{
in.get();
getline(in, line, ']');
stringstream buf(line);
buf >> currentbank;
}
else // Should be commands from this point on
{
getline(in, line);
stringstream buf;
buf << line;
string directive;
uInt16 start = 0, end = 0;
buf >> directive;
if(BSPF_startsWithIgnoreCase(directive, "ORG"))
{
buf >> hex >> start;
// TODO - figure out what to do with this
cerr << "ignoring directive: "
<< directive << " " << HEX4 << start << endl;
}
else if(BSPF_startsWithIgnoreCase(directive, "BLOCK"))
{
buf >> hex >> start;
buf >> hex >> end;
// TODO - add directive for this
cerr << "ignoring directive: " << directive << " "
<< HEX4 << start << " " << HEX4 << end << endl;
}
else if(BSPF_startsWithIgnoreCase(directive, "CODE"))
{
buf >> hex >> start;
buf >> hex >> end;
addDirective(CartDebug::CODE, start, end, currentbank);
}
else if(BSPF_startsWithIgnoreCase(directive, "DATA"))
{
buf >> hex >> start;
buf >> hex >> end;
addDirective(CartDebug::DATA, start, end, currentbank);
}
else if(BSPF_startsWithIgnoreCase(directive, "GFX"))
{
buf >> hex >> start;
buf >> hex >> end;
addDirective(CartDebug::GFX, start, end, currentbank);
}
}
}
in.close();
return "loaded " + node.getRelativePath() + " OK";
}
else
return DebuggerParser::red("config file not found");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveConfigFile(const string& f)
string CartDebug::saveConfigFile(string file)
{
return "NOT YET IMPLEMENTED";
}
@ -676,7 +786,7 @@ string CartDebug::listConfig(int bank)
<< (i->type == CartDebug::CODE ? "CODE" :
i->type == CartDebug::DATA ? "DATA" :
"GFX")
<< " " << hex << i->start << " " << hex << i->end << endl;
<< " " << HEX4 << i->start << " " << HEX4 << i->end << endl;
}
getBankDirectives(buf, info);
}

View File

@ -74,8 +74,7 @@ class CartDebug : public DebuggerSystem
} Disassembly;
public:
CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
const Settings& settings);
CartDebug(Debugger& dbg, Console& console, const OSystem& osystem);
virtual ~CartDebug();
const DebuggerState& getState();
@ -161,10 +160,12 @@ class CartDebug : public DebuggerSystem
@param type Currently, CODE/DATA/GFX are supported
@param start The start address (inclusive) to mark with the given type
@param end The end address (inclusive) to mark with the given type
@param bank Bank to which these directive apply (0 indicated current bank)
@return True if directive was added, else false if it was removed
*/
bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end);
bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end,
int bank = -1);
// The following are convenience methods that query the cartridge object
// for the desired information.
@ -216,8 +217,8 @@ class CartDebug : public DebuggerSystem
/**
Load/save Distella config file (Distella directives)
*/
string loadConfigFile(const string& file = "");
string saveConfigFile(const string& file = "");
string loadConfigFile(string file = "");
string saveConfigFile(string file = "");
/**
Show Distella directives (both set by the user and determined by Distella)
@ -274,6 +275,8 @@ class CartDebug : public DebuggerSystem
int extractValue(const char* c) const;
private:
const OSystem& myOSystem;
CartState myState;
CartState myOldState;

View File

@ -211,10 +211,9 @@ void Debugger::setConsole(Console* console)
delete myCartDebug;
// Register any RAM areas in the Cartridge
// Zero-page RAM is automatically recognized by CartDebug
myCartDebug = new CartDebug(*this, *myConsole, myConsole->cartridge().ramAreas(),
myOSystem->settings());
cerr << myOSystem->romFile() << endl;
myCartDebug = new CartDebug(*this, *myConsole, *myOSystem);
myCartDebug->loadSymbolFile(myOSystem->romFile());
myCartDebug->loadConfigFile();
delete myRiotDebug;
myRiotDebug = new RiotDebug(*this, *myConsole);
@ -256,8 +255,7 @@ string Debugger::autoExec()
ostringstream buf;
// autoexec.stella is always run
FilesystemNode autoexec(myOSystem->baseDir() + BSPF_PATH_SEPARATOR +
"autoexec.stella");
FilesystemNode autoexec(myOSystem->baseDir() + "autoexec.stella");
buf << "autoExec():" << endl
<< myParser->exec(autoexec) << endl;

View File

@ -1024,7 +1024,6 @@ void DebuggerParser::executeJump()
((address & 0xFFF) >= 0))
address--;
cerr << "address " << dec << address << " on line " << dec << line << endl;
if(line >= 0 && address >= 0)
{
debugger->myRom->scrollTo(line);

View File

@ -673,16 +673,14 @@ void Console::setControllers(const string& rommd5)
}
else if(right == "ATARIVOX")
{
const string& eepromfile = myOSystem->eepromDir() + BSPF_PATH_SEPARATOR +
"atarivox_eeprom.dat";
const string& eepromfile = myOSystem->eepromDir() + "atarivox_eeprom.dat";
myControllers[rightPort] = new AtariVox(Controller::Right, *myEvent,
*mySystem, myOSystem->serialPort(),
myOSystem->settings().getString("avoxport"), eepromfile);
}
else if(right == "SAVEKEY")
{
const string& eepromfile = myOSystem->eepromDir() + BSPF_PATH_SEPARATOR +
"savekey_eeprom.dat";
const string& eepromfile = myOSystem->eepromDir() + "savekey_eeprom.dat";
myControllers[rightPort] = new SaveKey(Controller::Right, *myEvent, *mySystem,
eepromfile);
}

View File

@ -572,7 +572,7 @@ void EventHandler::poll(uInt64 time)
case SDLK_s: // Ctrl-s saves properties to a file
{
string filename = myOSystem->baseDir() + BSPF_PATH_SEPARATOR +
string filename = myOSystem->baseDir() +
myOSystem->console().properties().get(Cartridge_Name) + ".pro";
ofstream out(filename.c_str(), ios::out);
if(out)
@ -1992,13 +1992,9 @@ void EventHandler::takeSnapshot(uInt32 number)
{
// Figure out the correct snapshot name
string filename;
string sspath = myOSystem->snapshotDir();
bool showmessage = number == 0;
if(sspath.length() > 0)
if(sspath.substr(sspath.length()-1) != BSPF_PATH_SEPARATOR)
sspath += BSPF_PATH_SEPARATOR;
sspath += myOSystem->console().properties().get(Cartridge_Name);
string sspath = myOSystem->snapshotDir() +
myOSystem->console().properties().get(Cartridge_Name);
// Check whether we want multiple snapshots created
if(number > 0)

View File

@ -311,44 +311,28 @@ void OSystem::setConfigPaths()
FilesystemNode node;
string s;
s = mySettings->getString("statedir");
if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "state";
node = FilesystemNode(s);
myStateDir = node.getPath();
mySettings->setString("statedir", node.getRelativePath());
if(!node.isDirectory())
AbstractFilesystemNode::makeDir(myStateDir);
validatePath("statedir", "state", myStateDir);
s = mySettings->getString("ssdir");
if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "snapshots";
node = FilesystemNode(s);
mySnapshotDir = node.getPath();
mySettings->setString("ssdir", node.getRelativePath());
if(!node.isDirectory())
AbstractFilesystemNode::makeDir(mySnapshotDir);
validatePath("ssdir", "snapshots", mySnapshotDir);
s = mySettings->getString("eepromdir");
if(s == "") s = myBaseDir;
node = FilesystemNode(s);
myEEPROMDir = node.getPath();
mySettings->setString("eepromdir", node.getRelativePath());
if(!node.isDirectory())
AbstractFilesystemNode::makeDir(myEEPROMDir);
validatePath("eepromdir", "", myEEPROMDir);
validatePath("cfgdir", "cfg", myCfgDir);
s = mySettings->getString("cheatfile");
if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.cht";
if(s == "") s = myBaseDir + "stella.cht";
node = FilesystemNode(s);
myCheatFile = node.getPath();
mySettings->setString("cheatfile", node.getRelativePath());
s = mySettings->getString("palettefile");
if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pal";
if(s == "") s = myBaseDir + "stella.pal";
node = FilesystemNode(s);
myPaletteFile = node.getPath();
mySettings->setString("palettefile", node.getRelativePath());
s = mySettings->getString("propsfile");
if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pro";
if(s == "") s = myBaseDir + "stella.pro";
node = FilesystemNode(s);
myPropertiesFile = node.getPath();
mySettings->setString("propsfile", node.getRelativePath());
@ -369,7 +353,10 @@ void OSystem::setBaseDir(const string& basedir)
FilesystemNode node(basedir);
myBaseDir = node.getPath();
if(!node.isDirectory())
{
AbstractFilesystemNode::makeDir(myBaseDir);
myBaseDir = FilesystemNode(node.getPath()).getPath();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -866,6 +853,22 @@ void OSystem::resetLoopTiming()
myTimingInfo.totalFrames = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::validatePath(const string& setting, const string& partialpath,
string& fullpath)
{
const string& s = mySettings->getString(setting) != "" ?
mySettings->getString(setting) : myBaseDir + partialpath;
FilesystemNode node = FilesystemNode(s);
if(!node.isDirectory())
{
AbstractFilesystemNode::makeDir(s);
node = FilesystemNode(node.getPath());
}
fullpath = node.getPath();
mySettings->setString(setting, node.getRelativePath());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setDefaultJoymap(Event::Type event, EventMode mode)
{

View File

@ -276,6 +276,11 @@ class OSystem
*/
const string& eepromDir() const { return myEEPROMDir; }
/**
Return the full/complete directory name for storing Distella cfg files.
*/
const string& cfgDir() const { return myCfgDir; }
/**
This method should be called to get the full path of the cheat file.
@ -540,6 +545,7 @@ class OSystem
string myStateDir;
string mySnapshotDir;
string myEEPROMDir;
string myCfgDir;
string myCheatFile;
string myConfigFile;
@ -641,6 +647,14 @@ class OSystem
*/
void resetLoopTiming();
/**
Validate the directory name, and create it if necessary.
Also, update the settings with the new name. For now, validation
means that the path must always end with the appropriate separator.
*/
void validatePath(const string& setting, const string& partialpath,
string& fullpath);
// Copy constructor isn't supported by this class so make it private
OSystem(const OSystem&);

View File

@ -102,6 +102,7 @@ Settings::Settings(OSystem* osystem)
setInternal("palettefile", "");
setInternal("propsfile", "");
setInternal("eepromdir", "");
setInternal("cfgdir", "");
// ROM browser options
setInternal("uselauncher", "true");
@ -418,6 +419,7 @@ void Settings::usage()
<< " -palettefile <file> Full pathname of user-defined palette file\n"
<< " -propsfile <file> Full pathname of ROM properties file\n"
<< " -eepromdir <dir> Directory in which to save EEPROM files\n"
<< " -cfgdir <dir> Directory in which to save Distella config files\n"
<< " -avoxport <name> The name of the serial port where an AtariVox is connected\n"
<< " -maxres <WxH> Used by developers to force the maximum size of the application window\n"
<< " -holdreset Start the emulator with the Game Reset switch held down\n"
@ -433,6 +435,7 @@ void Settings::usage()
<< endl
<< " -resolvedata <never| Set automatic code vs. data determination in the disassembler\n"
<< " always|auto>\n"
<< " -gfxformat <2|16> Set base to use for displaying GFX sections in the disassembler\n"
<< " -debuggerres <WxH> The resolution to use in debugger mode\n"
<< " -break <address> Set a breakpoint at 'address'\n"
<< " -debug Start in debugger mode\n"

View File

@ -61,7 +61,7 @@ bool StateManager::toggleRecordMode()
{
myActiveMode = kOffMode;
string moviefile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
string moviefile = /*myOSystem->baseDir() +*/ "test.inp";
if(myMovieWriter.isOpen())
myMovieWriter.close();
if(!myMovieWriter.open(moviefile))
@ -109,7 +109,7 @@ bool StateManager::toggleRewindMode()
{
myActiveMode = kOffMode;
string moviefile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
string moviefile = /*myOSystem->baseDir() + */ "test.inp";
if(myMovieReader.isOpen())
myMovieReader.close();
if(!myMovieReader.open(moviefile))
@ -178,7 +178,7 @@ void StateManager::loadState(int slot)
if(slot < 0) slot = myCurrentSlot;
ostringstream buf;
buf << myOSystem->stateDir() << BSPF_PATH_SEPARATOR
buf << myOSystem->stateDir()
<< myOSystem->console().properties().get(Cartridge_Name)
<< ".st" << slot;
@ -222,7 +222,7 @@ void StateManager::saveState(int slot)
if(slot < 0) slot = myCurrentSlot;
ostringstream buf;
buf << myOSystem->stateDir() << BSPF_PATH_SEPARATOR
buf << myOSystem->stateDir()
<< myOSystem->console().properties().get(Cartridge_Name)
<< ".st" << slot;

View File

@ -222,9 +222,7 @@ void FileSnapDialog::saveConfig()
void FileSnapDialog::setDefaults()
{
FilesystemNode node;
string basedir = instance().baseDir();
if(basedir.compare(basedir.length()-1, 1, BSPF_PATH_SEPARATOR, 0, 1) != 0)
basedir.append(BSPF_PATH_SEPARATOR);
const string& basedir = instance().baseDir();
node = FilesystemNode("~");
myRomPath->setEditString(node.getRelativePath());

View File

@ -147,11 +147,7 @@ void RomAuditDialog::auditRoms()
// Only rename the file if we found a valid properties entry
if(name != "" && name != files[idx].getDisplayName())
{
// Check for terminating separator
string newfile = auditPath;
if(newfile.find_last_of(BSPF_PATH_SEPARATOR) != newfile.length()-1)
newfile += BSPF_PATH_SEPARATOR;
newfile += name + "." + extension;
const string& newfile = node.getPath() + name + "." + extension;
if(files[idx].getPath() != newfile)
if(AbstractFilesystemNode::renameFile(files[idx].getPath(), newfile))

View File

@ -109,7 +109,7 @@ void RomInfoWidget::parseProperties()
myRomInfo.clear();
// Get a valid filename representing a snapshot file for this rom
const string& filename = instance().snapshotDir() + BSPF_PATH_SEPARATOR +
const string& filename = instance().snapshotDir() +
myProperties.get(Cartridge_Name) + ".png";
// Read the PNG file

View File

@ -161,7 +161,13 @@ POSIXFilesystemNode::POSIXFilesystemNode(const string& p, bool verify)
_displayName = lastPathComponent(_path);
if (verify)
{
setFlags();
// Add a trailing slash, if necessary
if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '/')
_path += '/';
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -278,7 +278,7 @@ WindowsFilesystemNode::WindowsFilesystemNode(const string& p)
_isDirectory = ((fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0);
_isValid = true;
// Add a trailing slash, if necessary.
// Add a trailing backslash, if necessary
if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '\\')
_path += '\\';
}