commit 641f8d11e6702155c33264c9e25879db56b000db Author: bergmann Date: Sun Jul 14 00:03:31 2019 +0200 * Initial commit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bd7cbfa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "/home/bergmann/projects/dnpnode/projects/cppcurl/cmake/modules"] + path = /home/bergmann/projects/dnpnode/projects/cppcurl/cmake/modules + url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..983444d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +# Initialize CMake ################################################################################ + +CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) + +# Set CMAKE_BUILD_TYPE +If ( NOT CMAKE_BUILD_TYPE ) + Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) +EndIf ( NOT CMAKE_BUILD_TYPE ) +Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) + +# Set CMAKE_MODULE_PATH +If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) + Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) +EndIf ( ) +If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) + Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) +EndIf ( ) + +# Project ######################################################################################### + +Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppcurl-var.cmake ) +Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppcurl-options.cmake ) +Project ( cppcurl + DESCRIPTION "A simple library" + VERSION "${CPPCURL_VERSION}" ) +Include ( CTest ) +Include ( GNUInstallDirs ) + +# Subdirectories +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) + +# Install +Include ( CMakePackageConfigHelpers ) +Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcurl-config-version.cmake" + VERSION ${CPPCURL_VERSION} + COMPATIBILITY AnyNewerVersion ) +Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppcurl-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcurl-config.cmake" + @ONLY ) + +Set ( ConfigPackageLocation "${CPPCURL_INSTALL_DIR_SHARE}/cmake" ) +Install ( EXPORT + cppcurl + NAMESPACE + cppcurl:: + DESTINATION + ${ConfigPackageLocation} ) +Install ( FILES + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcurl-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcurl-config-version.cmake" + DESTINATION + ${ConfigPackageLocation} + COMPONENT + Devel ) diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 0000000..46cae64 --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,3 @@ +#pragma once + +#cmakedefine CPPCURL_HAS_CPPCORE diff --git a/cmake/cppcurl-config.cmake b/cmake/cppcurl-config.cmake new file mode 100644 index 0000000..ad9c6d9 --- /dev/null +++ b/cmake/cppcurl-config.cmake @@ -0,0 +1,10 @@ +# cppcurl-config.cmake - package configuration file + +Message ( WARNING "Please configure the dependencies of this package!" ) +# Include ( CMakeFindDependencyMacro ) +# Find_Dependency ( ) + +Include ( FindPackageHandleStandardArgs ) +Set ( ${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE} ) +Find_Package_Handle_Standard_Args ( cppcurl CONFIG_MODE ) +Include ( "${CMAKE_CURRENT_LIST_DIR}/cppcurl.cmake") diff --git a/cmake/cppcurl-options.cmake b/cmake/cppcurl-options.cmake new file mode 100644 index 0000000..0e5f1a8 --- /dev/null +++ b/cmake/cppcurl-options.cmake @@ -0,0 +1,15 @@ +Option ( CPPCURL_INSTALL_HEADER + "Install headers of cppcurl." + ON ) +Option ( CPPCURL_INSTALL_STATIC + "Install static library of cppcurl." + ON ) +Option ( CPPCURL_INSTALL_SHARED + "Install shared library of cppcurl." + ON ) +Option ( CPPCURL_INSTALL_DEBUG + "Install the stripped debug informations of cppcurl." + OFF ) +Option ( CPPCURL_NO_STRIP + "Do not strip debug symbols from binary." + OFF ) diff --git a/cmake/cppcurl-var.cmake b/cmake/cppcurl-var.cmake new file mode 100644 index 0000000..44bb3c2 --- /dev/null +++ b/cmake/cppcurl-var.cmake @@ -0,0 +1,31 @@ +# Version +Set ( CPPCURL_VERSION_MAJOR 1 ) +Set ( CPPCURL_VERSION_MINOR 0 ) +Set ( CPPCURL_VERSION_PATCH 0 ) +Set ( CPPCURL_VERSION_BUILD 0 ) +Set ( CPPCURL_VERSION_SHORT "${CPPCURL_VERSION_MAJOR}.${CPPCURL_VERSION_MINOR}" ) +Set ( CPPCURL_VERSION "${CPPCURL_VERSION_SHORT}.${CPPCURL_VERSION_PATCH}.${CPPCURL_VERSION_BUILD}" ) +Set ( CPPCURL_NAME "cppcurl-${CPPCURL_VERSION_SHORT}" ) +Set ( CPPCURL_OUTPUTNAME "cppcurl" ) + +# Install directories +Set ( CPPCURL_INSTALL_DIR_INCLUDE "include/${CPPCURL_NAME}" ) +Set ( CPPCURL_INSTALL_DIR_LIB "lib" ) +Set ( CPPCURL_INSTALL_DIR_SHARE "share/${CPPCURL_NAME}" ) + +# C Standard +Set ( CMAKE_C_STANDARD 11 ) +Set ( CMAKE_CXX_STANDARD 17 ) +Set ( CMAKE_C_STANDARD_REQUIRED ON ) +Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) + +# Git Version +Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) +If ( HAS_GIT_HELPER ) + GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. + CPPCURL_VERSION_MAJOR + CPPCURL_VERSION_MINOR + CPPCURL_VERSION_PATCH + CPPCURL_VERSION_BUILD + CPPCURL_VERSION_HASH ) +EndIf ( ) diff --git a/cmake/modules b/cmake/modules new file mode 160000 index 0000000..a50f650 --- /dev/null +++ b/cmake/modules @@ -0,0 +1 @@ +Subproject commit a50f6505f4989b1d96449ba7cd498f8bf2880427 diff --git a/include/cppcurl.h b/include/cppcurl.h new file mode 100644 index 0000000..971c929 --- /dev/null +++ b/include/cppcurl.h @@ -0,0 +1,15 @@ +#pragma once + +#include "cppcurl/easy.h" +#include "cppcurl/exception.h" +#include "cppcurl/global.h" +#include "cppcurl/info.h" +#include "cppcurl/multi.h" +#include "cppcurl/option.h" +#include "cppcurl/slist.h" + +#include "cppcurl/easy.inl" +#include "cppcurl/exception.inl" +#include "cppcurl/global.inl" +#include "cppcurl/multi.inl" +#include "cppcurl/slist.inl" diff --git a/include/cppcurl/easy.h b/include/cppcurl/easy.h new file mode 100644 index 0000000..b6f546d --- /dev/null +++ b/include/cppcurl/easy.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +#include "info.h" +#include "slist.h" +#include "option.h" + +namespace cppcurl +{ + + struct easy + { + private: + using handle_ptr_u = std::unique_ptr; + + private: + handle_ptr_u _handle; + slist _header; + + public: + /** + * @brief Constructor. + */ + inline easy(); + + /** + * @brief Get the internal curl easy handle. + */ + inline CURL* handle() const; + + /** + * @brief Reset all options of the easy handle. + */ + inline void reset(); + + /** + * @brief Perform the action configured in this easy handle. + */ + inline void perform(); + + /** + * @brief Add header to easy handle. + */ + inline void add_header(const std::string& s); + + /** + * @brief Add option to the easy handle. + * + * @param[in] opt Option to add to the handle. + */ + template + inline void set_option(const __impl::option& opt); + + /** + * @brief Add option to the easy handle. + * + * @tparam T_option Option to add to the handle. + * @param[in] val Value of option to add to the handle. + */ + template + inline void set_option(const typename option::value_type& val); + + /** + * @brief Get an info from the easy handle. + */ + template + inline typename info::value_type get_info() const; + }; + +} + +#include "easy.inl" diff --git a/include/cppcurl/easy.inl b/include/cppcurl/easy.inl new file mode 100644 index 0000000..3dc851f --- /dev/null +++ b/include/cppcurl/easy.inl @@ -0,0 +1,190 @@ +#pragma once + +#include "easy.h" + +#include "slist.inl" +#include "global.inl" +#include "exception.inl" + +namespace cppcurl +{ + + namespace __impl + { + + /* opt_writer */ + + template + struct opt_writer; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, bool val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, static_cast(val)), + "Unable to set option on easy handle."); + } + }; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, long val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, val), + "Unable to set option on easy handle."); + } + }; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, void* val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, val), + "Unable to set option on easy handle."); + } + }; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, data_callback val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, val), + "Unable to set option on easy handle."); + } + }; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, const std::string& val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, val.c_str()), + "Unable to set option on easy handle."); + } + }; + + template + struct opt_writer< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline void write(CURL* handle, CURLoption opt, const slist& val) + { + easy_exception::throw_error( + curl_easy_setopt(handle, opt, val.handle()), + "Unable to set option on easy handle."); + } + }; + + /* info_reader */ + + template + struct info_reader; + + template + struct info_reader< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline long read(CURL* handle, CURLINFO info) + { + long ret; + easy_exception::throw_error( + curl_easy_getinfo(handle, info, &ret), + "Unable to get info from easy handle."); + return ret; + } + }; + + template + struct info_reader< + T, + std::enable_if_t< + std::is_same_v>>> + { + static inline std::string read(CURL* handle, CURLINFO info) + { + const char * ret; + easy_exception::throw_error( + curl_easy_getinfo(handle, info, &ret), + "Unable to get info from easy handle."); + return std::string(ret ? ret : ""); + } + }; + + } + + /* easy */ + + easy::easy() + : _handle(nullptr, &curl_easy_cleanup) + { + if (!global::is_initialized()) + throw multi_exception(CURLM_BAD_HANDLE, "libcurl was not initialized!"); + _handle.reset(curl_easy_init()); + if (!_handle) + throw multi_exception(CURLM_OUT_OF_MEMORY, "Unable to create easy handle"); + } + + CURL* easy::handle() const + { return _handle.get(); } + + void easy::reset() + { curl_easy_reset(_handle.get()); } + + void easy::perform() + { + easy_exception::throw_error( + curl_easy_perform(_handle.get()), + "Unable to perform easy handle operations."); + } + + void easy::add_header(const std::string& s) + { + _header.append(s); + set_option(_header); + } + + template + void easy::set_option(const __impl::option& opt) + { __impl::opt_writer::write(handle(), T_option, opt.value); } + + template + void easy::set_option(const typename option::value_type& val) + { set_option(option(val)); } + + template + typename info::value_type easy::get_info() const + { + using info_type = info; + using value_type = typename info_type::value_type; + return __impl::info_reader::read(handle(), T_info); + } + +} diff --git a/include/cppcurl/exception.h b/include/cppcurl/exception.h new file mode 100644 index 0000000..c5e3b4e --- /dev/null +++ b/include/cppcurl/exception.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#ifdef CPPCURL_HAS_CPPCORE + #include +#else + #include +#endif + +namespace cppcurl +{ + + /** + * @brief Exception to represent curl errors. + */ + template + struct exception + #ifdef CPPCURL_HAS_CPPCORE + : public ::cppcore::exception + #else + : public std::exception + #endif + { + public: + /** + * @brief Throw an exception if the passed error is not OK. + */ + static inline void throw_error(T_error err, const std::string& msg); + + public: + T_error error; + const std::string error_str; + + /** + * @brief Constructor. + */ + inline exception(T_error err, const std::string& msg); + + #ifdef CPPCURL_HAS_CPPCORE + protected: + /** + * @brief Print the message of the exception to the passed stream. + * + * @param[in] os Stream to print message of the exception to. + */ + inline void print_message(std::ostream& os) const override; + + #else + private: + const std::string _what; + + public: + /** + * @brief Get the exception message. + */ + inline const char* what() const throw() override; + #endif + }; + + using easy_exception = exception; + + using multi_exception = exception; +} diff --git a/include/cppcurl/exception.inl b/include/cppcurl/exception.inl new file mode 100644 index 0000000..a0b537f --- /dev/null +++ b/include/cppcurl/exception.inl @@ -0,0 +1,79 @@ +#pragma once + +#include "exception.h" + +namespace cppcurl +{ + + namespace __impl + { + + template + struct get_error_str + { + inline std::string operator()(T_error err) const = delete; + }; + + template<> + struct get_error_str + { + inline std::string operator()(CURLcode err) const + { return curl_easy_strerror(err); } + }; + + template<> + struct get_error_str + { + inline std::string operator()(CURLMcode err) const + { return curl_multi_strerror(err); } + }; + + } + + /* exception */ + + template + void exception + ::throw_error(T_error err, const std::string& msg) + { + if (static_cast(err)) + throw exception(err, msg); + } + +#ifdef CPPCURL_HAS_CPPCORE + template + exception + ::exception(T_error err, const std::string& msg) + : ::cppcore::exception (msg) + , error (err) + , error_str (__impl::get_error_str()(err)) + { } + + template + void exception + ::print_message(std::ostream& os) const + { + os << error_str + << '(' + << static_cast(error) + << "): " + << message; + } +#else + template + exception + ::exception(T_error err, const std::string& msg) + : _what (__impl::get_error_str()(err) + "(" + std::to_string(static_cast(err)) + "): " + msg) + , error (err) + , error_str (get_error_str()(err)) + { } + + template + const char* exception + ::what() const throw() + { + return _what.c_str(); + } +#endif + +} diff --git a/include/cppcurl/global.h b/include/cppcurl/global.h new file mode 100644 index 0000000..508f2e2 --- /dev/null +++ b/include/cppcurl/global.h @@ -0,0 +1,37 @@ +#pragma once + +namespace cppcurl +{ + + /** + * @brief Initializes libcurl. + */ + struct global + { + public: + /** + * @brief Constructor. + */ + inline global(); + + /** + * @brief Destructor. + */ + inline ~global(); + + public: + /** + * @brief Get the initialization state of cppcurl. + */ + static inline bool is_initialized(); + + private: + /** + * @brief Get the counter of initialized instances. + */ + static inline int& counter(); + }; + +} + +#include "global.inl" diff --git a/include/cppcurl/global.inl b/include/cppcurl/global.inl new file mode 100644 index 0000000..94ad929 --- /dev/null +++ b/include/cppcurl/global.inl @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "global.h" +#include "exception.inl" + +namespace cppcurl +{ + + /* global */ + + global::global() + { + if (counter()++ == 0) + { + auto err = curl_global_init(CURL_GLOBAL_DEFAULT); + if (err != CURLE_OK) + throw easy_exception(err, "Unable to initialize libcurl"); + } + } + + global::~global() + { + if (--counter() == 0) + { + // TODO logging? + curl_global_cleanup(); + } + } + + bool global::is_initialized() + { return static_cast(counter()); } + + int& global::counter() + { + static int value(0); + return value; + } + +} diff --git a/include/cppcurl/info.h b/include/cppcurl/info.h new file mode 100644 index 0000000..1a41d24 --- /dev/null +++ b/include/cppcurl/info.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace cppcurl +{ + + namespace __impl + { + + template + struct info + { + public: + using value_type = T_value; + + static constexpr CURLINFO id = T_info; + + public: + value_type value; + }; + + } + + template + struct info; + +#define cppcurl_define_info(nfo, type) \ + template<> \ + struct info \ + : public __impl::info \ + { } + + cppcurl_define_info(CURLINFO_CONTENT_TYPE, std::string); + cppcurl_define_info(CURLINFO_RESPONSE_CODE, long); + +#undef cppcurl_define_info +} diff --git a/include/cppcurl/multi.h b/include/cppcurl/multi.h new file mode 100644 index 0000000..a3b8af6 --- /dev/null +++ b/include/cppcurl/multi.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +namespace cppcurl +{ + + struct easy; + + struct multi + { + private: + using handle_ptr_u = std::unique_ptr; + + private: + handle_ptr_u _handle; + + public: + /** + * @brief Constructor. + */ + inline multi(); + + /** + * @brief Get the libcurl multi handle. + */ + inline CURLM * handle() const; + + /** + * @brief Add a standard curl handle to the multi stack. + */ + inline void add_handle(const easy& e); + + /** + * @brief Removes a curl handle from the multi stack again. + */ + inline void remove_handle(const easy& e); + + /** + * @brief Write all file descriptors known by the object to the passed file descriptor sets. + * + * @param[in] read File descriptor set to listen for read operations. + * @param[in] write File descriptor set to listen for write operations. + * @param[in] except File descriptor set to listen for exceptional condition. + * + * @return Greatest file descriptor. + */ + inline int prepare_fdsets(fd_set& read, fd_set& write, fd_set& except) const; + + /** + * @brief Perform any operations on the multi handle. + * + * @return Number of running easy handles. + */ + inline int perform(); + + /** + * @brief Get the max timeout to wait for file descriptors. + * + * @return Timeout to wait for file descriptors or -1 if not relevant. + */ + inline long timeout() const; + + /** + * @brief Read pending messages from the queue. + */ + inline CURLMsg * read_info() const; + + /** + * @brief Read all pending messages from the queue. + * Call the passed predicate one for each message. + */ + template + inline void read_infos(const T_pred&& pred) const; + }; + +} + +#include "multi.inl" diff --git a/include/cppcurl/multi.inl b/include/cppcurl/multi.inl new file mode 100644 index 0000000..5cd8267 --- /dev/null +++ b/include/cppcurl/multi.inl @@ -0,0 +1,84 @@ +#pragma once + +#include "multi.h" + +#include "easy.inl" +#include "global.inl" +#include "exception.inl" + +namespace cppcurl +{ + + /* multi */ + + multi::multi() + : _handle(nullptr, &curl_multi_cleanup) + { + if (!global::is_initialized()) + throw multi_exception(CURLM_BAD_HANDLE, "libcurl was not initialized!"); + _handle.reset(curl_multi_init()); + if (!_handle) + throw multi_exception(CURLM_OUT_OF_MEMORY, "Unable to create multi handle"); + } + + CURLM * multi::handle() const + { return _handle.get(); } + + void multi::add_handle(const easy& e) + { + multi_exception::throw_error( + curl_multi_add_handle(_handle.get(), e.handle()), + "Unable to add easy handle to multi handle"); + } + + void multi::remove_handle(const easy& e) + { + if (!e.handle()) + return; + multi_exception::throw_error( + curl_multi_remove_handle(_handle.get(), e.handle()), + "Unable to remove easy handle from multi handle"); + } + + int multi::prepare_fdsets(fd_set& read, fd_set& write, fd_set& except) const + { + int ret = -1; + multi_exception::throw_error( + curl_multi_fdset(_handle.get(), &read, &write, &except, &ret), + "Unable to get the file descriptor sets from multi handle"); + return ret; + } + + int multi::perform() + { + int ret = 0; + multi_exception::throw_error( + curl_multi_perform(_handle.get(), &ret), + "Unable to perform the operations on the multi handle"); + return ret; + } + + long multi::timeout() const + { + long ret; + multi_exception::throw_error( + curl_multi_timeout(_handle.get(), &ret), + "Unable to get timeout from multi handle"); + return ret; + } + + CURLMsg * multi::read_info() const + { + int i; + return curl_multi_info_read(_handle.get(), &i); + } + + template + void multi::read_infos(const T_pred&& pred) const + { + CURLMsg * msg; + while ((msg = read_info())) + pred(*msg); + } + +} diff --git a/include/cppcurl/option.h b/include/cppcurl/option.h new file mode 100644 index 0000000..11f1c81 --- /dev/null +++ b/include/cppcurl/option.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include "slist.h" + +namespace cppcurl +{ + + namespace __impl + { + + template + struct option + { + public: + using value_type = T_value; + + static constexpr CURLoption id = T_option; + + public: + value_type value; + + public: + inline option(const T_value& p_value) + : value(p_value) + { } + }; + + } + + using data_callback = size_t (*) (char*, size_t, size_t, void*); + + template + struct option; + +#define cppcurl_define_option(opt, type) \ + template<> \ + struct option \ + : public __impl::option \ + { using __impl::option::option; } + + cppcurl_define_option(CURLOPT_HTTPHEADER, const slist&); + cppcurl_define_option(CURLOPT_PRIVATE, void*); + cppcurl_define_option(CURLOPT_POST, bool); + cppcurl_define_option(CURLOPT_READFUNCTION, data_callback); + cppcurl_define_option(CURLOPT_READDATA, void*); + cppcurl_define_option(CURLOPT_WRITEFUNCTION, data_callback); + cppcurl_define_option(CURLOPT_WRITEDATA, void*); + cppcurl_define_option(CURLOPT_URL, std::string); + cppcurl_define_option(CURLOPT_POSTFIELDSIZE, long); + cppcurl_define_option(CURLOPT_TIMEOUT, long); + cppcurl_define_option(CURLOPT_FOLLOWLOCATION, bool); + +#undef cppcurl_define_option +} diff --git a/include/cppcurl/slist.h b/include/cppcurl/slist.h new file mode 100644 index 0000000..9fecaca --- /dev/null +++ b/include/cppcurl/slist.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include + +namespace cppcurl +{ + + struct slist + { + private: + using handle_ptr_u = std::unique_ptr; + using string_vector = std::vector; + + private: + handle_ptr_u _handle; + + public: + /** + * @brief Constructor. + */ + inline slist(); + + /** + * @brief Get the internal curl easy handle. + */ + inline curl_slist* handle() const; + + /** + * @brief Add string to the list. + */ + inline void append(const std::string& s); + + /** + * @brief clear the list. + */ + inline void reset(); + }; + +} + +#include "slist.inl" diff --git a/include/cppcurl/slist.inl b/include/cppcurl/slist.inl new file mode 100644 index 0000000..c627bcd --- /dev/null +++ b/include/cppcurl/slist.inl @@ -0,0 +1,23 @@ +#pragma once + +#include "slist.h" + +namespace cppcurl +{ + + /* slist */ + + slist::slist() + : _handle(nullptr, &curl_slist_free_all) + { } + + curl_slist* slist::handle() const + { return _handle.get(); } + + void slist::append(const std::string& s) + { _handle.reset(curl_slist_append(_handle.release(), s.c_str())); } + + void slist::reset() + { _handle.reset(); } + +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..20cdec2 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,43 @@ +# Initialize ###################################################################################### + +Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) +Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) +Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) + +Find_Package ( CURL REQUIRED) +Find_Package ( cppcore QUIET ) +If ( cppcore_FOUND ) + Set ( CPPCURL_HAS_CPPCORE true ) +EndIf ( ) + +# Interface Library ############################################################################### + +Set ( CPPCURL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) +Set ( CPPCURL_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/include ) +Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.h.in + ${CPPCURL_GENERATED_INCLUDE_DIR}/cppcurl/config.h ) +Add_Library ( cppcurl INTERFACE ) +Target_Include_Directories ( cppcurl + INTERFACE + $ + $ + $ ) +If ( CPPCURL_HAS_CPPCORE ) + Target_Link_Libraries ( cppcurl + INTERFACE + cppcore + CURL::libcurl ) +EndIf ( ) + +# Install ######################################################################################### + +# Header +Install ( FILES ${CPPCURL_INCLUDE_DIR}/cppcurl.h + DESTINATION ${CPPCURL_INSTALL_DIR_INCLUDE} ) +Install ( DIRECTORY ${CPPCURL_INCLUDE_DIR}/cppcurl + DESTINATION ${CPPCURL_INSTALL_DIR_INCLUDE} ) +Install ( DIRECTORY ${CPPCURL_GENERATED_INCLUDE_DIR}/cppcurl + DESTINATION ${CPPCURL_INSTALL_DIR_INCLUDE} ) +Install ( TARGETS cppcurl + EXPORT cppcurl + DESTINATION ${CPPCURL_INSTALL_DIR_INCLUDE} ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..85d0848 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,43 @@ +# Initialize ###################################################################################### + +Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) +Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) +Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) + +# Test ############################################################################################ + +Find_Package ( GTest ) +If ( NOT "${GTest_FOUND}" ) + Return ( ) +EndIf ( ) + +File ( GLOB_RECURSE CPPCURL_TEST_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) +File ( GLOB_RECURSE CPPCURL_TEST_INLINE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) +File ( GLOB_RECURSE CPPCURL_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) + +Add_Executable ( cppcurl-test + EXCLUDE_FROM_ALL + ${CPPCURL_TEST_HEADER_FILES} + ${CPPCURL_TEST_INLINE_FILES} + ${CPPCURL_TEST_SOURCE_FILES} ) +Target_Link_Libraries ( cppcurl-test + PUBLIC + cppcurl + GTest::Main ) + +# pedantic +If ( HAS_PEDANTIC ) + Pedantic_Apply_Flags_Target ( cppcurl-test ALL ) +EndIf ( ) + +# optimization +If ( HAS_COTIRE ) + Cotire ( cppcurl-test ) +EndIf ( ) + +# test +If ( HAS_CMAKE_TESTS ) + Add_CMake_Test ( NAME cppcurl TARGET cppcurl-test ) +Else ( ) + Add_Test ( NAME cppcurl COMMAND cppcurl-test ) +EndIf ( ) diff --git a/test/cppcurl/cppcurl-tests.cpp b/test/cppcurl/cppcurl-tests.cpp new file mode 100644 index 0000000..0f3a5ae --- /dev/null +++ b/test/cppcurl/cppcurl-tests.cpp @@ -0,0 +1,10 @@ +#include + +#include + +using namespace ::testing; +using namespace ::cppcurl; + +TEST(cppcurl, dummy) +{ +}