2012-01-21 00:14:35 +00:00
# include "configurationmanager.hpp"
2022-06-08 21:25:50 +00:00
# include <fstream>
2018-08-14 15:42:41 +00:00
# include <components/debug/debuglog.hpp>
2021-10-06 23:39:23 +00:00
# include <components/files/configfileparser.hpp>
2020-10-23 00:41:28 +00:00
# include <components/fallback/validate.hpp>
2022-09-11 01:26:06 +00:00
# include <components/misc/strings/conversion.hpp>
2016-07-26 23:58:31 +00:00
2022-06-25 15:51:01 +00:00
# include <boost/program_options/variables_map.hpp>
# include <boost/program_options/options_description.hpp>
2012-02-19 22:39:37 +00:00
/**
* \ namespace Files
*/
2012-01-21 00:14:35 +00:00
namespace Files
{
2022-04-26 20:36:03 +00:00
namespace bpo = boost : : program_options ;
2012-01-21 00:14:35 +00:00
static const char * const openmwCfgFile = " openmw.cfg " ;
2014-07-28 19:52:34 +00:00
# if defined(_WIN32) || defined(__WINDOWS__)
static const char * const applicationName = " OpenMW " ;
# else
static const char * const applicationName = " openmw " ;
# endif
2022-06-30 17:26:14 +00:00
static constexpr auto localToken = u8 " ?local? " ;
static constexpr auto userConfigToken = u8 " ?userconfig? " ;
static constexpr auto userDataToken = u8 " ?userdata? " ;
static constexpr auto globalToken = u8 " ?global? " ;
2012-01-21 00:14:35 +00:00
2015-01-30 21:11:26 +00:00
ConfigurationManager : : ConfigurationManager ( bool silent )
2014-07-28 19:52:34 +00:00
: mFixedPath ( applicationName )
2015-01-30 21:11:26 +00:00
, mSilent ( silent )
2012-01-21 00:14:35 +00:00
{
setupTokensMapping ( ) ;
2022-01-20 17:20:28 +00:00
// Initialize with fixed paths, will be overridden in `readConfiguration`.
mUserDataPath = mFixedPath . getUserDataPath ( ) ;
2020-04-20 16:22:50 +00:00
mScreenshotPath = mFixedPath . getUserDataPath ( ) / " screenshots " ;
2012-01-21 00:14:35 +00:00
}
ConfigurationManager : : ~ ConfigurationManager ( )
{
}
void ConfigurationManager : : setupTokensMapping ( )
{
2012-02-19 22:39:37 +00:00
mTokensMapping . insert ( std : : make_pair ( localToken , & FixedPath < > : : getLocalPath ) ) ;
2022-01-13 22:10:09 +00:00
mTokensMapping . insert ( std : : make_pair ( userConfigToken , & FixedPath < > : : getUserConfigPath ) ) ;
2014-06-18 15:18:48 +00:00
mTokensMapping . insert ( std : : make_pair ( userDataToken , & FixedPath < > : : getUserDataPath ) ) ;
2012-01-28 10:59:08 +00:00
mTokensMapping . insert ( std : : make_pair ( globalToken , & FixedPath < > : : getGlobalDataPath ) ) ;
2012-01-21 00:14:35 +00:00
}
2022-04-26 20:36:03 +00:00
static bool hasReplaceConfig ( const bpo : : variables_map & variables )
{
if ( variables [ " replace " ] . empty ( ) )
return false ;
for ( const std : : string & var : variables [ " replace " ] . as < std : : vector < std : : string > > ( ) )
{
if ( var = = " config " )
return true ;
}
return false ;
}
void ConfigurationManager : : readConfiguration ( bpo : : variables_map & variables ,
const bpo : : options_description & description , bool quiet )
2012-01-21 00:14:35 +00:00
{
2015-06-16 02:48:45 +00:00
bool silent = mSilent ;
mSilent = quiet ;
2020-10-22 20:38:22 +00:00
2022-04-26 20:36:03 +00:00
std : : optional < bpo : : variables_map > config = loadConfig ( mFixedPath . getLocalPath ( ) , description ) ;
2022-01-13 22:10:09 +00:00
if ( config )
mActiveConfigPaths . push_back ( mFixedPath . getLocalPath ( ) ) ;
else
{
mActiveConfigPaths . push_back ( mFixedPath . getGlobalConfigPath ( ) ) ;
config = loadConfig ( mFixedPath . getGlobalConfigPath ( ) , description ) ;
}
if ( ! config )
2015-12-02 18:21:10 +00:00
{
2022-01-13 22:10:09 +00:00
if ( ! quiet )
Log ( Debug : : Error ) < < " Neither local config nor global config are available. " ;
mSilent = silent ;
return ;
}
2022-06-08 21:25:50 +00:00
std : : stack < std : : filesystem : : path > extraConfigDirs ;
2022-01-13 22:10:09 +00:00
addExtraConfigDirs ( extraConfigDirs , variables ) ;
2022-04-26 20:36:03 +00:00
if ( ! hasReplaceConfig ( variables ) )
addExtraConfigDirs ( extraConfigDirs , * config ) ;
2022-01-13 22:10:09 +00:00
2022-04-26 20:36:03 +00:00
std : : vector < bpo : : variables_map > parsedConfigs { * std : : move ( config ) } ;
2022-06-08 21:25:50 +00:00
std : : set < std : : filesystem : : path > alreadyParsedPaths ; // needed to prevent infinite loop in case of a circular link
2022-06-30 17:26:14 +00:00
alreadyParsedPaths . insert ( mActiveConfigPaths . front ( ) ) ;
2022-01-13 22:10:09 +00:00
while ( ! extraConfigDirs . empty ( ) )
{
2022-08-19 22:26:23 +00:00
auto path = extraConfigDirs . top ( ) ;
2022-01-13 22:10:09 +00:00
extraConfigDirs . pop ( ) ;
if ( alreadyParsedPaths . count ( path ) > 0 )
{
if ( ! quiet )
Log ( Debug : : Warning ) < < " Repeated config dir: " < < path ;
continue ;
}
alreadyParsedPaths . insert ( path ) ;
config = loadConfig ( path , description ) ;
2022-04-26 20:36:03 +00:00
if ( config & & hasReplaceConfig ( * config ) & & parsedConfigs . size ( ) > 1 )
{
mActiveConfigPaths . resize ( 1 ) ;
parsedConfigs . resize ( 1 ) ;
Log ( Debug : : Info ) < < " Skipping previous configs except " < < ( mActiveConfigPaths . front ( ) / " openmw.cfg " ) < <
" due to replace=config in " < < ( path / " openmw.cfg " ) ;
}
2022-08-19 22:26:23 +00:00
mActiveConfigPaths . emplace_back ( std : : move ( path ) ) ;
2022-04-26 20:36:03 +00:00
if ( config )
{
addExtraConfigDirs ( extraConfigDirs , * config ) ;
parsedConfigs . push_back ( * std : : move ( config ) ) ;
}
2022-01-13 22:10:09 +00:00
}
2022-04-26 20:36:03 +00:00
for ( auto it = parsedConfigs . rbegin ( ) ; it ! = parsedConfigs . rend ( ) ; + + it )
2022-01-13 22:10:09 +00:00
{
auto composingVariables = separateComposingVariables ( variables , description ) ;
2022-04-26 20:36:03 +00:00
for ( auto & [ k , v ] : * it )
{
2022-07-01 12:27:19 +00:00
auto variable = variables . find ( k ) ;
if ( variable = = variables . end ( ) )
2022-04-26 20:36:03 +00:00
variables . insert ( { k , v } ) ;
2022-07-01 12:27:19 +00:00
else if ( variable - > second . defaulted ( ) )
variable - > second = v ;
2022-04-26 20:36:03 +00:00
}
2020-10-23 00:41:28 +00:00
mergeComposingVariables ( variables , composingVariables , description ) ;
2015-12-02 18:21:10 +00:00
}
2012-01-25 22:55:43 +00:00
2022-06-23 17:13:10 +00:00
mUserDataPath = variables [ " user-data " ] . as < Files : : MaybeQuotedPath > ( ) . u8string ( ) ; // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
2022-01-20 17:20:28 +00:00
if ( mUserDataPath . empty ( ) )
{
if ( ! quiet )
Log ( Debug : : Warning ) < < " Error: `user-data` is not specified " ;
mUserDataPath = mFixedPath . getUserDataPath ( ) ;
}
mScreenshotPath = mUserDataPath / " screenshots " ;
2022-06-08 21:25:50 +00:00
std : : filesystem : : create_directories ( getUserConfigPath ( ) ) ;
std : : filesystem : : create_directories ( mScreenshotPath ) ;
2022-01-20 17:20:28 +00:00
// probably not necessary but validate the creation of the screenshots directory and fallback to the original behavior if it fails
2022-06-08 21:25:50 +00:00
if ( ! std : : filesystem : : is_directory ( mScreenshotPath ) )
2022-01-20 17:20:28 +00:00
mScreenshotPath = mUserDataPath ;
if ( ! quiet )
{
2022-06-30 17:26:14 +00:00
Log ( Debug : : Info ) < < " Logs dir: " < < getUserConfigPath ( ) ;
Log ( Debug : : Info ) < < " User data dir: " < < mUserDataPath ;
Log ( Debug : : Info ) < < " Screenshots dir: " < < mScreenshotPath ;
2022-01-20 17:20:28 +00:00
}
2015-06-16 02:48:45 +00:00
mSilent = silent ;
2012-01-25 22:55:43 +00:00
}
2022-06-08 21:25:50 +00:00
void ConfigurationManager : : addExtraConfigDirs ( std : : stack < std : : filesystem : : path > & dirs ,
2022-04-26 20:36:03 +00:00
const bpo : : variables_map & variables ) const
2022-01-13 22:10:09 +00:00
{
auto configIt = variables . find ( " config " ) ;
if ( configIt = = variables . end ( ) )
return ;
Files : : PathContainer newDirs = asPathContainer ( configIt - > second . as < Files : : MaybeQuotedPathContainer > ( ) ) ;
for ( auto it = newDirs . rbegin ( ) ; it ! = newDirs . rend ( ) ; + + it )
dirs . push ( * it ) ;
}
2022-04-26 20:36:03 +00:00
void ConfigurationManager : : addCommonOptions ( bpo : : options_description & description )
2022-01-13 22:10:09 +00:00
{
description . add_options ( )
2022-02-06 22:09:06 +00:00
( " config " , bpo : : value < Files : : MaybeQuotedPathContainer > ( ) - > default_value ( Files : : MaybeQuotedPathContainer ( ) , " " )
- > multitoken ( ) - > composing ( ) , " additional config directories " )
2022-04-26 20:36:03 +00:00
( " replace " , bpo : : value < std : : vector < std : : string > > ( ) - > default_value ( std : : vector < std : : string > ( ) , " " ) - > multitoken ( ) - > composing ( ) ,
" settings where the values from the current source should replace those from lower-priority sources instead of being appended " )
( " user-data " , bpo : : value < Files : : MaybeQuotedPath > ( ) - > default_value ( Files : : MaybeQuotedPath ( ) , " " ) ,
2022-01-20 17:20:28 +00:00
" set user data directory (used for saves, screenshots, etc) " ) ;
2022-01-13 22:10:09 +00:00
}
2022-04-26 20:36:03 +00:00
bpo : : variables_map separateComposingVariables ( bpo : : variables_map & variables , const bpo : : options_description & description )
2020-10-23 00:41:28 +00:00
{
2022-04-26 20:36:03 +00:00
bpo : : variables_map composingVariables ;
2020-10-23 00:41:28 +00:00
for ( auto itr = variables . begin ( ) ; itr ! = variables . end ( ) ; )
{
2020-10-28 00:36:49 +00:00
if ( description . find ( itr - > first , false ) . semantic ( ) - > is_composing ( ) )
2020-10-23 00:41:28 +00:00
{
composingVariables . emplace ( * itr ) ;
itr = variables . erase ( itr ) ;
}
else
+ + itr ;
}
return composingVariables ;
}
2022-04-26 20:36:03 +00:00
void mergeComposingVariables ( bpo : : variables_map & first , bpo : : variables_map & second ,
const bpo : : options_description & description )
2020-10-23 00:41:28 +00:00
{
2021-08-01 01:47:10 +00:00
// There are a few places this assumes all variables are present in second, but it's never crashed in the wild, so it looks like that's guaranteed.
std : : set < std : : string > replacedVariables ;
if ( description . find_nothrow ( " replace " , false ) )
{
auto replace = second [ " replace " ] ;
2022-02-01 23:20:32 +00:00
if ( ! replace . defaulted ( ) & & ! replace . empty ( ) )
2021-08-01 01:47:10 +00:00
{
2021-10-09 00:49:08 +00:00
std : : vector < std : : string > replaceVector = replace . as < std : : vector < std : : string > > ( ) ;
2021-08-01 01:47:10 +00:00
replacedVariables . insert ( replaceVector . begin ( ) , replaceVector . end ( ) ) ;
}
}
2020-10-28 00:36:49 +00:00
for ( const auto & option : description . options ( ) )
2020-10-23 00:41:28 +00:00
{
2020-10-28 00:36:49 +00:00
if ( option - > semantic ( ) - > is_composing ( ) )
2020-10-23 00:41:28 +00:00
{
2020-10-28 00:36:49 +00:00
std : : string name = option - > canonical_display_name ( ) ;
auto firstPosition = first . find ( name ) ;
if ( firstPosition = = first . end ( ) )
{
first . emplace ( name , second [ name ] ) ;
continue ;
}
2022-02-01 23:20:32 +00:00
if ( replacedVariables . count ( name ) | | firstPosition - > second . defaulted ( ) | | firstPosition - > second . empty ( ) )
2021-08-01 01:47:10 +00:00
{
firstPosition - > second = second [ name ] ;
continue ;
}
2022-02-01 23:20:32 +00:00
if ( second [ name ] . defaulted ( ) | | second [ name ] . empty ( ) )
2020-10-23 00:41:28 +00:00
continue ;
2020-10-28 00:36:49 +00:00
boost : : any & firstValue = firstPosition - > second . value ( ) ;
2020-10-23 00:41:28 +00:00
const boost : : any & secondValue = second [ name ] . value ( ) ;
2022-06-30 17:26:14 +00:00
2021-11-21 19:51:02 +00:00
if ( firstValue . type ( ) = = typeid ( Files : : MaybeQuotedPathContainer ) )
2020-10-23 00:41:28 +00:00
{
2021-11-21 19:51:02 +00:00
auto & firstPathContainer = boost : : any_cast < Files : : MaybeQuotedPathContainer & > ( firstValue ) ;
const auto & secondPathContainer = boost : : any_cast < const Files : : MaybeQuotedPathContainer & > ( secondValue ) ;
2020-10-23 00:41:28 +00:00
firstPathContainer . insert ( firstPathContainer . end ( ) , secondPathContainer . begin ( ) , secondPathContainer . end ( ) ) ;
}
2021-10-09 00:49:08 +00:00
else if ( firstValue . type ( ) = = typeid ( std : : vector < std : : string > ) )
2020-10-23 00:58:43 +00:00
{
2021-10-09 00:49:08 +00:00
auto & firstVector = boost : : any_cast < std : : vector < std : : string > & > ( firstValue ) ;
const auto & secondVector = boost : : any_cast < const std : : vector < std : : string > & > ( secondValue ) ;
2020-10-23 00:58:43 +00:00
2021-10-09 00:49:08 +00:00
firstVector . insert ( firstVector . end ( ) , secondVector . begin ( ) , secondVector . end ( ) ) ;
2020-10-23 00:58:43 +00:00
}
2020-10-23 00:41:28 +00:00
else if ( firstValue . type ( ) = = typeid ( Fallback : : FallbackMap ) )
{
auto & firstMap = boost : : any_cast < Fallback : : FallbackMap & > ( firstValue ) ;
const auto & secondMap = boost : : any_cast < const Fallback : : FallbackMap & > ( secondValue ) ;
std : : map < std : : string , std : : string > tempMap ( secondMap . mMap ) ;
tempMap . merge ( firstMap . mMap ) ;
firstMap . mMap . swap ( tempMap ) ;
}
else
Log ( Debug : : Error ) < < " Unexpected composing variable type. Curse boost and their blasted arcane templates. " ;
}
}
}
2022-06-08 21:25:50 +00:00
void ConfigurationManager : : processPath ( std : : filesystem : : path & path , const std : : filesystem : : path & basePath ) const
2012-01-25 22:55:43 +00:00
{
2022-06-30 17:26:14 +00:00
const auto str = path . u8string ( ) ;
2022-01-20 17:20:28 +00:00
2022-06-30 17:26:14 +00:00
if ( str . empty ( ) | | str [ 0 ] ! = u8 ' ? ' )
2022-04-26 20:36:03 +00:00
{
if ( ! path . is_absolute ( ) )
path = basePath / path ;
2022-01-20 17:20:28 +00:00
return ;
2022-04-26 20:36:03 +00:00
}
2012-01-28 08:49:09 +00:00
2022-06-30 17:26:14 +00:00
const auto pos = str . find ( ' ? ' , 1 ) ;
if ( pos ! = std : : u8string : : npos & & pos ! = 0 )
2022-01-20 17:20:28 +00:00
{
auto tokenIt = mTokensMapping . find ( str . substr ( 0 , pos + 1 ) ) ;
if ( tokenIt ! = mTokensMapping . end ( ) )
2012-01-25 22:55:43 +00:00
{
2022-06-30 17:26:14 +00:00
auto tempPath ( ( ( mFixedPath ) . * ( tokenIt - > second ) ) ( ) ) ;
2022-01-20 17:20:28 +00:00
if ( pos < str . length ( ) - 1 )
2012-01-25 22:55:43 +00:00
{
2022-01-20 17:20:28 +00:00
// There is something after the token, so we should
// append it to the path
tempPath / = str . substr ( pos + 1 , str . length ( ) - pos ) ;
2012-01-25 22:55:43 +00:00
}
2022-01-20 17:20:28 +00:00
2022-06-30 17:26:14 +00:00
path = tempPath ;
2022-01-20 17:20:28 +00:00
}
else
{
if ( ! mSilent )
Log ( Debug : : Warning ) < < " Path starts with unknown token: " < < path ;
path . clear ( ) ;
2012-01-25 22:55:43 +00:00
}
2022-01-20 17:20:28 +00:00
}
2022-04-26 20:36:03 +00:00
}
2012-02-19 22:39:37 +00:00
2022-06-08 21:25:50 +00:00
void ConfigurationManager : : processPaths ( Files : : PathContainer & dataDirs , const std : : filesystem : : path & basePath ) const
2022-04-26 20:36:03 +00:00
{
for ( auto & path : dataDirs )
processPath ( path , basePath ) ;
2022-01-20 17:20:28 +00:00
}
2013-09-08 12:31:20 +00:00
2022-06-08 21:25:50 +00:00
void ConfigurationManager : : processPaths ( boost : : program_options : : variables_map & variables , const std : : filesystem : : path & basePath ) const
2022-01-20 17:20:28 +00:00
{
2022-04-26 20:36:03 +00:00
for ( auto & [ name , var ] : variables )
2022-01-20 17:20:28 +00:00
{
2022-04-26 20:36:03 +00:00
if ( var . defaulted ( ) )
continue ;
if ( var . value ( ) . type ( ) = = typeid ( MaybeQuotedPathContainer ) )
2022-01-20 17:20:28 +00:00
{
2022-04-26 20:36:03 +00:00
auto & pathContainer = boost : : any_cast < MaybeQuotedPathContainer & > ( var . value ( ) ) ;
for ( MaybeQuotedPath & path : pathContainer )
processPath ( path , basePath ) ;
}
else if ( var . value ( ) . type ( ) = = typeid ( MaybeQuotedPath ) )
{
2022-06-08 21:25:50 +00:00
std : : filesystem : : path & path = boost : : any_cast < Files : : MaybeQuotedPath & > ( var . value ( ) ) ;
2022-04-26 20:36:03 +00:00
processPath ( path , basePath ) ;
2012-02-19 22:39:37 +00:00
}
2012-01-25 22:55:43 +00:00
}
2022-04-26 20:36:03 +00:00
}
2012-01-25 22:55:43 +00:00
2022-04-26 20:36:03 +00:00
void ConfigurationManager : : filterOutNonExistingPaths ( Files : : PathContainer & dataDirs ) const
{
2012-02-19 22:39:37 +00:00
dataDirs . erase ( std : : remove_if ( dataDirs . begin ( ) , dataDirs . end ( ) ,
2022-06-08 21:25:50 +00:00
[ this ] ( const std : : filesystem : : path & p )
2022-04-26 20:36:03 +00:00
{
2022-06-08 21:25:50 +00:00
bool exists = std : : filesystem : : is_directory ( p ) ;
2022-04-26 20:36:03 +00:00
if ( ! exists & & ! mSilent )
Log ( Debug : : Warning ) < < " No such dir: " < < p ;
return ! exists ;
} ) ,
dataDirs . end ( ) ) ;
2012-01-21 00:14:35 +00:00
}
2022-04-26 20:36:03 +00:00
std : : optional < bpo : : variables_map > ConfigurationManager : : loadConfig (
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & path , const bpo : : options_description & description ) const
2012-01-21 00:14:35 +00:00
{
2022-06-08 21:25:50 +00:00
std : : filesystem : : path cfgFile ( path ) ;
2022-06-30 17:26:14 +00:00
cfgFile / = openmwCfgFile ;
2022-06-08 21:25:50 +00:00
if ( std : : filesystem : : is_regular_file ( cfgFile ) )
2012-01-21 00:14:35 +00:00
{
2015-01-30 21:11:26 +00:00
if ( ! mSilent )
2022-06-30 17:26:14 +00:00
Log ( Debug : : Info ) < < " Loading config file: " < < cfgFile ;
2012-01-21 00:14:35 +00:00
2022-06-08 21:25:50 +00:00
std : : ifstream configFileStream ( cfgFile ) ;
2021-09-30 01:48:47 +00:00
2021-10-09 00:49:08 +00:00
if ( configFileStream . is_open ( ) )
2022-04-26 20:36:03 +00:00
{
bpo : : variables_map variables ;
bpo : : store ( Files : : parse_config_file ( configFileStream , description , true ) , variables ) ;
processPaths ( variables , path ) ;
return variables ;
}
2022-01-13 22:10:09 +00:00
else if ( ! mSilent )
Log ( Debug : : Error ) < < " Loading failed. " ;
2012-01-21 00:14:35 +00:00
}
2022-01-13 22:10:09 +00:00
return std : : nullopt ;
2012-01-21 00:14:35 +00:00
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getGlobalPath ( ) const
2012-01-21 00:14:35 +00:00
{
2013-12-25 23:28:19 +00:00
return mFixedPath . getGlobalConfigPath ( ) ;
2012-01-21 00:14:35 +00:00
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getUserConfigPath ( ) const
2012-01-21 00:14:35 +00:00
{
2022-01-16 01:10:13 +00:00
if ( mActiveConfigPaths . empty ( ) )
return mFixedPath . getUserConfigPath ( ) ;
else
return mActiveConfigPaths . back ( ) ;
2012-01-21 00:14:35 +00:00
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getUserDataPath ( ) const
2013-12-26 00:24:43 +00:00
{
2022-01-20 17:20:28 +00:00
return mUserDataPath ;
2013-12-26 00:24:43 +00:00
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getLocalPath ( ) const
2012-01-21 00:14:35 +00:00
{
return mFixedPath . getLocalPath ( ) ;
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getGlobalDataPath ( ) const
2012-01-21 00:14:35 +00:00
{
2012-01-25 22:55:43 +00:00
return mFixedPath . getGlobalDataPath ( ) ;
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getCachePath ( ) const
2012-09-02 17:40:26 +00:00
{
return mFixedPath . getCachePath ( ) ;
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getInstallPath ( ) const
2012-01-25 22:55:43 +00:00
{
return mFixedPath . getInstallPath ( ) ;
}
2022-06-08 21:25:50 +00:00
const std : : filesystem : : path & ConfigurationManager : : getScreenshotPath ( ) const
2020-04-19 23:34:00 +00:00
{
2020-04-20 16:22:50 +00:00
return mScreenshotPath ;
2020-04-19 23:34:00 +00:00
}
2022-04-26 20:36:03 +00:00
void parseArgs ( int argc , const char * const argv [ ] , bpo : : variables_map & variables ,
const bpo : : options_description & description )
2021-09-30 01:48:47 +00:00
{
2022-04-26 20:36:03 +00:00
bpo : : store (
bpo : : command_line_parser ( argc , argv ) . options ( description ) . allow_unregistered ( ) . run ( ) ,
2021-09-30 01:48:47 +00:00
variables
) ;
}
2022-04-26 20:36:03 +00:00
void parseConfig ( std : : istream & stream , bpo : : variables_map & variables , const bpo : : options_description & description )
2021-09-30 01:48:47 +00:00
{
2022-04-26 20:36:03 +00:00
bpo : : store ( Files : : parse_config_file ( stream , description , true ) , variables ) ;
2021-09-30 01:48:47 +00:00
}
2021-11-21 19:51:02 +00:00
std : : istream & operator > > ( std : : istream & istream , MaybeQuotedPath & MaybeQuotedPath )
2021-11-14 00:22:44 +00:00
{
2022-06-11 21:38:09 +00:00
// If the stream starts with a double quote, read from stream using boost::filesystem::path rules, then discard anything remaining.
2021-11-14 00:22:44 +00:00
// This prevents boost::program_options getting upset that we've not consumed the whole stream.
2021-11-21 19:51:02 +00:00
// If it doesn't start with a double quote, read the whole thing verbatim
if ( istream . peek ( ) = = ' " ' )
2021-11-14 00:22:44 +00:00
{
2022-06-11 17:15:24 +00:00
std : : string intermediate ;
istream > > std : : quoted ( intermediate , ' " ' , ' & ' ) ;
2022-06-30 17:26:14 +00:00
static_cast < std : : filesystem : : path & > ( MaybeQuotedPath ) = Misc : : StringUtils : : stringToU8String ( intermediate ) ;
2021-11-21 19:51:02 +00:00
if ( istream & & ! istream . eof ( ) & & istream . peek ( ) ! = EOF )
{
2021-11-29 20:16:49 +00:00
std : : string remainder { std : : istreambuf_iterator ( istream ) , { } } ;
2022-06-30 17:26:14 +00:00
Log ( Debug : : Warning ) < < " Trailing data in path setting. Used ' " < < MaybeQuotedPath < < " ' but ' " < < remainder < < " ' remained " ;
2021-11-21 19:51:02 +00:00
}
}
else
{
2021-11-29 20:16:49 +00:00
std : : string intermediate { std : : istreambuf_iterator ( istream ) , { } } ;
2022-06-30 17:26:14 +00:00
static_cast < std : : filesystem : : path & > ( MaybeQuotedPath ) = Misc : : StringUtils : : stringToU8String ( intermediate ) ;
2021-11-14 00:22:44 +00:00
}
return istream ;
}
2021-11-21 19:51:02 +00:00
PathContainer asPathContainer ( const MaybeQuotedPathContainer & MaybeQuotedPathContainer )
2021-11-14 00:22:44 +00:00
{
2022-06-23 17:13:10 +00:00
PathContainer res ;
res . reserve ( MaybeQuotedPathContainer . size ( ) ) ;
for ( const auto & maybeQuotedPath : MaybeQuotedPathContainer )
{
res . emplace_back ( maybeQuotedPath . u8string ( ) ) ; // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
}
return res ;
2021-11-14 00:22:44 +00:00
}
2022-01-13 22:10:09 +00:00
} /* namespace Files */