/* The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. * * Copyright (c) 2010-2014, ITU/ISO/IEC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file CalypOptions.cpp * \brief Options handler */ #include "CalypOptions.h" #include #include #include #include #include "config.h" #include "lib/CalypFrame.h" #include "lib/CalypModuleIf.h" struct ParseFailure : public std::exception { std::string arg; std::string val; ParseFailure( std::string arg0, std::string val0 ) throw() : arg{ std::move( arg0 ) }, val{ std::move( val0 ) } {} ParseFailure( ParseFailure&& other ) noexcept = delete; ParseFailure& operator=( ParseFailure&& other ) noexcept = delete; ParseFailure( const ParseFailure& other ) = delete; ParseFailure& operator=( const ParseFailure& other ) = delete; ~ParseFailure() throw() {} const char* what() const throw() override { return "Option Parse Failure"; } }; /** Type specific option storage */ class boolOption : public CalypOptions::OptionBase { public: boolOption( const std::string& name, const std::string& desc ) : CalypOptions::OptionBase( name, desc, "(1-0)" ) { is_binary = true; } void parse( const std::string& arg ) override { arg_count++; } }; /** Type specific option storage */ template class StandardOption : public CalypOptions::OptionBase { public: StandardOption( const std::string& name, T& storage, const std::string& desc, const std::string& def ) : CalypOptions::OptionBase( name, desc, def ), opt_storage( storage ) {} void parse( const std::string& arg ) override; T& opt_storage; std::vector opt_storage_array; }; /* Generic parsing */ template inline void StandardOption::parse( const std::string& arg ) { if( !is_binary ) { std::istringstream arg_ss( arg, std::istringstream::in ); arg_ss.exceptions( std::ios::failbit ); try { arg_ss >> opt_storage; } catch( ... ) { throw ParseFailure( opt_string, arg ); } } arg_count++; } template <> inline void StandardOption>::parse( const std::string& arg ) { unsigned int aux_opt_storage{ 0 }; std::istringstream arg_ss( arg, std::istringstream::in ); arg_ss.exceptions( std::ios::failbit ); try { arg_ss >> aux_opt_storage; opt_storage.push_back( aux_opt_storage ); } catch( ... ) { throw ParseFailure( opt_string, arg ); } arg_count++; } template <> inline void StandardOption>::parse( const std::string& arg ) { int aux_opt_storage{ 0 }; std::istringstream arg_ss( arg, std::istringstream::in ); arg_ss.exceptions( std::ios::failbit ); try { arg_ss >> aux_opt_storage; opt_storage.push_back( aux_opt_storage ); } catch( ... ) { throw ParseFailure( opt_string, arg ); } arg_count++; } /* string parsing is specialized */ template <> inline void StandardOption::parse( const std::string& arg ) { opt_storage = arg; arg_count++; } /* string vector parsing is specialized */ template <> inline void StandardOption>::parse( const std::string& arg ) { opt_storage.push_back( arg ); arg_count++; } /** Option class for argument handling using a user provided function */ struct FunctionOption : public CalypOptions::OptionBase { using OptFunc = std::function; public: FunctionOption( const std::string& name, CalypOptions& parent, OptFunc func, const std::string& desc, const std::string& def ) : CalypOptions::OptionBase( name, desc, def ), m_parent( parent ), m_func( func ) { is_binary = false; } void parse( const std::string& arg ) override { m_func( m_parent, arg ); arg_count++; } private: CalypOptions& m_parent; OptFunc m_func; }; /* Helper method to initiate adding options to Options */ /** * Add option described by name to the parent Options list, * with storage for the option's value * with default_val as the default value * with desc as an optional help description */ CalypOptions& CalypOptions::operator()( const std::string& name, const std::string& desc ) { addOptionInternal( std::make_unique( name, desc ) ); return *this; } CalypOptions& CalypOptions::addOption( const std::string& name, const std::string& desc ) { addOptionInternal( std::make_unique( name, desc ) ); return *this; } /** * Add option described by name to the parent Options list, * with storage for the option's value * with desc as an optional help description */ template CalypOptions& CalypOptions::operator()( const std::string& name, T& storage, const std::string& desc ) { addOptionInternal( std::make_unique>( name, storage, desc, std::string( "" ) ) ); return *this; } template CalypOptions& CalypOptions::addOption( const std::string& name, T& storage, const std::string& desc ) { addOptionInternal( std::make_unique>( name, storage, desc, std::string( "" ) ) ); return *this; } template CalypOptions& CalypOptions::operator()( const std::string& name, T& storage, const std::string& desc, const std::string& defaults ) { addOptionInternal( std::make_unique>( name, storage, desc ) ); return *this; } template CalypOptions& CalypOptions::addOption( const std::string& name, T& storage, const std::string& desc, const std::string& defaults ) { addOptionInternal( std::make_unique>( name, storage, desc ) ); return *this; } template CalypOptions& CalypOptions::operator()( const std::string& name, bool& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, unsigned int& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, int& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, long& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, long long int& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, std::string& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, std::vector& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, std::vector& storage, const std::string& desc ); template CalypOptions& CalypOptions::operator()( const std::string& name, std::vector& storage, const std::string& desc ); CalypOptions::CalypOptions( std::string name ) : m_cOptionGroupName{ std::move( name ) } { } CalypOptions::OptionBase* CalypOptions::operator[]( const std::string& optName ) { return getOption( optName ); } CalypOptions::OptionBase* CalypOptions::getOption( const std::string& optName ) { std::map>::iterator opt_it; opt_it = opt_short_map.find( optName ); if( opt_it != opt_short_map.end() ) { auto opt_list = ( *opt_it ).second; for( auto& option : opt_list ) { return option->base_opt.get(); } } opt_it = opt_long_map.find( optName ); if( opt_it != opt_long_map.end() ) { auto opt_list = ( *opt_it ).second; for( auto& option : opt_list ) { return option->base_opt.get(); } } return NULL; } bool CalypOptions::hasOpt( const std::string& optName ) { OptionBase* opt = getOption( optName ); return opt ? opt->count() > 0 ? true : false : false; } CalypOptions& CalypOptions::addOptions() { return *this; } void CalypOptions::addOptionInternal( std::unique_ptr opt ) { auto names = std::make_unique