Compare commits
372
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9be955262e | ||
|
|
bfa411e9b7 | ||
|
|
dab015742a | ||
|
|
0ab81d36b9 | ||
|
|
4d905135e8 | ||
|
|
afad224ca0 | ||
|
|
99c159d46e | ||
|
|
733efd08dd | ||
|
|
3753c62783 | ||
|
|
3e804605b7 | ||
|
|
35b1d321fe | ||
|
|
6ab7f68f4b | ||
|
|
b2e149a737 | ||
|
|
e28c4fa5ca | ||
|
|
61dc19f635 | ||
|
|
60634bc445 | ||
|
|
b3e93eaf6e | ||
|
|
36dca92c2b | ||
|
|
5a1ed52d7c | ||
|
|
fd191b51ce | ||
|
|
6167159795 | ||
|
|
672afdbc34 | ||
|
|
27e61b3dec | ||
|
|
f1d00c9b40 | ||
|
|
1b00ece8c4 | ||
|
|
d0f24229b2 | ||
|
|
ab8795f6dc | ||
|
|
2fe60c9635 | ||
|
|
27a3ee3bce | ||
|
|
0721db3acd | ||
|
|
24b58cbe21 | ||
|
|
5b3274e688 | ||
|
|
fcd75cfae5 | ||
|
|
6387a1d6d0 | ||
|
|
fc4ce2528b | ||
|
|
18d2bfcd8b | ||
|
|
6738a3aa2b | ||
|
|
a8c1bef0bf | ||
|
|
4faf0ea468 | ||
|
|
80cc09fe90 | ||
|
|
ca8dbb985e | ||
|
|
751cdc32a8 | ||
|
|
1d978429f5 | ||
|
|
2b2e3ae5c4 | ||
|
|
0e3ac7e078 | ||
|
|
01ab3b2385 | ||
|
|
11cf87951c | ||
|
|
7c004a4c90 | ||
|
|
a48693d273 | ||
|
|
12d57a6373 | ||
|
|
c7c8fc7777 | ||
|
|
6e054e57ef | ||
|
|
1d89a76d13 | ||
|
|
65925cccdf | ||
|
|
898559ab31 | ||
|
|
ad3621e23b | ||
|
|
57b0f70a55 | ||
|
|
8d6e543cc2 | ||
|
|
bd93fb279b | ||
|
|
81bdae283a | ||
|
|
00e25404c7 | ||
|
|
6a157e1c08 | ||
|
|
7a6f9151a6 | ||
|
|
567293c14d | ||
|
|
2ff6a4966a | ||
|
|
b13d7f9392 | ||
|
|
d21137739d | ||
|
|
1e13cf6fec | ||
|
|
5c52cdc255 | ||
|
|
17d7808200 | ||
|
|
f144bd5a89 | ||
|
|
b72553f6f0 | ||
|
|
c82a14c252 | ||
|
|
faa559e9af | ||
|
|
c51c0c43ed | ||
|
|
2ab0122124 | ||
|
|
8626e0482d | ||
|
|
c9a4c0dac1 | ||
|
|
825d93423d | ||
|
|
ad24ce02e7 | ||
|
|
695616a8f2 | ||
|
|
b3bdf8636a | ||
|
|
c62c080a4b | ||
|
|
c90ab3df5b | ||
|
|
21e21a1fa8 | ||
|
|
92ebdbfacc | ||
|
|
8dbabc8b43 | ||
|
|
c83dc79357 | ||
|
|
a53c1bfe8b | ||
|
|
6185b8fd0d | ||
|
|
ef002f6dfa | ||
|
|
9cdec99fa4 | ||
|
|
9393f84972 | ||
|
|
ceba006c60 | ||
|
|
e9e2053c64 | ||
|
|
bf013aea54 | ||
|
|
454df4872a | ||
|
|
ec315bf26d | ||
|
|
74c304097d | ||
|
|
ad1833a4d5 | ||
|
|
d65bb58317 | ||
|
|
8cf11f9208 | ||
|
|
73f00bd842 | ||
|
|
1b6545fc05 | ||
|
|
40725a76ab | ||
|
|
75f40fad95 | ||
|
|
b458300c02 | ||
|
|
6c6e74e8d1 | ||
|
|
4bab064ad6 | ||
|
|
3da2880aae | ||
|
|
c8d802bc1d | ||
|
|
c3a169319c | ||
|
|
72af950573 | ||
|
|
edae7a2b75 | ||
|
|
1fa48e7edb | ||
|
|
d76992efe6 | ||
|
|
87da4680c7 | ||
|
|
9cc7508b07 | ||
|
|
b258bc598e | ||
|
|
f25c0c60a8 | ||
|
|
f350bd31bd | ||
|
|
06f1699223 | ||
|
|
3e4d528859 | ||
|
|
b847f57382 | ||
|
|
2d7ad25031 | ||
|
|
d670cc13ac | ||
|
|
43699d039f | ||
|
|
9192b009e1 | ||
|
|
3fe85809b2 | ||
|
|
a4b79d6882 | ||
|
|
fc21e6eafa | ||
|
|
11e243a216 | ||
|
|
9f862dcc0e | ||
|
|
faf43d2c4b | ||
|
|
b0580b2df5 | ||
|
|
308903dc91 | ||
|
|
1c7fd67c39 | ||
|
|
c3ae704610 | ||
|
|
9f8e6c0634 | ||
|
|
aab88b411e | ||
|
|
867cf6b60a | ||
|
|
ed87114c5e | ||
|
|
213adb5f0d | ||
|
|
c5c10a003a | ||
|
|
e78205f071 | ||
|
|
ba7134c2a2 | ||
|
|
1eadaa4cda | ||
|
|
d93ce29b20 | ||
|
|
0cddb9e843 | ||
|
|
67e2860cc3 | ||
|
|
0cf9dd165e | ||
|
|
3aa567b672 | ||
|
|
fa1e3cb183 | ||
|
|
14845bf3f2 | ||
|
|
120328eb2b | ||
|
|
e222c0888c | ||
|
|
ec19dfc2f2 | ||
|
|
da45c26e7d | ||
|
|
c39a5fd8c0 | ||
|
|
fb57fe9da7 | ||
|
|
02496da4d2 | ||
|
|
eb1afec22b | ||
|
|
1619df97f8 | ||
|
|
c653a82619 | ||
|
|
2289618cea | ||
|
|
dc886118ba | ||
|
|
879b01004b | ||
|
|
86f3169e4b | ||
|
|
d5957b8c5f | ||
|
|
595eb3efea | ||
|
|
81e93448e3 | ||
|
|
0f9fe8adef | ||
|
|
56933067c0 | ||
|
|
0919f5bf9c | ||
|
|
b91d4411b5 | ||
|
|
15c6131f0e | ||
|
|
c2f2f25046 | ||
|
|
94ced66f87 | ||
|
|
ece2f913a1 | ||
|
|
2b2ada2037 | ||
|
|
1a4568175c | ||
|
|
0c8949e723 | ||
|
|
012966f6a2 | ||
|
|
82b1cca247 | ||
|
|
2976dc29d5 | ||
|
|
99d5b0dc8a | ||
|
|
d1eb768de6 | ||
|
|
5db8e42c69 | ||
|
|
c7efa81efe | ||
|
|
7d92698644 | ||
|
|
4b280a00db | ||
|
|
02b61b145a | ||
|
|
0a7514c47b | ||
|
|
4b1a53367f | ||
|
|
de3625d992 | ||
|
|
65331599ec | ||
|
|
74cd8cf75c | ||
|
|
07586e84ce | ||
|
|
ca97b4371b | ||
|
|
b742607c76 | ||
|
|
1399cc9482 | ||
|
|
7464e17e22 | ||
|
|
053bda26a4 | ||
|
|
93995cd742 | ||
|
|
202dfc9ebe | ||
|
|
23f378cd93 | ||
|
|
70c564dd2c | ||
|
|
9bea6afb80 | ||
|
|
20fb7a9ce0 | ||
|
|
7762bc2cad | ||
|
|
f407785f10 | ||
|
|
138e28fcbe | ||
|
|
38f6a5a40a | ||
|
|
b28f030874 | ||
|
|
d883ab278d | ||
|
|
40ce45c8e9 | ||
|
|
fa754ecaf8 | ||
|
|
c11557316d | ||
|
|
5bf28d3f90 | ||
|
|
c8625ce599 | ||
|
|
991fafb839 | ||
|
|
d7323f5f19 | ||
|
|
10662e4ca5 | ||
|
|
b73dfb08ae | ||
|
|
d8a46cffa5 | ||
|
|
3b3093c72e | ||
|
|
3d841a214c | ||
|
|
2cbbb29eb5 | ||
|
|
c0677ad8c5 | ||
|
|
098c5b0924 | ||
|
|
01ac9a71b7 | ||
|
|
ab8b1d39bd | ||
|
|
b22a8debf2 | ||
|
|
92a3c8bbd8 | ||
|
|
c71f287498 | ||
|
|
b7f8fbe7a0 | ||
|
|
1ca3f60f80 | ||
|
|
7a903361e6 | ||
|
|
4f6e72de55 | ||
|
|
a68c4e9434 | ||
|
|
798b90e0a5 | ||
|
|
cba902f22b | ||
|
|
8eb51e813f | ||
|
|
9ac3c1a394 | ||
|
|
5486ca3b4a | ||
|
|
90845974ea | ||
|
|
57fd817486 | ||
|
|
b322fa8f32 | ||
|
|
81d1e16d7b | ||
|
|
4c52d77aa5 | ||
|
|
523d5166ef | ||
|
|
cde95864b4 | ||
|
|
7354201b5d | ||
|
|
14971f88ee | ||
|
|
0b114ac5cd | ||
|
|
c06eabff24 | ||
|
|
b3ef2478f5 | ||
|
|
39eb9837e9 | ||
|
|
1a429b63c5 | ||
|
|
ae6ad20940 | ||
|
|
3e57b50066 | ||
|
|
dd38e399ca | ||
|
|
319b59500c | ||
|
|
3a79b71e80 | ||
|
|
0c0eab9247 | ||
|
|
114ddcff52 | ||
|
|
57339486d9 | ||
|
|
5f9b17d55b | ||
|
|
325b89e023 | ||
|
|
9ebc823975 | ||
|
|
5fdf6ef4f3 | ||
|
|
0792962591 | ||
|
|
f964374027 | ||
|
|
4352c0a737 | ||
|
|
a0bdcb30fd | ||
|
|
7e0a10c016 | ||
|
|
7fb6f82ab1 | ||
|
|
fdcc9c9e0e | ||
|
|
846f024e91 | ||
|
|
7e969f4e28 | ||
|
|
10a701308d | ||
|
|
e2bed86bfc | ||
|
|
487cdc85cd | ||
|
|
052bbecc3b | ||
|
|
c860b12b3d | ||
|
|
e227008331 | ||
|
|
72f3a784de | ||
|
|
31c9df665d | ||
|
|
dd240116b1 | ||
|
|
92ec139175 | ||
|
|
f076c43b90 | ||
|
|
98215e3dbd | ||
|
|
6197098541 | ||
|
|
34b3c52a28 | ||
|
|
caea68007e | ||
|
|
c1dd8faa29 | ||
|
|
95d065b3d7 | ||
|
|
2303da846b | ||
|
|
7246edcb4b | ||
|
|
dc2f24dbed | ||
|
|
4b793d5344 | ||
|
|
72dd45388f | ||
|
|
b76f78c6da | ||
|
|
30482a3599 | ||
|
|
b3f9571b2d | ||
|
|
0d5afe83a2 | ||
|
|
8b35c9a4b1 | ||
|
|
a5d8eec25f | ||
|
|
df6ec4f94c | ||
|
|
61ebee12ad | ||
|
|
105d63a697 | ||
|
|
07036ac48f | ||
|
|
4f6c8f7784 | ||
|
|
8e57a61aed | ||
|
|
8707005a97 | ||
|
|
cb024dd82d | ||
|
|
84046a6717 | ||
|
|
8bcaa50ba6 | ||
|
|
c433d29171 | ||
|
|
64d51b5290 | ||
|
|
6393b7704e | ||
|
|
0a2071b2f1 | ||
|
|
7981809f36 | ||
|
|
ed87a0b032 | ||
|
|
fc2630e66d | ||
|
|
ec14050890 | ||
|
|
4b17ea95fc | ||
|
|
1be3e5771a | ||
|
|
232cbbac5e | ||
|
|
dee204d2b2 | ||
|
|
b71e9eac51 | ||
|
|
f88636f47c | ||
|
|
8a301efe8b | ||
|
|
5bd393135f | ||
|
|
d550eac525 | ||
|
|
fea59adbbe | ||
|
|
dae0d0ff8b | ||
|
|
86d739cc85 | ||
|
|
9d99f4ce30 | ||
|
|
460a666234 | ||
|
|
ba9342cd4b | ||
|
|
c37eae3b56 | ||
|
|
61cc8d6c50 | ||
|
|
758ab5e581 | ||
|
|
f05ff37560 | ||
|
|
14354090f9 | ||
|
|
0185884ca8 | ||
|
|
5665403d66 | ||
|
|
46b271d75c | ||
|
|
854b958797 | ||
|
|
ff52b55a25 | ||
|
|
e755735ac2 | ||
|
|
69e20a3931 | ||
|
|
05da3db2ed | ||
|
|
6d89cc6c1d | ||
|
|
35d1bb1149 | ||
|
|
5921fd19fb | ||
|
|
fce06105f9 | ||
|
|
b01718aae7 | ||
|
|
9ce026e22e | ||
|
|
4796c8b7f9 | ||
|
|
2ee5127748 | ||
|
|
934e769513 | ||
|
|
249e6130fd | ||
|
|
8d265a8123 | ||
|
|
e6a540660d | ||
|
|
12bed8e8ad | ||
|
|
5305095832 | ||
|
|
e4b9cbcb80 | ||
|
|
d4198659b7 | ||
|
|
ef1edc7ee8 | ||
|
|
3ccfb74028 |
@@ -15,3 +15,5 @@ install_manifest.txt
|
|||||||
build*
|
build*
|
||||||
Build
|
Build
|
||||||
CMakeLists.txt.user
|
CMakeLists.txt.user
|
||||||
|
3rdparty/expat_2.2.6/
|
||||||
|
nbproject
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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/expat_config.h"
|
"${PROJECT_BINARY_DIR}/3rdparty/expat/simgear_expat_config.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(expat_sources
|
set(expat_sources
|
||||||
|
|||||||
Vendored
+2
@@ -18,6 +18,8 @@
|
|||||||
#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 */
|
||||||
|
|||||||
Vendored
+2
@@ -12,6 +12,8 @@
|
|||||||
#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"
|
||||||
|
|||||||
Vendored
+2
@@ -12,6 +12,8 @@
|
|||||||
#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"
|
||||||
|
|||||||
Vendored
+3
-3
@@ -24,7 +24,7 @@
|
|||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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);
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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...
|
||||||
|
|||||||
Vendored
+4
-4
@@ -24,7 +24,7 @@
|
|||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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) {
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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;
|
||||||
}
|
}
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(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).
|
||||||
*/
|
*/
|
||||||
#ifdef WINDOWS
|
#if defined(_WINDOWS) || defined(WINDOWS)
|
||||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
#else
|
#else
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#ifndef WINDOWS
|
#if !defined(_WINDOWS) && !defined(WINDOWS)
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <netinet/in.h>
|
# include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+65
-49
@@ -10,6 +10,15 @@ 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()
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +41,7 @@ include (GenerateExportHeader)
|
|||||||
|
|
||||||
# only relevant for building shared libs but let's set it regardless
|
# only relevant for building shared libs but let's set it regardless
|
||||||
set(CMAKE_OSX_RPATH 1)
|
set(CMAKE_OSX_RPATH 1)
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
|
||||||
# let's use & require C++11 - note these are only functional with CMake 3.1
|
# let's use & require C++11 - note these are only functional with CMake 3.1
|
||||||
# we do manual fallbacks for CMake 3.0 in the compilers section
|
# we do manual fallbacks for CMake 3.0 in the compilers section
|
||||||
@@ -39,17 +49,12 @@ 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 version versionFile)
|
file(READ simgear-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)
|
||||||
|
|
||||||
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
|
# add a dependency on the version file
|
||||||
# Cmake documentation says we must set this before calling project(), but
|
|
||||||
# it only seems to be picked up setting it /after/ the call to project()
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
|
|
||||||
|
|
||||||
# add a dependency on the versino file
|
|
||||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS version)
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS version)
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
|
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
|
||||||
@@ -129,10 +134,16 @@ option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support"
|
|||||||
option(USE_AEONWAVE "Set to ON to use AeonWave instead of OpenAL" ON)
|
option(USE_AEONWAVE "Set to ON to use AeonWave instead of OpenAL" ON)
|
||||||
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
||||||
option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON)
|
option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON)
|
||||||
option(ENABLE_SIMD "Enable SSE/SSE2 support for x86 compilers" ON)
|
option(ENABLE_SIMD "Enable SSE/SSE2 support for compilers" ON)
|
||||||
|
option(ENABLE_SIMD_CODE "Enable SSE/SSE2 support code for compilers" OFF)
|
||||||
option(ENABLE_OPENMP "Enable OpenMP compiler support" OFF)
|
option(ENABLE_OPENMP "Enable OpenMP compiler support" OFF)
|
||||||
|
|
||||||
|
if (NOT ENABLE_SIMD AND ENABLE_SIMD_CODE)
|
||||||
|
set(ENABLE_SIMD_CODE OFF)
|
||||||
|
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
|
||||||
@@ -149,7 +160,7 @@ endif()
|
|||||||
|
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} DIRECTORY)
|
||||||
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)
|
||||||
@@ -160,6 +171,11 @@ 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)
|
||||||
@@ -172,15 +188,17 @@ 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} EQUAL "00")
|
if (${MSVC_VERSION_MINOR} GREATER_EQUAL "20")
|
||||||
set( OSG_MSVC ${OSG_MSVC}140 )
|
set( OSG_MSVC ${OSG_MSVC}142 )
|
||||||
else ()
|
elseif (${MSVC_VERSION_MINOR} GREATER_EQUAL "10")
|
||||||
set( OSG_MSVC ${OSG_MSVC}141 )
|
set( OSG_MSVC ${OSG_MSVC}141 )
|
||||||
|
else ()
|
||||||
|
set( OSG_MSVC ${OSG_MSVC}140 )
|
||||||
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/15/17 is required")
|
message(FATAL_ERROR "Visual Studio 2013 or higher is required")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CMAKE_CL_64)
|
if (CMAKE_CL_64)
|
||||||
@@ -197,7 +215,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} PATH)
|
get_filename_component(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} DIRECTORY)
|
||||||
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()
|
||||||
@@ -215,7 +233,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")
|
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION -DBOOST_NO_STDLIB_CONFIG")
|
||||||
include(BoostTestTargets)
|
include(BoostTestTargets)
|
||||||
|
|
||||||
if(SIMGEAR_HEADLESS)
|
if(SIMGEAR_HEADLESS)
|
||||||
@@ -270,9 +288,6 @@ 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)
|
||||||
@@ -291,11 +306,10 @@ 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}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
SET(ENV{PKG_CONFIG_PATH} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/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")
|
||||||
@@ -409,16 +423,8 @@ 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")
|
if (X86 OR X86_64)
|
||||||
set(CMAKE_C_FLAGS
|
set(SIMD_COMPILER_FLAGS "-msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
"${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)
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
|
||||||
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
|
||||||
@@ -427,6 +433,10 @@ 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)
|
||||||
@@ -437,17 +447,11 @@ 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++")
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
# override CMake default RelWithDebInfo flags.
|
||||||
set(CMAKE_C_FLAGS
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
|
||||||
"${CMAKE_C_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
|
||||||
set(CMAKE_CXX_FLAGS
|
|
||||||
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
|
set(SIMD_COMPILER_FLAGS "-msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
elseif (ENABLE_SIMD)
|
|
||||||
if (X86 OR X86_64)
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_OPENMP)
|
if (ENABLE_OPENMP)
|
||||||
@@ -479,14 +483,8 @@ 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)
|
||||||
@@ -510,6 +508,20 @@ 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}")
|
||||||
@@ -520,6 +532,10 @@ 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
|
||||||
|
|||||||
@@ -46,11 +46,17 @@ 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}'; want >=103400) ")
|
"(found: '${Boost_VERSION_MACRO}'; want >=103400) ")
|
||||||
if(ENABLE_TESTS)
|
if(ENABLE_TESTS)
|
||||||
message(FATAL_ERROR
|
message(FATAL_ERROR
|
||||||
${_shared_msg}
|
${_shared_msg}
|
||||||
@@ -66,7 +72,7 @@ endif()
|
|||||||
include(GetForceIncludeDefinitions)
|
include(GetForceIncludeDefinitions)
|
||||||
include(CopyResourcesToBuildTree)
|
include(CopyResourcesToBuildTree)
|
||||||
|
|
||||||
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}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)
|
||||||
@@ -80,7 +86,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
|||||||
set(_boostConfig "BoostTestTargetsDynamic.h")
|
set(_boostConfig "BoostTestTargetsDynamic.h")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
|
||||||
configure_file("${_moddir}/${_boostConfig}"
|
configure_file("${_moddir}/${_boostConfig}"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
|
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
|
||||||
COPYONLY)
|
COPYONLY)
|
||||||
@@ -129,7 +135,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}0" LESS "1034000")
|
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
|
||||||
|
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
@@ -221,7 +227,7 @@ function(add_boost_test _name)
|
|||||||
set(_test_command ${_target_name})
|
set(_test_command ${_target_name})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" ))
|
if(TESTS AND ( "${Boost_VERSION_MACRO}" VERSION_GREATER "103799" ))
|
||||||
foreach(_test ${TESTS})
|
foreach(_test ${TESTS})
|
||||||
add_test(
|
add_test(
|
||||||
${_name}-${_test}
|
${_name}-${_test}
|
||||||
|
|||||||
@@ -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}" PATH)
|
get_filename_component(_path "${_path}" DIRECTORY)
|
||||||
|
|
||||||
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}}" PATH)
|
get_filename_component(_path${_config} "${_path${_config}}" DIRECTORY)
|
||||||
add_custom_command(TARGET ${_target}
|
add_custom_command(TARGET ${_target}
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND
|
COMMAND
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# 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()
|
||||||
@@ -18,6 +18,16 @@ 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@)
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
2020.2.1
|
||||||
+27
-11
@@ -6,6 +6,7 @@ foreach( mylibfolder
|
|||||||
bvh
|
bvh
|
||||||
debug
|
debug
|
||||||
embedded_resources
|
embedded_resources
|
||||||
|
emesary
|
||||||
ephemeris
|
ephemeris
|
||||||
io
|
io
|
||||||
magvar
|
magvar
|
||||||
@@ -64,6 +65,9 @@ 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")
|
||||||
|
|
||||||
@@ -114,11 +118,22 @@ 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}
|
||||||
@@ -143,9 +158,10 @@ 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
|
target_link_libraries(SimGearCore PRIVATE
|
||||||
${ZLIB_LIBRARY}
|
|
||||||
${RT_LIBRARY}
|
${RT_LIBRARY}
|
||||||
${DL_LIBRARY}
|
${DL_LIBRARY}
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
@@ -154,29 +170,29 @@ target_link_libraries(SimGearCore
|
|||||||
${WINSOCK_LIBRARY})
|
${WINSOCK_LIBRARY})
|
||||||
|
|
||||||
if(SYSTEM_EXPAT)
|
if(SYSTEM_EXPAT)
|
||||||
target_link_libraries(SimGearCore
|
target_link_libraries(SimGearCore PRIVATE ${EXPAT_LIBRARIES})
|
||||||
${EXPAT_LIBRARIES})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_DNS AND SYSTEM_UDNS)
|
if(ENABLE_DNS AND SYSTEM_UDNS)
|
||||||
target_link_libraries(SimGearCore
|
target_link_libraries(SimGearCore PRIVATE ${UDNS_LIBRARIES})
|
||||||
${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
|
target_link_libraries(SimGearScene PUBLIC
|
||||||
SimGearCore
|
SimGearCore
|
||||||
${ZLIB_LIBRARY}
|
|
||||||
${OPENSCENEGRAPH_LIBRARIES}
|
${OPENSCENEGRAPH_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(SimGearScene PRIVATE
|
||||||
|
${ZLIB_LIBRARY}
|
||||||
${OPENAL_LIBRARY}
|
${OPENAL_LIBRARY}
|
||||||
${OPENGL_LIBRARY}
|
${OPENGL_LIBRARY}
|
||||||
${JPEG_LIBRARY})
|
${JPEG_LIBRARY})
|
||||||
|
|
||||||
if(ENABLE_GDAL)
|
if(ENABLE_GDAL)
|
||||||
target_link_libraries(SimGearScene
|
target_link_libraries(SimGearScene PRIVATE ${GDAL_LIBRARIES})
|
||||||
${GDAL_LIBRARIES})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# only actually needed by canvas/KeyboardEvent.cxx
|
# only actually needed by canvas/KeyboardEvent.cxx
|
||||||
@@ -188,5 +204,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_DIR}")
|
APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIRS}")
|
||||||
endif(ENABLE_RTI)
|
endif(ENABLE_RTI)
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> scopeLock(_mutex);
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
_requestList.push_back(request);
|
_requestList.push_back(request);
|
||||||
}
|
}
|
||||||
_Request _pop()
|
_Request _pop()
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> scopeLock(_mutex);
|
std::lock_guard<std::mutex> 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:
|
||||||
SGMutex _mutex;
|
std::mutex _mutex;
|
||||||
_RequestList _requestList;
|
_RequestList _requestList;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ struct BVHPager::_PrivateData : protected SGThread {
|
|||||||
}
|
}
|
||||||
void _push(const _Request& request)
|
void _push(const _Request& request)
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> scopeLock(_mutex);
|
std::lock_guard<std::mutex> 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()
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> scopeLock(_mutex);
|
std::lock_guard<std::mutex> 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:
|
||||||
SGMutex _mutex;
|
std::mutex _mutex;
|
||||||
SGWaitCondition _waitCondition;
|
SGWaitCondition _waitCondition;
|
||||||
_RequestList _requestList;
|
_RequestList _requestList;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,42 +28,39 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
class CanvasMgr:
|
class CanvasMgr : public PropertyBasedMgr
|
||||||
public PropertyBasedMgr
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/**
|
||||||
|
* @param node Root node of branch used to control canvasses
|
||||||
|
*/
|
||||||
|
CanvasMgr(SGPropertyNode_ptr node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node Root node of branch used to control canvasses
|
* Create a new canvas
|
||||||
*/
|
*
|
||||||
CanvasMgr(SGPropertyNode_ptr node);
|
* @param name Name of the new canvas
|
||||||
|
*/
|
||||||
|
CanvasPtr createCanvas(const std::string& name = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new canvas
|
* Get ::Canvas by index
|
||||||
*
|
*
|
||||||
* @param name Name of the new canvas
|
* @param index Index of texture node in /canvas/by-index/
|
||||||
*/
|
*/
|
||||||
CanvasPtr createCanvas(const std::string& name = "");
|
CanvasPtr getCanvas(size_t index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get ::Canvas by index
|
* Get ::Canvas by name
|
||||||
*
|
*
|
||||||
* @param index Index of texture node in /canvas/by-index/
|
* @param name Value of child node "name" in
|
||||||
*/
|
* /canvas/by-index/texture[i]/name
|
||||||
CanvasPtr getCanvas(size_t index) const;
|
*/
|
||||||
|
CanvasPtr getCanvas(const std::string& name) const;
|
||||||
|
|
||||||
/**
|
protected:
|
||||||
* Get ::Canvas by name
|
void elementCreated(PropertyBasedElementPtr element) override;
|
||||||
*
|
};
|
||||||
* @param name Value of child node "name" in
|
|
||||||
* /canvas/by-index/texture[i]/name
|
|
||||||
*/
|
|
||||||
CanvasPtr getCanvas(const std::string& name) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void elementCreated(PropertyBasedElementPtr element) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
} // namespace simgear
|
} // namespace simgear
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ namespace canvas
|
|||||||
Element* parent = 0 );
|
Element* parent = 0 );
|
||||||
virtual ~Window();
|
virtual ~Window();
|
||||||
|
|
||||||
virtual void update(double delta_time_sec);
|
void update(double delta_time_sec) override;
|
||||||
virtual void valueChanged(SGPropertyNode* node);
|
void valueChanged(SGPropertyNode* node) override;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
virtual void setVisible(bool visible);
|
void setVisible(bool visible) override;
|
||||||
virtual bool isVisible() const;
|
bool isVisible() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|||||||
@@ -250,10 +250,16 @@ 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->setTextureSize(_size_x, _size_y);
|
texture->setImage(image);
|
||||||
texture->setInternalFormat(GL_RGBA);
|
texture->setUnRefImageDataAfterApply(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSampling();
|
updateSampling();
|
||||||
|
|||||||
@@ -31,6 +31,11 @@
|
|||||||
// FreeBSD
|
// FreeBSD
|
||||||
#define VG_API_FREEBSD
|
#define VG_API_FREEBSD
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
|
||||||
|
// FreeBSD
|
||||||
|
#define VG_API_OPENBSD
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Unsupported system
|
// Unsupported system
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__)
|
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
|
||||||
# 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)
|
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD) || defined(VG_API_OPENBSD)
|
||||||
#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)
|
||||||
|
|||||||
@@ -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;
|
SHuint8 *newSegs, *newData=0;
|
||||||
void *userData[4];
|
void *userData[4];
|
||||||
SHint segment1, segment2;
|
SHint segment1, segment2;
|
||||||
SHint segindex, s,d,i;
|
SHint segindex, s,d,i;
|
||||||
|
|||||||
@@ -26,11 +26,9 @@
|
|||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osgText/Font>
|
#include <osgText/Font>
|
||||||
|
|
||||||
#include <boost/function.hpp>
|
#include <functional>
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <boost/weak_ptr.hpp>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -62,8 +60,8 @@ namespace canvas
|
|||||||
|
|
||||||
#define SG_FWD_DECL(name)\
|
#define SG_FWD_DECL(name)\
|
||||||
class name;\
|
class name;\
|
||||||
typedef boost::shared_ptr<name> name##Ptr;\
|
typedef std::shared_ptr<name> name##Ptr;\
|
||||||
typedef boost::weak_ptr<name> name##WeakPtr;
|
typedef std::weak_ptr<name> name##WeakPtr;
|
||||||
|
|
||||||
SG_FWD_DECL(Placement)
|
SG_FWD_DECL(Placement)
|
||||||
SG_FWD_DECL(SystemAdapter)
|
SG_FWD_DECL(SystemAdapter)
|
||||||
@@ -85,10 +83,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 boost::function<Placements( SGPropertyNode*,
|
typedef std::function<Placements( SGPropertyNode*,
|
||||||
CanvasPtr )> PlacementFactory;
|
CanvasPtr )> PlacementFactory;
|
||||||
|
|
||||||
typedef boost::function<void(const EventPtr&)> EventListener;
|
typedef std::function<void(const EventPtr&)> EventListener;
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
} // namespace simgear
|
} // namespace simgear
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
#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;
|
||||||
@@ -62,9 +59,9 @@ namespace canvas
|
|||||||
OSGUserData(ElementPtr element);
|
OSGUserData(ElementPtr element);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::function<bool(Element&, const SGPropertyNode*)>
|
typedef std::function<bool(Element&, const SGPropertyNode*)>
|
||||||
StyleSetterFunc;
|
StyleSetterFunc;
|
||||||
typedef boost::function<void(Element&, const SGPropertyNode*)>
|
typedef std::function<void(Element&, const SGPropertyNode*)>
|
||||||
StyleSetterFuncUnchecked;
|
StyleSetterFuncUnchecked;
|
||||||
struct StyleSetter:
|
struct StyleSetter:
|
||||||
public SGReferenced
|
public SGReferenced
|
||||||
@@ -319,7 +316,7 @@ namespace canvas
|
|||||||
StyleSetter
|
StyleSetter
|
||||||
addStyle( const std::string& name,
|
addStyle( const std::string& name,
|
||||||
const std::string& type,
|
const std::string& type,
|
||||||
const boost::function<void (Derived&, T2)>& setter,
|
const std::function<void (Derived&, T2)>& setter,
|
||||||
bool inheritable = true )
|
bool inheritable = true )
|
||||||
{
|
{
|
||||||
StyleInfo& style_info = _style_setters[ name ];
|
StyleInfo& style_info = _style_setters[ name ];
|
||||||
@@ -345,13 +342,10 @@ namespace canvas
|
|||||||
if( style->func )
|
if( style->func )
|
||||||
style = style->next = new StyleSetter;
|
style = style->next = new StyleSetter;
|
||||||
|
|
||||||
style->func = boost::bind
|
style->func = std::bind(&type_match<Derived>::call,
|
||||||
(
|
std::placeholders::_1,
|
||||||
&type_match<Derived>::call,
|
std::placeholders::_2,
|
||||||
_1,
|
bindStyleSetter<T1>(name, setter));
|
||||||
_2,
|
|
||||||
bindStyleSetter<T1>(name, setter)
|
|
||||||
);
|
|
||||||
return *style;
|
return *style;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +357,7 @@ namespace canvas
|
|||||||
StyleSetter
|
StyleSetter
|
||||||
addStyle( const std::string& name,
|
addStyle( const std::string& name,
|
||||||
const std::string& type,
|
const std::string& type,
|
||||||
const boost::function<void (Derived&, T)>& setter,
|
const std::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);
|
||||||
@@ -384,7 +378,7 @@ namespace canvas
|
|||||||
(
|
(
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
boost::function<void (Derived&, T)>(setter),
|
std::function<void (Derived&, T)>(setter),
|
||||||
inheritable
|
inheritable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -405,7 +399,7 @@ namespace canvas
|
|||||||
(
|
(
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
boost::function<void (Derived&, T2)>(setter),
|
std::function<void (Derived&, T2)>(setter),
|
||||||
inheritable
|
inheritable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -424,7 +418,7 @@ namespace canvas
|
|||||||
(
|
(
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
boost::function<void (Derived&, const std::string&)>(setter),
|
std::function<void (Derived&, const std::string&)>(setter),
|
||||||
inheritable
|
inheritable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -487,7 +481,7 @@ namespace canvas
|
|||||||
StyleSetter
|
StyleSetter
|
||||||
addStyle( const std::string& name,
|
addStyle( const std::string& name,
|
||||||
const std::string& type,
|
const std::string& type,
|
||||||
const boost::function<void (Other&, T2)>& setter,
|
const std::function<void (Other&, T2)>& setter,
|
||||||
OtherRef Derived::*instance_ref,
|
OtherRef Derived::*instance_ref,
|
||||||
bool inheritable = true )
|
bool inheritable = true )
|
||||||
{
|
{
|
||||||
@@ -517,7 +511,7 @@ namespace canvas
|
|||||||
(
|
(
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
boost::function<void (Other&, const std::string&)>(setter),
|
std::function<void (Other&, const std::string&)>(setter),
|
||||||
instance_ref,
|
instance_ref,
|
||||||
inheritable
|
inheritable
|
||||||
);
|
);
|
||||||
@@ -525,44 +519,37 @@ namespace canvas
|
|||||||
|
|
||||||
template<typename T, class Derived, class Other, class OtherRef>
|
template<typename T, class Derived, class Other, class OtherRef>
|
||||||
static
|
static
|
||||||
boost::function<void (Derived&, T)>
|
std::function<void (Derived&, T)>
|
||||||
bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
|
bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
|
||||||
{
|
{
|
||||||
return boost::bind(setter, boost::bind(instance_ref, _1), _2);
|
return std::bind(setter,
|
||||||
|
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
|
||||||
boost::function<void (Derived&, T)>
|
std::function<void (Derived&, T)>
|
||||||
bindOther( const boost::function<void (Other&, T)>& setter,
|
bindOther( const std::function<void (Other&, T)>& setter,
|
||||||
OtherRef Derived::*instance_ref )
|
OtherRef Derived::*instance_ref )
|
||||||
{
|
{
|
||||||
return boost::bind
|
return std::bind(setter,
|
||||||
(
|
std::bind(&reference_from_pointer<Other, OtherRef>,
|
||||||
setter,
|
std::bind(instance_ref, std::placeholders::_1)),
|
||||||
boost::bind
|
std::placeholders::_2);
|
||||||
(
|
|
||||||
&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 boost::function<void (Derived&, T2)>& setter )
|
const std::function<void (Derived&, T2)>& setter )
|
||||||
{
|
{
|
||||||
return boost::bind
|
return std::bind(setter,
|
||||||
(
|
// We will only call setters with Derived instances, so we can safely
|
||||||
setter,
|
// cast here.
|
||||||
// We will only call setters with Derived instances, so we can safely
|
std::bind(&derived_cast<Derived>, std::placeholders::_1),
|
||||||
// cast here.
|
std::bind(&getValue<T1>, std::placeholders::_2));
|
||||||
boost::bind(&derived_cast<Derived>, _1),
|
|
||||||
boost::bind(&getValue<T1>, _2)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStyleEmpty(const SGPropertyNode* child) const;
|
bool isStyleEmpty(const SGPropertyNode* child) const;
|
||||||
|
|||||||
@@ -838,5 +838,143 @@ 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
|
||||||
|
|||||||
@@ -101,6 +101,28 @@ 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
|
||||||
{
|
{
|
||||||
@@ -125,6 +147,8 @@ 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;
|
||||||
|
|||||||
@@ -53,26 +53,31 @@ 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;
|
SGVec2i sizeForWidth(int w) const;
|
||||||
|
|
||||||
osg::BoundingBox
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
|
||||||
computeBound()
|
|
||||||
#else
|
#else
|
||||||
computeBoundingBox()
|
TextLine nearestLine(float pos_y);
|
||||||
|
SGVec2i sizeForWidth(int w);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
|
osg::BoundingBox computeBound() const override;
|
||||||
|
#else
|
||||||
|
osg::BoundingBox computeBoundingBox() const override;
|
||||||
#endif
|
#endif
|
||||||
const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class TextLine;
|
friend class TextLine;
|
||||||
|
|
||||||
canvas::Text *_text_element;
|
canvas::Text *_text_element;
|
||||||
|
|
||||||
void computePositions(unsigned int contextID) const override;
|
#if OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
};
|
void computePositions(unsigned int contextID) const override;
|
||||||
|
#else
|
||||||
|
void computePositionsImplementation() override;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class TextLine
|
class TextLine
|
||||||
{
|
{
|
||||||
@@ -122,6 +127,7 @@ 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);
|
||||||
@@ -133,6 +139,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -161,34 +170,40 @@ namespace canvas
|
|||||||
|
|
||||||
if( empty() )
|
if( empty() )
|
||||||
return pos;
|
return pos;
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
|
||||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6)
|
||||||
|
// TODO: need 3.5.6 version of this.
|
||||||
#else
|
#else
|
||||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||||
|
#else
|
||||||
|
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||||
|
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||||
#endif
|
#endif
|
||||||
size_t global_i = _begin + i;
|
|
||||||
|
|
||||||
if( global_i == _begin )
|
size_t global_i = _begin + i;
|
||||||
// before first character of line
|
|
||||||
pos.x() = coords[_begin * 4].x();
|
|
||||||
else if( global_i == _end )
|
|
||||||
// After Last character of line
|
|
||||||
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float prev_l = coords[(global_i - 1) * 4].x(),
|
|
||||||
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
|
||||||
cur_l = coords[global_i * 4].x();
|
|
||||||
|
|
||||||
if( prev_l == prev_r )
|
if (global_i == _begin)
|
||||||
// If previous character width is zero set to begin of next character
|
// before first character of line
|
||||||
// (Happens eg. with spaces)
|
pos.x() = coords[_begin * 4].x();
|
||||||
pos.x() = cur_l;
|
else if (global_i == _end)
|
||||||
|
// After Last character of line
|
||||||
|
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
||||||
else
|
else
|
||||||
// position at center between characters
|
{
|
||||||
pos.x() = 0.5 * (prev_r + cur_l);
|
float prev_l = coords[(global_i - 1) * 4].x(),
|
||||||
}
|
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
||||||
|
cur_l = coords[global_i * 4].x();
|
||||||
|
|
||||||
|
if (prev_l == prev_r)
|
||||||
|
// If previous character width is zero set to begin of next character
|
||||||
|
// (Happens eg. with spaces)
|
||||||
|
pos.x() = cur_l;
|
||||||
|
else
|
||||||
|
// position at center between characters
|
||||||
|
pos.x() = 0.5 * (prev_r + cur_l);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@@ -196,17 +211,22 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::Vec2 TextLine::nearestCursor(float x) const
|
osg::Vec2 TextLine::nearestCursor(float x) const
|
||||||
{
|
{
|
||||||
if( empty() )
|
if (empty())
|
||||||
return cursorPos(0);
|
return cursorPos(0);
|
||||||
|
|
||||||
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6)
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
// TODO: need 3.5.7 version of this.
|
||||||
|
return cursorPos(0);
|
||||||
|
#else
|
||||||
|
#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
|
||||||
|
|
||||||
|
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();
|
||||||
@@ -225,6 +245,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
return cursorPos(i - _begin);
|
return cursorPos(i - _begin);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -303,9 +324,16 @@ 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);
|
||||||
|
|
||||||
@@ -327,12 +355,21 @@ 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);
|
||||||
|
|
||||||
@@ -612,19 +649,16 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::BoundingBox
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
Text::TextOSG::computeBound()
|
osg::BoundingBox Text::TextOSG::computeBound() const
|
||||||
#else
|
#else
|
||||||
Text::TextOSG::computeBoundingBox()
|
osg::BoundingBox Text::TextOSG::computeBoundingBox() const
|
||||||
#endif
|
#endif
|
||||||
const
|
|
||||||
{
|
{
|
||||||
osg::BoundingBox bb =
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
osgText::Text::computeBound();
|
osg::BoundingBox bb = osgText::Text::computeBound();
|
||||||
#else
|
#else
|
||||||
osgText::Text::computeBoundingBox();
|
osg::BoundingBox bb = osgText::Text::computeBoundingBox();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||||
@@ -640,7 +674,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 )
|
||||||
@@ -710,6 +744,14 @@ 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";
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace canvas
|
|||||||
int stretch,
|
int stretch,
|
||||||
uint8_t alignment )
|
uint8_t alignment )
|
||||||
{
|
{
|
||||||
ItemData item_data = {0};
|
ItemData item_data = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#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
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool NasalWidget::hasHeightForWidth() const
|
bool NasalWidget::hasHeightForWidth() const
|
||||||
{
|
{
|
||||||
return !_height_for_width.empty() || !_min_height_for_width.empty();
|
return _height_for_width || _min_height_for_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -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.empty() )
|
if( !hfw )
|
||||||
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.empty()
|
return callHeightForWidthFunc( _height_for_width
|
||||||
? _min_height_for_width
|
? _height_for_width
|
||||||
: _height_for_width, w );
|
: _min_height_for_width, w );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
int NasalWidget::minimumHeightForWidthImpl(int w) const
|
int NasalWidget::minimumHeightForWidthImpl(int w) const
|
||||||
{
|
{
|
||||||
return callHeightForWidthFunc( _min_height_for_width.empty()
|
return callHeightForWidthFunc( _min_height_for_width
|
||||||
? _height_for_width
|
? _min_height_for_width
|
||||||
: _min_height_for_width, w );
|
: _height_for_width, w );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef boost::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
|
typedef std::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
|
||||||
typedef boost::function<int (nasal::Me, int)> HeightForWidthFunc;
|
typedef std::function<int (nasal::Me, int)> HeightForWidthFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -22,13 +22,12 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
@@ -36,7 +35,7 @@ namespace simgear
|
|||||||
class BufferedLogCallback::BufferedLogCallbackPrivate
|
class BufferedLogCallback::BufferedLogCallbackPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SGMutex m_mutex;
|
std::mutex 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;
|
||||||
@@ -52,7 +51,7 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
|
|||||||
|
|
||||||
BufferedLogCallback::~BufferedLogCallback()
|
BufferedLogCallback::~BufferedLogCallback()
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(unsigned char* msg, d->m_buffer) {
|
for (auto msg : d->m_buffer) {
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +73,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());
|
||||||
}
|
}
|
||||||
|
|
||||||
SGGuard<SGMutex> g(d->m_mutex);
|
std::lock_guard<std::mutex> g(d->m_mutex);
|
||||||
d->m_buffer.push_back(msg);
|
d->m_buffer.push_back(msg);
|
||||||
d->m_stamp++;
|
d->m_stamp++;
|
||||||
}
|
}
|
||||||
@@ -86,7 +85,7 @@ unsigned int BufferedLogCallback::stamp() const
|
|||||||
|
|
||||||
unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput)
|
unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput)
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> g(d->m_mutex);
|
std::lock_guard<std::mutex> 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));
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory> // for std::unique_ptr
|
#include <memory> // for std::unique_ptr
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/LogCallback.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
|
||||||
include (SimGearComponent)
|
include (SimGearComponent)
|
||||||
|
|
||||||
set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx)
|
set(HEADERS debug_types.h
|
||||||
set(SOURCES logstream.cxx BufferedLogCallback.cxx)
|
logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx
|
||||||
|
LogCallback.hxx LogEntry.hxx)
|
||||||
|
set(SOURCES logstream.cxx BufferedLogCallback.cxx
|
||||||
|
LogCallback.cxx LogEntry.cxx)
|
||||||
|
|
||||||
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
// 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
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// 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
|
||||||
@@ -2,14 +2,13 @@
|
|||||||
|
|
||||||
#include <osg/Notify>
|
#include <osg/Notify>
|
||||||
|
|
||||||
using namespace osg;
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,
|
||||||
* and so we can display a GUI console with renderer issues, especially
|
* and so we can display a GUI console with renderer issues, especially
|
||||||
* shader compilation warnings and errors.
|
* shader compilation warnings and errors.
|
||||||
*/
|
*/
|
||||||
class NotifyLogger : public osg::NotifyHandler
|
class NotifyLogger : public osg::NotifyHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -22,24 +21,33 @@ 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);
|
||||||
int* trigger_segfault = 0;
|
#ifndef DEBUG
|
||||||
*trigger_segfault = 0;
|
throw new std::string(message);
|
||||||
|
//int* trigger_segfault = 0;
|
||||||
|
//*trigger_segfault = 0;
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SG_LOG(SG_GL, translateSeverity(severity), message);
|
char*tmessage = strdup(message);
|
||||||
|
char*lf = strrchr(tmessage, '\n');
|
||||||
|
if (lf)
|
||||||
|
*lf = 0;
|
||||||
|
|
||||||
|
SG_LOG(SG_OSG, translateSeverity(severity), tmessage);
|
||||||
|
free(tmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sgDebugPriority translateSeverity(osg::NotifySeverity severity) {
|
sgDebugPriority translateSeverity(osg::NotifySeverity severity) {
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case osg::ALWAYS:
|
case osg::ALWAYS:
|
||||||
case osg::FATAL: return SG_ALERT;
|
case osg::FATAL: return SG_ALERT;
|
||||||
case osg::WARN: return SG_WARN;
|
case osg::WARN: return SG_WARN;
|
||||||
case osg::NOTICE:
|
case osg::NOTICE:
|
||||||
case osg::INFO: return SG_INFO;
|
case osg::INFO: return SG_INFO;
|
||||||
case osg::DEBUG_FP:
|
case osg::DEBUG_FP:
|
||||||
case osg::DEBUG_INFO: return SG_DEBUG;
|
case osg::DEBUG_INFO: return SG_DEBUG;
|
||||||
default: return SG_ALERT;
|
default: return SG_ALERT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+16
-10
@@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
/** \file debug_types.h
|
/** \file debug_types.h
|
||||||
* Define the various logging classes and priorities
|
* Define the various logging classes and priorities
|
||||||
*/
|
*/
|
||||||
@@ -35,7 +37,10 @@ typedef enum {
|
|||||||
SG_TERRASYNC = 0x01000000,
|
SG_TERRASYNC = 0x01000000,
|
||||||
SG_PARTICLES = 0x02000000,
|
SG_PARTICLES = 0x02000000,
|
||||||
SG_HEADLESS = 0x04000000,
|
SG_HEADLESS = 0x04000000,
|
||||||
SG_UNDEFD = 0x08000000, // For range checking
|
// 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.
|
||||||
|
SG_OSG = 0x08000000,
|
||||||
|
SG_UNDEFD = 0x10000000, // For range checking
|
||||||
|
|
||||||
SG_ALL = 0xFFFFFFFF
|
SG_ALL = 0xFFFFFFFF
|
||||||
} sgDebugClass;
|
} sgDebugClass;
|
||||||
@@ -49,16 +54,17 @@ typedef enum {
|
|||||||
* appended, or the priority Nasal reports to compiled code will change.
|
* appended, or the priority Nasal reports to compiled code will change.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SG_BULK = 1, // For frequent messages
|
SG_BULK = 1, // For frequent messages
|
||||||
SG_DEBUG, // Less frequent debug type messages
|
SG_DEBUG, // Less frequent debug type messages
|
||||||
SG_INFO, // Informatory messages
|
SG_INFO, // Informatory messages
|
||||||
SG_WARN, // Possible impending problem
|
SG_WARN, // Possible impending problem
|
||||||
SG_ALERT, // Very possible impending problem
|
SG_ALERT, // Very possible impending problem
|
||||||
SG_POPUP, // Severe enough to alert using a pop-up window
|
SG_POPUP, // Severe enough to alert using a pop-up window
|
||||||
// SG_EXIT, // Problem (no core)
|
// SG_EXIT, // Problem (no core)
|
||||||
// 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
|
||||||
} sgDebugPriority;
|
|
||||||
|
|
||||||
|
SG_MANDATORY_INFO // information, but should always be shown
|
||||||
|
} sgDebugPriority;
|
||||||
|
|||||||
+160
-141
@@ -24,20 +24,22 @@
|
|||||||
|
|
||||||
#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
|
||||||
@@ -46,84 +48,55 @@
|
|||||||
#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();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(sgDebugClass c, sgDebugPriority p,
|
void operator()(sgDebugClass c, sgDebugPriority p,
|
||||||
const char* file, int line, const std::string& message)
|
const char* file, int line, const std::string& message) override
|
||||||
{
|
{
|
||||||
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;
|
||||||
@@ -132,9 +105,12 @@ 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)
|
||||||
@@ -144,12 +120,19 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual void operator()(sgDebugClass c, sgDebugPriority p,
|
void operator()(sgDebugClass c, sgDebugPriority p,
|
||||||
const char* file, int line, const std::string& aMessage)
|
const char* file, int line, const std::string& aMessage) override
|
||||||
{
|
{
|
||||||
if (!shouldLog(c, p)) return;
|
if (!shouldLog(c, p)) return;
|
||||||
|
//fprintf(stderr, "%s\n", aMessage.c_str());
|
||||||
|
|
||||||
fprintf(stderr, "%s\n", aMessage.c_str());
|
if (file && line > 0) {
|
||||||
|
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);
|
||||||
@@ -167,8 +150,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(sgDebugClass c, sgDebugPriority p,
|
void operator()(sgDebugClass c, sgDebugPriority p,
|
||||||
const char* file, int line, const std::string& aMessage)
|
const char* file, int line, const std::string& aMessage) override
|
||||||
{
|
{
|
||||||
if (!shouldLog(c, p)) return;
|
if (!shouldLog(c, p)) return;
|
||||||
|
|
||||||
@@ -183,28 +166,6 @@ 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.
|
||||||
@@ -328,22 +289,34 @@ 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)
|
|
||||||
m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
|
#if defined (SG_WINDOWS)
|
||||||
m_consoleCallbacks.push_back(m_callbacks.back());
|
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_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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMutex m_lock;
|
std::mutex m_lock;
|
||||||
SGBlockingQueue<LogEntry> m_entries;
|
SGBlockingQueue<simgear::LogEntry> m_entries;
|
||||||
|
|
||||||
// log entries posted during startup
|
// log entries posted during startup
|
||||||
std::vector<LogEntry> m_startupEntries;
|
std::vector<simgear::LogEntry> m_startupEntries;
|
||||||
bool m_startupLogging = false;
|
bool m_startupLogging = false;
|
||||||
|
|
||||||
typedef std::vector<simgear::LogCallback*> CallbackVec;
|
typedef std::vector<simgear::LogCallback*> CallbackVec;
|
||||||
@@ -361,13 +334,16 @@ 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()
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> g(m_lock);
|
std::lock_guard<std::mutex> g(m_lock);
|
||||||
if (m_isRunning) return;
|
if (m_isRunning) return;
|
||||||
m_isRunning = true;
|
m_isRunning = true;
|
||||||
start();
|
start();
|
||||||
@@ -379,44 +355,54 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_startupLogging = on;
|
{
|
||||||
|
std::lock_guard<std::mutex> g(m_lock);
|
||||||
|
m_startupLogging = on;
|
||||||
|
clearStartupEntriesLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearStartupEntriesLocked()
|
||||||
|
{
|
||||||
m_startupEntries.clear();
|
m_startupEntries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void run()
|
void run() override
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
LogEntry entry(m_entries.pop());
|
simgear::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) && !strcmp(entry.file, "done")) {
|
if ((entry.debugClass == SG_NONE) && entry.file && !strcmp(entry.file, "done")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
if (m_startupLogging) {
|
std::lock_guard<std::mutex> g(m_lock);
|
||||||
// save to the startup list for not-yet-added callbacks to
|
if (m_startupLogging) {
|
||||||
// pull down on startup
|
// save to the startup list for not-yet-added callbacks to
|
||||||
m_startupEntries.push_back(entry);
|
// pull down on startup
|
||||||
|
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)(entry.debugClass, entry.debugPriority,
|
cb->processEntry(entry);
|
||||||
entry.file, entry.line, entry.message);
|
|
||||||
}
|
}
|
||||||
} // of main thread loop
|
} // of main thread loop
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stop()
|
bool stop()
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> g(m_lock);
|
{
|
||||||
if (!m_isRunning) {
|
std::lock_guard<std::mutex> g(m_lock);
|
||||||
return false;
|
if (!m_isRunning) {
|
||||||
}
|
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, "");
|
log(SG_NONE, SG_ALERT, "done", -1, "", false);
|
||||||
|
}
|
||||||
join();
|
join();
|
||||||
|
|
||||||
m_isRunning = false;
|
m_isRunning = false;
|
||||||
@@ -430,9 +416,8 @@ 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 (auto entry : m_startupEntries) {
|
for (const auto& entry : m_startupEntries) {
|
||||||
(*cb)(entry.debugClass, entry.debugPriority,
|
cb->processEntry(entry);
|
||||||
entry.file, entry.line, entry.message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,9 +445,9 @@ public:
|
|||||||
PauseThread pause(this);
|
PauseThread pause(this);
|
||||||
m_logPriority = p;
|
m_logPriority = p;
|
||||||
m_logClass = c;
|
m_logClass = c;
|
||||||
BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) {
|
for (auto cb : m_consoleCallbacks) {
|
||||||
cb->setLogLevels(c, p);
|
cb->setLogLevels(c, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool would_log( sgDebugClass c, sgDebugPriority p ) const
|
bool would_log( sgDebugClass c, sgDebugPriority p ) const
|
||||||
@@ -470,16 +455,27 @@ 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)
|
||||||
{
|
{
|
||||||
p = translatePriority(p);
|
auto tp = translatePriority(p);
|
||||||
LogEntry entry(c, p, fileName, line, msg);
|
if (!m_fileLine) {
|
||||||
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +486,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in == SG_DEV_ALERT) {
|
if (in == SG_DEV_ALERT) {
|
||||||
return m_developerMode ? SG_POPUP : SG_WARN;
|
return m_developerMode ? SG_ALERT : SG_WARN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return in;
|
return in;
|
||||||
@@ -500,7 +496,7 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static std::unique_ptr<logstream> global_logstream;
|
static std::unique_ptr<logstream> global_logstream;
|
||||||
static SGMutex global_logStreamLock;
|
static std::mutex global_logStreamLock;
|
||||||
|
|
||||||
logstream::logstream()
|
logstream::logstream()
|
||||||
{
|
{
|
||||||
@@ -510,8 +506,8 @@ logstream::logstream()
|
|||||||
|
|
||||||
logstream::~logstream()
|
logstream::~logstream()
|
||||||
{
|
{
|
||||||
popup_msgs.clear();
|
|
||||||
d->stop();
|
d->stop();
|
||||||
|
d.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -525,6 +521,10 @@ 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,7 +542,14 @@ 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);
|
d->log(c, p, fileName, line, msg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -603,17 +610,18 @@ void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName,
|
|||||||
void
|
void
|
||||||
logstream::popup( const std::string& msg)
|
logstream::popup( const std::string& msg)
|
||||||
{
|
{
|
||||||
popup_msgs.push_back(msg);
|
std::lock_guard<std::mutex> g(d->m_lock);
|
||||||
|
d->_popupMessages.push_back(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
logstream::get_popup()
|
logstream::get_popup()
|
||||||
{
|
{
|
||||||
std::string rv = "";
|
std::string rv;
|
||||||
if (!popup_msgs.empty())
|
std::lock_guard<std::mutex> g(d->m_lock);
|
||||||
{
|
if (!d->_popupMessages.empty()) {
|
||||||
rv = popup_msgs.front();
|
rv = d->_popupMessages.front();
|
||||||
popup_msgs.erase(popup_msgs.begin());
|
d->_popupMessages.erase(d->_popupMessages.begin());
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -621,7 +629,8 @@ logstream::get_popup()
|
|||||||
bool
|
bool
|
||||||
logstream::has_popup()
|
logstream::has_popup()
|
||||||
{
|
{
|
||||||
return (popup_msgs.size() > 0) ? true : false;
|
std::lock_guard<std::mutex> g(d->m_lock);
|
||||||
|
return !d->_popupMessages.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -654,6 +663,16 @@ 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()
|
||||||
@@ -664,7 +683,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
|
||||||
SGGuard<SGMutex> g(global_logStreamLock);
|
std::lock_guard<std::mutex> g(global_logStreamLock);
|
||||||
|
|
||||||
if( !global_logstream )
|
if( !global_logstream )
|
||||||
global_logstream.reset(new logstream);
|
global_logstream.reset(new logstream);
|
||||||
@@ -745,7 +764,7 @@ void requestConsole()
|
|||||||
|
|
||||||
void shutdownLogging()
|
void shutdownLogging()
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> g(global_logStreamLock);
|
std::lock_guard<std::mutex> g(global_logStreamLock);
|
||||||
global_logstream.reset();
|
global_logstream.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-21
@@ -38,25 +38,7 @@ 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
|
||||||
@@ -104,6 +86,11 @@ 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
|
||||||
@@ -111,12 +98,26 @@ 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
|
||||||
*/
|
*/
|
||||||
@@ -178,8 +179,6 @@ 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;
|
||||||
@@ -203,9 +202,11 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
#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;
|
||||||
|
|
||||||
|
void UnlockList()
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
void LockList()
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
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);
|
||||||
|
|
||||||
|
UnlockList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes an object from receving message from this transmitter
|
||||||
|
virtual void DeRegister(IReceiver& R)
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
//printf("Remove %x\n", &R);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnlockList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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++;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
if (receiveDepth == 0)
|
||||||
|
deleted_recipients.clear();
|
||||||
|
receiveDepth++;
|
||||||
|
std::vector<IReceiver*> temp(recipient_list.size());
|
||||||
|
int idx = 0;
|
||||||
|
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
|
||||||
|
{
|
||||||
|
temp[idx++] = *i;
|
||||||
|
}
|
||||||
|
UnlockList();
|
||||||
|
int tempSize = temp.size();
|
||||||
|
for (int index = 0; index < tempSize; index++)
|
||||||
|
{
|
||||||
|
IReceiver* R = temp[index];
|
||||||
|
LockList();
|
||||||
|
if (deleted_recipients.size())
|
||||||
|
{
|
||||||
|
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
|
||||||
|
{
|
||||||
|
UnlockList();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnlockList();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
// return_status = ReceiptStatusAbort;
|
||||||
|
}
|
||||||
|
receiveDepth--;
|
||||||
|
return return_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of currently registered recipients
|
||||||
|
virtual int Count()
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
return recipient_list.size();
|
||||||
|
UnlockList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -38,9 +38,12 @@
|
|||||||
# 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/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
@@ -155,6 +158,320 @@ 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;
|
||||||
@@ -635,6 +952,8 @@ 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"))
|
||||||
|
|||||||
@@ -235,6 +235,11 @@ 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;
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ 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 )
|
||||||
@@ -64,6 +68,9 @@ 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);
|
||||||
@@ -227,6 +234,9 @@ 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;
|
||||||
|
|||||||
@@ -191,52 +191,11 @@ 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) {
|
||||||
@@ -291,10 +250,6 @@ 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) {
|
||||||
@@ -431,9 +386,6 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -471,10 +423,6 @@ 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) {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGEphemeris::SGEphemeris( const std::string &path ) {
|
SGEphemeris::SGEphemeris( const SGPath& 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 std::string &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( SGPath(path) );
|
stars = new SGStarData(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 std::string &path );
|
SGEphemeris( const SGPath &path );
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~SGEphemeris( void );
|
~SGEphemeris( void );
|
||||||
|
|||||||
@@ -19,11 +19,13 @@
|
|||||||
# 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/SGGuard.hxx"
|
#include "simgear/threads/SGThread.hxx"
|
||||||
#include "RTIFederate.hxx"
|
#include "RTIFederate.hxx"
|
||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
@@ -39,7 +41,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
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> guard(_mutex);
|
std::lock_guard<std::mutex> 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())
|
||||||
@@ -52,7 +54,7 @@ RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std:
|
|||||||
void
|
void
|
||||||
RTIFederateFactoryRegistry::registerFactory(RTIFederateFactory* factory)
|
RTIFederateFactoryRegistry::registerFactory(RTIFederateFactory* factory)
|
||||||
{
|
{
|
||||||
SGGuard<SGMutex> guard(_mutex);
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
_federateFactoryList.push_back(factory);
|
_federateFactoryList.push_back(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+61
-30
@@ -33,9 +33,7 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@@ -107,6 +105,8 @@ public:
|
|||||||
unsigned int bytesTransferred;
|
unsigned int bytesTransferred;
|
||||||
unsigned int lastTransferRate;
|
unsigned int lastTransferRate;
|
||||||
uint64_t totalBytesDownloaded;
|
uint64_t totalBytesDownloaded;
|
||||||
|
|
||||||
|
SGPath tlsCertificatePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
Client::Client() :
|
Client::Client() :
|
||||||
@@ -122,7 +122,12 @@ Client::Client() :
|
|||||||
d->maxPipelineDepth = 5;
|
d->maxPipelineDepth = 5;
|
||||||
setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
|
setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
|
||||||
|
|
||||||
|
d->tlsCertificatePath = SGPath::fromEnv("SIMGEAR_TLS_CERT_PATH");
|
||||||
|
|
||||||
static bool didInitCurlGlobal = false;
|
static bool didInitCurlGlobal = false;
|
||||||
|
static std::mutex initMutex;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> g(initMutex);
|
||||||
if (!didInitCurlGlobal) {
|
if (!didInitCurlGlobal) {
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
didInitCurlGlobal = true;
|
didInitCurlGlobal = true;
|
||||||
@@ -160,6 +165,14 @@ void Client::setMaxPipelineDepth(unsigned int depth)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::reset()
|
||||||
|
{
|
||||||
|
curl_multi_cleanup(d->curlMulti);
|
||||||
|
d.reset(new ClientPrivate);
|
||||||
|
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()) {
|
||||||
@@ -170,32 +183,22 @@ void Client::update(int waitTimeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int remainingActive, messagesInQueue;
|
int remainingActive, messagesInQueue;
|
||||||
#if defined(SG_MAC)
|
int numFds;
|
||||||
// Mac 10.8 libCurl lacks this, let's keep compat for now
|
CURLMcode mc = curl_multi_wait(d->curlMulti, NULL, 0, waitTimeout, &numFds);
|
||||||
fd_set curlReadFDs, curlWriteFDs, curlErrorFDs;
|
if (mc != CURLM_OK) {
|
||||||
int maxFD;
|
SG_LOG(SG_IO, SG_WARN, "curl_multi_wait failed:" << curl_multi_strerror(mc));
|
||||||
curl_multi_fdset(d->curlMulti,
|
return;
|
||||||
&curlReadFDs,
|
|
||||||
&curlWriteFDs,
|
|
||||||
&curlErrorFDs,
|
|
||||||
&maxFD);
|
|
||||||
|
|
||||||
struct timeval timeout;
|
|
||||||
long t;
|
|
||||||
|
|
||||||
curl_multi_timeout(d->curlMulti, &t);
|
|
||||||
if ((t < 0) || (t > waitTimeout)) {
|
|
||||||
t = waitTimeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout.tv_sec = t / 1000;
|
mc = curl_multi_perform(d->curlMulti, &remainingActive);
|
||||||
timeout.tv_usec = (t % 1000) * 1000;
|
if (mc == CURLM_CALL_MULTI_PERFORM) {
|
||||||
::select(maxFD, &curlReadFDs, &curlWriteFDs, &curlErrorFDs, &timeout);
|
// we could loop here, but don't want to get blocked
|
||||||
#else
|
// also this shouldn't ocurr in any modern libCurl
|
||||||
int numFds;
|
curl_multi_perform(d->curlMulti, &remainingActive);
|
||||||
curl_multi_wait(d->curlMulti, NULL, 0, waitTimeout, &numFds);
|
} else if (mc != CURLM_OK) {
|
||||||
#endif
|
SG_LOG(SG_IO, SG_WARN, "curl_multi_perform failed:" << curl_multi_strerror(mc));
|
||||||
curl_multi_perform(d->curlMulti, &remainingActive);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CURLMsg* msg;
|
CURLMsg* msg;
|
||||||
while ((msg = curl_multi_info_read(d->curlMulti, &messagesInQueue))) {
|
while ((msg = curl_multi_info_read(d->curlMulti, &messagesInQueue))) {
|
||||||
@@ -270,11 +273,25 @@ 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 +302,7 @@ void Client::makeRequest(const Request_ptr& r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string method = boost::to_lower_copy(r->method());
|
const std::string method = strutils::lowercase (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,12 +489,26 @@ 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;
|
||||||
@@ -504,8 +535,8 @@ size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems
|
|||||||
return byteSize;
|
return byteSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string key = strutils::simplify(h.substr(0, colonPos));
|
const std::string key = strutils::simplify(h.substr(0, colonPos));
|
||||||
std::string lkey = boost::to_lower_copy(key);
|
const std::string lkey = strutils::lowercase (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);
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ 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());
|
||||||
|
|||||||
+159
-112
@@ -34,9 +34,11 @@
|
|||||||
|
|
||||||
#include "simgear/debug/logstream.hxx"
|
#include "simgear/debug/logstream.hxx"
|
||||||
#include "simgear/misc/strutils.hxx"
|
#include "simgear/misc/strutils.hxx"
|
||||||
|
|
||||||
#include <simgear/misc/sg_dir.hxx>
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
#include <simgear/io/HTTPClient.hxx>
|
#include <simgear/io/HTTPClient.hxx>
|
||||||
#include <simgear/io/sg_file.hxx>
|
#include <simgear/io/sg_file.hxx>
|
||||||
|
#include <simgear/io/untar.hxx>
|
||||||
#include <simgear/io/iostreams/sgstream.hxx>
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/timing/timestamp.hxx>
|
#include <simgear/timing/timestamp.hxx>
|
||||||
@@ -47,6 +49,7 @@ namespace simgear
|
|||||||
{
|
{
|
||||||
|
|
||||||
class HTTPDirectory;
|
class HTTPDirectory;
|
||||||
|
using HTTPDirectory_ptr = std::unique_ptr<HTTPDirectory>;
|
||||||
|
|
||||||
class HTTPRepoGetRequest : public HTTP::Request
|
class HTTPRepoGetRequest : public HTTP::Request
|
||||||
{
|
{
|
||||||
@@ -135,7 +138,7 @@ public:
|
|||||||
SGPath basePath;
|
SGPath basePath;
|
||||||
bool isUpdating;
|
bool isUpdating;
|
||||||
HTTPRepository::ResultCode status;
|
HTTPRepository::ResultCode status;
|
||||||
HTTPDirectory* rootDir;
|
HTTPDirectory_ptr rootDir;
|
||||||
size_t totalDownloaded;
|
size_t totalDownloaded;
|
||||||
|
|
||||||
HTTP::Request_ptr updateFile(HTTPDirectory* dir, const std::string& name,
|
HTTP::Request_ptr updateFile(HTTPDirectory* dir, const std::string& name,
|
||||||
@@ -163,7 +166,7 @@ public:
|
|||||||
HTTPDirectory* getOrCreateDirectory(const std::string& path);
|
HTTPDirectory* getOrCreateDirectory(const std::string& path);
|
||||||
bool deleteDirectory(const std::string& relPath, const SGPath& absPath);
|
bool deleteDirectory(const std::string& relPath, const SGPath& absPath);
|
||||||
|
|
||||||
typedef std::vector<HTTPDirectory*> DirectoryVector;
|
typedef std::vector<HTTPDirectory_ptr> DirectoryVector;
|
||||||
DirectoryVector directories;
|
DirectoryVector directories;
|
||||||
|
|
||||||
SGPath installedCopyPath;
|
SGPath installedCopyPath;
|
||||||
@@ -176,7 +179,8 @@ class HTTPDirectory
|
|||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
FileType,
|
FileType,
|
||||||
DirectoryType
|
DirectoryType,
|
||||||
|
TarballType
|
||||||
};
|
};
|
||||||
|
|
||||||
ChildInfo(Type ty, const std::string & nameData, const std::string & hashData) :
|
ChildInfo(Type ty, const std::string & nameData, const std::string & hashData) :
|
||||||
@@ -186,7 +190,7 @@ class HTTPDirectory
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ChildInfo(const ChildInfo& other) = default;
|
ChildInfo(const ChildInfo& other) = default;
|
||||||
|
|
||||||
void setSize(const std::string & sizeData)
|
void setSize(const std::string & sizeData)
|
||||||
{
|
{
|
||||||
@@ -311,59 +315,41 @@ public:
|
|||||||
|
|
||||||
void updateChildrenBasedOnHash()
|
void updateChildrenBasedOnHash()
|
||||||
{
|
{
|
||||||
//SG_LOG(SG_TERRASYNC, SG_DEBUG, "updated children for:" << relativePath());
|
copyInstalledChildren();
|
||||||
|
|
||||||
copyInstalledChildren();
|
ChildInfoList toBeUpdated;
|
||||||
|
|
||||||
string_list toBeUpdated, orphans,
|
simgear::Dir d(absolutePath());
|
||||||
indexNames = indexChildren();
|
PathList fsChildren = d.children(0);
|
||||||
simgear::Dir d(absolutePath());
|
PathList orphans = d.children(0);
|
||||||
PathList fsChildren = d.children(0);
|
|
||||||
|
|
||||||
for (const auto& child : fsChildren) {
|
ChildInfoList::const_iterator it;
|
||||||
const auto& fileName = child.file();
|
for (it=children.begin(); it != children.end(); ++it) {
|
||||||
if ((fileName == ".dirindex") || (fileName == ".hashes")) {
|
// Check if the file exists
|
||||||
continue;
|
PathList::const_iterator p = std::find_if(fsChildren.begin(), fsChildren.end(), LocalFileMatcher(*it));
|
||||||
}
|
if (p == fsChildren.end()) {
|
||||||
|
// File or directory does not exist on local disk, so needs to be updated.
|
||||||
|
toBeUpdated.push_back(ChildInfo(*it));
|
||||||
|
} else if (hashForChild(*it) != it->hash) {
|
||||||
|
// File/directory exists, but hash doesn't match.
|
||||||
|
toBeUpdated.push_back(ChildInfo(*it));
|
||||||
|
orphans.erase(std::remove(orphans.begin(), orphans.end(), *p), orphans.end());
|
||||||
|
} else {
|
||||||
|
// File/Directory exists and hash is valid.
|
||||||
|
orphans.erase(std::remove(orphans.begin(), orphans.end(), *p), orphans.end());
|
||||||
|
|
||||||
ChildInfo info(child.isDir() ? ChildInfo::DirectoryType : ChildInfo::FileType,
|
if (it->type == ChildInfo::DirectoryType) {
|
||||||
fileName, "");
|
// If it's a directory,perform a recursive check.
|
||||||
info.path = child;
|
HTTPDirectory* childDir = childDirectory(it->name);
|
||||||
std::string hash = hashForChild(info);
|
childDir->updateChildrenBasedOnHash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ChildInfoList::iterator c = findIndexChild(fileName);
|
// We now have a list of entries that need to be updated, and a list
|
||||||
if (c == children.end()) {
|
// of orphan files that should be removed.
|
||||||
orphans.push_back(fileName);
|
removeOrphans(orphans);
|
||||||
} else if (c->hash != hash) {
|
scheduleUpdates(toBeUpdated);
|
||||||
#if 0
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "hash mismatch'" << fileName);
|
|
||||||
// file exists, but hash mismatch, schedule update
|
|
||||||
if (!hash.empty()) {
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "file exists but hash is wrong for:" << fileName);
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "on disk:" << hash << " vs in info:" << c->hash);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
toBeUpdated.push_back(fileName);
|
|
||||||
} else {
|
|
||||||
// file exists and hash is valid. If it's a directory,
|
|
||||||
// perform a recursive check.
|
|
||||||
if (c->type == ChildInfo::DirectoryType) {
|
|
||||||
HTTPDirectory* childDir = childDirectory(fileName);
|
|
||||||
childDir->updateChildrenBasedOnHash();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove existing file system children from the index list,
|
|
||||||
// so we can detect new children
|
|
||||||
// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Erase-Remove
|
|
||||||
indexNames.erase(std::remove(indexNames.begin(), indexNames.end(), fileName), indexNames.end());
|
|
||||||
} // of real children iteration
|
|
||||||
|
|
||||||
// all remaining names in indexChilden are new children
|
|
||||||
toBeUpdated.insert(toBeUpdated.end(), indexNames.begin(), indexNames.end());
|
|
||||||
|
|
||||||
removeOrphans(orphans);
|
|
||||||
scheduleUpdates(toBeUpdated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPDirectory* childDirectory(const std::string& name)
|
HTTPDirectory* childDirectory(const std::string& name)
|
||||||
@@ -372,10 +358,12 @@ public:
|
|||||||
return _repository->getOrCreateDirectory(childPath);
|
return _repository->getOrCreateDirectory(childPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOrphans(const string_list& orphans)
|
void removeOrphans(const PathList orphans)
|
||||||
{
|
{
|
||||||
string_list::const_iterator it;
|
PathList::const_iterator it;
|
||||||
for (it = orphans.begin(); it != orphans.end(); ++it) {
|
for (it = orphans.begin(); it != orphans.end(); ++it) {
|
||||||
|
if (it->file() == ".dirindex") continue;
|
||||||
|
if (it->file() == ".hash") continue;
|
||||||
removeChild(*it);
|
removeChild(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,21 +379,20 @@ public:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduleUpdates(const string_list& names)
|
void scheduleUpdates(const ChildInfoList names)
|
||||||
{
|
{
|
||||||
string_list::const_iterator it;
|
ChildInfoList::const_iterator it;
|
||||||
for (it = names.begin(); it != names.end(); ++it) {
|
for (it = names.begin(); it != names.end(); ++it) {
|
||||||
ChildInfoList::iterator cit = findIndexChild(*it);
|
if (it->type == ChildInfo::FileType) {
|
||||||
if (cit == children.end()) {
|
_repository->updateFile(this, it->name, it->sizeInBytes);
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "scheduleUpdate, unknown child:" << *it);
|
} else if (it->type == ChildInfo::DirectoryType){
|
||||||
continue;
|
HTTPDirectory* childDir = childDirectory(it->name);
|
||||||
}
|
_repository->updateDir(childDir, it->hash, it->sizeInBytes);
|
||||||
|
} else if (it->type == ChildInfo::TarballType) {
|
||||||
if (cit->type == ChildInfo::FileType) {
|
// Download a tarball just as a file.
|
||||||
_repository->updateFile(this, *it, cit->sizeInBytes);
|
_repository->updateFile(this, it->name, it->sizeInBytes);
|
||||||
} else {
|
} else {
|
||||||
HTTPDirectory* childDir = childDirectory(*it);
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Coding error! Unknown Child type to schedule update");
|
||||||
_repository->updateDir(childDir, cit->hash, cit->sizeInBytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,12 +417,58 @@ public:
|
|||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "updated file but not found in dir:" << _relativePath << " " << file);
|
SG_LOG(SG_TERRASYNC, SG_WARN, "updated file but not found in dir:" << _relativePath << " " << file);
|
||||||
} else {
|
} else {
|
||||||
if (it->hash != hash) {
|
if (it->hash != hash) {
|
||||||
// we don't erase the file on a hash mismatch, becuase if we're syncing during the
|
SG_LOG(SG_TERRASYNC, SG_WARN, "Checksum error for " << absolutePath() << "/" << file << " " << it->hash << " " << hash);
|
||||||
|
// we don't erase the file on a hash mismatch, because if we're syncing during the
|
||||||
// middle of a server-side update, the downloaded file may actually become valid.
|
// middle of a server-side update, the downloaded file may actually become valid.
|
||||||
_repository->failedToUpdateChild(_relativePath, HTTPRepository::REPO_ERROR_CHECKSUM);
|
_repository->failedToUpdateChild(_relativePath, HTTPRepository::REPO_ERROR_CHECKSUM);
|
||||||
} else {
|
} else {
|
||||||
_repository->updatedFileContents(it->path, hash);
|
_repository->updatedFileContents(it->path, hash);
|
||||||
_repository->totalDownloaded += sz;
|
_repository->totalDownloaded += sz;
|
||||||
|
SGPath p = SGPath(absolutePath(), file);
|
||||||
|
|
||||||
|
if ((p.extension() == "tgz") || (p.extension() == "zip")) {
|
||||||
|
// We require that any compressed files have the same filename as the file or directory
|
||||||
|
// they expand to, so we can remove the old file/directory before extracting the new
|
||||||
|
// data.
|
||||||
|
SGPath removePath = SGPath(p.base());
|
||||||
|
bool pathAvailable = true;
|
||||||
|
if (removePath.exists()) {
|
||||||
|
if (removePath.isDir()) {
|
||||||
|
simgear::Dir pd(removePath);
|
||||||
|
pathAvailable = pd.removeChildren();
|
||||||
|
} else {
|
||||||
|
pathAvailable = removePath.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathAvailable) {
|
||||||
|
// If this is a tarball, then extract it.
|
||||||
|
SGBinaryFile f(p);
|
||||||
|
if (! f.open(SG_IO_IN)) SG_LOG(SG_TERRASYNC, SG_ALERT, "Unable to open " << p << " to extract");
|
||||||
|
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_INFO, "Extracting " << absolutePath() << "/" << file << " to " << p.dir());
|
||||||
|
SGPath extractDir = p.dir();
|
||||||
|
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();
|
||||||
|
if (! ex.isAtEndOfArchive()) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.hasError()) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << p);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Unable to remove old file/directory " << removePath);
|
||||||
|
} // of pathAvailable
|
||||||
|
} // of handling tgz files
|
||||||
} // of hash matches
|
} // of hash matches
|
||||||
} // of found in child list
|
} // of found in child list
|
||||||
}
|
}
|
||||||
@@ -458,6 +491,16 @@ private:
|
|||||||
{ return info.name == name; }
|
{ return info.name == name; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LocalFileMatcher
|
||||||
|
{
|
||||||
|
LocalFileMatcher(const ChildInfo ci) : childInfo(ci) {}
|
||||||
|
ChildInfo childInfo;
|
||||||
|
|
||||||
|
bool operator()(const SGPath path) const {
|
||||||
|
return path.file() == childInfo.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ChildInfoList::iterator findIndexChild(const std::string& name)
|
ChildInfoList::iterator findIndexChild(const std::string& name)
|
||||||
{
|
{
|
||||||
return std::find_if(children.begin(), children.end(), ChildWithName(name));
|
return std::find_if(children.begin(), children.end(), ChildWithName(name));
|
||||||
@@ -519,8 +562,8 @@ private:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeData != "f" && typeData != "d" ) {
|
if (typeData != "f" && typeData != "d" && typeData != "t" ) {
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid type in line '" << line << "', expected 'd' or 'f', (ignoring line)"
|
SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid type in line '" << line << "', expected 't', 'd' or 'f', (ignoring line)"
|
||||||
<< "\n\tparsing:" << p.utf8Str());
|
<< "\n\tparsing:" << p.utf8Str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -533,8 +576,12 @@ private:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
children.emplace_back(ChildInfo(typeData == "f" ? ChildInfo::FileType : ChildInfo::DirectoryType, tokens[1], tokens[2]));
|
ChildInfo ci = ChildInfo(ChildInfo::FileType, tokens[1], tokens[2]);
|
||||||
children.back().path = absolutePath() / tokens[1];
|
if (typeData == "d") ci.type = ChildInfo::DirectoryType;
|
||||||
|
if (typeData == "t") ci.type = ChildInfo::TarballType;
|
||||||
|
|
||||||
|
children.emplace_back(ci);
|
||||||
|
children.back().path = absolutePath() / tokens[1];
|
||||||
if (tokens.size() > 3) {
|
if (tokens.size() > 3) {
|
||||||
children.back().setSize(tokens[3]);
|
children.back().setSize(tokens[3]);
|
||||||
}
|
}
|
||||||
@@ -543,40 +590,36 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeChild(const std::string& name)
|
void removeChild(SGPath path)
|
||||||
{
|
{
|
||||||
SGPath p(absolutePath());
|
|
||||||
p.append(name);
|
|
||||||
bool ok;
|
bool ok;
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_INFO, "Removing:" << path);
|
||||||
|
|
||||||
std::string fpath = _relativePath + "/" + name;
|
std::string fpath = _relativePath + "/" + path.file();
|
||||||
if (p.isDir()) {
|
if (path.isDir()) {
|
||||||
ok = _repository->deleteDirectory(fpath, p);
|
ok = _repository->deleteDirectory(fpath, path);
|
||||||
} else {
|
} else {
|
||||||
// remove the hash cache entry
|
// remove the hash cache entry
|
||||||
_repository->updatedFileContents(p, std::string());
|
_repository->updatedFileContents(path, std::string());
|
||||||
ok = p.remove();
|
ok = path.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "removal failed for:" << p);
|
SG_LOG(SG_TERRASYNC, SG_WARN, "removal failed for:" << path);
|
||||||
throw sg_io_exception("Failed to remove existing file/dir:", p);
|
throw sg_io_exception("Failed to remove existing file/dir:", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string hashForChild(const ChildInfo& child) const
|
std::string hashForChild(const ChildInfo& child) const
|
||||||
{
|
{
|
||||||
SGPath p(child.path);
|
SGPath p(child.path);
|
||||||
if (child.type == ChildInfo::DirectoryType) {
|
if (child.type == ChildInfo::DirectoryType) p.append(".dirindex");
|
||||||
p.append(".dirindex");
|
if (child.type == ChildInfo::TarballType) p.concat(".tgz"); // For tarballs the hash is against the tarball file itself
|
||||||
}
|
|
||||||
return _repository->hashForPath(p);
|
return _repository->hashForPath(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPRepoPrivate* _repository;
|
HTTPRepoPrivate* _repository;
|
||||||
std::string _relativePath; // in URL and file-system space
|
std::string _relativePath; // in URL and file-system space
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HTTPRepository::HTTPRepository(const SGPath& base, HTTP::Client *cl) :
|
HTTPRepository::HTTPRepository(const SGPath& base, HTTP::Client *cl) :
|
||||||
@@ -584,7 +627,7 @@ HTTPRepository::HTTPRepository(const SGPath& base, HTTP::Client *cl) :
|
|||||||
{
|
{
|
||||||
_d->http = cl;
|
_d->http = cl;
|
||||||
_d->basePath = base;
|
_d->basePath = base;
|
||||||
_d->rootDir = new HTTPDirectory(_d.get(), "");
|
_d->rootDir.reset(new HTTPDirectory(_d.get(), ""));
|
||||||
_d->parseHashCache();
|
_d->parseHashCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +664,7 @@ void HTTPRepository::update()
|
|||||||
_d->status = REPO_NO_ERROR;
|
_d->status = REPO_NO_ERROR;
|
||||||
_d->isUpdating = true;
|
_d->isUpdating = true;
|
||||||
_d->failures.clear();
|
_d->failures.clear();
|
||||||
_d->updateDir(_d->rootDir, std::string(), 0);
|
_d->updateDir(_d->rootDir.get(), {}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPRepository::isDoingSync() const
|
bool HTTPRepository::isDoingSync() const
|
||||||
@@ -889,10 +932,7 @@ HTTPRepository::failure() const
|
|||||||
http->cancelRequest(*rq, "Repository object deleted");
|
http->cancelRequest(*rq, "Repository object deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryVector::iterator it;
|
directories.clear(); // wil delete them all
|
||||||
for (it=directories.begin(); it != directories.end(); ++it) {
|
|
||||||
delete *it;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP::Request_ptr HTTPRepoPrivate::updateFile(HTTPDirectory* dir, const std::string& name, size_t sz)
|
HTTP::Request_ptr HTTPRepoPrivate::updateFile(HTTPDirectory* dir, const std::string& name, size_t sz)
|
||||||
@@ -944,16 +984,24 @@ HTTPRepository::failure() const
|
|||||||
std::string HTTPRepoPrivate::computeHashForPath(const SGPath& p)
|
std::string HTTPRepoPrivate::computeHashForPath(const SGPath& p)
|
||||||
{
|
{
|
||||||
if (!p.exists())
|
if (!p.exists())
|
||||||
return std::string();
|
return {};
|
||||||
|
|
||||||
sha1nfo info;
|
sha1nfo info;
|
||||||
sha1_init(&info);
|
sha1_init(&info);
|
||||||
char* buf = static_cast<char*>(malloc(1024 * 1024));
|
|
||||||
|
const int bufSize = 1024 * 1024;
|
||||||
|
char* buf = static_cast<char*>(malloc(bufSize));
|
||||||
|
if (!buf) {
|
||||||
|
sg_io_exception("Couldn't allocate SHA1 computation buffer");
|
||||||
|
}
|
||||||
|
|
||||||
size_t readLen;
|
size_t readLen;
|
||||||
SGBinaryFile f(p);
|
SGBinaryFile f(p);
|
||||||
if (!f.open(SG_IO_IN)) {
|
if (!f.open(SG_IO_IN)) {
|
||||||
|
free(buf);
|
||||||
throw sg_io_exception("Couldn't open file for compute hash", p);
|
throw sg_io_exception("Couldn't open file for compute hash", p);
|
||||||
}
|
}
|
||||||
while ((readLen = f.read(buf, 1024 * 1024)) > 0) {
|
while ((readLen = f.read(buf, bufSize)) > 0) {
|
||||||
sha1_write(&info, buf, readLen);
|
sha1_write(&info, buf, readLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1049,16 +1097,13 @@ HTTPRepository::failure() const
|
|||||||
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
|
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
|
||||||
hashes.push_back(entry);
|
hashes.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_INFO, "restored hashes:" << hashes.size());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DirectoryWithPath
|
class DirectoryWithPath
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DirectoryWithPath(const std::string& p) : path(p) {}
|
DirectoryWithPath(const std::string& p) : path(p) {}
|
||||||
bool operator()(const HTTPDirectory* entry) const
|
bool operator()(const HTTPDirectory_ptr& entry) const
|
||||||
{ return entry->relativePath() == path; }
|
{ return entry->relativePath() == path; }
|
||||||
private:
|
private:
|
||||||
std::string path;
|
std::string path;
|
||||||
@@ -1067,14 +1112,13 @@ HTTPRepository::failure() const
|
|||||||
HTTPDirectory* HTTPRepoPrivate::getOrCreateDirectory(const std::string& path)
|
HTTPDirectory* HTTPRepoPrivate::getOrCreateDirectory(const std::string& path)
|
||||||
{
|
{
|
||||||
DirectoryWithPath p(path);
|
DirectoryWithPath p(path);
|
||||||
DirectoryVector::iterator it = std::find_if(directories.begin(), directories.end(), p);
|
auto it = std::find_if(directories.begin(), directories.end(), p);
|
||||||
if (it != directories.end()) {
|
if (it != directories.end()) {
|
||||||
return *it;
|
return it->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPDirectory* d = new HTTPDirectory(this, path);
|
directories.emplace_back(new HTTPDirectory(this, path));
|
||||||
directories.push_back(d);
|
return directories.back().get();
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPRepoPrivate::deleteDirectory(const std::string& relPath, const SGPath& absPath)
|
bool HTTPRepoPrivate::deleteDirectory(const std::string& relPath, const SGPath& absPath)
|
||||||
@@ -1082,10 +1126,9 @@ HTTPRepository::failure() const
|
|||||||
DirectoryWithPath p(relPath);
|
DirectoryWithPath p(relPath);
|
||||||
auto it = std::find_if(directories.begin(), directories.end(), p);
|
auto it = std::find_if(directories.begin(), directories.end(), p);
|
||||||
if (it != directories.end()) {
|
if (it != directories.end()) {
|
||||||
HTTPDirectory* d = *it;
|
HTTPDirectory* d = it->get();
|
||||||
assert(d->absolutePath() == absPath);
|
assert(d->absolutePath() == absPath);
|
||||||
directories.erase(it);
|
directories.erase(it);
|
||||||
delete d;
|
|
||||||
} else {
|
} else {
|
||||||
// we encounter this code path when deleting an orphaned directory
|
// we encounter this code path when deleting an orphaned directory
|
||||||
}
|
}
|
||||||
@@ -1134,8 +1177,12 @@ HTTPRepository::failure() const
|
|||||||
|
|
||||||
void HTTPRepoPrivate::failedToGetRootIndex(HTTPRepository::ResultCode st)
|
void HTTPRepoPrivate::failedToGetRootIndex(HTTPRepository::ResultCode st)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "Failed to get root of repo:" << baseUrl << " " << st);
|
if (st == HTTPRepository::REPO_ERROR_FILE_NOT_FOUND) {
|
||||||
status = st;
|
status = HTTPRepository::REPO_ERROR_NOT_FOUND;
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN, "Failed to get root of repo:" << baseUrl << " " << st);
|
||||||
|
status = st;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPRepoPrivate::failedToUpdateChild(const SGPath& relativePath,
|
void HTTPRepoPrivate::failedToUpdateChild(const SGPath& relativePath,
|
||||||
@@ -1162,15 +1209,15 @@ HTTPRepository::failure() const
|
|||||||
} else if (fileStatus == HTTPRepository::REPO_ERROR_CANCELLED) {
|
} else if (fileStatus == HTTPRepository::REPO_ERROR_CANCELLED) {
|
||||||
// if we were cancelled, don't report or log
|
// if we were cancelled, don't report or log
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN, "failed to update entry:" << relativePath << " status/code: "
|
||||||
|
<< innerResultCodeAsString(fileStatus) << "/" << fileStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
Failure f;
|
Failure f;
|
||||||
f.path = relativePath;
|
f.path = relativePath;
|
||||||
f.error = fileStatus;
|
f.error = fileStatus;
|
||||||
failures.push_back(f);
|
failures.push_back(f);
|
||||||
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "failed to update entry:" << relativePath << " status/code: "
|
|
||||||
<< innerResultCodeAsString(fileStatus) << "/" << fileStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
+37
-10
@@ -18,6 +18,9 @@
|
|||||||
#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>
|
||||||
@@ -190,13 +193,16 @@ void Request::onDone()
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void Request::onFail()
|
void Request::onFail()
|
||||||
{
|
{
|
||||||
SG_LOG
|
// log if we FAIELD< but not if we CANCELLED
|
||||||
(
|
if (_ready_state == FAILED) {
|
||||||
SG_IO,
|
SG_LOG
|
||||||
SG_INFO,
|
(
|
||||||
"request failed:" << url() << " : "
|
SG_IO,
|
||||||
<< responseCode() << "/" << responseReason()
|
SG_INFO,
|
||||||
);
|
"request failed:" << url() << " : "
|
||||||
|
<< responseCode() << "/" << responseReason()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -328,15 +334,30 @@ 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(FAILED);
|
setReadyState(code < 0 ? CANCELLED : FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -360,6 +381,12 @@ 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;
|
||||||
|
|
||||||
@@ -389,7 +416,7 @@ bool Request::serverSupportsPipelining() const
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
bool Request::isComplete() const
|
bool Request::isComplete() const
|
||||||
{
|
{
|
||||||
return _ready_state == DONE || _ready_state == FAILED;
|
return _ready_state == DONE || _ready_state == FAILED || _ready_state == CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -28,8 +28,6 @@
|
|||||||
#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
|
||||||
@@ -46,7 +44,7 @@ class Request:
|
|||||||
public SGReferenced
|
public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef boost::function<void(Request*)> Callback;
|
typedef std::function<void(Request*)> Callback;
|
||||||
|
|
||||||
enum ReadyState
|
enum ReadyState
|
||||||
{
|
{
|
||||||
@@ -56,7 +54,8 @@ public:
|
|||||||
HEADERS_RECEIVED,
|
HEADERS_RECEIVED,
|
||||||
LOADING,
|
LOADING,
|
||||||
DONE,
|
DONE,
|
||||||
FAILED
|
FAILED,
|
||||||
|
CANCELLED
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Request();
|
virtual ~Request();
|
||||||
@@ -82,7 +81,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(boost::bind(mem_func, instance, _1));
|
return done(std::bind(mem_func, instance, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +96,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(boost::bind(mem_func, instance, _1));
|
return fail(std::bind(mem_func, instance, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,7 +111,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(boost::bind(mem_func, instance, _1));
|
return always(std::bind(mem_func, instance, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,7 +223,7 @@ protected:
|
|||||||
virtual void onAlways();
|
virtual void onAlways();
|
||||||
|
|
||||||
void setFailure(int code, const std::string& reason);
|
void setFailure(int code, const std::string& reason);
|
||||||
|
void setSuccess(int code);
|
||||||
private:
|
private:
|
||||||
friend class Client;
|
friend class Client;
|
||||||
friend class Connection;
|
friend class Connection;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#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>
|
||||||
@@ -123,7 +121,7 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARequest* req = new ARequest(url);
|
ARequest* req = new ARequest(url);
|
||||||
BOOST_FOREACH(string h, headers) {
|
for (const auto& h : headers) {
|
||||||
req->addHeader(h);
|
req->addHeader(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ static const uint32_t EndianMagic = 0x11223344;
|
|||||||
* gzContainerWriter
|
* gzContainerWriter
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
gzContainerWriter::gzContainerWriter(const std::string& name,
|
gzContainerWriter::gzContainerWriter(const SGPath& 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)
|
filename(name.utf8Str())
|
||||||
{
|
{
|
||||||
/* 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 std::string& name,
|
gzContainerReader::gzContainerReader(const SGPath& 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)
|
filename(name.utf8Str())
|
||||||
{
|
{
|
||||||
bool ok = (good() && !eof());
|
bool ok = (good() && !eof());
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ typedef int ContainerType;
|
|||||||
class gzContainerReader : public sg_gzifstream
|
class gzContainerReader : public sg_gzifstream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
gzContainerReader( const std::string& name,
|
gzContainerReader( const SGPath& 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 std::string& name,
|
gzContainerWriter( const SGPath& name,
|
||||||
const std::string& fileMagic);
|
const std::string& fileMagic);
|
||||||
|
|
||||||
bool writeContainerHeader(ContainerType Type, size_t Size);
|
bool writeContainerHeader(ContainerType Type, size_t Size);
|
||||||
|
|||||||
Regular → Executable
+18
-4
@@ -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.local8BitStr();
|
std::string ps = path.utf8Str();
|
||||||
#endif
|
#endif
|
||||||
std::ifstream::open(ps.c_str(), io_mode);
|
std::ifstream::open(ps.c_str(), io_mode);
|
||||||
}
|
}
|
||||||
@@ -222,17 +222,31 @@ 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.local8BitStr();
|
std::string ps = name.utf8Str();
|
||||||
#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.local8BitStr();
|
std::string ps = path.utf8Str();
|
||||||
#endif
|
#endif
|
||||||
std::ofstream::open(ps.c_str(), io_mode);
|
std::ofstream::open(ps.c_str(), io_mode);
|
||||||
}
|
}
|
||||||
@@ -242,7 +256,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.local8BitStr();
|
std::string ps = name.utf8Str();
|
||||||
#endif
|
#endif
|
||||||
std::ofstream::open(ps.c_str(), io_mode);
|
std::ofstream::open(ps.c_str(), io_mode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,6 +196,10 @@ 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
|
||||||
|
|||||||
@@ -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 (std::ios_base::failure) {
|
} catch (const 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
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#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)
|
||||||
@@ -213,7 +214,7 @@ private:
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMutex _lock;
|
std::mutex _lock;
|
||||||
SGWaitCondition _wait;
|
SGWaitCondition _wait;
|
||||||
|
|
||||||
typedef std::map<string, simgear::IPAddress*> AddressCache;
|
typedef std::map<string, simgear::IPAddress*> AddressCache;
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float readInt()
|
int32_t readInt()
|
||||||
{
|
{
|
||||||
unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset);
|
unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset);
|
||||||
if ( sgIsBigEndian() ) {
|
if ( sgIsBigEndian() ) {
|
||||||
|
|||||||
@@ -34,18 +34,15 @@
|
|||||||
#include <simgear/math/sg_types.hxx>
|
#include <simgear/math/sg_types.hxx>
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
#include <vector>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/array.hpp>
|
#include <vector>
|
||||||
|
|
||||||
#define MAX_TC_SETS (4)
|
#define MAX_TC_SETS (4)
|
||||||
#define MAX_VAS (8)
|
#define MAX_VAS (8)
|
||||||
|
|
||||||
// I really want to pass around fixed length arrays, as the size
|
typedef std::array<int_list, MAX_TC_SETS> tci_list;
|
||||||
// has to be hardcoded
|
typedef std::array<int_list, MAX_VAS> vai_list;
|
||||||
// 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;
|
||||||
|
|||||||
@@ -64,6 +64,31 @@ 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 std::string();
|
||||||
|
simgear::sha1nfo info;
|
||||||
|
sha1_init(&info);
|
||||||
|
char* buf = static_cast<char*>(malloc(1024 * 1024));
|
||||||
|
size_t readLen;
|
||||||
|
SGBinaryFile f(file_name);
|
||||||
|
if (!f.open(SG_IO_IN)) {
|
||||||
|
throw sg_io_exception("Couldn't open file for compute hash", file_name);
|
||||||
|
}
|
||||||
|
while ((readLen = f.read(buf, 1024 * 1024)) > 0) {
|
||||||
|
sha1_write(&info, buf, readLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
free(buf);
|
||||||
|
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 ) {
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ 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 {
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
#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"
|
||||||
|
|||||||
+83
-17
@@ -1,12 +1,10 @@
|
|||||||
#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"
|
||||||
@@ -61,23 +59,23 @@ public:
|
|||||||
std::map<string, string> headers;
|
std::map<string, string> headers;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void onDone()
|
void onDone() override
|
||||||
{
|
{
|
||||||
complete = true;
|
complete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void onFail()
|
void onFail() override
|
||||||
{
|
{
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void gotBodyData(const char* s, int n)
|
void gotBodyData(const char* s, int n) override
|
||||||
{
|
{
|
||||||
//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);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void responseHeader(const string& header, const string& value)
|
void responseHeader(const string& header, const string& value) override
|
||||||
{
|
{
|
||||||
Request::responseHeader(header, value);
|
Request::responseHeader(header, value);
|
||||||
headers[header] = value;
|
headers[header] = value;
|
||||||
@@ -273,7 +271,23 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -365,6 +379,26 @@ 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 );
|
||||||
@@ -440,6 +474,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,9 +620,10 @@ cout << "testing proxy close" << endl;
|
|||||||
HTTP::Request_ptr own3(tr3);
|
HTTP::Request_ptr own3(tr3);
|
||||||
cl.makeRequest(tr3);
|
cl.makeRequest(tr3);
|
||||||
|
|
||||||
waitForComplete(&cl, tr3);
|
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() {
|
||||||
SG_VERIFY(tr->complete);
|
return tr->complete && tr2->complete &&tr3->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));
|
||||||
@@ -615,9 +652,9 @@ cout << "testing proxy close" << endl;
|
|||||||
HTTP::Request_ptr own3(tr3);
|
HTTP::Request_ptr own3(tr3);
|
||||||
cl.makeRequest(tr3);
|
cl.makeRequest(tr3);
|
||||||
|
|
||||||
waitForComplete(&cl, tr3);
|
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() {
|
||||||
SG_VERIFY(tr->complete);
|
return tr->complete && tr2->complete &&tr3->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));
|
||||||
@@ -744,8 +781,15 @@ 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" << endl;
|
cout << "get-during-response-send\n\n" << endl;
|
||||||
cl.clearAllConnections();
|
cl.clearAllConnections();
|
||||||
//test_get_during_send
|
//test_get_during_send
|
||||||
|
|
||||||
@@ -765,7 +809,10 @@ cout << "testing proxy close" << endl;
|
|||||||
HTTP::Request_ptr own2(tr2);
|
HTTP::Request_ptr own2(tr2);
|
||||||
cl.makeRequest(tr2);
|
cl.makeRequest(tr2);
|
||||||
|
|
||||||
waitForComplete(&cl, tr2);
|
SG_VERIFY(waitFor(&cl, [tr, 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));
|
||||||
@@ -773,6 +820,25 @@ 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;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@@ -30,7 +31,6 @@ 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,7 +168,6 @@ public:
|
|||||||
|
|
||||||
virtual void handleClose (void)
|
virtual void handleClose (void)
|
||||||
{
|
{
|
||||||
std::cerr << "channel close" << std::endl;
|
|
||||||
NetBufferChannel::handleClose();
|
NetBufferChannel::handleClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -5,8 +6,6 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
|
|
||||||
#include <simgear/simgear_config.h>
|
#include <simgear/simgear_config.h>
|
||||||
|
|
||||||
#include "test_HTTP.hxx"
|
#include "test_HTTP.hxx"
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
|
|
||||||
#include <simgear/simgear_config.h>
|
#include <simgear/simgear_config.h>
|
||||||
|
|
||||||
#include "HTTPClient.hxx"
|
#include "HTTPClient.hxx"
|
||||||
|
|||||||
+28
-23
@@ -48,6 +48,8 @@ namespace simgear
|
|||||||
assert(outer);
|
assert(outer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~ArchiveExtractorPrivate() = default;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
INVALID = 0,
|
INVALID = 0,
|
||||||
READING_HEADER,
|
READING_HEADER,
|
||||||
@@ -338,7 +340,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isSafePath(tarPath)) {
|
if (!isSafePath(tarPath)) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "bad tar path:" << tarPath);
|
SG_LOG(SG_IO, SG_WARN, "unsafe tar path, skipping::" << tarPath);
|
||||||
skipCurrentEntry = true;
|
skipCurrentEntry = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +506,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs);
|
unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs);
|
||||||
|
|
||||||
const size_t BUFFER_SIZE = 32 * 1024;
|
const size_t BUFFER_SIZE = 1024 * 1024;
|
||||||
void* buf = malloc(BUFFER_SIZE);
|
void* buf = malloc(BUFFER_SIZE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -530,24 +532,28 @@ public:
|
|||||||
state = END_OF_ARCHIVE;
|
state = END_OF_ARCHIVE;
|
||||||
}
|
}
|
||||||
catch (sg_exception&) {
|
catch (sg_exception&) {
|
||||||
state = BAD_ARCHIVE;
|
state = BAD_ARCHIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
unzClose(zip);
|
unzClose(zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
|
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
unz_file_info fileInfo;
|
unz_file_info fileInfo;
|
||||||
unzGetCurrentFileInfo(zip, &fileInfo,
|
int result = unzGetCurrentFileInfo(zip, &fileInfo,
|
||||||
buffer, bufferSize,
|
buffer, bufferSize,
|
||||||
NULL, 0, /* extra field */
|
NULL, 0, /* extra field */
|
||||||
NULL, 0 /* comment field */);
|
NULL, 0 /* comment field */);
|
||||||
|
if (result != Z_OK) {
|
||||||
|
throw sg_io_exception("Failed to get zip current file info");
|
||||||
|
}
|
||||||
|
|
||||||
std::string name(buffer);
|
std::string name(buffer);
|
||||||
if (!isSafePath(name)) {
|
if (!isSafePath(name)) {
|
||||||
throw sg_format_exception("Bad zip path", name);
|
SG_LOG(SG_IO, SG_WARN, "unsafe zip path, skipping::" << name);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto filterResult = filterPath(name);
|
auto filterResult = filterPath(name);
|
||||||
@@ -566,7 +572,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = unzOpenCurrentFile(zip);
|
result = unzOpenCurrentFile(zip);
|
||||||
if (result != UNZ_OK) {
|
if (result != UNZ_OK) {
|
||||||
throw sg_io_exception("opening current zip file failed", sg_location(name));
|
throw sg_io_exception("opening current zip file failed", sg_location(name));
|
||||||
}
|
}
|
||||||
@@ -614,10 +620,7 @@ ArchiveExtractor::ArchiveExtractor(const SGPath& rootPath) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveExtractor::~ArchiveExtractor()
|
ArchiveExtractor::~ArchiveExtractor() = default;
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArchiveExtractor::extractBytes(const uint8_t* bytes, size_t count)
|
void ArchiveExtractor::extractBytes(const uint8_t* bytes, size_t count)
|
||||||
{
|
{
|
||||||
@@ -635,7 +638,7 @@ void ArchiveExtractor::extractBytes(const uint8_t* bytes, size_t count)
|
|||||||
d.reset(new ZipExtractorPrivate(this));
|
d.reset(new ZipExtractorPrivate(this));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Invcalid archive type");
|
SG_LOG(SG_IO, SG_WARN, "Invalid archive type");
|
||||||
_invalidDataType = true;
|
_invalidDataType = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -725,8 +728,10 @@ ArchiveExtractor::DetermineResult ArchiveExtractor::isTarData(const uint8_t* byt
|
|||||||
}
|
}
|
||||||
|
|
||||||
int result = inflate(&z, Z_SYNC_FLUSH);
|
int result = inflate(&z, Z_SYNC_FLUSH);
|
||||||
if (result != Z_OK) {
|
if ((result == Z_OK) || (result == Z_STREAM_END)) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "inflate failed:" << result);
|
// all good
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "isTarData: Zlib inflate failed:" << result);
|
||||||
inflateEnd(&z);
|
inflateEnd(&z);
|
||||||
return Invalid; // not tar data
|
return Invalid; // not tar data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ArchiveExtractor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ArchiveExtractor(const SGPath& rootPath);
|
ArchiveExtractor(const SGPath& rootPath);
|
||||||
~ArchiveExtractor();
|
virtual ~ArchiveExtractor();
|
||||||
|
|
||||||
enum DetermineResult
|
enum DetermineResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -537,6 +537,13 @@ SGGeodesy::advanceRadM(const SGGeoc& geoc, double course, double distance,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGGeoc SGGeodesy::advanceDegM(const SGGeoc &geoc, double course,
|
||||||
|
double distance) {
|
||||||
|
SGGeoc result;
|
||||||
|
advanceRadM(geoc, course * SG_DEGREES_TO_RADIANS, distance, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
SGGeodesy::courseRad(const SGGeoc& from, const SGGeoc& to)
|
SGGeodesy::courseRad(const SGGeoc& from, const SGGeoc& to)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ public:
|
|||||||
// Geocentric course/distance computation
|
// Geocentric course/distance computation
|
||||||
static void advanceRadM(const SGGeoc& geoc, double course, double distance,
|
static void advanceRadM(const SGGeoc& geoc, double course, double distance,
|
||||||
SGGeoc& result);
|
SGGeoc& result);
|
||||||
|
|
||||||
|
static SGGeoc advanceDegM(const SGGeoc &geoc, double course, double distance);
|
||||||
|
|
||||||
static double courseRad(const SGGeoc& from, const SGGeoc& to);
|
static double courseRad(const SGGeoc& from, const SGGeoc& to);
|
||||||
static double distanceRad(const SGGeoc& from, const SGGeoc& to);
|
static double distanceRad(const SGGeoc& from, const SGGeoc& to);
|
||||||
static double distanceM(const SGGeoc& from, const SGGeoc& to);
|
static double distanceM(const SGGeoc& from, const SGGeoc& to);
|
||||||
|
|||||||
+25
-2
@@ -193,8 +193,8 @@ min(S s, SGVec2<T> v)
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
SGVec2<T>
|
SGVec2<T>
|
||||||
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
max(SGVec2<T> v1, const SGVec2<T>& v2)
|
||||||
{ v1 = simd4::max(v1.simd2(), v2.simd2()); return v1; }
|
{ v1.simd2() = simd4::max(v1.simd2(), v2.simd2()); return v1; }
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
inline
|
inline
|
||||||
SGVec2<T>
|
SGVec2<T>
|
||||||
@@ -375,6 +375,29 @@ interpolate(T tau, const SGVec2<T>& v1, const SGVec2<T>& v2)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function for point_in_triangle
|
||||||
|
template <typename T>
|
||||||
|
inline
|
||||||
|
T
|
||||||
|
pt_determine(const SGVec2<T>& pt1, const SGVec2<T>& pt2, const SGVec2<T>& pt3)
|
||||||
|
{
|
||||||
|
return (pt1.x()-pt3.x()) * (pt2.y()-pt3.y()) - (pt2.x() - pt3.x()) * (pt1.y() - pt3.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is testpt inside the triangle formed by the other three points?
|
||||||
|
template <typename T>
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
point_in_triangle(const SGVec2<T>& testpt, const SGVec2<T>& pt1, const SGVec2<T>& pt2, const SGVec2<T>& pt3)
|
||||||
|
{
|
||||||
|
T d1 = pt_determine(testpt,pt1,pt2);
|
||||||
|
T d2 = pt_determine(testpt,pt2,pt3);
|
||||||
|
T d3 = pt_determine(testpt,pt3,pt1);
|
||||||
|
bool has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
||||||
|
bool has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
||||||
|
return !(has_neg && has_pos);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
|
|||||||
// file
|
// file
|
||||||
SGInterpTable::SGInterpTable( const std::string& file )
|
SGInterpTable::SGInterpTable( const std::string& file )
|
||||||
{
|
{
|
||||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
|
||||||
|
|
||||||
sg_gzifstream in( SGPath::fromUtf8(file) );
|
sg_gzifstream in( SGPath::fromUtf8(file) );
|
||||||
if ( !in.is_open() ) {
|
if ( !in.is_open() ) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
||||||
@@ -78,8 +76,6 @@ SGInterpTable::SGInterpTable( const std::string& file )
|
|||||||
// file
|
// file
|
||||||
SGInterpTable::SGInterpTable( const SGPath& file )
|
SGInterpTable::SGInterpTable( const SGPath& file )
|
||||||
{
|
{
|
||||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
|
||||||
|
|
||||||
sg_gzifstream in( file );
|
sg_gzifstream in( file );
|
||||||
if ( !in.is_open() ) {
|
if ( !in.is_open() ) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ inline simd4_t<T,N> operator*(simd4_t<T,N> v, T f) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SIMD
|
#ifdef ENABLE_SIMD_CODE
|
||||||
|
|
||||||
# ifdef __SSE__
|
# ifdef __SSE__
|
||||||
namespace simd4
|
namespace simd4
|
||||||
@@ -1305,7 +1305,7 @@ inline simd4_t<int,N> max(simd4_t<int,N> v1, const simd4_t<int,N>& v2) {
|
|||||||
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif /* ENABLE_SIMD */
|
#endif /* ENABLE_SIMD_CODE */
|
||||||
|
|
||||||
#endif /* __SIMD_H__ */
|
#endif /* __SIMD_H__ */
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ inline simd4x4_t<T,N> operator*(const simd4x4_t<T,N>& m1, const simd4x4_t<T,N>&
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_SIMD
|
#ifdef ENABLE_SIMD_CODE
|
||||||
|
|
||||||
# ifdef __SSE__
|
# ifdef __SSE__
|
||||||
template<>
|
template<>
|
||||||
@@ -1191,7 +1191,7 @@ inline simd4_t<int,3> transform<int>(const simd4x4_t<int,4>& m, const simd4_t<in
|
|||||||
} /* namespace simd4x */
|
} /* namespace simd4x */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif /* ENABLE_SIMD */
|
#endif /* ENABLE_SIMD_CODE */
|
||||||
|
|
||||||
#endif /* __SIMD4X4_H__ */
|
#endif /* __SIMD4X4_H__ */
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ set(HEADERS
|
|||||||
tabbed_values.hxx
|
tabbed_values.hxx
|
||||||
texcoord.hxx
|
texcoord.hxx
|
||||||
test_macros.hxx
|
test_macros.hxx
|
||||||
|
lru_cache.hxx
|
||||||
|
simgear_optional.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "CSSBorder.hxx"
|
#include "CSSBorder.hxx"
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/range.hpp>
|
|
||||||
#include <boost/tokenizer.hpp>
|
#include <boost/tokenizer.hpp>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -114,9 +112,9 @@ namespace simgear
|
|||||||
std::max
|
std::max
|
||||||
(
|
(
|
||||||
0.f,
|
0.f,
|
||||||
boost::lexical_cast<float>
|
std::stof
|
||||||
(
|
(
|
||||||
rel ? boost::make_iterator_range(tok->begin(), tok->end() - 1)
|
rel ? std::string(tok->begin(), tok->end() - 1)
|
||||||
: *tok
|
: *tok
|
||||||
)
|
)
|
||||||
/
|
/
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#define SG_LISTDIFF_HXX_
|
#define SG_LISTDIFF_HXX_
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/function.hpp>
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -30,7 +29,7 @@ namespace simgear
|
|||||||
struct ListDiff
|
struct ListDiff
|
||||||
{
|
{
|
||||||
typedef std::vector<T> List;
|
typedef std::vector<T> List;
|
||||||
typedef boost::function<void (T)> Callback;
|
typedef std::function<void (T)> Callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform list diff in-place (modifies both lists) and call cb_add for
|
* Perform list diff in-place (modifies both lists) and call cb_add for
|
||||||
|
|||||||
@@ -56,6 +56,15 @@ ResourceManager::~ResourceManager()
|
|||||||
std::for_each(_providers.begin(), _providers.end(),
|
std::for_each(_providers.begin(), _providers.end(),
|
||||||
[](ResourceProvider* p) { delete p; });
|
[](ResourceProvider* p) { delete p; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceManager::reset()
|
||||||
|
{
|
||||||
|
if (static_manager) {
|
||||||
|
delete static_manager;
|
||||||
|
static_manager = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trivial provider using a fixed base path
|
* trivial provider using a fixed base path
|
||||||
*/
|
*/
|
||||||
@@ -107,6 +116,8 @@ void ResourceManager::removeProvider(ResourceProvider* aProvider)
|
|||||||
SG_LOG(SG_GENERAL, SG_DEV_ALERT, "unknown provider doing remove");
|
SG_LOG(SG_GENERAL, SG_DEV_ALERT, "unknown provider doing remove");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_providers.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPath ResourceManager::findPath(const std::string& aResource, SGPath aContext)
|
SGPath ResourceManager::findPath(const std::string& aResource, SGPath aContext)
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ public:
|
|||||||
|
|
||||||
static ResourceManager* instance();
|
static ResourceManager* instance();
|
||||||
|
|
||||||
|
static void reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a simple fixed resource location, to resolve against
|
* add a simple fixed resource location, to resolve against
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,11 +30,16 @@
|
|||||||
// code can register another one immediately without worrying about
|
// code can register another one immediately without worrying about
|
||||||
// timer aliasing.
|
// timer aliasing.
|
||||||
|
|
||||||
class SGInterpolator : public SGSubsystem {
|
class SGInterpolator : public SGSubsystem
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
SGInterpolator() { _list = 0; }
|
SGInterpolator() { _list = 0; }
|
||||||
virtual void init() {}
|
|
||||||
virtual void update(double delta_time_sec);
|
// Subsystem API.
|
||||||
|
void update(double delta_time_sec) override;
|
||||||
|
|
||||||
|
// Subsystem identification.
|
||||||
|
static const char* staticSubsystemClassId() { return "interpolator"; }
|
||||||
|
|
||||||
// Simple method that interpolates a double property value from
|
// Simple method that interpolates a double property value from
|
||||||
// its current value (default of zero) to the specified target
|
// its current value (default of zero) to the specified target
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
///@file
|
||||||
|
/// Compare lists and get differences
|
||||||
|
//---------------------------------------------------------------------------//
|
||||||
|
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0
|
||||||
|
// See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
//
|
||||||
|
// See http://boostorg.github.com/compute for more information.
|
||||||
|
//---------------------------------------------------------------------------//
|
||||||
|
///
|
||||||
|
// Changes Copyright (C) 2019 Richard Harrison (rjh@zaretto.com)
|
||||||
|
//
|
||||||
|
// As the boost licence is lax and permissive see
|
||||||
|
// (https://www.gnu.org/licenses/license-list.en.html#boost)
|
||||||
|
// any changes to this module are covered under the GPL
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#ifndef LRU_CACHE_HXX_
|
||||||
|
#define LRU_CACHE_HXX_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <utility>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <simgear/threads/SGThread.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
// a cache which evicts the least recently used item when it is full
|
||||||
|
template<class Key, class Value>
|
||||||
|
class lru_cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::mutex _mutex;
|
||||||
|
|
||||||
|
typedef Key key_type;
|
||||||
|
typedef Value value_type;
|
||||||
|
typedef std::list<key_type> list_type;
|
||||||
|
typedef std::map<
|
||||||
|
key_type,
|
||||||
|
std::pair<value_type, typename list_type::iterator>
|
||||||
|
> map_type;
|
||||||
|
|
||||||
|
lru_cache(size_t capacity)
|
||||||
|
: m_capacity(capacity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~lru_cache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return m_map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const
|
||||||
|
{
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const key_type &key)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
return m_map.find(key) != m_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const key_type &key, const value_type &value)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if (i == m_map.end()) {
|
||||||
|
// insert item into the cache, but first check if it is full
|
||||||
|
if (size() >= m_capacity) {
|
||||||
|
// cache is full, evict the least recently used item
|
||||||
|
evict();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the new item
|
||||||
|
m_list.push_front(key);
|
||||||
|
m_map[key] = std::make_pair(value, m_list.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boost::optional<key_type> findValue(const std::string &requiredValue)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
for (typename map_type::iterator it = m_map.begin(); it != m_map.end(); ++it)
|
||||||
|
if (it->second.first == requiredValue)
|
||||||
|
return it->first;
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
boost::optional<value_type> get(const key_type &key)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
// lookup value in the cache
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if (i == m_map.end()) {
|
||||||
|
// value not in cache
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the value, but first update its place in the most
|
||||||
|
// recently used list
|
||||||
|
typename list_type::iterator j = i->second.second;
|
||||||
|
if (j != m_list.begin()) {
|
||||||
|
// move item to the front of the most recently used list
|
||||||
|
m_list.erase(j);
|
||||||
|
m_list.push_front(key);
|
||||||
|
|
||||||
|
// update iterator in map
|
||||||
|
j = m_list.begin();
|
||||||
|
const value_type &value = i->second.first;
|
||||||
|
m_map[key] = std::make_pair(value, j);
|
||||||
|
|
||||||
|
// return the value
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// the item is already at the front of the most recently
|
||||||
|
// used list so just return it
|
||||||
|
return i->second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
m_map.clear();
|
||||||
|
m_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void evict()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> scopeLock(_mutex);
|
||||||
|
// evict item from the end of most recently used list
|
||||||
|
typename list_type::iterator i = --m_list.end();
|
||||||
|
m_map.erase(*i);
|
||||||
|
m_list.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
map_type m_map;
|
||||||
|
list_type m_list;
|
||||||
|
size_t m_capacity;
|
||||||
|
};
|
||||||
|
} // namespace simgear
|
||||||
|
|
||||||
|
#endif /* SG_LISTDIFF_HXX_ */
|
||||||
Regular → Executable
+7
@@ -333,6 +333,12 @@ void test_hash_function()
|
|||||||
SG_CHECK_NE(std::hash<SGPath>{}(p), std::hash<SGPath>{}(p / "foobar"));
|
SG_CHECK_NE(std::hash<SGPath>{}(p), std::hash<SGPath>{}(p / "foobar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_null_path()
|
||||||
|
{
|
||||||
|
const SGPath nullPath;
|
||||||
|
SG_VERIFY(!nullPath.exists());
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
SGPath pa;
|
SGPath pa;
|
||||||
@@ -441,6 +447,7 @@ int main(int argc, char* argv[])
|
|||||||
test_update_dir();
|
test_update_dir();
|
||||||
test_comparisons();
|
test_comparisons();
|
||||||
test_hash_function();
|
test_hash_function();
|
||||||
|
test_null_path();
|
||||||
|
|
||||||
cout << "all tests passed OK" << endl;
|
cout << "all tests passed OK" << endl;
|
||||||
return 0; // passed
|
return 0; // passed
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
|
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -115,7 +114,7 @@ Dir Dir::tempDir(const std::string& templ)
|
|||||||
// Mac OS-X / BSD manual says any number of 'X's, but GLibc manual
|
// Mac OS-X / BSD manual says any number of 'X's, but GLibc manual
|
||||||
// says exactly six, so that's what I'm going with
|
// says exactly six, so that's what I'm going with
|
||||||
p.concat("-XXXXXX");
|
p.concat("-XXXXXX");
|
||||||
std::string s = p.local8BitStr();
|
std::string s = p.utf8Str();
|
||||||
::snprintf(buf, 1024, "%s", s.c_str());
|
::snprintf(buf, 1024, "%s", s.c_str());
|
||||||
if (!mkdtemp(buf)) {
|
if (!mkdtemp(buf)) {
|
||||||
SG_LOG(SG_IO, SG_WARN,
|
SG_LOG(SG_IO, SG_WARN,
|
||||||
@@ -206,7 +205,7 @@ PathList Dir::children(int types, const std::string& nameFilter) const
|
|||||||
|
|
||||||
FindClose(find);
|
FindClose(find);
|
||||||
#else
|
#else
|
||||||
std::string ps = _path.local8BitStr();
|
std::string ps = _path.utf8Str();
|
||||||
DIR* dp = opendir(ps.c_str());
|
DIR* dp = opendir(ps.c_str());
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: opendir failed:" << _path);
|
SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: opendir failed:" << _path);
|
||||||
@@ -290,7 +289,7 @@ bool Dir::isEmpty() const
|
|||||||
std::wstring ps = _path.wstr();
|
std::wstring ps = _path.wstr();
|
||||||
return PathIsDirectoryEmptyW( ps.c_str() );
|
return PathIsDirectoryEmptyW( ps.c_str() );
|
||||||
#else
|
#else
|
||||||
std::string ps = _path.local8BitStr();
|
std::string ps = _path.utf8Str();
|
||||||
DIR* dp = opendir( ps.c_str() );
|
DIR* dp = opendir( ps.c_str() );
|
||||||
if (!dp) return true;
|
if (!dp) return true;
|
||||||
|
|
||||||
@@ -339,7 +338,7 @@ bool Dir::create(mode_t mode)
|
|||||||
std::wstring ps = _path.wstr();
|
std::wstring ps = _path.wstr();
|
||||||
int err = _wmkdir(ps.c_str());
|
int err = _wmkdir(ps.c_str());
|
||||||
#else
|
#else
|
||||||
std::string ps = _path.local8BitStr();
|
std::string ps = _path.utf8Str();
|
||||||
int err = mkdir(ps.c_str(), mode);
|
int err = mkdir(ps.c_str(), mode);
|
||||||
#endif
|
#endif
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -359,7 +358,7 @@ bool Dir::removeChildren() const
|
|||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
PathList cs = children(NO_DOT_OR_DOTDOT | INCLUDE_HIDDEN | TYPE_FILE | TYPE_DIR);
|
PathList cs = children(NO_DOT_OR_DOTDOT | INCLUDE_HIDDEN | TYPE_FILE | TYPE_DIR);
|
||||||
BOOST_FOREACH(SGPath path, cs) {
|
for (auto path : cs) {
|
||||||
if (path.isDir()) {
|
if (path.isDir()) {
|
||||||
Dir childDir(path);
|
Dir childDir(path);
|
||||||
ok = childDir.remove(true);
|
ok = childDir.remove(true);
|
||||||
@@ -394,7 +393,7 @@ bool Dir::remove(bool recursive)
|
|||||||
std::wstring ps = _path.wstr();
|
std::wstring ps = _path.wstr();
|
||||||
int err = _wrmdir(ps.c_str());
|
int err = _wrmdir(ps.c_str());
|
||||||
#else
|
#else
|
||||||
std::string ps = _path.local8BitStr();
|
std::string ps = _path.utf8Str();
|
||||||
int err = rmdir(ps.c_str());
|
int err = rmdir(ps.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/io/iostreams/sgstream.hxx>
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -47,8 +48,6 @@
|
|||||||
|
|
||||||
#include "sg_path.hxx"
|
#include "sg_path.hxx"
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using simgear::strutils::starts_with;
|
using simgear::strutils::starts_with;
|
||||||
|
|
||||||
@@ -398,7 +397,7 @@ string SGPath::extension() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string SGPath::lower_extension() const {
|
string SGPath::lower_extension() const {
|
||||||
return boost::to_lower_copy(extension());
|
return simgear::strutils::lowercase (extension());
|
||||||
}
|
}
|
||||||
|
|
||||||
string SGPath::complete_lower_extension() const
|
string SGPath::complete_lower_extension() const
|
||||||
@@ -412,7 +411,7 @@ string SGPath::complete_lower_extension() const
|
|||||||
|
|
||||||
string::size_type firstDot = path.find(".", index);
|
string::size_type firstDot = path.find(".", index);
|
||||||
if ((firstDot != string::npos) && (path.find(sgDirPathSep, firstDot) == string::npos)) {
|
if ((firstDot != string::npos) && (path.find(sgDirPathSep, firstDot) == string::npos)) {
|
||||||
return boost::to_lower_copy(path.substr(firstDot + 1));
|
return simgear::strutils::lowercase (path.substr(firstDot + 1));
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -786,8 +785,8 @@ bool SGPath::rename(const SGPath& newName)
|
|||||||
std::wstring np = newName.wstr();
|
std::wstring np = newName.wstr();
|
||||||
if (_wrename(p.c_str(), np.c_str()) != 0)
|
if (_wrename(p.c_str(), np.c_str()) != 0)
|
||||||
#else
|
#else
|
||||||
std::string p = local8BitStr();
|
std::string p = utf8Str();
|
||||||
std::string np = newName.local8BitStr();
|
std::string np = newName.utf8Str();
|
||||||
if( ::rename(p.c_str(), np.c_str()) != 0 )
|
if( ::rename(p.c_str(), np.c_str()) != 0 )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// -*- coding: utf-8 -*-
|
||||||
|
//
|
||||||
|
// simgear_optional.hxx --- Mimic std::optional until we can use C++14
|
||||||
|
// Copyright (C) 2020 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 Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
// MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inefficient version of std::optional. It requires a default-constructable,
|
||||||
|
* copyable T type, unlike the real version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class optional
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
optional() = default;
|
||||||
|
|
||||||
|
optional(const T& v) :
|
||||||
|
_value(v),
|
||||||
|
_haveValue(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
optional(const optional<T>& other) :
|
||||||
|
_value(other._value),
|
||||||
|
_haveValue(other._haveValue)
|
||||||
|
{}
|
||||||
|
|
||||||
|
optional<T>& operator=(const optional<T>& other)
|
||||||
|
{
|
||||||
|
_haveValue = other._haveValue;
|
||||||
|
_value = other._value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
return _haveValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_value() const
|
||||||
|
{
|
||||||
|
return _haveValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& value() const
|
||||||
|
{
|
||||||
|
if (!_haveValue) {
|
||||||
|
throw sg_exception("No value in optional");
|
||||||
|
}
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& value()
|
||||||
|
{
|
||||||
|
if (!_haveValue) {
|
||||||
|
throw sg_exception("No value in optional");
|
||||||
|
}
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
_haveValue = false;
|
||||||
|
_value = {};
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T _value = {};
|
||||||
|
bool _haveValue = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // of namespace simgear
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user