diff --git a/src/util/error.cpp b/src/util/error.cpp index 6250272f..343c6fa9 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -25,12 +25,12 @@ String Error::what() const { // ----------------------------------------------------------------------------- : Parse errors ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& error) - : start(pos), end(pos), line(line), filename(filename) - , ParseError(error) + : ParseError(error) + , start(pos), end(pos), line(line), filename(filename) {} ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& exp, const String& found) - : start(pos), end(pos + found.size()), line(line), filename(filename) - , ParseError(_("Expected '") + exp + _("' instead of '") + found + _("'")) + : ParseError(_("Expected '") + exp + _("' instead of '") + found + _("'")) + , start(pos), end(pos + found.size()), line(line), filename(filename) {} String ScriptParseError::what() const { return String(_("(")) << (int)start << _("): ") << Error::what(); @@ -61,18 +61,20 @@ void show_pending_errors(); void show_pending_warnings(); void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { - // Thread safety - wxCriticalSectionLocker lock(crit_error_handling); - // Check duplicates - if (!allow_duplicate) { - FOR_EACH(pe, previous_errors) { - if (e == pe) return; + { + // Thread safety + wxCriticalSectionLocker lock(crit_error_handling); + // Check duplicates + if (!allow_duplicate) { + FOR_EACH(pe, previous_errors) { + if (e == pe) return; + } + previous_errors.push_back(e); } - previous_errors.push_back(e); + // Only show errors in the main thread + if (!pending_errors.empty()) pending_errors += _("\n\n"); + pending_errors += e; } - // Only show errors in the main thread - if (!pending_errors.empty()) pending_errors += _("\n\n"); - pending_errors += e; // show messages if (now && wxThread::IsMain()) { show_pending_warnings(); // warnings are older, show them first @@ -85,11 +87,13 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) { } void handle_warning(const String& w, bool now) { - // Check duplicates - wxCriticalSectionLocker lock(crit_error_handling); - // Only show errors in the main thread - if (!pending_warnings.empty()) pending_warnings += _("\n\n"); - pending_warnings += w; + { + // Check duplicates + wxCriticalSectionLocker lock(crit_error_handling); + // Only show errors in the main thread + if (!pending_warnings.empty()) pending_warnings += _("\n\n"); + pending_warnings += w; + } // show messages if (now && wxThread::IsMain()) { show_pending_errors(); diff --git a/src/util/io/package_manager.cpp b/src/util/io/package_manager.cpp index 17ff7c1b..b1d1f556 100644 --- a/src/util/io/package_manager.cpp +++ b/src/util/io/package_manager.cpp @@ -37,50 +37,67 @@ PackageManager packages; void PackageManager::init() { // determine data directory - data_directory = wxStandardPaths::Get().GetDataDir(); + global_data_directory = wxStandardPaths::Get().GetDataDir(); + local_data_directory = wxStandardPaths::Get().GetUserDataDir(); // check if this is the actual data directory, especially during debugging, // the data may be higher up: // exe path = mse/build/debug/mse.exe // data path = mse/data - while (!wxDirExists(data_directory + _("/data"))) { - String d = data_directory; - data_directory = wxPathOnly(data_directory); - if (d == data_directory) { + while (!wxDirExists(global_data_directory + _("/data"))) { + String d = global_data_directory; + global_data_directory = wxPathOnly(global_data_directory); + if (d == global_data_directory) { // we are at the root -> 'data' not found anywhere in the path -> fatal error - throw Error(_("The MSE data files can not be found, there should be a directory called 'data' with these files. The expected directory to find it in was ") + wxStandardPaths::Get().GetDataDir()); + throw Error(_("The global MSE data files can not be found, there should be a directory called 'data' with these files. The expected directory to find it in was ") + wxStandardPaths::Get().GetDataDir()); } } - data_directory += _("/data"); + global_data_directory += _("/data"); + // It's not an error for the local directory not to exist. + local_data_directory += _("/data"); } PackagedP PackageManager::openAny(const String& name, bool just_header) { - wxFileName fn( - (wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString)) - + name); - fn.Normalize(); - String filename = fn.GetFullPath(); + // Attempt to load local data first. + String filename; + wxFileName* fn; + if (wxFileName(name).IsRelative()) { + fn = new wxFileName(local_data_directory + _("/") + name); + fn->Normalize(); + filename = fn->GetFullPath(); + if (!wxFileExists(filename) && !wxDirExists(filename)) { + delete fn; + fn = new wxFileName(global_data_directory + _("/") + name); + fn->Normalize(); + filename = fn->GetFullPath(); + } + } else { // Absolute filename + fn = new wxFileName(name); + fn->Normalize(); + filename = fn->GetFullPath(); + } + // Is this package already loaded? PackagedP& p = loaded_packages[filename]; - if (p) { - return p; - } else { + if (!p) { // load with the right type, based on extension - if (fn.GetExt() == _("mse-game")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-style")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-locale")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-include")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-symbol-font")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-export-template")) p = new_intrusive(); + if (fn->GetExt() == _("mse-game")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-style")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-locale")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-include")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-symbol-font")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-export-template")) p = new_intrusive(); else { - throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name); + throw PackageError(_("Unrecognized package type: '") + fn->GetExt() + _("'\nwhile trying to open: ") + name); } p->open(filename, just_header); - return p; } + delete fn; + return p; } String PackageManager::findFirst(const String& pattern) { - return wxFindFirstFile(data_directory + _("/") + pattern, 0); + String file = wxFindFirstFile(local_data_directory + _("/") + pattern, 0); + return file.IsEmpty() ? wxFindFirstFile(global_data_directory + _("/") + pattern, 0) : file; } InputStreamP PackageManager::openFileFromPackage(const String& name) { @@ -97,10 +114,13 @@ InputStreamP PackageManager::openFileFromPackage(const String& name) { } bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) { - String name = data_directory + _("/") + dep.package; + String name = local_data_directory + _("/") + dep.package; if (!wxFileExists(name) && !wxDirExists(name)) { - handle_warning(_ERROR_1_("package not found", dep.package),false); - return false; + name = global_data_directory + _("/") + dep.package; + if (!wxFileExists(name) && !wxDirExists(name)) { + handle_warning(_ERROR_1_("package not found", dep.package),false); + return false; + } } PackagedP package = openAny(dep.package, true); if (package->version < dep.version) { diff --git a/src/util/io/package_manager.hpp b/src/util/io/package_manager.hpp index ec8dae2a..7c39f083 100644 --- a/src/util/io/package_manager.hpp +++ b/src/util/io/package_manager.hpp @@ -34,9 +34,14 @@ class PackageManager { /// Open a package with the specified name (including extension) template intrusive_ptr open(const String& name) { - wxFileName fn(data_directory + _("/") + name); - fn.Normalize(); - String filename = fn.GetFullPath(); + wxFileName loc(local_data_directory + _("/") + name); + loc.Normalize(); + String filename = loc.GetFullPath(); + if (!wxFileExists(filename) && !wxDirExists(filename)) { + wxFileName glob(global_data_directory + _("/") + name); + glob.Normalize(); + filename = glob.GetFullPath(); + } // Is this package already loaded? PackagedP& p = loaded_packages[filename]; intrusive_ptr typedP = dynamic_pointer_cast(p); @@ -70,7 +75,8 @@ class PackageManager { private: map loaded_packages; - String data_directory; + String global_data_directory; + String local_data_directory; }; /// The global PackageManager instance