/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2018 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include #include #include namespace { constexpr const char* BasePathToken = "${BASE}"; // We can't use ${SCRIPTS} here as that hasn't been defined by this point constexpr const char* InitialConfigHelper = "${BASE}/scripts/configuration_helper.lua"; // Variable names for the openspace.cfg file // These are also used in the _doc include file constexpr const char* KeySGCTConfig = "SGCTConfig"; constexpr const char* KeyAsset = "Asset"; constexpr const char* KeyGlobalCustomizationScripts = "GlobalCustomizationScripts"; constexpr const char* KeyPaths = "Paths"; constexpr const char* KeyFonts = "Fonts"; constexpr const char* KeyLogging = "Logging"; constexpr const char* KeyLogDir = "LogDir"; constexpr const char* KeyPerformancePrefix = "PerformancePrefix"; constexpr const char* KeyLogLevel = "LogLevel"; constexpr const char* KeyImmediateFlush = "ImmediateFlush"; constexpr const char* KeyLogs = "Logs"; constexpr const char* KeyCapabilitiesVerbosity = "CapabilitiesVerbosity"; constexpr const char* KeyLuaDocumentation = "LuaDocumentation"; constexpr const char* KeyPropertyDocumentation = "PropertyDocumentation"; constexpr const char* KeyScriptLog = "ScriptLog"; constexpr const char* KeyKeyboardShortcuts = "KeyboardShortcuts"; constexpr const char* KeyDocumentation = "Documentation"; constexpr const char* KeyFactoryDocumentation = "FactoryDocumentation"; constexpr const char* KeyRequireSocketAuthentication = "RequireSocketAuthentication"; constexpr const char* KeyServerPasskey = "ServerPasskey"; constexpr const char* KeyClientAddressWhitelist = "ClientAddressWhitelist"; constexpr const char* KeyLicenseDocumentation = "LicenseDocumentation"; constexpr const char* KeyShutdownCountdown = "ShutdownCountdown"; constexpr const char* KeyPerSceneCache = "PerSceneCache"; constexpr const char* KeyOnScreenTextScaling = "OnScreenTextScaling"; constexpr const char* KeyRenderingMethod = "RenderingMethod"; constexpr const char* KeyDisableRenderingOnMaster = "DisableRenderingOnMaster"; constexpr const char* KeyDisableSceneOnMaster = "DisableSceneOnMaster"; constexpr const char* KeyScreenshotUseDate = "ScreenshotUseDate"; constexpr const char* KeyHttpProxy = "HttpProxy"; constexpr const char* KeyAddress = "Address"; constexpr const char* KeyPort = "Port"; constexpr const char* KeyAuthentication = "Authentication"; constexpr const char* KeyUser = "User"; constexpr const char* KeyPassword = "Password"; constexpr const char* KeyOpenGLDebugContext = "OpenGLDebugContext"; constexpr const char* KeyActivate = "Activate"; constexpr const char* KeySynchronous = "Synchronous"; constexpr const char* KeyFilterIdentifier = "FilterIdentifier"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeySource = "Source"; constexpr const char* KeyType = "Type"; constexpr const char* KeyFilterSeverity = "FilterSeverity"; constexpr const char* KeyCheckOpenGLState = "CheckOpenGLState"; constexpr const char* KeyLogEachOpenGLCall = "LogEachOpenGLCall"; constexpr const char* KeyUseMultithreadedInitialization = "UseMultithreadedInitialization"; constexpr const char* KeyLoadingScreen = "LoadingScreen"; constexpr const char* KeyShowMessage = "ShowMessage"; constexpr const char* KeyShowNodeNames = "ShowNodeNames"; constexpr const char* KeyShowProgressbar = "ShowProgressbar"; constexpr const char* KeyModuleConfigurations = "ModuleConfigurations"; } // namespace #include "configuration_doc.inl" namespace openspace { template void getValue(ghoul::lua::LuaState& L, const char* name, T& value) { auto it = std::find_if( Configuration::Documentation.entries.begin(), Configuration::Documentation.entries.end(), [name](const documentation::DocumentationEntry& e) { return e.key == name; } ); bool isOptional = it != Configuration::Documentation.entries.end() ? it->optional : true; lua_getglobal(L, name); if (isOptional && lua_isnil(L, -1)) { return; } if (!isOptional && lua_isnil(L, -1)) { documentation::TestResult testResult = { false, { { name, documentation::TestResult::Offense::Reason::MissingKey} }, {} }; throw documentation::SpecificationError(std::move(testResult), "Configuration"); } // NOLINTNEXTLINE if constexpr (std::is_same_v>) { ghoul::Dictionary d = ghoul::lua::value(L); std::vector res; for (size_t i = 1; i <= d.size(); ++i) { res.push_back(d.value(std::to_string(i))); } value = res; } // NOLINTNEXTLINE else if constexpr (std::is_same_v>) { ghoul::Dictionary d = ghoul::lua::value(L); std::map res; for (size_t i = 0; i < d.size(); ++i) { std::string key = d.keys()[i]; std::string v = d.value(key); res[std::move(key)] = std::move(v); } value = res; } // NOLINTNEXTLINE else if constexpr (std::is_same_v>) { ghoul::Dictionary d = ghoul::lua::value(L); std::map res; for (size_t i = 0; i < d.size(); ++i) { std::string key = d.keys()[i]; ghoul::Dictionary v = d.value(key); res[std::move(key)] = std::move(v); } value = res; } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { Configuration::Logging& v = static_cast(value); ghoul::Dictionary d = ghoul::lua::value(L); d.getValue(KeyLogLevel, v.level); d.getValue(KeyLogDir, v.directory); d.getValue(KeyPerformancePrefix, v.performancePrefix); d.getValue(KeyImmediateFlush, v.forceImmediateFlush); d.getValue(KeyCapabilitiesVerbosity, v.capabilitiesVerbosity); if (d.hasKeyAndValue(KeyLogs)) { ghoul::Dictionary l = d.value(KeyLogs); std::vector res; for (size_t i = 1; i <= l.size(); ++i) { res.push_back(l.value(std::to_string(i))); } v.logs = res; } } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { Configuration::DocumentationInfo& v = static_cast(value); ghoul::Dictionary d = ghoul::lua::value(L); d.getValue(KeyLuaDocumentation, v.lua); d.getValue(KeyPropertyDocumentation, v.property); d.getValue("ScenePropertyDocumentation", v.sceneProperty); d.getValue(KeyKeyboardShortcuts, v.keyboard); d.getValue(KeyDocumentation, v.documentation); d.getValue(KeyFactoryDocumentation, v.factory); d.getValue(KeyLicenseDocumentation, v.license); } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { Configuration::LoadingScreen& v = static_cast(value); ghoul::Dictionary d = ghoul::lua::value(L); d.getValue(KeyShowMessage, v.isShowingMessages); d.getValue(KeyShowNodeNames, v.isShowingNodeNames); d.getValue(KeyShowProgressbar, v.isShowingProgressbar); } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { Configuration::OpenGLDebugContext& v = static_cast(value); ghoul::Dictionary d = ghoul::lua::value(L); d.getValue(KeyActivate, v.isActive); d.getValue(KeySynchronous, v.isSynchronous); if (d.hasKeyAndValue(KeyFilterIdentifier)) { ghoul::Dictionary f = d.value(KeyFilterIdentifier); std::vector res; for (size_t i = 1; i <= f.size(); ++i) { Configuration::OpenGLDebugContext::IdentifierFilter filter; ghoul::Dictionary fi = f.value(std::to_string(i)); double id = static_cast(filter.identifier); fi.getValue(KeyIdentifier, id); filter.identifier = static_cast(id); fi.getValue(KeySource, filter.source); fi.getValue(KeyType, filter.type); res.push_back(filter); } v.identifierFilters = res; } if (d.hasKeyAndValue(KeyFilterSeverity)) { ghoul::Dictionary f = d.value(KeyFilterSeverity); std::vector res; for (size_t i = 1; i <= f.size(); ++i) { res.push_back(f.value(std::to_string(i))); } v.severityFilters = res; } } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { Configuration::HTTPProxy& v = static_cast(value); ghoul::Dictionary d = ghoul::lua::value(L); d.getValue(KeyActivate, v.usingHttpProxy); d.getValue(KeyAddress, v.address); double p = static_cast(v.port); d.getValue(KeyPort, p); v.port = static_cast(p); d.getValue(KeyAuthentication, v.authentication); d.getValue(KeyUser, v.user); d.getValue(KeyPassword, v.password); } else { value = ghoul::lua::value(L); } } void parseLuaState(Configuration& configuration) { using namespace ghoul::lua; // Shorten the rest of this function Configuration& c = configuration; LuaState& s = c.state; getValue(s, KeySGCTConfig, c.windowConfiguration); getValue(s, KeyAsset, c.asset); getValue(s, KeyGlobalCustomizationScripts, c.globalCustomizationScripts); getValue(s, KeyPaths, c.pathTokens); getValue(s, KeyFonts, c.fonts); getValue(s, KeyScriptLog, c.scriptLog); getValue(s, KeyUseMultithreadedInitialization, c.useMultithreadedInitialization); getValue(s, KeyCheckOpenGLState, c.isCheckingOpenGLState); getValue(s, KeyLogEachOpenGLCall, c.isLoggingOpenGLCalls); getValue(s, KeyShutdownCountdown, c.shutdownCountdown); getValue(s, KeyScreenshotUseDate, c.shouldUseScreenshotDate); getValue(s, KeyOnScreenTextScaling, c.onScreenTextScaling); getValue(s, KeyPerSceneCache, c.usePerSceneCache); getValue(s, KeyDisableRenderingOnMaster, c.isRenderingOnMasterDisabled); getValue(s, KeyDisableSceneOnMaster, c.isSceneTranslationOnMasterDisabled); getValue(s, KeyRenderingMethod, c.renderingMethod); getValue(s, KeyServerPasskey, c.serverPasskey); getValue(s, KeyRequireSocketAuthentication, c.doesRequireSocketAuthentication); getValue(s, KeyClientAddressWhitelist, c.clientAddressWhitelist); getValue(s, "WebHelperLocation", c.webHelperLocation); getValue(s, "CefWebGuiUrl", c.cefWebGuiUrl); getValue(s, KeyLogging, c.logging); getValue(s, KeyDocumentation, c.documentation); getValue(s, KeyLoadingScreen, c.loadingScreen); getValue(s, KeyModuleConfigurations, c.moduleConfigurations); getValue(s, KeyOpenGLDebugContext, c.openGLDebugContext); getValue(s, KeyHttpProxy, c.httpProxy); } std::string findConfiguration(const std::string& filename) { using ghoul::filesystem::Directory; Directory directory = FileSys.currentDirectory(); while (true) { std::string fullPath = FileSys.pathByAppendingComponent( directory, filename ); if (FileSys.fileExists(fullPath)) { // We have found the configuration file and can bail out return fullPath; } // Otherwise, we traverse the directory tree up Directory nextDirectory = directory.parentDirectory( ghoul::filesystem::Directory::AbsolutePath::Yes ); if (directory.path() == nextDirectory.path()) { // We have reached the root of the file system and did not find the file throw ghoul::RuntimeError( "Could not find configuration file '" + filename + "'", "ConfigurationManager" ); } directory = nextDirectory; } } Configuration loadConfigurationFromFile(const std::string& filename) { ghoul_assert(!filename.empty(), "Filename must not be empty"); ghoul_assert(FileSys.fileExists(filename), "File must exist"); Configuration result; // Register the base path as the directory where 'filename' lives std::string basePath = ghoul::filesystem::File(filename).directoryName(); FileSys.registerPathToken(BasePathToken, basePath); // If there is an initial config helper file, load it into the state if (FileSys.fileExists(absPath(InitialConfigHelper))) { ghoul::lua::runScriptFile(result.state, absPath(InitialConfigHelper)); } // Load the configuration file into the state ghoul::lua::runScriptFile(result.state, filename); parseLuaState(result); return result; } } // namespace openspace