Compare commits

..
Author SHA1 Message Date
Torsten Dreyer 9a8c10cb0b New version: 2018.3.3 2019-07-28 22:43:16 +02:00
Erik Hofman fd32023437 Do not attempt to deregister the same emitter more than once 2019-01-26 10:17:11 +01:00
Erik Hofman c1ee4a9172 Use AAX_PROCESSED since AAX_STOPPED is only a request to stop but the library decides when it is actually stopped. And AeonWave has become more picky about destroying emitters which aren't completely processed yet since MIDI support was added. 2019-01-26 10:16:38 +01:00
Richard Harrison a5b32f8eb2 Fix for deleting referenced object from model registry
This should have been in the previous commit - However I managed to mess up the merging of this module due to other changes related to the DDS texture cache.
2019-01-25 21:39:03 +00:00
Richard Harrison 4a86368c8f Fix null ref during load.
This happened a few times
2019-01-25 21:39:03 +00:00
Richard Harrison 3730cc48a5 Fix particles active even when disabled during load.
Possibly this could be fixed better by using the plugin string data - but there is nothing that currently set this; and it seems easier to use the particle callback enabled flag.
2019-01-25 21:39:03 +00:00
Richard Harrison 8a55c2f44f Fix for deleting still referenced object
ref https://sourceforge.net/p/flightgear/codetickets/2105/

Use the thread safe versions (getRef) of the objectcache methods
2019-01-25 21:39:03 +00:00
Erik Hofman ef1cbae22b Split up SIMD support in ENABLE_SIMD which enables sse2 support for the compiler and ENABLE_SIMD_CODE which enables the hand crafted SIMD math functions which defaults to OFF now since compilers have catched up on generating optimized vectorized SIMD code. 2019-01-15 11:01:24 +01:00
James Turner 61f322f201 Bump patch version to 2018.3.2 2019-01-06 16:14:10 +00:00
Stuart Buchanan becbef96f5 Fix effects for MP models - ticket 2076
https://sourceforge.net/p/flightgear/codetickets/2076/

Effects were being instantiated by the loader for
all models, rather than just simple .ac/.obj models.
2018-11-06 17:44:06 +00:00
James Turner 89b3fadf0f Fix for assert with empty systems
Empty subsystem groups didn’t set their init state correctly, leading
to an assert on post-init. Fix this and add a test for it.

https://sourceforge.net/p/flightgear/codetickets/2043/
2018-10-23 15:30:32 +01:00
James Turner 4a1a9ea9c1 Catalogs: allow migration to alternate IDs 2018-10-17 16:24:26 +01:00
James Turner efc609577f Packages: check for existing update when scheduling
This is fixing an issue identified in the launcher in a secondary way,
to ensure if another user of the API tries to schedule an already
scheduled package, we ignore the second request.
2018-10-17 16:24:20 +01:00
James Turner 6ffc501566 Mac: Set CMake OS-X deployment target correctly
Also raises the OS-X min version to 10.9 for libc++ compat
2018-10-17 16:24:15 +01:00
James Turner 9785cadbd0 Fix a debug message left in the terrasync code 2018-10-05 10:41:39 +01:00
316 changed files with 7331 additions and 19824 deletions
-2
View File
@@ -15,5 +15,3 @@ install_manifest.txt
build* build*
Build Build
CMakeLists.txt.user CMakeLists.txt.user
3rdparty/expat_2.2.6/
nbproject
+1 -1
View File
@@ -1,7 +1,7 @@
configure_file ( configure_file (
"${PROJECT_SOURCE_DIR}/3rdparty/expat/expat_config_cmake.in" "${PROJECT_SOURCE_DIR}/3rdparty/expat/expat_config_cmake.in"
"${PROJECT_BINARY_DIR}/3rdparty/expat/simgear_expat_config.h" "${PROJECT_BINARY_DIR}/3rdparty/expat/expat_config.h"
) )
set(expat_sources set(expat_sources
-2
View File
@@ -18,8 +18,6 @@
#include "amigaconfig.h" #include "amigaconfig.h"
#elif defined(__WATCOMC__) #elif defined(__WATCOMC__)
#include "watcomconfig.h" #include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#elif defined(HAVE_EXPAT_CONFIG_H) #elif defined(HAVE_EXPAT_CONFIG_H)
#include "expat_config.h" #include "expat_config.h"
#endif /* ndef COMPILED_FROM_DSP */ #endif /* ndef COMPILED_FROM_DSP */
-2
View File
@@ -12,8 +12,6 @@
#include "amigaconfig.h" #include "amigaconfig.h"
#elif defined(__WATCOMC__) #elif defined(__WATCOMC__)
#include "watcomconfig.h" #include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#else #else
#ifdef HAVE_EXPAT_CONFIG_H #ifdef HAVE_EXPAT_CONFIG_H
#include "expat_config.h" #include "expat_config.h"
-2
View File
@@ -12,8 +12,6 @@
#include "amigaconfig.h" #include "amigaconfig.h"
#elif defined(__WATCOMC__) #elif defined(__WATCOMC__)
#include "watcomconfig.h" #include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#else #else
#ifdef HAVE_EXPAT_CONFIG_H #ifdef HAVE_EXPAT_CONFIG_H
#include "expat_config.h" #include "expat_config.h"
+3 -3
View File
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
# include <winsock2.h> /* includes <windows.h> */ # include <winsock2.h> /* includes <windows.h> */
# include <iphlpapi.h> /* for dns server addresses etc */ # include <iphlpapi.h> /* for dns server addresses etc */
#else #else
@@ -53,7 +53,7 @@ static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
dns_add_srch(ctx, srch); dns_add_srch(ctx, srch);
} }
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
#ifndef NO_IPHLPAPI #ifndef NO_IPHLPAPI
/* Apparently, some systems does not have proper headers for IPHLPAIP to work. /* Apparently, some systems does not have proper headers for IPHLPAIP to work.
@@ -217,7 +217,7 @@ int dns_init(struct dns_ctx *ctx, int do_open) {
ctx = &dns_defctx; ctx = &dns_defctx;
dns_reset(ctx); dns_reset(ctx);
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
if (dns_initns_iphlpapi(ctx) != 0) if (dns_initns_iphlpapi(ctx) != 0)
dns_initns_registry(ctx); dns_initns_registry(ctx);
/*XXX WINDOWS: probably good to get default domain and search list too... /*XXX WINDOWS: probably good to get default domain and search list too...
+4 -4
View File
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
# include <winsock2.h> /* includes <windows.h> */ # include <winsock2.h> /* includes <windows.h> */
# include <ws2tcpip.h> /* needed for struct in6_addr */ # include <ws2tcpip.h> /* needed for struct in6_addr */
#else #else
@@ -392,7 +392,7 @@ dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data) {
} }
static unsigned dns_nonrandom_32(void) { static unsigned dns_nonrandom_32(void) {
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
FILETIME ft; FILETIME ft;
GetSystemTimeAsFileTime(&ft); GetSystemTimeAsFileTime(&ft);
return ft.dwLowDateTime; return ft.dwLowDateTime;
@@ -551,7 +551,7 @@ int dns_open(struct dns_ctx *ctx) {
ctx->dnsc_qstatus = DNS_E_TEMPFAIL; ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
return -1; return -1;
} }
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
{ unsigned long on = 1; { unsigned long on = 1;
if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) { if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) {
closesocket(sock); closesocket(sock);
@@ -991,7 +991,7 @@ again: /* receive the reply */
* or remote. On local errors, we should stop, while * or remote. On local errors, we should stop, while
* remote errors should be ignored (for now anyway). * remote errors should be ignored (for now anyway).
*/ */
#if defined(_WINDOWS) || defined(WINDOWS) #ifdef WINDOWS
if (WSAGetLastError() == WSAEWOULDBLOCK) if (WSAGetLastError() == WSAEWOULDBLOCK)
#else #else
if (errno == EAGAIN) if (errno == EAGAIN)
+1 -1
View File
@@ -27,7 +27,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#if !defined(_WINDOWS) && !defined(WINDOWS) #ifndef WINDOWS
# include <sys/types.h> # include <sys/types.h>
# include <netinet/in.h> # include <netinet/in.h>
#endif #endif
+40 -63
View File
@@ -10,15 +10,6 @@ if(COMMAND cmake_policy)
if(POLICY CMP0067) if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW) cmake_policy(SET CMP0067 NEW)
endif() endif()
# OpenGL VND policy : use the old definition for now, until we can audit this
if(POLICY CMP0072)
cmake_policy(SET CMP0072 OLD)
endif()
if(POLICY CMP0093)
cmake_policy(SET CMP0093 NEW)
endif()
endif() endif()
@@ -49,7 +40,7 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_STANDARD_REQUIRED YES)
# read 'version' file into a variable (stripping any newlines or spaces) # read 'version' file into a variable (stripping any newlines or spaces)
file(READ simgear-version versionFile) file(READ version versionFile)
string(STRIP ${versionFile} SIMGEAR_VERSION) string(STRIP ${versionFile} SIMGEAR_VERSION)
project(SimGear VERSION ${SIMGEAR_VERSION} LANGUAGES C CXX) project(SimGear VERSION ${SIMGEAR_VERSION} LANGUAGES C CXX)
@@ -143,7 +134,6 @@ if (NOT ENABLE_SIMD AND ENABLE_SIMD_CODE)
endif() endif()
include (DetectArch) include (DetectArch)
include (ExportDebugSymbols)
# until the fstream fix is applied and generally available in OSG, # until the fstream fix is applied and generally available in OSG,
# keep the compatability link option as the default # keep the compatability link option as the default
@@ -160,7 +150,7 @@ endif()
if (MSVC) if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} DIRECTORY) GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
if (CMAKE_CL_64) if (CMAKE_CL_64)
SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty.x64") SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty.x64")
else (CMAKE_CL_64) else (CMAKE_CL_64)
@@ -171,11 +161,6 @@ if (MSVC)
else (EXISTS ${TEST_3RDPARTY_DIR}) else (EXISTS ${TEST_3RDPARTY_DIR})
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted") set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (EXISTS ${TEST_3RDPARTY_DIR}) endif (EXISTS ${TEST_3RDPARTY_DIR})
# override CMake default RelWithDebInfo flags. This is important to ensure
# good performance
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/Zi /O2 /Ob2 /D NDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/Zi /O2 /Ob2 /D NDEBUG")
else (MSVC) else (MSVC)
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted") set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (MSVC) endif (MSVC)
@@ -188,17 +173,15 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
set( OSG_MSVC "msvc" ) set( OSG_MSVC "msvc" )
if (${MSVC_VERSION_MAJOR} EQUAL "19") if (${MSVC_VERSION_MAJOR} EQUAL "19")
if (${MSVC_VERSION_MINOR} GREATER_EQUAL "20") if (${MSVC_VERSION_MINOR} EQUAL "00")
set( OSG_MSVC ${OSG_MSVC}142 )
elseif (${MSVC_VERSION_MINOR} GREATER_EQUAL "10")
set( OSG_MSVC ${OSG_MSVC}141 )
else ()
set( OSG_MSVC ${OSG_MSVC}140 ) set( OSG_MSVC ${OSG_MSVC}140 )
else ()
set( OSG_MSVC ${OSG_MSVC}141 )
endif () endif ()
elseif (${MSVC_VERSION_MAJOR} EQUAL "18") elseif (${MSVC_VERSION_MAJOR} EQUAL "18")
set( OSG_MSVC ${OSG_MSVC}120 ) set( OSG_MSVC ${OSG_MSVC}120 )
else () else ()
message(FATAL_ERROR "Visual Studio 2013 or higher is required") message(FATAL_ERROR "Visual Studio 2013/15/17 is required")
endif () endif ()
if (CMAKE_CL_64) if (CMAKE_CL_64)
@@ -215,7 +198,7 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
# if this variable was not set by the user, set it to 3rdparty root's # if this variable was not set by the user, set it to 3rdparty root's
# parent dir, which is the normal location for people using our # parent dir, which is the normal location for people using our
# windows-3rd-party repo # windows-3rd-party repo
get_filename_component(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} DIRECTORY) GET_FILENAME_COMPONENT(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} PATH)
set(BOOST_INCLUDEDIR ${MSVC_ROOT_PARENT_DIR}) set(BOOST_INCLUDEDIR ${MSVC_ROOT_PARENT_DIR})
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}") message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
endif() endif()
@@ -233,7 +216,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD
endif() endif()
find_package(Boost REQUIRED) find_package(Boost REQUIRED)
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION -DBOOST_NO_STDLIB_CONFIG") set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION")
include(BoostTestTargets) include(BoostTestTargets)
if(SIMGEAR_HEADLESS) if(SIMGEAR_HEADLESS)
@@ -278,15 +261,7 @@ else()
endif() endif()
endif(SIMGEAR_HEADLESS) endif(SIMGEAR_HEADLESS)
if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
# As of 2020-08-01, OpenBSD's system zlib is slightly old, but it's usable
# with a workaround in simgear/io/iostreams/gzfstream.cxx.
find_package(ZLIB 1.2.3 REQUIRED)
else()
find_package(ZLIB 1.2.4 REQUIRED) find_package(ZLIB 1.2.4 REQUIRED)
endif()
find_package(LibLZMA REQUIRED)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
if (SYSTEM_EXPAT) if (SYSTEM_EXPAT)
@@ -296,6 +271,9 @@ if (SYSTEM_EXPAT)
else() else()
message(STATUS "Using built-in expat code") message(STATUS "Using built-in expat code")
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
set(EXPAT_INCLUDE_DIRS set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat ${PROJECT_SOURCE_DIR}/3rdparty/expat
${PROJECT_BINARY_DIR}/3rdparty/expat) ${PROJECT_BINARY_DIR}/3rdparty/expat)
@@ -314,10 +292,11 @@ endif()
if(ENABLE_RTI) if(ENABLE_RTI)
find_package(PkgConfig) find_package(PkgConfig)
if(PKG_CONFIG_FOUND) if(PKG_CONFIG_FOUND)
SET(ENV{PKG_CONFIG_PATH} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig:$ENV{PKG_CONFIG_PATH}") SET(ENV{PKG_CONFIG_PATH} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
pkg_check_modules(RTI hla-rti13) pkg_check_modules(RTI hla-rti13)
endif(PKG_CONFIG_FOUND) endif(PKG_CONFIG_FOUND)
if(RTI_FOUND) if(RTI_FOUND)
SET(RTI_INCLUDE_DIR "${RTI_INCLUDE_DIRS}")
message(STATUS "RTI: ENABLED") message(STATUS "RTI: ENABLED")
else() else()
message(STATUS "RTI: DISABLED") message(STATUS "RTI: DISABLED")
@@ -431,8 +410,16 @@ if(CMAKE_COMPILER_IS_GNUCXX)
message(WARNING "GCC 4.4 will be required soon, please upgrade") message(WARNING "GCC 4.4 will be required soon, please upgrade")
endif() endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline")
elseif (ENABLE_SIMD)
if (X86 OR X86_64) if (X86 OR X86_64)
set(SIMD_COMPILER_FLAGS "-msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
endif()
endif() endif()
# certain GCC versions don't provide the atomic builds, and hence # certain GCC versions don't provide the atomic builds, and hence
@@ -441,10 +428,6 @@ if(CMAKE_COMPILER_IS_GNUCXX)
check_cxx_source_compiles( check_cxx_source_compiles(
"int main() { unsigned mValue; return __sync_add_and_fetch(&mValue, 1); }" "int main() { unsigned mValue; return __sync_add_and_fetch(&mValue, 1); }"
GCC_ATOMIC_BUILTINS_FOUND) GCC_ATOMIC_BUILTINS_FOUND)
# override CMake default RelWithDebInfo flags.
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
endif(CMAKE_COMPILER_IS_GNUCXX) endif(CMAKE_COMPILER_IS_GNUCXX)
if (CLANG) if (CLANG)
@@ -455,11 +438,17 @@ if (CLANG)
# fix Boost compilation :( # fix Boost compilation :(
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
# override CMake default RelWithDebInfo flags. if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG") set(CMAKE_C_FLAGS
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG") "${CMAKE_C_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
set(CMAKE_CXX_FLAGS
set(SIMD_COMPILER_FLAGS "-msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") "${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
elseif (ENABLE_SIMD)
if (X86 OR X86_64)
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
endif()
endif()
endif() endif()
if (ENABLE_OPENMP) if (ENABLE_OPENMP)
@@ -491,8 +480,14 @@ if(WIN32)
if(MSVC) if(MSVC)
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /MP") set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /MP")
if(ENABLE_SIMD)
if (X86) if (X86)
set(SIMD_COMPILER_FLAGS "/arch:SSE /arch:SSE2") SET(CMAKE_C_FLAGS_RELEASE "/O2 /arch:SSE /arch:SSE2")
SET(CMAKE_CXX_FLAGS_RELEASE "/O2 /arch:SSE /arch:SSE2")
else()
SET(CMAKE_C_FLAGS_RELEASE "/O2")
SET(CMAKE_CXX_FLAGS_RELEASE "/O2")
endif()
endif() endif()
if (NOT OSG_FSTREAM_EXPORT_FIXED) if (NOT OSG_FSTREAM_EXPORT_FIXED)
@@ -516,20 +511,6 @@ if(WIN32)
set( RT_LIBRARY "winmm" ) set( RT_LIBRARY "winmm" )
endif(WIN32) endif(WIN32)
# append the SIMD flags if requested
if (ENABLE_SIMD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SIMD_COMPILER_FLAGS}")
# set for multi-configuration generators
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${SIMD_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${SIMD_COMPILER_FLAGS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${SIMD_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${SIMD_COMPILER_FLAGS}")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
@@ -540,10 +521,6 @@ include(CheckCXXFeatures)
# ahead of system-installed libs # ahead of system-installed libs
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear) include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
include_directories("/usr/X11R6/include")
endif()
add_definitions(-DHAVE_CONFIG_H) add_definitions(-DHAVE_CONFIG_H)
# configure a header file to pass some of the CMake settings # configure a header file to pass some of the CMake settings
+6 -12
View File
@@ -46,17 +46,11 @@ set(BOOST_TEST_TARGET_PREFIX "test")
if(NOT Boost_FOUND) if(NOT Boost_FOUND)
find_package(Boost 1.34.0 QUIET) find_package(Boost 1.34.0 QUIET)
endif() endif()
if("${Boost_VERSION}0" LESS "1034000")
if (NOT Boost_VERSION_MACRO)
# Compatibility with pre CMP0093 (CMake 3.15)
set(Boost_VERSION_MACRO ${Boost_VERSION})
endif()
if("${Boost_VERSION_MACRO}0" LESS "1034000")
set(_shared_msg set(_shared_msg
"NOTE: boost::test-based targets and tests cannot " "NOTE: boost::test-based targets and tests cannot "
"be added: boost >= 1.34.0 required but not found. " "be added: boost >= 1.34.0 required but not found. "
"(found: '${Boost_VERSION_MACRO}'; want >=103400) ") "(found: '${Boost_VERSION}'; want >=103400) ")
if(ENABLE_TESTS) if(ENABLE_TESTS)
message(FATAL_ERROR message(FATAL_ERROR
${_shared_msg} ${_shared_msg}
@@ -72,7 +66,7 @@ endif()
include(GetForceIncludeDefinitions) include(GetForceIncludeDefinitions)
include(CopyResourcesToBuildTree) include(CopyResourcesToBuildTree)
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000") if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
set(_boosttesttargets_libs) set(_boosttesttargets_libs)
set(_boostConfig "BoostTestTargetsIncluded.h") set(_boostConfig "BoostTestTargetsIncluded.h")
if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
@@ -86,7 +80,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
set(_boostConfig "BoostTestTargetsDynamic.h") set(_boostConfig "BoostTestTargetsDynamic.h")
endif() endif()
endif() endif()
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY) get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH)
configure_file("${_moddir}/${_boostConfig}" configure_file("${_moddir}/${_boostConfig}"
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h" "${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
COPYONLY) COPYONLY)
@@ -135,7 +129,7 @@ function(add_boost_test _name)
"Syntax error in use of add_boost_test: at least one source file required!") "Syntax error in use of add_boost_test: at least one source file required!")
endif() endif()
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000") if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
@@ -227,7 +221,7 @@ function(add_boost_test _name)
set(_test_command ${_target_name}) set(_test_command ${_target_name})
endif() endif()
if(TESTS AND ( "${Boost_VERSION_MACRO}" VERSION_GREATER "103799" )) if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" ))
foreach(_test ${TESTS}) foreach(_test ${TESTS})
add_test( add_test(
${_name}-${_test} ${_name}-${_test}
+2 -2
View File
@@ -30,12 +30,12 @@ function(copy_resources_to_build_tree _target)
endif() endif()
get_target_property(_path ${_target} LOCATION) get_target_property(_path ${_target} LOCATION)
get_filename_component(_path "${_path}" DIRECTORY) get_filename_component(_path "${_path}" PATH)
if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles") if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles")
foreach(_config ${CMAKE_CONFIGURATION_TYPES}) foreach(_config ${CMAKE_CONFIGURATION_TYPES})
get_target_property(_path${_config} ${_target} LOCATION_${_config}) get_target_property(_path${_config} ${_target} LOCATION_${_config})
get_filename_component(_path${_config} "${_path${_config}}" DIRECTORY) get_filename_component(_path${_config} "${_path${_config}}" PATH)
add_custom_command(TARGET ${_target} add_custom_command(TARGET ${_target}
POST_BUILD POST_BUILD
COMMAND COMMAND
-26
View File
@@ -1,26 +0,0 @@
# placehodler target for other ones to depend upon
add_custom_target(
debug_symbols
)
function(export_debug_symbols target)
if (NOT SIMGEAR_SHARED)
return()
endif()
if (APPLE)
add_custom_target(${target}.dSYM
COMMENT "Generating dSYM files for ${target}"
COMMAND dsymutil --out=${target}.dSYM $<TARGET_FILE:${target}>
DEPENDS $<TARGET_FILE:${target}>
)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${target}.dSYM DESTINATION symbols OPTIONAL)
add_dependencies(debug_symbols ${target}.dSYM)
endif()
endfunction()
-124
View File
@@ -1,124 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindLibLZMA
-----------
Find LZMA compression algorithm headers and library.
Imported Targets
^^^^^^^^^^^^^^^^
This module defines :prop_tgt:`IMPORTED` target ``LibLZMA::LibLZMA``, if
liblzma has been found.
Result variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
``LIBLZMA_FOUND``
True if liblzma headers and library were found.
``LIBLZMA_INCLUDE_DIRS``
Directory where liblzma headers are located.
``LIBLZMA_LIBRARIES``
Lzma libraries to link against.
``LIBLZMA_HAS_AUTO_DECODER``
True if lzma_auto_decoder() is found (required).
``LIBLZMA_HAS_EASY_ENCODER``
True if lzma_easy_encoder() is found (required).
``LIBLZMA_HAS_LZMA_PRESET``
True if lzma_lzma_preset() is found (required).
``LIBLZMA_VERSION_MAJOR``
The major version of lzma
``LIBLZMA_VERSION_MINOR``
The minor version of lzma
``LIBLZMA_VERSION_PATCH``
The patch version of lzma
``LIBLZMA_VERSION_STRING``
version number as a string (ex: "5.0.3")
#]=======================================================================]
find_path(LIBLZMA_INCLUDE_DIR lzma.h )
if(NOT LIBLZMA_LIBRARY)
find_library(LIBLZMA_LIBRARY_RELEASE NAMES lzma liblzma NAMES_PER_DIR PATH_SUFFIXES lib)
find_library(LIBLZMA_LIBRARY_DEBUG NAMES lzmad liblzmad NAMES_PER_DIR PATH_SUFFIXES lib)
include(SelectLibraryConfigurations)
select_library_configurations(LIBLZMA)
else()
file(TO_CMAKE_PATH "${LIBLZMA_LIBRARY}" LIBLZMA_LIBRARY)
endif()
if(LIBLZMA_INCLUDE_DIR AND EXISTS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h")
file(STRINGS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h" LIBLZMA_HEADER_CONTENTS REGEX "#define LZMA_VERSION_[A-Z]+ [0-9]+")
string(REGEX REPLACE ".*#define LZMA_VERSION_MAJOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MAJOR "${LIBLZMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define LZMA_VERSION_MINOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MINOR "${LIBLZMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define LZMA_VERSION_PATCH ([0-9]+).*" "\\1" LIBLZMA_VERSION_PATCH "${LIBLZMA_HEADER_CONTENTS}")
set(LIBLZMA_VERSION_STRING "${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}")
unset(LIBLZMA_HEADER_CONTENTS)
endif()
# We're using new code known now as XZ, even library still been called LZMA
# it can be found in http://tukaani.org/xz/
# Avoid using old codebase
if (LIBLZMA_LIBRARY)
include(CheckLibraryExists)
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY})
if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)
set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY})
elseif(LIBLZMA_LIBRARY_RELEASE)
set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_RELEASE})
elseif(LIBLZMA_LIBRARY_DEBUG)
set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_DEBUG})
endif()
CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_auto_decoder "" LIBLZMA_HAS_AUTO_DECODER)
CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_easy_encoder "" LIBLZMA_HAS_EASY_ENCODER)
CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_lzma_preset "" LIBLZMA_HAS_LZMA_PRESET)
unset(LIBLZMA_LIBRARY_check)
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibLZMA REQUIRED_VARS LIBLZMA_LIBRARY
LIBLZMA_INCLUDE_DIR
LIBLZMA_HAS_AUTO_DECODER
LIBLZMA_HAS_EASY_ENCODER
LIBLZMA_HAS_LZMA_PRESET
VERSION_VAR LIBLZMA_VERSION_STRING
)
mark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY )
if (LIBLZMA_FOUND)
set(LIBLZMA_LIBRARIES ${LIBLZMA_LIBRARY})
set(LIBLZMA_INCLUDE_DIRS ${LIBLZMA_INCLUDE_DIR})
if(NOT TARGET LibLZMA::LibLZMA)
add_library(LibLZMA::LibLZMA UNKNOWN IMPORTED)
set_target_properties(LibLZMA::LibLZMA PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${LIBLZMA_INCLUDE_DIR}
IMPORTED_LINK_INTERFACE_LANGUAGES C)
if(LIBLZMA_LIBRARY_RELEASE)
set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(LibLZMA::LibLZMA PROPERTIES
IMPORTED_LOCATION_RELEASE "${LIBLZMA_LIBRARY_RELEASE}")
endif()
if(LIBLZMA_LIBRARY_DEBUG)
set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(LibLZMA::LibLZMA PROPERTIES
IMPORTED_LOCATION_DEBUG "${LIBLZMA_LIBRARY_DEBUG}")
endif()
if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)
set_target_properties(LibLZMA::LibLZMA PROPERTIES
IMPORTED_LOCATION "${LIBLZMA_LIBRARY}")
endif()
endif()
endif ()
+145 -283
View File
@@ -1,4 +1,4 @@
# Doxyfile 1.8.13 # Doxyfile 1.8.6
# This file describes the settings to be used by the documentation system # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@@ -38,7 +38,7 @@ PROJECT_NAME = SimGear
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 2019.2.0 PROJECT_NUMBER = 3.3.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@@ -46,10 +46,10 @@ PROJECT_NUMBER = 2019.2.0
PROJECT_BRIEF = PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify an logo or icon that is included in
# in the documentation. The maximum height of the logo should not exceed 55 # the documentation. The maximum height of the logo should not exceed 55 pixels
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
# the logo to the output directory. # to the output directory.
PROJECT_LOGO = PROJECT_LOGO =
@@ -58,9 +58,9 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If # entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used. # left blank the current directory will be used.
OUTPUT_DIRECTORY = ../docs/SimGear OUTPUT_DIRECTORY = ../doxy
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and # directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this # will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where # option can be useful when feeding doxygen a huge amount of source files, where
@@ -70,14 +70,6 @@ OUTPUT_DIRECTORY = ../docs/SimGear
CREATE_SUBDIRS = NO CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all # The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this # documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language. # information to generate all constant output in the proper language.
@@ -93,14 +85,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
# descriptions after the members that are listed in the file and class # descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this. # documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES. # The default value is: YES.
BRIEF_MEMBER_DESC = YES BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
# description of a member or function before the detailed description # description of a member or function before the detailed description
# #
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -135,7 +127,7 @@ ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the # before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used # shortest path that makes the file name unique will be used
# The default value is: YES. # The default value is: YES.
@@ -205,9 +197,9 @@ MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
# page for each member. If set to NO, the documentation of a member will be part # new page for each member. If set to NO, the documentation of a member will be
# of the file/class/namespace that contains it. # part of the file/class/namespace that contains it.
# The default value is: NO. # The default value is: NO.
SEPARATE_MEMBER_PAGES = NO SEPARATE_MEMBER_PAGES = NO
@@ -269,14 +261,11 @@ OPTIMIZE_OUTPUT_VHDL = NO
# extension. Doxygen has a built-in mapping, but you can override or extend it # extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and # using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript, # language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# Fortran. In the later case the parser tries to guess whether the code is fixed # (default is Fortran), use: inc=Fortran f=C.
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
# #
# Note: For files without extension you can use no_extension as a placeholder. # Note For files without extension you can use no_extension as a placeholder.
# #
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise # Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen. # the files are not read by doxygen.
@@ -293,19 +282,10 @@ EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES MARKDOWN_SUPPORT = YES
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
# When enabled doxygen tries to link words that correspond to documented # When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can # classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or # be prevented in individual cases by by putting a % sign in front of the word
# globally by setting AUTOLINK_SUPPORT to NO. # or globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES. # The default value is: YES.
AUTOLINK_SUPPORT = YES AUTOLINK_SUPPORT = YES
@@ -345,20 +325,13 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES then doxygen will reuse the documentation of the first # tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default # member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly. # all members of a group must be documented explicitly.
# The default value is: NO. # The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO DISTRIBUTE_GROUP_DOC = NO
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type # Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that # (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent # type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -417,7 +390,7 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options # Build related configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private # documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the # class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -425,37 +398,37 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES. # normally produced when WARNINGS is set to YES.
# The default value is: NO. # The default value is: NO.
EXTRACT_ALL = YES EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
# be included in the documentation. # be included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_PRIVATE = NO EXTRACT_PRIVATE = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# scope will be included in the documentation. # scope will be included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_PACKAGE = NO EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # If the EXTRACT_STATIC tag is set to YES all static members of a file will be
# included in the documentation. # included in the documentation.
# The default value is: NO. # The default value is: NO.
EXTRACT_STATIC = YES EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO, # locally in source files will be included in the documentation. If set to NO
# only classes defined in header files are included. Does not have any effect # only classes defined in header files are included. Does not have any effect
# for Java sources. # for Java sources.
# The default value is: YES. # The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. If set to YES, local methods, # This flag is only useful for Objective-C code. When set to YES local methods,
# which are defined in the implementation section but not in the interface are # which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO, only methods in the interface are # included in the documentation. If set to NO only methods in the interface are
# included. # included.
# The default value is: NO. # The default value is: NO.
@@ -480,21 +453,21 @@ HIDE_UNDOC_MEMBERS = YES
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set # undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option # to NO these classes will be included in the various overviews. This option has
# has no effect if EXTRACT_ALL is enabled. # no effect if EXTRACT_ALL is enabled.
# The default value is: NO. # The default value is: NO.
HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be # (class|struct|union) declarations. If set to NO these declarations will be
# included in the documentation. # included in the documentation.
# The default value is: NO. # The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO, these # documentation blocks found inside the body of a function. If set to NO these
# blocks will be appended to the function's detailed documentation block. # blocks will be appended to the function's detailed documentation block.
# The default value is: NO. # The default value is: NO.
@@ -508,7 +481,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also # names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ # allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows # in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO. # and Mac users are advised to set this option to NO.
@@ -517,19 +490,12 @@ INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES, the # their full class and namespace scopes in the documentation. If set to YES the
# scope will be hidden. # scope will be hidden.
# The default value is: NO. # The default value is: NO.
HIDE_SCOPE_NAMES = NO HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file. # the files that are included by a file in the documentation of that file.
# The default value is: YES. # The default value is: YES.
@@ -557,14 +523,14 @@ INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member # (detailed) documentation of file and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order. # name. If set to NO the members will appear in declaration order.
# The default value is: YES. # The default value is: YES.
SORT_MEMBER_DOCS = YES SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member # descriptions of file, namespace and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order. Note that # name. If set to NO the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list. # this will also influence the order of the classes in the class list.
# The default value is: NO. # The default value is: NO.
@@ -609,14 +575,16 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
# list. This list is created by putting \todo commands in the documentation. # todo list. This list is created by putting \todo commands in the
# documentation.
# The default value is: YES. # The default value is: YES.
GENERATE_TODOLIST = YES GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
# list. This list is created by putting \test commands in the documentation. # test list. This list is created by putting \test commands in the
# documentation.
# The default value is: YES. # The default value is: YES.
GENERATE_TESTLIST = YES GENERATE_TESTLIST = YES
@@ -652,8 +620,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30 MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES, the # the bottom of the documentation of classes and structs. If set to YES the list
# list will mention the files that were used to generate the documentation. # will mention the files that were used to generate the documentation.
# The default value is: YES. # The default value is: YES.
SHOW_USED_FILES = YES SHOW_USED_FILES = YES
@@ -701,7 +669,8 @@ LAYOUT_FILE =
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using # For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references. # search path. Do not use file names with spaces, bibtex cannot handle them. See
# also \cite for info how to create references.
CITE_BIB_FILES = CITE_BIB_FILES =
@@ -725,7 +694,7 @@ QUIET = NO
WARNINGS = YES WARNINGS = YES
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled. # will automatically be disabled.
# The default value is: YES. # The default value is: YES.
@@ -742,18 +711,12 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return # are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete # value. If set to NO doxygen will only warn about wrong or incomplete parameter
# parameter documentation, but not about the absence of documentation. # documentation, but not about the absence of documentation.
# The default value is: NO. # The default value is: NO.
WARN_NO_PARAMDOC = NO WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# The default value is: NO.
WARN_AS_ERROR = NO
# The WARN_FORMAT tag determines the format of the warning messages that doxygen # The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which # can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated # will be replaced by the file and line number from which the warning originated
@@ -777,7 +740,7 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain # The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or # documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with # directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # spaces.
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = DoxygenMain.cxx \ INPUT = DoxygenMain.cxx \
@@ -794,17 +757,12 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. # *.h) to filter out the source-files in the directories. If left blank the
# # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
# Note that for custom extensions or not directly supported extensions you also # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
# need to set EXTENSION_MAPPING for the extension otherwise the files are not # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
# read by doxygen. # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# # *.qsf, *.as and *.js.
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
FILE_PATTERNS = *.h \ FILE_PATTERNS = *.h \
*.hxx \ *.hxx \
@@ -894,10 +852,6 @@ IMAGE_PATH =
# Note that the filter must not add or remove lines; it is applied before the # Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # or removed, the anchors will not be placed correctly.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
INPUT_FILTER = INPUT_FILTER =
@@ -907,10 +861,6 @@ INPUT_FILTER =
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the # filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied. # patterns match the file name, INPUT_FILTER is applied.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
FILTER_PATTERNS = FILTER_PATTERNS =
@@ -975,7 +925,7 @@ REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES then the hyperlinks from functions in REFERENCES_RELATION and # to YES, then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation. # link to the documentation.
# The default value is: YES. # The default value is: YES.
@@ -1022,25 +972,6 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse-libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index # Configuration options related to the alphabetical class index
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1071,7 +1002,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output # Configuration options related to the HTML output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
# The default value is: YES. # The default value is: YES.
GENERATE_HTML = YES GENERATE_HTML = YES
@@ -1133,15 +1064,13 @@ HTML_FOOTER =
HTML_STYLESHEET = HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
# cascading style sheets that are included after the standard style sheets # defined cascading style sheet that is included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects. # created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the # This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefore more robust against future updates. # standard style sheet and is therefor more robust against future updates.
# Doxygen will copy the style sheet files to the output directory. # Doxygen will copy the style sheet file to the output directory. For an example
# Note: The order of the extra style sheet files is of importance (e.g. the last # see the documentation.
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = HTML_EXTRA_STYLESHEET =
@@ -1188,9 +1117,8 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this # page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the # to NO can help when comparing the output of multiple runs.
# documentation is up to date. # The default value is: YES.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES HTML_TIMESTAMP = YES
@@ -1286,15 +1214,15 @@ GENERATE_HTMLHELP = NO
CHM_FILE = CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path # The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler (hhc.exe). If non-empty, # including file name) of the HTML help compiler ( hhc.exe). If non-empty
# doxygen will try to run the HTML help compiler on the generated index.hhp. # doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path. # The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION = HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated # The GENERATE_CHI flag controls if a separate .chi index file is generated (
# (YES) or that it should be included in the master .chm file (NO). # YES) or that it should be included in the master .chm file ( NO).
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1306,9 +1234,8 @@ GENERATE_CHI = NO
CHM_INDEX_ENCODING = CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated # The BINARY_TOC flag controls whether a binary table of contents is generated (
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # YES) or a normal table of contents ( NO) in the .chm file.
# enables the Previous and Next buttons.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1449,7 +1376,7 @@ ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250 TREEVIEW_WIDTH = 250
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
# external symbols imported via tag files in a separate window. # external symbols imported via tag files in a separate window.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1478,7 +1405,7 @@ FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering # http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # instead of using prerendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When # installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path # enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option. # to it using the MATHJAX_RELPATH option.
@@ -1548,11 +1475,11 @@ SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There # implemented using a web server instead of a web client using Javascript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH # are two flavours of web server based searching depending on the
# setting. When disabled, doxygen will generate a PHP script for searching and # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing # searching and an index file used by the script. When EXTERNAL_SEARCH is
# and searching needs to be provided by external tools. See the section # enabled the indexing and searching needs to be provided by external tools. See
# "External Indexing and Searching" for details. # the section "External Indexing and Searching" for details.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES. # This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1615,7 +1542,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output # Configuration options related to the LaTeX output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
# The default value is: YES. # The default value is: YES.
GENERATE_LATEX = NO GENERATE_LATEX = NO
@@ -1646,7 +1573,7 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some # documents. This may be useful for small projects and may help to save some
# trees in general. # trees in general.
# The default value is: NO. # The default value is: NO.
@@ -1664,12 +1591,9 @@ COMPACT_LATEX = NO
PAPER_TYPE = letter PAPER_TYPE = letter
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. The package can be specified just # that should be included in the LaTeX output. To get the times font for
# by its name or with the correct syntax as to be used with the LaTeX # instance you can specify
# \usepackage command. To get the times font for instance you can specify : # EXTRA_PACKAGES=times
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
# To use the option intlimits with the amsmath package you can specify:
# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included. # If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1683,36 +1607,23 @@ EXTRA_PACKAGES =
# #
# Note: Only use a user-defined header if you know what you are doing! The # Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title, # following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber, # $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty # replace them by respectively the title of the page, the current date and time,
# string, for the replacement values of the other commands the user is referred # only the current date, the version number of doxygen, the project name (see
# to HTML_HEADER. # PROJECT_NAME), or the project number (see PROJECT_NUMBER).
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER = LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last # generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer. See # chapter. If it is left blank doxygen will generate a standard footer.
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
# #
# Note: Only use a user-defined footer if you know what you are doing! # Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER = LATEX_FOOTER =
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_STYLESHEET =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output # other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or # directory. Note that the files will be copied as-is; there are no commands or
@@ -1730,8 +1641,8 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate # If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a # the PDF file directly from the LaTeX files. Set this option to YES to get a
# higher quality PDF documentation. # higher quality PDF documentation.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1772,19 +1683,11 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the RTF output # Configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF # RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors. # readers/editors.
# The default value is: NO. # The default value is: NO.
@@ -1799,7 +1702,7 @@ GENERATE_RTF = YES
RTF_OUTPUT = rtf RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some # documents. This may be useful for small projects and may help to save some
# trees in general. # trees in general.
# The default value is: NO. # The default value is: NO.
@@ -1836,21 +1739,11 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE = RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the man page output # Configuration options related to the man page output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
# classes and files. # classes and files.
# The default value is: NO. # The default value is: NO.
@@ -1874,13 +1767,6 @@ MAN_OUTPUT = man
MAN_EXTENSION = .3 MAN_EXTENSION = .3
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_SUBDIR =
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real # will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without # man page(s). These additional files only source the real man page, but without
@@ -1894,7 +1780,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output # Configuration options related to the XML output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
# captures the structure of the code including all documentation. # captures the structure of the code including all documentation.
# The default value is: NO. # The default value is: NO.
@@ -1908,7 +1794,19 @@ GENERATE_XML = NO
XML_OUTPUT = xml XML_OUTPUT = xml
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_SCHEMA =
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to # listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size # the XML output. Note that enabling this will significantly increase the size
# of the XML output. # of the XML output.
@@ -1921,7 +1819,7 @@ XML_PROGRAMLISTING = YES
# Configuration options related to the DOCBOOK output # Configuration options related to the DOCBOOK output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
# that can be used to generate PDF. # that can be used to generate PDF.
# The default value is: NO. # The default value is: NO.
@@ -1935,23 +1833,14 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output # Configuration options for the AutoGen Definitions output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an # If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
# AutoGen Definitions (see http://autogen.sf.net) file that captures the # Definitions (see http://autogen.sf.net) file that captures the structure of
# structure of the code including all documentation. Note that this feature is # the code including all documentation. Note that this feature is still
# still experimental and incomplete at the moment. # experimental and incomplete at the moment.
# The default value is: NO. # The default value is: NO.
GENERATE_AUTOGEN_DEF = NO GENERATE_AUTOGEN_DEF = NO
@@ -1960,7 +1849,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output # Configuration options related to the Perl module output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
# file that captures the structure of the code including all documentation. # file that captures the structure of the code including all documentation.
# #
# Note that this feature is still experimental and incomplete at the moment. # Note that this feature is still experimental and incomplete at the moment.
@@ -1968,7 +1857,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output. # output from the Perl module output.
# The default value is: NO. # The default value is: NO.
@@ -1976,9 +1865,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to # formatted so it can be parsed by a human reader. This is useful if you want to
# understand what is going on. On the other hand, if this tag is set to NO, the # understand what is going on. On the other hand, if this tag is set to NO the
# size of the Perl module output will be much smaller and Perl will parse it # size of the Perl module output will be much smaller and Perl will parse it
# just the same. # just the same.
# The default value is: YES. # The default value is: YES.
@@ -1998,14 +1887,14 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor # Configuration options related to the preprocessor
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
# C-preprocessor directives found in the sources and include files. # C-preprocessor directives found in the sources and include files.
# The default value is: YES. # The default value is: YES.
ENABLE_PREPROCESSING = YES ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names # If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be # in the source code. If set to NO only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting # performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES. # EXPAND_ONLY_PREDEF to YES.
# The default value is: NO. # The default value is: NO.
@@ -2021,7 +1910,7 @@ MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES, the include files in the # If the SEARCH_INCLUDES tag is set to YES the includes files in the
# INCLUDE_PATH will be searched if a #include is found. # INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -2063,9 +1952,9 @@ PREDEFINED =
EXPAND_AS_DEFINED = EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all references to function-like macros that are alone on a line, have # remove all refrences to function-like macros that are alone on a line, have an
# an all uppercase name, and do not end with a semicolon. Such function macros # all uppercase name, and do not end with a semicolon. Such function macros are
# are typically used for boiler-plate code, and will confuse the parser if not # typically used for boiler-plate code, and will confuse the parser if not
# removed. # removed.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -2085,7 +1974,7 @@ SKIP_FUNCTION_MACROS = YES
# where loc1 and loc2 can be relative or absolute paths or URLs. See the # where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use # section "Linking to external documentation" for more information about the use
# of tag files. # of tag files.
# Note: Each tag file must have a unique name (where the name does NOT include # Note: Each tag file must have an unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is # the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here. # run, you must also specify the path to the tagfile here.
@@ -2097,21 +1986,20 @@ TAGFILES =
GENERATE_TAGFILE = GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in # If the ALLEXTERNALS tag is set to YES all external class will be listed in the
# the class index. If set to NO, only the inherited external classes will be # class index. If set to NO only the inherited external classes will be listed.
# listed.
# The default value is: NO. # The default value is: NO.
ALLEXTERNALS = NO ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
# in the modules index. If set to NO, only the current project's groups will be # the modules index. If set to NO, only the current project's groups will be
# listed. # listed.
# The default value is: YES. # The default value is: YES.
EXTERNAL_GROUPS = YES EXTERNAL_GROUPS = YES
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will # the related pages index. If set to NO, only the current project's pages will
# be listed. # be listed.
# The default value is: YES. # The default value is: YES.
@@ -2128,14 +2016,14 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool # Configuration options related to the dot tool
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT # NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more # disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs. # powerful graphs.
# The default value is: YES. # The default value is: YES.
CLASS_DIAGRAMS = NO CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc # You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see: # command. Doxygen will then run the mscgen tool (see:
@@ -2153,7 +2041,7 @@ MSCGEN_PATH =
DIA_PATH = DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance # If set to YES, the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class. # and usage relations if the target is undocumented or is not a class.
# The default value is: YES. # The default value is: YES.
@@ -2164,9 +2052,9 @@ HIDE_UNDOC_RELATIONS = YES
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is # Bell Labs. The other options in this section have no effect if this option is
# set to NO # set to NO
# The default value is: YES. # The default value is: NO.
HAVE_DOT = YES HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of # to run in parallel. When set to 0 doxygen will base this on the number of
@@ -2178,7 +2066,7 @@ HAVE_DOT = YES
DOT_NUM_THREADS = 0 DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen # When you want a differently looking font n the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make # generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a # sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by # standard location or by setting the DOTFONTPATH environment variable or by
@@ -2226,7 +2114,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling # collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language. # Language.
# The default value is: NO. # The default value is: NO.
@@ -2278,24 +2166,22 @@ INCLUDED_BY_GRAPH = YES
# #
# Note that enabling this option will significantly increase the time of a run. # Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected # So in most cases it will be better to enable call graphs for selected
# functions only using the \callgraph command. Disabling a call graph can be # functions only using the \callgraph command.
# accomplished by means of the command \hidecallgraph.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = YES CALL_GRAPH = NO
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method. # dependency graph for every global function or class method.
# #
# Note that enabling this option will significantly increase the time of a run. # Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected # So in most cases it will be better to enable caller graphs for selected
# functions only using the \callergraph command. Disabling a caller graph can be # functions only using the \callergraph command.
# accomplished by means of the command \hidecallergraph.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = YES CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
# hierarchy of all classes instead of a textual one. # hierarchy of all classes instead of a textual one.
@@ -2314,17 +2200,11 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section # generated by dot.
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this # to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement). # requirement).
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, # Possible values are: png, jpg, gif and svg.
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png. # The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
@@ -2367,24 +2247,6 @@ MSCFILE_DIRS =
DIAFILE_DIRS = DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
PLANTUML_JAR_PATH =
# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
# configuration file for plantuml.
PLANTUML_CFG_FILE =
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
PLANTUML_INCLUDE_PATH =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes # that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized # larger than this value, doxygen will truncate the graph, which is visualized
@@ -2421,7 +2283,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support # makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default. # this, this feature is disabled by default.
@@ -2438,7 +2300,7 @@ DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
# files that are used to generate the various graphs. # files that are used to generate the various graphs.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
-11
View File
@@ -1,7 +1,6 @@
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
find_dependency(ZLIB) find_dependency(ZLIB)
find_dependency(LibLZMA)
find_dependency(Threads) find_dependency(Threads)
# OSG # OSG
@@ -19,16 +18,6 @@ set(USE_AEONWAVE @USE_AEONWAVE@)
set(ENABLE_SIMD @ENABLE_SIMD@) set(ENABLE_SIMD @ENABLE_SIMD@)
# OpenRTI support
set(ENABLE_RTI @ENABLE_RTI@)
if(ENABLE_RTI)
set(RTI_FOUND @RTI_FOUND@)
if(RTI_FOUND)
set(RTI_INCLUDE_DIRS @RTI_INCLUDE_DIRS@)
set(RTI_LDFLAGS @RTI_LDFLAGS@)
endif(RTI_FOUND)
endif(ENABLE_RTI)
# Alternative terrain engine based on pagedLOD # Alternative terrain engine based on pagedLOD
set(ENABLE_GDAL @ENABLE_GDAL@) set(ENABLE_GDAL @ENABLE_GDAL@)
-1
View File
@@ -1 +0,0 @@
2020.3.9
+12 -31
View File
@@ -6,7 +6,6 @@ foreach( mylibfolder
bvh bvh
debug debug
embedded_resources embedded_resources
emesary
ephemeris ephemeris
io io
magvar magvar
@@ -65,9 +64,6 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearScene PROPERTY VERSION ${SIMGEAR_VERSION}) set_property(TARGET SimGearScene PROPERTY VERSION ${SIMGEAR_VERSION})
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION}) set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
endif() endif()
export_debug_symbols(SimGearCore)
export_debug_symbols(SimGearScene)
else() else()
message(STATUS "Library building mode: STATIC LIBRARIES") message(STATUS "Library building mode: STATIC LIBRARIES")
@@ -118,22 +114,11 @@ target_include_directories(SimGearCore BEFORE PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>) $<INSTALL_INTERFACE:include>)
# so simgear/simgear_config.h is found
target_include_directories(SimGearCore BEFORE PUBLIC
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
$<INSTALL_INTERFACE:include>)
target_include_directories(SimGearCore PUBLIC target_include_directories(SimGearCore PUBLIC
${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR}) ${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR})
target_include_directories(SimGearCore PRIVATE target_include_directories(SimGearCore PRIVATE
${EXPAT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) ${EXPAT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS})
if (NOT SYSTEM_EXPAT)
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
target_compile_definitions(SimGearCore PRIVATE HAVE_SIMGEAR_EXPAT_CONFIG_H XML_STATIC)
endif()
install(TARGETS SimGearCore install(TARGETS SimGearCore
EXPORT SimGearTargets EXPORT SimGearTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -158,44 +143,40 @@ if (NOT SIMGEAR_HEADLESS)
endif() endif()
endif() endif()
# we expose ZLib in some of our headers
target_link_libraries(SimGearCore PUBLIC ${ZLIB_LIBRARY})
target_link_libraries(SimGearCore PRIVATE target_link_libraries(SimGearCore
${ZLIB_LIBRARY}
${RT_LIBRARY} ${RT_LIBRARY}
${DL_LIBRARY} ${DL_LIBRARY}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${COCOA_LIBRARY} ${COCOA_LIBRARY}
${CURL_LIBRARIES} ${CURL_LIBRARIES}
${WINSOCK_LIBRARY} ${WINSOCK_LIBRARY})
${SHLWAPI_LIBRARY}
LibLZMA::LibLZMA
)
if(SYSTEM_EXPAT) if(SYSTEM_EXPAT)
target_link_libraries(SimGearCore PRIVATE ${EXPAT_LIBRARIES}) target_link_libraries(SimGearCore
${EXPAT_LIBRARIES})
endif() endif()
if(ENABLE_DNS AND SYSTEM_UDNS) if(ENABLE_DNS AND SYSTEM_UDNS)
target_link_libraries(SimGearCore PRIVATE ${UDNS_LIBRARIES}) target_link_libraries(SimGearCore
${UDNS_LIBRARIES})
endif() endif()
if(NOT SIMGEAR_HEADLESS) if(NOT SIMGEAR_HEADLESS)
target_include_directories(SimGearScene PRIVATE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include) target_include_directories(SimGearScene PRIVATE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
target_link_libraries(SimGearScene PUBLIC target_link_libraries(SimGearScene
SimGearCore SimGearCore
${OPENSCENEGRAPH_LIBRARIES}
)
target_link_libraries(SimGearScene PRIVATE
${ZLIB_LIBRARY} ${ZLIB_LIBRARY}
${OPENSCENEGRAPH_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
${OPENGL_LIBRARY} ${OPENGL_LIBRARY}
${JPEG_LIBRARY}) ${JPEG_LIBRARY})
if(ENABLE_GDAL) if(ENABLE_GDAL)
target_link_libraries(SimGearScene PRIVATE ${GDAL_LIBRARIES}) target_link_libraries(SimGearScene
${GDAL_LIBRARIES})
endif() endif()
# only actually needed by canvas/KeyboardEvent.cxx # only actually needed by canvas/KeyboardEvent.cxx
@@ -207,5 +188,5 @@ if(ENABLE_RTI)
set_property(SOURCE hla/RTI13InteractionClass.cxx hla/RTI13ObjectClass.cxx set_property(SOURCE hla/RTI13InteractionClass.cxx hla/RTI13ObjectClass.cxx
hla/RTI13ObjectInstance.cxx hla/RTI13Federate.cxx hla/RTI13ObjectInstance.cxx hla/RTI13Federate.cxx
hla/RTI13FederateFactory.cxx hla/RTI13FederateFactory.cxx
APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIRS}") APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIR}")
endif(ENABLE_RTI) endif(ENABLE_RTI)
+7 -7
View File
@@ -20,9 +20,9 @@
#include "BVHPager.hxx" #include "BVHPager.hxx"
#include <list> #include <list>
#include <mutex>
#include <simgear/threads/SGThread.hxx> #include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include "BVHPageNode.hxx" #include "BVHPageNode.hxx"
#include "BVHPageRequest.hxx" #include "BVHPageRequest.hxx"
@@ -37,12 +37,12 @@ struct BVHPager::_PrivateData : protected SGThread {
struct _LockedQueue { struct _LockedQueue {
void _push(const _Request& request) void _push(const _Request& request)
{ {
std::lock_guard<std::mutex> scopeLock(_mutex); SGGuard<SGMutex> scopeLock(_mutex);
_requestList.push_back(request); _requestList.push_back(request);
} }
_Request _pop() _Request _pop()
{ {
std::lock_guard<std::mutex> scopeLock(_mutex); SGGuard<SGMutex> scopeLock(_mutex);
if (_requestList.empty()) if (_requestList.empty())
return _Request(); return _Request();
_Request request; _Request request;
@@ -51,7 +51,7 @@ struct BVHPager::_PrivateData : protected SGThread {
return request; return request;
} }
private: private:
std::mutex _mutex; SGMutex _mutex;
_RequestList _requestList; _RequestList _requestList;
}; };
@@ -62,7 +62,7 @@ struct BVHPager::_PrivateData : protected SGThread {
} }
void _push(const _Request& request) void _push(const _Request& request)
{ {
std::lock_guard<std::mutex> scopeLock(_mutex); SGGuard<SGMutex> scopeLock(_mutex);
bool needSignal = _requestList.empty(); bool needSignal = _requestList.empty();
_requestList.push_back(request); _requestList.push_back(request);
if (needSignal) if (needSignal)
@@ -70,7 +70,7 @@ struct BVHPager::_PrivateData : protected SGThread {
} }
_Request _pop() _Request _pop()
{ {
std::lock_guard<std::mutex> scopeLock(_mutex); SGGuard<SGMutex> scopeLock(_mutex);
while (_requestList.empty()) while (_requestList.empty())
_waitCondition.wait(_mutex); _waitCondition.wait(_mutex);
_Request request; _Request request;
@@ -79,7 +79,7 @@ struct BVHPager::_PrivateData : protected SGThread {
return request; return request;
} }
private: private:
std::mutex _mutex; SGMutex _mutex;
SGWaitCondition _waitCondition; SGWaitCondition _waitCondition;
_RequestList _requestList; _RequestList _requestList;
}; };
-4
View File
@@ -691,10 +691,6 @@ namespace canvas
{ {
_sampling_dirty = true; _sampling_dirty = true;
} }
else if( name == "anisotropy" )
{
_texture.setMaxAnisotropy( node->getFloatValue() );
}
else if( name == "additive-blend" ) else if( name == "additive-blend" )
{ {
_texture.useAdditiveBlend( node->getBoolValue() ); _texture.useAdditiveBlend( node->getBoolValue() );
+4 -1
View File
@@ -28,9 +28,11 @@ namespace simgear
namespace canvas namespace canvas
{ {
class CanvasMgr : public PropertyBasedMgr class CanvasMgr:
public PropertyBasedMgr
{ {
public: public:
/** /**
* @param node Root node of branch used to control canvasses * @param node Root node of branch used to control canvasses
*/ */
@@ -59,6 +61,7 @@ public:
CanvasPtr getCanvas(const std::string& name) const; CanvasPtr getCanvas(const std::string& name) const;
protected: protected:
void elementCreated(PropertyBasedElementPtr element) override; void elementCreated(PropertyBasedElementPtr element) override;
}; };
+4 -4
View File
@@ -68,8 +68,8 @@ namespace canvas
Element* parent = 0 ); Element* parent = 0 );
virtual ~Window(); virtual ~Window();
void update(double delta_time_sec) override; virtual void update(double delta_time_sec);
void valueChanged(SGPropertyNode* node) override; virtual void valueChanged(SGPropertyNode* node);
const SGVec2<float> getPosition() const; const SGVec2<float> getPosition() const;
const SGRect<float> getScreenRegion() const; const SGRect<float> getScreenRegion() const;
@@ -84,8 +84,8 @@ namespace canvas
bool isResizable() const; bool isResizable() const;
bool isCapturingEvents() const; bool isCapturingEvents() const;
void setVisible(bool visible) override; virtual void setVisible(bool visible);
bool isVisible() const override; virtual bool isVisible() const;
/** /**
* Moves window on top of all other windows with the same z-index. * Moves window on top of all other windows with the same z-index.
+2 -14
View File
@@ -202,12 +202,6 @@ namespace canvas
updateSampling(); updateSampling();
} }
//----------------------------------------------------------------------------
void ODGauge::setMaxAnisotropy(float anis)
{
texture->setMaxAnisotropy(anis);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void ODGauge::setRender(bool render) void ODGauge::setRender(bool render)
{ {
@@ -256,16 +250,10 @@ namespace canvas
if( !texture ) if( !texture )
{ {
// It shouldn't be necessary to allocate an image for the
// texture that is the target of dynamic rendering, but
// otherwise OSG won't construct all the mipmaps for the texture
// and dynamic mipmap generation doesn't work.
osg::Image* image = new osg::Image;
image->allocateImage(_size_x, _size_y, 1, GL_RGBA, GL_UNSIGNED_BYTE);
texture = new osg::Texture2D; texture = new osg::Texture2D;
texture->setResizeNonPowerOfTwoHint(false); texture->setResizeNonPowerOfTwoHint(false);
texture->setImage(image); texture->setTextureSize(_size_x, _size_y);
texture->setUnRefImageDataAfterApply(true); texture->setInternalFormat(GL_RGBA);
} }
updateSampling(); updateSampling();
-2
View File
@@ -109,8 +109,6 @@ namespace canvas
int coverage_samples = 0, int coverage_samples = 0,
int color_samples = 0 ); int color_samples = 0 );
void setMaxAnisotropy(float anis);
/** /**
* Enable/Disable updating the texture (If disabled the contents of the * Enable/Disable updating the texture (If disabled the contents of the
* texture remains with the outcome of the last rendering pass) * texture remains with the outcome of the last rendering pass)
-5
View File
@@ -31,11 +31,6 @@
// FreeBSD // FreeBSD
#define VG_API_FREEBSD #define VG_API_FREEBSD
#elif defined(__OpenBSD__)
// FreeBSD
#define VG_API_OPENBSD
#else #else
// Unsupported system // Unsupported system
+2 -2
View File
@@ -34,7 +34,7 @@
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #if !defined(VG_API_MACOSX) && !defined(__FreeBSD__)
# include <malloc.h> # include <malloc.h>
#endif #endif
@@ -161,7 +161,7 @@ SHfloat getMaxFloat();
/* OpenGL headers */ /* OpenGL headers */
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD) || defined(VG_API_OPENBSD) #if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glx.h> #include <GL/glx.h>
#elif defined(VG_API_MACOSX) #elif defined(VG_API_MACOSX)
+1 -1
View File
@@ -1193,7 +1193,7 @@ VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, VGPath startPath,
SHfloat *procData1, *procData2; SHfloat *procData1, *procData2;
SHint procSegCount1=0, procSegCount2=0; SHint procSegCount1=0, procSegCount2=0;
SHint procDataCount1=0, procDataCount2=0; SHint procDataCount1=0, procDataCount2=0;
SHuint8 *newSegs, *newData=0; SHuint8 *newSegs, *newData;
void *userData[4]; void *userData[4];
SHint segment1, segment2; SHint segment1, segment2;
SHint segindex, s,d,i; SHint segindex, s,d,i;
+8 -6
View File
@@ -26,9 +26,11 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osgText/Font> #include <osgText/Font>
#include <functional> #include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <map> #include <map>
#include <memory>
#include <vector> #include <vector>
namespace simgear namespace simgear
@@ -60,8 +62,8 @@ namespace canvas
#define SG_FWD_DECL(name)\ #define SG_FWD_DECL(name)\
class name;\ class name;\
typedef std::shared_ptr<name> name##Ptr;\ typedef boost::shared_ptr<name> name##Ptr;\
typedef std::weak_ptr<name> name##WeakPtr; typedef boost::weak_ptr<name> name##WeakPtr;
SG_FWD_DECL(Placement) SG_FWD_DECL(Placement)
SG_FWD_DECL(SystemAdapter) SG_FWD_DECL(SystemAdapter)
@@ -83,10 +85,10 @@ namespace canvas
typedef osg::ref_ptr<osgText::Font> FontPtr; typedef osg::ref_ptr<osgText::Font> FontPtr;
typedef std::vector<PlacementPtr> Placements; typedef std::vector<PlacementPtr> Placements;
typedef std::function<Placements( SGPropertyNode*, typedef boost::function<Placements( SGPropertyNode*,
CanvasPtr )> PlacementFactory; CanvasPtr )> PlacementFactory;
typedef std::function<void(const EventPtr&)> EventListener; typedef boost::function<void(const EventPtr&)> EventListener;
} // namespace canvas } // namespace canvas
} // namespace simgear } // namespace simgear
+40 -27
View File
@@ -29,6 +29,9 @@
#include <osg/BoundingBox> #include <osg/BoundingBox>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <boost/bind.hpp>
#include <boost/function.hpp>
namespace osg namespace osg
{ {
class Drawable; class Drawable;
@@ -59,9 +62,9 @@ namespace canvas
OSGUserData(ElementPtr element); OSGUserData(ElementPtr element);
}; };
typedef std::function<bool(Element&, const SGPropertyNode*)> typedef boost::function<bool(Element&, const SGPropertyNode*)>
StyleSetterFunc; StyleSetterFunc;
typedef std::function<void(Element&, const SGPropertyNode*)> typedef boost::function<void(Element&, const SGPropertyNode*)>
StyleSetterFuncUnchecked; StyleSetterFuncUnchecked;
struct StyleSetter: struct StyleSetter:
public SGReferenced public SGReferenced
@@ -316,7 +319,7 @@ namespace canvas
StyleSetter StyleSetter
addStyle( const std::string& name, addStyle( const std::string& name,
const std::string& type, const std::string& type,
const std::function<void (Derived&, T2)>& setter, const boost::function<void (Derived&, T2)>& setter,
bool inheritable = true ) bool inheritable = true )
{ {
StyleInfo& style_info = _style_setters[ name ]; StyleInfo& style_info = _style_setters[ name ];
@@ -342,10 +345,13 @@ namespace canvas
if( style->func ) if( style->func )
style = style->next = new StyleSetter; style = style->next = new StyleSetter;
style->func = std::bind(&type_match<Derived>::call, style->func = boost::bind
std::placeholders::_1, (
std::placeholders::_2, &type_match<Derived>::call,
bindStyleSetter<T1>(name, setter)); _1,
_2,
bindStyleSetter<T1>(name, setter)
);
return *style; return *style;
} }
@@ -357,7 +363,7 @@ namespace canvas
StyleSetter StyleSetter
addStyle( const std::string& name, addStyle( const std::string& name,
const std::string& type, const std::string& type,
const std::function<void (Derived&, T)>& setter, const boost::function<void (Derived&, T)>& setter,
bool inheritable = true ) bool inheritable = true )
{ {
return addStyle<T, T>(name, type, setter, inheritable); return addStyle<T, T>(name, type, setter, inheritable);
@@ -378,7 +384,7 @@ namespace canvas
( (
name, name,
type, type,
std::function<void (Derived&, T)>(setter), boost::function<void (Derived&, T)>(setter),
inheritable inheritable
); );
} }
@@ -399,7 +405,7 @@ namespace canvas
( (
name, name,
type, type,
std::function<void (Derived&, T2)>(setter), boost::function<void (Derived&, T2)>(setter),
inheritable inheritable
); );
} }
@@ -418,7 +424,7 @@ namespace canvas
( (
name, name,
type, type,
std::function<void (Derived&, const std::string&)>(setter), boost::function<void (Derived&, const std::string&)>(setter),
inheritable inheritable
); );
} }
@@ -481,7 +487,7 @@ namespace canvas
StyleSetter StyleSetter
addStyle( const std::string& name, addStyle( const std::string& name,
const std::string& type, const std::string& type,
const std::function<void (Other&, T2)>& setter, const boost::function<void (Other&, T2)>& setter,
OtherRef Derived::*instance_ref, OtherRef Derived::*instance_ref,
bool inheritable = true ) bool inheritable = true )
{ {
@@ -511,7 +517,7 @@ namespace canvas
( (
name, name,
type, type,
std::function<void (Other&, const std::string&)>(setter), boost::function<void (Other&, const std::string&)>(setter),
instance_ref, instance_ref,
inheritable inheritable
); );
@@ -519,37 +525,44 @@ namespace canvas
template<typename T, class Derived, class Other, class OtherRef> template<typename T, class Derived, class Other, class OtherRef>
static static
std::function<void (Derived&, T)> boost::function<void (Derived&, T)>
bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref ) bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
{ {
return std::bind(setter, return boost::bind(setter, boost::bind(instance_ref, _1), _2);
std::bind(instance_ref, std::placeholders::_1),
std::placeholders::_2);
} }
template<typename T, class Derived, class Other, class OtherRef> template<typename T, class Derived, class Other, class OtherRef>
static static
std::function<void (Derived&, T)> boost::function<void (Derived&, T)>
bindOther( const std::function<void (Other&, T)>& setter, bindOther( const boost::function<void (Other&, T)>& setter,
OtherRef Derived::*instance_ref ) OtherRef Derived::*instance_ref )
{ {
return std::bind(setter, return boost::bind
std::bind(&reference_from_pointer<Other, OtherRef>, (
std::bind(instance_ref, std::placeholders::_1)), setter,
std::placeholders::_2); boost::bind
(
&reference_from_pointer<Other, OtherRef>,
boost::bind(instance_ref, _1)
),
_2
);
} }
template<typename T1, typename T2, class Derived> template<typename T1, typename T2, class Derived>
static static
StyleSetterFuncUnchecked StyleSetterFuncUnchecked
bindStyleSetter( const std::string& name, bindStyleSetter( const std::string& name,
const std::function<void (Derived&, T2)>& setter ) const boost::function<void (Derived&, T2)>& setter )
{ {
return std::bind(setter, return boost::bind
(
setter,
// We will only call setters with Derived instances, so we can safely // We will only call setters with Derived instances, so we can safely
// cast here. // cast here.
std::bind(&derived_cast<Derived>, std::placeholders::_1), boost::bind(&derived_cast<Derived>, _1),
std::bind(&getValue<T1>, std::placeholders::_2)); boost::bind(&getValue<T1>, _2)
);
} }
bool isStyleEmpty(const SGPropertyNode* child) const; bool isStyleEmpty(const SGPropertyNode* child) const;
-138
View File
@@ -838,143 +838,5 @@ namespace canvas
return false; return false;
} }
void Image::fillRect(const SGRect<int>& rect, const std::string& c)
{
osg::Vec4 color(1,1,1,1);
if(!c.empty() && !parseColor(c, color))
return;
fillRect(rect, color);
}
void fillRow(GLubyte* row, GLuint pixel, GLuint width, GLuint pixelBytes)
{
GLubyte* dst = row;
for (GLuint x = 0; x < width; ++x) {
memcpy(dst, &pixel, pixelBytes);
dst += pixelBytes;
}
}
SGRect<int> intersectRect(const SGRect<int>& a, const SGRect<int>& b)
{
SGVec2<int> m1 = max(a.getMin(), b.getMin());
SGVec2<int> m2 = min(a.getMax(), b.getMax());
return SGRect<int>(m1, m2);
}
void Image::fillRect(const SGRect<int>& rect, const osg::Vec4& color)
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image) {
allocateImage();
image = _texture->getImage();
}
if (image->getDataVariance() != osg::Object::DYNAMIC) {
image->setDataVariance(osg::Object::DYNAMIC);
}
const auto format = image->getInternalTextureFormat();
auto clippedRect = intersectRect(rect, SGRect<int>(0, 0, image->s(), image->t()));
if ((clippedRect.width() == 0) || (clippedRect.height() == 0)) {
return;
}
GLubyte* rowData = nullptr;
size_t rowByteSize = 0;
GLuint pixelWidth = clippedRect.width();
GLuint pixel = 0;
GLuint pixelBytes = 0;
switch (format) {
case GL_RGBA8:
case GL_RGBA:
rowByteSize = pixelWidth * 4;
rowData = static_cast<GLubyte*>(alloca(rowByteSize));
// assume litte-endian, so read out backwards, hence when we memcpy
// the data, it ends up in RGBA order
pixel = color.asABGR();
pixelBytes = 4;
fillRow(rowData, pixel, pixelWidth, pixelBytes);
break;
case GL_RGB8:
case GL_RGB:
rowByteSize = pixelWidth * 3;
rowData = static_cast<GLubyte*>(alloca(rowByteSize));
pixel = color.asABGR();
pixelBytes = 3;
fillRow(rowData, pixel, pixelWidth, pixelBytes);
break;
default:
SG_LOG(SG_IO, SG_WARN, "Image::fillRect: unsupported internal image format:" << format);
return;
}
for (int row=clippedRect.t(); row < clippedRect.b(); ++row) {
GLubyte* imageData = image->data(clippedRect.l(), row);
memcpy(imageData, rowData, rowByteSize);
}
image->dirty();
auto c = getCanvas().lock();
c->enableRendering(true); // force a repaint
}
void Image::setPixel(int x, int y, const std::string& c)
{
osg::Vec4 color(1,1,1,1);
if(!c.empty() && !parseColor(c, color))
return;
setPixel(x, y, color);
}
void Image::setPixel(int x, int y, const osg::Vec4& color)
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image) {
allocateImage();
image = _texture->getImage();
}
if (image->getDataVariance() != osg::Object::DYNAMIC) {
image->setDataVariance(osg::Object::DYNAMIC);
}
image->setColor(color, x, y);
}
void Image::dirtyPixels()
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image)
return;
image->dirty();
auto c = getCanvas().lock();
c->enableRendering(true); // force a repaint
}
void Image::allocateImage()
{
osg::Image* image = new osg::Image;
// default to RGBA
image->allocateImage(_node->getIntValue("size[0]"), _node->getIntValue("size[1]"), 1, GL_RGBA, GL_UNSIGNED_BYTE);
image->setInternalTextureFormat(GL_RGBA);
_texture->setImage(image);
}
osg::ref_ptr<osg::Image> Image::getImage() const
{
if (!_texture)
return {};
return _texture->getImage();
}
} // namespace canvas } // namespace canvas
} // namespace simgear } // namespace simgear
-24
View File
@@ -101,28 +101,6 @@ namespace canvas
*/ */
void setSourceRect(const SGRect<float>& sourceRect); void setSourceRect(const SGRect<float>& sourceRect);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& rect, const std::string& color);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& rect, const osg::Vec4& color);
void setPixel(int x, int y, const std::string& color);
void setPixel(int x, int y, const osg::Vec4& color);
/**
* mark the image pixels as modified, so the canvas is re-painted
*/
void dirtyPixels();
osg::ref_ptr<osg::Image> getImage() const;
// void setRow(int row, int offset, )
protected: protected:
enum ImageAttributes enum ImageAttributes
{ {
@@ -147,8 +125,6 @@ namespace canvas
HTTP::Request& request, HTTP::Request& request,
const std::string& type ); const std::string& type );
void allocateImage();
osg::ref_ptr<osg::Texture2D> _texture; osg::ref_ptr<osg::Texture2D> _texture;
// TODO optionally forward events to canvas // TODO optionally forward events to canvas
CanvasWeakPtr _src_canvas; CanvasWeakPtr _src_canvas;
+16 -58
View File
@@ -53,30 +53,25 @@ namespace canvas
TextLine lineAt(size_t i) const; TextLine lineAt(size_t i) const;
/// Get nearest line to given y-coordinate /// Get nearest line to given y-coordinate
#if OSG_VERSION_LESS_THAN(3,6,5)
TextLine nearestLine(float pos_y) const; TextLine nearestLine(float pos_y) const;
SGVec2i sizeForWidth(int w) const;
#else
TextLine nearestLine(float pos_y);
SGVec2i sizeForWidth(int w);
#endif
SGVec2i sizeForWidth(int w) const;
osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2) #if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox computeBound() const override; computeBound()
#else #else
osg::BoundingBox computeBoundingBox() const override; computeBoundingBox()
#endif #endif
const override;
protected: protected:
friend class TextLine; friend class TextLine;
canvas::Text *_text_element; canvas::Text *_text_element;
#if OSG_VERSION_LESS_THAN(3,5,6)
void computePositions(unsigned int contextID) const override; void computePositions(unsigned int contextID) const override;
#else
void computePositionsImplementation() override;
#endif
}; };
class TextLine class TextLine
@@ -127,7 +122,6 @@ namespace canvas
_quads = &text->_textureGlyphQuadMap.begin()->second; _quads = &text->_textureGlyphQuadMap.begin()->second;
#if OSG_VERSION_LESS_THAN(3,5,6)
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers; GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
GlyphQuads::LineNumbers::const_iterator begin_it = GlyphQuads::LineNumbers::const_iterator begin_it =
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line); std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
@@ -139,9 +133,6 @@ namespace canvas
_begin = begin_it - line_numbers.begin(); _begin = begin_it - line_numbers.begin();
_end = std::upper_bound(begin_it, line_numbers.end(), _line) _end = std::upper_bound(begin_it, line_numbers.end(), _line)
- line_numbers.begin(); - line_numbers.begin();
#else
// TODO: Need 3.5.6 version of this
#endif
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -170,17 +161,12 @@ namespace canvas
if( empty() ) if( empty() )
return pos; return pos;
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6)
// TODO: need 3.5.6 version of this.
#else
#if OSG_VERSION_LESS_THAN(3,3,5) #if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords; GlyphQuads::Coords2 const& coords = _quads->_coords;
#else #else
GlyphQuads::Coords2 refCoords = _quads->_coords; GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get(); GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif #endif
size_t global_i = _begin + i; size_t global_i = _begin + i;
if( global_i == _begin ) if( global_i == _begin )
@@ -203,7 +189,6 @@ namespace canvas
// position at center between characters // position at center between characters
pos.x() = 0.5 * (prev_r + cur_l); pos.x() = 0.5 * (prev_r + cur_l);
} }
#endif
return pos; return pos;
} }
@@ -214,10 +199,7 @@ namespace canvas
if( empty() ) if( empty() )
return cursorPos(0); return cursorPos(0);
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6) GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
// TODO: need 3.5.7 version of this.
return cursorPos(0);
#else
#if OSG_VERSION_LESS_THAN(3,3,5) #if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords; GlyphQuads::Coords2 const& coords = _quads->_coords;
#else #else
@@ -225,8 +207,6 @@ namespace canvas
GlyphQuads::Coords2::element_type &coords = *refCoords.get(); GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif #endif
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
float const HIT_FRACTION = 0.6; float const HIT_FRACTION = 0.6;
float const character_width = _text->getCharacterHeight() float const character_width = _text->getCharacterHeight()
* _text->getCharacterAspectRatio(); * _text->getCharacterAspectRatio();
@@ -245,7 +225,6 @@ namespace canvas
} }
return cursorPos(i - _begin); return cursorPos(i - _begin);
#endif
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -324,16 +303,9 @@ namespace canvas
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#if OSG_VERSION_LESS_THAN(3,6,5)
TextLine Text::TextOSG::nearestLine(float pos_y) const TextLine Text::TextOSG::nearestLine(float pos_y) const
{ {
osgText::Font const* font = getActiveFont(); osgText::Font const* font = getActiveFont();
#else
TextLine Text::TextOSG::nearestLine(float pos_y)
{
auto font = getActiveFont();
#endif
if( !font || lineCount() <= 0 ) if( !font || lineCount() <= 0 )
return TextLine(0, this); return TextLine(0, this);
@@ -355,21 +327,12 @@ namespace canvas
// simplified version of osgText::Text::computeGlyphRepresentation() to // simplified version of osgText::Text::computeGlyphRepresentation() to
// just calculate the size for a given weight. Glpyh calculations/creating // just calculate the size for a given weight. Glpyh calculations/creating
// is not necessary for this... // is not necessary for this...
#if OSG_VERSION_LESS_THAN(3,6,5)
SGVec2i Text::TextOSG::sizeForWidth(int w) const SGVec2i Text::TextOSG::sizeForWidth(int w) const
#else
SGVec2i Text::TextOSG::sizeForWidth(int w)
#endif
{ {
if( _text.empty() ) if( _text.empty() )
return SGVec2i(0, 0); return SGVec2i(0, 0);
#if OSG_VERSION_LESS_THAN(3,6,5)
osgText::Font* activefont = const_cast<osgText::Font*>(getActiveFont()); osgText::Font* activefont = const_cast<osgText::Font*>(getActiveFont());
#else
auto activefont = getActiveFont();
#endif
if( !activefont ) if( !activefont )
return SGVec2i(-1, -1); return SGVec2i(-1, -1);
@@ -649,16 +612,19 @@ namespace canvas
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2) #if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox Text::TextOSG::computeBound() const Text::TextOSG::computeBound()
#else #else
osg::BoundingBox Text::TextOSG::computeBoundingBox() const Text::TextOSG::computeBoundingBox()
#endif #endif
const
{ {
osg::BoundingBox bb =
#if OSG_VERSION_LESS_THAN(3,3,2) #if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox bb = osgText::Text::computeBound(); osgText::Text::computeBound();
#else #else
osg::BoundingBox bb = osgText::Text::computeBoundingBox(); osgText::Text::computeBoundingBox();
#endif #endif
#if OSG_VERSION_LESS_THAN(3,1,0) #if OSG_VERSION_LESS_THAN(3,1,0)
@@ -674,7 +640,7 @@ namespace canvas
return bb; return bb;
} }
#if OSG_VERSION_LESS_THAN(3,5,6) //----------------------------------------------------------------------------
void Text::TextOSG::computePositions(unsigned int contextID) const void Text::TextOSG::computePositions(unsigned int contextID) const
{ {
if( _textureGlyphQuadMap.empty() || _layout == VERTICAL ) if( _textureGlyphQuadMap.empty() || _layout == VERTICAL )
@@ -744,14 +710,6 @@ namespace canvas
return osgText::Text::computePositions(contextID); return osgText::Text::computePositions(contextID);
} }
#else
void Text::TextOSG::computePositionsImplementation()
{
TextBase::computePositionsImplementation();
}
#endif
//----------------------------------------------------------------------------
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const std::string Text::TYPE_NAME = "text"; const std::string Text::TYPE_NAME = "text";
+1 -1
View File
@@ -73,7 +73,7 @@ namespace canvas
int stretch, int stretch,
uint8_t alignment ) uint8_t alignment )
{ {
ItemData item_data = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ItemData item_data = {0};
item_data.layout_item = item; item_data.layout_item = item;
item_data.stretch = std::max(0, stretch); item_data.stretch = std::max(0, stretch);
-3
View File
@@ -18,9 +18,6 @@
#include <simgear_config.h> #include <simgear_config.h>
#include "Layout.hxx" #include "Layout.hxx"
#include <algorithm>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
namespace simgear namespace simgear
+8 -8
View File
@@ -150,7 +150,7 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool NasalWidget::hasHeightForWidth() const bool NasalWidget::hasHeightForWidth() const
{ {
return _height_for_width || _min_height_for_width; return !_height_for_width.empty() || !_min_height_for_width.empty();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -186,7 +186,7 @@ namespace canvas
int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw, int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
int w ) const int w ) const
{ {
if( !hfw ) if( hfw.empty() )
return -1; return -1;
try try
@@ -239,17 +239,17 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
int NasalWidget::heightForWidthImpl(int w) const int NasalWidget::heightForWidthImpl(int w) const
{ {
return callHeightForWidthFunc( _height_for_width return callHeightForWidthFunc( _height_for_width.empty()
? _height_for_width ? _min_height_for_width
: _min_height_for_width, w ); : _height_for_width, w );
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
int NasalWidget::minimumHeightForWidthImpl(int w) const int NasalWidget::minimumHeightForWidthImpl(int w) const
{ {
return callHeightForWidthFunc( _min_height_for_width return callHeightForWidthFunc( _min_height_for_width.empty()
? _min_height_for_width ? _height_for_width
: _height_for_width, w ); : _min_height_for_width, w );
} }
+2 -2
View File
@@ -40,8 +40,8 @@ namespace canvas
{ {
public: public:
typedef std::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc; typedef boost::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
typedef std::function<int (nasal::Me, int)> HeightForWidthFunc; typedef boost::function<int (nasal::Me, int)> HeightForWidthFunc;
/** /**
* *
-3
View File
@@ -218,9 +218,6 @@ const float SG_RADIANS_TO_DEGREES = 180.0f / SG_PI;
#define SG_OBJECT_RANGE_ROUGH 9000.0 #define SG_OBJECT_RANGE_ROUGH 9000.0
#define SG_OBJECT_RANGE_DETAILED 1500.0 #define SG_OBJECT_RANGE_DETAILED 1500.0
/** Minimum expiry time of PagedLOD within the Tile. Overridden by /sim/rendering/plod-minimum-expiry-time-secs **/
#define SG_TILE_MIN_EXPIRY 180.0
/** Radius of scenery tiles in m **/ /** Radius of scenery tiles in m **/
#define SG_TILE_RADIUS 14000.0 #define SG_TILE_RADIUS 14000.0
+7 -6
View File
@@ -22,12 +22,13 @@
#include <simgear_config.h> #include <simgear_config.h>
#include <simgear/debug/BufferedLogCallback.hxx> #include <simgear/debug/BufferedLogCallback.hxx>
#include <boost/foreach.hpp>
#include <simgear/sg_inlines.h> #include <simgear/sg_inlines.h>
#include <simgear/threads/SGThread.hxx> #include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <cstdlib> // for malloc #include <cstdlib> // for malloc
#include <cstring>
#include <mutex>
namespace simgear namespace simgear
{ {
@@ -35,7 +36,7 @@ namespace simgear
class BufferedLogCallback::BufferedLogCallbackPrivate class BufferedLogCallback::BufferedLogCallbackPrivate
{ {
public: public:
std::mutex m_mutex; SGMutex m_mutex;
vector_cstring m_buffer; vector_cstring m_buffer;
unsigned int m_stamp; unsigned int m_stamp;
unsigned int m_maxLength; unsigned int m_maxLength;
@@ -51,7 +52,7 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
BufferedLogCallback::~BufferedLogCallback() BufferedLogCallback::~BufferedLogCallback()
{ {
for (auto msg : d->m_buffer) { BOOST_FOREACH(unsigned char* msg, d->m_buffer) {
free(msg); free(msg);
} }
} }
@@ -73,7 +74,7 @@ void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p,
msg = (vector_cstring::value_type) strdup(aMessage.c_str()); msg = (vector_cstring::value_type) strdup(aMessage.c_str());
} }
std::lock_guard<std::mutex> g(d->m_mutex); SGGuard<SGMutex> g(d->m_mutex);
d->m_buffer.push_back(msg); d->m_buffer.push_back(msg);
d->m_stamp++; d->m_stamp++;
} }
@@ -85,7 +86,7 @@ unsigned int BufferedLogCallback::stamp() const
unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput) unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput)
{ {
std::lock_guard<std::mutex> g(d->m_mutex); SGGuard<SGMutex> g(d->m_mutex);
size_t sz = d->m_buffer.size(); size_t sz = d->m_buffer.size();
aOutput.resize(sz); aOutput.resize(sz);
memcpy(aOutput.data(), d->m_buffer.data(), sz * sizeof(vector_cstring::value_type)); memcpy(aOutput.data(), d->m_buffer.data(), sz * sizeof(vector_cstring::value_type));
+1 -1
View File
@@ -26,7 +26,7 @@
#include <vector> #include <vector>
#include <memory> // for std::unique_ptr #include <memory> // for std::unique_ptr
#include <simgear/debug/LogCallback.hxx> #include <simgear/debug/logstream.hxx>
namespace simgear namespace simgear
{ {
+2 -9
View File
@@ -1,14 +1,7 @@
include (SimGearComponent) include (SimGearComponent)
set(HEADERS debug_types.h set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx)
logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx set(SOURCES logstream.cxx BufferedLogCallback.cxx)
LogCallback.hxx LogEntry.hxx
ErrorReportingCallback.hxx)
set(SOURCES logstream.cxx BufferedLogCallback.cxx
LogCallback.cxx LogEntry.cxx
ErrorReportingCallback.cxx
)
simgear_component(debug debug "${SOURCES}" "${HEADERS}") simgear_component(debug debug "${SOURCES}" "${HEADERS}")
-47
View File
@@ -1,47 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <simgear_config.h>
#include "ErrorReportingCallback.hxx"
using std::string;
namespace simgear {
static ErrorReportCallback static_callback;
void setErrorReportCallback(ErrorReportCallback cb)
{
static_callback = cb;
}
void reportError(const std::string& msg, const std::string& more)
{
if (!static_callback)
return;
static_callback(msg, more, false);
}
void reportFatalError(const std::string& msg, const std::string& more)
{
if (!static_callback)
return;
static_callback(msg, more, true);
}
} // namespace simgear
-31
View File
@@ -1,31 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#pragma once
#include <functional>
#include <string>
namespace simgear {
void reportError(const std::string& msg, const std::string& more = {});
void reportFatalError(const std::string& msg, const std::string& more = {});
using ErrorReportCallback = std::function<void(const std::string& msg, const std::string& more, bool isFatal)>;
void setErrorReportCallback(ErrorReportCallback cb);
} // namespace simgear
-116
View File
@@ -1,116 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <simgear_config.h>
#include "LogCallback.hxx"
using namespace simgear;
LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) : m_class(c),
m_priority(p)
{
}
void LogCallback::operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage)
{
// override me
}
bool LogCallback::doProcessEntry(const LogEntry& e)
{
return false;
}
void LogCallback::processEntry(const LogEntry& e)
{
if (doProcessEntry(e))
return; // derived class used the new API
// call the old API
(*this)(e.debugClass, e.debugPriority, e.file, e.line, e.message);
}
bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const
{
if ((c & m_class) != 0 && p >= m_priority)
return true;
if (c == SG_OSG) // always have OSG logging as it OSG logging is configured separately.
return true;
return false;
}
void LogCallback::setLogLevels(sgDebugClass c, sgDebugPriority p)
{
m_priority = p;
m_class = c;
}
const char* LogCallback::debugPriorityToString(sgDebugPriority p)
{
switch (p) {
case SG_DEV_ALERT:
case SG_ALERT:
return "ALRT";
case SG_BULK: return "BULK";
case SG_DEBUG: return "DBUG";
case SG_MANDATORY_INFO:
case SG_INFO:
return "INFO";
case SG_POPUP: return "POPU";
case SG_DEV_WARN:
case SG_WARN:
return "WARN";
default: return "UNKN";
}
}
const char* LogCallback::debugClassToString(sgDebugClass c)
{
switch (c) {
case SG_NONE: return "none";
case SG_TERRAIN: return "terrain";
case SG_ASTRO: return "astro";
case SG_FLIGHT: return "flight";
case SG_INPUT: return "input";
case SG_GL: return "opengl";
case SG_VIEW: return "view";
case SG_COCKPIT: return "cockpit";
case SG_GENERAL: return "general";
case SG_MATH: return "math";
case SG_EVENT: return "event";
case SG_AIRCRAFT: return "aircraft";
case SG_AUTOPILOT: return "autopilot";
case SG_IO: return "io";
case SG_CLIPPER: return "clipper";
case SG_NETWORK: return "network";
case SG_ATC: return "atc";
case SG_NASAL: return "nasal";
case SG_INSTR: return "instruments";
case SG_SYSTEMS: return "systems";
case SG_AI: return "ai";
case SG_ENVIRONMENT: return "environment";
case SG_SOUND: return "sound";
case SG_NAVAID: return "navaid";
case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync";
case SG_PARTICLES: return "particles";
case SG_HEADLESS: return "headless";
case SG_OSG: return "OSG";
default: return "unknown";
}
}
-56
View File
@@ -1,56 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#pragma once
#include <string>
#include "LogEntry.hxx"
#include "debug_types.h"
namespace simgear {
class LogCallback
{
public:
virtual ~LogCallback() = default;
// newer API: return true if you handled the message, otherwise
// the old API will be called
virtual bool doProcessEntry(const LogEntry& e);
// old API, kept for compatability
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage);
void setLogLevels(sgDebugClass c, sgDebugPriority p);
void processEntry(const LogEntry& e);
protected:
LogCallback(sgDebugClass c, sgDebugPriority p);
bool shouldLog(sgDebugClass c, sgDebugPriority p) const;
static const char* debugClassToString(sgDebugClass c);
static const char* debugPriorityToString(sgDebugPriority p);
private:
sgDebugClass m_class;
sgDebugPriority m_priority;
};
} // namespace simgear
-45
View File
@@ -1,45 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <simgear_config.h>
#include "LogEntry.hxx"
#include <cstring> // for strdup
namespace simgear {
LogEntry::~LogEntry()
{
if (freeFilename) {
free(const_cast<char*>(file));
}
}
LogEntry::LogEntry(const LogEntry& c) : debugClass(c.debugClass),
debugPriority(c.debugPriority),
originalPriority(c.originalPriority),
file(c.file),
line(c.line),
message(c.message),
freeFilename(c.freeFilename)
{
if (c.freeFilename) {
file = strdup(c.file);
}
}
} // namespace simgear
-54
View File
@@ -1,54 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#pragma once
#include <string>
#include "debug_types.h"
namespace simgear {
/**
* storage of a single log entry. This is used to pass log entries from
* the various threads to the logging thread, and also to store the startup
* entries
*/
class LogEntry
{
public:
LogEntry(sgDebugClass c, sgDebugPriority p,
sgDebugPriority op,
const char* f, int l, const std::string& msg) : debugClass(c), debugPriority(p), originalPriority(op),
file(f), line(l),
message(msg)
{
}
LogEntry(const LogEntry& c);
LogEntry& operator=(const LogEntry& c) = delete;
~LogEntry();
const sgDebugClass debugClass;
const sgDebugPriority debugPriority;
const sgDebugPriority originalPriority;
const char* file;
const int line;
const std::string message;
bool freeFilename = false; ///< if true, we own, and therefore need to free, the memory pointed to by 'file'
};
} // namespace simgear
+5 -13
View File
@@ -2,7 +2,8 @@
#include <osg/Notify> #include <osg/Notify>
#include <simgear/debug/logstream.hxx> using namespace osg;
/** /**
* merge OSG output into our logging system, so it gets recorded to file, * merge OSG output into our logging system, so it gets recorded to file,
@@ -21,20 +22,11 @@ public:
if (strstr(message, "the final reference count was")) { if (strstr(message, "the final reference count was")) {
// as this is going to segfault ignore the translation of severity and always output the message. // as this is going to segfault ignore the translation of severity and always output the message.
SG_LOG(SG_GL, SG_ALERT, message); SG_LOG(SG_GL, SG_ALERT, message);
#ifndef DEBUG int* trigger_segfault = 0;
throw new std::string(message); *trigger_segfault = 0;
//int* trigger_segfault = 0;
//*trigger_segfault = 0;
#endif
return; return;
} }
char*tmessage = strdup(message); SG_LOG(SG_GL, translateSeverity(severity), message);
char*lf = strrchr(tmessage, '\n');
if (lf)
*lf = 0;
SG_LOG(SG_OSG, translateSeverity(severity), tmessage);
free(tmessage);
} }
private: private:
+3 -9
View File
@@ -1,5 +1,3 @@
#pragma once
/** \file debug_types.h /** \file debug_types.h
* Define the various logging classes and priorities * Define the various logging classes and priorities
*/ */
@@ -37,10 +35,7 @@ typedef enum {
SG_TERRASYNC = 0x01000000, SG_TERRASYNC = 0x01000000,
SG_PARTICLES = 0x02000000, SG_PARTICLES = 0x02000000,
SG_HEADLESS = 0x04000000, SG_HEADLESS = 0x04000000,
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured SG_UNDEFD = 0x08000000, // For range checking
// separately and thus it makes more sense to allow these message through.
SG_OSG = 0x08000000,
SG_UNDEFD = 0x10000000, // For range checking
SG_ALL = 0xFFFFFFFF SG_ALL = 0xFFFFFFFF
} sgDebugClass; } sgDebugClass;
@@ -64,7 +59,6 @@ typedef enum {
// SG_ABORT // Abandon ship (core) // SG_ABORT // Abandon ship (core)
SG_DEV_WARN, // Warning for developers, translated to other priority SG_DEV_WARN, // Warning for developers, translated to other priority
SG_DEV_ALERT, // Alert for developers, translated SG_DEV_ALERT // Alert for developers, translated
SG_MANDATORY_INFO // information, but should always be shown
} sgDebugPriority; } sgDebugPriority;
+127 -146
View File
@@ -24,22 +24,20 @@
#include "logstream.hxx" #include "logstream.hxx"
#include <cstring>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include <mutex>
#include <boost/foreach.hpp>
#include <simgear/sg_inlines.h> #include <simgear/sg_inlines.h>
#include <simgear/threads/SGThread.hxx> #include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGQueue.hxx> #include <simgear/threads/SGQueue.hxx>
#include <simgear/threads/SGGuard.hxx>
#include "LogCallback.hxx"
#include <simgear/io/iostreams/sgstream.hxx> #include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/timing/timestamp.hxx>
#if defined (SG_WINDOWS) #if defined (SG_WINDOWS)
// for AllocConsole, OutputDebugString // for AllocConsole, OutputDebugString
@@ -48,55 +46,84 @@
#include <io.h> #include <io.h>
#endif #endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
namespace simgear
{
LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) :
m_class(c),
m_priority(p)
{
}
bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const
{
return ((c & m_class) != 0 && p >= m_priority);
}
void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p )
{
m_priority = p;
m_class = c;
}
const char* LogCallback::debugClassToString(sgDebugClass c)
{
switch (c) {
case SG_NONE: return "none";
case SG_TERRAIN: return "terrain";
case SG_ASTRO: return "astro";
case SG_FLIGHT: return "flight";
case SG_INPUT: return "input";
case SG_GL: return "opengl";
case SG_VIEW: return "view";
case SG_COCKPIT: return "cockpit";
case SG_GENERAL: return "general";
case SG_MATH: return "math";
case SG_EVENT: return "event";
case SG_AIRCRAFT: return "aircraft";
case SG_AUTOPILOT: return "autopilot";
case SG_IO: return "io";
case SG_CLIPPER: return "clipper";
case SG_NETWORK: return "network";
case SG_ATC: return "atc";
case SG_NASAL: return "nasal";
case SG_INSTR: return "instruments";
case SG_SYSTEMS: return "systems";
case SG_AI: return "ai";
case SG_ENVIRONMENT:return "environment";
case SG_SOUND: return "sound";
case SG_NAVAID: return "navaid";
case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync";
case SG_PARTICLES: return "particles";
case SG_HEADLESS: return "headless";
default: return "unknown";
}
}
} // of namespace simgear
//////////////////////////////////////////////////////////////////////////////
class FileLogCallback : public simgear::LogCallback class FileLogCallback : public simgear::LogCallback
{ {
public: public:
SGTimeStamp logTimer;
FileLogCallback(const SGPath& aPath, sgDebugClass c, sgDebugPriority p) : FileLogCallback(const SGPath& aPath, sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c, p) simgear::LogCallback(c, p)
{ {
m_file.open(aPath, std::ios_base::out | std::ios_base::trunc); m_file.open(aPath, std::ios_base::out | std::ios_base::trunc);
logTimer.stamp();
} }
void operator()(sgDebugClass c, sgDebugPriority p, virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& message) override const char* file, int line, const std::string& message)
{ {
if (!shouldLog(c, p)) return; if (!shouldLog(c, p)) return;
m_file << debugClassToString(c) << ":" << (int) p
<< ":" << file << ":" << line << ":" << message << std::endl;
// fprintf(stderr, "%7.2f [%.8s]:%-10s %s\n", logTimer.elapsedMSec() / 1000.0, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
m_file
<< std::fixed
<< std::setprecision(2)
<< std::setw(8)
<< std::right
<< (logTimer.elapsedMSec() / 1000.0)
<< std::setw(8)
<< std::left
<< " ["+std::string(debugPriorityToString(p))+"]:"
<< std::setw(10)
<< std::left
<< debugClassToString(c)
;
if (file) {
/* <line> can be -ve to indicate that m_fileLine was false, but we
want to show file:line information regardless of m_fileLine. */
m_file
<< file
<< ":"
<< abs(line)
<< ": "
;
}
m_file
<< message << std::endl;
//m_file << debugClassToString(c) << ":" << (int)p
// << ":" << file << ":" << line << ":" << message << std::endl;
} }
private: private:
sg_ofstream m_file; sg_ofstream m_file;
@@ -105,12 +132,9 @@ private:
class StderrLogCallback : public simgear::LogCallback class StderrLogCallback : public simgear::LogCallback
{ {
public: public:
SGTimeStamp logTimer;
StderrLogCallback(sgDebugClass c, sgDebugPriority p) : StderrLogCallback(sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c, p) simgear::LogCallback(c, p)
{ {
logTimer.stamp();
} }
#if defined (SG_WINDOWS) #if defined (SG_WINDOWS)
@@ -120,19 +144,12 @@ public:
} }
#endif #endif
void operator()(sgDebugClass c, sgDebugPriority p, virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage) override const char* file, int line, const std::string& aMessage)
{ {
if (!shouldLog(c, p)) return; if (!shouldLog(c, p)) return;
//fprintf(stderr, "%s\n", aMessage.c_str());
if (file && line > 0) { fprintf(stderr, "%s\n", aMessage.c_str());
fprintf(stderr, "%8.2f %s:%i: [%.8s]:%-10s %s\n", logTimer.elapsedMSec()/1000.0, file, line, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
}
else {
fprintf(stderr, "%8.2f [%.8s]:%-10s %s\n", logTimer.elapsedMSec()/1000.0, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
}
// file, line, aMessage.c_str());
//fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p, //fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p,
// file, line, aMessage.c_str()); // file, line, aMessage.c_str());
fflush(stderr); fflush(stderr);
@@ -150,8 +167,8 @@ public:
{ {
} }
void operator()(sgDebugClass c, sgDebugPriority p, virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage) override const char* file, int line, const std::string& aMessage)
{ {
if (!shouldLog(c, p)) return; if (!shouldLog(c, p)) return;
@@ -166,6 +183,28 @@ public:
class logstream::LogStreamPrivate : public SGThread class logstream::LogStreamPrivate : public SGThread
{ {
private: private:
/**
* storage of a single log entry. This is used to pass log entries from
* the various threads to the logging thread, and also to store the startup
* entries
*/
class LogEntry
{
public:
LogEntry(sgDebugClass c, sgDebugPriority p,
const char* f, int l, const std::string& msg) :
debugClass(c), debugPriority(p), file(f), line(l),
message(msg)
{
}
const sgDebugClass debugClass;
const sgDebugPriority debugPriority;
const char* file;
const int line;
const std::string message;
};
/** /**
* RAII object to pause the logging thread if it's running, and restart it. * RAII object to pause the logging thread if it's running, and restart it.
* used to safely make configuration changes. * used to safely make configuration changes.
@@ -289,34 +328,22 @@ public:
m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority)); m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back()); m_consoleCallbacks.push_back(m_callbacks.back());
#if defined (SG_WINDOWS) && !defined(NDEBUG)
#if defined (SG_WINDOWS)
const char* winDebugEnv = ::getenv("SG_WINDEBUG");
const bool b = winDebugEnv ? simgear::strutils::to_bool(std::string{winDebugEnv}) : false;
if (b) {
m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority)); m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back()); m_consoleCallbacks.push_back(m_callbacks.back());
}
#endif #endif
} }
~LogStreamPrivate() ~LogStreamPrivate()
{ {
removeCallbacks(); removeCallbacks();
// house-keeping, avoid leak warnings if we exit before disabling
// startup logging
{
std::lock_guard<std::mutex> g(m_lock);
clearStartupEntriesLocked();
}
} }
std::mutex m_lock; SGMutex m_lock;
SGBlockingQueue<simgear::LogEntry> m_entries; SGBlockingQueue<LogEntry> m_entries;
// log entries posted during startup // log entries posted during startup
std::vector<simgear::LogEntry> m_startupEntries; std::vector<LogEntry> m_startupEntries;
bool m_startupLogging = false; bool m_startupLogging = false;
typedef std::vector<simgear::LogCallback*> CallbackVec; typedef std::vector<simgear::LogCallback*> CallbackVec;
@@ -334,16 +361,13 @@ public:
bool m_stdout_isRedirectedAlready = false; bool m_stdout_isRedirectedAlready = false;
#endif #endif
bool m_developerMode = false; bool m_developerMode = false;
bool m_fileLine = false;
// test suite mode. // test suite mode.
bool m_testMode = false; bool m_testMode = false;
std::vector<std::string> _popupMessages;
void startLog() void startLog()
{ {
std::lock_guard<std::mutex> g(m_lock); SGGuard<SGMutex> g(m_lock);
if (m_isRunning) return; if (m_isRunning) return;
m_isRunning = true; m_isRunning = true;
start(); start();
@@ -355,54 +379,44 @@ public:
return; return;
} }
{
std::lock_guard<std::mutex> g(m_lock);
m_startupLogging = on; m_startupLogging = on;
clearStartupEntriesLocked();
}
}
void clearStartupEntriesLocked()
{
m_startupEntries.clear(); m_startupEntries.clear();
} }
void run() override virtual void run()
{ {
while (1) { while (1) {
simgear::LogEntry entry(m_entries.pop()); LogEntry entry(m_entries.pop());
// special marker entry detected, terminate the thread since we are // special marker entry detected, terminate the thread since we are
// making a configuration change or quitting the app // making a configuration change or quitting the app
if ((entry.debugClass == SG_NONE) && entry.file && !strcmp(entry.file, "done")) { if ((entry.debugClass == SG_NONE) && !strcmp(entry.file, "done")) {
return; return;
} }
{
std::lock_guard<std::mutex> g(m_lock);
if (m_startupLogging) { if (m_startupLogging) {
// save to the startup list for not-yet-added callbacks to // save to the startup list for not-yet-added callbacks to
// pull down on startup // pull down on startup
m_startupEntries.push_back(entry); m_startupEntries.push_back(entry);
} }
}
// submit to each installed callback in turn // submit to each installed callback in turn
for (simgear::LogCallback* cb : m_callbacks) { for (simgear::LogCallback* cb : m_callbacks) {
cb->processEntry(entry); (*cb)(entry.debugClass, entry.debugPriority,
entry.file, entry.line, entry.message);
} }
} // of main thread loop } // of main thread loop
} }
bool stop() bool stop()
{ {
{ SGGuard<SGMutex> g(m_lock);
std::lock_guard<std::mutex> g(m_lock);
if (!m_isRunning) { if (!m_isRunning) {
return false; return false;
} }
// log a special marker value, which will cause the thread to wakeup, // log a special marker value, which will cause the thread to wakeup,
// and then exit // and then exit
log(SG_NONE, SG_ALERT, "done", -1, "", false); log(SG_NONE, SG_ALERT, "done", -1, "");
}
join(); join();
m_isRunning = false; m_isRunning = false;
@@ -416,8 +430,9 @@ public:
// we clear startup entries not using this, so always safe to run // we clear startup entries not using this, so always safe to run
// this code, container will simply be empty // this code, container will simply be empty
for (const auto& entry : m_startupEntries) { for (auto entry : m_startupEntries) {
cb->processEntry(entry); (*cb)(entry.debugClass, entry.debugPriority,
entry.file, entry.line, entry.message);
} }
} }
@@ -445,7 +460,7 @@ public:
PauseThread pause(this); PauseThread pause(this);
m_logPriority = p; m_logPriority = p;
m_logClass = c; m_logClass = c;
for (auto cb : m_consoleCallbacks) { BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) {
cb->setLogLevels(c, p); cb->setLogLevels(c, p);
} }
} }
@@ -455,27 +470,16 @@ public:
// Testing mode, so always log. // Testing mode, so always log.
if (m_testMode) return true; if (m_testMode) return true;
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured
// separately and thus it makes more sense to allow these message through.
if (static_cast<unsigned>(p) == static_cast<unsigned>(SG_OSG)) return true;
p = translatePriority(p); p = translatePriority(p);
if (p >= SG_INFO) return true; if (p >= SG_INFO) return true;
return ((c & m_logClass) != 0 && p >= m_logPriority); return ((c & m_logClass) != 0 && p >= m_logPriority);
} }
void log( sgDebugClass c, sgDebugPriority p, void log( sgDebugClass c, sgDebugPriority p,
const char* fileName, int line, const std::string& msg, const char* fileName, int line, const std::string& msg)
bool freeFilename)
{ {
auto tp = translatePriority(p); p = translatePriority(p);
if (!m_fileLine) { LogEntry entry(c, p, fileName, line, msg);
/* This prevents output of file:line in StderrLogCallback. */
line = -line;
}
simgear::LogEntry entry(c, tp, p, fileName, line, msg);
entry.freeFilename = freeFilename;
m_entries.push(entry); m_entries.push(entry);
} }
@@ -486,7 +490,7 @@ public:
} }
if (in == SG_DEV_ALERT) { if (in == SG_DEV_ALERT) {
return m_developerMode ? SG_ALERT : SG_WARN; return m_developerMode ? SG_POPUP : SG_WARN;
} }
return in; return in;
@@ -496,7 +500,7 @@ public:
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
static std::unique_ptr<logstream> global_logstream; static std::unique_ptr<logstream> global_logstream;
static std::mutex global_logStreamLock; static SGMutex global_logStreamLock;
logstream::logstream() logstream::logstream()
{ {
@@ -506,8 +510,8 @@ logstream::logstream()
logstream::~logstream() logstream::~logstream()
{ {
popup_msgs.clear();
d->stop(); d->stop();
d.reset();
} }
void void
@@ -521,10 +525,6 @@ void logstream::setDeveloperMode(bool devMode)
d->m_developerMode = devMode; d->m_developerMode = devMode;
} }
void logstream::setFileLine(bool fileLine)
{
d->m_fileLine = fileLine;
}
void void
logstream::addCallback(simgear::LogCallback* cb) logstream::addCallback(simgear::LogCallback* cb)
@@ -542,14 +542,7 @@ void
logstream::log( sgDebugClass c, sgDebugPriority p, logstream::log( sgDebugClass c, sgDebugPriority p,
const char* fileName, int line, const std::string& msg) const char* fileName, int line, const std::string& msg)
{ {
d->log(c, p, fileName, line, msg, false); d->log(c, p, fileName, line, msg);
}
void
logstream::logCopyingFilename( sgDebugClass c, sgDebugPriority p,
const char* fileName, int line, const std::string& msg)
{
d->log(c, p, strdup(fileName), line, msg, true);
} }
@@ -610,18 +603,17 @@ void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName,
void void
logstream::popup( const std::string& msg) logstream::popup( const std::string& msg)
{ {
std::lock_guard<std::mutex> g(d->m_lock); popup_msgs.push_back(msg);
d->_popupMessages.push_back(msg);
} }
std::string std::string
logstream::get_popup() logstream::get_popup()
{ {
std::string rv; std::string rv = "";
std::lock_guard<std::mutex> g(d->m_lock); if (!popup_msgs.empty())
if (!d->_popupMessages.empty()) { {
rv = d->_popupMessages.front(); rv = popup_msgs.front();
d->_popupMessages.erase(d->_popupMessages.begin()); popup_msgs.erase(popup_msgs.begin());
} }
return rv; return rv;
} }
@@ -629,8 +621,7 @@ logstream::get_popup()
bool bool
logstream::has_popup() logstream::has_popup()
{ {
std::lock_guard<std::mutex> g(d->m_lock); return (popup_msgs.size() > 0) ? true : false;
return !d->_popupMessages.empty();
} }
bool bool
@@ -663,16 +654,6 @@ logstream::set_log_classes( sgDebugClass c)
d->setLogLevels(c, d->m_logPriority); d->setLogLevels(c, d->m_logPriority);
} }
sgDebugPriority logstream::priorityFromString(const std::string& s)
{
if (s == "bulk") return SG_BULK;
if (s == "debug") return SG_DEBUG;
if (s == "info") return SG_INFO;
if (s == "warn") return SG_WARN;
if (s == "alert") return SG_ALERT;
throw std::invalid_argument("Couldn't parse log prioirty:" + s);
}
logstream& logstream&
sglog() sglog()
@@ -683,7 +664,7 @@ sglog()
// http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf // http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
// in the absence of portable memory barrier ops in Simgear, // in the absence of portable memory barrier ops in Simgear,
// let's keep this correct & safe // let's keep this correct & safe
std::lock_guard<std::mutex> g(global_logStreamLock); SGGuard<SGMutex> g(global_logStreamLock);
if( !global_logstream ) if( !global_logstream )
global_logstream.reset(new logstream); global_logstream.reset(new logstream);
@@ -764,7 +745,7 @@ void requestConsole()
void shutdownLogging() void shutdownLogging()
{ {
std::lock_guard<std::mutex> g(global_logStreamLock); SGGuard<SGMutex> g(global_logStreamLock);
global_logstream.reset(); global_logstream.reset();
} }
+21 -22
View File
@@ -38,7 +38,25 @@ class SGPath;
namespace simgear namespace simgear
{ {
class LogCallback; class LogCallback
{
public:
virtual ~LogCallback() {}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage) = 0;
void setLogLevels(sgDebugClass c, sgDebugPriority p);
protected:
LogCallback(sgDebugClass c, sgDebugPriority p);
bool shouldLog(sgDebugClass c, sgDebugPriority p) const;
static const char* debugClassToString(sgDebugClass c);
private:
sgDebugClass m_class;
sgDebugPriority m_priority;
};
/** /**
* Helper force a console on platforms where it might optional, when * Helper force a console on platforms where it might optional, when
* we need to show a console. This basically means Windows at the * we need to show a console. This basically means Windows at the
@@ -86,11 +104,6 @@ public:
sgDebugPriority get_log_priority() const; sgDebugPriority get_log_priority() const;
/**
@brief convert a string value to a log prioirty.
throws std::invalid_argument if the string is not valid
*/
static sgDebugPriority priorityFromString(const std::string& s);
/** /**
* set developer mode on/off. In developer mode, SG_DEV_WARN messags * set developer mode on/off. In developer mode, SG_DEV_WARN messags
* are treated as warnings. In normal (non-developer) mode they are * are treated as warnings. In normal (non-developer) mode they are
@@ -98,26 +111,12 @@ public:
*/ */
void setDeveloperMode(bool devMode); void setDeveloperMode(bool devMode);
/**
* set output of file:line mode on/off. If on, all log messages are
* prefixed by the file:line of the caller of SG_LOG().
*/
void setFileLine(bool fileLine);
/** /**
* the core logging method * the core logging method
*/ */
void log( sgDebugClass c, sgDebugPriority p, void log( sgDebugClass c, sgDebugPriority p,
const char* fileName, int line, const std::string& msg); const char* fileName, int line, const std::string& msg);
// overload of above, which can transfer ownership of the file-name.
// this is unecesary overhead when logging from C++, since __FILE__ points
// to constant data, but it's needed when the filename is Nasal data (for
// example) since during shutdown the filename is freed by Nasal GC
// asynchronously with the logging thread.
void logCopyingFilename( sgDebugClass c, sgDebugPriority p,
const char* fileName, int line, const std::string& msg);
/** /**
* output formatted hex dump of memory block * output formatted hex dump of memory block
*/ */
@@ -179,6 +178,8 @@ private:
// constructor // constructor
logstream(); logstream();
std::vector<std::string> popup_msgs;
class LogStreamPrivate; class LogStreamPrivate;
std::unique_ptr<LogStreamPrivate> d; std::unique_ptr<LogStreamPrivate> d;
@@ -202,11 +203,9 @@ logstream& sglog();
} } while(0) } } while(0)
#ifdef FG_NDEBUG #ifdef FG_NDEBUG
# define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0) # define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0)
# define SG_LOG_NAN(C,P,M) SG_LOG(C,P,M)
# define SG_HEXDUMP(C,P,MEM,LEN) # define SG_HEXDUMP(C,P,MEM,LEN)
#else #else
# define SG_LOG(C,P,M) SG_LOGX(C,P,M) # define SG_LOG(C,P,M) SG_LOGX(C,P,M)
# define SG_LOG_NAN(C,P,M) do { SG_LOGX(C,P,M); throw std::overflow_error(M); } while(0)
# define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) # define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN)
#endif #endif
-33
View File
@@ -1,33 +0,0 @@
include (SimGearComponent)
set(HEADERS
Emesary.hxx
INotification.hxx
IReceiver.hxx
ITransmitter.hxx
ReceiptStatus.hxx
Transmitter.hxx
notifications.hxx
)
set(SOURCES
Emesary.cxx
)
simgear_component(emesary emesary "${SOURCES}" "${HEADERS}")
if(ENABLE_TESTS)
add_executable(test_emesary test_emesary.cxx)
set_target_properties(test_emesary PROPERTIES
COMPILE_DEFINITIONS "SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" )
target_link_libraries(test_emesary ${TEST_LIBS})
add_test(emesary ${EXECUTABLE_OUTPUT_PATH}/test_emesary)
endif(ENABLE_TESTS)
-31
View File
@@ -1,31 +0,0 @@
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : Emesary main.
* : This only needs to instance the GlobalTransmitter as all of the
* : logic is in the header files (by design)
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002
*
* Version : $Header: $
*
* Copyright © 2002 Richard Harrison All Rights Reserved.
*
*---------------------------------------------------------------------------*/
#include "simgear/emesary/Emesary.hxx"
namespace simgear
{
namespace Emesary
{
}
}
-48
View File
@@ -1,48 +0,0 @@
#ifndef EMESARY_hxx
#define EMESARY_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : Provides generic inter-object communication. For an object to receive a message it
* : must first register with a Transmitter, such as GlobalTransmitter, and implement the
* : IReceiver interface. That's it.
* : To send a message use a Transmitter with an object. That's all there is to it.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
#include <typeinfo>
#include "ReceiptStatus.hxx"
#include "INotification.hxx"
#include "IReceiver.hxx"
#include "ITransmitter.hxx"
#include "Transmitter.hxx"
#include <simgear/structure/Singleton.hxx>
namespace simgear
{
namespace Emesary
{
class GlobalTransmitter : public simgear::Singleton<Transmitter>
{
public:
GlobalTransmitter()
{
}
virtual ~GlobalTransmitter() {}
};
}
}
#endif
-54
View File
@@ -1,54 +0,0 @@
#ifndef INOTIFICATION_hxx
#define INOTIFICATION_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Notification base class
*
* File Type : Implementation File
*
* Description : Base class (interface) for all Notifications.
* : This is also compatible with the usual implementation of how we
* : implement queued notifications.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base class) for all notifications.
class INotification
{
public:
// text representation of notification type. must be unique across all notifications
virtual const char *GetType() = 0;
/// Used to control the sending of notifications. If this returns false then the Transmitter
/// should not send this notification.
virtual bool IsReadyToSend() { return true; }
/// Used to control the timeout. If this notification has timed out - then the processor is entitled
/// to true.
virtual bool IsTimedOut() { return false; }
/// when this notification has completed the processing recipient must set this to true.
/// the processing recipient is responsible for follow on notifications.
/// a notification can remain as complete until the transmit queue decides to remove it from the queue.
/// there is no requirement that elements are removed immediately upon completion merely that once complete
/// the transmitter should not notify any more elements.
/// The current notification loop may be completed - following the usual convention unless Completed or Abort
/// is returned as the status.
virtual bool IsComplete() { return true; }
};
}
}
#endif
-47
View File
@@ -1,47 +0,0 @@
#ifndef IRECEIVER_hxx
#define IRECEIVER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Receiver base class
*
* File Type : Implementation File
*
* Description : Base class for all recipients.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base class) for a recipeint.
class IReceiver
{
public:
/// Receive notification - must be implemented
virtual ReceiptStatus Receive(INotification& message) = 0;
/// Called when registered at a transmitter
virtual void OnRegisteredAtTransmitter(class Transmitter *p)
{
}
/// Called when de-registered at a transmitter
virtual void OnDeRegisteredAtTransmitter(class Transmitter *p)
{
}
};
}
}
#endif
-52
View File
@@ -1,52 +0,0 @@
#ifndef ITRANSMITTER_hxx
#define ITRANSMITTER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Base class for all transmitters.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base clasee) for a transmitter.
/// Transmits Message derived objects. Each instance of this class provides a
/// event/databus to which any number of receivers can attach to.
class ITransmitter
{
public:
// Registers a recipient to receive message from this transmitter
virtual void Register(IReceiver& R) = 0;
// Removes a recipient from from this transmitter
virtual void DeRegister(IReceiver& R) = 0;
//Notify all registered recipients. Stop when receipt status of abort or finished are received.
//The receipt status from this method will be
// - OK > message handled
// - Fail > message not handled. A status of Abort from a recipient will result in our status
// being fail as Abort means that the message was not and cannot be handled, and
// allows for usages such as access controls.
virtual ReceiptStatus NotifyAll(INotification& M) = 0;
/// number of recipients
virtual int Count() = 0;
};
}
}
#endif
-54
View File
@@ -1,54 +0,0 @@
#ifndef RECEIPTSTATUS_hxx
#define RECEIPTSTATUS_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Defines the receipt status that can be returned from
* : a receive method.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
enum ReceiptStatus
{
/// Processing completed successfully
ReceiptStatusOK = 0,
/// Individual item failure
ReceiptStatusFail = 1,
/// Fatal error; stop processing any further recipieints of this message. Implicitly fail
ReceiptStatusAbort = 2,
/// Definitive completion - do not send message to any further recipieints
ReceiptStatusFinished = 3,
/// Return value when method doesn't process a message.
ReceiptStatusNotProcessed = 4,
/// Message has been sent but the return status cannot be determined as it has not been processed by the recipient.
/// e.g. a queue or outgoing bridge
ReceiptStatusPending = 5,
/// Message has been definitively handled but the return value cannot be determined. The message will not be sent any further
/// e.g. a point to point forwarding bridge
ReceiptStatusPendingFinished = 6,
};
}
}
#endif
-189
View File
@@ -1,189 +0,0 @@
#ifndef TRANSMITTER_hxx
#define TRANSMITTER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Defines the receipt status that can be returned from
* : a receive method.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
#include <algorithm>
#include <string>
#include <list>
#include <set>
#include <vector>
#include <atomic>
#include <mutex>
namespace simgear
{
namespace Emesary
{
// Implementation of a ITransmitter
class Transmitter : public ITransmitter
{
protected:
typedef std::list<IReceiver *> RecipientList;
RecipientList recipient_list;
RecipientList deleted_recipients;
int CurrentRecipientIndex = 0;
std::mutex _lock;
std::atomic<int> receiveDepth;
std::atomic<int> sentMessageCount;
public:
Transmitter() : receiveDepth(0), sentMessageCount(0)
{
}
virtual ~Transmitter()
{
}
// Registers an object to receive messsages from this transmitter.
// This object is added to the top of the list of objects to be notified. This is deliberate as
// the sequence of registration and message receipt can influence the way messages are processing
// when ReceiptStatus of Abort or Finished are encountered. So it was a deliberate decision that the
// most recently registered recipients should process the messages/events first.
virtual void Register(IReceiver& r)
{
std::lock_guard<std::mutex> scopeLock(_lock);
recipient_list.push_back(&r);
r.OnRegisteredAtTransmitter(this);
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
deleted_recipients.remove(&r);
}
// Removes an object from receving message from this transmitter
virtual void DeRegister(IReceiver& R)
{
std::lock_guard<std::mutex> scopeLock(_lock);
if (recipient_list.size())
{
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
{
recipient_list.remove(&R);
R.OnDeRegisteredAtTransmitter(this);
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &R) == deleted_recipients.end())
deleted_recipients.push_back(&R);
}
}
}
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
// The receipt status from this method will be
// - OK > message handled
// - Fail > message not handled. A status of Abort from a recipient will result in our status
// being fail as Abort means that the message was not and cannot be handled, and
// allows for usages such as access controls.
virtual ReceiptStatus NotifyAll(INotification& M)
{
ReceiptStatus return_status = ReceiptStatusNotProcessed;
sentMessageCount++;
std::vector<IReceiver*> temp;
{
std::lock_guard<std::mutex> scopeLock(_lock);
if (receiveDepth == 0)
deleted_recipients.clear();
receiveDepth++;
int idx = 0;
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
{
temp.push_back(*i);
}
}
int tempSize = temp.size();
for (int index = 0; index < tempSize; index++)
{
IReceiver* R = temp[index];
{
std::lock_guard<std::mutex> scopeLock(_lock);
if (deleted_recipients.size())
{
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
{
continue;
}
}
}
if (R)
{
ReceiptStatus rstat = R->Receive(M);
switch (rstat)
{
case ReceiptStatusFail:
return_status = ReceiptStatusFail;
break;
case ReceiptStatusPending:
return_status = ReceiptStatusPending;
break;
case ReceiptStatusPendingFinished:
return rstat;
case ReceiptStatusNotProcessed:
break;
case ReceiptStatusOK:
if (return_status == ReceiptStatusNotProcessed)
return_status = rstat;
break;
case ReceiptStatusAbort:
return ReceiptStatusAbort;
case ReceiptStatusFinished:
return ReceiptStatusOK;
}
}
}
receiveDepth--;
return return_status;
}
// number of currently registered recipients
virtual int Count()
{
std::lock_guard<std::mutex> scopeLock(_lock);
return recipient_list.size();
}
// number of sent messages.
int SentMessageCount()
{
return sentMessageCount;
}
// ascertain if a receipt status can be interpreted as failure.
static bool Failed(ReceiptStatus receiptStatus)
{
//
// failed is either Fail or Abort.
// NotProcessed isn't a failure because it hasn't been processed.
return receiptStatus == ReceiptStatusFail
|| receiptStatus == ReceiptStatusAbort;
}
};
}
}
#endif
-68
View File
@@ -1,68 +0,0 @@
#ifndef NOTIFICATIONS_hxx
#define NOTIFICATIONS_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : simgear notifications
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017
*
* Version : $Header: $
*
* Copyright � 2002 - 2017 Richard Harrison All Rights Reserved.
*
*---------------------------------------------------------------------------*/
#include "INotification.hxx"
namespace simgear
{
namespace Notifications
{
class MainLoopNotification : public simgear::Emesary::INotification
{
public:
enum Type { Started, Stopped, Begin, End };
MainLoopNotification(Type v) : _type(v) {}
virtual Type GetValue() { return _type; }
virtual const char *GetType() { return "MainLoop"; }
protected:
Type _type;
};
class NasalGarbageCollectionConfigurationNotification : public simgear::Emesary::INotification
{
public:
NasalGarbageCollectionConfigurationNotification(bool canWait, bool active) : CanWait(canWait), Active(active) {}
virtual bool GetCanWait() { return CanWait; }
virtual bool GetActive() { return Active; }
virtual const char *GetType() { return "NasalGarbageCollectionConfiguration"; }
virtual bool SetWait(bool wait) {
if (wait == CanWait)
return false;
CanWait = wait;
return true;
}
virtual bool SetActive(bool active) {
if (active == Active)
return false;
Active = active;
return true;
}
public:
bool CanWait;
bool Active;
};
}
}
#endif
-130
View File
@@ -1,130 +0,0 @@
////////////////////////////////////////////////////////////////////////
// Test harness for Emesary.
////////////////////////////////////////////////////////////////////////
#include <simgear_config.h>
#include <simgear/compiler.h>
#include <iostream>
#include <simgear/threads/SGThread.hxx>
#include <simgear/emesary/Emesary.hxx>
using std::cout;
using std::cerr;
using std::endl;
std::atomic<int> nthread {0};
std::atomic<int> noperations {0};
const int MaxIterations = 9999;
class TestThreadNotification : public simgear::Emesary::INotification
{
protected:
const char *baseValue;
public:
TestThreadNotification(const char *v) : baseValue(v) {}
virtual const char* GetType () { return baseValue; }
};
class TestThreadRecipient : public simgear::Emesary::IReceiver
{
public:
TestThreadRecipient() : receiveCount(0)
{
}
std::atomic<int> receiveCount;
virtual simgear::Emesary::ReceiptStatus Receive(simgear::Emesary::INotification &n)
{
if (n.GetType() == (const char*)this)
{
// Unused: TestThreadNotification *tn = dynamic_cast<TestThreadNotification *>(&n);
receiveCount++;
TestThreadNotification onwardNotification("AL");
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(onwardNotification);
return simgear::Emesary::ReceiptStatusOK;
}
return simgear::Emesary::ReceiptStatusOK;
}
};
class EmesaryTestThread : public SGThread
{
protected:
virtual void run() {
int threadId = nthread.fetch_add(1);
//System.Threading.Interlocked.Increment(ref nthread);
//var rng = new Random();
TestThreadRecipient r;
char temp[100];
sprintf(temp, "Notif %d", threadId);
printf("starting thread %s\n", temp);
TestThreadNotification tn((const char*)&r);
for (int i = 0; i < MaxIterations; i++)
{
simgear::Emesary::GlobalTransmitter::instance()->Register(r);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(tn);
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(r);
//System.Threading.Thread.Sleep(rng.Next(MaxSleep));
noperations++;
}
printf("%s invocations %d\n", temp, (int)r.receiveCount);
printf("finish thread %s\n", temp);
}
};
class EmesaryTest
{
public:
void Emesary_MultiThreadTransmitterTest()
{
int num_threads = 12;
std::list<EmesaryTestThread*> threads;
for (int i = 0; i < num_threads; i++)
{
EmesaryTestThread *thread = new EmesaryTestThread();
threads.push_back(thread);
thread->start();
}
for (std::list<EmesaryTestThread*>::iterator i = threads.begin(); i != threads.end(); i++)
{
(*i)->join();
}
}
};
void testEmesaryThreaded()
{
TestThreadRecipient r;
TestThreadNotification tn((const char*)&r);
simgear::Emesary::GlobalTransmitter::instance()->Register(r);
for (int i = 0; i < MaxIterations*MaxIterations; i++)
{
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(tn);
//System.Threading.Thread.Sleep(rng.Next(MaxSleep));
noperations++;
}
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(r);
printf("invocations %d\n", simgear::Emesary::GlobalTransmitter::instance()->SentMessageCount());
EmesaryTest t;
t.Emesary_MultiThreadTransmitterTest();
}
int main(int ac, char ** av)
{
testEmesaryThreaded();
std::cout << "all tests passed" << std::endl;
return 0;
}
+8 -352
View File
@@ -38,15 +38,11 @@
# include <simgear_config.h> # include <simgear_config.h>
#endif #endif
#include <iomanip>
#include <string> #include <string>
#include <time.h> #include <time.h>
#include <cstring> #include <cstring>
#include <ostream>
#include <sstream>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include "metar.hxx" #include "metar.hxx"
@@ -159,320 +155,6 @@ SGMetar::~SGMetar()
} }
static const char *azimuthName(double d)
{
const char *dir[] = {
"N", "NNE", "NE", "ENE",
"E", "ESE", "SE", "SSE",
"S", "SSW", "SW", "WSW",
"W", "WNW", "NW", "NNW"
};
d += 11.25;
while (d < 0)
d += 360;
while (d >= 360)
d -= 360;
return dir[int(d / 22.5)];
}
// round double to 10^g
static double rnd(double r, int g = 0)
{
double f = pow(10.0, g);
return f * floor(r / f + 0.5);
}
/* A manipulator that can use spaces to emulate tab characters. */
struct Tab
{
/* If <stops> is 0, we simply insert tab characters. Otherwise we insert
spaces to align with the next column at multiple of <stops>. */
explicit Tab(int stops)
:
_stops(stops)
{}
int _stops;
};
std::ostream& operator << (std::ostream& out, const Tab& t)
{
if (t._stops == 0) {
return out << '\t';
}
std::ostringstream& out2 = *(std::ostringstream*) &out;
std::string s = out2.str();
if (t._stops < 0) {
if (!s.size() || s[s.size()-1] != ' ') {
out << ' ';
}
return out;
}
auto nl = s.rfind('\n');
if (nl < 0) nl = 0;
int column = 0;
for (auto i = nl+1; i != s.size(); ++i) {
if (s[i] == '\t')
column = (column + t._stops) / t._stops * t._stops;
else
column += 1;
}
int column2 = (column + t._stops) / t._stops * t._stops;
for (int i=column; i<column2; ++i) {
out << ' ';
}
return out;
}
/* Manipulator for SGMetarVisibility using a Tab. */
struct SGMetarVisibilityManip
{
explicit SGMetarVisibilityManip(const SGMetarVisibility& v, const Tab& tab)
:
_v(v),
_tab(tab)
{}
const SGMetarVisibility& _v;
const Tab& _tab;
};
std::ostream& operator << (std::ostream& out, const SGMetarVisibilityManip& v)
{
int m = v._v.getModifier();
const char *mod;
if (m == SGMetarVisibility::GREATER_THAN)
mod = ">=";
else if (m == SGMetarVisibility::LESS_THAN)
mod = "<";
else
mod = "";
out << mod;
double dist = rnd(v._v.getVisibility_m(), 1);
if (dist < 1000.0)
out << rnd(dist, 1) << " m";
else
out << rnd(dist / 1000.0, -1) << " km";
const char *dir = "";
int i;
if ((i = v._v.getDirection()) != -1) {
dir = azimuthName(i);
out << " " << dir;
}
out << v._tab << v._tab << v._tab << v._tab << v._tab;
out << mod << rnd(v._v.getVisibility_sm(), -1) << " US-miles " << dir;
return out;
}
std::string SGMetar::getDescription(int tabstops) const
{
std::ostringstream out;
const char *s;
char buf[256];
double d;
int i, lineno;
Tab tab(tabstops);
if ((i = getReportType()) == SGMetar::AUTO)
out << "(METAR automatically generated)\n";
else if (i == SGMetar::COR)
out << "(METAR manually corrected)\n";
else if (i == SGMetar::RTD)
out << "(METAR routine delayed)\n";
out << "Airport-Id:" << tab << tab << getId() << "\n";
// date/time
int year = getYear();
int month = getMonth();
out << "Report time:" << tab << tab << year << '/' << month << '/' << getDay();
out << ' ' << getHour() << ':';
out << std::setw(2) << std::setfill('0') << getMinute() << " UTC\n";
// visibility
SGMetarVisibility minvis = getMinVisibility();
SGMetarVisibility maxvis = getMaxVisibility();
double min = minvis.getVisibility_m();
double max = maxvis.getVisibility_m();
if (min != NaN) {
if (max != NaN) {
out << "min. Visibility:" << tab << SGMetarVisibilityManip(minvis, tab) << "\n";
out << "max. Visibility:" << tab << SGMetarVisibilityManip(maxvis, tab) << "\n";
} else {
out << "Visibility:" << tab << tab << SGMetarVisibilityManip(minvis, tab) << "\n";
}
}
// directed visibility
const SGMetarVisibility *dirvis = getDirVisibility();
for (i = 0; i < 8; i++, dirvis++)
if (dirvis->getVisibility_m() != NaN)
out << tab << tab << tab << SGMetarVisibilityManip(*dirvis, tab) << "\n";
// vertical visibility
SGMetarVisibility vertvis = getVertVisibility();
if ((d = vertvis.getVisibility_ft()) != NaN)
out << "Vert. visibility:" << tab << SGMetarVisibilityManip(vertvis, tab) << "\n";
else if (vertvis.getModifier() == SGMetarVisibility::NOGO)
out << "Vert. visibility:" << tab << "impossible to determine" << "\n";
// wind
d = getWindSpeed_kmh();
out << "Wind:" << tab << tab << tab;
if (d < .1)
out << "none" << "\n";
else {
if ((i = getWindDir()) == -1)
out << "from variable directions";
else
out << "from the " << azimuthName(i) << " (" << i << " deg)";
out << " at " << rnd(d, -1) << " km/h";
out << tab << tab << rnd(getWindSpeed_kt(), -1) << " kt";
out << " = " << rnd(getWindSpeed_mph(), -1) << " mph";
out << " = " << rnd(getWindSpeed_mps(), -1) << " m/s";
out << "\n";
d = getGustSpeed_kmh();
if (d != NaN && d != 0) {
out << tab << tab << tab << "with gusts at " << rnd(d, -1) << " km/h";
out << tab << tab << tab << rnd(getGustSpeed_kt(), -1) << " kt";
out << " = " << rnd(getGustSpeed_mph(), -1) << " mph";
out << " = " << rnd(getGustSpeed_mps(), -1) << " m/s";
out << "\n";
}
int from = getWindRangeFrom();
int to = getWindRangeTo();
if (from != to) {
out << tab << tab << tab << "variable from " << azimuthName(from);
out << " to " << azimuthName(to);
out << " (" << from << "deg --" << to << " deg)" << "\n";
}
}
// temperature/humidity/air pressure
if ((d = getTemperature_C()) != NaN) {
out << "Temperature:" << tab << tab << d << " C" << tab << tab << tab << tab << tab;
out << rnd(getTemperature_F(), -1) << " F" << "\n";
if ((d = getDewpoint_C()) != NaN) {
out << "Dewpoint:" << tab << tab << d << " C" << tab << tab << tab << tab << tab;
out << rnd(getDewpoint_F(), -1) << " F" << "\n";
out << "Rel. Humidity: " << tab << tab << rnd(getRelHumidity()) << " %" << "\n";
}
}
if ((d = getPressure_hPa()) != NaN) {
out << "Pressure:" << tab << tab << rnd(d) << " hPa" << tab << tab << tab << tab;
out << rnd(getPressure_inHg(), -2) << " in. Hg" << "\n";
}
// weather phenomena
vector<string> wv = getWeather();
vector<string>::iterator weather;
for (i = 0, weather = wv.begin(); weather != wv.end(); weather++, i++) {
out << (i ? ", " : "Weather:") << tab << tab << weather->c_str();
}
if (i)
out << "\n";
// cloud layers
const char *coverage_string[5] = {
"clear skies", "few clouds", "scattered clouds", "broken clouds", "sky overcast"
};
vector<SGMetarCloud> cv = getClouds();
vector<SGMetarCloud>::iterator cloud;
for (lineno = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, lineno++) {
if (lineno) out << tab << tab << tab;
else out << "Sky condition:" << tab << tab;
if ((i = cloud->getCoverage()) != -1)
out << coverage_string[i];
if ((d = cloud->getAltitude_ft()) != NaN)
out << " at " << rnd(d, 1) << " ft";
if ((s = cloud->getTypeLongString()))
out << " (" << s << ')';
if (d != NaN)
out << tab << tab << tab << rnd(cloud->getAltitude_m(), 1) << " m";
out << "\n";
}
// runways
map<string, SGMetarRunway> rm = getRunways();
map<string, SGMetarRunway>::iterator runway;
for (runway = rm.begin(); runway != rm.end(); runway++) {
lineno = 0;
if (!strcmp(runway->first.c_str(), "ALL"))
out << "All runways:" << tab << tab;
else
out << "Runway " << runway->first << ":" << tab << tab;
SGMetarRunway rwy = runway->second;
// assemble surface string
vector<string> surface;
if ((s = rwy.getDepositString()) && strlen(s))
surface.push_back(s);
if ((s = rwy.getExtentString()) && strlen(s))
surface.push_back(s);
if ((d = rwy.getDepth()) != NaN) {
sprintf(buf, "%.1lf mm", d * 1000.0);
surface.push_back(buf);
}
if ((s = rwy.getFrictionString()) && strlen(s))
surface.push_back(s);
if ((d = rwy.getFriction()) != NaN) {
sprintf(buf, "friction: %.2lf", d);
surface.push_back(buf);
}
if (! surface.empty()) {
vector<string>::iterator rwysurf = surface.begin();
for (i = 0; rwysurf != surface.end(); rwysurf++, i++) {
if (i)
out << ", ";
out << *rwysurf;
}
lineno++;
}
// assemble visibility string
SGMetarVisibility minvis = rwy.getMinVisibility();
SGMetarVisibility maxvis = rwy.getMaxVisibility();
if ((d = minvis.getVisibility_m()) != NaN) {
if (lineno++)
out << "\n" << tab << tab << tab;
out << SGMetarVisibilityManip(minvis, tab);
}
if (maxvis.getVisibility_m() != d) {
out << "\n" << tab << tab << tab << SGMetarVisibilityManip(maxvis, tab) << "\n";
lineno++;
}
if (rwy.getWindShear()) {
if (lineno++)
out << "\n" << tab << tab << tab;
out << "critical wind shear" << "\n";
}
out << "\n";
}
out << "\n";
return out.str();
}
void SGMetar::useCurrentDate() void SGMetar::useCurrentDate()
{ {
struct tm now; struct tm now;
@@ -632,41 +314,30 @@ bool SGMetar::scanWind()
int dir; int dir;
if (!strncmp(m, "VRB", 3)) if (!strncmp(m, "VRB", 3))
m += 3, dir = -1; m += 3, dir = -1;
else if (!strncmp(m, "///", 3)) // direction not measurable
m += 3, dir = -1;
else if (!scanNumber(&m, &dir, 3)) else if (!scanNumber(&m, &dir, 3))
return false; return false;
int i; int i;
if (!strncmp(m, "//", 2)) // speed not measurable if (!scanNumber(&m, &i, 2, 3))
m += 2, i = -1;
else if (!scanNumber(&m, &i, 2, 3))
return false; return false;
double speed = i; double speed = i;
double gust = NaN; double gust = NaN;
if (*m == 'G') { if (*m == 'G') {
m++; m++;
if (!strncmp(m, "//", 2)) // speed not measurable if (!scanNumber(&m, &i, 2, 3))
m += 2, i = -1;
else if (!scanNumber(&m, &i, 2, 3))
return false; return false;
if (i != -1)
gust = i; gust = i;
} }
double factor; double factor;
if (!strncmp(m, "KT", 2)) if (!strncmp(m, "KT", 2))
m += 2, factor = SG_KT_TO_MPS; m += 2, factor = SG_KT_TO_MPS;
else if (!strncmp(m, "KMH", 3)) // invalid Km/h else if (!strncmp(m, "KMH", 3))
m += 3, factor = SG_KMH_TO_MPS; m += 3, factor = SG_KMH_TO_MPS;
else if (!strncmp(m, "KPH", 3)) // invalid Km/h else if (!strncmp(m, "KPH", 3)) // ??
m += 3, factor = SG_KMH_TO_MPS; m += 3, factor = SG_KMH_TO_MPS;
else if (!strncmp(m, "MPS", 3)) else if (!strncmp(m, "MPS", 3))
m += 3, factor = 1.0; m += 3, factor = 1.0;
else if (!strncmp(m, " ", 1)) // default to Knots
factor = SG_KT_TO_MPS;
else else
return false; return false;
if (!scanBoundary(&m)) if (!scanBoundary(&m))
@@ -686,28 +357,18 @@ bool SGMetar::scanVariability()
{ {
char *m = _m; char *m = _m;
int from, to; int from, to;
if (!scanNumber(&m, &from, 3))
if (!strncmp(m, "///", 3)) // direction not measurable
m += 3, from = -1;
else if (!scanNumber(&m, &from, 3))
return false; return false;
if (*m++ != 'V') if (*m++ != 'V')
return false; return false;
if (!scanNumber(&m, &to, 3))
if (!strncmp(m, "///", 3)) // direction not measurable
m += 3, to = -1;
else if (!scanNumber(&m, &to, 3))
return false; return false;
if (!scanBoundary(&m)) if (!scanBoundary(&m))
return false; return false;
_m = m; _m = m;
_wind_range_from = from; _wind_range_from = from;
_wind_range_to = to; _wind_range_to = to;
_grpcount++; _grpcount++;
return true; return true;
} }
@@ -974,8 +635,6 @@ bool SGMetar::scanWeather()
weather += string(a->text) + " "; weather += string(a->text) + " ";
if (!strcmp(a->id, "RA")) if (!strcmp(a->id, "RA"))
_rain = w.intensity; _rain = w.intensity;
else if (!strcmp(a->id, "DZ"))
_rain = LIGHT;
else if (!strcmp(a->id, "HA")) else if (!strcmp(a->id, "HA"))
_hail = w.intensity; _hail = w.intensity;
else if (!strcmp(a->id, "SN")) else if (!strcmp(a->id, "SN"))
@@ -1069,12 +728,9 @@ bool SGMetar::scanSkyCondition()
return false; return false;
m += i; m += i;
if (!strncmp(m, "///", 3)) { // vis not measurable (e.g. because of heavy snowing) if (!strncmp(m, "///", 3)) // vis not measurable (e.g. because of heavy snowing)
m += 3, i = -1; m += 3, i = -1;
sg_srandom_time(); else if (scanBoundary(&m)) {
// randomize the base height to avoid the black sky issue
i = 50 + static_cast<int>(sg_random() * 250.0); // range [5,000, 30,000]
} else if (scanBoundary(&m)) {
_m = m; _m = m;
return true; // ignore single OVC/BKN/... return true; // ignore single OVC/BKN/...
} else if (!scanNumber(&m, &i, 3)) } else if (!scanNumber(&m, &i, 3))
-5
View File
@@ -235,11 +235,6 @@ public:
inline const std::vector<std::string>& getWeather() const { return _weather; } inline const std::vector<std::string>& getWeather() const { return _weather; }
inline const std::vector<struct Weather> getWeather2() const { return _weather2; } inline const std::vector<struct Weather> getWeather2() const { return _weather2; }
/* Returns human-readable description. If tabtops is 0, we use tab
characters. If +ve we use spaces to pad to multiple of <tabstops>. If
-1 all sequences of tabs are represented by a single space. */
std::string getDescription(int tabstops) const;
protected: protected:
std::string _url; std::string _url;
int _grpcount; int _grpcount;
-10
View File
@@ -44,10 +44,6 @@ SGPrecipitation::SGPrecipitation() :
void SGPrecipitation::setEnabled( bool value ) void SGPrecipitation::setEnabled( bool value )
{ {
_enabled = value; _enabled = value;
if (!_enabled) {
_precipitationEffect->snow(0);
_precipitationEffect->rain(0);
}
} }
void SGPrecipitation::setDropletExternal( bool value ) void SGPrecipitation::setDropletExternal( bool value )
@@ -68,9 +64,6 @@ bool SGPrecipitation::getEnabled() const
*/ */
osg::Group* SGPrecipitation::build(void) osg::Group* SGPrecipitation::build(void)
{ {
if (!_enabled)
return nullptr;
osg::ref_ptr<osg::Group> group = new osg::Group; osg::ref_ptr<osg::Group> group = new osg::Group;
_precipitationEffect->snow(0); _precipitationEffect->snow(0);
@@ -234,9 +227,6 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
*/ */
bool SGPrecipitation::update(void) bool SGPrecipitation::update(void)
{ {
if (!_enabled)
return false;
if (this->_freeze) { if (this->_freeze) {
if (this->_rain_intensity > 0) { if (this->_rain_intensity > 0) {
this->_snow_intensity = this->_rain_intensity; this->_snow_intensity = this->_rain_intensity;
-26
View File
@@ -76,38 +76,12 @@ void test_sensor_failure_cloud()
SG_CHECK_EQUAL_EP2(m1.getPressure_hPa(), 1025, TEST_EPSILON); SG_CHECK_EQUAL_EP2(m1.getPressure_hPa(), 1025, TEST_EPSILON);
} }
void test_sensor_failure_wind()
{
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
SG_CHECK_EQUAL(m1.getWindDir(), -1);
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
SGMetar m2("2020/10/21 16:55 LIVD 211655Z /////KT CAVOK 07/03 Q1023 RMK SKC VIS MIN 9999 BLU");
SG_CHECK_EQUAL(m2.getWindDir(), -1);
SG_CHECK_EQUAL_EP2(m2.getWindSpeed_kt(), -1, TEST_EPSILON);
SGMetar m3("2020/11/17 16:00 CYAZ 171600Z 14040G//KT 10SM -RA OVC012 12/11 A2895 RMK NS8 VIA CYXY SLP806 DENSITY ALT 900FT");
SG_CHECK_EQUAL(m3.getWindDir(), 140);
SG_CHECK_EQUAL_EP2(m3.getWindSpeed_kt(), 40, TEST_EPSILON);
SG_CHECK_EQUAL_EP2(m3.getGustSpeed_kt(), SGMetarNaN, TEST_EPSILON);
}
void test_wind_unit_not_specified()
{
SGMetar m1("2020/10/23 11:58 KLSV 231158Z 05010G14 10SM CLR 16/M04 A2992 RMK SLPNO WND DATA ESTMD ALSTG/SLP ESTMD 10320 20124 5//// $");
SG_CHECK_EQUAL(m1.getWindDir(), 50);
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), 10.0, TEST_EPSILON);
SG_CHECK_EQUAL_EP2(m1.getGustSpeed_kt(), 14.0, TEST_EPSILON);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
try { try {
test_basic(); test_basic();
test_sensor_failure_weather(); test_sensor_failure_weather();
test_sensor_failure_cloud(); test_sensor_failure_cloud();
test_sensor_failure_wind();
test_wind_unit_not_specified();
} catch (sg_exception& e) { } catch (sg_exception& e) {
cerr << "got exception:" << e.getMessage() << endl; cerr << "got exception:" << e.getMessage() << endl;
return -1; return -1;
+52
View File
@@ -191,11 +191,52 @@ SGEnviro::~SGEnviro(void) {
// OSGFIXME // OSGFIXME
return; return;
list_of_lightning::iterator iLightning;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; ++iLightning ) {
delete (*iLightning);
}
lightnings.clear();
} }
void SGEnviro::startOfFrame( SGVec3f p, SGVec3f up, double lon, double lat, double alt, double delta_time) { void SGEnviro::startOfFrame( SGVec3f p, SGVec3f up, double lon, double lat, double alt, double delta_time) {
// OSGFIXME // OSGFIXME
return; return;
view_in_cloud = false;
// ask the impostor cache to do some cleanup
last_cloud_turbulence = cloud_turbulence;
cloud_turbulence = 0.0;
elapsed_time += delta_time;
min_time_before_lt -= delta_time;
dt = delta_time;
#if 0
sgMat4 T1, LON, LAT;
sgVec3 axis;
sgMakeTransMat4( T1, p );
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon, axis );
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat, axis );
sgMat4 TRANSFORM;
sgCopyMat4( TRANSFORM, T1 );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord pos;
sgSetCoord( &pos, TRANSFORM );
sgMakeCoordMat4( transform, &pos );
#endif
last_lon = lon;
last_lat = lat;
last_alt = alt;
radarEcho.clear();
precipitation_max_alt = 400.0;
} }
void SGEnviro::endOfFrame(void) { void SGEnviro::endOfFrame(void) {
@@ -250,6 +291,10 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
void SGEnviro::setLight(SGVec4f adj_fog_color) { void SGEnviro::setLight(SGVec4f adj_fog_color) {
// OSGFIXME // OSGFIXME
return; return;
fog_color = adj_fog_color;
if( false ) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
}
} }
#if 0 #if 0
void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) { void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
@@ -386,6 +431,9 @@ void SGEnviro::set_sampleGroup(SGSampleGroup *sgr) {
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) { void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
// OSGFIXME // OSGFIXME
return; return;
if( precipitation_enable_state && rain_norm > 0.0)
if( precipitation_max_alt >= last_alt )
drawRain(pitch, roll, heading, hspeed, rain_norm);
} }
@@ -423,6 +471,10 @@ void SGLightning::lt_Render(void) {
void SGEnviro::addLightning(double lon, double lat, double alt) { void SGEnviro::addLightning(double lon, double lat, double alt) {
// OSGFIXME // OSGFIXME
return; return;
if( lightnings.size() > 10)
return;
SGLightning *lt= new SGLightning(lon, lat, alt);
lightnings.push_back(lt);
} }
void SGEnviro::drawLightning(void) { void SGEnviro::drawLightning(void) {
+2 -2
View File
@@ -31,7 +31,7 @@
// Constructor // Constructor
SGEphemeris::SGEphemeris( const SGPath& path ) { SGEphemeris::SGEphemeris( const std::string &path ) {
our_sun = new Star; our_sun = new Star;
moon = new MoonPos; moon = new MoonPos;
mercury = new Mercury; mercury = new Mercury;
@@ -44,7 +44,7 @@ SGEphemeris::SGEphemeris( const SGPath& path ) {
nplanets = 7; nplanets = 7;
for ( int i = 0; i < nplanets; ++i ) for ( int i = 0; i < nplanets; ++i )
planets[i] = SGVec3d::zeros(); planets[i] = SGVec3d::zeros();
stars = new SGStarData(path); stars = new SGStarData( SGPath(path) );
} }
+1 -1
View File
@@ -97,7 +97,7 @@ public:
* calling the constructor you need to provide a path pointing to * calling the constructor you need to provide a path pointing to
* your star database file. * your star database file.
* @param path path to your star database */ * @param path path to your star database */
SGEphemeris( const SGPath &path ); SGEphemeris( const std::string &path );
/** Destructor */ /** Destructor */
~SGEphemeris( void ); ~SGEphemeris( void );
+3 -5
View File
@@ -19,13 +19,11 @@
# include <simgear_config.h> # include <simgear_config.h>
#endif #endif
#include <mutex>
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include "RTIFederateFactoryRegistry.hxx" #include "RTIFederateFactoryRegistry.hxx"
#include "simgear/threads/SGThread.hxx" #include "simgear/threads/SGGuard.hxx"
#include "RTIFederate.hxx" #include "RTIFederate.hxx"
namespace simgear { namespace simgear {
@@ -41,7 +39,7 @@ RTIFederateFactoryRegistry::~RTIFederateFactoryRegistry()
SGSharedPtr<RTIFederate> SGSharedPtr<RTIFederate>
RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std::string>& stringList) const RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std::string>& stringList) const
{ {
std::lock_guard<std::mutex> guard(_mutex); SGGuard<SGMutex> guard(_mutex);
for (FederateFactoryList::const_iterator i = _federateFactoryList.begin(); i != _federateFactoryList.end(); ++i) { for (FederateFactoryList::const_iterator i = _federateFactoryList.begin(); i != _federateFactoryList.end(); ++i) {
SGSharedPtr<RTIFederate> federate = (*i)->create(name, stringList); SGSharedPtr<RTIFederate> federate = (*i)->create(name, stringList);
if (!federate.valid()) if (!federate.valid())
@@ -54,7 +52,7 @@ RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std:
void void
RTIFederateFactoryRegistry::registerFactory(RTIFederateFactory* factory) RTIFederateFactoryRegistry::registerFactory(RTIFederateFactory* factory)
{ {
std::lock_guard<std::mutex> guard(_mutex); SGGuard<SGMutex> guard(_mutex);
_federateFactoryList.push_back(factory); _federateFactoryList.push_back(factory);
} }
-90
View File
@@ -1,90 +0,0 @@
// Copyright (C) 2021 James Turner - <james@flightgear.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#pragma once
#include "untar.hxx"
namespace simgear {
class ArchiveExtractorPrivate
{
public:
ArchiveExtractorPrivate(ArchiveExtractor* o) : outer(o)
{
assert(outer);
}
virtual ~ArchiveExtractorPrivate() = default;
typedef enum {
INVALID = 0,
READING_HEADER,
READING_FILE,
READING_PADDING,
READING_PAX_GLOBAL_ATTRIBUTES,
READING_PAX_FILE_ATTRIBUTES,
PRE_END_OF_ARCHVE,
END_OF_ARCHIVE,
ERROR_STATE, ///< states above this are error conditions
BAD_ARCHIVE,
BAD_DATA,
FILTER_STOPPED
} State;
State state = INVALID;
ArchiveExtractor* outer = nullptr;
virtual void extractBytes(const uint8_t* bytes, size_t count) = 0;
virtual void flush() = 0;
SGPath extractRootPath()
{
return outer->_rootPath;
}
ArchiveExtractor::PathResult filterPath(std::string& pathToExtract)
{
return outer->filterPath(pathToExtract);
}
bool isSafePath(const std::string& p) const
{
if (p.empty()) {
return false;
}
// reject absolute paths
if (p.at(0) == '/') {
return false;
}
// reject paths containing '..'
size_t doubleDot = p.find("..");
if (doubleDot != std::string::npos) {
return false;
}
// on POSIX could use realpath to sanity check
return true;
}
};
} // namespace simgear
-3
View File
@@ -35,12 +35,10 @@ set(SOURCES
sg_socket.cxx sg_socket.cxx
sg_socket_udp.cxx sg_socket_udp.cxx
HTTPClient.cxx HTTPClient.cxx
HTTPTestApi_private.hxx
HTTPFileRequest.cxx HTTPFileRequest.cxx
HTTPMemoryRequest.cxx HTTPMemoryRequest.cxx
HTTPRequest.cxx HTTPRequest.cxx
HTTPRepository.cxx HTTPRepository.cxx
HTTPRepository_private.hxx
untar.cxx untar.cxx
) )
@@ -83,7 +81,6 @@ add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj)
add_executable(test_repository test_repository.cxx) add_executable(test_repository test_repository.cxx)
target_link_libraries(test_repository ${TEST_LIBS}) target_link_libraries(test_repository ${TEST_LIBS})
target_compile_definitions(test_repository PUBLIC BUILDING_TESTSUITE)
add_test(http_repository ${EXECUTABLE_OUTPUT_PATH}/test_repository) add_test(http_repository ${EXECUTABLE_OUTPUT_PATH}/test_repository)
add_executable(test_untar test_untar.cxx) add_executable(test_untar test_untar.cxx)
+4 -47
View File
@@ -61,10 +61,6 @@ public:
struct dns_ctx * ctx; struct dns_ctx * ctx;
static size_t instanceCounter; static size_t instanceCounter;
using RequestVec = std::vector<Request_ptr>;
RequestVec _activeRequests;
}; };
size_t Client::ClientPrivate::instanceCounter = 0; size_t Client::ClientPrivate::instanceCounter = 0;
@@ -82,11 +78,6 @@ Request::~Request()
{ {
} }
void Request::cancel()
{
_cancelled = true;
}
bool Request::isTimeout() const bool Request::isTimeout() const
{ {
return (time(NULL) - _start) > _timeout_secs; return (time(NULL) - _start) > _timeout_secs;
@@ -123,7 +114,6 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
{ {
SRVRequest * r = static_cast<SRVRequest*>(data); SRVRequest * r = static_cast<SRVRequest*>(data);
if (result) { if (result) {
if (!r->isCancelled()) {
r->cname = result->dnssrv_cname; r->cname = result->dnssrv_cname;
r->qname = result->dnssrv_qname; r->qname = result->dnssrv_qname;
r->ttl = result->dnssrv_ttl; r->ttl = result->dnssrv_ttl;
@@ -136,7 +126,6 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
srv->target = result->dnssrv_srv[i].name; srv->target = result->dnssrv_srv[i].name;
} }
std::sort( r->entries.begin(), r->entries.end(), sortSRV ); std::sort( r->entries.begin(), r->entries.end(), sortSRV );
}
free(result); free(result);
} }
r->setComplete(); r->setComplete();
@@ -145,16 +134,11 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
void SRVRequest::submit( Client * client ) void SRVRequest::submit( Client * client )
{ {
// if service is defined, pass service and protocol // if service is defined, pass service and protocol
auto q = dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), if (!dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), _service.empty() ? NULL : _protocol.c_str(), 0, dnscbSRV, this )) {
_service.empty() ? NULL : _protocol.c_str(),
0, dnscbSRV, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
TXTRequest::TXTRequest( const std::string & dn ) : TXTRequest::TXTRequest( const std::string & dn ) :
@@ -167,25 +151,18 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
{ {
TXTRequest * r = static_cast<TXTRequest*>(data); TXTRequest * r = static_cast<TXTRequest*>(data);
if (result) { if (result) {
if (!r->isCancelled()) {
r->cname = result->dnstxt_cname; r->cname = result->dnstxt_cname;
r->qname = result->dnstxt_qname; r->qname = result->dnstxt_qname;
r->ttl = result->dnstxt_ttl; r->ttl = result->dnstxt_ttl;
for (int i = 0; i < result->dnstxt_nrr; i++) { for (int i = 0; i < result->dnstxt_nrr; i++) {
//TODO: interprete the .len field of dnstxt_txt? //TODO: interprete the .len field of dnstxt_txt?
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt); string txt = string((char*)result->dnstxt_txt[i].txt);
if (!rawTxt) {
continue;
}
const string txt{rawTxt};
r->entries.push_back( txt ); r->entries.push_back( txt );
string_list tokens = simgear::strutils::split( txt, "=", 1 ); string_list tokens = simgear::strutils::split( txt, "=", 1 );
if( tokens.size() == 2 ) { if( tokens.size() == 2 ) {
r->attributes[tokens[0]] = tokens[1]; r->attributes[tokens[0]] = tokens[1];
} }
} }
}
free(result); free(result);
} }
r->setComplete(); r->setComplete();
@@ -194,13 +171,11 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
void TXTRequest::submit( Client * client ) void TXTRequest::submit( Client * client )
{ {
// protocol and service an already encoded in DN so pass in NULL for both // protocol and service an already encoded in DN so pass in NULL for both
auto q = dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this); if (!dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this )) {
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
@@ -215,7 +190,6 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
{ {
NAPTRRequest * r = static_cast<NAPTRRequest*>(data); NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
if (result) { if (result) {
if (!r->isCancelled()) {
r->cname = result->dnsnaptr_cname; r->cname = result->dnsnaptr_cname;
r->qname = result->dnsnaptr_qname; r->qname = result->dnsnaptr_qname;
r->ttl = result->dnsnaptr_ttl; r->ttl = result->dnsnaptr_ttl;
@@ -237,7 +211,6 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
naptr->replacement = result->dnsnaptr_naptr[i].replacement; naptr->replacement = result->dnsnaptr_naptr[i].replacement;
} }
std::sort( r->entries.begin(), r->entries.end(), sortNAPTR ); std::sort( r->entries.begin(), r->entries.end(), sortNAPTR );
}
free(result); free(result);
} }
r->setComplete(); r->setComplete();
@@ -245,13 +218,11 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
void NAPTRRequest::submit( Client * client ) void NAPTRRequest::submit( Client * client )
{ {
auto q = dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this); if (!dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this )) {
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
@@ -266,7 +237,6 @@ Client::Client() :
void Client::makeRequest(const Request_ptr& r) void Client::makeRequest(const Request_ptr& r)
{ {
d->_activeRequests.push_back(r);
r->submit(this); r->submit(this);
} }
@@ -277,19 +247,6 @@ void Client::update(int waitTimeout)
return; return;
dns_ioevent(d->ctx, now); dns_ioevent(d->ctx, now);
// drop our owning ref to completed requests,
// and cancel any which timed out
auto it = std::remove_if(d->_activeRequests.begin(), d->_activeRequests.end(),
[this](const Request_ptr& r) {
if (r->isTimeout()) {
dns_cancel(d->ctx, reinterpret_cast<struct dns_query*>(r->_query));
return true;
}
return r->isComplete();
});
d->_activeRequests.erase(it, d->_activeRequests.end());
} }
} // of namespace DNS } // of namespace DNS
+4 -14
View File
@@ -40,38 +40,28 @@ namespace DNS
{ {
class Client; class Client;
using UDNSQueryPtr = void*;
class Request : public SGReferenced class Request : public SGReferenced
{ {
public: public:
Request( const std::string & dn ); Request( const std::string & dn );
virtual ~Request(); virtual ~Request();
const std::string& getDn() const { return _dn; } std::string getDn() const { return _dn; }
int getType() const { return _type; } int getType() const { return _type; }
bool isComplete() const { return _complete; } bool isComplete() const { return _complete; }
bool isTimeout() const; bool isTimeout() const;
void setComplete( bool b = true ) { _complete = b; } void setComplete( bool b = true ) { _complete = b; }
bool isCancelled() const { return _cancelled; }
virtual void submit( Client * client) = 0; virtual void submit( Client * client) = 0;
void cancel();
std::string cname; std::string cname;
std::string qname; std::string qname;
unsigned ttl; unsigned ttl;
protected: protected:
friend class Client;
UDNSQueryPtr _query = nullptr;
std::string _dn; std::string _dn;
int _type; int _type;
bool _complete; bool _complete;
time_t _timeout_secs; time_t _timeout_secs;
time_t _start; time_t _start;
bool _cancelled = false;
}; };
typedef SGSharedPtr<Request> Request_ptr; typedef SGSharedPtr<Request> Request_ptr;
@@ -79,7 +69,7 @@ class NAPTRRequest : public Request
{ {
public: public:
NAPTRRequest( const std::string & dn ); NAPTRRequest( const std::string & dn );
void submit(Client* client) override; virtual void submit( Client * client );
struct NAPTR : SGReferenced { struct NAPTR : SGReferenced {
int order; int order;
@@ -102,7 +92,7 @@ class SRVRequest : public Request
public: public:
SRVRequest( const std::string & dn ); SRVRequest( const std::string & dn );
SRVRequest( const std::string & dn, const string & service, const string & protocol ); SRVRequest( const std::string & dn, const string & service, const string & protocol );
void submit(Client* client) override; virtual void submit( Client * client );
struct SRV : SGReferenced { struct SRV : SGReferenced {
int priority; int priority;
@@ -122,7 +112,7 @@ class TXTRequest : public Request
{ {
public: public:
TXTRequest( const std::string & dn ); TXTRequest( const std::string & dn );
void submit(Client* client) override; virtual void submit( Client * client );
typedef std::vector<string> TXT_list; typedef std::vector<string> TXT_list;
typedef std::map<std::string,std::string> TXT_Attribute_map; typedef std::map<std::string,std::string> TXT_Attribute_map;
+77 -102
View File
@@ -33,10 +33,13 @@
#include <errno.h> #include <errno.h>
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <mutex>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h> #include <simgear/simgear_config.h>
#include <curl/multi.h>
#include <simgear/io/sg_netChat.hxx> #include <simgear/io/sg_netChat.hxx>
@@ -46,9 +49,6 @@
#include <simgear/timing/timestamp.hxx> #include <simgear/timing/timestamp.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include "HTTPClient_private.hxx"
#include "HTTPTestApi_private.hxx"
#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H #if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
#include "version.h" #include "version.h"
#else #else
@@ -66,14 +66,23 @@ namespace HTTP
extern const int DEFAULT_HTTP_PORT = 80; extern const int DEFAULT_HTTP_PORT = 80;
const char* CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded"; const char* CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded";
void Client::ClientPrivate::createCurlMulti() { class Connection;
typedef std::multimap<std::string, Connection*> ConnectionDict;
typedef std::list<Request_ptr> RequestList;
class Client::ClientPrivate
{
public:
CURLM* curlMulti;
void createCurlMulti()
{
curlMulti = curl_multi_init(); curlMulti = curl_multi_init();
// see https://curl.haxx.se/libcurl/c/CURLMOPT_PIPELINING.html // see https://curl.haxx.se/libcurl/c/CURLMOPT_PIPELINING.html
// we request HTTP 1.1 pipelining // we request HTTP 1.1 pipelining
curl_multi_setopt(curlMulti, CURLMOPT_PIPELINING, 1 /* aka CURLPIPE_HTTP1 */); curl_multi_setopt(curlMulti, CURLMOPT_PIPELINING, 1 /* aka CURLPIPE_HTTP1 */);
#if (LIBCURL_VERSION_MINOR >= 30) #if (LIBCURL_VERSION_MINOR >= 30)
curl_multi_setopt(curlMulti, CURLMOPT_MAX_TOTAL_CONNECTIONS, curl_multi_setopt(curlMulti, CURLMOPT_MAX_TOTAL_CONNECTIONS, (long) maxConnections);
(long)maxConnections);
curl_multi_setopt(curlMulti, CURLMOPT_MAX_PIPELINE_LENGTH, curl_multi_setopt(curlMulti, CURLMOPT_MAX_PIPELINE_LENGTH,
(long) maxPipelineDepth); (long) maxPipelineDepth);
curl_multi_setopt(curlMulti, CURLMOPT_MAX_HOST_CONNECTIONS, curl_multi_setopt(curlMulti, CURLMOPT_MAX_HOST_CONNECTIONS,
@@ -81,18 +90,45 @@ void Client::ClientPrivate::createCurlMulti() {
#endif #endif
} }
Client::Client() typedef std::map<Request_ptr, CURL*> RequestCurlMap;
{ RequestCurlMap requests;
static bool didInitCurlGlobal = false;
static std::mutex initMutex;
std::lock_guard<std::mutex> g(initMutex); std::string userAgent;
std::string proxy;
int proxyPort;
std::string proxyAuth;
unsigned int maxConnections;
unsigned int maxHostConnections;
unsigned int maxPipelineDepth;
RequestList pendingRequests;
SGTimeStamp timeTransferSample;
unsigned int bytesTransferred;
unsigned int lastTransferRate;
uint64_t totalBytesDownloaded;
};
Client::Client() :
d(new ClientPrivate)
{
d->proxyPort = 0;
d->maxConnections = 4;
d->maxHostConnections = 4;
d->bytesTransferred = 0;
d->lastTransferRate = 0;
d->timeTransferSample.stamp();
d->totalBytesDownloaded = 0;
d->maxPipelineDepth = 5;
setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
static bool didInitCurlGlobal = false;
if (!didInitCurlGlobal) { if (!didInitCurlGlobal) {
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
didInitCurlGlobal = true; didInitCurlGlobal = true;
} }
reset(); d->createCurlMulti();
} }
Client::~Client() Client::~Client()
@@ -124,27 +160,6 @@ void Client::setMaxPipelineDepth(unsigned int depth)
#endif #endif
} }
void Client::reset()
{
if (d.get()) {
curl_multi_cleanup(d->curlMulti);
}
d.reset(new ClientPrivate);
d->proxyPort = 0;
d->maxConnections = 4;
d->maxHostConnections = 4;
d->bytesTransferred = 0;
d->lastTransferRate = 0;
d->timeTransferSample.stamp();
d->totalBytesDownloaded = 0;
d->maxPipelineDepth = 5;
setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
d->tlsCertificatePath = SGPath::fromEnv("SIMGEAR_TLS_CERT_PATH");
d->createCurlMulti();
}
void Client::update(int waitTimeout) void Client::update(int waitTimeout)
{ {
if (d->requests.empty()) { if (d->requests.empty()) {
@@ -155,22 +170,32 @@ void Client::update(int waitTimeout)
} }
int remainingActive, messagesInQueue; int remainingActive, messagesInQueue;
int numFds; #if defined(SG_MAC)
CURLMcode mc = curl_multi_wait(d->curlMulti, NULL, 0, waitTimeout, &numFds); // Mac 10.8 libCurl lacks this, let's keep compat for now
if (mc != CURLM_OK) { fd_set curlReadFDs, curlWriteFDs, curlErrorFDs;
SG_LOG(SG_IO, SG_WARN, "curl_multi_wait failed:" << curl_multi_strerror(mc)); int maxFD;
return; curl_multi_fdset(d->curlMulti,
&curlReadFDs,
&curlWriteFDs,
&curlErrorFDs,
&maxFD);
struct timeval timeout;
long t;
curl_multi_timeout(d->curlMulti, &t);
if ((t < 0) || (t > waitTimeout)) {
t = waitTimeout;
} }
mc = curl_multi_perform(d->curlMulti, &remainingActive); timeout.tv_sec = t / 1000;
if (mc == CURLM_CALL_MULTI_PERFORM) { timeout.tv_usec = (t % 1000) * 1000;
// we could loop here, but don't want to get blocked ::select(maxFD, &curlReadFDs, &curlWriteFDs, &curlErrorFDs, &timeout);
// also this shouldn't ocurr in any modern libCurl #else
int numFds;
curl_multi_wait(d->curlMulti, NULL, 0, waitTimeout, &numFds);
#endif
curl_multi_perform(d->curlMulti, &remainingActive); curl_multi_perform(d->curlMulti, &remainingActive);
} else if (mc != CURLM_OK) {
SG_LOG(SG_IO, SG_WARN, "curl_multi_perform failed:" << curl_multi_strerror(mc));
return;
}
CURLMsg* msg; CURLMsg* msg;
while ((msg = curl_multi_info_read(d->curlMulti, &messagesInQueue))) { while ((msg = curl_multi_info_read(d->curlMulti, &messagesInQueue))) {
@@ -195,22 +220,11 @@ void Client::update(int waitTimeout)
assert(it->second == e); assert(it->second == e);
d->requests.erase(it); d->requests.erase(it);
bool doProcess = true;
if (d->testsuiteResponseDoneCallback) {
doProcess =
!d->testsuiteResponseDoneCallback(msg->data.result, req);
}
if (doProcess) {
if (msg->data.result == 0) { if (msg->data.result == 0) {
req->responseComplete(); req->responseComplete();
} else { } else {
SG_LOG(SG_IO, SG_WARN, SG_LOG(SG_IO, SG_WARN, "CURL Result:" << msg->data.result << " " << curl_easy_strerror(msg->data.result));
"CURL Result:" << msg->data.result << " " req->setFailure(msg->data.result, curl_easy_strerror(msg->data.result));
<< curl_easy_strerror(msg->data.result));
req->setFailure(msg->data.result,
curl_easy_strerror(msg->data.result));
}
} }
curl_multi_remove_handle(d->curlMulti, e); curl_multi_remove_handle(d->curlMulti, e);
@@ -256,25 +270,11 @@ void Client::makeRequest(const Request_ptr& r)
curl_easy_setopt(curlRequest, CURLOPT_HEADERFUNCTION, requestHeaderCallback); curl_easy_setopt(curlRequest, CURLOPT_HEADERFUNCTION, requestHeaderCallback);
curl_easy_setopt(curlRequest, CURLOPT_HEADERDATA, r.get()); curl_easy_setopt(curlRequest, CURLOPT_HEADERDATA, r.get());
#if !defined(CURL_MAX_READ_SIZE)
const int CURL_MAX_READ_SIZE = 512 * 1024;
#endif
curl_easy_setopt(curlRequest, CURLOPT_BUFFERSIZE, CURL_MAX_READ_SIZE);
curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str()); curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str());
curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
if (sglog().would_log(SG_TERRASYNC, SG_DEBUG)) {
curl_easy_setopt(curlRequest, CURLOPT_VERBOSE, 1);
}
curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1);
if (!d->tlsCertificatePath.isNull()) {
const auto utf8 = d->tlsCertificatePath.utf8Str();
curl_easy_setopt(curlRequest, CURLOPT_CAINFO, utf8.c_str());
}
if (!d->proxy.empty()) { if (!d->proxy.empty()) {
curl_easy_setopt(curlRequest, CURLOPT_PROXY, d->proxy.c_str()); curl_easy_setopt(curlRequest, CURLOPT_PROXY, d->proxy.c_str());
curl_easy_setopt(curlRequest, CURLOPT_PROXYPORT, d->proxyPort); curl_easy_setopt(curlRequest, CURLOPT_PROXYPORT, d->proxyPort);
@@ -285,7 +285,7 @@ void Client::makeRequest(const Request_ptr& r)
} }
} }
const std::string method = strutils::lowercase (r->method()); std::string method = boost::to_lower_copy(r->method());
if (method == "get") { if (method == "get") {
curl_easy_setopt(curlRequest, CURLOPT_HTTPGET, 1); curl_easy_setopt(curlRequest, CURLOPT_HTTPGET, 1);
} else if (method == "put") { } else if (method == "put") {
@@ -472,26 +472,12 @@ size_t Client::requestReadCallback(char *ptr, size_t size, size_t nmemb, void *u
return actualBytes; return actualBytes;
} }
bool isRedirectStatus(int code)
{
return ((code >= 300) && (code < 400));
}
size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems, void *userdata) size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems, void *userdata)
{ {
size_t byteSize = size * nitems; size_t byteSize = size * nitems;
Request* req = static_cast<Request*>(userdata); Request* req = static_cast<Request*>(userdata);
std::string h = strutils::simplify(std::string(rawBuffer, byteSize)); std::string h = strutils::simplify(std::string(rawBuffer, byteSize));
if (req->readyState() >= HTTP::Request::HEADERS_RECEIVED) {
// this can happen with chunked transfers (secondary chunks)
// or redirects
if (isRedirectStatus(req->responseCode())) {
req->responseStart(h);
return byteSize;
}
}
if (req->readyState() == HTTP::Request::OPENED) { if (req->readyState() == HTTP::Request::OPENED) {
req->responseStart(h); req->responseStart(h);
return byteSize; return byteSize;
@@ -518,8 +504,8 @@ size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems
return byteSize; return byteSize;
} }
const std::string key = strutils::simplify(h.substr(0, colonPos)); std::string key = strutils::simplify(h.substr(0, colonPos));
const std::string lkey = strutils::lowercase (key); std::string lkey = boost::to_lower_copy(key);
std::string value = strutils::strip(h.substr(colonPos + 1)); std::string value = strutils::strip(h.substr(colonPos + 1));
req->responseHeader(lkey, value); req->responseHeader(lkey, value);
@@ -542,17 +528,6 @@ void Client::clearAllConnections()
d->createCurlMulti(); d->createCurlMulti();
} }
/////////////////////////////////////////////////////////////////////
void TestApi::setResponseDoneCallback(Client *cl, ResponseDoneCallback cb) {
cl->d->testsuiteResponseDoneCallback = cb;
}
void TestApi::markRequestAsFailed(Request_ptr req, int curlCode,
const std::string &message) {
req->setFailure(curlCode, message);
}
} // of namespace HTTP } // of namespace HTTP
} // of namespace simgear } // of namespace simgear
-4
View File
@@ -24,7 +24,6 @@
#ifndef SG_HTTP_CLIENT_HXX #ifndef SG_HTTP_CLIENT_HXX
#define SG_HTTP_CLIENT_HXX #define SG_HTTP_CLIENT_HXX
#include <functional>
#include <memory> // for std::unique_ptr #include <memory> // for std::unique_ptr
#include <stdint.h> // for uint_64t #include <stdint.h> // for uint_64t
@@ -48,8 +47,6 @@ public:
void update(int waitTimeout = 0); void update(int waitTimeout = 0);
void reset();
void makeRequest(const Request_ptr& r); void makeRequest(const Request_ptr& r);
void cancelRequest(const Request_ptr& r, std::string reason = std::string()); void cancelRequest(const Request_ptr& r, std::string reason = std::string());
@@ -126,7 +123,6 @@ private:
friend class Connection; friend class Connection;
friend class Request; friend class Request;
friend class TestApi;
class ClientPrivate; class ClientPrivate;
std::unique_ptr<ClientPrivate> d; std::unique_ptr<ClientPrivate> d;
-68
View File
@@ -1,68 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#pragma once
#include <list>
#include <map>
#include "HTTPClient.hxx"
#include "HTTPRequest.hxx"
#include <simgear/timing/timestamp.hxx>
#include <curl/multi.h>
namespace simgear {
namespace HTTP {
typedef std::list<Request_ptr> RequestList;
using ResponseDoneCallback =
std::function<bool(int curlResult, Request_ptr req)>;
class Client::ClientPrivate {
public:
CURLM *curlMulti;
void createCurlMulti();
typedef std::map<Request_ptr, CURL *> RequestCurlMap;
RequestCurlMap requests;
std::string userAgent;
std::string proxy;
int proxyPort;
std::string proxyAuth;
unsigned int maxConnections;
unsigned int maxHostConnections;
unsigned int maxPipelineDepth;
RequestList pendingRequests;
SGTimeStamp timeTransferSample;
unsigned int bytesTransferred;
unsigned int lastTransferRate;
uint64_t totalBytesDownloaded;
SGPath tlsCertificatePath;
// only used by unit-tests / test-api, but
// only costs us a pointe here to declare it.
ResponseDoneCallback testsuiteResponseDoneCallback;
};
} // namespace HTTP
} // namespace simgear
File diff suppressed because it is too large Load Diff
+1 -38
View File
@@ -20,7 +20,6 @@
#ifndef SG_IO_HTTP_REPOSITORY_HXX #ifndef SG_IO_HTTP_REPOSITORY_HXX
#define SG_IO_HTTP_REPOSITORY_HXX #define SG_IO_HTTP_REPOSITORY_HXX
#include <functional>
#include <memory> #include <memory>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
@@ -44,8 +43,7 @@ public:
REPO_ERROR_FILE_NOT_FOUND, REPO_ERROR_FILE_NOT_FOUND,
REPO_ERROR_HTTP, REPO_ERROR_HTTP,
REPO_ERROR_CANCELLED, REPO_ERROR_CANCELLED,
REPO_PARTIAL_UPDATE ///< repository is working, but file-level failures REPO_PARTIAL_UPDATE
///< occurred
}; };
HTTPRepository(const SGPath& root, HTTP::Client* cl); HTTPRepository(const SGPath& root, HTTP::Client* cl);
@@ -62,19 +60,12 @@ public:
virtual bool isDoingSync() const; virtual bool isDoingSync() const;
/**
@brief call this periodically to progress non-network tasks
*/
void process();
virtual ResultCode failure() const; virtual ResultCode failure() const;
virtual size_t bytesToDownload() const; virtual size_t bytesToDownload() const;
virtual size_t bytesDownloaded() const; virtual size_t bytesDownloaded() const;
virtual size_t bytesToExtract() const;
/** /**
* optionally provide the location of an installer copy of this * optionally provide the location of an installer copy of this
* repository. When a file is missing it will be copied from this tree. * repository. When a file is missing it will be copied from this tree.
@@ -83,34 +74,6 @@ public:
static std::string resultCodeAsString(ResultCode code); static std::string resultCodeAsString(ResultCode code);
enum class SyncAction { Add, Update, Delete, UpToDate };
enum EntryType { FileType, DirectoryType, TarballType };
struct SyncItem {
const std::string directory; // relative path in the repository
const EntryType type;
const std::string filename;
const SyncAction action;
const SGPath pathOnDisk; // path the entry does / will have
};
using SyncPredicate = std::function<bool(const SyncItem &item)>;
void setFilter(SyncPredicate sp);
struct Failure {
SGPath path;
ResultCode error;
};
using FailureVec = std::vector<Failure>;
/**
* @brief return file-level failures
*/
FailureVec failures() const;
private: private:
bool isBare() const; bool isBare() const;
-127
View File
@@ -1,127 +0,0 @@
// HTTPRepository.cxx -- plain HTTP TerraSync remote client
//
// Copyright (C) 20126 James Turner <zakalawe@mac.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
#pragma once
#include <deque>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/misc/sg_path.hxx>
#include "HTTPRepository.hxx"
namespace simgear {
class HTTPDirectory;
using HTTPDirectory_ptr = std::unique_ptr<HTTPDirectory>;
class HTTPRepoGetRequest : public HTTP::Request {
public:
HTTPRepoGetRequest(HTTPDirectory *d, const std::string &u)
: HTTP::Request(u), _directory(d) {}
virtual void cancel();
size_t contentSize() const { return _contentSize; }
void setContentSize(size_t sz) { _contentSize = sz; }
protected:
HTTPDirectory *_directory;
size_t _contentSize = 0;
};
using RepoRequestPtr = SGSharedPtr<HTTPRepoGetRequest>;
class HTTPRepoPrivate {
public:
HTTPRepository::FailureVec failures;
int maxPermittedFailures = 16;
HTTPRepoPrivate(HTTPRepository* parent)
: p(parent)
{
}
~HTTPRepoPrivate();
HTTPRepository *p; // link back to outer
HTTP::Client* http = nullptr;
std::string baseUrl;
SGPath basePath;
bool isUpdating = false;
HTTPRepository::ResultCode status = HTTPRepository::REPO_NO_ERROR;
HTTPDirectory_ptr rootDir;
size_t totalDownloaded = 0;
size_t bytesToExtract = 0;
size_t bytesExtracted = 0;
HTTPRepository::SyncPredicate syncPredicate;
HTTP::Request_ptr updateFile(HTTPDirectory *dir, const std::string &name,
size_t sz);
HTTP::Request_ptr updateDir(HTTPDirectory *dir, const std::string &hash,
size_t sz);
void failedToGetRootIndex(HTTPRepository::ResultCode st);
void failedToUpdateChild(const SGPath &relativePath,
HTTPRepository::ResultCode fileStatus);
void updatedChildSuccessfully(const SGPath &relativePath);
void checkForComplete();
typedef std::vector<RepoRequestPtr> RequestVector;
RequestVector queuedRequests, activeRequests;
void makeRequest(RepoRequestPtr req);
enum class RequestFinish { Done, Retry };
void finishedRequest(const RepoRequestPtr &req, RequestFinish retryRequest);
HTTPDirectory *getOrCreateDirectory(const std::string &path);
bool deleteDirectory(const std::string &relPath, const SGPath &absPath);
typedef std::vector<HTTPDirectory_ptr> DirectoryVector;
DirectoryVector directories;
void scheduleUpdateOfChildren(HTTPDirectory *dir);
SGPath installedCopyPath;
int countDirtyHashCaches() const;
void flushHashCaches();
enum ProcessResult { ProcessContinue, ProcessDone, ProcessFailed };
using RepoProcessTask = std::function<ProcessResult(HTTPRepoPrivate *repo)>;
void addTask(RepoProcessTask task);
std::deque<RepoProcessTask> pendingTasks;
};
} // namespace simgear
+3 -39
View File
@@ -18,9 +18,6 @@
#include <simgear_config.h> #include <simgear_config.h>
#include "HTTPRequest.hxx" #include "HTTPRequest.hxx"
#include <cstring>
#include <algorithm> // for std::min
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/misc/strutils.hxx> #include <simgear/misc/strutils.hxx>
@@ -56,15 +53,6 @@ Request::~Request()
} }
void Request::prepareForRetry() {
setReadyState(UNSENT);
_willClose = false;
_connectionCloseHeader = false;
_responseStatus = 0;
_responseLength = 0;
_receivedBodyBytes = 0;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Request* Request::done(const Callback& cb) Request* Request::done(const Callback& cb)
{ {
@@ -202,8 +190,6 @@ void Request::onDone()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Request::onFail() void Request::onFail()
{ {
// log if we FAIELD< but not if we CANCELLED
if (_ready_state == FAILED) {
SG_LOG SG_LOG
( (
SG_IO, SG_IO,
@@ -212,7 +198,6 @@ void Request::onFail()
<< responseCode() << "/" << responseReason() << responseCode() << "/" << responseReason()
); );
} }
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Request::onAlways() void Request::onAlways()
@@ -343,30 +328,15 @@ unsigned int Request::responseLength() const
return _responseLength; return _responseLength;
} }
//------------------------------------------------------------------------------
void Request::setSuccess(int code)
{
_responseStatus = code;
_responseReason.clear();
if( !isComplete() ) {
setReadyState(DONE);
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Request::setFailure(int code, const std::string& reason) void Request::setFailure(int code, const std::string& reason)
{ {
// we use -1 for cancellation, don't be noisy in that case
if (code >= 0) {
SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason); SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason);
}
_responseStatus = code; _responseStatus = code;
_responseReason = reason; _responseReason = reason;
if( !isComplete() ) { if( !isComplete() )
setReadyState(code < 0 ? CANCELLED : FAILED); setReadyState(FAILED);
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -390,12 +360,6 @@ void Request::setReadyState(ReadyState state)
_cb_fail(this); _cb_fail(this);
} }
else if (state == CANCELLED )
{
onFail(); // do this for compatability
onAlways();
_cb_fail(this);
}
else else
return; return;
@@ -425,7 +389,7 @@ bool Request::serverSupportsPipelining() const
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool Request::isComplete() const bool Request::isComplete() const
{ {
return _ready_state == DONE || _ready_state == FAILED || _ready_state == CANCELLED; return _ready_state == DONE || _ready_state == FAILED;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
+7 -10
View File
@@ -28,6 +28,8 @@
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/sg_types.hxx> #include <simgear/math/sg_types.hxx>
#include <boost/bind.hpp>
class SGPropertyNode; class SGPropertyNode;
namespace simgear namespace simgear
@@ -44,7 +46,7 @@ class Request:
public SGReferenced public SGReferenced
{ {
public: public:
typedef std::function<void(Request*)> Callback; typedef boost::function<void(Request*)> Callback;
enum ReadyState enum ReadyState
{ {
@@ -54,8 +56,7 @@ public:
HEADERS_RECEIVED, HEADERS_RECEIVED,
LOADING, LOADING,
DONE, DONE,
FAILED, FAILED
CANCELLED
}; };
virtual ~Request(); virtual ~Request();
@@ -81,7 +82,7 @@ public:
template<class C> template<class C>
Request* done(C* instance, void (C::*mem_func)(Request*)) Request* done(C* instance, void (C::*mem_func)(Request*))
{ {
return done(std::bind(mem_func, instance, std::placeholders::_1)); return done(boost::bind(mem_func, instance, _1));
} }
/** /**
@@ -96,7 +97,7 @@ public:
template<class C> template<class C>
Request* fail(C* instance, void (C::*mem_func)(Request*)) Request* fail(C* instance, void (C::*mem_func)(Request*))
{ {
return fail(std::bind(mem_func, instance, std::placeholders::_1)); return fail(boost::bind(mem_func, instance, _1));
} }
/** /**
@@ -111,7 +112,7 @@ public:
template<class C> template<class C>
Request* always(C* instance, void (C::*mem_func)(Request*)) Request* always(C* instance, void (C::*mem_func)(Request*))
{ {
return always(std::bind(mem_func, instance, std::placeholders::_1)); return always(boost::bind(mem_func, instance, _1));
} }
/** /**
@@ -208,8 +209,6 @@ public:
*/ */
bool serverSupportsPipelining() const; bool serverSupportsPipelining() const;
virtual void prepareForRetry();
protected: protected:
Request(const std::string& url, const std::string method = "GET"); Request(const std::string& url, const std::string method = "GET");
@@ -224,14 +223,12 @@ public:
virtual void onFail(); virtual void onFail();
virtual void onAlways(); virtual void onAlways();
void setSuccess(int code);
void setFailure(int code, const std::string& reason); void setFailure(int code, const std::string& reason);
private: private:
friend class Client; friend class Client;
friend class Connection; friend class Connection;
friend class ContentDecoder; friend class ContentDecoder;
friend class TestApi;
Request(const Request&); // = delete; Request(const Request&); // = delete;
Request& operator=(const Request&); // = delete; Request& operator=(const Request&); // = delete;
-45
View File
@@ -1,45 +0,0 @@
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#pragma once
#include <functional>
#include "HTTPRequest.hxx"
namespace simgear {
namespace HTTP {
class Client;
using ResponseDoneCallback =
std::function<bool(int curlResult, Request_ptr req)>;
/**
* @brief this API is for unit-testing HTTP code.
* Don't use it for anything else. It's for unit-testing.
*/
class TestApi {
public:
// alow test suite to manipulate requests to simulate network errors;
// without this, it's hard to provoke certain failures in a loop-back
// network sitation.
static void setResponseDoneCallback(Client *cl, ResponseDoneCallback cb);
static void markRequestAsFailed(Request_ptr req, int curlCode,
const std::string &message);
};
} // namespace HTTP
} // namespace simgear
+3 -1
View File
@@ -5,6 +5,8 @@
#include <signal.h> #include <signal.h>
#include <iostream> #include <iostream>
#include <boost/foreach.hpp>
#include <simgear/io/sg_file.hxx> #include <simgear/io/sg_file.hxx>
#include <simgear/io/HTTPClient.hxx> #include <simgear/io/HTTPClient.hxx>
@@ -121,7 +123,7 @@ int main(int argc, char* argv[])
} }
ARequest* req = new ARequest(url); ARequest* req = new ARequest(url);
for (const auto& h : headers) { BOOST_FOREACH(string h, headers) {
req->addHeader(h); req->addHeader(h);
} }
+4 -4
View File
@@ -71,10 +71,10 @@ static const uint32_t EndianMagic = 0x11223344;
* gzContainerWriter * gzContainerWriter
**************************************************************************/ **************************************************************************/
gzContainerWriter::gzContainerWriter(const SGPath& name, gzContainerWriter::gzContainerWriter(const std::string& name,
const std::string& fileMagic) : const std::string& fileMagic) :
sg_gzofstream(name, ios_out | ios_binary), sg_gzofstream(name, ios_out | ios_binary),
filename(name.utf8Str()) filename(name)
{ {
/* write byte-order marker **************************************/ /* write byte-order marker **************************************/
write((char*)&EndianMagic, sizeof(EndianMagic)); write((char*)&EndianMagic, sizeof(EndianMagic));
@@ -138,10 +138,10 @@ gzContainerWriter::writeContainer(ContainerType Type, SGPropertyNode* root)
* gzContainerReader * gzContainerReader
**************************************************************************/ **************************************************************************/
gzContainerReader::gzContainerReader(const SGPath& name, gzContainerReader::gzContainerReader(const std::string& name,
const std::string& fileMagic) : const std::string& fileMagic) :
sg_gzifstream(SGPath(name), ios_in | ios_binary), sg_gzifstream(SGPath(name), ios_in | ios_binary),
filename(name.utf8Str()) filename(name)
{ {
bool ok = (good() && !eof()); bool ok = (good() && !eof());
+2 -2
View File
@@ -35,7 +35,7 @@ typedef int ContainerType;
class gzContainerReader : public sg_gzifstream class gzContainerReader : public sg_gzifstream
{ {
public: public:
gzContainerReader( const SGPath& name, gzContainerReader( const std::string& name,
const std::string& fileMagic); const std::string& fileMagic);
bool readContainerHeader(ContainerType* pType, size_t* pSize); bool readContainerHeader(ContainerType* pType, size_t* pSize);
@@ -48,7 +48,7 @@ private:
class gzContainerWriter : public sg_gzofstream class gzContainerWriter : public sg_gzofstream
{ {
public: public:
gzContainerWriter( const SGPath& name, gzContainerWriter( const std::string& name,
const std::string& fileMagic); const std::string& fileMagic);
bool writeContainerHeader(ContainerType Type, size_t Size); bool writeContainerHeader(ContainerType Type, size_t Size);
+1 -4
View File
@@ -185,9 +185,6 @@ gzfilebuf::setcompressionstrategy( int comp_strategy )
z_off_t z_off_t
gzfilebuf::approxOffset() { gzfilebuf::approxOffset() {
#ifdef __OpenBSD__
z_off_t res = 0;
#else
z_off_t res = gzoffset(file); z_off_t res = gzoffset(file);
if (res == -1) { if (res == -1) {
@@ -204,7 +201,7 @@ gzfilebuf::approxOffset() {
SG_LOG( SG_GENERAL, SG_ALERT, errMsg ); SG_LOG( SG_GENERAL, SG_ALERT, errMsg );
throw sg_io_exception(errMsg); throw sg_io_exception(errMsg);
} }
#endif
return res; return res;
} }
+4 -18
View File
@@ -212,7 +212,7 @@ sg_ifstream::sg_ifstream(const SGPath& path, ios_openmode io_mode)
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
std::wstring ps = path.wstr(); std::wstring ps = path.wstr();
#else #else
std::string ps = path.utf8Str(); std::string ps = path.local8BitStr();
#endif #endif
std::ifstream::open(ps.c_str(), io_mode); std::ifstream::open(ps.c_str(), io_mode);
} }
@@ -222,31 +222,17 @@ void sg_ifstream::open( const SGPath& name, ios_openmode io_mode )
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
std::wstring ps = name.wstr(); std::wstring ps = name.wstr();
#else #else
std::string ps = name.utf8Str(); std::string ps = name.local8BitStr();
#endif #endif
std::ifstream::open(ps.c_str(), io_mode); std::ifstream::open(ps.c_str(), io_mode);
} }
std::string sg_ifstream::read_all()
{
this->seekg(0, std::ios::end); // seek to end
const auto pos = this->tellg();
std::string result;
result.resize(pos);
this->seekg(0, std::ios::beg);
this->read(const_cast<char*>(result.data()), pos);
return result;
}
sg_ofstream::sg_ofstream(const SGPath& path, ios_openmode io_mode) sg_ofstream::sg_ofstream(const SGPath& path, ios_openmode io_mode)
{ {
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
std::wstring ps = path.wstr(); std::wstring ps = path.wstr();
#else #else
std::string ps = path.utf8Str(); std::string ps = path.local8BitStr();
#endif #endif
std::ofstream::open(ps.c_str(), io_mode); std::ofstream::open(ps.c_str(), io_mode);
} }
@@ -256,7 +242,7 @@ void sg_ofstream::open( const SGPath& name, ios_openmode io_mode )
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
std::wstring ps = name.wstr(); std::wstring ps = name.wstr();
#else #else
std::string ps = name.utf8Str(); std::string ps = name.local8BitStr();
#endif #endif
std::ofstream::open(ps.c_str(), io_mode); std::ofstream::open(ps.c_str(), io_mode);
} }
-4
View File
@@ -196,10 +196,6 @@ public:
void open( const SGPath& name, void open( const SGPath& name,
ios_openmode io_mode = ios_in|ios_binary ); ios_openmode io_mode = ios_in|ios_binary );
/// read the entire stream into a buffer. Use on files, etc - not recommended on streams
/// which never EOF, will bvlock forever.
std::string read_all();
}; };
class sg_ofstream : public std::ofstream class sg_ofstream : public std::ofstream
+1 -1
View File
@@ -431,7 +431,7 @@ void test_ZlibDecompressorIStream_readPutbackEtc()
try { try {
// 'Z' is not the last character read from the stream // 'Z' is not the last character read from the stream
decompressor.putback('Z'); decompressor.putback('Z');
} catch (const std::ios_base::failure&) { } catch (std::ios_base::failure) {
gotException = true; gotException = true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
// gcc fails to catch std::ios_base::failure due to an inconsistent C++11 // gcc fails to catch std::ios_base::failure due to an inconsistent C++11
+40 -68
View File
@@ -23,41 +23,28 @@
// $Id$ // $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h> # include <simgear_config.h>
#endif
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include <errno.h>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/misc/sg_path.hxx>
#include "lowlevel.hxx" #include "lowlevel.hxx"
thread_local SGPath thread_gzPath;
void setThreadLocalSimgearReadPath(const SGPath& path) static int read_error = false ;
{ static int write_error = false ;
thread_gzPath = path;
}
static std::string gzErrorMessage(gzFile fd) void sgClearReadError() { read_error = false; }
{ void sgClearWriteError() { write_error = false; }
int errNum = 0; int sgReadError() { return read_error ; }
const char *gzMsg = gzerror(fd, &errNum); int sgWriteError() { return write_error ; }
if (errNum == Z_ERRNO) {
return simgear::strutils::error_string(errno);
} else {
return {gzMsg};
}
}
void sgReadChar ( gzFile fd, char *var ) void sgReadChar ( gzFile fd, char *var )
{ {
if ( gzread ( fd, var, sizeof(char) ) != sizeof(char) ) { if ( gzread ( fd, var, sizeof(char) ) != sizeof(char) ) {
throw sg_io_exception("sgReadChar: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
} }
@@ -65,7 +52,7 @@ void sgReadChar ( gzFile fd, char *var )
void sgWriteChar ( gzFile fd, const char var ) void sgWriteChar ( gzFile fd, const char var )
{ {
if ( gzwrite ( fd, (void *)(&var), sizeof(char) ) != sizeof(char) ) { if ( gzwrite ( fd, (void *)(&var), sizeof(char) ) != sizeof(char) ) {
throw sg_io_exception("sgWriteChar: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -74,8 +61,7 @@ void sgReadFloat ( gzFile fd, float *var )
{ {
union { float v; uint32_t u; } buf; union { float v; uint32_t u; } buf;
if ( gzread ( fd, &buf.u, sizeof(float) ) != sizeof(float) ) { if ( gzread ( fd, &buf.u, sizeof(float) ) != sizeof(float) ) {
throw sg_io_exception("sgReadFloat: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( &buf.u ); sgEndianSwap( &buf.u );
@@ -92,7 +78,7 @@ void sgWriteFloat ( gzFile fd, const float var )
sgEndianSwap( &buf.u ); sgEndianSwap( &buf.u );
} }
if ( gzwrite ( fd, (void *)(&buf.u), sizeof(float) ) != sizeof(float) ) { if ( gzwrite ( fd, (void *)(&buf.u), sizeof(float) ) != sizeof(float) ) {
throw sg_io_exception("sgWriteFloat: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -101,8 +87,7 @@ void sgReadDouble ( gzFile fd, double *var )
{ {
union { double v; uint64_t u; } buf; union { double v; uint64_t u; } buf;
if ( gzread ( fd, &buf.u, sizeof(double) ) != sizeof(double) ) { if ( gzread ( fd, &buf.u, sizeof(double) ) != sizeof(double) ) {
throw sg_io_exception("sgReadDouble: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( &buf.u ); sgEndianSwap( &buf.u );
@@ -119,7 +104,7 @@ void sgWriteDouble ( gzFile fd, const double var )
sgEndianSwap( &buf.u ); sgEndianSwap( &buf.u );
} }
if ( gzwrite ( fd, (void *)(&buf.u), sizeof(double) ) != sizeof(double) ) { if ( gzwrite ( fd, (void *)(&buf.u), sizeof(double) ) != sizeof(double) ) {
throw sg_io_exception("sgWriteDouble: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -127,8 +112,7 @@ void sgWriteDouble ( gzFile fd, const double var )
void sgReadUInt ( gzFile fd, unsigned int *var ) void sgReadUInt ( gzFile fd, unsigned int *var )
{ {
if ( gzread ( fd, var, sizeof(unsigned int) ) != sizeof(unsigned int) ) { if ( gzread ( fd, var, sizeof(unsigned int) ) != sizeof(unsigned int) ) {
throw sg_io_exception("sgReadUInt: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var); sgEndianSwap( (uint32_t *)var);
@@ -144,7 +128,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int var )
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned int) ) if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned int) )
!= sizeof(unsigned int) ) != sizeof(unsigned int) )
{ {
throw sg_io_exception("sgWriteUInt: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -152,8 +136,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int var )
void sgReadInt ( gzFile fd, int *var ) void sgReadInt ( gzFile fd, int *var )
{ {
if ( gzread ( fd, var, sizeof(int) ) != sizeof(int) ) { if ( gzread ( fd, var, sizeof(int) ) != sizeof(int) ) {
throw sg_io_exception("sgReadInt: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var); sgEndianSwap( (uint32_t *)var);
@@ -167,7 +150,7 @@ void sgWriteInt ( gzFile fd, const int var )
sgEndianSwap( (uint32_t *)&var); sgEndianSwap( (uint32_t *)&var);
} }
if ( gzwrite ( fd, (void *)(&var), sizeof(int) ) != sizeof(int) ) { if ( gzwrite ( fd, (void *)(&var), sizeof(int) ) != sizeof(int) ) {
throw sg_io_exception("sgWriteInt: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -175,8 +158,7 @@ void sgWriteInt ( gzFile fd, const int var )
void sgReadLong ( gzFile fd, int32_t *var ) void sgReadLong ( gzFile fd, int32_t *var )
{ {
if ( gzread ( fd, var, sizeof(int32_t) ) != sizeof(int32_t) ) { if ( gzread ( fd, var, sizeof(int32_t) ) != sizeof(int32_t) ) {
throw sg_io_exception("sgReadLong: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var); sgEndianSwap( (uint32_t *)var);
@@ -192,7 +174,7 @@ void sgWriteLong ( gzFile fd, const int32_t var )
if ( gzwrite ( fd, (void *)(&var), sizeof(int32_t) ) if ( gzwrite ( fd, (void *)(&var), sizeof(int32_t) )
!= sizeof(int32_t) ) != sizeof(int32_t) )
{ {
throw sg_io_exception("sgWriteLong: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -200,8 +182,7 @@ void sgWriteLong ( gzFile fd, const int32_t var )
void sgReadLongLong ( gzFile fd, int64_t *var ) void sgReadLongLong ( gzFile fd, int64_t *var )
{ {
if ( gzread ( fd, var, sizeof(int64_t) ) != sizeof(int64_t) ) { if ( gzread ( fd, var, sizeof(int64_t) ) != sizeof(int64_t) ) {
throw sg_io_exception("sgReadLongLong: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64_t *)var); sgEndianSwap( (uint64_t *)var);
@@ -217,7 +198,7 @@ void sgWriteLongLong ( gzFile fd, const int64_t var )
if ( gzwrite ( fd, (void *)(&var), sizeof(int64_t) ) if ( gzwrite ( fd, (void *)(&var), sizeof(int64_t) )
!= sizeof(int64_t) ) != sizeof(int64_t) )
{ {
throw sg_io_exception("sgWriteLongLong: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -225,8 +206,7 @@ void sgWriteLongLong ( gzFile fd, const int64_t var )
void sgReadUShort ( gzFile fd, unsigned short *var ) void sgReadUShort ( gzFile fd, unsigned short *var )
{ {
if ( gzread ( fd, var, sizeof(unsigned short) ) != sizeof(unsigned short) ){ if ( gzread ( fd, var, sizeof(unsigned short) ) != sizeof(unsigned short) ){
throw sg_io_exception("sgReadUShort: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint16_t *)var); sgEndianSwap( (uint16_t *)var);
@@ -242,7 +222,7 @@ void sgWriteUShort ( gzFile fd, const unsigned short var )
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned short) ) if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned short) )
!= sizeof(unsigned short) ) != sizeof(unsigned short) )
{ {
throw sg_io_exception("sgWriteUShort: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -250,8 +230,7 @@ void sgWriteUShort ( gzFile fd, const unsigned short var )
void sgReadShort ( gzFile fd, short *var ) void sgReadShort ( gzFile fd, short *var )
{ {
if ( gzread ( fd, var, sizeof(short) ) != sizeof(short) ) { if ( gzread ( fd, var, sizeof(short) ) != sizeof(short) ) {
throw sg_io_exception("sgReadShort: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
sgEndianSwap( (uint16_t *)var); sgEndianSwap( (uint16_t *)var);
@@ -265,7 +244,7 @@ void sgWriteShort ( gzFile fd, const short var )
sgEndianSwap( (uint16_t *)&var); sgEndianSwap( (uint16_t *)&var);
} }
if ( gzwrite ( fd, (void *)(&var), sizeof(short) ) != sizeof(short) ) { if ( gzwrite ( fd, (void *)(&var), sizeof(short) ) != sizeof(short) ) {
throw sg_io_exception("sgWriteShort: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -273,8 +252,7 @@ void sgWriteShort ( gzFile fd, const short var )
void sgReadFloat ( gzFile fd, const unsigned int n, float *var ) void sgReadFloat ( gzFile fd, const unsigned int n, float *var )
{ {
if ( gzread ( fd, var, sizeof(float) * n ) != (int)(sizeof(float) * n) ) { if ( gzread ( fd, var, sizeof(float) * n ) != (int)(sizeof(float) * n) ) {
throw sg_io_exception("sgReadFloat array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -298,15 +276,14 @@ void sgWriteFloat ( gzFile fd, const unsigned int n, const float *var )
if ( gzwrite ( fd, (void *)var, sizeof(float) * n ) if ( gzwrite ( fd, (void *)var, sizeof(float) * n )
!= (int)(sizeof(float) * n) ) != (int)(sizeof(float) * n) )
{ {
throw sg_io_exception("sgWriteFloat array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
void sgReadDouble ( gzFile fd, const unsigned int n, double *var ) void sgReadDouble ( gzFile fd, const unsigned int n, double *var )
{ {
if ( gzread ( fd, var, sizeof(double) * n ) != (int)(sizeof(double) * n) ) { if ( gzread ( fd, var, sizeof(double) * n ) != (int)(sizeof(double) * n) ) {
throw sg_io_exception("sgReadDouble array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -330,7 +307,7 @@ void sgWriteDouble ( gzFile fd, const unsigned int n, const double *var )
if ( gzwrite ( fd, (void *)var, sizeof(double) * n ) if ( gzwrite ( fd, (void *)var, sizeof(double) * n )
!= (int)(sizeof(double) * n) ) != (int)(sizeof(double) * n) )
{ {
throw sg_io_exception("sgWriteDouble array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -338,8 +315,7 @@ void sgReadBytes ( gzFile fd, const unsigned int n, void *var )
{ {
if ( n == 0) return; if ( n == 0) return;
if ( gzread ( fd, var, n ) != (int)n ) { if ( gzread ( fd, var, n ) != (int)n ) {
throw sg_io_exception("sgReadBytes: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
} }
@@ -347,7 +323,7 @@ void sgWriteBytes ( gzFile fd, const unsigned int n, const void *var )
{ {
if ( n == 0) return; if ( n == 0) return;
if ( gzwrite ( fd, (void *)var, n ) != (int)n ) { if ( gzwrite ( fd, (void *)var, n ) != (int)n ) {
throw sg_io_exception("sgWriteBytes: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -357,8 +333,7 @@ void sgReadUShort ( gzFile fd, const unsigned int n, unsigned short *var )
if ( gzread ( fd, var, sizeof(unsigned short) * n ) if ( gzread ( fd, var, sizeof(unsigned short) * n )
!= (int)(sizeof(unsigned short) * n) ) != (int)(sizeof(unsigned short) * n) )
{ {
throw sg_io_exception("sgReadUShort array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -382,7 +357,7 @@ void sgWriteUShort ( gzFile fd, const unsigned int n, const unsigned short *var
if ( gzwrite ( fd, (void *)var, sizeof(unsigned short) * n ) if ( gzwrite ( fd, (void *)var, sizeof(unsigned short) * n )
!= (int)(sizeof(unsigned short) * n) ) != (int)(sizeof(unsigned short) * n) )
{ {
throw sg_io_exception("sgWriteUShort array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -393,8 +368,7 @@ void sgReadShort ( gzFile fd, const unsigned int n, short *var )
if ( gzread ( fd, var, sizeof(short) * n ) if ( gzread ( fd, var, sizeof(short) * n )
!= (int)(sizeof(short) * n) ) != (int)(sizeof(short) * n) )
{ {
throw sg_io_exception("sgReadShort array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -418,7 +392,7 @@ void sgWriteShort ( gzFile fd, const unsigned int n, const short *var )
if ( gzwrite ( fd, (void *)var, sizeof(short) * n ) if ( gzwrite ( fd, (void *)var, sizeof(short) * n )
!= (int)(sizeof(short) * n) ) != (int)(sizeof(short) * n) )
{ {
throw sg_io_exception("sgWriteShort array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -428,8 +402,7 @@ void sgReadUInt ( gzFile fd, const unsigned int n, unsigned int *var )
if ( gzread ( fd, var, sizeof(unsigned int) * n ) if ( gzread ( fd, var, sizeof(unsigned int) * n )
!= (int)(sizeof(unsigned int) * n) ) != (int)(sizeof(unsigned int) * n) )
{ {
throw sg_io_exception("sgReadUInt array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -453,7 +426,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int n, const unsigned int *var )
if ( gzwrite ( fd, (void *)var, sizeof(unsigned int) * n ) if ( gzwrite ( fd, (void *)var, sizeof(unsigned int) * n )
!= (int)(sizeof(unsigned int) * n) ) != (int)(sizeof(unsigned int) * n) )
{ {
throw sg_io_exception("sgWriteUInt array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
@@ -464,8 +437,7 @@ void sgReadInt ( gzFile fd, const unsigned int n, int *var )
if ( gzread ( fd, var, sizeof(int) * n ) if ( gzread ( fd, var, sizeof(int) * n )
!= (int)(sizeof(int) * n) ) != (int)(sizeof(int) * n) )
{ {
throw sg_io_exception("sgReadInt array: GZRead failed:" + gzErrorMessage(fd), read_error = true ;
sg_location{thread_gzPath}, nullptr, false);
} }
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) { for ( unsigned int i = 0; i < n; ++i ) {
@@ -489,7 +461,7 @@ void sgWriteInt ( gzFile fd, const unsigned int n, const int *var )
if ( gzwrite ( fd, (void *)var, sizeof(int) * n ) if ( gzwrite ( fd, (void *)var, sizeof(int) * n )
!= (int)(sizeof(int) * n) ) != (int)(sizeof(int) * n) )
{ {
throw sg_io_exception("sgWriteInt array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false); write_error = true ;
} }
} }
+4 -8
View File
@@ -35,9 +35,6 @@
#include <simgear/math/SGMath.hxx> #include <simgear/math/SGMath.hxx>
// forward decls
class SGPath;
// Note that output is written in little endian form (and converted as // Note that output is written in little endian form (and converted as
// necessary for big endian machines) // necessary for big endian machines)
@@ -124,10 +121,9 @@ inline void sgWriteGeod ( gzFile fd, const SGGeod& var ) {
sgWriteDouble( fd, var.getElevationM() ); sgWriteDouble( fd, var.getElevationM() );
} }
/** void sgClearReadError();
@ error aid: allow calling code to specify which file path we're reading from, so that erros we void sgClearWriteError();
throw from sgReadXXXX can have a valid location set. int sgReadError();
*/ int sgWriteError();
void setThreadLocalSimgearReadPath(const SGPath& path);
#endif // _SG_LOWLEVEL_HXX #endif // _SG_LOWLEVEL_HXX
+1 -2
View File
@@ -36,7 +36,6 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <cstdio> // for snprintf #include <cstdio> // for snprintf
#include <mutex>
#include <errno.h> #include <errno.h>
#if defined(WINSOCK) #if defined(WINSOCK)
@@ -214,7 +213,7 @@ private:
return ok; return ok;
} }
std::mutex _lock; SGMutex _lock;
SGWaitCondition _wait; SGWaitCondition _wait;
typedef std::map<string, simgear::IPAddress*> AddressCache; typedef std::map<string, simgear::IPAddress*> AddressCache;
+35 -27
View File
@@ -42,7 +42,6 @@
#include <simgear/bucket/newbucket.hxx> #include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/math/SGGeometry.hxx> #include <simgear/math/SGGeometry.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
@@ -161,7 +160,7 @@ public:
} }
} }
int32_t readInt() float readInt()
{ {
unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset); unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset);
if ( sgIsBigEndian() ) { if ( sgIsBigEndian() ) {
@@ -454,6 +453,10 @@ void SGBinObject::read_object( gzFile fp,
} }
} }
if ( sgReadError() ) {
throw sg_exception("Error reading object properties");
}
size_t indexCount = std::bitset<32>((int)idx_mask).count(); size_t indexCount = std::bitset<32>((int)idx_mask).count();
if (indexCount == 0) { if (indexCount == 0) {
throw sg_exception("object index mask has no bits set"); throw sg_exception("object index mask has no bits set");
@@ -461,10 +464,18 @@ void SGBinObject::read_object( gzFile fp,
for ( j = 0; j < nelements; ++j ) { for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes ); sgReadUInt( fp, &nbytes );
if ( sgReadError() ) {
throw sg_exception("Error reading element size");
}
buf.resize( nbytes ); buf.resize( nbytes );
char *ptr = buf.get_ptr(); char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr ); sgReadBytes( fp, nbytes, ptr );
if ( sgReadError() ) {
throw sg_exception("Error reading element bytes");
}
int_list vs; int_list vs;
int_list ns; int_list ns;
int_list cs; int_list cs;
@@ -491,11 +502,7 @@ void SGBinObject::read_object( gzFile fp,
// read a binary file and populate the provided structures. // read a binary file and populate the provided structures.
bool SGBinObject::read_bin( const SGPath& file ) bool SGBinObject::read_bin( const SGPath& file ) {
{
gzFile fp = NULL;
try {
SGVec3d p; SGVec3d p;
int i, k; int i, k;
size_t j; size_t j;
@@ -544,24 +551,27 @@ bool SGBinObject::read_bin( const SGPath& file )
withGZ.concat(".gz"); withGZ.concat(".gz");
fp = gzFileFromSGPath(withGZ, "rb"); fp = gzFileFromSGPath(withGZ, "rb");
if (fp == nullptr) { if (fp == nullptr) {
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file), {}, false); SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << withGZ << " for reading!");
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file));
} }
} }
setThreadLocalSimgearReadPath(file); sgClearReadError();
// read headers // read headers
unsigned int header; unsigned int header;
sgReadUInt( fp, &header ); sgReadUInt( fp, &header );
if ( ((header & 0xFF000000) >> 24) == 'S' && if ( ((header & 0xFF000000) >> 24) == 'S' &&
((header & 0x00FF0000) >> 16) == 'G' ) { ((header & 0x00FF0000) >> 16) == 'G' ) {
// read file version // read file version
version = (header & 0x0000FFFF); version = (header & 0x0000FFFF);
} else { } else {
throw sg_io_exception("Bad BTG magic/version", sg_location(file), {}, false); // close the file before we return
gzclose(fp);
throw sg_io_exception("Bad BTG magic/version", sg_location(file));
} }
// read creation time // read creation time
@@ -597,6 +607,9 @@ bool SGBinObject::read_bin( const SGPath& file )
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects); SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects);
if ( sgReadError() ) {
throw sg_io_exception("Error reading BTG file header", sg_location(file));
}
// read in objects // read in objects
for ( i = 0; i < nobjects; ++i ) { for ( i = 0; i < nobjects; ++i ) {
@@ -781,19 +794,14 @@ bool SGBinObject::read_bin( const SGPath& file )
sgReadBytes( fp, nbytes, ptr ); sgReadBytes( fp, nbytes, ptr );
} }
} }
if ( sgReadError() ) {
throw sg_io_exception("Error while reading object", sg_location(file, i));
}
} }
gzclose(fp);
fp = NULL;
} catch (std::exception&) {
if (fp) {
// close the file // close the file
gzclose(fp); gzclose(fp);
}
throw; // re-throw
}
return true; return true;
} }
@@ -967,7 +975,8 @@ bool SGBinObject::write_bin_file(const SGPath& file)
return false; return false;
} }
try { sgClearWriteError();
SG_LOG(SG_IO, SG_DEBUG, "points size = " << pts_v.size() SG_LOG(SG_IO, SG_DEBUG, "points size = " << pts_v.size()
<< " pt_materials = " << pt_materials.size() ); << " pt_materials = " << pt_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "triangles size = " << tris_v.size() SG_LOG(SG_IO, SG_DEBUG, "triangles size = " << tris_v.size()
@@ -1066,13 +1075,12 @@ bool SGBinObject::write_bin_file(const SGPath& file)
// close the file // close the file
gzclose(fp); gzclose(fp);
fp = NULL;
} catch (std::exception&) { if ( sgWriteError() ) {
if (fp) { cout << "Error while writing file " << file << endl;
gzclose(fp);
}
return false; return false;
} }
return true; return true;
} }
+7 -4
View File
@@ -34,15 +34,18 @@
#include <simgear/math/sg_types.hxx> #include <simgear/math/sg_types.hxx>
#include <simgear/math/SGMath.hxx> #include <simgear/math/SGMath.hxx>
#include <array>
#include <string>
#include <vector> #include <vector>
#include <string>
#include <boost/array.hpp>
#define MAX_TC_SETS (4) #define MAX_TC_SETS (4)
#define MAX_VAS (8) #define MAX_VAS (8)
typedef std::array<int_list, MAX_TC_SETS> tci_list; // I really want to pass around fixed length arrays, as the size
typedef std::array<int_list, MAX_VAS> vai_list; // has to be hardcoded
// but it's a C++0x feature use boost in its absence
typedef boost::array<int_list, MAX_TC_SETS> tci_list;
typedef boost::array<int_list, MAX_VAS> vai_list;
/** STL Structure used to store (integer index) object information */ /** STL Structure used to store (integer index) object information */
typedef std::vector < int_list > group_list; typedef std::vector < int_list > group_list;
-37
View File
@@ -64,43 +64,6 @@ SGFile::SGFile( int existingFd ) :
SGFile::~SGFile() { SGFile::~SGFile() {
} }
#include <simgear/misc/sg_hash.hxx>
#include <simgear/structure/exception.hxx>
#include "simgear/misc/strutils.hxx"
std::string SGFile::computeHash()
{
if (!file_name.exists())
return {};
simgear::sha1nfo info;
sha1_init(&info);
// unique_ptr with custom deleter for exception safety
const int bufSize = 1024 * 1024;
std::unique_ptr<char, std::function<void(char*)>> buf{static_cast<char*>(malloc(bufSize)),
[](char* p) { free(p); }};
if (!buf) {
// @TODO report out of memory error
SG_LOG(SG_IO, SG_ALERT, "Failed to malloc buffer for SHA1 check:" << file_name);
return {};
}
size_t readLen;
SGBinaryFile f(file_name);
if (!f.open(SG_IO_IN)) {
SG_LOG(SG_IO, SG_ALERT, "SGFile::computeHash: Failed to open " << file_name);
return {};
}
while ((readLen = f.read(buf.get(), bufSize)) > 0) {
sha1_write(&info, buf.get(), readLen);
}
f.close();
std::string hashBytes((char*)sha1_result(&info), HASH_LENGTH);
return simgear::strutils::encodeHex(hashBytes);
}
// open the file based on specified direction // open the file based on specified direction
bool SGFile::open( const SGProtocolDir d ) { bool SGFile::open( const SGProtocolDir d ) {
-3
View File
@@ -87,9 +87,6 @@ public:
/** @return true of eof conditions exists */ /** @return true of eof conditions exists */
virtual bool eof() const { return eof_flag; }; virtual bool eof() const { return eof_flag; };
std::string computeHash();
}; };
class SGBinaryFile : public SGFile { class SGBinaryFile : public SGFile {
Binary file not shown.
+2
View File
@@ -7,6 +7,8 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h> #include <simgear/simgear_config.h>
#include "DNSClient.hxx" #include "DNSClient.hxx"
+16 -82
View File
@@ -1,10 +1,12 @@
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <sstream> #include <sstream>
#include <cerrno> #include <cerrno>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h> #include <simgear/simgear_config.h>
#include "HTTPClient.hxx" #include "HTTPClient.hxx"
@@ -59,23 +61,23 @@ public:
std::map<string, string> headers; std::map<string, string> headers;
protected: protected:
void onDone() override virtual void onDone()
{ {
complete = true; complete = true;
} }
void onFail() override virtual void onFail()
{ {
failed = true; failed = true;
} }
void gotBodyData(const char* s, int n) override virtual void gotBodyData(const char* s, int n)
{ {
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl; //std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
bodyData += string(s, n); bodyData += string(s, n);
} }
void responseHeader(const string& header, const string& value) override virtual void responseHeader(const string& header, const string& value)
{ {
Request::responseHeader(header, value); Request::responseHeader(header, value);
headers[header] = value; headers[header] = value;
@@ -271,23 +273,7 @@ public:
d << "\r\n"; // final CRLF to terminate the headers d << "\r\n"; // final CRLF to terminate the headers
d << contentStr; d << contentStr;
push(d.str().c_str()); push(d.str().c_str());
} else if (path == "/test_redirect") {
string contentStr("<html>See <a href=\"wibble\">Here</a></html>");
stringstream d;
d << "HTTP/1.1 " << 302 << " " << "Found" << "\r\n";
d << "Location:" << " http://localhost:2000/was_redirected" << "\r\n";
d << "Content-Length:" << contentStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << contentStr;
push(d.str().c_str());
} else if (path == "/was_redirected") {
string contentStr(BODY1);
stringstream d;
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
d << "Content-Length:" << contentStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << contentStr;
push(d.str().c_str());
} else { } else {
TestServerChannel::processRequestHeaders(); TestServerChannel::processRequestHeaders();
} }
@@ -379,26 +365,6 @@ void waitForFailed(HTTP::Client* cl, TestRequest* tr)
cerr << "timed out waiting for failure" << endl; cerr << "timed out waiting for failure" << endl;
} }
using CompletionCheck = std::function<bool()>;
bool waitFor(HTTP::Client* cl, CompletionCheck ccheck)
{
SGTimeStamp start(SGTimeStamp::now());
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (ccheck()) {
return true;
}
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out" << endl;
return false;
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
sglog().setLogLevels( SG_ALL, SG_INFO ); sglog().setLogLevels( SG_ALL, SG_INFO );
@@ -474,8 +440,6 @@ int main(int argc, char* argv[])
// larger get request // larger get request
for (unsigned int i=0; i<body2Size; ++i) { for (unsigned int i=0; i<body2Size; ++i) {
// this contains embeded 0s on purpose, i.e it's
// not text data but binary
body2[i] = (i << 4) | (i >> 2); body2[i] = (i << 4) | (i >> 2);
} }
@@ -620,10 +584,9 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own3(tr3); HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3); cl.makeRequest(tr3);
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() { waitForComplete(&cl, tr3);
return tr->complete && tr2->complete &&tr3->complete; SG_VERIFY(tr->complete);
})); SG_VERIFY(tr2->complete);
SG_CHECK_EQUAL(tr->bodyData, string(BODY1)); SG_CHECK_EQUAL(tr->bodyData, string(BODY1));
SG_CHECK_EQUAL(tr2->responseLength(), strlen(BODY3)); SG_CHECK_EQUAL(tr2->responseLength(), strlen(BODY3));
@@ -652,9 +615,9 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own3(tr3); HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3); cl.makeRequest(tr3);
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() { waitForComplete(&cl, tr3);
return tr->complete && tr2->complete &&tr3->complete; SG_VERIFY(tr->complete);
})); SG_VERIFY(tr2->complete);
SG_CHECK_EQUAL(tr->responseLength(), strlen(BODY1)); SG_CHECK_EQUAL(tr->responseLength(), strlen(BODY1));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY1)); SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY1));
@@ -781,15 +744,8 @@ cout << "testing proxy close" << endl;
SG_CHECK_EQUAL(tr3->bodyData, string(BODY1)); SG_CHECK_EQUAL(tr3->bodyData, string(BODY1));
} }
// disabling this test for now, since it seems to have changed depending
// on the libCurl version. (Or some other configuration which is currently
// not apparent).
// old behaviour: Curl sends the second request soon after makeRequest
// new behaviour: Curl waits for the first request to complete, before
// sending the second request (i.e acts as if HTTP pipelining is disabled)
#if 0
{ {
cout << "get-during-response-send\n\n" << endl; cout << "get-during-response-send" << endl;
cl.clearAllConnections(); cl.clearAllConnections();
//test_get_during_send //test_get_during_send
@@ -809,10 +765,7 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own2(tr2); HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2); cl.makeRequest(tr2);
SG_VERIFY(waitFor(&cl, [tr, tr2]() { waitForComplete(&cl, tr2);
return tr->isComplete() && tr2->isComplete();
}));
SG_CHECK_EQUAL(tr->responseCode(), 200); SG_CHECK_EQUAL(tr->responseCode(), 200);
SG_CHECK_EQUAL(tr->bodyData, string(BODY3)); SG_CHECK_EQUAL(tr->bodyData, string(BODY3));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY3)); SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY3));
@@ -820,25 +773,6 @@ cout << "testing proxy close" << endl;
SG_CHECK_EQUAL(tr2->bodyData, string(BODY1)); SG_CHECK_EQUAL(tr2->bodyData, string(BODY1));
SG_CHECK_EQUAL(tr2->responseBytesReceived(), strlen(BODY1)); SG_CHECK_EQUAL(tr2->responseBytesReceived(), strlen(BODY1));
} }
#endif
{
cout << "redirect test" << endl;
// redirect test
testServer.disconnectAll();
cl.clearAllConnections();
TestRequest* tr = new TestRequest("http://localhost:2000/test_redirect");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
SG_CHECK_EQUAL(tr->responseCode(), 200);
SG_CHECK_EQUAL(tr->responseReason(), string("OK"));
SG_CHECK_EQUAL(tr->responseLength(), strlen(BODY1));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY1));
SG_CHECK_EQUAL(tr->bodyData, string(BODY1));
}
cout << "all tests passed ok" << endl; cout << "all tests passed ok" << endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
+4 -3
View File
@@ -1,7 +1,6 @@
#ifndef SIMGEAR_IO_TEST_HTTP_HXX #ifndef SIMGEAR_IO_TEST_HTTP_HXX
#define SIMGEAR_IO_TEST_HTTP_HXX #define SIMGEAR_IO_TEST_HTTP_HXX
#include <algorithm>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@@ -31,6 +30,7 @@ public:
virtual ~TestServerChannel() virtual ~TestServerChannel()
{ {
std::cerr << "dtor test server channel" << std::endl;
} }
virtual void collectIncomingData(const char* s, int n) virtual void collectIncomingData(const char* s, int n)
@@ -139,8 +139,8 @@ public:
void sendErrorResponse(int code, bool close, std::string content) void sendErrorResponse(int code, bool close, std::string content)
{ {
// std::cerr << "sending error " << code << " for " << path << std::endl; std::cerr << "sending error " << code << " for " << path << std::endl;
// std::cerr << "\tcontent:" << content << std::endl; std::cerr << "\tcontent:" << content << std::endl;
std::stringstream headerData; std::stringstream headerData;
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n"; headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
@@ -168,6 +168,7 @@ public:
virtual void handleClose (void) virtual void handleClose (void)
{ {
std::cerr << "channel close" << std::endl;
NetBufferChannel::handleClose(); NetBufferChannel::handleClose();
} }
+14 -186
View File
@@ -1,18 +1,17 @@
#include <cassert>
#include <cstdlib> #include <cstdlib>
#include <errno.h>
#include <fcntl.h>
#include <functional>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <sstream> #include <sstream>
#include <errno.h>
#include <fcntl.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h> #include <simgear/simgear_config.h>
#include "HTTPClient.hxx"
#include "HTTPRepository.hxx"
#include "HTTPTestApi_private.hxx"
#include "test_HTTP.hxx" #include "test_HTTP.hxx"
#include "HTTPRepository.hxx"
#include "HTTPClient.hxx"
#include <simgear/misc/strutils.hxx> #include <simgear/misc/strutils.hxx>
#include <simgear/misc/sg_hash.hxx> #include <simgear/misc/sg_hash.hxx>
@@ -27,14 +26,8 @@
using namespace simgear; using namespace simgear;
using TestApi = simgear::HTTP::TestApi;
std::string dataForFile(const std::string& parentName, const std::string& name, int revision) std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
{ {
if (name == "zeroByteFile") {
return {};
}
std::ostringstream os; std::ostringstream os;
// random content but which definitely depends on our tree location // random content but which definitely depends on our tree location
// and revision. // and revision.
@@ -53,9 +46,6 @@ std::string hashForData(const std::string& d)
return strutils::encodeHex(sha1_result(&info), HASH_LENGTH); return strutils::encodeHex(sha1_result(&info), HASH_LENGTH);
} }
class TestRepoEntry;
using AccessCallback = std::function<void(TestRepoEntry &entry)>;
class TestRepoEntry class TestRepoEntry
{ {
public: public:
@@ -81,8 +71,7 @@ public:
int requestCount; int requestCount;
bool getWillFail; bool getWillFail;
bool returnCorruptData; bool returnCorruptData;
std::unique_ptr<SGCallback> accessCallback;
AccessCallback accessCallback;
void clearRequestCounts(); void clearRequestCounts();
@@ -282,8 +271,8 @@ public:
return; return;
} }
if (entry->accessCallback) { if (entry->accessCallback.get()) {
entry->accessCallback(*entry); (*entry->accessCallback)();
} }
if (entry->getWillFail) { if (entry->getWillFail) {
@@ -294,29 +283,20 @@ public:
entry->requestCount++; entry->requestCount++;
std::string content; std::string content;
bool closeSocket = false;
size_t contentSize = 0;
if (entry->returnCorruptData) { if (entry->returnCorruptData) {
content = dataForFile("!$£$!" + entry->parent->name, content = dataForFile("!$£$!" + entry->parent->name,
"corrupt_" + entry->name, "corrupt_" + entry->name,
entry->revision); entry->revision);
contentSize = content.size();
} else { } else {
content = entry->data(); content = entry->data();
contentSize = content.size();
} }
std::stringstream d; std::stringstream d;
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n"; d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
d << "Content-Length:" << contentSize << "\r\n"; d << "Content-Length:" << content.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers d << "\r\n"; // final CRLF to terminate the headers
d << content; d << content;
push(d.str().c_str()); push(d.str().c_str());
if (closeSocket) {
closeWhenDone();
}
} else { } else {
sendErrorResponse(404, false, ""); sendErrorResponse(404, false, "");
} }
@@ -413,7 +393,6 @@ void waitForUpdateComplete(HTTP::Client* cl, HTTPRepository* repo)
cl->update(); cl->update();
testServer.poll(); testServer.poll();
repo->process();
if (!repo->isDoingSync()) { if (!repo->isDoingSync()) {
return; return;
} }
@@ -423,16 +402,6 @@ void waitForUpdateComplete(HTTP::Client* cl, HTTPRepository* repo)
std::cerr << "timed out" << std::endl; std::cerr << "timed out" << std::endl;
} }
void runForTime(HTTP::Client *cl, HTTPRepository *repo, int msec = 15) {
SGTimeStamp start(SGTimeStamp::now());
while (start.elapsedMSec() < msec) {
cl->update();
testServer.poll();
repo->process();
SGTimeStamp::sleepForMSec(1);
}
}
void testBasicClone(HTTP::Client* cl) void testBasicClone(HTTP::Client* cl)
{ {
std::unique_ptr<HTTPRepository> repo; std::unique_ptr<HTTPRepository> repo;
@@ -450,7 +419,6 @@ void testBasicClone(HTTP::Client* cl)
verifyFileState(p, "fileA"); verifyFileState(p, "fileA");
verifyFileState(p, "dirA/subdirA/fileAAA"); verifyFileState(p, "dirA/subdirA/fileAAA");
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA"); verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
verifyFileState(p, "dirA/subdirA/zeroByteFile");
global_repo->findEntry("fileA")->revision++; global_repo->findEntry("fileA")->revision++;
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++; global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
@@ -651,21 +619,11 @@ void testAbandonCorruptFiles(HTTP::Client* cl)
repo->setBaseUrl("http://localhost:2000/repo"); repo->setBaseUrl("http://localhost:2000/repo");
repo->update(); repo->update();
waitForUpdateComplete(cl, repo.get()); waitForUpdateComplete(cl, repo.get());
if (repo->failure() != HTTPRepository::REPO_PARTIAL_UPDATE) { if (repo->failure() != HTTPRepository::REPO_ERROR_CHECKSUM) {
std::cerr << "Got failure state:" << repo->failure() << std::endl; std::cerr << "Got failure state:" << repo->failure() << std::endl;
throw sg_exception("Bad result from corrupt files test"); throw sg_exception("Bad result from corrupt files test");
} }
auto failedFiles = repo->failures();
if (failedFiles.size() != 1) {
throw sg_exception("Bad result from corrupt files test");
}
if (failedFiles.front().path.utf8Str() != "dirB/subdirG/fileBGA") {
throw sg_exception("Bad path from corrupt files test:" +
failedFiles.front().path.utf8Str());
}
repo.reset(); repo.reset();
if (cl->hasActiveRequests()) { if (cl->hasActiveRequests()) {
cl->debugDumpRequests(); cl->debugDumpRequests();
@@ -700,20 +658,14 @@ void testServerModifyDuringSync(HTTP::Client* cl)
repo.reset(new HTTPRepository(p, cl)); repo.reset(new HTTPRepository(p, cl));
repo->setBaseUrl("http://localhost:2000/repo"); repo->setBaseUrl("http://localhost:2000/repo");
global_repo->findEntry("dirA/fileAA")->accessCallback = global_repo->findEntry("dirA/fileAA")->accessCallback.reset(make_callback(&modifyBTree));
[](const TestRepoEntry &r) {
std::cout << "Modifying sub-tree" << std::endl;
global_repo->findEntry("dirB/subdirA/fileBAC")->revision++;
global_repo->defineFile("dirB/subdirZ/fileBZA");
global_repo->findEntry("dirB/subdirB/fileBBB")->revision++;
};
repo->update(); repo->update();
waitForUpdateComplete(cl, repo.get()); waitForUpdateComplete(cl, repo.get());
global_repo->findEntry("dirA/fileAA")->accessCallback = AccessCallback{}; global_repo->findEntry("dirA/fileAA")->accessCallback.reset();
if (repo->failure() != HTTPRepository::REPO_PARTIAL_UPDATE) { if (repo->failure() != HTTPRepository::REPO_ERROR_CHECKSUM) {
throw sg_exception("Bad result from modify during sync test"); throw sg_exception("Bad result from modify during sync test");
} }
@@ -804,124 +756,6 @@ void testCopyInstalledChildren(HTTP::Client* cl)
std::cout << "passed Copy installed children" << std::endl; std::cout << "passed Copy installed children" << std::endl;
} }
void testRetryAfterSocketFailure(HTTP::Client *cl) {
global_repo->clearRequestCounts();
global_repo->clearFailFlags();
std::unique_ptr<HTTPRepository> repo;
SGPath p(simgear::Dir::current().path());
p.append("http_repo_retry_after_socket_fail");
simgear::Dir pd(p);
if (pd.exists()) {
pd.removeChildren();
}
repo.reset(new HTTPRepository(p, cl));
repo->setBaseUrl("http://localhost:2000/repo");
int aaFailsRemaining = 2;
int subdirBAFailsRemaining = 2;
TestApi::setResponseDoneCallback(
cl, [&aaFailsRemaining, &subdirBAFailsRemaining](int curlResult,
HTTP::Request_ptr req) {
if (req->url() == "http://localhost:2000/repo/dirA/fileAA") {
if (aaFailsRemaining == 0)
return false;
--aaFailsRemaining;
TestApi::markRequestAsFailed(req, 56, "Simulated socket failure");
return true;
} else if (req->url() ==
"http://localhost:2000/repo/dirB/subdirA/.dirindex") {
if (subdirBAFailsRemaining == 0)
return false;
--subdirBAFailsRemaining;
TestApi::markRequestAsFailed(req, 56, "Simulated socket failure");
return true;
} else {
return false;
}
});
repo->update();
waitForUpdateComplete(cl, repo.get());
if (repo->failure() != HTTPRepository::REPO_NO_ERROR) {
throw sg_exception("Bad result from retry socket failure test");
}
verifyFileState(p, "dirA/fileAA");
verifyFileState(p, "dirB/subdirA/fileBAA");
verifyFileState(p, "dirB/subdirA/fileBAC");
verifyRequestCount("dirA/fileAA", 3);
verifyRequestCount("dirB/subdirA", 3);
verifyRequestCount("dirB/subdirA/fileBAC", 1);
}
void testPersistentSocketFailure(HTTP::Client *cl) {
global_repo->clearRequestCounts();
global_repo->clearFailFlags();
std::unique_ptr<HTTPRepository> repo;
SGPath p(simgear::Dir::current().path());
p.append("http_repo_persistent_socket_fail");
simgear::Dir pd(p);
if (pd.exists()) {
pd.removeChildren();
}
repo.reset(new HTTPRepository(p, cl));
repo->setBaseUrl("http://localhost:2000/repo");
TestApi::setResponseDoneCallback(
cl, [](int curlResult, HTTP::Request_ptr req) {
const auto url = req->url();
if (url.find("http://localhost:2000/repo/dirB") == 0) {
TestApi::markRequestAsFailed(req, 56, "Simulated socket failure");
return true;
}
return false;
});
repo->update();
waitForUpdateComplete(cl, repo.get());
if (repo->failure() != HTTPRepository::REPO_PARTIAL_UPDATE) {
throw sg_exception("Bad result from retry socket failure test");
}
verifyFileState(p, "dirA/fileAA");
verifyRequestCount("dirA/fileAA", 1);
verifyRequestCount("dirD/fileDA", 1);
verifyRequestCount("dirD/subdirDA/fileDAA", 1);
verifyRequestCount("dirD/subdirDB/fileDBA", 1);
}
void testHashOnEmptyFile()
{
std::unique_ptr<HTTPRepository> repo;
SGPath p(simgear::Dir::current().path());
p.append("sgfile_compute_hash");
simgear::Dir pd(p);
if (pd.exists()) {
pd.removeChildren();
} else {
pd.create(0700);
}
SGPath fPath = p / "test_empty_file";
SGFile file(fPath);
file.open(SG_IO_OUT);
file.close();
const auto hash = file.computeHash();
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
sglog().setLogLevels( SG_ALL, SG_INFO ); sglog().setLogLevels( SG_ALL, SG_INFO );
@@ -937,8 +771,6 @@ int main(int argc, char* argv[])
global_repo->defineFile("dirA/fileAC"); global_repo->defineFile("dirA/fileAC");
global_repo->defineFile("dirA/subdirA/fileAAA"); global_repo->defineFile("dirA/subdirA/fileAAA");
global_repo->defineFile("dirA/subdirA/fileAAB"); global_repo->defineFile("dirA/subdirA/fileAAB");
global_repo->defineFile("dirA/subdirA/zeroByteFile");
global_repo->defineFile("dirB/subdirA/fileBAA"); global_repo->defineFile("dirB/subdirA/fileBAA");
global_repo->defineFile("dirB/subdirA/fileBAB"); global_repo->defineFile("dirB/subdirA/fileBAB");
global_repo->defineFile("dirB/subdirA/fileBAC"); global_repo->defineFile("dirB/subdirA/fileBAC");
@@ -969,10 +801,6 @@ int main(int argc, char* argv[])
cl.clearAllConnections(); cl.clearAllConnections();
testCopyInstalledChildren(&cl); testCopyInstalledChildren(&cl);
testRetryAfterSocketFailure(&cl);
testPersistentSocketFailure(&cl);
testHashOnEmptyFile();
std::cout << "all tests passed ok" << std::endl; std::cout << "all tests passed ok" << std::endl;
return 0; return 0;
+1 -30
View File
@@ -32,7 +32,7 @@ void testTarGz()
uint8_t* buf = (uint8_t*) alloca(8192); uint8_t* buf = (uint8_t*) alloca(8192);
size_t bufSize = f.read((char*) buf, 8192); size_t bufSize = f.read((char*) buf, 8192);
SG_VERIFY(ArchiveExtractor::determineType(buf, bufSize) == ArchiveExtractor::GZData); SG_VERIFY(ArchiveExtractor::determineType(buf, bufSize) == ArchiveExtractor::TarData);
f.close(); f.close();
} }
@@ -174,34 +174,6 @@ void testPAXAttributes()
} }
void testExtractXZ()
{
SGPath p = SGPath(SRC_DIR);
p.append("test.tar.xz");
SGBinaryFile f(p);
f.open(SG_IO_IN);
SGPath extractDir = simgear::Dir::current().path() / "test_extract_xz";
simgear::Dir pd(extractDir);
pd.removeChildren();
ArchiveExtractor ex(extractDir);
uint8_t* buf = (uint8_t*)alloca(128);
while (!f.eof()) {
size_t bufSize = f.read((char*)buf, 128);
ex.extractBytes(buf, bufSize);
}
ex.flush();
SG_VERIFY(ex.isAtEndOfArchive());
SG_VERIFY(ex.hasError() == false);
SG_VERIFY((extractDir / "testDir/hello.c").exists());
SG_VERIFY((extractDir / "testDir/foo.txt").exists());
}
int main(int ac, char ** av) int main(int ac, char ** av)
{ {
testTarGz(); testTarGz();
@@ -209,7 +181,6 @@ int main(int ac, char ** av)
testFilterTar(); testFilterTar();
testExtractStreamed(); testExtractStreamed();
testExtractZip(); testExtractZip();
testExtractXZ();
// disabled to avoiding checking in large PAX archive // disabled to avoiding checking in large PAX archive
// testPAXAttributes(); // testPAXAttributes();

Some files were not shown because too many files have changed in this diff Show More