Files
scummvm-cursorfix/engines/bagel/spacebar/boflib/options.cpp
2026-02-02 04:50:13 +01:00

362 lines
8.8 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/config-manager.h"
#include "common/file.h"
#include "bagel/spacebar/boflib/options.h"
#include "bagel/boflib/misc.h"
#include "bagel/boflib/log.h"
#include "bagel/boflib/string_functions.h"
namespace Bagel {
namespace SpaceBar {
COption::COption(const char *pszInit) {
_szBuf[0] = '\0';
if (pszInit != nullptr) {
assert(strlen(pszInit) < MAX_OPTION_LEN);
Common::strcpy_s(_szBuf, pszInit);
}
}
CBofOptions::CBofOptions(const char *pszOptionFile) {
_szFileName[0] = '\0';
_pOptionList = nullptr;
_bDirty = false;
if (pszOptionFile != nullptr) {
loadOptionFile(pszOptionFile);
}
}
CBofOptions::~CBofOptions() {
assert(isValidObject(this));
release();
_szFileName[0] = '\0';
}
ErrorCode CBofOptions::loadOptionFile(const char *pszOptionFile) {
assert(isValidObject(this));
assert(pszOptionFile != nullptr);
assert(*pszOptionFile != '\0');
assert(strlen(pszOptionFile) < MAX_FNAME);
release();
Common::strcpy_s(_szFileName, pszOptionFile);
return load();
}
ErrorCode CBofOptions::load() {
assert(isValidObject(this));
// Assume no error
ErrorCode errorCode = ERR_NONE;
// Free any previous option info
release();
Common::File f;
if (Common::File::exists(_szFileName) && f.open(_szFileName)) {
char szBuf[MAX_OPTION_LEN];
assert(_pOptionList == nullptr);
while (readLine(&f, szBuf)) {
COption *pNewOption = new COption(szBuf);
if (_pOptionList != nullptr) {
_pOptionList->addToTail(pNewOption);
} else {
_pOptionList = pNewOption;
}
}
if (_pOptionList != nullptr) {
// _pOptionList must always be the head of the list!
assert(_pOptionList == _pOptionList->getHead());
}
f.close();
} else {
errorCode = ERR_FOPEN;
}
return errorCode;
}
void CBofOptions::release() {
assert(isValidObject(this));
commit();
// Release each item in the list
while (_pOptionList != nullptr) {
COption *pNextItem = (COption *)_pOptionList->getNext();
delete _pOptionList;
_pOptionList = pNextItem;
}
}
ErrorCode CBofOptions::commit() {
assert(isValidObject(this));
ErrorCode errorCode = ERR_NONE;
if ((_pOptionList != nullptr) && _bDirty) {
// _pOptionList must always be the head of the list!
assert(_pOptionList == _pOptionList->getHead());
warning("TODO: Look into refactoring options to ConfMan if needed");
}
return errorCode;
}
ErrorCode CBofOptions::writeSetting(const char *pszSection, const char *pszVar, const char *pszNewValue) {
// Can't access nullptr pointers
assert(pszSection != nullptr);
assert(pszVar != nullptr);
assert(pszNewValue != nullptr);
char szValueBuf[MAX_OPTION_LEN];
// Assume no error
ErrorCode errorCode = ERR_NONE;
// Indicate that the options file needs to be updated
_bDirty = true;
Common::sprintf_s(szValueBuf, "%s=%s", pszVar, pszNewValue);
// Find this option based on it's section
COption *pOption = findOption(pszSection, pszVar);
if (pOption != nullptr) {
// Update option with new value
Common::strcpy_s(pOption->_szBuf, szValueBuf);
} else {
// Did not find option (or possibly also did not find section)
// If this section is not in the file
COption *pSection = findSection(pszSection);
if (pSection == nullptr) {
char szSectionBuf[MAX_OPTION_LEN];
// Then create a new section
Common::sprintf_s(szSectionBuf, "[%s]", pszSection);
pSection = new COption(szSectionBuf);
if (_pOptionList != nullptr) {
_pOptionList->addToTail(pSection);
} else {
_pOptionList = pSection;
}
}
// Add this option to the specified section
pOption = new COption(szValueBuf);
pSection->Insert(pOption);
}
return errorCode;
}
ErrorCode CBofOptions::writeSetting(const char *pszSection, const char *pszVar, int nNewValue) {
// Can't access nullptr pointers
assert(pszSection != nullptr);
assert(pszVar != nullptr);
char szBuf[20];
Common::sprintf_s(szBuf, "%d", nNewValue);
ErrorCode errorCode = writeSetting(pszSection, pszVar, szBuf);
return errorCode;
}
ErrorCode CBofOptions::readSetting(const char *section, const char *option, char *stringValue, const char *defaultValue, uint32 maxLen) {
// Can't access nullptr pointers
assert(section != nullptr);
assert(option != nullptr);
assert(stringValue != nullptr);
assert(defaultValue != nullptr);
// If ConfMan has a key of a given name, no matter the section,
// than it takes precedence over any INI file value
if (ConfMan.hasKey(option)) {
Common::String str = ConfMan.get(option);
Common::strcpy_s(stringValue, maxLen, str.c_str());
return ERR_NONE;
}
char szBuf[MAX_OPTION_LEN];
// Assume no error
ErrorCode errorCode = ERR_NONE;
// Assume we will need to use the default setting
Common::strcpy_s(stringValue, maxLen, defaultValue);
// Try to find this option
COption *pOption = findOption(section, option);
if (pOption != nullptr) {
assert(strlen(pOption->_szBuf) < MAX_OPTION_LEN);
Common::strcpy_s(szBuf, pOption->_szBuf);
// Strip out any comments
strreplaceChar(szBuf, ';', '\0');
// Find 1st equal sign
char *p = strchr(szBuf, '=');
// Error in .INI file if we can't find the equal sign
if (p != nullptr) {
p++;
if (strlen(p) > 0)
Common::strcpy_s(stringValue, maxLen, p);
} else {
logError(buildString("Error in %s, section: %s, entry: %s", _szFileName, section, option));
errorCode = ERR_FTYPE;
}
}
return errorCode;
}
ErrorCode CBofOptions::readSetting(const char *section, const char *option, int *intValue, int defaultValue) {
assert(section != nullptr);
assert(option != nullptr);
assert(intValue != nullptr);
// If ConfMan has a key of a given name, no matter the section,
// than it takes precedence over any INI file value
if (ConfMan.hasKey(option)) {
*intValue = ConfMan.getInt(option);
return ERR_NONE;
}
char szDefault[20], szBuf[20];
Common::sprintf_s(szDefault, "%d", defaultValue);
ErrorCode errorCode = readSetting(section, option, szBuf, szDefault, 20);
*intValue = atoi(szBuf);
return errorCode;
}
ErrorCode CBofOptions::readSetting(const char *section, const char *option, bool *boolValue, bool defaultValue) {
assert(section != nullptr);
assert(option != nullptr);
assert(boolValue != nullptr);
// If ConfMan has a key of a given name, no matter the section,
// than it takes precedence over any INI file value
if (ConfMan.hasKey(option)) {
*boolValue = ConfMan.getBool(option);
return ERR_NONE;
}
int v;
ErrorCode errorCode = readSetting(section, option, &v, defaultValue);
*boolValue = v != 0;
return errorCode;
}
COption *CBofOptions::findSection(const char *pszSection) {
assert(isValidObject(this));
assert(pszSection != nullptr);
assert(*pszSection != '\0');
char szSectionBuf[MAX_OPTION_LEN];
Common::sprintf_s(szSectionBuf, "[%s]", pszSection);
int nLength = strlen(szSectionBuf);
COption *pOption = _pOptionList;
while (pOption != nullptr) {
if (!scumm_strnicmp(pOption->_szBuf, szSectionBuf, nLength)) {
break;
}
pOption = (COption *)pOption->getNext();
}
return pOption;
}
COption *CBofOptions::findOption(const char *pszSection, const char *pszVar) {
assert(isValidObject(this));
assert(pszSection != nullptr);
assert(pszVar != nullptr);
assert(*pszSection != '\0');
assert(*pszVar != '\0');
// Assume we won't find the option
COption *pFound = nullptr;
int nLength = strlen(pszVar);
COption *pStart = findSection(pszSection);
if (pStart != nullptr) {
COption *pOption = (COption *)pStart->getNext();
while (pOption != nullptr) {
if (pOption->_szBuf[0] == '[') {
// this option was not found
pFound = nullptr;
break;
}
if (!scumm_strnicmp(pOption->_szBuf, pszVar, nLength)) {
pFound = pOption;
break;
}
pOption = (COption *)pOption->getNext();
}
}
return pFound;
}
bool CBofOptions::readLine(Common::SeekableReadStream *pFile, char *pszBuf) {
assert(pFile != nullptr);
assert(pszBuf != nullptr);
if (pFile->eos())
return false;
Common::String line = pFile->readLine();
Common::strcpy_s(pszBuf, 256, line.c_str());
return true;
}
} // namespace SpaceBar
} // namespace Bagel